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