Index: include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h +++ include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h @@ -245,7 +245,7 @@ struct Header : public HeaderPOD { SmallString<8> AugmentationString; - Error extract(const DWARFDataExtractor &AS, uint32_t *Offset); + void extract(const DataExtractor &AS, DataExtractor::Cursor &C); void dump(ScopedPrinter &W) const; }; @@ -406,12 +406,11 @@ Optional Hash) const; void dumpBucket(ScopedPrinter &W, uint32_t Bucket) const; - Expected extractAttributeEncoding(uint32_t *Offset); + AttributeEncoding extractAttributeEncoding(DataExtractor::Cursor &C); - Expected> - extractAttributeEncodings(uint32_t *Offset); + std::vector extractAttributeEncodings(DataExtractor::Cursor &C); - Expected extractAbbrev(uint32_t *Offset); + Abbrev extractAbbrev(DataExtractor::Cursor &C); public: NameIndex(const DWARFDebugNames &Section, uint32_t Base) Index: include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h +++ include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h @@ -36,13 +36,18 @@ /// Extracts a value and applies a relocation to the result if /// one exists for the given offset. uint64_t getRelocatedValue(uint32_t Size, uint32_t *Off, - uint64_t *SectionIndex = nullptr) const; + uint64_t *SectionIndex = nullptr, + Error *Err = nullptr) const; /// Extracts an address-sized value and applies a relocation to the result if /// one exists for the given offset. uint64_t getRelocatedAddress(uint32_t *Off, uint64_t *SecIx = nullptr) const { return getRelocatedValue(getAddressSize(), Off, SecIx); } + uint64_t getRelocatedAddress(Cursor &C, uint64_t *SecIx = nullptr) const { + return getRelocatedValue(getAddressSize(), &getOffset(C), SecIx, + &getError(C)); + } /// Extracts a DWARF-encoded pointer in \p Offset using \p Encoding. /// There is a DWARF encoding that uses a PC-relative adjustment. Index: include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h +++ include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h @@ -68,8 +68,9 @@ /// Return the location list at the given offset or nullptr. LocationList const *getLocationListAtOffset(uint64_t Offset) const; - static Expected parseOneLocationList(DWARFDataExtractor Data, - uint32_t *Offset); + static Expected + parseOneLocationList(const DWARFDataExtractor &Data, + DataExtractor::Cursor &C); }; class DWARFDebugLoclists { @@ -106,8 +107,9 @@ /// Return the location list at the given offset or nullptr. LocationList const *getLocationListAtOffset(uint64_t Offset) const; - static Expected - parseOneLocationList(DataExtractor Data, unsigned *Offset, unsigned Version); + static Expected parseOneLocationList(const DataExtractor &Data, + DataExtractor::Cursor &C, + unsigned Version); }; } // end namespace llvm Index: include/llvm/Support/DataExtractor.h =================================================================== --- include/llvm/Support/DataExtractor.h +++ include/llvm/Support/DataExtractor.h @@ -11,6 +11,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/Error.h" namespace llvm { @@ -42,6 +43,21 @@ uint8_t IsLittleEndian; uint8_t AddressSize; public: + + class Cursor { + uint32_t Offset; + Error Err; + + friend class DataExtractor; + + public: + explicit Cursor(uint32_t Offset = 0) + : Offset(Offset), Err(Error::success()) {} + explicit operator bool() { return !Err; } + uint32_t tell() const { return Offset; } + Error takeError() { return std::move(Err); } + }; + /// Construct with a buffer that is owned by the caller. /// /// This constructor allows us to use data that is owned by the @@ -127,7 +143,11 @@ /// @return /// The unsigned integer value that was extracted, or zero on /// failure. - uint64_t getUnsigned(uint32_t *offset_ptr, uint32_t byte_size) const; + uint64_t getUnsigned(uint32_t *offset_ptr, uint32_t byte_size, + Error *Err = nullptr) const; + uint64_t getUnsigned(Cursor &C, uint32_t Size) const { + return getUnsigned(&C.Offset, Size, &C.Err); + } /// Extract an signed integer of size \a byte_size from \a *offset_ptr. /// @@ -174,6 +194,7 @@ uint64_t getAddress(uint32_t *offset_ptr) const { return getUnsigned(offset_ptr, AddressSize); } + uint64_t getAddress(Cursor &C) const { return getUnsigned(C, AddressSize); } /// Extract a uint8_t value from \a *offset_ptr. /// @@ -189,7 +210,8 @@ /// /// @return /// The extracted uint8_t value. - uint8_t getU8(uint32_t *offset_ptr) const; + uint8_t getU8(uint32_t *offset_ptr, Error *Err = nullptr) const; + uint8_t getU8(Cursor &C) const { return getU8(&C.Offset, &C.Err); } /// Extract \a count uint8_t values from \a *offset_ptr. /// @@ -215,6 +237,19 @@ /// \a dst if all values were properly extracted and copied, /// NULL otherise. uint8_t *getU8(uint32_t *offset_ptr, uint8_t *dst, uint32_t count) const; + uint8_t *getU8(Cursor &C, uint8_t *Dst, uint32_t Count) const; + + template + void getU8(Cursor &C, SmallVectorImpl &Dst, uint32_t Count) const { + static_assert( + std::is_same::value || std::is_same::value, ""); + if (isValidOffsetForDataOfSize(C.Offset, Count)) + Dst.resize(Count); + + // This relies on the fact that getU8 will not attempt to write to the + // buffer it isValidOffsetForDataOfSize(C.Offset, Count) is false. + getU8(C, reinterpret_cast(Dst.data()), Count); + } //------------------------------------------------------------------ /// Extract a uint16_t value from \a *offset_ptr. @@ -232,7 +267,8 @@ /// @return /// The extracted uint16_t value. //------------------------------------------------------------------ - uint16_t getU16(uint32_t *offset_ptr) const; + uint16_t getU16(uint32_t *offset_ptr, Error *Err = nullptr) const; + uint16_t getU16(Cursor &C) const { return getU16(&C.Offset, &C.Err); } /// Extract \a count uint16_t values from \a *offset_ptr. /// @@ -290,7 +326,8 @@ /// /// @return /// The extracted uint32_t value. - uint32_t getU32(uint32_t *offset_ptr) const; + uint32_t getU32(uint32_t *offset_ptr, Error *Err = nullptr) const; + uint32_t getU32(Cursor &C) const { return getU32(&C.Offset, &C.Err); } /// Extract \a count uint32_t values from \a *offset_ptr. /// @@ -331,7 +368,8 @@ /// /// @return /// The extracted uint64_t value. - uint64_t getU64(uint32_t *offset_ptr) const; + uint64_t getU64(uint32_t *offset_ptr, Error *Err = nullptr) const; + uint64_t getU64(Cursor &C) const { return getU64(&C.Offset, &C.Err); } /// Extract \a count uint64_t values from \a *offset_ptr. /// @@ -392,7 +430,11 @@ /// /// @return /// The extracted unsigned integer value. - uint64_t getULEB128(uint32_t *offset_ptr) const; + uint64_t getULEB128(uint32_t *offset_ptr, llvm::Error *Err = nullptr) const; + uint64_t getULEB128(Cursor &C) const { return getULEB128(&C.Offset, &C.Err); } + + void skip(Cursor &C, uint32_t Length) const; + bool eof(const Cursor &C) const { return Data.size() == C.Offset; } /// Test the validity of \a offset. /// @@ -420,6 +462,12 @@ bool isValidOffsetForAddress(uint32_t offset) const { return isValidOffsetForDataOfSize(offset, AddressSize); } + +protected: + // Make it possible for subclasses to access these fields without making them + // public. + static uint32_t &getOffset(Cursor &C) { return C.Offset; } + static Error &getError(Cursor &C) { return C.Err; } }; } // namespace llvm Index: lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -42,19 +42,26 @@ DWARFAcceleratorTable::~DWARFAcceleratorTable() = default; Error AppleAcceleratorTable::extract() { - uint32_t Offset = 0; + DataExtractor::Cursor C; - // Check that we can at least read the header. - if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength) + 4)) - return createStringError(errc::illegal_byte_sequence, - "Section too small: cannot read header."); + Hdr.Magic = AccelSection.getU32(C); + Hdr.Version = AccelSection.getU16(C); + Hdr.HashFunction = AccelSection.getU16(C); + Hdr.BucketCount = AccelSection.getU32(C); + Hdr.HashCount = AccelSection.getU32(C); + Hdr.HeaderDataLength = AccelSection.getU32(C); + + HdrData.DIEOffsetBase = AccelSection.getU32(C); + uint32_t NumAtoms = AccelSection.getU32(C); - Hdr.Magic = AccelSection.getU32(&Offset); - Hdr.Version = AccelSection.getU16(&Offset); - Hdr.HashFunction = AccelSection.getU16(&Offset); - Hdr.BucketCount = AccelSection.getU32(&Offset); - Hdr.HashCount = AccelSection.getU32(&Offset); - Hdr.HeaderDataLength = AccelSection.getU32(&Offset); + for (unsigned i = 0; i < NumAtoms && C; ++i) { + uint16_t AtomType = AccelSection.getU16(C); + auto AtomForm = static_cast(AccelSection.getU16(C)); + HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm)); + } + + if (Error E = C.takeError()) + return E; // Check that we can read all the hashes and offsets from the // section (see SourceLevelDebugging.rst for the structure of the index). @@ -66,15 +73,6 @@ errc::illegal_byte_sequence, "Section too small: cannot read buckets and hashes."); - HdrData.DIEOffsetBase = AccelSection.getU32(&Offset); - uint32_t NumAtoms = AccelSection.getU32(&Offset); - - for (unsigned i = 0; i < NumAtoms; ++i) { - uint16_t AtomType = AccelSection.getU16(&Offset); - auto AtomForm = static_cast(AccelSection.getU16(&Offset)); - HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm)); - } - IsValid = true; return Error::success(); } @@ -376,32 +374,20 @@ W.startLine() << "Augmentation: '" << AugmentationString << "'\n"; } -Error DWARFDebugNames::Header::extract(const DWARFDataExtractor &AS, - uint32_t *Offset) { - // Check that we can read the fixed-size part. - if (!AS.isValidOffset(*Offset + sizeof(HeaderPOD) - 1)) - return createStringError(errc::illegal_byte_sequence, - "Section too small: cannot read header."); - - UnitLength = AS.getU32(Offset); - Version = AS.getU16(Offset); - Padding = AS.getU16(Offset); - 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)) - return createStringError( - errc::illegal_byte_sequence, - "Section too small: cannot read header augmentation."); - AugmentationString.resize(AugmentationStringSize); - AS.getU8(Offset, reinterpret_cast(AugmentationString.data()), - AugmentationStringSize); - return Error::success(); +void DWARFDebugNames::Header::extract(const DataExtractor &AS, + DataExtractor::Cursor &C) { + UnitLength = AS.getU32(C); + Version = AS.getU16(C); + Padding = AS.getU16(C); + 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); + AS.getU8(C, AugmentationString, AugmentationStringSize); } void DWARFDebugNames::Abbrev::dump(ScopedPrinter &W) const { @@ -436,87 +422,81 @@ return DWARFDebugNames::Abbrev(~0, dwarf::Tag(0), {}); } -Expected -DWARFDebugNames::NameIndex::extractAttributeEncoding(uint32_t *Offset) { - if (*Offset >= EntriesBase) { - return createStringError(errc::illegal_byte_sequence, - "Incorrectly terminated abbreviation table."); - } - - uint32_t Index = Section.AccelSection.getULEB128(Offset); - uint32_t Form = Section.AccelSection.getULEB128(Offset); +DWARFDebugNames::AttributeEncoding +DWARFDebugNames::NameIndex::extractAttributeEncoding(DataExtractor::Cursor &C) { + uint32_t Index = Section.AccelSection.getULEB128(C); + uint32_t Form = Section.AccelSection.getULEB128(C); return AttributeEncoding(dwarf::Index(Index), dwarf::Form(Form)); } -Expected> -DWARFDebugNames::NameIndex::extractAttributeEncodings(uint32_t *Offset) { +std::vector +DWARFDebugNames::NameIndex::extractAttributeEncodings(DataExtractor::Cursor &C) { std::vector Result; for (;;) { - auto AttrEncOr = extractAttributeEncoding(Offset); - if (!AttrEncOr) - return AttrEncOr.takeError(); - if (isSentinel(*AttrEncOr)) - return std::move(Result); + AttributeEncoding AttrEnc = extractAttributeEncoding(C); + if (isSentinel(AttrEnc)) + return Result; - Result.emplace_back(*AttrEncOr); + Result.emplace_back(AttrEnc); } } -Expected -DWARFDebugNames::NameIndex::extractAbbrev(uint32_t *Offset) { - if (*Offset >= EntriesBase) { - return createStringError(errc::illegal_byte_sequence, - "Incorrectly terminated abbreviation table."); - } - - uint32_t Code = Section.AccelSection.getULEB128(Offset); +DWARFDebugNames::Abbrev +DWARFDebugNames::NameIndex::extractAbbrev(DataExtractor::Cursor &C) { + uint32_t Code = Section.AccelSection.getULEB128(C); if (Code == 0) return sentinelAbbrev(); - uint32_t Tag = Section.AccelSection.getULEB128(Offset); - auto AttrEncOr = extractAttributeEncodings(Offset); - if (!AttrEncOr) - return AttrEncOr.takeError(); - return Abbrev(Code, dwarf::Tag(Tag), std::move(*AttrEncOr)); + uint32_t Tag = Section.AccelSection.getULEB128(C); + std::vector AttrEnc = extractAttributeEncodings(C); + return Abbrev(Code, dwarf::Tag(Tag), std::move(AttrEnc)); } Error DWARFDebugNames::NameIndex::extract() { const DWARFDataExtractor &AS = Section.AccelSection; - uint32_t Offset = Base; - if (Error E = Hdr.extract(AS, &Offset)) - return E; - - CUsBase = Offset; - Offset += Hdr.CompUnitCount * 4; - Offset += Hdr.LocalTypeUnitCount * 4; - Offset += Hdr.ForeignTypeUnitCount * 8; - BucketsBase = Offset; - Offset += Hdr.BucketCount * 4; - HashesBase = Offset; + DataExtractor::Cursor C(Base); + Hdr.extract(AS, C); + + CUsBase = C.tell(); + AS.skip(C, Hdr.CompUnitCount * 4); + AS.skip(C, Hdr.LocalTypeUnitCount * 4); + AS.skip(C, Hdr.ForeignTypeUnitCount * 8); + BucketsBase = C.tell(); + AS.skip(C, Hdr.BucketCount * 4); + HashesBase = C.tell(); if (Hdr.BucketCount > 0) - Offset += Hdr.NameCount * 4; - StringOffsetsBase = Offset; - Offset += Hdr.NameCount * 4; - EntryOffsetsBase = Offset; - Offset += Hdr.NameCount * 4; + AS.skip(C, Hdr.NameCount * 4); + StringOffsetsBase = C.tell(); + AS.skip(C, Hdr.NameCount * 4); + EntryOffsetsBase = C.tell(); + AS.skip(C, Hdr.NameCount * 4); - if (!AS.isValidOffsetForDataOfSize(Offset, Hdr.AbbrevTableSize)) + if (Error E = C.takeError()) + return E; + + uint32_t AbbrevBase = C.tell(); + if (!AS.isValidOffsetForDataOfSize(AbbrevBase, Hdr.AbbrevTableSize)) return createStringError(errc::illegal_byte_sequence, "Section too small: cannot read abbreviations."); - EntriesBase = Offset + Hdr.AbbrevTableSize; + EntriesBase = C.tell() + Hdr.AbbrevTableSize; for (;;) { - auto AbbrevOr = extractAbbrev(&Offset); - if (!AbbrevOr) - return AbbrevOr.takeError(); - if (isSentinel(*AbbrevOr)) - return Error::success(); + Abbrev Abbr = extractAbbrev(C); + if (llvm::Error E = C.takeError()) + return E; + if (isSentinel(Abbr)) + break; - if (!Abbrevs.insert(std::move(*AbbrevOr)).second) + if (!Abbrevs.insert(std::move(Abbr)).second) { return createStringError(errc::invalid_argument, "Duplicate abbreviation code."); + } } + if (C.tell() > EntriesBase) + return createStringError(errc::illegal_byte_sequence, + "Incorrectly terminated abbreviation table."); + return Error::success(); } DWARFDebugNames::Entry::Entry(const NameIndex &NameIdx, const Abbrev &Abbr) Index: lib/DebugInfo/DWARF/DWARFDataExtractor.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDataExtractor.cpp +++ lib/DebugInfo/DWARF/DWARFDataExtractor.cpp @@ -13,13 +13,14 @@ using namespace llvm; uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint32_t *Off, - uint64_t *SecNdx) const { + uint64_t *SecNdx, + Error *Err) const { if (SecNdx) *SecNdx = object::SectionedAddress::UndefSection; if (!Section) - return getUnsigned(Off, Size); + return getUnsigned(Off, Size, Err); Optional E = Obj->find(*Section, *Off); - uint64_t A = getUnsigned(Off, Size); + uint64_t A = getUnsigned(Off, Size, Err); if (!E) return A; if (SecNdx) Index: lib/DebugInfo/DWARF/DWARFDebugLoc.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDebugLoc.cpp +++ lib/DebugInfo/DWARF/DWARFDebugLoc.cpp @@ -28,10 +28,6 @@ return createStringError(inconvertibleErrorCode(), Fmt, Vals...); } -static llvm::Error createOverflowError(const char *Section) { - return createError("location list overflows the %s section", Section); -} - // When directly dumping the .debug_loc without a compile unit, we have to guess // at the DWARF version. This only affects DW_OP_call_ref, which is a rare // expression that LLVM doesn't produce. Guessing the wrong version means we @@ -93,41 +89,33 @@ } Expected -DWARFDebugLoc::parseOneLocationList(DWARFDataExtractor Data, unsigned *Offset) { +DWARFDebugLoc::parseOneLocationList(const DWARFDataExtractor &Data, + DataExtractor::Cursor &C) { LocationList LL; - LL.Offset = *Offset; + LL.Offset = C.tell(); // 2.6.2 Location Lists // A location list entry consists of: while (true) { Entry E; - if (!Data.isValidOffsetForDataOfSize(*Offset, 2 * Data.getAddressSize())) - return createOverflowError("debug_loc"); // 1. A beginning address offset. ... - E.Begin = Data.getRelocatedAddress(Offset); + E.Begin = Data.getRelocatedAddress(C); // 2. An ending address offset. ... - E.End = Data.getRelocatedAddress(Offset); + E.End = Data.getRelocatedAddress(C); + if (Error Err = C.takeError()) + return std::move(Err); // The end of any given location list is marked by an end of list entry, // which consists of a 0 for the beginning address offset and a 0 for the // ending address offset. if (E.Begin == 0 && E.End == 0) return LL; - if (!Data.isValidOffsetForDataOfSize(*Offset, 2)) - return createOverflowError("debug_loc"); - - unsigned Bytes = Data.getU16(Offset); - if (!Data.isValidOffsetForDataOfSize(*Offset, Bytes)) - return createOverflowError("debug_loc"); - + unsigned Bytes = Data.getU16(C); // A single location description describing the location of the object... - StringRef str = Data.getData().substr(*Offset, Bytes); - *Offset += Bytes; - E.Loc.reserve(str.size()); - llvm::copy(str, std::back_inserter(E.Loc)); + Data.getU8(C, E.Loc, Bytes); LL.Entries.push_back(std::move(E)); } } @@ -136,101 +124,75 @@ IsLittleEndian = data.isLittleEndian(); AddressSize = data.getAddressSize(); - uint32_t Offset = 0; - while (data.isValidOffset(Offset + data.getAddressSize() - 1)) { - if (auto LL = parseOneLocationList(data, &Offset)) + DataExtractor::Cursor C(0); + while (!data.eof(C)) { + if (auto LL = parseOneLocationList(data, C)) Locations.push_back(std::move(*LL)); else { logAllUnhandledErrors(LL.takeError(), WithColor::error()); break; } } - if (data.isValidOffset(Offset)) - WithColor::error() << "failed to consume entire .debug_loc section\n"; } Expected -DWARFDebugLoclists::parseOneLocationList(DataExtractor Data, unsigned *Offset, +DWARFDebugLoclists::parseOneLocationList(const DataExtractor &Data, + DataExtractor::Cursor &C, unsigned Version) { LocationList LL; - LL.Offset = *Offset; - - while (true) { - if (!Data.isValidOffset(*Offset)) - return createOverflowError("debug_loclists"); + LL.Offset = C.tell(); + // dwarf::DW_LLE_end_of_list_entry is 0 and indicates the end of the list. + while (auto Kind = static_cast(Data.getU8(C))) { Entry E; - E.Kind = static_cast(Data.getU8(Offset)); - if (E.Kind == dwarf::DW_LLE_end_of_list) - return LL; - - // Verify that the reads were sucessful by checking the offset field before - // and after the read. This relies on DataExtractor not updating the offset - // on failure. - // TODO: Simplify this code once we have a better way of handling - // DataExtractor errors. - unsigned SavedOffset = *Offset; - switch (E.Kind) { - case dwarf::DW_LLE_startx_length: - case dwarf::DW_LLE_offset_pair: - E.Value0 = Data.getULEB128(Offset); - break; - case dwarf::DW_LLE_start_length: - case dwarf::DW_LLE_base_address: - E.Value0 = Data.getAddress(Offset); - break; - default: - return createError("LLE of kind %x not implemented", (int)E.Kind); - } - if (SavedOffset == *Offset) - return createOverflowError("debug_loclists"); - - SavedOffset = *Offset; - switch (E.Kind) { + E.Kind = Kind; + switch (Kind) { case dwarf::DW_LLE_startx_length: + E.Value0 = Data.getULEB128(C); // Pre-DWARF 5 has different interpretation of the length field. We have // to support both pre- and standartized styles for the compatibility. if (Version < 5) - E.Value1 = Data.getU32(Offset); + E.Value1 = Data.getU32(C); else - E.Value1 = Data.getULEB128(Offset); + E.Value1 = Data.getULEB128(C); break; case dwarf::DW_LLE_start_length: + E.Value0 = Data.getAddress(C); + E.Value1 = Data.getULEB128(C); + break; case dwarf::DW_LLE_offset_pair: - E.Value1 = Data.getULEB128(Offset); + E.Value0 = Data.getULEB128(C); + E.Value1 = Data.getULEB128(C); break; case dwarf::DW_LLE_base_address: + E.Value0 = Data.getAddress(C); break; + default: + if (Error Err = C.takeError()) + return std::move(Err); + return createError("LLE of kind %x not implemented", (int)E.Kind); } - if (E.Kind != dwarf::DW_LLE_base_address) { - if (SavedOffset == *Offset) - return createOverflowError("debug_loclists"); - - SavedOffset = *Offset; - unsigned Bytes = - Version >= 5 ? Data.getULEB128(Offset) : Data.getU16(Offset); - if (SavedOffset == *Offset || - !Data.isValidOffsetForDataOfSize(*Offset, Bytes)) - return createOverflowError("debug_loclists"); + if (Kind != dwarf::DW_LLE_base_address) { + unsigned Bytes = Version >= 5 ? Data.getULEB128(C) : Data.getU16(C); // A single location description describing the location of the object... - StringRef str = Data.getData().substr(*Offset, Bytes); - *Offset += Bytes; - E.Loc.resize(str.size()); - llvm::copy(str, E.Loc.begin()); + Data.getU8(C, E.Loc, Bytes); } LL.Entries.push_back(std::move(E)); } + if (llvm::Error E = C.takeError()) + return std::move(E); + return LL; } void DWARFDebugLoclists::parse(DataExtractor data, unsigned Version) { IsLittleEndian = data.isLittleEndian(); AddressSize = data.getAddressSize(); - uint32_t Offset = 0; - while (data.isValidOffset(Offset)) { - if (auto LL = parseOneLocationList(data, &Offset, Version)) + DataExtractor::Cursor C(0); + while (!data.eof(C)) { + if (auto LL = parseOneLocationList(data, C, Version)) Locations.push_back(std::move(*LL)); else { logAllUnhandledErrors(LL.takeError(), WithColor::error()); Index: lib/DebugInfo/DWARF/DWARFDie.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDie.cpp +++ lib/DebugInfo/DWARF/DWARFDie.cpp @@ -97,7 +97,8 @@ DWARFDebugLoc DebugLoc; DWARFDataExtractor Data(Obj, *U->getLocSection(), Ctx.isLittleEndian(), Obj.getAddressSize()); - if (auto LL = DebugLoc.parseOneLocationList(Data, &Offset)) { + DataExtractor::Cursor C(Offset); + if (auto LL = DebugLoc.parseOneLocationList(Data, C)) { uint64_t BaseAddr = 0; if (Optional BA = U->getBaseAddress()) BaseAddr = BA->Address; @@ -121,8 +122,9 @@ // Modern locations list (.debug_loclists) are used starting from v5. // Ideally we should take the version from the .debug_loclists section // header, but using CU's version for simplicity. + DataExtractor::Cursor C(Offset); auto LL = DWARFDebugLoclists::parseOneLocationList( - Data, &Offset, UseLocLists ? U->getVersion() : 4); + Data, C, UseLocLists ? U->getVersion() : 4); uint64_t BaseAddr = 0; if (Optional BA = U->getBaseAddress()) Index: lib/Support/DataExtractor.cpp =================================================================== --- lib/Support/DataExtractor.cpp +++ lib/Support/DataExtractor.cpp @@ -7,104 +7,133 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Host.h" #include "llvm/Support/SwapByteOrder.h" + using namespace llvm; +static Error createError() { + return createStringError(errc::illegal_byte_sequence, + "unexpected end of data"); +} + +static void unexpectedEndReached(Error *E) { + if (E && !*E) + *E = createError(); +} + +static void setErrorToUnchecked(Error *E) { +#ifdef _DEBUG + if (E && !*E) + *E = llvm::Error::success(); +#endif +} + template static T getU(uint32_t *offset_ptr, const DataExtractor *de, - bool isLittleEndian, const char *Data) { - T val = 0; + bool isLittleEndian, const char *Data, llvm::Error *Err) { + setErrorToUnchecked(Err); uint32_t offset = *offset_ptr; - if (de->isValidOffsetForDataOfSize(offset, sizeof(val))) { + if (de->isValidOffsetForDataOfSize(offset, sizeof(T))) { + T val = 0; std::memcpy(&val, &Data[offset], sizeof(val)); if (sys::IsLittleEndianHost != isLittleEndian) sys::swapByteOrder(val); // Advance the offset *offset_ptr += sizeof(val); + return val; } - return val; + unexpectedEndReached(Err); + return T(0); } template static T *getUs(uint32_t *offset_ptr, T *dst, uint32_t count, - const DataExtractor *de, bool isLittleEndian, const char *Data){ + const DataExtractor *de, bool isLittleEndian, const char *Data, + llvm::Error *Err) { + setErrorToUnchecked(Err); uint32_t offset = *offset_ptr; - if (count > 0 && de->isValidOffsetForDataOfSize(offset, sizeof(*dst)*count)) { + if (de->isValidOffsetForDataOfSize(offset, sizeof(*dst) * count)) { for (T *value_ptr = dst, *end = dst + count; value_ptr != end; ++value_ptr, offset += sizeof(*dst)) - *value_ptr = getU(offset_ptr, de, isLittleEndian, Data); + *value_ptr = getU(offset_ptr, de, isLittleEndian, Data, Err); // Advance the offset *offset_ptr = offset; // Return a non-NULL pointer to the converted data as an indicator of // success return dst; } + unexpectedEndReached(Err); return nullptr; } -uint8_t DataExtractor::getU8(uint32_t *offset_ptr) const { - return getU(offset_ptr, this, IsLittleEndian, Data.data()); +uint8_t DataExtractor::getU8(uint32_t *offset_ptr, Error *Err) const { + return getU(offset_ptr, this, IsLittleEndian, Data.data(), Err); } uint8_t * DataExtractor::getU8(uint32_t *offset_ptr, uint8_t *dst, uint32_t count) const { return getUs(offset_ptr, dst, count, this, IsLittleEndian, - Data.data()); + Data.data(), nullptr); } +uint8_t *DataExtractor::getU8(Cursor &C, uint8_t *Dst, uint32_t Count) const { + return getUs(&C.Offset, Dst, Count, this, IsLittleEndian, + Data.data(), &C.Err); +} -uint16_t DataExtractor::getU16(uint32_t *offset_ptr) const { - return getU(offset_ptr, this, IsLittleEndian, Data.data()); +uint16_t DataExtractor::getU16(uint32_t *offset_ptr, Error *Err) const { + return getU(offset_ptr, this, IsLittleEndian, Data.data(), Err); } uint16_t *DataExtractor::getU16(uint32_t *offset_ptr, uint16_t *dst, uint32_t count) const { return getUs(offset_ptr, dst, count, this, IsLittleEndian, - Data.data()); + Data.data(), nullptr); } uint32_t DataExtractor::getU24(uint32_t *offset_ptr) const { uint24_t ExtractedVal = - getU(offset_ptr, this, IsLittleEndian, Data.data()); + getU(offset_ptr, this, IsLittleEndian, Data.data(), nullptr); // The 3 bytes are in the correct byte order for the host. return ExtractedVal.getAsUint32(sys::IsLittleEndianHost); } -uint32_t DataExtractor::getU32(uint32_t *offset_ptr) const { - return getU(offset_ptr, this, IsLittleEndian, Data.data()); +uint32_t DataExtractor::getU32(uint32_t *offset_ptr, Error *Err) const { + return getU(offset_ptr, this, IsLittleEndian, Data.data(), Err); } uint32_t *DataExtractor::getU32(uint32_t *offset_ptr, uint32_t *dst, uint32_t count) const { return getUs(offset_ptr, dst, count, this, IsLittleEndian, - Data.data()); + Data.data(), nullptr); } -uint64_t DataExtractor::getU64(uint32_t *offset_ptr) const { - return getU(offset_ptr, this, IsLittleEndian, Data.data()); +uint64_t DataExtractor::getU64(uint32_t *offset_ptr, Error *Err) const { + return getU(offset_ptr, this, IsLittleEndian, Data.data(), Err); } uint64_t *DataExtractor::getU64(uint32_t *offset_ptr, uint64_t *dst, uint32_t count) const { return getUs(offset_ptr, dst, count, this, IsLittleEndian, - Data.data()); + Data.data(), nullptr); } -uint64_t -DataExtractor::getUnsigned(uint32_t *offset_ptr, uint32_t byte_size) const { +uint64_t DataExtractor::getUnsigned(uint32_t *offset_ptr, uint32_t byte_size, + Error *Err) const { switch (byte_size) { case 1: - return getU8(offset_ptr); + return getU8(offset_ptr, Err); case 2: - return getU16(offset_ptr); + return getU16(offset_ptr, Err); case 4: - return getU32(offset_ptr); + return getU32(offset_ptr, Err); case 8: - return getU64(offset_ptr); + return getU64(offset_ptr, Err); } llvm_unreachable("getUnsigned unhandled case!"); } @@ -144,11 +173,10 @@ return StringRef(); } -uint64_t DataExtractor::getULEB128(uint32_t *offset_ptr) const { +uint64_t DataExtractor::getULEB128(uint32_t *offset_ptr, + llvm::Error *Err) const { + setErrorToUnchecked(Err); uint64_t result = 0; - if (Data.empty()) - return 0; - unsigned shift = 0; uint32_t offset = *offset_ptr; uint8_t byte = 0; @@ -162,6 +190,7 @@ return result; } } + unexpectedEndReached(Err); return 0; } @@ -189,3 +218,11 @@ } return 0; } + +void DataExtractor::skip(Cursor &C, uint32_t Length) const { + setErrorToUnchecked(&C.Err); + if (isValidOffsetForDataOfSize(C.Offset, Length)) + C.Offset += Length; + else + unexpectedEndReached(&C.Err); +} Index: test/DebugInfo/X86/dwarfdump-debug-loc-error-cases.s =================================================================== --- test/DebugInfo/X86/dwarfdump-debug-loc-error-cases.s +++ test/DebugInfo/X86/dwarfdump-debug-loc-error-cases.s @@ -1,8 +1,8 @@ # RUN: llvm-mc %s -filetype obj -triple x86_64-pc-linux --defsym CASE1=0 -o %t1.o -# RUN: llvm-dwarfdump -debug-loc %t1.o 2>&1 | FileCheck %s --check-prefix=CONSUME +# RUN: llvm-dwarfdump -debug-loc %t1.o 2>&1 | FileCheck %s # RUN: llvm-mc %s -filetype obj -triple x86_64-pc-linux --defsym CASE2=0 -o %t2.o -# RUN: llvm-dwarfdump -debug-loc %t2.o 2>&1 | FileCheck %s --check-prefix=CONSUME +# RUN: llvm-dwarfdump -debug-loc %t2.o 2>&1 | FileCheck %s # RUN: llvm-mc %s -filetype obj -triple x86_64-pc-linux --defsym CASE3=0 -o %t3.o # RUN: llvm-dwarfdump -debug-loc %t3.o 2>&1 | FileCheck %s @@ -13,9 +13,7 @@ # RUN: llvm-mc %s -filetype obj -triple x86_64-pc-linux --defsym CASE5=0 -o %t5.o # RUN: llvm-dwarfdump -debug-loc %t5.o 2>&1 | FileCheck %s -# CONSUME: error: failed to consume entire .debug_loc section - -# CHECK: error: location list overflows the debug_loc section +# CHECK: error: unexpected end of data .section .debug_loc,"",@progbits .ifdef CASE1 Index: test/DebugInfo/X86/dwarfdump-debug-loclists-error-cases.s =================================================================== --- test/DebugInfo/X86/dwarfdump-debug-loclists-error-cases.s +++ test/DebugInfo/X86/dwarfdump-debug-loclists-error-cases.s @@ -16,7 +16,7 @@ # RUN: llvm-mc %s -filetype obj -triple x86_64-pc-linux --defsym CASE6=0 -o %t6.o # RUN: llvm-dwarfdump -debug-loclists %t6.o 2>&1 | FileCheck %s --check-prefix=UNIMPL -# CHECK: error: location list overflows the debug_loclists section +# CHECK: error: unexpected end of data # UNIMPL: error: LLE of kind 47 not implemented Index: test/tools/llvm-dwarfdump/X86/debug-names-verify-abbrev-short.s =================================================================== --- test/tools/llvm-dwarfdump/X86/debug-names-verify-abbrev-short.s +++ test/tools/llvm-dwarfdump/X86/debug-names-verify-abbrev-short.s @@ -1,7 +1,7 @@ # RUN: llvm-mc -triple x86_64-pc-linux %s -filetype=obj | \ # RUN: not llvm-dwarfdump -verify - | FileCheck %s -# CHECK: Incorrectly terminated abbreviation table. +# CHECK: error: unexpected end of data .section .debug_str,"MS",@progbits,1 .Lstring_producer: Index: test/tools/llvm-dwarfdump/X86/debug-names-verify-short1.s =================================================================== --- test/tools/llvm-dwarfdump/X86/debug-names-verify-short1.s +++ 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: Index: test/tools/llvm-dwarfdump/X86/debug-names-verify-short2.s =================================================================== --- test/tools/llvm-dwarfdump/X86/debug-names-verify-short2.s +++ test/tools/llvm-dwarfdump/X86/debug-names-verify-short2.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 augmentation. +# CHECK: error: unexpected end of data .section .debug_str,"MS",@progbits,1 .Lstring_producer: