Index: include/lldb/Expression/DWARFExpression.h =================================================================== --- include/lldb/Expression/DWARFExpression.h +++ include/lldb/Expression/DWARFExpression.h @@ -218,7 +218,8 @@ /// The byte length of the location expression. //------------------------------------------------------------------ void CopyOpcodeData(lldb::ModuleSP module_sp, const DataExtractor &data, - lldb::offset_t data_offset, lldb::offset_t data_length); + lldb::offset_t data_file_offset, + lldb::offset_t data_length); void CopyOpcodeData(const void *data, lldb::offset_t data_length, lldb::ByteOrder byte_order, uint8_t addr_byte_size); Index: include/lldb/Utility/ConstString.h =================================================================== --- include/lldb/Utility/ConstString.h +++ include/lldb/Utility/ConstString.h @@ -466,6 +466,18 @@ //------------------------------------------------------------------ static size_t StaticMemorySize(); + class Hasher { + public: + size_t operator()(const ConstString &key) const { + // https://stackoverflow.com/questions/7666509/hash-function-for-string + // C++17: std::string_view + size_t hash = 5381; + for (const char *p = key.m_string; *p; ++p) + hash = hash * 33 + static_cast(*p); + return hash; + } + }; + protected: //------------------------------------------------------------------ // Member variables Index: include/lldb/Utility/FileSpec.h =================================================================== --- include/lldb/Utility/FileSpec.h +++ include/lldb/Utility/FileSpec.h @@ -574,6 +574,14 @@ llvm::sys::fs::file_type file_type, const FileSpec &spec)> DirectoryCallback; + 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: //------------------------------------------------------------------ // Member variables Index: include/lldb/lldb-enumerations.h =================================================================== --- include/lldb/lldb-enumerations.h +++ include/lldb/lldb-enumerations.h @@ -644,6 +644,7 @@ eSectionTypeDWARFAppleTypes, eSectionTypeDWARFAppleNamespaces, eSectionTypeDWARFAppleObjC, + eSectionTypeDWARFGNUDebugAltLink, eSectionTypeELFSymbolTable, // Elf SHT_SYMTAB section eSectionTypeELFDynamicSymbols, // Elf SHT_DYNSYM section eSectionTypeELFRelocationEntries, // Elf SHT_REL or SHT_REL section Index: packages/Python/lldbsuite/test/lldbinline.py =================================================================== --- packages/Python/lldbsuite/test/lldbinline.py +++ packages/Python/lldbsuite/test/lldbinline.py @@ -159,6 +159,12 @@ self.buildGModules() self.do_test() + def __test_with_dwz(self): + self.using_dsym = False + self.BuildMakefile() + self.buildDwz() + self.do_test() + def execute_user_command(self, __command): exec(__command, globals(), locals()) @@ -241,6 +247,10 @@ "gmodules", target_platform, configuration.compiler): test.test_with_gmodules = ApplyDecoratorsToFunction( test._InlineTest__test_with_gmodules, decorators) + if test_categories.is_supported_on_platform( + "dwz", target_platform, configuration.compiler): + test.test_with_dwz = ApplyDecoratorsToFunction( + test._InlineTest__test_with_dwz, decorators) # Add the test case to the globals, and hide InlineTest __globals.update({test_name: test}) Index: packages/Python/lldbsuite/test/lldbtest.py =================================================================== --- packages/Python/lldbsuite/test/lldbtest.py +++ packages/Python/lldbsuite/test/lldbtest.py @@ -1570,6 +1570,22 @@ clean): raise Exception("Don't know how to build binary with gmodules") + def buildDwz( + self, + architecture=None, + compiler=None, + dictionary=None, + clean=True): + """Platform specific way to build binaries with dwz optimizer.""" + module = builder_module() + if not module.buildDwz( + self, + architecture, + compiler, + dictionary, + clean): + raise Exception("Don't know how to build binary with DWZ") + def buildGo(self): """Build the default go binary. """ @@ -1755,6 +1771,16 @@ gmodules_test_method.__name__ = gmodules_method_name newattrs[gmodules_method_name] = gmodules_test_method + if "dwz" in supported_categories: + @decorators.add_test_categories(["dwz"]) + @wraps(attrvalue) + def dwz_test_method(self, attrvalue=attrvalue): + self.debug_info = "dwz" + return attrvalue(self) + dwz_method_name = attrname + "_dwz" + dwz_test_method.__name__ = dwz_method_name + newattrs[dwz_method_name] = dwz_test_method + else: newattrs[attrname] = attrvalue return super( @@ -2265,6 +2291,9 @@ elif self.debug_info == "gmodules": return self.buildGModules( architecture, compiler, dictionary, clean) + elif self.debug_info == "dwz": + return self.buildDwz( + architecture, compiler, dictionary, clean) else: self.fail("Can't build for debug info: %s" % self.debug_info) Index: packages/Python/lldbsuite/test/make/Makefile.rules =================================================================== --- packages/Python/lldbsuite/test/make/Makefile.rules +++ packages/Python/lldbsuite/test/make/Makefile.rules @@ -18,6 +18,7 @@ # LD_EXTRAS := # SPLIT_DEBUG_SYMBOLS := YES # CROSS_COMPILE := +# DWZ := YES # # And test/functionalities/archives/Makefile: # MAKE_DSYM := NO @@ -313,6 +314,19 @@ LDFLAGS += -pie endif +#---------------------------------------------------------------------- +# Make the dSYM file from the executable if $(DWZ) = "YES" +#---------------------------------------------------------------------- +ifeq "$(DWZ)" "YES" + dwz_strip = \ + eu-strip --remove-comment -f "$(1).debug" "$(1)" \ + && cp "$(1).debug" "$(1).debug.dup" \ + && dwz -m "$(1).debug.dwz" "$(1).debug" "$(1).debug.dup" \ + && /usr/lib/rpm/sepdebugcrcfix . "$(1)" +else + dwz_strip = +endif + #---------------------------------------------------------------------- # Windows specific options #---------------------------------------------------------------------- @@ -514,12 +528,14 @@ ifeq "$(DYLIB_ONLY)" "" $(EXE) : $(OBJECTS) $(ARCHIVE_NAME) $(DYLIB_FILENAME) $(LD) $(OBJECTS) $(ARCHIVE_NAME) -L. -l$(DYLIB_NAME) $(LDFLAGS) -o "$(EXE)" + $(call dwz_strip,$(EXE)) else EXE = $(DYLIB_FILENAME) endif else $(EXE) : $(OBJECTS) $(ARCHIVE_NAME) $(LD) $(OBJECTS) $(LDFLAGS) $(ARCHIVE_NAME) -o "$(EXE)" + $(call dwz_strip,$(EXE)) endif #---------------------------------------------------------------------- @@ -554,6 +570,7 @@ $(OBJCOPY) --only-keep-debug "$(DYLIB_FILENAME)" "$(DYLIB_FILENAME).debug" $(OBJCOPY) --strip-debug --add-gnu-debuglink="$(DYLIB_FILENAME).debug" "$(DYLIB_FILENAME)" "$(DYLIB_FILENAME)" endif + $(call dwz_strip,$(DYLIB_FILENAME)) endif #---------------------------------------------------------------------- @@ -639,6 +656,7 @@ ifneq "$(DYLIB_NAME)" "" $(RM) -r $(DYLIB_FILENAME).dSYM $(RM) $(DYLIB_OBJECTS) $(DYLIB_PREREQS) $(DYLIB_PREREQS:.d=.d.tmp) $(DYLIB_DWOS) $(DYLIB_FILENAME) $(DYLIB_FILENAME).debug + $(RM) $(DYLIB_FILENAME).debug.dup $(DYLIB_FILENAME).debug.dwz endif ifneq "$(PCH_OUTPUT)" "" $(RM) $(PCH_OUTPUT) @@ -654,7 +672,7 @@ $(RM) $(DYLIB_NAME).lib $(DYLIB_NAME).exp endif else - $(RM) "$(EXE)" + $(RM) "$(EXE)" "$(EXE).debug" "$(EXE).debug.dup" "$(EXE).debug.dwz" endif #---------------------------------------------------------------------- Index: packages/Python/lldbsuite/test/plugins/builder_base.py =================================================================== --- packages/Python/lldbsuite/test/plugins/builder_base.py +++ packages/Python/lldbsuite/test/plugins/builder_base.py @@ -192,6 +192,24 @@ # True signifies that we can handle building with gmodules. return True +def buildDwz( + sender=None, + architecture=None, + compiler=None, + dictionary=None, + clean=True): + """Build the binaries with type units (type in a .debug_types section).""" + commands = [] + if clean: + commands.append([getMake(), "clean", getCmdLine(dictionary)]) + # dwz has a bug being unable to process non-separated debug info. + commands.append([getMake(), "MAKE_DSYM=NO", "DWZ=YES", + getArchSpec(architecture), getCCSpec(compiler), + getCmdLine(dictionary)]) + + runBuildCommands(commands, sender=sender) + # True signifies that we can handle building dwo. + return True def cleanup(sender=None, dictionary=None): """Perform a platform-specific cleanup after the test.""" Index: packages/Python/lldbsuite/test/test_categories.py =================================================================== --- packages/Python/lldbsuite/test/test_categories.py +++ packages/Python/lldbsuite/test/test_categories.py @@ -7,6 +7,8 @@ # System modules import sys +import os +import distutils.spawn # Third-party modules @@ -38,6 +40,12 @@ 'watchpoint': 'Watchpoint-related tests', } +if (os.access("/usr/lib/rpm/sepdebugcrcfix", os.X_OK) + and distutils.spawn.find_executable("eu-strip") is not None + and distutils.spawn.find_executable("dwz") is not None): + debug_info_categories.append('dwz') + all_categories['dwz'] = 'Tests using the DWARF type units (-fdebug-types-section)'; + def unique_string_match(yourentry, list): candidate = None @@ -61,6 +69,8 @@ if platform not in ["linux", "freebsd", "darwin", "macosx", "ios", "watchos", "tvos", "bridgeos"]: return False return gmodules.is_compiler_clang_with_gmodules(compiler_path) + elif category == "dwz": + return platform in ["linux"] return True Index: source/Core/Section.cpp =================================================================== --- source/Core/Section.cpp +++ source/Core/Section.cpp @@ -105,6 +105,8 @@ return "apple-namespaces"; case eSectionTypeDWARFAppleObjC: return "apple-objc"; + case eSectionTypeDWARFGNUDebugAltLink: + return "dwarf-gnu-debugaltlink"; case eSectionTypeEHFrame: return "eh-frame"; case eSectionTypeARMexidx: Index: source/Expression/DWARFExpression.cpp =================================================================== --- source/Expression/DWARFExpression.cpp +++ source/Expression/DWARFExpression.cpp @@ -89,9 +89,9 @@ void DWARFExpression::CopyOpcodeData(lldb::ModuleSP module_sp, const DataExtractor &data, - lldb::offset_t data_offset, + lldb::offset_t data_file_offset, lldb::offset_t data_length) { - const uint8_t *bytes = data.PeekData(data_offset, data_length); + const uint8_t *bytes = data.PeekData(data_file_offset, data_length); if (bytes) { m_module_wp = module_sp; m_data.SetData(DataBufferSP(new DataBufferHeap(bytes, data_length))); Index: source/Expression/IRExecutionUnit.cpp =================================================================== --- source/Expression/IRExecutionUnit.cpp +++ source/Expression/IRExecutionUnit.cpp @@ -1124,6 +1124,7 @@ case lldb::eSectionTypeDWARFAppleTypes: case lldb::eSectionTypeDWARFAppleNamespaces: case lldb::eSectionTypeDWARFAppleObjC: + case lldb::eSectionTypeDWARFGNUDebugAltLink: error.Clear(); break; default: Index: source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp =================================================================== --- source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -1867,6 +1867,7 @@ static ConstString g_sect_name_arm_exidx(".ARM.exidx"); static ConstString g_sect_name_arm_extab(".ARM.extab"); static ConstString g_sect_name_go_symtab(".gosymtab"); + static ConstString g_sect_name_dwarf_gnu_debugaltlink(".gnu_debugaltlink"); SectionType sect_type = eSectionTypeOther; @@ -1957,6 +1958,8 @@ sect_type = eSectionTypeARMextab; else if (name == g_sect_name_go_symtab) sect_type = eSectionTypeGoSymtab; + else if (name == g_sect_name_dwarf_gnu_debugaltlink) + sect_type = eSectionTypeDWARFGNUDebugAltLink; const uint32_t permissions = ((header.sh_flags & SHF_ALLOC) ? ePermissionsReadable : 0u) | Index: source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp =================================================================== --- source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -1216,6 +1216,7 @@ case eSectionTypeDWARFAppleTypes: case eSectionTypeDWARFAppleNamespaces: case eSectionTypeDWARFAppleObjC: + case eSectionTypeDWARFGNUDebugAltLink: return eAddressClassDebug; case eSectionTypeEHFrame: Index: source/Plugins/SymbolFile/DWARF/CMakeLists.txt =================================================================== --- source/Plugins/SymbolFile/DWARF/CMakeLists.txt +++ source/Plugins/SymbolFile/DWARF/CMakeLists.txt @@ -24,6 +24,7 @@ DWARFDefines.cpp DWARFDIE.cpp DWARFDIECollection.cpp + DWARFFileOffset.cpp DWARFFormValue.cpp HashedNameToDIE.cpp LogChannelDWARF.cpp Index: source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -186,7 +186,7 @@ AccessType accessibility = eAccessNone; if (die) { - SymbolFileDWARF *dwarf = die.GetDWARF(); + SymbolFileDWARF *dwarf = die.GetMainDWARF(); if (log) { DWARFDIE context_die; clang::DeclContext *context = @@ -3555,7 +3555,7 @@ Type *DWARFASTParserClang::GetTypeForDIE(const DWARFDIE &die) { if (die) { - SymbolFileDWARF *dwarf = die.GetDWARF(); + SymbolFileDWARF *dwarf = die.GetMainDWARF(); DWARFAttributes attributes; const size_t num_attributes = die.GetAttributes(attributes); if (num_attributes > 0) { @@ -3613,7 +3613,7 @@ case DW_TAG_variable: case DW_TAG_constant: case DW_TAG_formal_parameter: { - SymbolFileDWARF *dwarf = die.GetDWARF(); + SymbolFileDWARF *dwarf = die.GetMainDWARF(); Type *type = GetTypeForDIE(die); if (dwarf && type) { const char *name = die.GetName(); @@ -3627,7 +3627,7 @@ break; } case DW_TAG_imported_declaration: { - SymbolFileDWARF *dwarf = die.GetDWARF(); + SymbolFileDWARF *dwarf = die.GetMainDWARF(); DWARFDIE imported_uid = die.GetAttributeValueAsReferenceDIE(DW_AT_import); if (imported_uid) { CompilerDecl imported_decl = imported_uid.GetDecl(); @@ -3645,7 +3645,7 @@ break; } case DW_TAG_imported_module: { - SymbolFileDWARF *dwarf = die.GetDWARF(); + SymbolFileDWARF *dwarf = die.GetMainDWARF(); DWARFDIE imported_uid = die.GetAttributeValueAsReferenceDIE(DW_AT_import); if (imported_uid) { @@ -3701,7 +3701,7 @@ } if (decl_ctx == nullptr && try_parsing_type) { - Type *type = die.GetDWARF()->ResolveType(die); + Type *type = die.GetMainDWARF()->ResolveType(die); if (type) decl_ctx = GetCachedClangDeclContextForDIE(die); } Index: source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp @@ -51,9 +51,9 @@ const DWARFCompileUnit *cu = CompileUnitAtIndex(i); form_value.SetCompileUnit(cu); form_value.SetForm(FormAtIndex(i)); - lldb::offset_t offset = DIEOffsetAtIndex(i); + lldb::offset_t file_offset = cu->ThisCUUniqToFileOffset(DIEOffsetAtIndex(i)); return form_value.ExtractValue( - cu->GetSymbolFileDWARF()->get_debug_info_data(), &offset); + cu->GetSymbolFileDWARF()->get_debug_info_data(), &file_offset); } uint64_t DWARFAttributes::FormValueAsUnsigned(dw_attr_t attr, Index: source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h +++ source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -12,13 +12,17 @@ #include "DWARFDIE.h" #include "DWARFDebugInfoEntry.h" +#include "DWARFFileOffset.h" #include "lldb/lldb-enumerations.h" +#include "lldb/Utility/LLDBAssert.h" class NameToDIE; class SymbolFileDWARF; class SymbolFileDWARFDwo; -class DWARFCompileUnit { +typedef std::shared_ptr DWARFCompileUnitSP; + +class DWARFCompileUnitDecls { public: enum Producer { eProducerInvalid = 0, @@ -27,49 +31,117 @@ eProducerLLVMGCC, eProcucerOther }; +}; - DWARFCompileUnit(SymbolFileDWARF *dwarf2Data); +class DWARFCompileUnitData : public DWARFCompileUnitDecls { +public: + DWARFCompileUnitData(SymbolFileDWARF *dwarf2Data); + + static uint8_t GetDefaultAddressSize(); + + static void SetDefaultAddressSize(uint8_t addr_size); + + SymbolFileDWARF *m_dwarf2Data; + std::unique_ptr m_dwo_symbol_file; + const DWARFAbbreviationDeclarationSet *m_abbrevs; + void *m_user_data = nullptr; + DWARFDebugInfoEntry::collection + m_die_array; // The compile unit debug information entry item + std::unique_ptr m_func_aranges_ap; // A table similar to + // the .debug_aranges + // table, but this one + // points to the exact + // DW_TAG_subprogram + // DIEs + dw_addr_t m_base_addr = 0; + dw_offset_t m_length; + uint16_t m_version; + uint8_t m_addr_size; + Producer m_producer = eProducerInvalid; + uint32_t m_producer_version_major = 0; + uint32_t m_producer_version_minor = 0; + uint32_t m_producer_version_update = 0; + lldb::LanguageType m_language_type = lldb::eLanguageTypeUnknown; + bool m_is_dwarf64; + lldb_private::LazyBool m_is_optimized = lldb_private::eLazyBoolCalculate; + dw_addr_t m_addr_base = 0; // Value of DW_AT_addr_base + dw_addr_t m_ranges_base = 0; // Value of DW_AT_ranges_base + // If this is a dwo compile unit this is the offset of the base compile unit + // in the main object file + dw_offset_t m_base_obj_offset = DW_INVALID_OFFSET; + dw_offset_t m_file_offset; + + std::mutex m_extractdies_mutex; + bool m_die_array_finished; + + std::map + m_dwz_file_to_cu; + + // All DW_TAG_partial_unit's extracted for Index-ing this DW_TAG_compile_unit. + std::forward_list m_extracted_pu; + + // Is this object used by more than one DWARFCompileUnit? + bool m_any_partial_unit = false; + +private: + static uint8_t g_default_addr_size; + + DISALLOW_COPY_AND_ASSIGN(DWARFCompileUnitData); +}; + +class DWARFCompileUnit : public DWARFCompileUnitDecls { +public: + friend class DWARFFileOffset; + + static DWARFCompileUnitSP Extract(SymbolFileDWARF *dwarf2Data, + lldb::offset_t *offset_ptr); + DWARFCompileUnit(DWARFCompileUnitData *data, DWARFCompileUnit *main_cu); ~DWARFCompileUnit(); - bool Extract(const lldb_private::DWARFDataExtractor &debug_info, - lldb::offset_t *offset_ptr); - size_t ExtractDIEsIfNeeded(bool cu_die_only); + enum class ExtractDIEsIfNeededKind { + CuDieOnly, + AllDies, + AllDiesButCuDieOnlyForPartialUnits, + }; + size_t ExtractDIEsIfNeeded(ExtractDIEsIfNeededKind kind); + DWARFDIE LookupAddress(const dw_addr_t address); size_t AppendDIEsWithTag(const dw_tag_t tag, DWARFDIECollection &matching_dies, uint32_t depth = UINT32_MAX) const; - void Clear(); bool Verify(lldb_private::Stream *s) const; void Dump(lldb_private::Stream *s) const; // Offset of the initial length field. dw_offset_t GetOffset() const { return m_offset; } + void SetOffset(dw_offset_t offset); lldb::user_id_t GetID() const; // Size in bytes of the initial length + compile unit header. - uint32_t Size() const { return m_is_dwarf64 ? 23 : 11; } + uint32_t Size() const { return m_data->m_is_dwarf64 ? 23 : 11; } bool ContainsDIEOffset(dw_offset_t die_offset) const { return die_offset >= GetFirstDIEOffset() && die_offset < GetNextCompileUnitOffset(); } dw_offset_t GetFirstDIEOffset() const { return m_offset + Size(); } dw_offset_t GetNextCompileUnitOffset() const { - return m_offset + (m_is_dwarf64 ? 12 : 4) + m_length; + return m_offset + (m_data->m_is_dwarf64 ? 12 : 4) + m_data->m_length; } // Size of the CU data (without initial length and without header). size_t GetDebugInfoSize() const { - return (m_is_dwarf64 ? 12 : 4) + m_length - Size(); + return (m_data->m_is_dwarf64 ? 12 : 4) + m_data->m_length - Size(); } // Size of the CU data incl. header but without initial length. - uint32_t GetLength() const { return m_length; } - uint16_t GetVersion() const { return m_version; } + uint32_t GetLength() const { return m_data->m_length; } + uint16_t GetVersion() const { return m_data->m_version; } const DWARFAbbreviationDeclarationSet *GetAbbreviations() const { - return m_abbrevs; + return m_data->m_abbrevs; } dw_offset_t GetAbbrevOffset() const; - uint8_t GetAddressByteSize() const { return m_addr_size; } - dw_addr_t GetBaseAddress() const { return m_base_addr; } - dw_addr_t GetAddrBase() const { return m_addr_base; } - dw_addr_t GetRangesBase() const { return m_ranges_base; } - void SetAddrBase(dw_addr_t addr_base, dw_addr_t ranges_base, dw_offset_t base_obj_offset); + uint8_t GetAddressByteSize() const { return m_data->m_addr_size; } + dw_addr_t GetBaseAddress() const { return m_data->m_base_addr; } + dw_addr_t GetAddrBase() const { return m_data->m_addr_base; } + dw_addr_t GetRangesBase() const { return m_data->m_ranges_base; } + void SetAddrBase( + dw_addr_t addr_base, dw_addr_t ranges_base, dw_offset_t base_obj_offset); void ClearDIEs(bool keep_compile_unit_die); void BuildAddressRangeTable(SymbolFileDWARF *dwarf2Data, DWARFDebugAranges *debug_aranges); @@ -80,7 +152,7 @@ DWARFFormValue::FixedFormSizes GetFixedFormSizes(); - void SetBaseAddress(dw_addr_t base_addr) { m_base_addr = base_addr; } + void SetBaseAddress(dw_addr_t base_addr) { m_data->m_base_addr = base_addr; } DWARFDIE GetCompileUnitDIEOnly() { return DWARFDIE(this, GetCompileUnitDIEPtrOnly()); } @@ -98,14 +170,14 @@ // the first entry, so if our size is 1, then we are adding // the first compile unit child DIE and should reserve // the memory. - if (m_die_array.empty()) - m_die_array.reserve(GetDebugInfoSize() / 24); - m_die_array.push_back(die); + if (m_data->m_die_array.empty()) + m_data->m_die_array.reserve(GetDebugInfoSize() / 24); + m_data->m_die_array.push_back(die); } void AddCompileUnitDIE(DWARFDebugInfoEntry &die); - bool HasDIEsParsed() const { return m_die_array.size() > 1; } + bool HasDIEsParsed() const { return m_data->m_die_array.size() > 1; } DWARFDIE GetDIE(dw_offset_t die_offset); @@ -114,11 +186,7 @@ static bool IsDWARF64(const DWARFCompileUnit *cu); - static uint8_t GetDefaultAddressSize(); - - static void SetDefaultAddressSize(uint8_t addr_size); - - void *GetUserData() const { return m_user_data; } + void *GetUserData() const { return m_data->m_user_data; } void SetUserData(void *d); @@ -135,7 +203,7 @@ const DWARFDebugAranges &GetFunctionAranges(); - SymbolFileDWARF *GetSymbolFileDWARF() const { return m_dwarf2Data; } + SymbolFileDWARF *GetSymbolFileDWARF() const { return m_data->m_dwarf2Data; } Producer GetProducer(); @@ -154,43 +222,36 @@ bool GetIsOptimized(); SymbolFileDWARFDwo *GetDwoSymbolFile() const { - return m_dwo_symbol_file.get(); + return m_data->m_dwo_symbol_file.get(); } - dw_offset_t GetBaseObjOffset() const { return m_base_obj_offset; } + dw_offset_t GetBaseObjOffset() const { return m_data->m_base_obj_offset; } -protected: - SymbolFileDWARF *m_dwarf2Data; - std::unique_ptr m_dwo_symbol_file; - const DWARFAbbreviationDeclarationSet *m_abbrevs; - void *m_user_data; - DWARFDebugInfoEntry::collection - m_die_array; // The compile unit debug information entry item - std::unique_ptr m_func_aranges_ap; // A table similar to - // the .debug_aranges - // table, but this one - // points to the exact - // DW_TAG_subprogram - // DIEs - dw_addr_t m_base_addr; - // Offset of the initial length field. - dw_offset_t m_offset; - dw_offset_t m_length; - uint16_t m_version; - uint8_t m_addr_size; - Producer m_producer; - uint32_t m_producer_version_major; - uint32_t m_producer_version_minor; - uint32_t m_producer_version_update; - lldb::LanguageType m_language_type; - bool m_is_dwarf64; - lldb_private::LazyBool m_is_optimized; - dw_addr_t m_addr_base; // Value of DW_AT_addr_base - dw_addr_t m_ranges_base; // Value of DW_AT_ranges_base - dw_offset_t m_base_obj_offset; // If this is a dwo compile unit this is the - // offset of the base compile unit in the main - // object file + // DW_TAG_compile_unit with DW_TAG_imported_unit for this DW_TAG_partial_unit. + DWARFCompileUnit *GetMainCU() const { return m_main_cu; } + + dw_offset_t GetFileOffset() const { return m_data->m_file_offset; } + dw_offset_t FileOffsetToUniqOffset(DWARFFileOffset file) const; + dw_offset_t ThisCUFileOffsetToUniq_nocheck(dw_offset_t file) const { + return file + (GetOffset() - GetFileOffset()); + } + dw_offset_t ThisCUFileOffsetToUniq(dw_offset_t file) const { + dw_offset_t uniq = ThisCUFileOffsetToUniq_nocheck(file); + lldbassert(ContainsDIEOffset(uniq)); + return uniq; + } + dw_offset_t ThisCUUniqToFileOffset(dw_offset_t uniq) const { + lldbassert(ContainsDIEOffset(uniq)); + return uniq - (GetOffset() - GetFileOffset()); + } + bool ContainsFileOffset(dw_offset_t file) const { + return ContainsDIEOffset(ThisCUFileOffsetToUniq_nocheck(file)); + } + dw_offset_t GetNextCompileUnitFileOffset() const { + return ThisCUUniqToFileOffset(GetNextCompileUnitOffset() - 1) + 1; + } +protected: void ParseProducerInfo(); static void @@ -201,19 +262,33 @@ NameToDIE &func_selectors, NameToDIE &objc_class_selectors, NameToDIE &globals, NameToDIE &types, NameToDIE &namespaces); + DWARFCompileUnit *InsertFileOffsetGetNewCU(DWARFFileOffset file); + DWARFCompileUnit *FileOffsetToCU(DWARFFileOffset file); + DWARFCompileUnit *FileOffsetToCULookup(DWARFFileOffset file); + + DWARFCompileUnitData *m_data; + + // DW_TAG_compile_unit with DW_TAG_imported_unit for this DW_TAG_partial_unit. + DWARFCompileUnit *m_main_cu; + + // Offset of the initial length field. + dw_offset_t m_offset = DW_INVALID_OFFSET; + private: + DWARFCompileUnit(SymbolFileDWARF *dwarf2Data); + const DWARFDebugInfoEntry *GetCompileUnitDIEPtrOnly() { - ExtractDIEsIfNeeded(true); - if (m_die_array.empty()) + ExtractDIEsIfNeeded(ExtractDIEsIfNeededKind::CuDieOnly); + if (m_data->m_die_array.empty()) return NULL; - return &m_die_array[0]; + return &m_data->m_die_array[0]; } const DWARFDebugInfoEntry *DIEPtr() { - ExtractDIEsIfNeeded(false); - if (m_die_array.empty()) + ExtractDIEsIfNeeded(ExtractDIEsIfNeededKind::AllDies); + if (m_data->m_die_array.empty()) return NULL; - return &m_die_array[0]; + return &m_data->m_die_array[0]; } DISALLOW_COPY_AND_ASSIGN(DWARFCompileUnit); Index: source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -38,73 +38,75 @@ extern int g_verbose; -DWARFCompileUnit::DWARFCompileUnit(SymbolFileDWARF *dwarf2Data) - : m_dwarf2Data(dwarf2Data), m_abbrevs(NULL), m_user_data(NULL), - m_die_array(), m_func_aranges_ap(), m_base_addr(0), - m_offset(DW_INVALID_OFFSET), m_length(0), m_version(0), - m_addr_size(DWARFCompileUnit::GetDefaultAddressSize()), - m_producer(eProducerInvalid), m_producer_version_major(0), - m_producer_version_minor(0), m_producer_version_update(0), - m_language_type(eLanguageTypeUnknown), m_is_dwarf64(false), - m_is_optimized(eLazyBoolCalculate), m_addr_base(0), - m_ranges_base(0), m_base_obj_offset(DW_INVALID_OFFSET) {} +DWARFCompileUnitData::DWARFCompileUnitData(SymbolFileDWARF *dwarf2Data) + : m_dwarf2Data(dwarf2Data) {} -DWARFCompileUnit::~DWARFCompileUnit() {} +DWARFCompileUnit::DWARFCompileUnit(SymbolFileDWARF *dwarf2Data) + : m_data(dwarf2Data->NewCompileUnitData()), m_main_cu(this) {} -void DWARFCompileUnit::Clear() { - m_offset = DW_INVALID_OFFSET; - m_length = 0; - m_version = 0; - m_abbrevs = NULL; - m_addr_size = DWARFCompileUnit::GetDefaultAddressSize(); - m_base_addr = 0; - m_die_array.clear(); - m_func_aranges_ap.reset(); - m_user_data = NULL; - m_producer = eProducerInvalid; - m_language_type = eLanguageTypeUnknown; - m_is_dwarf64 = false; - m_is_optimized = eLazyBoolCalculate; - m_addr_base = 0; - m_base_obj_offset = DW_INVALID_OFFSET; +DWARFCompileUnit::DWARFCompileUnit( + DWARFCompileUnitData *data, DWARFCompileUnit *main_cu) + : m_data(data), m_main_cu(main_cu) { + m_data->m_any_partial_unit = true; + lldbassert(!m_main_cu->m_data->m_dwarf2Data->GetIsDWZ()); } -bool DWARFCompileUnit::Extract(const DWARFDataExtractor &debug_info, - lldb::offset_t *offset_ptr) { - Clear(); +DWARFCompileUnit::~DWARFCompileUnit() {} - m_offset = *offset_ptr; +DWARFCompileUnitSP DWARFCompileUnit::Extract(SymbolFileDWARF *dwarf2Data, + lldb::offset_t *file_offset_ptr) { + DWARFCompileUnitSP cu_sp(new DWARFCompileUnit(dwarf2Data)); + // Out of memory? + if (cu_sp.get() == NULL) + return nullptr; + DWARFCompileUnitData *m_data = cu_sp->m_data; + + const DWARFDataExtractor &debug_info = dwarf2Data->get_debug_info_data(); + + m_data->m_file_offset = *file_offset_ptr; + cu_sp->m_offset = m_data->m_file_offset; + // All CUs in a base symbol file are shifted after its DWZ file (if exists). + SymbolFileDWARF *dwz_symbol_file = dwarf2Data->GetDWZSymbolFile(); + if (dwz_symbol_file) { + const DWARFDataExtractor &dwz_debug_info_data = + dwz_symbol_file->get_debug_info_data(); + cu_sp->m_offset += dwz_debug_info_data.GetByteSize(); + } - if (debug_info.ValidOffset(*offset_ptr)) { + if (debug_info.ValidOffset(*file_offset_ptr)) { dw_offset_t abbr_offset; - const DWARFDebugAbbrev *abbr = m_dwarf2Data->DebugAbbrev(); - m_length = debug_info.GetDWARFInitialLength(offset_ptr); - m_is_dwarf64 = debug_info.IsDWARF64(); - m_version = debug_info.GetU16(offset_ptr); - abbr_offset = debug_info.GetDWARFOffset(offset_ptr); - m_addr_size = debug_info.GetU8(offset_ptr); - - bool length_OK = debug_info.ValidOffset(GetNextCompileUnitOffset() - 1); - bool version_OK = SymbolFileDWARF::SupportedVersion(m_version); + const DWARFDebugAbbrev *abbr = dwarf2Data->DebugAbbrev(); + m_data->m_length = debug_info.GetDWARFInitialLength(file_offset_ptr); + m_data->m_is_dwarf64 = debug_info.IsDWARF64(); + m_data->m_version = debug_info.GetU16(file_offset_ptr); + abbr_offset = debug_info.GetDWARFOffset(file_offset_ptr); + m_data->m_addr_size = debug_info.GetU8(file_offset_ptr); + + bool length_OK = debug_info.ValidOffset( + cu_sp->GetNextCompileUnitFileOffset() - 1); + bool version_OK = SymbolFileDWARF::SupportedVersion(m_data->m_version); bool abbr_offset_OK = - m_dwarf2Data->get_debug_abbrev_data().ValidOffset(abbr_offset); - bool addr_size_OK = ((m_addr_size == 4) || (m_addr_size == 8)); + dwarf2Data->get_debug_abbrev_data().ValidOffset(abbr_offset); + bool addr_size_OK = + (m_data->m_addr_size == 4) || (m_data->m_addr_size == 8); if (length_OK && version_OK && addr_size_OK && abbr_offset_OK && abbr != NULL) { - m_abbrevs = abbr->GetAbbreviationDeclarationSet(abbr_offset); - return true; + m_data->m_abbrevs = abbr->GetAbbreviationDeclarationSet(abbr_offset); + return cu_sp; } // reset the offset to where we tried to parse from if anything went wrong - *offset_ptr = m_offset; + *file_offset_ptr = m_data->m_file_offset; } - return false; + return nullptr; } void DWARFCompileUnit::ClearDIEs(bool keep_compile_unit_die) { - if (m_die_array.size() > 1) { + if (m_data->m_die_array.size() > 1) { + std::lock_guard guard(m_data->m_extractdies_mutex); + // std::vectors never get any smaller when resized to a smaller size, // or when clear() or erase() are called, the size will report that it // is smaller, but the memory allocated remains intact (call capacity() @@ -115,13 +117,19 @@ // Save at least the compile unit DIE DWARFDebugInfoEntry::collection tmp_array; - m_die_array.swap(tmp_array); + m_data->m_die_array.swap(tmp_array); if (keep_compile_unit_die) - m_die_array.push_back(tmp_array.front()); + m_data->m_die_array.push_back(tmp_array.front()); + + while (!m_data->m_extracted_pu.empty()) { + m_data->m_extracted_pu.front()->ClearDIEs(keep_compile_unit_die); + m_data->m_extracted_pu.pop_front(); + } } - if (m_dwo_symbol_file) - m_dwo_symbol_file->GetCompileUnit()->ClearDIEs(keep_compile_unit_die); + if (m_data->m_dwo_symbol_file) + m_data->m_dwo_symbol_file->GetCompileUnit() + ->ClearDIEs(keep_compile_unit_die); } //---------------------------------------------------------------------- @@ -130,32 +138,61 @@ // Parses a compile unit and indexes its DIEs if it hasn't already been // done. //---------------------------------------------------------------------- -size_t DWARFCompileUnit::ExtractDIEsIfNeeded(bool cu_die_only) { - const size_t initial_die_array_size = m_die_array.size(); - if ((cu_die_only && initial_die_array_size > 0) || initial_die_array_size > 1) - return 0; // Already parsed +size_t DWARFCompileUnit::ExtractDIEsIfNeeded(ExtractDIEsIfNeededKind kind) { + size_t initial_die_array_size; + auto already_parsed = + [kind, &initial_die_array_size, this]() -> bool { + initial_die_array_size = m_data->m_die_array.size(); + if (initial_die_array_size > 1) + return true; + switch (kind) { + case ExtractDIEsIfNeededKind::CuDieOnly: + if (initial_die_array_size > 0) + return true; + break; + case ExtractDIEsIfNeededKind::AllDies: + break; + case ExtractDIEsIfNeededKind::AllDiesButCuDieOnlyForPartialUnits: { + if (initial_die_array_size > 0 + && GetCompileUnitDIEOnly().TagOrig() == DW_TAG_partial_unit) + return true; + } break; + } + return false; + }; + if (already_parsed() && m_data->m_die_array_finished) + return 0; + std::lock_guard guard(m_data->m_extractdies_mutex); + if (already_parsed()) { + lldbassert(m_data->m_die_array_finished); + return 0; + } + m_data->m_die_array_finished = false; + std::shared_ptr m_die_array_finished_set(nullptr, + [&](void*){ m_data->m_die_array_finished = true; }); static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer( func_cat, - "%8.8x: DWARFCompileUnit::ExtractDIEsIfNeeded( cu_die_only = %i )", - m_offset, cu_die_only); + "%8.8x: DWARFCompileUnit::ExtractDIEsIfNeeded( kind = %i )", + m_offset, int(kind)); // Set the offset to that of the first DIE and calculate the start of the // next compilation unit header. - lldb::offset_t offset = GetFirstDIEOffset(); + lldb::offset_t file_offset = ThisCUUniqToFileOffset(GetFirstDIEOffset()); lldb::offset_t next_cu_offset = GetNextCompileUnitOffset(); DWARFDebugInfoEntry die; // Keep a flat array of the DIE for binary lookup by DIE offset - if (!cu_die_only) { + if (kind != ExtractDIEsIfNeededKind::CuDieOnly) { Log *log( LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO | DWARF_LOG_LOOKUPS)); if (log) { - m_dwarf2Data->GetObjectFile()->GetModule()->LogMessageVerboseBacktrace( - log, "DWARFCompileUnit::ExtractDIEsIfNeeded () for compile unit at " - ".debug_info[0x%8.8x]", - GetOffset()); + m_data->m_dwarf2Data->GetObjectFile()->GetModule() + ->LogMessageVerboseBacktrace( + log, "DWARFCompileUnit::ExtractDIEsIfNeeded () " + "for compile unit at .debug_info[0x%8.8x]", + GetOffset()); } } @@ -163,16 +200,17 @@ // We are in our compile unit, parse starting at the offset // we were told to parse const DWARFDataExtractor &debug_info_data = - m_dwarf2Data->get_debug_info_data(); + m_data->m_dwarf2Data->get_debug_info_data(); std::vector die_index_stack; die_index_stack.reserve(32); die_index_stack.push_back(0); bool prev_die_had_children = false; DWARFFormValue::FixedFormSizes fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(), - m_is_dwarf64); - while (offset < next_cu_offset && - die.FastExtract(debug_info_data, this, fixed_form_sizes, &offset)) { + m_data->m_is_dwarf64); + while (ThisCUFileOffsetToUniq_nocheck(file_offset) < next_cu_offset && + die.FastExtract(debug_info_data, this, fixed_form_sizes, &file_offset)) + { // if (log) // log->Printf("0x%8.8x: %*.*s%s%s", // die.GetOffset(), @@ -185,12 +223,18 @@ if (initial_die_array_size == 0) AddCompileUnitDIE(die); uint64_t base_addr = die.GetAttributeValueAsAddress( - m_dwarf2Data, this, DW_AT_low_pc, LLDB_INVALID_ADDRESS); + m_data->m_dwarf2Data, this, DW_AT_low_pc, LLDB_INVALID_ADDRESS); if (base_addr == LLDB_INVALID_ADDRESS) - base_addr = die.GetAttributeValueAsAddress(m_dwarf2Data, this, + base_addr = die.GetAttributeValueAsAddress(m_data->m_dwarf2Data, this, DW_AT_entry_pc, 0); SetBaseAddress(base_addr); - if (cu_die_only) + lldbassert(!(die.TagOrig() == DW_TAG_partial_unit + && m_main_cu == this + && kind == ExtractDIEsIfNeededKind::AllDies)); + if (kind == ExtractDIEsIfNeededKind::CuDieOnly) + return 1; + if (kind == ExtractDIEsIfNeededKind::AllDiesButCuDieOnlyForPartialUnits + && die.TagOrig() == DW_TAG_partial_unit) return 1; } else { if (null_die) { @@ -200,18 +244,19 @@ // the NULL DIEs from the list (saves up to 25% in C++ code), // we need a way to let the DIE know that it actually doesn't // have children. - if (!m_die_array.empty()) - m_die_array.back().SetEmptyChildren(true); + if (!m_data->m_die_array.empty()) + m_data->m_die_array.back().SetEmptyChildren(true); } } else { - die.SetParentIndex(m_die_array.size() - die_index_stack[depth - 1]); + die.SetParentIndex( + m_data->m_die_array.size() - die_index_stack[depth - 1]); if (die_index_stack.back()) - m_die_array[die_index_stack.back()].SetSiblingIndex( - m_die_array.size() - die_index_stack.back()); + m_data->m_die_array[die_index_stack.back()].SetSiblingIndex( + m_data->m_die_array.size() - die_index_stack.back()); // Only push the DIE if it isn't a NULL DIE - m_die_array.push_back(die); + m_data->m_die_array.push_back(die); } } @@ -227,7 +272,7 @@ prev_die_had_children = false; } else { - die_index_stack.back() = m_die_array.size() - 1; + die_index_stack.back() = m_data->m_die_array.size() - 1; // Normal DIE const bool die_has_children = die.HasChildren(); if (die_has_children) { @@ -241,11 +286,11 @@ // Give a little bit of info if we encounter corrupt DWARF (our offset // should always terminate at or before the start of the next compilation // unit header). - if (offset > next_cu_offset) { - m_dwarf2Data->GetObjectFile()->GetModule()->ReportWarning( + if (ThisCUFileOffsetToUniq_nocheck(file_offset) > next_cu_offset) { + m_data->m_dwarf2Data->GetObjectFile()->GetModule()->ReportWarning( "DWARF compile unit extends beyond its bounds cu 0x%8.8x at " - "0x%8.8" PRIx64 "\n", - GetOffset(), offset); + "0x%8.8" PRIx32 "\n", + GetOffset(), ThisCUFileOffsetToUniq(file_offset)); } // Since std::vector objects will double their size, we really need to @@ -253,38 +298,38 @@ // space. So here we copy and swap to make sure we don't have any extra // memory taken up. - if (m_die_array.size() < m_die_array.capacity()) { - DWARFDebugInfoEntry::collection exact_size_die_array(m_die_array.begin(), - m_die_array.end()); - exact_size_die_array.swap(m_die_array); + if (m_data->m_die_array.size() < m_data->m_die_array.capacity()) { + DWARFDebugInfoEntry::collection exact_size_die_array( + m_data->m_die_array.begin(), m_data->m_die_array.end()); + exact_size_die_array.swap(m_data->m_die_array); } Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); if (log && log->GetVerbose()) { StreamString strm; Dump(&strm); - if (m_die_array.empty()) + if (m_data->m_die_array.empty()) strm.Printf("error: no DIE for compile unit"); else - m_die_array[0].Dump(m_dwarf2Data, this, strm, UINT32_MAX); + m_data->m_die_array[0].Dump(m_data->m_dwarf2Data, this, strm, UINT32_MAX); log->PutString(strm.GetString()); } - if (!m_dwo_symbol_file) - return m_die_array.size(); + if (!m_data->m_dwo_symbol_file) + return m_data->m_die_array.size(); - DWARFCompileUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit(); - size_t dwo_die_count = dwo_cu->ExtractDIEsIfNeeded(cu_die_only); - return m_die_array.size() + dwo_die_count - + DWARFCompileUnit *dwo_cu = m_data->m_dwo_symbol_file->GetCompileUnit(); + size_t dwo_die_count = dwo_cu->ExtractDIEsIfNeeded(kind); + return m_data->m_die_array.size() + dwo_die_count - 1; // We have 2 CU die, but we want to count it only as one } void DWARFCompileUnit::AddCompileUnitDIE(DWARFDebugInfoEntry &die) { - assert(m_die_array.empty() && "Compile unit DIE already added"); + assert(m_data->m_die_array.empty() && "Compile unit DIE already added"); AddDIE(die); - const DWARFDebugInfoEntry &cu_die = m_die_array.front(); + const DWARFDebugInfoEntry &cu_die = m_data->m_die_array.front(); std::unique_ptr dwo_symbol_file = - m_dwarf2Data->GetDwoSymbolFileForCompileUnit(*this, cu_die); + m_data->m_dwarf2Data->GetDwoSymbolFileForCompileUnit(*this, cu_die); if (!dwo_symbol_file) return; @@ -297,40 +342,42 @@ return; // Can't fetch the compile unit DIE from the dwo file. uint64_t main_dwo_id = cu_die.GetAttributeValueAsUnsigned( - m_dwarf2Data, this, DW_AT_GNU_dwo_id, 0); + m_data->m_dwarf2Data, this, DW_AT_GNU_dwo_id, 0); uint64_t sub_dwo_id = dwo_cu_die.GetAttributeValueAsUnsigned(DW_AT_GNU_dwo_id, 0); if (main_dwo_id != sub_dwo_id) return; // The 2 dwo ID isn't match. Don't use the dwo file as it belongs to // a differectn compilation. - m_dwo_symbol_file = std::move(dwo_symbol_file); + m_data->m_dwo_symbol_file = std::move(dwo_symbol_file); dw_addr_t addr_base = cu_die.GetAttributeValueAsUnsigned( - m_dwarf2Data, this, DW_AT_GNU_addr_base, 0); + m_data->m_dwarf2Data, this, DW_AT_GNU_addr_base, 0); dw_addr_t ranges_base = cu_die.GetAttributeValueAsUnsigned( - m_dwarf2Data, this, DW_AT_GNU_ranges_base, 0); + m_data->m_dwarf2Data, this, DW_AT_GNU_ranges_base, 0); dwo_cu->SetAddrBase(addr_base, ranges_base, m_offset); } dw_offset_t DWARFCompileUnit::GetAbbrevOffset() const { - return m_abbrevs ? m_abbrevs->GetOffset() : DW_INVALID_OFFSET; + return m_data->m_abbrevs ? m_data->m_abbrevs->GetOffset() : DW_INVALID_OFFSET; } bool DWARFCompileUnit::Verify(Stream *s) const { - const DWARFDataExtractor &debug_info = m_dwarf2Data->get_debug_info_data(); + const DWARFDataExtractor &debug_info = + m_data->m_dwarf2Data->get_debug_info_data(); bool valid_offset = debug_info.ValidOffset(m_offset); bool length_OK = debug_info.ValidOffset(GetNextCompileUnitOffset() - 1); - bool version_OK = SymbolFileDWARF::SupportedVersion(m_version); - bool abbr_offset_OK = - m_dwarf2Data->get_debug_abbrev_data().ValidOffset(GetAbbrevOffset()); - bool addr_size_OK = ((m_addr_size == 4) || (m_addr_size == 8)); + bool version_OK = SymbolFileDWARF::SupportedVersion(m_data->m_version); + bool abbr_offset_OK = m_data->m_dwarf2Data->get_debug_abbrev_data() + .ValidOffset(GetAbbrevOffset()); + bool addr_size_OK = + ((m_data->m_addr_size == 4) || (m_data->m_addr_size == 8)); if (valid_offset && length_OK && version_OK && addr_size_OK && abbr_offset_OK) { return true; } else { s->Printf(" 0x%8.8x: ", m_offset); - DumpDataExtractor(m_dwarf2Data->get_debug_info_data(), s, m_offset, + DumpDataExtractor(m_data->m_dwarf2Data->get_debug_info_data(), s, m_offset, lldb::eFormatHex, 1, Size(), 32, LLDB_INVALID_ADDRESS, 0, 0); s->EOL(); @@ -338,7 +385,7 @@ if (!length_OK) s->Printf(" The length (0x%8.8x) for this compile unit is too " "large for the .debug_info provided.\n", - m_length); + m_data->m_length); if (!version_OK) s->Printf(" The 16 bit compile unit header version is not " "supported.\n"); @@ -348,7 +395,7 @@ GetAbbrevOffset()); if (!addr_size_OK) s->Printf(" The address size is unsupported: 0x%2.2x\n", - m_addr_size); + m_data->m_addr_size); } else s->Printf(" The start offset of the compile unit header in the " ".debug_info is invalid.\n"); @@ -360,16 +407,16 @@ s->Printf("0x%8.8x: Compile Unit: length = 0x%8.8x, version = 0x%4.4x, " "abbr_offset = 0x%8.8x, addr_size = 0x%2.2x (next CU at " "{0x%8.8x})\n", - m_offset, m_length, m_version, GetAbbrevOffset(), m_addr_size, - GetNextCompileUnitOffset()); + m_offset, m_data->m_length, m_data->m_version, GetAbbrevOffset(), + m_data->m_addr_size, GetNextCompileUnitOffset()); } -static uint8_t g_default_addr_size = 4; +uint8_t DWARFCompileUnitData::g_default_addr_size = 4; uint8_t DWARFCompileUnit::GetAddressByteSize(const DWARFCompileUnit *cu) { if (cu) return cu->GetAddressByteSize(); - return DWARFCompileUnit::GetDefaultAddressSize(); + return DWARFCompileUnitData::GetDefaultAddressSize(); } bool DWARFCompileUnit::IsDWARF64(const DWARFCompileUnit *cu) { @@ -378,19 +425,19 @@ return false; } -uint8_t DWARFCompileUnit::GetDefaultAddressSize() { +uint8_t DWARFCompileUnitData::GetDefaultAddressSize() { return g_default_addr_size; } -void DWARFCompileUnit::SetDefaultAddressSize(uint8_t addr_size) { +void DWARFCompileUnitData::SetDefaultAddressSize(uint8_t addr_size) { g_default_addr_size = addr_size; } lldb::user_id_t DWARFCompileUnit::GetID() const { - dw_offset_t local_id = - m_base_obj_offset != DW_INVALID_OFFSET ? m_base_obj_offset : m_offset; - if (m_dwarf2Data) - return DIERef(local_id, local_id).GetUID(m_dwarf2Data); + dw_offset_t local_id = m_data->m_base_obj_offset != DW_INVALID_OFFSET + ? m_data->m_base_obj_offset : m_offset; + if (m_data->m_dwarf2Data) + return DIERef(local_id, local_id).GetUID(m_data->m_dwarf2Data); else return local_id; } @@ -431,9 +478,10 @@ // units // to stay loaded when they weren't needed. So we can end up parsing the DWARF // and then throwing them all away to keep memory usage down. - const bool clear_dies = ExtractDIEsIfNeeded(false) > 1; + const bool clear_dies = ExtractDIEsIfNeeded( + ExtractDIEsIfNeededKind::AllDiesButCuDieOnlyForPartialUnits) > 1; - die = DIEPtr(); + die = GetCompileUnitDIEPtrOnly(); if (die) die->BuildAddressRangeTable(dwarf2Data, this, debug_aranges); @@ -444,7 +492,7 @@ sc.comp_unit = dwarf2Data->GetCompUnitForDWARFCompUnit(this); if (sc.comp_unit) { SymbolFileDWARFDebugMap *debug_map_sym_file = - m_dwarf2Data->GetDebugMapSymfile(); + m_data->m_dwarf2Data->GetDebugMapSymfile(); if (debug_map_sym_file == NULL) { LineTable *line_table = sc.comp_unit->GetLineTable(); @@ -495,33 +543,34 @@ } const DWARFDebugAranges &DWARFCompileUnit::GetFunctionAranges() { - if (m_func_aranges_ap.get() == NULL) { - m_func_aranges_ap.reset(new DWARFDebugAranges()); + if (m_data->m_func_aranges_ap.get() == NULL) { + m_data->m_func_aranges_ap.reset(new DWARFDebugAranges()); Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES)); if (log) { - m_dwarf2Data->GetObjectFile()->GetModule()->LogMessage( + m_data->m_dwarf2Data->GetObjectFile()->GetModule()->LogMessage( log, "DWARFCompileUnit::GetFunctionAranges() for compile unit at " ".debug_info[0x%8.8x]", GetOffset()); } const DWARFDebugInfoEntry *die = DIEPtr(); if (die) - die->BuildFunctionAddressRangeTable(m_dwarf2Data, this, - m_func_aranges_ap.get()); + die->BuildFunctionAddressRangeTable(m_data->m_dwarf2Data, this, + m_data->m_func_aranges_ap.get()); - if (m_dwo_symbol_file) { - DWARFCompileUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit(); + if (m_data->m_dwo_symbol_file) { + DWARFCompileUnit *dwo_cu = m_data->m_dwo_symbol_file->GetCompileUnit(); const DWARFDebugInfoEntry *dwo_die = dwo_cu->DIEPtr(); if (dwo_die) - dwo_die->BuildFunctionAddressRangeTable(m_dwo_symbol_file.get(), dwo_cu, - m_func_aranges_ap.get()); + dwo_die->BuildFunctionAddressRangeTable( + m_data->m_dwo_symbol_file.get(), dwo_cu, + m_data->m_func_aranges_ap.get()); } const bool minimize = false; - m_func_aranges_ap->Sort(minimize); + m_data->m_func_aranges_ap->Sort(minimize); } - return *m_func_aranges_ap.get(); + return *m_data->m_func_aranges_ap.get(); } DWARFDIE @@ -539,9 +588,9 @@ //---------------------------------------------------------------------- // Compare function DWARFDebugAranges::Range structures //---------------------------------------------------------------------- -static bool CompareDIEOffset(const DWARFDebugInfoEntry &die, - const dw_offset_t die_offset) { - return die.GetOffset() < die_offset; +static bool CompareDIEFileOffset(const DWARFDebugInfoEntry &die, + const dw_offset_t die_file_offset) { + return die.GetFileOffset() < die_file_offset; } //---------------------------------------------------------------------- @@ -555,23 +604,26 @@ DWARFDIE DWARFCompileUnit::GetDIE(dw_offset_t die_offset) { if (die_offset != DW_INVALID_OFFSET) { - if (m_dwo_symbol_file) - return m_dwo_symbol_file->GetCompileUnit()->GetDIE(die_offset); + if (m_data->m_dwo_symbol_file) + return m_data->m_dwo_symbol_file->GetCompileUnit()->GetDIE(die_offset); if (ContainsDIEOffset(die_offset)) { - ExtractDIEsIfNeeded(false); - DWARFDebugInfoEntry::iterator end = m_die_array.end(); - DWARFDebugInfoEntry::iterator pos = - lower_bound(m_die_array.begin(), end, die_offset, CompareDIEOffset); + ExtractDIEsIfNeeded(ExtractDIEsIfNeededKind::AllDies); + dw_offset_t die_file_offset = ThisCUUniqToFileOffset(die_offset); + DWARFDebugInfoEntry::iterator end = m_data->m_die_array.end(); + DWARFDebugInfoEntry::iterator pos = lower_bound( + m_data->m_die_array.begin(), end, die_file_offset, + CompareDIEFileOffset); if (pos != end) { - if (die_offset == (*pos).GetOffset()) + if (die_file_offset == (*pos).GetFileOffset()) return DWARFDIE(this, &(*pos)); } } else { // Don't specify the compile unit offset as we don't know it because the // DIE belongs to // a different compile unit in the same symbol file. - return m_dwarf2Data->DebugInfo()->GetDIEForDIEOffset(die_offset); + return GetMainCU()->m_data->m_dwarf2Data->DebugInfo() + ->GetDIEForDIEOffset(die_offset); } } return DWARFDIE(); // Not found @@ -582,8 +634,8 @@ uint32_t depth) const { size_t old_size = dies.Size(); DWARFDebugInfoEntry::const_iterator pos; - DWARFDebugInfoEntry::const_iterator end = m_die_array.end(); - for (pos = m_die_array.begin(); pos != end; ++pos) { + DWARFDebugInfoEntry::const_iterator end = m_data->m_die_array.end(); + for (pos = m_data->m_die_array.begin(); pos != end; ++pos) { if (pos->Tag() == tag) dies.Append(DWARFDIE(this, &(*pos))); } @@ -605,11 +657,11 @@ // // Indexes to all file level global and static variables // m_global_die_indexes; // -// if (m_die_array.empty()) +// if (m_data->m_die_array.empty()) // return; // -// const DWARFDebugInfoEntry* first_die = &m_die_array[0]; -// const DWARFDebugInfoEntry* end = first_die + m_die_array.size(); +// const DWARFDebugInfoEntry* first_die = &m_data->m_die_array[0]; +// const DWARFDebugInfoEntry* end = first_die + m_data->m_die_array.size(); // if (first_die <= die && die < end) // m_global_die_indexes.push_back (die - first_die); //} @@ -620,14 +672,14 @@ NameToDIE &objc_class_selectors, NameToDIE &globals, NameToDIE &types, NameToDIE &namespaces) { - assert(!m_dwarf2Data->GetBaseCompileUnit() && + assert(!m_data->m_dwarf2Data->GetBaseCompileUnit() && "DWARFCompileUnit associated with .dwo or .dwp " "should not be indexed directly"); Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); if (log) { - m_dwarf2Data->GetObjectFile()->GetModule()->LogMessage( + m_data->m_dwarf2Data->GetObjectFile()->GetModule()->LogMessage( log, "DWARFCompileUnit::Index() for compile unit at .debug_info[0x%8.8x]", GetOffset()); @@ -636,7 +688,7 @@ const LanguageType cu_language = GetLanguageType(); DWARFFormValue::FixedFormSizes fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(), - m_is_dwarf64); + m_data->m_is_dwarf64); IndexPrivate(this, cu_language, fixed_form_sizes, GetOffset(), func_basenames, func_fullnames, func_methods, func_selectors, @@ -659,8 +711,9 @@ NameToDIE &func_selectors, NameToDIE &objc_class_selectors, NameToDIE &globals, NameToDIE &types, NameToDIE &namespaces) { DWARFDebugInfoEntry::const_iterator pos; - DWARFDebugInfoEntry::const_iterator begin = dwarf_cu->m_die_array.begin(); - DWARFDebugInfoEntry::const_iterator end = dwarf_cu->m_die_array.end(); + DWARFDebugInfoEntry::const_iterator begin = + dwarf_cu->m_data->m_die_array.begin(); + DWARFDebugInfoEntry::const_iterator end = dwarf_cu->m_data->m_die_array.end(); for (pos = begin; pos != end; ++pos) { const DWARFDebugInfoEntry &die = *pos; @@ -682,6 +735,7 @@ case DW_TAG_union_type: case DW_TAG_unspecified_type: case DW_TAG_variable: + case DW_TAG_imported_unit: break; default: @@ -697,7 +751,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(dwarf_cu, fixed_form_sizes, attributes); if (num_attributes > 0) { @@ -800,6 +854,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; } } } @@ -817,20 +876,20 @@ objc_method.GetFullNameWithoutCategory(true)); ConstString objc_class_name_no_category(objc_method.GetClassName()); func_fullnames.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); + DIERef(cu_offset, die.GetOffset(dwarf_cu))); if (objc_class_name_with_category) objc_class_selectors.Insert(objc_class_name_with_category, - DIERef(cu_offset, die.GetOffset())); + DIERef(cu_offset, die.GetOffset(dwarf_cu))); if (objc_class_name_no_category && objc_class_name_no_category != objc_class_name_with_category) objc_class_selectors.Insert(objc_class_name_no_category, - DIERef(cu_offset, die.GetOffset())); + DIERef(cu_offset, die.GetOffset(dwarf_cu))); if (objc_selector_name) func_selectors.Insert(objc_selector_name, - DIERef(cu_offset, die.GetOffset())); + DIERef(cu_offset, die.GetOffset(dwarf_cu))); if (objc_fullname_no_category_name) func_fullnames.Insert(objc_fullname_no_category_name, - DIERef(cu_offset, die.GetOffset())); + DIERef(cu_offset, die.GetOffset(dwarf_cu))); } // If we have a mangled name, then the DW_AT_name attribute // is usually the method name without the class or any parameters @@ -854,14 +913,14 @@ if (is_method) func_methods.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); + DIERef(cu_offset, die.GetOffset(dwarf_cu))); else func_basenames.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); + DIERef(cu_offset, die.GetOffset(dwarf_cu))); if (!is_method && !mangled_cstr && !objc_method.IsValid(true)) func_fullnames.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); + DIERef(cu_offset, die.GetOffset(dwarf_cu))); } if (mangled_cstr) { // Make sure our mangled name isn't the same string table entry @@ -873,11 +932,11 @@ (::strcmp(name, mangled_cstr) != 0))) { Mangled mangled(ConstString(mangled_cstr), true); func_fullnames.Insert(mangled.GetMangledName(), - DIERef(cu_offset, die.GetOffset())); + DIERef(cu_offset, die.GetOffset(dwarf_cu))); ConstString demangled = mangled.GetDemangledName(cu_language); if (demangled) func_fullnames.Insert(demangled, - DIERef(cu_offset, die.GetOffset())); + DIERef(cu_offset, die.GetOffset(dwarf_cu))); } } } @@ -887,7 +946,7 @@ if (has_address) { if (name) func_basenames.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); + DIERef(cu_offset, die.GetOffset(dwarf_cu))); if (mangled_cstr) { // Make sure our mangled name isn't the same string table entry // as our name. If it starts with '_', then it is ok, else compare @@ -898,15 +957,15 @@ (::strcmp(name, mangled_cstr) != 0))) { Mangled mangled(ConstString(mangled_cstr), true); func_fullnames.Insert(mangled.GetMangledName(), - DIERef(cu_offset, die.GetOffset())); + DIERef(cu_offset, die.GetOffset(dwarf_cu))); ConstString demangled = mangled.GetDemangledName(cu_language); if (demangled) func_fullnames.Insert(demangled, - DIERef(cu_offset, die.GetOffset())); + DIERef(cu_offset, die.GetOffset(dwarf_cu))); } } else func_fullnames.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); + DIERef(cu_offset, die.GetOffset(dwarf_cu))); } break; @@ -922,21 +981,23 @@ case DW_TAG_union_type: case DW_TAG_unspecified_type: if (name && !is_declaration) - types.Insert(ConstString(name), DIERef(cu_offset, die.GetOffset())); + types.Insert(ConstString(name), + DIERef(cu_offset, die.GetOffset(dwarf_cu))); if (mangled_cstr && !is_declaration) types.Insert(ConstString(mangled_cstr), - DIERef(cu_offset, die.GetOffset())); + DIERef(cu_offset, die.GetOffset(dwarf_cu))); break; case DW_TAG_namespace: if (name) namespaces.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); + DIERef(cu_offset, die.GetOffset(dwarf_cu))); break; case DW_TAG_variable: if (name && has_location_or_const_value && is_global_or_static_variable) { - globals.Insert(ConstString(name), DIERef(cu_offset, die.GetOffset())); + globals.Insert(ConstString(name), + DIERef(cu_offset, die.GetOffset(dwarf_cu))); // Be sure to include variables by their mangled and demangled // names if they have any since a variable can have a basename // "i", a mangled named "_ZN12_GLOBAL__N_11iE" and a demangled @@ -950,14 +1011,58 @@ ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0))) { Mangled mangled(ConstString(mangled_cstr), true); globals.Insert(mangled.GetMangledName(), - DIERef(cu_offset, die.GetOffset())); + DIERef(cu_offset, die.GetOffset(dwarf_cu))); ConstString demangled = mangled.GetDemangledName(cu_language); if (demangled) - globals.Insert(demangled, DIERef(cu_offset, die.GetOffset())); + globals.Insert(demangled, + DIERef(cu_offset, die.GetOffset(dwarf_cu))); } } 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) { + dwarf_cu->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", + dwarf_cu->GetOffset(), die.GetOffset(dwarf_cu)); + break; + } + DWARFFileOffset import_file = import_die_form.ReferenceInFile(); + DWARFCompileUnit *main_cu = dwarf_cu->m_main_cu; + DWARFCompileUnit *import_cu = main_cu->FileOffsetToCU(import_file); + if (!import_cu) + break; + dw_offset_t import_cu_firstdie_file = + import_cu->ThisCUUniqToFileOffset(import_cu->GetFirstDIEOffset()); + if (import_file.GetFileOffset() != import_cu_firstdie_file) { + dwarf_cu->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, + dwarf_cu->GetOffset(), die.GetOffset(dwarf_cu), + import_file.GetFileOffset(), import_cu_firstdie_file); + break; + } + if (import_cu->ExtractDIEsIfNeeded(ExtractDIEsIfNeededKind::AllDies) + > 1) { + std::lock_guard + guard(main_cu->m_data->m_extractdies_mutex); + main_cu->m_data->m_extracted_pu.push_front(import_cu); + } + import_cu->Index(func_basenames, func_fullnames, func_methods, + func_selectors, objc_class_selectors, globals, types, namespaces); + } + break; + default: continue; } @@ -990,22 +1095,22 @@ } void DWARFCompileUnit::ParseProducerInfo() { - m_producer_version_major = UINT32_MAX; - m_producer_version_minor = UINT32_MAX; - m_producer_version_update = UINT32_MAX; + m_data->m_producer_version_major = UINT32_MAX; + m_data->m_producer_version_minor = UINT32_MAX; + m_data->m_producer_version_update = UINT32_MAX; const DWARFDebugInfoEntry *die = GetCompileUnitDIEPtrOnly(); if (die) { const char *producer_cstr = die->GetAttributeValueAsString( - m_dwarf2Data, this, DW_AT_producer, NULL); + m_data->m_dwarf2Data, this, DW_AT_producer, NULL); if (producer_cstr) { RegularExpression llvm_gcc_regex( llvm::StringRef("^4\\.[012]\\.[01] \\(Based on Apple " "Inc\\. build [0-9]+\\) \\(LLVM build " "[\\.0-9]+\\)$")); if (llvm_gcc_regex.Execute(llvm::StringRef(producer_cstr))) { - m_producer = eProducerLLVMGCC; + m_data->m_producer = eProducerLLVMGCC; } else if (strstr(producer_cstr, "clang")) { static RegularExpression g_clang_version_regex( llvm::StringRef("clang-([0-9]+)\\.([0-9]+)\\.([0-9]+)")); @@ -1014,46 +1119,46 @@ ®ex_match)) { std::string str; if (regex_match.GetMatchAtIndex(producer_cstr, 1, str)) - m_producer_version_major = + m_data->m_producer_version_major = StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); if (regex_match.GetMatchAtIndex(producer_cstr, 2, str)) - m_producer_version_minor = + m_data->m_producer_version_minor = StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); if (regex_match.GetMatchAtIndex(producer_cstr, 3, str)) - m_producer_version_update = + m_data->m_producer_version_update = StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); } - m_producer = eProducerClang; + m_data->m_producer = eProducerClang; } else if (strstr(producer_cstr, "GNU")) - m_producer = eProducerGCC; + m_data->m_producer = eProducerGCC; } } - if (m_producer == eProducerInvalid) - m_producer = eProcucerOther; + if (m_data->m_producer == eProducerInvalid) + m_data->m_producer = eProcucerOther; } DWARFCompileUnit::Producer DWARFCompileUnit::GetProducer() { - if (m_producer == eProducerInvalid) + if (m_data->m_producer == eProducerInvalid) ParseProducerInfo(); - return m_producer; + return m_data->m_producer; } uint32_t DWARFCompileUnit::GetProducerVersionMajor() { - if (m_producer_version_major == 0) + if (m_data->m_producer_version_major == 0) ParseProducerInfo(); - return m_producer_version_major; + return m_data->m_producer_version_major; } uint32_t DWARFCompileUnit::GetProducerVersionMinor() { - if (m_producer_version_minor == 0) + if (m_data->m_producer_version_minor == 0) ParseProducerInfo(); - return m_producer_version_minor; + return m_data->m_producer_version_minor; } uint32_t DWARFCompileUnit::GetProducerVersionUpdate() { - if (m_producer_version_update == 0) + if (m_data->m_producer_version_update == 0) ParseProducerInfo(); - return m_producer_version_update; + return m_data->m_producer_version_update; } LanguageType DWARFCompileUnit::LanguageTypeFromDWARF(uint64_t val) { @@ -1070,30 +1175,33 @@ } LanguageType DWARFCompileUnit::GetLanguageType() { - if (m_language_type != eLanguageTypeUnknown) - return m_language_type; + if (GetMainCU() != this) + return GetMainCU()->GetLanguageType(); + if (m_data->m_language_type != eLanguageTypeUnknown) + return m_data->m_language_type; const DWARFDebugInfoEntry *die = GetCompileUnitDIEPtrOnly(); if (die) - m_language_type = LanguageTypeFromDWARF(die->GetAttributeValueAsUnsigned( - m_dwarf2Data, this, DW_AT_language, 0)); - return m_language_type; + m_data->m_language_type = LanguageTypeFromDWARF( + die->GetAttributeValueAsUnsigned( + m_data->m_dwarf2Data, this, DW_AT_language, 0)); + return m_data->m_language_type; } -bool DWARFCompileUnit::IsDWARF64() const { return m_is_dwarf64; } +bool DWARFCompileUnit::IsDWARF64() const { return m_data->m_is_dwarf64; } bool DWARFCompileUnit::GetIsOptimized() { - if (m_is_optimized == eLazyBoolCalculate) { + if (m_data->m_is_optimized == eLazyBoolCalculate) { const DWARFDebugInfoEntry *die = GetCompileUnitDIEPtrOnly(); if (die) { - m_is_optimized = eLazyBoolNo; - if (die->GetAttributeValueAsUnsigned(m_dwarf2Data, this, + m_data->m_is_optimized = eLazyBoolNo; + if (die->GetAttributeValueAsUnsigned(m_data->m_dwarf2Data, this, DW_AT_APPLE_optimized, 0) == 1) { - m_is_optimized = eLazyBoolYes; + m_data->m_is_optimized = eLazyBoolYes; } } } - if (m_is_optimized == eLazyBoolYes) { + if (m_data->m_is_optimized == eLazyBoolYes) { return true; } else { return false; @@ -1106,26 +1214,126 @@ } TypeSystem *DWARFCompileUnit::GetTypeSystem() { - if (m_dwarf2Data) - return m_dwarf2Data->GetTypeSystemForLanguage(GetLanguageType()); + if (GetMainCU() != this) + return GetMainCU()->GetTypeSystem(); + if (m_data->m_dwarf2Data) + return m_data->m_dwarf2Data->GetTypeSystemForLanguage(GetLanguageType()); else return nullptr; } void DWARFCompileUnit::SetUserData(void *d) { - m_user_data = d; - if (m_dwo_symbol_file) - m_dwo_symbol_file->GetCompileUnit()->SetUserData(d); + m_data->m_user_data = d; + if (m_data->m_dwo_symbol_file) + m_data->m_dwo_symbol_file->GetCompileUnit()->SetUserData(d); } void DWARFCompileUnit::SetAddrBase(dw_addr_t addr_base, dw_addr_t ranges_base, dw_offset_t base_obj_offset) { - m_addr_base = addr_base; - m_ranges_base = ranges_base; - m_base_obj_offset = base_obj_offset; + m_data->m_addr_base = addr_base; + m_data->m_ranges_base = ranges_base; + m_data->m_base_obj_offset = base_obj_offset; } lldb::ByteOrder DWARFCompileUnit::GetByteOrder() const { - return m_dwarf2Data->GetObjectFile()->GetByteOrder(); + return m_data->m_dwarf2Data->GetObjectFile()->GetByteOrder(); +} + +DWARFCompileUnit *DWARFCompileUnit::InsertFileOffsetGetNewCU( + DWARFFileOffset file) { + lldbassert(m_main_cu == this); + lldbassert(file.GetIsDWZ() || !ContainsFileOffset(file.GetFileOffset())); + SymbolFileDWARF *main_symbol_file = m_data->m_dwarf2Data; + lldbassert(!main_symbol_file->GetIsDWZ()); + dw_offset_t file_as_uniq = file.GetFileOffset(); + SymbolFileDWARF *dwz_symbol_file = main_symbol_file->GetDWZSymbolFile(); + if (!file.GetIsDWZ() && dwz_symbol_file) { + // All CUs in a base symbol file are shifted after its DWZ file (if exists). + const DWARFDataExtractor &dwz_debug_info_data = + dwz_symbol_file->get_debug_info_data(); + file_as_uniq += dwz_debug_info_data.GetByteSize(); + } + DWARFDebugInfo *main_debuginfo = main_symbol_file->DebugInfo(); + DWARFCompileUnit *file_cu = + main_debuginfo->GetCompileUnitContainingDIEOffset(file_as_uniq); + if (!file_cu) { + main_symbol_file->GetObjectFile()->GetModule()->ReportError( + "There is no CU for DIE file offset 0x%8.8" PRIx32, + file.GetFileOffset()); + return nullptr; + } + lldbassert(file_cu->m_main_cu == file_cu); + auto cu_sp = std::make_shared(file_cu->m_data, this); + lldbassert(cu_sp->m_data->m_file_offset != DW_INVALID_OFFSET); + DWARFCompileUnit *cu = cu_sp.get(); + main_debuginfo->InsertCUGetUniqOffset(std::move(cu_sp)); + DWARFFileOffset file_start = DWARFFileOffset(file_cu); + lldbassert(file_start.GetIsDWZ() == file.GetIsDWZ()); + lldbassert(file_start.GetFileOffset() < file.GetFileOffset()); + auto insertpair = m_data->m_dwz_file_to_cu.emplace(file_start, cu); + lldbassert(insertpair.second); + return cu; +} + +DWARFCompileUnit *DWARFCompileUnit::FileOffsetToCULookup(DWARFFileOffset file) { + lldbassert(m_main_cu == this); + SymbolFileDWARF *main_symbol_file = m_data->m_dwarf2Data; + lldbassert(!main_symbol_file->GetIsDWZ()); + if (!file.GetIsDWZ() && ContainsFileOffset(file.GetFileOffset())) + return this; + SymbolFileDWARF *file_symbol_file = main_symbol_file; + if (file.GetIsDWZ()) { + file_symbol_file = main_symbol_file->GetDWZSymbolFile(); + if (!file_symbol_file) { + main_symbol_file->GetObjectFile()->GetModule()->ReportError( + "File reference 0x%8.8" PRIx32 " (DWZ file = 1)" + " is in a file without associated DWZ common file", + file.GetFileOffset()); + return nullptr; + } + } + const DWARFDataExtractor &file_debug_info_data = + file_symbol_file->get_debug_info_data(); + if (file.GetFileOffset() >= file_debug_info_data.GetByteSize()) { + main_symbol_file->GetObjectFile()->GetModule()->ReportError( + "File reference 0x%8.8" PRIx32 " (DWZ file = %d)" + " does not belong to the file of size 0x%8.8" PRIx64, + file.GetFileOffset(), file.GetIsDWZ(), + file_debug_info_data.GetByteSize()); + return nullptr; + } + auto it = m_data->m_dwz_file_to_cu.upper_bound(file); + if (it == m_data->m_dwz_file_to_cu.begin()) + return nullptr; + --it; + DWARFCompileUnit *cu = it->second; + if (cu->m_data->m_dwarf2Data->GetIsDWZ() != file.GetIsDWZ() + || !cu->ContainsFileOffset(file.GetFileOffset())) + return nullptr; + return cu; +} + +DWARFCompileUnit *DWARFCompileUnit::FileOffsetToCU(DWARFFileOffset file) { + DWARFCompileUnit *cu = FileOffsetToCULookup(file); + if (!cu) { + cu = InsertFileOffsetGetNewCU(file); + assert(!cu || cu == FileOffsetToCULookup(file)); + } + return cu; +} + +dw_offset_t DWARFCompileUnit::FileOffsetToUniqOffset( + DWARFFileOffset file) const { + DWARFCompileUnit *cu = m_main_cu->FileOffsetToCU(file); + if (!cu) { + // InsertFileOffsetGetNewCU already did ReportError. + return file.GetFileOffset(); + } + return cu->ThisCUFileOffsetToUniq(file.GetFileOffset()); +} + +void DWARFCompileUnit::SetOffset(dw_offset_t offset) { + lldbassert(m_offset == DW_INVALID_OFFSET); + m_offset = offset; } Index: source/Plugins/SymbolFile/DWARF/DWARFDIE.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDIE.h +++ source/Plugins/SymbolFile/DWARF/DWARFDIE.h @@ -57,6 +57,9 @@ //---------------------------------------------------------------------- SymbolFileDWARF *GetDWARF() const; + // File which referenced DWZCommonFile (where this DIE may be located). + SymbolFileDWARF *GetMainDWARF() const; + DWARFCompileUnit *GetCU() const { return m_cu; } DWARFDebugInfoEntry *GetDIE() const { return m_die; } @@ -89,6 +92,8 @@ //---------------------------------------------------------------------- // Accessing information about a DIE //---------------------------------------------------------------------- + dw_tag_t TagOrig() const; + dw_tag_t Tag() const; const char *GetTagAsCString() const; Index: source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -25,6 +25,7 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/TypeSystem.h" +#include "lldb/Utility/LLDBAssert.h" using namespace lldb_private; @@ -35,7 +36,14 @@ dw_offset_t cu_offset = m_cu->GetOffset(); if (m_cu->GetBaseObjOffset() != DW_INVALID_OFFSET) cu_offset = m_cu->GetBaseObjOffset(); - return DIERef(cu_offset, m_die->GetOffset()); + return DIERef(cu_offset, m_die->GetOffset(m_cu)); +} + +dw_tag_t DWARFDIE::TagOrig() const { + if (m_die) + return m_die->TagOrig(); + else + return 0; } dw_tag_t DWARFDIE::Tag() const { @@ -127,7 +135,8 @@ DWARFFormValue form_value; if (m_die->GetAttributeValue(dwarf, cu, attr, form_value, nullptr, check_specification_or_abstract_origin)) - return dwarf->GetDIE(DIERef(form_value)); + return cu->GetMainCU()->GetSymbolFileDWARF() + ->GetDIE(DIERef(form_value)); } return DWARFDIE(); } @@ -159,11 +168,11 @@ DWARFDebugInfoEntry *block_die = nullptr; if (m_die->LookupAddress(file_addr, dwarf, cu, &function_die, &block_die)) { if (block_die && block_die != function_die) { - if (cu->ContainsDIEOffset(block_die->GetOffset())) + if (cu->ContainsDIEOffset(block_die->GetOffset(cu))) return DWARFDIE(cu, block_die); else return DWARFDIE(dwarf->DebugInfo()->GetCompileUnit( - DIERef(cu->GetOffset(), block_die->GetOffset())), + DIERef(cu->GetOffset(), block_die->GetOffset(cu))), block_die); } } @@ -233,7 +242,7 @@ } lldb_private::Type *DWARFDIE::ResolveTypeUID(const DIERef &die_ref) const { - SymbolFileDWARF *dwarf = GetDWARF(); + SymbolFileDWARF *dwarf = GetMainDWARF(); if (dwarf) return dwarf->ResolveTypeUID(dwarf->GetDIE(die_ref), true); else @@ -318,16 +327,17 @@ } dw_offset_t DWARFDIE::GetOffset() const { - if (IsValid()) - return m_die->GetOffset(); - else + if (IsValid()) { + lldbassert(m_cu); + return m_die->GetOffset(m_cu); + } else return DW_INVALID_OFFSET; } dw_offset_t DWARFDIE::GetCompileUnitRelativeOffset() const { - if (IsValid()) - return m_die->GetOffset() - m_cu->GetOffset(); - else + if (IsValid()) { + return m_die->GetOffset(m_cu) - m_cu->GetOffset(); + } else return DW_INVALID_OFFSET; } @@ -338,6 +348,13 @@ return nullptr; } +SymbolFileDWARF *DWARFDIE::GetMainDWARF() const { + if (m_cu) + return m_cu->GetMainCU()->GetSymbolFileDWARF(); + else + return nullptr; +} + lldb_private::TypeSystem *DWARFDIE::GetTypeSystem() const { if (m_cu) return m_cu->GetTypeSystem(); Index: source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h +++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h @@ -12,6 +12,7 @@ #include #include +#include #include "DWARFDIE.h" #include "SymbolFileDWARF.h" @@ -28,7 +29,7 @@ typedef dw_offset_t (*Callback)(SymbolFileDWARF *dwarf2Data, DWARFCompileUnit *cu, DWARFDebugInfoEntry *die, - const dw_offset_t next_offset, + const dw_offset_t next_file_offset, const uint32_t depth, void *userData); DWARFDebugInfo(); @@ -60,6 +61,8 @@ DWARFDebugAranges &GetCompileUnitAranges(); + void InsertCUGetUniqOffset(std::shared_ptr &&cu_sp); + protected: typedef std::shared_ptr DWARFCompileUnitSP; @@ -68,6 +71,12 @@ typedef std::vector CompileUnitColl; + DWARFDebugInfo *DWZRedirect(dw_offset_t &offset); + DWARFCompileUnit *GetCompileUnitInFile(dw_offset_t cu_offset, + uint32_t *idx_ptr); + DWARFCompileUnit *GetCompileUnitContainingDIEOffsetInFile( + dw_offset_t die_offset); + //---------------------------------------------------------------------- // Member variables //---------------------------------------------------------------------- @@ -76,6 +85,12 @@ std::unique_ptr m_cu_aranges_ap; // A quick address to compile unit table + // Last offset after existing files for remapping DW_TAG_partial_unit's. + dw_offset_t m_dwz_uniq_last = DW_INVALID_OFFSET; + // Protect m_compile_units and m_dwz_uniq_last. + // C++14: mutable std::shared_timed_mutex m_dwz_uniq_mutex; + mutable std::recursive_mutex m_dwz_uniq_mutex; + private: // All parsing needs to be done partially any managed by this class as // accessors are called. Index: source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -39,8 +39,29 @@ // SetDwarfData //---------------------------------------------------------------------- void DWARFDebugInfo::SetDwarfData(SymbolFileDWARF *dwarf2Data) { + // C++14: std::lock_guard guard(m_dwz_uniq_mutex); + std::lock_guard guard(m_dwz_uniq_mutex); m_dwarf2Data = dwarf2Data; m_compile_units.clear(); + SymbolFileDWARF *main_symbol_file = m_dwarf2Data; + const DWARFDataExtractor &main_debug_info_data = + main_symbol_file->get_debug_info_data(); + m_dwz_uniq_last = main_debug_info_data.GetByteSize(); + SymbolFileDWARF *dwz_symbol_file = main_symbol_file->GetDWZSymbolFile(); + if (dwz_symbol_file) { + const DWARFDataExtractor &dwz_debug_info_data = + dwz_symbol_file->get_debug_info_data(); + m_dwz_uniq_last += dwz_debug_info_data.GetByteSize(); + } +} + +void DWARFDebugInfo::InsertCUGetUniqOffset(DWARFCompileUnitSP &&cu_sp) { + lldbassert(!m_dwarf2Data->GetIsDWZ()); + // C++14: std::lock_guard guard(m_dwz_uniq_mutex); + std::lock_guard guard(m_dwz_uniq_mutex); + cu_sp->SetOffset(m_dwz_uniq_last); + m_dwz_uniq_last += cu_sp->Size() + cu_sp->GetDebugInfoSize(); + m_compile_units.push_back(std::move(cu_sp)); } DWARFDebugAranges &DWARFDebugInfo::GetCompileUnitAranges() { @@ -74,6 +95,8 @@ for (size_t idx = 0; idx < num_compile_units; ++idx) { DWARFCompileUnit *cu = GetCompileUnitAtIndex(idx); + if (cu->GetMainCU() != cu) + continue; dw_offset_t offset = cu->GetOffset(); if (cus_with_data.find(offset) == cus_with_data.end()) { if (log) { @@ -94,41 +117,51 @@ } void DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded() { - if (m_compile_units.empty()) { - if (m_dwarf2Data != NULL) { - lldb::offset_t offset = 0; - const DWARFDataExtractor &debug_info_data = - m_dwarf2Data->get_debug_info_data(); - while (debug_info_data.ValidOffset(offset)) { - DWARFCompileUnitSP cu_sp(new DWARFCompileUnit(m_dwarf2Data)); - // Out of memory? - if (cu_sp.get() == NULL) - break; - - if (cu_sp->Extract(debug_info_data, &offset) == false) - break; - - m_compile_units.push_back(cu_sp); - - offset = cu_sp->GetNextCompileUnitOffset(); - } + { + // C++14: std::shared_lock guard(m_dwz_uniq_mutex); + std::lock_guard guard(m_dwz_uniq_mutex); + if (!m_compile_units.empty()) + return; + } + if (m_dwarf2Data == NULL) + return; + lldb::offset_t file_offset = 0; + for (;;) { + DWARFCompileUnitSP cu_sp = + DWARFCompileUnit::Extract(m_dwarf2Data, &file_offset); + if (cu_sp.get() == NULL) + break; + + { + // C++14: std::lock_guard + // guard(m_dwz_uniq_mutex); + std::lock_guard guard(m_dwz_uniq_mutex); + m_compile_units.push_back(cu_sp); } + + file_offset = cu_sp->GetNextCompileUnitFileOffset(); } } size_t DWARFDebugInfo::GetNumCompileUnits() { ParseCompileUnitHeadersIfNeeded(); + // C++14: std::shared_lock guard(m_dwz_uniq_mutex); + std::lock_guard guard(m_dwz_uniq_mutex); return m_compile_units.size(); } DWARFCompileUnit *DWARFDebugInfo::GetCompileUnitAtIndex(uint32_t idx) { DWARFCompileUnit *cu = NULL; + // C++14: std::shared_lock guard(m_dwz_uniq_mutex); + std::lock_guard guard(m_dwz_uniq_mutex); if (idx < GetNumCompileUnits()) cu = m_compile_units[idx].get(); return cu; } bool DWARFDebugInfo::ContainsCompileUnit(const DWARFCompileUnit *cu) const { + // C++14: std::shared_lock guard(m_dwz_uniq_mutex); + std::lock_guard guard(m_dwz_uniq_mutex); // Not a verify efficient function, but it is handy for use in assertions // to make sure that a compile unit comes from a debug information file. CompileUnitColl::const_iterator end_pos = m_compile_units.end(); @@ -146,8 +179,28 @@ return offset < cu_sp->GetOffset(); } +DWARFDebugInfo *DWARFDebugInfo::DWZRedirect(dw_offset_t &offset) { + lldbassert(!m_dwarf2Data->GetIsDWZ()); + if (!m_dwarf2Data->GetDWZSymbolFile()) + return this; + SymbolFileDWARF *dwz_symbol_file = m_dwarf2Data->GetDWZSymbolFile(); + const DWARFDataExtractor &dwz_debug_info_data = + dwz_symbol_file->get_debug_info_data(); + auto dwz_debug_info_size = dwz_debug_info_data.GetByteSize(); + if (offset < dwz_debug_info_size) + return dwz_symbol_file->DebugInfo(); + return this; +} + DWARFCompileUnit *DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset, uint32_t *idx_ptr) { + return DWZRedirect(cu_offset)->GetCompileUnitInFile(cu_offset, idx_ptr); +} + +DWARFCompileUnit *DWARFDebugInfo::GetCompileUnitInFile(dw_offset_t cu_offset, + uint32_t *idx_ptr) { + // C++14: std::shared_lock guard(m_dwz_uniq_mutex); + std::lock_guard guard(m_dwz_uniq_mutex); DWARFCompileUnitSP cu_sp; uint32_t cu_idx = DW_INVALID_INDEX; if (cu_offset != DW_INVALID_OFFSET) { @@ -180,7 +233,10 @@ } DWARFCompileUnit *DWARFDebugInfo::GetCompileUnit(const DIERef &die_ref) { - if (die_ref.cu_offset == DW_INVALID_OFFSET) + if (die_ref.cu_offset == DW_INVALID_OFFSET + // FIXME: Workaround default cu_offset = 0 in DIERef ctor. + // Why does GetCompileUnit exist at all? + || (die_ref.cu_offset == 0 && m_dwarf2Data->GetDWZSymbolFile())) return GetCompileUnitContainingDIEOffset(die_ref.die_offset); else return GetCompileUnit(die_ref.cu_offset); @@ -188,8 +244,17 @@ DWARFCompileUnit * DWARFDebugInfo::GetCompileUnitContainingDIEOffset(dw_offset_t die_offset) { + return DWZRedirect(die_offset)->GetCompileUnitContainingDIEOffsetInFile( + die_offset); +} + +DWARFCompileUnit * +DWARFDebugInfo::GetCompileUnitContainingDIEOffsetInFile( + dw_offset_t die_offset) { ParseCompileUnitHeadersIfNeeded(); + // C++14: std::shared_lock guard(m_dwz_uniq_mutex); + std::lock_guard guard(m_dwz_uniq_mutex); DWARFCompileUnitSP cu_sp; // Watch out for single compile unit executable as they are pretty common @@ -246,31 +311,37 @@ void DWARFDebugInfo::Parse(SymbolFileDWARF *dwarf2Data, Callback callback, void *userData) { if (dwarf2Data) { - lldb::offset_t offset = 0; + lldbassert(!dwarf2Data->GetIsDWZ()); + lldb::offset_t file_offset = 0; uint32_t depth = 0; - DWARFCompileUnitSP cu(new DWARFCompileUnit(dwarf2Data)); - if (cu.get() == NULL) - return; DWARFDebugInfoEntry die; - while (cu->Extract(dwarf2Data->get_debug_info_data(), &offset)) { - const dw_offset_t next_cu_offset = cu->GetNextCompileUnitOffset(); + for (;;) { + DWARFCompileUnitSP cu = + DWARFCompileUnit::Extract(dwarf2Data, &file_offset); + if (cu.get() == NULL) + break; + + dw_offset_t next_cu_file_offset = cu->GetNextCompileUnitFileOffset(); depth = 0; // Call the callback function with no DIE pointer for the compile unit - // and get the offset that we are to continue to parse from - offset = callback(dwarf2Data, cu.get(), NULL, offset, depth, userData); + // and get the file_offset that we are to continue to parse from + file_offset = + callback(dwarf2Data, cu.get(), NULL, file_offset, depth, userData); // Make sure we are within our compile unit - if (offset < next_cu_offset) { - // We are in our compile unit, parse starting at the offset + if (file_offset < next_cu_file_offset) { + // We are in our compile unit, parse starting at the file_offset // we were told to parse bool done = false; - while (!done && die.Extract(dwarf2Data, cu.get(), &offset)) { + while (!done && die.Extract(dwarf2Data, cu.get(), &file_offset)) { // Call the callback function with DIE pointer that falls within the // compile unit - offset = - callback(dwarf2Data, cu.get(), &die, offset, depth, userData); + file_offset = callback( + dwarf2Data, cu.get(), &die, file_offset, depth, userData); + + // Missing DWZ support: DW_TAG_imported_unit if (die.IsNULL()) { if (depth) @@ -282,30 +353,24 @@ } } - // Make sure the offset returned is valid, and if not stop parsing. + // Make sure the file_offset returned is valid, and if not stop parsing. // Returning DW_INVALID_OFFSET from this callback is a good way to end // all parsing - if (!dwarf2Data->get_debug_info_data().ValidOffset(offset)) + if (!dwarf2Data->get_debug_info_data().ValidOffset(file_offset)) break; - // See if during the callback anyone retained a copy of the compile - // unit other than ourselves and if so, let whomever did own the object - // and create a new one for our own use! - if (!cu.unique()) - cu.reset(new DWARFCompileUnit(dwarf2Data)); - // Make sure we start on a proper - offset = next_cu_offset; + file_offset = next_cu_file_offset; } } } typedef struct DumpInfo { DumpInfo(Stream *init_strm, uint32_t off, uint32_t depth) - : strm(init_strm), die_offset(off), recurse_depth(depth), + : strm(init_strm), die_file_offset(off), recurse_depth(depth), found_depth(UINT32_MAX), found_die(false), ancestors() {} Stream *strm; - const uint32_t die_offset; + const uint32_t die_file_offset; const uint32_t recurse_depth; uint32_t found_depth; bool found_die; @@ -326,7 +391,7 @@ //---------------------------------------------------------------------- static dw_offset_t DumpCallback(SymbolFileDWARF *dwarf2Data, DWARFCompileUnit *cu, DWARFDebugInfoEntry *die, - const dw_offset_t next_offset, + const dw_offset_t next_file_offset, const uint32_t curr_depth, void *userData) { DumpInfo *dumpInfo = (DumpInfo *)userData; Stream *s = dumpInfo->strm; @@ -335,13 +400,13 @@ if (die) { // Are we dumping everything? - if (dumpInfo->die_offset == DW_INVALID_OFFSET) { + if (dumpInfo->die_file_offset == DW_INVALID_OFFSET) { // Yes we are dumping everything. Obey our recurse level though if (curr_depth < dumpInfo->recurse_depth) die->Dump(dwarf2Data, cu, *s, 0); } else { // We are dumping a specific DIE entry by offset - if (dumpInfo->die_offset == die->GetOffset()) { + if (dumpInfo->die_file_offset == die->GetFileOffset()) { // We found the DIE we were looking for, dump it! if (show_parents) { s->SetIndentLevel(0); @@ -376,7 +441,7 @@ if (dumpInfo->recurse_depth == UINT32_MAX || curr_depth <= dumpInfo->found_depth + dumpInfo->recurse_depth) die->Dump(dwarf2Data, cu, *s, 0); - } else if (dumpInfo->die_offset > die->GetOffset()) { + } else if (dumpInfo->die_file_offset > die->GetFileOffset()) { if (show_parents) dumpInfo->ancestors.back() = *die; } @@ -405,7 +470,7 @@ s->SetIndentLevel(0); // See if we are dumping everything? - if (dumpInfo->die_offset == DW_INVALID_OFFSET) { + if (dumpInfo->die_file_offset == DW_INVALID_OFFSET) { // We are dumping everything if (cu) { cu->Dump(s); @@ -422,15 +487,17 @@ // We are dumping only a single DIE possibly with it's children and // we must find it's compile unit before we can dump it properly - if (cu && dumpInfo->die_offset < cu->GetFirstDIEOffset()) { + if (cu && dumpInfo->die_file_offset + < cu->ThisCUUniqToFileOffset(cu->GetFirstDIEOffset())) { // Not found, maybe the DIE offset provided wasn't correct? // *ostrm_ptr << "DIE at offset " << HEX32 << dumpInfo->die_offset << " // was not found." << endl; return DW_INVALID_OFFSET; } else { // See if the DIE is in this compile unit? - if (cu && dumpInfo->die_offset < cu->GetNextCompileUnitOffset()) { - return next_offset; + if (cu && dumpInfo->die_file_offset + < cu->GetNextCompileUnitFileOffset()) { + return next_file_offset; // // We found our compile unit that contains our DIE, just skip to // dumping the requested DIE... // return dumpInfo->die_offset; @@ -447,7 +514,7 @@ } // Just return the current offset to parse the next CU or DIE entry - return next_offset; + return next_file_offset; } //---------------------------------------------------------------------- @@ -498,6 +565,8 @@ CompileUnitColl::const_iterator pos; uint32_t curr_depth = 0; ParseCompileUnitHeadersIfNeeded(); + // C++14: std::shared_lock guard(m_dwz_uniq_mutex); + std::lock_guard guard(m_dwz_uniq_mutex); for (pos = m_compile_units.begin(); pos != m_compile_units.end(); ++pos) { DWARFCompileUnit *cu = pos->get(); DumpCallback(m_dwarf2Data, cu, NULL, 0, curr_depth, &dumpInfo); Index: source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -56,7 +56,7 @@ typedef offset_collection::const_iterator offset_collection_const_iterator; DWARFDebugInfoEntry() - : m_offset(DW_INVALID_OFFSET), m_parent_idx(0), m_sibling_idx(0), + : m_file_offset(DW_INVALID_OFFSET), m_parent_idx(0), m_sibling_idx(0), m_empty_children(false), m_abbr_idx(0), m_has_children(false), m_tag(0) {} @@ -71,10 +71,10 @@ bool FastExtract(const lldb_private::DWARFDataExtractor &debug_info_data, const DWARFCompileUnit *cu, const DWARFFormValue::FixedFormSizes &fixed_form_sizes, - lldb::offset_t *offset_ptr); + lldb::offset_t *file_offset_ptr); bool Extract(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, - lldb::offset_t *offset_ptr); + lldb::offset_t *file_offset_ptr); bool LookupAddress(const dw_addr_t address, SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, @@ -173,7 +173,7 @@ static void DumpAttribute(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, const lldb_private::DWARFDataExtractor &debug_info_data, - lldb::offset_t *offset_ptr, lldb_private::Stream &s, + lldb::offset_t *file_offset_ptr, lldb_private::Stream &s, dw_attr_t attr, dw_form_t form); // This one dumps the comp unit name, objfile name and die offset for this die // so the stream S. @@ -191,13 +191,19 @@ const DWARFAbbreviationDeclaration * GetAbbreviationDeclarationPtr(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, - lldb::offset_t &offset) const; + lldb::offset_t &file_offset) const; - dw_tag_t Tag() const { return m_tag; } + dw_tag_t TagOrig() const { return m_tag; } + + dw_tag_t Tag() const { + return m_tag != DW_TAG_partial_unit ? m_tag : dw_tag_t(DW_TAG_compile_unit); + } bool IsNULL() const { return m_abbr_idx == 0; } - dw_offset_t GetOffset() const { return m_offset; } + dw_offset_t GetFileOffset() const { return m_file_offset; } + + dw_offset_t GetOffset(const DWARFCompileUnit *cu) const; bool HasChildren() const { return m_has_children; } @@ -277,7 +283,7 @@ protected: dw_offset_t - m_offset; // Offset within the .debug_info of the start of this entry + m_file_offset; // Offset within the .debug_info of the start of this entry uint32_t m_parent_idx; // How many to subtract from "this" to get the parent. // If zero this die has no parent uint32_t m_sibling_idx : 31, // How many to add to "this" to get the sibling. Index: source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -36,12 +36,12 @@ bool DWARFDebugInfoEntry::FastExtract( const DWARFDataExtractor &debug_info_data, const DWARFCompileUnit *cu, const DWARFFormValue::FixedFormSizes &fixed_form_sizes, - lldb::offset_t *offset_ptr) { - m_offset = *offset_ptr; + lldb::offset_t *file_offset_ptr) { + m_file_offset = *file_offset_ptr; m_parent_idx = 0; m_sibling_idx = 0; m_empty_children = false; - const uint64_t abbr_idx = debug_info_data.GetULEB128(offset_ptr); + const uint64_t abbr_idx = debug_info_data.GetULEB128(file_offset_ptr); assert(abbr_idx < (1 << DIE_ABBR_IDX_BITSIZE)); m_abbr_idx = abbr_idx; @@ -49,7 +49,7 @@ // specified! if (m_abbr_idx) { - lldb::offset_t offset = *offset_ptr; + lldb::offset_t file_offset = *file_offset_ptr; const DWARFAbbreviationDeclaration *abbrevDecl = cu->GetAbbreviations()->GetAbbreviationDeclaration(m_abbr_idx); @@ -58,9 +58,9 @@ cu->GetSymbolFileDWARF()->GetObjectFile()->GetModule()->ReportError( "{0x%8.8x}: invalid abbreviation code %u, please file a bug and " "attach the file at the start of this error message", - m_offset, (unsigned)abbr_idx); + m_file_offset, (unsigned)abbr_idx); // WE can't parse anymore if the DWARF is borked... - *offset_ptr = UINT32_MAX; + *file_offset_ptr = UINT32_MAX; return false; } m_tag = abbrevDecl->Tag(); @@ -74,7 +74,7 @@ const uint8_t fixed_skip_size = fixed_form_sizes.GetSize(form); if (fixed_skip_size) - offset += fixed_skip_size; + file_offset += fixed_skip_size; else { bool form_is_indirect = false; do { @@ -85,21 +85,21 @@ // inlined in the .debug_info case DW_FORM_exprloc: case DW_FORM_block: - form_size = debug_info_data.GetULEB128(&offset); + form_size = debug_info_data.GetULEB128(&file_offset); break; case DW_FORM_block1: - form_size = debug_info_data.GetU8_unchecked(&offset); + form_size = debug_info_data.GetU8_unchecked(&file_offset); break; case DW_FORM_block2: - form_size = debug_info_data.GetU16_unchecked(&offset); + form_size = debug_info_data.GetU16_unchecked(&file_offset); break; case DW_FORM_block4: - form_size = debug_info_data.GetU32_unchecked(&offset); + form_size = debug_info_data.GetU32_unchecked(&file_offset); break; // Inlined NULL terminated C-strings case DW_FORM_string: - debug_info_data.GetCStr(&offset); + debug_info_data.GetCStr(&file_offset); break; // Compile unit address sized values @@ -112,6 +112,9 @@ else form_size = cu->IsDWARF64() ? 8 : 4; break; + case DW_FORM_GNU_ref_alt: + form_size = cu->IsDWARF64() ? 8 : 4; + break; // 0 sized form case DW_FORM_flag_present: @@ -150,32 +153,33 @@ case DW_FORM_ref_udata: case DW_FORM_GNU_addr_index: case DW_FORM_GNU_str_index: - debug_info_data.Skip_LEB128(&offset); + debug_info_data.Skip_LEB128(&file_offset); break; case DW_FORM_indirect: form_is_indirect = true; - form = debug_info_data.GetULEB128(&offset); + form = debug_info_data.GetULEB128(&file_offset); break; case DW_FORM_strp: + case DW_FORM_GNU_strp_alt: case DW_FORM_sec_offset: if (cu->IsDWARF64()) - debug_info_data.GetU64(&offset); + debug_info_data.GetU64(&file_offset); else - debug_info_data.GetU32(&offset); + debug_info_data.GetU32(&file_offset); break; default: - *offset_ptr = m_offset; + *file_offset_ptr = m_file_offset; return false; } - offset += form_size; + file_offset += form_size; } while (form_is_indirect); } } - *offset_ptr = offset; + *file_offset_ptr = file_offset; return true; } else { m_tag = 0; @@ -195,19 +199,20 @@ //---------------------------------------------------------------------- bool DWARFDebugInfoEntry::Extract(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, - lldb::offset_t *offset_ptr) { + lldb::offset_t *file_offset_ptr) { const DWARFDataExtractor &debug_info_data = dwarf2Data->get_debug_info_data(); // const DWARFDataExtractor& debug_str_data = // dwarf2Data->get_debug_str_data(); const uint32_t cu_end_offset = cu->GetNextCompileUnitOffset(); - lldb::offset_t offset = *offset_ptr; - // if (offset >= cu_end_offset) + lldb::offset_t file_offset = *file_offset_ptr; + // if (cu->ThisCUFileOffsetToUniq(file_offset) >= cu_end_offset) // Log::Status("DIE at offset 0x%8.8x is beyond the end of the current // compile unit (0x%8.8x)", m_offset, cu_end_offset); - if ((offset < cu_end_offset) && debug_info_data.ValidOffset(offset)) { - m_offset = offset; + if ((cu->ThisCUFileOffsetToUniq(file_offset) < cu_end_offset) + && debug_info_data.ValidOffset(file_offset)) { + m_file_offset = file_offset; - const uint64_t abbr_idx = debug_info_data.GetULEB128(&offset); + const uint64_t abbr_idx = debug_info_data.GetULEB128(&file_offset); assert(abbr_idx < (1 << DIE_ABBR_IDX_BITSIZE)); m_abbr_idx = abbr_idx; if (abbr_idx) { @@ -233,7 +238,7 @@ if (isCompileUnitTag && ((attr == DW_AT_entry_pc) || (attr == DW_AT_low_pc))) { DWARFFormValue form_value(cu, form); - if (form_value.ExtractValue(debug_info_data, &offset)) { + if (form_value.ExtractValue(debug_info_data, &file_offset)) { if (attr == DW_AT_low_pc || attr == DW_AT_entry_pc) const_cast(cu)->SetBaseAddress( form_value.Address()); @@ -249,21 +254,21 @@ // inlined in the .debug_info case DW_FORM_exprloc: case DW_FORM_block: - form_size = debug_info_data.GetULEB128(&offset); + form_size = debug_info_data.GetULEB128(&file_offset); break; case DW_FORM_block1: - form_size = debug_info_data.GetU8(&offset); + form_size = debug_info_data.GetU8(&file_offset); break; case DW_FORM_block2: - form_size = debug_info_data.GetU16(&offset); + form_size = debug_info_data.GetU16(&file_offset); break; case DW_FORM_block4: - form_size = debug_info_data.GetU32(&offset); + form_size = debug_info_data.GetU32(&file_offset); break; // Inlined NULL terminated C-strings case DW_FORM_string: - debug_info_data.GetCStr(&offset); + debug_info_data.GetCStr(&file_offset); break; // Compile unit address sized values @@ -276,6 +281,9 @@ else form_size = cu->IsDWARF64() ? 8 : 4; break; + case DW_FORM_GNU_ref_alt: + form_size = cu->IsDWARF64() ? 8 : 4; + break; // 0 sized form case DW_FORM_flag_present: @@ -314,38 +322,39 @@ case DW_FORM_ref_udata: case DW_FORM_GNU_addr_index: case DW_FORM_GNU_str_index: - debug_info_data.Skip_LEB128(&offset); + debug_info_data.Skip_LEB128(&file_offset); break; case DW_FORM_indirect: - form = debug_info_data.GetULEB128(&offset); + form = debug_info_data.GetULEB128(&file_offset); form_is_indirect = true; break; case DW_FORM_strp: + case DW_FORM_GNU_strp_alt: case DW_FORM_sec_offset: if (cu->IsDWARF64()) - debug_info_data.GetU64(&offset); + debug_info_data.GetU64(&file_offset); else - debug_info_data.GetU32(&offset); + debug_info_data.GetU32(&file_offset); break; default: - *offset_ptr = offset; + *file_offset_ptr = file_offset; return false; } - offset += form_size; + file_offset += form_size; } while (form_is_indirect); } } - *offset_ptr = offset; + *file_offset_ptr = file_offset; return true; } } else { m_tag = 0; m_has_children = false; - *offset_ptr = offset; + *file_offset_ptr = file_offset; return true; // NULL debug tag entry } } @@ -384,6 +393,9 @@ int &call_column, DWARFExpression *frame_base) const { if (dwarf2Data == nullptr) return false; + // DIERef(DWARFFormValue)->DWARFFormValue::Reference() may need + // FileOffsetToUniqOffset. + dwarf2Data->PreloadSymbols(); SymbolFileDWARFDwo *dwo_symbol_file = cu->GetDwoSymbolFile(); if (dwo_symbol_file) @@ -397,9 +409,9 @@ std::vector die_refs; bool set_frame_base_loclist_addr = false; - lldb::offset_t offset; + lldb::offset_t file_offset; const DWARFAbbreviationDeclaration *abbrevDecl = - GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset); + GetAbbreviationDeclarationPtr(dwarf2Data, cu, file_offset); lldb::ModuleSP module = dwarf2Data->GetObjectFile()->GetModule(); @@ -407,7 +419,7 @@ const DWARFDataExtractor &debug_info_data = dwarf2Data->get_debug_info_data(); - if (!debug_info_data.ValidOffset(offset)) + if (!debug_info_data.ValidOffset(file_offset)) return false; const uint32_t numAttributes = abbrevDecl->NumAttributes(); @@ -419,7 +431,7 @@ for (i = 0; i < numAttributes; ++i) { abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form); DWARFFormValue form_value(cu, form); - if (form_value.ExtractValue(debug_info_data, &offset)) { + if (form_value.ExtractValue(debug_info_data, &file_offset)) { switch (attr) { case DW_AT_low_pc: lo_pc = form_value.Address(); @@ -460,7 +472,7 @@ "{0x%8.8x}: DIE has DW_AT_ranges(0x%" PRIx64 ") attribute yet DWARF has no .debug_ranges, please file a bug " "and attach the file at the start of this error message", - m_offset, form_value.Unsigned()); + m_file_offset, form_value.Unsigned()); } } break; @@ -568,7 +580,8 @@ if (ranges.IsEmpty() || name == NULL || mangled == NULL) { for (const DIERef &die_ref : die_refs) { if (die_ref.die_offset != DW_INVALID_OFFSET) { - DWARFDIE die = dwarf2Data->GetDIE(die_ref); + DWARFDIE die = cu->GetMainCU()->GetSymbolFileDWARF() + ->GetDIE(die_ref); if (die) die.GetDIE()->GetDIENamesAndRanges( die.GetDWARF(), die.GetCU(), name, mangled, ranges, decl_file, @@ -589,12 +602,12 @@ const DWARFCompileUnit *cu, Stream &s, uint32_t recurse_depth) const { const DWARFDataExtractor &debug_info_data = dwarf2Data->get_debug_info_data(); - lldb::offset_t offset = m_offset; + lldb::offset_t file_offset = m_file_offset; - if (debug_info_data.ValidOffset(offset)) { - dw_uleb128_t abbrCode = debug_info_data.GetULEB128(&offset); + if (debug_info_data.ValidOffset(file_offset)) { + dw_uleb128_t abbrCode = debug_info_data.GetULEB128(&file_offset); - s.Printf("\n0x%8.8x: ", m_offset); + s.Printf("\n0x%8.8x: ", m_file_offset); s.Indent(); if (abbrCode != m_abbr_idx) { s.Printf("error: DWARF has been modified\n"); @@ -614,7 +627,7 @@ for (i = 0; i < numAttributes; ++i) { abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form); - DumpAttribute(dwarf2Data, cu, debug_info_data, &offset, s, attr, + DumpAttribute(dwarf2Data, cu, debug_info_data, &file_offset, s, attr, form); } @@ -651,7 +664,8 @@ obj_file->GetFileSpec().GetFilename().AsCString(""); const char *die_name = GetName(dwarf2Data, cu); s.Printf("0x%8.8x/0x%8.8x: %-30s (from %s in %s)", cu->GetOffset(), - GetOffset(), die_name ? die_name : "", cu_name ? cu_name : "", + GetFileOffset(), die_name ? die_name : "", + cu_name ? cu_name : "", obj_file_name ? obj_file_name : ""); } @@ -664,7 +678,7 @@ //---------------------------------------------------------------------- void DWARFDebugInfoEntry::DumpAttribute( SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, - const DWARFDataExtractor &debug_info_data, lldb::offset_t *offset_ptr, + const DWARFDataExtractor &debug_info_data, lldb::offset_t *file_offset_ptr, Stream &s, dw_attr_t attr, dw_form_t form) { bool show_form = s.GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowForm); @@ -677,7 +691,7 @@ DWARFFormValue form_value(cu, form); - if (!form_value.ExtractValue(debug_info_data, offset_ptr)) + if (!form_value.ExtractValue(debug_info_data, file_offset_ptr)) return; if (show_form) { @@ -710,9 +724,9 @@ const uint8_t *blockData = form_value.BlockData(); if (blockData) { // Location description is inlined in data in the form value - DWARFDataExtractor locationData(debug_info_data, - (*offset_ptr) - form_value.Unsigned(), - form_value.Unsigned()); + DWARFDataExtractor locationData( + debug_info_data, (*file_offset_ptr) - form_value.Unsigned(), + form_value.Unsigned()); DWARFExpression::PrintDWARFExpression( s, locationData, DWARFCompileUnit::GetAddressByteSize(cu), 4, false); } else { @@ -768,7 +782,7 @@ DWARFAttributes &attributes, uint32_t curr_depth) const { SymbolFileDWARF *dwarf2Data = nullptr; const DWARFAbbreviationDeclaration *abbrevDecl = nullptr; - lldb::offset_t offset = 0; + lldb::offset_t file_offset = 0; if (cu) { if (m_tag != DW_TAG_compile_unit) { SymbolFileDWARFDwo *dwo_symbol_file = cu->GetDwoSymbolFile(); @@ -778,7 +792,7 @@ } dwarf2Data = cu->GetSymbolFileDWARF(); - abbrevDecl = GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset); + abbrevDecl = GetAbbreviationDeclarationPtr(dwarf2Data, cu, file_offset); } if (abbrevDecl) { @@ -810,13 +824,14 @@ } LLVM_FALLTHROUGH; default: - attributes.Append(cu, offset, attr, form); + attributes.Append( + cu, cu->ThisCUFileOffsetToUniq(file_offset), attr, form); break; } if ((attr == DW_AT_specification) || (attr == DW_AT_abstract_origin)) { DWARFFormValue form_value(cu, form); - if (form_value.ExtractValue(debug_info_data, &offset)) { + if (form_value.ExtractValue(debug_info_data, &file_offset)) { dw_offset_t die_offset = form_value.Reference(); DWARFDIE spec_die = const_cast(cu)->GetDIE(die_offset); @@ -826,9 +841,9 @@ } else { const uint8_t fixed_skip_size = fixed_form_sizes.GetSize(form); if (fixed_skip_size) - offset += fixed_skip_size; + file_offset += fixed_skip_size; else - DWARFFormValue::SkipValue(form, debug_info_data, &offset, cu); + DWARFFormValue::SkipValue(form, debug_info_data, &file_offset, cu); } } } else { @@ -856,9 +871,9 @@ attr, form_value, end_attr_offset_ptr, check_specification_or_abstract_origin); - lldb::offset_t offset; + lldb::offset_t file_offset; const DWARFAbbreviationDeclaration *abbrevDecl = - GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset); + GetAbbreviationDeclarationPtr(dwarf2Data, cu, file_offset); if (abbrevDecl) { uint32_t attr_idx = abbrevDecl->FindAttributeIndex(attr); @@ -870,14 +885,14 @@ uint32_t idx = 0; while (idx < attr_idx) DWARFFormValue::SkipValue(abbrevDecl->GetFormByIndex(idx++), - debug_info_data, &offset, cu); + debug_info_data, &file_offset, cu); - const dw_offset_t attr_offset = offset; + const dw_offset_t attr_offset = file_offset; form_value.SetCompileUnit(cu); form_value.SetForm(abbrevDecl->GetFormByIndex(idx)); - if (form_value.ExtractValue(debug_info_data, &offset)) { + if (form_value.ExtractValue(debug_info_data, &file_offset)) { if (end_attr_offset_ptr) - *end_attr_offset_ptr = offset; + *end_attr_offset_ptr = file_offset; return attr_offset; } } @@ -1199,8 +1214,8 @@ } DWARFDebugInfoEntry die; - lldb::offset_t offset = die_offset; - if (die.Extract(dwarf2Data, cu, &offset)) { + lldb::offset_t file_offset = cu->ThisCUUniqToFileOffset(die_offset); + if (die.Extract(dwarf2Data, cu, &file_offset)) { if (die.IsNULL()) { s.PutCString("NULL"); return true; @@ -1211,7 +1226,7 @@ else { bool result = true; const DWARFAbbreviationDeclaration *abbrevDecl = - die.GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset); + die.GetAbbreviationDeclarationPtr(dwarf2Data, cu, file_offset); if (abbrevDecl == NULL) return false; @@ -1320,7 +1335,7 @@ void DWARFDebugInfoEntry::BuildAddressRangeTable( SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, DWARFDebugAranges *debug_aranges) const { - if (m_tag) { + if (m_tag && m_tag != DW_TAG_partial_unit) { if (m_tag == DW_TAG_subprogram) { dw_addr_t lo_pc = LLDB_INVALID_ADDRESS; dw_addr_t hi_pc = LLDB_INVALID_ADDRESS; @@ -1359,7 +1374,7 @@ LLDB_INVALID_ADDRESS)) { // printf("BuildAddressRangeTable() 0x%8.8x: [0x%16.16" PRIx64 " - // 0x%16.16" PRIx64 ")\n", m_offset, lo_pc, hi_pc); // DEBUG ONLY - debug_aranges->AppendRange(GetOffset(), lo_pc, hi_pc); + debug_aranges->AppendRange(GetOffset(cu), lo_pc, hi_pc); } } @@ -1773,9 +1788,9 @@ const DWARFAbbreviationDeclaration * DWARFDebugInfoEntry::GetAbbreviationDeclarationPtr( SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, - lldb::offset_t &offset) const { + lldb::offset_t &file_offset) const { if (dwarf2Data) { - offset = GetOffset(); + file_offset = GetFileOffset(); const DWARFAbbreviationDeclarationSet *abbrev_set = cu->GetAbbreviations(); if (abbrev_set) { @@ -1786,7 +1801,7 @@ // the DWARF data was mmap'ed, the backing file might have been modified // which is bad news. const uint64_t abbrev_code = - dwarf2Data->get_debug_info_data().GetULEB128(&offset); + dwarf2Data->get_debug_info_data().GetULEB128(&file_offset); if (abbrev_decl->Code() == abbrev_code) return abbrev_decl; @@ -1794,17 +1809,18 @@ dwarf2Data->GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( "0x%8.8x: the DWARF debug information has been modified (abbrev " "code was %u, and is now %u)", - GetOffset(), (uint32_t)abbrev_decl->Code(), (uint32_t)abbrev_code); + GetFileOffset(), (uint32_t)abbrev_decl->Code(), + (uint32_t)abbrev_code); } } } - offset = DW_INVALID_OFFSET; + file_offset = DW_INVALID_OFFSET; return NULL; } bool DWARFDebugInfoEntry::OffsetLessThan(const DWARFDebugInfoEntry &a, const DWARFDebugInfoEntry &b) { - return a.GetOffset() < b.GetOffset(); + return a.GetFileOffset() < b.GetFileOffset(); } void DWARFDebugInfoEntry::DumpDIECollection( @@ -1818,10 +1834,14 @@ const DWARFDebugInfoEntry *p = die_ref.GetParent(); const DWARFDebugInfoEntry *s = die_ref.GetSibling(); const DWARFDebugInfoEntry *c = die_ref.GetFirstChild(); - strm.Printf("%.8x: %.8x %.8x %.8x 0x%4.4x %s%s\n", die_ref.GetOffset(), - p ? p->GetOffset() : 0, s ? s->GetOffset() : 0, - c ? c->GetOffset() : 0, die_ref.Tag(), + strm.Printf("%.8x: %.8x %.8x %.8x 0x%4.4x %s%s\n", die_ref.GetFileOffset(), + p ? p->GetFileOffset() : 0, s ? s->GetFileOffset() : 0, + c ? c->GetFileOffset() : 0, die_ref.Tag(), DW_TAG_value_to_name(die_ref.Tag()), die_ref.HasChildren() ? " *" : ""); } } + +dw_offset_t DWARFDebugInfoEntry::GetOffset(const DWARFCompileUnit *cu) const { + return cu->ThisCUFileOffsetToUniq(m_file_offset); +} Index: source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp @@ -76,7 +76,10 @@ DWARFFormValue::GetFixedFormSizesForAddressSize( cu->GetAddressByteSize(), cu->IsDWARF64()); - bool clear_dies = cu->ExtractDIEsIfNeeded(false) > 1; + bool clear_dies = cu->ExtractDIEsIfNeeded( + DWARFCompileUnit::ExtractDIEsIfNeededKind::AllDies) > 1; + // In DW_TAG_partial_unit by DWZ cannot be DW_TAG_subprogram definition + // (see DWZ checksum_die). But there can be DW_TAG_variable. DWARFDIECollection dies; const size_t die_count = cu->AppendDIEsWithTag(DW_TAG_subprogram, dies) + Index: source/Plugins/SymbolFile/DWARF/DWARFFileOffset.h =================================================================== --- /dev/null +++ source/Plugins/SymbolFile/DWARF/DWARFFileOffset.h @@ -0,0 +1,53 @@ + +//===-- DWARFFileOffset.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef SymbolFileDWARF_DWARFFileOffset_h_ +#define SymbolFileDWARF_DWARFFileOffset_h_ + +#include "lldb/Core/dwarf.h" +#include "lldb/Utility/LLDBAssert.h" + +class DWARFCompileUnitData; +class DWARFCompileUnit; + +class DWARFFileOffset { +public: + DWARFFileOffset() : m_file_offset(DW_INVALID_OFFSET) {} + DWARFFileOffset(dw_offset_t file_offset, bool is_dwz) + : m_file_offset(file_offset), m_is_dwz(is_dwz) {} + DWARFFileOffset(DWARFCompileUnitData *cudata); + DWARFFileOffset(DWARFCompileUnit *cu); + dw_offset_t GetFileOffset() const { + lldbassert(m_file_offset != DW_INVALID_OFFSET); + return m_file_offset; + } + bool GetIsDWZ() const { + lldbassert(m_file_offset != DW_INVALID_OFFSET); + return m_is_dwz; + } + explicit operator bool() const { return m_file_offset != DW_INVALID_OFFSET; } + + friend class Less; + struct Less { + bool operator()(const DWARFFileOffset &a, const DWARFFileOffset &b) const { + if (a.m_is_dwz != b.m_is_dwz) + return a.m_is_dwz < b.m_is_dwz; + if (a.m_file_offset != b.m_file_offset) + return a.m_file_offset < b.m_file_offset; + return false; + } + }; + +protected: + dw_offset_t m_file_offset; + bool m_is_dwz; +}; + +#endif // SymbolFileDWARF_DWARFFileOffset_h_ Index: source/Plugins/SymbolFile/DWARF/DWARFFileOffset.cpp =================================================================== --- /dev/null +++ source/Plugins/SymbolFile/DWARF/DWARFFileOffset.cpp @@ -0,0 +1,18 @@ +//===-- DWARFFileOffset.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFFileOffset.h" +#include "DWARFCompileUnit.h" + +DWARFFileOffset::DWARFFileOffset(DWARFCompileUnitData *cudata) + : m_file_offset(cudata->m_file_offset), + m_is_dwz(cudata->m_dwarf2Data->GetIsDWZ()) {} + +DWARFFileOffset::DWARFFileOffset(DWARFCompileUnit *cu) + : DWARFFileOffset(cu->m_data) {} Index: source/Plugins/SymbolFile/DWARF/DWARFFormValue.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFFormValue.h +++ source/Plugins/SymbolFile/DWARF/DWARFFormValue.h @@ -14,6 +14,7 @@ #include // for NULL class DWARFCompileUnit; +class DWARFFileOffset; class DWARFFormValue { public: @@ -63,8 +64,9 @@ const ValueType &Value() const { return m_value; } void Dump(lldb_private::Stream &s) const; bool ExtractValue(const lldb_private::DWARFDataExtractor &data, - lldb::offset_t *offset_ptr); + lldb::offset_t *file_offset_ptr); const uint8_t *BlockData() const; + DWARFFileOffset ReferenceInFile() const; uint64_t Reference() const; uint64_t Reference(dw_offset_t offset) const; bool Boolean() const { return m_value.value.uval != 0; } @@ -76,10 +78,11 @@ dw_addr_t Address() const; bool IsValid() const { return m_form != 0; } bool SkipValue(const lldb_private::DWARFDataExtractor &debug_info_data, - lldb::offset_t *offset_ptr) const; + lldb::offset_t *file_offset_ptr) const; static bool SkipValue(const dw_form_t form, const lldb_private::DWARFDataExtractor &debug_info_data, - lldb::offset_t *offset_ptr, const DWARFCompileUnit *cu); + lldb::offset_t *file_offset_ptr, + const DWARFCompileUnit *cu); static bool IsBlockForm(const dw_form_t form); static bool IsDataForm(const dw_form_t form); static FixedFormSizes GetFixedFormSizesForAddressSize(uint8_t addr_size, Index: source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -11,9 +11,12 @@ #include "lldb/Core/dwarf.h" #include "lldb/Utility/Stream.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Core/Module.h" #include "DWARFCompileUnit.h" #include "DWARFFormValue.h" +#include "DWARFDebugInfo.h" class DWARFCompileUnit; @@ -164,7 +167,7 @@ } bool DWARFFormValue::ExtractValue(const DWARFDataExtractor &data, - lldb::offset_t *offset_ptr) { + lldb::offset_t *file_offset_ptr) { bool indirect = false; bool is_block = false; m_value.data = NULL; @@ -177,54 +180,55 @@ case DW_FORM_addr: assert(m_cu); m_value.value.uval = data.GetMaxU64( - offset_ptr, DWARFCompileUnit::GetAddressByteSize(m_cu)); + file_offset_ptr, DWARFCompileUnit::GetAddressByteSize(m_cu)); break; case DW_FORM_block2: - m_value.value.uval = data.GetU16(offset_ptr); + m_value.value.uval = data.GetU16(file_offset_ptr); is_block = true; break; case DW_FORM_block4: - m_value.value.uval = data.GetU32(offset_ptr); + m_value.value.uval = data.GetU32(file_offset_ptr); is_block = true; break; case DW_FORM_data2: - m_value.value.uval = data.GetU16(offset_ptr); + m_value.value.uval = data.GetU16(file_offset_ptr); break; case DW_FORM_data4: - m_value.value.uval = data.GetU32(offset_ptr); + m_value.value.uval = data.GetU32(file_offset_ptr); break; case DW_FORM_data8: - m_value.value.uval = data.GetU64(offset_ptr); + m_value.value.uval = data.GetU64(file_offset_ptr); break; case DW_FORM_string: - m_value.value.cstr = data.GetCStr(offset_ptr); + m_value.value.cstr = data.GetCStr(file_offset_ptr); break; case DW_FORM_exprloc: case DW_FORM_block: - m_value.value.uval = data.GetULEB128(offset_ptr); + m_value.value.uval = data.GetULEB128(file_offset_ptr); is_block = true; break; case DW_FORM_block1: - m_value.value.uval = data.GetU8(offset_ptr); + m_value.value.uval = data.GetU8(file_offset_ptr); is_block = true; break; case DW_FORM_data1: - m_value.value.uval = data.GetU8(offset_ptr); + m_value.value.uval = data.GetU8(file_offset_ptr); break; case DW_FORM_flag: - m_value.value.uval = data.GetU8(offset_ptr); + m_value.value.uval = data.GetU8(file_offset_ptr); break; case DW_FORM_sdata: - m_value.value.sval = data.GetSLEB128(offset_ptr); + m_value.value.sval = data.GetSLEB128(file_offset_ptr); break; case DW_FORM_strp: + case DW_FORM_GNU_strp_alt: assert(m_cu); - m_value.value.uval = - data.GetMaxU64(offset_ptr, DWARFCompileUnit::IsDWARF64(m_cu) ? 8 : 4); + m_value.value.uval = data.GetMaxU64( + file_offset_ptr, DWARFCompileUnit::IsDWARF64(m_cu) ? 8 : 4); break; // case DW_FORM_APPLE_db_str: case DW_FORM_udata: - m_value.value.uval = data.GetULEB128(offset_ptr); + m_value.value.uval = data.GetULEB128(file_offset_ptr); break; case DW_FORM_ref_addr: assert(m_cu); @@ -233,44 +237,49 @@ ref_addr_size = m_cu->GetAddressByteSize(); else ref_addr_size = m_cu->IsDWARF64() ? 8 : 4; - m_value.value.uval = data.GetMaxU64(offset_ptr, ref_addr_size); + m_value.value.uval = data.GetMaxU64(file_offset_ptr, ref_addr_size); break; case DW_FORM_ref1: - m_value.value.uval = data.GetU8(offset_ptr); + m_value.value.uval = data.GetU8(file_offset_ptr); break; case DW_FORM_ref2: - m_value.value.uval = data.GetU16(offset_ptr); + m_value.value.uval = data.GetU16(file_offset_ptr); break; case DW_FORM_ref4: - m_value.value.uval = data.GetU32(offset_ptr); + m_value.value.uval = data.GetU32(file_offset_ptr); break; case DW_FORM_ref8: - m_value.value.uval = data.GetU64(offset_ptr); + m_value.value.uval = data.GetU64(file_offset_ptr); break; case DW_FORM_ref_udata: - m_value.value.uval = data.GetULEB128(offset_ptr); + m_value.value.uval = data.GetULEB128(file_offset_ptr); + break; + case DW_FORM_GNU_ref_alt: + assert(m_cu); + ref_addr_size = m_cu->IsDWARF64() ? 8 : 4; + m_value.value.uval = data.GetMaxU64(file_offset_ptr, ref_addr_size); break; case DW_FORM_indirect: - m_form = data.GetULEB128(offset_ptr); + m_form = data.GetULEB128(file_offset_ptr); indirect = true; break; case DW_FORM_sec_offset: assert(m_cu); - m_value.value.uval = - data.GetMaxU64(offset_ptr, DWARFCompileUnit::IsDWARF64(m_cu) ? 8 : 4); + m_value.value.uval = data.GetMaxU64( + file_offset_ptr, DWARFCompileUnit::IsDWARF64(m_cu) ? 8 : 4); break; case DW_FORM_flag_present: m_value.value.uval = 1; break; case DW_FORM_ref_sig8: - m_value.value.uval = data.GetU64(offset_ptr); + m_value.value.uval = data.GetU64(file_offset_ptr); break; case DW_FORM_GNU_str_index: - m_value.value.uval = data.GetULEB128(offset_ptr); + m_value.value.uval = data.GetULEB128(file_offset_ptr); break; case DW_FORM_GNU_addr_index: - m_value.value.uval = data.GetULEB128(offset_ptr); + m_value.value.uval = data.GetULEB128(file_offset_ptr); break; default: return false; @@ -279,9 +288,9 @@ } while (indirect); if (is_block) { - m_value.data = data.PeekData(*offset_ptr, m_value.value.uval); + m_value.data = data.PeekData(*file_offset_ptr, m_value.value.uval); if (m_value.data != NULL) { - *offset_ptr += m_value.value.uval; + *file_offset_ptr += m_value.value.uval; } } @@ -289,13 +298,14 @@ } bool DWARFFormValue::SkipValue(const DWARFDataExtractor &debug_info_data, - lldb::offset_t *offset_ptr) const { - return DWARFFormValue::SkipValue(m_form, debug_info_data, offset_ptr, m_cu); + lldb::offset_t *file_offset_ptr) const { + return DWARFFormValue::SkipValue( + m_form, debug_info_data, file_offset_ptr, m_cu); } bool DWARFFormValue::SkipValue(dw_form_t form, const DWARFDataExtractor &debug_info_data, - lldb::offset_t *offset_ptr, + lldb::offset_t *file_offset_ptr, const DWARFCompileUnit *cu) { uint8_t ref_addr_size; switch (form) { @@ -303,34 +313,34 @@ // inlined in the .debug_info case DW_FORM_exprloc: case DW_FORM_block: { - dw_uleb128_t size = debug_info_data.GetULEB128(offset_ptr); - *offset_ptr += size; + dw_uleb128_t size = debug_info_data.GetULEB128(file_offset_ptr); + *file_offset_ptr += size; } return true; case DW_FORM_block1: { - dw_uleb128_t size = debug_info_data.GetU8(offset_ptr); - *offset_ptr += size; + dw_uleb128_t size = debug_info_data.GetU8(file_offset_ptr); + *file_offset_ptr += size; } return true; case DW_FORM_block2: { - dw_uleb128_t size = debug_info_data.GetU16(offset_ptr); - *offset_ptr += size; + dw_uleb128_t size = debug_info_data.GetU16(file_offset_ptr); + *file_offset_ptr += size; } return true; case DW_FORM_block4: { - dw_uleb128_t size = debug_info_data.GetU32(offset_ptr); - *offset_ptr += size; + dw_uleb128_t size = debug_info_data.GetU32(file_offset_ptr); + *file_offset_ptr += size; } return true; // Inlined NULL terminated C-strings case DW_FORM_string: - debug_info_data.GetCStr(offset_ptr); + debug_info_data.GetCStr(file_offset_ptr); return true; // Compile unit address sized values case DW_FORM_addr: - *offset_ptr += DWARFCompileUnit::GetAddressByteSize(cu); + *file_offset_ptr += DWARFCompileUnit::GetAddressByteSize(cu); return true; case DW_FORM_ref_addr: @@ -341,7 +351,14 @@ ref_addr_size = cu->GetAddressByteSize(); else ref_addr_size = cu->IsDWARF64() ? 8 : 4; - *offset_ptr += ref_addr_size; + *file_offset_ptr += ref_addr_size; + return true; + + case DW_FORM_GNU_ref_alt: + assert(cu); // CU must be valid for DW_FORM_GNU_ref_alt objects or we will get + // this wrong + ref_addr_size = cu->IsDWARF64() ? 8 : 4; + *file_offset_ptr += ref_addr_size; return true; // 0 bytes values (implied from DW_FORM) @@ -352,33 +369,34 @@ case DW_FORM_data1: case DW_FORM_flag: case DW_FORM_ref1: - *offset_ptr += 1; + *file_offset_ptr += 1; return true; // 2 byte values case DW_FORM_data2: case DW_FORM_ref2: - *offset_ptr += 2; + *file_offset_ptr += 2; return true; // 32 bit for DWARF 32, 64 for DWARF 64 case DW_FORM_sec_offset: case DW_FORM_strp: + case DW_FORM_GNU_strp_alt: assert(cu); - *offset_ptr += (cu->IsDWARF64() ? 8 : 4); + *file_offset_ptr += (cu->IsDWARF64() ? 8 : 4); return true; // 4 byte values case DW_FORM_data4: case DW_FORM_ref4: - *offset_ptr += 4; + *file_offset_ptr += 4; return true; // 8 byte values case DW_FORM_data8: case DW_FORM_ref8: case DW_FORM_ref_sig8: - *offset_ptr += 8; + *file_offset_ptr += 8; return true; // signed or unsigned LEB 128 values @@ -387,13 +405,13 @@ case DW_FORM_ref_udata: case DW_FORM_GNU_addr_index: case DW_FORM_GNU_str_index: - debug_info_data.Skip_LEB128(offset_ptr); + debug_info_data.Skip_LEB128(file_offset_ptr); return true; case DW_FORM_indirect: { - dw_form_t indirect_form = debug_info_data.GetULEB128(offset_ptr); - return DWARFFormValue::SkipValue(indirect_form, debug_info_data, offset_ptr, - cu); + dw_form_t indirect_form = debug_info_data.GetULEB128(file_offset_ptr); + return DWARFFormValue::SkipValue(indirect_form, debug_info_data, + file_offset_ptr, cu); } default: @@ -505,6 +523,13 @@ case DW_FORM_ref_udata: cu_relative_offset = true; break; + case DW_FORM_GNU_ref_alt: { + assert(m_cu); // CU must be valid for DW_FORM_GNU_ref_alt objects or we will + // get this wrong + s.Address(uvalue, 4 * 2); // 4 for DWARF32, 8 for DWARF64, but we don't + // support DWARF64 yet + break; + } // All DW_FORM_indirect attributes should be resolved prior to calling this // function @@ -545,6 +570,16 @@ symbol_file->get_debug_str_offsets_data().GetMaxU64(&offset, index_size); return symbol_file->get_debug_str_data().PeekCStr(str_offset); + } else if (m_form == DW_FORM_GNU_strp_alt) { + SymbolFileDWARF *dwz_symbol_file = symbol_file->GetDWZSymbolFile(); + if (!dwz_symbol_file) { + symbol_file->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->get_debug_str_data().PeekCStr(m_value.value.uval); } return nullptr; } @@ -567,24 +602,34 @@ return symbol_file->get_debug_addr_data().GetMaxU64(&offset, index_size); } -uint64_t DWARFFormValue::Reference() const { - uint64_t die_offset = m_value.value.uval; +DWARFFileOffset DWARFFormValue::ReferenceInFile() const { + uint64_t die_file_offset = m_value.value.uval; + assert(m_cu); + bool is_dwz = m_cu->GetSymbolFileDWARF()->GetIsDWZ();; switch (m_form) { case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_udata: - assert(m_cu); // CU must be valid for DW_FORM_ref forms that are compile - // unit relative or we will get this wrong - die_offset += m_cu->GetOffset(); + die_file_offset += m_cu->GetFileOffset(); + break; + + case DW_FORM_GNU_ref_alt: // DWZ + is_dwz = true; break; + case DW_FORM_ref_addr: default: break; } - return die_offset; + return DWARFFileOffset(die_file_offset, is_dwz); +} + +uint64_t DWARFFormValue::Reference() const { + DWARFFileOffset file = ReferenceInFile(); + return m_cu->FileOffsetToUniqOffset(file); } uint64_t DWARFFormValue::Reference(dw_offset_t base_offset) const { @@ -707,6 +752,7 @@ case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_udata: { + case DW_FORM_GNU_ref_alt: // DWZ uint64_t a = a_value.Reference(); uint64_t b = b_value.Reference(); if (a < b) @@ -755,6 +801,8 @@ case DW_FORM_ref_sig8: case DW_FORM_GNU_str_index: case DW_FORM_GNU_addr_index: + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: return true; default: break; Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -18,6 +18,8 @@ #include #include #include +#include +#include // Other libraries and framework includes #include "llvm/ADT/DenseMap.h" @@ -62,6 +64,7 @@ class SymbolFileDWARFDebugMap; class SymbolFileDWARFDwo; class SymbolFileDWARFDwp; +class DWARFCompileUnitData; #define DIE_IS_BEING_PARSED ((lldb_private::Type *)1) @@ -251,6 +254,7 @@ const lldb_private::DWARFDataExtractor &get_apple_types_data(); const lldb_private::DWARFDataExtractor &get_apple_namespaces_data(); const lldb_private::DWARFDataExtractor &get_apple_objc_data(); + const lldb_private::DWARFDataExtractor &get_gnu_debugaltlink(); DWARFDebugAbbrev *DebugAbbrev(); @@ -304,6 +308,14 @@ // the method returns a pointer to the base compile unit. virtual DWARFCompileUnit *GetBaseCompileUnit(); + DWARFCompileUnitData *NewCompileUnitData(); + SymbolFileDWARF *GetDWZSymbolFile() const { + if (!m_dwz_common_file) + return nullptr; + return m_dwz_common_file->SymbolFile(); + } + bool GetIsDWZ() const { return m_is_dwz; } + protected: typedef llvm::DenseMap DIEToTypePtr; @@ -468,6 +480,47 @@ SymbolFileDWARFDwp *GetDwpSymbolFile(); + void InitializeDWZ(); + + class DWZCommonFile { + public: + // C++14: Use heterogenous lookup. + DWZCommonFile(const lldb_private::FileSpec &filespec_ref); + DWZCommonFile(std::unique_ptr &&symbol_file, + lldb::ObjectFileSP &&obj_file, lldb::ModuleSP &&module); + SymbolFileDWARF *SymbolFile() const { return m_symbol_file.get(); } + + bool operator==(const DWZCommonFile &rhs) const { + return m_filespec_ref == rhs.m_filespec_ref; + } + bool operator!=(const DWZCommonFile &rhs) const { return !(*this == rhs); } + class Hasher { + public: + size_t operator()(const DWZCommonFile &key) const { + return lldb_private::FileSpec::Hasher()(key.m_filespec_ref); + } + }; + + // C++14: atomic_size_t + size_t m_use_count = 0; + + private: + std::unique_ptr m_symbol_file; + lldb::ObjectFileSP m_obj_file; + lldb::ModuleSP m_module; + const lldb_private::FileSpec &m_filespec_ref; + + DISALLOW_COPY_AND_ASSIGN(DWZCommonFile); + }; + DWZCommonFile *m_dwz_common_file = nullptr; + void DWZCommonFileClear(); + static std::unordered_set + m_filespec_to_dwzcommonfile; + // C++14: static std::shared_timed_mutex m_filespec_to_dwzcommonfile_mutex; + static std::recursive_mutex m_filespec_to_dwzcommonfile_mutex; + bool m_is_dwz = false; + std::forward_list m_compile_unit_data_list; + lldb::ModuleWP m_debug_map_module_wp; SymbolFileDWARFDebugMap *m_debug_map_symfile; @@ -491,6 +544,7 @@ DWARFDataSegment m_data_apple_types; DWARFDataSegment m_data_apple_namespaces; DWARFDataSegment m_data_apple_objc; + DWARFDataSegment m_data_gnu_debugaltlink; // The unique pointer items below are generated on demand if and when someone // accesses Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -409,7 +409,9 @@ m_supports_DW_AT_APPLE_objc_complete_type(eLazyBoolCalculate), m_ranges(), m_unique_ast_type_map() {} -SymbolFileDWARF::~SymbolFileDWARF() {} +SymbolFileDWARF::~SymbolFileDWARF() { + DWZCommonFileClear(); +} static const ConstString &GetDWARFMachOSegmentName() { static ConstString g_dwarf_section_name("__DWARF"); @@ -425,6 +427,7 @@ } TypeSystem *SymbolFileDWARF::GetTypeSystemForLanguage(LanguageType language) { + lldbassert(!GetIsDWZ()); SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); TypeSystem *type_system; if (debug_map_symfile) { @@ -489,6 +492,8 @@ else m_apple_objc_ap.reset(); } + + InitializeDWZ(); } bool SymbolFileDWARF::SupportedVersion(uint16_t version) { @@ -683,6 +688,11 @@ return GetCachedSectionData(eSectionTypeDWARFAppleObjC, m_data_apple_objc); } +const DWARFDataExtractor &SymbolFileDWARF::get_gnu_debugaltlink() { + return GetCachedSectionData(eSectionTypeDWARFGNUDebugAltLink, + m_data_gnu_debugaltlink); +} + DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() { if (m_abbr.get() == NULL) { const DWARFDataExtractor &debug_abbrev_data = get_debug_abbrev_data(); @@ -730,6 +740,8 @@ DWARFCompileUnit *dwarf_cu = info->GetCompileUnit((dw_offset_t)comp_unit->GetID()); + if (dwarf_cu) + dwarf_cu = dwarf_cu->GetMainCU(); if (dwarf_cu && dwarf_cu->GetUserData() == NULL) dwarf_cu->SetUserData(comp_unit); return dwarf_cu; @@ -759,6 +771,7 @@ uint32_t cu_idx) { CompUnitSP cu_sp; if (dwarf_cu) { + dwarf_cu = dwarf_cu->GetMainCU(); CompileUnit *comp_unit = (CompileUnit *)dwarf_cu->GetUserData(); if (comp_unit) { // We already parsed this compile unit, had out a shared pointer to it @@ -1366,6 +1379,9 @@ Type *SymbolFileDWARF::ResolveTypeUID(const DWARFDIE &die, bool assert_not_being_parsed) { + // this can be neither die.GetDWARF() nor die.GetMainDWARF(). + if (die.GetMainDWARF() != this) + return die.GetMainDWARF()->ResolveTypeUID(die, assert_not_being_parsed); if (die) { Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); if (log) @@ -1478,6 +1494,10 @@ Type *SymbolFileDWARF::ResolveType(const DWARFDIE &die, bool assert_not_being_parsed, bool resolve_function_context) { + // this can be neither die.GetDWARF() nor die.GetMainDWARF(). + if (die.GetMainDWARF() != this) + return die.GetMainDWARF()->ResolveType( + die, assert_not_being_parsed, resolve_function_context); if (die) { Type *type = GetTypeForDIE(die, resolve_function_context).get(); @@ -1498,6 +1518,7 @@ CompileUnit * SymbolFileDWARF::GetCompUnitForDWARFCompUnit(DWARFCompileUnit *dwarf_cu, uint32_t cu_idx) { + dwarf_cu = dwarf_cu->GetMainCU(); // Check if the symbol vendor already knows about this compile unit? if (dwarf_cu->GetUserData() == NULL) { // The symbol vendor doesn't know about this compile unit, we @@ -2026,7 +2047,9 @@ &global_index, &type_index, &namespace_index](size_t cu_idx) { DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); - if (dwarf_cu) { + if (dwarf_cu + && dwarf_cu->GetCompileUnitDIEOnly().TagOrig() + == DW_TAG_compile_unit) { dwarf_cu->Index( function_basename_index[cu_idx], function_fullname_index[cu_idx], function_method_index[cu_idx], function_selector_index[cu_idx], @@ -2038,9 +2061,10 @@ auto extract_fn = [debug_info, &clear_cu_dies](size_t cu_idx) { DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); if (dwarf_cu) { - // dwarf_cu->ExtractDIEsIfNeeded(false) will return zero if the + // dwarf_cu->ExtractDIEsIfNeeded will return zero if the // DIEs for a compile unit have already been parsed. - if (dwarf_cu->ExtractDIEsIfNeeded(false) > 1) + if (dwarf_cu->ExtractDIEsIfNeeded(DWARFCompileUnit:: + ExtractDIEsIfNeededKind::AllDiesButCuDieOnlyForPartialUnits) > 1) clear_cu_dies[cu_idx] = true; } }; @@ -3812,7 +3836,8 @@ DWARFFormValue::GetFixedFormSizesForAddressSize( attributes.CompileUnitAtIndex(i)->GetAddressByteSize(), attributes.CompileUnitAtIndex(i)->IsDWARF64()); - uint32_t data_offset = attributes.DIEOffsetAtIndex(i); + uint32_t data_file_offset = die.GetCU() + ->ThisCUUniqToFileOffset(attributes.DIEOffsetAtIndex(i)); uint32_t data_length = fixed_form_sizes.GetSize(form_value.Form()); if (data_length == 0) { @@ -3825,8 +3850,8 @@ const_value = form_value; } } else - location.CopyOpcodeData(module, debug_info_data, data_offset, - data_length); + location.CopyOpcodeData(module, debug_info_data, + data_file_offset, data_length); } else { // Retrieve the value as a string expression. if (form_value.Form() == DW_FORM_strp) { @@ -3835,11 +3860,12 @@ attributes.CompileUnitAtIndex(i) ->GetAddressByteSize(), attributes.CompileUnitAtIndex(i)->IsDWARF64()); - uint32_t data_offset = attributes.DIEOffsetAtIndex(i); + uint32_t data_file_offset = die.GetCU() + ->ThisCUUniqToFileOffset(attributes.DIEOffsetAtIndex(i)); uint32_t data_length = fixed_form_sizes.GetSize(form_value.Form()); - location.CopyOpcodeData(module, debug_info_data, data_offset, - data_length); + location.CopyOpcodeData(module, debug_info_data, + data_file_offset, data_length); } else { const char *str = form_value.AsCString(); uint32_t string_offset = @@ -4369,3 +4395,145 @@ }); return m_dwp_symfile.get(); } + +DWARFCompileUnitData *SymbolFileDWARF::NewCompileUnitData() { + m_compile_unit_data_list.emplace_front(this); + return &m_compile_unit_data_list.front(); +} + +std::unordered_set + SymbolFileDWARF::m_filespec_to_dwzcommonfile; +std::recursive_mutex SymbolFileDWARF::m_filespec_to_dwzcommonfile_mutex; + +void SymbolFileDWARF::InitializeDWZ() { + const DWARFDataExtractor §ion_extractor(get_gnu_debugaltlink()); + if (section_extractor.GetByteSize() == 0) + return; // .gnu_debugaltlink does not exist + if (GetIsDWZ()) { + 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) { + 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) { + GetObjectFile()->GetModule()->ReportWarning( + "Cannot get DWZ common file - missing build-id" + " in section .gnu_debugaltlink with string \"%s\"", + link_cstr); + return; + } + lldb_private::UUID link_uuid; + if (!link_uuid.SetBytes(uuid_bytes,uuid_bytes_size)) { + 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, false /* resolve_path */); + dwz_fspec.PrependPathComponent( + GetObjectFile()->GetFileSpec().CopyByRemovingLastPathComponent()); + // C++14: Use heterogenous lookup. + DWZCommonFile dwz_fspec_lookup(dwz_fspec); + { + // C++14: std::shared_lock + std::lock_guard + guard(m_filespec_to_dwzcommonfile_mutex); + const auto it = m_filespec_to_dwzcommonfile.find(dwz_fspec_lookup); + if (it != m_filespec_to_dwzcommonfile.end()) { + m_dwz_common_file = const_cast(&*it); + ++m_dwz_common_file->m_use_count; + return; + } + } + dwz_module_spec.GetArchitecture() = + 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, dwz_fspec.GetByteSize(), + dwz_file_data_sp, dwz_file_data_offset); + if (!dwz_obj_file) { + GetObjectFile()->GetModule()->ReportWarning( + "Cannot get DWZ common file - file \"%s\" cannot be opened", + dwz_fspec.GetCString()); + return; + } + lldbassert(dwz_obj_file->GetFileSpec() == dwz_fspec); + lldb_private::UUID dwz_uuid; + if (!dwz_obj_file->GetUUID(&dwz_uuid)) { + GetObjectFile()->GetModule()->ReportWarning( + "Cannot get DWZ common file - file \"%s\" does not have build-id", + dwz_fspec.GetCString()); + return; + } + if (link_uuid != dwz_uuid) { + 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 = + llvm::make_unique(dwz_obj_file.get()); + dwz_symbol_file->m_is_dwz = true; + dwz_symbol_file->InitializeObject(); + // Call private DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded() as + // otherwise DWARFCompileUnit::GetAbbreviations() would have no data. + dwz_symbol_file->DebugInfo()->GetNumCompileUnits(); + { + // C++14: std::lock_guard + std::lock_guard + guard(m_filespec_to_dwzcommonfile_mutex); + const auto it = m_filespec_to_dwzcommonfile.find(dwz_fspec_lookup); + if (it != m_filespec_to_dwzcommonfile.end()) + m_dwz_common_file = const_cast(&*it); + else { + const auto insertpair = m_filespec_to_dwzcommonfile.emplace( + std::move(dwz_symbol_file), std::move(dwz_obj_file), + std::move(dwz_module)); + lldbassert(insertpair.second); + m_dwz_common_file = const_cast(&*insertpair.first); + lldbassert(*m_dwz_common_file == dwz_fspec_lookup); + } + ++m_dwz_common_file->m_use_count; + } +} + +void SymbolFileDWARF::DWZCommonFileClear() { + if (!m_dwz_common_file) + return; + // C++14: std::lock_guard + std::lock_guard + guard(m_filespec_to_dwzcommonfile_mutex); + lldbassert(m_dwz_common_file->m_use_count); + if (--m_dwz_common_file->m_use_count) + return; + size_t erased = m_filespec_to_dwzcommonfile.erase(*m_dwz_common_file); + lldbassert(erased == 1); +} + +SymbolFileDWARF::DWZCommonFile::DWZCommonFile( + const lldb_private::FileSpec &filespec_ref) + : m_filespec_ref(filespec_ref) {} + +SymbolFileDWARF::DWZCommonFile::DWZCommonFile( + std::unique_ptr &&symbol_file, + lldb::ObjectFileSP &&obj_file, lldb::ModuleSP &&module) + : m_symbol_file(std::move(symbol_file)), m_obj_file(std::move(obj_file)), + m_module(std::move(module)), m_filespec_ref(m_obj_file->GetFileSpec()) {} Index: source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp =================================================================== --- source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp +++ source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp @@ -134,7 +134,7 @@ eSectionTypeDWARFDebugMacInfo, eSectionTypeDWARFDebugPubNames, eSectionTypeDWARFDebugPubTypes, eSectionTypeDWARFDebugRanges, eSectionTypeDWARFDebugStr, eSectionTypeDWARFDebugStrOffsets, - eSectionTypeELFSymbolTable, + eSectionTypeELFSymbolTable, eSectionTypeDWARFGNUDebugAltLink, }; for (size_t idx = 0; idx < sizeof(g_sections) / sizeof(g_sections[0]); ++idx) { Index: source/Symbol/ObjectFile.cpp =================================================================== --- source/Symbol/ObjectFile.cpp +++ source/Symbol/ObjectFile.cpp @@ -364,6 +364,7 @@ case eSectionTypeDWARFAppleTypes: case eSectionTypeDWARFAppleNamespaces: case eSectionTypeDWARFAppleObjC: + case eSectionTypeDWARFGNUDebugAltLink: return eAddressClassDebug; case eSectionTypeEHFrame: case eSectionTypeARMexidx: