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