diff --git a/llvm/tools/dsymutil/Options.td b/llvm/tools/dsymutil/Options.td --- a/llvm/tools/dsymutil/Options.td +++ b/llvm/tools/dsymutil/Options.td @@ -49,6 +49,10 @@ HelpText<"Do not use ODR (One Definition Rule) for type uniquing.">, Group; +def collect_crash_inputs: F<"collect-crash-inputs">, + HelpText<"Collect the crash inputs along with a shell script to reproduce the command line">, + Group; + def dump_debug_map: F<"dump-debug-map">, HelpText<"Parse and dump the debug map to standard output. Not DWARF link will take place.">, Group; diff --git a/llvm/tools/dsymutil/dsymutil.cpp b/llvm/tools/dsymutil/dsymutil.cpp --- a/llvm/tools/dsymutil/dsymutil.cpp +++ b/llvm/tools/dsymutil/dsymutil.cpp @@ -23,6 +23,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" +#include "llvm/Config/config.h" #include "llvm/DebugInfo/DIContext.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFVerifier.h" @@ -32,11 +33,13 @@ #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/FileCollector.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/ThreadPool.h" #include "llvm/Support/WithColor.h" @@ -470,18 +473,23 @@ return OutputLocation(std::string(Path.str()), ResourceDir); } -int main(int argc, char **argv) { - InitLLVM X(argc, argv); - +static auto parseArguments(int argc, char **argv) { // Parse arguments. DsymutilOptTable T; unsigned MAI; unsigned MAC; ArrayRef ArgsArr = makeArrayRef(argv + 1, argc - 1); - opt::InputArgList Args = T.ParseArgs(ArgsArr, MAI, MAC); + return std::make_pair(T, T.ParseArgs(ArgsArr, MAI, MAC)); +} +static int dsymutil_main(int argc, char **argv) { + + std::string progname{argv[0]}; + auto argPair = parseArguments(argc, argv); + auto &T = argPair.first; + auto &Args = argPair.second; void *P = (void *)(intptr_t)getOutputFileName; - std::string SDKPath = sys::fs::getMainExecutable(argv[0], P); + std::string SDKPath = sys::fs::getMainExecutable(progname.c_str(), P); SDKPath = std::string(sys::path::parent_path(SDKPath)); for (auto *Arg : Args.filtered(OPT_UNKNOWN)) { @@ -491,7 +499,7 @@ if (Args.hasArg(OPT_help)) { T.PrintHelp( - outs(), (std::string(argv[0]) + " [options] ").c_str(), + outs(), (progname + " [options] ").c_str(), "manipulate archived DWARF debug symbol files.\n\n" "dsymutil links the DWARF debug information found in the object files\n" "for the executable by using debug symbols information\n" @@ -690,3 +698,109 @@ return 0; } + +static std::string getTemporaryPath(StringRef Prefix, StringRef Suffix) { + SmallVector Path; + auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, Path); + if (EC) { + dbgs() << EC.message(); + return {}; + } + return {Path.begin(), Path.end()}; +} + +static void GenerateDiagnosticFiles(DsymutilOptions &Options) { + dbgs() << "\n********************\n\n" + "PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:\n" + "Binar(ies|y) object file(s) and associated debug map(s) are " + "located at:\n"; + for (const auto &InputFile : Options.InputFiles) { + // Copy Input file in + auto DiagInputFile = getTemporaryPath("input", InputFile); + if (DiagInputFile.empty()) + continue; + auto ECInputCopy = sys::fs::copy_file(InputFile, DiagInputFile); + if (ECInputCopy) { + dbgs() << "error copying " << InputFile << " to " << DiagInputFile + << " due to " << ECInputCopy.message() << "\n"; + } else { + dbgs() << "Input: " << DiagInputFile << "\n"; + } + auto DebugMapPtrsOrErr = + parseDebugMap(Options.LinkOpts.VFS, InputFile, Options.Archs, + Options.LinkOpts.PrependPath, Options.PaperTrailWarnings, + Options.LinkOpts.Verbose, Options.InputIsYAMLDebugMap); + if (DebugMapPtrsOrErr) { + std::string prefix{"object-"}; + prefix += InputFile + "-"; + for (auto &Map : *DebugMapPtrsOrErr) { + for (const auto &Object : *Map) { + // Copy object files in + auto ObjectFile = Object->getObjectFilename(); + auto DiagObjectFile = + getTemporaryPath(prefix, sys::path::filename(ObjectFile)); + if (DiagObjectFile.empty()) + continue; + auto ECObjectCopy = sys::fs::copy_file(ObjectFile, DiagObjectFile); + if (ECObjectCopy) { + dbgs() << "error copying " << ObjectFile << " to " << DiagObjectFile + << " due to " << ECInputCopy.message() << "\n"; + } else { + dbgs() << "Object: " << DiagObjectFile << "\n"; + } + } + // Now print a yaml debug map + auto DiagDebugMapFile = getTemporaryPath("debug-map", "yaml"); + if (DiagDebugMapFile.empty()) + continue; + std::error_code ECDebugMap; + raw_fd_ostream DiagDebugMap{DiagDebugMapFile, ECDebugMap, + sys::fs::CD_OpenExisting, sys::fs::FA_Write, + sys::fs::OF_Text}; + if (ECDebugMap) { + dbgs() << "error creating " << DiagDebugMapFile << " due to " + << ECDebugMap.message() << "\n"; + continue; + } + // FIXME: We are just dumping the debug map here but maybe we should + // reset the filename to our new filename? + Map->print(DiagDebugMap); + dbgs() << "Debug Map: " << DiagDebugMapFile << "\n"; + } + } + } +} + +int main(int argc, char **argv) { + InitLLVM X(argc, argv); + setBugReportMsg( + "PLEASE submit a bug report to " BUG_REPORT_URL + " and include the crash backtrace, object files and debug map.\n"); + CrashRecoveryContext::Enable(); + CrashRecoveryContext CRC; + CRC.DumpStackAndCleanupOnFailure = true; + int rval = 0; + if (!CRC.RunSafely( + [&rval, argc, argv]() { rval = dsymutil_main(argc, argv); })) { + auto argPair = parseArguments(argc, argv); + auto &Args = argPair.second; + // Now generate all the diagnostic info + if (Args.hasArg(OPT_collect_crash_inputs)) { + // Generate our files into the temp directory + auto OptionsOrErr = getOptions(Args); + if (OptionsOrErr) + GenerateDiagnosticFiles(*OptionsOrErr); + } else { + dbgs() << "dsymutil crashed please re-run dsymutil with " + "--collect-crash-inputs "; + for (auto i = 0U; i < Args.size(); i++) { + dbgs() << Args.getArgString(i) << " "; + } + dbgs() << "and file a bug and include the files produced by the above " + "command\n"; + } + return CRC.RetCode; + } else { + return rval; + } +}