diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -582,6 +582,10 @@ timeTraceProfilerCleanup(); } + + if (args.getLastArg(OPT_debug_crash)) { + LLVM_BUILTIN_TRAP; + } } static std::string getRpath(opt::InputArgList &args) { diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -351,6 +351,12 @@ Eq<"reproduce", "Write tar file containing inputs and command to reproduce link">; +def reproduce_on_crash: F<"reproduce-on-crash">, + HelpText<"Generate tar file containing inputs and command when program crashes">; + +def debug_crash: F<"debug-crash">, + HelpText<"Debug flag to crash lld on purpose">; + defm rosegment: BB<"rosegment", "Put read-only non-executable sections in their own segment (default)", "Do not put read-only non-executable sections in their own segment">; diff --git a/lld/tools/lld/lld.cpp b/lld/tools/lld/lld.cpp --- a/lld/tools/lld/lld.cpp +++ b/lld/tools/lld/lld.cpp @@ -173,8 +173,40 @@ llvm::CrashRecoveryContext crc; if (!crc.RunSafely([&]() { r = lldMain(argc, argv, stdoutOS, stderrOS, /*exitEarly=*/false); - })) - return {crc.RetCode, /*canRunAgain=*/false}; + })) { + // lld crashed, save return code. + SafeReturn ret{crc.RetCode, /*canRunAgain=*/false}; + // Generate reproducer if related flag is specified. + std::vector args(argv, argv + argc); + bool hasReproducer = false; + bool hasReproduceOnCrash = false; + for (const char *arg : args) { + std::string arg_str(arg); + if (arg_str == "--reproduce-on-crash") + hasReproduceOnCrash = true; + if (StringRef(arg_str).startswith("--reproduce=")) + hasReproducer = true; + } + if (hasReproduceOnCrash && !hasReproducer) { + // Creat temp file for reproducer. + SmallString<128> reproducerPath; + std::error_code EC = + llvm::sys::fs::createTemporaryFile("lld", "tar", reproducerPath); + if (EC) { + stderrOS << "failed to create temporary file for reproducer\n"; + return ret; + } + stdoutOS << "reproducer writes to \"" << reproducerPath << "\"\n"; + std::string reproduceArg = "--reproduce=" + std::string(reproducerPath); + args.push_back(reproduceArg.c_str()); + llvm::CrashRecoveryContext crcReproducer; + crcReproducer.RunSafely([&]() { + lldMain(args.size(), args.data(), stdoutOS, stderrOS, + /*exitEarly=*/false); + }); + } + return ret; + } } // Cleanup memory and reset everything back in pristine condition. This path