Index: llvm/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h +++ 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; } Index: llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp +++ 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,53 @@ 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. + + // We do not call FormParams::getRefAddrByteSize(), + // so 4 for Version and 4 for AddrSize are taken arbitrary. + dwarf::FormParams params = {4, 4, dwarf::DWARF32}; HeaderData.Length = data.getU32(offset_ptr); + if (HeaderData.Length == dwarf::DW_LENGTH_DWARF64) { + HeaderData.Length = data.getU64(offset_ptr); + params.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, params.getDwarfOffsetByteSize()); 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(params.Format) + HeaderData.Length; + if (!data.isValidOffsetForDataOfSize(Offset, full_length)) return createStringError(errc::invalid_argument, "address range table at offset 0x%" PRIx64 " has invalid length", @@ -104,10 +130,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); Index: llvm/test/DebugInfo/X86/dwarfdump-debug-aranges-error-cases.s =================================================================== --- llvm/test/DebugInfo/X86/dwarfdump-debug-aranges-error-cases.s +++ llvm/test/DebugInfo/X86/dwarfdump-debug-aranges-error-cases.s @@ -10,6 +10,14 @@ # RUN: llvm-dwarfdump -debug-aranges - 2>&1 | \ # RUN: FileCheck %s --check-prefix=CHECK3 +# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj --defsym CASE4=0 -o - | \ +# RUN: llvm-dwarfdump -debug-aranges - 2>&1 | \ +# RUN: FileCheck %s --check-prefix=CHECK4 + +# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj --defsym CASE5=0 -o - | \ +# RUN: llvm-dwarfdump -debug-aranges - 2>&1 | \ +# RUN: FileCheck %s --check-prefix=CHECK5 + .section .debug_aranges,"",@progbits .ifdef CASE1 # CHECK1: address range table at offset 0x0 has invalid length @@ -58,3 +66,26 @@ # The set is not properly terminated .Lend: .endif # CASE3 + +.ifdef CASE4 +## Length overrun for the DWARF64 case. +# CHECK4: address range table at offset 0x0 has invalid length +.Llen: + .long 0xffffffff # DWARF64 mark + .quad .Lend - .Lversion + 1 # The length exceeds the section boundaries +.Lversion: + .short 2 # Version + .quad 0 # Debug Info Offset + .byte 4 # Address Size + .byte 0 # Segment Selector Size + .space 7 - (. - .Llen + 7) % 8 # Padding +.Ltuples: + .long 0, 1 # Address and length + .long 0, 0 # Termination tuple +.Lend: +.endif # CASE4 + +.ifdef CASE5 +# CHECK5: address range table at offset 0x0 has unsupported reserved unit length of value 0xfffffff0 + .long 0xfffffff0 # Reserved unit length value +.endif # CASE5 Index: llvm/test/DebugInfo/X86/dwarfdump-debug-aranges.s =================================================================== --- llvm/test/DebugInfo/X86/dwarfdump-debug-aranges.s +++ llvm/test/DebugInfo/X86/dwarfdump-debug-aranges.s @@ -66,3 +66,25 @@ .quad 0, 0 # Termination tuple # CHECK-NOT: [0x .L3end: + +## Case 4: Check that 64-bit DWARF format is supported. +.L4: + .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 + .space 7 - (. - .L4 + 7) % 8 # Padding +.L4tuples: + .long 0, 1 # Address and length +# CHECK-NEXT: [0x00000000, 0x00000001) + .long 0, 0 # Termination tuple +# CHECK-NOT: [0x +.L4end: