[libcxx-commits] [clang] [libcxxabi] [lldb] [llvm] [WIP (PR #115245)

Michael Buch via libcxx-commits libcxx-commits at lists.llvm.org
Wed Nov 6 17:03:42 PST 2024


https://github.com/Michael137 created https://github.com/llvm/llvm-project/pull/115245

None

>From f8087e96f8d8d242a4da2e74a3259161a3bfc179 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 5 Nov 2024 00:22:07 +0000
Subject: [PATCH] Init

---
 clang/include/clang/Basic/Attr.td             |   7 +
 clang/include/clang/Basic/AttrDocs.td         |   5 +
 clang/lib/AST/Mangle.cpp                      |  16 +-
 clang/lib/Sema/SemaDeclAttr.cpp               |  11 ++
 libcxxabi/src/demangle/ItaniumDemangle.h      |   2 +
 lldb/source/Expression/IRExecutionUnit.cpp    | 181 ++++++++++++++++++
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  |  29 ++-
 .../TypeSystem/Clang/TypeSystemClang.cpp      |  12 +-
 llvm/include/llvm/Demangle/Demangle.h         |   2 +
 llvm/include/llvm/Demangle/ItaniumDemangle.h  |   2 +
 llvm/lib/Demangle/ItaniumDemangle.cpp         |  17 +-
 11 files changed, 271 insertions(+), 13 deletions(-)

diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 70fad60d4edbb5..c0a4c38e479990 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -784,6 +784,13 @@ def AbiTag : Attr {
   let Documentation = [AbiTagsDocs];
 }
 
+def StructorName : Attr {
+    let Spellings = [Clang<"structor_name">];
+    let Args = [StringArgument<"Name">];
+    let Subjects = SubjectList<[Function], ErrorDiag>;
+    let Documentation = [StructorNameDocs];
+}
+
 def AddressSpace : TypeAttr {
   let Spellings = [Clang<"address_space">];
   let Args = [IntArgument<"AddressSpace">];
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 546e5100b79dd9..3672d0d5019fc9 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -3568,6 +3568,11 @@ manipulating bits of the enumerator when issuing warnings.
   }];
 }
 
+def StructorNameDocs : Documentation {
+    let Category = DocCatDecl;
+    let Content = [{ TODO }];
+}
+
 def AsmLabelDocs : Documentation {
   let Category = DocCatDecl;
   let Content = [{
diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp
index 4875e8537b3c11..e193c96dd064e7 100644
--- a/clang/lib/AST/Mangle.cpp
+++ b/clang/lib/AST/Mangle.cpp
@@ -126,7 +126,7 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
 
   // Any decl can be declared with __asm("foo") on it, and this takes precedence
   // over all other naming in the .o file.
-  if (D->hasAttr<AsmLabelAttr>())
+  if (D->hasAttr<AsmLabelAttr>() || D->hasAttr<StructorNameAttr>())
     return true;
 
   // Declarations that don't have identifier names always need to be mangled.
@@ -140,6 +140,20 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
   const ASTContext &ASTContext = getASTContext();
   const NamedDecl *D = cast<NamedDecl>(GD.getDecl());
 
+  if (const auto *SNA = D->getAttr<StructorNameAttr>()) {
+    Out << SNA->getName() << ':';
+
+    if (isa<CXXConstructorDecl>(D)) {
+      Out << 'C';
+      Out << GD.getCtorType();
+    } else {
+      Out << 'D';
+      Out << GD.getDtorType();
+    }
+
+    return;
+  }
+
   // Any decl can be declared with __asm("foo") on it, and this takes precedence
   // over all other naming in the .o file.
   if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 14cc51cf89665a..21302245484cfa 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -1689,6 +1689,14 @@ static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   D->addAttr(::new (S.Context) IFuncAttr(S.Context, AL, Str));
 }
 
+static void handleStructorNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+  StringRef Str;
+  if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
+    return;
+
+  D->addAttr(::new (S.Context) StructorNameAttr(S.Context, AL, Str));
+}
+
 static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   StringRef Str;
   if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
@@ -6983,6 +6991,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
     S.HLSL().handleParamModifierAttr(D, AL);
     break;
 
+  case ParsedAttr::AT_StructorName:
+    handleStructorNameAttr(S, D, AL);
+    break;
   case ParsedAttr::AT_AbiTag:
     handleAbiTagAttr(S, D, AL);
     break;
diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index 3b041efe3aac00..ea32fa4827d290 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -1728,6 +1728,8 @@ class CtorDtorName final : public Node {
 
   template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); }
 
+  int getVariant() const { return Variant; }
+
   void printLeft(OutputBuffer &OB) const override {
     if (IsDtor)
       OB += "~";
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index 15ca2ddbbae046..edcc82a397021b 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -6,6 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/Basic/ABI.h"
+#include "llvm/Demangle/Demangle.h"
 #include "llvm/ExecutionEngine/ExecutionEngine.h"
 #include "llvm/ExecutionEngine/ObjectCache.h"
 #include "llvm/IR/Constants.h"
@@ -13,9 +15,14 @@
 #include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/SourceMgr.h"
 #include "llvm/Support/raw_ostream.h"
 
+#include "Plugins/SymbolFile/DWARF/DWARFBaseDIE.h"
+#include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
+
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/Disassembler.h"
 #include "lldb/Core/Module.h"
@@ -36,8 +43,10 @@
 #include "lldb/Utility/LLDBAssert.h"
 #include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/Log.h"
+#include "lldb/lldb-defines.h"
 
 #include <optional>
+#include <variant>
 
 using namespace lldb_private;
 
@@ -762,6 +771,120 @@ class LoadAddressResolver {
   lldb::addr_t m_best_internal_load_address = LLDB_INVALID_ADDRESS;
 };
 
+using namespace lldb_private::plugin::dwarf;
+
+struct StructorVariant {
+  std::variant<clang::CXXCtorType, clang::CXXDtorType> m_variant;
+};
+
+static llvm::Expected<StructorVariant>
+MakeStructorVariant(llvm::StringRef variant_num) {
+  if (variant_num.consume_front("D")) {
+    std::underlying_type_t<clang::CXXDtorType> dtor_type;
+    if (variant_num.consumeInteger(10, dtor_type))
+      return llvm::createStringError("Invalid ctor variant code.");
+
+    return StructorVariant{.m_variant =
+                               static_cast<clang::CXXDtorType>(dtor_type)};
+  }
+
+  if (variant_num.consume_front("C")) {
+    std::underlying_type_t<clang::CXXCtorType> ctor_type;
+    if (variant_num.consumeInteger(10, ctor_type))
+      return llvm::createStringError("Invalid dtor variant code.");
+
+    return StructorVariant{.m_variant =
+                               static_cast<clang::CXXCtorType>(ctor_type)};
+  }
+
+  return llvm::createStringError("Incorrect structor variant prefix.");
+}
+
+static int GetItaniumVariantCode(StructorVariant structor) {
+  if (auto const *ctor = std::get_if<clang::CXXCtorType>(&structor.m_variant)) {
+    switch (*ctor) {
+    case clang::CXXCtorType::Ctor_Complete:
+      return 1;
+    case clang::CXXCtorType::Ctor_Base:
+      return 2;
+    default:
+      llvm_unreachable("Unimplemented");
+    }
+  } else {
+    switch (std::get<clang::CXXDtorType>(structor.m_variant)) {
+    case clang::CXXDtorType::Dtor_Complete:
+      return 1;
+    case clang::CXXDtorType::Dtor_Base:
+      return 2;
+    default:
+      llvm_unreachable("Unimplemented");
+    }
+  }
+}
+
+// TODO:
+// 1. MS-ABI
+// 2. GCC-style dtor/ctor declarations
+// 3. Inheriting ctors
+// 4. Regular functions
+static std::string FindStructorLinkageName(DWARFDIE die,
+                                           StructorVariant structor_variant) {
+  auto *dwarf = die.GetDWARF();
+  assert(dwarf);
+
+  // Note, GCC only puts DW_AT_linkage_name (not DW_AT_name) on constructor
+  // decls Will those cases still work?
+  ConstString func_name(die.GetName());
+  assert(func_name);
+
+  SymbolContextList sc_list;
+  Module::LookupInfo lookup_info(
+      func_name,
+      lldb::FunctionNameType::eFunctionNameTypeMethod |
+          lldb::FunctionNameType::eFunctionNameTypeFull,
+      lldb::LanguageType::eLanguageTypeUnknown);
+  dwarf->FindFunctions(lookup_info, {}, true, sc_list);
+
+  llvm::DenseMap<int, std::string> variants;
+
+  for (auto const &sc : sc_list.SymbolContexts()) {
+    if (!sc.function)
+      continue;
+
+    auto func_die = dwarf->GetDIE(sc.function->GetID());
+    if (!func_die.IsValid())
+      continue;
+
+    auto spec_die = func_die.GetAttributeValueAsReferenceDIE(
+        llvm::dwarf::DW_AT_specification);
+    if (!spec_die.IsValid() || spec_die != die)
+      continue;
+
+    llvm::ItaniumPartialDemangler D;
+    if (D.partialDemangle(func_die.GetMangledName()))
+      continue;
+
+    const auto maybe_structor_kind = D.getCtorDtorVariant();
+    // TODO: this need not be true
+    assert(maybe_structor_kind);
+
+    variants.insert({*maybe_structor_kind, func_die.GetMangledName()});
+  }
+
+  auto itanium_code = GetItaniumVariantCode(structor_variant);
+  auto it = variants.find(itanium_code);
+  if (it != variants.end())
+    return it->second;
+
+  // If only C2 was emitted but we tried calling C1,
+  // we can probably (?) safely call C2.
+  if (itanium_code == 1 && variants.size() == 1)
+    if (auto retry = variants.find(2); retry != variants.end())
+      return retry->second;
+
+  return {};
+}
+
 lldb::addr_t
 IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
                                const lldb_private::SymbolContext &sc,
@@ -781,6 +904,64 @@ IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
   function_options.include_inlines = false;
 
   for (const ConstString &name : names) {
+    auto ref = name.GetStringRef();
+    if (ref.consume_front("$__lldb_func_")) {
+      uintptr_t module_ptr;
+      if (ref.consumeInteger(0, module_ptr))
+        return LLDB_INVALID_ADDRESS;
+
+      if (module_ptr == 0) {
+        // TODO: log this case. We should ever be putting a null module pointer
+        // here
+        return LLDB_INVALID_ADDRESS;
+      }
+
+      auto *mod = (lldb_private::Module *)module_ptr;
+      assert(mod);
+      auto *sym = mod->GetSymbolFile();
+      assert(sym);
+
+      if (!ref.consume_front(":"))
+        return LLDB_INVALID_ADDRESS;
+
+      lldb::user_id_t die_id;
+      if (ref.consumeInteger(10, die_id))
+        return LLDB_INVALID_ADDRESS;
+
+      auto *dwarf = llvm::dyn_cast<plugin::dwarf::SymbolFileDWARF>(sym);
+      if (!dwarf)
+        return LLDB_INVALID_ADDRESS;
+
+      auto die = dwarf->GetDIE(die_id);
+      if (!die.IsValid())
+        return LLDB_INVALID_ADDRESS;
+
+      // TODO: account for MS-ABI (where there are no ctor variants in the
+      // mangling)
+      if (!ref.consume_front(":"))
+        return LLDB_INVALID_ADDRESS;
+
+      auto structor_variant_or_err = MakeStructorVariant(ref);
+      if (!structor_variant_or_err) {
+        LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions),
+                       structor_variant_or_err.takeError(),
+                       "Failed to parse structor variant encoding for {1}: {0}",
+                       name.GetStringRef());
+        return LLDB_INVALID_ADDRESS;
+      }
+
+      ConstString mangled(
+          FindStructorLinkageName(die, *structor_variant_or_err));
+
+      Module::LookupInfo lookup_info(
+          mangled, lldb::FunctionNameType::eFunctionNameTypeAny,
+          lldb::LanguageType::eLanguageTypeC_plus_plus);
+      SymbolContextList sc_list;
+      dwarf->FindFunctions(lookup_info, {}, false, sc_list);
+      if (auto load_addr = resolver.Resolve(sc_list))
+        return *load_addr;
+    }
+
     if (sc.module_sp) {
       SymbolContextList sc_list;
       sc.module_sp->FindFunctions(name, CompilerDeclContext(),
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 70540fe7fada68..9078234cf3fa35 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -1040,6 +1040,16 @@ bool DWARFASTParserClang::ParseObjCMethod(
   return true;
 }
 
+static bool IsStructorDIE(DWARFDIE const &die, DWARFDIE const &parent_die) {
+  llvm::StringRef name = die.GetName();
+  llvm::StringRef parent_name = parent_die.GetName();
+
+  name.consume_front("~");
+  parent_name = parent_name.substr(0, parent_name.find('<'));
+
+  return name == parent_name;
+}
+
 std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod(
     const DWARFDIE &die, CompilerType clang_type,
     const ParsedDWARFTypeAttributes &attrs, const DWARFDIE &decl_ctx_die,
@@ -1140,11 +1150,22 @@ std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod(
   const auto accessibility =
       attrs.accessibility == eAccessNone ? eAccessPublic : attrs.accessibility;
 
+  // TODO: we should also include mangled name in identifier for
+  // better diagnostics and easier debugging when reading the
+  // expression evaluator IR.
+  std::string mangled_name;
+  if (IsStructorDIE(die, decl_ctx_die))
+    mangled_name = llvm::formatv("$__lldb_func_{0}:{1}", die.GetModule().get(),
+                                 die.GetID())
+                       .str();
+
+  char const *mangled =
+      mangled_name.empty() ? attrs.mangled_name : mangled_name.c_str();
+
   clang::CXXMethodDecl *cxx_method_decl = m_ast.AddMethodToCXXRecordType(
-      class_opaque_type.GetOpaqueQualType(), attrs.name.GetCString(),
-      attrs.mangled_name, clang_type, accessibility, attrs.is_virtual,
-      is_static, attrs.is_inline, attrs.is_explicit, is_attr_used,
-      attrs.is_artificial);
+      class_opaque_type.GetOpaqueQualType(), attrs.name.GetCString(), mangled,
+      clang_type, accessibility, attrs.is_virtual, is_static, attrs.is_inline,
+      attrs.is_explicit, is_attr_used, attrs.is_artificial);
 
   if (cxx_method_decl) {
     LinkDeclContextToDIE(cxx_method_decl, die);
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index b0f49ebf2d2cbb..f8096bfca6bf4b 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -7777,6 +7777,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
       nullptr /*expr*/, is_explicit ? clang::ExplicitSpecKind::ResolvedTrue
                                     : clang::ExplicitSpecKind::ResolvedFalse);
 
+  bool is_ctor_or_dtor = false;
   if (name.starts_with("~")) {
     cxx_dtor_decl = clang::CXXDestructorDecl::CreateDeserialized(
         getASTContext(), GlobalDeclID());
@@ -7803,6 +7804,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
     cxx_ctor_decl->setNumCtorInitializers(0);
     cxx_ctor_decl->setExplicitSpecifier(explicit_spec);
     cxx_method_decl = cxx_ctor_decl;
+    is_ctor_or_dtor = true;
   } else {
     clang::StorageClass SC = is_static ? clang::SC_Static : clang::SC_None;
     clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS;
@@ -7826,6 +7828,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
         cxx_method_decl->setStorageClass(SC);
         cxx_method_decl->setInlineSpecified(is_inline);
         cxx_method_decl->setConstexprKind(ConstexprSpecKind::Unspecified);
+        is_ctor_or_dtor = true;
       } else if (num_params == 0) {
         // Conversion operators don't take params...
         auto *cxx_conversion_decl =
@@ -7867,8 +7870,13 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
     cxx_method_decl->addAttr(clang::UsedAttr::CreateImplicit(getASTContext()));
 
   if (mangled_name != nullptr) {
-    cxx_method_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(
-        getASTContext(), mangled_name, /*literal=*/false));
+    if (is_ctor_or_dtor) {
+      cxx_method_decl->addAttr(clang::StructorNameAttr::CreateImplicit(
+          getASTContext(), mangled_name));
+    } else {
+      cxx_method_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(
+          getASTContext(), mangled_name, /*literal=*/false));
+    }
   }
 
   // Populate the method decl with parameter decls
diff --git a/llvm/include/llvm/Demangle/Demangle.h b/llvm/include/llvm/Demangle/Demangle.h
index fe129603c0785d..c9b61995133d04 100644
--- a/llvm/include/llvm/Demangle/Demangle.h
+++ b/llvm/include/llvm/Demangle/Demangle.h
@@ -10,6 +10,7 @@
 #define LLVM_DEMANGLE_DEMANGLE_H
 
 #include <cstddef>
+#include <optional>
 #include <string>
 #include <string_view>
 
@@ -110,6 +111,7 @@ struct ItaniumPartialDemangler {
 
   /// If this symbol describes a constructor or destructor.
   bool isCtorOrDtor() const;
+  std::optional<int> getCtorDtorVariant() const;
 
   /// If this symbol describes a function.
   bool isFunction() const;
diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index 0af0224bc83fa8..39389132430ab0 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -1728,6 +1728,8 @@ class CtorDtorName final : public Node {
 
   template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); }
 
+  int getVariant() const { return Variant; }
+
   void printLeft(OutputBuffer &OB) const override {
     if (IsDtor)
       OB += "~";
diff --git a/llvm/lib/Demangle/ItaniumDemangle.cpp b/llvm/lib/Demangle/ItaniumDemangle.cpp
index 5c21b06a1d0955..a1693c9fb3ffd1 100644
--- a/llvm/lib/Demangle/ItaniumDemangle.cpp
+++ b/llvm/lib/Demangle/ItaniumDemangle.cpp
@@ -548,15 +548,16 @@ bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
   return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone;
 }
 
-bool ItaniumPartialDemangler::isCtorOrDtor() const {
+std::optional<int> ItaniumPartialDemangler::getCtorDtorVariant() const {
   const Node *N = static_cast<const Node *>(RootNode);
   while (N) {
     switch (N->getKind()) {
     default:
-      return false;
-    case Node::KCtorDtorName:
-      return true;
-
+      return std::nullopt;
+    case Node::KCtorDtorName: {
+      auto const *StructorNode = static_cast<const CtorDtorName *>(N);
+      return StructorNode->getVariant();
+    }
     case Node::KAbiTagAttr:
       N = static_cast<const AbiTagAttr *>(N)->Base;
       break;
@@ -577,7 +578,11 @@ bool ItaniumPartialDemangler::isCtorOrDtor() const {
       break;
     }
   }
-  return false;
+  return std::nullopt;
+}
+
+bool ItaniumPartialDemangler::isCtorOrDtor() const {
+  return getCtorDtorVariant().has_value();
 }
 
 bool ItaniumPartialDemangler::isFunction() const {



More information about the libcxx-commits mailing list