[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
Tue Jan 2 05:15:36 PST 2024
https://github.com/felipepiovezan updated https://github.com/llvm/llvm-project/pull/75365
>From 1fafdee241e98c469a3a06e29d4a375bd8af1ca0 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] [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 7a382cd2ad261808c3aa014590a9120d7900cfa1 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] [llvm][DebugNames] Implement DW_IDX_parent entries
---
llvm/include/llvm/CodeGen/AccelTable.h | 24 ++++++++---
llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp | 43 ++++++++++++++++---
llvm/lib/DWARFLinker/DWARFLinker.cpp | 8 ++++
.../DWARFLinkerParallel/DWARFLinkerImpl.cpp | 3 +-
.../lib/DWARFLinkerParallel/DWARFLinkerUnit.h | 3 ++
5 files changed, 70 insertions(+), 11 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/AccelTable.h b/llvm/include/llvm/CodeGen/AccelTable.h
index 6eb09f32f9f951..725b434868d21e 100644
--- a/llvm/include/llvm/CodeGen/AccelTable.h
+++ b/llvm/include/llvm/CodeGen/AccelTable.h
@@ -261,9 +261,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;
@@ -278,14 +281,24 @@ 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(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;
@@ -334,7 +347,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 30ea7eef3a12ba..f96971680a621c 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
@@ -224,6 +224,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 +234,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 +416,7 @@ static uint32_t constructAbbreviationTag(
if (EntryRet)
AbbrvTag |= 1 << EntryRet->Encoding.Index;
AbbrvTag |= 1 << dwarf::DW_IDX_die_offset;
+ AbbrvTag |= 1 << dwarf::DW_IDX_parent;
AbbrvTag |= Tag << LowerBitSize;
return AbbrvTag;
}
@@ -427,10 +430,11 @@ void Dwarf5AccelTableWriter<DataT>::populateAbbrevsMap() {
unsigned Tag = static_cast<const DataT *>(Value)->getDieTag();
uint32_t AbbrvTag = constructAbbreviationTag(Tag, EntryRet);
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});
+ UA.push_back({dwarf::DW_IDX_parent, dwarf::DW_FORM_ref4});
Abbreviations.try_emplace(AbbrvTag, UA);
}
}
@@ -507,7 +511,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 +520,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 +547,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 +577,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 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..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 d0a2150a5b374006933a4b872fdc85211c9d2967 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] [llvm][DebugNames] Implement Entry::GetParentEntry query
---
.../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 b922242102039abd394738687fe193c3c796db3e 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 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 f0cf444830f8e358e9db4668481dc3c5387422bd 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] [llvm][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 7b077b17005adf1390eb9a4190b73697a1cad775 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] [lldb][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 fa922cf93bd5efa29f749ecc92e7ddfaeea69851 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] [lldb][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 505ea29ca4d4f5..e7dc9115cd80e7 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -3095,7 +3095,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++.
@@ -3122,9 +3122,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::"
@@ -3134,10 +3133,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 837bc0f476820f9ee5695223420105dedfea8d79 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 8/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);
}
>From 0450d05d26418796de24083acb240feec9f058d3 Mon Sep 17 00:00:00 2001
From: Felipe de Azevedo Piovezan <fpiovezan at apple.com>
Date: Tue, 2 Jan 2024 10:14:39 -0300
Subject: [PATCH 9/9] wip_dense_map_of_offsets_per_entry
---
llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp b/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
index f96971680a621c..6714eff3e16708 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"
@@ -211,7 +212,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;
@@ -234,7 +235,8 @@ class Dwarf5AccelTableWriter : public AccelTableWriter {
void emitBuckets() const;
void emitStringOffsets() const;
void emitAbbrevs() const;
- void emitEntry(const DataT &Entry);
+ void emitEntry(const DataT &Entry,
+ const DenseSet<uint64_t> &OffsetsOfIndexedDIEs);
void emitData();
public:
@@ -511,7 +513,8 @@ void Dwarf5AccelTableWriter<DataT>::emitAbbrevs() const {
}
template <typename DataT>
-void Dwarf5AccelTableWriter<DataT>::emitEntry(const DataT &Entry) {
+void Dwarf5AccelTableWriter<DataT>::emitEntry(
+ const DataT &Entry, const DenseSet<uint64_t> &OffsetsOfIndexedDIEs) {
std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
getIndexForEntry(Entry);
uint32_t AbbrvTag = constructAbbreviationTag(Entry.getDieTag(), EntryRet);
@@ -566,13 +569,20 @@ void Dwarf5AccelTableWriter<DataT>::emitEntry(const DataT &Entry) {
}
template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emitData() {
+ DenseSet<uint64_t> OffsetsOfIndexedDIEs;
+ for (auto &Bucket : Contents.getBuckets())
+ for (auto *Hash : Bucket)
+ for (const auto *Value : Hash->Values)
+ OffsetsOfIndexedDIEs.insert(
+ static_cast<const DataT *>(Value)->getDieOffset());
+
Asm->OutStreamer->emitLabel(EntryPool);
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 DataT *>(Value));
+ emitEntry(*static_cast<const DataT *>(Value), OffsetsOfIndexedDIEs);
Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString());
Asm->emitInt8(0);
}
More information about the lldb-commits
mailing list