Index: llvm/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h +++ llvm/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h @@ -11,6 +11,7 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Error.h" #include #include @@ -57,7 +58,7 @@ DWARFDebugArangeSet() { clear(); } void clear(); - bool extract(DataExtractor data, uint64_t *offset_ptr); + Error extract(DataExtractor data, uint64_t *offset_ptr); void dump(raw_ostream &OS) const; uint32_t getCompileUnitDIEOffset() const { return HeaderData.CuOffset; } Index: llvm/lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -453,8 +453,12 @@ uint64_t offset = 0; DataExtractor arangesData(DObj->getArangesSection(), isLittleEndian(), 0); DWARFDebugArangeSet set; - while (set.extract(arangesData, &offset)) - set.dump(OS); + while (arangesData.isValidOffset(offset)) + if (Error E = set.extract(arangesData, &offset)) { + WithColor::error() << toString(std::move(E)) << '\n'; + break; + } else + set.dump(OS); } auto DumpLineSection = [&](DWARFDebugLine::SectionParser Parser, 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/Support/Errc.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" #include @@ -29,73 +30,77 @@ ArangeDescriptors.clear(); } -bool -DWARFDebugArangeSet::extract(DataExtractor data, uint64_t *offset_ptr) { - if (data.isValidOffset(*offset_ptr)) { - ArangeDescriptors.clear(); - Offset = *offset_ptr; - - // 7.20 Address Range Table - // - // 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. - HeaderData.Length = data.getU32(offset_ptr); - HeaderData.Version = data.getU16(offset_ptr); - HeaderData.CuOffset = data.getU32(offset_ptr); - 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) || - (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)) { - clear(); - return false; - } - - // The first tuple following the header in each set begins at an offset - // that is a multiple of the size of a single tuple (that is, twice the - // size of an address). The header is padded, if necessary, to the - // appropriate boundary. - const uint32_t header_size = *offset_ptr - Offset; - const uint32_t tuple_size = HeaderData.AddrSize * 2; - uint32_t first_tuple_offset = 0; - while (first_tuple_offset < header_size) - first_tuple_offset += tuple_size; - - *offset_ptr = Offset + first_tuple_offset; - - Descriptor arangeDescriptor; - - static_assert(sizeof(arangeDescriptor.Address) == - sizeof(arangeDescriptor.Length), - "Different datatypes for addresses and sizes!"); - assert(sizeof(arangeDescriptor.Address) >= HeaderData.AddrSize); - - while (data.isValidOffset(*offset_ptr)) { - arangeDescriptor.Address = data.getUnsigned(offset_ptr, HeaderData.AddrSize); - arangeDescriptor.Length = data.getUnsigned(offset_ptr, HeaderData.AddrSize); - - // Each set of tuples is terminated by a 0 for the address and 0 - // for the length. - if (arangeDescriptor.Address || arangeDescriptor.Length) - ArangeDescriptors.push_back(arangeDescriptor); - else - return true; // We are done if we get a zero address and length - } - - return false; // No termination tuple is found. +Error DWARFDebugArangeSet::extract(DataExtractor data, uint64_t *offset_ptr) { + assert(data.isValidOffset(*offset_ptr)); + ArangeDescriptors.clear(); + Offset = *offset_ptr; + + // 7.20 Address Range Table + // + // 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. + HeaderData.Length = data.getU32(offset_ptr); + HeaderData.Version = data.getU16(offset_ptr); + HeaderData.CuOffset = data.getU32(offset_ptr); + 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)) + return createStringError(errc::invalid_argument, + "address range table at offset 0x%" PRIx64 + " has invalid length", + Offset); + if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) + return createStringError(errc::invalid_argument, + "address range table at offset 0x%" PRIx64 + " has invalid address size", + Offset); + + // The first tuple following the header in each set begins at an offset + // that is a multiple of the size of a single tuple (that is, twice the + // size of an address). The header is padded, if necessary, to the + // appropriate boundary. + const uint32_t header_size = *offset_ptr - Offset; + const uint32_t tuple_size = HeaderData.AddrSize * 2; + uint32_t first_tuple_offset = 0; + while (first_tuple_offset < header_size) + first_tuple_offset += tuple_size; + + *offset_ptr = Offset + first_tuple_offset; + + Descriptor arangeDescriptor; + + static_assert(sizeof(arangeDescriptor.Address) == + sizeof(arangeDescriptor.Length), + "Different datatypes for addresses and sizes!"); + assert(sizeof(arangeDescriptor.Address) >= HeaderData.AddrSize); + + while (data.isValidOffset(*offset_ptr)) { + arangeDescriptor.Address = data.getUnsigned(offset_ptr, HeaderData.AddrSize); + arangeDescriptor.Length = data.getUnsigned(offset_ptr, HeaderData.AddrSize); + + // Each set of tuples is terminated by a 0 for the address and 0 + // for the length. + if (arangeDescriptor.Address == 0 && arangeDescriptor.Length == 0) + return ErrorSuccess(); + ArangeDescriptors.push_back(arangeDescriptor); } - return false; + + return createStringError(errc::invalid_argument, + "address range table at offset 0x%" PRIx64 + " is not terminated by null entry", + Offset); } void DWARFDebugArangeSet::dump(raw_ostream &OS) const { Index: llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp @@ -26,7 +26,8 @@ uint64_t Offset = 0; DWARFDebugArangeSet Set; - while (Set.extract(DebugArangesData, &Offset)) { + while (DebugArangesData.isValidOffset(Offset) && + !errorToBool(Set.extract(DebugArangesData, &Offset))) { uint64_t CUOffset = Set.getCompileUnitDIEOffset(); for (const auto &Desc : Set.descriptors()) { uint64_t LowPC = Desc.Address; Index: llvm/test/DebugInfo/X86/dwarfdump-debug-aranges-error-cases.s =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/dwarfdump-debug-aranges-error-cases.s @@ -0,0 +1,60 @@ +# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj --defsym CASE1=0 -o - | \ +# RUN: llvm-dwarfdump -debug-aranges - 2>&1 | \ +# RUN: FileCheck %s --check-prefix=CHECK1 + +# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj --defsym CASE2=0 -o - | \ +# RUN: llvm-dwarfdump -debug-aranges - 2>&1 | \ +# RUN: FileCheck %s --check-prefix=CHECK2 + +# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj --defsym CASE3=0 -o - | \ +# RUN: llvm-dwarfdump -debug-aranges - 2>&1 | \ +# RUN: FileCheck %s --check-prefix=CHECK3 + + .section .debug_aranges,"",@progbits +.ifdef CASE1 +# CHECK1: address range table at offset 0x0 has invalid length +.Llen: + .long .Lend - .Lversion + 1 # The length exceeds the section boundaries +.Lversion: + .short 2 # Version + .long 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 # CASE1 + +.ifdef CASE2 +# CHECK2: address range table at offset 0x0 has invalid address size +.Llen: + .long .Lend - .Lversion # Length +.Lversion: + .short 2 # Version + .long 0 # Debug Info Offset + .byte 5 # Address Size (invalid) + .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 # CASE2 + +.ifdef CASE3 +# CHECK3: address range table at offset 0x0 is not terminated by null entry +.Llen: + .long .Lend - .Lversion # Length +.Lversion: + .short 2 # Version + .long 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 + # The set is not properly terminated +.Lend: +.endif # CASE3 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 @@ -5,7 +5,7 @@ .section .debug_aranges,"",@progbits # CHECK: .debug_aranges contents: -## Check that an empty set of ranges is supported. +## Case 1: Check that an empty set of ranges is supported. .L1: .long .L1end - .L1version # Length # CHECK: Address Range Header: length = 0x00000014, @@ -23,3 +23,46 @@ .long 0, 0 # Termination tuple # CHECK-NOT: [0x .L1end: + +## Case 2: Check that the address size of 4 is supported. +.L2: + .long .L2end - .L2version # Length +# CHECK: Address Range Header: length = 0x0000001c, +.L2version: + .short 2 # Version + .long 0x11223344 # Debug Info Offset + .byte 4 # Address Size + .byte 0 # Segment Selector Size +# CHECK-SAME: version = 0x0002, +# CHECK-SAME: cu_offset = 0x11223344, +# CHECK-SAME: addr_size = 0x04, +# CHECK-SAME: seg_size = 0x00 + .space 7 - (. - .L2 + 7) % 8 # Padding +.L2tuples: + .long 0x11223344, 0x01020304 # Address and length +# CHECK-NEXT: [0x11223344, 0x12243648) + .long 0, 0 # Termination tuple +# CHECK-NOT: [0x +.L2end: + +## Case 3: Check that the address size of 8 is also supported. +.L3: + .long .L3end - .L3version # Length +# CHECK: Address Range Header: length = 0x0000002c, +.L3version: + .short 2 # Version + .long 0x22334455 # Debug Info Offset + .byte 8 # Address Size + .byte 0 # Segment Selector Size +# CHECK-SAME: version = 0x0002, +# CHECK-SAME: cu_offset = 0x22334455, +# CHECK-SAME: addr_size = 0x08, +# CHECK-SAME: seg_size = 0x00 + .space 15 - (. - .L3 + 15) % 16 # Padding +.L3tuples: + .quad 0x1122334455667788 # Address + .quad 0x0102030405060708 # Length +# CHECK-NEXT: [0x1122334455667788, 0x122436485a6c7e90) + .quad 0, 0 # Termination tuple +# CHECK-NOT: [0x +.L3end: Index: llvm/tools/obj2yaml/dwarf2yaml.cpp =================================================================== --- llvm/tools/obj2yaml/dwarf2yaml.cpp +++ llvm/tools/obj2yaml/dwarf2yaml.cpp @@ -62,7 +62,8 @@ uint64_t Offset = 0; DWARFDebugArangeSet Set; - while (Set.extract(ArangesData, &Offset)) { + while (ArangesData.isValidOffset(Offset) && + !errorToBool(Set.extract(ArangesData, &Offset))) { DWARFYAML::ARange Range; Range.Length.setLength(Set.getHeader().Length); Range.Version = Set.getHeader().Version;