Skip to content

Commit 3ddc4d4

Browse files
committed
[clang][Mangle] Inject structor type into mangled name when mangling for LLDB JIT expressions
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 b8f31ec commit 3ddc4d4

File tree

2 files changed

+107
-1
lines changed

2 files changed

+107
-1
lines changed

clang/lib/AST/Mangle.cpp

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,33 @@ 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 (llvm::isa<clang::CXXConstructorDecl>(GD.getDecl()))
175+
Out << "C" << GD.getCtorType();
176+
else if (llvm::isa<clang::CXXDestructorDecl>(GD.getDecl()))
177+
Out << "D" << GD.getDtorType();
178+
179+
Out << label.substr(g_lldb_func_call_label_prefix.size());
180+
}
181+
155182
void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
156183
const ASTContext &ASTContext = getASTContext();
157184
const NamedDecl *D = cast<NamedDecl>(GD.getDecl());
@@ -185,7 +212,11 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
185212
if (!UserLabelPrefix.empty())
186213
Out << '\01'; // LLVM IR Marker for __asm("foo")
187214

188-
Out << ALA->getLabel();
215+
if (ALA->getLabel().starts_with(g_lldb_func_call_label_prefix))
216+
emitLLDBAsmLabel(ALA->getLabel(), GD, Out);
217+
else
218+
Out << ALA->getLabel();
219+
189220
return;
190221
}
191222

clang/unittests/AST/DeclTest.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "clang/AST/Mangle.h"
1717
#include "clang/ASTMatchers/ASTMatchFinder.h"
1818
#include "clang/ASTMatchers/ASTMatchers.h"
19+
#include "clang/Basic/ABI.h"
1920
#include "clang/Basic/Diagnostic.h"
2021
#include "clang/Basic/LLVM.h"
2122
#include "clang/Basic/TargetInfo.h"
@@ -102,6 +103,80 @@ TEST(Decl, AsmLabelAttr) {
102103
"foo");
103104
}
104105

106+
TEST(Decl, AsmLabelAttr_LLDB) {
107+
StringRef Code = R"(
108+
struct S {
109+
void f() {}
110+
S() = default;
111+
~S() = default;
112+
};
113+
)";
114+
auto AST =
115+
tooling::buildASTFromCodeWithArgs(Code, {"-target", "i386-apple-darwin"});
116+
ASTContext &Ctx = AST->getASTContext();
117+
assert(Ctx.getTargetInfo().getUserLabelPrefix() == StringRef("_") &&
118+
"Expected target to have a global prefix");
119+
DiagnosticsEngine &Diags = AST->getDiagnostics();
120+
121+
const auto *DeclS =
122+
selectFirst<CXXRecordDecl>("d", match(cxxRecordDecl().bind("d"), Ctx));
123+
124+
auto *DeclF = *DeclS->method_begin();
125+
auto *Ctor = *DeclS->ctor_begin();
126+
auto *Dtor = DeclS->getDestructor();
127+
128+
ASSERT_TRUE(DeclF);
129+
ASSERT_TRUE(Ctor);
130+
ASSERT_TRUE(Dtor);
131+
132+
DeclF->addAttr(AsmLabelAttr::Create(Ctx, "$__lldb_func::123:123:_Z1fv"));
133+
Ctor->addAttr(AsmLabelAttr::Create(Ctx, "$__lldb_func::123:123:S"));
134+
Dtor->addAttr(AsmLabelAttr::Create(Ctx, "$__lldb_func::123:123:~S"));
135+
136+
std::unique_ptr<ItaniumMangleContext> MC(
137+
ItaniumMangleContext::create(Ctx, Diags));
138+
139+
{
140+
std::string Mangled;
141+
llvm::raw_string_ostream OS_Mangled(Mangled);
142+
MC->mangleName(DeclF, OS_Mangled);
143+
144+
ASSERT_EQ(Mangled, "\x01$__lldb_func::123:123:_Z1fv");
145+
};
146+
147+
{
148+
std::string Mangled;
149+
llvm::raw_string_ostream OS_Mangled(Mangled);
150+
MC->mangleName(GlobalDecl(Ctor, CXXCtorType::Ctor_Complete), OS_Mangled);
151+
152+
ASSERT_EQ(Mangled, "\x01$__lldb_func:C0:123:123:S");
153+
};
154+
155+
{
156+
std::string Mangled;
157+
llvm::raw_string_ostream OS_Mangled(Mangled);
158+
MC->mangleName(GlobalDecl(Ctor, CXXCtorType::Ctor_Base), OS_Mangled);
159+
160+
ASSERT_EQ(Mangled, "\x01$__lldb_func:C1:123:123:S");
161+
};
162+
163+
{
164+
std::string Mangled;
165+
llvm::raw_string_ostream OS_Mangled(Mangled);
166+
MC->mangleName(GlobalDecl(Dtor, CXXDtorType::Dtor_Deleting), OS_Mangled);
167+
168+
ASSERT_EQ(Mangled, "\x01$__lldb_func:D0:123:123:~S");
169+
};
170+
171+
{
172+
std::string Mangled;
173+
llvm::raw_string_ostream OS_Mangled(Mangled);
174+
MC->mangleName(GlobalDecl(Dtor, CXXDtorType::Dtor_Base), OS_Mangled);
175+
176+
ASSERT_EQ(Mangled, "\x01$__lldb_func:D2:123:123:~S");
177+
};
178+
}
179+
105180
TEST(Decl, MangleDependentSizedArray) {
106181
StringRef Code = R"(
107182
template <int ...N>

0 commit comments

Comments
 (0)