EwanCrawford created this revision.
EwanCrawford added reviewers: spyffe, clayborg.
EwanCrawford added a subscriber: lldb-commits.
EwanCrawford set the repository for this revision to rL LLVM.
Fixes bugzilla ticket https://llvm.org/bugs/show_bug.cgi?id=26694
Where we can currently pick the incorrect declaration when calling a C function
with the overloadable attribute.
This is done by checking if we're using language C, but the function has a
mangled name.
Patch also includes some additional fallback parameter manglings for when clang
doesn't emit a matching symbol.
Repository:
rL LLVM
http://reviews.llvm.org/D17957
Files:
packages/Python/lldbsuite/test/expression_command/call-overloaded-c-fuction/Makefile
packages/Python/lldbsuite/test/expression_command/call-overloaded-c-fuction/TestCallOverloadedCFunction.py
packages/Python/lldbsuite/test/expression_command/call-overloaded-c-fuction/main.c
source/Expression/IRExecutionUnit.cpp
source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
Index: source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
===================================================================
--- source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -2028,9 +2028,9 @@
Type *function_type = function->GetType();
const lldb::LanguageType comp_unit_language = function->GetCompileUnit()->GetLanguage();
- const bool extern_c = Language::LanguageIsC(comp_unit_language) ||
- (Language::LanguageIsObjC(comp_unit_language) &&
- !Language::LanguageIsCPlusPlus(comp_unit_language));
+ bool extern_c = Language::LanguageIsC(comp_unit_language) ||
+ (Language::LanguageIsObjC(comp_unit_language) &&
+ !Language::LanguageIsCPlusPlus(comp_unit_language));
if (!extern_c)
{
@@ -2075,6 +2075,10 @@
}
}
+ // __attribute__((overloadable)) in C can mangle names
+ if (extern_c && Language::LanguageIsC(comp_unit_language))
+ extern_c = !CPlusPlusLanguage::IsCPPMangledName(function->GetMangled().GetMangledName().AsCString());
+
if (!function_type)
{
if (log)
Index: source/Expression/IRExecutionUnit.cpp
===================================================================
--- source/Expression/IRExecutionUnit.cpp
+++ source/Expression/IRExecutionUnit.cpp
@@ -700,6 +700,42 @@
return ConstString();
}
+// Given a mangled function, replaces all the function parameters of mangled type
+// 'search', with parameters of type 'replace'.
+static ConstString
+SubstituteMangledParameters(const llvm::StringRef& mangled, const llvm::StringRef& search, const llvm::StringRef& replace)
+{
+ // Find length of function name, already encoded in mangled symbol
+ static const llvm::StringRef numeric_digits("0123456789");
+ const size_t encoded_length_start = mangled.find_first_of(numeric_digits);
+ if (encoded_length_start == llvm::StringRef::npos)
+ return ConstString();
+
+ const size_t encoded_length_end = mangled.find_first_not_of(numeric_digits, encoded_length_start);
+ if (encoded_length_end == llvm::StringRef::npos || encoded_length_end <= encoded_length_start)
+ return ConstString();
+
+ // Parse encoded length into name_length
+ int name_length;
+ const llvm::StringRef encoded_length_str = mangled.substr(encoded_length_start, encoded_length_end - encoded_length_start);
+ if (encoded_length_str.getAsInteger(10, name_length) || name_length == 0)
+ return ConstString();
+
+ // Position in 'mangled' string of first function parameter
+ size_t param_pos = encoded_length_end + name_length;
+
+ // Iterate over all matching parameters, replacing them with string 'replace'
+ std::string modified_str = mangled.str();
+ while ((param_pos = modified_str.find(search, param_pos)) != std::string::npos)
+ {
+ modified_str.replace(param_pos, search.size(), replace);
+ param_pos += replace.size();
+ }
+
+ return ConstString(modified_str);
+}
+
+
struct IRExecutionUnit::SearchSpec
{
ConstString name;
@@ -763,6 +799,20 @@
CPP_specs.push_back(ConstString(fixed_scratch.c_str()));
}
+ // Char is implementation defined as either signed or unsigned.
+ // As a result a char parameter has 3 possible manglings: 'c'-char, 'a'-signed char, 'h'-unsigned char.
+ // If we're looking for symbols with a signed char parameter,
+ // try finding matches which have the general case 'c'.
+ ConstString char_fixup = SubstituteMangledParameters(name.GetStringRef(), llvm::StringRef("a"), llvm::StringRef("c"));
+ CPP_specs.push_back(SearchSpec(char_fixup, lldb::eFunctionNameTypeFull));
+
+ // long long parameter mangling 'x', may actually just be a long 'l' argument
+ ConstString long_fixup = SubstituteMangledParameters(name.GetStringRef(), llvm::StringRef("x"), llvm::StringRef("l"));
+ CPP_specs.push_back(SearchSpec(long_fixup, lldb::eFunctionNameTypeFull));
+
+ // unsigned long long parameter mangling 'y', may actually just be unsigned long 'm' argument
+ ConstString ulong_fixup = SubstituteMangledParameters(name.AsCString(), llvm::StringRef("y"), llvm::StringRef("m"));
+ CPP_specs.push_back(SearchSpec(ulong_fixup, lldb::eFunctionNameTypeFull));
}
}
Index: packages/Python/lldbsuite/test/expression_command/call-overloaded-c-fuction/main.c
===================================================================
--- packages/Python/lldbsuite/test/expression_command/call-overloaded-c-fuction/main.c
+++ packages/Python/lldbsuite/test/expression_command/call-overloaded-c-fuction/main.c
@@ -0,0 +1,17 @@
+char __attribute__((overloadable)) get_arg_type(float x)
+{
+ return 'F'; // 'F' for float
+}
+
+char __attribute__((overloadable)) get_arg_type(int x)
+{
+ return 'I'; // 'I' for int
+}
+
+int main()
+{
+ char float_result = get_arg_type(0.1f);
+ char int_result = get_arg_type(2);
+
+ return 0; // break here
+}
Index: packages/Python/lldbsuite/test/expression_command/call-overloaded-c-fuction/TestCallOverloadedCFunction.py
===================================================================
--- packages/Python/lldbsuite/test/expression_command/call-overloaded-c-fuction/TestCallOverloadedCFunction.py
+++ packages/Python/lldbsuite/test/expression_command/call-overloaded-c-fuction/TestCallOverloadedCFunction.py
@@ -0,0 +1,50 @@
+"""
+Test calling user defined C functions using expression evaluation.
+This test checks that expression evaluation works correctly for
+functions defined with __attribute__((overloadable)).
+
+Ticket: https://llvm.org/bugs/show_bug.cgi?id=26694
+"""
+
+from __future__ import print_function
+
+import lldb
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestExprCallOverloadedCFunction(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def setUp(self):
+ TestBase.setUp(self)
+ # Find the line number to break for main.c.
+ self.line = line_number('main.c',
+ '// break here')
+
+ @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24489: Name lookup not working correctly on Windows")
+ @expectedFailureAll(compiler='gcc') # attribute overloadable only supported by clang
+ def test(self):
+ """Test calling overloaded C functions."""
+ self.build()
+
+ # Set breakpoint in main and run exe
+ self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
+ lldbutil.run_break_set_by_file_and_line(
+ self,
+ "main.c",
+ self.line,
+ num_expected_locations=-1,
+ loc_exact=True
+ )
+
+ self.runCmd("run", RUN_SUCCEEDED)
+
+ # Test floating point type overload.
+ self.expect("expr get_arg_type(0.5f)", substrs=["$0 = 'F'"])
+
+ # Test integer type overload
+ self.expect("expr get_arg_type(8)", substrs=["$1 = 'I'"])
Index: packages/Python/lldbsuite/test/expression_command/call-overloaded-c-fuction/Makefile
===================================================================
--- packages/Python/lldbsuite/test/expression_command/call-overloaded-c-fuction/Makefile
+++ packages/Python/lldbsuite/test/expression_command/call-overloaded-c-fuction/Makefile
@@ -0,0 +1,16 @@
+LEVEL = ../../make
+
+CXX_SOURCES := main.cpp
+
+# clang-3.5+ outputs FullDebugInfo by default for Darwin/FreeBSD
+# targets. Other targets do not, which causes this test to fail.
+# This flag enables FullDebugInfo for all targets.
+ifneq (,$(findstring clang,$(CC)))
+ CFLAGS_EXTRAS += -fno-limit-debug-info
+endif
+
+# Note: overloadable attribute only supported by clang
+include $(LEVEL)/Makefile.rules
+
+clean::
+ rm -rf $(wildcard *.o *.d *.dSYM)
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits