https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/115245
>From 63ca211312cd9dcbf28d30866a429262b504bdb3 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@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 | 186 ++++++++++++++++++ .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 29 ++- .../TypeSystem/Clang/TypeSystemClang.cpp | 12 +- llvm/include/llvm/Demangle/Demangle.h | 1 + llvm/include/llvm/Demangle/ItaniumDemangle.h | 2 + llvm/lib/Demangle/ItaniumDemangle.cpp | 17 +- 11 files changed, 275 insertions(+), 13 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index fd9e686485552..d72ae1fd80e81 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -812,6 +812,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 c8b371280e35d..32eec4d2f8b79 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -4067,6 +4067,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 b44ab23f1d0e1..124b06a430e69 100644 --- a/clang/lib/AST/Mangle.cpp +++ b/clang/lib/AST/Mangle.cpp @@ -125,7 +125,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. @@ -139,6 +139,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 0b844b44930b9..9906131c684bc 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -1730,6 +1730,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)) @@ -7532,6 +7540,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 3df41b5f4d7d0..9ae7c1160d2e9 100644 --- a/libcxxabi/src/demangle/ItaniumDemangle.h +++ b/libcxxabi/src/demangle/ItaniumDemangle.h @@ -1750,6 +1750,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 06b0cb7769f64..1056195b108fb 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; @@ -769,6 +778,180 @@ 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 {}; +} + +static lldb::addr_t FindSpecialLinkageName( + LoadAddressResolver &resolver,ConstString name, llvm::StringRef symbol) { + uintptr_t module_ptr; + if (symbol.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 (!symbol.consume_front(":")) + return LLDB_INVALID_ADDRESS; + + lldb::user_id_t die_id; + if (symbol.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 (!symbol.consume_front(":")) + return LLDB_INVALID_ADDRESS; + + auto structor_variant_or_err = MakeStructorVariant(symbol); + 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; + + return LLDB_INVALID_ADDRESS; +} + lldb::addr_t IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names, const lldb_private::SymbolContext &sc, @@ -795,6 +978,9 @@ IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names, function_options.include_inlines = false; for (const ConstString &name : names) { + if (auto ref = name.GetStringRef(); ref.consume_front("$__lldb_func_")) + return FindSpecialLinkageName(resolver, name, ref); + // The lookup order here is as follows: // 1) Functions in `sc.module_sp` // 2) Functions in the preferred modules list diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 0b632751574ad..a096c439aa27f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -1112,6 +1112,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, @@ -1212,11 +1222,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 ed6297cc6f3e0..74f816c49ab61 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -7822,6 +7822,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()); @@ -7834,6 +7835,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( cxx_dtor_decl->setInlineSpecified(is_inline); cxx_dtor_decl->setConstexprKind(ConstexprSpecKind::Unspecified); cxx_method_decl = cxx_dtor_decl; + is_ctor_or_dtor = true; } else if (decl_name == cxx_record_decl->getDeclName()) { cxx_ctor_decl = clang::CXXConstructorDecl::CreateDeserialized( getASTContext(), GlobalDeclID(), 0); @@ -7848,6 +7850,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; @@ -7912,8 +7915,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)); + } } // Parameters on member function declarations in DWARF generally don't diff --git a/llvm/include/llvm/Demangle/Demangle.h b/llvm/include/llvm/Demangle/Demangle.h index 132e5088b5514..de02921f18aa3 100644 --- a/llvm/include/llvm/Demangle/Demangle.h +++ b/llvm/include/llvm/Demangle/Demangle.h @@ -114,6 +114,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 b0363c1a7a786..4b74626c36a09 100644 --- a/llvm/include/llvm/Demangle/ItaniumDemangle.h +++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h @@ -1750,6 +1750,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 5c21b06a1d095..a1693c9fb3ffd 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 { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits