https://github.com/felipepiovezan updated https://github.com/llvm/llvm-project/pull/77121
>From 6d5fec644004c4c1ad84ef29761306651f22fcf7 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 1/3] [llvm][DebugNames] Implement Entry::GetParentEntry query --- .../DebugInfo/DWARF/DWARFAcceleratorTable.h | 17 +++++++++++++++++ .../DebugInfo/DWARF/DWARFAcceleratorTable.cpp | 15 +++++++++++++++ llvm/test/CodeGen/X86/dwarf-headers.o | 0 3 files changed, 32 insertions(+) create mode 100644 llvm/test/CodeGen/X86/dwarf-headers.o diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h index b89536bc0c7230c..de743216677938b 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h @@ -460,6 +460,16 @@ class DWARFDebugNames : public DWARFAcceleratorTable { /// Returns the Offset of the DIE within the containing CU or TU. std::optional<uint64_t> getDIEUnitOffset() const; + /// Returns true if this Entry has information about its parent DIE (i.e. if + /// it has an IDX_parent attribute) + bool hasParentInformation() const; + + /// Returns the Entry corresponding to the parent of the DIE represented by + /// `this` Entry. If the parent is not in the table, nullopt is returned. + /// Precondition: hasParentInformation() == true. + /// An error is returned for ill-formed tables. + Expected<std::optional<DWARFDebugNames::Entry>> getParentDIEEntry() const; + /// Return the Abbreviation that can be used to interpret the raw values of /// this Accelerator Entry. const Abbrev &getAbbrev() const { return *Abbr; } @@ -609,6 +619,13 @@ class DWARFDebugNames : public DWARFAcceleratorTable { Expected<Entry> getEntry(uint64_t *Offset) const; + // Returns the Entry at the relative `Offset` from the start of the Entry + // pool. + Expected<Entry> getEntryAtRelativeOffset(uint64_t Offset) const { + auto OffsetFromSection = Offset + this->EntriesBase; + return getEntry(&OffsetFromSection); + } + /// Look up all entries in this Name Index matching \c Key. iterator_range<ValueIterator> equal_range(StringRef Key) const; diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp index 0f9c8ef485d456e..d09c5e541a9cc9a 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -611,6 +611,10 @@ DWARFDebugNames::Entry::lookup(dwarf::Index Index) const { return std::nullopt; } +bool DWARFDebugNames::Entry::hasParentInformation() const { + return lookup(dwarf::DW_IDX_parent).has_value(); +} + std::optional<uint64_t> DWARFDebugNames::Entry::getDIEUnitOffset() const { if (std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_die_offset)) return Off->getAsReferenceUVal(); @@ -650,6 +654,17 @@ std::optional<uint64_t> DWARFDebugNames::Entry::getLocalTUIndex() const { return std::nullopt; } +Expected<std::optional<DWARFDebugNames::Entry>> +DWARFDebugNames::Entry::getParentDIEEntry() const { + // The offset of the accelerator table entry for the parent. + std::optional<DWARFFormValue> ParentEntryOff = lookup(dwarf::DW_IDX_parent); + assert(ParentEntryOff.has_value() && "hasParentInformation() must be called"); + + if (ParentEntryOff->getForm() == dwarf::Form::DW_FORM_flag_present) + return std::nullopt; + return NameIdx->getEntryAtRelativeOffset(ParentEntryOff->getRawUValue()); +} + void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const { W.startLine() << formatv("Abbrev: {0:x}\n", Abbr->Code); W.startLine() << formatv("Tag: {0}\n", Abbr->Tag); diff --git a/llvm/test/CodeGen/X86/dwarf-headers.o b/llvm/test/CodeGen/X86/dwarf-headers.o new file mode 100644 index 000000000000000..e69de29bb2d1d64 >From d0dea8281695c7174901215fe5bfbf79270985ce 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 2/3] [lldb][DWARFUnit] Implement PeekDIEName query This allows us to query the AT_Name of a DIE without parsing the entire CU. Part of the ongoing effort to support IDX_Parent in accelerator tables [1]. [1]: https://discourse.llvm.org/t/rfc-improve-dwarf-5-debug-names-type-lookup-parsing-speed/74151/44 --- .../SymbolFile/DWARF/DWARFDebugInfo.cpp | 6 ++ .../Plugins/SymbolFile/DWARF/DWARFDebugInfo.h | 5 ++ .../SymbolFile/DWARF/DWARFFormValue.cpp | 24 +++--- .../Plugins/SymbolFile/DWARF/DWARFFormValue.h | 6 ++ .../Plugins/SymbolFile/DWARF/DWARFUnit.cpp | 24 ++++++ .../Plugins/SymbolFile/DWARF/DWARFUnit.h | 5 ++ .../SymbolFile/DWARF/DWARFDIETest.cpp | 83 +++++++++++++++++++ 7 files changed, 143 insertions(+), 10 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp index 553b6a4c551d205..340b9acf80d023b 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -191,3 +191,9 @@ DWARFDebugInfo::GetDIE(const DIERef &die_ref) { return cu->GetNonSkeletonUnit().GetDIE(die_ref.die_offset()); return DWARFDIE(); // Not found } + +llvm::StringRef DWARFDebugInfo::PeekDIEName(const DIERef &die_ref) { + if (DWARFUnit *cu = GetUnit(die_ref)) + return cu->GetNonSkeletonUnit().PeekDIEName(die_ref.die_offset()); + return llvm::StringRef(); +} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h index d5e48f312ea0e98..a8b5abc3beed2d0 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/DWARFFormValue.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp index 0a7029a55c047bb..e1f73f1997e3692 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -18,8 +18,6 @@ #include "DWARFFormValue.h" #include "DWARFUnit.h" -class DWARFUnit; - using namespace lldb_private; using namespace lldb_private::dwarf; using namespace lldb_private::plugin::dwarf; @@ -502,7 +500,8 @@ dw_addr_t DWARFFormValue::Address() const { &offset, index_size); } -DWARFDIE DWARFFormValue::Reference() const { +std::pair<DWARFUnit *, uint64_t> +DWARFFormValue::ReferencedUnitAndOffset() const { uint64_t value = m_value.value.uval; switch (m_form) { case DW_FORM_ref1: @@ -516,9 +515,9 @@ DWARFDIE DWARFFormValue::Reference() const { if (!m_unit->ContainsDIEOffset(value)) { m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( "DW_FORM_ref* DIE reference {0:x16} is outside of its CU", value); - return {}; + return {nullptr, 0}; } - return const_cast<DWARFUnit *>(m_unit)->GetDIE(value); + return {const_cast<DWARFUnit *>(m_unit), value}; case DW_FORM_ref_addr: { DWARFUnit *ref_cu = @@ -527,24 +526,29 @@ DWARFDIE DWARFFormValue::Reference() const { if (!ref_cu) { m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( "DW_FORM_ref_addr DIE reference {0:x16} has no matching CU", value); - return {}; + return {nullptr, 0}; } - return ref_cu->GetDIE(value); + return {ref_cu, value}; } case DW_FORM_ref_sig8: { DWARFTypeUnit *tu = m_unit->GetSymbolFileDWARF().DebugInfo().GetTypeUnitForHash(value); if (!tu) - return {}; - return tu->GetDIE(tu->GetTypeOffset()); + return {nullptr, 0}; + return {tu, tu->GetTypeOffset()}; } default: - return {}; + return {nullptr, 0}; } } +DWARFDIE DWARFFormValue::Reference() const { + auto [unit, offset] = ReferencedUnitAndOffset(); + return unit ? unit->GetDIE(offset) : DWARFDIE(); +} + uint64_t DWARFFormValue::Reference(dw_offset_t base_offset) const { uint64_t value = m_value.value.uval; switch (m_form) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h index 445749a6aac3ac7..fdd5b3c278a4e80 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h @@ -60,6 +60,12 @@ class DWARFFormValue { const DWARFUnit *u); std::optional<uint8_t> GetFixedSize() const; DWARFDIE Reference() const; + + /// If this is a reference to another DIE, return the corresponding DWARFUnit + /// and DIE offset such that Unit->GetDIE(offset) produces the desired DIE. + /// Otherwise, a nullptr and unspecified offset are returned. + std::pair<DWARFUnit *, uint64_t> ReferencedUnitAndOffset() const; + uint64_t Reference(dw_offset_t offset) const; bool Boolean() const { return m_value.value.uval != 0; } uint64_t Unsigned() const { return m_value.value.uval; } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index 0e2f4d45543bb53..7a40361cdede7a7 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -663,6 +663,30 @@ DWARFUnit::GetDIE(dw_offset_t die_offset) { return DWARFDIE(); // Not found } +llvm::StringRef DWARFUnit::PeekDIEName(dw_offset_t die_offset) { + DWARFDebugInfoEntry die; + if (!die.Extract(GetData(), this, &die_offset)) + return llvm::StringRef(); + + // Does die contain a DW_AT_Name? + if (const char *name = + die.GetAttributeValueAsString(this, DW_AT_name, nullptr)) + return name; + + // Does its DW_AT_specification or DW_AT_abstract_origin contain an AT_Name? + for (auto attr : {DW_AT_specification, DW_AT_abstract_origin}) { + DWARFFormValue form_value; + if (!die.GetAttributeValue(this, attr, form_value)) + continue; + auto [unit, offset] = form_value.ReferencedUnitAndOffset(); + if (unit) + if (auto name = unit->PeekDIEName(offset); !name.empty()) + return name; + } + + return llvm::StringRef(); +} + DWARFUnit &DWARFUnit::GetNonSkeletonUnit() { ExtractUnitDIEIfNeeded(); if (m_dwo) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index 3f528e913d8cfab..bc225a52e1d0309 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); diff --git a/lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp b/lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp index 8497855b2f3db59..bcb211815f9f351 100644 --- a/lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp +++ b/lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "Plugins/SymbolFile/DWARF/DWARFDIE.h" +#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" #include "TestingSupport/Symbol/YAMLModuleTester.h" #include "llvm/ADT/STLExtras.h" #include "gmock/gmock.h" @@ -104,3 +105,85 @@ TEST(DWARFDIETest, ChildIteration) { DWARFDIE no_children_die(unit, die_child0); EXPECT_TRUE(no_children_die.children().empty()); } + +TEST(DWARFDIETest, PeekName) { + const char *yamldata = R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_386 +DWARF: + debug_str: + - 'NameType1' + - 'NameType2' + debug_abbrev: + - Table: + - Code: 0x00000001 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Code: 0x00000002 + Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Code: 0x00000003 + Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_abstract_origin + Form: DW_FORM_ref1 + - Code: 0x00000004 + Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_specification + Form: DW_FORM_ref1 + debug_info: + - Version: 4 + AddrSize: 8 + Entries: + - AbbrCode: 0x00000001 + Values: + - Value: 0x000000000000000C + - AbbrCode: 0x00000002 + Values: + - Value: 0x0000000000000000 # Name = NameType1 + - AbbrCode: 0x00000002 + Values: + - Value: 0x000000000000000a # Name = NameType2 + - AbbrCode: 0x00000003 + Values: + - Value: 0x000000000000000e # Ref abstract origin to NameType1 DIE. + - AbbrCode: 0x00000004 + Values: + - Value: 0x0000000000000013 # Ref specification to NameType2 DIE. + - AbbrCode: 0x00000000 +)"; + + YAMLModuleTester t(yamldata); + auto *symbol_file = + llvm::cast<SymbolFileDWARF>(t.GetModule()->GetSymbolFile()); + auto &debug_info = symbol_file->DebugInfo(); + + DIERef first_die(std::nullopt, DIERef::Section::DebugInfo, + 11 /*FirstDIEOffset*/); + EXPECT_EQ(debug_info.PeekDIEName(first_die), ""); + + DIERef second_die(std::nullopt, DIERef::Section::DebugInfo, 14); + EXPECT_EQ(debug_info.PeekDIEName(second_die), "NameType1"); + + DIERef third_die(std::nullopt, DIERef::Section::DebugInfo, 19); + EXPECT_EQ(debug_info.PeekDIEName(third_die), "NameType2"); + + DIERef fourth_die(std::nullopt, DIERef::Section::DebugInfo, 24); + EXPECT_EQ(debug_info.PeekDIEName(fourth_die), "NameType1"); + + DIERef fifth_die(std::nullopt, DIERef::Section::DebugInfo, 26); + EXPECT_EQ(debug_info.PeekDIEName(fifth_die), "NameType2"); +} >From 52dc223f049adaa605c6be6267eedb6539dafd0c Mon Sep 17 00:00:00 2001 From: Felipe de Azevedo Piovezan <fpiove...@apple.com> Date: Thu, 4 Jan 2024 12:56:25 -0300 Subject: [PATCH 3/3] [lldb][DWARFIndex] Use IDX_parent to implement GetFullyQualifiedType query This commit changes DebugNamesDWARFIndex so that it now overrides `GetFullyQualifiedType` and attempts to use DW_IDX_parent, when available, to speed up such queries. When this type of information is not available, the base-class implementation is used. --- .../SymbolFile/DWARF/DebugNamesDWARFIndex.cpp | 98 +++++++++++++++++++ .../SymbolFile/DWARF/DebugNamesDWARFIndex.h | 9 ++ 2 files changed, 107 insertions(+) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp index b718f98340a70bf..e7b2a4b59f3f024 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp @@ -13,6 +13,7 @@ #include "lldb/Core/Module.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Stream.h" +#include "llvm/ADT/Sequence.h" #include <optional> using namespace lldb_private; @@ -218,6 +219,103 @@ void DebugNamesDWARFIndex::GetCompleteObjCClass( m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, callback); } +namespace { +using Entry = llvm::DWARFDebugNames::Entry; + +// If `entry` and all of its parents have an `IDX_parent`, use that information +// to build and return a list of at most `max_parents` parent Entries. +// `entry` itself is not included in the list. +// If any parent does not have an `IDX_parent`, nullopt is returned. +static std::optional<llvm::SmallVector<Entry, 4>> +getParentChain(Entry entry, uint32_t max_parents) { + llvm::SmallVector<Entry, 4> parent_entries; + + do { + if (!entry.hasParentInformation()) + return std::nullopt; + + llvm::Expected<std::optional<Entry>> parent = entry.getParentDIEEntry(); + if (!parent) { // Bad data. + consumeError(parent.takeError()); + return std::nullopt; + } + + // Last parent in the chain + if (!parent->has_value()) + break; + + parent_entries.push_back(**parent); + entry = **parent; + } while (parent_entries.size() < max_parents); + + return parent_entries; +} +} // namespace + +void DebugNamesDWARFIndex::GetFullyQualifiedType( + const DWARFDeclContext &context, + llvm::function_ref<bool(DWARFDIE die)> callback) { + + // Fallback: use the base class implementation. + auto fallback_impl = [&](const DebugNames::Entry &entry) { + return ProcessEntry(entry, [&](DWARFDIE die) { + return GetFullyQualifiedTypeImpl(context, die, callback); + }); + }; + + if (context.GetSize() == 0) + return; + llvm::StringRef leaf_name = context[0].name; + auto parent_names = llvm::to_vector_of<llvm::StringRef>( + llvm::map_range(llvm::seq<int>(1, context.GetSize()), + [&](int idx) { return context[idx].name; })); + + for (const DebugNames::Entry &entry : + m_debug_names_up->equal_range(leaf_name)) { + if (!isType(entry.tag())) + continue; + + // Grab at most one extra parent, extra parents are not useful to test + // equality. + auto parent_chain = getParentChain(entry, parent_names.size() + 1); + + if (!parent_chain) { + if (!fallback_impl(entry)) + return; + continue; + } + + if (CheckParentChain(parent_names, *parent_chain) && + (!ProcessEntry(entry, callback))) + return; + } +} + +bool DebugNamesDWARFIndex::CheckParentChain( + llvm::ArrayRef<llvm::StringRef> expected_parent_names, + llvm::ArrayRef<DebugNames::Entry> parent_entries) const { + + if (parent_entries.size() != expected_parent_names.size()) + return false; + + auto CompareEntryATName = [this](llvm::StringRef expected_name, + const DebugNames::Entry &entry) { + auto maybe_dieoffset = entry.getDIEUnitOffset(); + if (!maybe_dieoffset) + return false; + auto die_ref = ToDIERef(entry); + if (!die_ref) + return false; + return expected_name == m_debug_info.PeekDIEName(*die_ref); + }; + + for (auto [expected_parent_name, parent_entry] : + llvm::zip_equal(expected_parent_names, parent_entries)) + if (!CompareEntryATName(expected_parent_name, parent_entry)) + return false; + return true; +} + void DebugNamesDWARFIndex::GetTypes( ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) { for (const DebugNames::Entry &entry : diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h index cca0913c4124c91..15eff7a26596333 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h @@ -14,6 +14,7 @@ #include "Plugins/SymbolFile/DWARF/ManualDWARFIndex.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" #include "lldb/Utility/ConstString.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" #include <optional> @@ -42,6 +43,11 @@ class DebugNamesDWARFIndex : public DWARFIndex { void GetCompleteObjCClass( ConstString class_name, bool must_be_implementation, llvm::function_ref<bool(DWARFDIE die)> callback) override; + + /// Uses DWARF5's IDX_parent fields, when available, to speed up this query. + void GetFullyQualifiedType( + const DWARFDeclContext &context, + llvm::function_ref<bool(DWARFDIE die)> callback) override; void GetTypes(ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) override; void GetTypes(const DWARFDeclContext &context, @@ -83,6 +89,9 @@ class DebugNamesDWARFIndex : public DWARFIndex { bool ProcessEntry(const DebugNames::Entry &entry, llvm::function_ref<bool(DWARFDIE die)> callback); + bool CheckParentChain(llvm::ArrayRef<llvm::StringRef> parent_names, + llvm::ArrayRef<DebugNames::Entry> parent_entries) const; + static void MaybeLogLookupError(llvm::Error error, const DebugNames::NameIndex &ni, llvm::StringRef name); _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits