Index: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h +++ llvm/trunk/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/trunk/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h +++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h @@ -24,30 +24,24 @@ 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; } + uint64_t getTypeHash() const { return getHeader().getTypeHash(); } + uint32_t getTypeOffset() const { return getHeader().getTypeOffset(); } 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/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -40,6 +40,54 @@ 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 { + // 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 getOffset() const { return Offset; } + 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(); + } + uint32_t getLength() const { return Length; } + uint64_t getAbbrOffset() const { return AbbrOffset; } + const DWARFUnitIndex::Entry *getIndexEntry() const { return IndexEntry; } + uint64_t getTypeHash() const { return TypeHash; } + uint32_t getTypeOffset() const { return TypeOffset; } + uint8_t getUnitType() const { return UnitType; } + bool isTypeUnit() const { + return UnitType == dwarf::DW_UT_type || UnitType == dwarf::DW_UT_split_type; + } + // 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 +181,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; }; } @@ -195,6 +244,7 @@ /// Section containing this DWARFUnit. const DWARFSection &InfoSection; + DWARFUnitHeader Header; const DWARFDebugAbbrev *Abbrev; const DWARFSection *RangeSection; uint32_t RangeSectionBase; @@ -207,17 +257,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; @@ -232,8 +276,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()); @@ -241,8 +283,7 @@ } protected: - virtual bool extractImpl(const DWARFDataExtractor &debug_info, - uint32_t *offset_ptr); + const DWARFUnitHeader &getHeader() const { return Header; } /// Size in bytes of the unit header. virtual uint32_t getHeaderSize() const { return getVersion() <= 4 ? 11 : 12; } @@ -264,16 +305,28 @@ 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(); DWARFContext& getContext() const { return Context; } - + uint32_t getOffset() const { return Header.getOffset(); } + const dwarf::FormParams &getFormParams() const { + return Header.getFormParams(); + } + uint16_t getVersion() const { return Header.getVersion(); } + uint8_t getAddressByteSize() const { return Header.getAddressByteSize(); } + uint8_t getRefAddrByteSize() const { return Header.getRefAddrByteSize(); } + uint8_t getDwarfOffsetByteSize() const { + return Header.getDwarfOffsetByteSize(); + } + uint32_t getLength() const { return Header.getLength(); } + uint8_t getUnitType() const { return Header.getUnitType(); } + uint32_t getNextUnitOffset() const { return Header.getNextUnitOffset(); } const DWARFSection &getLineSection() const { return LineSection; } StringRef getStringSection() const { return StringSection; } const DWARFSection &getStringOffsetSection() const { @@ -302,30 +355,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); @@ -339,8 +379,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: @@ -453,7 +491,7 @@ } uint32_t getLineTableOffset() const { - if (IndexEntry) + if (auto IndexEntry = Header.getIndexEntry()) if (const auto *Contrib = IndexEntry->getOffset(DW_SECT_LINE)) return Contrib->Offset; return 0; @@ -466,7 +504,9 @@ private: /// Size in bytes of the .debug_info data associated with this compile unit. - size_t getDebugInfoSize() const { return Length + 4 - getHeaderSize(); } + size_t getDebugInfoSize() const { + return Header.getLength() + 4 - getHeaderSize(); + } /// extractDIEsIfNeeded - Parses a compile unit and indexes its DIEs if it /// hasn't already been done. Returns the number of DIEs parsed at this call. Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp @@ -18,26 +18,13 @@ 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()); + DWARFDie TD = getDIEForOffset(getTypeOffset() + getOffset()); const char *Name = TD.getName(DINameKind::ShortName); if (DumpOpts.SummarizeTypes) { OS << "name = '" << Name << "'" - << " type_signature = " << format("0x%016" PRIx64, TypeHash) + << " type_signature = " << format("0x%016" PRIx64, getTypeHash()) << " length = " << format("0x%08x", getLength()) << '\n'; return; } @@ -50,8 +37,8 @@ OS << " abbr_offset = " << format("0x%04x", getAbbreviations()->getOffset()) << " addr_size = " << format("0x%02x", getAddressByteSize()) << " name = '" << Name << "'" - << " type_signature = " << format("0x%016" PRIx64, TypeHash) - << " type_offset = " << format("0x%04x", TypeOffset) + << " type_signature = " << format("0x%016" PRIx64, getTypeHash()) + << " type_offset = " << format("0x%04x", getTypeOffset()) << " (next unit at " << format("0x%08x", getNextUnitOffset()) << ")\n"; if (DWARFDie TU = getUnitDIE(false)) Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -48,15 +48,15 @@ } 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), - LineSection(LS), StringSection(SS), StringOffsetSection(SOS), - AddrOffsetSection(AOS), isLittleEndian(LE), isDWO(IsDWO), - UnitSection(UnitSection), IndexEntry(IndexEntry) { + bool IsDWO, const DWARFUnitSectionBase &UnitSection) + : Context(DC), InfoSection(Section), Header(Header), Abbrev(DA), + RangeSection(RS), LineSection(LS), StringSection(SS), + StringOffsetSection(SOS), AddrOffsetSection(AOS), isLittleEndian(LE), + isDWO(IsDWO), UnitSection(UnitSection) { clear(); } @@ -92,10 +92,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 +111,12 @@ } 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 distinguishing compile and type units is generally enough. + if (SectionKind == DW_SECT_TYPES) + UnitType = DW_UT_type; + else + UnitType = DW_UT_compile; } if (IndexEntry) { if (AbbrOffset) @@ -117,12 +129,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 +150,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 +161,7 @@ } void DWARFUnit::clear() { - Offset = 0; - Length = 0; Abbrevs = nullptr; - FormParams = dwarf::FormParams({0, 0, DWARF32}); BaseAddr.reset(); RangeSectionBase = 0; AddrOffsetSectionBase = 0; @@ -185,7 +185,7 @@ // Set the offset to that of the first DIE and calculate the start of the // next compilation unit header. - uint32_t DIEOffset = Offset + getHeaderSize(); + uint32_t DIEOffset = getOffset() + getHeaderSize(); uint32_t NextCUOffset = getNextUnitOffset(); DWARFDebugInfoEntry DIE; DWARFDataExtractor DebugInfoData = getDebugInfoExtractor(); @@ -266,6 +266,7 @@ // which may differ from the unit's format. uint64_t StringOffsetsContributionBase = isDWO ? 0 : toSectionOffset(UnitDie.find(DW_AT_str_offsets_base), 0); + auto IndexEntry = Header.getIndexEntry(); if (IndexEntry) if (const auto *C = IndexEntry->getOffset(DW_SECT_STR_OFFSETS)) StringOffsetsContributionBase += C->Offset; @@ -486,7 +487,7 @@ const DWARFAbbreviationDeclarationSet *DWARFUnit::getAbbreviations() const { if (!Abbrevs) - Abbrevs = Abbrev->getAbbreviationDeclarationSet(AbbrOffset); + Abbrevs = Abbrev->getAbbreviationDeclarationSet(Header.getAbbrOffset()); return Abbrevs; } @@ -570,6 +571,7 @@ // index table (in a package file). In a .dwo file it is simply // the length of the string offsets section. uint64_t Size = 0; + auto IndexEntry = Header.getIndexEntry(); if (!IndexEntry) Size = StringOffsetSection.Data.size(); else if (const auto *C = IndexEntry->getOffset(DW_SECT_STR_OFFSETS)) Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFVerifier.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ llvm/trunk/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; }