Skip to content

Commit 925b220

Browse files
authored
[lldb] Recurse through DW_AT_signature when looking for attributes (#107241)
This allows e.g. DWARFDIE::GetName() to return the name of the type when looking at its declaration (which contains only DW_AT_declaration+DW_AT_signature). This is similar to how we recurse through DW_AT_specification when looking for a function name. Llvm dwarf parser has obtained the same functionality through #99495. This fixes a bug where we would confuse a type like NS::Outer::Struct with NS::Struct (because NS::Outer (and its name) was in a type unit).
1 parent fffdd9e commit 925b220

File tree

4 files changed

+113
-91
lines changed

4 files changed

+113
-91
lines changed

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

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ using namespace lldb_private::plugin::dwarf;
2525
namespace {
2626

2727
/// Iterate through all DIEs elaborating (i.e. reachable by a chain of
28-
/// DW_AT_specification and DW_AT_abstract_origin attributes) a given DIE. For
29-
/// convenience, the starting die is included in the sequence as the first
30-
/// item.
28+
/// DW_AT_specification, DW_AT_abstract_origin and/or DW_AT_signature
29+
/// attributes) a given DIE. For convenience, the starting die is included in
30+
/// the sequence as the first item.
3131
class ElaboratingDIEIterator
3232
: public llvm::iterator_facade_base<
3333
ElaboratingDIEIterator, std::input_iterator_tag, DWARFDIE,
@@ -50,7 +50,8 @@ class ElaboratingDIEIterator
5050
m_worklist.pop_back();
5151

5252
// And add back any items that elaborate it.
53-
for (dw_attr_t attr : {DW_AT_specification, DW_AT_abstract_origin}) {
53+
for (dw_attr_t attr :
54+
{DW_AT_specification, DW_AT_abstract_origin, DW_AT_signature}) {
5455
if (DWARFDIE d = die.GetReferencedDIE(attr))
5556
if (m_seen.insert(die.GetDIE()).second)
5657
m_worklist.push_back(d);
@@ -129,10 +130,10 @@ DWARFDIE
129130
DWARFDIE::GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const {
130131
if (IsValid()) {
131132
DWARFUnit *cu = GetCU();
132-
const bool check_specification_or_abstract_origin = true;
133+
const bool check_elaborating_dies = true;
133134
DWARFFormValue form_value;
134135
if (m_die->GetAttributeValue(cu, attr, form_value, nullptr,
135-
check_specification_or_abstract_origin))
136+
check_elaborating_dies))
136137
return form_value.Reference();
137138
}
138139
return DWARFDIE();
@@ -377,11 +378,6 @@ static void GetDeclContextImpl(DWARFDIE die,
377378
die = spec;
378379
continue;
379380
}
380-
// To find the name of a type in a type unit, we must follow the signature.
381-
if (DWARFDIE spec = die.GetReferencedDIE(DW_AT_signature)) {
382-
die = spec;
383-
continue;
384-
}
385381

386382
// Add this DIE's contribution at the end of the chain.
387383
auto push_ctx = [&](CompilerContextKind kind, llvm::StringRef name) {
@@ -434,12 +430,6 @@ static void GetTypeLookupContextImpl(DWARFDIE die,
434430
std::vector<CompilerContext> &context) {
435431
// Stop if we hit a cycle.
436432
while (die && seen.insert(die.GetID()).second) {
437-
// To find the name of a type in a type unit, we must follow the signature.
438-
if (DWARFDIE spec = die.GetReferencedDIE(DW_AT_signature)) {
439-
die = spec;
440-
continue;
441-
}
442-
443433
// Add this DIE's contribution at the end of the chain.
444434
auto push_ctx = [&](CompilerContextKind kind, llvm::StringRef name) {
445435
context.push_back({kind, ConstString(name)});

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

Lines changed: 32 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -355,8 +355,7 @@ void DWARFDebugInfoEntry::GetAttributes(DWARFUnit *cu,
355355
// would be a compile unit header).
356356
dw_offset_t DWARFDebugInfoEntry::GetAttributeValue(
357357
const DWARFUnit *cu, const dw_attr_t attr, DWARFFormValue &form_value,
358-
dw_offset_t *end_attr_offset_ptr,
359-
bool check_specification_or_abstract_origin) const {
358+
dw_offset_t *end_attr_offset_ptr, bool check_elaborating_dies) const {
360359
if (const auto *abbrevDecl = GetAbbreviationDeclarationPtr(cu)) {
361360
std::optional<uint32_t> attr_idx = abbrevDecl->findAttributeIndex(attr);
362361

@@ -380,25 +379,18 @@ dw_offset_t DWARFDebugInfoEntry::GetAttributeValue(
380379
}
381380
}
382381

383-
if (check_specification_or_abstract_origin) {
384-
if (GetAttributeValue(cu, DW_AT_specification, form_value)) {
382+
if (check_elaborating_dies) {
383+
for (dw_attr_t elaborating_attr :
384+
{DW_AT_specification, DW_AT_abstract_origin, DW_AT_signature}) {
385+
if (!GetAttributeValue(cu, elaborating_attr, form_value))
386+
continue;
385387
DWARFDIE die = form_value.Reference();
386-
if (die) {
387-
dw_offset_t die_offset = die.GetDIE()->GetAttributeValue(
388-
die.GetCU(), attr, form_value, end_attr_offset_ptr, false);
389-
if (die_offset)
390-
return die_offset;
391-
}
392-
}
393-
394-
if (GetAttributeValue(cu, DW_AT_abstract_origin, form_value)) {
395-
DWARFDIE die = form_value.Reference();
396-
if (die) {
397-
dw_offset_t die_offset = die.GetDIE()->GetAttributeValue(
398-
die.GetCU(), attr, form_value, end_attr_offset_ptr, false);
399-
if (die_offset)
400-
return die_offset;
401-
}
388+
if (!die)
389+
continue;
390+
dw_offset_t die_offset = die.GetDIE()->GetAttributeValue(
391+
die.GetCU(), attr, form_value, end_attr_offset_ptr, false);
392+
if (die_offset)
393+
return die_offset;
402394
}
403395
}
404396
return 0;
@@ -412,10 +404,9 @@ dw_offset_t DWARFDebugInfoEntry::GetAttributeValue(
412404
// doesn't change.
413405
const char *DWARFDebugInfoEntry::GetAttributeValueAsString(
414406
const DWARFUnit *cu, const dw_attr_t attr, const char *fail_value,
415-
bool check_specification_or_abstract_origin) const {
407+
bool check_elaborating_dies) const {
416408
DWARFFormValue form_value;
417-
if (GetAttributeValue(cu, attr, form_value, nullptr,
418-
check_specification_or_abstract_origin))
409+
if (GetAttributeValue(cu, attr, form_value, nullptr, check_elaborating_dies))
419410
return form_value.AsCString();
420411
return fail_value;
421412
}
@@ -425,21 +416,19 @@ const char *DWARFDebugInfoEntry::GetAttributeValueAsString(
425416
// Get the value of an attribute as unsigned and return it.
426417
uint64_t DWARFDebugInfoEntry::GetAttributeValueAsUnsigned(
427418
const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value,
428-
bool check_specification_or_abstract_origin) const {
419+
bool check_elaborating_dies) const {
429420
DWARFFormValue form_value;
430-
if (GetAttributeValue(cu, attr, form_value, nullptr,
431-
check_specification_or_abstract_origin))
421+
if (GetAttributeValue(cu, attr, form_value, nullptr, check_elaborating_dies))
432422
return form_value.Unsigned();
433423
return fail_value;
434424
}
435425

436426
std::optional<uint64_t>
437427
DWARFDebugInfoEntry::GetAttributeValueAsOptionalUnsigned(
438428
const DWARFUnit *cu, const dw_attr_t attr,
439-
bool check_specification_or_abstract_origin) const {
429+
bool check_elaborating_dies) const {
440430
DWARFFormValue form_value;
441-
if (GetAttributeValue(cu, attr, form_value, nullptr,
442-
check_specification_or_abstract_origin))
431+
if (GetAttributeValue(cu, attr, form_value, nullptr, check_elaborating_dies))
443432
return form_value.Unsigned();
444433
return std::nullopt;
445434
}
@@ -450,20 +439,18 @@ DWARFDebugInfoEntry::GetAttributeValueAsOptionalUnsigned(
450439
// relative offsets as needed.
451440
DWARFDIE DWARFDebugInfoEntry::GetAttributeValueAsReference(
452441
const DWARFUnit *cu, const dw_attr_t attr,
453-
bool check_specification_or_abstract_origin) const {
442+
bool check_elaborating_dies) const {
454443
DWARFFormValue form_value;
455-
if (GetAttributeValue(cu, attr, form_value, nullptr,
456-
check_specification_or_abstract_origin))
444+
if (GetAttributeValue(cu, attr, form_value, nullptr, check_elaborating_dies))
457445
return form_value.Reference();
458446
return {};
459447
}
460448

461449
uint64_t DWARFDebugInfoEntry::GetAttributeValueAsAddress(
462450
const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value,
463-
bool check_specification_or_abstract_origin) const {
451+
bool check_elaborating_dies) const {
464452
DWARFFormValue form_value;
465-
if (GetAttributeValue(cu, attr, form_value, nullptr,
466-
check_specification_or_abstract_origin))
453+
if (GetAttributeValue(cu, attr, form_value, nullptr, check_elaborating_dies))
467454
return form_value.Address();
468455
return fail_value;
469456
}
@@ -474,12 +461,13 @@ uint64_t DWARFDebugInfoEntry::GetAttributeValueAsAddress(
474461
// pc>.
475462
//
476463
// Returns the hi_pc or fail_value.
477-
dw_addr_t DWARFDebugInfoEntry::GetAttributeHighPC(
478-
const DWARFUnit *cu, dw_addr_t lo_pc, uint64_t fail_value,
479-
bool check_specification_or_abstract_origin) const {
464+
dw_addr_t
465+
DWARFDebugInfoEntry::GetAttributeHighPC(const DWARFUnit *cu, dw_addr_t lo_pc,
466+
uint64_t fail_value,
467+
bool check_elaborating_dies) const {
480468
DWARFFormValue form_value;
481469
if (GetAttributeValue(cu, DW_AT_high_pc, form_value, nullptr,
482-
check_specification_or_abstract_origin)) {
470+
check_elaborating_dies)) {
483471
dw_form_t form = form_value.Form();
484472
if (form == DW_FORM_addr || form == DW_FORM_addrx ||
485473
form == DW_FORM_GNU_addr_index)
@@ -499,12 +487,11 @@ dw_addr_t DWARFDebugInfoEntry::GetAttributeHighPC(
499487
// Returns true or sets lo_pc and hi_pc to fail_value.
500488
bool DWARFDebugInfoEntry::GetAttributeAddressRange(
501489
const DWARFUnit *cu, dw_addr_t &lo_pc, dw_addr_t &hi_pc,
502-
uint64_t fail_value, bool check_specification_or_abstract_origin) const {
490+
uint64_t fail_value, bool check_elaborating_dies) const {
503491
lo_pc = GetAttributeValueAsAddress(cu, DW_AT_low_pc, fail_value,
504-
check_specification_or_abstract_origin);
492+
check_elaborating_dies);
505493
if (lo_pc != fail_value) {
506-
hi_pc = GetAttributeHighPC(cu, lo_pc, fail_value,
507-
check_specification_or_abstract_origin);
494+
hi_pc = GetAttributeHighPC(cu, lo_pc, fail_value, check_elaborating_dies);
508495
if (hi_pc != fail_value)
509496
return true;
510497
}
@@ -514,8 +501,7 @@ bool DWARFDebugInfoEntry::GetAttributeAddressRange(
514501
}
515502

516503
DWARFRangeList DWARFDebugInfoEntry::GetAttributeAddressRanges(
517-
DWARFUnit *cu, bool check_hi_lo_pc,
518-
bool check_specification_or_abstract_origin) const {
504+
DWARFUnit *cu, bool check_hi_lo_pc, bool check_elaborating_dies) const {
519505

520506
DWARFFormValue form_value;
521507
if (GetAttributeValue(cu, DW_AT_ranges, form_value))
@@ -526,7 +512,7 @@ DWARFRangeList DWARFDebugInfoEntry::GetAttributeAddressRanges(
526512
dw_addr_t lo_pc = LLDB_INVALID_ADDRESS;
527513
dw_addr_t hi_pc = LLDB_INVALID_ADDRESS;
528514
if (GetAttributeAddressRange(cu, lo_pc, hi_pc, LLDB_INVALID_ADDRESS,
529-
check_specification_or_abstract_origin)) {
515+
check_elaborating_dies)) {
530516
if (lo_pc < hi_pc)
531517
ranges.Append(DWARFRangeList::Entry(lo_pc, hi_pc - lo_pc));
532518
}

lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -60,44 +60,45 @@ class DWARFDebugInfoEntry {
6060
return attrs;
6161
}
6262

63-
dw_offset_t
64-
GetAttributeValue(const DWARFUnit *cu, const dw_attr_t attr,
65-
DWARFFormValue &formValue,
66-
dw_offset_t *end_attr_offset_ptr = nullptr,
67-
bool check_specification_or_abstract_origin = false) const;
63+
dw_offset_t GetAttributeValue(const DWARFUnit *cu, const dw_attr_t attr,
64+
DWARFFormValue &formValue,
65+
dw_offset_t *end_attr_offset_ptr = nullptr,
66+
bool check_elaborating_dies = false) const;
6867

69-
const char *GetAttributeValueAsString(
70-
const DWARFUnit *cu, const dw_attr_t attr, const char *fail_value,
71-
bool check_specification_or_abstract_origin = false) const;
68+
const char *
69+
GetAttributeValueAsString(const DWARFUnit *cu, const dw_attr_t attr,
70+
const char *fail_value,
71+
bool check_elaborating_dies = false) const;
7272

73-
uint64_t GetAttributeValueAsUnsigned(
74-
const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value,
75-
bool check_specification_or_abstract_origin = false) const;
73+
uint64_t
74+
GetAttributeValueAsUnsigned(const DWARFUnit *cu, const dw_attr_t attr,
75+
uint64_t fail_value,
76+
bool check_elaborating_dies = false) const;
7677

7778
std::optional<uint64_t> GetAttributeValueAsOptionalUnsigned(
7879
const DWARFUnit *cu, const dw_attr_t attr,
79-
bool check_specification_or_abstract_origin = false) const;
80+
bool check_elaborating_dies = false) const;
8081

81-
DWARFDIE GetAttributeValueAsReference(
82-
const DWARFUnit *cu, const dw_attr_t attr,
83-
bool check_specification_or_abstract_origin = false) const;
82+
DWARFDIE
83+
GetAttributeValueAsReference(const DWARFUnit *cu, const dw_attr_t attr,
84+
bool check_elaborating_dies = false) const;
8485

85-
uint64_t GetAttributeValueAsAddress(
86-
const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value,
87-
bool check_specification_or_abstract_origin = false) const;
86+
uint64_t
87+
GetAttributeValueAsAddress(const DWARFUnit *cu, const dw_attr_t attr,
88+
uint64_t fail_value,
89+
bool check_elaborating_dies = false) const;
8890

89-
dw_addr_t
90-
GetAttributeHighPC(const DWARFUnit *cu, dw_addr_t lo_pc, uint64_t fail_value,
91-
bool check_specification_or_abstract_origin = false) const;
91+
dw_addr_t GetAttributeHighPC(const DWARFUnit *cu, dw_addr_t lo_pc,
92+
uint64_t fail_value,
93+
bool check_elaborating_dies = false) const;
9294

93-
bool GetAttributeAddressRange(
94-
const DWARFUnit *cu, dw_addr_t &lo_pc, dw_addr_t &hi_pc,
95-
uint64_t fail_value,
96-
bool check_specification_or_abstract_origin = false) const;
95+
bool GetAttributeAddressRange(const DWARFUnit *cu, dw_addr_t &lo_pc,
96+
dw_addr_t &hi_pc, uint64_t fail_value,
97+
bool check_elaborating_dies = false) const;
9798

98-
DWARFRangeList GetAttributeAddressRanges(
99-
DWARFUnit *cu, bool check_hi_lo_pc,
100-
bool check_specification_or_abstract_origin = false) const;
99+
DWARFRangeList
100+
GetAttributeAddressRanges(DWARFUnit *cu, bool check_hi_lo_pc,
101+
bool check_elaborating_dies = false) const;
101102

102103
const char *GetName(const DWARFUnit *cu) const;
103104

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Test that we can correctly disambiguate a nested type (where the outer type
2+
// is in a type unit) from a non-nested type with the same basename. Failure to
3+
// do so can cause us to think a type is a member of itself, which caused
4+
// infinite recursion (crash) in the past.
5+
6+
// REQUIRES: lld
7+
8+
// RUN: %clang --target=x86_64-pc-linux -c %s -o %t-a.o -g -fdebug-types-section -flimit-debug-info -DFILE_A
9+
// RUN: %clang --target=x86_64-pc-linux -c %s -o %t-b.o -g -fdebug-types-section -flimit-debug-info -DFILE_B
10+
// RUN: ld.lld -z undefs %t-a.o %t-b.o -o %t
11+
// RUN: %lldb %t -o "target variable x" -o exit | FileCheck %s
12+
13+
// CHECK: (lldb) target variable
14+
// CHECK-NEXT: (const X) x = {
15+
// CHECK-NEXT: NS::Outer::Struct = {
16+
// CHECK-NEXT: x = 42
17+
// CHECK-NEXT: o = (x = 47)
18+
// CHECK-NEXT: y = 24
19+
// CHECK-NEXT: }
20+
// CHECK-NEXT: }
21+
22+
namespace NS {
23+
struct Struct {
24+
int x = 47;
25+
virtual void anchor();
26+
};
27+
} // namespace NS
28+
29+
#ifdef FILE_A
30+
namespace NS {
31+
struct Outer {
32+
struct Struct {
33+
int x = 42;
34+
NS::Struct o;
35+
int y = 24;
36+
};
37+
};
38+
} // namespace NS
39+
40+
struct X : NS::Outer::Struct {};
41+
extern constexpr X x = {};
42+
#endif
43+
#ifdef FILE_B
44+
void NS::Struct::anchor() {}
45+
#endif

0 commit comments

Comments
 (0)