1#include "CommandObjectSession.h"
2#include "lldb/Host/OptionParser.h"
3#include "lldb/Interpreter/CommandInterpreter.h"
4#include "lldb/Interpreter/CommandOptionArgumentTable.h"
5#include "lldb/Interpreter/CommandReturnObject.h"
6#include "lldb/Interpreter/OptionArgParser.h"
7#include "lldb/Interpreter/OptionValue.h"
8#include "lldb/Interpreter/OptionValueBoolean.h"
9#include "lldb/Interpreter/OptionValueString.h"
10#include "lldb/Interpreter/OptionValueUInt64.h"
11#include "lldb/Interpreter/Options.h"
12
13using namespace lldb;
14using namespace lldb_private;
15
16class CommandObjectSessionSave : public CommandObjectParsed {
17public:
18 CommandObjectSessionSave(CommandInterpreter &interpreter)
19 : CommandObjectParsed(interpreter, "session save",
20 "Save the current session transcripts to a file.\n"
21 "If no file if specified, transcripts will be "
22 "saved to a temporary file.",
23 "session save [file]") {
24 CommandArgumentEntry arg1;
25 arg1.emplace_back(args: eArgTypePath, args: eArgRepeatOptional);
26 m_arguments.push_back(x: arg1);
27 }
28
29 ~CommandObjectSessionSave() override = default;
30
31 void
32 HandleArgumentCompletion(CompletionRequest &request,
33 OptionElementVector &opt_element_vector) override {
34 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
35 interpreter&: GetCommandInterpreter(), completion_mask: lldb::eDiskFileCompletion, request, searcher: nullptr);
36 }
37
38protected:
39 void DoExecute(Args &args, CommandReturnObject &result) override {
40 llvm::StringRef file_path;
41
42 if (!args.empty())
43 file_path = args[0].ref();
44
45 if (m_interpreter.SaveTranscript(result, output_file: file_path.str()))
46 result.SetStatus(eReturnStatusSuccessFinishNoResult);
47 else
48 result.SetStatus(eReturnStatusFailed);
49 }
50};
51
52#define LLDB_OPTIONS_history
53#include "CommandOptions.inc"
54
55class CommandObjectSessionHistory : public CommandObjectParsed {
56public:
57 CommandObjectSessionHistory(CommandInterpreter &interpreter)
58 : CommandObjectParsed(interpreter, "session history",
59 "Dump the history of commands in this session.\n"
60 "Commands in the history list can be run again "
61 "using \"!<INDEX>\". \"!-<OFFSET>\" will re-run "
62 "the command that is <OFFSET> commands from the end"
63 " of the list (counting the current command).",
64 nullptr) {}
65
66 ~CommandObjectSessionHistory() override = default;
67
68 Options *GetOptions() override { return &m_options; }
69
70protected:
71 class CommandOptions : public Options {
72 public:
73 CommandOptions()
74 : m_start_idx(0), m_stop_idx(0), m_count(0), m_clear(false) {}
75
76 ~CommandOptions() override = default;
77
78 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
79 ExecutionContext *execution_context) override {
80 Status error;
81 const int short_option = m_getopt_table[option_idx].val;
82
83 switch (short_option) {
84 case 'c':
85 error = m_count.SetValueFromString(value: option_arg, op: eVarSetOperationAssign);
86 break;
87 case 's':
88 if (option_arg == "end") {
89 m_start_idx.SetCurrentValue(UINT64_MAX);
90 m_start_idx.SetOptionWasSet();
91 } else
92 error = m_start_idx.SetValueFromString(value: option_arg,
93 op: eVarSetOperationAssign);
94 break;
95 case 'e':
96 error =
97 m_stop_idx.SetValueFromString(value: option_arg, op: eVarSetOperationAssign);
98 break;
99 case 'C':
100 m_clear.SetCurrentValue(true);
101 m_clear.SetOptionWasSet();
102 break;
103 default:
104 llvm_unreachable("Unimplemented option");
105 }
106
107 return error;
108 }
109
110 void OptionParsingStarting(ExecutionContext *execution_context) override {
111 m_start_idx.Clear();
112 m_stop_idx.Clear();
113 m_count.Clear();
114 m_clear.Clear();
115 }
116
117 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
118 return llvm::ArrayRef(g_history_options);
119 }
120
121 // Instance variables to hold the values for command options.
122
123 OptionValueUInt64 m_start_idx;
124 OptionValueUInt64 m_stop_idx;
125 OptionValueUInt64 m_count;
126 OptionValueBoolean m_clear;
127 };
128
129 void DoExecute(Args &command, CommandReturnObject &result) override {
130 if (m_options.m_clear.GetCurrentValue() &&
131 m_options.m_clear.OptionWasSet()) {
132 m_interpreter.GetCommandHistory().Clear();
133 result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
134 } else {
135 if (m_options.m_start_idx.OptionWasSet() &&
136 m_options.m_stop_idx.OptionWasSet() &&
137 m_options.m_count.OptionWasSet()) {
138 result.AppendError(in_string: "--count, --start-index and --end-index cannot be "
139 "all specified in the same invocation");
140 result.SetStatus(lldb::eReturnStatusFailed);
141 } else {
142 std::pair<bool, uint64_t> start_idx(
143 m_options.m_start_idx.OptionWasSet(),
144 m_options.m_start_idx.GetCurrentValue());
145 std::pair<bool, uint64_t> stop_idx(
146 m_options.m_stop_idx.OptionWasSet(),
147 m_options.m_stop_idx.GetCurrentValue());
148 std::pair<bool, uint64_t> count(m_options.m_count.OptionWasSet(),
149 m_options.m_count.GetCurrentValue());
150
151 const CommandHistory &history(m_interpreter.GetCommandHistory());
152
153 if (start_idx.first && start_idx.second == UINT64_MAX) {
154 if (count.first) {
155 start_idx.second = history.GetSize() - count.second;
156 stop_idx.second = history.GetSize() - 1;
157 } else if (stop_idx.first) {
158 start_idx.second = stop_idx.second;
159 stop_idx.second = history.GetSize() - 1;
160 } else {
161 start_idx.second = 0;
162 stop_idx.second = history.GetSize() - 1;
163 }
164 } else {
165 if (!start_idx.first && !stop_idx.first && !count.first) {
166 start_idx.second = 0;
167 stop_idx.second = history.GetSize() - 1;
168 } else if (start_idx.first) {
169 if (count.first) {
170 stop_idx.second = start_idx.second + count.second - 1;
171 } else if (!stop_idx.first) {
172 stop_idx.second = history.GetSize() - 1;
173 }
174 } else if (stop_idx.first) {
175 if (count.first) {
176 if (stop_idx.second >= count.second)
177 start_idx.second = stop_idx.second - count.second + 1;
178 else
179 start_idx.second = 0;
180 }
181 } else /* if (count.first) */
182 {
183 start_idx.second = 0;
184 stop_idx.second = count.second - 1;
185 }
186 }
187 history.Dump(stream&: result.GetOutputStream(), start_idx: start_idx.second,
188 stop_idx: stop_idx.second);
189 }
190 }
191 }
192
193 CommandOptions m_options;
194};
195
196CommandObjectSession::CommandObjectSession(CommandInterpreter &interpreter)
197 : CommandObjectMultiword(interpreter, "session",
198 "Commands controlling LLDB session.",
199 "session <subcommand> [<command-options>]") {
200 LoadSubCommand(cmd_name: "save",
201 command_obj: CommandObjectSP(new CommandObjectSessionSave(interpreter)));
202 LoadSubCommand(cmd_name: "history",
203 command_obj: CommandObjectSP(new CommandObjectSessionHistory(interpreter)));
204}
205

source code of lldb/source/Commands/CommandObjectSession.cpp