1 //===-- CommandObjectBugreport.cpp ------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "CommandObjectBugreport.h"
11 
12 // C Includes
13 #include <cstdio>
14 
15 // C++ Includes
16 // Other libraries and framework includes
17 
18 // Project includes
19 #include "lldb/Interpreter/CommandInterpreter.h"
20 #include "lldb/Interpreter/CommandReturnObject.h"
21 #include "lldb/Interpreter/OptionGroupOutputFile.h"
22 #include "lldb/Target/Thread.h"
23 
24 using namespace lldb;
25 using namespace lldb_private;
26 
27 //-------------------------------------------------------------------------
28 // "bugreport unwind"
29 //-------------------------------------------------------------------------
30 
31 class CommandObjectBugreportUnwind : public CommandObjectParsed
32 {
33 public:
34     CommandObjectBugreportUnwind(CommandInterpreter &interpreter) :
35         CommandObjectParsed(interpreter,
36                             "bugreport unwind",
37                             "Create a bugreport for a bug in the stack unwinding code.",
38                             nullptr),
39         m_option_group(interpreter),
40         m_outfile_options()
41     {
42         m_option_group.Append (&m_outfile_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
43         m_option_group.Finalize();
44     }
45 
46     ~CommandObjectBugreportUnwind() override
47     {
48     }
49 
50     Options *
51     GetOptions() override
52     {
53         return &m_option_group;
54     }
55 
56 protected:
57     bool
58     DoExecute(Args& command, CommandReturnObject &result) override
59     {
60         StringList commands;
61         commands.AppendString("thread backtrace");
62 
63         Thread *thread = m_exe_ctx.GetThreadPtr();
64         if (thread)
65         {
66             char command_buffer[256];
67 
68             uint32_t frame_count = thread->GetStackFrameCount();
69             for (uint32_t i = 0; i < frame_count; ++i)
70             {
71                 StackFrameSP frame = thread->GetStackFrameAtIndex(i);
72                 lldb::addr_t pc = frame->GetStackID().GetPC();
73 
74                 snprintf(command_buffer, sizeof(command_buffer), "disassemble --bytes --address 0x%" PRIx64, pc);
75                 commands.AppendString(command_buffer);
76 
77                 snprintf(command_buffer, sizeof(command_buffer), "image show-unwind --address 0x%" PRIx64, pc);
78                 commands.AppendString(command_buffer);
79             }
80         }
81 
82         const FileSpec &outfile_spec = m_outfile_options.GetFile().GetCurrentValue();
83         if (outfile_spec)
84         {
85             char path[PATH_MAX];
86             outfile_spec.GetPath (path, sizeof(path));
87 
88             uint32_t open_options = File::eOpenOptionWrite |
89                                     File::eOpenOptionCanCreate |
90                                     File::eOpenOptionAppend |
91                                     File::eOpenOptionCloseOnExec;
92 
93             const bool append = m_outfile_options.GetAppend().GetCurrentValue();
94             if (!append)
95                 open_options |= File::eOpenOptionTruncate;
96 
97             StreamFileSP outfile_stream = std::make_shared<StreamFile>();
98             Error error = outfile_stream->GetFile().Open(path, open_options);
99             if (error.Fail())
100             {
101                 result.AppendErrorWithFormat("Failed to open file '%s' for %s: %s\n",
102                                              path,
103                                              append ? "append" : "write",
104                                              error.AsCString());
105                 result.SetStatus(eReturnStatusFailed);
106                 return false;
107             }
108 
109             result.SetImmediateOutputStream(outfile_stream);
110         }
111 
112         CommandInterpreterRunOptions options;
113         options.SetStopOnError(false);
114         options.SetEchoCommands(true);
115         options.SetPrintResults(true);
116         options.SetAddToHistory(false);
117         m_interpreter.HandleCommands(commands, &m_exe_ctx, options, result);
118 
119         return result.Succeeded();
120     }
121 
122 private:
123     OptionGroupOptions m_option_group;
124     OptionGroupOutputFile m_outfile_options;
125 };
126 
127 #pragma mark CommandObjectMultiwordBugreport
128 
129 //-------------------------------------------------------------------------
130 // CommandObjectMultiwordBugreport
131 //-------------------------------------------------------------------------
132 
133 CommandObjectMultiwordBugreport::CommandObjectMultiwordBugreport(CommandInterpreter &interpreter)
134     : CommandObjectMultiword(interpreter, "bugreport", "Commands for creating domain-specific bug reports.",
135                              "bugreport <subcommand> [<subcommand-options>]")
136 {
137 
138     LoadSubCommand("unwind", CommandObjectSP(new CommandObjectBugreportUnwind(interpreter)));
139 }
140 
141 CommandObjectMultiwordBugreport::~CommandObjectMultiwordBugreport ()
142 {
143 }
144