//===-- CommandObjectBugreport.cpp ------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "CommandObjectBugreport.h" #include #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) { 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(); File &file = outfile_stream->GetFile(); Status error = FileSystem::Instance().Open(file, outfile_spec, open_options); if (error.Fail()) { auto path = outfile_spec.GetPath(); result.AppendErrorWithFormat("Failed to open file '%s' for %s: %s\n", path.c_str(), 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.SetPrintErrors(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() {}