diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAddr.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAddr.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAddr.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAddr.h @@ -31,7 +31,7 @@ uint64_t Offset; /// The total length of the entries for this table, not including the length /// field itself. - uint32_t Length = 0; + uint64_t Length = 0; /// The DWARF version number. uint16_t Version; /// The size in bytes of an address on the target architecture. For diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp @@ -50,34 +50,48 @@ "section is not large enough to contain an " "address table length at offset 0x%" PRIx64, Offset); - // TODO: Add support for DWARF64. Format = dwarf::DwarfFormat::DWARF32; Length = Data.getU32(OffsetPtr); if (Length == dwarf::DW_LENGTH_DWARF64) { + // Check that we can read the extended unit length field. + if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, 8)) { + invalidateLength(); + return createStringError( + errc::invalid_argument, + "section is not large enough to contain an extended length field " + "of the address table at offset 0x%" PRIx64, + Offset); + } + Format = dwarf::DwarfFormat::DWARF64; + Length = Data.getU64(OffsetPtr); + } else if (Length >= dwarf::DW_LENGTH_lo_reserved) { + uint64_t DiagnosticLength = Length; invalidateLength(); return createStringError( errc::not_supported, - "DWARF64 is not supported in .debug_addr at offset 0x%" PRIx64, Offset); + "address table at offset 0x%" PRIx64 + " has unsupported reserved unit length of value 0x%" PRIx64, + Offset, DiagnosticLength); } if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, Length)) { - uint32_t DiagnosticLength = Length; + uint64_t DiagnosticLength = Length; invalidateLength(); return createStringError( errc::invalid_argument, "section is not large enough to contain an address table " - "at offset 0x%" PRIx64 " with a unit_length value of 0x%" PRIx32, + "at offset 0x%" PRIx64 " with a unit_length value of 0x%" PRIx64, Offset, DiagnosticLength); } uint64_t EndOffset = *OffsetPtr + Length; // Ensure that we can read the remaining header fields. if (Length < 4) { - uint32_t DiagnosticLength = Length; + uint64_t DiagnosticLength = Length; invalidateLength(); return createStringError( errc::invalid_argument, "address table at offset 0x%" PRIx64 - " has a unit_length value of 0x%" PRIx32 + " has a unit_length value of 0x%" PRIx64 ", which is too small to contain a complete header", Offset, DiagnosticLength); } @@ -142,12 +156,14 @@ void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { if (DumpOpts.Verbose) - OS << format("0x%8.8" PRIx32 ": ", Offset); - if (Length) - OS << format("Address table header: length = 0x%8.8" PRIx32 + OS << format("0x%8.8" PRIx64 ": ", Offset); + if (Length) { + int LengthFieldWidth = (Format == dwarf::DwarfFormat::DWARF64) ? 16 : 8; + OS << format("Address table header: length = 0x%0*" PRIx64 ", version = 0x%4.4" PRIx16 ", addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8 "\n", - Length, Version, AddrSize, SegSize); + LengthFieldWidth, Length, Version, AddrSize, SegSize); + } if (Addrs.size() > 0) { const char *AddrFmt = @@ -171,7 +187,6 @@ Optional DWARFDebugAddrTable::getFullLength() const { if (Length == 0) return None; - // TODO: DWARF64 support. - return Length + sizeof(uint32_t); + return Length + dwarf::getUnitLengthFieldByteSize(Format); } diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_dwarf64.s b/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_dwarf64.s --- a/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_dwarf64.s +++ b/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_dwarf64.s @@ -1,19 +1,25 @@ -# RUN: llvm-mc %s -filetype obj -triple i386-pc-linux -o - | \ -# RUN: llvm-dwarfdump -debug-addr - 2> %t.err | FileCheck %s -# RUN: FileCheck %s -input-file %t.err -check-prefix=ERR +# RUN: llvm-mc %s -filetype obj -triple x86_64-pc-linux -o - | \ +# RUN: llvm-dwarfdump -debug-addr - | \ +# RUN: FileCheck %s -# CHECK: .debug_addr contents: -# CHECK-NOT: {{.}} -# ERR: DWARF64 is not supported in .debug_addr at offset 0x0 -# ERR-NOT: {{.}} +# CHECK: .debug_addr contents: +# CHECK-NEXT: Address table header: +# CHECK-SAME: length = 0x000000000000000c, +# CHECK-SAME: version = 0x0005, +# CHECK-SAME: addr_size = 0x04, +# CHECK-SAME: seg_size = 0x00 +# CHECK-NEXT: Addrs: [ +# CHECK-NEXT: 0x00000000 +# CHECK-NEXT: 0x00001000 +# CHECK-NEXT: ] -# DWARF64 table - .section .debug_addr,"",@progbits -.Ldebug_addr0: - .long 0xffffffff # unit_length DWARF64 mark - .quad 12 # unit_length - .short 5 # version - .byte 3 # address_size - .byte 0 # segment_selector_size - .long 0x00000000 - .long 0x00000001 + .section .debug_addr,"",@progbits + .long 0xffffffff # DWARF64 mark + .quad .LAddr0end-.LAddr0version # Length +.LAddr0version: + .short 5 # Version + .byte 4 # Address size + .byte 0 # Segment selector size + .long 0x00000000 + .long 0x00001000 +.LAddr0end: diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_reserved_length.s b/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_reserved_length.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_reserved_length.s @@ -0,0 +1,8 @@ +# RUN: llvm-mc %s -filetype obj -triple x86_64-pc-linux -o - | \ +# RUN: llvm-dwarfdump --debug-addr - 2>&1 | \ +# RUN: FileCheck %s --implicit-check-not=error + +# CHECK: error: address table at offset 0x0 has unsupported reserved unit length of value 0xfffffff0 + +.section .debug_addr,"",@progbits +.long 0xfffffff0 diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_too_small_for_extended_length_field.s b/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_too_small_for_extended_length_field.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_too_small_for_extended_length_field.s @@ -0,0 +1,13 @@ +# RUN: llvm-mc %s -filetype obj -triple i386-pc-linux -o - | \ +# RUN: llvm-dwarfdump -debug-addr - 2> %t.err | FileCheck %s +# RUN: FileCheck %s -input-file %t.err -check-prefix=ERR + +# CHECK: .debug_addr contents: +# CHECK-NOT: {{.}} +# ERR: section is not large enough to contain an extended length field of the address table at offset 0x0 +# ERR-NOT: {{.}} + +# too small section to contain an extended length field of a DWARF64 address table. + .section .debug_addr,"",@progbits + .long 0xffffffff # DWARF64 mark + .space 7 # a DWARF64 unit length field takes 8 bytes.