Skip to content

[lldb][DWARFUnit] Implement PeekDIEName query #78486

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

Merged
merged 5 commits into from
Jan 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,9 @@ DWARFDebugInfo::GetDIE(const DIERef &die_ref) {
return cu->GetNonSkeletonUnit().GetDIE(die_ref.die_offset());
return DWARFDIE(); // Not found
}

llvm::StringRef DWARFDebugInfo::PeekDIEName(const DIERef &die_ref) {
if (DWARFUnit *cu = GetUnit(die_ref))
return cu->GetNonSkeletonUnit().PeekDIEName(die_ref.die_offset());
return llvm::StringRef();
}
5 changes: 5 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ class DWARFDebugInfo {
bool ContainsTypeUnits();
DWARFDIE GetDIE(const DIERef &die_ref);

/// Returns the AT_Name of this DIE, if it exists, without parsing the entire
/// compile unit. An empty is string is returned upon error or if the
/// attribute is not present.
llvm::StringRef PeekDIEName(const DIERef &die_ref);

enum {
eDumpFlag_Verbose = (1 << 0), // Verbose dumping
eDumpFlag_ShowForm = (1 << 1), // Show the DW_form type
Expand Down
24 changes: 14 additions & 10 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
#include "DWARFFormValue.h"
#include "DWARFUnit.h"

class DWARFUnit;

using namespace lldb_private;
using namespace lldb_private::dwarf;
using namespace lldb_private::plugin::dwarf;
Expand Down Expand Up @@ -502,7 +500,8 @@ dw_addr_t DWARFFormValue::Address() const {
&offset, index_size);
}

DWARFDIE DWARFFormValue::Reference() const {
std::pair<DWARFUnit *, uint64_t>
DWARFFormValue::ReferencedUnitAndOffset() const {
uint64_t value = m_value.value.uval;
switch (m_form) {
case DW_FORM_ref1:
Expand All @@ -516,9 +515,9 @@ DWARFDIE DWARFFormValue::Reference() const {
if (!m_unit->ContainsDIEOffset(value)) {
m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
"DW_FORM_ref* DIE reference {0:x16} is outside of its CU", value);
return {};
return {nullptr, 0};
}
return const_cast<DWARFUnit *>(m_unit)->GetDIE(value);
return {const_cast<DWARFUnit *>(m_unit), value};

case DW_FORM_ref_addr: {
DWARFUnit *ref_cu =
Expand All @@ -527,24 +526,29 @@ DWARFDIE DWARFFormValue::Reference() const {
if (!ref_cu) {
m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
"DW_FORM_ref_addr DIE reference {0:x16} has no matching CU", value);
return {};
return {nullptr, 0};
}
return ref_cu->GetDIE(value);
return {ref_cu, value};
}

case DW_FORM_ref_sig8: {
DWARFTypeUnit *tu =
m_unit->GetSymbolFileDWARF().DebugInfo().GetTypeUnitForHash(value);
if (!tu)
return {};
return tu->GetDIE(tu->GetTypeOffset());
return {nullptr, 0};
return {tu, tu->GetTypeOffset()};
}

default:
return {};
return {nullptr, 0};
}
}

DWARFDIE DWARFFormValue::Reference() const {
auto [unit, offset] = ReferencedUnitAndOffset();
return unit ? unit->GetDIE(offset) : DWARFDIE();
}

uint64_t DWARFFormValue::Reference(dw_offset_t base_offset) const {
uint64_t value = m_value.value.uval;
switch (m_form) {
Expand Down
6 changes: 6 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ class DWARFFormValue {
const DWARFUnit *u);
std::optional<uint8_t> GetFixedSize() const;
DWARFDIE Reference() const;

/// If this is a reference to another DIE, return the corresponding DWARFUnit
/// and DIE offset such that Unit->GetDIE(offset) produces the desired DIE.
/// Otherwise, a nullptr and unspecified offset are returned.
std::pair<DWARFUnit *, uint64_t> ReferencedUnitAndOffset() const;

uint64_t Reference(dw_offset_t offset) const;
bool Boolean() const { return m_value.value.uval != 0; }
uint64_t Unsigned() const { return m_value.value.uval; }
Expand Down
24 changes: 24 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,30 @@ DWARFUnit::GetDIE(dw_offset_t die_offset) {
return DWARFDIE(); // Not found
}

llvm::StringRef DWARFUnit::PeekDIEName(dw_offset_t die_offset) {
DWARFDebugInfoEntry die;
if (!die.Extract(GetData(), this, &die_offset))
return llvm::StringRef();

// Does die contain a DW_AT_Name?
if (const char *name =
die.GetAttributeValueAsString(this, DW_AT_name, nullptr))
return name;

// Does its DW_AT_specification or DW_AT_abstract_origin contain an AT_Name?
for (auto attr : {DW_AT_specification, DW_AT_abstract_origin}) {
DWARFFormValue form_value;
if (!die.GetAttributeValue(this, attr, form_value))
continue;
auto [unit, offset] = form_value.ReferencedUnitAndOffset();
if (unit)
if (auto name = unit->PeekDIEName(offset); !name.empty())
return name;
}

return llvm::StringRef();
}

DWARFUnit &DWARFUnit::GetNonSkeletonUnit() {
ExtractUnitDIEIfNeeded();
if (m_dwo)
Expand Down
5 changes: 5 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ class DWARFUnit : public UserID {

DWARFDIE GetDIE(dw_offset_t die_offset);

/// Returns the AT_Name of the DIE at `die_offset`, if it exists, without
/// parsing the entire compile unit. An empty is string is returned upon
/// error or if the attribute is not present.
llvm::StringRef PeekDIEName(dw_offset_t die_offset);

DWARFUnit &GetNonSkeletonUnit();

static uint8_t GetAddressByteSize(const DWARFUnit *cu);
Expand Down
83 changes: 83 additions & 0 deletions lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
#include "TestingSupport/Symbol/YAMLModuleTester.h"
#include "llvm/ADT/STLExtras.h"
#include "gmock/gmock.h"
Expand Down Expand Up @@ -104,3 +105,85 @@ TEST(DWARFDIETest, ChildIteration) {
DWARFDIE no_children_die(unit, die_child0);
EXPECT_TRUE(no_children_die.children().empty());
}

TEST(DWARFDIETest, PeekName) {
const char *yamldata = R"(
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_386
DWARF:
debug_str:
- 'NameType1'
- 'NameType2'
debug_abbrev:
- Table:
- Code: 0x00000001
Tag: DW_TAG_compile_unit
Children: DW_CHILDREN_yes
Attributes:
- Attribute: DW_AT_language
Form: DW_FORM_data2
- Code: 0x00000002
Tag: DW_TAG_base_type
Children: DW_CHILDREN_no
Attributes:
- Attribute: DW_AT_name
Form: DW_FORM_strp
- Code: 0x00000003
Tag: DW_TAG_base_type
Children: DW_CHILDREN_no
Attributes:
- Attribute: DW_AT_abstract_origin
Form: DW_FORM_ref1
- Code: 0x00000004
Tag: DW_TAG_base_type
Children: DW_CHILDREN_no
Attributes:
- Attribute: DW_AT_specification
Form: DW_FORM_ref1
debug_info:
- Version: 4
AddrSize: 8
Entries:
- AbbrCode: 0x00000001
Values:
- Value: 0x000000000000000C
- AbbrCode: 0x00000002
Values:
- Value: 0x0000000000000000 # Name = NameType1
- AbbrCode: 0x00000002
Values:
- Value: 0x000000000000000a # Name = NameType2
- AbbrCode: 0x00000003
Values:
- Value: 0x000000000000000e # Ref abstract origin to NameType1 DIE.
- AbbrCode: 0x00000004
Values:
- Value: 0x0000000000000013 # Ref specification to NameType2 DIE.
- AbbrCode: 0x00000000
)";

YAMLModuleTester t(yamldata);
auto *symbol_file =
llvm::cast<SymbolFileDWARF>(t.GetModule()->GetSymbolFile());
auto &debug_info = symbol_file->DebugInfo();

DIERef first_die(std::nullopt, DIERef::Section::DebugInfo,
11 /*FirstDIEOffset*/);
EXPECT_EQ(debug_info.PeekDIEName(first_die), "");

DIERef second_die(std::nullopt, DIERef::Section::DebugInfo, 14);
EXPECT_EQ(debug_info.PeekDIEName(second_die), "NameType1");

DIERef third_die(std::nullopt, DIERef::Section::DebugInfo, 19);
EXPECT_EQ(debug_info.PeekDIEName(third_die), "NameType2");

DIERef fourth_die(std::nullopt, DIERef::Section::DebugInfo, 24);
EXPECT_EQ(debug_info.PeekDIEName(fourth_die), "NameType1");

DIERef fifth_die(std::nullopt, DIERef::Section::DebugInfo, 26);
EXPECT_EQ(debug_info.PeekDIEName(fifth_die), "NameType2");
}