[Lldb-commits] [lldb] [llvm] [DoNotMerge] DW_IDX_parent full implementation (PR #77121)
Felipe de Azevedo Piovezan via lldb-commits
lldb-commits at lists.llvm.org
Fri Jan 5 09:32:56 PST 2024
https://github.com/felipepiovezan updated https://github.com/llvm/llvm-project/pull/77121
>From 8ec587dc14144f14d3d86a41901a261f75d1ae9b Mon Sep 17 00:00:00 2001
From: Felipe de Azevedo Piovezan <fpiovezan at apple.com>
Date: Wed, 3 Jan 2024 11:19:04 -0300
Subject: [PATCH 1/7] [AccelTable][nfc] Add helper function to cast Data
This reduces the number of casts that have to be made in the middle of code,
making it easier to read.
---
llvm/include/llvm/CodeGen/AccelTable.h | 11 +++++++----
llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp | 11 +++++------
2 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/AccelTable.h b/llvm/include/llvm/CodeGen/AccelTable.h
index 6eb09f32f9f951..d8643b1f450d17 100644
--- a/llvm/include/llvm/CodeGen/AccelTable.h
+++ b/llvm/include/llvm/CodeGen/AccelTable.h
@@ -143,6 +143,11 @@ class AccelTableBase {
std::vector<AccelTableData *> Values;
MCSymbol *Sym;
+ template <typename T = AccelTableData *> auto getValues() const {
+ return map_range(
+ Values, [](AccelTableData *Data) { return static_cast<T>(Data); });
+ }
+
#ifndef NDEBUG
void print(raw_ostream &OS) const;
void dump() const { print(dbgs()); }
@@ -319,8 +324,7 @@ class DWARF5AccelTable : public AccelTable<DWARF5AccelTableData> {
/// Needs to be called after DIE offsets are computed.
void convertDieToOffset() {
for (auto &Entry : Entries) {
- for (AccelTableData *Value : Entry.second.Values) {
- DWARF5AccelTableData *Data = static_cast<DWARF5AccelTableData *>(Value);
+ for (auto *Data : Entry.second.getValues<DWARF5AccelTableData *>()) {
// For TU we normalize as each Unit is emitted.
// So when this is invoked after CU construction we will be in mixed
// state.
@@ -332,8 +336,7 @@ class DWARF5AccelTable : public AccelTable<DWARF5AccelTableData> {
void addTypeEntries(DWARF5AccelTable &Table) {
for (auto &Entry : Table.getEntries()) {
- for (AccelTableData *Value : Entry.second.Values) {
- DWARF5AccelTableData *Data = static_cast<DWARF5AccelTableData *>(Value);
+ for (auto *Data : Entry.second.getValues<DWARF5AccelTableData *>()) {
addName(Entry.second.Name, Data->getDieOffset(), Data->getDieTag(),
Data->getUnitID(), true);
}
diff --git a/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp b/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
index bf580269eca62e..b72c17aa6f54a3 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
@@ -342,8 +342,8 @@ void AppleAccelTableWriter::emitData() const {
Asm->emitDwarfStringOffset(Hash->Name);
Asm->OutStreamer->AddComment("Num DIEs");
Asm->emitInt32(Hash->Values.size());
- for (const auto *V : Hash->Values)
- static_cast<const AppleAccelTableData *>(V)->emit(Asm);
+ for (const auto *V : Hash->getValues<const AppleAccelTableData *>())
+ V->emit(Asm);
PrevHash = Hash->HashValue;
}
// Emit the final end marker for the bucket.
@@ -415,11 +415,10 @@ static uint32_t constructAbbreviationTag(
void Dwarf5AccelTableWriter::populateAbbrevsMap() {
for (auto &Bucket : Contents.getBuckets()) {
for (auto *Hash : Bucket) {
- for (auto *Value : Hash->Values) {
+ for (auto *Value : Hash->getValues<DWARF5AccelTableData *>()) {
std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
- getIndexForEntry(*static_cast<const DWARF5AccelTableData *>(Value));
- unsigned Tag =
- static_cast<const DWARF5AccelTableData *>(Value)->getDieTag();
+ getIndexForEntry(*Value);
+ unsigned Tag = Value->getDieTag();
uint32_t AbbrvTag = constructAbbreviationTag(Tag, EntryRet);
if (Abbreviations.count(AbbrvTag) == 0) {
SmallVector<DWARF5AccelTableData::AttributeEncoding, 2> UA;
>From 683cfd5217e5e39fe207d37fc8b53e58ebad0af7 Mon Sep 17 00:00:00 2001
From: Felipe de Azevedo Piovezan <fpiovezan at apple.com>
Date: Thu, 4 Jan 2024 12:44:43 -0300
Subject: [PATCH 2/7] [lldb][DWARFIndex][nfc] Factor out fully qualified name
query
This moves the functionally of finding a DIE based on a fully qualified name
from SymbolFileDWARF into DWARFIndex itself, so that specializations of
DWARFIndex can implement faster versions of this query.
---
.../Plugins/SymbolFile/DWARF/DWARFIndex.cpp | 20 +++++++++++++++++++
.../Plugins/SymbolFile/DWARF/DWARFIndex.h | 14 +++++++++++++
.../SymbolFile/DWARF/SymbolFileDWARF.cpp | 9 ++-------
3 files changed, 36 insertions(+), 7 deletions(-)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
index b1c323b101cef3..20c07a94b50769 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
@@ -7,6 +7,8 @@
//===----------------------------------------------------------------------===//
#include "Plugins/SymbolFile/DWARF/DWARFIndex.h"
+#include "DWARFDebugInfoEntry.h"
+#include "DWARFDeclContext.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
#include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
@@ -112,3 +114,21 @@ void DWARFIndex::ReportInvalidDIERef(DIERef ref, llvm::StringRef name) const {
"bad die {0:x16} for '{1}')\n",
ref.die_offset(), name.str().c_str());
}
+
+void DWARFIndex::GetFullyQualifiedType(
+ const DWARFDeclContext &context,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ GetTypes(context, [&](DWARFDIE die) {
+ return GetFullyQualifiedTypeImpl(context, die, callback);
+ });
+}
+
+bool DWARFIndex::GetFullyQualifiedTypeImpl(
+ const DWARFDeclContext &context, DWARFDIE die,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ DWARFDeclContext dwarf_decl_ctx =
+ die.GetDIE()->GetDWARFDeclContext(die.GetCU());
+ if (dwarf_decl_ctx == context)
+ return callback(die);
+ return true;
+}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
index 9aadeddbb21753..0551b07100a96b 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
@@ -53,6 +53,14 @@ class DWARFIndex {
llvm::function_ref<bool(DWARFDIE die)> callback) = 0;
virtual void GetTypes(const DWARFDeclContext &context,
llvm::function_ref<bool(DWARFDIE die)> callback) = 0;
+
+ /// Finds all DIEs whose fully qualified name matches `context`. A base
+ /// implementation is provided, and it uses the entire CU to check the DIE
+ /// parent hierarchy. Specializations should override this if they are able
+ /// to provide a faster implementation.
+ virtual void
+ GetFullyQualifiedType(const DWARFDeclContext &context,
+ llvm::function_ref<bool(DWARFDIE die)> callback);
virtual void
GetNamespaces(ConstString name,
llvm::function_ref<bool(DWARFDIE die)> callback) = 0;
@@ -102,6 +110,12 @@ class DWARFIndex {
}
void ReportInvalidDIERef(DIERef ref, llvm::StringRef name) const;
+
+ /// Implementation of `GetFullyQualifiedType` to check a single entry,
+ /// shareable with derived classes.
+ bool
+ GetFullyQualifiedTypeImpl(const DWARFDeclContext &context, DWARFDIE die,
+ llvm::function_ref<bool(DWARFDIE die)> callback);
};
} // namespace dwarf
} // namespace lldb_private::plugin
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 447930ffe07b3f..737da7798b82b9 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -3138,7 +3138,7 @@ SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die) {
}
const DWARFDeclContext die_dwarf_decl_ctx = GetDWARFDeclContext(die);
- m_index->GetTypes(die_dwarf_decl_ctx, [&](DWARFDIE type_die) {
+ m_index->GetFullyQualifiedType(die_dwarf_decl_ctx, [&](DWARFDIE type_die) {
// Make sure type_die's language matches the type system we are
// looking for. We don't want to find a "Foo" type from Java if we
// are looking for a "Foo" type for C, C++, ObjC, or ObjC++.
@@ -3165,9 +3165,8 @@ SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die) {
return true;
}
- DWARFDeclContext type_dwarf_decl_ctx = GetDWARFDeclContext(type_die);
-
if (log) {
+ DWARFDeclContext type_dwarf_decl_ctx = GetDWARFDeclContext(type_die);
GetObjectFile()->GetModule()->LogMessage(
log,
"SymbolFileDWARF::"
@@ -3177,10 +3176,6 @@ SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die) {
type_dwarf_decl_ctx.GetQualifiedName());
}
- // Make sure the decl contexts match all the way up
- if (die_dwarf_decl_ctx != type_dwarf_decl_ctx)
- return true;
-
Type *resolved_type = ResolveType(type_die, false);
if (!resolved_type || resolved_type == DIE_IS_BEING_PARSED)
return true;
>From fa08a9dbc97d040ac950f293e56f559f5166d01b Mon Sep 17 00:00:00 2001
From: Felipe de Azevedo Piovezan <fpiovezan at apple.com>
Date: Mon, 11 Dec 2023 12:42:40 -0300
Subject: [PATCH 3/7] [lldb][[DWARFDeclContext] Add function to extract
qualified names as vector
---
.../SymbolFile/DWARF/DWARFDeclContext.cpp | 6 +
.../SymbolFile/DWARF/DWARFDeclContext.h | 5 +
.../SymbolFile/DWARF/DWARFDIETest.cpp | 109 ++++++++++++++++++
3 files changed, 120 insertions(+)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp
index 44421c0eda3eec..3cdb47d50bbfc0 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp
@@ -55,6 +55,12 @@ const char *DWARFDeclContext::GetQualifiedName() const {
return m_qualified_name.c_str();
}
+llvm::SmallVector<llvm::StringRef>
+DWARFDeclContext::GetQualifiedNameAsVector() const {
+ return llvm::to_vector_of<llvm::StringRef>(
+ llvm::map_range(m_entries, GetName));
+}
+
bool DWARFDeclContext::operator==(const DWARFDeclContext &rhs) const {
if (m_entries.size() != rhs.m_entries.size())
return false;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h
index a20a862d340296..40ebb72c91d8f0 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h
@@ -68,6 +68,11 @@ class DWARFDeclContext {
const char *GetQualifiedName() const;
+ /// Returns a vector of string, one string per entry in the fully qualified
+ /// name. For example, for the name `A::B::C`, this methods returns `{"A",
+ /// "B", "C"}`
+ llvm::SmallVector<llvm::StringRef> GetQualifiedNameAsVector() const;
+
// Same as GetQualifiedName, but the life time of the returned string will
// be that of the LLDB session.
ConstString GetQualifiedNameAsConstString() const {
diff --git a/lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp b/lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp
index 8497855b2f3db5..5672270ee31f89 100644
--- a/lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp
+++ b/lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp
@@ -7,8 +7,10 @@
//===----------------------------------------------------------------------===//
#include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
+#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
#include "TestingSupport/Symbol/YAMLModuleTester.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -104,3 +106,110 @@ TEST(DWARFDIETest, ChildIteration) {
DWARFDIE no_children_die(unit, die_child0);
EXPECT_TRUE(no_children_die.children().empty());
}
+
+TEST(DWARFDIETest, DeclContext) {
+ const char *yamldata = R"(
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_386
+DWARF:
+ debug_str:
+ - 'mynamespace'
+ - 'mystruct'
+ - 'mytype'
+ 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_structure_type
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Code: 0x00000003
+ Tag: DW_TAG_base_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Code: 0x00000004
+ Tag: DW_TAG_namespace
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ debug_info:
+ - Version: 4
+ AddrSize: 8
+ Entries:
+ - AbbrCode: 0x00000001 # compile_unit
+ Values:
+ - Value: 0x000000000000000C
+ - AbbrCode: 0x00000004 # namespace
+ Values:
+ - Value: 0x0000000000000000 # DW_ATE_strp
+ - AbbrCode: 0x00000002 # structure_type
+ Values:
+ - Value: 0x000000000000000c # DW_ATE_strp
+ - AbbrCode: 0x00000003 # base_type
+ Values:
+ - Value: 0x0000000000000015 # DW_ATE_strp
+ - AbbrCode: 0x00000000
+)";
+
+ YAMLModuleTester t(yamldata);
+ DWARFUnit *unit = t.GetDwarfUnit();
+ ASSERT_TRUE(unit != nullptr);
+ auto &ctx = unit->GetSymbolFileDWARF();
+
+ auto top_level_die = unit->DIE();
+ {
+ ASSERT_TRUE(top_level_die);
+ auto top_level_ctx = ctx.GetDWARFDeclContext(top_level_die);
+ auto top_level_name = llvm::StringRef(top_level_ctx.GetQualifiedName());
+ ASSERT_EQ(top_level_name, "");
+ }
+
+ auto namespace_die = top_level_die.GetFirstChild();
+ {
+ ASSERT_TRUE(namespace_die);
+ auto namespace_ctx = ctx.GetDWARFDeclContext(namespace_die);
+ auto namespace_name = llvm::StringRef(namespace_ctx.GetQualifiedName());
+ ASSERT_EQ(namespace_name, "::mynamespace");
+ auto namespace_names = namespace_ctx.GetQualifiedNameAsVector();
+ ASSERT_EQ(namespace_names.size(), 1u);
+ ASSERT_EQ(namespace_names.front(), "mynamespace");
+ }
+
+ auto struct_die = namespace_die.GetFirstChild();
+ {
+ ASSERT_TRUE(struct_die);
+ auto struct_ctx = ctx.GetDWARFDeclContext(struct_die);
+ auto struct_name = llvm::StringRef(struct_ctx.GetQualifiedName());
+ ASSERT_EQ(struct_name, "mynamespace::mystruct");
+ auto struct_names = struct_ctx.GetQualifiedNameAsVector();
+ ASSERT_EQ(struct_names.size(), 2u);
+ ASSERT_EQ(struct_names[0], "mystruct");
+ ASSERT_EQ(struct_names[1], "mynamespace");
+ }
+ auto simple_type_die = struct_die.GetFirstChild();
+ {
+ ASSERT_TRUE(simple_type_die);
+ auto simple_type_ctx = ctx.GetDWARFDeclContext(simple_type_die);
+ auto simple_type_name = llvm::StringRef(simple_type_ctx.GetQualifiedName());
+ ASSERT_EQ(simple_type_name, "mynamespace::mystruct::mytype");
+ auto simple_type_names = simple_type_ctx.GetQualifiedNameAsVector();
+ ASSERT_EQ(simple_type_names.size(), 3u);
+ ASSERT_EQ(simple_type_names[0], "mytype");
+ ASSERT_EQ(simple_type_names[1], "mystruct");
+ ASSERT_EQ(simple_type_names[2], "mynamespace");
+ }
+}
>From b99113215416296c9b8d951088f4b3c81ecdcc63 Mon Sep 17 00:00:00 2001
From: Felipe de Azevedo Piovezan <fpiovezan at apple.com>
Date: Wed, 6 Dec 2023 11:26:18 -0800
Subject: [PATCH 4/7] [AsmPrinter][DebugNames] Implement DW_IDX_parent entries
This is implementation of the ideas discussed in [1].
To summarize, this commit changes AsmPrinter so that is outputs DW_IDX_parent
information for debug_name entries. It will enable debuggers to speed up queries
for fully qualified types (based on a DWARFDeclContext) significantly, as
debuggers will no longer need to parse the entire CU in order to inspect the
parent chain of a DIE. Instead, a debugger can simply take the parent DIE offset
from the accelerator table and peek at its name in the debug_info/debug_str
sections.
The implementation uses two types of DW_FORM for the DW_IDX_parent attribute:
1. DW_FORM_ref4, which points to the accelerator table entry for the parent.
2. DW_FORM_flag_present, when the entry has a parent that is not in the table
(that is, the parent doesn't have a name, or isn't allowed to be in the table as
per the DWARF spec). This attribute is used for space efficiency, since it takes
0 bytes.
When all patches related to this are merged, we are able to show that evaluating
an expression such as:
```
lldb --batch -o 'b CodeGenFunction::GenerateCode' -o run -o 'expr Fn' -- \
clang++ -c -g test.cpp -o /dev/null
```
is far faster: from ~5000 ms to ~1500ms.
Building llvm-project + clang with and without this patch, and looking at its
impact on size:
```
ls -la $(find build_stage2_Debug_idx_parent_assert_dwarf5 -name \*.cpp.o) | awk '{s+=$5} END {printf "%\047d\n", s}'
11,507,327,592
-la $(find build_stage2_Debug_no_idx_parent_assert_dwarf5 -name \*.cpp.o) | awk '{s+=$5} END {printf "%\047d\n", s}'
11,436,446,616
```
That is, an increase of 0.62% in total object file size.
Looking only at debug_names:
```
$stage1_build/bin/llvm-objdump --section-headers $(find build_stage2_Debug_idx_parent_assert_dwarf5 -name \*.cpp.o) | grep __debug_names | awk '{s+="0x"$3} END {printf "%\047d\n", s}'
440,772,348
$stage1_build/bin/llvm-objdump --section-headers $(find build_stage2_Debug_no_idx_parent_assert_dwarf5 -name \*.cpp.o) | grep __debug_names | awk '{s+="0x"$3} END {printf "%\047d\n", s}'
369,867,920
```
That is an increase of 19%.
DWARF Linkers need to be changed in order to support this. This commit already
brings support to "base" linker, but it does not attempt to modify the parallel
linker. Accelerator entries refer to the corresponding DIE offset, and this
patch also requires the parent DIE offset -- it's not clear how the parallel
linker can access this. It may be obvious to someone familiar with it, but it
would be nice to get help from its authors.
[1]: https://discourse.llvm.org/t/rfc-improve-dwarf-5-debug-names-type-lookup-parsing-speed/74151/
---
llvm/include/llvm/CodeGen/AccelTable.h | 23 +++-
llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp | 116 +++++++++++++++---
llvm/lib/DWARFLinker/DWARFLinker.cpp | 8 ++
.../DWARFLinkerParallel/DWARFLinkerImpl.cpp | 3 +-
llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp | 16 ++-
.../test/DebugInfo/X86/debug-names-dwarf64.ll | 16 ++-
.../DebugInfo/X86/debug-names-end-of-list.ll | 6 +-
llvm/test/DebugInfo/X86/debug-names-types.ll | 58 ++++++---
.../ARM/accel-imported-declarations.test | 2 +
.../ARM/dwarf5-dwarf4-combination-macho.test | 12 +-
10 files changed, 210 insertions(+), 50 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/AccelTable.h b/llvm/include/llvm/CodeGen/AccelTable.h
index d8643b1f450d17..ddccc4600f14c1 100644
--- a/llvm/include/llvm/CodeGen/AccelTable.h
+++ b/llvm/include/llvm/CodeGen/AccelTable.h
@@ -266,9 +266,12 @@ class DWARF5AccelTableData : public AccelTableData {
DWARF5AccelTableData(const DIE &Die, const uint32_t UnitID,
const bool IsTU = false);
- DWARF5AccelTableData(const uint64_t DieOffset, const unsigned DieTag,
- const unsigned UnitID, const bool IsTU = false)
- : OffsetVal(DieOffset), DieTag(DieTag), UnitID(UnitID), IsTU(IsTU) {}
+ DWARF5AccelTableData(const uint64_t DieOffset,
+ const std::optional<uint64_t> ParentOffset,
+ const unsigned DieTag, const unsigned UnitID,
+ const bool IsTU = false)
+ : OffsetVal(DieOffset), ParentOffset(ParentOffset), DieTag(DieTag),
+ UnitID(UnitID), IsTU(IsTU) {}
#ifndef NDEBUG
void print(raw_ostream &OS) const override;
@@ -283,14 +286,23 @@ class DWARF5AccelTableData : public AccelTableData {
bool isTU() const { return IsTU; }
void normalizeDIEToOffset() {
assert(!isNormalized() && "Accessing offset after normalizing.");
- OffsetVal = std::get<const DIE *>(OffsetVal)->getOffset();
+ const DIE *Entry = std::get<const DIE *>(OffsetVal);
+ ParentOffset = Entry->getParent() ? Entry->getParent()->getOffset()
+ : std::optional<uint64_t>();
+ OffsetVal = Entry->getOffset();
}
bool isNormalized() const {
return std::holds_alternative<uint64_t>(OffsetVal);
}
+ std::optional<uint64_t> getParentDieOffset() const {
+ assert(isNormalized() && "Accessing DIE Offset before normalizing.");
+ return ParentOffset;
+ }
+
protected:
std::variant<const DIE *, uint64_t> OffsetVal;
+ std::optional<uint64_t> ParentOffset;
uint32_t DieTag : 16;
uint32_t UnitID : 15;
uint32_t IsTU : 1;
@@ -337,7 +349,8 @@ class DWARF5AccelTable : public AccelTable<DWARF5AccelTableData> {
void addTypeEntries(DWARF5AccelTable &Table) {
for (auto &Entry : Table.getEntries()) {
for (auto *Data : Entry.second.getValues<DWARF5AccelTableData *>()) {
- addName(Entry.second.Name, Data->getDieOffset(), Data->getDieTag(),
+ addName(Entry.second.Name, Data->getDieOffset(),
+ Data->getParentDieOffset(), Data->getDieTag(),
Data->getUnitID(), true);
}
}
diff --git a/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp b/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
index b72c17aa6f54a3..c412d17c67175c 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
@@ -13,6 +13,7 @@
#include "llvm/CodeGen/AccelTable.h"
#include "DwarfCompileUnit.h"
#include "DwarfUnit.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/Dwarf.h"
@@ -207,7 +208,7 @@ class Dwarf5AccelTableWriter : public AccelTableWriter {
};
Header Header;
- DenseMap<uint32_t, SmallVector<DWARF5AccelTableData::AttributeEncoding, 2>>
+ DenseMap<uint32_t, SmallVector<DWARF5AccelTableData::AttributeEncoding, 3>>
Abbreviations;
ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits;
ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits;
@@ -220,6 +221,8 @@ class Dwarf5AccelTableWriter : public AccelTableWriter {
MCSymbol *EntryPool = Asm->createTempSymbol("names_entries");
// Indicates if this module is built with Split Dwarf enabled.
bool IsSplitDwarf = false;
+ // Stores the DIE offsets which are indexed by this table.
+ DenseSet<uint64_t> IndexedOffsets;
void populateAbbrevsMap();
@@ -228,8 +231,11 @@ class Dwarf5AccelTableWriter : public AccelTableWriter {
void emitBuckets() const;
void emitStringOffsets() const;
void emitAbbrevs() const;
- void emitEntry(const DWARF5AccelTableData &Entry) const;
- void emitData() const;
+ void
+ emitEntry(const DWARF5AccelTableData &Entry,
+ const DenseMap<uint64_t, MCSymbol *> &DIEOffsetToAccelEntryLabel,
+ DenseSet<MCSymbol *> &EmittedAccelEntrySymbols) const;
+ void emitData();
public:
Dwarf5AccelTableWriter(
@@ -395,23 +401,63 @@ void Dwarf5AccelTableWriter::Header::emit(Dwarf5AccelTableWriter &Ctx) {
Asm->OutStreamer->emitBytes({AugmentationString, AugmentationStringSize});
}
-static uint32_t constexpr LowerBitSize = dwarf::DW_IDX_type_hash;
+enum IdxParentEncoding : uint8_t {
+ NoIndexedParent = 0, // Parent information present but parent isn't indexed.
+ Ref4 = 1, // Parent information present and parent is indexed.
+ NoParent = 2, // Parent information missing.
+};
+
+static uint32_t constexpr NumBitsIdxParent = 2;
+
+uint8_t encodeIdxParent(std::optional<dwarf::Form> MaybeParentForm) {
+ if (!MaybeParentForm)
+ return NoParent;
+ switch (*MaybeParentForm) {
+ case dwarf::Form::DW_FORM_flag_present:
+ return NoIndexedParent;
+ case dwarf::Form::DW_FORM_ref4:
+ return Ref4;
+ default:
+ break;
+ }
+ llvm_unreachable("Bad form for IDX_parent");
+}
+
+static uint32_t constexpr ParentBitOffset = dwarf::DW_IDX_type_hash;
+static uint32_t constexpr TagBitOffset = ParentBitOffset + NumBitsIdxParent;
static uint32_t getTagFromAbbreviationTag(const uint32_t AbbrvTag) {
- return AbbrvTag >> LowerBitSize;
+ return AbbrvTag >> TagBitOffset;
}
/// Constructs a unique AbbrevTag that captures what a DIE accesses.
/// Using this tag we can emit a unique abbreviation for each DIE.
static uint32_t constructAbbreviationTag(
const unsigned Tag,
- const std::optional<DWARF5AccelTable::UnitIndexAndEncoding> &EntryRet) {
+ const std::optional<DWARF5AccelTable::UnitIndexAndEncoding> &EntryRet,
+ std::optional<dwarf::Form> MaybeParentForm) {
uint32_t AbbrvTag = 0;
if (EntryRet)
AbbrvTag |= 1 << EntryRet->Encoding.Index;
AbbrvTag |= 1 << dwarf::DW_IDX_die_offset;
- AbbrvTag |= Tag << LowerBitSize;
+ AbbrvTag |= 1 << dwarf::DW_IDX_parent;
+ AbbrvTag |= encodeIdxParent(MaybeParentForm) << ParentBitOffset;
+ AbbrvTag |= Tag << TagBitOffset;
return AbbrvTag;
}
+
+static std::optional<dwarf::Form>
+getFormForIdxParent(const DenseSet<uint64_t> &IndexedOffsets,
+ std::optional<uint64_t> ParentOffset) {
+ // No parent information
+ if (!ParentOffset)
+ return std::nullopt;
+ // Parent is indexed by this table.
+ if (IndexedOffsets.contains(*ParentOffset))
+ return dwarf::Form::DW_FORM_ref4;
+ // Parent is not indexed by this table.
+ return dwarf::Form::DW_FORM_flag_present;
+}
+
void Dwarf5AccelTableWriter::populateAbbrevsMap() {
for (auto &Bucket : Contents.getBuckets()) {
for (auto *Hash : Bucket) {
@@ -419,12 +465,17 @@ void Dwarf5AccelTableWriter::populateAbbrevsMap() {
std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
getIndexForEntry(*Value);
unsigned Tag = Value->getDieTag();
- uint32_t AbbrvTag = constructAbbreviationTag(Tag, EntryRet);
+ std::optional<dwarf::Form> MaybeParentForm =
+ getFormForIdxParent(IndexedOffsets, Value->getParentDieOffset());
+ uint32_t AbbrvTag =
+ constructAbbreviationTag(Tag, EntryRet, MaybeParentForm);
if (Abbreviations.count(AbbrvTag) == 0) {
- SmallVector<DWARF5AccelTableData::AttributeEncoding, 2> UA;
+ SmallVector<DWARF5AccelTableData::AttributeEncoding, 3> UA;
if (EntryRet)
UA.push_back(EntryRet->Encoding);
UA.push_back({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
+ if (MaybeParentForm)
+ UA.push_back({dwarf::DW_IDX_parent, *MaybeParentForm});
Abbreviations.try_emplace(AbbrvTag, UA);
}
}
@@ -496,15 +547,32 @@ void Dwarf5AccelTableWriter::emitAbbrevs() const {
}
void Dwarf5AccelTableWriter::emitEntry(
- const DWARF5AccelTableData &Entry) const {
+ const DWARF5AccelTableData &Entry,
+ const DenseMap<uint64_t, MCSymbol *> &DIEOffsetToAccelEntryLabel,
+ DenseSet<MCSymbol *> &EmittedAccelEntrySymbols) const {
std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
getIndexForEntry(Entry);
- uint32_t AbbrvTag = constructAbbreviationTag(Entry.getDieTag(), EntryRet);
+ std::optional<uint64_t> MaybeParentOffset = Entry.getParentDieOffset();
+ std::optional<dwarf::Form> MaybeParentForm =
+ getFormForIdxParent(IndexedOffsets, MaybeParentOffset);
+ uint32_t AbbrvTag =
+ constructAbbreviationTag(Entry.getDieTag(), EntryRet, MaybeParentForm);
auto AbbrevIt = Abbreviations.find(AbbrvTag);
assert(AbbrevIt != Abbreviations.end() &&
"Why wasn't this abbrev generated?");
assert(getTagFromAbbreviationTag(AbbrevIt->first) == Entry.getDieTag() &&
"Invalid Tag");
+
+ auto EntrySymbolIt = DIEOffsetToAccelEntryLabel.find(Entry.getDieOffset());
+ assert(EntrySymbolIt != DIEOffsetToAccelEntryLabel.end());
+ MCSymbol *EntrySymbol = EntrySymbolIt->getSecond();
+
+ // Emit the label for this Entry, so that IDX_parents may refer to it.
+ // Note: a DIE may have multiple accelerator Entries; this check avoids
+ // creating multiple labels for the same DIE.
+ if (EmittedAccelEntrySymbols.insert(EntrySymbol).second)
+ Asm->OutStreamer->emitLabel(EntrySymbol);
+
Asm->emitULEB128(AbbrevIt->first, "Abbreviation code");
for (const auto &AttrEnc : AbbrevIt->second) {
@@ -520,20 +588,34 @@ void Dwarf5AccelTableWriter::emitEntry(
assert(AttrEnc.Form == dwarf::DW_FORM_ref4);
Asm->emitInt32(Entry.getDieOffset());
break;
+ case dwarf::DW_IDX_parent: {
+ if (AttrEnc.Form == dwarf::Form::DW_FORM_flag_present)
+ break;
+ auto ParentSymbolIt = DIEOffsetToAccelEntryLabel.find(*MaybeParentOffset);
+ assert(ParentSymbolIt != DIEOffsetToAccelEntryLabel.end());
+ Asm->emitLabelDifference(ParentSymbolIt->getSecond(), EntryPool, 4);
+ break;
+ }
default:
llvm_unreachable("Unexpected index attribute!");
}
}
}
-void Dwarf5AccelTableWriter::emitData() const {
+void Dwarf5AccelTableWriter::emitData() {
+ DenseMap<uint64_t, MCSymbol*> DIEOffsetToAccelEntryLabel;
+
+ for (auto Offset : IndexedOffsets)
+ DIEOffsetToAccelEntryLabel[Offset] = Asm->createTempSymbol("symbol");
+
Asm->OutStreamer->emitLabel(EntryPool);
+ DenseSet<MCSymbol *> EmittedAccelEntrySymbols;
for (auto &Bucket : Contents.getBuckets()) {
for (auto *Hash : Bucket) {
// Remember to emit the label for our offset.
Asm->OutStreamer->emitLabel(Hash->Sym);
- for (const auto *Value : Hash->Values)
- emitEntry(*static_cast<const DWARF5AccelTableData *>(Value));
+ for (const auto *Value : Hash->getValues<DWARF5AccelTableData*>())
+ emitEntry(*Value, DIEOffsetToAccelEntryLabel, EmittedAccelEntrySymbols);
Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString());
Asm->emitInt8(0);
}
@@ -555,6 +637,12 @@ Dwarf5AccelTableWriter::Dwarf5AccelTableWriter(
CompUnits(CompUnits), TypeUnits(TypeUnits),
getIndexForEntry(std::move(getIndexForEntry)),
IsSplitDwarf(IsSplitDwarf) {
+
+ for (auto &Bucket : Contents.getBuckets())
+ for (auto *Hash : Bucket)
+ for (auto *Value : Hash->getValues<DWARF5AccelTableData *>())
+ IndexedOffsets.insert(Value->getDieOffset());
+
populateAbbrevsMap();
}
diff --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp
index 10967123a562e7..3900902ac07eda 100644
--- a/llvm/lib/DWARFLinker/DWARFLinker.cpp
+++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp
@@ -2253,14 +2253,22 @@ void DWARFLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) {
TheDwarfEmitter->emitPubTypesForUnit(Unit);
} break;
case AccelTableKind::DebugNames: {
+ auto ParentOffsetOrNull = [](const DIE *Die) -> std::optional<uint64_t> {
+ if (const DIE *Parent = Die->getParent())
+ return Die->getParent()->getOffset();
+ return std::nullopt;
+ };
for (const auto &Namespace : Unit.getNamespaces())
DebugNames.addName(Namespace.Name, Namespace.Die->getOffset(),
+ ParentOffsetOrNull(Namespace.Die),
Namespace.Die->getTag(), Unit.getUniqueID());
for (const auto &Pubname : Unit.getPubnames())
DebugNames.addName(Pubname.Name, Pubname.Die->getOffset(),
+ ParentOffsetOrNull(Pubname.Die),
Pubname.Die->getTag(), Unit.getUniqueID());
for (const auto &Pubtype : Unit.getPubtypes())
DebugNames.addName(Pubtype.Name, Pubtype.Die->getOffset(),
+ ParentOffsetOrNull(Pubtype.Die),
Pubtype.Die->getTag(), Unit.getUniqueID());
} break;
}
diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp b/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp
index c49b9ef0cdf989..6d7861d08bc03a 100644
--- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp
@@ -1376,7 +1376,8 @@ void DWARFLinkerImpl::emitDWARFv5DebugNamesSection(const Triple &TargetTriple) {
case DwarfUnit::AccelType::Namespace:
case DwarfUnit::AccelType::Type: {
DebugNames->addName(*DebugStrStrings.getExistingEntry(Info.String),
- Info.OutOffset, Info.Tag, CU->getUniqueID());
+ Info.OutOffset, std::nullopt /*ParentDIEOffset*/,
+ Info.Tag, CU->getUniqueID());
} break;
default:
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
index 43ed60d7f9775d..cc37f7eb8a00da 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
#include "llvm/ADT/IntervalMap.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
@@ -1267,6 +1268,20 @@ unsigned DWARFVerifier::verifyNameIndexAttribute(
NI.getUnitOffset(), Abbr.Code, AttrEnc.Form, dwarf::DW_FORM_data8);
return 1;
}
+ return 0;
+ }
+
+ if (AttrEnc.Index == dwarf::DW_IDX_parent) {
+ constexpr static auto AllowedForms = {dwarf::Form::DW_FORM_flag_present,
+ dwarf::Form::DW_FORM_ref4};
+ if (!is_contained(AllowedForms, AttrEnc.Form)) {
+ error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_parent "
+ "uses an unexpected form {2} (should be "
+ "DW_FORM_ref4 or DW_FORM_flag_present).\n",
+ NI.getUnitOffset(), Abbr.Code, AttrEnc.Form);
+ return 1;
+ }
+ return 0;
}
// A list of known index attributes and their expected form classes.
@@ -1281,7 +1296,6 @@ unsigned DWARFVerifier::verifyNameIndexAttribute(
{dwarf::DW_IDX_compile_unit, DWARFFormValue::FC_Constant, {"constant"}},
{dwarf::DW_IDX_type_unit, DWARFFormValue::FC_Constant, {"constant"}},
{dwarf::DW_IDX_die_offset, DWARFFormValue::FC_Reference, {"reference"}},
- {dwarf::DW_IDX_parent, DWARFFormValue::FC_Constant, {"constant"}},
};
ArrayRef<FormClassTable> TableRef(Table);
diff --git a/llvm/test/DebugInfo/X86/debug-names-dwarf64.ll b/llvm/test/DebugInfo/X86/debug-names-dwarf64.ll
index b94bdbcb12010c..a6855d77a34ac2 100644
--- a/llvm/test/DebugInfo/X86/debug-names-dwarf64.ll
+++ b/llvm/test/DebugInfo/X86/debug-names-dwarf64.ll
@@ -30,21 +30,25 @@
; CHECK-NEXT: CU[0]: 0x00000000
; CHECK-NEXT: ]
; CHECK-NEXT: Abbreviations [
+; CHECK-NEXT: Abbreviation [[ABBREV_LABEL:0x[0-9a-f]*]] {
+; CHECK-NEXT: Tag: DW_TAG_label
+; CHECK-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+; CHECK-NEXT: DW_IDX_parent: DW_FORM_ref4
+; CHECK-NEXT: }
; CHECK-NEXT: Abbreviation [[ABBREV:0x[0-9a-f]*]] {
; CHECK-NEXT: Tag: DW_TAG_base_type
; CHECK-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+; CHECK-NEXT: DW_IDX_parent: DW_FORM_flag_present
; CHECK-NEXT: }
; CHECK-NEXT: Abbreviation [[ABBREV1:0x[0-9a-f]*]] {
; CHECK-NEXT: Tag: DW_TAG_variable
; CHECK-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+; CHECK-NEXT: DW_IDX_parent: DW_FORM_flag_present
; CHECK-NEXT: }
; CHECK-NEXT: Abbreviation [[ABBREV_SP:0x[0-9a-f]*]] {
; CHECK-NEXT: Tag: DW_TAG_subprogram
; CHECK-NEXT: DW_IDX_die_offset: DW_FORM_ref4
-; CHECK-NEXT: }
-; CHECK-NEXT: Abbreviation [[ABBREV_LABEL:0x[0-9a-f]*]] {
-; CHECK-NEXT: Tag: DW_TAG_label
-; CHECK-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+; CHECK-NEXT: DW_IDX_parent: DW_FORM_flag_present
; CHECK-NEXT: }
; CHECK-NEXT: ]
; CHECK-NEXT: Bucket 0 [
@@ -55,6 +59,7 @@
; CHECK-NEXT: Abbrev: [[ABBREV]]
; CHECK-NEXT: Tag: DW_TAG_base_type
; CHECK-NEXT: DW_IDX_die_offset: [[TYPEDIE]]
+; CHECK-NEXT: DW_IDX_parent: true
; CHECK-NEXT: }
; CHECK-NEXT: }
; CHECK-NEXT: ]
@@ -66,6 +71,7 @@
; CHECK-NEXT: Abbrev: [[ABBREV1]]
; CHECK-NEXT: Tag: DW_TAG_variable
; CHECK-NEXT: DW_IDX_die_offset: [[VARDIE]]
+; CHECK-NEXT: DW_IDX_parent: true
; CHECK-NEXT: }
; CHECK-NEXT: }
; CHECK-NEXT: Name 3 {
@@ -75,6 +81,7 @@
; CHECK-NEXT: Abbrev: [[ABBREV_SP]]
; CHECK-NEXT: Tag: DW_TAG_subprogram
; CHECK-NEXT: DW_IDX_die_offset: [[SPDIE]]
+; CHECK-NEXT: DW_IDX_parent: true
; CHECK-NEXT: }
; CHECK-NEXT: }
; CHECK-NEXT: ]
@@ -89,6 +96,7 @@
; CHECK-NEXT: Abbrev: [[ABBREV_LABEL]]
; CHECK-NEXT: Tag: DW_TAG_label
; CHECK-NEXT: DW_IDX_die_offset: [[LABELDIE]]
+; CHECK-NEXT: DW_IDX_parent: 0x{{.*}}
; CHECK-NEXT: }
; CHECK-NEXT: }
; CHECK-NEXT: ]
diff --git a/llvm/test/DebugInfo/X86/debug-names-end-of-list.ll b/llvm/test/DebugInfo/X86/debug-names-end-of-list.ll
index f57168a8eff386..b8d4046201c342 100644
--- a/llvm/test/DebugInfo/X86/debug-names-end-of-list.ll
+++ b/llvm/test/DebugInfo/X86/debug-names-end-of-list.ll
@@ -6,8 +6,10 @@
; CHECK: .section .debug_names,"", at progbits
; CHECK: .Lnames_entries0:
-; CHECK: .byte 0 # End of list: int
-; CHECK: .byte 0 # End of list: foo
+; CHECK: .byte 0
+; CHECK-NEXT: # End of list: int
+; CHECK: .byte 0
+; CHECK-NEXT: # End of list: foo
@foo = common dso_local global i32 0, align 4, !dbg !5
diff --git a/llvm/test/DebugInfo/X86/debug-names-types.ll b/llvm/test/DebugInfo/X86/debug-names-types.ll
index 501b7efd88eb9a..c44e82578f14a4 100644
--- a/llvm/test/DebugInfo/X86/debug-names-types.ll
+++ b/llvm/test/DebugInfo/X86/debug-names-types.ll
@@ -37,27 +37,32 @@
; CHECK-NEXT: LocalTU[0]: 0x00000000
; CHECK-NEXT: ]
; CHECK: Abbreviations [
-; CHECK-NEXT: Abbreviation [[ABBREV1:0x[0-9a-f]*]] {
+; CHECK-NEXT: Abbreviation [[ABBREV3:0x[0-9a-f]*]] {
; CHECK-NEXT: Tag: DW_TAG_structure_type
+; CHECK-NEXT: DW_IDX_type_unit: DW_FORM_data1
; CHECK-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+; CHECK-NEXT: DW_IDX_parent: DW_FORM_flag_present
; CHECK-NEXT: }
-; CHECK-NEXT: Abbreviation [[ABBREV3:0x[0-9a-f]*]] {
-; CHECK-NEXT: Tag: DW_TAG_structure_type
+; CHECK-NEXT: Abbreviation [[ABBREV4:0x[0-9a-f]*]] {
+; CHECK-NEXT: Tag: DW_TAG_base_type
; CHECK-NEXT: DW_IDX_type_unit: DW_FORM_data1
; CHECK-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+; CHECK-NEXT: DW_IDX_parent: DW_FORM_flag_present
; CHECK-NEXT: }
; CHECK-NEXT: Abbreviation [[ABBREV:0x[0-9a-f]*]] {
; CHECK-NEXT: Tag: DW_TAG_base_type
; CHECK-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+; CHECK-NEXT: DW_IDX_parent: DW_FORM_flag_present
; CHECK-NEXT: }
-; CHECK-NEXT: Abbreviation [[ABBREV2:0x[0-9a-f]*]] {
-; CHECK-NEXT: Tag: DW_TAG_subprogram
+; CHECK-NEXT: Abbreviation [[ABBREV1:0x[0-9a-f]*]] {
+; CHECK-NEXT: Tag: DW_TAG_structure_type
; CHECK-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+; CHECK-NEXT: DW_IDX_parent: DW_FORM_flag_present
; CHECK-NEXT: }
-; CHECK-NEXT: Abbreviation [[ABBREV4:0x[0-9a-f]*]] {
-; CHECK-NEXT: Tag: DW_TAG_base_type
-; CHECK-NEXT: DW_IDX_type_unit: DW_FORM_data1
+; CHECK-NEXT: Abbreviation [[ABBREV2:0x[0-9a-f]*]] {
+; CHECK-NEXT: Tag: DW_TAG_subprogram
; CHECK-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+; CHECK-NEXT: DW_IDX_parent: DW_FORM_flag_present
; CHECK-NEXT: }
; CHECK-NEXT: ]
; CHECK-NEXT: Bucket 0 [
@@ -68,6 +73,7 @@
; CHECK-NEXT: Abbrev: [[ABBREV]]
; CHECK-NEXT: Tag: DW_TAG_base_type
; CHECK-NEXT: DW_IDX_die_offset: 0x0000003e
+; CHECK-NEXT: DW_IDX_parent: true
; CHECK-NEXT: }
; CHECK-NEXT: }
; CHECK-NEXT: ]
@@ -80,11 +86,13 @@
; CHECK-NEXT: Tag: DW_TAG_structure_type
; CHECK-NEXT: DW_IDX_type_unit: 0x00
; CHECK-NEXT: DW_IDX_die_offset: 0x00000023
+; CHECK-NEXT: DW_IDX_parent: true
; CHECK-NEXT: }
-; CHECK-NEXT: Entry @ 0xaa {
+; CHECK-NEXT: Entry @ {{.+}} {
; CHECK-NEXT: Abbrev: [[ABBREV1]]
; CHECK-NEXT: Tag: DW_TAG_structure_type
; CHECK-NEXT: DW_IDX_die_offset: 0x00000042
+; CHECK-NEXT: DW_IDX_parent: true
; CHECK-NEXT: }
; CHECK-NEXT: }
; CHECK-NEXT: ]
@@ -96,6 +104,7 @@
; CHECK-NEXT: Abbrev: [[ABBREV2]]
; CHECK-NEXT: Tag: DW_TAG_subprogram
; CHECK-NEXT: DW_IDX_die_offset: 0x00000023
+; CHECK-NEXT: DW_IDX_parent: true
; CHECK-NEXT: }
; CHECK-NEXT: }
; CHECK-NEXT: ]
@@ -108,6 +117,7 @@
; CHECK-NEXT: Tag: DW_TAG_base_type
; CHECK-NEXT: DW_IDX_type_unit: 0x00
; CHECK-NEXT: DW_IDX_die_offset: 0x00000038
+; CHECK-NEXT: DW_IDX_parent: true
; CHECK-NEXT: }
; CHECK-NEXT: }
; CHECK-NEXT: ]
@@ -120,7 +130,7 @@
; CHECK-SPLIT: Foreign TU count: 1
; CHECK-SPLIT-NEXT: Bucket count: 4
; CHECK-SPLIT-NEXT: Name count: 4
-; CHECK-SPLIT-NEXT: Abbreviations table size: 0x28
+; CHECK-SPLIT-NEXT: Abbreviations table size: 0x32
; CHECK-SPLIT-NEXT: Augmentation: 'LLVM0700'
; CHECK-SPLIT-NEXT: }
; CHECK-SPLIT-NEXT: Compilation Unit offsets [
@@ -130,27 +140,32 @@
; CHECK-SPLIT-NEXT: ForeignTU[0]: 0x675d23e4f33235f2
; CHECK-SPLIT-NEXT: ]
; CHECK-SPLIT-NEXT: Abbreviations [
-; CHECK-SPLIT-NEXT: Abbreviation [[ABBREV:0x[0-9a-f]*]] {
+; CHECK-SPLIT-NEXT: Abbreviation [[ABBREV1:0x[0-9a-f]*]] {
; CHECK-SPLIT-NEXT: Tag: DW_TAG_structure_type
+; CHECK-SPLIT-NEXT: DW_IDX_type_unit: DW_FORM_data1
; CHECK-SPLIT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+; CHECK-SPLIT-NEXT: DW_IDX_parent: DW_FORM_flag_present
; CHECK-SPLIT-NEXT: }
-; CHECK-SPLIT-NEXT: Abbreviation [[ABBREV1:0x[0-9a-f]*]] {
-; CHECK-SPLIT-NEXT: Tag: DW_TAG_structure_type
+; CHECK-SPLIT-NEXT: Abbreviation [[ABBREV4:0x[0-9a-f]*]] {
+; CHECK-SPLIT-NEXT: Tag: DW_TAG_base_type
; CHECK-SPLIT-NEXT: DW_IDX_type_unit: DW_FORM_data1
; CHECK-SPLIT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+; CHECK-SPLIT-NEXT: DW_IDX_parent: DW_FORM_flag_present
; CHECK-SPLIT-NEXT: }
; CHECK-SPLIT-NEXT: Abbreviation [[ABBREV2:0x[0-9a-f]*]] {
; CHECK-SPLIT-NEXT: Tag: DW_TAG_base_type
; CHECK-SPLIT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+; CHECK-SPLIT-NEXT: DW_IDX_parent: DW_FORM_flag_present
; CHECK-SPLIT-NEXT: }
-; CHECK-SPLIT-NEXT: Abbreviation [[ABBREV3:0x[0-9a-f]*]] {
-; CHECK-SPLIT-NEXT: Tag: DW_TAG_subprogram
+; CHECK-SPLIT-NEXT: Abbreviation [[ABBREV:0x[0-9a-f]*]] {
+; CHECK-SPLIT-NEXT: Tag: DW_TAG_structure_type
; CHECK-SPLIT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+; CHECK-SPLIT-NEXT: DW_IDX_parent: DW_FORM_flag_present
; CHECK-SPLIT-NEXT: }
-; CHECK-SPLIT-NEXT: Abbreviation [[ABBREV4:0x[0-9a-f]*]] {
-; CHECK-SPLIT-NEXT: Tag: DW_TAG_base_type
-; CHECK-SPLIT-NEXT: DW_IDX_type_unit: DW_FORM_data1
+; CHECK-SPLIT-NEXT: Abbreviation [[ABBREV3:0x[0-9a-f]*]] {
+; CHECK-SPLIT-NEXT: Tag: DW_TAG_subprogram
; CHECK-SPLIT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+; CHECK-SPLIT-NEXT: DW_IDX_parent: DW_FORM_flag_present
; CHECK-SPLIT-NEXT: }
; CHECK-SPLIT-NEXT: ]
; CHECK-SPLIT-NEXT: Bucket 0 [
@@ -161,6 +176,7 @@
; CHECK-SPLIT-NEXT: Abbrev: [[ABBREV2]]
; CHECK-SPLIT-NEXT: Tag: DW_TAG_base_type
; CHECK-SPLIT-NEXT: DW_IDX_die_offset: 0x00000035
+; CHECK-SPLIT-NEXT: DW_IDX_parent: true
; CHECK-SPLIT-NEXT: }
; CHECK-SPLIT-NEXT: }
; CHECK-SPLIT-NEXT: ]
@@ -173,11 +189,13 @@
; CHECK-SPLIT-NEXT: Tag: DW_TAG_structure_type
; CHECK-SPLIT-NEXT: DW_IDX_type_unit: 0x00
; CHECK-SPLIT-NEXT: DW_IDX_die_offset: 0x00000021
+; CHECK-SPLIT-NEXT: DW_IDX_parent: true
; CHECK-SPLIT-NEXT: }
-; CHECK-SPLIT-NEXT: Entry @ 0xae {
+; CHECK-SPLIT-NEXT: Entry @ {{.*}} {
; CHECK-SPLIT-NEXT: Abbrev: [[ABBREV]]
; CHECK-SPLIT-NEXT: Tag: DW_TAG_structure_type
; CHECK-SPLIT-NEXT: DW_IDX_die_offset: 0x00000039
+; CHECK-SPLIT-NEXT: DW_IDX_parent: true
; CHECK-SPLIT-NEXT: }
; CHECK-SPLIT-NEXT: }
; CHECK-SPLIT-NEXT: ]
@@ -189,6 +207,7 @@
; CHECK-SPLIT-NEXT: Abbrev: [[ABBREV3]]
; CHECK-SPLIT-NEXT: Tag: DW_TAG_subprogram
; CHECK-SPLIT-NEXT: DW_IDX_die_offset: 0x0000001a
+; CHECK-SPLIT-NEXT: DW_IDX_parent: true
; CHECK-SPLIT-NEXT: }
; CHECK-SPLIT-NEXT: }
; CHECK-SPLIT-NEXT: ]
@@ -201,6 +220,7 @@
; CHECK-SPLIT-NEXT: Tag: DW_TAG_base_type
; CHECK-SPLIT-NEXT: DW_IDX_type_unit: 0x00
; CHECK-SPLIT-NEXT: DW_IDX_die_offset: 0x00000036
+; CHECK-SPLIT-NEXT: DW_IDX_parent: true
; CHECK-SPLIT-NEXT: }
; CHECK-SPLIT-NEXT: }
; CHECK-SPLIT-NEXT: ]
diff --git a/llvm/test/tools/dsymutil/ARM/accel-imported-declarations.test b/llvm/test/tools/dsymutil/ARM/accel-imported-declarations.test
index 057e89d060b1d2..a8bf191e036f75 100644
--- a/llvm/test/tools/dsymutil/ARM/accel-imported-declarations.test
+++ b/llvm/test/tools/dsymutil/ARM/accel-imported-declarations.test
@@ -23,11 +23,13 @@ DWARF-NEXT: Entry {{.*}} {
DWARF-NEXT: Abbrev: {{.*}}
DWARF-NEXT: Tag: DW_TAG_namespace
DWARF: DW_IDX_die_offset: [[NAMESPACE]]
+DWARF-NEXT: DW_IDX_parent: 0x{{.*}}
DWARF-NEXT: }
DWARF-NEXT: Entry {{.*}} {
DWARF-NEXT: Abbrev: {{.*}}
DWARF: Tag: DW_TAG_imported_declaration
DWARF: DW_IDX_die_offset: 0x0000005c
+DWARF-NEXT: DW_IDX_parent: 0x{{.*}}
DWARF-NEXT: }
DWARF-NEXT: }
diff --git a/llvm/test/tools/dsymutil/ARM/dwarf5-dwarf4-combination-macho.test b/llvm/test/tools/dsymutil/ARM/dwarf5-dwarf4-combination-macho.test
index 0199bf28681bc4..5409b44bdb23b8 100644
--- a/llvm/test/tools/dsymutil/ARM/dwarf5-dwarf4-combination-macho.test
+++ b/llvm/test/tools/dsymutil/ARM/dwarf5-dwarf4-combination-macho.test
@@ -31,14 +31,14 @@
RUN: rm -rf %t.dir && mkdir -p %t.dir
RUN: dsymutil -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWARF5-DWARF4-combination -o %t.dir/dwarf5-dwarf4-combination-macho.dSYM
-RUN: llvm-dwarfdump %t.dir/dwarf5-dwarf4-combination-macho.dSYM -a --verbose | FileCheck %s
+RUN: llvm-dwarfdump %t.dir/dwarf5-dwarf4-combination-macho.dSYM -a --verbose | FileCheck %s --check-prefixes=CHECK,WITH-PARENTS
RUN: rm -rf %t.dir && mkdir -p %t.dir
RUN: dsymutil --no-odr --linker llvm -y %p/dummy-debug-map-amr64.map \
RUN: -oso-prepend-path=%p/../Inputs/DWARF5-DWARF4-combination \
RUN: -o %t.dir/dwarf5-dwarf4-combination-macho.dSYM
RUN: llvm-dwarfdump %t.dir/dwarf5-dwarf4-combination-macho.dSYM \
-RUN: -a --verbose | FileCheck %s
+RUN: -a --verbose | FileCheck %s --check-prefixes=CHECK,NO-PARENTS
### Uncomment following when llvm-dwarfdump will dump address ranges
### correctly for severall compile units case.
@@ -219,7 +219,10 @@ CHECK-NEXT: 0x00000028: 000000dc "int"
CHECK: .debug_names contents:
CHECK-NEXT: Name Index @ 0x0 {
CHECK-NEXT: Header {
-CHECK-NEXT: Length: 0xC4
+; FIXME: when the parallel dwarf linker is able to generate DW_IDX_parent,
+; these headers should be the same.
+WITH-PARENTS-NEXT: Length: 0xC8
+NO-PARENTS-NEXT: Length: 0xC4
CHECK-NEXT: Format: DWARF32
CHECK-NEXT: Version: 5
CHECK-NEXT: CU count: 2
@@ -227,6 +230,7 @@ CHECK-NEXT: Local TU count: 0
CHECK-NEXT: Foreign TU count: 0
CHECK-NEXT: Bucket count: 5
CHECK-NEXT: Name count: 5
-CHECK-NEXT: Abbreviations table size: 0x13
+WITH-PARENTS-NEXT: Abbreviations table size: 0x17
+NO-PARENTS-NEXT: Abbreviations table size: 0x13
CHECK-NEXT: Augmentation: 'LLVM0700'
CHECK-NEXT: }
>From 58b6d9b4038ce77d128e0fa5647e81d73f8efaec Mon Sep 17 00:00:00 2001
From: Felipe de Azevedo Piovezan <fpiovezan at apple.com>
Date: Thu, 7 Dec 2023 11:24:39 -0800
Subject: [PATCH 5/7] [llvm][DebugNames] Implement Entry::GetParentEntry query
---
.../DebugInfo/DWARF/DWARFAcceleratorTable.h | 17 +++++++++++++++++
.../DebugInfo/DWARF/DWARFAcceleratorTable.cpp | 15 +++++++++++++++
llvm/test/CodeGen/X86/dwarf-headers.o | 0
3 files changed, 32 insertions(+)
create mode 100644 llvm/test/CodeGen/X86/dwarf-headers.o
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
index b89536bc0c7230..de743216677938 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
@@ -460,6 +460,16 @@ class DWARFDebugNames : public DWARFAcceleratorTable {
/// Returns the Offset of the DIE within the containing CU or TU.
std::optional<uint64_t> getDIEUnitOffset() const;
+ /// Returns true if this Entry has information about its parent DIE (i.e. if
+ /// it has an IDX_parent attribute)
+ bool hasParentInformation() const;
+
+ /// Returns the Entry corresponding to the parent of the DIE represented by
+ /// `this` Entry. If the parent is not in the table, nullopt is returned.
+ /// Precondition: hasParentInformation() == true.
+ /// An error is returned for ill-formed tables.
+ Expected<std::optional<DWARFDebugNames::Entry>> getParentDIEEntry() const;
+
/// Return the Abbreviation that can be used to interpret the raw values of
/// this Accelerator Entry.
const Abbrev &getAbbrev() const { return *Abbr; }
@@ -609,6 +619,13 @@ class DWARFDebugNames : public DWARFAcceleratorTable {
Expected<Entry> getEntry(uint64_t *Offset) const;
+ // Returns the Entry at the relative `Offset` from the start of the Entry
+ // pool.
+ Expected<Entry> getEntryAtRelativeOffset(uint64_t Offset) const {
+ auto OffsetFromSection = Offset + this->EntriesBase;
+ return getEntry(&OffsetFromSection);
+ }
+
/// Look up all entries in this Name Index matching \c Key.
iterator_range<ValueIterator> equal_range(StringRef Key) const;
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
index 0f9c8ef485d456..d09c5e541a9cc9 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
@@ -611,6 +611,10 @@ DWARFDebugNames::Entry::lookup(dwarf::Index Index) const {
return std::nullopt;
}
+bool DWARFDebugNames::Entry::hasParentInformation() const {
+ return lookup(dwarf::DW_IDX_parent).has_value();
+}
+
std::optional<uint64_t> DWARFDebugNames::Entry::getDIEUnitOffset() const {
if (std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_die_offset))
return Off->getAsReferenceUVal();
@@ -650,6 +654,17 @@ std::optional<uint64_t> DWARFDebugNames::Entry::getLocalTUIndex() const {
return std::nullopt;
}
+Expected<std::optional<DWARFDebugNames::Entry>>
+DWARFDebugNames::Entry::getParentDIEEntry() const {
+ // The offset of the accelerator table entry for the parent.
+ std::optional<DWARFFormValue> ParentEntryOff = lookup(dwarf::DW_IDX_parent);
+ assert(ParentEntryOff.has_value() && "hasParentInformation() must be called");
+
+ if (ParentEntryOff->getForm() == dwarf::Form::DW_FORM_flag_present)
+ return std::nullopt;
+ return NameIdx->getEntryAtRelativeOffset(ParentEntryOff->getRawUValue());
+}
+
void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const {
W.startLine() << formatv("Abbrev: {0:x}\n", Abbr->Code);
W.startLine() << formatv("Tag: {0}\n", Abbr->Tag);
diff --git a/llvm/test/CodeGen/X86/dwarf-headers.o b/llvm/test/CodeGen/X86/dwarf-headers.o
new file mode 100644
index 00000000000000..e69de29bb2d1d6
>From 9ca21052af4bbcf8d0bc76a8b13b4d4a27632e13 Mon Sep 17 00:00:00 2001
From: Felipe de Azevedo Piovezan <fpiovezan at apple.com>
Date: Thu, 7 Dec 2023 11:26:52 -0800
Subject: [PATCH 6/7] [lldb][DWARFUnit] Implement PeekDIEName query
This allows us to not parse the entire DIE.
---
lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp | 7 +++++++
lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h | 5 +++++
lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp | 8 ++++++++
lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h | 5 +++++
4 files changed, 25 insertions(+)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
index 553b6a4c551d20..775b7a2e73f512 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
@@ -191,3 +191,10 @@ 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();
+}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
index d5e48f312ea0e9..a8b5abc3beed2d 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
@@ -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
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
index 0e2f4d45543bb5..7db279ed37d04a 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
@@ -663,6 +663,14 @@ DWARFUnit::GetDIE(dw_offset_t die_offset) {
return DWARFDIE(); // Not found
}
+llvm::StringRef DWARFUnit::PeekDIEName(dw_offset_t die_offset) {
+ const DWARFDataExtractor &data = GetData();
+ DWARFDebugInfoEntry die;
+ if (!die.Extract(data, this, &die_offset))
+ return llvm::StringRef();
+ return die.GetName(this);
+}
+
DWARFUnit &DWARFUnit::GetNonSkeletonUnit() {
ExtractUnitDIEIfNeeded();
if (m_dwo)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
index 3f528e913d8cfa..bc225a52e1d030 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
@@ -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);
>From 6f62cfd1b5099180c206a69a9ccdb3f216ee97fa Mon Sep 17 00:00:00 2001
From: Felipe de Azevedo Piovezan <fpiovezan at apple.com>
Date: Thu, 4 Jan 2024 12:56:25 -0300
Subject: [PATCH 7/7] [lldb][DWARFIndex] Use IDX_parent to implement
GetFullyQualifiedType query
This commit changes DebugNamesDWARFIndex so that it now overrides
`GetFullyQualifiedType` and attempts to use DW_IDX_parent, when available, to
speed up such queries. When this type of information is not available, the
base-class implementation is used.
---
.../SymbolFile/DWARF/DebugNamesDWARFIndex.cpp | 96 +++++++++++++++++++
.../SymbolFile/DWARF/DebugNamesDWARFIndex.h | 9 ++
2 files changed, 105 insertions(+)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
index b718f98340a70b..8a82a77e6b1642 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
@@ -218,6 +218,102 @@ void DebugNamesDWARFIndex::GetCompleteObjCClass(
m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, callback);
}
+namespace {
+using Entry = llvm::DWARFDebugNames::Entry;
+
+// If `entry` and all of its parents have an `IDX_parent`, use that information
+// to build and return a list of at most `max_parents` parent Entries.
+// `entry` itself is not included in the list.
+// If any parent does not have an `IDX_parent`, nullopt is returned.
+static std::optional<llvm::SmallVector<Entry, 4>>
+getParentChain(Entry entry, uint32_t max_parents) {
+ llvm::SmallVector<Entry, 4> parent_entries;
+
+ do {
+ if (!entry.hasParentInformation())
+ return std::nullopt;
+
+ llvm::Expected<std::optional<Entry>> parent = entry.getParentDIEEntry();
+ if (!parent) { // Bad data.
+ consumeError(parent.takeError());
+ return std::nullopt;
+ }
+
+ // Last parent in the chain
+ if (!parent->has_value())
+ break;
+
+ parent_entries.push_back(**parent);
+ entry = **parent;
+ } while (parent_entries.size() < max_parents);
+
+ return parent_entries;
+}
+} // namespace
+
+void DebugNamesDWARFIndex::GetFullyQualifiedType(
+ const DWARFDeclContext &context,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+
+ // Fallback: use the base class implementation.
+ auto fallback_impl = [&](const DebugNames::Entry &entry) {
+ return ProcessEntry(entry, [&](DWARFDIE die) {
+ return GetFullyQualifiedTypeImpl(context, die, callback);
+ });
+ };
+
+ auto qualified_names = context.GetQualifiedNameAsVector();
+ if (qualified_names.empty())
+ return;
+ auto leaf_name = qualified_names.front();
+ auto parent_names = llvm::makeArrayRef(qualified_names).drop_front();
+
+ for (const DebugNames::Entry &entry :
+ m_debug_names_up->equal_range(leaf_name)) {
+ if (!isType(entry.tag()))
+ continue;
+
+ // Grab at most one extra parent, extra parents are not useful to test
+ // equality.
+ auto parent_chain = getParentChain(entry, parent_names.size() + 1);
+
+ if (!parent_chain) {
+ if (!fallback_impl(entry))
+ return;
+ continue;
+ }
+
+ if (CheckParentChain(parent_names, *parent_chain) &&
+ (!ProcessEntry(entry, callback)))
+ return;
+ }
+}
+
+bool DebugNamesDWARFIndex::CheckParentChain(
+ llvm::ArrayRef<llvm::StringRef> expected_parent_names,
+ llvm::ArrayRef<DebugNames::Entry> parent_entries) const {
+
+ if (parent_entries.size() != expected_parent_names.size())
+ return false;
+
+ auto CompareEntryATName = [this](llvm::StringRef expected_name,
+ const DebugNames::Entry &entry) {
+ auto maybe_dieoffset = entry.getDIEUnitOffset();
+ if (!maybe_dieoffset)
+ return false;
+ auto die_ref = ToDIERef(entry);
+ if (!die_ref)
+ return false;
+ return expected_name == m_debug_info.PeekDIEName(*die_ref);
+ };
+
+ for (auto [expected_parent_name, parent_entry] :
+ llvm::zip_equal(expected_parent_names, parent_entries))
+ if (!CompareEntryATName(expected_parent_name, parent_entry))
+ return false;
+ return true;
+}
+
void DebugNamesDWARFIndex::GetTypes(
ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
for (const DebugNames::Entry &entry :
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h
index cca0913c4124c9..15eff7a2659633 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h
@@ -14,6 +14,7 @@
#include "Plugins/SymbolFile/DWARF/ManualDWARFIndex.h"
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
#include "lldb/Utility/ConstString.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
#include <optional>
@@ -42,6 +43,11 @@ class DebugNamesDWARFIndex : public DWARFIndex {
void GetCompleteObjCClass(
ConstString class_name, bool must_be_implementation,
llvm::function_ref<bool(DWARFDIE die)> callback) override;
+
+ /// Uses DWARF5's IDX_parent fields, when available, to speed up this query.
+ void GetFullyQualifiedType(
+ const DWARFDeclContext &context,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
void GetTypes(ConstString name,
llvm::function_ref<bool(DWARFDIE die)> callback) override;
void GetTypes(const DWARFDeclContext &context,
@@ -83,6 +89,9 @@ class DebugNamesDWARFIndex : public DWARFIndex {
bool ProcessEntry(const DebugNames::Entry &entry,
llvm::function_ref<bool(DWARFDIE die)> callback);
+ bool CheckParentChain(llvm::ArrayRef<llvm::StringRef> parent_names,
+ llvm::ArrayRef<DebugNames::Entry> parent_entries) const;
+
static void MaybeLogLookupError(llvm::Error error,
const DebugNames::NameIndex &ni,
llvm::StringRef name);
More information about the lldb-commits
mailing list