diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h @@ -9,6 +9,7 @@ #ifndef LLVM_DEBUGINFO_DWARFDATAEXTRACTOR_H #define LLVM_DEBUGINFO_DWARFDATAEXTRACTOR_H +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFSection.h" #include "llvm/Support/DataExtractor.h" @@ -38,11 +39,22 @@ StringRef(reinterpret_cast(Data.data()), Data.size()), IsLittleEndian, AddressSize) {} + std::pair + getInitialLength(uint64_t *Off, Error *Err = nullptr) const; + + std::pair getInitialLength(Cursor &C) const { + return getInitialLength(&getOffset(C), &getError(C)); + } + /// Extracts a value and applies a relocation to the result if /// one exists for the given offset. uint64_t getRelocatedValue(uint32_t Size, uint64_t *Off, uint64_t *SectionIndex = nullptr, Error *Err = nullptr) const; + uint64_t getRelocatedValue(Cursor &C, uint32_t Size, + uint64_t *SectionIndex = nullptr) const { + return getRelocatedValue(Size, &getOffset(C), SectionIndex, &getError(C)); + } /// Extracts an address-sized value and applies a relocation to the result if /// one exists for the given offset. diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -377,56 +377,31 @@ Error DWARFDebugNames::Header::extract(const DWARFDataExtractor &AS, uint64_t *Offset) { - uint64_t StartingOffset = *Offset; - // Check that we can read the unit length field. - if (!AS.isValidOffsetForDataOfSize(StartingOffset, 4)) - return createStringError(errc::illegal_byte_sequence, - "Section too small: cannot read header."); - UnitLength = AS.getU32(Offset); - if (UnitLength >= dwarf::DW_LENGTH_lo_reserved && - UnitLength != dwarf::DW_LENGTH_DWARF64) - return createStringError(errc::illegal_byte_sequence, - "Unsupported reserved unit length value"); - Format = (UnitLength == dwarf::DW_LENGTH_DWARF64) ? dwarf::DWARF64 - : dwarf::DWARF32; - - // These fields are the same for 32-bit and 64-bit DWARF formats. - constexpr unsigned CommonHeaderSize = 2 + // Version - 2 + // Padding - 4 + // CU count - 4 + // Local TU count - 4 + // Foreign TU count - 4 + // Bucket count - 4 + // Name count - 4 + // Abbreviations table size - 4; // Augmentation string size - // Check that we can read the fixed-size part. - if (!AS.isValidOffsetForDataOfSize( - StartingOffset, - CommonHeaderSize + dwarf::getUnitLengthFieldByteSize(Format))) - return createStringError(errc::illegal_byte_sequence, - "Section too small: cannot read header."); - if (Format == dwarf::DWARF64) - UnitLength = AS.getU64(Offset); - Version = AS.getU16(Offset); - // Skip padding - *Offset += 2; - CompUnitCount = AS.getU32(Offset); - LocalTypeUnitCount = AS.getU32(Offset); - ForeignTypeUnitCount = AS.getU32(Offset); - BucketCount = AS.getU32(Offset); - NameCount = AS.getU32(Offset); - AbbrevTableSize = AS.getU32(Offset); - AugmentationStringSize = alignTo(AS.getU32(Offset), 4); - - if (!AS.isValidOffsetForDataOfSize(*Offset, AugmentationStringSize)) + DataExtractor::Cursor C(*Offset); + std::tie(UnitLength, Format) = AS.getInitialLength(C); + + Version = AS.getU16(C); + AS.skip(C, 2); // padding + CompUnitCount = AS.getU32(C); + LocalTypeUnitCount = AS.getU32(C); + ForeignTypeUnitCount = AS.getU32(C); + BucketCount = AS.getU32(C); + NameCount = AS.getU32(C); + AbbrevTableSize = AS.getU32(C); + AugmentationStringSize = alignTo(AS.getU32(C), 4); + + if (!C) + return C.takeError(); + + if (!AS.isValidOffsetForDataOfSize(C.tell(), AugmentationStringSize)) return createStringError( errc::illegal_byte_sequence, "Section too small: cannot read header augmentation."); AugmentationString.resize(AugmentationStringSize); - AS.getU8(Offset, reinterpret_cast(AugmentationString.data()), + AS.getU8(C, reinterpret_cast(AugmentationString.data()), AugmentationStringSize); - return Error::success(); + *Offset = C.tell(); + return C.takeError(); } void DWARFDebugNames::Abbrev::dump(ScopedPrinter &W) const { diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp @@ -7,11 +7,44 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" -#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" using namespace llvm; +std::pair +DWARFDataExtractor::getInitialLength(uint64_t *Off, Error *Err) const { + ErrorAsOutParameter ErrAsOut(Err); + if (Err && *Err) + return {0, dwarf::DWARF32}; + + Cursor C(*Off); + uint64_t Length = getRelocatedValue(C, 4); + dwarf::DwarfFormat Format = dwarf::DWARF32; + if (Length == dwarf::DW_LENGTH_DWARF64) { + Length = getRelocatedValue(C, 8); + Format = dwarf::DWARF64; + } else if (Length >= dwarf::DW_LENGTH_lo_reserved) { + cantFail(C.takeError()); + if (Err) + *Err = createStringError( + errc::invalid_argument, + "Unsupported reserved unit length of value 0x%8.8" PRIx64 + " at offset 0x%" PRIx64, + Length, *Off); + return {0, dwarf::DWARF32}; + } + + if (C) { + *Off = C.tell(); + return {Length, Format}; + } + if (Err) + *Err = C.takeError(); + else + consumeError(C.takeError()); + return {0, dwarf::DWARF32}; +} + uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint64_t *Off, uint64_t *SecNdx, Error *Err) const { diff --git a/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp @@ -18,25 +18,13 @@ Error DWARFListTableHeader::extract(DWARFDataExtractor Data, uint64_t *OffsetPtr) { HeaderOffset = *OffsetPtr; - // Read and verify the length field. - if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t))) - return createStringError(errc::invalid_argument, - "section is not large enough to contain a " - "%s table length at offset 0x%" PRIx64, - SectionName.data(), *OffsetPtr); - Format = dwarf::DwarfFormat::DWARF32; - uint8_t OffsetByteSize = 4; - HeaderData.Length = Data.getRelocatedValue(4, OffsetPtr); - if (HeaderData.Length == dwarf::DW_LENGTH_DWARF64) { - Format = dwarf::DwarfFormat::DWARF64; - OffsetByteSize = 8; - HeaderData.Length = Data.getU64(OffsetPtr); - } else if (HeaderData.Length >= dwarf::DW_LENGTH_lo_reserved) { - return createStringError(errc::invalid_argument, - "%s table at offset 0x%" PRIx64 - " has unsupported reserved unit length of value 0x%8.8" PRIx64, - SectionName.data(), HeaderOffset, HeaderData.Length); - } + Error Err = Error::success(); + + std::tie(HeaderData.Length, Format) = Data.getInitialLength(OffsetPtr, &Err); + if (Err) + return Err; + + uint8_t OffsetByteSize = Format == dwarf::DWARF64 ? 8 : 4; uint64_t FullLength = HeaderData.Length + dwarf::getUnitLengthFieldByteSize(Format); assert(FullLength == length()); diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-short1.s b/llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-short1.s --- a/llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-short1.s +++ b/llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-short1.s @@ -1,7 +1,7 @@ # RUN: llvm-mc -triple x86_64-pc-linux %s -filetype=obj | \ # RUN: not llvm-dwarfdump -verify - | FileCheck %s -# CHECK: Section too small: cannot read header. +# CHECK: error: unexpected end of data .section .debug_str,"MS",@progbits,1 .Lstring_producer: diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s b/llvm/test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s --- a/llvm/test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s +++ b/llvm/test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s @@ -2,7 +2,7 @@ # RUN: llvm-dwarfdump --debug-rnglists - 2>&1 | FileCheck %s --check-prefix=SHORT # SHORT-NOT: error: # SHORT-NOT: range list header -# SHORT: error: section is not large enough to contain a .debug_rnglists table length at offset 0 +# SHORT: error: unexpected end of data # SHORT-NOT: range list header # SHORT-NOT: error: diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug_rnglists_reserved_length.s b/llvm/test/tools/llvm-dwarfdump/X86/debug_rnglists_reserved_length.s --- a/llvm/test/tools/llvm-dwarfdump/X86/debug_rnglists_reserved_length.s +++ b/llvm/test/tools/llvm-dwarfdump/X86/debug_rnglists_reserved_length.s @@ -2,7 +2,7 @@ # RUN: llvm-dwarfdump --debug-rnglists - 2>&1 | \ # RUN: FileCheck %s --implicit-check-not=error -# CHECK: error: .debug_rnglists table at offset 0x0 has unsupported reserved unit length of value 0xfffffff0 +# CHECK: error: Unsupported reserved unit length of value 0xfffffff0 at offset 0x0 .section .debug_rnglists,"",@progbits .long 0xfffffff0 diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp --- a/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp @@ -16,12 +16,7 @@ void ExpectDebugNamesExtractError(StringRef NamesSecData, StringRef StrSecData, const char *ErrorMessage) { - DWARFSection NamesDWARFSection; - NamesDWARFSection.Data = NamesSecData; - StringMap> Sections; - auto Context = DWARFContext::create(Sections, /* AddrSize = */ 4, - /* isLittleEndian = */ true); - DWARFDataExtractor NamesExtractor(Context->getDWARFObj(), NamesDWARFSection, + DWARFDataExtractor NamesExtractor(NamesSecData, /* isLittleEndian = */ true, /* AddrSize = */ 4); DataExtractor StrExtractor(StrSecData, @@ -36,17 +31,16 @@ TEST(DWARFDebugNames, ReservedUnitLength) { static const char NamesSecData[64] = "\xf0\xff\xff\xff"; // Reserved unit length value - ExpectDebugNamesExtractError(StringRef(NamesSecData, sizeof(NamesSecData)), - StringRef(), - "Unsupported reserved unit length value"); + ExpectDebugNamesExtractError( + StringRef(NamesSecData, sizeof(NamesSecData)), StringRef(), + "Unsupported reserved unit length of value 0xfffffff0 at offset 0x0"); } TEST(DWARFDebugNames, TooSmallForDWARF64) { // DWARF64 header takes at least 44 bytes. static const char NamesSecData[43] = "\xff\xff\xff\xff"; // DWARF64 mark - ExpectDebugNamesExtractError( - StringRef(NamesSecData, sizeof(NamesSecData)), StringRef(), - "Section too small: cannot read header."); + ExpectDebugNamesExtractError(StringRef(NamesSecData, sizeof(NamesSecData)), + StringRef(), "unexpected end of data"); } } // end anonymous namespace