diff options
Diffstat (limited to 'lib/IR/Verifier.cpp')
-rw-r--r-- | lib/IR/Verifier.cpp | 566 |
1 files changed, 496 insertions, 70 deletions
diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index fcf48c4..fba78e9 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -87,10 +87,9 @@ struct VerifierSupport { /// \brief Track the brokenness of the module while recursively visiting. bool Broken; - bool EverBroken; explicit VerifierSupport(raw_ostream &OS) - : OS(OS), M(nullptr), Broken(false), EverBroken(false) {} + : OS(OS), M(nullptr), Broken(false) {} private: void Write(const Value *V) { @@ -111,6 +110,10 @@ private: OS << '\n'; } + template <class T> void Write(const MDTupleTypedArrayWrapper<T> &MD) { + Write(MD.get()); + } + void Write(const NamedMDNode *NMD) { if (!NMD) return; @@ -145,7 +148,7 @@ public: /// something is not correct. void CheckFailed(const Twine &Message) { OS << Message << '\n'; - EverBroken = Broken = true; + Broken = true; } /// \brief A check failed (with values to print). @@ -175,6 +178,9 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport { /// \brief Keep track of the metadata nodes that have been checked already. SmallPtrSet<const Metadata *, 32> MDNodes; + /// \brief Track unresolved string-based type references. + SmallDenseMap<const MDString *, const MDNode *, 32> UnresolvedTypeRefs; + /// \brief The personality function referenced by the LandingPadInsts. /// All LandingPadInsts within the same function must use the same /// personality function. @@ -268,8 +274,8 @@ public: visitModuleFlags(M); visitModuleIdents(M); - // Verify debug info last. - verifyDebugInfo(); + // Verify type referneces last. + verifyTypeRefs(); return !Broken; } @@ -296,8 +302,37 @@ private: void visitBasicBlock(BasicBlock &BB); void visitRangeMetadata(Instruction& I, MDNode* Range, Type* Ty); + template <class Ty> bool isValidMetadataArray(const MDTuple &N); #define HANDLE_SPECIALIZED_MDNODE_LEAF(CLASS) void visit##CLASS(const CLASS &N); #include "llvm/IR/Metadata.def" + void visitMDScope(const MDScope &N); + void visitMDDerivedTypeBase(const MDDerivedTypeBase &N); + void visitMDVariable(const MDVariable &N); + void visitMDLexicalBlockBase(const MDLexicalBlockBase &N); + void visitMDTemplateParameter(const MDTemplateParameter &N); + + void visitTemplateParams(const MDNode &N, const Metadata &RawParams); + + /// \brief Check for a valid string-based type reference. + /// + /// Checks if \c MD is a string-based type reference. If it is, keeps track + /// of it (and its user, \c N) for error messages later. + bool isValidUUID(const MDNode &N, const Metadata *MD); + + /// \brief Check for a valid type reference. + /// + /// Checks for subclasses of \a MDType, or \a isValidUUID(). + bool isTypeRef(const MDNode &N, const Metadata *MD); + + /// \brief Check for a valid scope reference. + /// + /// Checks for subclasses of \a MDScope, or \a isValidUUID(). + bool isScopeRef(const MDNode &N, const Metadata *MD); + + /// \brief Check for a valid debug info reference. + /// + /// Checks for subclasses of \a DebugNode, or \a isValidUUID(). + bool isDIRef(const MDNode &N, const Metadata *MD); // InstVisitor overrides... using InstVisitor<Verifier>::visit; @@ -371,9 +406,11 @@ private: void verifyFrameRecoverIndices(); // Module-level debug info verification... - void verifyDebugInfo(); - void processInstructions(DebugInfoFinder &Finder); - void processCallInst(DebugInfoFinder &Finder, const CallInst &CI); + void verifyTypeRefs(); + template <class MapTy> + void verifyBitPieceExpression(const DbgInfoIntrinsic &I, + const MapTy &TypeRefs); + void visitUnresolvedTypeRef(const MDString *S, const MDNode *N); }; } // End anonymous namespace @@ -566,13 +603,14 @@ void Verifier::visitGlobalAlias(const GlobalAlias &GA) { void Verifier::visitNamedMDNode(const NamedMDNode &NMD) { for (unsigned i = 0, e = NMD.getNumOperands(); i != e; ++i) { MDNode *MD = NMD.getOperand(i); - if (!MD) - continue; if (NMD.getName() == "llvm.dbg.cu") { - Assert(isa<MDCompileUnit>(MD), "invalid compile unit", &NMD, MD); + Assert(MD && isa<MDCompileUnit>(MD), "invalid compile unit", &NMD, MD); } + if (!MD) + continue; + visitMDNode(*MD); } } @@ -658,6 +696,58 @@ void Verifier::visitMetadataAsValue(const MetadataAsValue &MDV, Function *F) { visitValueAsMetadata(*V, F); } +bool Verifier::isValidUUID(const MDNode &N, const Metadata *MD) { + auto *S = dyn_cast<MDString>(MD); + if (!S) + return false; + if (S->getString().empty()) + return false; + + // Keep track of names of types referenced via UUID so we can check that they + // actually exist. + UnresolvedTypeRefs.insert(std::make_pair(S, &N)); + return true; +} + +/// \brief Check if a value can be a reference to a type. +bool Verifier::isTypeRef(const MDNode &N, const Metadata *MD) { + return !MD || isValidUUID(N, MD) || isa<MDType>(MD); +} + +/// \brief Check if a value can be a ScopeRef. +bool Verifier::isScopeRef(const MDNode &N, const Metadata *MD) { + return !MD || isValidUUID(N, MD) || isa<MDScope>(MD); +} + +/// \brief Check if a value can be a debug info ref. +bool Verifier::isDIRef(const MDNode &N, const Metadata *MD) { + return !MD || isValidUUID(N, MD) || isa<DebugNode>(MD); +} + +template <class Ty> +bool isValidMetadataArrayImpl(const MDTuple &N, bool AllowNull) { + for (Metadata *MD : N.operands()) { + if (MD) { + if (!isa<Ty>(MD)) + return false; + } else { + if (!AllowNull) + return false; + } + } + return true; +} + +template <class Ty> +bool isValidMetadataArray(const MDTuple &N) { + return isValidMetadataArrayImpl<Ty>(N, /* AllowNull */ false); +} + +template <class Ty> +bool isValidMetadataNullArray(const MDTuple &N) { + return isValidMetadataArrayImpl<Ty>(N, /* AllowNull */ true); +} + void Verifier::visitMDLocation(const MDLocation &N) { Assert(N.getRawScope() && isa<MDLocalScope>(N.getRawScope()), "location requires a valid scope", &N, N.getRawScope()); @@ -669,8 +759,14 @@ void Verifier::visitGenericDebugNode(const GenericDebugNode &N) { Assert(N.getTag(), "invalid tag", &N); } +void Verifier::visitMDScope(const MDScope &N) { + if (auto *F = N.getRawFile()) + Assert(isa<MDFile>(F), "invalid file", &N, F); +} + void Verifier::visitMDSubrange(const MDSubrange &N) { Assert(N.getTag() == dwarf::DW_TAG_subrange_type, "invalid tag", &N); + Assert(N.getCount() >= -1, "invalid subrange count", &N); } void Verifier::visitMDEnumerator(const MDEnumerator &N) { @@ -683,7 +779,39 @@ void Verifier::visitMDBasicType(const MDBasicType &N) { "invalid tag", &N); } +void Verifier::visitMDDerivedTypeBase(const MDDerivedTypeBase &N) { + // Common scope checks. + visitMDScope(N); + + Assert(isScopeRef(N, N.getScope()), "invalid scope", &N, N.getScope()); + Assert(isTypeRef(N, N.getBaseType()), "invalid base type", &N, + N.getBaseType()); + + // FIXME: Sink this into the subclass verifies. + if (!N.getFile() || N.getFile()->getFilename().empty()) { + // Check whether the filename is allowed to be empty. + uint16_t Tag = N.getTag(); + Assert( + Tag == dwarf::DW_TAG_const_type || Tag == dwarf::DW_TAG_volatile_type || + Tag == dwarf::DW_TAG_pointer_type || + Tag == dwarf::DW_TAG_ptr_to_member_type || + Tag == dwarf::DW_TAG_reference_type || + Tag == dwarf::DW_TAG_rvalue_reference_type || + Tag == dwarf::DW_TAG_restrict_type || + Tag == dwarf::DW_TAG_array_type || + Tag == dwarf::DW_TAG_enumeration_type || + Tag == dwarf::DW_TAG_subroutine_type || + Tag == dwarf::DW_TAG_inheritance || Tag == dwarf::DW_TAG_friend || + Tag == dwarf::DW_TAG_structure_type || + Tag == dwarf::DW_TAG_member || Tag == dwarf::DW_TAG_typedef, + "derived/composite type requires a filename", &N, N.getFile()); + } +} + void Verifier::visitMDDerivedType(const MDDerivedType &N) { + // Common derived type checks. + visitMDDerivedTypeBase(N); + Assert(N.getTag() == dwarf::DW_TAG_typedef || N.getTag() == dwarf::DW_TAG_pointer_type || N.getTag() == dwarf::DW_TAG_ptr_to_member_type || @@ -696,9 +824,30 @@ void Verifier::visitMDDerivedType(const MDDerivedType &N) { 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(isTypeRef(N, N.getExtraData()), "invalid pointer to member type", &N, + N.getExtraData()); + } +} + +static bool hasConflictingReferenceFlags(unsigned Flags) { + return (Flags & DebugNode::FlagLValueReference) && + (Flags & DebugNode::FlagRValueReference); +} + +void Verifier::visitTemplateParams(const MDNode &N, const Metadata &RawParams) { + auto *Params = dyn_cast<MDTuple>(&RawParams); + Assert(Params, "invalid template params", &N, &RawParams); + for (Metadata *Op : Params->operands()) { + Assert(Op && isa<MDTemplateParameter>(Op), "invalid template parameter", &N, + Params, Op); + } } void Verifier::visitMDCompositeType(const MDCompositeType &N) { + // Common derived type checks. + visitMDDerivedTypeBase(N); + Assert(N.getTag() == dwarf::DW_TAG_array_type || N.getTag() == dwarf::DW_TAG_structure_type || N.getTag() == dwarf::DW_TAG_union_type || @@ -706,10 +855,29 @@ void Verifier::visitMDCompositeType(const MDCompositeType &N) { N.getTag() == dwarf::DW_TAG_subroutine_type || N.getTag() == dwarf::DW_TAG_class_type, "invalid tag", &N); + + Assert(!N.getRawElements() || isa<MDTuple>(N.getRawElements()), + "invalid composite elements", &N, N.getRawElements()); + Assert(isTypeRef(N, N.getRawVTableHolder()), "invalid vtable holder", &N, + N.getRawVTableHolder()); + Assert(!N.getRawElements() || isa<MDTuple>(N.getRawElements()), + "invalid composite elements", &N, N.getRawElements()); + Assert(!hasConflictingReferenceFlags(N.getFlags()), "invalid reference flags", + &N); + if (auto *Params = N.getRawTemplateParams()) + visitTemplateParams(N, *Params); } void Verifier::visitMDSubroutineType(const MDSubroutineType &N) { Assert(N.getTag() == dwarf::DW_TAG_subroutine_type, "invalid tag", &N); + if (auto *Types = N.getRawTypeArray()) { + Assert(isa<MDTuple>(Types), "invalid composite elements", &N, Types); + for (Metadata *Ty : N.getTypeArray()->operands()) { + Assert(isTypeRef(N, Ty), "invalid subroutine type ref", &N, Types, Ty); + } + } + Assert(!hasConflictingReferenceFlags(N.getFlags()), "invalid reference flags", + &N); } void Verifier::visitMDFile(const MDFile &N) { @@ -718,45 +886,195 @@ void Verifier::visitMDFile(const MDFile &N) { void Verifier::visitMDCompileUnit(const MDCompileUnit &N) { Assert(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<MDFile>(N.getRawFile()), + "invalid file", &N, N.getRawFile()); + Assert(!N.getFile()->getFilename().empty(), "invalid filename", &N, + N.getFile()); + + if (auto *Array = N.getRawEnumTypes()) { + Assert(isa<MDTuple>(Array), "invalid enum list", &N, Array); + for (Metadata *Op : N.getEnumTypes()->operands()) { + auto *Enum = dyn_cast_or_null<MDCompositeType>(Op); + Assert(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); + for (Metadata *Op : N.getRetainedTypes()->operands()) { + Assert(Op && isa<MDType>(Op), "invalid retained type", &N, Op); + } + } + if (auto *Array = N.getRawSubprograms()) { + Assert(isa<MDTuple>(Array), "invalid subprogram list", &N, Array); + for (Metadata *Op : N.getSubprograms()->operands()) { + Assert(Op && isa<MDSubprogram>(Op), "invalid subprogram ref", &N, Op); + } + } + if (auto *Array = N.getRawGlobalVariables()) { + Assert(isa<MDTuple>(Array), "invalid global variable list", &N, Array); + for (Metadata *Op : N.getGlobalVariables()->operands()) { + Assert(Op && isa<MDGlobalVariable>(Op), "invalid global variable ref", &N, + Op); + } + } + if (auto *Array = N.getRawImportedEntities()) { + Assert(isa<MDTuple>(Array), "invalid imported entity list", &N, Array); + for (Metadata *Op : N.getImportedEntities()->operands()) { + Assert(Op && isa<MDImportedEntity>(Op), "invalid imported entity ref", &N, + Op); + } + } } void Verifier::visitMDSubprogram(const MDSubprogram &N) { Assert(N.getTag() == dwarf::DW_TAG_subprogram, "invalid tag", &N); + Assert(isScopeRef(N, N.getRawScope()), "invalid scope", &N, N.getRawScope()); + if (auto *T = N.getRawType()) + Assert(isa<MDSubroutineType>(T), "invalid subroutine type", &N, T); + Assert(isTypeRef(N, N.getRawContainingType()), "invalid containing type", &N, + N.getRawContainingType()); + if (auto *RawF = N.getRawFunction()) { + auto *FMD = dyn_cast<ConstantAsMetadata>(RawF); + auto *F = FMD ? FMD->getValue() : nullptr; + auto *FT = F ? dyn_cast<PointerType>(F->getType()) : nullptr; + Assert(F && FT && isa<FunctionType>(FT->getElementType()), + "invalid function", &N, F, FT); + } + if (auto *Params = N.getRawTemplateParams()) + visitTemplateParams(N, *Params); + if (auto *S = N.getRawDeclaration()) { + Assert(isa<MDSubprogram>(S) && !cast<MDSubprogram>(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); + for (Metadata *Op : Vars->operands()) { + Assert(Op && isa<MDLocalVariable>(Op), "invalid local variable", &N, Vars, + Op); + } + } + Assert(!hasConflictingReferenceFlags(N.getFlags()), "invalid reference flags", + &N); + + auto *F = N.getFunction(); + if (!F) + return; + + // Check that all !dbg attachments lead to back to N (or, at least, another + // subprogram that describes the same function). + // + // FIXME: Check this incrementally while visiting !dbg attachments. + // FIXME: Only check when N is the canonical subprogram for F. + SmallPtrSet<const MDNode *, 32> Seen; + for (auto &BB : *F) + for (auto &I : BB) { + // Be careful about using MDLocation here since we might be dealing with + // broken code (this is the Verifier after all). + MDLocation *DL = + dyn_cast_or_null<MDLocation>(I.getDebugLoc().getAsMDNode()); + if (!DL) + continue; + if (!Seen.insert(DL).second) + continue; + + MDLocalScope *Scope = DL->getInlinedAtScope(); + if (Scope && !Seen.insert(Scope).second) + continue; + + MDSubprogram *SP = Scope ? Scope->getSubprogram() : nullptr; + if (SP && !Seen.insert(SP).second) + continue; + + // FIXME: Once N is canonical, check "SP == &N". + Assert(SP->describes(F), + "!dbg attachment points at wrong subprogram for function", &N, F, + &I, DL, Scope, SP); + } } -void Verifier::visitMDLexicalBlock(const MDLexicalBlock &N) { +void Verifier::visitMDLexicalBlockBase(const MDLexicalBlockBase &N) { Assert(N.getTag() == dwarf::DW_TAG_lexical_block, "invalid tag", &N); + Assert(N.getRawScope() && isa<MDLocalScope>(N.getRawScope()), + "invalid local scope", &N, N.getRawScope()); +} + +void Verifier::visitMDLexicalBlock(const MDLexicalBlock &N) { + visitMDLexicalBlockBase(N); + + Assert(N.getLine() || !N.getColumn(), + "cannot have column info without line info", &N); } void Verifier::visitMDLexicalBlockFile(const MDLexicalBlockFile &N) { - Assert(N.getTag() == dwarf::DW_TAG_lexical_block, "invalid tag", &N); + visitMDLexicalBlockBase(N); } void Verifier::visitMDNamespace(const MDNamespace &N) { Assert(N.getTag() == dwarf::DW_TAG_namespace, "invalid tag", &N); + if (auto *S = N.getRawScope()) + Assert(isa<MDScope>(S), "invalid scope ref", &N, S); +} + +void Verifier::visitMDTemplateParameter(const MDTemplateParameter &N) { + Assert(isTypeRef(N, N.getType()), "invalid type ref", &N, N.getType()); } void Verifier::visitMDTemplateTypeParameter(const MDTemplateTypeParameter &N) { + visitMDTemplateParameter(N); + Assert(N.getTag() == dwarf::DW_TAG_template_type_parameter, "invalid tag", &N); } void Verifier::visitMDTemplateValueParameter( const MDTemplateValueParameter &N) { + visitMDTemplateParameter(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); } +void Verifier::visitMDVariable(const MDVariable &N) { + if (auto *S = N.getRawScope()) + Assert(isa<MDScope>(S), "invalid scope", &N, S); + Assert(isTypeRef(N, N.getRawType()), "invalid type ref", &N, N.getRawType()); + if (auto *F = N.getRawFile()) + Assert(isa<MDFile>(F), "invalid file", &N, F); +} + void Verifier::visitMDGlobalVariable(const MDGlobalVariable &N) { + // Checks common to all variables. + visitMDVariable(N); + Assert(N.getTag() == dwarf::DW_TAG_variable, "invalid tag", &N); + Assert(!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); + } + if (auto *Member = N.getRawStaticDataMemberDeclaration()) { + Assert(isa<MDDerivedType>(Member), "invalid static data member declaration", + &N, Member); + } } void Verifier::visitMDLocalVariable(const MDLocalVariable &N) { + // Checks common to all variables. + visitMDVariable(N); + Assert(N.getTag() == dwarf::DW_TAG_auto_variable || N.getTag() == dwarf::DW_TAG_arg_variable, "invalid tag", &N); + Assert(N.getRawScope() && isa<MDLocalScope>(N.getRawScope()), + "local variable requires a valid scope", &N, N.getRawScope()); } void Verifier::visitMDExpression(const MDExpression &N) { @@ -765,12 +1083,20 @@ void Verifier::visitMDExpression(const MDExpression &N) { void Verifier::visitMDObjCProperty(const MDObjCProperty &N) { Assert(N.getTag() == dwarf::DW_TAG_APPLE_property, "invalid tag", &N); + if (auto *T = N.getRawType()) + Assert(isa<MDType>(T), "invalid type ref", &N, T); + if (auto *F = N.getRawFile()) + Assert(isa<MDFile>(F), "invalid file", &N, F); } void Verifier::visitMDImportedEntity(const MDImportedEntity &N) { Assert(N.getTag() == dwarf::DW_TAG_imported_module || N.getTag() == dwarf::DW_TAG_imported_declaration, "invalid tag", &N); + if (auto *S = N.getRawScope()) + Assert(isa<MDScope>(S), "invalid scope for imported entity", &N, S); + Assert(isDIRef(N, N.getEntity()), "invalid imported entity", &N, + N.getEntity()); } void Verifier::visitComdat(const Comdat &C) { @@ -2133,7 +2459,7 @@ void Verifier::visitGetElementPtrInst(GetElementPtrInst &GEP) { SmallVector<Value*, 16> Idxs(GEP.idx_begin(), GEP.idx_end()); Type *ElTy = - GetElementPtrInst::getIndexedType(GEP.getPointerOperandType(), Idxs); + GetElementPtrInst::getIndexedType(GEP.getSourceElementType(), Idxs); Assert(ElTy, "Invalid indices for GEP pointer type!", &GEP); Assert(GEP.getType()->getScalarType()->isPointerTy() && @@ -2214,9 +2540,7 @@ void Verifier::visitRangeMetadata(Instruction& I, void Verifier::visitLoadInst(LoadInst &LI) { PointerType *PTy = dyn_cast<PointerType>(LI.getOperand(0)->getType()); Assert(PTy, "Load operand must be a pointer.", &LI); - Type *ElTy = PTy->getElementType(); - Assert(ElTy == LI.getType(), - "Load result type does not match pointer operand type!", &LI, ElTy); + Type *ElTy = LI.getType(); Assert(LI.getAlignment() <= Value::MaximumAlignment, "huge alignment values are unsupported", &LI); if (LI.isAtomic()) { @@ -2885,6 +3209,8 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { Assert(!SawFrameEscape, "multiple calls to llvm.frameescape in one function", &CI); for (Value *Arg : CI.arg_operands()) { + if (isa<ConstantPointerNull>(Arg)) + continue; // Null values are allowed as placeholders. auto *AI = dyn_cast<AllocaInst>(Arg->stripPointerCasts()); Assert(AI && AI->isStaticAlloca(), "llvm.frameescape only accepts static allocas", &CI); @@ -2909,16 +3235,11 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { break; } - case Intrinsic::eh_unwindhelp: { - auto *AI = dyn_cast<AllocaInst>(CI.getArgOperand(0)->stripPointerCasts()); - Assert(AI && AI->isStaticAlloca(), - "llvm.eh.unwindhelp requires a static alloca", &CI); - break; - } - case Intrinsic::experimental_gc_statepoint: Assert(!CI.isInlineAsm(), "gc.statepoint support for inline assembly unimplemented", &CI); + Assert(CI.getParent()->getParent()->hasGC(), + "Enclosing function does not use GC.", &CI); VerifyStatepoint(ImmutableCallSite(&CI)); break; @@ -2926,6 +3247,8 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { case Intrinsic::experimental_gc_result_float: case Intrinsic::experimental_gc_result_ptr: case Intrinsic::experimental_gc_result: { + Assert(CI.getParent()->getParent()->hasGC(), + "Enclosing function does not use GC.", &CI); // Are we tied to a statepoint properly? CallSite StatepointCS(CI.getArgOperand(0)); const Function *StatepointFn = @@ -3035,6 +3358,25 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { }; } +/// \brief Carefully grab the subprogram from a local scope. +/// +/// This carefully grabs the subprogram from a local scope, avoiding the +/// built-in assertions that would typically fire. +static MDSubprogram *getSubprogram(Metadata *LocalScope) { + if (!LocalScope) + return nullptr; + + if (auto *SP = dyn_cast<MDSubprogram>(LocalScope)) + return SP; + + if (auto *LB = dyn_cast<MDLexicalBlockBase>(LocalScope)) + return getSubprogram(LB->getRawScope()); + + // Just return null; broken scope chains are checked elsewhere. + assert(!isa<MDLocalScope>(LocalScope) && "Unknown type of local scope"); + return nullptr; +} + template <class DbgIntrinsicTy> void Verifier::visitDbgIntrinsic(StringRef Kind, DbgIntrinsicTy &DII) { auto *MD = cast<MetadataAsValue>(DII.getArgOperand(0))->getMetadata(); @@ -3047,61 +3389,145 @@ void Verifier::visitDbgIntrinsic(StringRef Kind, DbgIntrinsicTy &DII) { Assert(isa<MDExpression>(DII.getRawExpression()), "invalid llvm.dbg." + Kind + " intrinsic expression", &DII, DII.getRawExpression()); -} -void Verifier::verifyDebugInfo() { - // Run the debug info verifier only if the regular verifier succeeds, since - // sometimes checks that have already failed will cause crashes here. - if (EverBroken || !VerifyDebugInfo) - return; + // Ignore broken !dbg attachments; they're checked elsewhere. + if (MDNode *N = DII.getDebugLoc().getAsMDNode()) + if (!isa<MDLocation>(N)) + return; - DebugInfoFinder Finder; - Finder.processModule(*M); - processInstructions(Finder); + BasicBlock *BB = DII.getParent(); + Function *F = BB ? BB->getParent() : nullptr; + + // The scopes for variables and !dbg attachments must agree. + MDLocalVariable *Var = DII.getVariable(); + MDLocation *Loc = DII.getDebugLoc(); + Assert(Loc, "llvm.dbg." + Kind + " intrinsic requires a !dbg attachment", + &DII, BB, F); + + MDSubprogram *VarSP = getSubprogram(Var->getRawScope()); + MDSubprogram *LocSP = getSubprogram(Loc->getRawScope()); + if (!VarSP || !LocSP) + return; // Broken scope chains are checked elsewhere. + + Assert(VarSP == LocSP, "mismatched subprogram between llvm.dbg." + Kind + + " variable and !dbg attachment", + &DII, BB, F, Var, Var->getScope()->getSubprogram(), Loc, + Loc->getScope()->getSubprogram()); +} + +template <class MapTy> +static uint64_t getVariableSize(const MDLocalVariable &V, const MapTy &Map) { + // Be careful of broken types (checked elsewhere). + const Metadata *RawType = V.getRawType(); + while (RawType) { + // Try to get the size directly. + if (auto *T = dyn_cast<MDType>(RawType)) + if (uint64_t Size = T->getSizeInBits()) + return Size; + + if (auto *DT = dyn_cast<MDDerivedType>(RawType)) { + // Look at the base type. + RawType = DT->getRawBaseType(); + continue; + } - // Verify Debug Info. - // - // NOTE: The loud braces are necessary for MSVC compatibility. - for (DICompileUnit CU : Finder.compile_units()) { - Assert(CU.Verify(), "DICompileUnit does not Verify!", CU); - } - for (DISubprogram S : Finder.subprograms()) { - Assert(S.Verify(), "DISubprogram does not Verify!", S); - } - for (DIGlobalVariable GV : Finder.global_variables()) { - Assert(GV.Verify(), "DIGlobalVariable does not Verify!", GV); - } - for (DIType T : Finder.types()) { - Assert(T.Verify(), "DIType does not Verify!", T); + if (auto *S = dyn_cast<MDString>(RawType)) { + // Don't error on missing types (checked elsewhere). + RawType = Map.lookup(S); + continue; + } + + // Missing type or size. + break; } - for (DIScope S : Finder.scopes()) { - Assert(S.Verify(), "DIScope does not Verify!", S); + + // Fail gracefully. + return 0; +} + +template <class MapTy> +void Verifier::verifyBitPieceExpression(const DbgInfoIntrinsic &I, + const MapTy &TypeRefs) { + MDLocalVariable *V; + MDExpression *E; + if (auto *DVI = dyn_cast<DbgValueInst>(&I)) { + V = dyn_cast_or_null<MDLocalVariable>(DVI->getRawVariable()); + E = dyn_cast_or_null<MDExpression>(DVI->getRawExpression()); + } else { + auto *DDI = cast<DbgDeclareInst>(&I); + V = dyn_cast_or_null<MDLocalVariable>(DDI->getRawVariable()); + E = dyn_cast_or_null<MDExpression>(DDI->getRawExpression()); } + + // We don't know whether this intrinsic verified correctly. + if (!V || !E || !E->isValid()) + return; + + // Nothing to do if this isn't a bit piece expression. + if (!E->isBitPiece()) + return; + + // If there's no size, the type is broken, but that should be checked + // elsewhere. + uint64_t VarSize = getVariableSize(*V, TypeRefs); + if (!VarSize) + return; + + unsigned PieceSize = E->getBitPieceSize(); + unsigned PieceOffset = E->getBitPieceOffset(); + Assert(PieceSize + PieceOffset <= VarSize, + "piece is larger than or outside of variable", &I, V, E); + Assert(PieceSize != VarSize, "piece covers entire variable", &I, V, E); } -void Verifier::processInstructions(DebugInfoFinder &Finder) { - for (const Function &F : *M) - for (auto I = inst_begin(&F), E = inst_end(&F); I != E; ++I) { - if (MDNode *MD = I->getMetadata(LLVMContext::MD_dbg)) - Finder.processLocation(*M, DILocation(MD)); - if (const CallInst *CI = dyn_cast<CallInst>(&*I)) - processCallInst(Finder, *CI); - } +void Verifier::visitUnresolvedTypeRef(const MDString *S, const MDNode *N) { + // This is in its own function so we get an error for each bad type ref (not + // just the first). + Assert(false, "unresolved type ref", S, N); } -void Verifier::processCallInst(DebugInfoFinder &Finder, const CallInst &CI) { - if (Function *F = CI.getCalledFunction()) - if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID()) - switch (ID) { - case Intrinsic::dbg_declare: - Finder.processDeclare(*M, cast<DbgDeclareInst>(&CI)); - break; - case Intrinsic::dbg_value: - Finder.processValue(*M, cast<DbgValueInst>(&CI)); - break; - default: - break; - } +void Verifier::verifyTypeRefs() { + auto *CUs = M->getNamedMetadata("llvm.dbg.cu"); + if (!CUs) + return; + + // Visit all the compile units again to map the type references. + SmallDenseMap<const MDString *, const MDType *, 32> TypeRefs; + for (auto *CU : CUs->operands()) + if (auto Ts = cast<MDCompileUnit>(CU)->getRetainedTypes()) + for (MDType *Op : Ts) + if (auto *T = dyn_cast<MDCompositeType>(Op)) + if (auto *S = T->getRawIdentifier()) { + UnresolvedTypeRefs.erase(S); + TypeRefs.insert(std::make_pair(S, T)); + } + + // Verify debug info intrinsic bit piece expressions. This needs a second + // pass through the intructions, since we haven't built TypeRefs yet when + // verifying functions, and simply queuing the DbgInfoIntrinsics to evaluate + // later/now would queue up some that could be later deleted. + for (const Function &F : *M) + for (const BasicBlock &BB : F) + for (const Instruction &I : BB) + if (auto *DII = dyn_cast<DbgInfoIntrinsic>(&I)) + verifyBitPieceExpression(*DII, TypeRefs); + + // Return early if all typerefs were resolved. + if (UnresolvedTypeRefs.empty()) + return; + + // Sort the unresolved references by name so the output is deterministic. + typedef std::pair<const MDString *, const MDNode *> TypeRef; + SmallVector<TypeRef, 32> Unresolved(UnresolvedTypeRefs.begin(), + UnresolvedTypeRefs.end()); + std::sort(Unresolved.begin(), Unresolved.end(), + [](const TypeRef &LHS, const TypeRef &RHS) { + return LHS.first->getString() < RHS.first->getString(); + }); + + // Visit the unresolved refs (printing out the errors). + for (const TypeRef &TR : Unresolved) + visitUnresolvedTypeRef(TR.first, TR.second); } //===----------------------------------------------------------------------===// |