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) 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/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: 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: 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)