Index: include/lldb/lldb-enumerations.h =================================================================== --- include/lldb/lldb-enumerations.h +++ include/lldb/lldb-enumerations.h @@ -656,6 +656,7 @@ eSectionTypeGoSymtab, eSectionTypeAbsoluteAddress, // Dummy section for symbols with absolute // address + eSectionTypeDWARFDebugTypes, // DWARF .debug_types section eSectionTypeOther }; Index: include/lldb/lldb-forward.h =================================================================== --- include/lldb/lldb-forward.h +++ include/lldb/lldb-forward.h @@ -85,6 +85,7 @@ class DiagnosticManager; class Disassembler; class DumpValueObjectOptions; +class DWARFDataExtractor; class DynamicCheckerFunctions; class DynamicLoader; class Editline; Index: lldb.xcodeproj/project.pbxproj =================================================================== --- lldb.xcodeproj/project.pbxproj +++ lldb.xcodeproj/project.pbxproj @@ -226,6 +226,8 @@ 2657AFB71B86910100958979 /* CompilerDeclContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2657AFB61B86910100958979 /* CompilerDeclContext.cpp */; }; 2660AAB914622483003A9694 /* LLDBWrapPython.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A4EEB511682AAC007A372A /* LLDBWrapPython.cpp */; settings = {COMPILER_FLAGS = "-Dregister="; }; }; 26651A18133BF9E0005B64B7 /* Opcode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26651A17133BF9DF005B64B7 /* Opcode.cpp */; }; + 26652E662076BC0A0053A2FC /* DWARFTypeUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26652E642076BC0A0053A2FC /* DWARFTypeUnit.cpp */; }; + 26652E672076BC0A0053A2FC /* DWARFTypeUnit.h in Headers */ = {isa = PBXBuildFile; fileRef = 26652E652076BC0A0053A2FC /* DWARFTypeUnit.h */; }; 2666ADC61B3CB675001FAFD3 /* DynamicLoaderHexagonDYLD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2666ADC11B3CB675001FAFD3 /* DynamicLoaderHexagonDYLD.cpp */; }; 2666ADC81B3CB675001FAFD3 /* HexagonDYLDRendezvous.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2666ADC31B3CB675001FAFD3 /* HexagonDYLDRendezvous.cpp */; }; 2668020E115FD12C008E1FE4 /* lldb-defines.h in Headers */ = {isa = PBXBuildFile; fileRef = 26BC7C2510F1B3BC00F91463 /* lldb-defines.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1749,6 +1751,8 @@ 26651A14133BEC76005B64B7 /* lldb-public.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "lldb-public.h"; path = "include/lldb/lldb-public.h"; sourceTree = ""; }; 26651A15133BF9CC005B64B7 /* Opcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Opcode.h; path = include/lldb/Core/Opcode.h; sourceTree = ""; }; 26651A17133BF9DF005B64B7 /* Opcode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Opcode.cpp; path = source/Core/Opcode.cpp; sourceTree = ""; }; + 26652E642076BC0A0053A2FC /* DWARFTypeUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFTypeUnit.cpp; sourceTree = ""; }; + 26652E652076BC0A0053A2FC /* DWARFTypeUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFTypeUnit.h; sourceTree = ""; }; 2665CD0D15080846002C8FAE /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; 2666ADC11B3CB675001FAFD3 /* DynamicLoaderHexagonDYLD.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DynamicLoaderHexagonDYLD.cpp; sourceTree = ""; }; 2666ADC21B3CB675001FAFD3 /* DynamicLoaderHexagonDYLD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DynamicLoaderHexagonDYLD.h; sourceTree = ""; }; @@ -3964,6 +3968,8 @@ 260C89D210F57C5600BB2B04 /* DWARFDIECollection.h */, 260C89D310F57C5600BB2B04 /* DWARFFormValue.cpp */, 260C89D410F57C5600BB2B04 /* DWARFFormValue.h */, + 26652E642076BC0A0053A2FC /* DWARFTypeUnit.cpp */, + 26652E652076BC0A0053A2FC /* DWARFTypeUnit.h */, 7F2AAA5920601BE000A422D8 /* DWARFUnit.cpp */, 7F2AAA5820601BDF00A422D8 /* DWARFUnit.h */, 26A0DA4D140F721D006DA411 /* HashedNameToDIE.h */, @@ -6879,6 +6885,7 @@ 260A63171861008E00FECF8E /* IOHandler.h in Headers */, 267F68581CC02EAE0086832B /* RegisterContextPOSIX_s390x.h in Headers */, 6D0F614F1C80AB0C00A4ECEE /* JavaLanguageRuntime.h in Headers */, + 26652E672076BC0A0053A2FC /* DWARFTypeUnit.h in Headers */, AF27AD561D3603EA00CF2833 /* DynamicLoaderDarwin.h in Headers */, AFCB2BBE1BF577F40018B553 /* PythonExceptionState.h in Headers */, 267F684B1CC02DED0086832B /* ABISysV_s390x.h in Headers */, @@ -7586,6 +7593,7 @@ 2689002C13353E0400698AC0 /* AddressResolver.cpp in Sources */, 945261C01B9A11FC00BF138D /* LibCxx.cpp in Sources */, 949EEDB11BA7672D008C63CF /* NSDictionary.cpp in Sources */, + 26652E662076BC0A0053A2FC /* DWARFTypeUnit.cpp in Sources */, 2689002D13353E0400698AC0 /* AddressResolverFileLine.cpp in Sources */, 2689002E13353E0400698AC0 /* AddressResolverName.cpp in Sources */, 250D6AE31A9679440049CC70 /* FileSystem.cpp in Sources */, Index: packages/Python/lldbsuite/test/lldbinline.py =================================================================== --- packages/Python/lldbsuite/test/lldbinline.py +++ packages/Python/lldbsuite/test/lldbinline.py @@ -167,6 +167,14 @@ self.do_test() __test_with_gmodules.debug_info = "gmodules" + @add_test_categories(["dwarf_type_units"]) + def __test_with_dwarf_type_units(self): + self.using_dsym = False + self.BuildMakefile() + self.build() + self.do_test() + __test_with_dwarf_type_units.debug_info = "dwarf_type_units" + def execute_user_command(self, __command): exec(__command, globals(), locals()) @@ -249,6 +257,8 @@ test._InlineTest__test_with_dwo, decorators) test.test_with_gmodules = ApplyDecoratorsToFunction( test._InlineTest__test_with_gmodules, decorators) + test.test_with_dwarf_type_units = ApplyDecoratorsToFunction( + test._InlineTest__test_with_dwarf_type_units, 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 @@ -700,8 +700,8 @@ """Return the full path to the current test.""" return os.path.join(os.environ["LLDB_BUILD"], self.mydir, self.getBuildDirBasename()) - - + + def makeBuildDir(self): """Create the test-specific working directory, deleting any previous contents.""" @@ -710,11 +710,11 @@ if os.path.isdir(bdir): shutil.rmtree(bdir) lldbutil.mkdir_p(bdir) - + def getBuildArtifact(self, name="a.out"): """Return absolute path to an artifact in the test's build directory.""" return os.path.join(self.getBuildDir(), name) - + def getSourcePath(self, name): """Return absolute path to a file in the test's source directory.""" return os.path.join(self.getSourceDir(), name) @@ -1579,6 +1579,24 @@ dictionary, testdir, testname): raise Exception("Don't know how to build binary with gmodules") + def buildDwarfTypeUnits( + self, + architecture=None, + compiler=None, + dictionary=None, + clean=True): + """Platform specific way to build binaries with DWARF type units.""" + testdir = self.mydir + testname = self.getBuildDirBasename() + if self.getDebugInfo() != "dwarf_type_units": + raise Exception("NO_DEBUG_INFO_TESTCASE must build with buildDefault") + + module = builder_module() + dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) + if not module.buildDwarfTypeUnits(self, architecture, compiler, + dictionary, clean, testdir, testname): + raise Exception("Don't know how to build binary with DWARF type units") + def buildGo(self): """Build the default go binary. """ @@ -1840,7 +1858,7 @@ temp = os.path.join(self.getSourceDir(), template) with open(temp, 'r') as f: content = f.read() - + public_api_dir = os.path.join( os.environ["LLDB_SRC"], "include", "lldb", "API") @@ -2278,6 +2296,8 @@ return self.buildDwo(architecture, compiler, dictionary) elif self.getDebugInfo() == "gmodules": return self.buildGModules(architecture, compiler, dictionary) + elif self.getDebugInfo() == "dwarf_type_units": + return self.buildDwarfTypeUnits(architecture, compiler, dictionary) else: self.fail("Can't build for debug info: %s" % self.getDebugInfo()) Index: packages/Python/lldbsuite/test/make/Makefile.rules =================================================================== --- packages/Python/lldbsuite/test/make/Makefile.rules +++ packages/Python/lldbsuite/test/make/Makefile.rules @@ -247,6 +247,12 @@ CFLAGS += $(MANDATORY_MODULE_BUILD_CFLAGS) endif +MANDATORY_DWARF_TYPE_UNITS_CFLAGS := -fdebug-types-section + +ifeq "$(DWARF_TYPE_UNITS)" "YES" + CFLAGS += $(MANDATORY_DWARF_TYPE_UNITS_CFLAGS) +endif + CXXFLAGS += -std=c++11 $(CFLAGS) LD = $(CC) LDFLAGS ?= $(CFLAGS) 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 @@ -212,6 +212,31 @@ return True +def buildDwarfTypeUnits( + sender=None, + architecture=None, + compiler=None, + dictionary=None, + clean=True, + testdir=None, + testname=None): + """Build the binaries with type units (type in a .debug_types section).""" + commands = [] + if clean: + commands.append(getMake(testdir, testname) + + ["clean", getCmdLine(dictionary)]) + commands.append(getMake(testdir, testname) + + ["MAKE_DSYM=NO", + "DWARF_TYPE_UNITS=YES", + getArchSpec(architecture), + getCCSpec(compiler), + getCmdLine(dictionary)]) + + lldbtest.system(commands, sender=sender) + # True signifies that we can handle building with type units. + return True + + def cleanup(sender=None, dictionary=None): """Perform a platform-specific cleanup after the test.""" return True Index: packages/Python/lldbsuite/test/test_categories.py =================================================================== --- packages/Python/lldbsuite/test/test_categories.py +++ packages/Python/lldbsuite/test/test_categories.py @@ -15,7 +15,7 @@ debug_info_categories = [ - 'dwarf', 'dwo', 'dsym', 'gmodules' + 'dwarf', 'dwo', 'dsym', 'gmodules', 'dwarf_type_units' ] all_categories = { @@ -24,6 +24,7 @@ 'dwo': 'Tests that can be run with DWO debug information', 'dsym': 'Tests that can be run with DSYM debug information', 'gmodules': 'Tests that can be run with -gmodules debug information', + 'dwarf_type_units' : 'Tests that can be run with DWARF type units', 'expression': 'Tests related to the expression parser', 'libc++': 'Test for libc++ data formatters', 'objc': 'Tests related to the Objective-C programming language support', @@ -61,6 +62,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 == "dwarf_type_units": + return platform in ["linux"] return True Index: source/Core/Section.cpp =================================================================== --- source/Core/Section.cpp +++ source/Core/Section.cpp @@ -89,6 +89,8 @@ return "dwarf-str"; case eSectionTypeDWARFDebugStrOffsets: return "dwarf-str-offsets"; + case eSectionTypeDWARFDebugTypes: + return "dwarf-types"; case eSectionTypeELFSymbolTable: return "elf-symbol-table"; case eSectionTypeELFDynamicSymbols: Index: source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp =================================================================== --- source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -1819,6 +1819,7 @@ static ConstString g_sect_name_dwarf_debug_str_dwo(".debug_str.dwo"); static ConstString g_sect_name_dwarf_debug_str_offsets_dwo( ".debug_str_offsets.dwo"); + static ConstString g_sect_name_dwarf_debug_types(".debug_types"); static ConstString g_sect_name_eh_frame(".eh_frame"); static ConstString g_sect_name_arm_exidx(".ARM.exidx"); static ConstString g_sect_name_arm_extab(".ARM.extab"); @@ -1889,6 +1890,8 @@ sect_type = eSectionTypeDWARFDebugRanges; else if (name == g_sect_name_dwarf_debug_str) sect_type = eSectionTypeDWARFDebugStr; + else if (name == g_sect_name_dwarf_debug_types) + sect_type = eSectionTypeDWARFDebugTypes; else if (name == g_sect_name_dwarf_debug_str_offsets) sect_type = eSectionTypeDWARFDebugStrOffsets; else if (name == g_sect_name_dwarf_debug_abbrev_dwo) Index: source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp =================================================================== --- source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -1208,6 +1208,7 @@ case eSectionTypeDWARFDebugRanges: case eSectionTypeDWARFDebugStr: case eSectionTypeDWARFDebugStrOffsets: + case eSectionTypeDWARFDebugTypes: case eSectionTypeDWARFAppleNames: case eSectionTypeDWARFAppleTypes: case eSectionTypeDWARFAppleNamespaces: @@ -1460,6 +1461,7 @@ static ConstString g_sect_name_dwarf_debug_pubtypes("__debug_pubtypes"); static ConstString g_sect_name_dwarf_debug_ranges("__debug_ranges"); static ConstString g_sect_name_dwarf_debug_str("__debug_str"); + static ConstString g_sect_name_dwarf_debug_types("__debug_types"); static ConstString g_sect_name_dwarf_apple_names("__apple_names"); static ConstString g_sect_name_dwarf_apple_types("__apple_types"); static ConstString g_sect_name_dwarf_apple_namespaces("__apple_namespac"); @@ -1492,6 +1494,8 @@ return eSectionTypeDWARFDebugRanges; if (section_name == g_sect_name_dwarf_debug_str) return eSectionTypeDWARFDebugStr; + if (section_name == g_sect_name_dwarf_debug_types) + return eSectionTypeDWARFDebugTypes; if (section_name == g_sect_name_dwarf_apple_names) return eSectionTypeDWARFAppleNames; if (section_name == g_sect_name_dwarf_apple_types) Index: source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp =================================================================== --- source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -696,6 +696,7 @@ static ConstString g_sect_name_dwarf_debug_pubtypes(".debug_pubtypes"); static ConstString g_sect_name_dwarf_debug_ranges(".debug_ranges"); static ConstString g_sect_name_dwarf_debug_str(".debug_str"); + static ConstString g_sect_name_dwarf_debug_types(".debug_types"); static ConstString g_sect_name_eh_frame(".eh_frame"); static ConstString g_sect_name_go_symtab(".gosymtab"); SectionType section_type = eSectionTypeOther; @@ -744,6 +745,8 @@ section_type = eSectionTypeDWARFDebugRanges; else if (const_sect_name == g_sect_name_dwarf_debug_str) section_type = eSectionTypeDWARFDebugStr; + else if (const_sect_name == g_sect_name_dwarf_debug_types) + section_type = eSectionTypeDWARFDebugTypes; else if (const_sect_name == g_sect_name_eh_frame) section_type = eSectionTypeEHFrame; else if (const_sect_name == g_sect_name_go_symtab) Index: source/Plugins/SymbolFile/DWARF/CMakeLists.txt =================================================================== --- source/Plugins/SymbolFile/DWARF/CMakeLists.txt +++ source/Plugins/SymbolFile/DWARF/CMakeLists.txt @@ -24,6 +24,7 @@ DWARFDIECollection.cpp DWARFFormValue.cpp DWARFUnit.cpp + DWARFTypeUnit.cpp HashedNameToDIE.cpp LogChannelDWARF.cpp NameToDIE.cpp Index: source/Plugins/SymbolFile/DWARF/DIERef.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DIERef.cpp +++ source/Plugins/SymbolFile/DWARF/DIERef.cpp @@ -9,6 +9,7 @@ #include "DIERef.h" #include "DWARFUnit.h" +#include "DWARFTypeUnit.h" #include "DWARFDebugInfo.h" #include "DWARFFormValue.h" #include "SymbolFileDWARF.h" @@ -47,10 +48,24 @@ if (form_value.IsValid()) { const DWARFUnit *dwarf_cu = form_value.GetCompileUnit(); if (dwarf_cu) { - if (dwarf_cu->GetBaseObjOffset() != DW_INVALID_OFFSET) - cu_offset = dwarf_cu->GetBaseObjOffset(); - else - cu_offset = dwarf_cu->GetOffset(); + // Replace the compile unit with the type signature compile unit + // and DIE for the type signature. When a type is referred to by a + // DW_FORM_ref_sig8 form, the real information for the type in + // contained in a DW_TAG_type_unit. + if (form_value.Form() == DW_FORM_ref_sig8) { + uint64_t type_sig = form_value.Unsigned(); + auto debug_info = dwarf_cu->GetSymbolFileDWARF()->DebugInfo(); + auto tu = debug_info->GetTypeUnitForSignature(type_sig); + if (tu) { + cu_offset = tu->GetOffset(); + die_offset = tu->GetTypeUnitDIEOffset(); + } + } else { + if (dwarf_cu->GetBaseObjOffset() != DW_INVALID_OFFSET) + cu_offset = dwarf_cu->GetBaseObjOffset(); + else + cu_offset = dwarf_cu->GetOffset(); + } } die_offset = form_value.Reference(); } Index: source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -253,8 +253,21 @@ context_die.GetOffset(), die.GetTagAsCString(), die.GetName()); } Type *type_ptr = dwarf->GetDIEToType().lookup(die.GetDIE()); - TypeList *type_list = dwarf->GetTypeList(); if (type_ptr == NULL) { + + // If we have .debug_types defer to the complete version in the + // .debug_types section, not the broken incomplete definition in real + // compile units that are only there so addresses can be assigned to + // static values. + auto signature_die = die.GetAttributeValueAsReferenceDIE(DW_AT_signature); + if (signature_die) { + type_sp = ParseTypeFromDWARF(sc, signature_die, log, type_is_new_ptr); + if (type_sp) { + dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); + return type_sp; + } + } + if (type_is_new_ptr) *type_is_new_ptr = true; @@ -1940,7 +1953,7 @@ // We are ready to put this type into the uniqued list up at the module // level - type_list->Insert(type_sp); + dwarf->GetTypeList()->Insert(type_sp); dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); } @@ -2911,8 +2924,7 @@ if (form_value.BlockData()) { Value initialValue(0); Value memberOffset(0); - const DWARFDataExtractor &debug_info_data = - die.GetDWARF()->get_debug_info_data(); + const DWARFDataExtractor &debug_info_data = die.GetData(); uint32_t block_length = form_value.Unsigned(); uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); @@ -3383,8 +3395,7 @@ if (form_value.BlockData()) { Value initialValue(0); Value memberOffset(0); - const DWARFDataExtractor &debug_info_data = - die.GetDWARF()->get_debug_info_data(); + const DWARFDataExtractor &debug_info_data = die.GetData(); uint32_t block_length = form_value.Unsigned(); uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); Index: source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp @@ -654,8 +654,7 @@ if (form_value.BlockData()) { Value initialValue(0); Value memberOffset(0); - const DWARFDataExtractor &debug_info_data = - die.GetDWARF()->get_debug_info_data(); + const DWARFDataExtractor &debug_info_data = die.GetData(); uint32_t block_length = form_value.Unsigned(); uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); Index: source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp @@ -52,8 +52,7 @@ form_value.SetCompileUnit(cu); form_value.SetForm(FormAtIndex(i)); lldb::offset_t offset = DIEOffsetAtIndex(i); - return form_value.ExtractValue( - cu->GetSymbolFileDWARF()->get_debug_info_data(), &offset); + return form_value.ExtractValue(cu->GetData(), &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 @@ -16,10 +16,30 @@ friend class DWARFUnit; public: - static DWARFUnitSP Extract(SymbolFileDWARF *dwarf2Data, - lldb::offset_t *offset_ptr); + static DWARFCompileUnitSP Extract(SymbolFileDWARF *dwarf2Data, + const lldb_private::DWARFDataExtractor &data, lldb::offset_t *offset_ptr); void Dump(lldb_private::Stream *s) const override; + //------------------------------------------------------------------ + /// Get the data that contains the DIE information for this unit. + /// + /// @return + /// The correct data (.debug_types for DWARF 4 and earlier, and + /// .debug_info for DWARF 5 and later) for the DIE information in + /// this unit. + //------------------------------------------------------------------ + const lldb_private::DWARFDataExtractor &GetData() const override; + + //------------------------------------------------------------------ + /// Get the size in bytes of the header. + /// + /// @return + /// Byte size of the compile unit header + //------------------------------------------------------------------ + uint32_t GetHeaderByteSize() const override { + return m_is_dwarf64 ? 23 : 11; + } + private: DWARFCompileUnit(SymbolFileDWARF *dwarf2Data); DISALLOW_COPY_AND_ASSIGN(DWARFCompileUnit); Index: source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -14,49 +14,19 @@ using namespace lldb; using namespace lldb_private; -extern int g_verbose; - DWARFCompileUnit::DWARFCompileUnit(SymbolFileDWARF *dwarf2Data) : DWARFUnit(dwarf2Data) {} -DWARFUnitSP DWARFCompileUnit::Extract(SymbolFileDWARF *dwarf2Data, +DWARFCompileUnitSP DWARFCompileUnit::Extract(SymbolFileDWARF *dwarf2Data, + const lldb_private::DWARFDataExtractor &data, lldb::offset_t *offset_ptr) { // std::make_shared would require the ctor to be public. std::shared_ptr cu_sp(new DWARFCompileUnit(dwarf2Data)); // Out of memory? - if (cu_sp.get() == NULL) + if (!cu_sp) return nullptr; - - const DWARFDataExtractor &debug_info = dwarf2Data->get_debug_info_data(); - - cu_sp->m_offset = *offset_ptr; - - if (debug_info.ValidOffset(*offset_ptr)) { - dw_offset_t abbr_offset; - const DWARFDebugAbbrev *abbr = dwarf2Data->DebugAbbrev(); - cu_sp->m_length = debug_info.GetDWARFInitialLength(offset_ptr); - cu_sp->m_is_dwarf64 = debug_info.IsDWARF64(); - cu_sp->m_version = debug_info.GetU16(offset_ptr); - abbr_offset = debug_info.GetDWARFOffset(offset_ptr); - cu_sp->m_addr_size = debug_info.GetU8(offset_ptr); - - bool length_OK = - debug_info.ValidOffset(cu_sp->GetNextCompileUnitOffset() - 1); - bool version_OK = SymbolFileDWARF::SupportedVersion(cu_sp->m_version); - bool abbr_offset_OK = - dwarf2Data->get_debug_abbrev_data().ValidOffset(abbr_offset); - bool addr_size_OK = (cu_sp->m_addr_size == 4) || (cu_sp->m_addr_size == 8); - - if (length_OK && version_OK && addr_size_OK && abbr_offset_OK && - abbr != NULL) { - cu_sp->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 = cu_sp->m_offset; - } - + if (cu_sp->ExtractHeader(dwarf2Data, data, offset_ptr)) + return cu_sp; return nullptr; } @@ -67,3 +37,8 @@ m_offset, m_length, m_version, GetAbbrevOffset(), m_addr_size, GetNextCompileUnitOffset()); } + + +const lldb_private::DWARFDataExtractor &DWARFCompileUnit::GetData() const { + return m_dwarf->get_debug_info_data(); +} Index: source/Plugins/SymbolFile/DWARF/DWARFDIE.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDIE.h +++ source/Plugins/SymbolFile/DWARF/DWARFDIE.h @@ -87,6 +87,16 @@ GetContainingDWOModuleDIE() const; //---------------------------------------------------------------------- + // Get the data that contains the attribute values for this DIE. Support + // for .debug_types means that any DIE can have its data either in the + // .debug_info or the .debug_types section; this method will return the + // correct section data. + // + // Clients must validate that this object is valid before calling this. + //---------------------------------------------------------------------- + const lldb_private::DWARFDataExtractor &GetData() const; + + //---------------------------------------------------------------------- // Accessing information about a DIE //---------------------------------------------------------------------- dw_tag_t Tag() const; Index: source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -460,3 +460,9 @@ bool operator!=(const DWARFDIE &lhs, const DWARFDIE &rhs) { return !(lhs == rhs); } + +const DWARFDataExtractor &DWARFDIE::GetData() const { + // Clients must check if this DIE is valid before calling this function. + assert(IsValid()); + return m_cu->GetData(); +} Index: source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h +++ source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h @@ -29,9 +29,33 @@ dw_offset_t GetDWARFOffset(lldb::offset_t *offset_ptr) const; size_t GetDWARFSizeofInitialLength() const { return m_is_dwarf64 ? 12 : 4; } - + size_t GetDWARFSizeOfOffset() const { return m_is_dwarf64 ? 8 : 4; } bool IsDWARF64() const { return m_is_dwarf64; } + //------------------------------------------------------------------ + /// Slide the data in the buffer so that access to the data will + /// start at offset \a offset. + /// + /// This is currently used to provide access to the .debug_types + /// section and pretend it starts at at offset of the size of the + /// .debug_info section. This allows a minimally invasive change to + /// add support for .debug_types by allowing all DIEs to have unique + /// offsets and thus allowing no code to change in the DWARF parser. + /// Modifying the offsets in the .debug_types doesn't affect + /// anything because since all info in the .debug_types is type unit + /// relative and no types within a type unit can refer to any DIEs + /// outside of the type unit without using DW_AT_signature. It also + /// sets us up to move to DWARF5 where there is no .debug_types + /// section as compile units and type units are in the .debug_info. + /// + /// @param[in] offset + /// The amount to slide the data contents by. + //------------------------------------------------------------------ + void OffsetData(lldb::offset_t offset) { + if (GetByteSize()) + m_start -= offset; + } + protected: mutable bool m_is_dwarf64; }; Index: source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp @@ -22,6 +22,6 @@ dw_offset_t DWARFDataExtractor::GetDWARFOffset(lldb::offset_t *offset_ptr) const { - return GetMaxU64(offset_ptr, m_is_dwarf64 ? 8 : 4); + return GetMaxU64(offset_ptr, GetDWARFSizeOfOffset()); } } Index: source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h +++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h @@ -11,6 +11,7 @@ #define SymbolFileDWARF_DWARFDebugInfo_h_ #include +#include #include #include "DWARFUnit.h" @@ -19,6 +20,8 @@ #include "lldb/Core/STLUtils.h" #include "lldb/lldb-private.h" +class DWARFTypeUnit; + typedef std::multimap CStringToDIEMap; typedef CStringToDIEMap::iterator CStringToDIEMapIter; @@ -38,6 +41,7 @@ size_t GetNumCompileUnits(); bool ContainsCompileUnit(const DWARFUnit *cu) const; DWARFUnit *GetCompileUnitAtIndex(uint32_t idx); + DWARFTypeUnit *GetTypeUnitForSignature(uint64_t type_sig); DWARFUnit *GetCompileUnit(dw_offset_t cu_offset, uint32_t *idx_ptr = NULL); DWARFUnit *GetCompileUnitContainingDIEOffset(dw_offset_t die_offset); DWARFUnit *GetCompileUnit(const DIERef &die_ref); @@ -65,12 +69,14 @@ const DWARFUnitSP &cu_sp); typedef std::vector CompileUnitColl; + typedef std::unordered_map TypeSignatureMap; //---------------------------------------------------------------------- // Member variables //---------------------------------------------------------------------- SymbolFileDWARF *m_dwarf2Data; CompileUnitColl m_compile_units; + TypeSignatureMap m_type_sig_to_cu_index; std::unique_ptr m_cu_aranges_ap; // A quick address to compile unit table Index: source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -23,6 +23,7 @@ #include "DWARFDebugInfo.h" #include "DWARFDebugInfoEntry.h" #include "DWARFFormValue.h" +#include "DWARFTypeUnit.h" #include "LogChannelDWARF.h" using namespace lldb; @@ -94,17 +95,44 @@ } void DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded() { - if (m_compile_units.empty()) { - if (m_dwarf2Data != NULL) { - lldb::offset_t offset = 0; - DWARFUnitSP cu_sp; - while ((cu_sp = DWARFCompileUnit::Extract(m_dwarf2Data, &offset))) { - m_compile_units.push_back(cu_sp); + if (!m_compile_units.empty()) + return; + + if (m_dwarf2Data == nullptr) + return; - offset = cu_sp->GetNextCompileUnitOffset(); - } - } + lldb::offset_t offset = 0; + DWARFCompileUnitSP cu_sp; + const auto &debug_info_data = m_dwarf2Data->get_debug_info_data(); + while ((cu_sp = DWARFCompileUnit::Extract(m_dwarf2Data, debug_info_data, + &offset))) { + m_compile_units.push_back(cu_sp); + offset = cu_sp->GetNextCompileUnitOffset(); } + + // If we have a separate .debug_types section, it means we are using DWARF4 + // or earlier where type units are a separate section. All data in the + // .debug_types section doesn't refer directly to any other DIEs, all + // references are done via type signatures. With this in mind, we can support + // parsing .debug_types by pretending that the data in .debug_types + // immediately follows all data in the .debug_info section. This allows all + // types in the .debug_types to have a unique DIE offset that is: + // offset = sizeof(.debug_info) + debug_type_offset + // + // So below we set "offset" to be the size of the .debug_info section. We have + // modified the debug_types_data to know that its first byte starts at this + // offset. + auto debug_types_data = m_dwarf2Data->get_debug_types_data(); + if (debug_types_data.GetByteSize() == 0) + return; + offset = debug_info_data.GetByteSize(); + DWARFTypeUnitSP tu_sp; + while ((tu_sp = DWARFTypeUnit::Extract(m_dwarf2Data, debug_types_data, + &offset))) { + m_type_sig_to_cu_index[tu_sp->GetTypeSignature()] = m_compile_units.size(); + m_compile_units.push_back(tu_sp); + offset = tu_sp->GetNextCompileUnitOffset(); + } } size_t DWARFDebugInfo::GetNumCompileUnits() { @@ -224,269 +252,10 @@ return DWARFDIE(); // Not found } -//---------------------------------------------------------------------- -// Parse -// -// Parses the .debug_info section and uses the .debug_abbrev section -// and various other sections in the SymbolFileDWARF class and calls the -// supplied callback function each time a compile unit header, or debug -// information entry is successfully parsed. This function can be used -// for different tasks such as parsing the file contents into a -// structured data, dumping, verifying and much more. -//---------------------------------------------------------------------- -void DWARFDebugInfo::Parse(SymbolFileDWARF *dwarf2Data, Callback callback, - void *userData) { - if (dwarf2Data) { - lldb::offset_t offset = 0; - uint32_t depth = 0; - DWARFDebugInfoEntry die; - - DWARFUnitSP cu; - while ((cu = DWARFCompileUnit::Extract(dwarf2Data, &offset))) { - const dw_offset_t next_cu_offset = cu->GetNextCompileUnitOffset(); - - 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); - - // Make sure we are within our compile unit - if (offset < next_cu_offset) { - // We are in our compile unit, parse starting at the offset - // we were told to parse - bool done = false; - while (!done && die.Extract(dwarf2Data, cu.get(), &offset)) { - // Call the callback function with DIE pointer that falls within the - // compile unit - offset = - callback(dwarf2Data, cu.get(), &die, offset, depth, userData); - - if (die.IsNULL()) { - if (depth) - --depth; - else - done = true; // We are done with this compile unit! - } else if (die.HasChildren()) - ++depth; - } - } - - // Make sure the 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)) - break; - - // Make sure we start on a proper - offset = next_cu_offset; - } - } +DWARFTypeUnit *DWARFDebugInfo::GetTypeUnitForSignature(uint64_t type_sig) { + auto pos = m_type_sig_to_cu_index.find(type_sig); + if (pos != m_type_sig_to_cu_index.end()) + return GetCompileUnitAtIndex(pos->second)->GetAsTypeUnit(); + return nullptr; } - -typedef struct DumpInfo { - DumpInfo(Stream *init_strm, uint32_t off, uint32_t depth) - : strm(init_strm), die_offset(off), recurse_depth(depth), - found_depth(UINT32_MAX), found_die(false), ancestors() {} - Stream *strm; - const uint32_t die_offset; - const uint32_t recurse_depth; - uint32_t found_depth; - bool found_die; - std::vector ancestors; - - DISALLOW_COPY_AND_ASSIGN(DumpInfo); -} DumpInfo; - -//---------------------------------------------------------------------- -// DumpCallback -// -// A callback function for the static DWARFDebugInfo::Parse() function -// that gets called each time a compile unit header or debug information -// entry is successfully parsed. -// -// This function dump DWARF information and obey recurse depth and -// whether a single DIE is to be dumped (or all of the data). -//---------------------------------------------------------------------- -static dw_offset_t DumpCallback(SymbolFileDWARF *dwarf2Data, - DWARFUnit *cu, DWARFDebugInfoEntry *die, - const dw_offset_t next_offset, - const uint32_t curr_depth, void *userData) { - DumpInfo *dumpInfo = (DumpInfo *)userData; - Stream *s = dumpInfo->strm; - bool show_parents = - s->GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowAncestors); - - if (die) { - // Are we dumping everything? - if (dumpInfo->die_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()) { - // We found the DIE we were looking for, dump it! - if (show_parents) { - s->SetIndentLevel(0); - const uint32_t num_ancestors = dumpInfo->ancestors.size(); - if (num_ancestors > 0) { - for (uint32_t i = 0; i < num_ancestors - 1; ++i) { - dumpInfo->ancestors[i].Dump(dwarf2Data, cu, *s, 0); - s->IndentMore(); - } - } - } - - dumpInfo->found_depth = curr_depth; - - die->Dump(dwarf2Data, cu, *s, 0); - - // Note that we found the DIE we were looking for - dumpInfo->found_die = true; - - // Since we are dumping a single DIE, if there are no children we are - // done! - if (!die->HasChildren() || dumpInfo->recurse_depth == 0) - return DW_INVALID_OFFSET; // Return an invalid address to end parsing - } else if (dumpInfo->found_die) { - // Are we done with all the children? - if (curr_depth <= dumpInfo->found_depth) - return DW_INVALID_OFFSET; - - // We have already found our DIE and are printing it's children. Obey - // our recurse depth and return an invalid offset if we get done - // dumping all of the children - 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()) { - if (show_parents) - dumpInfo->ancestors.back() = *die; - } - } - - // Keep up with our indent level - if (die->IsNULL()) { - if (show_parents) - dumpInfo->ancestors.pop_back(); - - if (curr_depth <= 1) - return cu->GetNextCompileUnitOffset(); - else - s->IndentLess(); - } else if (die->HasChildren()) { - if (show_parents) { - DWARFDebugInfoEntry null_die; - dumpInfo->ancestors.push_back(null_die); - } - s->IndentMore(); - } - } else { - if (cu == NULL) - s->PutCString("NULL - cu"); - // We have a compile unit, reset our indent level to zero just in case - s->SetIndentLevel(0); - - // See if we are dumping everything? - if (dumpInfo->die_offset == DW_INVALID_OFFSET) { - // We are dumping everything - if (cu) { - cu->Dump(s); - return cu->GetFirstDIEOffset(); // Return true to parse all DIEs in this - // Compile Unit - } else { - return DW_INVALID_OFFSET; - } - } else { - if (show_parents) { - dumpInfo->ancestors.clear(); - dumpInfo->ancestors.resize(1); - } - - // 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()) { - // 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; - // // We found our compile unit that contains our DIE, just skip to - // dumping the requested DIE... - // return dumpInfo->die_offset; - } else { - // Skip to the next compile unit as the DIE isn't in the current one! - if (cu) { - return cu->GetNextCompileUnitOffset(); - } else { - return DW_INVALID_OFFSET; - } - } - } - } - } - - // Just return the current offset to parse the next CU or DIE entry - return next_offset; -} - -//---------------------------------------------------------------------- -// Dump -// -// Dump the information in the .debug_info section to the specified -// ostream. If die_offset is valid, a single DIE will be dumped. If the -// die_offset is invalid, all the DWARF information will be dumped. Both -// cases will obey a "recurse_depth" or how deep to traverse into the -// children of each DIE entry. A recurse_depth of zero will dump all -// compile unit headers. A recurse_depth of 1 will dump all compile unit -// headers and the DW_TAG_compile unit tags. A depth of 2 will also -// dump all types and functions. -//---------------------------------------------------------------------- -void DWARFDebugInfo::Dump(Stream *s, SymbolFileDWARF *dwarf2Data, - const uint32_t die_offset, - const uint32_t recurse_depth) { - DumpInfo dumpInfo(s, die_offset, recurse_depth); - s->PutCString(".debug_info contents"); - if (dwarf2Data->get_debug_info_data().GetByteSize() > 0) { - if (die_offset == DW_INVALID_OFFSET) - s->PutCString(":\n"); - else { - s->Printf(" for DIE entry at .debug_info[0x%8.8x]", die_offset); - if (recurse_depth != UINT32_MAX) - s->Printf(" recursing %u levels deep.", recurse_depth); - s->EOL(); - } - } else { - s->PutCString(": < EMPTY >\n"); - return; - } - DWARFDebugInfo::Parse(dwarf2Data, DumpCallback, &dumpInfo); -} - -//---------------------------------------------------------------------- -// Dump -// -// Dump the contents of this DWARFDebugInfo object as has been parsed -// and/or modified after it has been parsed. -//---------------------------------------------------------------------- -void DWARFDebugInfo::Dump(Stream *s, const uint32_t die_offset, - const uint32_t recurse_depth) { - DumpInfo dumpInfo(s, die_offset, recurse_depth); - - s->PutCString("Dumping .debug_info section from internal representation\n"); - - CompileUnitColl::const_iterator pos; - uint32_t curr_depth = 0; - ParseCompileUnitHeadersIfNeeded(); - for (pos = m_compile_units.begin(); pos != m_compile_units.end(); ++pos) { - DWARFUnit *cu = pos->get(); - DumpCallback(m_dwarf2Data, cu, NULL, 0, curr_depth, &dumpInfo); - - const DWARFDIE die = cu->DIE(); - if (die) - die.Dump(s, recurse_depth); - } -} + Index: source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -196,7 +196,7 @@ bool DWARFDebugInfoEntry::Extract(SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, lldb::offset_t *offset_ptr) { - const DWARFDataExtractor &debug_info_data = dwarf2Data->get_debug_info_data(); + const DWARFDataExtractor &debug_info_data = cu->GetData(); // const DWARFDataExtractor& debug_str_data = // dwarf2Data->get_debug_str_data(); const uint32_t cu_end_offset = cu->GetNextCompileUnitOffset(); @@ -404,8 +404,7 @@ lldb::ModuleSP module = dwarf2Data->GetObjectFile()->GetModule(); if (abbrevDecl) { - const DWARFDataExtractor &debug_info_data = - dwarf2Data->get_debug_info_data(); + const DWARFDataExtractor &debug_info_data = cu->GetData(); if (!debug_info_data.ValidOffset(offset)) return false; @@ -588,7 +587,7 @@ void DWARFDebugInfoEntry::Dump(SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, Stream &s, uint32_t recurse_depth) const { - const DWARFDataExtractor &debug_info_data = dwarf2Data->get_debug_info_data(); + const DWARFDataExtractor &debug_info_data = cu->GetData(); lldb::offset_t offset = m_offset; if (debug_info_data.ValidOffset(offset)) { @@ -782,8 +781,7 @@ } if (abbrevDecl) { - const DWARFDataExtractor &debug_info_data = - dwarf2Data->get_debug_info_data(); + const DWARFDataExtractor &debug_info_data = cu->GetData(); if (fixed_form_sizes.Empty()) fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize( @@ -864,8 +862,7 @@ uint32_t attr_idx = abbrevDecl->FindAttributeIndex(attr); if (attr_idx != DW_INVALID_INDEX) { - const DWARFDataExtractor &debug_info_data = - dwarf2Data->get_debug_info_data(); + const DWARFDataExtractor &debug_info_data = cu->GetData(); uint32_t idx = 0; while (idx < attr_idx) @@ -1785,8 +1782,7 @@ // Make sure the abbreviation code still matches. If it doesn't and // 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); + const uint64_t abbrev_code = cu->GetData().GetULEB128(&offset); if (abbrev_decl->Code() == abbrev_code) return abbrev_decl; Index: source/Plugins/SymbolFile/DWARF/DWARFFormValue.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFFormValue.h +++ source/Plugins/SymbolFile/DWARF/DWARFFormValue.h @@ -10,6 +10,7 @@ #ifndef SymbolFileDWARF_DWARFFormValue_h_ #define SymbolFileDWARF_DWARFFormValue_h_ +#include "DWARFDIE.h" #include "DWARFDataExtractor.h" #include // for NULL @@ -67,6 +68,7 @@ const uint8_t *BlockData() const; uint64_t Reference() const; uint64_t Reference(dw_offset_t offset) const; + DWARFDIE GetTypeSignatureDIE() const; bool Boolean() const { return m_value.value.uval != 0; } uint64_t Unsigned() const { return m_value.value.uval; } void SetUnsigned(uint64_t uval) { m_value.value.uval = uval; } Index: source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -580,6 +580,13 @@ die_offset += m_cu->GetOffset(); break; + case DW_FORM_ref_sig8: + // CU must be valid since we will need to back up into the debug info and + // find the DIE offset of the type in the type unit. + assert(m_cu); + die_offset = m_cu->FindTypeSignatureDIEOffset(m_value.value.uval); + break; + default: break; } @@ -598,6 +605,14 @@ die_offset += base_offset; break; + case DW_FORM_ref_sig8: + // CU must be valid since we will need to back up into the debug info and + // find the DIE offset of the type in the type unit. + assert(m_cu); + die_offset = + m_cu->FindTypeSignatureDIEOffset(m_value.value.uval) + base_offset; + break; + default: break; } @@ -605,6 +620,17 @@ return die_offset; } +DWARFDIE DWARFFormValue::GetTypeSignatureDIE() const { + if (m_form == DW_FORM_ref_sig8) { + // CU must be valid since we will need to back up into the debug info and + // find the DIE offset of the type in the type unit. + assert(m_cu); + return m_cu->FindTypeSignatureDIE(m_value.value.uval); + } + + return DWARFDIE(); +} + const uint8_t *DWARFFormValue::BlockData() const { return m_value.data; } bool DWARFFormValue::IsBlockForm(const dw_form_t form) { Index: source/Plugins/SymbolFile/DWARF/DWARFUnit.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -15,12 +15,15 @@ #include "lldb/lldb-enumerations.h" class DWARFUnit; +class DWARFTypeUnit; class DWARFCompileUnit; class NameToDIE; class SymbolFileDWARF; class SymbolFileDWARFDwo; typedef std::shared_ptr DWARFUnitSP; +typedef std::shared_ptr DWARFTypeUnitSP; +typedef std::shared_ptr DWARFCompileUnitSP; enum DWARFProducer { eProducerInvalid = 0, @@ -36,6 +39,12 @@ public: virtual ~DWARFUnit(); + bool ExtractHeader(SymbolFileDWARF *dwarf, + const lldb_private::DWARFDataExtractor &data, + lldb::offset_t *offset_ptr); + + DWARFTypeUnit *GetAsTypeUnit(); + DWARFCompileUnit *GetAsCompileUnit(); size_t ExtractDIEsIfNeeded(bool cu_die_only); DWARFDIE LookupAddress(const dw_addr_t address); size_t AppendDIEsWithTag(const dw_tag_t tag, @@ -43,28 +52,55 @@ uint32_t depth = UINT32_MAX) const; bool Verify(lldb_private::Stream *s) const; virtual void Dump(lldb_private::Stream *s) const = 0; + //------------------------------------------------------------------ + /// Get the data that contains the DIE information for this unit. + /// + /// This will return the correct bytes that contain the data for + /// this DWARFUnit. It could be .debug_info or .debug_types + /// depending on where the data for this unit originates. + /// + /// @return + /// The correct data for the DIE information in this unit. + //------------------------------------------------------------------ + virtual const lldb_private::DWARFDataExtractor &GetData() const = 0; + //------------------------------------------------------------------ + /// Get the size in bytes of the compile unit header. + /// + /// @return + /// Byte size of the compile unit header + //------------------------------------------------------------------ + virtual uint32_t GetHeaderByteSize() const = 0; // Offset of the initial length field. dw_offset_t GetOffset() const { return m_offset; } lldb::user_id_t GetID() const; - // Size in bytes of the initial length + compile unit header. - uint32_t Size() const; + //------------------------------------------------------------------ + /// Get the size in bytes of the length field in the header. + /// + /// In DWARF32 this is just 4 bytes, and DWARF64 it is 12 where 4 + /// are 0xFFFFFFFF followed by the actual 64 bit length. + /// + /// @return + /// Byte size of the compile unit header length field + //------------------------------------------------------------------ + size_t GetLengthByteSize() const { return IsDWARF64() ? 12 : 4; } + 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 GetFirstDIEOffset() const { return m_offset + GetHeaderByteSize(); } dw_offset_t GetNextCompileUnitOffset() const; // Size of the CU data (without initial length and without header). size_t GetDebugInfoSize() const; // Size of the CU data incl. header but without initial length. - uint32_t GetLength() const; - uint16_t GetVersion() const; + uint32_t GetLength() const { return m_length; } + uint16_t GetVersion() const { return m_version; } const DWARFAbbreviationDeclarationSet *GetAbbreviations() const; dw_offset_t GetAbbrevOffset() const; - uint8_t GetAddressByteSize() const; - dw_addr_t GetBaseAddress() const; - dw_addr_t GetAddrBase() const; - dw_addr_t GetRangesBase() 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); void ClearDIEs(bool keep_compile_unit_die); @@ -124,7 +160,7 @@ lldb::LanguageType GetLanguageType(); - bool IsDWARF64() const; + bool IsDWARF64() const { return m_is_dwarf64; } bool GetIsOptimized(); @@ -132,6 +168,10 @@ dw_offset_t GetBaseObjOffset() const; + DWARFDIE FindTypeSignatureDIE(uint64_t type_sig) const; + + dw_offset_t FindTypeSignatureDIEOffset(uint64_t type_sig) const; + protected: DWARFUnit(SymbolFileDWARF *dwarf); Index: source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -17,10 +17,12 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/Timer.h" +#include "DWARFCompileUnit.h" #include "DWARFDIECollection.h" #include "DWARFDebugAbbrev.h" #include "DWARFDebugAranges.h" #include "DWARFDebugInfo.h" +#include "DWARFTypeUnit.h" #include "LogChannelDWARF.h" #include "SymbolFileDWARFDebugMap.h" #include "SymbolFileDWARFDwo.h" @@ -73,16 +75,16 @@ uint32_t depth = 0; // We are in our compile unit, parse starting at the offset // we were told to parse - const DWARFDataExtractor &debug_info_data = m_dwarf->get_debug_info_data(); + const DWARFDataExtractor &data = GetData(); 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); + IsDWARF64()); while (offset < next_cu_offset && - die.FastExtract(debug_info_data, this, fixed_form_sizes, &offset)) { + die.FastExtract(data, this, fixed_form_sizes, &offset)) { // if (log) // log->Printf("0x%8.8x: %*.*s%s%s", // die.GetOffset(), @@ -193,7 +195,7 @@ // The average bytes per DIE entry has been seen to be around 14-20 so lets // pre-reserve half of that since we are now stripping the NULL tags. - + // Only reserve the memory if we are adding children of the main compile unit // DIE. The compile unit DIE is always the first entry, so if our size is 1, // then we are adding the first compile unit child DIE and should reserve @@ -268,19 +270,14 @@ return local_id; } -uint32_t DWARFUnit::Size() const { return IsDWARF64() ? 23 : 11; } - dw_offset_t DWARFUnit::GetNextCompileUnitOffset() const { - return m_offset + (IsDWARF64() ? 12 : 4) + GetLength(); + return m_offset + GetLengthByteSize() + GetLength(); } size_t DWARFUnit::GetDebugInfoSize() const { - return (IsDWARF64() ? 12 : 4) + GetLength() - Size(); + return GetLengthByteSize() + GetLength() - GetHeaderByteSize(); } -uint32_t DWARFUnit::GetLength() const { return m_length; } -uint16_t DWARFUnit::GetVersion() const { return m_version; } - const DWARFAbbreviationDeclarationSet *DWARFUnit::GetAbbreviations() const { return m_abbrevs; } @@ -289,14 +286,6 @@ return m_abbrevs ? m_abbrevs->GetOffset() : DW_INVALID_OFFSET; } -uint8_t DWARFUnit::GetAddressByteSize() const { return m_addr_size; } - -dw_addr_t DWARFUnit::GetBaseAddress() const { return m_base_addr; } - -dw_addr_t DWARFUnit::GetAddrBase() const { return m_addr_base; } - -dw_addr_t DWARFUnit::GetRangesBase() const { return m_ranges_base; } - void DWARFUnit::SetAddrBase(dw_addr_t addr_base, dw_addr_t ranges_base, dw_offset_t base_obj_offset) { @@ -328,6 +317,10 @@ void DWARFUnit::BuildAddressRangeTable(SymbolFileDWARF *dwarf, DWARFDebugAranges *debug_aranges) { + // No addresses in a type unit + if (GetAsTypeUnit()) + return; + // This function is usually called if there in no .debug_aranges section // in order to produce a compile unit level set of address ranges that // is accurate. @@ -625,8 +618,6 @@ return m_language_type; } -bool DWARFUnit::IsDWARF64() const { return m_is_dwarf64; } - bool DWARFUnit::GetIsOptimized() { if (m_is_optimized == eLazyBoolCalculate) { const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); @@ -1012,3 +1003,60 @@ } return *m_func_aranges_ap.get(); } + +DWARFDIE DWARFUnit::FindTypeSignatureDIE(uint64_t type_sig) const { + if (auto cu = m_dwarf->DebugInfo()->GetTypeUnitForSignature(type_sig)) + return cu->GetTypeUnitDIE(); + return DWARFDIE(); +} + +dw_offset_t +DWARFUnit::FindTypeSignatureDIEOffset(uint64_t type_sig) const { + if (auto cu = m_dwarf->DebugInfo()->GetTypeUnitForSignature(type_sig)) + return cu->GetTypeUnitDIEOffset(); + return DW_INVALID_OFFSET; +} + +DWARFTypeUnit *DWARFUnit::GetAsTypeUnit() { + if (GetUnitDIEOnly().Tag() == DW_TAG_type_unit) + return static_cast(this); + return nullptr; +} + +DWARFCompileUnit *DWARFUnit::GetAsCompileUnit() { + if (GetUnitDIEOnly().Tag() == DW_TAG_compile_unit) + return static_cast(this); + return nullptr; +} + +bool +DWARFUnit::ExtractHeader(SymbolFileDWARF *dwarf, + const lldb_private::DWARFDataExtractor &data, + lldb::offset_t *offset_ptr) { + m_offset = *offset_ptr; + + if (data.ValidOffset(*offset_ptr)) { + dw_offset_t abbr_offset; + const DWARFDebugAbbrev *abbr = dwarf->DebugAbbrev(); + m_length = data.GetDWARFInitialLength(offset_ptr); + m_is_dwarf64 = data.IsDWARF64(); + m_version = data.GetU16(offset_ptr); + abbr_offset = data.GetDWARFOffset(offset_ptr); + m_addr_size = data.GetU8(offset_ptr); + + bool length_OK = data.ValidOffset(GetNextCompileUnitOffset() - 1); + bool version_OK = SymbolFileDWARF::SupportedVersion(m_version); + bool abbr_offset_OK = + dwarf->get_debug_abbrev_data().ValidOffset(abbr_offset); + bool addr_size_OK = (m_addr_size == 4) || (m_addr_size == 8); + + if (length_OK && version_OK && addr_size_OK && abbr_offset_OK && abbr) { + m_abbrevs = abbr->GetAbbreviationDeclarationSet(abbr_offset); + return m_abbrevs != nullptr; + } + + // reset the offset to where we tried to parse from if anything went wrong + *offset_ptr = m_offset; + } + return false; +} Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -246,6 +246,7 @@ const lldb_private::DWARFDataExtractor &get_debug_ranges_data(); const lldb_private::DWARFDataExtractor &get_debug_str_data(); const lldb_private::DWARFDataExtractor &get_debug_str_offsets_data(); + const lldb_private::DWARFDataExtractor &get_debug_types_data(); const lldb_private::DWARFDataExtractor &get_apple_names_data(); const lldb_private::DWARFDataExtractor &get_apple_types_data(); const lldb_private::DWARFDataExtractor &get_apple_namespaces_data(); @@ -491,6 +492,7 @@ DWARFDataSegment m_data_debug_ranges; DWARFDataSegment m_data_debug_str; DWARFDataSegment m_data_debug_str_offsets; + DWARFDataSegment m_data_debug_types; DWARFDataSegment m_data_apple_names; DWARFDataSegment m_data_apple_types; DWARFDataSegment m_data_apple_namespaces; Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -501,21 +501,6 @@ if (section_list == NULL) return 0; - // On non Apple platforms we might have .debug_types debug info that - // is created by using "-fdebug-types-section". LLDB currently will try - // to load this debug info, but it causes crashes during debugging when - // types are missing since it doesn't know how to parse the info in - // the .debug_types type units. This causes all complex debug info - // types to be unresolved. Because this causes LLDB to crash and since - // it really doesn't provide a solid debuggiung experience, we should - // disable trying to debug this kind of DWARF until support gets - // added or deprecated. - if (section_list->FindSectionByName(ConstString(".debug_types"))) { - m_obj_file->GetModule()->ReportWarning( - "lldb doesn’t support .debug_types debug info"); - return 0; - } - uint64_t debug_abbrev_file_size = 0; uint64_t debug_info_file_size = 0; uint64_t debug_line_file_size = 0; @@ -591,8 +576,24 @@ const DWARFDataExtractor & SymbolFileDWARF::GetCachedSectionData(lldb::SectionType sect_type, DWARFDataSegment &data_segment) { - llvm::call_once(data_segment.m_flag, [this, sect_type, &data_segment] { + llvm::call_once(data_segment.m_flag, [&] { this->LoadSectionData(sect_type, std::ref(data_segment.m_data)); + if (sect_type == eSectionTypeDWARFDebugTypes) { + // To add .debug_types support in DWARF 4 and earlier with minimally + // invasive changes to the current DWARF parsing code, we pretend that + // any DIEs in .debug_types start at the end of the .debug_info section. + // All info in .debug_types is relative and has no external DIE + // references unless thay are DW_AT_signature references, so the DIE + // offset for things in the .debug_types. If we do this, then we can + // just add the type units to the compile units collection and treat all + // information just as we do for all other information in the DWARF and + // everything just works. If we were to try to split this out, we would + // end up having to change a TON of code. Also DWARF 5 will have compile + // and type units in the .debug_info, so coding it this way will prepare + // use for an easy transition to DWARF 5. + uint64_t debug_info_size = get_debug_info_data().GetByteSize(); + data_segment.m_data.OffsetData(debug_info_size); + } }); return data_segment.m_data; } @@ -664,6 +665,10 @@ m_data_debug_str_offsets); } +const DWARFDataExtractor &SymbolFileDWARF::get_debug_types_data() { + return GetCachedSectionData(eSectionTypeDWARFDebugTypes, m_data_debug_types); +} + const DWARFDataExtractor &SymbolFileDWARF::get_apple_names_data() { return GetCachedSectionData(eSectionTypeDWARFAppleNames, m_data_apple_names); } @@ -799,12 +804,10 @@ cu_sp.reset(new CompileUnit( module_sp, dwarf_cu, cu_file_spec, dwarf_cu->GetID(), cu_language, is_optimized ? eLazyBoolYes : eLazyBoolNo)); - if (cu_sp) { + if (dwarf_cu->GetAsCompileUnit() && cu_sp) { // If we just created a compile unit with an invalid file spec, - // try and get the - // first entry in the supports files from the line table as that - // should be the - // compile unit. + // try and get the first entry in the supports files from the + // line table as that should be the compile unit. if (!cu_file_spec) { cu_file_spec = cu_sp->GetSupportFiles().GetFileSpecAtIndex(1); if (cu_file_spec) { @@ -814,16 +817,16 @@ cu_sp->GetSupportFiles().Replace(0, cu_file_spec); } } + } - dwarf_cu->SetUserData(cu_sp.get()); + dwarf_cu->SetUserData(cu_sp.get()); - // Figure out the compile unit index if we weren't given one - if (cu_idx == UINT32_MAX) - DebugInfo()->GetCompileUnit(dwarf_cu->GetOffset(), &cu_idx); + // Figure out the compile unit index if we weren't given one + if (cu_idx == UINT32_MAX) + DebugInfo()->GetCompileUnit(dwarf_cu->GetOffset(), &cu_idx); - m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex( - cu_idx, cu_sp); - } + m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex( + cu_idx, cu_sp); } } } @@ -3794,7 +3797,7 @@ location_is_const_value_data = true; // The constant value will be either a block, a data value or a // string. - const DWARFDataExtractor &debug_info_data = get_debug_info_data(); + auto debug_info_data = die.GetData(); if (DWARFFormValue::IsBlockForm(form_value.Form())) { // Retrieve the value as a block expression. uint32_t block_offset = @@ -3851,12 +3854,12 @@ location_is_const_value_data = false; has_explicit_location = true; if (DWARFFormValue::IsBlockForm(form_value.Form())) { - const DWARFDataExtractor &debug_info_data = get_debug_info_data(); + auto debug_info_data = die.GetData(); uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); uint32_t block_length = form_value.Unsigned(); - location.CopyOpcodeData(module, get_debug_info_data(), + location.CopyOpcodeData(module, debug_info_data, block_offset, block_length); } else { const DWARFDataExtractor &debug_loc_data = get_debug_loc_data(); Index: source/Symbol/ObjectFile.cpp =================================================================== --- source/Symbol/ObjectFile.cpp +++ source/Symbol/ObjectFile.cpp @@ -359,6 +359,7 @@ case eSectionTypeDWARFDebugRanges: case eSectionTypeDWARFDebugStr: case eSectionTypeDWARFDebugStrOffsets: + case eSectionTypeDWARFDebugTypes: case eSectionTypeDWARFAppleNames: case eSectionTypeDWARFAppleTypes: case eSectionTypeDWARFAppleNamespaces: