forked from OSchip/llvm-project
Refactor the Verifier so it can diagnose IR validation errors and debug
info metadata errors separately. (NFC) This patch refactors the Verifier so it can diagnose IR validation errors and debug info metadata errors separately. The motivation behind this change is that broken (or outdated) debug info can be "recovered" from by stripping the debug info. The problem I'm trying to solve with this sequence of patches is that historically we've done a really bad job at verifying debug info. We want to be able to make the verifier stricter without having to worry about breaking bitcode compatibility with existing producers. For example, we don't necessarily want IR produced by an older version of clang to be rejected by an LTO link just because of malformed debug info, and rather provide an option to strip it. Note that merely outdated (but well-formed) debug info would continue to be auto-upgraded in this scenario. http://reviews.llvm.org/D19986 rdar://problem/25818489 llvm-svn: 268778
This commit is contained in:
parent
de87e5f875
commit
541a9c58d4
|
@ -89,6 +89,10 @@ struct VerifierSupport {
|
|||
|
||||
/// Track the brokenness of the module while recursively visiting.
|
||||
bool Broken = false;
|
||||
/// Broken debug info can be "recovered" from by stripping the debug info.
|
||||
bool BrokenDebugInfo = false;
|
||||
/// Whether to treat broken debug info as an error.
|
||||
bool TreatBrokenDebugInfoAsError = true;
|
||||
|
||||
explicit VerifierSupport(raw_ostream *OS) : OS(OS) {}
|
||||
|
||||
|
@ -182,6 +186,23 @@ public:
|
|||
if (OS)
|
||||
WriteTs(V1, Vs...);
|
||||
}
|
||||
|
||||
/// A debug info check failed.
|
||||
void DebugInfoCheckFailed(const Twine &Message) {
|
||||
if (OS)
|
||||
*OS << Message << '\n';
|
||||
Broken |= TreatBrokenDebugInfoAsError;
|
||||
BrokenDebugInfo = true;
|
||||
}
|
||||
|
||||
/// A debug info check failed (with values to print).
|
||||
template <typename T1, typename... Ts>
|
||||
void DebugInfoCheckFailed(const Twine &Message, const T1 &V1,
|
||||
const Ts &... Vs) {
|
||||
DebugInfoCheckFailed(Message);
|
||||
if (OS)
|
||||
WriteTs(V1, Vs...);
|
||||
}
|
||||
};
|
||||
|
||||
class Verifier : public InstVisitor<Verifier>, VerifierSupport {
|
||||
|
@ -238,9 +259,13 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
|
|||
}
|
||||
|
||||
public:
|
||||
explicit Verifier(raw_ostream *OS)
|
||||
explicit Verifier(raw_ostream *OS, bool ShouldTreatBrokenDebugInfoAsError)
|
||||
: VerifierSupport(OS), Context(nullptr), LandingPadResultTy(nullptr),
|
||||
SawFrameEscape(false) {}
|
||||
SawFrameEscape(false) {
|
||||
TreatBrokenDebugInfoAsError = ShouldTreatBrokenDebugInfoAsError;
|
||||
}
|
||||
|
||||
bool hasBrokenDebugInfo() const { return BrokenDebugInfo; }
|
||||
|
||||
bool verify(const Function &F) {
|
||||
updateModule(F.getParent());
|
||||
|
@ -447,10 +472,16 @@ private:
|
|||
};
|
||||
} // End anonymous namespace
|
||||
|
||||
// Assert - We know that cond should be true, if not print an error message.
|
||||
/// We know that cond should be true, if not print an error message.
|
||||
#define Assert(C, ...) \
|
||||
do { if (!(C)) { CheckFailed(__VA_ARGS__); return; } } while (0)
|
||||
|
||||
/// We know that a debug info condition should be true, if not print
|
||||
/// an error message.
|
||||
#define AssertDI(C, ...) \
|
||||
do { if (!(C)) { DebugInfoCheckFailed(__VA_ARGS__); return; } } while (0)
|
||||
|
||||
|
||||
void Verifier::visit(Instruction &I) {
|
||||
for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i)
|
||||
Assert(I.getOperand(i) != nullptr, "Operand is null", &I);
|
||||
|
@ -652,7 +683,7 @@ void Verifier::visitGlobalAlias(const GlobalAlias &GA) {
|
|||
void Verifier::visitNamedMDNode(const NamedMDNode &NMD) {
|
||||
for (const MDNode *MD : NMD.operands()) {
|
||||
if (NMD.getName() == "llvm.dbg.cu") {
|
||||
Assert(MD && isa<DICompileUnit>(MD), "invalid compile unit", &NMD, MD);
|
||||
AssertDI(MD && isa<DICompileUnit>(MD), "invalid compile unit", &NMD, MD);
|
||||
}
|
||||
|
||||
if (!MD)
|
||||
|
@ -771,60 +802,60 @@ bool isValidMetadataNullArray(const MDTuple &N) {
|
|||
}
|
||||
|
||||
void Verifier::visitDILocation(const DILocation &N) {
|
||||
Assert(N.getRawScope() && isa<DILocalScope>(N.getRawScope()),
|
||||
"location requires a valid scope", &N, N.getRawScope());
|
||||
AssertDI(N.getRawScope() && isa<DILocalScope>(N.getRawScope()),
|
||||
"location requires a valid scope", &N, N.getRawScope());
|
||||
if (auto *IA = N.getRawInlinedAt())
|
||||
Assert(isa<DILocation>(IA), "inlined-at should be a location", &N, IA);
|
||||
AssertDI(isa<DILocation>(IA), "inlined-at should be a location", &N, IA);
|
||||
}
|
||||
|
||||
void Verifier::visitGenericDINode(const GenericDINode &N) {
|
||||
Assert(N.getTag(), "invalid tag", &N);
|
||||
AssertDI(N.getTag(), "invalid tag", &N);
|
||||
}
|
||||
|
||||
void Verifier::visitDIScope(const DIScope &N) {
|
||||
if (auto *F = N.getRawFile())
|
||||
Assert(isa<DIFile>(F), "invalid file", &N, F);
|
||||
AssertDI(isa<DIFile>(F), "invalid file", &N, F);
|
||||
}
|
||||
|
||||
void Verifier::visitDISubrange(const DISubrange &N) {
|
||||
Assert(N.getTag() == dwarf::DW_TAG_subrange_type, "invalid tag", &N);
|
||||
Assert(N.getCount() >= -1, "invalid subrange count", &N);
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_subrange_type, "invalid tag", &N);
|
||||
AssertDI(N.getCount() >= -1, "invalid subrange count", &N);
|
||||
}
|
||||
|
||||
void Verifier::visitDIEnumerator(const DIEnumerator &N) {
|
||||
Assert(N.getTag() == dwarf::DW_TAG_enumerator, "invalid tag", &N);
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_enumerator, "invalid tag", &N);
|
||||
}
|
||||
|
||||
void Verifier::visitDIBasicType(const DIBasicType &N) {
|
||||
Assert(N.getTag() == dwarf::DW_TAG_base_type ||
|
||||
N.getTag() == dwarf::DW_TAG_unspecified_type,
|
||||
"invalid tag", &N);
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_base_type ||
|
||||
N.getTag() == dwarf::DW_TAG_unspecified_type,
|
||||
"invalid tag", &N);
|
||||
}
|
||||
|
||||
void Verifier::visitDIDerivedType(const DIDerivedType &N) {
|
||||
// Common scope checks.
|
||||
visitDIScope(N);
|
||||
|
||||
Assert(N.getTag() == dwarf::DW_TAG_typedef ||
|
||||
N.getTag() == dwarf::DW_TAG_pointer_type ||
|
||||
N.getTag() == dwarf::DW_TAG_ptr_to_member_type ||
|
||||
N.getTag() == dwarf::DW_TAG_reference_type ||
|
||||
N.getTag() == dwarf::DW_TAG_rvalue_reference_type ||
|
||||
N.getTag() == dwarf::DW_TAG_const_type ||
|
||||
N.getTag() == dwarf::DW_TAG_volatile_type ||
|
||||
N.getTag() == dwarf::DW_TAG_restrict_type ||
|
||||
N.getTag() == dwarf::DW_TAG_member ||
|
||||
N.getTag() == dwarf::DW_TAG_inheritance ||
|
||||
N.getTag() == dwarf::DW_TAG_friend,
|
||||
"invalid tag", &N);
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_typedef ||
|
||||
N.getTag() == dwarf::DW_TAG_pointer_type ||
|
||||
N.getTag() == dwarf::DW_TAG_ptr_to_member_type ||
|
||||
N.getTag() == dwarf::DW_TAG_reference_type ||
|
||||
N.getTag() == dwarf::DW_TAG_rvalue_reference_type ||
|
||||
N.getTag() == dwarf::DW_TAG_const_type ||
|
||||
N.getTag() == dwarf::DW_TAG_volatile_type ||
|
||||
N.getTag() == dwarf::DW_TAG_restrict_type ||
|
||||
N.getTag() == dwarf::DW_TAG_member ||
|
||||
N.getTag() == dwarf::DW_TAG_inheritance ||
|
||||
N.getTag() == dwarf::DW_TAG_friend,
|
||||
"invalid tag", &N);
|
||||
if (N.getTag() == dwarf::DW_TAG_ptr_to_member_type) {
|
||||
Assert(isType(N.getRawExtraData()), "invalid pointer to member type", &N,
|
||||
N.getRawExtraData());
|
||||
AssertDI(isType(N.getRawExtraData()), "invalid pointer to member type", &N,
|
||||
N.getRawExtraData());
|
||||
}
|
||||
|
||||
Assert(isScope(N.getRawScope()), "invalid scope", &N, N.getRawScope());
|
||||
Assert(isType(N.getRawBaseType()), "invalid base type", &N,
|
||||
N.getRawBaseType());
|
||||
AssertDI(isScope(N.getRawScope()), "invalid scope", &N, N.getRawScope());
|
||||
AssertDI(isType(N.getRawBaseType()), "invalid base type", &N,
|
||||
N.getRawBaseType());
|
||||
}
|
||||
|
||||
static bool hasConflictingReferenceFlags(unsigned Flags) {
|
||||
|
@ -834,10 +865,10 @@ static bool hasConflictingReferenceFlags(unsigned Flags) {
|
|||
|
||||
void Verifier::visitTemplateParams(const MDNode &N, const Metadata &RawParams) {
|
||||
auto *Params = dyn_cast<MDTuple>(&RawParams);
|
||||
Assert(Params, "invalid template params", &N, &RawParams);
|
||||
AssertDI(Params, "invalid template params", &N, &RawParams);
|
||||
for (Metadata *Op : Params->operands()) {
|
||||
Assert(Op && isa<DITemplateParameter>(Op), "invalid template parameter", &N,
|
||||
Params, Op);
|
||||
AssertDI(Op && isa<DITemplateParameter>(Op), "invalid template parameter",
|
||||
&N, Params, Op);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -845,151 +876,151 @@ void Verifier::visitDICompositeType(const DICompositeType &N) {
|
|||
// Common scope checks.
|
||||
visitDIScope(N);
|
||||
|
||||
Assert(N.getTag() == dwarf::DW_TAG_array_type ||
|
||||
N.getTag() == dwarf::DW_TAG_structure_type ||
|
||||
N.getTag() == dwarf::DW_TAG_union_type ||
|
||||
N.getTag() == dwarf::DW_TAG_enumeration_type ||
|
||||
N.getTag() == dwarf::DW_TAG_class_type,
|
||||
"invalid tag", &N);
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_array_type ||
|
||||
N.getTag() == dwarf::DW_TAG_structure_type ||
|
||||
N.getTag() == dwarf::DW_TAG_union_type ||
|
||||
N.getTag() == dwarf::DW_TAG_enumeration_type ||
|
||||
N.getTag() == dwarf::DW_TAG_class_type,
|
||||
"invalid tag", &N);
|
||||
|
||||
Assert(isScope(N.getRawScope()), "invalid scope", &N, N.getRawScope());
|
||||
Assert(isType(N.getRawBaseType()), "invalid base type", &N,
|
||||
N.getRawBaseType());
|
||||
AssertDI(isScope(N.getRawScope()), "invalid scope", &N, N.getRawScope());
|
||||
AssertDI(isType(N.getRawBaseType()), "invalid base type", &N,
|
||||
N.getRawBaseType());
|
||||
|
||||
Assert(!N.getRawElements() || isa<MDTuple>(N.getRawElements()),
|
||||
"invalid composite elements", &N, N.getRawElements());
|
||||
Assert(isType(N.getRawVTableHolder()), "invalid vtable holder", &N,
|
||||
N.getRawVTableHolder());
|
||||
Assert(!hasConflictingReferenceFlags(N.getFlags()), "invalid reference flags",
|
||||
&N);
|
||||
AssertDI(!N.getRawElements() || isa<MDTuple>(N.getRawElements()),
|
||||
"invalid composite elements", &N, N.getRawElements());
|
||||
AssertDI(isType(N.getRawVTableHolder()), "invalid vtable holder", &N,
|
||||
N.getRawVTableHolder());
|
||||
AssertDI(!hasConflictingReferenceFlags(N.getFlags()),
|
||||
"invalid reference flags", &N);
|
||||
if (auto *Params = N.getRawTemplateParams())
|
||||
visitTemplateParams(N, *Params);
|
||||
|
||||
if (N.getTag() == dwarf::DW_TAG_class_type ||
|
||||
N.getTag() == dwarf::DW_TAG_union_type) {
|
||||
Assert(N.getFile() && !N.getFile()->getFilename().empty(),
|
||||
"class/union requires a filename", &N, N.getFile());
|
||||
AssertDI(N.getFile() && !N.getFile()->getFilename().empty(),
|
||||
"class/union requires a filename", &N, N.getFile());
|
||||
}
|
||||
}
|
||||
|
||||
void Verifier::visitDISubroutineType(const DISubroutineType &N) {
|
||||
Assert(N.getTag() == dwarf::DW_TAG_subroutine_type, "invalid tag", &N);
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_subroutine_type, "invalid tag", &N);
|
||||
if (auto *Types = N.getRawTypeArray()) {
|
||||
Assert(isa<MDTuple>(Types), "invalid composite elements", &N, Types);
|
||||
AssertDI(isa<MDTuple>(Types), "invalid composite elements", &N, Types);
|
||||
for (Metadata *Ty : N.getTypeArray()->operands()) {
|
||||
Assert(isType(Ty), "invalid subroutine type ref", &N, Types, Ty);
|
||||
AssertDI(isType(Ty), "invalid subroutine type ref", &N, Types, Ty);
|
||||
}
|
||||
}
|
||||
Assert(!hasConflictingReferenceFlags(N.getFlags()), "invalid reference flags",
|
||||
&N);
|
||||
AssertDI(!hasConflictingReferenceFlags(N.getFlags()),
|
||||
"invalid reference flags", &N);
|
||||
}
|
||||
|
||||
void Verifier::visitDIFile(const DIFile &N) {
|
||||
Assert(N.getTag() == dwarf::DW_TAG_file_type, "invalid tag", &N);
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_file_type, "invalid tag", &N);
|
||||
}
|
||||
|
||||
void Verifier::visitDICompileUnit(const DICompileUnit &N) {
|
||||
Assert(N.isDistinct(), "compile units must be distinct", &N);
|
||||
Assert(N.getTag() == dwarf::DW_TAG_compile_unit, "invalid tag", &N);
|
||||
AssertDI(N.isDistinct(), "compile units must be distinct", &N);
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_compile_unit, "invalid tag", &N);
|
||||
|
||||
// Don't bother verifying the compilation directory or producer string
|
||||
// as those could be empty.
|
||||
Assert(N.getRawFile() && isa<DIFile>(N.getRawFile()), "invalid file", &N,
|
||||
N.getRawFile());
|
||||
Assert(!N.getFile()->getFilename().empty(), "invalid filename", &N,
|
||||
N.getFile());
|
||||
AssertDI(N.getRawFile() && isa<DIFile>(N.getRawFile()), "invalid file", &N,
|
||||
N.getRawFile());
|
||||
AssertDI(!N.getFile()->getFilename().empty(), "invalid filename", &N,
|
||||
N.getFile());
|
||||
|
||||
Assert((N.getEmissionKind() <= DICompileUnit::LastEmissionKind),
|
||||
"invalid emission kind", &N);
|
||||
AssertDI((N.getEmissionKind() <= DICompileUnit::LastEmissionKind),
|
||||
"invalid emission kind", &N);
|
||||
|
||||
if (auto *Array = N.getRawEnumTypes()) {
|
||||
Assert(isa<MDTuple>(Array), "invalid enum list", &N, Array);
|
||||
AssertDI(isa<MDTuple>(Array), "invalid enum list", &N, Array);
|
||||
for (Metadata *Op : N.getEnumTypes()->operands()) {
|
||||
auto *Enum = dyn_cast_or_null<DICompositeType>(Op);
|
||||
Assert(Enum && Enum->getTag() == dwarf::DW_TAG_enumeration_type,
|
||||
"invalid enum type", &N, N.getEnumTypes(), Op);
|
||||
AssertDI(Enum && Enum->getTag() == dwarf::DW_TAG_enumeration_type,
|
||||
"invalid enum type", &N, N.getEnumTypes(), Op);
|
||||
}
|
||||
}
|
||||
if (auto *Array = N.getRawRetainedTypes()) {
|
||||
Assert(isa<MDTuple>(Array), "invalid retained type list", &N, Array);
|
||||
AssertDI(isa<MDTuple>(Array), "invalid retained type list", &N, Array);
|
||||
for (Metadata *Op : N.getRetainedTypes()->operands()) {
|
||||
Assert(Op && (isa<DIType>(Op) ||
|
||||
(isa<DISubprogram>(Op) &&
|
||||
cast<DISubprogram>(Op)->isDefinition() == false)),
|
||||
"invalid retained type", &N, Op);
|
||||
AssertDI(Op && (isa<DIType>(Op) ||
|
||||
(isa<DISubprogram>(Op) &&
|
||||
cast<DISubprogram>(Op)->isDefinition() == false)),
|
||||
"invalid retained type", &N, Op);
|
||||
}
|
||||
}
|
||||
if (auto *Array = N.getRawGlobalVariables()) {
|
||||
Assert(isa<MDTuple>(Array), "invalid global variable list", &N, Array);
|
||||
AssertDI(isa<MDTuple>(Array), "invalid global variable list", &N, Array);
|
||||
for (Metadata *Op : N.getGlobalVariables()->operands()) {
|
||||
Assert(Op && isa<DIGlobalVariable>(Op), "invalid global variable ref", &N,
|
||||
Op);
|
||||
AssertDI(Op && isa<DIGlobalVariable>(Op), "invalid global variable ref",
|
||||
&N, Op);
|
||||
}
|
||||
}
|
||||
if (auto *Array = N.getRawImportedEntities()) {
|
||||
Assert(isa<MDTuple>(Array), "invalid imported entity list", &N, Array);
|
||||
AssertDI(isa<MDTuple>(Array), "invalid imported entity list", &N, Array);
|
||||
for (Metadata *Op : N.getImportedEntities()->operands()) {
|
||||
Assert(Op && isa<DIImportedEntity>(Op), "invalid imported entity ref", &N,
|
||||
Op);
|
||||
AssertDI(Op && isa<DIImportedEntity>(Op), "invalid imported entity ref",
|
||||
&N, Op);
|
||||
}
|
||||
}
|
||||
if (auto *Array = N.getRawMacros()) {
|
||||
Assert(isa<MDTuple>(Array), "invalid macro list", &N, Array);
|
||||
AssertDI(isa<MDTuple>(Array), "invalid macro list", &N, Array);
|
||||
for (Metadata *Op : N.getMacros()->operands()) {
|
||||
Assert(Op && isa<DIMacroNode>(Op), "invalid macro ref", &N, Op);
|
||||
AssertDI(Op && isa<DIMacroNode>(Op), "invalid macro ref", &N, Op);
|
||||
}
|
||||
}
|
||||
CUVisited.insert(&N);
|
||||
}
|
||||
|
||||
void Verifier::visitDISubprogram(const DISubprogram &N) {
|
||||
Assert(N.getTag() == dwarf::DW_TAG_subprogram, "invalid tag", &N);
|
||||
Assert(isScope(N.getRawScope()), "invalid scope", &N, N.getRawScope());
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_subprogram, "invalid tag", &N);
|
||||
AssertDI(isScope(N.getRawScope()), "invalid scope", &N, N.getRawScope());
|
||||
if (auto *F = N.getRawFile())
|
||||
Assert(isa<DIFile>(F), "invalid file", &N, F);
|
||||
AssertDI(isa<DIFile>(F), "invalid file", &N, F);
|
||||
if (auto *T = N.getRawType())
|
||||
Assert(isa<DISubroutineType>(T), "invalid subroutine type", &N, T);
|
||||
Assert(isType(N.getRawContainingType()), "invalid containing type", &N,
|
||||
N.getRawContainingType());
|
||||
AssertDI(isa<DISubroutineType>(T), "invalid subroutine type", &N, T);
|
||||
AssertDI(isType(N.getRawContainingType()), "invalid containing type", &N,
|
||||
N.getRawContainingType());
|
||||
if (auto *Params = N.getRawTemplateParams())
|
||||
visitTemplateParams(N, *Params);
|
||||
if (auto *S = N.getRawDeclaration())
|
||||
Assert(isa<DISubprogram>(S) && !cast<DISubprogram>(S)->isDefinition(),
|
||||
"invalid subprogram declaration", &N, S);
|
||||
AssertDI(isa<DISubprogram>(S) && !cast<DISubprogram>(S)->isDefinition(),
|
||||
"invalid subprogram declaration", &N, S);
|
||||
if (auto *RawVars = N.getRawVariables()) {
|
||||
auto *Vars = dyn_cast<MDTuple>(RawVars);
|
||||
Assert(Vars, "invalid variable list", &N, RawVars);
|
||||
AssertDI(Vars, "invalid variable list", &N, RawVars);
|
||||
for (Metadata *Op : Vars->operands()) {
|
||||
Assert(Op && isa<DILocalVariable>(Op), "invalid local variable", &N, Vars,
|
||||
Op);
|
||||
AssertDI(Op && isa<DILocalVariable>(Op), "invalid local variable", &N,
|
||||
Vars, Op);
|
||||
}
|
||||
}
|
||||
Assert(!hasConflictingReferenceFlags(N.getFlags()), "invalid reference flags",
|
||||
&N);
|
||||
AssertDI(!hasConflictingReferenceFlags(N.getFlags()),
|
||||
"invalid reference flags", &N);
|
||||
|
||||
auto *Unit = N.getRawUnit();
|
||||
if (N.isDefinition()) {
|
||||
// Subprogram definitions (not part of the type hierarchy).
|
||||
Assert(N.isDistinct(), "subprogram definitions must be distinct", &N);
|
||||
Assert(Unit, "subprogram definitions must have a compile unit", &N);
|
||||
Assert(isa<DICompileUnit>(Unit), "invalid unit type", &N, Unit);
|
||||
AssertDI(N.isDistinct(), "subprogram definitions must be distinct", &N);
|
||||
AssertDI(Unit, "subprogram definitions must have a compile unit", &N);
|
||||
AssertDI(isa<DICompileUnit>(Unit), "invalid unit type", &N, Unit);
|
||||
} else {
|
||||
// Subprogram declarations (part of the type hierarchy).
|
||||
Assert(!Unit, "subprogram declarations must not have a compile unit", &N);
|
||||
AssertDI(!Unit, "subprogram declarations must not have a compile unit", &N);
|
||||
}
|
||||
}
|
||||
|
||||
void Verifier::visitDILexicalBlockBase(const DILexicalBlockBase &N) {
|
||||
Assert(N.getTag() == dwarf::DW_TAG_lexical_block, "invalid tag", &N);
|
||||
Assert(N.getRawScope() && isa<DILocalScope>(N.getRawScope()),
|
||||
"invalid local scope", &N, N.getRawScope());
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_lexical_block, "invalid tag", &N);
|
||||
AssertDI(N.getRawScope() && isa<DILocalScope>(N.getRawScope()),
|
||||
"invalid local scope", &N, N.getRawScope());
|
||||
}
|
||||
|
||||
void Verifier::visitDILexicalBlock(const DILexicalBlock &N) {
|
||||
visitDILexicalBlockBase(N);
|
||||
|
||||
Assert(N.getLine() || !N.getColumn(),
|
||||
"cannot have column info without line info", &N);
|
||||
AssertDI(N.getLine() || !N.getColumn(),
|
||||
"cannot have column info without line info", &N);
|
||||
}
|
||||
|
||||
void Verifier::visitDILexicalBlockFile(const DILexicalBlockFile &N) {
|
||||
|
@ -997,84 +1028,84 @@ void Verifier::visitDILexicalBlockFile(const DILexicalBlockFile &N) {
|
|||
}
|
||||
|
||||
void Verifier::visitDINamespace(const DINamespace &N) {
|
||||
Assert(N.getTag() == dwarf::DW_TAG_namespace, "invalid tag", &N);
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_namespace, "invalid tag", &N);
|
||||
if (auto *S = N.getRawScope())
|
||||
Assert(isa<DIScope>(S), "invalid scope ref", &N, S);
|
||||
AssertDI(isa<DIScope>(S), "invalid scope ref", &N, S);
|
||||
}
|
||||
|
||||
void Verifier::visitDIMacro(const DIMacro &N) {
|
||||
Assert(N.getMacinfoType() == dwarf::DW_MACINFO_define ||
|
||||
N.getMacinfoType() == dwarf::DW_MACINFO_undef,
|
||||
"invalid macinfo type", &N);
|
||||
Assert(!N.getName().empty(), "anonymous macro", &N);
|
||||
AssertDI(N.getMacinfoType() == dwarf::DW_MACINFO_define ||
|
||||
N.getMacinfoType() == dwarf::DW_MACINFO_undef,
|
||||
"invalid macinfo type", &N);
|
||||
AssertDI(!N.getName().empty(), "anonymous macro", &N);
|
||||
if (!N.getValue().empty()) {
|
||||
assert(N.getValue().data()[0] != ' ' && "Macro value has a space prefix");
|
||||
}
|
||||
}
|
||||
|
||||
void Verifier::visitDIMacroFile(const DIMacroFile &N) {
|
||||
Assert(N.getMacinfoType() == dwarf::DW_MACINFO_start_file,
|
||||
"invalid macinfo type", &N);
|
||||
AssertDI(N.getMacinfoType() == dwarf::DW_MACINFO_start_file,
|
||||
"invalid macinfo type", &N);
|
||||
if (auto *F = N.getRawFile())
|
||||
Assert(isa<DIFile>(F), "invalid file", &N, F);
|
||||
AssertDI(isa<DIFile>(F), "invalid file", &N, F);
|
||||
|
||||
if (auto *Array = N.getRawElements()) {
|
||||
Assert(isa<MDTuple>(Array), "invalid macro list", &N, Array);
|
||||
AssertDI(isa<MDTuple>(Array), "invalid macro list", &N, Array);
|
||||
for (Metadata *Op : N.getElements()->operands()) {
|
||||
Assert(Op && isa<DIMacroNode>(Op), "invalid macro ref", &N, Op);
|
||||
AssertDI(Op && isa<DIMacroNode>(Op), "invalid macro ref", &N, Op);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Verifier::visitDIModule(const DIModule &N) {
|
||||
Assert(N.getTag() == dwarf::DW_TAG_module, "invalid tag", &N);
|
||||
Assert(!N.getName().empty(), "anonymous module", &N);
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_module, "invalid tag", &N);
|
||||
AssertDI(!N.getName().empty(), "anonymous module", &N);
|
||||
}
|
||||
|
||||
void Verifier::visitDITemplateParameter(const DITemplateParameter &N) {
|
||||
Assert(isType(N.getRawType()), "invalid type ref", &N, N.getRawType());
|
||||
AssertDI(isType(N.getRawType()), "invalid type ref", &N, N.getRawType());
|
||||
}
|
||||
|
||||
void Verifier::visitDITemplateTypeParameter(const DITemplateTypeParameter &N) {
|
||||
visitDITemplateParameter(N);
|
||||
|
||||
Assert(N.getTag() == dwarf::DW_TAG_template_type_parameter, "invalid tag",
|
||||
&N);
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_template_type_parameter, "invalid tag",
|
||||
&N);
|
||||
}
|
||||
|
||||
void Verifier::visitDITemplateValueParameter(
|
||||
const DITemplateValueParameter &N) {
|
||||
visitDITemplateParameter(N);
|
||||
|
||||
Assert(N.getTag() == dwarf::DW_TAG_template_value_parameter ||
|
||||
N.getTag() == dwarf::DW_TAG_GNU_template_template_param ||
|
||||
N.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack,
|
||||
"invalid tag", &N);
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_template_value_parameter ||
|
||||
N.getTag() == dwarf::DW_TAG_GNU_template_template_param ||
|
||||
N.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack,
|
||||
"invalid tag", &N);
|
||||
}
|
||||
|
||||
void Verifier::visitDIVariable(const DIVariable &N) {
|
||||
if (auto *S = N.getRawScope())
|
||||
Assert(isa<DIScope>(S), "invalid scope", &N, S);
|
||||
Assert(isType(N.getRawType()), "invalid type ref", &N, N.getRawType());
|
||||
AssertDI(isa<DIScope>(S), "invalid scope", &N, S);
|
||||
AssertDI(isType(N.getRawType()), "invalid type ref", &N, N.getRawType());
|
||||
if (auto *F = N.getRawFile())
|
||||
Assert(isa<DIFile>(F), "invalid file", &N, F);
|
||||
AssertDI(isa<DIFile>(F), "invalid file", &N, F);
|
||||
}
|
||||
|
||||
void Verifier::visitDIGlobalVariable(const DIGlobalVariable &N) {
|
||||
// Checks common to all variables.
|
||||
visitDIVariable(N);
|
||||
|
||||
Assert(N.getTag() == dwarf::DW_TAG_variable, "invalid tag", &N);
|
||||
Assert(!N.getName().empty(), "missing global variable name", &N);
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_variable, "invalid tag", &N);
|
||||
AssertDI(!N.getName().empty(), "missing global variable name", &N);
|
||||
if (auto *V = N.getRawVariable()) {
|
||||
Assert(isa<ConstantAsMetadata>(V) &&
|
||||
!isa<Function>(cast<ConstantAsMetadata>(V)->getValue()),
|
||||
"invalid global varaible ref", &N, V);
|
||||
AssertDI(isa<ConstantAsMetadata>(V) &&
|
||||
!isa<Function>(cast<ConstantAsMetadata>(V)->getValue()),
|
||||
"invalid global varaible ref", &N, V);
|
||||
visitConstantExprsRecursively(cast<ConstantAsMetadata>(V)->getValue());
|
||||
}
|
||||
if (auto *Member = N.getRawStaticDataMemberDeclaration()) {
|
||||
Assert(isa<DIDerivedType>(Member), "invalid static data member declaration",
|
||||
&N, Member);
|
||||
AssertDI(isa<DIDerivedType>(Member),
|
||||
"invalid static data member declaration", &N, Member);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1082,31 +1113,31 @@ void Verifier::visitDILocalVariable(const DILocalVariable &N) {
|
|||
// Checks common to all variables.
|
||||
visitDIVariable(N);
|
||||
|
||||
Assert(N.getTag() == dwarf::DW_TAG_variable, "invalid tag", &N);
|
||||
Assert(N.getRawScope() && isa<DILocalScope>(N.getRawScope()),
|
||||
"local variable requires a valid scope", &N, N.getRawScope());
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_variable, "invalid tag", &N);
|
||||
AssertDI(N.getRawScope() && isa<DILocalScope>(N.getRawScope()),
|
||||
"local variable requires a valid scope", &N, N.getRawScope());
|
||||
}
|
||||
|
||||
void Verifier::visitDIExpression(const DIExpression &N) {
|
||||
Assert(N.isValid(), "invalid expression", &N);
|
||||
AssertDI(N.isValid(), "invalid expression", &N);
|
||||
}
|
||||
|
||||
void Verifier::visitDIObjCProperty(const DIObjCProperty &N) {
|
||||
Assert(N.getTag() == dwarf::DW_TAG_APPLE_property, "invalid tag", &N);
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_APPLE_property, "invalid tag", &N);
|
||||
if (auto *T = N.getRawType())
|
||||
Assert(isType(T), "invalid type ref", &N, T);
|
||||
AssertDI(isType(T), "invalid type ref", &N, T);
|
||||
if (auto *F = N.getRawFile())
|
||||
Assert(isa<DIFile>(F), "invalid file", &N, F);
|
||||
AssertDI(isa<DIFile>(F), "invalid file", &N, F);
|
||||
}
|
||||
|
||||
void Verifier::visitDIImportedEntity(const DIImportedEntity &N) {
|
||||
Assert(N.getTag() == dwarf::DW_TAG_imported_module ||
|
||||
N.getTag() == dwarf::DW_TAG_imported_declaration,
|
||||
"invalid tag", &N);
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_imported_module ||
|
||||
N.getTag() == dwarf::DW_TAG_imported_declaration,
|
||||
"invalid tag", &N);
|
||||
if (auto *S = N.getRawScope())
|
||||
Assert(isa<DIScope>(S), "invalid scope for imported entity", &N, S);
|
||||
Assert(isDINode(N.getRawEntity()), "invalid imported entity", &N,
|
||||
N.getRawEntity());
|
||||
AssertDI(isa<DIScope>(S), "invalid scope for imported entity", &N, S);
|
||||
AssertDI(isDINode(N.getRawEntity()), "invalid imported entity", &N,
|
||||
N.getRawEntity());
|
||||
}
|
||||
|
||||
void Verifier::visitComdat(const Comdat &C) {
|
||||
|
@ -1960,8 +1991,8 @@ void Verifier::visitFunction(const Function &F) {
|
|||
default:
|
||||
break;
|
||||
case LLVMContext::MD_dbg:
|
||||
Assert(isa<DISubprogram>(I.second),
|
||||
"function !dbg attachment must be a subprogram", &F, I.second);
|
||||
AssertDI(isa<DISubprogram>(I.second),
|
||||
"function !dbg attachment must be a subprogram", &F, I.second);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3676,7 +3707,7 @@ void Verifier::visitInstruction(Instruction &I) {
|
|||
}
|
||||
|
||||
if (MDNode *N = I.getDebugLoc().getAsMDNode()) {
|
||||
Assert(isa<DILocation>(N), "invalid !dbg metadata attachment", &I, N);
|
||||
AssertDI(isa<DILocation>(N), "invalid !dbg metadata attachment", &I, N);
|
||||
visitMDNode(*N);
|
||||
}
|
||||
|
||||
|
@ -4258,13 +4289,13 @@ static DISubprogram *getSubprogram(Metadata *LocalScope) {
|
|||
template <class DbgIntrinsicTy>
|
||||
void Verifier::visitDbgIntrinsic(StringRef Kind, DbgIntrinsicTy &DII) {
|
||||
auto *MD = cast<MetadataAsValue>(DII.getArgOperand(0))->getMetadata();
|
||||
Assert(isa<ValueAsMetadata>(MD) ||
|
||||
AssertDI(isa<ValueAsMetadata>(MD) ||
|
||||
(isa<MDNode>(MD) && !cast<MDNode>(MD)->getNumOperands()),
|
||||
"invalid llvm.dbg." + Kind + " intrinsic address/value", &DII, MD);
|
||||
Assert(isa<DILocalVariable>(DII.getRawVariable()),
|
||||
AssertDI(isa<DILocalVariable>(DII.getRawVariable()),
|
||||
"invalid llvm.dbg." + Kind + " intrinsic variable", &DII,
|
||||
DII.getRawVariable());
|
||||
Assert(isa<DIExpression>(DII.getRawExpression()),
|
||||
AssertDI(isa<DIExpression>(DII.getRawExpression()),
|
||||
"invalid llvm.dbg." + Kind + " intrinsic expression", &DII,
|
||||
DII.getRawExpression());
|
||||
|
||||
|
@ -4379,7 +4410,7 @@ bool llvm::verifyFunction(const Function &f, raw_ostream *OS) {
|
|||
assert(!F.isDeclaration() && "Cannot verify external functions");
|
||||
|
||||
// Don't use a raw_null_ostream. Printing IR is expensive.
|
||||
Verifier V(OS);
|
||||
Verifier V(OS, /*ShouldTreatBrokenDebugInfoAsError=*/true);
|
||||
|
||||
// Note that this function's return value is inverted from what you would
|
||||
// expect of a function called "verify".
|
||||
|
@ -4388,7 +4419,7 @@ bool llvm::verifyFunction(const Function &f, raw_ostream *OS) {
|
|||
|
||||
bool llvm::verifyModule(const Module &M, raw_ostream *OS) {
|
||||
// Don't use a raw_null_ostream. Printing IR is expensive.
|
||||
Verifier V(OS);
|
||||
Verifier V(OS, /*ShouldTreatBrokenDebugInfoAsError=*/true);
|
||||
|
||||
bool Broken = false;
|
||||
for (const Function &F : M)
|
||||
|
@ -4407,11 +4438,16 @@ struct VerifierLegacyPass : public FunctionPass {
|
|||
Verifier V;
|
||||
bool FatalErrors;
|
||||
|
||||
VerifierLegacyPass() : FunctionPass(ID), V(&dbgs()), FatalErrors(true) {
|
||||
VerifierLegacyPass()
|
||||
: FunctionPass(ID),
|
||||
V(&dbgs(), /*ShouldTreatBrokenDebugInfoAsError=*/true),
|
||||
FatalErrors(true) {
|
||||
initializeVerifierLegacyPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
explicit VerifierLegacyPass(bool FatalErrors)
|
||||
: FunctionPass(ID), V(&dbgs()), FatalErrors(FatalErrors) {
|
||||
: FunctionPass(ID),
|
||||
V(&dbgs(), /*ShouldTreatBrokenDebugInfoAsError=*/true),
|
||||
FatalErrors(FatalErrors) {
|
||||
initializeVerifierLegacyPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue