Index: include/llvm/DebugInfo/DWARF/DWARFUnit.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -238,6 +238,35 @@ uint8_t getUnitType() const { return UnitType; } + static bool validateUnitType(uint8_t UnitType) { + return UnitType == dwarf::DW_UT_compile || UnitType == dwarf::DW_UT_type || + UnitType == dwarf::DW_UT_partial || + UnitType == dwarf::DW_UT_skeleton || + UnitType == dwarf::DW_UT_split_compile || + UnitType == dwarf::DW_UT_split_type; + } + + static uint32_t computeDWARF5HeaderSize(uint8_t UnitType) { + uint32_t HeaderSize = 12; + switch (UnitType) { + case dwarf::DW_UT_compile: + case dwarf::DW_UT_partial: + break; + case dwarf::DW_UT_skeleton: + case dwarf::DW_UT_split_compile: + HeaderSize = 20; + break; + case dwarf::DW_UT_type: + case dwarf::DW_UT_split_type: + HeaderSize = 24; + break; + + default: + break; + } + return HeaderSize; + } + uint64_t getBaseAddress() const { return BaseAddr; } void setBaseAddress(uint64_t base_addr) { Index: include/llvm/DebugInfo/DWARF/DWARFVerifier.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFVerifier.h +++ include/llvm/DebugInfo/DWARF/DWARFVerifier.h @@ -30,6 +30,7 @@ /// can verify each reference points to a valid DIE and not an offset that /// lies between to valid DIEs. std::map> ReferenceToDIEOffsets; + uint32_t NumDebugInfoUnitHeaderChainErrors = 0; uint32_t NumDebugInfoErrors = 0; uint32_t NumDebugLineErrors = 0; uint32_t NumAppleNamesErrors = 0; @@ -78,6 +79,14 @@ public: DWARFVerifier(raw_ostream &S, DWARFContext &D) : OS(S), DCtx(D) {} + /// Verify the unit header chain in the .debug_info section. + /// + /// Any errors are reported to the stream that this object was + /// constructed with. + /// + /// \returns true if the unit header chain verifies successfully, false + /// otherwise. + bool handleDebugInfoUnitHeaderChain(); /// Verify the information in the .debug_info section. /// /// Any errors are reported to the stream that was this object was Index: lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFContext.cpp +++ lib/DebugInfo/DWARF/DWARFContext.cpp @@ -414,9 +414,15 @@ bool DWARFContext::verify(raw_ostream &OS, DIDumpType DumpType) { bool Success = true; DWARFVerifier verifier(OS, *this); - if (DumpType == DIDT_All || DumpType == DIDT_Info) { - if (!verifier.handleDebugInfo()) - Success = false; + if (verifier.handleDebugInfoUnitHeaderChain()) { + if (DumpType == DIDT_All || DumpType == DIDT_Info) { + if (!verifier.handleDebugInfo()) + Success = false; + } + } else { + OS << "Verification of .debug_info unit header chain failed; no need to " + "verify .debug_info contents\n"; + Success = false; } if (DumpType == DIDT_All || DumpType == DIDT_Line) { if (!verifier.handleDebugLine()) Index: lib/DebugInfo/DWARF/DWARFVerifier.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -24,6 +24,78 @@ using namespace dwarf; using namespace object; +bool DWARFVerifier::handleDebugInfoUnitHeaderChain() { + OS << "Verifying .debug_info Unit Header Chain...\n"; + + DWARFDataExtractor DebugInfoData(DCtx.getInfoSection(), DCtx.isLittleEndian(), + 0); + + uint32_t AbbrOffset, OffsetStart, Length; + uint8_t AddrSize = 0, UnitType = 0; + bool ValidOffset = false, ValidLength = false, ValidVersion = false, + ValidAddrSize = false; + bool ValidType = true, ValidAbbrevOffset = true; + + uint32_t Offset = 4; + uint16_t Version = DebugInfoData.getU16(&Offset); + uint32_t HeaderSize = 11; + if (Version >= 5) { + UnitType = DebugInfoData.getU8(&Offset); + HeaderSize = DWARFUnit::computeDWARF5HeaderSize(UnitType); + } + + Offset = 0; + while (DebugInfoData.isValidOffset(Offset + HeaderSize)) { + OffsetStart = Offset; + ValidOffset = DebugInfoData.isValidOffset(Offset); + Length = DebugInfoData.getU32(&Offset); + Version = DebugInfoData.getU16(&Offset); + + if (Version >= 5) { + UnitType = DebugInfoData.getU8(&Offset); + AddrSize = DebugInfoData.getU8(&Offset); + AbbrOffset = DebugInfoData.getU32(&Offset); + ValidType = DWARFUnit::validateUnitType(UnitType); + HeaderSize = DWARFUnit::computeDWARF5HeaderSize(UnitType); + } else { + AbbrOffset = DebugInfoData.getU32(&Offset); + AddrSize = DebugInfoData.getU8(&Offset); + HeaderSize = 11; // means that we have only compile units in .debug_info + } + if (!DCtx.getDebugAbbrev()->getAbbreviationDeclarationSet(AbbrOffset)) + ValidAbbrevOffset = false; + + ValidLength = DebugInfoData.isValidOffset(OffsetStart + Length + 3); + ValidVersion = DWARFContext::isSupportedVersion(Version); + ValidAddrSize = AddrSize == 4 || AddrSize == 8; + + if (!ValidOffset || !ValidLength || !ValidVersion || !ValidAddrSize || + !ValidAbbrevOffset || !ValidType) { + ++NumDebugInfoUnitHeaderChainErrors; + OS << format("Unit Start Offset: 0x%08x \n", OffsetStart); + if (ValidOffset) { + if (!ValidLength) + OS << format("The length 0x%08x for this unit is too " + "large for the .debug_info provided.\n", + Length); + if (!ValidVersion) + OS << "The 16 bit unit header version is not valid.\n"; + if (!ValidType) + OS << "The unit type encoding is not valid.\n"; + if (!ValidAbbrevOffset) + OS << "The offset into the .debug_abbrev section is " + "not valid.\n"; + if (!ValidAddrSize) + OS << format("The address size is unsupported: 0x%08x\n", AddrSize); + } else + OS << "The start offset of the unit header in the " + ".debug_info is invalid.\n"; + } + Offset = OffsetStart + Length + 4; + } + return NumDebugInfoUnitHeaderChainErrors == 0; +} + void DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, DWARFAttribute &AttrValue) { const auto Attr = AttrValue.Attr;