https://github.com/clayborg updated https://github.com/llvm/llvm-project/pull/87740
>From c364215cef4d383bf5cb51bf61d442a5bc9fbfe9 Mon Sep 17 00:00:00 2001 From: Greg Clayton <clayb...@gmail.com> Date: Sat, 30 Mar 2024 10:50:34 -0700 Subject: [PATCH 1/8] Add support for using foreign type units in .debug_names. This patch adds support for the new foreign type unit support in .debug_names. Features include: - don't manually index foreign TUs if we have info for them - only use the type unit entries that match the .dwo files when we have a .dwp file - fix crashers that happen due to PeekDIEName() using wrong offsets --- .../SymbolFile/DWARF/DWARFDebugInfo.cpp | 18 ++++ .../Plugins/SymbolFile/DWARF/DWARFDebugInfo.h | 2 + .../SymbolFile/DWARF/DebugNamesDWARFIndex.cpp | 65 ++++++++++++- .../SymbolFile/DWARF/DebugNamesDWARFIndex.h | 6 +- .../SymbolFile/DWARF/ManualDWARFIndex.cpp | 6 +- .../SymbolFile/DWARF/ManualDWARFIndex.h | 7 +- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 66 ++++++++------ .../SymbolFile/DWARF/SymbolFileDWARF.h | 9 ++ .../DWARF/x86/dwp-foreign-type-units.cpp | 91 +++++++++++++++++++ .../DebugInfo/DWARF/DWARFAcceleratorTable.h | 11 +++ .../DebugInfo/DWARF/DWARFAcceleratorTable.cpp | 13 +++ 11 files changed, 257 insertions(+), 37 deletions(-) create mode 100644 lldb/test/Shell/SymbolFile/DWARF/x86/dwp-foreign-type-units.cpp diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp index c37cc91e08ed1..056c6d4b0605f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -222,6 +222,20 @@ DWARFUnit *DWARFDebugInfo::GetUnitAtOffset(DIERef::Section section, return result; } +DWARFUnit *DWARFDebugInfo::GetUnit(const DIERef &die_ref) { + // Make sure we get the correct SymbolFileDWARF from the DIERef before + // asking for information from a debug info object. We might start with the + // DWARFDebugInfo for the main executable in a split DWARF and the DIERef + // might be pointing to a specific .dwo file or to the .dwp file. So this + // makes sure we get the right SymbolFileDWARF instance before finding the + // DWARFUnit that contains the offset. If we just use this object to do the + // search, we might be using the wrong .debug_info section from the wrong + // file with an offset meant for a different section. + SymbolFileDWARF *dwarf = m_dwarf.GetDIERefSymbolFile(die_ref); + return dwarf->DebugInfo().GetUnitContainingDIEOffset(die_ref.section(), + die_ref.die_offset()); +} + DWARFUnit * DWARFDebugInfo::GetUnitContainingDIEOffset(DIERef::Section section, dw_offset_t die_offset) { @@ -232,6 +246,10 @@ DWARFDebugInfo::GetUnitContainingDIEOffset(DIERef::Section section, return result; } +const std::shared_ptr<SymbolFileDWARFDwo> DWARFDebugInfo::GetDwpSymbolFile() { + return m_dwarf.GetDwpSymbolFile(); +} + DWARFTypeUnit *DWARFDebugInfo::GetTypeUnitForHash(uint64_t hash) { auto pos = llvm::lower_bound(m_type_hash_to_unit_index, std::make_pair(hash, 0u), llvm::less_first()); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h index 4706b55d38ea9..4d4555a338252 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h @@ -52,6 +52,8 @@ class DWARFDebugInfo { const DWARFDebugAranges &GetCompileUnitAranges(); + const std::shared_ptr<SymbolFileDWARFDwo> GetDwpSymbolFile(); + protected: typedef std::vector<DWARFUnitSP> UnitColl; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp index 56717bab1ecd8..a07c454ea7ee3 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp @@ -34,6 +34,18 @@ DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names, module, std::move(index_up), debug_names, debug_str, dwarf)); } + +llvm::DenseSet<uint64_t> +DebugNamesDWARFIndex::GetTypeUnitSigs(const DebugNames &debug_names) { + llvm::DenseSet<uint64_t> result; + for (const DebugNames::NameIndex &ni : debug_names) { + const uint32_t num_tus = ni.getForeignTUCount(); + for (uint32_t tu = 0; tu < num_tus; ++tu) + result.insert(ni.getForeignTUSignature(tu)); + } + return result; +} + llvm::DenseSet<dw_offset_t> DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) { llvm::DenseSet<dw_offset_t> result; @@ -48,17 +60,22 @@ DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) { return result; } +DWARFTypeUnit * +DebugNamesDWARFIndex::GetForeignTypeUnit(const DebugNames::Entry &entry) const { + std::optional<uint64_t> type_sig = entry.getForeignTUTypeSignature(); + if (type_sig) + if (auto dwp_sp = m_debug_info.GetDwpSymbolFile()) + return dwp_sp->DebugInfo().GetTypeUnitForHash(*type_sig); + return nullptr; +} + DWARFUnit * DebugNamesDWARFIndex::GetNonSkeletonUnit(const DebugNames::Entry &entry) const { // Look for a DWARF unit offset (CU offset or local TU offset) as they are // both offsets into the .debug_info section. std::optional<uint64_t> unit_offset = entry.getCUOffset(); - if (!unit_offset) { + if (!unit_offset) unit_offset = entry.getLocalTUOffset(); - if (!unit_offset) - return nullptr; - } - DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *unit_offset); return cu ? &cu->GetNonSkeletonUnit() : nullptr; @@ -273,6 +290,44 @@ void DebugNamesDWARFIndex::GetFullyQualifiedType( if (!isType(entry.tag())) continue; + + DWARFTypeUnit *foreign_tu = GetForeignTypeUnit(entry); + if (foreign_tu) { + // If this entry represents a foreign type unit, we need to verify that + // the type unit that ended up in the final .dwp file is the right type + // unit. Type units have signatures which are the same across multiple + // .dwo files, but only one of those type units will end up in the .dwp + // file. The contents of type units for the same type can be different + // in different .dwo file, which means the DIE offsets might not be the + // same between two different type units. So we need to determine if this + // accelerator table matches the type unit in the .dwp file. If it doesn't + // match, then we need to ignore this accelerator table entry as the type + // unit that is in the .dwp file will have its own index. + const llvm::DWARFDebugNames::NameIndex *name_index = entry.getNameIndex(); + if (name_index == nullptr) + continue; + // In order to determine if the type unit that ended up in a .dwp file + // is valid, we need to grab the type unit and check the attribute on the + // type unit matches the .dwo file. For this to happen we rely on each + // .dwo file having its own .debug_names table with a single compile unit + // and multiple type units. This is the only way we can tell if a type + // unit came from a specific .dwo file. + if (name_index->getCUCount() == 1) { + dw_offset_t cu_offset = name_index->getCUOffset(0); + DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::DebugInfo, + cu_offset); + if (cu) { + DWARFBaseDIE cu_die = cu->GetUnitDIEOnly(); + DWARFBaseDIE tu_die = foreign_tu->GetUnitDIEOnly(); + llvm::StringRef cu_dwo_name = + cu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr); + llvm::StringRef tu_dwo_name = + tu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr); + if (cu_dwo_name != tu_dwo_name) + continue; // Ignore this entry, the CU DWO doesn't match the TU DWO + } + } + } // Grab at most one extra parent, subsequent parents are not necessary to // test equality. std::optional<llvm::SmallVector<Entry, 4>> parent_chain = diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h index a27a414ecdd19..94fce2ed9c175 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h @@ -70,7 +70,8 @@ class DebugNamesDWARFIndex : public DWARFIndex { : DWARFIndex(module), m_debug_info(dwarf.DebugInfo()), m_debug_names_data(debug_names_data), m_debug_str_data(debug_str_data), m_debug_names_up(std::move(debug_names_up)), - m_fallback(module, dwarf, GetUnits(*m_debug_names_up)) {} + m_fallback(module, dwarf, GetUnits(*m_debug_names_up), + GetTypeUnitSigs(*m_debug_names_up)) {} DWARFDebugInfo &m_debug_info; @@ -85,6 +86,8 @@ class DebugNamesDWARFIndex : public DWARFIndex { DWARFUnit *GetNonSkeletonUnit(const DebugNames::Entry &entry) const; DWARFDIE GetDIE(const DebugNames::Entry &entry) const; + DWARFTypeUnit *GetForeignTypeUnit(const DebugNames::Entry &entry) const; + // std::optional<DIERef> ToDIERef(const DebugNames::Entry &entry) const; bool ProcessEntry(const DebugNames::Entry &entry, llvm::function_ref<bool(DWARFDIE die)> callback); @@ -97,6 +100,7 @@ class DebugNamesDWARFIndex : public DWARFIndex { llvm::StringRef name); static llvm::DenseSet<dw_offset_t> GetUnits(const DebugNames &debug_names); + static llvm::DenseSet<uint64_t> GetTypeUnitSigs(const DebugNames &debug_names); }; } // namespace dwarf diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index 92275600f99ca..103e157d3cac5 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -60,8 +60,10 @@ void ManualDWARFIndex::Index() { } if (dwp_info && dwp_info->ContainsTypeUnits()) { for (size_t U = 0; U < dwp_info->GetNumUnits(); ++U) { - if (auto *tu = llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U))) - units_to_index.push_back(tu); + if (auto *tu = llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U))) { + if (m_type_sigs_to_avoid.count(tu->GetTypeHash()) == 0) + units_to_index.push_back(tu); + } } } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h index 0126e587e52d8..3f0bb39dfc20c 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h @@ -21,9 +21,11 @@ class SymbolFileDWARFDwo; class ManualDWARFIndex : public DWARFIndex { public: ManualDWARFIndex(Module &module, SymbolFileDWARF &dwarf, - llvm::DenseSet<dw_offset_t> units_to_avoid = {}) + llvm::DenseSet<dw_offset_t> units_to_avoid = {}, + llvm::DenseSet<uint64_t> type_sigs_to_avoid = {}) : DWARFIndex(module), m_dwarf(&dwarf), - m_units_to_avoid(std::move(units_to_avoid)) {} + m_units_to_avoid(std::move(units_to_avoid)), + m_type_sigs_to_avoid(type_sigs_to_avoid) {} void Preload() override { Index(); } @@ -170,6 +172,7 @@ class ManualDWARFIndex : public DWARFIndex { SymbolFileDWARF *m_dwarf; /// Which dwarf units should we skip while building the index. llvm::DenseSet<dw_offset_t> m_units_to_avoid; + llvm::DenseSet<uint64_t> m_type_sigs_to_avoid; IndexSet m_set; bool m_indexed = false; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 661e4a78a0215..3606e5b1251bc 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -700,7 +700,6 @@ llvm::DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() { if (debug_abbrev_data.GetByteSize() == 0) return nullptr; - ElapsedTime elapsed(m_parse_time); auto abbr = std::make_unique<llvm::DWARFDebugAbbrev>(debug_abbrev_data.GetAsLLVM()); llvm::Error error = abbr->parse(); @@ -1741,14 +1740,7 @@ lldb::ModuleSP SymbolFileDWARF::GetExternalModule(ConstString name) { return pos->second; } -DWARFDIE -SymbolFileDWARF::GetDIE(const DIERef &die_ref) { - // This method can be called without going through the symbol vendor so we - // need to lock the module. - std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); - - SymbolFileDWARF *symbol_file = nullptr; - +SymbolFileDWARF *SymbolFileDWARF::GetDIERefSymbolFile(const DIERef &die_ref) { // Anytime we get a "lldb::user_id_t" from an lldb_private::SymbolFile API we // must make sure we use the correct DWARF file when resolving things. On // MacOSX, when using SymbolFileDWARFDebugMap, we will use multiple @@ -1756,30 +1748,51 @@ SymbolFileDWARF::GetDIE(const DIERef &die_ref) { // references to other DWARF objects and we must be ready to receive a // "lldb::user_id_t" that specifies a DIE from another SymbolFileDWARF // instance. + std::optional<uint32_t> file_index = die_ref.file_index(); + + // If the file index matches, then we have the right SymbolFileDWARF already. + // This will work for both .dwo file and DWARF in .o files for mac. Also if + // both the file indexes are invalid, then we have a match. + if (GetFileIndex() == file_index) + return this; + + // If we are currently in a .dwo file and our file index doesn't match we need + // to let the base symbol file handle this. + SymbolFileDWARFDwo *dwo = llvm::dyn_cast_or_null<SymbolFileDWARFDwo>(this); + if (dwo) + return dwo->GetBaseSymbolFile().GetDIERefSymbolFile(die_ref); + if (file_index) { - if (SymbolFileDWARFDebugMap *debug_map = GetDebugMapSymfile()) { - symbol_file = debug_map->GetSymbolFileByOSOIndex(*file_index); // OSO case - if (symbol_file) - return symbol_file->DebugInfo().GetDIE(die_ref.section(), - die_ref.die_offset()); - return DWARFDIE(); - } + SymbolFileDWARFDebugMap *debug_map = GetDebugMapSymfile(); + if (debug_map) { + // We have a SymbolFileDWARFDebugMap, so let it find the right file + return debug_map->GetSymbolFileByOSOIndex(*file_index); + } else { + // Handle the .dwp file case correctly + if (*file_index == DIERef::k_file_index_mask) + return GetDwpSymbolFile().get(); // DWP case - if (*file_index == DIERef::k_file_index_mask) - symbol_file = GetDwpSymbolFile().get(); // DWP case - else - symbol_file = this->DebugInfo() - .GetUnitAtIndex(*die_ref.file_index()) + // Handle the .dwo file case correctly + return DebugInfo().GetUnitAtIndex(*die_ref.file_index()) ->GetDwoSymbolFile(); // DWO case - } else if (die_ref.die_offset() == DW_INVALID_OFFSET) { - return DWARFDIE(); + } } + return this; +} - if (symbol_file) - return symbol_file->GetDIE(die_ref); +DWARFDIE +SymbolFileDWARF::GetDIE(const DIERef &die_ref) { + if (die_ref.die_offset() == DW_INVALID_OFFSET) + return DWARFDIE(); - return DebugInfo().GetDIE(die_ref.section(), die_ref.die_offset()); + // This method can be called without going through the symbol vendor so we + // need to lock the module. + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); + SymbolFileDWARF *symbol_file = GetDIERefSymbolFile(die_ref); + if (symbol_file) + return symbol_file->DebugInfo().GetDIE(die_ref); + return DWARFDIE(); } /// Return the DW_AT_(GNU_)dwo_id. @@ -2733,7 +2746,6 @@ void SymbolFileDWARF::FindTypes(const TypeQuery &query, TypeResults &results) { die_context = die.GetDeclContext(); else die_context = die.GetTypeLookupContext(); - assert(!die_context.empty()); if (!query.ContextMatches(die_context)) return true; // Keep iterating over index types, context mismatch. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 35893f2072dd6..661be827149eb 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -241,6 +241,15 @@ class SymbolFileDWARF : public SymbolFileCommon { return m_external_type_modules; } + /// Given a DIERef, find the correct SymbolFileDWARF. + /// + /// A DIERef contains a file index that can uniquely identify a N_OSO file for + /// DWARF in .o files on mac, or a .dwo or .dwp file index for split DWARF. + /// Calling this function will find the correct symbol file to use so that + /// further lookups can be done on the correct symbol file so that the DIE + /// offset makes sense in the DIERef. + SymbolFileDWARF *GetDIERefSymbolFile(const DIERef &die_ref); + virtual DWARFDIE GetDIE(const DIERef &die_ref); DWARFDIE GetDIE(lldb::user_id_t uid); diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/dwp-foreign-type-units.cpp b/lldb/test/Shell/SymbolFile/DWARF/x86/dwp-foreign-type-units.cpp new file mode 100644 index 0000000000000..3662059166790 --- /dev/null +++ b/lldb/test/Shell/SymbolFile/DWARF/x86/dwp-foreign-type-units.cpp @@ -0,0 +1,91 @@ +// REQUIRES: lld + +// This test will make a type that will be compiled differently into two +// different .dwo files in a type unit with the same type hash, but with +// differing contents. I have discovered that the hash for the type unit is +// simply based off of the typename and doesn't seem to differ when the contents +// differ, so that will help us test foreign type units in the .debug_names +// section of the main executable. When a DWP file is made, only one type unit +// will be kept and the type unit that is kept has the .dwo file name that it +// came from. When LLDB loads the foreign type units, it needs to verify that +// any entries from foreign type units come from the right .dwo file. We test +// this since the contents of type units are not always the same even though +// they have the same type hash. We don't want invalid accelerator table entries +// to come from one .dwo file and be used on a type unit from another since this +// could cause invalid lookups to happen. LLDB knows how to track down which +// .dwo file a type unit comes from by looking at the DW_AT_dwo_name attribute +// in the DW_TAG_type_unit. + +// Now test with DWARF5 +// RUN: %clang -target x86_64-pc-linux -gdwarf-5 -gsplit-dwarf \ +// RUN: -fdebug-types-section -gpubnames -c %s -o %t.main.o +// RUN: %clang -target x86_64-pc-linux -gdwarf-5 -gsplit-dwarf -DVARIANT \ +// RUN: -fdebug-types-section -gpubnames -c %s -o %t.foo.o +// RUN: ld.lld %t.main.o %t.foo.o -o %t + +// First we check when we make the .dwp file with %t.main.dwo first so it will +// pick the type unit from %t.main.dwo. Verify we find only the types from +// %t.main.dwo's type unit. +// RUN: llvm-dwp %t.main.dwo %t.foo.dwo -o %t.dwp +// RUN: %lldb \ +// RUN: -o "type lookup IntegerType" \ +// RUN: -o "type lookup FloatType" \ +// RUN: -o "type lookup IntegerType" \ +// RUN: -b %t | FileCheck %s +// CHECK: (lldb) type lookup IntegerType +// CHECK-NEXT: int +// CHECK-NEXT: (lldb) type lookup FloatType +// CHECK-NEXT: double +// CHECK-NEXT: (lldb) type lookup IntegerType +// CHECK-NEXT: int + +// Next we check when we make the .dwp file with %t.foo.dwo first so it will +// pick the type unit from %t.main.dwo. Verify we find only the types from +// %t.main.dwo's type unit. +// RUN: llvm-dwp %t.foo.dwo %t.main.dwo -o %t.dwp +// RUN: %lldb \ +// RUN: -o "type lookup IntegerType" \ +// RUN: -o "type lookup FloatType" \ +// RUN: -o "type lookup IntegerType" \ +// RUN: -b %t | FileCheck %s --check-prefix=VARIANT + +// VARIANT: (lldb) type lookup IntegerType +// VARIANT-NEXT: unsigned int +// VARIANT-NEXT: (lldb) type lookup FloatType +// VARIANT-NEXT: float +// VARIANT-NEXT: (lldb) type lookup IntegerType +// VARIANT-NEXT: unsigned int + + +// We need to do this so we end with a type unit in each .dwo file and that has +// the same signature but different contents. When we make the .dwp file, then +// one of the type units will end up in the .dwp file and we will have +// .debug_names accelerator tables for both type units and we need to ignore +// the type units .debug_names entries that don't match the .dwo file whose +// copy of the type unit ends up in the final .dwp file. To do this, LLDB will +// look at the type unit and take the DWO name attribute and make sure it +// matches, and if it doesn't, it will ignore the accelerator table entry. +struct CustomType { + // We switch the order of "FloatType" and "IntegerType" so that if we do + // end up reading the wrong accelerator table entry, that we would end up + // getting an invalid offset and not find anything, or the offset would have + // matched and we would find the wrong thing. +#ifdef VARIANT + typedef float FloatType; + typedef unsigned IntegerType; +#else + typedef int IntegerType; + typedef double FloatType; +#endif + IntegerType x; + FloatType y; +}; + +#ifdef VARIANT +int foo() { +#else +int main() { +#endif + CustomType c = {1, 2.0}; + return 0; +} diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h index 0d447a78cdc61..6c7132eb35021 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h @@ -64,6 +64,14 @@ class DWARFAcceleratorTable { return std::nullopt; } + /// Returns the type signature of the Type Unit associated with this + /// Accelerator Entry or std::nullopt if the Type Unit offset is not + /// recorded in this Accelerator Entry. + virtual std::optional<uint64_t> getForeignTUTypeSignature() const { + // Default return for accelerator tables that don't support type units. + return std::nullopt; + } + /// Returns the Tag of the Debug Info Entry associated with this /// Accelerator Entry or std::nullopt if the Tag is not recorded in this /// Accelerator Entry. @@ -433,8 +441,11 @@ class DWARFDebugNames : public DWARFAcceleratorTable { Entry(const NameIndex &NameIdx, const Abbrev &Abbr); public: + const NameIndex *getNameIndex() const { return NameIdx; } std::optional<uint64_t> getCUOffset() const override; std::optional<uint64_t> getLocalTUOffset() const override; + std::optional<uint64_t> getForeignTUTypeSignature() const override; + std::optional<dwarf::Tag> getTag() const override { return tag(); } /// Returns the Index into the Compilation Unit list of the owning Name diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp index ac19ac7932971..e120b59ccb4e6 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -657,6 +657,19 @@ std::optional<uint64_t> DWARFDebugNames::Entry::getLocalTUOffset() const { return NameIdx->getLocalTUOffset(*Index); } +std::optional<uint64_t> +DWARFDebugNames::Entry::getForeignTUTypeSignature() const { + std::optional<uint64_t> Index = getLocalTUIndex(); + const uint32_t NumLocalTUs = NameIdx->getLocalTUCount(); + if (!Index || *Index < NumLocalTUs) + return std::nullopt; // Invalid TU index or TU index is for a local TU + // The foreign TU index is the TU index minus the number of local TUs. + const uint64_t ForeignTUIndex = *Index - NumLocalTUs; + if (ForeignTUIndex >= NameIdx->getForeignTUCount()) + return std::nullopt; // Invalid foreign TU index. + return NameIdx->getForeignTUSignature(ForeignTUIndex); +} + std::optional<uint64_t> DWARFDebugNames::Entry::getLocalTUIndex() const { if (std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_type_unit)) return Off->getAsUnsignedConstant(); >From 9ffb03d8941a95b9bd021c4e6a2338ba9d3b49be Mon Sep 17 00:00:00 2001 From: Greg Clayton <clayb...@gmail.com> Date: Sun, 5 May 2024 09:36:56 -0700 Subject: [PATCH 2/8] Add support for BOLT generated .debug_names. BOLT creates a single .debug_names table where foreign type units have both a DW_IDX_type_unit and a DW_IDX_compile_unit to uniquely identify the .dwo file that the type unit came from. --- .../SymbolFile/DWARF/DebugNamesDWARFIndex.cpp | 110 +++++++++++------- .../SymbolFile/DWARF/DebugNamesDWARFIndex.h | 25 ++++ .../DebugInfo/DWARF/DWARFAcceleratorTable.h | 20 ++++ .../DebugInfo/DWARF/DWARFAcceleratorTable.cpp | 20 ++++ 4 files changed, 134 insertions(+), 41 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp index a07c454ea7ee3..bfdbb7765ae9e 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp @@ -60,13 +60,71 @@ DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) { return result; } -DWARFTypeUnit * -DebugNamesDWARFIndex::GetForeignTypeUnit(const DebugNames::Entry &entry) const { +bool +DebugNamesDWARFIndex::IsForeignTypeUnit(const DebugNames::Entry &entry, + DWARFTypeUnit *&foreign_tu) const { + foreign_tu = nullptr; std::optional<uint64_t> type_sig = entry.getForeignTUTypeSignature(); - if (type_sig) - if (auto dwp_sp = m_debug_info.GetDwpSymbolFile()) - return dwp_sp->DebugInfo().GetTypeUnitForHash(*type_sig); - return nullptr; + if (!type_sig.has_value()) + return false; + auto dwp_sp = m_debug_info.GetDwpSymbolFile(); + if (dwp_sp) { + // We have a .dwp file, just get the type unit from there. + foreign_tu = dwp_sp->DebugInfo().GetTypeUnitForHash(*type_sig); + } else { + // We have a .dwo file that contains the type unit. + foreign_tu = nullptr; // TODO: fixme before checkin + } + if (foreign_tu == nullptr) + return true; + // If this entry represents a foreign type unit, we need to verify that + // the type unit that ended up in the final .dwp file is the right type + // unit. Type units have signatures which are the same across multiple + // .dwo files, but only one of those type units will end up in the .dwp + // file. The contents of type units for the same type can be different + // in different .dwo file, which means the DIE offsets might not be the + // same between two different type units. So we need to determine if this + // accelerator table matches the type unit in the .dwp file. If it doesn't + // match, then we need to ignore this accelerator table entry as the type + // unit that is in the .dwp file will have its own index. + // In order to determine if the type unit that ended up in a .dwp file + // matches this DebugNames::Entry, we need to find the skeleton compile + // unit for this entry. We rely on each DebugNames::Entry either having + // both a DW_IDX_type_unit and a DW_IDX_compile_unit, or the .debug_names + // table has only a single compile unit with multiple type units. Once + // we find the skeleton compile unit, we make sure the DW_AT_dwo_name + // attributes match. + const llvm::DWARFDebugNames::NameIndex *name_index = entry.getNameIndex(); + assert(name_index); + // Ask the entry for the skeleton compile unit offset. + std::optional<uint64_t> cu_offset = entry.getForeignTUSkeletonCUOffset(); + // If the entry doesn't specify the skeleton compile unit offset, then check + // if the .debug_names table only has one compile unit. If so, then this is + // the skeleton compile unit we should used. + if (!cu_offset && name_index->getCUCount() == 1) + cu_offset = name_index->getCUOffset(0); + + // If we couldn't find the skeleton compile unit offset, be safe and say there + // is no match. We don't want to use an invalid DIE offset on the wrong type + // unit. + if (cu_offset) { + DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::DebugInfo, *cu_offset); + if (cu) { + DWARFBaseDIE cu_die = cu->GetUnitDIEOnly(); + DWARFBaseDIE tu_die = foreign_tu->GetUnitDIEOnly(); + llvm::StringRef cu_dwo_name = + cu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr); + llvm::StringRef tu_dwo_name = + tu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr); + if (cu_dwo_name != tu_dwo_name) + foreign_tu = nullptr; // Ignore this entry, the DWO name doesn't match. + } else { + foreign_tu = nullptr; // Ignore this entry, we can find the skeleton CU + } + } else { + foreign_tu = nullptr; // Ignore this entry, we can find the skeleton CU + } + return true; } DWARFUnit * @@ -291,42 +349,12 @@ void DebugNamesDWARFIndex::GetFullyQualifiedType( continue; - DWARFTypeUnit *foreign_tu = GetForeignTypeUnit(entry); - if (foreign_tu) { - // If this entry represents a foreign type unit, we need to verify that - // the type unit that ended up in the final .dwp file is the right type - // unit. Type units have signatures which are the same across multiple - // .dwo files, but only one of those type units will end up in the .dwp - // file. The contents of type units for the same type can be different - // in different .dwo file, which means the DIE offsets might not be the - // same between two different type units. So we need to determine if this - // accelerator table matches the type unit in the .dwp file. If it doesn't - // match, then we need to ignore this accelerator table entry as the type - // unit that is in the .dwp file will have its own index. - const llvm::DWARFDebugNames::NameIndex *name_index = entry.getNameIndex(); - if (name_index == nullptr) + DWARFTypeUnit *foreign_tu = nullptr; + if (IsForeignTypeUnit(entry, foreign_tu)) { + // If we get a NULL foreign_tu back, the entry doesn't match the type unit + // in the .dwp file. + if (!foreign_tu) continue; - // In order to determine if the type unit that ended up in a .dwp file - // is valid, we need to grab the type unit and check the attribute on the - // type unit matches the .dwo file. For this to happen we rely on each - // .dwo file having its own .debug_names table with a single compile unit - // and multiple type units. This is the only way we can tell if a type - // unit came from a specific .dwo file. - if (name_index->getCUCount() == 1) { - dw_offset_t cu_offset = name_index->getCUOffset(0); - DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::DebugInfo, - cu_offset); - if (cu) { - DWARFBaseDIE cu_die = cu->GetUnitDIEOnly(); - DWARFBaseDIE tu_die = foreign_tu->GetUnitDIEOnly(); - llvm::StringRef cu_dwo_name = - cu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr); - llvm::StringRef tu_dwo_name = - tu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr); - if (cu_dwo_name != tu_dwo_name) - continue; // Ignore this entry, the CU DWO doesn't match the TU DWO - } - } } // Grab at most one extra parent, subsequent parents are not necessary to // test equality. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h index 94fce2ed9c175..984dbd84417b9 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h @@ -88,6 +88,31 @@ class DebugNamesDWARFIndex : public DWARFIndex { DWARFDIE GetDIE(const DebugNames::Entry &entry) const; DWARFTypeUnit *GetForeignTypeUnit(const DebugNames::Entry &entry) const; // std::optional<DIERef> ToDIERef(const DebugNames::Entry &entry) const; + + /// Checks if an entry is a foreign TU and fetch the type unit. + /// + /// This function checks if the DebugNames::Entry refers to a foreign TU and + /// returns true or false to indicate this. The \a foreign_tu pointer will be + /// filled in if this entry matches the type unit's originating .dwo file by + /// verifying that the DW_TAG_type_unit DIE has a DW_AT_dwo_name that matches + /// the DWO name from the originating skeleton compile unit. + /// + /// \param[in] entry + /// The accelerator table entry to check. + /// + /// \param[out] foreign_tu + /// A reference to the foreign type unit pointer that will be filled in + /// with a valid type unit if the entry matches the type unit, or filled in + /// with NULL if the entry isn't valid for the type unit that ended up in + /// the .dwp file. + /// + /// \returns + /// True if \a entry represents a foreign type unit, false otherwise. + bool IsForeignTypeUnit(const DebugNames::Entry &entry, DWARFTypeUnit *&foreign_tu) const; + + DWARFTypeUnit *GetForeignTypeUnit(const DebugNames::Entry &entry) const; + + std::optional<DIERef> ToDIERef(const DebugNames::Entry &entry) const; bool ProcessEntry(const DebugNames::Entry &entry, llvm::function_ref<bool(DWARFDIE die)> callback); diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h index 6c7132eb35021..bc9b11ea89587 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h @@ -72,6 +72,25 @@ class DWARFAcceleratorTable { return std::nullopt; } + // Returns the the CU offset for a foreign TU. + // + // Entries that represent foreign type units can have both a + // DW_IDX_compile_unit and a DW_IDX_type_unit. In this case the + // DW_IDX_compile_unit represents the skeleton CU offset for the .dwo file + // that matches this foreign type unit entry. The type unit will have a + // DW_AT_dwo_name attribute that must match the attribute in the skeleton + // CU. This function is needed be because the getCUOffset() method will + // return the first CU if there is no DW_IDX_compile_unit attribute in this + // entry, and it won't return a value CU offset if there is a + // DW_IDX_type_unit. But this function will return std::nullopt if there is + // no DW_IDX_compile_unit attribute or if this doesn't represent a foreign + // type unit. + virtual std::optional<uint64_t> getForeignTUSkeletonCUOffset() const { + // Default return for accelerator tables that don't support type units. + return std::nullopt; + } + + /// Returns the Tag of the Debug Info Entry associated with this /// Accelerator Entry or std::nullopt if the Tag is not recorded in this /// Accelerator Entry. @@ -445,6 +464,7 @@ class DWARFDebugNames : public DWARFAcceleratorTable { std::optional<uint64_t> getCUOffset() const override; std::optional<uint64_t> getLocalTUOffset() const override; std::optional<uint64_t> getForeignTUTypeSignature() const override; + std::optional<uint64_t> getForeignTUSkeletonCUOffset() const override; std::optional<dwarf::Tag> getTag() const override { return tag(); } diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp index e120b59ccb4e6..01d68ec5bcbf3 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -670,6 +670,26 @@ DWARFDebugNames::Entry::getForeignTUTypeSignature() const { return NameIdx->getForeignTUSignature(ForeignTUIndex); } + +std::optional<uint64_t> +DWARFDebugNames::Entry::getForeignTUSkeletonCUOffset() const { + // Must have a DW_IDX_type_unit and it must be a foreign type unit. + if (!getForeignTUTypeSignature()) + return std::nullopt; + // Lookup the DW_IDX_compile_unit and make sure we have one, if we don't + // we don't default to returning the first compile unit like getCUOffset(). + std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_compile_unit); + if (!Off) + return std::nullopt; + // Extract the CU index and return the right CU offset. + if (std::optional<uint64_t> CUIndex = Off->getAsUnsignedConstant()) { + if (*CUIndex >= NameIdx->getCUCount()) + return std::nullopt; + return NameIdx->getCUOffset(*CUIndex); + } + return std::nullopt; +} + std::optional<uint64_t> DWARFDebugNames::Entry::getLocalTUIndex() const { if (std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_type_unit)) return Off->getAsUnsignedConstant(); >From 63d56ad0a2ef7bcafcd2489ba64d7e46799b4354 Mon Sep 17 00:00:00 2001 From: Greg Clayton <clayb...@gmail.com> Date: Mon, 3 Jun 2024 16:05:06 -0700 Subject: [PATCH 3/8] Finish merges with upstream HEAD. --- .../SymbolFile/DWARF/DWARFDebugInfo.cpp | 26 +++++++++---------- .../SymbolFile/DWARF/DebugNamesDWARFIndex.cpp | 1 + .../SymbolFile/DWARF/DebugNamesDWARFIndex.h | 2 +- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 3 ++- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp index 056c6d4b0605f..28df305a0c771 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -222,19 +222,19 @@ DWARFUnit *DWARFDebugInfo::GetUnitAtOffset(DIERef::Section section, return result; } -DWARFUnit *DWARFDebugInfo::GetUnit(const DIERef &die_ref) { - // Make sure we get the correct SymbolFileDWARF from the DIERef before - // asking for information from a debug info object. We might start with the - // DWARFDebugInfo for the main executable in a split DWARF and the DIERef - // might be pointing to a specific .dwo file or to the .dwp file. So this - // makes sure we get the right SymbolFileDWARF instance before finding the - // DWARFUnit that contains the offset. If we just use this object to do the - // search, we might be using the wrong .debug_info section from the wrong - // file with an offset meant for a different section. - SymbolFileDWARF *dwarf = m_dwarf.GetDIERefSymbolFile(die_ref); - return dwarf->DebugInfo().GetUnitContainingDIEOffset(die_ref.section(), - die_ref.die_offset()); -} +// DWARFUnit *DWARFDebugInfo::GetUnit(const DIERef &die_ref) { +// // Make sure we get the correct SymbolFileDWARF from the DIERef before +// // asking for information from a debug info object. We might start with the +// // DWARFDebugInfo for the main executable in a split DWARF and the DIERef +// // might be pointing to a specific .dwo file or to the .dwp file. So this +// // makes sure we get the right SymbolFileDWARF instance before finding the +// // DWARFUnit that contains the offset. If we just use this object to do the +// // search, we might be using the wrong .debug_info section from the wrong +// // file with an offset meant for a different section. +// SymbolFileDWARF *dwarf = m_dwarf.GetDIERefSymbolFile(die_ref); +// return dwarf->DebugInfo().GetUnitContainingDIEOffset(die_ref.section(), +// die_ref.die_offset()); +// } DWARFUnit * DWARFDebugInfo::GetUnitContainingDIEOffset(DIERef::Section section, diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp index bfdbb7765ae9e..47d55fbb7ec2c 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp @@ -10,6 +10,7 @@ #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" #include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h" #include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h" +#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h" #include "lldb/Core/Module.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Stream.h" diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h index 984dbd84417b9..22f881e66c2bc 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h @@ -86,7 +86,7 @@ class DebugNamesDWARFIndex : public DWARFIndex { DWARFUnit *GetNonSkeletonUnit(const DebugNames::Entry &entry) const; DWARFDIE GetDIE(const DebugNames::Entry &entry) const; - DWARFTypeUnit *GetForeignTypeUnit(const DebugNames::Entry &entry) const; + // std::optional<DIERef> ToDIERef(const DebugNames::Entry &entry) const; /// Checks if an entry is a foreign TU and fetch the type unit. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 3606e5b1251bc..727561b0205eb 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1791,7 +1791,8 @@ SymbolFileDWARF::GetDIE(const DIERef &die_ref) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); SymbolFileDWARF *symbol_file = GetDIERefSymbolFile(die_ref); if (symbol_file) - return symbol_file->DebugInfo().GetDIE(die_ref); + return symbol_file->DebugInfo().GetDIE(die_ref.section(), + die_ref.die_offset()); return DWARFDIE(); } >From 4cdeaec8455e2f27c1e46388364a7aa7cb174557 Mon Sep 17 00:00:00 2001 From: Greg Clayton <clayb...@gmail.com> Date: Fri, 7 Jun 2024 14:36:22 -0700 Subject: [PATCH 4/8] Modified IsForeignTypeUnit to return a std::optional and modify to work with new DWARF changes. --- .../SymbolFile/DWARF/DebugNamesDWARFIndex.cpp | 117 +++++++++--------- .../SymbolFile/DWARF/DebugNamesDWARFIndex.h | 18 +-- .../DebugInfo/DWARF/DWARFAcceleratorTable.cpp | 16 ++- 3 files changed, 78 insertions(+), 73 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp index 47d55fbb7ec2c..76dc1c9bb6723 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp @@ -61,53 +61,50 @@ DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) { return result; } -bool -DebugNamesDWARFIndex::IsForeignTypeUnit(const DebugNames::Entry &entry, - DWARFTypeUnit *&foreign_tu) const { - foreign_tu = nullptr; +std::optional<DWARFTypeUnit *> +DebugNamesDWARFIndex::IsForeignTypeUnit(const DebugNames::Entry &entry) const { std::optional<uint64_t> type_sig = entry.getForeignTUTypeSignature(); if (!type_sig.has_value()) - return false; + return std::nullopt; auto dwp_sp = m_debug_info.GetDwpSymbolFile(); - if (dwp_sp) { - // We have a .dwp file, just get the type unit from there. - foreign_tu = dwp_sp->DebugInfo().GetTypeUnitForHash(*type_sig); - } else { - // We have a .dwo file that contains the type unit. - foreign_tu = nullptr; // TODO: fixme before checkin + if (!dwp_sp) { + // No .dwp file, we need to load the .dwo file. + + // Ask the entry for the skeleton compile unit offset and fetch the .dwo + // file from it and get the type unit by signature from there. If we find + // the type unit in the .dwo file, we don't need to check that the + // DW_AT_dwo_name matches because each .dwo file can have its own type unit. + std::optional<uint64_t> unit_offset = entry.getForeignTUSkeletonCUOffset(); + if (!unit_offset) + return nullptr; // Return NULL, this is a type unit, but couldn't find it. + DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, + *unit_offset); + if (!cu) + return nullptr; // Return NULL, this is a type unit, but couldn't find it. + DWARFUnit &dwo_cu = cu->GetNonSkeletonUnit(); + // We don't need the check if the type unit matches the .dwo file if we have + // a .dwo file (not a .dwp), so we can just return the value here. + if (!dwo_cu.IsDWOUnit()) + return nullptr; // We weren't able to load the .dwo file. + return dwo_cu.GetSymbolFileDWARF().DebugInfo().GetTypeUnitForHash(*type_sig); } - if (foreign_tu == nullptr) - return true; - // If this entry represents a foreign type unit, we need to verify that - // the type unit that ended up in the final .dwp file is the right type - // unit. Type units have signatures which are the same across multiple - // .dwo files, but only one of those type units will end up in the .dwp - // file. The contents of type units for the same type can be different - // in different .dwo file, which means the DIE offsets might not be the - // same between two different type units. So we need to determine if this - // accelerator table matches the type unit in the .dwp file. If it doesn't - // match, then we need to ignore this accelerator table entry as the type - // unit that is in the .dwp file will have its own index. - // In order to determine if the type unit that ended up in a .dwp file - // matches this DebugNames::Entry, we need to find the skeleton compile - // unit for this entry. We rely on each DebugNames::Entry either having - // both a DW_IDX_type_unit and a DW_IDX_compile_unit, or the .debug_names - // table has only a single compile unit with multiple type units. Once - // we find the skeleton compile unit, we make sure the DW_AT_dwo_name - // attributes match. - const llvm::DWARFDebugNames::NameIndex *name_index = entry.getNameIndex(); - assert(name_index); - // Ask the entry for the skeleton compile unit offset. + // We have a .dwp file, just get the type unit from there. We need to verify + // that the type unit that ended up in the final .dwp file is the right type + // unit. Type units have signatures which are the same across multiple .dwo + // files, but only one of those type units will end up in the .dwp file. The + // contents of type units for the same type can be different in different .dwo + // files, which means the DIE offsets might not be the same between two + // different type units. So we need to determine if this accelerator table + // matches the type unit that ended up in the .dwp file. If it doesn't match, + // then we need to ignore this accelerator table entry as the type unit that + // is in the .dwp file will have its own index. In order to determine if the + // type unit that ended up in a .dwp file matches this DebugNames::Entry, we + // need to find the skeleton compile unit for this entry. + DWARFTypeUnit *foreign_tu = dwp_sp->DebugInfo().GetTypeUnitForHash(*type_sig); + if (!foreign_tu) + return nullptr; // Return NULL, this is a type unit, but couldn't find it. + std::optional<uint64_t> cu_offset = entry.getForeignTUSkeletonCUOffset(); - // If the entry doesn't specify the skeleton compile unit offset, then check - // if the .debug_names table only has one compile unit. If so, then this is - // the skeleton compile unit we should used. - if (!cu_offset && name_index->getCUCount() == 1) - cu_offset = name_index->getCUOffset(0); - - // If we couldn't find the skeleton compile unit offset, be safe and say there - // is no match. We don't want to use an invalid DIE offset on the wrong type - // unit. if (cu_offset) { DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::DebugInfo, *cu_offset); if (cu) { @@ -117,27 +114,30 @@ DebugNamesDWARFIndex::IsForeignTypeUnit(const DebugNames::Entry &entry, cu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr); llvm::StringRef tu_dwo_name = tu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr); - if (cu_dwo_name != tu_dwo_name) - foreign_tu = nullptr; // Ignore this entry, the DWO name doesn't match. - } else { - foreign_tu = nullptr; // Ignore this entry, we can find the skeleton CU + if (cu_dwo_name == tu_dwo_name) + return foreign_tu; // We found a match! } - } else { - foreign_tu = nullptr; // Ignore this entry, we can find the skeleton CU } - return true; + return nullptr; // Return NULL, this is a type unit, but couldn't find it. } DWARFUnit * DebugNamesDWARFIndex::GetNonSkeletonUnit(const DebugNames::Entry &entry) const { + + if (std::optional<DWARFTypeUnit *> foreign_tu = IsForeignTypeUnit(entry)) + return foreign_tu.value(); + // Look for a DWARF unit offset (CU offset or local TU offset) as they are // both offsets into the .debug_info section. std::optional<uint64_t> unit_offset = entry.getCUOffset(); if (!unit_offset) unit_offset = entry.getLocalTUOffset(); - DWARFUnit *cu = - m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *unit_offset); - return cu ? &cu->GetNonSkeletonUnit() : nullptr; + if (unit_offset) { + if (DWARFUnit *cu = + m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *unit_offset)) + return &cu->GetNonSkeletonUnit(); + } + return nullptr; } DWARFDIE DebugNamesDWARFIndex::GetDIE(const DebugNames::Entry &entry) const { @@ -349,14 +349,13 @@ void DebugNamesDWARFIndex::GetFullyQualifiedType( if (!isType(entry.tag())) continue; - - DWARFTypeUnit *foreign_tu = nullptr; - if (IsForeignTypeUnit(entry, foreign_tu)) { - // If we get a NULL foreign_tu back, the entry doesn't match the type unit - // in the .dwp file. - if (!foreign_tu) + // If we get a NULL foreign_tu back, the entry doesn't match the type unit + // in the .dwp file, or we were not able to load the .dwo file or the DWO ID + // didn't match. + std::optional<DWARFTypeUnit *> foreign_tu = IsForeignTypeUnit(entry); + if (foreign_tu && foreign_tu.value() == nullptr) continue; - } + // Grab at most one extra parent, subsequent parents are not necessary to // test equality. std::optional<llvm::SmallVector<Entry, 4>> parent_chain = diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h index 22f881e66c2bc..311eba5062d2c 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h @@ -100,15 +100,17 @@ class DebugNamesDWARFIndex : public DWARFIndex { /// \param[in] entry /// The accelerator table entry to check. /// - /// \param[out] foreign_tu - /// A reference to the foreign type unit pointer that will be filled in - /// with a valid type unit if the entry matches the type unit, or filled in - /// with NULL if the entry isn't valid for the type unit that ended up in - /// the .dwp file. - /// /// \returns - /// True if \a entry represents a foreign type unit, false otherwise. - bool IsForeignTypeUnit(const DebugNames::Entry &entry, DWARFTypeUnit *&foreign_tu) const; + /// A std::optional that has a value if this entry represents a foreign type + /// unit. If the pointer is valid, then we were able to find and match the + /// entry to the type unit in the .dwo or .dwp file. The returned value can + /// have a valid, yet contain NULL in the following cases: + /// - we were not able to load the .dwo file (missing or DWO ID mismatch) + /// - we were able to load the .dwp file, but the type units DWO name + /// doesn't match the originating skeleton compile unit's entry + /// Returns std::nullopt if this entry is not a foreign type unit entry. + std::optional<DWARFTypeUnit *> + IsForeignTypeUnit(const DebugNames::Entry &entry) const; DWARFTypeUnit *GetForeignTypeUnit(const DebugNames::Entry &entry) const; diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp index 01d68ec5bcbf3..7c26836978568 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -678,15 +678,19 @@ DWARFDebugNames::Entry::getForeignTUSkeletonCUOffset() const { return std::nullopt; // Lookup the DW_IDX_compile_unit and make sure we have one, if we don't // we don't default to returning the first compile unit like getCUOffset(). + std::optional<uint64_t> CUIndex; std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_compile_unit); - if (!Off) - return std::nullopt; + if (Off) { + CUIndex = Off->getAsUnsignedConstant(); + } else { + // Check if there is only 1 CU and return that. Most .o files generate one + // .debug_names table per source file where there is 1 CU and many TUs. + if (NameIdx->getCUCount() == 1) + CUIndex = 0; + } // Extract the CU index and return the right CU offset. - if (std::optional<uint64_t> CUIndex = Off->getAsUnsignedConstant()) { - if (*CUIndex >= NameIdx->getCUCount()) - return std::nullopt; + if (CUIndex && *CUIndex < NameIdx->getCUCount()) return NameIdx->getCUOffset(*CUIndex); - } return std::nullopt; } >From 554e080632e415e825421494f0d1fe020a3f4fb8 Mon Sep 17 00:00:00 2001 From: Greg Clayton <clayb...@gmail.com> Date: Fri, 7 Jun 2024 15:45:10 -0700 Subject: [PATCH 5/8] Add tests for .dwo files. --- .../DWARF/x86/dwp-foreign-type-units.cpp | 71 ++++++++++++++----- 1 file changed, 54 insertions(+), 17 deletions(-) diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/dwp-foreign-type-units.cpp b/lldb/test/Shell/SymbolFile/DWARF/x86/dwp-foreign-type-units.cpp index 3662059166790..30f91de15fa4b 100644 --- a/lldb/test/Shell/SymbolFile/DWARF/x86/dwp-foreign-type-units.cpp +++ b/lldb/test/Shell/SymbolFile/DWARF/x86/dwp-foreign-type-units.cpp @@ -23,21 +23,53 @@ // RUN: -fdebug-types-section -gpubnames -c %s -o %t.foo.o // RUN: ld.lld %t.main.o %t.foo.o -o %t -// First we check when we make the .dwp file with %t.main.dwo first so it will +// Check when have no .dwp file that we can find the types in both .dwo files. +// RUN: rm -f %t.dwp +// RUN: %lldb \ +// RUN: -o "type lookup IntegerType" \ +// RUN: -o "type lookup FloatType" \ +// RUN: -o "type lookup CustomType" \ +// RUN: -b %t | FileCheck %s --check-prefix=NODWP +// NODWP: (lldb) type lookup IntegerType +// NODWP-NEXT: int +// NODWP-NEXT: unsigned int +// NODWP: (lldb) type lookup FloatType +// NODWP-NEXT: double +// NODWP-NEXT: float +// NODWP: (lldb) type lookup CustomType +// NODWP-NEXT: struct CustomType { +// NODWP-NEXT: typedef int IntegerType; +// NODWP-NEXT: typedef double FloatType; +// NODWP-NEXT: CustomType::IntegerType x; +// NODWP-NEXT: CustomType::FloatType y; +// NODWP-NEXT: } +// NODWP-NEXT: struct CustomType { +// NODWP-NEXT: typedef unsigned int IntegerType; +// NODWP-NEXT: typedef float FloatType; +// NODWP-NEXT: CustomType::IntegerType x; +// NODWP-NEXT: CustomType::FloatType y; +// NODWP-NEXT: } + +// Check when we make the .dwp file with %t.main.dwo first so it will // pick the type unit from %t.main.dwo. Verify we find only the types from // %t.main.dwo's type unit. // RUN: llvm-dwp %t.main.dwo %t.foo.dwo -o %t.dwp // RUN: %lldb \ // RUN: -o "type lookup IntegerType" \ // RUN: -o "type lookup FloatType" \ -// RUN: -o "type lookup IntegerType" \ -// RUN: -b %t | FileCheck %s -// CHECK: (lldb) type lookup IntegerType -// CHECK-NEXT: int -// CHECK-NEXT: (lldb) type lookup FloatType -// CHECK-NEXT: double -// CHECK-NEXT: (lldb) type lookup IntegerType -// CHECK-NEXT: int +// RUN: -o "type lookup CustomType" \ +// RUN: -b %t | FileCheck %s --check-prefix=DWPMAIN +// DWPMAIN: (lldb) type lookup IntegerType +// DWPMAIN-NEXT: int +// DWPMAIN: (lldb) type lookup FloatType +// DWPMAIN-NEXT: double +// DWPMAIN: (lldb) type lookup CustomType +// DWPMAIN-NEXT: struct CustomType { +// DWPMAIN-NEXT: typedef int IntegerType; +// DWPMAIN-NEXT: typedef double FloatType; +// DWPMAIN-NEXT: CustomType::IntegerType x; +// DWPMAIN-NEXT: CustomType::FloatType y; +// DWPMAIN-NEXT: } // Next we check when we make the .dwp file with %t.foo.dwo first so it will // pick the type unit from %t.main.dwo. Verify we find only the types from @@ -46,15 +78,20 @@ // RUN: %lldb \ // RUN: -o "type lookup IntegerType" \ // RUN: -o "type lookup FloatType" \ -// RUN: -o "type lookup IntegerType" \ -// RUN: -b %t | FileCheck %s --check-prefix=VARIANT +// RUN: -o "type lookup CustomType" \ +// RUN: -b %t | FileCheck %s --check-prefix=DWPFOO -// VARIANT: (lldb) type lookup IntegerType -// VARIANT-NEXT: unsigned int -// VARIANT-NEXT: (lldb) type lookup FloatType -// VARIANT-NEXT: float -// VARIANT-NEXT: (lldb) type lookup IntegerType -// VARIANT-NEXT: unsigned int +// DWPFOO: (lldb) type lookup IntegerType +// DWPFOO-NEXT: unsigned int +// DWPFOO: (lldb) type lookup FloatType +// DWPFOO-NEXT: float +// DWPFOO: (lldb) type lookup CustomType +// DWPFOO-NEXT: struct CustomType { +// DWPFOO-NEXT: typedef unsigned int IntegerType; +// DWPFOO-NEXT: typedef float FloatType; +// DWPFOO-NEXT: CustomType::IntegerType x; +// DWPFOO-NEXT: CustomType::FloatType y; +// DWPFOO-NEXT: } // We need to do this so we end with a type unit in each .dwo file and that has >From b518e9a4060be817ca95458f3ae600b27f9e86f1 Mon Sep 17 00:00:00 2001 From: Greg Clayton <clayb...@gmail.com> Date: Fri, 7 Jun 2024 16:01:29 -0700 Subject: [PATCH 6/8] After merge, address review comments and remove dead code. --- .../SymbolFile/DWARF/DWARFDebugInfo.cpp | 16 +----------- .../Plugins/SymbolFile/DWARF/DWARFDebugInfo.h | 2 +- .../SymbolFile/DWARF/DebugNamesDWARFIndex.cpp | 2 +- .../SymbolFile/DWARF/DebugNamesDWARFIndex.h | 18 +++++-------- .../SymbolFile/DWARF/ManualDWARFIndex.cpp | 2 +- .../SymbolFile/DWARF/ManualDWARFIndex.h | 2 +- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 2 ++ .../DWARF/x86/dwp-foreign-type-units.cpp | 26 +++++++++---------- 8 files changed, 27 insertions(+), 43 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp index 28df305a0c771..f7df38d240191 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -222,20 +222,6 @@ DWARFUnit *DWARFDebugInfo::GetUnitAtOffset(DIERef::Section section, return result; } -// DWARFUnit *DWARFDebugInfo::GetUnit(const DIERef &die_ref) { -// // Make sure we get the correct SymbolFileDWARF from the DIERef before -// // asking for information from a debug info object. We might start with the -// // DWARFDebugInfo for the main executable in a split DWARF and the DIERef -// // might be pointing to a specific .dwo file or to the .dwp file. So this -// // makes sure we get the right SymbolFileDWARF instance before finding the -// // DWARFUnit that contains the offset. If we just use this object to do the -// // search, we might be using the wrong .debug_info section from the wrong -// // file with an offset meant for a different section. -// SymbolFileDWARF *dwarf = m_dwarf.GetDIERefSymbolFile(die_ref); -// return dwarf->DebugInfo().GetUnitContainingDIEOffset(die_ref.section(), -// die_ref.die_offset()); -// } - DWARFUnit * DWARFDebugInfo::GetUnitContainingDIEOffset(DIERef::Section section, dw_offset_t die_offset) { @@ -246,7 +232,7 @@ DWARFDebugInfo::GetUnitContainingDIEOffset(DIERef::Section section, return result; } -const std::shared_ptr<SymbolFileDWARFDwo> DWARFDebugInfo::GetDwpSymbolFile() { +const std::shared_ptr<SymbolFileDWARFDwo> &DWARFDebugInfo::GetDwpSymbolFile() { return m_dwarf.GetDwpSymbolFile(); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h index 4d4555a338252..598739bf3cb95 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h @@ -52,7 +52,7 @@ class DWARFDebugInfo { const DWARFDebugAranges &GetCompileUnitAranges(); - const std::shared_ptr<SymbolFileDWARFDwo> GetDwpSymbolFile(); + const std::shared_ptr<SymbolFileDWARFDwo> &GetDwpSymbolFile(); protected: typedef std::vector<DWARFUnitSP> UnitColl; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp index 76dc1c9bb6723..68f1c476889cf 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp @@ -37,7 +37,7 @@ DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names, llvm::DenseSet<uint64_t> -DebugNamesDWARFIndex::GetTypeUnitSigs(const DebugNames &debug_names) { +DebugNamesDWARFIndex::GetTypeUnitSignatures(const DebugNames &debug_names) { llvm::DenseSet<uint64_t> result; for (const DebugNames::NameIndex &ni : debug_names) { const uint32_t num_tus = ni.getForeignTUCount(); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h index 311eba5062d2c..93ba3f5a66883 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h @@ -71,7 +71,7 @@ class DebugNamesDWARFIndex : public DWARFIndex { m_debug_names_data(debug_names_data), m_debug_str_data(debug_str_data), m_debug_names_up(std::move(debug_names_up)), m_fallback(module, dwarf, GetUnits(*m_debug_names_up), - GetTypeUnitSigs(*m_debug_names_up)) {} + GetTypeUnitSignatures(*m_debug_names_up)) {} DWARFDebugInfo &m_debug_info; @@ -87,15 +87,14 @@ class DebugNamesDWARFIndex : public DWARFIndex { DWARFUnit *GetNonSkeletonUnit(const DebugNames::Entry &entry) const; DWARFDIE GetDIE(const DebugNames::Entry &entry) const; - // std::optional<DIERef> ToDIERef(const DebugNames::Entry &entry) const; - /// Checks if an entry is a foreign TU and fetch the type unit. /// /// This function checks if the DebugNames::Entry refers to a foreign TU and - /// returns true or false to indicate this. The \a foreign_tu pointer will be - /// filled in if this entry matches the type unit's originating .dwo file by - /// verifying that the DW_TAG_type_unit DIE has a DW_AT_dwo_name that matches - /// the DWO name from the originating skeleton compile unit. + /// returns an optional with a value of the \a entry is a foreign type unit + /// entry. A valid pointer will be returned if this entry is from a .dwo file + /// or if it is from a .dwp file and it matches the type unit's originating + /// .dwo file by verifying that the DW_TAG_type_unit DIE has a DW_AT_dwo_name + /// that matches the DWO name from the originating skeleton compile unit. /// /// \param[in] entry /// The accelerator table entry to check. @@ -112,9 +111,6 @@ class DebugNamesDWARFIndex : public DWARFIndex { std::optional<DWARFTypeUnit *> IsForeignTypeUnit(const DebugNames::Entry &entry) const; - DWARFTypeUnit *GetForeignTypeUnit(const DebugNames::Entry &entry) const; - - std::optional<DIERef> ToDIERef(const DebugNames::Entry &entry) const; bool ProcessEntry(const DebugNames::Entry &entry, llvm::function_ref<bool(DWARFDIE die)> callback); @@ -127,7 +123,7 @@ class DebugNamesDWARFIndex : public DWARFIndex { llvm::StringRef name); static llvm::DenseSet<dw_offset_t> GetUnits(const DebugNames &debug_names); - static llvm::DenseSet<uint64_t> GetTypeUnitSigs(const DebugNames &debug_names); + static llvm::DenseSet<uint64_t> GetTypeUnitSignatures(const DebugNames &debug_names); }; } // namespace dwarf diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index 103e157d3cac5..118ed97f802f7 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -61,7 +61,7 @@ void ManualDWARFIndex::Index() { if (dwp_info && dwp_info->ContainsTypeUnits()) { for (size_t U = 0; U < dwp_info->GetNumUnits(); ++U) { if (auto *tu = llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U))) { - if (m_type_sigs_to_avoid.count(tu->GetTypeHash()) == 0) + if (!m_type_sigs_to_avoid.contains(tu->GetTypeHash())) units_to_index.push_back(tu); } } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h index 3f0bb39dfc20c..d8c4a22ab21f7 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h @@ -25,7 +25,7 @@ class ManualDWARFIndex : public DWARFIndex { llvm::DenseSet<uint64_t> type_sigs_to_avoid = {}) : DWARFIndex(module), m_dwarf(&dwarf), m_units_to_avoid(std::move(units_to_avoid)), - m_type_sigs_to_avoid(type_sigs_to_avoid) {} + m_type_sigs_to_avoid(std::move(type_sigs_to_avoid)) {} void Preload() override { Index(); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 727561b0205eb..dc4f91628ba7f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -700,6 +700,7 @@ llvm::DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() { if (debug_abbrev_data.GetByteSize() == 0) return nullptr; + ElapsedTime elapsed(m_parse_time); auto abbr = std::make_unique<llvm::DWARFDebugAbbrev>(debug_abbrev_data.GetAsLLVM()); llvm::Error error = abbr->parse(); @@ -2747,6 +2748,7 @@ void SymbolFileDWARF::FindTypes(const TypeQuery &query, TypeResults &results) { die_context = die.GetDeclContext(); else die_context = die.GetTypeLookupContext(); + assert(!die_context.empty()); if (!query.ContextMatches(die_context)) return true; // Keep iterating over index types, context mismatch. diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/dwp-foreign-type-units.cpp b/lldb/test/Shell/SymbolFile/DWARF/x86/dwp-foreign-type-units.cpp index 30f91de15fa4b..90e8220837abe 100644 --- a/lldb/test/Shell/SymbolFile/DWARF/x86/dwp-foreign-type-units.cpp +++ b/lldb/test/Shell/SymbolFile/DWARF/x86/dwp-foreign-type-units.cpp @@ -2,19 +2,19 @@ // This test will make a type that will be compiled differently into two // different .dwo files in a type unit with the same type hash, but with -// differing contents. I have discovered that the hash for the type unit is -// simply based off of the typename and doesn't seem to differ when the contents -// differ, so that will help us test foreign type units in the .debug_names -// section of the main executable. When a DWP file is made, only one type unit -// will be kept and the type unit that is kept has the .dwo file name that it -// came from. When LLDB loads the foreign type units, it needs to verify that -// any entries from foreign type units come from the right .dwo file. We test -// this since the contents of type units are not always the same even though -// they have the same type hash. We don't want invalid accelerator table entries -// to come from one .dwo file and be used on a type unit from another since this -// could cause invalid lookups to happen. LLDB knows how to track down which -// .dwo file a type unit comes from by looking at the DW_AT_dwo_name attribute -// in the DW_TAG_type_unit. +// differing contents. Clang's type unit signature is based only on the mangled +// name of the type, regardless of the contents of the type, so that will help +// us test foreign type units in the .debug_names section of the main +// executable. When a DWP file is made, only one type unit will be kept and the +// type unit that is kept has the .dwo file name that it came from. When LLDB +// loads the foreign type units, it needs to verify that any entries from +// foreign type units come from the right .dwo file. We test this since the +// contents of type units are not always the same even though they have the same +// type hash. We don't want invalid accelerator table entries to come from one +// .dwo file and be used on a type unit from another since this could cause +// invalid lookups to happen. LLDB knows how to track down which .dwo file a +// type unit comes from by looking at the DW_AT_dwo_name attribute in the +// DW_TAG_type_unit. // Now test with DWARF5 // RUN: %clang -target x86_64-pc-linux -gdwarf-5 -gsplit-dwarf \ >From 8671b21eb5235b220846d3c37cca52b7ca522d79 Mon Sep 17 00:00:00 2001 From: Greg Clayton <clayb...@gmail.com> Date: Fri, 7 Jun 2024 16:02:26 -0700 Subject: [PATCH 7/8] Ran clang-format. --- .../SymbolFile/DWARF/DebugNamesDWARFIndex.cpp | 14 +++++++------- .../SymbolFile/DWARF/DebugNamesDWARFIndex.h | 3 ++- .../Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp | 3 ++- .../Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 7 ++++--- .../DWARF/x86/dwp-foreign-type-units.cpp | 1 - .../llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h | 1 - llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp | 5 ++--- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp index 68f1c476889cf..334d742d4e10e 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp @@ -35,7 +35,6 @@ DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names, module, std::move(index_up), debug_names, debug_str, dwarf)); } - llvm::DenseSet<uint64_t> DebugNamesDWARFIndex::GetTypeUnitSignatures(const DebugNames &debug_names) { llvm::DenseSet<uint64_t> result; @@ -77,8 +76,8 @@ DebugNamesDWARFIndex::IsForeignTypeUnit(const DebugNames::Entry &entry) const { std::optional<uint64_t> unit_offset = entry.getForeignTUSkeletonCUOffset(); if (!unit_offset) return nullptr; // Return NULL, this is a type unit, but couldn't find it. - DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, - *unit_offset); + DWARFUnit *cu = + m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *unit_offset); if (!cu) return nullptr; // Return NULL, this is a type unit, but couldn't find it. DWARFUnit &dwo_cu = cu->GetNonSkeletonUnit(); @@ -86,7 +85,8 @@ DebugNamesDWARFIndex::IsForeignTypeUnit(const DebugNames::Entry &entry) const { // a .dwo file (not a .dwp), so we can just return the value here. if (!dwo_cu.IsDWOUnit()) return nullptr; // We weren't able to load the .dwo file. - return dwo_cu.GetSymbolFileDWARF().DebugInfo().GetTypeUnitForHash(*type_sig); + return dwo_cu.GetSymbolFileDWARF().DebugInfo().GetTypeUnitForHash( + *type_sig); } // We have a .dwp file, just get the type unit from there. We need to verify // that the type unit that ended up in the final .dwp file is the right type @@ -133,8 +133,8 @@ DebugNamesDWARFIndex::GetNonSkeletonUnit(const DebugNames::Entry &entry) const { if (!unit_offset) unit_offset = entry.getLocalTUOffset(); if (unit_offset) { - if (DWARFUnit *cu = - m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *unit_offset)) + if (DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, + *unit_offset)) return &cu->GetNonSkeletonUnit(); } return nullptr; @@ -354,7 +354,7 @@ void DebugNamesDWARFIndex::GetFullyQualifiedType( // didn't match. std::optional<DWARFTypeUnit *> foreign_tu = IsForeignTypeUnit(entry); if (foreign_tu && foreign_tu.value() == nullptr) - continue; + continue; // Grab at most one extra parent, subsequent parents are not necessary to // test equality. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h index 93ba3f5a66883..6233c053f5f00 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h @@ -123,7 +123,8 @@ class DebugNamesDWARFIndex : public DWARFIndex { llvm::StringRef name); static llvm::DenseSet<dw_offset_t> GetUnits(const DebugNames &debug_names); - static llvm::DenseSet<uint64_t> GetTypeUnitSignatures(const DebugNames &debug_names); + static llvm::DenseSet<uint64_t> + GetTypeUnitSignatures(const DebugNames &debug_names); }; } // namespace dwarf diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index 118ed97f802f7..d581d3773ab23 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -60,7 +60,8 @@ void ManualDWARFIndex::Index() { } if (dwp_info && dwp_info->ContainsTypeUnits()) { for (size_t U = 0; U < dwp_info->GetNumUnits(); ++U) { - if (auto *tu = llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U))) { + if (auto *tu = + llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U))) { if (!m_type_sigs_to_avoid.contains(tu->GetTypeHash())) units_to_index.push_back(tu); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index dc4f91628ba7f..5253c0d138955 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1767,7 +1767,7 @@ SymbolFileDWARF *SymbolFileDWARF::GetDIERefSymbolFile(const DIERef &die_ref) { if (file_index) { SymbolFileDWARFDebugMap *debug_map = GetDebugMapSymfile(); if (debug_map) { - // We have a SymbolFileDWARFDebugMap, so let it find the right file + // We have a SymbolFileDWARFDebugMap, so let it find the right file return debug_map->GetSymbolFileByOSOIndex(*file_index); } else { // Handle the .dwp file case correctly @@ -1775,8 +1775,9 @@ SymbolFileDWARF *SymbolFileDWARF::GetDIERefSymbolFile(const DIERef &die_ref) { return GetDwpSymbolFile().get(); // DWP case // Handle the .dwo file case correctly - return DebugInfo().GetUnitAtIndex(*die_ref.file_index()) - ->GetDwoSymbolFile(); // DWO case + return DebugInfo() + .GetUnitAtIndex(*die_ref.file_index()) + ->GetDwoSymbolFile(); // DWO case } } return this; diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/dwp-foreign-type-units.cpp b/lldb/test/Shell/SymbolFile/DWARF/x86/dwp-foreign-type-units.cpp index 90e8220837abe..046395670d046 100644 --- a/lldb/test/Shell/SymbolFile/DWARF/x86/dwp-foreign-type-units.cpp +++ b/lldb/test/Shell/SymbolFile/DWARF/x86/dwp-foreign-type-units.cpp @@ -93,7 +93,6 @@ // DWPFOO-NEXT: CustomType::FloatType y; // DWPFOO-NEXT: } - // We need to do this so we end with a type unit in each .dwo file and that has // the same signature but different contents. When we make the .dwp file, then // one of the type units will end up in the .dwp file and we will have diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h index bc9b11ea89587..7765a0607c3f9 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h @@ -90,7 +90,6 @@ class DWARFAcceleratorTable { return std::nullopt; } - /// Returns the Tag of the Debug Info Entry associated with this /// Accelerator Entry or std::nullopt if the Tag is not recorded in this /// Accelerator Entry. diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp index 7c26836978568..0ea73ad9c23a4 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -662,15 +662,14 @@ DWARFDebugNames::Entry::getForeignTUTypeSignature() const { std::optional<uint64_t> Index = getLocalTUIndex(); const uint32_t NumLocalTUs = NameIdx->getLocalTUCount(); if (!Index || *Index < NumLocalTUs) - return std::nullopt; // Invalid TU index or TU index is for a local TU + return std::nullopt; // Invalid TU index or TU index is for a local TU // The foreign TU index is the TU index minus the number of local TUs. const uint64_t ForeignTUIndex = *Index - NumLocalTUs; if (ForeignTUIndex >= NameIdx->getForeignTUCount()) - return std::nullopt; // Invalid foreign TU index. + return std::nullopt; // Invalid foreign TU index. return NameIdx->getForeignTUSignature(ForeignTUIndex); } - std::optional<uint64_t> DWARFDebugNames::Entry::getForeignTUSkeletonCUOffset() const { // Must have a DW_IDX_type_unit and it must be a foreign type unit. >From 33938d5953c48939b0abc225847101619cea8305 Mon Sep 17 00:00:00 2001 From: Greg Clayton <clayb...@gmail.com> Date: Mon, 10 Jun 2024 17:32:54 -0700 Subject: [PATCH 8/8] Respond to user comments. --- .../SymbolFile/DWARF/DebugNamesDWARFIndex.cpp | 48 +++++++++---------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp index 334d742d4e10e..acaf6da25b9ad 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp @@ -65,21 +65,23 @@ DebugNamesDWARFIndex::IsForeignTypeUnit(const DebugNames::Entry &entry) const { std::optional<uint64_t> type_sig = entry.getForeignTUTypeSignature(); if (!type_sig.has_value()) return std::nullopt; + + // Ask the entry for the skeleton compile unit offset and fetch the .dwo + // file from it and get the type unit by signature from there. If we find + // the type unit in the .dwo file, we don't need to check that the + // DW_AT_dwo_name matches because each .dwo file can have its own type unit. + std::optional<uint64_t> cu_offset = entry.getForeignTUSkeletonCUOffset(); + if (!cu_offset) + return nullptr; // Return NULL, this is a type unit, but couldn't find it. + + DWARFUnit *cu = + m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset); + if (!cu) + return nullptr; // Return NULL, this is a type unit, but couldn't find it. + auto dwp_sp = m_debug_info.GetDwpSymbolFile(); if (!dwp_sp) { // No .dwp file, we need to load the .dwo file. - - // Ask the entry for the skeleton compile unit offset and fetch the .dwo - // file from it and get the type unit by signature from there. If we find - // the type unit in the .dwo file, we don't need to check that the - // DW_AT_dwo_name matches because each .dwo file can have its own type unit. - std::optional<uint64_t> unit_offset = entry.getForeignTUSkeletonCUOffset(); - if (!unit_offset) - return nullptr; // Return NULL, this is a type unit, but couldn't find it. - DWARFUnit *cu = - m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *unit_offset); - if (!cu) - return nullptr; // Return NULL, this is a type unit, but couldn't find it. DWARFUnit &dwo_cu = cu->GetNonSkeletonUnit(); // We don't need the check if the type unit matches the .dwo file if we have // a .dwo file (not a .dwp), so we can just return the value here. @@ -104,20 +106,14 @@ DebugNamesDWARFIndex::IsForeignTypeUnit(const DebugNames::Entry &entry) const { if (!foreign_tu) return nullptr; // Return NULL, this is a type unit, but couldn't find it. - std::optional<uint64_t> cu_offset = entry.getForeignTUSkeletonCUOffset(); - if (cu_offset) { - DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::DebugInfo, *cu_offset); - if (cu) { - DWARFBaseDIE cu_die = cu->GetUnitDIEOnly(); - DWARFBaseDIE tu_die = foreign_tu->GetUnitDIEOnly(); - llvm::StringRef cu_dwo_name = - cu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr); - llvm::StringRef tu_dwo_name = - tu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr); - if (cu_dwo_name == tu_dwo_name) - return foreign_tu; // We found a match! - } - } + DWARFBaseDIE cu_die = cu->GetUnitDIEOnly(); + DWARFBaseDIE tu_die = foreign_tu->GetUnitDIEOnly(); + llvm::StringRef cu_dwo_name = + cu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr); + llvm::StringRef tu_dwo_name = + tu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr); + if (cu_dwo_name == tu_dwo_name) + return foreign_tu; // We found a match! return nullptr; // Return NULL, this is a type unit, but couldn't find it. } _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits