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