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