Skip to content

Commit 4684507

Browse files
[lldb][DWARFUnit] Implement PeekDIEName query (#78486)
This allows us to query the AT_Name of a DIE without parsing the entire CU. Part of the ongoing effort to support IDX_Parent in accelerator tables [1]. [1]: https://discourse.llvm.org/t/rfc-improve-dwarf-5-debug-names-type-lookup-parsing-speed/74151/44
1 parent 904cf66 commit 4684507

File tree

7 files changed

+143
-10
lines changed

7 files changed

+143
-10
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,9 @@ DWARFDebugInfo::GetDIE(const DIERef &die_ref) {
191191
return cu->GetNonSkeletonUnit().GetDIE(die_ref.die_offset());
192192
return DWARFDIE(); // Not found
193193
}
194+
195+
llvm::StringRef DWARFDebugInfo::PeekDIEName(const DIERef &die_ref) {
196+
if (DWARFUnit *cu = GetUnit(die_ref))
197+
return cu->GetNonSkeletonUnit().PeekDIEName(die_ref.die_offset());
198+
return llvm::StringRef();
199+
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ class DWARFDebugInfo {
4343
bool ContainsTypeUnits();
4444
DWARFDIE GetDIE(const DIERef &die_ref);
4545

46+
/// Returns the AT_Name of this DIE, if it exists, without parsing the entire
47+
/// compile unit. An empty is string is returned upon error or if the
48+
/// attribute is not present.
49+
llvm::StringRef PeekDIEName(const DIERef &die_ref);
50+
4651
enum {
4752
eDumpFlag_Verbose = (1 << 0), // Verbose dumping
4853
eDumpFlag_ShowForm = (1 << 1), // Show the DW_form type

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

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818
#include "DWARFFormValue.h"
1919
#include "DWARFUnit.h"
2020

21-
class DWARFUnit;
22-
2321
using namespace lldb_private;
2422
using namespace lldb_private::dwarf;
2523
using namespace lldb_private::plugin::dwarf;
@@ -502,7 +500,8 @@ dw_addr_t DWARFFormValue::Address() const {
502500
&offset, index_size);
503501
}
504502

505-
DWARFDIE DWARFFormValue::Reference() const {
503+
std::pair<DWARFUnit *, uint64_t>
504+
DWARFFormValue::ReferencedUnitAndOffset() const {
506505
uint64_t value = m_value.value.uval;
507506
switch (m_form) {
508507
case DW_FORM_ref1:
@@ -516,9 +515,9 @@ DWARFDIE DWARFFormValue::Reference() const {
516515
if (!m_unit->ContainsDIEOffset(value)) {
517516
m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
518517
"DW_FORM_ref* DIE reference {0:x16} is outside of its CU", value);
519-
return {};
518+
return {nullptr, 0};
520519
}
521-
return const_cast<DWARFUnit *>(m_unit)->GetDIE(value);
520+
return {const_cast<DWARFUnit *>(m_unit), value};
522521

523522
case DW_FORM_ref_addr: {
524523
DWARFUnit *ref_cu =
@@ -527,24 +526,29 @@ DWARFDIE DWARFFormValue::Reference() const {
527526
if (!ref_cu) {
528527
m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
529528
"DW_FORM_ref_addr DIE reference {0:x16} has no matching CU", value);
530-
return {};
529+
return {nullptr, 0};
531530
}
532-
return ref_cu->GetDIE(value);
531+
return {ref_cu, value};
533532
}
534533

535534
case DW_FORM_ref_sig8: {
536535
DWARFTypeUnit *tu =
537536
m_unit->GetSymbolFileDWARF().DebugInfo().GetTypeUnitForHash(value);
538537
if (!tu)
539-
return {};
540-
return tu->GetDIE(tu->GetTypeOffset());
538+
return {nullptr, 0};
539+
return {tu, tu->GetTypeOffset()};
541540
}
542541

543542
default:
544-
return {};
543+
return {nullptr, 0};
545544
}
546545
}
547546

547+
DWARFDIE DWARFFormValue::Reference() const {
548+
auto [unit, offset] = ReferencedUnitAndOffset();
549+
return unit ? unit->GetDIE(offset) : DWARFDIE();
550+
}
551+
548552
uint64_t DWARFFormValue::Reference(dw_offset_t base_offset) const {
549553
uint64_t value = m_value.value.uval;
550554
switch (m_form) {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ class DWARFFormValue {
6060
const DWARFUnit *u);
6161
std::optional<uint8_t> GetFixedSize() const;
6262
DWARFDIE Reference() const;
63+
64+
/// If this is a reference to another DIE, return the corresponding DWARFUnit
65+
/// and DIE offset such that Unit->GetDIE(offset) produces the desired DIE.
66+
/// Otherwise, a nullptr and unspecified offset are returned.
67+
std::pair<DWARFUnit *, uint64_t> ReferencedUnitAndOffset() const;
68+
6369
uint64_t Reference(dw_offset_t offset) const;
6470
bool Boolean() const { return m_value.value.uval != 0; }
6571
uint64_t Unsigned() const { return m_value.value.uval; }

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,30 @@ DWARFUnit::GetDIE(dw_offset_t die_offset) {
663663
return DWARFDIE(); // Not found
664664
}
665665

666+
llvm::StringRef DWARFUnit::PeekDIEName(dw_offset_t die_offset) {
667+
DWARFDebugInfoEntry die;
668+
if (!die.Extract(GetData(), this, &die_offset))
669+
return llvm::StringRef();
670+
671+
// Does die contain a DW_AT_Name?
672+
if (const char *name =
673+
die.GetAttributeValueAsString(this, DW_AT_name, nullptr))
674+
return name;
675+
676+
// Does its DW_AT_specification or DW_AT_abstract_origin contain an AT_Name?
677+
for (auto attr : {DW_AT_specification, DW_AT_abstract_origin}) {
678+
DWARFFormValue form_value;
679+
if (!die.GetAttributeValue(this, attr, form_value))
680+
continue;
681+
auto [unit, offset] = form_value.ReferencedUnitAndOffset();
682+
if (unit)
683+
if (auto name = unit->PeekDIEName(offset); !name.empty())
684+
return name;
685+
}
686+
687+
return llvm::StringRef();
688+
}
689+
666690
DWARFUnit &DWARFUnit::GetNonSkeletonUnit() {
667691
ExtractUnitDIEIfNeeded();
668692
if (m_dwo)

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,11 @@ class DWARFUnit : public UserID {
187187

188188
DWARFDIE GetDIE(dw_offset_t die_offset);
189189

190+
/// Returns the AT_Name of the DIE at `die_offset`, if it exists, without
191+
/// parsing the entire compile unit. An empty is string is returned upon
192+
/// error or if the attribute is not present.
193+
llvm::StringRef PeekDIEName(dw_offset_t die_offset);
194+
190195
DWARFUnit &GetNonSkeletonUnit();
191196

192197
static uint8_t GetAddressByteSize(const DWARFUnit *cu);

lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp

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

99
#include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
10+
#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
1011
#include "TestingSupport/Symbol/YAMLModuleTester.h"
1112
#include "llvm/ADT/STLExtras.h"
1213
#include "gmock/gmock.h"
@@ -104,3 +105,85 @@ TEST(DWARFDIETest, ChildIteration) {
104105
DWARFDIE no_children_die(unit, die_child0);
105106
EXPECT_TRUE(no_children_die.children().empty());
106107
}
108+
109+
TEST(DWARFDIETest, PeekName) {
110+
const char *yamldata = R"(
111+
--- !ELF
112+
FileHeader:
113+
Class: ELFCLASS64
114+
Data: ELFDATA2LSB
115+
Type: ET_EXEC
116+
Machine: EM_386
117+
DWARF:
118+
debug_str:
119+
- 'NameType1'
120+
- 'NameType2'
121+
debug_abbrev:
122+
- Table:
123+
- Code: 0x00000001
124+
Tag: DW_TAG_compile_unit
125+
Children: DW_CHILDREN_yes
126+
Attributes:
127+
- Attribute: DW_AT_language
128+
Form: DW_FORM_data2
129+
- Code: 0x00000002
130+
Tag: DW_TAG_base_type
131+
Children: DW_CHILDREN_no
132+
Attributes:
133+
- Attribute: DW_AT_name
134+
Form: DW_FORM_strp
135+
- Code: 0x00000003
136+
Tag: DW_TAG_base_type
137+
Children: DW_CHILDREN_no
138+
Attributes:
139+
- Attribute: DW_AT_abstract_origin
140+
Form: DW_FORM_ref1
141+
- Code: 0x00000004
142+
Tag: DW_TAG_base_type
143+
Children: DW_CHILDREN_no
144+
Attributes:
145+
- Attribute: DW_AT_specification
146+
Form: DW_FORM_ref1
147+
debug_info:
148+
- Version: 4
149+
AddrSize: 8
150+
Entries:
151+
- AbbrCode: 0x00000001
152+
Values:
153+
- Value: 0x000000000000000C
154+
- AbbrCode: 0x00000002
155+
Values:
156+
- Value: 0x0000000000000000 # Name = NameType1
157+
- AbbrCode: 0x00000002
158+
Values:
159+
- Value: 0x000000000000000a # Name = NameType2
160+
- AbbrCode: 0x00000003
161+
Values:
162+
- Value: 0x000000000000000e # Ref abstract origin to NameType1 DIE.
163+
- AbbrCode: 0x00000004
164+
Values:
165+
- Value: 0x0000000000000013 # Ref specification to NameType2 DIE.
166+
- AbbrCode: 0x00000000
167+
)";
168+
169+
YAMLModuleTester t(yamldata);
170+
auto *symbol_file =
171+
llvm::cast<SymbolFileDWARF>(t.GetModule()->GetSymbolFile());
172+
auto &debug_info = symbol_file->DebugInfo();
173+
174+
DIERef first_die(std::nullopt, DIERef::Section::DebugInfo,
175+
11 /*FirstDIEOffset*/);
176+
EXPECT_EQ(debug_info.PeekDIEName(first_die), "");
177+
178+
DIERef second_die(std::nullopt, DIERef::Section::DebugInfo, 14);
179+
EXPECT_EQ(debug_info.PeekDIEName(second_die), "NameType1");
180+
181+
DIERef third_die(std::nullopt, DIERef::Section::DebugInfo, 19);
182+
EXPECT_EQ(debug_info.PeekDIEName(third_die), "NameType2");
183+
184+
DIERef fourth_die(std::nullopt, DIERef::Section::DebugInfo, 24);
185+
EXPECT_EQ(debug_info.PeekDIEName(fourth_die), "NameType1");
186+
187+
DIERef fifth_die(std::nullopt, DIERef::Section::DebugInfo, 26);
188+
EXPECT_EQ(debug_info.PeekDIEName(fifth_die), "NameType2");
189+
}

0 commit comments

Comments
 (0)