summaryrefslogtreecommitdiff
path: root/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp')
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp105
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)