Skip to content

Commit e10a1eb

Browse files
committed
LLDB
1 parent cea4ad1 commit e10a1eb

File tree

7 files changed

+191
-46
lines changed

7 files changed

+191
-46
lines changed

clang/lib/AST/Mangle.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,20 @@ 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+
static void emitLLDBAsmLabel(llvm::StringRef label, GlobalDecl GD,
158+
llvm::raw_ostream &Out) {
159+
Out << g_lldb_func_call_label_prefix << ":";
160+
161+
if (llvm::isa<clang::CXXConstructorDecl>(GD.getDecl()))
162+
Out << "C" << GD.getCtorType();
163+
else if (llvm::isa<clang::CXXDestructorDecl>(GD.getDecl()))
164+
Out << "D" << GD.getDtorType();
165+
166+
Out << label.substr(g_lldb_func_call_label_prefix.size() + 1);
167+
}
168+
155169
void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
156170
const ASTContext &ASTContext = getASTContext();
157171
const NamedDecl *D = cast<NamedDecl>(GD.getDecl());
@@ -185,7 +199,11 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
185199
if (!UserLabelPrefix.empty())
186200
Out << '\01'; // LLVM IR Marker for __asm("foo")
187201

188-
Out << ALA->getLabel();
202+
if (ALA->getLabel().starts_with(g_lldb_func_call_label_prefix))
203+
emitLLDBAsmLabel(ALA->getLabel(), GD, Out);
204+
else
205+
Out << ALA->getLabel();
206+
189207
return;
190208
}
191209

