ldrumm updated this revision to Diff 81753.
ldrumm marked 6 inline comments as done.
ldrumm added a comment.

updated to use StringRef-based parser rather than char pointers


https://reviews.llvm.org/D27223

Files:
  include/lldb/Core/FastDemangle.h
  
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/Core/FastDemangle.cpp
  source/Expression/IRExecutionUnit.cpp
  source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
  source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
  source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h

Index: source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
===================================================================
--- source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
+++ source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -12,6 +12,7 @@
 
 // C Includes
 // C++ Includes
+#include <set>
 #include <vector>
 
 // Other libraries and framework includes
@@ -93,7 +94,6 @@
   }
 
   std::unique_ptr<TypeScavenger> GetTypeScavenger() override;
-  
   lldb::TypeCategoryImplSP GetFormatters() override;
 
   HardcodedFormatters::HardcodedSummaryFinder GetHardcodedSummaries() override;
@@ -142,6 +142,12 @@
   static uint32_t FindEquivalentNames(ConstString type_name,
                                       std::vector<ConstString> &equivalents);
 
+  // Given a mangled function name, calculates some alternative manglings since
+  // the compiler mangling may not line up with the symbol we are expecting
+  static uint32_t
+  FindAlternateFunctionManglings(const ConstString mangled,
+                                 std::set<ConstString> &candidates);
+
   //------------------------------------------------------------------
   // PluginInterface protocol
   //------------------------------------------------------------------
Index: source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
===================================================================
--- source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -10,17 +10,22 @@
 #include "CPlusPlusLanguage.h"
 
 // C Includes
-// C++ Includes
 #include <cctype>
 #include <cstring>
+
+// C++ Includes
 #include <functional>
+#include <memory>
 #include <mutex>
+#include <set>
 
 // Other libraries and framework includes
 #include "llvm/ADT/StringRef.h"
 
 // Project includes
 #include "lldb/Core/ConstString.h"
+#include "lldb/Core/FastDemangle.h"
+#include "lldb/Core/Log.h"
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/RegularExpression.h"
 #include "lldb/Core/UniqueCStringMap.h"
@@ -440,6 +445,101 @@
   return count;
 }
 
+/// Given a mangled function `mangled`, replace all the primitive function type
+/// arguments of `search` with type `replace`.
+static ConstString SubsPrimitiveParmItanium(llvm::StringRef mangled,
+                                            llvm::StringRef search,
+                                            llvm::StringRef replace) {
+  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
+
+  const size_t max_len =
+      mangled.size() + mangled.count(search) * replace.size() + 1;
+
+  // Make a temporary buffer to fix up the mangled parameter types and copy the
+  // original there
+  std::string output_buf;
+  output_buf.reserve(max_len);
+  output_buf.insert(0, mangled.str());
+  ptrdiff_t replaced_offset = 0;
+
+  auto swap_parms_hook = [&](const char *parsee) {
+    if (!parsee || !*parsee)
+      return;
+
+    // Check whether we've found a substitutee
+    llvm::StringRef s(parsee);
+    if (s.startswith(search)) {
+      // account for the case where a replacement is of a different length to
+      // the original
+      replaced_offset += replace.size() - search.size();
+
+      ptrdiff_t replace_idx = (mangled.size() - s.size()) + replaced_offset;
+      output_buf.erase(replace_idx, search.size());
+      output_buf.insert(replace_idx, replace.str());
+    }
+  };
+
+  // FastDemangle will call our hook for each instance of a primitive type,
+  // allowing us to perform substitution
+  const char *const demangled =
+      FastDemangle(mangled.str().c_str(), mangled.size(), swap_parms_hook);
+
+  if (log)
+    log->Printf("substituted mangling for %s:{%s} %s:{%s}\n",
+                mangled.str().c_str(), demangled, output_buf.c_str(),
+                FastDemangle(output_buf.c_str()));
+
+  return output_buf == mangled ? ConstString() : ConstString(output_buf);
+}
+
+uint32_t CPlusPlusLanguage::FindAlternateFunctionManglings(
+    const ConstString mangled_name, std::set<ConstString> &alternates) {
+  const auto start_size = alternates.size();
+  /// Get a basic set of alternative manglings for the given symbol `name`, by
+  /// making a few basic possible substitutions on basic types, storage duration
+  /// and `const`ness for the given symbol. The output parameter `alternates`
+  /// is filled with a best-guess, non-exhaustive set of different manglings
+  /// for the given name.
+
+  // Maybe we're looking for a const symbol but the debug info told us it was
+  // non-const...
+  if (!strncmp(mangled_name.GetCString(), "_ZN", 3) &&
+      strncmp(mangled_name.GetCString(), "_ZNK", 4)) {
+    std::string fixed_scratch("_ZNK");
+    fixed_scratch.append(mangled_name.GetCString() + 3);
+    alternates.insert(ConstString(fixed_scratch));
+  }
+
+  // Maybe we're looking for a static symbol but we thought it was global...
+  if (!strncmp(mangled_name.GetCString(), "_Z", 2) &&
+      strncmp(mangled_name.GetCString(), "_ZL", 3)) {
+    std::string fixed_scratch("_ZL");
+    fixed_scratch.append(mangled_name.GetCString() + 2);
+    alternates.insert(ConstString(fixed_scratch));
+  }
+
+  // `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'.
+  if (ConstString char_fixup =
+          SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "a", "c"))
+    alternates.insert(char_fixup);
+
+  // long long parameter mangling 'x', may actually just be a long 'l' argument
+  if (ConstString long_fixup =
+          SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "x", "l"))
+    alternates.insert(long_fixup);
+
+  // unsigned long long parameter mangling 'y', may actually just be unsigned
+  // long 'm' argument
+  if (ConstString ulong_fixup =
+          SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "y", "m"))
+    alternates.insert(ulong_fixup);
+
+  return alternates.size() - start_size;
+}
+
 static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
   if (!cpp_category_sp)
     return;
@@ -931,7 +1031,7 @@
       return candidate;
     }
   };
-  
+
   return std::unique_ptr<TypeScavenger>(new CPlusPlusTypeScavenger());
 }
 
Index: source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
===================================================================
--- source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -1978,11 +1978,12 @@
   if (function) {
     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));
+    const auto lang = function->GetCompileUnit()->GetLanguage();
+    const auto name = function->GetMangled().GetMangledName().AsCString();
+    const bool extern_c = (Language::LanguageIsC(lang) &&
+                           !CPlusPlusLanguage::IsCPPMangledName(name)) ||
+                          (Language::LanguageIsObjC(lang) &&
+                           !Language::LanguageIsCPlusPlus(lang));
 
     if (!extern_c) {
       TypeSystem *type_system = function->GetDeclContext().GetTypeSystem();
Index: source/Expression/IRExecutionUnit.cpp
===================================================================
--- source/Expression/IRExecutionUnit.cpp
+++ source/Expression/IRExecutionUnit.cpp
@@ -776,22 +776,9 @@
       }
     }
 
-    // Maybe we're looking for a const symbol but the debug info told us it was
-    // const...
-    if (!strncmp(name.GetCString(), "_ZN", 3) &&
-        strncmp(name.GetCString(), "_ZNK", 4)) {
-      std::string fixed_scratch("_ZNK");
-      fixed_scratch.append(name.GetCString() + 3);
-      CPP_specs.push_back(ConstString(fixed_scratch.c_str()));
-    }
-
-    // Maybe we're looking for a static symbol but we thought it was global...
-    if (!strncmp(name.GetCString(), "_Z", 2) &&
-        strncmp(name.GetCString(), "_ZL", 3)) {
-      std::string fixed_scratch("_ZL");
-      fixed_scratch.append(name.GetCString() + 2);
-      CPP_specs.push_back(ConstString(fixed_scratch.c_str()));
-    }
+    std::set<ConstString> alternates;
+    CPlusPlusLanguage::FindAlternateFunctionManglings(name, alternates);
+    CPP_specs.insert(CPP_specs.end(), alternates.begin(), alternates.end());
   }
 }
 
Index: source/Core/FastDemangle.cpp
===================================================================
--- source/Core/FastDemangle.cpp
+++ source/Core/FastDemangle.cpp
@@ -11,6 +11,9 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <functional>
+
+#include "lldb/Core/FastDemangle.h"
 #include "lldb/lldb-private.h"
 
 //#define DEBUG_FAILURES 1
@@ -119,7 +122,9 @@
   /// @param storage_size Number of bytes of space available scratch memory
   /// referenced by storage_ptr
 
