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 @@ -284,6 +284,10 @@ return &m_die_array[0]; } + llvm::Expected + CreateListTableHeader(const llvm::DWARFDataExtractor &data, uint64_t offset, + DwarfFormat format) const; + const llvm::Optional &GetRnglistTable(); SymbolFileDWARF &m_dwarf; 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 @@ -434,24 +434,36 @@ 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; - } + // Correct Offset so that it points to the start of the header. + 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; } +llvm::Expected +DWARFUnit::CreateListTableHeader(const llvm::DWARFDataExtractor &data, + uint64_t offset, DwarfFormat format) const { + if (offset > 0) + return ParseListTableHeader(data, offset, + format); + + // Unspecified Offset means only DW_FORM_sec_offset (and not DW_FORM_rnglistx) + // will be used. Make up a header covering the whole .debug_rnglists section. + llvm::DWARFDebugRnglistTable Table; + if (llvm::Error E = Table.createHeaderAndOffsets( + data, m_header.GetVersion(), m_header.GetAddressByteSize(), DWARF32)) + return std::move(E); + return Table; +} + void DWARFUnit::SetLoclistsBase(dw_addr_t loclists_base) { m_loclists_base = loclists_base; @@ -504,10 +516,9 @@ DWARFUnit::GetRnglistTable() { if (GetVersion() >= 5 && !m_rnglist_table_done) { m_rnglist_table_done = true; - if (auto table_or_error = - ParseListTableHeader( - m_dwarf.GetDWARFContext().getOrLoadRngListsData().GetAsLLVM(), - m_ranges_base, DWARF32)) + if (auto table_or_error = CreateListTableHeader( + m_dwarf.GetDWARFContext().getOrLoadRngListsData().GetAsLLVM(), + m_ranges_base, DWARF32)) m_rnglist_table = std::move(table_or_error.get()); else GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( diff --git a/lldb/test/Shell/SymbolFile/DWARF/DW_AT_range-DW_FORM_sec_offset.s b/lldb/test/Shell/SymbolFile/DWARF/DW_AT_range-DW_FORM_sec_offset.s --- a/lldb/test/Shell/SymbolFile/DWARF/DW_AT_range-DW_FORM_sec_offset.s +++ b/lldb/test/Shell/SymbolFile/DWARF/DW_AT_range-DW_FORM_sec_offset.s @@ -29,7 +29,7 @@ # RUN: -o exit 2>&1 | FileCheck --check-prefix=RNGLISTBASE %s # RNGLISTBASE-LABEL: image lookup -v -s lookup_rnglists -# RNGLISTBASE: error: {{.*}}-rnglistbase {0x00000043}: DIE has DW_AT_ranges(DW_FORM_rnglistx 0x0) attribute, but range extraction failed (invalid range list table index 0; OffsetEntryCount is 0, DW_AT_rnglists_base is 12), please file a bug and attach the file at the start of this error message +# RNGLISTBASE: error: {{.*}}-rnglistbase {0x00000043}: DIE has DW_AT_ranges(DW_FORM_rnglistx 0x0) attribute, but range extraction failed (invalid range list table index 0; OffsetEntryCount is 0, DW_AT_rnglists_base is 24), please file a bug and attach the file at the start of this error message .text rnglists: @@ -97,7 +97,7 @@ .long .Lrnglists_end-rnglists # DW_AT_high_pc .long .Laddr_table_base0 # DW_AT_addr_base .ifdef RNGLISTBASE - .long .Ldebug_ranges0 # DW_AT_rnglists_base + .long .Ldebug_ranges1 # DW_AT_rnglists_base .endif .byte 2 # Abbrev [2] 0x2b:0x37 DW_TAG_subprogram .quad rnglists # DW_AT_low_pc @@ -105,7 +105,7 @@ .asciz "rnglists" # DW_AT_name .byte 5 # Abbrev [5] 0x52:0xf DW_TAG_lexical_block .ifndef RNGLISTX - .long .Ldebug_ranges0 # DW_AT_ranges DW_FORM_sec_offset + .long .Ldebug_ranges1 # DW_AT_ranges DW_FORM_sec_offset .else .uleb128 0 # DW_AT_ranges DW_FORM_rnglistx .endif @@ -130,9 +130,17 @@ .byte 8 # Address size .byte 0 # Segment selector size .long 0 # Offset entry count -.Ldebug_ranges0: +.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 0 # Offset entry count +.Ldebug_ranges1: .byte 4 # DW_RLE_offset_pair .uleb128 .Lblock1_begin-rnglists # starting offset .uleb128 .Lblock1_end-rnglists # ending offset .byte 0 # DW_RLE_end_of_list -.Ldebug_rnglist_table_end0: +.Ldebug_rnglist_table_end1: diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFListTable.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFListTable.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFListTable.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFListTable.h @@ -136,6 +136,10 @@ /// Extract the table header and the array of offsets. Error extract(DWARFDataExtractor Data, uint64_t *OffsetPtr); + // Make up a header from DWARFUnit header to cover the whole Data section. + Error create(DWARFDataExtractor Data, unsigned Version, unsigned AddrSize, + dwarf::DwarfFormat FormatParam); + /// Returns the length of the table, including the length field, or 0 if the /// length has not been determined (e.g. because the table has not yet been /// parsed, or there was a problem in parsing). @@ -170,6 +174,11 @@ Error extractHeaderAndOffsets(DWARFDataExtractor Data, uint64_t *OffsetPtr) { return Header.extract(Data, OffsetPtr); } + // Make up a header from DWARFUnit header to cover the whole Data section. + Error createHeaderAndOffsets(DWARFDataExtractor Data, unsigned Version, + unsigned AddrSize, dwarf::DwarfFormat Format) { + return Header.create(Data, Version, AddrSize, Format); + } /// Extract an entire table, including all list entries. Error extract(DWARFDataExtractor Data, uint64_t *OffsetPtr); /// Look up a list based on a given offset. Extract it and enter it into the diff --git a/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp @@ -29,6 +29,31 @@ return Error::success(); } +Error DWARFListTableHeader::create(DWARFDataExtractor Data, unsigned Version, + unsigned AddrSize, + dwarf::DwarfFormat FormatParam) { + Format = FormatParam; + HeaderOffset = 0; + if (Data.size() < getHeaderSize(Format)) + return createStringError(errc::invalid_argument, + "%s table at offset 0x%" PRIx64 + " has too small length (0x%" PRIx64 + ") to contain a complete header", + SectionName.data(), HeaderOffset, Data.size()); + + HeaderData.Length = Data.size() - dwarf::getUnitLengthFieldByteSize(Format); + HeaderData.Version = Version; + HeaderData.AddrSize = AddrSize; + HeaderData.SegSize = 0; + HeaderData.OffsetEntryCount = 0; + if (Error Err = HeaderData.verify()) + return createStringError( + errc::invalid_argument, "parsing %s table at offset 0x%" PRIx64 ": %s", + SectionName.data(), HeaderOffset, toString(std::move(Err)).c_str()); + + return Error::success(); +} + Error DWARFListTableHeader::extract(DWARFDataExtractor Data, uint64_t *OffsetPtr) { HeaderOffset = *OffsetPtr;