| //===-- CommandObjectBugreport.cpp ------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "CommandObjectBugreport.h" |
| |
| // C Includes |
| #include <cstdio> |
| |
| // C++ Includes |
| // Other libraries and framework includes |
| |
| // Project includes |
| #include "lldb/Interpreter/CommandInterpreter.h" |
| #include "lldb/Interpreter/CommandReturnObject.h" |
| #include "lldb/Interpreter/OptionGroupOutputFile.h" |
| #include "lldb/Target/Thread.h" |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| |
| //------------------------------------------------------------------------- |
| // "bugreport unwind" |
| //------------------------------------------------------------------------- |
| |
| class CommandObjectBugreportUnwind : public CommandObjectParsed { |
| public: |
| CommandObjectBugreportUnwind(CommandInterpreter &interpreter) |
| : CommandObjectParsed( |
| interpreter, "bugreport unwind", |
| "Create a bugreport for a bug in the stack unwinding code.", |
| nullptr), |
| m_option_group(), m_outfile_options() { |
| m_option_group.Append(&m_outfile_options, LLDB_OPT_SET_ALL, |
| LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3); |
| m_option_group.Finalize(); |
| } |
| |
| ~CommandObjectBugreportUnwind() override {} |
| |
| Options *GetOptions() override { return &m_option_group; } |
| |
| protected: |
| bool DoExecute(Args &command, CommandReturnObject &result) override { |
| StringList commands; |
| commands.AppendString("thread backtrace"); |
| |
| Thread *thread = m_exe_ctx.GetThreadPtr(); |
| if (thread) { |
| char command_buffer[256]; |
| |
| uint32_t frame_count = thread->GetStackFrameCount(); |
| for (uint32_t i = 0; i < frame_count; ++i) { |
| StackFrameSP frame = thread->GetStackFrameAtIndex(i); |
| lldb::addr_t pc = frame->GetStackID().GetPC(); |
| |
| snprintf(command_buffer, sizeof(command_buffer), |
| "disassemble --bytes --address 0x%" PRIx64, pc); |
| commands.AppendString(command_buffer); |
| |
| snprintf(command_buffer, sizeof(command_buffer), |
| "image show-unwind --address 0x%" PRIx64, pc); |
| commands.AppendString(command_buffer); |
| } |
| } |
| |
| const FileSpec &outfile_spec = |
| m_outfile_options.GetFile().GetCurrentValue(); |
| if (outfile_spec) { |
| char path[PATH_MAX]; |
| outfile_spec.GetPath(path, sizeof(path)); |
| |
| uint32_t open_options = |
| File::eOpenOptionWrite | File::eOpenOptionCanCreate | |
| File::eOpenOptionAppend | File::eOpenOptionCloseOnExec; |
| |
| const bool append = m_outfile_options.GetAppend().GetCurrentValue(); |
| if (!append) |
| open_options |= File::eOpenOptionTruncate; |
| |
| StreamFileSP outfile_stream = std::make_shared<StreamFile>(); |
| Status error = outfile_stream->GetFile().Open(path, open_options); |
| if (error.Fail()) { |
| result.AppendErrorWithFormat("Failed to open file '%s' for %s: %s\n", |
| path, append ? "append" : "write", |
| error.AsCString()); |
| result.SetStatus(eReturnStatusFailed); |
| return false; |
| } |
| |
| result.SetImmediateOutputStream(outfile_stream); |
| } |
| |
| CommandInterpreterRunOptions options; |
| options.SetStopOnError(false); |
| options.SetEchoCommands(true); |
| options.SetPrintResults(true); |
| options.SetAddToHistory(false); |
| m_interpreter.HandleCommands(commands, &m_exe_ctx, options, result); |
| |
| return result.Succeeded(); |
| } |
| |
| private: |
| OptionGroupOptions m_option_group; |
| OptionGroupOutputFile m_outfile_options; |
| }; |
| |
| #pragma mark CommandObjectMultiwordBugreport |
| |
| //------------------------------------------------------------------------- |
| // CommandObjectMultiwordBugreport |
| //------------------------------------------------------------------------- |
| |
| CommandObjectMultiwordBugreport::CommandObjectMultiwordBugreport( |
| CommandInterpreter &interpreter) |
| : CommandObjectMultiword( |
| interpreter, "bugreport", |
| "Commands for creating domain-specific bug reports.", |
| "bugreport <subcommand> [<subcommand-options>]") { |
| |
| LoadSubCommand( |
| "unwind", CommandObjectSP(new CommandObjectBugreportUnwind(interpreter))); |
| } |
| |
| CommandObjectMultiwordBugreport::~CommandObjectMultiwordBugreport() {} |