Index: source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h +++ source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -14,33 +14,21 @@ class DWARFCompileUnit : public DWARFUnit { public: - static llvm::Expected - extract(SymbolFileDWARF *dwarf2Data, lldb::user_id_t uid, - 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. - /// - /// \return - /// Byte size of the compile unit header - uint32_t GetHeaderByteSize() const override; - DIERef::Section GetDebugSection() const override { return DIERef::Section::DebugInfo; } private: - DWARFCompileUnit(SymbolFileDWARF *dwarf2Data, lldb::user_id_t uid); + DWARFCompileUnit(SymbolFileDWARF *dwarf, lldb::user_id_t uid, + const DWARFUnitHeader &header, + const DWARFAbbreviationDeclarationSet &abbrevs) + : DWARFUnit(dwarf, uid, header, abbrevs) {} + DISALLOW_COPY_AND_ASSIGN(DWARFCompileUnit); + + friend class DWARFUnit; }; #endif // SymbolFileDWARF_DWARFCompileUnit_h_ Index: source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -8,104 +8,15 @@ #include "DWARFCompileUnit.h" -#include "SymbolFileDWARF.h" #include "lldb/Utility/Stream.h" -#include "llvm/Object/Error.h" using namespace lldb; using namespace lldb_private; -DWARFCompileUnit::DWARFCompileUnit(SymbolFileDWARF *dwarf2Data, - lldb::user_id_t uid) - : DWARFUnit(dwarf2Data, uid) {} - - -llvm::Expected DWARFCompileUnit::extract( - SymbolFileDWARF *dwarf2Data, user_id_t uid, - const DWARFDataExtractor &debug_info, lldb::offset_t *offset_ptr) { - assert(debug_info.ValidOffset(*offset_ptr)); - - // std::make_shared would require the ctor to be public. - std::shared_ptr cu_sp( - new DWARFCompileUnit(dwarf2Data, uid)); - - cu_sp->m_offset = *offset_ptr; - - dw_offset_t abbr_offset; - const DWARFDebugAbbrev *abbr = dwarf2Data->DebugAbbrev(); - if (!abbr) - return llvm::make_error( - "No debug_abbrev data"); - - cu_sp->m_length = debug_info.GetDWARFInitialLength(offset_ptr); - 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->GetNextUnitOffset() - 1); - bool version_OK = SymbolFileDWARF::SupportedVersion(cu_sp->m_version); - bool abbr_offset_OK = - dwarf2Data->GetDWARFContext().getOrLoadAbbrevData().ValidOffset( - abbr_offset); - bool addr_size_OK = (cu_sp->m_addr_size == 4) || (cu_sp->m_addr_size == 8); - - if (!length_OK) - return llvm::make_error( - "Invalid compile unit length"); - if (!version_OK) - return llvm::make_error( - "Unsupported compile unit version"); - if (!abbr_offset_OK) - return llvm::make_error( - "Abbreviation offset for compile unit is not valid"); - if (!addr_size_OK) - return llvm::make_error( - "Invalid compile unit address size"); - - cu_sp->m_abbrevs = abbr->GetAbbreviationDeclarationSet(abbr_offset); - if (!cu_sp->m_abbrevs) - return llvm::make_error( - "No abbrev exists at the specified offset."); - - return cu_sp; -} - void DWARFCompileUnit::Dump(Stream *s) const { s->Printf("0x%8.8x: Compile Unit: length = 0x%8.8x, version = 0x%4.4x, " "abbr_offset = 0x%8.8x, addr_size = 0x%2.2x (next CU at " "{0x%8.8x})\n", - m_offset, m_length, m_version, GetAbbrevOffset(), m_addr_size, - GetNextUnitOffset()); -} - -uint32_t DWARFCompileUnit::GetHeaderByteSize() const { - if (m_version < 5) - return 11; - - switch (m_unit_type) { - case llvm::dwarf::DW_UT_compile: - case llvm::dwarf::DW_UT_partial: - return 12; - case llvm::dwarf::DW_UT_skeleton: - case llvm::dwarf::DW_UT_split_compile: - return 20; - case llvm::dwarf::DW_UT_type: - case llvm::dwarf::DW_UT_split_type: - return 24; - } - llvm_unreachable("invalid UnitType."); -} - -const lldb_private::DWARFDataExtractor &DWARFCompileUnit::GetData() const { - return m_dwarf->GetDWARFContext().getOrLoadDebugInfoData(); + GetOffset(), GetLength(), GetVersion(), GetAbbrevOffset(), + GetAddressByteSize(), GetNextUnitOffset()); } Index: source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -81,23 +81,22 @@ lldb::offset_t offset = 0; const auto &debug_info_data = m_context.getOrLoadDebugInfoData(); - while (debug_info_data.ValidOffset(offset)) { - llvm::Expected cu_sp = DWARFCompileUnit::extract( + llvm::Expected unit_sp = DWARFUnit::extract( m_dwarf2Data, m_units.size(), debug_info_data, &offset); - if (!cu_sp) { + if (!unit_sp) { // FIXME: Propagate this error up. - llvm::consumeError(cu_sp.takeError()); + llvm::consumeError(unit_sp.takeError()); return; } // If it didn't return an error, then it should be returning a valid Unit. - assert(*cu_sp); + assert(*unit_sp); - m_units.push_back(*cu_sp); + m_units.push_back(*unit_sp); - offset = (*cu_sp)->GetNextUnitOffset(); + offset = (*unit_sp)->GetNextUnitOffset(); } } Index: source/Plugins/SymbolFile/DWARF/DWARFUnit.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -31,11 +31,46 @@ eProcucerOther }; +/// Base class describing the header of any kind of "unit." Some information +/// is specific to certain unit types. We separate this class out so we can +/// parse the header before deciding what specific kind of unit to construct. +class DWARFUnitHeader { + dw_offset_t m_offset = 0; + dw_offset_t m_length = 0; + uint16_t m_version = 0; + dw_offset_t m_abbr_offset = 0; + uint8_t m_unit_type = 0; + uint8_t m_addr_size = 0; + uint64_t m_dwo_id = 0; + + DWARFUnitHeader() = default; + +public: + dw_offset_t GetOffset() const { return m_offset; } + uint16_t GetVersion() const { return m_version; } + uint16_t GetAddressByteSize() const { return m_addr_size; } + dw_offset_t GetLength() const { return m_length; } + dw_offset_t GetAbbrOffset() const { return m_abbr_offset; } + uint8_t GetUnitType() const { return m_unit_type; } + bool IsTypeUnit() const { + return m_unit_type == DW_UT_type || m_unit_type == DW_UT_split_type; + } + uint32_t GetNextUnitOffset() const { return m_offset + m_length + 4; } + + static llvm::Expected + extract(const lldb_private::DWARFDataExtractor &data, + lldb::offset_t *offset_ptr); +}; + class DWARFUnit : public lldb_private::UserID { using die_iterator_range = llvm::iterator_range; public: + static llvm::Expected + extract(SymbolFileDWARF *dwarf2Data, lldb::user_id_t uid, + const lldb_private::DWARFDataExtractor &debug_info, + lldb::offset_t *offset_ptr); virtual ~DWARFUnit(); void ExtractUnitDIEIfNeeded(); @@ -66,14 +101,16 @@ /// /// \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. + const lldb_private::DWARFDataExtractor &GetData() const; + + /// Get the size in bytes of the unit header. /// /// \return - /// Byte size of the compile unit header - virtual uint32_t GetHeaderByteSize() const = 0; + /// Byte size of the unit header + uint32_t GetHeaderByteSize() const; + // Offset of the initial length field. - dw_offset_t GetOffset() const { return m_offset; } + dw_offset_t GetOffset() const { return m_header.GetOffset(); } /// Get the size in bytes of the length field in the header. /// /// In DWARF32 this is just 4 bytes @@ -87,17 +124,17 @@ die_offset < GetNextUnitOffset(); } dw_offset_t GetFirstDIEOffset() const { - return m_offset + GetHeaderByteSize(); + return GetOffset() + GetHeaderByteSize(); } - dw_offset_t GetNextUnitOffset() const; + dw_offset_t GetNextUnitOffset() const { return m_header.GetNextUnitOffset(); } // 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 { return m_length; } - uint16_t GetVersion() const { return m_version; } + uint32_t GetLength() const { return m_header.GetLength(); } + uint16_t GetVersion() const { return m_header.GetVersion(); } const DWARFAbbreviationDeclarationSet *GetAbbreviations() const; dw_offset_t GetAbbrevOffset() const; - uint8_t GetAddressByteSize() const { return m_addr_size; } + uint8_t GetAddressByteSize() const { return m_header.GetAddressByteSize(); } 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; } @@ -170,10 +207,13 @@ virtual DIERef::Section GetDebugSection() const = 0; protected: - DWARFUnit(SymbolFileDWARF *dwarf, lldb::user_id_t uid); + DWARFUnit(SymbolFileDWARF *dwarf, lldb::user_id_t uid, + const DWARFUnitHeader &header, + const DWARFAbbreviationDeclarationSet &abbrevs); SymbolFileDWARF *m_dwarf = nullptr; std::unique_ptr m_dwo_symbol_file; + DWARFUnitHeader m_header; const DWARFAbbreviationDeclarationSet *m_abbrevs = nullptr; void *m_user_data = nullptr; // The compile unit debug information entry item @@ -193,11 +233,6 @@ // exact DW_TAG_subprogram DIEs std::unique_ptr m_func_aranges_up; dw_addr_t m_base_addr = 0; - dw_offset_t m_length = 0; - uint16_t m_version = 0; - uint8_t m_addr_size = 0; - uint8_t m_unit_type = 0; - uint64_t m_dwo_id = 0; DWARFProducer m_producer = eProducerInvalid; uint32_t m_producer_version_major = 0; uint32_t m_producer_version_minor = 0; @@ -211,8 +246,6 @@ // in the main object file dw_offset_t m_base_obj_offset = DW_INVALID_OFFSET; dw_offset_t m_str_offsets_base = 0; // Value of DW_AT_str_offsets_base. - // Offset of the initial length field. - dw_offset_t m_offset; private: void ParseProducerInfo(); Index: source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -16,7 +16,9 @@ #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" +#include "llvm/Object/Error.h" +#include "DWARFCompileUnit.h" #include "DWARFDebugAranges.h" #include "DWARFDebugInfo.h" #include "LogChannelDWARF.h" @@ -29,10 +31,13 @@ extern int g_verbose; -DWARFUnit::DWARFUnit(SymbolFileDWARF *dwarf, user_id_t uid) - : UserID(uid), m_dwarf(dwarf), m_cancel_scopes(false) {} +DWARFUnit::DWARFUnit(SymbolFileDWARF *dwarf, lldb::user_id_t uid, + const DWARFUnitHeader &header, + const DWARFAbbreviationDeclarationSet &abbrevs) + : UserID(uid), m_dwarf(dwarf), m_header(header), m_abbrevs(&abbrevs), + m_cancel_scopes(false) {} -DWARFUnit::~DWARFUnit() {} +DWARFUnit::~DWARFUnit() = default; // Parses first DIE of a compile unit. void DWARFUnit::ExtractUnitDIEIfNeeded() { @@ -46,8 +51,8 @@ return; // Already parsed static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, "%8.8x: DWARFUnit::ExtractUnitDIEIfNeeded()", m_offset); + Timer scoped_timer(func_cat, "%8.8x: DWARFUnit::ExtractUnitDIEIfNeeded()", + GetOffset()); // Set the offset to that of the first DIE and calculate the start of the // next compilation unit header. @@ -145,8 +150,8 @@ llvm::sys::ScopedWriter first_die_lock(m_first_die_mutex); static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, "%8.8x: DWARFUnit::ExtractDIEsIfNeeded()", m_offset); + Timer scoped_timer(func_cat, "%8.8x: DWARFUnit::ExtractDIEsIfNeeded()", + GetOffset()); // Set the offset to that of the first DIE and calculate the start of the // next compilation unit header. @@ -332,7 +337,7 @@ DW_AT_GNU_ranges_base, 0); dwo_cu->SetRangesBase(ranges_base); - dwo_cu->SetBaseObjOffset(m_offset); + dwo_cu->SetBaseObjOffset(GetOffset()); SetDwoStrOffsetsBase(dwo_cu); } @@ -366,10 +371,6 @@ return dies.size() - old_size; } -dw_offset_t DWARFUnit::GetNextUnitOffset() const { - return m_offset + GetLengthByteSize() + GetLength(); -} - size_t DWARFUnit::GetDebugInfoSize() const { return GetLengthByteSize() + GetLength() - GetHeaderByteSize(); } @@ -790,3 +791,92 @@ return *m_func_aranges_up; } +llvm::Expected +DWARFUnitHeader::extract(const DWARFDataExtractor &data, + lldb::offset_t *offset_ptr) { + DWARFUnitHeader header; + header.m_offset = *offset_ptr; + header.m_length = data.GetDWARFInitialLength(offset_ptr); + header.m_version = data.GetU16(offset_ptr); + if (header.m_version == 5) { + header.m_unit_type = data.GetU8(offset_ptr); + header.m_addr_size = data.GetU8(offset_ptr); + header.m_abbr_offset = data.GetDWARFOffset(offset_ptr); + if (header.m_unit_type == llvm::dwarf::DW_UT_skeleton) + header.m_dwo_id = data.GetU64(offset_ptr); + } else { + header.m_abbr_offset = data.GetDWARFOffset(offset_ptr); + header.m_addr_size = data.GetU8(offset_ptr); + // Only compile units supported so far. + header.m_unit_type = DW_UT_compile; + } + + bool length_OK = data.ValidOffset(header.GetNextUnitOffset() - 1); + bool version_OK = SymbolFileDWARF::SupportedVersion(header.m_version); + bool addr_size_OK = (header.m_addr_size == 4) || (header.m_addr_size == 8); + + if (!length_OK) + return llvm::make_error( + "Invalid unit length"); + if (!version_OK) + return llvm::make_error( + "Unsupported unit version"); + if (!addr_size_OK) + return llvm::make_error( + "Invalid unit address size"); + + return header; +} + +llvm::Expected +DWARFUnit::extract(SymbolFileDWARF *dwarf, user_id_t uid, + const DWARFDataExtractor &debug_info, + lldb::offset_t *offset_ptr) { + assert(debug_info.ValidOffset(*offset_ptr)); + + auto expected_header = DWARFUnitHeader::extract(debug_info, offset_ptr); + if (!expected_header) + return expected_header.takeError(); + + const DWARFDebugAbbrev *abbr = dwarf->DebugAbbrev(); + if (!abbr) + return llvm::make_error( + "No debug_abbrev data"); + + bool abbr_offset_OK = + dwarf->GetDWARFContext().getOrLoadAbbrevData().ValidOffset( + expected_header->GetAbbrOffset()); + if (!abbr_offset_OK) + return llvm::make_error( + "Abbreviation offset for unit is not valid"); + + const DWARFAbbreviationDeclarationSet *abbrevs = + abbr->GetAbbreviationDeclarationSet(expected_header->GetAbbrOffset()); + if (!abbrevs) + return llvm::make_error( + "No abbrev exists at the specified offset."); + + DWARFUnitSP unit_sp( + new DWARFCompileUnit(dwarf, uid, *expected_header, *abbrevs)); + + return unit_sp; +} + +const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const { + return m_dwarf->GetDWARFContext().getOrLoadDebugInfoData(); +} + +uint32_t DWARFUnit::GetHeaderByteSize() const { + switch (m_header.GetUnitType()) { + case llvm::dwarf::DW_UT_compile: + case llvm::dwarf::DW_UT_partial: + return GetVersion() < 5 ? 11 : 12; + case llvm::dwarf::DW_UT_skeleton: + case llvm::dwarf::DW_UT_split_compile: + return 20; + case llvm::dwarf::DW_UT_type: + case llvm::dwarf::DW_UT_split_type: + return GetVersion() < 5 ? 23 : 24; + } + llvm_unreachable("invalid UnitType."); +}