-  SymbolDemangler(void *storage_ptr, int storage_size) {
+  SymbolDemangler(void *storage_ptr, size_t storage_size,
+                  std::function<void(const char *)> builtins_hook = nullptr)
+      : m_builtins_hook(builtins_hook) {
     // Use up to 1/8th of the provided space for rewrite ranges
     m_rewrite_ranges_size = (storage_size >> 3) / sizeof(BufferRange);
     m_rewrite_ranges = (BufferRange *)storage_ptr;
@@ -509,6 +514,9 @@
   //                ::= u <source-name>    # vendor extended type
 
   const char *TryParseBuiltinType() {
+    if (m_builtins_hook)
+      m_builtins_hook(m_read_ptr);
+
     switch (*m_read_ptr++) {
     case 'v':
       return "void";
@@ -1150,6 +1158,23 @@
     return RewriteTemplateArg(count + 1);
   }
 
+  // <vector-type>
+  // Dv <dimension number> _ <vector type>
+  bool TryParseVectorType() {
+    const int dimension = TryParseNumber();
+    if (dimension == -1)
+      return false;
+
+    if (*m_read_ptr++ != '_')
+      return false;
+
+    char vec_dimens[32] = {'\0'};
+    ::snprintf(vec_dimens, sizeof vec_dimens - 1, " __vector(%d)", dimension);
+    ParseType();
+    Write(vec_dimens);
+    return true;
+  }
+
   // <type> ::= <builtin-type>
   //        ::= <function-type>
   //        ::= <class-enum-type>
@@ -1191,9 +1216,12 @@
         if (!ParseType())
           return false;
         break;
+      case 'v':
+        if (!TryParseVectorType())
+          return false;
+        break;
       case 'T':
       case 't':
-      case 'v':
       default:
 #ifdef DEBUG_FAILURES
         printf("*** Unsupported type: %.3s\n", failed_type);
@@ -2346,6 +2374,7 @@
   char *m_write_ptr;
   int m_next_template_arg_index;
   int m_next_substitute_index;
+  std::function<void(const char *s)> m_builtins_hook;
 };
 
 } // Anonymous namespace
@@ -2358,9 +2387,10 @@
   return demangler.GetDemangledCopy(mangled_name);
 }
 
-char *FastDemangle(const char *mangled_name, long mangled_name_length) {
+char *FastDemangle(const char *mangled_name, size_t mangled_name_length,
+                   std::function<void(const char *s)> builtins_hook) {
   char buffer[16384];
-  SymbolDemangler demangler(buffer, sizeof(buffer));
+  SymbolDemangler demangler(buffer, sizeof(buffer), builtins_hook);
   return demangler.GetDemangledCopy(mangled_name, mangled_name_length);
 }
 } // lldb_private namespace
Index: packages/Python/lldbsuite/test/expression_command/call-overloaded-c-fuction/main.c
===================================================================
--- /dev/null
+++ 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
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/expression_command/call-overloaded-c-fuction/TestCallOverloadedCFunction.py
@@ -0,0 +1,60 @@
+"""
+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 (
+    skipIf,
+    expectedFailureAll
+)
+from lldbsuite.test.lldbtest import (
+    TestBase,
+    CURRENT_EXECUTABLE_SET,
+    RUN_SUCCEEDED,
+    line_number,
+    no_match,
+)
+from lldbsuite.test import lldbutil
+
+
+class TestExprCallOverloadedCFunction(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def setUp(self):
+        super(TestExprCallOverloadedCFunction, self).setUp()
+        # Find the line number to break for main.c.
+        self.line = line_number('main.c', '// break here')
+
+    @skipIf(compiler=no_match('clang'))  # `overloadable` is only supported by clang"
+    @expectedFailureAll(
+        oslist=["windows"],
+        bugnumber="llvm.org/pr24489: Name lookup broken on Windows")
+    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
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/expression_command/call-overloaded-c-fuction/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../make
+
+C_SOURCES := main.c
+
+include $(LEVEL)/Makefile.rules
Index: include/lldb/Core/FastDemangle.h
===================================================================
--- include/lldb/Core/FastDemangle.h
+++ include/lldb/Core/FastDemangle.h
@@ -10,11 +10,17 @@
 #ifndef liblldb_FastDemangle_h_
 #define liblldb_FastDemangle_h_
 
+#include <cstddef>
+
+#include <functional>
+
 namespace lldb_private {
 
 char *FastDemangle(const char *mangled_name);
 
-char *FastDemangle(const char *mangled_name, long mangled_name_length);
+char *
+FastDemangle(const char *mangled_name, size_t mangled_name_length,
+             std::function<void(const char *s)> primitive_type_hook = nullptr);
 }
 
 #endif
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to