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