lldb/include/lldb/Expression/Expression.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,15 @@ class Expression {
103103
///
104104
/// The format being:
105105
///
106-
/// <prefix>:<module uid>:<symbol uid>:<name>
106+
/// <prefix>:<discriminator>:<module uid>:<symbol uid>:<name>
107107
///
108108
/// The label string needs to stay valid for the entire lifetime
109109
/// of this object.
110110
struct FunctionCallLabel {
111+
/// Arbitrary string which language plugins can interpret for their
112+
/// own needs.
113+
llvm::StringRef discriminator;
114+
111115
/// Unique identifier of the lldb_private::Module
112116
/// which contains the symbol identified by \c symbol_id.
113117
lldb::user_id_t module_id;
@@ -133,7 +137,7 @@ struct FunctionCallLabel {
133137
///
134138
/// The representation roundtrips through \c fromString:
135139
/// \code{.cpp}
136-
/// llvm::StringRef encoded = "$__lldb_func:0x0:0x0:_Z3foov";
140+
/// llvm::StringRef encoded = "$__lldb_func:blah:0x0:0x0:_Z3foov";
137141
/// FunctionCallLabel label = *fromString(label);
138142
///
139143
/// assert (label.toString() == encoded);

lldb/source/Expression/Expression.cpp

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,21 @@ Expression::Expression(ExecutionContextScope &exe_scope)
3434

3535
llvm::Expected<FunctionCallLabel>
3636
lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) {
37-
llvm::SmallVector<llvm::StringRef, 4> components;
38-
label.split(components, ":", /*MaxSplit=*/3);
37+
llvm::SmallVector<llvm::StringRef, 5> components;
38+
label.split(components, ":", /*MaxSplit=*/4);
3939

40-
if (components.size() != 4)
40+
if (components.size() != 5)
4141
return llvm::createStringError("malformed function call label.");
4242

4343
if (components[0] != FunctionCallLabelPrefix)
4444
return llvm::createStringError(llvm::formatv(
4545
"expected function call label prefix '{0}' but found '{1}' instead.",
4646
FunctionCallLabelPrefix, components[0]));
4747

48-
llvm::StringRef module_label = components[1];
49-
llvm::StringRef die_label = components[2];
48+
llvm::StringRef discriminator = components[1];
49+
llvm::StringRef module_label = components[2];
50+
llvm::StringRef die_label = components[3];
51+
llvm::StringRef lookup_name = components[4];
5052

5153
lldb::user_id_t module_id = 0;
5254
if (!llvm::to_integer(module_label, module_id))
@@ -58,20 +60,23 @@ lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) {
5860
return llvm::createStringError(
5961
llvm::formatv("failed to parse symbol ID from '{0}'.", die_label));
6062

61-
return FunctionCallLabel{/*.module_id=*/module_id,
63+
return FunctionCallLabel{/*.discriminator=*/discriminator,
64+
/*.module_id=*/module_id,
6265
/*.symbol_id=*/die_id,
63-
/*.lookup_name=*/components[3]};
66+
/*.lookup_name=*/lookup_name};
6467
}
6568

6669
std::string lldb_private::FunctionCallLabel::toString() const {
67-
return llvm::formatv("{0}:{1:x}:{2:x}:{3}", FunctionCallLabelPrefix,
68-
module_id, symbol_id, lookup_name)
70+
return llvm::formatv("{0}:{1}:{2:x}:{3:x}:{4}", FunctionCallLabelPrefix,
71+
discriminator, module_id, symbol_id, lookup_name)
6972
.str();
7073
}
7174

7275
void llvm::format_provider<FunctionCallLabel>::format(
7376
const FunctionCallLabel &label, raw_ostream &OS, StringRef Style) {
74-
OS << llvm::formatv("FunctionCallLabel{ module_id: {0:x}, symbol_id: {1:x}, "
75-
"lookup_name: {2} }",
76-
label.module_id, label.symbol_id, label.lookup_name);
77+
OS << llvm::formatv("FunctionCallLabel{ discriminator: {0}, module_id: "
78+
"{1:x}, symbol_id: {2:x}, "
79+
"lookup_name: {3} }",
80+
label.discriminator, label.module_id, label.symbol_id,
81+
label.lookup_name);
7782
}

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,36 @@ static unsigned GetCXXMethodCVQuals(const DWARFDIE &subprogram,
250250
return cv_quals;
251251
}
252252

253+
static const char *GetMangledOrStructorName(const DWARFDIE &die) {
254+
const char *name = die.GetMangledName(/*substitute_name_allowed*/ false);
255+
if (name)
256+
return name;
257+
258+
name = die.GetName();
259+
if (!name)
260+
return nullptr;
261+
262+
DWARFDIE parent = die.GetParent();
263+
if (!parent.IsStructUnionOrClass())
264+
return nullptr;
265+
266+
const char *parent_name = parent.GetName();
267+
if (!parent_name)
268+
return nullptr;
269+
270+
// Constructor.
271+
if (::strcmp(parent_name, name) == 0)
272+
return name;
273+
274+
// Destructor.
275+
if (name[0] == '~' && ::strcmp(parent_name, name + 1))
276+
return name;
277+
278+
return nullptr;
279+
}
280+
253281
static std::string MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
254-
char const *name = die.GetMangledName(/*substitute_name_allowed*/ false);
282+
char const *name = GetMangledOrStructorName(die);
255283
if (!name)
256284
return {};
257285

@@ -285,7 +313,9 @@ static std::string MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
285313
if (die_id == LLDB_INVALID_UID)
286314
return {};
287315

288-
return FunctionCallLabel{/*module_id=*/module_id,
316+
// Note, discriminator is added by Clang during mangling.
317+
return FunctionCallLabel{/*discriminator=*/{},
318+
/*module_id=*/module_id,
289319
/*symbol_id=*/die_id,
290320
/*.lookup_name=*/name}
291321
.toString();

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp

Lines changed: 88 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "SymbolFileDWARF.h"
10+
#include "clang/Basic/ABI.h"
1011
#include "llvm/ADT/STLExtras.h"
12+
#include "llvm/ADT/StringExtras.h"
1113
#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
1214
#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
1315
#include "llvm/Support/Casting.h"
@@ -78,6 +80,7 @@
7880

7981
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
8082
#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
83+
#include "llvm/Demangle/Demangle.h"
8184
#include "llvm/Support/FileSystem.h"
8285
#include "llvm/Support/FormatVariadic.h"
8386

@@ -2482,6 +2485,56 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die,
24822485
return false;
24832486
}
24842487

2488+
static uint8_t ClangToItaniumCtorKind(clang::CXXCtorType kind) {
2489+
switch (kind) {
2490+
case clang::CXXCtorType::Ctor_Complete:
2491+
return 1;
2492+
case clang::CXXCtorType::Ctor_Base:
2493+
return 2;
2494+
case clang::CXXCtorType::Ctor_CopyingClosure:
2495+
case clang::CXXCtorType::Ctor_DefaultClosure:
2496+
case clang::CXXCtorType::Ctor_Comdat:
2497+
llvm_unreachable("Unexpected constructor kind.");
2498+
}
2499+
}
2500+
2501+
static uint8_t ClangToItaniumDtorKind(clang::CXXDtorType kind) {
2502+
switch (kind) {
2503+
case clang::CXXDtorType::Dtor_Deleting:
2504+
return 0;
2505+
case clang::CXXDtorType::Dtor_Complete:
2506+
return 1;
2507+
case clang::CXXDtorType::Dtor_Base:
2508+
return 2;
2509+
case clang::CXXDtorType::Dtor_Comdat:
2510+
llvm_unreachable("Unexpected destructor kind.");
2511+
}
2512+
}
2513+
2514+
static std::optional<uint8_t>
2515+
GetItaniumCtorDtorVariant(llvm::StringRef discriminator) {
2516+
const bool is_ctor = discriminator.consume_front("C");
2517+
if (!is_ctor && !discriminator.consume_front("D"))
2518+
return std::nullopt;
2519+
2520+
uint64_t structor_kind;
2521+
if (!llvm::to_integer(discriminator, structor_kind))
2522+
return std::nullopt;
2523+
2524+
if (is_ctor) {
2525+
if (structor_kind > clang::CXXCtorType::Ctor_DefaultClosure)
2526+
return std::nullopt;
2527+
2528+
return ClangToItaniumCtorKind(
2529+
static_cast<clang::CXXCtorType>(structor_kind));
2530+
}
2531+
2532+
if (structor_kind > clang::CXXDtorType::Dtor_Deleting)
2533+
return std::nullopt;
2534+
2535+
return ClangToItaniumDtorKind(static_cast<clang::CXXDtorType>(structor_kind));
2536+
}
2537+
24852538
llvm::Expected<SymbolContext>
24862539
SymbolFileDWARF::ResolveFunctionCallLabel(const FunctionCallLabel &label) {
24872540
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
@@ -2494,21 +2547,49 @@ SymbolFileDWARF::ResolveFunctionCallLabel(const FunctionCallLabel &label) {
24942547
// Label was created using a declaration DIE. Need to fetch the definition
24952548
// to resolve the function call.
24962549
if (die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) {
2550+
// eFunctionNameTypeFull for mangled name lookup.
2551+
// eFunctionNameTypeMethod is required for structor lookups (since we look
2552+
// those up by DW_AT_name).
24972553
Module::LookupInfo info(ConstString(label.lookup_name),
2498-
lldb::eFunctionNameTypeFull,
2554+
lldb::eFunctionNameTypeFull |
2555+
lldb::eFunctionNameTypeMethod,
24992556
lldb::eLanguageTypeUnknown);
25002557

25012558
m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) {
25022559
if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
25032560
return IterationAction::Continue;
25042561

2505-
// We don't check whether the specification DIE for this function
2506-
// corresponds to the declaration DIE because the declaration might be in
2507-
// a type-unit but the definition in the compile-unit (and it's
2508-
// specifcation would point to the declaration in the compile-unit). We
2509-
// rely on the mangled name within the module to be enough to find us the
2510-
// unique definition.
2562+
// TODO: this specification check doesn't work if declaration DIE was in a
2563+
// type-unit (we should only encode DIEs from .debug_info).
2564+
auto spec = entry.GetAttributeValueAsReferenceDIE(DW_AT_specification);
2565+
if (!spec)
2566+
return IterationAction::Continue;
2567+
2568+
if (spec != die)
2569+
return IterationAction::Continue;
2570+
2571+
// We're not picking a specific structor variant DIE, so we're done here.
2572+
if (label.discriminator.empty()) {
2573+
die = entry;
2574+
return IterationAction::Continue;
2575+
}
2576+
2577+
const char *mangled =
2578+
entry.GetMangledName(/*substitute_name_allowed=*/false);
2579+
if (!mangled)
2580+
return IterationAction::Continue;
2581+
2582+
llvm::ItaniumPartialDemangler D;
2583+
if (D.partialDemangle(mangled))
2584+
return IterationAction::Continue;
2585+
2586+
// TODO: account for constructor alias (only an issue on Linux)
2587+
if (D.getCtorOrDtorVariant() !=
2588+
GetItaniumCtorDtorVariant(label.discriminator).value_or(-1))
2589+
return IterationAction::Continue;
2590+
25112591
die = entry;
2592+
25122593
return IterationAction::Stop;
25132594
});
25142595

lldb/unittests/Expression/ExpressionTest.cpp

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,63 +23,68 @@ struct LabelTestCase {
2323

2424
static LabelTestCase g_label_test_cases[] = {
2525
// Failure modes
26-
{"bar:0x0:0x0:_Z3foov",
26+
{"bar:blah:0x0:0x0:_Z3foov",
2727
{},
2828
{"expected function call label prefix '$__lldb_func' but found 'bar' "
2929
"instead."}},
30-
{"$__lldb_func :0x0:0x0:_Z3foov",
30+
{"$__lldb_func :blah:0x0:0x0:_Z3foov",
3131
{},
3232
{"expected function call label prefix '$__lldb_func' but found "
3333
"'$__lldb_func ' instead."}},
34-
{"$__lldb_funcc:0x0:0x0:_Z3foov",
34+
{"$__lldb_funcc:blah:0x0:0x0:_Z3foov",
3535
{},
3636
{"expected function call label prefix '$__lldb_func' but found "
3737
"'$__lldb_funcc' instead."}},
3838
{"", {}, {"malformed function call label."}},
3939
{"foo", {}, {"malformed function call label."}},
4040
{"$__lldb_func", {}, {"malformed function call label."}},
4141
{"$__lldb_func:", {}, {"malformed function call label."}},
42-
{"$__lldb_func:0x0:0x0", {}, {"malformed function call label."}},
43-
{"$__lldb_func:abc:0x0:_Z3foov",
42+
{"$__lldb_func:blah", {}, {"malformed function call label."}},
43+
{"$__lldb_func:blah:0x0", {}, {"malformed function call label."}},
44+
{"$__lldb_func:111:0x0:0x0", {}, {"malformed function call label."}},
45+
{"$__lldb_func:111:abc:0x0:_Z3foov",
4446
{},
4547
{"failed to parse module ID from 'abc'."}},
46-
{"$__lldb_func:-1:0x0:_Z3foov",
48+
{"$__lldb_func:111:-1:0x0:_Z3foov",
4749
{},
4850
{"failed to parse module ID from '-1'."}},
49-
{"$__lldb_func:0x0invalid:0x0:_Z3foov",
51+
{"$__lldb_func:111:0x0invalid:0x0:_Z3foov",
5052
{},
5153
{"failed to parse module ID from '0x0invalid'."}},
52-
{"$__lldb_func:0x0 :0x0:_Z3foov",
54+
{"$__lldb_func:111:0x0 :0x0:_Z3foov",
5355
{},
5456
{"failed to parse module ID from '0x0 '."}},
55-
{"$__lldb_func:0x0:abc:_Z3foov",
57+
{"$__lldb_func:blah:0x0:abc:_Z3foov",
5658
{},
5759
{"failed to parse symbol ID from 'abc'."}},
58-
{"$__lldb_func:0x5:-1:_Z3foov",
60+
{"$__lldb_func:blah:0x5:-1:_Z3foov",
5961
{},
6062
{"failed to parse symbol ID from '-1'."}},
61-
{"$__lldb_func:0x5:0x0invalid:_Z3foov",
63+
{"$__lldb_func:blah:0x5:0x0invalid:_Z3foov",
6264
{},
6365
{"failed to parse symbol ID from '0x0invalid'."}},
64-
{"$__lldb_func:0x5:0x0 :_Z3foov",
66+
{"$__lldb_func:blah:0x5:0x0 :_Z3foov",
6567
{},
6668
{"failed to parse symbol ID from '0x0 '."}},
67-
{"$__lldb_func:0x0:0x0:_Z3foov",
69+
{"$__lldb_func:blah:0x0:0x0:_Z3foov",
6870
{
71+
/*.discriminator=*/"blah",
6972
/*.module_id=*/0x0,
7073
/*.symbol_id=*/0x0,
7174
/*.lookup_name=*/"_Z3foov",
7275
},
7376
{}},
74-
{"$__lldb_func:0x0:0x0:abc:def:::a",
77+
{"$__lldb_func::0x0:0x0:abc:def:::a",
7578
{
79+
/*.discriminator=*/"",
7680
/*.module_id=*/0x0,
7781
/*.symbol_id=*/0x0,
7882
/*.lookup_name=*/"abc:def:::a",
7983
},
8084
{}},
81-
{"$__lldb_func:0xd2:0xf0:$__lldb_func",
85+
{"$__lldb_func:0x45:0xd2:0xf0:$__lldb_func",
8286
{
87+
/*.discriminator=*/"0x45",
8388
/*.module_id=*/0xd2,
8489
/*.symbol_id=*/0xf0,
8590
/*.lookup_name=*/"$__lldb_func",
@@ -106,13 +111,15 @@ TEST_P(ExpressionTestFixture, FunctionCallLabel) {
106111
EXPECT_EQ(decoded_or_err->toString(), encoded);
107112
EXPECT_EQ(label_str, encoded);
108113

114+
EXPECT_EQ(decoded_or_err->discriminator, label.discriminator);
109115
EXPECT_EQ(decoded_or_err->module_id, label.module_id);
110116
EXPECT_EQ(decoded_or_err->symbol_id, label.symbol_id);
111117
EXPECT_EQ(decoded_or_err->lookup_name, label.lookup_name);
112118

113119
auto roundtrip_or_err = FunctionCallLabel::fromString(label_str);
114120
EXPECT_THAT_EXPECTED(roundtrip_or_err, llvm::Succeeded());
115121

122+
EXPECT_EQ(roundtrip_or_err->discriminator, label.discriminator);
116123
EXPECT_EQ(roundtrip_or_err->module_id, label.module_id);
117124
EXPECT_EQ(roundtrip_or_err->symbol_id, label.symbol_id);
118125
EXPECT_EQ(roundtrip_or_err->lookup_name, label.lookup_name);

0 commit comments

Comments
 (0)