Index: llvm/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h +++ llvm/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h @@ -18,13 +18,13 @@ class DWARFCompileUnit : public DWARFUnit { public: DWARFCompileUnit(DWARFContext &Context, const DWARFSection &Section, + const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA, const DWARFSection *RS, StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, const DWARFSection &LS, bool LE, - bool IsDWO, const DWARFUnitSectionBase &UnitSection, - const DWARFUnitIndex::Entry *Entry) - : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, - UnitSection, Entry) {} + bool IsDWO, const DWARFUnitSectionBase &UnitSection) + : DWARFUnit(Context, Section, Header, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, + UnitSection) {} // VTable anchor. ~DWARFCompileUnit() override; Index: llvm/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h +++ llvm/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h @@ -24,19 +24,15 @@ class raw_ostream; class DWARFTypeUnit : public DWARFUnit { -private: - uint64_t TypeHash; - uint32_t TypeOffset; - public: DWARFTypeUnit(DWARFContext &Context, const DWARFSection &Section, + const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA, const DWARFSection *RS, StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, const DWARFSection &LS, bool LE, bool IsDWO, - const DWARFUnitSectionBase &UnitSection, - const DWARFUnitIndex::Entry *Entry) - : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, - UnitSection, Entry) {} + const DWARFUnitSectionBase &UnitSection) + : DWARFUnit(Context, Section, Header, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, + UnitSection) {} uint32_t getHeaderSize() const override { return DWARFUnit::getHeaderSize() + 12; @@ -44,10 +40,6 @@ void dump(raw_ostream &OS, DIDumpOptions DumpOpts = {}); static const DWARFSectionKind Section = DW_SECT_TYPES; - -protected: - bool extractImpl(const DWARFDataExtractor &debug_info, - uint32_t *offset_ptr) override; }; } // end namespace llvm Index: llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -40,6 +40,51 @@ class DWARFDebugAbbrev; class DWARFUnit; +/// Base class describing the header of any kind of "unit." Some information +/// is specific to certain unit types. We separate this class out so we can +/// parse the header before deciding what specific kind of unit to construct. +class DWARFUnitHeader { +protected: + // Offset within section. + uint32_t Offset = 0; + // Version, address size, and DWARF format. + dwarf::FormParams FormParams; + uint32_t Length = 0; + uint64_t AbbrOffset = 0; + + // For DWO units only. + const DWARFUnitIndex::Entry *IndexEntry = nullptr; + + // For type units only. + uint64_t TypeHash = 0; + uint32_t TypeOffset = 0; + + // Unit type as parsed, or derived from the section kind. + uint8_t UnitType = 0; + +public: + /// Parse a unit header from \p debug_info starting at \p offset_ptr. + bool extract(DWARFContext &Context, const DWARFDataExtractor &debug_info, + uint32_t *offset_ptr, DWARFSectionKind Kind = DW_SECT_INFO, + const DWARFUnitIndex *Index = nullptr); + uint32_t getLength() const { return Length; } + const dwarf::FormParams &getFormParams() const { return FormParams; } + uint16_t getVersion() const { return FormParams.Version; } + dwarf::DwarfFormat getFormat() const { return FormParams.Format; } + uint8_t getAddressByteSize() const { return FormParams.AddrSize; } + uint8_t getRefAddrByteSize() const { return FormParams.getRefAddrByteSize(); } + uint8_t getDwarfOffsetByteSize() const { + return FormParams.getDwarfOffsetByteSize(); + } + uint8_t getUnitType() const { return UnitType; } + bool isTypeUnit() const { + return UnitType == dwarf::DW_UT_type || UnitType == dwarf::DW_UT_split_type; + } + uint32_t getOffset() const { return Offset; } + // FIXME: Support DWARF64. + uint32_t getNextUnitOffset() const { return Offset + Length + 4; } +}; + /// Base class for all DWARFUnitSection classes. This provides the /// functionality common to all unit types. class DWARFUnitSectionBase { @@ -133,11 +178,12 @@ &LS](uint32_t Offset) -> std::unique_ptr { if (!Data.isValidOffset(Offset)) return nullptr; - auto U = llvm::make_unique( - Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, *this, - Index ? Index->getFromOffset(Offset) : nullptr); - if (!U->extract(Data, &Offset)) + DWARFUnitHeader Header; + if (!Header.extract(Context, Data, &Offset, UnitType::Section, Index)) return nullptr; + auto U = llvm::make_unique( + Context, Section, Header, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, + *this); return U; }; } @@ -189,7 +235,7 @@ validateContributionSize(DWARFDataExtractor &DA); }; -class DWARFUnit { +class DWARFUnit : public DWARFUnitHeader { DWARFContext &Context; /// Section containing this DWARFUnit. const DWARFSection &InfoSection; @@ -206,17 +252,11 @@ bool isDWO; const DWARFUnitSectionBase &UnitSection; - // Version, address size, and DWARF format. - dwarf::FormParams FormParams; /// Start, length, and DWARF format of the unit's contribution to the string /// offsets table (DWARF v5). Optional StringOffsetsTableContribution; - uint32_t Offset; - uint32_t Length; mutable const DWARFAbbreviationDeclarationSet *Abbrevs; - uint64_t AbbrOffset; - uint8_t UnitType; llvm::Optional BaseAddr; /// The compile unit debug information entry items. std::vector DieArray; @@ -231,8 +271,6 @@ std::shared_ptr DWO; - const DWARFUnitIndex::Entry *IndexEntry; - uint32_t getDIEIndex(const DWARFDebugInfoEntry *Die) { auto First = DieArray.data(); assert(Die >= First && Die < First + DieArray.size()); @@ -240,9 +278,6 @@ } protected: - virtual bool extractImpl(const DWARFDataExtractor &debug_info, - uint32_t *offset_ptr); - /// Size in bytes of the unit header. virtual uint32_t getHeaderSize() const { return getVersion() <= 4 ? 11 : 12; } @@ -263,11 +298,11 @@ public: DWARFUnit(DWARFContext &Context, const DWARFSection &Section, + const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA, const DWARFSection *RS, StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, const DWARFSection &LS, bool LE, bool IsDWO, - const DWARFUnitSectionBase &UnitSection, - const DWARFUnitIndex::Entry *IndexEntry = nullptr); + const DWARFUnitSectionBase &UnitSection); virtual ~DWARFUnit(); @@ -301,30 +336,17 @@ return DataExtractor(StringSection, false, 0); } - bool extract(const DWARFDataExtractor &debug_info, uint32_t *offset_ptr); - /// extractRangeList - extracts the range list referenced by this compile /// unit from .debug_ranges section. Returns true on success. /// Requires that compile unit is already extracted. bool extractRangeList(uint32_t RangeListOffset, DWARFDebugRangeList &RangeList) const; void clear(); - uint32_t getOffset() const { return Offset; } - uint32_t getNextUnitOffset() const { return Offset + Length + 4; } - uint32_t getLength() const { return Length; } const Optional & getStringOffsetsTableContribution() const { return StringOffsetsTableContribution; } - const dwarf::FormParams &getFormParams() const { return FormParams; } - uint16_t getVersion() const { return FormParams.Version; } - dwarf::DwarfFormat getFormat() const { return FormParams.Format; } - uint8_t getAddressByteSize() const { return FormParams.AddrSize; } - uint8_t getRefAddrByteSize() const { return FormParams.getRefAddrByteSize(); } - uint8_t getDwarfOffsetByteSize() const { - return FormParams.getDwarfOffsetByteSize(); - } uint8_t getDwarfStringOffsetsByteSize() const { assert(StringOffsetsTableContribution); @@ -338,8 +360,6 @@ const DWARFAbbreviationDeclarationSet *getAbbreviations() const; - uint8_t getUnitType() const { return UnitType; } - static bool isMatchingUnitTypeAndTag(uint8_t UnitType, dwarf::Tag Tag) { switch (UnitType) { case dwarf::DW_UT_compile: Index: llvm/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp @@ -18,19 +18,6 @@ using namespace llvm; -bool DWARFTypeUnit::extractImpl(const DWARFDataExtractor &debug_info, - uint32_t *offset_ptr) { - if (!DWARFUnit::extractImpl(debug_info, offset_ptr)) - return false; - TypeHash = debug_info.getU64(offset_ptr); - TypeOffset = debug_info.getU32(offset_ptr); - // TypeOffset is relative to the beginning of the header, - // so we have to account for the leading length field. - // FIXME: The size of the length field is 12 in DWARF64. - unsigned SizeOfLength = 4; - return TypeOffset < getLength() + SizeOfLength; -} - void DWARFTypeUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) { DWARFDie TD = getDIEForOffset(TypeOffset + getOffset()); const char *Name = TD.getName(DINameKind::ShortName); Index: llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -48,15 +48,16 @@ } DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section, + const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA, const DWARFSection *RS, StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, const DWARFSection &LS, bool LE, - bool IsDWO, const DWARFUnitSectionBase &UnitSection, - const DWARFUnitIndex::Entry *IndexEntry) - : Context(DC), InfoSection(Section), Abbrev(DA), RangeSection(RS), + bool IsDWO, const DWARFUnitSectionBase &UnitSection) + : DWARFUnitHeader(Header), + Context(DC), InfoSection(Section), Abbrev(DA), RangeSection(RS), LineSection(LS), StringSection(SS), StringOffsetSection(SOS), AddrOffsetSection(AOS), isLittleEndian(LE), isDWO(IsDWO), - UnitSection(UnitSection), IndexEntry(IndexEntry) { + UnitSection(UnitSection) { clear(); } @@ -92,10 +93,16 @@ return true; } -bool DWARFUnit::extractImpl(const DWARFDataExtractor &debug_info, - uint32_t *offset_ptr) { +bool DWARFUnitHeader::extract(DWARFContext &Context, + const DWARFDataExtractor &debug_info, + uint32_t *offset_ptr, + DWARFSectionKind SectionKind, + const DWARFUnitIndex *Index) { + Offset = *offset_ptr; + IndexEntry = Index ? Index->getFromOffset(*offset_ptr) : nullptr; Length = debug_info.getU32(offset_ptr); // FIXME: Support DWARF64. + unsigned SizeOfLength = 4; FormParams.Format = DWARF32; FormParams.Version = debug_info.getU16(offset_ptr); if (FormParams.Version >= 5) { @@ -105,6 +112,13 @@ } else { AbbrOffset = debug_info.getRelocatedValue(4, offset_ptr); FormParams.AddrSize = debug_info.getU8(offset_ptr); + // Fake a unit type based on the section type. This isn't perfect, + // but to do better we'd need to look at the unit DIE. The crucial + // distinction is type unit or not, because the header differs. + if (SectionKind == DW_SECT_TYPES) + UnitType = DW_UT_type; + else + UnitType = DW_UT_compile; } if (IndexEntry) { if (AbbrOffset) @@ -117,12 +131,20 @@ return false; AbbrOffset = AbbrEntry->Offset; } - + bool TypeOffsetOK = true; + if (isTypeUnit()) { + TypeHash = debug_info.getU64(offset_ptr); + TypeOffset = debug_info.getU32(offset_ptr); + // Type offset is unit-relative; should be after the header and before + // the end of the current unit. + TypeOffsetOK = TypeOffset >= *offset_ptr - Offset && + TypeOffset < getLength() + SizeOfLength; + } bool LengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1); bool VersionOK = DWARFContext::isSupportedVersion(getVersion()); bool AddrSizeOK = getAddressByteSize() == 4 || getAddressByteSize() == 8; - if (!LengthOK || !VersionOK || !AddrSizeOK) + if (!LengthOK || !VersionOK || !AddrSizeOK || !TypeOffsetOK) return false; // Keep track of the highest DWARF version we encounter across all units. @@ -130,23 +152,6 @@ return true; } -bool DWARFUnit::extract(const DWARFDataExtractor &debug_info, - uint32_t *offset_ptr) { - clear(); - - Offset = *offset_ptr; - - if (debug_info.isValidOffset(*offset_ptr)) { - if (extractImpl(debug_info, offset_ptr)) - return true; - - // reset the offset to where we tried to parse from if anything went wrong - *offset_ptr = Offset; - } - - return false; -} - bool DWARFUnit::extractRangeList(uint32_t RangeListOffset, DWARFDebugRangeList &RangeList) const { // Require that compile unit is extracted. @@ -158,10 +163,7 @@ } void DWARFUnit::clear() { - Offset = 0; - Length = 0; Abbrevs = nullptr; - FormParams = dwarf::FormParams({0, 0, DWARF32}); BaseAddr.reset(); RangeSectionBase = 0; AddrOffsetSectionBase = 0; Index: llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -274,16 +274,17 @@ if (isUnitDWARF64) break; } else { + DWARFUnitHeader Header; + Header.extract(DCtx, DebugInfoData, &OffsetStart); std::unique_ptr Unit; switch (UnitType) { case dwarf::DW_UT_type: case dwarf::DW_UT_split_type: { Unit.reset(new DWARFTypeUnit( - DCtx, DObj.getInfoSection(), DCtx.getDebugAbbrev(), + DCtx, DObj.getInfoSection(), Header, DCtx.getDebugAbbrev(), &DObj.getRangeSection(), DObj.getStringSection(), DObj.getStringOffsetSection(), &DObj.getAppleObjCSection(), - DObj.getLineSection(), DCtx.isLittleEndian(), false, TUSection, - nullptr)); + DObj.getLineSection(), DCtx.isLittleEndian(), false, TUSection)); break; } case dwarf::DW_UT_skeleton: @@ -294,16 +295,14 @@ // verifying a compile unit in DWARF v4. case 0: { Unit.reset(new DWARFCompileUnit( - DCtx, DObj.getInfoSection(), DCtx.getDebugAbbrev(), + DCtx, DObj.getInfoSection(), Header, DCtx.getDebugAbbrev(), &DObj.getRangeSection(), DObj.getStringSection(), DObj.getStringOffsetSection(), &DObj.getAppleObjCSection(), - DObj.getLineSection(), DCtx.isLittleEndian(), false, CUSection, - nullptr)); + DObj.getLineSection(), DCtx.isLittleEndian(), false, CUSection)); break; } default: { llvm_unreachable("Invalid UnitType."); } } - Unit->extract(DebugInfoData, &OffsetStart); if (!verifyUnitContents(*Unit, UnitType)) ++NumDebugInfoErrors; }