Skip to content

Commit db8cad0

Browse files
authored
[clang][Mangle] Inject structor type into mangled name when mangling for LLDB JIT expressions (#155485)
Part of #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.
1 parent 6b780af commit db8cad0

File tree

3 files changed

+160
-5
lines changed

3 files changed

+160
-5
lines changed

clang/lib/AST/Mangle.cpp

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,37 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
152152
return shouldMangleCXXName(D);
153153
}
154154

155+
static llvm::StringRef g_lldb_func_call_label_prefix = "$__lldb_func:";
156+
157+
/// Given an LLDB function call label, this function prints the label
158+
/// into \c Out, together with the structor type of \c GD (if the
159+
/// decl is a constructor/destructor). LLDB knows how to handle mangled
160+
/// names with this encoding.
161+
///
162+
/// Example input label:
163+
/// $__lldb_func::123:456:~Foo
164+
///
165+
/// Example output:
166+
/// $__lldb_func:D1:123:456:~Foo
167+
///
168+
static void emitLLDBAsmLabel(llvm::StringRef label, GlobalDecl GD,
169+
llvm::raw_ostream &Out) {
170+
assert(label.starts_with(g_lldb_func_call_label_prefix));
171+
172+
Out << g_lldb_func_call_label_prefix;
173+
174+
if (auto *Ctor = llvm::dyn_cast<clang::CXXConstructorDecl>(GD.getDecl())) {
175+
Out << "C";
176+
if (Ctor->getInheritedConstructor().getConstructor())
177+
Out << "I";
178+
Out << GD.getCtorType();
179+
} else if (llvm::isa<clang::CXXDestructorDecl>(GD.getDecl())) {
180+
Out << "D" << GD.getDtorType();
181+
}
182+
183+
Out << label.substr(g_lldb_func_call_label_prefix.size());
184+
}
185+
155186
void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
156187
const ASTContext &ASTContext = getASTContext();
157188
const NamedDecl *D = cast<NamedDecl>(GD.getDecl());
@@ -185,7 +216,11 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
185216
if (!UserLabelPrefix.empty())
186217
Out << '\01'; // LLVM IR Marker for __asm("foo")
187218

188-
Out << ALA->getLabel();
219+
if (ALA->getLabel().starts_with(g_lldb_func_call_label_prefix))
220+
emitLLDBAsmLabel(ALA->getLabel(), GD, Out);
221+
else
222+
Out << ALA->getLabel();
223+
189224
return;
190225
}
191226

clang/unittests/AST/DeclTest.cpp

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@
1212

1313
#include "clang/AST/Decl.h"
1414
#include "clang/AST/ASTContext.h"
15+
#include "clang/AST/DeclCXX.h"
1516
#include "clang/AST/DeclTemplate.h"
1617
#include "clang/AST/Mangle.h"
1718
#include "clang/ASTMatchers/ASTMatchFinder.h"
1819
#include "clang/ASTMatchers/ASTMatchers.h"
20+
#include "clang/Basic/ABI.h"
1921
#include "clang/Basic/Diagnostic.h"
2022
#include "clang/Basic/LLVM.h"
2123
#include "clang/Basic/TargetInfo.h"
@@ -102,6 +104,124 @@ TEST(Decl, AsmLabelAttr) {
102104
"foo");
103105
}
104106

