-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[lldb] Recurse through DW_AT_signature when looking for attributes #107241
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,7 +50,8 @@ class ElaboratingDIEIterator | |
m_worklist.pop_back(); | ||
|
||
// And add back any items that elaborate it. | ||
for (dw_attr_t attr : {DW_AT_specification, DW_AT_abstract_origin}) { | ||
for (dw_attr_t attr : | ||
{DW_AT_specification, DW_AT_abstract_origin, DW_AT_specification}) { | ||
if (DWARFDIE d = die.GetReferencedDIE(attr)) | ||
if (m_seen.insert(die.GetDIE()).second) | ||
m_worklist.push_back(d); | ||
|
@@ -129,10 +130,10 @@ DWARFDIE | |
DWARFDIE::GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const { | ||
if (IsValid()) { | ||
DWARFUnit *cu = GetCU(); | ||
const bool check_specification_or_abstract_origin = true; | ||
const bool check_elaborating_dies = true; | ||
DWARFFormValue form_value; | ||
if (m_die->GetAttributeValue(cu, attr, form_value, nullptr, | ||
check_specification_or_abstract_origin)) | ||
check_elaborating_dies)) | ||
return form_value.Reference(); | ||
} | ||
return DWARFDIE(); | ||
|
@@ -377,11 +378,6 @@ static void GetDeclContextImpl(DWARFDIE die, | |
die = spec; | ||
continue; | ||
} | ||
// To find the name of a type in a type unit, we must follow the signature. | ||
if (DWARFDIE spec = die.GetReferencedDIE(DW_AT_signature)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you elaborate on why we don't need this anymore? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because die.GetName() will now find the correct name on its own. And (unlike with DW_AT_specification) the correct context can be reconstructed by following the parent chain in the original dwarf unit. For nested structs like
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ahh right, makes sense. So for |
||
die = spec; | ||
continue; | ||
} | ||
|
||
// Add this DIE's contribution at the end of the chain. | ||
auto push_ctx = [&](CompilerContextKind kind, llvm::StringRef name) { | ||
|
@@ -434,12 +430,6 @@ static void GetTypeLookupContextImpl(DWARFDIE die, | |
std::vector<CompilerContext> &context) { | ||
// Stop if we hit a cycle. | ||
while (die && seen.insert(die.GetID()).second) { | ||
// To find the name of a type in a type unit, we must follow the signature. | ||
if (DWARFDIE spec = die.GetReferencedDIE(DW_AT_signature)) { | ||
die = spec; | ||
continue; | ||
} | ||
|
||
// Add this DIE's contribution at the end of the chain. | ||
auto push_ctx = [&](CompilerContextKind kind, llvm::StringRef name) { | ||
context.push_back({kind, ConstString(name)}); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,44 +60,45 @@ class DWARFDebugInfoEntry { | |
return attrs; | ||
} | ||
|
||
dw_offset_t | ||
GetAttributeValue(const DWARFUnit *cu, const dw_attr_t attr, | ||
DWARFFormValue &formValue, | ||
dw_offset_t *end_attr_offset_ptr = nullptr, | ||
bool check_specification_or_abstract_origin = false) const; | ||
dw_offset_t GetAttributeValue(const DWARFUnit *cu, const dw_attr_t attr, | ||
DWARFFormValue &formValue, | ||
dw_offset_t *end_attr_offset_ptr = nullptr, | ||
bool check_elaborating_dies = false) const; | ||
|
||
const char *GetAttributeValueAsString( | ||
const DWARFUnit *cu, const dw_attr_t attr, const char *fail_value, | ||
bool check_specification_or_abstract_origin = false) const; | ||
const char * | ||
GetAttributeValueAsString(const DWARFUnit *cu, const dw_attr_t attr, | ||
const char *fail_value, | ||
bool check_elaborating_dies = false) const; | ||
|
||
uint64_t GetAttributeValueAsUnsigned( | ||
const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value, | ||
bool check_specification_or_abstract_origin = false) const; | ||
uint64_t | ||
GetAttributeValueAsUnsigned(const DWARFUnit *cu, const dw_attr_t attr, | ||
uint64_t fail_value, | ||
bool check_elaborating_dies = false) const; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Out of curiosity, when do we not want to recurse through the specifications/origin/signature? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Most of the time, I'd say. DW_AT_specification says "this DIE is an out of line definition of the function declared in ". It normally does not list the name of the function because the name is already given on the other die, but it'd perfectly reasonable for |
||
|
||
std::optional<uint64_t> GetAttributeValueAsOptionalUnsigned( | ||
const DWARFUnit *cu, const dw_attr_t attr, | ||
bool check_specification_or_abstract_origin = false) const; | ||
bool check_elaborating_dies = false) const; | ||
|
||
DWARFDIE GetAttributeValueAsReference( | ||
const DWARFUnit *cu, const dw_attr_t attr, | ||
bool check_specification_or_abstract_origin = false) const; | ||
DWARFDIE | ||
GetAttributeValueAsReference(const DWARFUnit *cu, const dw_attr_t attr, | ||
bool check_elaborating_dies = false) const; | ||
|
||
uint64_t GetAttributeValueAsAddress( | ||
const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value, | ||
bool check_specification_or_abstract_origin = false) const; | ||
uint64_t | ||
GetAttributeValueAsAddress(const DWARFUnit *cu, const dw_attr_t attr, | ||
uint64_t fail_value, | ||
bool check_elaborating_dies = false) const; | ||
|
||
dw_addr_t | ||
GetAttributeHighPC(const DWARFUnit *cu, dw_addr_t lo_pc, uint64_t fail_value, | ||
bool check_specification_or_abstract_origin = false) const; | ||
dw_addr_t GetAttributeHighPC(const DWARFUnit *cu, dw_addr_t lo_pc, | ||
uint64_t fail_value, | ||
bool check_elaborating_dies = false) const; | ||
|
||
bool GetAttributeAddressRange( | ||
const DWARFUnit *cu, dw_addr_t &lo_pc, dw_addr_t &hi_pc, | ||
uint64_t fail_value, | ||
bool check_specification_or_abstract_origin = false) const; | ||
bool GetAttributeAddressRange(const DWARFUnit *cu, dw_addr_t &lo_pc, | ||
dw_addr_t &hi_pc, uint64_t fail_value, | ||
bool check_elaborating_dies = false) const; | ||
|
||
DWARFRangeList GetAttributeAddressRanges( | ||
DWARFUnit *cu, bool check_hi_lo_pc, | ||
bool check_specification_or_abstract_origin = false) const; | ||
DWARFRangeList | ||
GetAttributeAddressRanges(DWARFUnit *cu, bool check_hi_lo_pc, | ||
bool check_elaborating_dies = false) const; | ||
|
||
const char *GetName(const DWARFUnit *cu) const; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// Test that we can correctly disambiguate a nested type (where the outer type | ||
// is in a type unit) from a non-nested type with the same basename. Failure to | ||
// do so can cause us to think a type is a member of itself, which caused | ||
// infinite recursion (crash) in the past. | ||
|
||
// REQUIRES: lld | ||
|
||
// RUN: %clang --target=x86_64-pc-linux -c %s -o %t-a.o -g -fdebug-types-section -flimit-debug-info -DFILE_A | ||
// RUN: %clang --target=x86_64-pc-linux -c %s -o %t-b.o -g -fdebug-types-section -flimit-debug-info -DFILE_B | ||
// RUN: ld.lld -z undefs %t-a.o %t-b.o -o %t | ||
// RUN: %lldb %t -o "target variable x" -o exit | FileCheck %s | ||
|
||
// CHECK: (lldb) target variable | ||
// CHECK-NEXT: (const X) x = { | ||
// CHECK-NEXT: NS::Outer::Struct = { | ||
// CHECK-NEXT: x = 42 | ||
// CHECK-NEXT: o = (x = 47) | ||
// CHECK-NEXT: y = 24 | ||
// CHECK-NEXT: } | ||
// CHECK-NEXT: } | ||
|
||
namespace NS { | ||
struct Struct { | ||
int x = 47; | ||
virtual void anchor(); | ||
}; | ||
} // namespace NS | ||
|
||
#ifdef FILE_A | ||
namespace NS { | ||
struct Outer { | ||
struct Struct { | ||
int x = 42; | ||
NS::Struct o; | ||
int y = 24; | ||
}; | ||
}; | ||
} // namespace NS | ||
|
||
struct X : NS::Outer::Struct {}; | ||
extern constexpr X x = {}; | ||
#endif | ||
#ifdef FILE_B | ||
void NS::Struct::anchor() {} | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you mean for one of these to be
DW_AT_signature
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just from cursory reading it seems like
ElaboratingDIEIterator
is only useful for method DIEs currently? Which might be why no tests were affected here?If you do need it as part of this patch then there's a couple of comments to fix up in
ElaboratingDIEIterator
that specifically talk aboutDW_AT_specification
/DW_AT_abstract_origin
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I meant that to be DW_AT_signature. Oops.
This isn't really needed for this patch, but I thought it makes sense to add it for symmetry. The class is only currently used in
DWARFDIE::IsMethod
which does not make sense for types, but I could imagine this class being used elsewhere as well.