Index: test/tools/dsymutil/X86/verify.test =================================================================== --- /dev/null +++ test/tools/dsymutil/X86/verify.test @@ -0,0 +1,8 @@ +# Multiple inputs in flat mode +RUN: not llvm-dsymutil -verify -oso-prepend-path=%p/.. %p/../Inputs/basic.macho.x86_64 %p/../Inputs/basic-archive.macho.x86_64 %p/../Inputs/basic-lto.macho.x86_64 %p/../Inputs/basic-lto-dw4.macho.x86_64 -o %t 2>&1 | FileCheck %s --check-prefix=QUIET +RUN: not llvm-dsymutil -verify -verbose -oso-prepend-path=%p/.. %p/../Inputs/basic.macho.x86_64 %p/../Inputs/basic-archive.macho.x86_64 %p/../Inputs/basic-lto.macho.x86_64 %p/../Inputs/basic-lto-dw4.macho.x86_64 -o %t 2>&1 | FileCheck %s --check-prefix=QUIET --check-prefix=VERBOSE + +VERBOSE: Verifying DWARF for architecture: x86_64 +VERBOSE: error: DIE has invalid DW_AT_location encoding: +VERBOSE: error: DIE has invalid DW_AT_location encoding: +QUIET: error: verification failed Index: test/tools/dsymutil/cmdline.test =================================================================== --- test/tools/dsymutil/cmdline.test +++ test/tools/dsymutil/cmdline.test @@ -14,6 +14,7 @@ HELP: -oso-prepend-path= HELP: -symtab HELP: -verbose +HELP: -verify HELP: -y HELP-NOT: -reverse-iterate Index: tools/dsymutil/dsymutil.cpp =================================================================== --- tools/dsymutil/dsymutil.cpp +++ tools/dsymutil/dsymutil.cpp @@ -20,6 +20,10 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFVerifier.h" +#include "llvm/Object/Binary.h" #include "llvm/Object/MachO.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" @@ -40,6 +44,7 @@ using namespace llvm; using namespace llvm::cl; using namespace llvm::dsymutil; +using namespace object; static OptionCategory DsymCategory("Specific Options"); static opt Help("h", desc("Alias for -help"), Hidden); @@ -114,6 +119,9 @@ "y", desc("Treat the input file is a YAML debug map rather than a binary."), init(false), cat(DsymCategory)); +static opt Verify("verify", desc("Verify the linked DWARF debug info."), + cat(DsymCategory)); + static bool createPlistFile(llvm::StringRef Bin, llvm::StringRef BundleRoot) { if (NoOutput) return true; @@ -184,6 +192,34 @@ return true; } +static bool verify(llvm::StringRef OutputFile, llvm::StringRef Arch) { + if (OutputFile == "-") { + llvm::errs() << "warning: verification skipped for " << Arch + << "because writing to stdout.\n"; + return true; + } + + Expected> BinOrErr = createBinary(OutputFile); + if (!BinOrErr) { + errs() << OutputFile << ": " << toString(BinOrErr.takeError()); + return false; + } + + Binary &Binary = *BinOrErr.get().getBinary(); + if (auto *Obj = dyn_cast(&Binary)) { + raw_ostream &os = Verbose ? errs() : nulls(); + os << "Verifying DWARF for architecture: " << Arch << "\n"; + std::unique_ptr DICtx = DWARFContext::create(*Obj); + DIDumpOptions DumpOpts; + bool success = DICtx->verify(os, DumpOpts.noImplicitRecursion()); + if (!success) + errs() << "error: verification failed for " << Arch << '\n'; + return success; + } + + return false; +} + static std::string getOutputFileName(llvm::StringRef InputFile) { if (FlatOut) { // If a flat dSYM has been requested, things are pretty simple. @@ -361,6 +397,7 @@ std::atomic_char AllOK(1); auto LinkLambda = [&]() { AllOK.fetch_and(linkDwarf(*OS, *Map, Options)); + OS->flush(); }; // FIXME: The DwarfLinker can have some very deep recursion that can max @@ -376,6 +413,10 @@ if (!AllOK) return 1; + if (Verify && !NoOutput && + !verify(OutputFile, Map->getTriple().getArchName())) + return 1; + if (NeedsTempFiles) TempFiles.emplace_back(Map->getTriple().getArchName().str(), OutputFile);