mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-26 23:21:11 +00:00
[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
This commit is contained in:
parent
904cf66ec1
commit
4684507455
@ -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();
|
||||
}
|
||||
|
@ -43,6 +43,11 @@ public:
|
||||
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
|
||||
|
@ -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;
|
||||
@ -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:
|
||||
@ -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 =
|
||||
@ -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) {
|
||||
|
@ -60,6 +60,12 @@ public:
|
||||
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; }
|
||||
|
@ -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)
|
||||
|
@ -187,6 +187,11 @@ public:
|
||||
|
||||
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);
|
||||
|
@ -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"
|
||||
@ -104,3 +105,85 @@ DWARF:
|
||||
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");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user