summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/IR/DiagnosticInfo.h24
-rw-r--r--llvm/include/llvm/IR/Verifier.h29
-rw-r--r--llvm/lib/IR/DiagnosticInfo.cpp5
-rw-r--r--llvm/lib/IR/Verifier.cpp34
-rw-r--r--llvm/lib/Passes/PassRegistry.def2
-rw-r--r--llvm/unittests/IR/VerifierTest.cpp25
6 files changed, 110 insertions, 9 deletions
diff --git a/llvm/include/llvm/IR/DiagnosticInfo.h b/llvm/include/llvm/IR/DiagnosticInfo.h
index 3bcf7345d9e..78d7de27b43 100644
--- a/llvm/include/llvm/IR/DiagnosticInfo.h
+++ b/llvm/include/llvm/IR/DiagnosticInfo.h
@@ -51,6 +51,7 @@ enum DiagnosticKind {
DK_StackSize,
DK_Linker,
DK_DebugMetadataVersion,
+ DK_DebugMetadataInvalid,
DK_SampleProfile,
DK_OptimizationRemark,
DK_OptimizationRemarkMissed,
@@ -214,6 +215,29 @@ public:
}
};
+/// Diagnostic information for stripping invalid debug metadata.
+class DiagnosticInfoIgnoringInvalidDebugMetadata : public DiagnosticInfo {
+private:
+ /// The module that is concerned by this debug metadata version diagnostic.
+ const Module &M;
+
+public:
+ /// \p The module that is concerned by this debug metadata version diagnostic.
+ DiagnosticInfoIgnoringInvalidDebugMetadata(
+ const Module &M, DiagnosticSeverity Severity = DS_Warning)
+ : DiagnosticInfo(DK_DebugMetadataVersion, Severity), M(M) {}
+
+ const Module &getModule() const { return M; }
+
+ /// \see DiagnosticInfo::print.
+ void print(DiagnosticPrinter &DP) const override;
+
+ static bool classof(const DiagnosticInfo *DI) {
+ return DI->getKind() == DK_DebugMetadataInvalid;
+ }
+};
+
+
/// Diagnostic information for the sample profiler.
class DiagnosticInfoSampleProfile : public DiagnosticInfo {
public:
diff --git a/llvm/include/llvm/IR/Verifier.h b/llvm/include/llvm/IR/Verifier.h
index 70bec787a4c..654b29c5fcb 100644
--- a/llvm/include/llvm/IR/Verifier.h
+++ b/llvm/include/llvm/IR/Verifier.h
@@ -52,6 +52,28 @@ bool verifyFunction(const Function &F, raw_ostream *OS = nullptr);
bool verifyModule(const Module &M, raw_ostream *OS = nullptr,
bool *BrokenDebugInfo = nullptr);
+FunctionPass *createVerifierPass(bool FatalErrors = true);
+
+/// Check a module for errors, and report separate error states for IR
+/// and debug info errors.
+class VerifierAnalysis : public AnalysisInfoMixin<VerifierAnalysis> {
+ friend AnalysisInfoMixin<VerifierAnalysis>;
+ static char PassID;
+
+public:
+ struct Result {
+ bool IRBroken, DebugInfoBroken;
+ };
+ static void *ID() { return (void *)&PassID; }
+ Result run(Module &M);
+ Result run(Function &F);
+};
+
+/// Check a module for errors, but report debug info errors separately.
+/// Otherwise behaves as the normal verifyModule. Debug info errors can be
+/// "recovered" from by stripping the debug info.
+bool verifyModule(bool &BrokenDebugInfo, const Module &M, raw_ostream *OS);
+
/// \brief Create a verifier pass.
///
/// Check a module or function for validity. This is essentially a pass wrapped
@@ -62,18 +84,17 @@ bool verifyModule(const Module &M, raw_ostream *OS = nullptr,
///
/// Note that this creates a pass suitable for the legacy pass manager. It has
/// nothing to do with \c VerifierPass.
-FunctionPass *createVerifierPass(bool FatalErrors = true);
-
class VerifierPass : public PassInfoMixin<VerifierPass> {
bool FatalErrors;
public:
explicit VerifierPass(bool FatalErrors = true) : FatalErrors(FatalErrors) {}
- PreservedAnalyses run(Module &M);
- PreservedAnalyses run(Function &F);
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
+
} // End llvm namespace
#endif
diff --git a/llvm/lib/IR/DiagnosticInfo.cpp b/llvm/lib/IR/DiagnosticInfo.cpp
index 10d9d55ed71..91463ec5f1e 100644
--- a/llvm/lib/IR/DiagnosticInfo.cpp
+++ b/llvm/lib/IR/DiagnosticInfo.cpp
@@ -122,6 +122,11 @@ void DiagnosticInfoDebugMetadataVersion::print(DiagnosticPrinter &DP) const {
<< ") in " << getModule();
}
+void DiagnosticInfoIgnoringInvalidDebugMetadata::print(
+ DiagnosticPrinter &DP) const {
+ DP << "ignoring invalid debug info in " << getModule().getModuleIdentifier();
+}
+
void DiagnosticInfoSampleProfile::print(DiagnosticPrinter &DP) const {
if (!FileName.empty()) {
DP << getFileName();
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index e09f763f10b..9abe8d850f5 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -59,6 +59,7 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/InstIterator.h"
@@ -4482,15 +4483,38 @@ FunctionPass *llvm::createVerifierPass(bool FatalErrors) {
return new VerifierLegacyPass(FatalErrors);
}
-PreservedAnalyses VerifierPass::run(Module &M) {
- if (verifyModule(M, &dbgs()) && FatalErrors)
- report_fatal_error("Broken module found, compilation aborted!");
+char VerifierAnalysis::PassID;
+VerifierAnalysis::Result VerifierAnalysis::run(Module &M) {
+ Result Res;
+ Res.IRBroken = llvm::verifyModule(M, &dbgs(), &Res.DebugInfoBroken);
+ return Res;
+}
+
+VerifierAnalysis::Result VerifierAnalysis::run(Function &F) {
+ return { llvm::verifyFunction(F, &dbgs()), false };
+}
+PreservedAnalyses VerifierPass::run(Module &M, ModuleAnalysisManager &AM) {
+ auto Res = AM.getResult<VerifierAnalysis>(M);
+ if (FatalErrors) {
+ if (Res.IRBroken)
+ report_fatal_error("Broken module found, compilation aborted!");
+ assert(!Res.DebugInfoBroken && "Module contains invalid debug info");
+ }
+
+ // Strip broken debug info.
+ if (Res.DebugInfoBroken) {
+ DiagnosticInfoIgnoringInvalidDebugMetadata DiagInvalid(M);
+ M.getContext().diagnose(DiagInvalid);
+ if (!StripDebugInfo(M))
+ report_fatal_error("Failed to strip malformed debug info");
+ }
return PreservedAnalyses::all();
}
-PreservedAnalyses VerifierPass::run(Function &F) {
- if (verifyFunction(F, &dbgs()) && FatalErrors)
+PreservedAnalyses VerifierPass::run(Function &F, FunctionAnalysisManager &AM) {
+ auto res = AM.getResult<VerifierAnalysis>(F);
+ if (res.IRBroken && FatalErrors)
report_fatal_error("Broken function found, compilation aborted!");
return PreservedAnalyses::all();
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 9a31be3c816..d79a39cf952 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -23,6 +23,7 @@ MODULE_ANALYSIS("callgraph", CallGraphAnalysis())
MODULE_ANALYSIS("lcg", LazyCallGraphAnalysis())
MODULE_ANALYSIS("no-op-module", NoOpModuleAnalysis())
MODULE_ANALYSIS("targetlibinfo", TargetLibraryAnalysis())
+MODULE_ANALYSIS("verify", VerifierAnalysis())
#ifndef MODULE_ALIAS_ANALYSIS
#define MODULE_ALIAS_ANALYSIS(NAME, CREATE_PASS) \
@@ -87,6 +88,7 @@ FUNCTION_ANALYSIS("scalar-evolution", ScalarEvolutionAnalysis())
FUNCTION_ANALYSIS("targetlibinfo", TargetLibraryAnalysis())
FUNCTION_ANALYSIS("targetir",
TM ? TM->getTargetIRAnalysis() : TargetIRAnalysis())
+FUNCTION_ANALYSIS("verify", VerifierAnalysis())
#ifndef FUNCTION_ALIAS_ANALYSIS
#define FUNCTION_ALIAS_ANALYSIS(NAME, CREATE_PASS) \
diff --git a/llvm/unittests/IR/VerifierTest.cpp b/llvm/unittests/IR/VerifierTest.cpp
index 8b951739e47..1fc50da16a9 100644
--- a/llvm/unittests/IR/VerifierTest.cpp
+++ b/llvm/unittests/IR/VerifierTest.cpp
@@ -144,5 +144,30 @@ TEST(VerifierTest, CrossModuleMetadataRef) {
EXPECT_TRUE(StringRef(ErrorOS.str())
.startswith("Referencing global in another module!"));
}
+
+TEST(VerifierTest, StripInvalidDebugInfo) {
+ LLVMContext C;
+ Module M("M", C);
+ DIBuilder DIB(M);
+ DIB.createCompileUnit(dwarf::DW_LANG_C89, "broken.c", "/",
+ "unittest", false, "", 0);
+ DIB.finalize();
+ EXPECT_FALSE(verifyModule(M));
+
+ // Now break it.
+ auto *File = DIB.createFile("not-a-CU.f", ".");
+ NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.cu");
+ NMD->addOperand(File);
+ EXPECT_TRUE(verifyModule(M));
+
+ ModulePassManager MPM(true);
+ MPM.addPass(VerifierPass(false));
+ ModuleAnalysisManager MAM(true);
+ MAM.registerPass([&] { return VerifierAnalysis(); });
+ MPM.run(M, MAM);
+ EXPECT_FALSE(verifyModule(M));
+}
+
+
} // end anonymous namespace
} // end namespace llvm
OpenPOWER on IntegriCloud