[Lldb-commits] [lldb] [llvm] [DO NOT MERGE][DebugInfo] Implement debug_names's IDX_parent attribute (PR #75365)
Felipe de Azevedo Piovezan via lldb-commits
lldb-commits at lists.llvm.org
Wed Dec 13 09:59:56 PST 2023
https://github.com/felipepiovezan created https://github.com/llvm/llvm-project/pull/75365
The commits are meant to be looked at one at a time
>From ece936d56a22dad7f604d6610d02a9a59bac0345 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 1/9] [DWARFDeclContext] Add helper function to extract
qualified names as vector
squash_23540ceb4639
---
lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp | 6 ++++++
lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h | 5 +++++
2 files changed, 11 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 {
>From 81b7009a751430593a6e20aba5dd677ca5ffebe9 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 2/9] [DebugNames] Implement DW_IDX_parent entries
squash_81501dd8dcd1
---
llvm/include/llvm/CodeGen/AccelTable.h | 24 ++++++++--
llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp | 46 +++++++++++++++++--
llvm/lib/DWARFLinker/DWARFLinker.cpp | 8 ++++
.../DWARFLinkerParallel/DWARFLinkerImpl.cpp | 3 +-
.../lib/DWARFLinkerParallel/DWARFLinkerUnit.h | 3 ++
5 files changed, 74 insertions(+), 10 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/AccelTable.h b/llvm/include/llvm/CodeGen/AccelTable.h
index 0f35fd3514fae7..b6662232ce5137 100644
--- a/llvm/include/llvm/CodeGen/AccelTable.h
+++ b/llvm/include/llvm/CodeGen/AccelTable.h
@@ -262,9 +262,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;
@@ -281,14 +284,24 @@ class DWARF5AccelTableData : public AccelTableData {
void normalizeDIEToOffset() {
assert(std::holds_alternative<const DIE *>(OffsetVal) &&
"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(std::holds_alternative<uint64_t>(OffsetVal) &&
+ "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 +350,8 @@ class DWARF5AccelTable : public AccelTable<DWARF5AccelTableData> {
for (auto &Entry : Table.getEntries()) {
for (AccelTableData *Value : Entry.second.Values) {
DWARF5AccelTableData *Data = static_cast<DWARF5AccelTableData *>(Value);
- 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 d6f487c18b0301..f1ad8db8acd4e2 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
@@ -30,6 +30,9 @@
using namespace llvm;
+static cl::opt<bool> EnableParents("enable-debugname-parents", cl::init(false),
+ cl::Hidden);
+
void AccelTableBase::computeBucketCount() {
// First get the number of unique hashes.
std::vector<uint32_t> Uniques;
@@ -224,6 +227,8 @@ class Dwarf5AccelTableWriter : public AccelTableWriter {
MCSymbol *EntryPool = Asm->createTempSymbol("names_entries");
// Indicates if this module is built with Split Dwarf enabled.
bool IsSplitDwarf = false;
+ DenseMap<uint64_t, MCSymbol *> DieOffsetToAccelEntrySymbol;
+ llvm::DenseSet<MCSymbol *> EmittedAccelEntrySymbols;
void populateAbbrevsMap();
@@ -232,8 +237,8 @@ class Dwarf5AccelTableWriter : public AccelTableWriter {
void emitBuckets() const;
void emitStringOffsets() const;
void emitAbbrevs() const;
- void emitEntry(const DataT &Entry) const;
- void emitData() const;
+ void emitEntry(const DataT &Entry);
+ void emitData();
public:
Dwarf5AccelTableWriter(
@@ -414,6 +419,8 @@ static uint32_t constructAbbreviationTag(
if (EntryRet)
AbbrvTag |= 1 << EntryRet->Endoding.Index;
AbbrvTag |= 1 << dwarf::DW_IDX_die_offset;
+ if (EnableParents)
+ AbbrvTag |= 1 << dwarf::DW_IDX_parent;
AbbrvTag |= Tag << LowerBitSize;
return AbbrvTag;
}
@@ -431,6 +438,8 @@ void Dwarf5AccelTableWriter<DataT>::populateAbbrevsMap() {
if (EntryRet)
UA.push_back(EntryRet->Endoding);
UA.push_back({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
+ if (EnableParents)
+ UA.push_back({dwarf::DW_IDX_parent, dwarf::DW_FORM_ref4});
Abbreviations.try_emplace(AbbrvTag, UA);
}
}
@@ -507,7 +516,7 @@ void Dwarf5AccelTableWriter<DataT>::emitAbbrevs() const {
}
template <typename DataT>
-void Dwarf5AccelTableWriter<DataT>::emitEntry(const DataT &Entry) const {
+void Dwarf5AccelTableWriter<DataT>::emitEntry(const DataT &Entry) {
std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
getIndexForEntry(Entry);
uint32_t AbbrvTag = constructAbbreviationTag(Entry.getDieTag(), EntryRet);
@@ -516,6 +525,18 @@ void Dwarf5AccelTableWriter<DataT>::emitEntry(const DataT &Entry) const {
"Why wasn't this abbrev generated?");
assert(getTagFromAbbreviationTag(AbbrevIt->first) == Entry.getDieTag() &&
"Invalid Tag");
+
+ // Create a label for this Entry, if not yet created by a IDX_parent
+ // reference to the same underlying DIE.
+ MCSymbol *&EntrySymbol = DieOffsetToAccelEntrySymbol[Entry.getDieOffset()];
+ if (EntrySymbol == nullptr)
+ EntrySymbol = Asm->createTempSymbol("symbol");
+
+ // Emit the label for this Entry, if a label hasn't yet been emitted for some
+ // other Entry of the same underlying DIE (a DIE may have multiple Entries).
+ if (EmittedAccelEntrySymbols.insert(EntrySymbol).second)
+ Asm->OutStreamer->emitLabel(EntrySymbol);
+
Asm->emitULEB128(AbbrevIt->first, "Abbreviation code");
for (const auto &AttrEnc : AbbrevIt->second) {
@@ -531,13 +552,25 @@ void Dwarf5AccelTableWriter<DataT>::emitEntry(const DataT &Entry) const {
assert(AttrEnc.Form == dwarf::DW_FORM_ref4);
Asm->emitInt32(Entry.getDieOffset());
break;
+ case dwarf::DW_IDX_parent: {
+ // If a DIE is being placed on the table, its parent is always non-null
+ // (top-level DIEs are not placed in the table), though the parent may not
+ // be indexed. Bad input is handled like a parent that is not indexed,
+ // i.e., with an offset that is not in the table.
+ uint64_t ParentOffset = Entry.getParentDieOffset().value_or(-1);
+ MCSymbol *&ParentSymbol = DieOffsetToAccelEntrySymbol[ParentOffset];
+ if (ParentSymbol == nullptr)
+ ParentSymbol = Asm->createTempSymbol("symbol");
+ Asm->emitLabelDifference(ParentSymbol, EntryPool, 4);
+ break;
+ }
default:
llvm_unreachable("Unexpected index attribute!");
}
}
}
-template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emitData() const {
+template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emitData() {
Asm->OutStreamer->emitLabel(EntryPool);
for (auto &Bucket : Contents.getBuckets()) {
for (auto *Hash : Bucket) {
@@ -549,6 +582,11 @@ template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emitData() const {
Asm->emitInt8(0);
}
}
+ // Any labels not yet emitted refer to DIEs that are not present in the
+ // accelerator table. Point them to end of the table.
+ for (MCSymbol *Symbol : make_second_range(DieOffsetToAccelEntrySymbol))
+ if (EmittedAccelEntrySymbols.insert(Symbol).second)
+ Asm->OutStreamer->emitLabel(Symbol);
}
template <typename DataT>
diff --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp
index 1a7ea47adc5ca3..c8e1948326d2b8 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..2f514b6140f4aa 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, Info.ParentOutOffset, Info.Tag,
+ CU->getUniqueID());
} break;
default:
diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h b/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h
index 9640a8ee711eb0..4ca1920208761c 100644
--- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h
@@ -125,6 +125,9 @@ class DwarfUnit : public OutputSections {
/// Output offset of the DIE this entry describes.
uint64_t OutOffset;
+ /// Output offset of the parent of the DIE this entry describes.
+ std::optional<uint64_t> ParentOutOffset;
+
/// Hash of the fully qualified name.
uint32_t QualifiedNameHash = 0;
>From ba88a1f639c23f4bc5e0aba49a6d93ae1ad6c99d 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 3/9] [DebugNames] Implement Entry::GetParentEntry query
squash_0caa45fd3e26
---
.../llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h | 12 ++++++++++++
llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp | 10 ++++++++++
llvm/test/CodeGen/X86/dwarf-headers.o | 0
3 files changed, 22 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..0fabe98210f423 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
@@ -460,6 +460,11 @@ class DWARFDebugNames : public DWARFAcceleratorTable {
/// Returns the Offset of the DIE within the containing CU or TU.
std::optional<uint64_t> getDIEUnitOffset() const;
+ /// Returns the Entry corresponding to the parent of the DIE represented by
+ /// `this` Entry. If the parent DIE is not indexed by this table, or if this
+ /// table does not track parents through IDX_parent, an error is returned.
+ Expected<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 +614,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..b0f9953d46ee85 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
@@ -650,6 +650,16 @@ std::optional<uint64_t> DWARFDebugNames::Entry::getLocalTUIndex() const {
return std::nullopt;
}
+Expected<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);
+ if (!ParentEntryOff)
+ return createStringError(errc::illegal_byte_sequence,
+ "Incorrectly terminated entry list.");
+ 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 5fc385893eb35df8264aec9f5149bd2889317015 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 4/9] [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 6f771c66a725cf..b82f2df0010c61 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 bf4ce83e43186221b0a99768171bf8756f9d30b3 Mon Sep 17 00:00:00 2001
From: Felipe de Azevedo Piovezan <fpiovezan at apple.com>
Date: Wed, 13 Dec 2023 13:57:07 -0300
Subject: [PATCH 5/9] [DebugNames] Implement supportsIdxParent query
---
llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h | 8 ++++++++
llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp | 5 +++++
2 files changed, 13 insertions(+)
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
index 0fabe98210f423..13ba8269fc3d19 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
@@ -557,6 +557,7 @@ class DWARFDebugNames : public DWARFAcceleratorTable {
uint64_t StringOffsetsBase;
uint64_t EntryOffsetsBase;
uint64_t EntriesBase;
+ bool HasIdxParent = false;
void dumpCUs(ScopedPrinter &W) const;
void dumpLocalTUs(ScopedPrinter &W) const;
@@ -770,6 +771,13 @@ class DWARFDebugNames : public DWARFAcceleratorTable {
/// Return the Name Index covering the compile unit at CUOffset, or nullptr if
/// there is no Name Index covering that unit.
const NameIndex *getCUNameIndex(uint64_t CUOffset);
+
+ /// Returns true if all the NameIndices in this table provide IDX_parent
+ /// capabilities.
+ bool supportsIdxParent() const {
+ return all_of(NameIndices,
+ [](const NameIndex &Idx) { return Idx.HasIdxParent; });
+ }
};
/// If `Name` is the name of a templated function that includes template
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
index b0f9953d46ee85..ef06cb68665882 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
@@ -578,6 +578,10 @@ Error DWARFDebugNames::NameIndex::extract() {
"Section too small: cannot read abbreviations.");
EntriesBase = Offset + Hdr.AbbrevTableSize;
+ HasIdxParent = false;
+ auto IsIdxParent = [](auto IdxFormPair) {
+ return IdxFormPair.Index == dwarf::Index::DW_IDX_parent;
+ };
for (;;) {
auto AbbrevOr = extractAbbrev(&Offset);
@@ -585,6 +589,7 @@ Error DWARFDebugNames::NameIndex::extract() {
return AbbrevOr.takeError();
if (isSentinel(*AbbrevOr))
return Error::success();
+ HasIdxParent |= any_of(AbbrevOr->Attributes, IsIdxParent);
if (!Abbrevs.insert(std::move(*AbbrevOr)).second)
return createStringError(errc::invalid_argument,
>From 585b765a4a26ac208321f13a7eb35341c91389d1 Mon Sep 17 00:00:00 2001
From: Felipe de Azevedo Piovezan <fpiovezan at apple.com>
Date: Thu, 7 Dec 2023 11:27:47 -0800
Subject: [PATCH 6/9] [DWARFIndex] Implement GetFullyQualifiedType query
Combines:
1. the accelerator table capability of finding parents
2. the DWARFUnit capability of finding the name of a DIE without parsing the
whole CU.
---
.../Plugins/SymbolFile/DWARF/DWARFIndex.cpp | 19 +++++++
.../Plugins/SymbolFile/DWARF/DWARFIndex.h | 8 +++
.../SymbolFile/DWARF/DebugNamesDWARFIndex.cpp | 49 +++++++++++++++++++
.../SymbolFile/DWARF/DebugNamesDWARFIndex.h | 5 ++
4 files changed, 81 insertions(+)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
index b1c323b101cef3..bc3477d9e86e56 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "Plugins/SymbolFile/DWARF/DWARFIndex.h"
+#include "DWARFDeclContext.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
#include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
@@ -112,3 +113,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) {
+ auto qualified_names = context.GetQualifiedNameAsVector();
+ if (qualified_names.empty())
+ return;
+ auto parent_names = llvm::makeArrayRef(qualified_names).drop_front();
+ GetTypes(context, [&](DWARFDIE die) {
+ auto original_die = die;
+ for (auto parent_name : parent_names) {
+ die = die.GetParent();
+ if (!die || die.GetName() != parent_name)
+ return false;
+ }
+ return callback(original_die);
+ });
+}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
index 9aadeddbb21753..4fd10a634fc57f 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;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
index 7c253553d57b48..5cc60a3ca8dad7 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
@@ -218,6 +218,55 @@ void DebugNamesDWARFIndex::GetCompleteObjCClass(
m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, callback);
}
+void DebugNamesDWARFIndex::GetFullyQualifiedType(
+ const DWARFDeclContext &context,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ if (!m_debug_names_up->supportsIdxParent())
+ return DWARFIndex::GetFullyQualifiedType(context, callback);
+
+ auto qualified_names = context.GetQualifiedNameAsVector();
+ if (qualified_names.empty())
+ return;
+
+ 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);
+ };
+
+ auto parent_names = llvm::makeArrayRef(qualified_names).drop_front();
+ auto CheckParentChain = [&](DebugNames::Entry entry) {
+ for (auto expected_name : parent_names) {
+ auto maybe_parent_entry = entry.getParentDIEEntry();
+ if (!maybe_parent_entry) {
+ consumeError(maybe_parent_entry.takeError());
+ return false;
+ }
+ entry = *maybe_parent_entry;
+ if (!CompareEntryATName(expected_name, entry))
+ return false;
+ }
+ /// All expected names matched. The remaining entry should have no parent
+ /// for a match to occur.
+ auto maybe_parent_entry = entry.getParentDIEEntry();
+ if (maybe_parent_entry)
+ return false;
+ consumeError(maybe_parent_entry.takeError());
+ return true;
+ };
+
+ auto leaf_matches = m_debug_names_up->equal_range(qualified_names.front());
+ for (const DebugNames::Entry &entry : leaf_matches)
+ if (isType(entry.tag()) && CheckParentChain(entry) &&
+ (!ProcessEntry(entry, callback)))
+ return;
+}
+
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 7ce630a56137d1..72d02ca0064969 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h
@@ -42,6 +42,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,
>From a753876917d39345275eded75e561f741b20cf5d Mon Sep 17 00:00:00 2001
From: Felipe de Azevedo Piovezan <fpiovezan at apple.com>
Date: Mon, 11 Dec 2023 12:44:39 -0300
Subject: [PATCH 7/9] [SymbolFileDWARF] Use DWARFIndex::GetFullyQualifiedType
query
---
lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index d4c573ecd468c4..c3c79d20bc1d86 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -3115,7 +3115,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++.
@@ -3142,9 +3142,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::"
@@ -3154,10 +3153,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 a8733ef68947279638c8c2de982a91562530a0f8 Mon Sep 17 00:00:00 2001
From: Felipe de Azevedo Piovezan <fpiovezan at apple.com>
Date: Tue, 12 Dec 2023 16:04:31 -0300
Subject: [PATCH 8/9] [AsmPrinter][AccelTable] Make IDX_parent on by default
---
llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp b/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
index f1ad8db8acd4e2..87c7b547e4d7e3 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
@@ -30,7 +30,7 @@
using namespace llvm;
-static cl::opt<bool> EnableParents("enable-debugname-parents", cl::init(false),
+static cl::opt<bool> EnableParents("enable-debugname-parents", cl::init(true),
cl::Hidden);
void AccelTableBase::computeBucketCount() {
>From 4d3fa42597ae39f41dc338cec1489d885f34eec7 Mon Sep 17 00:00:00 2001
From: Felipe de Azevedo Piovezan <fpiovezan at apple.com>
Date: Tue, 17 Oct 2023 09:27:19 -0700
Subject: [PATCH 9/9] [lldb] Add timer to EvaluateExpression method
---
lldb/source/Commands/CommandObjectExpression.cpp | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp
index 3a2dc11e1e71cc..59ea097fe82378 100644
--- a/lldb/source/Commands/CommandObjectExpression.cpp
+++ b/lldb/source/Commands/CommandObjectExpression.cpp
@@ -414,6 +414,8 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr,
Stream &output_stream,
Stream &error_stream,
CommandReturnObject &result) {
+ auto start = std::chrono::steady_clock::now();
+
// Don't use m_exe_ctx as this might be called asynchronously after the
// command object DoExecute has finished when doing multi-line expression
// that use an input reader...
@@ -514,6 +516,9 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr,
error_stream.Printf("error: unknown error\n");
}
+ auto end = std::chrono::steady_clock::now();
+ auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
+ error_stream.Printf("Finished expr in: %" PRIu64, duration.count());
return (success != eExpressionSetupError &&
success != eExpressionParseError);
}
More information about the lldb-commits
mailing list