diff options
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; |