diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h @@ -24,10 +24,10 @@ struct Header { /// The total length of the entries for that set, not including the length /// field itself. - uint32_t Length; + uint64_t Length; /// The offset from the beginning of the .debug_info section of the /// compilation unit entry referenced by the table. - uint32_t CuOffset; + uint64_t CuOffset; /// The DWARF version number. uint16_t Version; /// The size in bytes of an address on the target architecture. For segmented @@ -61,7 +61,7 @@ Error extract(DataExtractor data, uint64_t *offset_ptr); void dump(raw_ostream &OS) const; - uint32_t getCompileUnitDIEOffset() const { return HeaderData.CuOffset; } + uint64_t getCompileUnitDIEOffset() const { return HeaderData.CuOffset; } const Header &getHeader() const { return HeaderData; } diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" @@ -35,28 +36,51 @@ ArangeDescriptors.clear(); Offset = *offset_ptr; - // 7.20 Address Range Table - // + // 7.21 Address Range Table (extract) // Each set of entries in the table of address ranges contained in - // the .debug_aranges section begins with a header consisting of: a - // 4-byte length containing the length of the set of entries for this - // compilation unit, not including the length field itself; a 2-byte - // version identifier containing the value 2 for DWARF Version 2; a - // 4-byte offset into the.debug_infosection; a 1-byte unsigned integer - // containing the size in bytes of an address (or the offset portion of - // an address for segmented addressing) on the target system; and a - // 1-byte unsigned integer containing the size in bytes of a segment - // descriptor on the target system. This header is followed by a series - // of tuples. Each tuple consists of an address and a length, each in - // the size appropriate for an address on the target architecture. + // the .debug_aranges section begins with a header containing: + // 1. unit_length (initial length) + // A 4-byte (32-bit DWARF) or 12-byte (64-bit DWARF) length containing + // the length of the set of entries for this compilation unit, + // not including the length field itself. + // 2. version (uhalf) + // The value in this field is 2. + // 3. debug_info_offset (section offset) + // A 4-byte (32-bit DWARF) or 8-byte (64-bit DWARF) offset into the + // .debug_info section of the compilation unit header. + // 4. address_size (ubyte) + // 5. segment_selector_size (ubyte) + // This header is followed by a series of tuples. Each tuple consists of + // a segment, an address and a length. The segment selector size is given by + // the segment_selector_size field of the header; the address and length + // size are each given by the address_size field of the header. Each set of + // tuples is terminated by a 0 for the segment, a 0 for the address and 0 + // for the length. If the segment_selector_size field in the header is zero, + // the segment selectors are omitted from all tuples, including + // the terminating tuple. + + dwarf::DwarfFormat format = dwarf::DWARF32; HeaderData.Length = data.getU32(offset_ptr); + if (HeaderData.Length == dwarf::DW_LENGTH_DWARF64) { + HeaderData.Length = data.getU64(offset_ptr); + format = dwarf::DWARF64; + } else if (HeaderData.Length >= dwarf::DW_LENGTH_lo_reserved) { + return createStringError( + errc::invalid_argument, + "address range table at offset 0x%" PRIx64 + " has unsupported reserved unit length of value 0x%8.8" PRIx64, + Offset, HeaderData.Length); + } HeaderData.Version = data.getU16(offset_ptr); - HeaderData.CuOffset = data.getU32(offset_ptr); + HeaderData.CuOffset = + data.getUnsigned(offset_ptr, dwarf::getDwarfOffsetByteSize(format)); HeaderData.AddrSize = data.getU8(offset_ptr); HeaderData.SegSize = data.getU8(offset_ptr); // Perform basic validation of the header fields. - if (!data.isValidOffsetForDataOfSize(Offset, HeaderData.Length + 4)) + uint64_t full_length = + dwarf::getUnitLengthFieldByteSize(format) + HeaderData.Length; + if (!data.isValidOffsetForDataOfSize(Offset, full_length)) return createStringError(errc::invalid_argument, "the length of address range table at offset " "0x%" PRIx64 " exceeds section size", @@ -105,10 +129,12 @@ } void DWARFDebugArangeSet::dump(raw_ostream &OS) const { - OS << format("Address Range Header: length = 0x%8.8x, version = 0x%4.4x, ", - HeaderData.Length, HeaderData.Version) - << format("cu_offset = 0x%8.8x, addr_size = 0x%2.2x, seg_size = 0x%2.2x\n", - HeaderData.CuOffset, HeaderData.AddrSize, HeaderData.SegSize); + OS << "Address Range Header: " + << format("length = 0x%8.8" PRIx64 ", ", HeaderData.Length) + << format("version = 0x%4.4x, ", HeaderData.Version) + << format("cu_offset = 0x%8.8" PRIx64 ", ", HeaderData.CuOffset) + << format("addr_size = 0x%2.2x, ", HeaderData.AddrSize) + << format("seg_size = 0x%2.2x\n", HeaderData.SegSize); for (const auto &Desc : ArangeDescriptors) { Desc.dump(OS, HeaderData.AddrSize); diff --git a/llvm/test/DebugInfo/X86/dwarfdump-debug-aranges.s b/llvm/test/DebugInfo/X86/dwarfdump-debug-aranges.s --- a/llvm/test/DebugInfo/X86/dwarfdump-debug-aranges.s +++ b/llvm/test/DebugInfo/X86/dwarfdump-debug-aranges.s @@ -63,3 +63,24 @@ .quad 0, 0 # Termination tuple # CHECK-NOT: [0x .L3end: + +## Case 4: Check that 64-bit DWARF format is supported. + .long 0xffffffff # DWARF64 mark + .quad .L4end - .L4version # Length +# CHECK: Address Range Header: length = 0x0000001c, +.L4version: + .short 2 # Version + .quad 0x1234567899aabbcc # Debug Info Offset + .byte 4 # Address Size + .byte 0 # Segment Selector Size +# CHECK-SAME: version = 0x0002, +# CHECK-SAME: cu_offset = 0x1234567899aabbcc, +# CHECK-SAME: addr_size = 0x04, +# CHECK-SAME: seg_size = 0x00 + # No padding +.L4tuples: + .long 0, 1 # Address and length +# CHECK-NEXT: [0x00000000, 0x00000001) + .long 0, 0 # Termination tuple +# CHECK-NOT: [0x +.L4end: diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugArangeSetTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugArangeSetTest.cpp --- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugArangeSetTest.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugArangeSetTest.cpp @@ -41,6 +41,23 @@ "the length of address range table at offset 0x0 exceeds section size"); } +TEST(DWARFDebugArangeSet, LengthExceedsSectionSizeDWARF64) { + static const char DebugArangesSecRaw[] = + "\xff\xff\xff\xff" // DWARF64 mark + "\x15\x00\x00\x00\x00\x00\x00\x00" // The length exceeds the section + // boundaries + "\x02\x00" // Version + "\x00\x00\x00\x00\x00\x00\x00\x00" // Debug Info Offset + "\x04" // Address Size + "\x00" // Segment Selector Size + // No padding + "\x00\x00\x00\x00" // Termination tuple + "\x00\x00\x00\x00"; + ExpectExtractError( + DebugArangesSecRaw, + "the length of address range table at offset 0x0 exceeds section size"); +} + TEST(DWARFDebugArangeSet, UnsupportedAddressSize) { static const char DebugArangesSecRaw[] = "\x0c\x00\x00\x00" // Length @@ -72,4 +89,13 @@ "address range table at offset 0x0 is not terminated by null entry"); } +TEST(DWARFDebugArangeSet, ReservedUnitLength) { + static const char DebugArangesSecRaw[] = + "\xf0\xff\xff\xff"; // Reserved unit length value + ExpectExtractError( + DebugArangesSecRaw, + "address range table at offset 0x0 has unsupported reserved unit length " + "of value 0xfffffff0"); +} + } // end anonymous namespace