Index: include/llvm/IR/Verifier.h =================================================================== --- include/llvm/IR/Verifier.h +++ include/llvm/IR/Verifier.h @@ -41,10 +41,15 @@ /// \brief Check a module for errors. /// -/// If there are no errors, the function returns false. If an error is found, -/// a message describing the error is written to OS (if non-null) and true is -/// returned. -bool verifyModule(const Module &M, raw_ostream *OS = nullptr); +/// If there are no errors, the function returns false. If an error is +/// found, a message describing the error is written to OS (if +/// non-null) and true is returned. +/// +/// \return true if the module is broken. If BrokenDebugInfo is +/// supplied, DebugInfo verification failures won't be considered as +/// error and instead *BrokenDebugInfo will be set to true. +bool verifyModule(const Module &M, raw_ostream *OS = nullptr, + bool *BrokenDebugInfo = nullptr); /// \brief Create a verifier pass. /// Index: include/llvm/LTO/LTOCodeGenerator.h =================================================================== --- include/llvm/LTO/LTOCodeGenerator.h +++ include/llvm/LTO/LTOCodeGenerator.h @@ -198,6 +198,7 @@ void DiagnosticHandler2(const DiagnosticInfo &DI); void emitError(const std::string &ErrMsg); + void emitWarning(const std::string &WarnMsg); LLVMContext &Context; std::unique_ptr MergedModule; Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -259,10 +259,10 @@ } public: - explicit Verifier(raw_ostream *OS, bool treatBrokenDebugInfoAsError = true) + explicit Verifier(raw_ostream *OS, bool ShouldTreatBrokenDebugInfoAsError) : VerifierSupport(OS), Context(nullptr), LandingPadResultTy(nullptr), SawFrameEscape(false) { - TreatBrokenDebugInfoAsError = treatBrokenDebugInfoAsError; + TreatBrokenDebugInfoAsError = ShouldTreatBrokenDebugInfoAsError; } bool hasBrokenDebugInfo() const { return BrokenDebugInfo; } @@ -4409,25 +4409,29 @@ 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". return !V.verify(F); } -bool llvm::verifyModule(const Module &M, raw_ostream *OS) { +bool llvm::verifyModule(const Module &M, raw_ostream *OS, + bool *BrokenDebugInfo) { // Don't use a raw_null_ostream. Printing IR is expensive. - Verifier V(OS); + Verifier V(OS, /*ShouldTreatBrokenDebugInfoAsError=*/!BrokenDebugInfo); bool Broken = false; for (const Function &F : M) if (!F.isDeclaration() && !F.isMaterializable()) Broken |= !V.verify(F); + Broken |= !V.verify(M); + if (BrokenDebugInfo) + *BrokenDebugInfo = V.hasBrokenDebugInfo(); // Note that this function's return value is inverted from what you would // expect of a function called "verify". - return !V.verify(M) || Broken; + return Broken; } namespace { @@ -4437,11 +4441,16 @@ 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()); } Index: lib/LTO/LTOCodeGenerator.cpp =================================================================== --- lib/LTO/LTOCodeGenerator.cpp +++ lib/LTO/LTOCodeGenerator.cpp @@ -26,6 +26,7 @@ #include "llvm/Config/config.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" @@ -78,6 +79,16 @@ cl::init(false), #endif cl::Hidden); + +cl::opt LTOStripInvalidDebugInfo( + "lto-strip-invalid-debug-info", + cl::desc("Strip invalid debug info metadata during LTO instead of aborting."), +#ifdef NDEBUG + cl::init(true), +#else + cl::init(false), +#endif + cl::Hidden); } LTOCodeGenerator::LTOCodeGenerator(LLVMContext &Context) @@ -478,6 +489,15 @@ return; HasVerifiedInput = true; + if (LTOStripInvalidDebugInfo) { + bool BrokenDebugInfo = false; + if (verifyModule(*MergedModule, &dbgs(), &BrokenDebugInfo)) + report_fatal_error("Broken module found, compilation aborted!"); + if (BrokenDebugInfo) { + emitWarning("Invalid debug info found, debug info will be stripped"); + StripDebugInfo(*MergedModule); + } + } if (verifyModule(*MergedModule, &dbgs())) report_fatal_error("Broken module found, compilation aborted!"); } @@ -643,3 +663,10 @@ else Context.diagnose(LTODiagnosticInfo(ErrMsg)); } + +void LTOCodeGenerator::emitWarning(const std::string &WarnMsg) { + if (DiagHandler) + (*DiagHandler)(LTO_DS_WARNING, WarnMsg.c_str(), DiagContext); + else + Context.diagnose(LTODiagnosticInfo(WarnMsg, DS_Warning)); +} Index: test/LTO/X86/strip-debug-info.ll =================================================================== --- /dev/null +++ test/LTO/X86/strip-debug-info.ll @@ -0,0 +1,20 @@ +; RUN: not llvm-lto -lto-strip-invalid-debug-info=false \ +; RUN: -o %t.o %S/Inputs/strip-debug-info.bc 2>&1 | \ +; RUN: FileCheck %s -allow-empty -check-prefix=CHECK-ERR +; RUN: llvm-lto -lto-strip-invalid-debug-info=true -exported-symbol _foo \ +; RUN: -o %t.o %S/Inputs/strip-debug-info.bc 2>&1 | \ +; RUN: FileCheck %s -allow-empty -check-prefix=CHECK-WARN +; RUN: llvm-nm %t.o | FileCheck %s + +; CHECK-ERR: Broken module found, compilation aborted +; CHECK-WARN: Invalid debug info found, debug info will be stripped +; CHECK: foo +define void @foo() { + ret void +} + +!llvm.module.flags = !{!0} +!llvm.dbg.cu = !{!1} + +!0 = !{i32 2, !"Debug Info Version", i32 3} +!1 = !DIFile(filename: "broken", directory: "")