diff options
Diffstat (limited to 'llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp')
| -rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp | 105 |
1 files changed, 79 insertions, 26 deletions
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp index ac624ec8b80f..dcabefb9896e 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFVerifier.h" #include "llvm/ADT/SmallSet.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" @@ -50,6 +51,9 @@ DWARFVerifier::DieRangeInfo::insert(const DWARFAddressRange &R) { DWARFVerifier::DieRangeInfo::die_range_info_iterator DWARFVerifier::DieRangeInfo::insert(const DieRangeInfo &RI) { + if (RI.Ranges.empty()) + return Children.end(); + auto End = Children.end(); auto Iter = Children.begin(); while (Iter != End) { @@ -158,7 +162,30 @@ bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData, return Success; } -unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit) { +bool DWARFVerifier::verifyName(const DWARFDie &Die) { + // FIXME Add some kind of record of which DIE names have already failed and + // don't bother checking a DIE that uses an already failed DIE. + + std::string ReconstructedName; + raw_string_ostream OS(ReconstructedName); + std::string OriginalFullName; + Die.getFullName(OS, &OriginalFullName); + OS.flush(); + if (OriginalFullName.empty() || OriginalFullName == ReconstructedName) + return 0; + + error() << "Simplified template DW_AT_name could not be reconstituted:\n" + << formatv(" original: {0}\n" + " reconstituted: {1}\n", + OriginalFullName, ReconstructedName); + dump(Die) << '\n'; + dump(Die.getDwarfUnit()->getUnitDIE()) << '\n'; + return 1; +} + +unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit, + ReferenceMap &UnitLocalReferences, + ReferenceMap &CrossUnitReferences) { unsigned NumUnitErrors = 0; unsigned NumDies = Unit.getNumDIEs(); for (unsigned I = 0; I < NumDies; ++I) { @@ -169,9 +196,12 @@ unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit) { for (auto AttrValue : Die.attributes()) { NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue); - NumUnitErrors += verifyDebugInfoForm(Die, AttrValue); + NumUnitErrors += verifyDebugInfoForm(Die, AttrValue, UnitLocalReferences, + CrossUnitReferences); } + NumUnitErrors += verifyName(Die); + if (Die.hasChildren()) { if (Die.getFirstChild().isValid() && Die.getFirstChild().getTag() == DW_TAG_null) { @@ -299,6 +329,10 @@ unsigned DWARFVerifier::verifyUnitSection(const DWARFSection &S, bool hasDIE = DebugInfoData.isValidOffset(Offset); DWARFUnitVector TypeUnitVector; DWARFUnitVector CompileUnitVector; + /// A map that tracks all references (converted absolute references) so we + /// can verify each reference points to a valid DIE and not an offset that + /// lies between to valid DIEs. + ReferenceMap CrossUnitReferences; while (hasDIE) { OffsetStart = Offset; if (!verifyUnitHeader(DebugInfoData, &Offset, UnitIdx, UnitType, @@ -309,6 +343,7 @@ unsigned DWARFVerifier::verifyUnitSection(const DWARFSection &S, } else { DWARFUnitHeader Header; Header.extract(DCtx, DebugInfoData, &OffsetStart, SectionKind); + ReferenceMap UnitLocalReferences; DWARFUnit *Unit; switch (UnitType) { case dwarf::DW_UT_type: @@ -337,7 +372,10 @@ unsigned DWARFVerifier::verifyUnitSection(const DWARFSection &S, } default: { llvm_unreachable("Invalid UnitType."); } } - NumDebugInfoErrors += verifyUnitContents(*Unit); + NumDebugInfoErrors += + verifyUnitContents(*Unit, UnitLocalReferences, CrossUnitReferences); + NumDebugInfoErrors += verifyDebugInfoReferences( + UnitLocalReferences, [&](uint64_t Offset) { return Unit; }); } hasDIE = DebugInfoData.isValidOffset(Offset); ++UnitIdx; @@ -348,7 +386,14 @@ unsigned DWARFVerifier::verifyUnitSection(const DWARFSection &S, } if (!isHeaderChainValid) ++NumDebugInfoErrors; - NumDebugInfoErrors += verifyDebugInfoReferences(); + NumDebugInfoErrors += verifyDebugInfoReferences( + CrossUnitReferences, [&](uint64_t Offset) -> DWARFUnit * { + if (DWARFUnit *U = TypeUnitVector.getUnitForOffset(Offset)) + return U; + if (DWARFUnit *U = CompileUnitVector.getUnitForOffset(Offset)) + return U; + return nullptr; + }); return NumDebugInfoErrors; } @@ -383,7 +428,7 @@ unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die, return NumErrors; } - DWARFAddressRangesVector Ranges = RangesOrError.get(); + const DWARFAddressRangesVector &Ranges = RangesOrError.get(); // Build RI for this DIE and check that ranges within this DIE do not // overlap. DieRangeInfo RI(Die); @@ -409,7 +454,7 @@ unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die, if (!IsObjectFile || IsMachOObject || Die.getTag() != DW_TAG_compile_unit) { bool DumpDieAfterError = false; - for (auto Range : Ranges) { + for (const auto &Range : Ranges) { if (!Range.valid()) { ++NumErrors; error() << "Invalid address range " << Range << "\n"; @@ -444,7 +489,7 @@ unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die, } // Verify that ranges are contained within their parent. - bool ShouldBeContained = !Ranges.empty() && !ParentRI.Ranges.empty() && + bool ShouldBeContained = !RI.Ranges.empty() && !ParentRI.Ranges.empty() && !(Die.getTag() == DW_TAG_subprogram && ParentRI.Die.getTag() == DW_TAG_subprogram); if (ShouldBeContained && !ParentRI.contains(RI)) { @@ -507,9 +552,10 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(), 0); DWARFExpression Expression(Data, U->getAddressByteSize(), U->getFormParams().Format); - bool Error = any_of(Expression, [](DWARFExpression::Operation &Op) { - return Op.isError(); - }); + bool Error = + any_of(Expression, [](const DWARFExpression::Operation &Op) { + return Op.isError(); + }); if (Error || !Expression.verify(U)) ReportError("DIE contains invalid DWARF expression:"); } @@ -587,7 +633,9 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, } unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, - DWARFAttribute &AttrValue) { + DWARFAttribute &AttrValue, + ReferenceMap &LocalReferences, + ReferenceMap &CrossUnitReferences) { const DWARFObject &DObj = DCtx.getDWARFObj(); auto DieCU = Die.getDwarfUnit(); unsigned NumErrors = 0; @@ -615,7 +663,7 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, } else { // Valid reference, but we will verify it points to an actual // DIE later. - ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset()); + LocalReferences[*RefVal].insert(Die.getOffset()); } } break; @@ -634,7 +682,7 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, } else { // Valid reference, but we will verify it points to an actual // DIE later. - ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset()); + CrossUnitReferences[*RefVal].insert(Die.getOffset()); } } break; @@ -694,20 +742,24 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, return NumErrors; } -unsigned DWARFVerifier::verifyDebugInfoReferences() { - // Take all references and make sure they point to an actual DIE by - // getting the DIE by offset and emitting an error - OS << "Verifying .debug_info references...\n"; +unsigned DWARFVerifier::verifyDebugInfoReferences( + const ReferenceMap &References, + llvm::function_ref<DWARFUnit *(uint64_t)> GetUnitForOffset) { + auto GetDIEForOffset = [&](uint64_t Offset) { + if (DWARFUnit *U = GetUnitForOffset(Offset)) + return U->getDIEForOffset(Offset); + return DWARFDie(); + }; unsigned NumErrors = 0; for (const std::pair<const uint64_t, std::set<uint64_t>> &Pair : - ReferenceToDIEOffsets) { - if (DCtx.getDIEForOffset(Pair.first)) + References) { + if (GetDIEForOffset(Pair.first)) continue; ++NumErrors; error() << "invalid DIE reference " << format("0x%08" PRIx64, Pair.first) << ". Offset is in between DIEs:\n"; for (auto Offset : Pair.second) - dump(DCtx.getDIEForOffset(Offset)) << '\n'; + dump(GetDIEForOffset(Offset)) << '\n'; OS << "\n"; } return NumErrors; @@ -1349,11 +1401,12 @@ static bool isVariableIndexable(const DWARFDie &Die, DWARFContext &DCtx) { U->getAddressByteSize()); DWARFExpression Expression(Data, U->getAddressByteSize(), U->getFormParams().Format); - bool IsInteresting = any_of(Expression, [](DWARFExpression::Operation &Op) { - return !Op.isError() && (Op.getCode() == DW_OP_addr || - Op.getCode() == DW_OP_form_tls_address || - Op.getCode() == DW_OP_GNU_push_tls_address); - }); + bool IsInteresting = + any_of(Expression, [](const DWARFExpression::Operation &Op) { + return !Op.isError() && (Op.getCode() == DW_OP_addr || + Op.getCode() == DW_OP_form_tls_address || + Op.getCode() == DW_OP_GNU_push_tls_address); + }); if (IsInteresting) return true; } @@ -1488,7 +1541,7 @@ unsigned DWARFVerifier::verifyDebugNames(const DWARFSection &AccelSection, if (NumErrors > 0) return NumErrors; for (const auto &NI : AccelTable) - for (DWARFDebugNames::NameTableEntry NTE : NI) + for (const DWARFDebugNames::NameTableEntry &NTE : NI) NumErrors += verifyNameIndexEntries(NI, NTE); if (NumErrors > 0) |
