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,71 @@ 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 - break; // We are done if we get a zero address and length - } - - return !ArangeDescriptors.empty(); +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)) + return createStringError(errc::invalid_argument, + "Invalid arange header length"); + if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) + return createStringError(errc::invalid_argument, + "Invalid arange header address size"); + + // 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) + return ErrorSuccess(); + ArangeDescriptors.push_back(arangeDescriptor); } - return false; + + return createStringError(errc::invalid_argument, + "arange descriptors not terminated by null entry"); } 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.s =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/dwarfdump-debug-aranges-error.s @@ -0,0 +1,18 @@ +# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o - | \ +# RUN: llvm-dwarfdump -debug-aranges - 2>&1 | \ +# RUN: FileCheck %s + + .section .debug_aranges,"",@progbits + .long .AREnd - .ARVersion # Length +.ARVersion: + .short 2 # Version + .long 0 # Debug Info Offset + .byte 5 # Address Size (invalid) + .byte 0 # Segment Selector Size + .balign 0+4+4 # The first tuple alignment +.ARTable: + .long 0, 1 # Address and size + .long 0, 0 # Termination tuple +.AREnd: + +# CHECK: Invalid arange header address size 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;