diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -50,7 +50,7 @@ bool Extract(const lldb_private::DWARFDataExtractor &data, const DWARFUnit *cu, lldb::offset_t *offset_ptr); - bool LookupAddress(const dw_addr_t address, const DWARFUnit *cu, + bool LookupAddress(const dw_addr_t address, DWARFUnit *cu, DWARFDebugInfoEntry **function_die, DWARFDebugInfoEntry **block_die); @@ -91,7 +91,7 @@ bool check_specification_or_abstract_origin = false) const; size_t GetAttributeAddressRanges( - const DWARFUnit *cu, DWARFRangeList &ranges, bool check_hi_lo_pc, + DWARFUnit *cu, DWARFRangeList &ranges, bool check_hi_lo_pc, bool check_specification_or_abstract_origin = false) const; const char *GetName(const DWARFUnit *cu) const; @@ -116,7 +116,7 @@ dw_attr_t attr, DWARFFormValue &form_value); bool GetDIENamesAndRanges( - const DWARFUnit *cu, const char *&name, const char *&mangled, + DWARFUnit *cu, const char *&name, const char *&mangled, DWARFRangeList &rangeList, int &decl_file, int &decl_line, int &decl_column, int &call_file, int &call_line, int &call_column, lldb_private::DWARFExpression *frame_base = nullptr) const; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -200,7 +200,7 @@ return false; } -static DWARFRangeList GetRangesOrReportError(const DWARFUnit &unit, +static DWARFRangeList GetRangesOrReportError(DWARFUnit &unit, const DWARFDebugInfoEntry &die, const DWARFFormValue &value) { llvm::Expected expected_ranges = @@ -223,7 +223,7 @@ // Gets the valid address ranges for a given DIE by looking for a // DW_AT_low_pc/DW_AT_high_pc pair, DW_AT_entry_pc, or DW_AT_ranges attributes. bool DWARFDebugInfoEntry::GetDIENamesAndRanges( - const DWARFUnit *cu, const char *&name, const char *&mangled, + DWARFUnit *cu, const char *&name, const char *&mangled, DWARFRangeList &ranges, int &decl_file, int &decl_line, int &decl_column, int &call_file, int &call_line, int &call_column, DWARFExpression *frame_base) const { @@ -766,7 +766,7 @@ } size_t DWARFDebugInfoEntry::GetAttributeAddressRanges( - const DWARFUnit *cu, DWARFRangeList &ranges, bool check_hi_lo_pc, + DWARFUnit *cu, DWARFRangeList &ranges, bool check_hi_lo_pc, bool check_specification_or_abstract_origin) const { ranges.Clear(); @@ -1012,8 +1012,7 @@ return storage.c_str(); } -bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, - const DWARFUnit *cu, +bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, DWARFUnit *cu, DWARFDebugInfoEntry **function_die, DWARFDebugInfoEntry **block_die) { bool found_address = false; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h @@ -48,27 +48,4 @@ range_map m_range_map; }; -// DWARF v5 .debug_rnglists section. -class DWARFDebugRngLists final : public DWARFDebugRangesBase { - struct RngListEntry { - uint8_t encoding; - uint64_t value0; - uint64_t value1; - }; - -public: - void Extract(lldb_private::DWARFContext &context) override; - bool FindRanges(const DWARFUnit *cu, dw_offset_t debug_ranges_offset, - DWARFRangeList &range_list) const override; - uint64_t GetOffset(size_t Index) const; - -protected: - bool ExtractRangeList(const lldb_private::DWARFDataExtractor &data, - uint8_t addrSize, lldb::offset_t *offset_ptr, - std::vector &list); - - std::vector Offsets; - std::map> m_range_map; -}; - #endif // SymbolFileDWARF_DWARFDebugRanges_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp @@ -122,164 +122,3 @@ } return false; } - -bool DWARFDebugRngLists::ExtractRangeList( - const DWARFDataExtractor &data, uint8_t addrSize, - lldb::offset_t *offset_ptr, std::vector &rangeList) { - rangeList.clear(); - - bool error = false; - while (!error) { - switch (data.GetU8(offset_ptr)) { - case DW_RLE_end_of_list: - return true; - - case DW_RLE_start_length: { - dw_addr_t begin = data.GetMaxU64(offset_ptr, addrSize); - dw_addr_t len = data.GetULEB128(offset_ptr); - rangeList.push_back({DW_RLE_start_length, begin, len}); - break; - } - - case DW_RLE_start_end: { - dw_addr_t begin = data.GetMaxU64(offset_ptr, addrSize); - dw_addr_t end = data.GetMaxU64(offset_ptr, addrSize); - rangeList.push_back({DW_RLE_start_end, begin, end}); - break; - } - - case DW_RLE_base_address: { - dw_addr_t base = data.GetMaxU64(offset_ptr, addrSize); - rangeList.push_back({DW_RLE_base_address, base, 0}); - break; - } - - case DW_RLE_offset_pair: { - dw_addr_t begin = data.GetULEB128(offset_ptr); - dw_addr_t end = data.GetULEB128(offset_ptr); - rangeList.push_back({DW_RLE_offset_pair, begin, end}); - break; - } - - case DW_RLE_base_addressx: { - dw_addr_t base = data.GetULEB128(offset_ptr); - rangeList.push_back({DW_RLE_base_addressx, base, 0}); - break; - } - - case DW_RLE_startx_endx: { - dw_addr_t start = data.GetULEB128(offset_ptr); - dw_addr_t end = data.GetULEB128(offset_ptr); - rangeList.push_back({DW_RLE_startx_endx, start, end}); - break; - } - - case DW_RLE_startx_length: { - dw_addr_t start = data.GetULEB128(offset_ptr); - dw_addr_t length = data.GetULEB128(offset_ptr); - rangeList.push_back({DW_RLE_startx_length, start, length}); - break; - } - - default: - lldbassert(0 && "unknown range list entry encoding"); - error = true; - } - } - - return false; -} - -static uint64_t ReadAddressFromDebugAddrSection(const DWARFUnit *cu, - uint32_t index) { - uint32_t index_size = cu->GetAddressByteSize(); - dw_offset_t addr_base = cu->GetAddrBase(); - lldb::offset_t offset = addr_base + index * index_size; - return cu->GetSymbolFileDWARF() - .GetDWARFContext() - .getOrLoadAddrData() - .GetMaxU64(&offset, index_size); -} - -bool DWARFDebugRngLists::FindRanges(const DWARFUnit *cu, - dw_offset_t debug_ranges_offset, - DWARFRangeList &range_list) const { - range_list.Clear(); - dw_addr_t debug_ranges_address = cu->GetRangesBase() + debug_ranges_offset; - auto pos = m_range_map.find(debug_ranges_address); - if (pos != m_range_map.end()) { - dw_addr_t BaseAddr = cu->GetBaseAddress(); - for (const RngListEntry &E : pos->second) { - switch (E.encoding) { - case DW_RLE_start_length: - range_list.Append(DWARFRangeList::Entry(E.value0, E.value1)); - break; - case DW_RLE_base_address: - BaseAddr = E.value0; - break; - case DW_RLE_start_end: - range_list.Append(DWARFRangeList::Entry(E.value0, E.value1 - E.value0)); - break; - case DW_RLE_offset_pair: - range_list.Append( - DWARFRangeList::Entry(BaseAddr + E.value0, E.value1 - E.value0)); - break; - case DW_RLE_base_addressx: { - BaseAddr = ReadAddressFromDebugAddrSection(cu, E.value0); - break; - } - case DW_RLE_startx_endx: { - dw_addr_t start = ReadAddressFromDebugAddrSection(cu, E.value0); - dw_addr_t end = ReadAddressFromDebugAddrSection(cu, E.value1); - range_list.Append(DWARFRangeList::Entry(start, end - start)); - break; - } - case DW_RLE_startx_length: { - dw_addr_t start = ReadAddressFromDebugAddrSection(cu, E.value0); - range_list.Append(DWARFRangeList::Entry(start, E.value1)); - break; - } - default: - llvm_unreachable("unexpected encoding"); - } - } - return true; - } - return false; -} - -void DWARFDebugRngLists::Extract(DWARFContext &context) { - const DWARFDataExtractor &data = context.getOrLoadRngListsData(); - lldb::offset_t offset = 0; - - uint64_t length = data.GetU32(&offset); - // FIXME: Handle DWARF64. - lldb::offset_t end = offset + length; - - // Check version. - if (data.GetU16(&offset) < 5) - return; - - uint8_t addrSize = data.GetU8(&offset); - - // We do not support non-zero segment selector size. - if (data.GetU8(&offset) != 0) { - lldbassert(0 && "not implemented"); - return; - } - - uint32_t offsetsAmount = data.GetU32(&offset); - for (uint32_t i = 0; i < offsetsAmount; ++i) - Offsets.push_back(data.GetMaxU64(&offset, 4)); - - lldb::offset_t listOffset = offset; - std::vector rangeList; - while (offset < end && ExtractRangeList(data, addrSize, &offset, rangeList)) { - m_range_map[listOffset] = rangeList; - listOffset = offset; - } -} - -uint64_t DWARFDebugRngLists::GetOffset(size_t Index) const { - return Offsets[Index]; -} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -216,12 +216,23 @@ /// Return a list of address ranges resulting from a (possibly encoded) /// range list starting at a given offset in the appropriate ranges section. - llvm::Expected FindRnglistFromOffset(dw_offset_t offset) const; + llvm::Expected FindRnglistFromOffset(dw_offset_t offset); /// Return a list of address ranges retrieved from an encoded range /// list whose offset is found via a table lookup given an index (DWARF v5 /// and later). - llvm::Expected FindRnglistFromIndex(uint32_t index) const; + llvm::Expected FindRnglistFromIndex(uint32_t index); + + /// Return a rangelist's offset based on an index. The index designates + /// an entry in the rangelist table's offset array and is supplied by + /// DW_FORM_rnglistx. + llvm::Optional GetRnglistOffset(uint32_t Index) const { + if (!m_rnglist_table) + return llvm::None; + if (llvm::Optional off = m_rnglist_table->getOffsetEntry(Index)) + return *off + m_ranges_base; + return llvm::None; + } protected: DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, @@ -288,6 +299,9 @@ dw_offset_t m_line_table_offset = DW_INVALID_OFFSET; dw_offset_t m_str_offsets_base = 0; // Value of DW_AT_str_offsets_base. + + llvm::Optional m_rnglist_table; + const DIERef::Section m_section; private: diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -417,8 +417,44 @@ void DWARFUnit::SetAddrBase(dw_addr_t addr_base) { m_addr_base = addr_base; } +// Parse the rangelist table header, including the optional array of offsets +// following it (DWARF v5 and later). +template +static llvm::Expected +ParseListTableHeader(const llvm::DWARFDataExtractor &data, uint64_t offset, + DwarfFormat format) { + // We are expected to be called with Offset 0 or pointing just past the table + // header. Correct Offset in the latter case so that it points to the start + // of the header. + if (offset > 0) { + uint64_t HeaderSize = llvm::DWARFListTableHeader::getHeaderSize(format); + if (offset < HeaderSize) + return llvm::createStringError(errc::invalid_argument, + "did not detect a valid" + " list table with base = 0x%" PRIx64 "\n", + offset); + offset -= HeaderSize; + } + ListTableType Table; + if (llvm::Error E = Table.extractHeaderAndOffsets(data, &offset)) + return std::move(E); + return Table; +} + void DWARFUnit::SetRangesBase(dw_addr_t ranges_base) { m_ranges_base = ranges_base; + + if (GetVersion() < 5) + return; + + if (auto table_or_error = ParseListTableHeader( + m_dwarf.GetDWARFContext().getOrLoadRngListsData().GetAsLLVM(), + ranges_base, DWARF32)) + m_rnglist_table = std::move(table_or_error.get()); + else + GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( + "Failed to extract range list table at offset 0x%" PRIx64 ": %s", + ranges_base, toString(table_or_error.takeError()).c_str()); } void DWARFUnit::SetStrOffsetsBase(dw_offset_t str_offsets_base) { @@ -845,30 +881,56 @@ } llvm::Expected -DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) const { - const DWARFDebugRangesBase *debug_ranges; - llvm::StringRef section; +DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) { if (GetVersion() <= 4) { - debug_ranges = m_dwarf.GetDebugRanges(); - section = "debug_ranges"; - } else { - debug_ranges = m_dwarf.GetDebugRngLists(); - section = "debug_rnglists"; + const DWARFDebugRangesBase *debug_ranges = m_dwarf.GetDebugRanges(); + if (!debug_ranges) + return llvm::make_error( + "No debug_ranges section"); + DWARFRangeList ranges; + debug_ranges->FindRanges(this, offset, ranges); + return ranges; } - if (!debug_ranges) - return llvm::make_error("No " + section + - " section"); + + if (!m_rnglist_table) + return llvm::createStringError(errc::invalid_argument, + "missing or invalid range list table"); + + auto range_list_or_error = m_rnglist_table->findList( + m_dwarf.GetDWARFContext().getOrLoadRngListsData().GetAsLLVM(), offset); + if (!range_list_or_error) + return range_list_or_error.takeError(); + + llvm::Expected llvm_ranges = + range_list_or_error->getAbsoluteRanges( + llvm::object::SectionedAddress{GetBaseAddress()}, + [&](uint32_t index) { + uint32_t index_size = GetAddressByteSize(); + dw_offset_t addr_base = GetAddrBase(); + lldb::offset_t offset = addr_base + index * index_size; + return llvm::object::SectionedAddress{ + m_dwarf.GetDWARFContext().getOrLoadAddrData().GetMaxU64( + &offset, index_size)}; + }); + if (!llvm_ranges) + return llvm_ranges.takeError(); DWARFRangeList ranges; - debug_ranges->FindRanges(this, offset, ranges); + for (const llvm::DWARFAddressRange &llvm_range : *llvm_ranges) { + ranges.Append(DWARFRangeList::Entry(llvm_range.LowPC, + llvm_range.HighPC - llvm_range.LowPC)); + } return ranges; } llvm::Expected -DWARFUnit::FindRnglistFromIndex(uint32_t index) const { - const DWARFDebugRngLists *debug_rnglists = m_dwarf.GetDebugRngLists(); - if (!debug_rnglists) - return llvm::make_error( - "No debug_rnglists section"); - return FindRnglistFromOffset(debug_rnglists->GetOffset(index)); +DWARFUnit::FindRnglistFromIndex(uint32_t index) { + if (llvm::Optional offset = GetRnglistOffset(index)) + return FindRnglistFromOffset(*offset); + if (m_rnglist_table) + return llvm::createStringError(errc::invalid_argument, + "invalid range list table index %d", index); + + return llvm::createStringError(errc::invalid_argument, + "missing or invalid range list table"); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -47,7 +47,6 @@ class DWARFDebugInfoEntry; class DWARFDebugLine; class DWARFDebugRanges; -class DWARFDebugRngLists; class DWARFDeclContext; class DWARFFormValue; class DWARFTypeUnit; @@ -236,7 +235,6 @@ const DWARFDebugInfo *DebugInfo() const; DWARFDebugRanges *GetDebugRanges(); - DWARFDebugRngLists *GetDebugRngLists(); const lldb_private::DWARFDataExtractor &DebugLocData(); @@ -499,7 +497,6 @@ typedef llvm::StringMap NameToOffsetMap; NameToOffsetMap m_function_scope_qualified_name_map; std::unique_ptr m_ranges; - std::unique_ptr m_rnglists; UniqueDWARFASTTypeMap m_unique_ast_type_map; DIEToTypePtr m_die_to_type; DIEToVariableSP m_die_to_variable_sp; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -676,21 +676,6 @@ return m_ranges.get(); } -DWARFDebugRngLists *SymbolFileDWARF::GetDebugRngLists() { - if (!m_rnglists) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%s this = %p", LLVM_PRETTY_FUNCTION, - static_cast(this)); - - if (m_context.getOrLoadRngListsData().GetByteSize() > 0) - m_rnglists.reset(new DWARFDebugRngLists()); - - if (m_rnglists) - m_rnglists->Extract(m_context); - } - return m_rnglists.get(); -} - lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { CompUnitSP cu_sp; CompileUnit *comp_unit = (CompileUnit *)dwarf_cu.GetUserData(); diff --git a/lldb/test/Shell/SymbolFile/DWARF/debug_rnglists.s b/lldb/test/Shell/SymbolFile/DWARF/debug_rnglists.s --- a/lldb/test/Shell/SymbolFile/DWARF/debug_rnglists.s +++ b/lldb/test/Shell/SymbolFile/DWARF/debug_rnglists.s @@ -1,12 +1,19 @@ # REQUIRES: x86 # RUN: llvm-mc -triple=x86_64-pc-linux -filetype=obj %s > %t -# RUN: %lldb %t -o "image lookup -v -s lookup_rnglists" -o exit | FileCheck %s +# RUN: %lldb %t -o "image lookup -v -s lookup_rnglists" \ +# RUN: -o "image lookup -v -s lookup_rnglists2" -o exit | FileCheck %s +# CHECK-LABEL: image lookup -v -s lookup_rnglists # CHECK: Function: id = {0x7fffffff00000030}, name = "rnglists", range = [0x0000000000000000-0x0000000000000004) # CHECK: Blocks: id = {0x7fffffff00000030}, range = [0x00000000-0x00000004) # CHECK-NEXT: id = {0x7fffffff00000046}, ranges = [0x00000001-0x00000002)[0x00000003-0x00000004) +# CHECK-LABEL: image lookup -v -s lookup_rnglists2 +# CHECK: Function: id = {0x7fffffff0000007a}, name = "rnglists2", range = [0x0000000000000004-0x0000000000000007) +# CHECK: Blocks: id = {0x7fffffff0000007a}, range = [0x00000004-0x00000007) +# CHECK-NEXT: id = {0x7fffffff00000091}, range = [0x00000005-0x00000007) + .text .p2align 12 rnglists: @@ -21,6 +28,15 @@ .Lblock2_end: .Lrnglists_end: +rnglists2: + nop +.Lblock3_begin: +lookup_rnglists2: + nop + nop +.Lblock3_end: +.Lrnglists2_end: + .section .debug_abbrev,"",@progbits .byte 1 # Abbreviation Code .byte 17 # DW_TAG_compile_unit @@ -78,6 +94,28 @@ .byte 0 # End Of Children Mark .Ldebug_info_end0: +.Lcu_begin1: + .long .Ldebug_info_end1-.Ldebug_info_start1 # Length of Unit +.Ldebug_info_start1: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 1 # Abbrev [1] 0xc:0x5f DW_TAG_compile_unit + .asciz "Hand-written DWARF" # DW_AT_producer + .quad rnglists2 # DW_AT_low_pc + .long .Lrnglists2_end-rnglists2 # DW_AT_high_pc + .long .Lrnglists_table_base1 # DW_AT_rnglists_base + .byte 2 # Abbrev [2] 0x2b:0x37 DW_TAG_subprogram + .quad rnglists2 # DW_AT_low_pc + .long .Lrnglists2_end-rnglists2 # DW_AT_high_pc + .asciz "rnglists2" # DW_AT_name + .byte 5 # Abbrev [5] 0x52:0xf DW_TAG_lexical_block + .byte 0 # DW_AT_ranges + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark +.Ldebug_info_end1: + .section .debug_rnglists,"",@progbits .long .Ldebug_rnglist_table_end0-.Ldebug_rnglist_table_start0 # Length .Ldebug_rnglist_table_start0: @@ -96,3 +134,18 @@ .uleb128 .Lblock2_end-rnglists # ending offset .byte 0 # DW_RLE_end_of_list .Ldebug_rnglist_table_end0: + + .long .Ldebug_rnglist_table_end1-.Ldebug_rnglist_table_start1 # Length +.Ldebug_rnglist_table_start1: + .short 5 # Version + .byte 8 # Address size + .byte 0 # Segment selector size + .long 1 # Offset entry count +.Lrnglists_table_base1: + .long .Ldebug_ranges1-.Lrnglists_table_base1 +.Ldebug_ranges1: + .byte 4 # DW_RLE_offset_pair + .uleb128 .Lblock3_begin-rnglists2 # starting offset + .uleb128 .Lblock3_end-rnglists2 # ending offset + .byte 0 # DW_RLE_end_of_list +.Ldebug_rnglist_table_end1: