[dsymutil] Verify the keep chain when asserts are enabled
Verify that every DIE that's marked as kept, has a parent that's kept as well. This invariant should always hold and is easy to verify when asserts are enabled. Differential revision: https://reviews.llvm.org/D140227
This commit is contained in:
@@ -81,6 +81,10 @@ public:
|
||||
|
||||
/// Is this a reference to a DIE that hasn't been cloned yet?
|
||||
bool UnclonedReference : 1;
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
LLVM_DUMP_METHOD void dump();
|
||||
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
};
|
||||
|
||||
CompileUnit(DWARFUnit &OrigUnit, unsigned ID, bool CanUseODR,
|
||||
|
||||
@@ -850,6 +850,58 @@ void DWARFLinker::lookForDIEsToKeep(AddressesMap &AddressesMap,
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
/// A broken link in the keep chain. By recording both the parent and the child
|
||||
/// we can show only broken links for DIEs with multiple children.
|
||||
struct BrokenLink {
|
||||
BrokenLink(DWARFDie Parent, DWARFDie Child) : Parent(Parent), Child(Child) {}
|
||||
DWARFDie Parent;
|
||||
DWARFDie Child;
|
||||
};
|
||||
|
||||
/// Verify the keep chain by looking for DIEs that are kept but who's parent
|
||||
/// isn't.
|
||||
static void verifyKeepChain(CompileUnit &CU) {
|
||||
std::vector<DWARFDie> Worklist;
|
||||
Worklist.push_back(CU.getOrigUnit().getUnitDIE());
|
||||
|
||||
// List of broken links.
|
||||
std::vector<BrokenLink> BrokenLinks;
|
||||
|
||||
while (!Worklist.empty()) {
|
||||
const DWARFDie Current = Worklist.back();
|
||||
Worklist.pop_back();
|
||||
|
||||
const bool CurrentDieIsKept = CU.getInfo(Current).Keep;
|
||||
|
||||
for (DWARFDie Child : reverse(Current.children())) {
|
||||
Worklist.push_back(Child);
|
||||
|
||||
const bool ChildDieIsKept = CU.getInfo(Child).Keep;
|
||||
if (!CurrentDieIsKept && ChildDieIsKept)
|
||||
BrokenLinks.emplace_back(Current, Child);
|
||||
}
|
||||
}
|
||||
|
||||
if (!BrokenLinks.empty()) {
|
||||
for (BrokenLink Link : BrokenLinks) {
|
||||
WithColor::error() << formatv(
|
||||
"Found invalid link in keep chain between {0:x} and {1:x}\n",
|
||||
Link.Parent.getOffset(), Link.Child.getOffset());
|
||||
|
||||
errs() << "Parent:";
|
||||
Link.Parent.dump(errs(), 0, {});
|
||||
CU.getInfo(Link.Parent).dump();
|
||||
|
||||
errs() << "Child:";
|
||||
Link.Child.dump(errs(), 2, {});
|
||||
CU.getInfo(Link.Child).dump();
|
||||
}
|
||||
report_fatal_error("invalid keep chain");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Assign an abbreviation number to \p Abbrev.
|
||||
///
|
||||
/// Our DIEs get freed after every DebugMapObject has been processed,
|
||||
@@ -2535,12 +2587,16 @@ Error DWARFLinker::link() {
|
||||
CurrentUnit->markEverythingAsKept();
|
||||
copyInvariantDebugSection(*OptContext.File.Dwarf);
|
||||
} else {
|
||||
for (auto &CurrentUnit : OptContext.CompileUnits)
|
||||
for (auto &CurrentUnit : OptContext.CompileUnits) {
|
||||
lookForDIEsToKeep(*OptContext.File.Addresses,
|
||||
OptContext.File.Addresses->getValidAddressRanges(),
|
||||
OptContext.CompileUnits,
|
||||
CurrentUnit->getOrigUnit().getUnitDIE(),
|
||||
OptContext.File, *CurrentUnit, 0);
|
||||
#ifndef NDEBUG
|
||||
verifyKeepChain(*CurrentUnit);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// The calls to applyValidRelocs inside cloneDIE will walk the reloc
|
||||
|
||||
@@ -8,9 +8,28 @@
|
||||
|
||||
#include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h"
|
||||
#include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
LLVM_DUMP_METHOD void CompileUnit::DIEInfo::dump() {
|
||||
llvm::errs() << "{\n";
|
||||
llvm::errs() << " AddrAdjust: " << AddrAdjust << '\n';
|
||||
llvm::errs() << " Ctxt: " << formatv("{0:x}", Ctxt) << '\n';
|
||||
llvm::errs() << " Clone: " << formatv("{0:x}", Clone) << '\n';
|
||||
llvm::errs() << " ParentIdx: " << ParentIdx << '\n';
|
||||
llvm::errs() << " Keep: " << Keep << '\n';
|
||||
llvm::errs() << " InDebugMap: " << InDebugMap << '\n';
|
||||
llvm::errs() << " Prune: " << Prune << '\n';
|
||||
llvm::errs() << " Incomplete: " << Incomplete << '\n';
|
||||
llvm::errs() << " InModuleScope: " << InModuleScope << '\n';
|
||||
llvm::errs() << " ODRMarkingDone: " << ODRMarkingDone << '\n';
|
||||
llvm::errs() << " UnclonedReference: " << UnclonedReference << '\n';
|
||||
llvm::errs() << "}\n";
|
||||
}
|
||||
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
|
||||
/// Check if the DIE at \p Idx is in the scope of a function.
|
||||
static bool inFunctionScope(CompileUnit &U, unsigned Idx) {
|
||||
while (Idx) {
|
||||
|
||||
Reference in New Issue
Block a user