Index: include/lldb/lldb-forward.h =================================================================== --- include/lldb/lldb-forward.h +++ include/lldb/lldb-forward.h @@ -86,6 +86,7 @@ class DiagnosticManager; class Disassembler; class DumpValueObjectOptions; +class DWARFDataExtractor; class DynamicCheckerFunctions; class DynamicLoader; class Editline; Index: packages/Python/lldbsuite/test/lldbtest.py =================================================================== --- packages/Python/lldbsuite/test/lldbtest.py +++ packages/Python/lldbsuite/test/lldbtest.py @@ -1575,6 +1575,23 @@ dictionary, testdir, testname): raise Exception("Don't know how to build binary with gmodules") + def buildDwarfTypeUnits( + self, + architecture=None, + compiler=None, + dictionary=None): + """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, testdir, testname): + raise Exception("Don't know how to build binary with DWARF type units") + def signBinary(self, binary_path): if sys.platform.startswith("darwin"): codesign_cmd = "codesign --force --sign \"%s\" %s" % ( @@ -2396,6 +2413,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 @@ -254,6 +254,12 @@ endif 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) $(ARCH_CXXFLAGS) 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,27 @@ return True +def buildDwarfTypeUnits( + sender=None, + architecture=None, + compiler=None, + dictionary=None, + testdir=None, + testname=None): + """Build the binaries with type units (type in a .debug_types section).""" + commands = [] + 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', 'libstdcxx': 'Test for libstdcxx data formatters', @@ -62,6 +63,8 @@ if platform not in ["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/Plugins/SymbolFile/DWARF/CMakeLists.txt =================================================================== --- source/Plugins/SymbolFile/DWARF/CMakeLists.txt +++ source/Plugins/SymbolFile/DWARF/CMakeLists.txt @@ -25,6 +25,7 @@ DWARFFormValue.cpp DWARFIndex.cpp DWARFUnit.cpp + DWARFTypeUnit.cpp HashedNameToDIE.cpp LogChannelDWARF.cpp ManualDWARFIndex.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" @@ -42,10 +43,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 @@ -251,8 +251,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; @@ -1891,7 +1904,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(); } Index: source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h +++ source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -14,21 +14,11 @@ class DWARFCompileUnit : public DWARFUnit { public: - static DWARFUnitSP Extract(SymbolFileDWARF *dwarf2Data, - const lldb_private::DWARFDataExtractor &debug_info, - lldb::offset_t *offset_ptr); + static DWARFCompileUnitSP Extract(SymbolFileDWARF *dwarf2Data, + const lldb_private::DWARFDataExtractor &debug_info, + 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. /// Index: source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -15,56 +15,17 @@ 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 DWARFDataExtractor &debug_info, lldb::offset_t *offset_ptr) { // std::make_shared would require the ctor to be public. - std::shared_ptr cu_sp(new DWARFCompileUnit(dwarf2Data)); - - 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); - - if (cu_sp->m_version == 5) { - cu_sp->m_unit_type = debug_info.GetU8(offset_ptr); - cu_sp->m_addr_size = debug_info.GetU8(offset_ptr); - abbr_offset = debug_info.GetDWARFOffset(offset_ptr); - - if (cu_sp->m_unit_type == llvm::dwarf::DW_UT_skeleton) - cu_sp->m_dwo_id = debug_info.GetU64(offset_ptr); - } else { - 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; - } - - return nullptr; + DWARFCompileUnitSP cu_sp(new DWARFCompileUnit(dwarf2Data)); + if (cu_sp->ExtractHeader(dwarf2Data, debug_info, offset_ptr)) + return cu_sp; + return DWARFCompileUnitSP(); } void DWARFCompileUnit::Dump(Stream *s) const { @@ -92,7 +53,3 @@ } llvm_unreachable("invalid UnitType."); } - -const lldb_private::DWARFDataExtractor &DWARFCompileUnit::GetData() const { - return m_dwarf->get_debug_info_data(); -} 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); @@ -58,12 +62,14 @@ const DWARFUnitSP &cu_sp); typedef std::vector CompileUnitColl; + typedef llvm::DenseMap 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,18 +95,37 @@ } void DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded() { - if (m_compile_units.empty()) { - if (m_dwarf2Data != NULL) { - lldb::offset_t offset = 0; - DWARFUnitSP 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 (!m_compile_units.empty()) + return; + + if (m_dwarf2Data == nullptr) + return; + + lldb::offset_t offset = 0; + DWARFCompileUnitSP cu_sp; + const auto &raw_debug_info_data = m_dwarf2Data->get_raw_debug_info_data(); + while ((cu_sp = DWARFCompileUnit::Extract(m_dwarf2Data, raw_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 + // 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) + (possible gap) + debug_type_offset + const auto &debug_info_data = m_dwarf2Data->get_debug_info_data(); + offset = m_dwarf2Data->get_debug_types_offset(); + DWARFTypeUnitSP tu_sp; + while ((tu_sp = DWARFTypeUnit::Extract(m_dwarf2Data, debug_info_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(); } } @@ -226,3 +246,9 @@ return DWARFDIE(); // Not found } +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; +} 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 @@ -73,6 +74,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 @@ -629,6 +629,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; } @@ -647,6 +654,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; } @@ -654,6 +669,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/DWARFTypeUnit.h =================================================================== --- /dev/null +++ source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h @@ -0,0 +1,85 @@ +//===-- DWARFTypeUnit.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_DWARFTypeUnit_h_ +#define SymbolFileDWARF_DWARFTypeUnit_h_ + +#include "DWARFUnit.h" + +class DWARFTypeUnit : public DWARFUnit { + friend class DWARFUnit; + +public: + virtual ~DWARFTypeUnit(); + + static DWARFTypeUnitSP Extract(SymbolFileDWARF *dwarf2Data, + const lldb_private::DWARFDataExtractor &data, + lldb::offset_t *offset_ptr); + + void Dump(lldb_private::Stream *s) const override; + + //------------------------------------------------------------------ + /// Get the size in bytes of the header. + /// + /// @return + /// Byte size of the type unit header + //------------------------------------------------------------------ + uint32_t GetHeaderByteSize() const override { + return m_is_dwarf64 ? 39 : 23; + } + + //------------------------------------------------------------------ + /// Get the type DIE offset if this is a type unit. + /// + /// If this unit is a type unit, return type DIE offset for the type + /// in this unit. + /// + /// @return + /// The DIE offset that points to the type unit type if this is + /// a type unit, otherwise return DW_INVALID_OFFSET. + //------------------------------------------------------------------ + dw_offset_t GetTypeUnitDIEOffset() { + return m_offset + m_type_offset; + } + + //------------------------------------------------------------------ + /// Get the type signature for the type contained in this unit. + /// + /// @return + /// The 64 bit type signature for the type contained in this type + /// unit. This value will not be valid if this compile unit is not + /// a type unit. + //------------------------------------------------------------------ + uint64_t GetTypeSignature() const { return m_type_signature; } + + //------------------------------------------------------------------ + /// Get the type DIE if this is a type unit. + /// + /// If this unit is a type unit, return type contained within it as + /// a DWARFDIE object. + /// + /// @return + /// The DIE representing the type if this is a type unit, or an + /// invalid DWARFDIE if this is not a type unit. + //------------------------------------------------------------------ + DWARFDIE GetTypeUnitDIE(); + +protected: + // Type signature contained in a type unit which will be valid (non-zero) + // for type units only. + uint64_t m_type_signature = 0; + // Compile unit relative type offset for type units only. + dw_offset_t m_type_offset = DW_INVALID_OFFSET; + +private: + DWARFTypeUnit(SymbolFileDWARF *dwarf2Data); + DISALLOW_COPY_AND_ASSIGN(DWARFTypeUnit); +}; + +#endif // SymbolFileDWARF_DWARFTypeUnit_h_ Index: source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp =================================================================== --- /dev/null +++ source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp @@ -0,0 +1,53 @@ +//===-- DWARFTypeUnit.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFTypeUnit.h" +#include "DWARFDataExtractor.h" +#include "SymbolFileDWARF.h" +#include "lldb/Utility/Stream.h" + +using namespace lldb; +using namespace lldb_private; + +DWARFTypeUnit::DWARFTypeUnit(SymbolFileDWARF *dwarf2Data) + : DWARFUnit(dwarf2Data) {} + +DWARFTypeUnit::~DWARFTypeUnit() {} + +void DWARFTypeUnit::Dump(Stream *s) const { + s->Printf("0x%8.8x: Type Unit: length = 0x%8.8x, version = 0x%4.4x, " + "abbr_offset = 0x%8.8x, addr_size = 0x%2.2x, " + "type_signature = 0x%16.16" PRIx64 ", type_offset = 0x%8.8x " + "(next CU at {0x%8.8x})\n", + m_offset, m_length, m_version, GetAbbrevOffset(), m_addr_size, + m_type_signature, m_type_offset, GetNextCompileUnitOffset()); +} + +DWARFTypeUnitSP DWARFTypeUnit::Extract(SymbolFileDWARF *dwarf, + 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 DWARFTypeUnit(dwarf)); + // Out of memory? + if (!cu_sp) + return nullptr; + if (cu_sp->ExtractHeader(dwarf, data, offset_ptr)) { + cu_sp->m_type_signature = data.GetU64(offset_ptr); + cu_sp->m_type_offset = data.GetDWARFOffset(offset_ptr); + return cu_sp; + } + // reset the offset to where we tried to parse from if anything went wrong + *offset_ptr = cu_sp->m_offset; + return nullptr; +} + +DWARFDIE DWARFTypeUnit::GetTypeUnitDIE() { + // The type offset is compile unit relative, so we need to add the compile + // unit offset to ensure we get the correct DIE. + return GetDIE(GetTypeUnitDIEOffset()); +} Index: source/Plugins/SymbolFile/DWARF/DWARFUnit.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -17,12 +17,15 @@ #include 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, @@ -39,6 +42,12 @@ public: virtual ~DWARFUnit(); + bool ExtractHeader(SymbolFileDWARF *dwarf, + const lldb_private::DWARFDataExtractor &data, + lldb::offset_t *offset_ptr); + + DWARFTypeUnit *GetAsTypeUnit(); + DWARFCompileUnit *GetAsCompileUnit(); void ExtractUnitDIEIfNeeded(); void ExtractDIEsIfNeeded(); @@ -70,7 +79,7 @@ /// @return /// The correct data for the DIE information in this unit. //------------------------------------------------------------------ - virtual const lldb_private::DWARFDataExtractor &GetData() const = 0; + const lldb_private::DWARFDataExtractor &GetData() const; //------------------------------------------------------------------ /// Get the size in bytes of the compile unit header. /// @@ -176,6 +185,10 @@ return die_iterator_range(m_die_array.begin(), m_die_array.end()); } + 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 @@ -18,9 +18,11 @@ #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" +#include "DWARFCompileUnit.h" #include "DWARFDIECollection.h" #include "DWARFDebugAranges.h" #include "DWARFDebugInfo.h" +#include "DWARFTypeUnit.h" #include "LogChannelDWARF.h" #include "SymbolFileDWARFDebugMap.h" #include "SymbolFileDWARFDwo.h" @@ -429,6 +431,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. @@ -768,3 +774,72 @@ 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); + if (m_version == 5) { + m_unit_type = data.GetU8(offset_ptr); + m_addr_size = data.GetU8(offset_ptr); + abbr_offset = data.GetDWARFOffset(offset_ptr); + + if (m_unit_type == llvm::dwarf::DW_UT_skeleton) + m_dwo_id = data.GetU64(offset_ptr); + } else { + 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; +} + +const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const { + return m_dwarf->get_debug_info_data(); +} Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -242,6 +242,7 @@ const lldb_private::DWARFDataExtractor &get_debug_aranges_data(); const lldb_private::DWARFDataExtractor &get_debug_frame_data(); const lldb_private::DWARFDataExtractor &get_debug_info_data(); + const lldb_private::DWARFDataExtractor &get_raw_debug_info_data(); const lldb_private::DWARFDataExtractor &get_debug_line_data(); const lldb_private::DWARFDataExtractor &get_debug_line_str_data(); const lldb_private::DWARFDataExtractor &get_debug_macro_data(); @@ -251,7 +252,7 @@ const lldb_private::DWARFDataExtractor &get_debug_rnglists_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_raw_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(); @@ -331,6 +332,10 @@ void DumpClangAST(lldb_private::Stream &s) override; + uint64_t get_debug_types_offset() const { + return m_debug_info_concatenated_types_offset; + } + protected: typedef llvm::DenseMap DIEToTypePtr; @@ -477,7 +482,7 @@ DWARFDataSegment m_data_debug_addr; DWARFDataSegment m_data_debug_aranges; DWARFDataSegment m_data_debug_frame; - DWARFDataSegment m_data_debug_info; + DWARFDataSegment m_data_raw_debug_info; DWARFDataSegment m_data_debug_line; DWARFDataSegment m_data_debug_line_str; DWARFDataSegment m_data_debug_macro; @@ -487,13 +492,17 @@ DWARFDataSegment m_data_debug_rnglists; DWARFDataSegment m_data_debug_str; DWARFDataSegment m_data_debug_str_offsets; - DWARFDataSegment m_data_debug_types; + DWARFDataSegment m_data_raw_debug_types; DWARFDataSegment m_data_apple_names; DWARFDataSegment m_data_apple_types; DWARFDataSegment m_data_apple_namespaces; DWARFDataSegment m_data_apple_objc; DWARFDataSegment m_data_gnu_debugaltlink; + llvm::once_flag m_concatenated_data_once; + lldb_private::DWARFDataExtractor m_data_debug_info_concatenated; + uint64_t m_debug_info_concatenated_types_offset; + // The unique pointer items below are generated on demand if and when someone // accesses // them through a non const version of this class. Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -412,7 +412,7 @@ // when this class parses .o files to // contain the .o file index/ID m_debug_map_module_wp(), m_debug_map_symfile(NULL), m_data_debug_abbrev(), - m_data_debug_aranges(), m_data_debug_frame(), m_data_debug_info(), + m_data_debug_aranges(), m_data_debug_frame(), m_data_raw_debug_info(), m_data_debug_line(), m_data_debug_macro(), m_data_debug_loc(), m_data_debug_ranges(), m_data_debug_rnglists(), m_data_debug_str(), m_data_apple_names(), m_data_apple_types(), m_data_apple_namespaces(), @@ -506,20 +506,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; @@ -638,8 +624,9 @@ return GetCachedSectionData(eSectionTypeDWARFDebugFrame, m_data_debug_frame); } -const DWARFDataExtractor &SymbolFileDWARF::get_debug_info_data() { - return GetCachedSectionData(eSectionTypeDWARFDebugInfo, m_data_debug_info); +const DWARFDataExtractor &SymbolFileDWARF::get_raw_debug_info_data() { + return GetCachedSectionData(eSectionTypeDWARFDebugInfo, + m_data_raw_debug_info); } const DWARFDataExtractor &SymbolFileDWARF::get_debug_line_data() { @@ -689,8 +676,9 @@ m_data_debug_str_offsets); } -const DWARFDataExtractor &SymbolFileDWARF::get_debug_types_data() { - return GetCachedSectionData(eSectionTypeDWARFDebugTypes, m_data_debug_types); +const DWARFDataExtractor &SymbolFileDWARF::get_raw_debug_types_data() { + return GetCachedSectionData(eSectionTypeDWARFDebugTypes, + m_data_raw_debug_types); } const DWARFDataExtractor &SymbolFileDWARF::get_apple_names_data() { @@ -715,6 +703,71 @@ m_data_gnu_debugaltlink); } +const DWARFDataExtractor & + SymbolFileDWARF::get_debug_info_data() { + llvm::call_once(m_concatenated_data_once, [&] { + const auto &debug_info_data = get_raw_debug_info_data(); + const auto &debug_types_data = get_raw_debug_types_data(); + if (!debug_info_data.GetByteSize() && !debug_types_data.GetByteSize()) + return; + // For this optimization of mmapped sections we do not handle .debug_types + // present without .debug_info as that should not happen. + if (debug_info_data.GetByteSize() + && (!debug_types_data.GetByteSize() + || debug_info_data.GetDataStart() + debug_info_data.GetByteSize() + <= debug_types_data.GetDataStart())) { + uint64_t length; + if (debug_types_data.GetByteSize()) { + m_debug_info_concatenated_types_offset = + debug_types_data.GetDataStart() - debug_info_data.GetDataStart(); + length = debug_types_data.GetDataStart() + + debug_types_data.GetByteSize() - debug_info_data.GetDataStart(); + } else { + m_debug_info_concatenated_types_offset = debug_info_data.GetByteSize(); + length = debug_info_data.GetByteSize(); + } + if (m_dwarf_data.GetByteSize()) { +//lldbassert(0 && "some OSX case"); + m_data_debug_info_concatenated.SetData(m_dwarf_data, + debug_info_data.GetDataStart() - m_dwarf_data.GetDataStart(), + length); + return; + } + if (!m_obj_file->IsInMemory()) { + const SectionList *section_list = + m_obj_file->GetSectionList(false /* update_module_section_list */); + if (section_list) { + SectionSP section_sp(section_list->FindSectionByType( + eSectionTypeDWARFDebugInfo, true)); + if (section_sp) { + lldbassert(section_sp->GetObjectFile() == m_obj_file); + m_obj_file->GetData(section_sp->GetFileOffset(), length, + m_data_debug_info_concatenated); + return; + } + } + } + } +//lldbassert(0 && "fallback to data copy"); + DataBufferHeap *databufferheap = new DataBufferHeap(); + DataBufferSP databuffer = DataBufferSP(databufferheap); + databufferheap->AppendData( + debug_info_data.GetDataStart(), + debug_info_data.GetByteSize()); + m_debug_info_concatenated_types_offset = + databufferheap->GetByteSize(); + databufferheap->AppendData( + debug_types_data.GetDataStart(), + debug_types_data.GetByteSize()); + m_data_debug_info_concatenated.SetData(databuffer); + m_data_debug_info_concatenated.SetByteOrder( + debug_info_data.GetByteOrder()); + m_data_debug_info_concatenated.SetAddressByteSize( + debug_info_data.GetAddressByteSize()); + }); + return m_data_debug_info_concatenated; +} + DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() { if (m_abbr.get() == NULL) { const DWARFDataExtractor &debug_abbrev_data = get_debug_abbrev_data(); @@ -836,7 +889,7 @@ 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. @@ -849,16 +902,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); } } }