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