//===-- 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 // 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(); 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 []") { LoadSubCommand( "unwind", CommandObjectSP(new CommandObjectBugreportUnwind(interpreter))); } CommandObjectMultiwordBugreport::~CommandObjectMultiwordBugreport() {}