11c3bbb01SEd Maste //===-- CommandObjectBugreport.cpp ------------------------------*- C++ -*-===//
21c3bbb01SEd Maste //
31c3bbb01SEd Maste //                     The LLVM Compiler Infrastructure
41c3bbb01SEd Maste //
51c3bbb01SEd Maste // This file is distributed under the University of Illinois Open Source
61c3bbb01SEd Maste // License. See LICENSE.TXT for details.
71c3bbb01SEd Maste //
81c3bbb01SEd Maste //===----------------------------------------------------------------------===//
91c3bbb01SEd Maste 
101c3bbb01SEd Maste #include "CommandObjectBugreport.h"
111c3bbb01SEd Maste 
121c3bbb01SEd Maste #include <cstdio>
131c3bbb01SEd Maste 
141c3bbb01SEd Maste 
151c3bbb01SEd Maste #include "lldb/Interpreter/CommandInterpreter.h"
161c3bbb01SEd Maste #include "lldb/Interpreter/CommandReturnObject.h"
171c3bbb01SEd Maste #include "lldb/Interpreter/OptionGroupOutputFile.h"
181c3bbb01SEd Maste #include "lldb/Target/Thread.h"
191c3bbb01SEd Maste 
201c3bbb01SEd Maste using namespace lldb;
211c3bbb01SEd Maste using namespace lldb_private;
221c3bbb01SEd Maste 
231c3bbb01SEd Maste //-------------------------------------------------------------------------
241c3bbb01SEd Maste // "bugreport unwind"
251c3bbb01SEd Maste //-------------------------------------------------------------------------
261c3bbb01SEd Maste 
27435933ddSDimitry Andric class CommandObjectBugreportUnwind : public CommandObjectParsed {
281c3bbb01SEd Maste public:
CommandObjectBugreportUnwind(CommandInterpreter & interpreter)29435933ddSDimitry Andric   CommandObjectBugreportUnwind(CommandInterpreter &interpreter)
30435933ddSDimitry Andric       : CommandObjectParsed(
31435933ddSDimitry Andric             interpreter, "bugreport unwind",
321c3bbb01SEd Maste             "Create a bugreport for a bug in the stack unwinding code.",
331c3bbb01SEd Maste             nullptr),
34435933ddSDimitry Andric         m_option_group(), m_outfile_options() {
35435933ddSDimitry Andric     m_option_group.Append(&m_outfile_options, LLDB_OPT_SET_ALL,
36435933ddSDimitry Andric                           LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
371c3bbb01SEd Maste     m_option_group.Finalize();
381c3bbb01SEd Maste   }
391c3bbb01SEd Maste 
~CommandObjectBugreportUnwind()40435933ddSDimitry Andric   ~CommandObjectBugreportUnwind() override {}
411c3bbb01SEd Maste 
GetOptions()42435933ddSDimitry Andric   Options *GetOptions() override { return &m_option_group; }
431c3bbb01SEd Maste 
441c3bbb01SEd Maste protected:
DoExecute(Args & command,CommandReturnObject & result)45435933ddSDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
461c3bbb01SEd Maste     StringList commands;
471c3bbb01SEd Maste     commands.AppendString("thread backtrace");
481c3bbb01SEd Maste 
491c3bbb01SEd Maste     Thread *thread = m_exe_ctx.GetThreadPtr();
50435933ddSDimitry Andric     if (thread) {
511c3bbb01SEd Maste       char command_buffer[256];
521c3bbb01SEd Maste 
531c3bbb01SEd Maste       uint32_t frame_count = thread->GetStackFrameCount();
54435933ddSDimitry Andric       for (uint32_t i = 0; i < frame_count; ++i) {
551c3bbb01SEd Maste         StackFrameSP frame = thread->GetStackFrameAtIndex(i);
561c3bbb01SEd Maste         lldb::addr_t pc = frame->GetStackID().GetPC();
571c3bbb01SEd Maste 
58435933ddSDimitry Andric         snprintf(command_buffer, sizeof(command_buffer),
59435933ddSDimitry Andric                  "disassemble --bytes --address 0x%" PRIx64, pc);
601c3bbb01SEd Maste         commands.AppendString(command_buffer);
611c3bbb01SEd Maste 
62435933ddSDimitry Andric         snprintf(command_buffer, sizeof(command_buffer),
63435933ddSDimitry Andric                  "image show-unwind --address 0x%" PRIx64, pc);
641c3bbb01SEd Maste         commands.AppendString(command_buffer);
651c3bbb01SEd Maste       }
661c3bbb01SEd Maste     }
671c3bbb01SEd Maste 
68435933ddSDimitry Andric     const FileSpec &outfile_spec =
69435933ddSDimitry Andric         m_outfile_options.GetFile().GetCurrentValue();
70435933ddSDimitry Andric     if (outfile_spec) {
711c3bbb01SEd Maste 
72435933ddSDimitry Andric       uint32_t open_options =
73435933ddSDimitry Andric           File::eOpenOptionWrite | File::eOpenOptionCanCreate |
74435933ddSDimitry Andric           File::eOpenOptionAppend | File::eOpenOptionCloseOnExec;
751c3bbb01SEd Maste 
761c3bbb01SEd Maste       const bool append = m_outfile_options.GetAppend().GetCurrentValue();
771c3bbb01SEd Maste       if (!append)
781c3bbb01SEd Maste         open_options |= File::eOpenOptionTruncate;
791c3bbb01SEd Maste 
801c3bbb01SEd Maste       StreamFileSP outfile_stream = std::make_shared<StreamFile>();
81*b5893f02SDimitry Andric       File &file = outfile_stream->GetFile();
82*b5893f02SDimitry Andric       Status error =
83*b5893f02SDimitry Andric           FileSystem::Instance().Open(file, outfile_spec, open_options);
84435933ddSDimitry Andric       if (error.Fail()) {
85*b5893f02SDimitry Andric         auto path = outfile_spec.GetPath();
861c3bbb01SEd Maste         result.AppendErrorWithFormat("Failed to open file '%s' for %s: %s\n",
87*b5893f02SDimitry Andric                                      path.c_str(), append ? "append" : "write",
881c3bbb01SEd Maste                                      error.AsCString());
891c3bbb01SEd Maste         result.SetStatus(eReturnStatusFailed);
901c3bbb01SEd Maste         return false;
911c3bbb01SEd Maste       }
921c3bbb01SEd Maste 
931c3bbb01SEd Maste       result.SetImmediateOutputStream(outfile_stream);
941c3bbb01SEd Maste     }
951c3bbb01SEd Maste 
961c3bbb01SEd Maste     CommandInterpreterRunOptions options;
971c3bbb01SEd Maste     options.SetStopOnError(false);
981c3bbb01SEd Maste     options.SetEchoCommands(true);
991c3bbb01SEd Maste     options.SetPrintResults(true);
1001c3bbb01SEd Maste     options.SetAddToHistory(false);
1011c3bbb01SEd Maste     m_interpreter.HandleCommands(commands, &m_exe_ctx, options, result);
1021c3bbb01SEd Maste 
1031c3bbb01SEd Maste     return result.Succeeded();
1041c3bbb01SEd Maste   }
1051c3bbb01SEd Maste 
1061c3bbb01SEd Maste private:
1071c3bbb01SEd Maste   OptionGroupOptions m_option_group;
1081c3bbb01SEd Maste   OptionGroupOutputFile m_outfile_options;
1091c3bbb01SEd Maste };
1101c3bbb01SEd Maste 
1111c3bbb01SEd Maste #pragma mark CommandObjectMultiwordBugreport
1121c3bbb01SEd Maste 
1131c3bbb01SEd Maste //-------------------------------------------------------------------------
1141c3bbb01SEd Maste // CommandObjectMultiwordBugreport
1151c3bbb01SEd Maste //-------------------------------------------------------------------------
1161c3bbb01SEd Maste 
CommandObjectMultiwordBugreport(CommandInterpreter & interpreter)117435933ddSDimitry Andric CommandObjectMultiwordBugreport::CommandObjectMultiwordBugreport(
118435933ddSDimitry Andric     CommandInterpreter &interpreter)
119435933ddSDimitry Andric     : CommandObjectMultiword(
120435933ddSDimitry Andric           interpreter, "bugreport",
121435933ddSDimitry Andric           "Commands for creating domain-specific bug reports.",
122435933ddSDimitry Andric           "bugreport <subcommand> [<subcommand-options>]") {
1231c3bbb01SEd Maste 
124435933ddSDimitry Andric   LoadSubCommand(
125435933ddSDimitry Andric       "unwind", CommandObjectSP(new CommandObjectBugreportUnwind(interpreter)));
1261c3bbb01SEd Maste }
1271c3bbb01SEd Maste 
~CommandObjectMultiwordBugreport()128435933ddSDimitry Andric CommandObjectMultiwordBugreport::~CommandObjectMultiwordBugreport() {}
129