Index: include/llvm/DebugInfo/DWARF/DWARFUnit.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -198,7 +198,7 @@ DWARFUnitHeader Header; const DWARFDebugAbbrev *Abbrev; const DWARFSection *RangeSection; - uint32_t RangeSectionBase; + uint64_t RangeSectionBase; /// We either keep track of the location list section or its data, depending /// on whether we are handling a split DWARF section or not. union { @@ -304,7 +304,7 @@ /// Recursively update address to Die map. void updateAddressDieMap(DWARFDie Die); - void setRangesSection(const DWARFSection *RS, uint32_t Base) { + void setRangesSection(const DWARFSection *RS, uint64_t Base) { RangeSection = RS; RangeSectionBase = Base; } Index: lib/DebugInfo/DWARF/DWARFUnit.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFUnit.cpp +++ lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -306,16 +306,18 @@ // Parse the rangelist table header, including the optional array of offsets // following it (DWARF v5 and later). static Expected -parseRngListTableHeader(DWARFDataExtractor &DA, uint64_t Offset) { - // TODO: Support DWARF64 +parseRngListTableHeader(DWARFDataExtractor &DA, uint64_t Offset, + DwarfFormat Format) { // We are expected to be called with Offset 0 or pointing just past the table - // header, which is 12 bytes long for DWARF32. + // header. Correct Offset in the latter case so that it points to the start + // of the header. if (Offset > 0) { - if (Offset < 12U) + uint64_t HeaderSize = DWARFListTableHeader::getHeaderSize(Format); + if (Offset < HeaderSize) return createStringError(errc::invalid_argument, "Did not detect a valid" - " range list table with base = 0x%" PRIx64, + " range list table with base = 0x%" PRIx64 "\n", Offset); - Offset -= 12U; + Offset -= HeaderSize; } llvm::DWARFDebugRnglistTable Table; if (Error E = Table.extractHeaderAndOffsets(DA, &Offset)) @@ -469,8 +471,8 @@ // extracted lazily. DWARFDataExtractor RangesDA(Context.getDWARFObj(), *RangeSection, isLittleEndian, 0); - auto TableOrError = - parseRngListTableHeader(RangesDA, RangeSectionBase); + auto TableOrError = parseRngListTableHeader(RangesDA, RangeSectionBase, + Header.getFormat()); if (!TableOrError) return createStringError(errc::invalid_argument, "parsing a range list table: " + @@ -525,7 +527,8 @@ DWO->setRangesSection(&Context.getDWARFObj().getRnglistsDWOSection(), 0); DWARFDataExtractor RangesDA(Context.getDWARFObj(), *RangeSection, isLittleEndian, 0); - if (auto TableOrError = parseRngListTableHeader(RangesDA, RangeSectionBase)) + if (auto TableOrError = parseRngListTableHeader(RangesDA, RangeSectionBase, + Header.getFormat())) DWO->RngListTable = TableOrError.get(); else WithColor::error() << "parsing a range list table: " Index: test/DebugInfo/X86/dwarfdump-rnglists-dwarf64.s =================================================================== --- /dev/null +++ test/DebugInfo/X86/dwarfdump-rnglists-dwarf64.s @@ -0,0 +1,211 @@ +# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o %t.o +# RUN: llvm-dwarfdump -v -debug-info %t.o 2> %t.err | tee %t.di.log | FileCheck %s +# RUN: FileCheck %s --input-file %t.err --check-prefix=ERR +# RUN: llvm-dwarfdump -lookup 10 %t.o 2> %t2.err > %t.lkup.log +# RUN: FileCheck %s --input-file %t2.err --check-prefix=ERR + +# Test object to verify dwarfdump handles v5 range lists in 64-bit DWARF format. +# This is similar to 'dwarfdump-rnglists.s', which uses 32-bit DWARF format. +# We use very simplified compile unit dies. +# There are 2 full CUs with DW_AT_rnglists_base, one with a DW_AT_ranges +# attribute using DW_FORM_sec_offset, the other with DW_AT_ranges using +# DW_FORM_rnglistx. + + .section .debug_abbrev,"",@progbits + .byte 0x01 # Abbrev code + .byte 0x11 # DW_TAG_compile_unit + .byte 0x00 # DW_CHILDREN_no + .byte 0x74 # DW_AT_rnglists_base + .byte 0x17 # DW_FORM_sec_offset + .byte 0x55 # DW_AT_ranges + .byte 0x17 # DW_FORM_sec_offset + .byte 0x00 # EOM(1) + .byte 0x00 # EOM(2) + .byte 0x02 # Abbrev code + .byte 0x11 # DW_TAG_compile_unit + .byte 0x00 # DW_CHILDREN_no + .byte 0x74 # DW_AT_rnglists_base + .byte 0x17 # DW_FORM_sec_offset + .byte 0x55 # DW_AT_ranges + .byte 0x23 # DW_FORM_rnglistx + .byte 0x00 # EOM(1) + .byte 0x00 # EOM(2) + .byte 0x00 # EOM(3) + +# The split CU uses DW_FORM_rnglistx (the only correct option). +# There is no DW_AT_rnglists_base in split units. + .section .debug_abbrev.dwo,"",@progbits + .byte 0x01 # Abbrev code + .byte 0x11 # DW_TAG_compile_unit + .byte 0x00 # DW_CHILDREN_no + .byte 0x55 # DW_AT_ranges + .byte 0x23 # DW_FORM_rnglistx + .byte 0x00 # EOM(1) + .byte 0x00 # EOM(2) + .byte 0x00 # EOM(3) + + .section .debug_info,"",@progbits + .long 0xffffffff # DWARF64 mark + .quad CU1_5_64_end - CU1_5_64_version # Length of Unit +CU1_5_64_version: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 4 # Address Size (in bytes) + .quad .debug_abbrev # Offset Into Abbrev. Section +# The compile-unit DIE, which has DW_AT_rnglists_base and DW_AT_ranges. + .byte 1 # Abbreviation code + .quad Rnglist_Table0_base # DW_AT_rnglists_base + .quad Rnglist_Table0_Rnglist0 # DW_AT_ranges +CU1_5_64_end: + + .long 0xffffffff # DWARF64 mark + .quad CU2_5_64_end - CU2_5_64_version # Length of Unit +CU2_5_64_version: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 4 # Address Size (in bytes) + .quad .debug_abbrev # Offset Into Abbrev. Section +# The compile-unit DIE, which has DW_AT_rnglists_base and DW_AT_ranges. + .byte 2 # Abbreviation code + .quad Rnglist_Table0_base # DW_AT_rnglists_base + .uleb128 1 # DW_AT_ranges +CU2_5_64_end: + +# A CU with an invalid DW_AT_rnglists_base attribute + .long 0xffffffff # DWARF64 mark + .quad CU3_5_64_end - CU3_5_64_version # Length of Unit +CU3_5_64_version: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 4 # Address Size (in bytes) + .quad .debug_abbrev # Offset Into Abbrev. Section +# The compile-unit DIE, which has DW_AT_rnglists_base and DW_AT_ranges. + .byte 2 # Abbreviation code + .quad 0x8 # DW_AT_rnglists_base + .uleb128 0 # DW_AT_ranges +CU3_5_64_end: + +# A CU DIE with an incorrect DW_AT_ranges attribute + .long 0xffffffff # DWARF64 mark + .quad CU4_5_64_end - CU4_5_64_version # Length of Unit +CU4_5_64_version: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 4 # Address Size (in bytes) + .quad .debug_abbrev # Offset Into Abbrev. Section +# The compile-unit DIE, which has DW_AT_rnglists_base and DW_AT_ranges. + .byte 1 # Abbreviation code + .quad Rnglist_Table0_base # DW_AT_rnglists_base + .quad 4000 # DW_AT_ranges +CU4_5_64_end: + + .section .debug_info.dwo,"",@progbits + +# DWARF v5 split CU header. + .long 0xffffffff # DWARF64 mark + .quad CU_split_5_64_end-CU_split_5_64_version # Length of Unit +CU_split_5_64_version: + .short 5 # DWARF version number + .byte 5 # DWARF Unit Type + .byte 4 # Address Size (in bytes) + .quad 0 # Offset Into Abbrev Section +# The compile-unit DIE, which has DW_AT_rnglists_base and DW_AT_ranges. + .byte 1 # Abbreviation code + .uleb128 1 # DW_AT_ranges +CU_split_5_64_end: + + .section .debug_rnglists,"",@progbits +# A rnglist table with 2 range lists. The first one uses DW_RLE_start_end +# and DW_RLE_start_length. The second one uses DW_RLE_base_address and +# DW_RLE_offset_pair. The range lists have entries in the offset table. + .long 0xffffffff # DWARF64 mark + .quad Rnglist_Table0_end - Rnglist_Table0 # table length +Rnglist_Table0: + .short 5 # version + .byte 4 # address size + .byte 0 # segment selector size + .long 2 # offset entry count +Rnglist_Table0_base: +# 2 offset entries which can be used by DW_FORM_rnglistx. + .quad Rnglist_Table0_Rnglist0 - Rnglist_Table0_base + .quad Rnglist_Table0_Rnglist1 - Rnglist_Table0_base +Rnglist_Table0_Rnglist0: + .byte 6 # DW_RLE_start_end + .long Range0_start + .long Range0_end + .byte 7 # DW_RLE_start_length + .long Range1_start + .uleb128 Range1_end - Range1_start + .byte 0 # DW_RLE_end_of_list +Rnglist_Table0_Rnglist1: + .byte 5 # DW_RLE_base_address + .long Range0_start + .byte 4 # DW_RLE_offset_pair + .uleb128 Range1_start - Range0_start + .uleb128 Range1_end - Range0_start + .byte 0 # DW_RLE_end_of_list +Rnglist_Table0_end: + +# A rnglist table for the split unit with an empty rangelist and one that +# uses DW_RLE_base_address and DW_RLE_offset_pair. The ranges have entries +# in the offset table. We use the empty range list so we can test +# DW_FORM_rnglistx with an index other than 0. + .section .debug_rnglists.dwo,"",@progbits + .long 0xffffffff # DWARF64 mark + .quad Rnglist_Table0_dwo_end - Rnglist_Table0_dwo # table length +Rnglist_Table0_dwo: + .short 5 # version + .byte 4 # address size + .byte 0 # segment selector size + .long 2 # offset entry count +Rnglist_Table0_base_dwo: +# 2 offset entries which can be used by DW_FORM_rnglistx. + .quad Rnglist_Table0_Rnglist0_dwo - Rnglist_Table0_base_dwo + .quad Rnglist_Table0_Rnglist1_dwo - Rnglist_Table0_base_dwo +Rnglist_Table0_Rnglist0_dwo: + .byte 0 # DW_RLE_start_end +Rnglist_Table0_Rnglist1_dwo: + .byte 5 # DW_RLE_base_address + .long Range0_start - .text + .byte 4 # DW_RLE_offset_pair + .uleb128 Range1_start - Range0_start + .uleb128 Range1_end - Range0_start + .byte 0 # DW_RLE_end_of_list +Rnglist_Table0_dwo_end: + +.text + .space 20 +Range0_start: # Range0: 0x14 - 0x1c + .space 10 +Range0_end: + .space 12 +Range1_start: # Range1: 0x2a - 0x34 + .space 10 +Range1_end: + +# CHECK: .debug_info contents: +# CHECK: Compile Unit: +# CHECK-NOT: Compile Unit: +# CHECK: DW_TAG_compile_unit +# CHECK-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x00000014) +# CHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000024 +# CHECK-NEXT: [0x00000014, 0x0000001e) ".text" +# CHECK-NEXT: [0x0000002a, 0x00000034) ".text") + +# CHECK: Compile Unit: +# CHECK-NOT: Compile Unit: +# CHECK: DW_TAG_compile_unit +# CHECK-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x00000014) +# CHECK-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x1) rangelist = 0x00000020 +# CHECK-NEXT: [0x0000002a, 0x00000034) ".text") + +# CHECK: .debug_info.dwo contents: +# CHECK: Compile Unit: +# CHECK-NOT: contents: +# CHECK: DW_TAG_compile_unit +# CHECK-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x1) rangelist = 0x00000011 +# CHECK-NEXT: [0x0000002a, 0x00000034)) + +#ERR: error: parsing a range list table: Did not detect a valid range list table with base = 0x8 +#ERR: error: decoding address ranges: missing or invalid range list table +#ERR: error: decoding address ranges: invalid range list offset 0xfa0