Author: Michael Buch Date: 2025-09-09T09:08:50+01:00 New Revision: db8cad0c8d00a691d1365e9b2962a7f2f4ff0890
URL: https://github.com/llvm/llvm-project/commit/db8cad0c8d00a691d1365e9b2962a7f2f4ff0890 DIFF: https://github.com/llvm/llvm-project/commit/db8cad0c8d00a691d1365e9b2962a7f2f4ff0890.diff LOG: [clang][Mangle] Inject structor type into mangled name when mangling for LLDB JIT expressions (#155485) Part of https://github.com/llvm/llvm-project/pull/149827 This patch adds special handling for `AsmLabel`s created by LLDB. LLDB uses `AsmLabel`s to encode information about a function declaration to make it easier to locate function symbols when JITing C++ expressions. For constructors/destructors LLDB doesn't know at the time of creating the `AsmLabelAttr` which structor variant the expression evaluator will need to call (this is decided when compiling the expression). So we make the Clang mangler inject this information into our custom label when we're JITting the expression. Added: Modified: clang/lib/AST/Mangle.cpp clang/unittests/AST/DeclTest.cpp lldb/unittests/Symbol/TestTypeSystemClang.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp index 0bfb51c11f0a5..780b2c585c810 100644 --- a/clang/lib/AST/Mangle.cpp +++ b/clang/lib/AST/Mangle.cpp @@ -152,6 +152,37 @@ 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 (auto *Ctor = llvm::dyn_cast<clang::CXXConstructorDecl>(GD.getDecl())) { + Out << "C"; + if (Ctor->getInheritedConstructor().getConstructor()) + Out << "I"; + Out << GD.getCtorType(); + } else if (llvm::isa<clang::CXXDestructorDecl>(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<NamedDecl>(GD.getDecl()); @@ -185,7 +216,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/unittests/AST/DeclTest.cpp b/clang/unittests/AST/DeclTest.cpp index e76edbfe95b68..b95d361896e21 100644 --- a/clang/unittests/AST/DeclTest.cpp +++ b/clang/unittests/AST/DeclTest.cpp @@ -12,10 +12,12 @@ #include "clang/AST/Decl.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #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 +104,124 @@ 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<CXXRecordDecl>("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<ItaniumMangleContext> 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, AsmLabelAttr_LLDB_Inherit) { + StringRef Code = R"( + struct Base { + Base(int x) {} + }; + + struct Derived : Base { + using Base::Base; + } d(5); + )"; + 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 *Ctor = selectFirst<CXXConstructorDecl>( + "ctor", + match(cxxConstructorDecl(isInheritingConstructor()).bind("ctor"), Ctx)); + + const_cast<CXXConstructorDecl *>(Ctor)->addAttr( + AsmLabelAttr::Create(Ctx, "$__lldb_func::123:123:Derived")); + + std::unique_ptr<ItaniumMangleContext> MC( + ItaniumMangleContext::create(Ctx, Diags)); + + { + 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:CI0:123:123:Derived"); + }; + + { + 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:CI1:123:123:Derived"); + }; +} + TEST(Decl, MangleDependentSizedArray) { StringRef Code = R"( template <int ...N> diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp index b993b82612497..91cfc6839e777 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 { _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits