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 <fpiove...@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 <fpiove...@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 <fpiove...@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 <fpiove...@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 <fpiove...@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 <fpiove...@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 <fpiove...@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 <fpiove...@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 <fpiove...@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); } _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits