diff options
author | Jonas Devlieghere <jonas@devlieghere.com> | 2019-11-19 17:28:46 -0800 |
---|---|---|
committer | Jonas Devlieghere <jonas@devlieghere.com> | 2019-11-20 13:14:16 -0800 |
commit | c8dfe907299e16aeb17175cb0896c17043fc7c81 (patch) | |
tree | 85aa1fcf033d71c0243f3efec47e593a5ba0818e /lldb/source/Commands/CommandObjectReproducer.cpp | |
parent | 824b25fc02dc4544adae55e6451d355f4c6d7055 (diff) | |
download | bcm5719-llvm-c8dfe907299e16aeb17175cb0896c17043fc7c81.tar.gz bcm5719-llvm-c8dfe907299e16aeb17175cb0896c17043fc7c81.zip |
[Reproducer] Generate LLDB reproducer on crash
This patch hooks the reproducer infrastructure with the signal handlers.
When lldb crashes with reproducers capture enabled, it will now generate
the reproducer and print a short message the standard out. This doesn't
affect the pretty stack traces, which are still printed before.
This patch also introduces a new reproducer sub-command that
intentionally raises a given signal to test the reproducer signal
handling.
Currently the signal handler is doing too much work. Instead of copying
over files into the reproducers in the signal handler, we should
re-invoke ourselves with a special command line flag that looks at the
VFS mapping and performs the copy.
This is a NO-OP when reproducers are disabled.
Differential revision: https://reviews.llvm.org/D70474
Diffstat (limited to 'lldb/source/Commands/CommandObjectReproducer.cpp')
-rw-r--r-- | lldb/source/Commands/CommandObjectReproducer.cpp | 126 |
1 files changed, 124 insertions, 2 deletions
diff --git a/lldb/source/Commands/CommandObjectReproducer.cpp b/lldb/source/Commands/CommandObjectReproducer.cpp index a22c704ebd0..7f97ba2875c 100644 --- a/lldb/source/Commands/CommandObjectReproducer.cpp +++ b/lldb/source/Commands/CommandObjectReproducer.cpp @@ -17,6 +17,8 @@ #include "lldb/Interpreter/OptionArgParser.h" #include "lldb/Interpreter/OptionGroupBoolean.h" +#include <csignal> + using namespace lldb; using namespace llvm; using namespace lldb_private; @@ -71,6 +73,37 @@ static constexpr OptionEnumValues ReproducerProviderType() { #define LLDB_OPTIONS_reproducer_dump #include "CommandOptions.inc" +enum ReproducerCrashSignal { + eReproducerCrashSigbus, + eReproducerCrashSigill, + eReproducerCrashSigsegv, +}; + +static constexpr OptionEnumValueElement g_reproducer_signaltype[] = { + { + eReproducerCrashSigbus, + "SIGBUS", + "Bus error", + }, + { + eReproducerCrashSigill, + "SIGILL", + "Illegal instruction", + }, + { + eReproducerCrashSigsegv, + "SIGSEGV", + "Segmentation fault", + }, +}; + +static constexpr OptionEnumValues ReproducerSignalType() { + return OptionEnumValues(g_reproducer_signaltype); +} + +#define LLDB_OPTIONS_reproducer_xcrash +#include "CommandOptions.inc" + class CommandObjectReproducerGenerate : public CommandObjectParsed { public: CommandObjectReproducerGenerate(CommandInterpreter &interpreter) @@ -117,12 +150,98 @@ protected: } }; +class CommandObjectReproducerXCrash : public CommandObjectParsed { +public: + CommandObjectReproducerXCrash(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "reproducer xcrash", + "Intentionally force the debugger to crash in " + "order to trigger and test reproducer generation.", + nullptr) {} + + ~CommandObjectReproducerXCrash() override = default; + + Options *GetOptions() override { return &m_options; } + + class CommandOptions : public Options { + public: + CommandOptions() : Options() {} + + ~CommandOptions() override = default; + + Status SetOptionValue(uint32_t option_idx, StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 's': + signal = (ReproducerCrashSignal)OptionArgParser::ToOptionEnum( + option_arg, GetDefinitions()[option_idx].enum_values, 0, error); + if (!error.Success()) + error.SetErrorStringWithFormat("unrecognized value for signal '%s'", + option_arg.str().c_str()); + break; + default: + llvm_unreachable("Unimplemented option"); + } + + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + signal = eReproducerCrashSigsegv; + } + + ArrayRef<OptionDefinition> GetDefinitions() override { + return makeArrayRef(g_reproducer_xcrash_options); + } + + ReproducerCrashSignal signal = eReproducerCrashSigsegv; + }; + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + if (!command.empty()) { + result.AppendErrorWithFormat("'%s' takes no arguments", + m_cmd_name.c_str()); + return false; + } + + auto &r = Reproducer::Instance(); + if (!r.IsCapturing()) { + result.SetError( + "forcing a crash is only supported when capturing a reproducer."); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return false; + } + + switch (m_options.signal) { + case eReproducerCrashSigill: + std::raise(SIGILL); + break; + case eReproducerCrashSigbus: + std::raise(SIGBUS); + break; + case eReproducerCrashSigsegv: + std::raise(SIGSEGV); + break; + } + + result.SetStatus(eReturnStatusQuit); + return result.Succeeded(); + } + +private: + CommandOptions m_options; +}; + class CommandObjectReproducerStatus : public CommandObjectParsed { public: CommandObjectReproducerStatus(CommandInterpreter &interpreter) : CommandObjectParsed( interpreter, "reproducer status", - "Show the current reproducer status. In capture mode the debugger " + "Show the current reproducer status. In capture mode the " + "debugger " "is collecting all the information it needs to create a " "reproducer. In replay mode the reproducer is replaying a " "reproducer. When the reproducers are off, no data is collected " @@ -365,7 +484,8 @@ CommandObjectReproducer::CommandObjectReproducer( CommandInterpreter &interpreter) : CommandObjectMultiword( interpreter, "reproducer", - "Commands for manipulating reproducers. Reproducers make it possible " + "Commands for manipulating reproducers. Reproducers make it " + "possible " "to capture full debug sessions with all its dependencies. The " "resulting reproducer is used to replay the debug session while " "debugging the debugger.\n" @@ -382,6 +502,8 @@ CommandObjectReproducer::CommandObjectReproducer( new CommandObjectReproducerStatus(interpreter))); LoadSubCommand("dump", CommandObjectSP(new CommandObjectReproducerDump(interpreter))); + LoadSubCommand("xcrash", CommandObjectSP( + new CommandObjectReproducerXCrash(interpreter))); } CommandObjectReproducer::~CommandObjectReproducer() = default; |