Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -92,6 +92,7 @@ uint64_t GetDWOId(); void ExtractUnitDIEIfNeeded(); + void ExtractUnitDIENoDwoIfNeeded(); void ExtractDIEsIfNeeded(); class ScopedExtractDIEs { @@ -204,6 +205,8 @@ bool GetIsOptimized(); + lldb_private::LazyBool GetLazyIsOptimized(); + const lldb_private::FileSpec &GetCompilationDirectory(); const lldb_private::FileSpec &GetAbsolutePath(); lldb_private::FileSpec GetFile(size_t file_idx); @@ -276,7 +279,7 @@ // Get the DWARF unit DWARF debug information entry. Parse the single DIE // if needed. const DWARFDebugInfoEntry *GetUnitDIEPtrOnly() { - ExtractUnitDIEIfNeeded(); + ExtractUnitDIENoDwoIfNeeded(); // m_first_die_mutex is not required as m_first_die is never cleared. if (!m_first_die) return NULL; @@ -324,6 +327,8 @@ dw_addr_t m_addr_base = 0; ///< Value of DW_AT_addr_base. dw_addr_t m_loclists_base = 0; ///< Value of DW_AT_loclists_base. dw_addr_t m_ranges_base = 0; ///< Value of DW_AT_rnglists_base. + llvm::Optional m_gnu_addr_base; + llvm::Optional m_gnu_ranges_base; /// Value of DW_AT_stmt_list. dw_offset_t m_line_table_offset = DW_INVALID_OFFSET; @@ -335,6 +340,8 @@ const DIERef::Section m_section; bool m_is_dwo; + bool m_has_ensured_dwo; + bool m_has_addr_base; /// Value of DW_AT_GNU_dwo_id (v4) or dwo_id from CU header (v5). uint64_t m_dwo_id; Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -35,12 +35,13 @@ DIERef::Section section, bool is_dwo) : UserID(uid), m_dwarf(dwarf), m_header(header), m_abbrevs(&abbrevs), m_cancel_scopes(false), m_section(section), m_is_dwo(is_dwo), + m_has_ensured_dwo(false), m_has_addr_base(false), m_dwo_id(header.GetDWOId()) {} DWARFUnit::~DWARFUnit() = default; -// Parses first DIE of a compile unit. -void DWARFUnit::ExtractUnitDIEIfNeeded() { +// Parses first DIE of a compile unit, excluding DWO. +void DWARFUnit::ExtractUnitDIENoDwoIfNeeded() { { llvm::sys::ScopedReader lock(m_first_die_mutex); if (m_first_die) @@ -66,6 +67,58 @@ } } +// Parses first DIE of a compile unit including DWO. +void DWARFUnit::ExtractUnitDIEIfNeeded() { + ExtractUnitDIENoDwoIfNeeded(); + + if (!m_has_ensured_dwo) { + m_has_ensured_dwo = true; + + std::shared_ptr dwo_symbol_file = + m_dwarf.GetDwoSymbolFileForCompileUnit(*this, m_first_die); + if (!dwo_symbol_file) + return; + + DWARFUnit *dwo_cu = dwo_symbol_file->GetDWOCompileUnitForHash(m_dwo_id); + + if (!dwo_cu) + return; // Can't fetch the compile unit from the dwo file. + dwo_cu->SetUserData(this); + + DWARFBaseDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly(); + if (!dwo_cu_die.IsValid()) + return; // Can't fetch the compile unit DIE from the dwo file. + + // Here for DWO CU we want to use the address base set in the skeleton unit + // (DW_AT_addr_base) if it is available and use the DW_AT_GNU_addr_base + // otherwise. We do that because pre-DWARF v5 could use the DW_AT_GNU_* + // attributes which were applicable to the DWO units. The corresponding + // DW_AT_* attributes standardized in DWARF v5 are also applicable to the + // main unit in contrast. + if (m_has_addr_base) + dwo_cu->SetAddrBase(m_addr_base); + else if (m_gnu_addr_base) + dwo_cu->SetAddrBase(*m_gnu_addr_base); + + if (GetVersion() <= 4 && m_gnu_ranges_base) + dwo_cu->SetRangesBase(*m_gnu_ranges_base); + else if (dwo_symbol_file->GetDWARFContext() + .getOrLoadRngListsData() + .GetByteSize() > 0) + dwo_cu->SetRangesBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32)); + + if (GetVersion() >= 5 && dwo_symbol_file->GetDWARFContext() + .getOrLoadLocListsData() + .GetByteSize() > 0) + dwo_cu->SetLoclistsBase( + llvm::DWARFListTableHeader::getHeaderSize(DWARF32)); + + dwo_cu->SetBaseAddress(GetBaseAddress()); + + m_dwo = std::shared_ptr(std::move(dwo_symbol_file), dwo_cu); + } +} + // Parses a compile unit and indexes its DIEs if it hasn't already been done. // It will leave this compile unit extracted forever. void DWARFUnit::ExtractDIEsIfNeeded() { @@ -291,13 +344,13 @@ } uint64_t DWARFUnit::GetDWOId() { - ExtractUnitDIEIfNeeded(); + ExtractUnitDIENoDwoIfNeeded(); return m_dwo_id; } // m_die_array_mutex must be already held as read/write. void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { - llvm::Optional addr_base, gnu_addr_base, gnu_ranges_base; + llvm::Optional addr_base; DWARFAttributes attributes; size_t num_attributes = cu_die.GetAttributes(this, attributes); @@ -341,10 +394,10 @@ m_line_table_offset = form_value.Unsigned(); break; case DW_AT_GNU_addr_base: - gnu_addr_base = form_value.Unsigned(); + m_gnu_addr_base = form_value.Unsigned(); break; case DW_AT_GNU_ranges_base: - gnu_ranges_base = form_value.Unsigned(); + m_gnu_ranges_base = form_value.Unsigned(); break; case DW_AT_GNU_dwo_id: m_dwo_id = form_value.Unsigned(); @@ -353,50 +406,10 @@ } if (m_is_dwo) { + m_has_ensured_dwo = true; SetDwoStrOffsetsBase(); return; } - - std::shared_ptr dwo_symbol_file = - m_dwarf.GetDwoSymbolFileForCompileUnit(*this, cu_die); - if (!dwo_symbol_file) - return; - - DWARFUnit *dwo_cu = dwo_symbol_file->GetDWOCompileUnitForHash(m_dwo_id); - - if (!dwo_cu) - return; // Can't fetch the compile unit from the dwo file. - dwo_cu->SetUserData(this); - - DWARFBaseDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly(); - if (!dwo_cu_die.IsValid()) - return; // Can't fetch the compile unit DIE from the dwo file. - - // Here for DWO CU we want to use the address base set in the skeleton unit - // (DW_AT_addr_base) if it is available and use the DW_AT_GNU_addr_base - // otherwise. We do that because pre-DWARF v5 could use the DW_AT_GNU_* - // attributes which were applicable to the DWO units. The corresponding - // DW_AT_* attributes standardized in DWARF v5 are also applicable to the main - // unit in contrast. - if (addr_base) - dwo_cu->SetAddrBase(*addr_base); - else if (gnu_addr_base) - dwo_cu->SetAddrBase(*gnu_addr_base); - - if (GetVersion() <= 4 && gnu_ranges_base) - dwo_cu->SetRangesBase(*gnu_ranges_base); - else if (dwo_symbol_file->GetDWARFContext() - .getOrLoadRngListsData() - .GetByteSize() > 0) - dwo_cu->SetRangesBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32)); - - if (GetVersion() >= 5 && - dwo_symbol_file->GetDWARFContext().getOrLoadLocListsData().GetByteSize() > - 0) - dwo_cu->SetLoclistsBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32)); - dwo_cu->SetBaseAddress(GetBaseAddress()); - - m_dwo = std::shared_ptr(std::move(dwo_symbol_file), dwo_cu); } size_t DWARFUnit::GetDebugInfoSize() const { @@ -412,11 +425,14 @@ } dw_offset_t DWARFUnit::GetLineTableOffset() { - ExtractUnitDIEIfNeeded(); + ExtractUnitDIENoDwoIfNeeded(); return m_line_table_offset; } -void DWARFUnit::SetAddrBase(dw_addr_t addr_base) { m_addr_base = addr_base; } +void DWARFUnit::SetAddrBase(dw_addr_t addr_base) { + m_addr_base = addr_base; + m_has_addr_base = true; +} // Parse the rangelist table header, including the optional array of offsets // following it (DWARF v5 and later). @@ -680,6 +696,24 @@ return m_is_optimized == eLazyBoolYes; } +LazyBool DWARFUnit::GetLazyIsOptimized() { + if (m_is_optimized == eLazyBoolCalculate) { + const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); + if (die) { + switch ( + die->GetAttributeValueAsUnsigned(this, DW_AT_APPLE_optimized, 2)) { + case 0: + m_is_optimized = eLazyBoolNo; + break; + case 1: + m_is_optimized = eLazyBoolYes; + break; + } + } + } + return m_is_optimized; +} + FileSpec::Style DWARFUnit::GetPathStyle() { if (!m_comp_dir) ComputeCompDirAndGuessPathStyle(); Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -24,6 +24,7 @@ #include "lldb/Symbol/DebugMacros.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/SymbolFile.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Flags.h" #include "lldb/Utility/RangeMap.h" @@ -367,6 +368,9 @@ lldb::TypeSP ParseType(const lldb_private::SymbolContext &sc, const DWARFDIE &die, bool *type_is_new); + bool ParseSupportFiles(DWARFUnit &dwarf_cu, const lldb::ModuleSP &module, + lldb_private::FileSpecList &support_files); + lldb_private::Type *ResolveTypeUID(const DWARFDIE &die, bool assert_not_being_parsed); Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -700,25 +700,57 @@ } else { ModuleSP module_sp(m_objfile_sp->GetModule()); if (module_sp) { - const DWARFBaseDIE cu_die = - dwarf_cu.GetNonSkeletonUnit().GetUnitDIEOnly(); - if (cu_die) { - FileSpec cu_file_spec(cu_die.GetName(), dwarf_cu.GetPathStyle()); - MakeAbsoluteAndRemap(cu_file_spec, dwarf_cu, module_sp); - - LanguageType cu_language = SymbolFileDWARF::LanguageTypeFromDWARF( - cu_die.GetAttributeValueAsUnsigned(DW_AT_language, 0)); - - bool is_optimized = dwarf_cu.GetNonSkeletonUnit().GetIsOptimized(); - BuildCuTranslationTable(); - cu_sp = std::make_shared( - module_sp, &dwarf_cu, cu_file_spec, - *GetDWARFUnitIndex(dwarf_cu.GetID()), cu_language, - is_optimized ? eLazyBoolYes : eLazyBoolNo); - - dwarf_cu.SetUserData(cu_sp.get()); - - SetCompileUnitAtIndex(dwarf_cu.GetID(), cu_sp); + bool need_non_skeleton = true; + if (dwarf_cu.GetVersion() >= 5) { + // With DWARFv5 we can assume that the first support + // file is also the name of the compile unit. This + // allows us to avoid loading the non-skeleton unit, + // which may be in a separate DWO file. + FileSpecList support_files; + if (ParseSupportFiles(dwarf_cu, module_sp, support_files) && + support_files.GetSize() > 0) { + // Get language and is_optimized from the unit if + // they are present. (It might be a skeleton unit.) + // If they are not present they will be parsed from + // the non-skeleton unit on demand. + LanguageType cu_language = SymbolFileDWARF::LanguageTypeFromDWARF( + dwarf_cu.GetDWARFLanguageType()); + LazyBool is_optimized = dwarf_cu.GetLazyIsOptimized(); + + BuildCuTranslationTable(); + cu_sp = std::make_shared( + module_sp, &dwarf_cu, support_files.GetFileSpecAtIndex(0), + *GetDWARFUnitIndex(dwarf_cu.GetID()), cu_language, + is_optimized); + + dwarf_cu.SetUserData(cu_sp.get()); + + SetCompileUnitAtIndex(dwarf_cu.GetID(), cu_sp); + cu_sp->SetSupportFiles(support_files); + need_non_skeleton = false; + } + } + if (need_non_skeleton) { + const DWARFBaseDIE cu_die = + dwarf_cu.GetNonSkeletonUnit().GetUnitDIEOnly(); + if (cu_die) { + FileSpec cu_file_spec(cu_die.GetName(), dwarf_cu.GetPathStyle()); + MakeAbsoluteAndRemap(cu_file_spec, dwarf_cu, module_sp); + + LanguageType cu_language = SymbolFileDWARF::LanguageTypeFromDWARF( + cu_die.GetAttributeValueAsUnsigned(DW_AT_language, 0)); + + bool is_optimized = dwarf_cu.GetNonSkeletonUnit().GetIsOptimized(); + BuildCuTranslationTable(); + cu_sp = std::make_shared( + module_sp, &dwarf_cu, cu_file_spec, + *GetDWARFUnitIndex(dwarf_cu.GetID()), cu_language, + is_optimized ? eLazyBoolYes : eLazyBoolNo); + + dwarf_cu.SetUserData(cu_sp.get()); + + SetCompileUnitAtIndex(dwarf_cu.GetID(), cu_sp); + } } } } @@ -806,7 +838,7 @@ std::lock_guard guard(GetModuleMutex()); DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); if (dwarf_cu) - return GetLanguage(*dwarf_cu); + return GetLanguage(dwarf_cu->GetNonSkeletonUnit()); else return eLanguageTypeUnknown; } @@ -897,18 +929,29 @@ if (!dwarf_cu) return false; - dw_offset_t offset = dwarf_cu->GetLineTableOffset(); + if (!ParseSupportFiles(*dwarf_cu, comp_unit.GetModule(), support_files)) + return false; + + comp_unit.SetSupportFiles(support_files); + return true; +} + +bool SymbolFileDWARF::ParseSupportFiles(DWARFUnit &dwarf_cu, + const ModuleSP &module, + FileSpecList &support_files) { + + dw_offset_t offset = dwarf_cu.GetLineTableOffset(); if (offset == DW_INVALID_OFFSET) return false; llvm::DWARFDebugLine::Prologue prologue; if (!ParseLLVMLineTablePrologue(m_context, prologue, offset, - dwarf_cu->GetOffset())) + dwarf_cu.GetOffset())) return false; - comp_unit.SetSupportFiles(ParseSupportFilesFromPrologue( - comp_unit.GetModule(), prologue, dwarf_cu->GetPathStyle(), - dwarf_cu->GetCompilationDirectory().GetCString())); + support_files = ParseSupportFilesFromPrologue( + module, prologue, dwarf_cu.GetPathStyle(), + dwarf_cu.GetCompilationDirectory().GetCString()); return true; } @@ -964,7 +1007,7 @@ std::lock_guard guard(GetModuleMutex()); DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); if (dwarf_cu) - return dwarf_cu->GetIsOptimized(); + return dwarf_cu->GetNonSkeletonUnit().GetIsOptimized(); return false; }