107+
TEST(Decl, AsmLabelAttr_LLDB) {
108+
StringRef Code = R"(
109+
struct S {
110+
void f() {}
111+
S() = default;
112+
~S() = default;
113+
};
114+
)";
115+
auto AST =
116+
tooling::buildASTFromCodeWithArgs(Code, {"-target", "i386-apple-darwin"});
117+
ASTContext &Ctx = AST->getASTContext();
118+
assert(Ctx.getTargetInfo().getUserLabelPrefix() == StringRef("_") &&
119+
"Expected target to have a global prefix");
120+
DiagnosticsEngine &Diags = AST->getDiagnostics();
121+
122+
const auto *DeclS =
123+
selectFirst<CXXRecordDecl>("d", match(cxxRecordDecl().bind("d"), Ctx));
124+
125+
auto *DeclF = *DeclS->method_begin();
126+
auto *Ctor = *DeclS->ctor_begin();
127+
auto *Dtor = DeclS->getDestructor();
128+
129+
ASSERT_TRUE(DeclF);
130+
ASSERT_TRUE(Ctor);
131+
ASSERT_TRUE(Dtor);
132+
133+
DeclF->addAttr(AsmLabelAttr::Create(Ctx, "$__lldb_func::123:123:_Z1fv"));
134+
Ctor->addAttr(AsmLabelAttr::Create(Ctx, "$__lldb_func::123:123:S"));
135+
Dtor->addAttr(AsmLabelAttr::Create(Ctx, "$__lldb_func::123:123:~S"));
136+
137+
std::unique_ptr<ItaniumMangleContext> MC(
138+
ItaniumMangleContext::create(Ctx, Diags));
139+
140+
{
141+
std::string Mangled;
142+
llvm::raw_string_ostream OS_Mangled(Mangled);
143+
MC->mangleName(DeclF, OS_Mangled);
144+
145+
ASSERT_EQ(Mangled, "\x01$__lldb_func::123:123:_Z1fv");
146+
};
147+
148+
{
149+
std::string Mangled;
150+
llvm::raw_string_ostream OS_Mangled(Mangled);
151+
MC->mangleName(GlobalDecl(Ctor, CXXCtorType::Ctor_Complete), OS_Mangled);
152+
153+
ASSERT_EQ(Mangled, "\x01$__lldb_func:C0:123:123:S");
154+
};
155+
156+
{
157+
std::string Mangled;
158+
llvm::raw_string_ostream OS_Mangled(Mangled);
159+
MC->mangleName(GlobalDecl(Ctor, CXXCtorType::Ctor_Base), OS_Mangled);
160+
161+
ASSERT_EQ(Mangled, "\x01$__lldb_func:C1:123:123:S");
162+
};
163+
164+
{
165+
std::string Mangled;
166+
llvm::raw_string_ostream OS_Mangled(Mangled);
167+
MC->mangleName(GlobalDecl(Dtor, CXXDtorType::Dtor_Deleting), OS_Mangled);
168+
169+
ASSERT_EQ(Mangled, "\x01$__lldb_func:D0:123:123:~S");
170+
};
171+
172+
{
173+
std::string Mangled;
174+
llvm::raw_string_ostream OS_Mangled(Mangled);
175+
MC->mangleName(GlobalDecl(Dtor, CXXDtorType::Dtor_Base), OS_Mangled);
176+
177+
ASSERT_EQ(Mangled, "\x01$__lldb_func:D2:123:123:~S");
178+
};
179+
}
180+
181+
TEST(Decl, AsmLabelAttr_LLDB_Inherit) {
182+
StringRef Code = R"(
183+
struct Base {
184+
Base(int x) {}
185+
};
186+
187+
struct Derived : Base {
188+
using Base::Base;
189+
} d(5);
190+
)";
191+
auto AST =
192+
tooling::buildASTFromCodeWithArgs(Code, {"-target", "i386-apple-darwin"});
193+
ASTContext &Ctx = AST->getASTContext();
194+
assert(Ctx.getTargetInfo().getUserLabelPrefix() == StringRef("_") &&
195+
"Expected target to have a global prefix");
196+
DiagnosticsEngine &Diags = AST->getDiagnostics();
197+
198+
const auto *Ctor = selectFirst<CXXConstructorDecl>(
199+
"ctor",
200+
match(cxxConstructorDecl(isInheritingConstructor()).bind("ctor"), Ctx));
201+
202+
const_cast<CXXConstructorDecl *>(Ctor)->addAttr(
203+
AsmLabelAttr::Create(Ctx, "$__lldb_func::123:123:Derived"));
204+
205+
std::unique_ptr<ItaniumMangleContext> MC(
206+
ItaniumMangleContext::create(Ctx, Diags));
207+
208+
{
209+
std::string Mangled;
210+
llvm::raw_string_ostream OS_Mangled(Mangled);
211+
MC->mangleName(GlobalDecl(Ctor, CXXCtorType::Ctor_Complete), OS_Mangled);
212+
213+
ASSERT_EQ(Mangled, "\x01$__lldb_func:CI0:123:123:Derived");
214+
};
215+
216+
{
217+
std::string Mangled;
218+
llvm::raw_string_ostream OS_Mangled(Mangled);
219+
MC->mangleName(GlobalDecl(Ctor, CXXCtorType::Ctor_Base), OS_Mangled);
220+
221+
ASSERT_EQ(Mangled, "\x01$__lldb_func:CI1:123:123:Derived");
222+
};
223+
}
224+
105225
TEST(Decl, MangleDependentSizedArray) {
106226
StringRef Code = R"(
107227
template <int ...N>

lldb/unittests/Symbol/TestTypeSystemClang.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,12 +1150,12 @@ TEST_F(TestTypeSystemClang, AsmLabel_CtorDtor) {
11501150
is_explicit, is_attr_used, is_artificial);
11511151

11521152
auto *ctor = m_ast->AddMethodToCXXRecordType(
1153-
t.GetOpaqueQualType(), "S", /*asm_label=*/"$__lldb_func:0x0:0x0:S",
1153+
t.GetOpaqueQualType(), "S", /*asm_label=*/"$__lldb_func::0x0:0x0:S",
11541154
function_type, lldb::AccessType::eAccessPublic, is_virtual, is_static,
11551155
is_inline, is_explicit, is_attr_used, is_artificial);
11561156

11571157
auto *dtor = m_ast->AddMethodToCXXRecordType(
1158-
t.GetOpaqueQualType(), "~S", /*asm_label=*/"$__lldb_func:0x0:0x0:~S",
1158+
t.GetOpaqueQualType(), "~S", /*asm_label=*/"$__lldb_func::0x0:0x0:~S",
11591159
function_type, lldb::AccessType::eAccessPublic, is_virtual, is_static,
11601160
is_inline, is_explicit, is_attr_used, is_artificial);
11611161

@@ -1181,11 +1181,11 @@ TEST_F(TestTypeSystemClang, AsmLabel_CtorDtor) {
11811181
EXPECT_STREQ(llvm::GlobalValue::dropLLVMManglingEscape(
11821182
m_ast->DeclGetMangledName(ctor).GetStringRef())
11831183
.data(),
1184-
"$__lldb_func:0x0:0x0:S");
1184+
"$__lldb_func:C0:0x0:0x0:S");
11851185
EXPECT_STREQ(llvm::GlobalValue::dropLLVMManglingEscape(
11861186
m_ast->DeclGetMangledName(dtor).GetStringRef())
11871187
.data(),
1188-
"$__lldb_func:0x0:0x0:~S");
1188+
"$__lldb_func:D1:0x0:0x0:~S");
11891189
}
11901190

11911191
struct AsmLabelTestCase {

0 commit comments

Comments
 (0)