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
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to