diff --git a/lldb/include/lldb/Utility/ConstString.h b/lldb/include/lldb/Utility/ConstString.h --- a/lldb/include/lldb/Utility/ConstString.h +++ b/lldb/include/lldb/Utility/ConstString.h @@ -408,6 +408,17 @@ /// in memory. static size_t StaticMemorySize(); + class Hasher { + public: + size_t operator()(const ConstString &key) const { + // https://stackoverflow.com/questions/7666509/hash-function-for-string + size_t hash = 5381; + for (const char *p = key.m_string; *p; ++p) + hash = hash * 33 + static_cast(*p); + return hash; + } + }; + protected: template friend struct ::llvm::DenseMapInfo; /// Only used by DenseMapInfo. diff --git a/lldb/include/lldb/Utility/FileSpec.h b/lldb/include/lldb/Utility/FileSpec.h --- a/lldb/include/lldb/Utility/FileSpec.h +++ b/lldb/include/lldb/Utility/FileSpec.h @@ -397,6 +397,14 @@ ConstString GetLastPathComponent() const; + class Hasher { + public: + size_t operator()(const FileSpec &key) const { + return (ConstString::Hasher()(key.m_directory) << 16) ^ + ConstString::Hasher()(key.m_filename) ^ key.m_is_resolved; + } + }; + protected: friend struct llvm::yaml::MappingTraits; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt b/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt --- a/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt +++ b/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt @@ -39,6 +39,7 @@ NameToDIE.cpp SymbolFileDWARF.cpp SymbolFileDWARFDwo.cpp + SymbolFileDWARFDwz.cpp SymbolFileDWARFDebugMap.cpp UniqueDWARFASTType.cpp diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp @@ -34,7 +34,9 @@ return DIERef( m_cu->GetSymbolFileDWARF().GetDwoNum(), (!main_unit ? llvm::None : llvm::Optional(main_unit->GetID())), - DIERef::MainDwz, m_cu->GetDebugSection(), m_die->GetOffset()); + GetCU()->GetSymbolFileDWARF().GetIsDwz() ? DIERef::CommonDwz + : DIERef::MainDwz, + m_cu->GetDebugSection(), m_die->GetOffset()); } dw_tag_t DWARFBaseDIE::Tag() const { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -32,6 +32,11 @@ DWARFDIE DIE() { return {DWARFUnitPair(this), DIEPtr()}; } + static DWARFCompileUnit *GetMainUnit(const lldb_private::SymbolContext &sc, + SymbolFileDWARF **dwarf_return); + static DWARFCompileUnit *GetMainUnit(lldb_private::CompileUnit &comp_unit, + SymbolFileDWARF **dwarf_return); + private: DWARFCompileUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, const DWARFUnitHeader &header, @@ -42,6 +47,10 @@ DWARFCompileUnit(const DWARFCompileUnit &) = delete; const DWARFCompileUnit &operator=(const DWARFCompileUnit &) = delete; + static DWARFCompileUnit *GetMainUnit(lldb_private::Module &module, + lldb_private::CompileUnit *comp_unit, + SymbolFileDWARF **dwarf_return); + friend class DWARFUnit; }; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -10,6 +10,7 @@ #include "DWARFDebugAranges.h" #include "SymbolFileDWARFDebugMap.h" +#include "lldb/Core/Module.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Utility/Stream.h" @@ -36,6 +37,10 @@ // First get the compile unit DIE only and check contains ranges information. const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); + // DWZ partial units never contain any PC. + if (die && die->Tag() == DW_TAG_partial_unit) + return; + const dw_offset_t cu_offset = GetOffset(); if (die) { DWARFRangeList ranges; @@ -116,3 +121,40 @@ } return DWARFDIE(); } + +DWARFCompileUnit * +DWARFCompileUnit::GetMainUnit(Module &module, CompileUnit *comp_unit, + SymbolFileDWARF **dwarf_return) { + SymbolFile *symfile = module.GetSymbolFile(); + SymbolFileDWARF *dwarf; + if (auto *debug_map_symfile = + llvm::dyn_cast(symfile)) { + lldbassert(comp_unit); + dwarf = debug_map_symfile->GetSymbolFile(*comp_unit); + } else { + dwarf = llvm::dyn_cast(symfile); + lldbassert(dwarf); + } + if (dwarf_return) + *dwarf_return = dwarf; + if (!comp_unit) { + lldbassert(dwarf_return); + return nullptr; + } + return dwarf->GetDWARFCompileUnit(comp_unit); +} + +DWARFCompileUnit * +DWARFCompileUnit::GetMainUnit(CompileUnit &comp_unit, + SymbolFileDWARF **dwarf_return) { + ModuleSP module_sp = comp_unit.CalculateSymbolContextModule(); + lldbassert(module_sp); + return GetMainUnit(*module_sp, &comp_unit, dwarf_return); +} + +DWARFCompileUnit * +DWARFCompileUnit::GetMainUnit(const SymbolContext &sc, + SymbolFileDWARF **dwarf_return) { + lldbassert(sc.module_sp); + return GetMainUnit(*sc.module_sp, sc.comp_unit, dwarf_return); +} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -24,6 +24,7 @@ #include "DWARFDebugInfoEntry.h" #include "DWARFFormValue.h" #include "DWARFTypeUnit.h" +#include "SymbolFileDWARFDwz.h" using namespace lldb; using namespace lldb_private; @@ -38,6 +39,8 @@ if (m_cu_aranges_up) return *m_cu_aranges_up; + lldbassert(!m_dwarf.GetIsDwz()); + m_cu_aranges_up = std::make_unique(); const DWARFDataExtractor &debug_aranges_data = m_context.getOrLoadArangesData(); @@ -150,11 +153,24 @@ } DWARFUnit *DWARFDebugInfo::GetUnit(const DIERef &die_ref) { + bool dwz_common = + die_ref.main_cu() && die_ref.dwz_common() == DIERef::CommonDwz; + if (dwz_common && !m_dwarf.GetIsDwz()) { + lldbassert(m_dwarf.GetDwzSymbolFile()); + return m_dwarf.GetDwzSymbolFile()->DebugInfo().GetUnit(die_ref); + } + lldbassert(dwz_common == m_dwarf.GetIsDwz()); return GetUnitContainingDIEOffset(die_ref.section(), die_ref.die_offset()); } DWARFUnit *DWARFDebugInfo::GetMainUnit(const DIERef &die_ref) { - return GetUnit(die_ref); + DWARFUnit *main_unit; + if (!die_ref.main_cu()) + main_unit = GetUnit(die_ref); + else + main_unit = GetUnitAtIndex(*m_dwarf.GetDWARFUnitIndex(*die_ref.main_cu())); + lldbassert(!main_unit->GetSymbolFileDWARF().GetIsDwz()); + return main_unit; } DWARFUnit * diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -116,6 +116,9 @@ else form_size = 4; break; + case DW_FORM_GNU_ref_alt: + form_size = 4; + break; // 0 sized form case DW_FORM_flag_present: @@ -180,6 +183,7 @@ case DW_FORM_strp: case DW_FORM_line_strp: + case DW_FORM_GNU_strp_alt: case DW_FORM_sec_offset: data.GetU32(&offset); break; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -18,6 +18,7 @@ #include "DWARFFormValue.h" #include "DWARFSimpleDIE.h" #include "DWARFUnit.h" +#include "SymbolFileDWARFDwz.h" class DWARFUnit; @@ -78,6 +79,7 @@ case DW_FORM_strp: case DW_FORM_line_strp: case DW_FORM_sec_offset: + case DW_FORM_GNU_strp_alt: m_value.value.uval = data.GetMaxU64(offset_ptr, 4); break; case DW_FORM_addrx1: @@ -126,6 +128,11 @@ ref_addr_size = 4; m_value.value.uval = data.GetMaxU64(offset_ptr, ref_addr_size); break; + case DW_FORM_GNU_ref_alt: + assert(m_unit); + ref_addr_size = 4; + m_value.value.uval = data.GetMaxU64(offset_ptr, ref_addr_size); + break; case DW_FORM_indirect: m_form = data.GetULEB128(offset_ptr); indirect = true; @@ -257,6 +264,11 @@ *offset_ptr += ref_addr_size; return true; + case DW_FORM_GNU_ref_alt: + ref_addr_size = 4; + *offset_ptr += ref_addr_size; + return true; + // 0 bytes values (implied from DW_FORM) case DW_FORM_flag_present: case DW_FORM_implicit_const: @@ -289,6 +301,7 @@ case DW_FORM_sec_offset: case DW_FORM_strp: case DW_FORM_line_strp: + case DW_FORM_GNU_strp_alt: *offset_ptr += 4; return true; @@ -437,6 +450,9 @@ case DW_FORM_ref_udata: unit_relative_offset = true; break; + case DW_FORM_GNU_ref_alt: + DumpAddress(s.AsRawOstream(), uvalue, 4 * 2); + break; // All DW_FORM_indirect attributes should be resolved prior to calling this // function @@ -479,6 +495,20 @@ if (m_form == DW_FORM_line_strp) return context.getOrLoadLineStrData().PeekCStr(m_value.value.uval); + if (m_form == DW_FORM_GNU_strp_alt) { + SymbolFileDWARFDwz *dwz_symbol_file = + m_unit->GetSymbolFileDWARF().GetDwzSymbolFile(); + if (!dwz_symbol_file) { + m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( + "String reference to DWZ offset 0x%8.8" PRIx64 + " is in a file without associated DWZ common file", + m_value.value.uval); + return nullptr; + } + return dwz_symbol_file->GetDWARFContext().getOrLoadStrData().PeekCStr( + m_value.value.uval); + } + return nullptr; } @@ -510,6 +540,7 @@ case DW_FORM_ref_udata: { assert(m_unit); // Unit must be valid for DW_FORM_ref forms that are compile // unit relative or we will get this wrong + // The offset adjustment is already appropriate inside this CU. value += m_unit->GetOffset(); if (!m_unit->ContainsDIEOffset(value)) { m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( @@ -521,7 +552,48 @@ return {cu, cu->GetDIEPtr(value)}; } + case DW_FORM_GNU_ref_alt: { + assert(m_unit); + SymbolFileDWARF &symbol_file = m_unit->GetSymbolFileDWARF(); + if (symbol_file.GetIsDwz()) + symbol_file.GetObjectFile()->GetModule()->ReportError( + "DW_FORM_GNU_ref_alt to DWZ offset 0x%8.8" PRIx64 + " is in a DWZ common file itself", + value); + else if (!symbol_file.GetDwzSymbolFile()) { + symbol_file.GetObjectFile()->GetModule()->ReportError( + "DW_FORM_GNU_ref_alt to DWZ offset 0x%8.8" PRIx64 + " has no DWZ common file", + value); + return {}; + } + SymbolFileDWARF *target_symbol_file = &symbol_file; + if (!target_symbol_file->GetIsDwz()) { + target_symbol_file = symbol_file.GetDwzSymbolFile(); + if (!target_symbol_file) { + symbol_file.GetObjectFile()->GetModule()->ReportError( + "There is Reference to DWZ offset 0x%8.8" PRIx64 + " but the DWZ common file is missing", + value); + return {}; + } + } + lldbassert(target_symbol_file->GetIsDwz()); + DWARFDebugInfo &target_debuginfo = target_symbol_file->DebugInfo(); + DWARFUnit *target_cu = target_debuginfo.GetUnitContainingDIEOffset( + DIERef::Section::DebugInfo, value); + if (!target_cu) { + symbol_file.GetObjectFile()->GetModule()->ReportError( + "There is Reference to DWZ offset 0x%8.8" PRIx64 + " but the DWZ common file does not contain a unit for that offset", + value); + return {}; + } + return target_cu->GetDIE(const_cast(m_unit), value); + } + case DW_FORM_ref_addr: { + assert(m_unit); DWARFUnit *ref_cu = m_unit->GetSymbolFileDWARF().DebugInfo().GetUnitContainingDIEOffset( DIERef::Section::DebugInfo, value); @@ -647,6 +719,8 @@ case DW_FORM_GNU_str_index: case DW_FORM_GNU_addr_index: case DW_FORM_implicit_const: + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: return true; default: break; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h @@ -29,7 +29,9 @@ const DWARFUnitHeader &header, const DWARFAbbreviationDeclarationSet &abbrevs, DIERef::Section section, bool is_dwo) - : DWARFUnit(dwarf, uid, header, abbrevs, section, is_dwo) {} + : DWARFUnit(dwarf, uid, header, abbrevs, section, is_dwo) { + assert(!dwarf.GetIsDwz()); + } friend class DWARFUnit; }; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -737,6 +737,8 @@ } uint64_t DWARFUnit::GetDWARFLanguageType() { + lldbassert(!GetSymbolFileDWARF().GetIsDwz()); + if (m_language_type) return *m_language_type; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnitPair.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnitPair.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnitPair.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnitPair.cpp @@ -6,7 +6,8 @@ // //===----------------------------------------------------------------------===// -#include "Plugins/SymbolFile/DWARF/DWARFUnitPair.h" +#include "DWARFUnitPair.h" +#include "DWARFUnit.h" #include DWARFUnitPair::DWARFUnitPair() : m_cu(nullptr), m_main_cu(nullptr) {} @@ -14,6 +15,7 @@ : m_cu(cu), m_main_cu(main_cu) { assert(m_cu); assert(m_main_cu); + assert(!m_main_cu->GetSymbolFileDWARF().GetIsDwz()); } DWARFUnitPair::DWARFUnitPair(DWARFUnit *main_cu) : DWARFUnitPair(static_cast(main_cu), main_cu) {} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp @@ -46,6 +46,7 @@ if (!cu_offset) return llvm::None; + // FIXME: .debug_names have no DWZ support yet. DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset); if (!cu) return llvm::None; @@ -170,6 +171,7 @@ if (!ref) continue; + // FIXME: .debug_names have no DWZ support yet. DWARFUnit *cu = m_debug_info.GetUnit(*ref); if (!cu || !cu->Supports_DW_AT_APPLE_objc_complete_type()) { incomplete_types.push_back(*ref); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -11,6 +11,7 @@ #include "Plugins/SymbolFile/DWARF/DWARFCompileUnit.h" #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" #include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h" +#include "Plugins/SymbolFile/DWARF/DWARFSimpleDIE.h" #include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h" #include "lldb/Core/Module.h" @@ -132,6 +133,8 @@ // DWZ DW_TAG_partial_unit will get indexed by DW_AT_import // from its DW_TAG_compile_unit (possibly transitively). // Try to prevent GetUnitDIEOnly() which is expensive. + if (unit.GetSymbolFileDWARF().GetIsDwz()) + return; if (unit.GetUnitDIEOnly().Tag() == DW_TAG_partial_unit) return; IndexUnit(&unit, dwp, set); @@ -144,6 +147,8 @@ // DWZ DW_TAG_partial_unit will get indexed by DW_AT_import // from its DW_TAG_compile_unit (possibly transitively). // GetUnitDIEPtrOnly() is too expensive. + if (unit->GetSymbolFileDWARF().GetIsDwz()) + return; if (unit->GetUnitDIEOnly().Tag() == DW_TAG_partial_unit) return; } @@ -157,6 +162,15 @@ unit->GetOffset(), unit.GetMainCU()->GetOffset()); } + // DWZ DW_TAG_partial_unit will get indexed through DW_TAG_imported_unit from + // its main DW_TAG_compile_unit (possibly transitively). Indexing it + // standalone is not possible as we would not have its main CU. Also try to + // prevent calling GetUnitDIEOnly() which may be expensive. + if (unit->GetSymbolFileDWARF().GetIsDwz()) + return; + if (unit->GetUnitDIEOnly().Tag() == DW_TAG_partial_unit) + return; + IndexUnitImpl(unit, set); if (SymbolFileDWARFDwo *dwo_symbol_file = unit->GetDwoSymbolFile()) { @@ -202,6 +216,7 @@ case DW_TAG_union_type: case DW_TAG_unspecified_type: case DW_TAG_variable: + case DW_TAG_imported_unit: break; default: @@ -217,7 +232,7 @@ bool has_location_or_const_value = false; bool is_global_or_static_variable = false; - DWARFFormValue specification_die_form; + DWARFFormValue specification_die_form, import_die_form; const size_t num_attributes = die.GetAttributes(&unit, attributes); if (num_attributes > 0) { for (uint32_t i = 0; i < num_attributes; ++i) { @@ -261,6 +276,11 @@ if (attributes.ExtractFormValueAtIndex(i, form_value)) specification_die_form = form_value; break; + + case DW_AT_import: + if (attributes.ExtractFormValueAtIndex(i, form_value)) + import_die_form = form_value; + break; } } } @@ -363,6 +383,39 @@ } break; + case DW_TAG_imported_unit: + if (import_die_form.IsValid()) { + // DWZ is using DW_TAG_imported_unit only at the top level of CUs. + // Therefore GetParent() of any top level DIE in partial unit is always + // DW_TAG_compile_unit (possibly after multiple import levels). + const DWARFDebugInfoEntry *parent_die = die.GetParent(); + if (!parent_die || (parent_die->Tag() != DW_TAG_compile_unit && + parent_die->Tag() != DW_TAG_partial_unit)) { + unit.GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( + "CU 0x%8.8" PRIx32 " DIE 0x%8.8" PRIx32 + " DW_TAG_imported_unit does not have DW_TAG_compile_unit" + " as its parent", + unit.GetOffset(), die.GetOffset()); + break; + } + DWARFSimpleDIE import_die = import_die_form.Reference(); + if (!import_die.IsValid()) + break; + DWARFUnit *import_cu = import_die.GetCU(); + dw_offset_t import_cu_firstdie_offset = import_cu->GetFirstDIEOffset(); + if (import_die.GetOffset() != import_cu_firstdie_offset) { + unit.GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( + "CU 0x%8.8" PRIx32 " DIE 0x%8.8" PRIx32 + " DW_TAG_imported_unit of DIE 0x%16.16" PRIx32 + " is not the target CU first DIE 0x%8.8" PRIx32, + unit.GetOffset(), die.GetOffset(), import_die.GetOffset(), + import_cu_firstdie_offset); + break; + } + IndexUnitImpl({import_cu, unitpair.GetMainCU()}, set); + } + break; + default: continue; } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp @@ -9,6 +9,7 @@ #include "NameToDIE.h" #include "DWARFDebugInfo.h" #include "DWARFUnit.h" +#include "SymbolFileDWARFDwz.h" #include "lldb/Core/Module.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/ConstString.h" @@ -51,6 +52,7 @@ lldbassert(!s_unit.GetSymbolFileDWARF().GetDwoNum()); const DWARFUnit &ns_unit = s_unit.GetNonSkeletonUnit(); SymbolFileDWARF *ns_symfile = &ns_unit.GetSymbolFileDWARF(); + lldbassert(!ns_symfile->GetIsDwz()); const uint32_t size = m_map.GetSize(); for (uint32_t i = 0; i < size; ++i) { const DIERef &die_ref = m_map.GetValueAtIndexUnchecked(i); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -52,6 +52,7 @@ class SymbolFileDWARFDebugMap; class SymbolFileDWARFDwo; class SymbolFileDWARFDwp; +class SymbolFileDWARFDwz; #define DIE_IS_BEING_PARSED ((lldb_private::Type *)1) @@ -75,6 +76,7 @@ friend class DWARFCompileUnit; friend class DWARFDIE; friend class DWARFASTParserClang; + friend class SymbolFileDWARFDwz; // Static Functions static void Initialize(); @@ -318,6 +320,9 @@ /// Same as GetLanguage() but reports all C++ versions as C++ (no version). static lldb::LanguageType GetLanguageFamily(DWARFUnit &unit); + SymbolFileDWARFDwz *GetDwzSymbolFile() const { return m_dwz_symfile; } + virtual bool GetIsDwz() const { return false; } + llvm::Optional GetDWARFUnitIndex(uint32_t cu_idx); protected: @@ -484,6 +489,8 @@ const lldb_private::FileSpecList &GetSharedUnitSupportFiles(DWARFUnit &tu); + SymbolFileDWARFDwz *m_dwz_symfile = nullptr; + lldb::ModuleWP m_debug_map_module_wp; SymbolFileDWARFDebugMap *m_debug_map_symfile; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -72,6 +72,7 @@ #include "ManualDWARFIndex.h" #include "SymbolFileDWARFDebugMap.h" #include "SymbolFileDWARFDwo.h" +#include "SymbolFileDWARFDwz.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/Support/FileSystem.h" @@ -440,7 +441,10 @@ m_fetched_external_modules(false), m_supports_DW_AT_APPLE_objc_complete_type(eLazyBoolCalculate) {} -SymbolFileDWARF::~SymbolFileDWARF() = default; +SymbolFileDWARF::~SymbolFileDWARF() { + if (m_dwz_symfile) + m_dwz_symfile->ClearForDWARF(*this); +} static ConstString GetDWARFMachOSegmentName() { static ConstString g_dwarf_section_name("__DWARF"); @@ -457,6 +461,8 @@ llvm::Expected SymbolFileDWARF::GetTypeSystemForLanguage(LanguageType language) { + lldbassert(!GetIsDwz()); + if (SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile()) return debug_map_symfile->GetTypeSystemForLanguage(language); @@ -471,6 +477,9 @@ void SymbolFileDWARF::InitializeObject() { Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO); + // DWZ needs to be already prepared for indexing below. + SymbolFileDWARFDwz::InitializeForDWARF(*this); + if (!GetGlobalPluginProperties()->IgnoreFileIndexes()) { StreamString module_desc; GetObjectFile()->GetModule()->GetDescription(module_desc.AsRawOstream(), @@ -700,6 +709,7 @@ } lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { + lldbassert(!GetIsDwz()); CompUnitSP cu_sp; CompileUnit *comp_unit = (CompileUnit *)dwarf_cu.GetUserData(); if (comp_unit) { @@ -981,9 +991,13 @@ FileSpec SymbolFileDWARF::GetFile(DWARFUnit &unit, size_t file_idx) { if (auto *dwarf_cu = llvm::dyn_cast(&unit)) { - if (CompileUnit *lldb_cu = GetCompUnitForDWARFCompUnit(*dwarf_cu)) - return lldb_cu->GetSupportFiles().GetFileSpecAtIndex(file_idx); - return FileSpec(); + // Try to prevent GetUnitDIEOnly() which may be expensive. + if (!unit.GetSymbolFileDWARF().GetIsDwz() && + unit.GetUnitDIEOnly().Tag() == DW_TAG_compile_unit) { + if (CompileUnit *lldb_cu = GetCompUnitForDWARFCompUnit(*dwarf_cu)) + return lldb_cu->GetSupportFiles().GetFileSpecAtIndex(file_idx); + return FileSpec(); + } } return GetSharedUnitSupportFiles(unit).GetFileSpecAtIndex(file_idx); @@ -1341,6 +1355,8 @@ if (GetDebugMapSymfile()) return GetID() | ref.die_offset(); + lldbassert(!GetIsDwz()); + #ifndef NDEBUG DWARFDIE dwarfdie_check = GetDIE(ref); lldbassert(dwarfdie_check.IsValid()); @@ -1400,8 +1416,15 @@ if (kind == DIERef::Kind::DwoKind) dwo_num = uid >> 32 & 0x1fffffff; - return DecodedUID{ - *this, {dwo_num, llvm::None, DIERef::MainDwz, section, die_offset}}; + llvm::Optional main_cu = uid >> 32 & 0x1fffffff; + if (kind != DIERef::Kind::MainDwzKind && kind != DIERef::Kind::DwzCommonKind) + main_cu = llvm::None; + + return DecodedUID{*this, + {dwo_num, main_cu, + kind == DIERef::Kind::DwzCommonKind ? DIERef::CommonDwz + : DIERef::MainDwz, + section, die_offset}}; } DWARFDIE @@ -1663,6 +1686,8 @@ DWARFDIE SymbolFileDWARF::GetDIE(const DIERef &die_ref) { if (die_ref.dwo_num()) { + lldbassert(!GetIsDwz()); + lldbassert(!GetDwzSymbolFile()); SymbolFileDWARF *dwarf = *die_ref.dwo_num() == 0x1fffffff ? m_dwp_symfile.get() : this->DebugInfo() @@ -3959,6 +3984,8 @@ } LanguageType SymbolFileDWARF::GetLanguage(DWARFUnit &unit) { + // Caller should have called GetMainCU(). + lldbassert(unit.GetUnitDIEOnly().Tag() != DW_TAG_partial_unit); return LanguageTypeFromDWARF(unit.GetDWARFLanguageType()); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwz.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwz.h new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwz.h @@ -0,0 +1,36 @@ +//===-- SymbolFileDWARFDwz.h ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SymbolFileDWARFDwz_SymbolFileDWARFDwz_h_ +#define SymbolFileDWARFDwz_SymbolFileDWARFDwz_h_ + +#include "SymbolFileDWARF.h" + +typedef std::unique_ptr SymbolFileDWARFDwzUP; + +class SymbolFileDWARFDwz : public SymbolFileDWARF { +public: + SymbolFileDWARFDwz(lldb::ObjectFileSP objfile, lldb::ModuleSP m_module); + + bool GetIsDwz() const override { return true; } + + static void InitializeForDWARF(SymbolFileDWARF &dwarf); + + void ClearForDWARF(SymbolFileDWARF &dwarf); + +private: + void SetForDWARF(SymbolFileDWARF &dwarf); + + size_t m_use_count = 0; + lldb::ModuleSP m_module; + + SymbolFileDWARFDwz(const SymbolFileDWARFDwz &) = delete; + const SymbolFileDWARFDwz &operator=(const SymbolFileDWARFDwz &) = delete; +}; + +#endif // SymbolFileDWARFDwz_SymbolFileDWARFDwz_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwz.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwz.cpp new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwz.cpp @@ -0,0 +1,175 @@ +//===-- SymbolFileDWARFDwz.cpp ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "SymbolFileDWARFDwz.h" +#include "DWARFDebugInfo.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/FileSpec.h" +#include "llvm/ADT/PointerUnion.h" + +using namespace lldb; +using namespace lldb_private; + +SymbolFileDWARFDwz::SymbolFileDWARFDwz(ObjectFileSP objfile, ModuleSP module) + : SymbolFileDWARF(std::move(objfile), /*dwo_section_list*/ nullptr), + m_module(std::move(module)) { + InitializeObject(); + // Call private DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded() as + // otherwise DWARFCompileUnit::GetAbbreviations() would have no data. + DebugInfo().GetNumUnits(); +} + +// C++20: Use heterogeneous lookup for unordered container instead. +class DwzAsKey { +public: + DwzAsKey(SymbolFileDWARFDwz &dwz) : ptr(&dwz) {} + DwzAsKey(FileSpec &fspec) : ptr(&fspec) {} + DwzAsKey() {} + SymbolFileDWARFDwz &GetDwz() const { + return *ptr.get(); + } + FileSpec &GetFileSpec() const { + if (ptr.is()) + return *ptr.get(); + return GetDwz().GetObjectFile()->GetFileSpec(); + } + bool operator==(const DwzAsKey &rhs) const { + return GetFileSpec() == rhs.GetFileSpec(); + } + bool operator!=(const DwzAsKey &rhs) const { return !(*this == rhs); } + class Hasher { + public: + size_t operator()(const DwzAsKey &key) const { + return FileSpec::Hasher()(key.GetFileSpec()); + } + }; + +private: + llvm::PointerUnion ptr; +}; + +static std::unordered_map + dwz_map; +static llvm::sys::RWMutex dwz_map_mutex; + +void SymbolFileDWARFDwz::InitializeForDWARF(SymbolFileDWARF &dwarf) { + const DWARFDataExtractor §ion_extractor( + dwarf.GetDWARFContext().getOrLoadGNUDebugAltLink()); + if (section_extractor.GetByteSize() == 0) + return; // .gnu_debugaltlink does not exist + if (dwarf.GetIsDwz()) { + dwarf.GetObjectFile()->GetModule()->ReportWarning( + "Error reading DWZ common file - it does contain .gnu_debugaltlink"); + return; + } + lldb::offset_t offset = 0; + const char *link_cstr(section_extractor.GetCStr(&offset)); + if (!link_cstr) { + dwarf.GetObjectFile()->GetModule()->ReportWarning( + "Cannot get DWZ common file - missing section .gnu_debugaltlink"); + return; + } + lldb::offset_t uuid_bytes_size = section_extractor.BytesLeft(offset); + const void *uuid_bytes(section_extractor.GetData(&offset, uuid_bytes_size)); + if (!uuid_bytes) { + dwarf.GetObjectFile()->GetModule()->ReportWarning( + "Cannot get DWZ common file - missing build-id" + " in section .gnu_debugaltlink with string \"%s\"", + link_cstr); + return; + } + UUID link_uuid = UUID::fromOptionalData(uuid_bytes, uuid_bytes_size); + if (!link_uuid.IsValid()) { + dwarf.GetObjectFile()->GetModule()->ReportWarning( + "Cannot get DWZ common file - invalid build-id size %" PRIu64 + " in section .gnu_debugaltlink with string \"%s\"", + uuid_bytes_size, link_cstr); + return; + } + // For objfile "/usr/lib/debug/usr/bin/true.debug" + // link_cstr is "../../.dwz/coreutils-8.25-17.fc25.x86_64". + ModuleSpec dwz_module_spec; + FileSpec &dwz_fspec = dwz_module_spec.GetFileSpec(); + dwz_fspec = FileSpec(link_cstr); + dwz_fspec.PrependPathComponent( + dwarf.GetObjectFile()->GetFileSpec().CopyByRemovingLastPathComponent()); + DwzAsKey dwz_fspec_lookup(dwz_fspec); + { + llvm::sys::ScopedReader lock(dwz_map_mutex); + const auto it = dwz_map.find(dwz_fspec_lookup); + if (it != dwz_map.end()) { + it->second->SetForDWARF(dwarf); + return; + } + } + dwz_module_spec.GetArchitecture() = + dwarf.GetObjectFile()->GetModule()->GetArchitecture(); + ModuleSP dwz_module = std::make_shared(dwz_module_spec); + DataBufferSP dwz_file_data_sp; + lldb::offset_t dwz_file_data_offset = 0; + lldb::ObjectFileSP dwz_obj_file = ObjectFile::FindPlugin( + dwz_module, &dwz_fspec, 0, FileSystem::Instance().GetByteSize(dwz_fspec), + dwz_file_data_sp, dwz_file_data_offset); + if (!dwz_obj_file) { + dwarf.GetObjectFile()->GetModule()->ReportWarning( + "Cannot get DWZ common file - file \"%s\" cannot be opened", + dwz_fspec.GetCString()); + return; + } + lldbassert(dwz_obj_file->GetFileSpec() == dwz_fspec); + UUID dwz_uuid = dwz_obj_file->GetUUID(); + if (!dwz_uuid) { + dwarf.GetObjectFile()->GetModule()->ReportWarning( + "Cannot get DWZ common file - file \"%s\" does not have build-id", + dwz_fspec.GetCString()); + return; + } + if (link_uuid != dwz_uuid) { + dwarf.GetObjectFile()->GetModule()->ReportWarning( + "Cannot get DWZ common file - expected build-id %s but file \"%s\"" + " has build-id %s", + link_uuid.GetAsString().c_str(), dwz_fspec.GetCString(), + dwz_uuid.GetAsString().c_str()); + return; + } + auto dwz_symbol_file = + std::make_unique(dwz_obj_file, std::move(dwz_module)); + assert(DwzAsKey(*dwz_symbol_file) == dwz_fspec_lookup); + { + llvm::sys::ScopedWriter lock(dwz_map_mutex); + const auto it = dwz_map.find(dwz_fspec_lookup); + if (it != dwz_map.end()) + it->second->SetForDWARF(dwarf); + else { + dwz_symbol_file->SetForDWARF(dwarf); + const auto insertpair = dwz_map.emplace(DwzAsKey(*dwz_symbol_file), + std::move(dwz_symbol_file)); + lldbassert(insertpair.second); + } + } +} + +void SymbolFileDWARFDwz::SetForDWARF(SymbolFileDWARF &dwarf) { + lldbassert(&dwarf != this); + lldbassert(!dwarf.m_dwz_symfile); + dwarf.m_dwz_symfile = this; + ++m_use_count; +} + +void SymbolFileDWARFDwz::ClearForDWARF(SymbolFileDWARF &main_dwarf) { + lldbassert(main_dwarf.m_dwz_symfile == this); + llvm::sys::ScopedWriter lock(dwz_map_mutex); + lldbassert(m_use_count); + if (--m_use_count) + return; + size_t erased = dwz_map.erase(DwzAsKey(*this)); + lldbassert(erased == 1); +}