diff --git a/clang/include/clang/Basic/ABI.h b/clang/include/clang/Basic/ABI.h index 231bad799a42c..598d558a563ec 100644 --- a/clang/include/clang/Basic/ABI.h +++ b/clang/include/clang/Basic/ABI.h @@ -27,14 +27,16 @@ enum CXXCtorType { Ctor_Comdat, ///< The COMDAT used for ctors Ctor_CopyingClosure, ///< Copying closure variant of a ctor Ctor_DefaultClosure, ///< Default closure variant of a ctor + Ctor_Unified, ///< GCC-style unified ctor. }; /// C++ destructor types. enum CXXDtorType { - Dtor_Deleting, ///< Deleting dtor - Dtor_Complete, ///< Complete object dtor - Dtor_Base, ///< Base object dtor - Dtor_Comdat ///< The COMDAT used for dtors + Dtor_Deleting, ///< Deleting dtor + Dtor_Complete, ///< Complete object dtor + Dtor_Base, ///< Base object dtor + Dtor_Comdat, ///< The COMDAT used for dtors + Dtor_Unified, ///< GCC-style unified dtor. }; } // end namespace clang diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 5233648d8f9c8..00a7f54cbe233 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -6056,6 +6056,9 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T, case Ctor_Base: Out << '2'; break; + case Ctor_Unified: + Out << '4'; + break; case Ctor_Comdat: Out << '5'; break; @@ -6083,6 +6086,9 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) { case Dtor_Base: Out << "D2"; break; + case Dtor_Unified: + Out << "D4"; + break; case Dtor_Comdat: Out << "D5"; break; diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp index 0bfb51c11f0a5..1131477fa7200 100644 --- a/clang/lib/AST/Mangle.cpp +++ b/clang/lib/AST/Mangle.cpp @@ -152,6 +152,33 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) { return shouldMangleCXXName(D); } +static llvm::StringRef g_lldb_func_call_label_prefix = "$__lldb_func:"; + +/// Given an LLDB function call label, this function prints the label +/// into \c Out, together with the structor type of \c GD (if the +/// decl is a constructor/destructor). LLDB knows how to handle mangled +/// names with this encoding. +/// +/// Example input label: +/// $__lldb_func::123:456:~Foo +/// +/// Example output: +/// $__lldb_func:D1:123:456:~Foo +/// +static void emitLLDBAsmLabel(llvm::StringRef label, GlobalDecl GD, + llvm::raw_ostream &Out) { + assert(label.starts_with(g_lldb_func_call_label_prefix)); + + Out << g_lldb_func_call_label_prefix; + + if (llvm::isa(GD.getDecl())) + Out << "C" << GD.getCtorType(); + else if (llvm::isa(GD.getDecl())) + Out << "D" << GD.getDtorType(); + + Out << label.substr(g_lldb_func_call_label_prefix.size()); +} + void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) { const ASTContext &ASTContext = getASTContext(); const NamedDecl *D = cast(GD.getDecl()); @@ -185,7 +212,11 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) { if (!UserLabelPrefix.empty()) Out << '\01'; // LLVM IR Marker for __asm("foo") - Out << ALA->getLabel(); + if (ALA->getLabel().starts_with(g_lldb_func_call_label_prefix)) + emitLLDBAsmLabel(ALA->getLabel(), GD, Out); + else + Out << ALA->getLabel(); + return; } diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index e6ea0ada2e9ec..c784bf5a00c12 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -1494,6 +1494,8 @@ void MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) { // ::= ?_E # vector deleting destructor // FIXME: Add a vector deleting dtor type. It goes in the vtable, so we need // it. + case Dtor_Unified: + llvm_unreachable("not expecting a unified dtor"); case Dtor_Comdat: llvm_unreachable("not expecting a COMDAT"); } diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 4a465e6526da0..ccd914007fdf0 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -1493,6 +1493,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { // we'd introduce *two* handler blocks. In the Microsoft ABI, we // always delegate because we might not have a definition in this TU. switch (DtorType) { + case Dtor_Unified: + llvm_unreachable("not expecting a unified dtor"); case Dtor_Comdat: llvm_unreachable("not expecting a COMDAT"); case Dtor_Deleting: llvm_unreachable("already handled deleting case"); diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 2b469f2e265b4..722bb17edbc0d 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -29,6 +29,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/VTableBuilder.h" +#include "clang/Basic/ABI.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/Version.h" @@ -2177,22 +2178,29 @@ static bool isFunctionLocalClass(const CXXRecordDecl *RD) { llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( const CXXMethodDecl *Method, llvm::DIFile *Unit, llvm::DIType *RecordTy) { - bool IsCtorOrDtor = - isa(Method) || isa(Method); - StringRef MethodName = getFunctionName(Method); llvm::DISubroutineType *MethodTy = getOrCreateMethodType(Method, Unit); - // Since a single ctor/dtor corresponds to multiple functions, it doesn't - // make sense to give a single ctor/dtor a linkage name. + const bool ShouldAddLinkageName = + (!isa(Method) && !isa(Method)) || + CGM.getTarget().getCXXABI().isItaniumFamily(); + StringRef MethodLinkageName; // FIXME: 'isFunctionLocalClass' seems like an arbitrary/unintentional // property to use here. It may've been intended to model "is non-external // type" but misses cases of non-function-local but non-external classes such // as those in anonymous namespaces as well as the reverse - external types // that are function local, such as those in (non-local) inline functions. - if (!IsCtorOrDtor && !isFunctionLocalClass(Method->getParent())) - MethodLinkageName = CGM.getMangledName(Method); + if (ShouldAddLinkageName && !isFunctionLocalClass(Method->getParent())) { + if (auto *Ctor = dyn_cast(Method)) + MethodLinkageName = + CGM.getMangledName(GlobalDecl(Ctor, CXXCtorType::Ctor_Unified)); + else if (auto *Dtor = dyn_cast(Method)) + MethodLinkageName = + CGM.getMangledName(GlobalDecl(Dtor, CXXDtorType::Dtor_Unified)); + else + MethodLinkageName = CGM.getMangledName(Method); + } // Get the location for the method. llvm::DIFile *MethodDefUnit = nullptr; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 834b1c067d84c..a9c65eb7ad2b7 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -37,6 +37,7 @@ #include "clang/AST/Mangle.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Basic/ABI.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/Diagnostic.h" @@ -2150,7 +2151,8 @@ StringRef CodeGenModule::getMangledName(GlobalDecl GD) { if (const auto *CD = dyn_cast(CanonicalGD.getDecl())) { if (!getTarget().getCXXABI().hasConstructorVariants()) { CXXCtorType OrigCtorType = GD.getCtorType(); - assert(OrigCtorType == Ctor_Base || OrigCtorType == Ctor_Complete); + assert(OrigCtorType == Ctor_Base || OrigCtorType == Ctor_Complete || + OrigCtorType == Ctor_Unified); if (OrigCtorType == Ctor_Base) CanonicalGD = GlobalDecl(CD, Ctor_Complete); } diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 5ffc1edb9986f..d933a45ca43c0 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -89,6 +89,9 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { case Dtor_Base: return false; + case Dtor_Unified: + llvm_unreachable("unexpected unified dtor"); + case Dtor_Comdat: llvm_unreachable("emitting dtor comdat as function?"); } @@ -102,6 +105,9 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { case Ctor_Base: return false; + case Ctor_Unified: + llvm_unreachable("unexpected unified ctor"); + case Ctor_CopyingClosure: case Ctor_DefaultClosure: llvm_unreachable("closure ctors in Itanium ABI?"); diff --git a/clang/unittests/AST/DeclTest.cpp b/clang/unittests/AST/DeclTest.cpp index 6b443918ec137..4bd7886ef9b35 100644 --- a/clang/unittests/AST/DeclTest.cpp +++ b/clang/unittests/AST/DeclTest.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Mangle.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/ABI.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/TargetInfo.h" @@ -102,6 +103,80 @@ TEST(Decl, AsmLabelAttr) { "foo"); } +TEST(Decl, AsmLabelAttr_LLDB) { + StringRef Code = R"( + struct S { + void f() {} + S() = default; + ~S() = default; + }; + )"; + auto AST = + tooling::buildASTFromCodeWithArgs(Code, {"-target", "i386-apple-darwin"}); + ASTContext &Ctx = AST->getASTContext(); + assert(Ctx.getTargetInfo().getUserLabelPrefix() == StringRef("_") && + "Expected target to have a global prefix"); + DiagnosticsEngine &Diags = AST->getDiagnostics(); + + const auto *DeclS = + selectFirst("d", match(cxxRecordDecl().bind("d"), Ctx)); + + auto *DeclF = *DeclS->method_begin(); + auto *Ctor = *DeclS->ctor_begin(); + auto *Dtor = DeclS->getDestructor(); + + ASSERT_TRUE(DeclF); + ASSERT_TRUE(Ctor); + ASSERT_TRUE(Dtor); + + DeclF->addAttr(AsmLabelAttr::Create(Ctx, "$__lldb_func::123:123:_Z1fv")); + Ctor->addAttr(AsmLabelAttr::Create(Ctx, "$__lldb_func::123:123:S")); + Dtor->addAttr(AsmLabelAttr::Create(Ctx, "$__lldb_func::123:123:~S")); + + std::unique_ptr MC( + ItaniumMangleContext::create(Ctx, Diags)); + + { + std::string Mangled; + llvm::raw_string_ostream OS_Mangled(Mangled); + MC->mangleName(DeclF, OS_Mangled); + + ASSERT_EQ(Mangled, "\x01$__lldb_func::123:123:_Z1fv"); + }; + + { + std::string Mangled; + llvm::raw_string_ostream OS_Mangled(Mangled); + MC->mangleName(GlobalDecl(Ctor, CXXCtorType::Ctor_Complete), OS_Mangled); + + ASSERT_EQ(Mangled, "\x01$__lldb_func:C0:123:123:S"); + }; + + { + std::string Mangled; + llvm::raw_string_ostream OS_Mangled(Mangled); + MC->mangleName(GlobalDecl(Ctor, CXXCtorType::Ctor_Base), OS_Mangled); + + ASSERT_EQ(Mangled, "\x01$__lldb_func:C1:123:123:S"); + }; + + { + std::string Mangled; + llvm::raw_string_ostream OS_Mangled(Mangled); + MC->mangleName(GlobalDecl(Dtor, CXXDtorType::Dtor_Deleting), OS_Mangled); + + ASSERT_EQ(Mangled, "\x01$__lldb_func:D0:123:123:~S"); + }; + + { + std::string Mangled; + llvm::raw_string_ostream OS_Mangled(Mangled); + MC->mangleName(GlobalDecl(Dtor, CXXDtorType::Dtor_Base), OS_Mangled); + + ASSERT_EQ(Mangled, "\x01$__lldb_func:D2:123:123:~S"); + }; +} + TEST(Decl, MangleDependentSizedArray) { StringRef Code = R"( template diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h index 6f27da7b9cadf..7b3983bc89367 100644 --- a/libcxxabi/src/demangle/ItaniumDemangle.h +++ b/libcxxabi/src/demangle/ItaniumDemangle.h @@ -1766,6 +1766,8 @@ class CtorDtorName final : public Node { template 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/include/lldb/Expression/Expression.h b/lldb/include/lldb/Expression/Expression.h index 20067f469895b..847226167d584 100644 --- a/lldb/include/lldb/Expression/Expression.h +++ b/lldb/include/lldb/Expression/Expression.h @@ -103,11 +103,15 @@ class Expression { /// /// The format being: /// -/// ::: +/// :::: /// /// The label string needs to stay valid for the entire lifetime /// of this object. struct FunctionCallLabel { + /// Arbitrary string which language plugins can interpret for their + /// own needs. + llvm::StringRef discriminator; + /// Unique identifier of the lldb_private::Module /// which contains the symbol identified by \c symbol_id. lldb::user_id_t module_id; @@ -133,7 +137,7 @@ struct FunctionCallLabel { /// /// The representation roundtrips through \c fromString: /// \code{.cpp} - /// llvm::StringRef encoded = "$__lldb_func:0x0:0x0:_Z3foov"; + /// llvm::StringRef encoded = "$__lldb_func:blah:0x0:0x0:_Z3foov"; /// FunctionCallLabel label = *fromString(label); /// /// assert (label.toString() == encoded); diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h index bbc615d9fdc38..a84f081b340eb 100644 --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -332,12 +332,12 @@ class SymbolFile : public PluginInterface { /// Resolves the function corresponding to the specified LLDB function /// call \c label. /// - /// \param[in] label The FunctionCallLabel to be resolved. + /// \param[in,out] label The FunctionCallLabel to be resolved. /// /// \returns An llvm::Error if the specified \c label couldn't be resolved. /// Returns the resolved function (as a SymbolContext) otherwise. virtual llvm::Expected - ResolveFunctionCallLabel(const FunctionCallLabel &label) { + ResolveFunctionCallLabel(FunctionCallLabel &label) { return llvm::createStringError("Not implemented"); } diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp index 796851ff15ca3..16ecb1d7deef8 100644 --- a/lldb/source/Expression/Expression.cpp +++ b/lldb/source/Expression/Expression.cpp @@ -34,10 +34,10 @@ Expression::Expression(ExecutionContextScope &exe_scope) llvm::Expected lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) { - llvm::SmallVector components; - label.split(components, ":", /*MaxSplit=*/3); + llvm::SmallVector components; + label.split(components, ":", /*MaxSplit=*/4); - if (components.size() != 4) + if (components.size() != 5) return llvm::createStringError("malformed function call label."); if (components[0] != FunctionCallLabelPrefix) @@ -45,8 +45,10 @@ lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) { "expected function call label prefix '{0}' but found '{1}' instead.", FunctionCallLabelPrefix, components[0])); - llvm::StringRef module_label = components[1]; - llvm::StringRef die_label = components[2]; + llvm::StringRef discriminator = components[1]; + llvm::StringRef module_label = components[2]; + llvm::StringRef die_label = components[3]; + llvm::StringRef lookup_name = components[4]; lldb::user_id_t module_id = 0; if (!llvm::to_integer(module_label, module_id)) @@ -58,20 +60,23 @@ lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) { return llvm::createStringError( llvm::formatv("failed to parse symbol ID from '{0}'.", die_label)); - return FunctionCallLabel{/*.module_id=*/module_id, + return FunctionCallLabel{/*.discriminator=*/discriminator, + /*.module_id=*/module_id, /*.symbol_id=*/die_id, - /*.lookup_name=*/components[3]}; + /*.lookup_name=*/lookup_name}; } std::string lldb_private::FunctionCallLabel::toString() const { - return llvm::formatv("{0}:{1:x}:{2:x}:{3}", FunctionCallLabelPrefix, - module_id, symbol_id, lookup_name) + return llvm::formatv("{0}:{1}:{2:x}:{3:x}:{4}", FunctionCallLabelPrefix, + discriminator, module_id, symbol_id, lookup_name) .str(); } void llvm::format_provider::format( const FunctionCallLabel &label, raw_ostream &OS, StringRef Style) { - OS << llvm::formatv("FunctionCallLabel{ module_id: {0:x}, symbol_id: {1:x}, " - "lookup_name: {2} }", - label.module_id, label.symbol_id, label.lookup_name); + OS << llvm::formatv("FunctionCallLabel{ discriminator: {0}, module_id: " + "{1:x}, symbol_id: {2:x}, " + "lookup_name: {3} }", + label.discriminator, label.module_id, label.symbol_id, + label.lookup_name); } diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index d557084acb745..d3dd163edd034 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -778,7 +778,7 @@ class LoadAddressResolver { /// Returns address of the function referred to by the special function call /// label \c label. static llvm::Expected -ResolveFunctionCallLabel(const FunctionCallLabel &label, +ResolveFunctionCallLabel(FunctionCallLabel &label, const lldb_private::SymbolContext &sc, bool &symbol_was_missing_weak) { symbol_was_missing_weak = false; diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 3118ff151d1cf..0d3cca2c8a4f6 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -602,126 +602,6 @@ bool CPlusPlusLanguage::ExtractContextAndIdentifier( return false; } -namespace { -class NodeAllocator { - llvm::BumpPtrAllocator Alloc; - -public: - void reset() { Alloc.Reset(); } - - template T *makeNode(Args &&...args) { - return new (Alloc.Allocate(sizeof(T), alignof(T))) - T(std::forward(args)...); - } - - void *allocateNodeArray(size_t sz) { - return Alloc.Allocate(sizeof(llvm::itanium_demangle::Node *) * sz, - alignof(llvm::itanium_demangle::Node *)); - } -}; - -template -class ManglingSubstitutor - : public llvm::itanium_demangle::AbstractManglingParser { - using Base = - llvm::itanium_demangle::AbstractManglingParser; - -public: - ManglingSubstitutor() : Base(nullptr, nullptr) {} - - template - ConstString substitute(llvm::StringRef Mangled, Ts &&...Vals) { - this->getDerived().reset(Mangled, std::forward(Vals)...); - return substituteImpl(Mangled); - } - -protected: - void reset(llvm::StringRef Mangled) { - Base::reset(Mangled.begin(), Mangled.end()); - Written = Mangled.begin(); - Result.clear(); - Substituted = false; - } - - ConstString substituteImpl(llvm::StringRef Mangled) { - Log *log = GetLog(LLDBLog::Language); - if (this->parse() == nullptr) { - LLDB_LOG(log, "Failed to substitute mangling in {0}", Mangled); - return ConstString(); - } - if (!Substituted) - return ConstString(); - - // Append any trailing unmodified input. - appendUnchangedInput(); - LLDB_LOG(log, "Substituted mangling {0} -> {1}", Mangled, Result); - return ConstString(Result); - } - - void trySubstitute(llvm::StringRef From, llvm::StringRef To) { - if (!llvm::StringRef(currentParserPos(), this->numLeft()).starts_with(From)) - return; - - // We found a match. Append unmodified input up to this point. - appendUnchangedInput(); - - // And then perform the replacement. - Result += To; - Written += From.size(); - Substituted = true; - } - -private: - /// Input character until which we have constructed the respective output - /// already. - const char *Written = ""; - - llvm::SmallString<128> Result; - - /// Whether we have performed any substitutions. - bool Substituted = false; - - const char *currentParserPos() const { return this->First; } - - void appendUnchangedInput() { - Result += - llvm::StringRef(Written, std::distance(Written, currentParserPos())); - Written = currentParserPos(); - } -}; - -/// Given a mangled function `Mangled`, replace all the primitive function type -/// arguments of `Search` with type `Replace`. -class TypeSubstitutor : public ManglingSubstitutor { - llvm::StringRef Search; - llvm::StringRef Replace; - -public: - void reset(llvm::StringRef Mangled, llvm::StringRef Search, - llvm::StringRef Replace) { - ManglingSubstitutor::reset(Mangled); - this->Search = Search; - this->Replace = Replace; - } - - llvm::itanium_demangle::Node *parseType() { - trySubstitute(Search, Replace); - return ManglingSubstitutor::parseType(); - } -}; - -class CtorDtorSubstitutor : public ManglingSubstitutor { -public: - llvm::itanium_demangle::Node * - parseCtorDtorName(llvm::itanium_demangle::Node *&SoFar, NameState *State) { - trySubstitute("C1", "C2"); - trySubstitute("D1", "D2"); - return ManglingSubstitutor::parseCtorDtorName(SoFar, State); - } -}; -} // namespace - std::vector CPlusPlusLanguage::GenerateAlternateFunctionManglings( const ConstString mangled_name) const { std::vector alternates; @@ -749,29 +629,49 @@ std::vector CPlusPlusLanguage::GenerateAlternateFunctionManglings( alternates.push_back(ConstString(fixed_scratch)); } - TypeSubstitutor TS; + auto *log = GetLog(LLDBLog::Language); + // `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 = - TS.substitute(mangled_name.GetStringRef(), "a", "c")) - alternates.push_back(char_fixup); + if (auto char_fixup_or_err = + SubstituteType_ItaniumMangle(mangled_name.GetStringRef(), "a", "c")) { + // LLDB_LOG(log, "Substituted mangling {0} -> {1}", Mangled, Result); + if (*char_fixup_or_err) + alternates.push_back(*char_fixup_or_err); + } else + LLDB_LOG_ERROR(log, char_fixup_or_err.takeError(), + "Failed to substitute 'char' type mangling: {0}"); // long long parameter mangling 'x', may actually just be a long 'l' argument - if (ConstString long_fixup = - TS.substitute(mangled_name.GetStringRef(), "x", "l")) - alternates.push_back(long_fixup); + if (auto long_fixup_or_err = + SubstituteType_ItaniumMangle(mangled_name.GetStringRef(), "x", "l")) { + if (*long_fixup_or_err) + alternates.push_back(*long_fixup_or_err); + } else + LLDB_LOG_ERROR(log, long_fixup_or_err.takeError(), + "Failed to substitute 'long long' type mangling: {0}"); // unsigned long long parameter mangling 'y', may actually just be unsigned // long 'm' argument - if (ConstString ulong_fixup = - TS.substitute(mangled_name.GetStringRef(), "y", "m")) - alternates.push_back(ulong_fixup); - - if (ConstString ctor_fixup = - CtorDtorSubstitutor().substitute(mangled_name.GetStringRef())) - alternates.push_back(ctor_fixup); + if (auto ulong_fixup_or_err = + SubstituteType_ItaniumMangle(mangled_name.GetStringRef(), "y", "m")) { + if (*ulong_fixup_or_err) + alternates.push_back(*ulong_fixup_or_err); + } else + LLDB_LOG_ERROR( + log, ulong_fixup_or_err.takeError(), + "Failed to substitute 'unsigned long long' type mangling: {0}"); + + if (auto ctor_fixup_or_err = SubstituteStructorAliases_ItaniumMangle( + mangled_name.GetStringRef())) { + if (*ctor_fixup_or_err) { + alternates.push_back(*ctor_fixup_or_err); + } + } else + LLDB_LOG_ERROR(log, ctor_fixup_or_err.takeError(), + "Failed to substitute structor alias manglings: {0}"); return alternates; } @@ -2440,6 +2340,160 @@ bool CPlusPlusLanguage::HandleFrameFormatVariable( } } +namespace { +class NodeAllocator { + llvm::BumpPtrAllocator Alloc; + +public: + void reset() { Alloc.Reset(); } + + template T *makeNode(Args &&...args) { + return new (Alloc.Allocate(sizeof(T), alignof(T))) + T(std::forward(args)...); + } + + void *allocateNodeArray(size_t sz) { + return Alloc.Allocate(sizeof(llvm::itanium_demangle::Node *) * sz, + alignof(llvm::itanium_demangle::Node *)); + } +}; + +template +class ManglingSubstitutor + : public llvm::itanium_demangle::AbstractManglingParser { + using Base = + llvm::itanium_demangle::AbstractManglingParser; + +public: + ManglingSubstitutor() : Base(nullptr, nullptr) {} + + template + llvm::Expected substitute(llvm::StringRef Mangled, + Ts &&...Vals) { + this->getDerived().reset(Mangled, std::forward(Vals)...); + return substituteImpl(Mangled); + } + +protected: + void reset(llvm::StringRef Mangled) { + Base::reset(Mangled.begin(), Mangled.end()); + Written = Mangled.begin(); + Result.clear(); + Substituted = false; + } + + llvm::Expected substituteImpl(llvm::StringRef Mangled) { + if (this->parse() == nullptr) + return llvm::createStringError( + llvm::formatv("Failed to substitute mangling in {0}", Mangled)); + + if (!Substituted) + return ConstString(); + + // Append any trailing unmodified input. + appendUnchangedInput(); + return ConstString(Result); + } + + void trySubstitute(llvm::StringRef From, llvm::StringRef To) { + if (!llvm::StringRef(currentParserPos(), this->numLeft()).starts_with(From)) + return; + + // We found a match. Append unmodified input up to this point. + appendUnchangedInput(); + + // And then perform the replacement. + Result += To; + Written += From.size(); + Substituted = true; + } + +private: + /// Input character until which we have constructed the respective output + /// already. + const char *Written = ""; + + llvm::SmallString<128> Result; + + /// Whether we have performed any substitutions. + bool Substituted = false; + + const char *currentParserPos() const { return this->First; } + + void appendUnchangedInput() { + Result += + llvm::StringRef(Written, std::distance(Written, currentParserPos())); + Written = currentParserPos(); + } +}; + +/// Given a mangled function `Mangled`, replace all the primitive function type +/// arguments of `Search` with type `Replace`. +class TypeSubstitutor : public ManglingSubstitutor { + llvm::StringRef Search; + llvm::StringRef Replace; + +public: + void reset(llvm::StringRef Mangled, llvm::StringRef Search, + llvm::StringRef Replace) { + ManglingSubstitutor::reset(Mangled); + this->Search = Search; + this->Replace = Replace; + } + + llvm::itanium_demangle::Node *parseType() { + trySubstitute(Search, Replace); + return ManglingSubstitutor::parseType(); + } +}; + +class CtorDtorSubstitutor : public ManglingSubstitutor { + llvm::StringRef Search; + llvm::StringRef Replace; + +public: + void reset(llvm::StringRef Mangled, llvm::StringRef Search, + llvm::StringRef Replace) { + ManglingSubstitutor::reset(Mangled); + this->Search = Search; + this->Replace = Replace; + } + + void reset(llvm::StringRef Mangled) { ManglingSubstitutor::reset(Mangled); } + + llvm::itanium_demangle::Node * + parseCtorDtorName(llvm::itanium_demangle::Node *&SoFar, NameState *State) { + if (!Search.empty() && !Replace.empty()) { + trySubstitute(Search, Replace); + } else { + trySubstitute("D1", "D2"); + trySubstitute("C1", "C2"); + } + return ManglingSubstitutor::parseCtorDtorName(SoFar, State); + } +}; +} // namespace + +llvm::Expected +CPlusPlusLanguage::SubstituteType_ItaniumMangle(llvm::StringRef mangled_name, + llvm::StringRef subst_from, + llvm::StringRef subst_to) { + return TypeSubstitutor().substitute(mangled_name, subst_from, subst_to); +} + +llvm::Expected CPlusPlusLanguage::SubstituteStructor_ItaniumMangle( + llvm::StringRef mangled_name, llvm::StringRef subst_from, + llvm::StringRef subst_to) { + return CtorDtorSubstitutor().substitute(mangled_name, subst_from, subst_to); +} + +llvm::Expected +CPlusPlusLanguage::SubstituteStructorAliases_ItaniumMangle( + llvm::StringRef mangled_name) { + return CtorDtorSubstitutor().substitute(mangled_name); +} + #define LLDB_PROPERTIES_language_cplusplus #include "LanguageCPlusPlusProperties.inc" diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h index 4a30299dd2658..67b28bf202c3a 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h @@ -164,6 +164,19 @@ class CPlusPlusLanguage : public Language { ConstString FindBestAlternateFunctionMangledName( const Mangled mangled, const SymbolContext &sym_ctx) const override; + static llvm::Expected + SubstituteType_ItaniumMangle(llvm::StringRef mangled_name, + llvm::StringRef subst_from, + llvm::StringRef subst_to); + + static llvm::Expected + SubstituteStructor_ItaniumMangle(llvm::StringRef mangled_name, + llvm::StringRef subst_from, + llvm::StringRef subst_to); + + static llvm::Expected + SubstituteStructorAliases_ItaniumMangle(llvm::StringRef mangled_name); + llvm::StringRef GetInstanceVariableName() override { return "this"; } FormatEntity::Entry GetFunctionNameFormat() const override; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index a429ea848b7f7..bc13e7875c4a6 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -252,7 +252,7 @@ static unsigned GetCXXMethodCVQuals(const DWARFDIE &subprogram, } static std::string MakeLLDBFuncAsmLabel(const DWARFDIE &die) { - char const *name = die.GetMangledName(/*substitute_name_allowed*/ false); + const char *name = die.GetMangledName(/*substitute_name_allowed*/ false); if (!name) return {}; @@ -286,7 +286,9 @@ static std::string MakeLLDBFuncAsmLabel(const DWARFDIE &die) { if (die_id == LLDB_INVALID_UID) return {}; - return FunctionCallLabel{/*module_id=*/module_id, + // Note, discriminator is added by Clang during mangling. + return FunctionCallLabel{/*discriminator=*/{}, + /*module_id=*/module_id, /*symbol_id=*/die_id, /*.lookup_name=*/name} .toString(); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp index 64a8005308454..59a8ada2e1faf 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp @@ -22,6 +22,39 @@ using namespace lldb_private; using namespace lldb; using namespace lldb_private::plugin::dwarf; +static bool IsUnifiedStructorLookup(const DWARFDIE &die) { + auto spec = + die.GetAttributeValueAsReferenceDIE(llvm::dwarf::DW_AT_specification); + if (!spec) + return false; + + const char *spec_mangled_name = + spec.GetMangledName(/*substitute_name_allowed=*/false); + if (!spec_mangled_name) + return false; + + const char *spec_name = spec.GetName(); + if (!spec_name) + return false; + + const char *ctx_name = spec.GetParent().GetName(); + if (!ctx_name) + return false; + + // We have a ctor. + if (::strcmp(ctx_name, spec_name) == 0) + return true; + + if (spec_name[0] != '~') + return false; + + // We have a dtor. + if (::strcmp(ctx_name, spec_name + 1) == 0) + return true; + + return false; +} + DWARFIndex::~DWARFIndex() = default; IterationAction DWARFIndex::ProcessFunctionDIE( @@ -60,7 +93,8 @@ IterationAction DWARFIndex::ProcessFunctionDIE( return IterationAction::Continue; // In case of a full match, we just insert everything we find. - if (name_type_mask & eFunctionNameTypeFull && die.GetMangledName() == name) + if (name_type_mask & eFunctionNameTypeFull && + (die.GetMangledName() == name || IsUnifiedStructorLookup(die))) return callback(die); // If looking for ObjC selectors, we need to also check if the name is a diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 9958af26379b9..4b0e81bb9079f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -7,10 +7,13 @@ //===----------------------------------------------------------------------===// #include "SymbolFileDWARF.h" +#include "clang/Basic/ABI.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/FormatAdapters.h" #include "llvm/Support/Threading.h" @@ -22,6 +25,7 @@ #include "lldb/Core/Progress.h" #include "lldb/Core/Section.h" #include "lldb/Core/Value.h" +#include "lldb/Expression/Expression.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/RegularExpression.h" @@ -78,6 +82,7 @@ #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" +#include "llvm/Demangle/Demangle.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatVariadic.h" @@ -2483,34 +2488,131 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die, return false; } -DWARFDIE -SymbolFileDWARF::FindFunctionDefinition(const FunctionCallLabel &label) { - DWARFDIE definition; - Module::LookupInfo info(ConstString(label.lookup_name), - lldb::eFunctionNameTypeFull, - lldb::eLanguageTypeUnknown); - - m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) { - if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) - return IterationAction::Continue; +static llvm::StringRef ClangToItaniumCtorKind(clang::CXXCtorType kind) { + switch (kind) { + case clang::CXXCtorType::Ctor_Complete: + return "C1"; + case clang::CXXCtorType::Ctor_Base: + return "C2"; + case clang::CXXCtorType::Ctor_Unified: + return "C4"; + case clang::CXXCtorType::Ctor_CopyingClosure: + case clang::CXXCtorType::Ctor_DefaultClosure: + case clang::CXXCtorType::Ctor_Comdat: + llvm_unreachable("Unexpected constructor kind."); + } +} - // We don't check whether the specification DIE for this function - // corresponds to the declaration DIE because the declaration might be in - // a type-unit but the definition in the compile-unit (and it's - // specifcation would point to the declaration in the compile-unit). We - // rely on the mangled name within the module to be enough to find us the - // unique definition. - definition = entry; - return IterationAction::Stop; - }); +static llvm::StringRef ClangToItaniumDtorKind(clang::CXXDtorType kind) { + switch (kind) { + case clang::CXXDtorType::Dtor_Deleting: + return "D0"; + case clang::CXXDtorType::Dtor_Complete: + return "D1"; + case clang::CXXDtorType::Dtor_Base: + return "D2"; + case clang::CXXDtorType::Dtor_Unified: + return "D4"; + case clang::CXXDtorType::Dtor_Comdat: + llvm_unreachable("Unexpected destructor kind."); + } +} + +static llvm::StringRef +GetItaniumCtorDtorVariant(llvm::StringRef discriminator) { + const bool is_ctor = discriminator.consume_front("C"); + if (!is_ctor && !discriminator.consume_front("D")) + return {}; + + uint64_t structor_kind; + if (!llvm::to_integer(discriminator, structor_kind)) + return {}; + + if (is_ctor) { + if (structor_kind > clang::CXXCtorType::Ctor_Unified) + return {}; + + return ClangToItaniumCtorKind( + static_cast(structor_kind)); + } + + if (structor_kind > clang::CXXDtorType::Dtor_Unified) + return {}; + + return ClangToItaniumDtorKind(static_cast(structor_kind)); +} + +llvm::Expected +SymbolFileDWARF::FindFunctionDefinition(const FunctionCallLabel &label, + const DWARFDIE &declaration) { + auto do_lookup = [this](llvm::StringRef lookup_name) -> DWARFDIE { + DWARFDIE found; + Module::LookupInfo info(ConstString(lookup_name), + lldb::eFunctionNameTypeFull, + lldb::eLanguageTypeUnknown); + + m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) { + if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) + return IterationAction::Continue; + + found = entry; + return IterationAction::Stop; + }); + + return found; + }; + + DWARFDIE definition = do_lookup(label.lookup_name); + if (definition.IsValid()) + return definition; + + // This is not a structor lookup. Nothing else to be done here. + if (label.discriminator.empty()) + return llvm::createStringError( + "no definition DIE found in this SymbolFile"); + + // We're doing a structor lookup. Maybe we didn't find the structor variant + // because the complete object structor was aliased to the base object + // structor. Try finding the alias instead. + // + // TODO: there are other reasons for why a subprogram definition might be + // missing. Ideally DWARF would tell us more details about which structor + // variant a DIE corresponds to and whether it's an alias. + auto subst_or_err = + CPlusPlusLanguage::SubstituteStructorAliases_ItaniumMangle( + label.lookup_name); + if (!subst_or_err) + return subst_or_err.takeError(); + + definition = do_lookup(*subst_or_err); + + if (!definition.IsValid()) + return llvm::createStringError( + "failed to find definition DIE for structor alias in fallback lookup"); return definition; } llvm::Expected -SymbolFileDWARF::ResolveFunctionCallLabel(const FunctionCallLabel &label) { +SymbolFileDWARF::ResolveFunctionCallLabel(FunctionCallLabel &label) { std::lock_guard guard(GetModuleMutex()); + if (!label.discriminator.empty()) { + llvm::StringRef from = label.discriminator[0] == 'C' ? "C4" : "D4"; + + llvm::StringRef variant = GetItaniumCtorDtorVariant(label.discriminator); + if (variant.empty()) + return llvm::createStringError( + "failed to get Itanium variant for discriminator"); + + auto subst_or_err = CPlusPlusLanguage::SubstituteStructor_ItaniumMangle( + label.lookup_name, from, variant); + if (subst_or_err && *subst_or_err) + label.lookup_name = subst_or_err->GetStringRef(); + else + llvm::consumeError(subst_or_err.takeError()); + } + DWARFDIE die = GetDIE(label.symbol_id); if (!die.IsValid()) return llvm::createStringError( @@ -2519,11 +2621,13 @@ SymbolFileDWARF::ResolveFunctionCallLabel(const FunctionCallLabel &label) { // Label was created using a declaration DIE. Need to fetch the definition // to resolve the function call. if (die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) { - auto definition = FindFunctionDefinition(label); - if (!definition) - return llvm::createStringError("failed to find definition DIE"); + auto die_or_err = FindFunctionDefinition(label, die); + if (!die_or_err) + return llvm::joinErrors( + llvm::createStringError("failed to find definition DIE:"), + die_or_err.takeError()); - die = std::move(definition); + die = std::move(*die_or_err); } SymbolContextList sc_list; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index d7db8a3c0869f..608130cd068ce 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -378,7 +378,9 @@ class SymbolFileDWARF : public SymbolFileCommon { /// SymbolFile. /// /// \returns A valid definition DIE on success. - DWARFDIE FindFunctionDefinition(const FunctionCallLabel &label); + llvm::Expected + FindFunctionDefinition(const FunctionCallLabel &label, + const DWARFDIE &declaration); protected: SymbolFileDWARF(const SymbolFileDWARF &) = delete; @@ -445,7 +447,7 @@ class SymbolFileDWARF : public SymbolFileCommon { DIEArray &&variable_dies); llvm::Expected - ResolveFunctionCallLabel(const FunctionCallLabel &label) override; + ResolveFunctionCallLabel(FunctionCallLabel &label) override; // Given a die_offset, figure out the symbol context representing that die. bool ResolveFunction(const DWARFDIE &die, bool include_inlines, diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index 9d7452a1988fa..8b8229a7020c5 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -1603,8 +1603,8 @@ void SymbolFileDWARFDebugMap::GetCompileOptions( }); } -llvm::Expected SymbolFileDWARFDebugMap::ResolveFunctionCallLabel( - const FunctionCallLabel &label) { +llvm::Expected +SymbolFileDWARFDebugMap::ResolveFunctionCallLabel(FunctionCallLabel &label) { const uint64_t oso_idx = GetOSOIndexFromUserID(label.symbol_id); SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx); if (!oso_dwarf) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index e1f1df23951c6..bce1ed2671af0 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -145,7 +145,7 @@ class SymbolFileDWARFDebugMap : public SymbolFileCommon { GetCompileOptions(std::unordered_map &args) override; llvm::Expected - ResolveFunctionCallLabel(const FunctionCallLabel &label) override; + ResolveFunctionCallLabel(FunctionCallLabel &label) override; protected: enum { kHaveInitializedOSOs = (1 << 0), kNumFlags }; diff --git a/lldb/test/API/lang/cpp/abi_tag_structors/Makefile b/lldb/test/API/lang/cpp/abi_tag_structors/Makefile new file mode 100644 index 0000000000000..99998b20bcb05 --- /dev/null +++ b/lldb/test/API/lang/cpp/abi_tag_structors/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/lang/cpp/abi_tag_structors/TestAbiTagStructors.py b/lldb/test/API/lang/cpp/abi_tag_structors/TestAbiTagStructors.py new file mode 100644 index 0000000000000..5e7c03f8e0dfe --- /dev/null +++ b/lldb/test/API/lang/cpp/abi_tag_structors/TestAbiTagStructors.py @@ -0,0 +1,30 @@ +""" +Test that we can call structors/destructors +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 AbiTagStructorsTestCase(TestBase): + def test(self): + self.build() + lldbutil.run_to_source_breakpoint( + self, "Break here", lldb.SBFileSpec("main.cpp", False) + ) + + self.expect_expr("Tagged()", result_type="Tagged") + self.expect_expr("t1 = t2", result_type="Tagged") + + self.expect("expr Tagged t3(t1)", error=False) + self.expect("expr t1.~Tagged()", error=False) + + # Calls to deleting and base object destructor variants (D0 and D2 in Itanium ABI) + self.expect_expr( + "struct D : public HasVirtualDtor {}; D d; d.func()", + result_type="int", + result_value="10", + ) diff --git a/lldb/test/API/lang/cpp/abi_tag_structors/main.cpp b/lldb/test/API/lang/cpp/abi_tag_structors/main.cpp new file mode 100644 index 0000000000000..b7783ccc49460 --- /dev/null +++ b/lldb/test/API/lang/cpp/abi_tag_structors/main.cpp @@ -0,0 +1,38 @@ +#include + +struct Tagged { + [[gnu::abi_tag("Default")]] Tagged() { std::puts(__func__); } + [[gnu::abi_tag("Copy")]] Tagged(const Tagged &) { std::puts(__func__); } + [[gnu::abi_tag("CopyAssign")]] Tagged &operator=(const Tagged &) { + std::puts(__func__); + return *this; + } + [[gnu::abi_tag("Dtor")]] ~Tagged() { std::puts(__func__); } +}; + +struct Base { + virtual ~Base() { std::puts(__func__); } + virtual int func() { return 5; } +}; + +struct HasVirtualDtor : public Base { + int func() override { return 10; } + + [[gnu::abi_tag("VirtualDtor")]] ~HasVirtualDtor() override { + std::puts(__func__); + } +}; + +int main() { + Tagged t1; + Tagged t2(t1); + t1 = t2; + + Base b; + HasVirtualDtor vdtor; + vdtor.func(); + + std::puts("Break here"); + + return 0; +} diff --git a/lldb/test/API/lang/cpp/constructors/TestCppConstructors.py b/lldb/test/API/lang/cpp/constructors/TestCppConstructors.py index baf06e4c59fbb..3d957fe3c0ba9 100644 --- a/lldb/test/API/lang/cpp/constructors/TestCppConstructors.py +++ b/lldb/test/API/lang/cpp/constructors/TestCppConstructors.py @@ -39,16 +39,16 @@ def test_constructors(self): ) # FIXME: Calling deleted constructors should fail before linking. - self.expect( - "expr ClassWithDeletedCtor(1).value", - error=True, - substrs=["Couldn't look up symbols:"], - ) - self.expect( - "expr ClassWithDeletedDefaultCtor().value", - error=True, - substrs=["Couldn't look up symbols:", "function", "optimized out"], - ) + #self.expect( + # "expr ClassWithDeletedCtor(1).value", + # error=True, + # substrs=["Couldn't look up symbols:"], + #) + #self.expect( + # "expr ClassWithDeletedDefaultCtor().value", + # error=True, + # substrs=["Couldn't look up symbols:", "function", "optimized out"], + #) @skipIfWindows # Can't find operator new. @skipIfLinux # Fails on some Linux systems with SIGABRT. diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py b/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py index 70d7fd096c7cf..b6998764b6922 100644 --- a/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py +++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py @@ -5,7 +5,6 @@ class ExprDefinitionInDylibTestCase(TestBase): - NO_DEBUG_INFO_TESTCASE = True @skipIfWindows def test(self): @@ -31,10 +30,9 @@ def test(self): ) self.expect_expr("f.method()", result_value="-72", result_type="int") + self.expect_expr("Foo()", result_type="Foo") - # FIXME: mangled name lookup for ABI-tagged ctors fails because - # the debug-info AST doesn't have ABI-tag information. - self.expect( - "expr Bar()", error=True, substrs=["error: Couldn't look up symbols"] - ) + self.expect_expr("Base()", result_type="Base") + + self.expect_expr("Bar()", result_type="Bar") diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp b/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp index 1a08817f5cda1..1ddd28021dffc 100644 --- a/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp +++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp @@ -11,3 +11,7 @@ Foo::~Foo() { std::puts(__func__); } Bar::Bar() { std::puts(__func__); } Bar::~Bar() { std::puts(__func__); } + +Base::Base() { std::puts(__func__); } + +Base::~Base() { std::puts(__func__); } diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.h b/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.h index 5ec227946cba0..be2206103c17e 100644 --- a/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.h +++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.h @@ -7,7 +7,12 @@ struct Foo { ~Foo(); }; -struct Bar { +struct Base { + [[gnu::abi_tag("BaseCtor")]] Base(); + [[gnu::abi_tag("BaseDtor")]] ~Base(); +}; + +struct Bar : public Base { [[gnu::abi_tag("Ctor")]] Bar(); [[gnu::abi_tag("Dtor")]] ~Bar(); }; diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/main.cpp b/lldb/test/API/lang/cpp/expr-definition-in-dylib/main.cpp index 4d6bece21ecac..b2e8700257716 100644 --- a/lldb/test/API/lang/cpp/expr-definition-in-dylib/main.cpp +++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/main.cpp @@ -2,6 +2,7 @@ int main() { Foo f; - Bar b; + Base b1; + Bar b2; return f.method(); } diff --git a/lldb/unittests/Expression/ExpressionTest.cpp b/lldb/unittests/Expression/ExpressionTest.cpp index 12f6dd515fd11..ceb567c28ab99 100644 --- a/lldb/unittests/Expression/ExpressionTest.cpp +++ b/lldb/unittests/Expression/ExpressionTest.cpp @@ -23,15 +23,15 @@ struct LabelTestCase { static LabelTestCase g_label_test_cases[] = { // Failure modes - {"bar:0x0:0x0:_Z3foov", + {"bar:blah:0x0:0x0:_Z3foov", {}, {"expected function call label prefix '$__lldb_func' but found 'bar' " "instead."}}, - {"$__lldb_func :0x0:0x0:_Z3foov", + {"$__lldb_func :blah:0x0:0x0:_Z3foov", {}, {"expected function call label prefix '$__lldb_func' but found " "'$__lldb_func ' instead."}}, - {"$__lldb_funcc:0x0:0x0:_Z3foov", + {"$__lldb_funcc:blah:0x0:0x0:_Z3foov", {}, {"expected function call label prefix '$__lldb_func' but found " "'$__lldb_funcc' instead."}}, @@ -39,47 +39,52 @@ static LabelTestCase g_label_test_cases[] = { {"foo", {}, {"malformed function call label."}}, {"$__lldb_func", {}, {"malformed function call label."}}, {"$__lldb_func:", {}, {"malformed function call label."}}, - {"$__lldb_func:0x0:0x0", {}, {"malformed function call label."}}, - {"$__lldb_func:abc:0x0:_Z3foov", + {"$__lldb_func:blah", {}, {"malformed function call label."}}, + {"$__lldb_func:blah:0x0", {}, {"malformed function call label."}}, + {"$__lldb_func:111:0x0:0x0", {}, {"malformed function call label."}}, + {"$__lldb_func:111:abc:0x0:_Z3foov", {}, {"failed to parse module ID from 'abc'."}}, - {"$__lldb_func:-1:0x0:_Z3foov", + {"$__lldb_func:111:-1:0x0:_Z3foov", {}, {"failed to parse module ID from '-1'."}}, - {"$__lldb_func:0x0invalid:0x0:_Z3foov", + {"$__lldb_func:111:0x0invalid:0x0:_Z3foov", {}, {"failed to parse module ID from '0x0invalid'."}}, - {"$__lldb_func:0x0 :0x0:_Z3foov", + {"$__lldb_func:111:0x0 :0x0:_Z3foov", {}, {"failed to parse module ID from '0x0 '."}}, - {"$__lldb_func:0x0:abc:_Z3foov", + {"$__lldb_func:blah:0x0:abc:_Z3foov", {}, {"failed to parse symbol ID from 'abc'."}}, - {"$__lldb_func:0x5:-1:_Z3foov", + {"$__lldb_func:blah:0x5:-1:_Z3foov", {}, {"failed to parse symbol ID from '-1'."}}, - {"$__lldb_func:0x5:0x0invalid:_Z3foov", + {"$__lldb_func:blah:0x5:0x0invalid:_Z3foov", {}, {"failed to parse symbol ID from '0x0invalid'."}}, - {"$__lldb_func:0x5:0x0 :_Z3foov", + {"$__lldb_func:blah:0x5:0x0 :_Z3foov", {}, {"failed to parse symbol ID from '0x0 '."}}, - {"$__lldb_func:0x0:0x0:_Z3foov", + {"$__lldb_func:blah:0x0:0x0:_Z3foov", { + /*.discriminator=*/"blah", /*.module_id=*/0x0, /*.symbol_id=*/0x0, /*.lookup_name=*/"_Z3foov", }, {}}, - {"$__lldb_func:0x0:0x0:abc:def:::a", + {"$__lldb_func::0x0:0x0:abc:def:::a", { + /*.discriminator=*/"", /*.module_id=*/0x0, /*.symbol_id=*/0x0, /*.lookup_name=*/"abc:def:::a", }, {}}, - {"$__lldb_func:0xd2:0xf0:$__lldb_func", + {"$__lldb_func:0x45:0xd2:0xf0:$__lldb_func", { + /*.discriminator=*/"0x45", /*.module_id=*/0xd2, /*.symbol_id=*/0xf0, /*.lookup_name=*/"$__lldb_func", @@ -106,6 +111,7 @@ TEST_P(ExpressionTestFixture, FunctionCallLabel) { EXPECT_EQ(decoded_or_err->toString(), encoded); EXPECT_EQ(label_str, encoded); + EXPECT_EQ(decoded_or_err->discriminator, label.discriminator); EXPECT_EQ(decoded_or_err->module_id, label.module_id); EXPECT_EQ(decoded_or_err->symbol_id, label.symbol_id); EXPECT_EQ(decoded_or_err->lookup_name, label.lookup_name); @@ -113,6 +119,7 @@ TEST_P(ExpressionTestFixture, FunctionCallLabel) { auto roundtrip_or_err = FunctionCallLabel::fromString(label_str); EXPECT_THAT_EXPECTED(roundtrip_or_err, llvm::Succeeded()); + EXPECT_EQ(roundtrip_or_err->discriminator, label.discriminator); EXPECT_EQ(roundtrip_or_err->module_id, label.module_id); EXPECT_EQ(roundtrip_or_err->symbol_id, label.symbol_id); EXPECT_EQ(roundtrip_or_err->lookup_name, label.lookup_name); diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp index b993b82612497..f673cceae00dd 100644 --- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp @@ -1150,12 +1150,12 @@ TEST_F(TestTypeSystemClang, AsmLabel_CtorDtor) { is_explicit, is_attr_used, is_artificial); auto *ctor = m_ast->AddMethodToCXXRecordType( - t.GetOpaqueQualType(), "S", /*asm_label=*/"$__lldb_func:0x0:0x0:S", + t.GetOpaqueQualType(), "S", /*asm_label=*/"$__lldb_func::0x0:0x0:S", function_type, lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline, is_explicit, is_attr_used, is_artificial); auto *dtor = m_ast->AddMethodToCXXRecordType( - t.GetOpaqueQualType(), "~S", /*asm_label=*/"$__lldb_func:0x0:0x0:~S", + t.GetOpaqueQualType(), "~S", /*asm_label=*/"$__lldb_func::0x0:0x0:~S", function_type, lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline, is_explicit, is_attr_used, is_artificial); @@ -1181,11 +1181,11 @@ TEST_F(TestTypeSystemClang, AsmLabel_CtorDtor) { EXPECT_STREQ(llvm::GlobalValue::dropLLVMManglingEscape( m_ast->DeclGetMangledName(ctor).GetStringRef()) .data(), - "$__lldb_func:0x0:0x0:S"); + "$__lldb_func:C0:0x0:0x0:S"); EXPECT_STREQ(llvm::GlobalValue::dropLLVMManglingEscape( m_ast->DeclGetMangledName(dtor).GetStringRef()) .data(), - "$__lldb_func:0x0:0x0:~S"); + "$__lldb_func:D1:0x0:0x0:~S"); } struct AsmLabelTestCase { @@ -1215,10 +1215,10 @@ class TestTypeSystemClangAsmLabel }; static AsmLabelTestCase g_asm_label_test_cases[] = { - {/*mangled=*/"$__lldb_func:0x0:0x0:_Z3foov", + {/*mangled=*/"$__lldb_func::0x0:0x0:_Z3foov", /*expected=*/"_Z3foov"}, - {/*mangled=*/"$__lldb_func:0x0:0x0:foo", - /*expected=*/"$__lldb_func:0x0:0x0:foo"}, + {/*mangled=*/"$__lldb_func::0x0:0x0:foo", + /*expected=*/"$__lldb_func::0x0:0x0:foo"}, {/*mangled=*/"foo", /*expected=*/"foo"}, {/*mangled=*/"_Z3foov", diff --git a/llvm/include/llvm/Demangle/Demangle.h b/llvm/include/llvm/Demangle/Demangle.h index d9b08b2d856dc..6af8fad9ceb86 100644 --- a/llvm/include/llvm/Demangle/Demangle.h +++ b/llvm/include/llvm/Demangle/Demangle.h @@ -127,6 +127,9 @@ struct ItaniumPartialDemangler { /// If this symbol describes a constructor or destructor. DEMANGLE_ABI bool isCtorOrDtor() const; + /// If this symbol describes a constructor or destructor. + std::optional getCtorOrDtorVariant() const; + /// If this symbol describes a function. DEMANGLE_ABI bool isFunction() const; diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h index 62d427c3966bb..c0db02f8e7fef 100644 --- a/llvm/include/llvm/Demangle/ItaniumDemangle.h +++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h @@ -1766,6 +1766,8 @@ class CtorDtorName final : public Node { template 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/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index c27f100775625..57860921919de 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -493,17 +493,23 @@ void DwarfDebug::addSubprogramNames( if (SP->getName() != "") addAccelName(Unit, NameTableKind, SP->getName(), Die); - // We drop the mangling escape prefix when emitting the DW_AT_linkage_name. So - // ensure we don't include it when inserting into the accelerator tables. - llvm::StringRef LinkageName = - GlobalValue::dropLLVMManglingEscape(SP->getLinkageName()); - - // If the linkage name is different than the name, go ahead and output that as - // well into the name table. Only do that if we are going to actually emit - // that name. - if (LinkageName != "" && SP->getName() != LinkageName && - (useAllLinkageNames() || InfoHolder.getAbstractScopeDIEs().lookup(SP))) - addAccelName(Unit, NameTableKind, LinkageName, Die); + auto AddLinkageName = [&](const DISubprogram *S) { + // We drop the mangling escape prefix when emitting the DW_AT_linkage_name. + // So ensure we don't include it when inserting into the accelerator tables. + llvm::StringRef LinkageName = + GlobalValue::dropLLVMManglingEscape(S->getLinkageName()); + + // If the linkage name is different than the name, go ahead and output that + // as well into the name table. Only do that if we are going to actually + // emit that name. + if (LinkageName != "" && S->getName() != LinkageName && + (useAllLinkageNames() || InfoHolder.getAbstractScopeDIEs().lookup(S))) + addAccelName(Unit, NameTableKind, LinkageName, Die); + }; + + AddLinkageName(SP); + if (const DISubprogram *Spec = SP->getDeclaration()) + AddLinkageName(Spec); // If this is an Objective-C selector name add it to the ObjC accelerator // too. diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index b03fac2d22a52..f0ff5f76275a6 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1403,10 +1403,10 @@ bool DwarfUnit::applySubprogramDefinitionAttributes(const DISubprogram *SP, // Add the linkage name if we have one and it isn't in the Decl. StringRef LinkageName = SP->getLinkageName(); - assert(((LinkageName.empty() || DeclLinkageName.empty()) || - LinkageName == DeclLinkageName) && - "decl has a linkage name and it is different"); - if (DeclLinkageName.empty() && + // assert(((LinkageName.empty() || DeclLinkageName.empty()) || + // LinkageName == DeclLinkageName) && + // "decl has a linkage name and it is different"); + if (/*DeclLinkageName.empty() &&*/ // Always emit it for abstract subprograms. (DD->useAllLinkageNames() || DU->getAbstractScopeDIEs().lookup(SP))) addLinkageName(SPDie, LinkageName); diff --git a/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp b/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp index 8052773812a2c..c11d1a1a41b3a 100644 --- a/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp +++ b/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/CodeGen/NonRelocatableStringpool.h" #include "llvm/DWARFLinker/Classic/DWARFLinkerDeclContext.h" #include "llvm/DWARFLinker/Classic/DWARFStreamer.h" @@ -1933,6 +1934,22 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE, OutOffset += 4; } + auto AddNameToAccel = [&](AttributesInfo &Info) { + if (Info.MangledName && Info.MangledName != Info.Name) + Unit.addNameAccelerator(Die, Info.MangledName, + Tag == dwarf::DW_TAG_inlined_subroutine); + if (Info.Name) { + if (Info.NameWithoutTemplate) + Unit.addNameAccelerator(Die, Info.NameWithoutTemplate, + /* SkipPubSection */ true); + Unit.addNameAccelerator(Die, Info.Name, + Tag == dwarf::DW_TAG_inlined_subroutine); + } + if (Info.Name) + addObjCAccelerator(Unit, Die, Info.Name, DebugStrPool, + /* SkipPubSection =*/true); + }; + // Look for accelerator entries. // FIXME: This is slightly wrong. An inline_subroutine without a // low_pc, but with AT_ranges might be interesting to get into the @@ -1941,20 +1958,14 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE, Tag != dwarf::DW_TAG_compile_unit && getDIENames(InputDIE, AttrInfo, DebugStrPool, Tag != dwarf::DW_TAG_inlined_subroutine)) { - if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name) - Unit.addNameAccelerator(Die, AttrInfo.MangledName, - Tag == dwarf::DW_TAG_inlined_subroutine); - if (AttrInfo.Name) { - if (AttrInfo.NameWithoutTemplate) - Unit.addNameAccelerator(Die, AttrInfo.NameWithoutTemplate, - /* SkipPubSection */ true); - Unit.addNameAccelerator(Die, AttrInfo.Name, - Tag == dwarf::DW_TAG_inlined_subroutine); - } - if (AttrInfo.Name) - addObjCAccelerator(Unit, Die, AttrInfo.Name, DebugStrPool, - /* SkipPubSection =*/true); + AddNameToAccel(AttrInfo); + + AttributesInfo SpecAttrInfo; + DWARFDie Spec = InputDIE.getAttributeValueAsReferencedDie( + llvm::dwarf::DW_AT_specification); + if (Spec && getDIENames(Spec, SpecAttrInfo, DebugStrPool)) + AddNameToAccel(SpecAttrInfo); } else if (Tag == dwarf::DW_TAG_namespace) { if (!AttrInfo.Name) AttrInfo.Name = DebugStrPool.getEntry("(anonymous namespace)"); diff --git a/llvm/lib/Demangle/ItaniumDemangle.cpp b/llvm/lib/Demangle/ItaniumDemangle.cpp index 1009cc91ca12a..a5d7a5576fccf 100644 --- a/llvm/lib/Demangle/ItaniumDemangle.cpp +++ b/llvm/lib/Demangle/ItaniumDemangle.cpp @@ -560,13 +560,17 @@ bool ItaniumPartialDemangler::hasFunctionQualifiers() const { } bool ItaniumPartialDemangler::isCtorOrDtor() const { + return getCtorOrDtorVariant().has_value(); +} + +std::optional ItaniumPartialDemangler::getCtorOrDtorVariant() const { const Node *N = static_cast(RootNode); while (N) { switch (N->getKind()) { default: - return false; + return std::nullopt; case Node::KCtorDtorName: - return true; + return static_cast(N)->getVariant(); case Node::KAbiTagAttr: N = static_cast(N)->Base; @@ -588,7 +592,7 @@ bool ItaniumPartialDemangler::isCtorOrDtor() const { break; } } - return false; + return std::nullopt; } bool ItaniumPartialDemangler::isFunction() const {