Michael137 updated this revision to Diff 452547.
Michael137 marked 5 inline comments as done.
Michael137 added a comment.

- Use ConstString::GetLength where possible
- Add more comments
- Rebase
- Add test case


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D131335/new/

https://reviews.llvm.org/D131335

Files:
  lldb/packages/Python/lldbsuite/test/make/Makefile.rules
  lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
  lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
  lldb/test/API/lang/cpp/abi_tag_lookup/Makefile
  lldb/test/API/lang/cpp/abi_tag_lookup/TestAbiTagLookup.py
  lldb/test/API/lang/cpp/abi_tag_lookup/main.cpp

Index: lldb/test/API/lang/cpp/abi_tag_lookup/main.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/lang/cpp/abi_tag_lookup/main.cpp
@@ -0,0 +1,71 @@
+#include <cstdio>
+
+namespace A {
+template <typename T> bool operator<(const T &, const T &) { return true; }
+
+template <typename T>
+[[gnu::abi_tag("Two", "Tags")]] bool operator>(const T &, const T &) {
+  return true;
+}
+
+template <typename T>
+[[gnu::abi_tag("OneTag")]] bool operator==(const T &, const T &) {
+  return true;
+}
+
+[[gnu::abi_tag("Foo")]] int withAbiTagInNS(const int &, const int &) {
+  return 1;
+}
+
+template <typename T>
+[[gnu::abi_tag("Bar")]] int withAbiTagInNS(const T &, const T &) {
+  return 2;
+}
+
+struct B {};
+} // namespace A
+
+template <typename T>
+[[gnu::abi_tag("Baz")]] int withAbiTag(const T &, const T &) {
+  return 3;
+}
+
+[[gnu::abi_tag("Baz")]] int withAbiTag(const int &, const int &) { return -3; }
+
+struct Simple {
+  int mem;
+};
+
+struct [[gnu::abi_tag("Qux")]] Tagged {
+  int mem;
+
+  int const &Value() const { return mem; }
+};
+
+template <typename T> struct [[gnu::abi_tag("Quux", "Quuux")]] TaggedTemplate {
+  T mem;
+
+  T const &Value() const { return mem; }
+};
+
+// clang-format off
+inline namespace [[gnu::abi_tag("Inline", "NS")]] v1 {
+template <typename T> int withImplicitTag(T const &t) { return t.mem; }
+} // namespace
+// clang-format on
+
+int main() {
+  A::B b1;
+  A::B b2;
+  Tagged t{.mem = 4};
+  TaggedTemplate<int> tt{.mem = 5};
+
+  int result = (b1 < b2) + (b1 > b2) + (b1 == b2) + withAbiTag(b1, b2) +
+               A::withAbiTagInNS(1.0, 2.0) + withAbiTagInNS(b1, b2) +
+               A::withAbiTagInNS(1, 2) + withImplicitTag(Tagged{.mem = 6}) +
+               withImplicitTag(Simple{.mem = 6}) + t.Value() + tt.Value();
+
+  std::puts("Break here");
+
+  return result;
+}
Index: lldb/test/API/lang/cpp/abi_tag_lookup/TestAbiTagLookup.py
===================================================================
--- /dev/null
+++ lldb/test/API/lang/cpp/abi_tag_lookup/TestAbiTagLookup.py
@@ -0,0 +1,56 @@
+"""
+Test that we can call functions and use types
+annotated (and thus mangled) with ABI tags.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class AbiTagLookupTestCase(TestBase):
+
+    @skipIfWindows
+    @expectedFailureAll(debug_info=["dwarf", "gmodules", "dwo"])
+    def test_abi_tag_lookup(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(self, 'Break here',
+                lldb.SBFileSpec("main.cpp", False))
+
+        # Qualified/unqualified lookup to templates in namespace
+        self.expect_expr("operator<(b1, b2)", result_type="bool", result_value="true")
+        self.expect_expr("A::operator<(b1, b2)", result_type="bool", result_value="true")
+        self.expect_expr("b1 < b2", result_type="bool", result_value="true")
+
+        # Qualified/unqualified lookup to templates with ABI tags in namespace
+        self.expect_expr("operator>(b1, b2)", result_type="bool", result_value="true")
+        self.expect_expr("A::operator>(b1, b2)", result_type="bool", result_value="true")
+        self.expect_expr("b1 > b2", result_type="bool", result_value="true")
+
+        # Call non-operator templates with ABI tags
+        self.expect_expr("A::withAbiTagInNS(1, 1)", result_type="int", result_value="1")
+
+        self.expect_expr("A::withAbiTagInNS(1.0, 1.0)", result_type="int", result_value="2")
+        self.expect_expr("withAbiTagInNS(b1, b2)", result_type="int", result_value="2")
+        self.expect_expr("A::withAbiTagInNS(b1, b2)", result_type="int", result_value="2")
+
+        self.expect_expr("withAbiTag(b1, b2)", result_type="int", result_value="3")
+        self.expect_expr("withAbiTag(0, 0)", result_type="int", result_value="-3")
+
+        # Structures with ABI tags
+        self.expect_expr("t.Value()", result_type="const int", result_value="4")
+        self.expect_expr("tt.Value()", result_type="const int", result_value="5")
+
+        self.expect_expr("Tagged{.mem = 6}", result_type="Tagged",
+                         result_children=[ValueCheck(name="mem", value="6")])
+
+        # Inline namespaces with ABI tags
+        self.expect_expr("v1::withImplicitTag(Simple{.mem = 6})", result_type="int", result_value="6")
+        self.expect_expr("withImplicitTag(Simple{.mem = 6})", result_type="int", result_value="6")
+
+        # FIXME: this currently fails because CPlusPlusLanguage::FindBestAlternateFunctionMangledName
+        #        requires at least the parameters of the symbols it compares to match. However,
+        #        the IR we generate doesn't include ABI tags on the parameter. To fix this we need
+        #        to add ABI tag attributes to the decls that DWARFASTParserClang generates.
+        self.expect("expr v1::withImplicitTag(Tagged{.mem = 6})", error=True, substrs=["error: Couldn't lookup symbols:"])
+        self.expect("expr withImplicitTag(Tagged{.mem = 6})", error=True, substrs=["error: Couldn't lookup symbols:"])
Index: lldb/test/API/lang/cpp/abi_tag_lookup/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/lang/cpp/abi_tag_lookup/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
Index: lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
===================================================================
--- lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
+++ lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -107,7 +107,7 @@
   static llvm::StringRef GetPluginNameStatic() { return "cplusplus"; }
 
   bool SymbolNameFitsToLanguage(Mangled mangled) const override;
-  
+
   bool DemangledNameContainsPath(llvm::StringRef path, 
                                  ConstString demangled) const override;
 
@@ -141,6 +141,16 @@
 
   // PluginInterface protocol
   llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+private:
+  void
+  CollectAlternateFunctionNamesFromMangled(std::vector<ConstString> &results,
+                                           ConstString name,
+                                           const SymbolContext &sc) const;
+
+  void CollectAlternateFunctionNamesItanium(std::vector<ConstString> &results,
+                                            ConstString name,
+                                            const SymbolContext &sc) const;
 };
 
 } // namespace lldb_private
Index: lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
===================================================================
--- lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -18,6 +18,8 @@
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Demangle/ItaniumDemangle.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorHandling.h"
 
 #include "lldb/Core/Mangled.h"
 #include "lldb/Core/Module.h"
@@ -510,6 +512,33 @@
   return alternates;
 }
 
+char const *printNode(const llvm::itanium_demangle::Node *RootNode) {
+  llvm::itanium_demangle::OutputBuffer OB;
+
+  // Initial size of name buffer. Will get resized inside of
+  // 'OutputBuffer' if necessary.
+  constexpr size_t KInitBufferSize = 128;
+
+  if (!initializeOutputBuffer(nullptr, nullptr, OB, KInitBufferSize))
+    return nullptr;
+  RootNode->print(OB);
+  OB += '\0';
+  return OB.getBuffer();
+}
+
+char const *getFunctionName(llvm::itanium_demangle::Node const *root) {
+  using namespace llvm::itanium_demangle;
+
+  if (root->getKind() != Node::KFunctionEncoding)
+    return nullptr;
+
+  auto *Name = static_cast<FunctionEncoding const *>(root)->getName();
+
+  assert(Name != nullptr);
+
+  return printNode(Name);
+}
+
 static ConstString
 FindBestAlternateFunctionMangledName(const Mangled mangled,
                                      const SymbolContext &sym_ctx) {
@@ -561,6 +590,89 @@
     return ConstString();
 }
 
+ConstString
+FindBestAlternateFunctionMangledName(llvm::itanium_demangle::Node const *node,
+                                     const SymbolContext &sym_ctx) {
+  if (!sym_ctx.module_sp)
+    return ConstString();
+
+  lldb_private::SymbolFile *sym_file = sym_ctx.module_sp->GetSymbolFile();
+  if (!sym_file)
+    return ConstString();
+
+  using namespace llvm::itanium_demangle;
+  assert(node != nullptr);
+
+  if (node->getKind() != Node::KFunctionEncoding)
+    return ConstString();
+
+  std::vector<ConstString> alternates;
+  sym_file->GetMangledNamesForFunction(getFunctionName(node), alternates);
+
+  auto const *encoding = static_cast<FunctionEncoding const *>(node);
+  Qualifiers quals = encoding->getCVQuals();
+  FunctionRefQual refQual = encoding->getRefQual();
+  NodeArray params = encoding->getParams();
+  auto const *attrs = encoding->getAttrs();
+
+  // Iterate over all candidate function names and
+  // find a match for the mangled function name
+  // represented by 'node'. We demangle each candidate
+  // into a mangle tree and compare it to the tree rooted
+  // at 'node'. We return a perfect match if we find one.
+  // Otherwise we collect all approximate matches and return
+  // one of them. A "match" is defined as:
+  //
+  // * Perfect match: parameters, CV-quals, reference-quals,
+  //                  attributes are all equal to those of
+  //                  the input node
+  //
+  // * Approximate match: parameters are equal to those of the
+  //                      input node
+  std::vector<ConstString> param_matches;
+  for (ConstString alternate_mangled_name : alternates) {
+    if (!alternate_mangled_name)
+      continue;
+
+    char const *alternate = alternate_mangled_name.GetCString();
+    const auto alternate_len = alternate_mangled_name.GetLength();
+    ManglingParser<NodeAllocator> alternate_parser(alternate,
+                                                   alternate + alternate_len);
+
+    if (auto const *alt_node = alternate_parser.parse()) {
+      assert(alt_node->getKind() == Node::KFunctionEncoding);
+      auto const *alt_encoding =
+          static_cast<FunctionEncoding const *>(alt_node);
+      Qualifiers alt_quals = alt_encoding->getCVQuals();
+      FunctionRefQual alt_refQual = alt_encoding->getRefQual();
+      NodeArray alt_params = alt_encoding->getParams();
+      auto const *alt_attrs = alt_encoding->getAttrs();
+
+      if (params == alt_params) {
+        if (quals == alt_quals && refQual == alt_refQual) {
+          if ((attrs && alt_attrs && attrs->equals(alt_attrs)) ||
+              (!attrs && !alt_attrs)) {
+            // Perfect match. Return it.
+            return alternate_mangled_name;
+          }
+        }
+
+        // Not a perfect match, but count matching parameters
+        // as an approximate match.
+        param_matches.push_back(alternate_mangled_name);
+      }
+    }
+  }
+
+  // No perfect match. Return one of the approximate
+  // matches as a best match.
+  if (param_matches.size())
+    return param_matches[0];
+
+  // No matches.
+  return ConstString();
+}
+
 static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
   if (!cpp_category_sp)
     return;
@@ -1407,27 +1519,85 @@
   return file_path.contains("/usr/include/c++/");
 }
 
+void CPlusPlusLanguage::CollectAlternateFunctionNamesFromMangled(
+    std::vector<ConstString> &results, ConstString name,
+    const SymbolContext &sc) const {
+  Mangled mangled(name);
+  if (SymbolNameFitsToLanguage(mangled)) {
+    if (ConstString best_alternate =
+            FindBestAlternateFunctionMangledName(mangled, sc)) {
+      results.push_back(best_alternate);
+    }
+  }
+
+  std::vector<ConstString> alternates =
+      GenerateAlternateFunctionManglings(name);
+  results.insert(results.end(), alternates.begin(), alternates.end());
+
+  // As a last-ditch fallback, try the base name for C++ names.  It's
+  // terrible, but the DWARF doesn't always encode "extern C" correctly.
+  ConstString basename = GetDemangledFunctionNameWithoutArguments(mangled);
+  results.push_back(basename);
+}
+
+void CPlusPlusLanguage::CollectAlternateFunctionNamesItanium(
+    std::vector<ConstString> &results, ConstString name,
+    const SymbolContext &sc) const {
+  if (!name)
+    return;
+
+  char const *mangled = name.GetCString();
+  const auto mangled_len = name.GetLength();
+  using namespace llvm::itanium_demangle;
+  ManglingParser<NodeAllocator> parser(mangled, mangled + mangled_len);
+  auto const *node = parser.parse();
+
+  if (node && CPlusPlusLanguage::IsCPPMangledName(name.GetStringRef())) {
+    if (ConstString best_alternate =
+            FindBestAlternateFunctionMangledName(node, sc)) {
+      results.push_back(best_alternate);
+    }
+  }
+
+  std::vector<ConstString> alternates =
+      GenerateAlternateFunctionManglings(name);
+  results.insert(results.end(), alternates.begin(), alternates.end());
+
+  // As a last-ditch fallback, try the base name for C++ names.  It's
+  // terrible, but the DWARF doesn't always encode "extern C" correctly.
+  if (node) {
+    ConstString basename(getFunctionName(node));
+    results.push_back(basename);
+  }
+}
+
 std::vector<ConstString> CPlusPlusLanguage::CollectAlternateFunctionNames(
     const std::vector<ConstString> &mangled_names,
     const SymbolContext &sc) const {
   std::vector<ConstString> results;
   for (const ConstString &name : mangled_names) {
-    Mangled mangled(name);
-    if (SymbolNameFitsToLanguage(mangled)) {
-      if (ConstString best_alternate =
-              FindBestAlternateFunctionMangledName(mangled, sc)) {
-        results.push_back(best_alternate);
+    auto scheme = Mangled::GetManglingScheme(name.GetStringRef());
+    switch (scheme) {
+    case Mangled::ManglingScheme::eManglingSchemeItanium:
+      CollectAlternateFunctionNamesItanium(results, name, sc);
+      break;
+    case Mangled::ManglingScheme::eManglingSchemeNone:
+      // Macho-O symbols sometimes contain the non-standard
+      // double-underscore prefix which 'Mangled::GetManglingScheme'
+      // purposefully doesn't support.
+      if (name.GetStringRef().startswith("__Z")) {
+        CollectAlternateFunctionNamesItanium(results, name, sc);
+        break;
       }
+      LLVM_FALLTHROUGH;
+    case Mangled::ManglingScheme::eManglingSchemeMSVC:
+    case Mangled::ManglingScheme::eManglingSchemeRustV0:
+    case Mangled::ManglingScheme::eManglingSchemeD:
+      // We don't have a mangle tree API available. Fall back
+      // to parsing demangled function names to find alternates
+      CollectAlternateFunctionNamesFromMangled(results, name, sc);
+      break;
     }
-
-    std::vector<ConstString> alternates =
-        GenerateAlternateFunctionManglings(name);
-    results.insert(results.end(), alternates.begin(), alternates.end());
-
-    // As a last-ditch fallback, try the base name for C++ names.  It's
-    // terrible, but the DWARF doesn't always encode "extern C" correctly.
-    ConstString basename = GetDemangledFunctionNameWithoutArguments(mangled);
-    results.push_back(basename);
   }
 
   return results;
Index: lldb/packages/Python/lldbsuite/test/make/Makefile.rules
===================================================================
--- lldb/packages/Python/lldbsuite/test/make/Makefile.rules
+++ lldb/packages/Python/lldbsuite/test/make/Makefile.rules
@@ -387,8 +387,7 @@
 endif
 
 ifeq (1,$(USE_LIBCPP))
-	# TODO: Teach LLDB to handle ABI tags in libc++ namespaces.
-	CXXFLAGS += -DLLDB_USING_LIBCPP -D_LIBCPP_NO_ABI_TAG
+	CXXFLAGS += -DLLDB_USING_LIBCPP
 	ifeq "$(OS)" "Android"
 		# Nothing to do, this is already handled in
 		# Android.rules.
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to