15bb742b1SMed Ismail Bennani #include "CommandObjectSession.h"
285fbb08fSMed Ismail Bennani #include "lldb/Host/OptionParser.h"
35bb742b1SMed Ismail Bennani #include "lldb/Interpreter/CommandInterpreter.h"
4*7ced9fffSJonas Devlieghere #include "lldb/Interpreter/CommandOptionArgumentTable.h"
55bb742b1SMed Ismail Bennani #include "lldb/Interpreter/CommandReturnObject.h"
685fbb08fSMed Ismail Bennani #include "lldb/Interpreter/OptionArgParser.h"
785fbb08fSMed Ismail Bennani #include "lldb/Interpreter/OptionValue.h"
885fbb08fSMed Ismail Bennani #include "lldb/Interpreter/OptionValueBoolean.h"
985fbb08fSMed Ismail Bennani #include "lldb/Interpreter/OptionValueString.h"
1085fbb08fSMed Ismail Bennani #include "lldb/Interpreter/OptionValueUInt64.h"
1185fbb08fSMed Ismail Bennani #include "lldb/Interpreter/Options.h"
125bb742b1SMed Ismail Bennani 
135bb742b1SMed Ismail Bennani using namespace lldb;
145bb742b1SMed Ismail Bennani using namespace lldb_private;
155bb742b1SMed Ismail Bennani 
165bb742b1SMed Ismail Bennani class CommandObjectSessionSave : public CommandObjectParsed {
175bb742b1SMed Ismail Bennani public:
CommandObjectSessionSave(CommandInterpreter & interpreter)185bb742b1SMed Ismail Bennani   CommandObjectSessionSave(CommandInterpreter &interpreter)
195bb742b1SMed Ismail Bennani       : CommandObjectParsed(interpreter, "session save",
205bb742b1SMed Ismail Bennani                             "Save the current session transcripts to a file.\n"
215bb742b1SMed Ismail Bennani                             "If no file if specified, transcripts will be "
225bb742b1SMed Ismail Bennani                             "saved to a temporary file.",
235bb742b1SMed Ismail Bennani                             "session save [file]") {
245bb742b1SMed Ismail Bennani     CommandArgumentEntry arg1;
255bb742b1SMed Ismail Bennani     arg1.emplace_back(eArgTypePath, eArgRepeatOptional);
265bb742b1SMed Ismail Bennani     m_arguments.push_back(arg1);
275bb742b1SMed Ismail Bennani   }
285bb742b1SMed Ismail Bennani 
295bb742b1SMed Ismail Bennani   ~CommandObjectSessionSave() override = default;
305bb742b1SMed Ismail Bennani 
315bb742b1SMed Ismail Bennani   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)325bb742b1SMed Ismail Bennani   HandleArgumentCompletion(CompletionRequest &request,
335bb742b1SMed Ismail Bennani                            OptionElementVector &opt_element_vector) override {
345bb742b1SMed Ismail Bennani     CommandCompletions::InvokeCommonCompletionCallbacks(
355bb742b1SMed Ismail Bennani         GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
365bb742b1SMed Ismail Bennani         request, nullptr);
375bb742b1SMed Ismail Bennani   }
385bb742b1SMed Ismail Bennani 
395bb742b1SMed Ismail Bennani protected:
DoExecute(Args & args,CommandReturnObject & result)405bb742b1SMed Ismail Bennani   bool DoExecute(Args &args, CommandReturnObject &result) override {
415bb742b1SMed Ismail Bennani     llvm::StringRef file_path;
425bb742b1SMed Ismail Bennani 
435bb742b1SMed Ismail Bennani     if (!args.empty())
445bb742b1SMed Ismail Bennani       file_path = args[0].ref();
455bb742b1SMed Ismail Bennani 
465bb742b1SMed Ismail Bennani     if (m_interpreter.SaveTranscript(result, file_path.str()))
475bb742b1SMed Ismail Bennani       result.SetStatus(eReturnStatusSuccessFinishNoResult);
485bb742b1SMed Ismail Bennani     else
495bb742b1SMed Ismail Bennani       result.SetStatus(eReturnStatusFailed);
505bb742b1SMed Ismail Bennani     return result.Succeeded();
515bb742b1SMed Ismail Bennani   }
525bb742b1SMed Ismail Bennani };
535bb742b1SMed Ismail Bennani 
5485fbb08fSMed Ismail Bennani #define LLDB_OPTIONS_history
5585fbb08fSMed Ismail Bennani #include "CommandOptions.inc"
5685fbb08fSMed Ismail Bennani 
5785fbb08fSMed Ismail Bennani class CommandObjectSessionHistory : public CommandObjectParsed {
5885fbb08fSMed Ismail Bennani public:
CommandObjectSessionHistory(CommandInterpreter & interpreter)5985fbb08fSMed Ismail Bennani   CommandObjectSessionHistory(CommandInterpreter &interpreter)
6085fbb08fSMed Ismail Bennani       : CommandObjectParsed(interpreter, "session history",
6185fbb08fSMed Ismail Bennani                             "Dump the history of commands in this session.\n"
6285fbb08fSMed Ismail Bennani                             "Commands in the history list can be run again "
6385fbb08fSMed Ismail Bennani                             "using \"!<INDEX>\".   \"!-<OFFSET>\" will re-run "
6485fbb08fSMed Ismail Bennani                             "the command that is <OFFSET> commands from the end"
6585fbb08fSMed Ismail Bennani                             " of the list (counting the current command).",
66abb0ed44SKazu Hirata                             nullptr) {}
6785fbb08fSMed Ismail Bennani 
6885fbb08fSMed Ismail Bennani   ~CommandObjectSessionHistory() override = default;
6985fbb08fSMed Ismail Bennani 
GetOptions()7085fbb08fSMed Ismail Bennani   Options *GetOptions() override { return &m_options; }
7185fbb08fSMed Ismail Bennani 
7285fbb08fSMed Ismail Bennani protected:
7385fbb08fSMed Ismail Bennani   class CommandOptions : public Options {
7485fbb08fSMed Ismail Bennani   public:
CommandOptions()7585fbb08fSMed Ismail Bennani     CommandOptions()
76abb0ed44SKazu Hirata         : m_start_idx(0), m_stop_idx(0), m_count(0), m_clear(false) {}
7785fbb08fSMed Ismail Bennani 
7885fbb08fSMed Ismail Bennani     ~CommandOptions() override = default;
7985fbb08fSMed Ismail Bennani 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)8085fbb08fSMed Ismail Bennani     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
8185fbb08fSMed Ismail Bennani                           ExecutionContext *execution_context) override {
8285fbb08fSMed Ismail Bennani       Status error;
8385fbb08fSMed Ismail Bennani       const int short_option = m_getopt_table[option_idx].val;
8485fbb08fSMed Ismail Bennani 
8585fbb08fSMed Ismail Bennani       switch (short_option) {
8685fbb08fSMed Ismail Bennani       case 'c':
8785fbb08fSMed Ismail Bennani         error = m_count.SetValueFromString(option_arg, eVarSetOperationAssign);
8885fbb08fSMed Ismail Bennani         break;
8985fbb08fSMed Ismail Bennani       case 's':
9085fbb08fSMed Ismail Bennani         if (option_arg == "end") {
9185fbb08fSMed Ismail Bennani           m_start_idx.SetCurrentValue(UINT64_MAX);
9285fbb08fSMed Ismail Bennani           m_start_idx.SetOptionWasSet();
9385fbb08fSMed Ismail Bennani         } else
9485fbb08fSMed Ismail Bennani           error = m_start_idx.SetValueFromString(option_arg,
9585fbb08fSMed Ismail Bennani                                                  eVarSetOperationAssign);
9685fbb08fSMed Ismail Bennani         break;
9785fbb08fSMed Ismail Bennani       case 'e':
9885fbb08fSMed Ismail Bennani         error =
9985fbb08fSMed Ismail Bennani             m_stop_idx.SetValueFromString(option_arg, eVarSetOperationAssign);
10085fbb08fSMed Ismail Bennani         break;
10185fbb08fSMed Ismail Bennani       case 'C':
10285fbb08fSMed Ismail Bennani         m_clear.SetCurrentValue(true);
10385fbb08fSMed Ismail Bennani         m_clear.SetOptionWasSet();
10485fbb08fSMed Ismail Bennani         break;
10585fbb08fSMed Ismail Bennani       default:
10685fbb08fSMed Ismail Bennani         llvm_unreachable("Unimplemented option");
10785fbb08fSMed Ismail Bennani       }
10885fbb08fSMed Ismail Bennani 
10985fbb08fSMed Ismail Bennani       return error;
11085fbb08fSMed Ismail Bennani     }
11185fbb08fSMed Ismail Bennani 
OptionParsingStarting(ExecutionContext * execution_context)11285fbb08fSMed Ismail Bennani     void OptionParsingStarting(ExecutionContext *execution_context) override {
11385fbb08fSMed Ismail Bennani       m_start_idx.Clear();
11485fbb08fSMed Ismail Bennani       m_stop_idx.Clear();
11585fbb08fSMed Ismail Bennani       m_count.Clear();
11685fbb08fSMed Ismail Bennani       m_clear.Clear();
11785fbb08fSMed Ismail Bennani     }
11885fbb08fSMed Ismail Bennani 
GetDefinitions()11985fbb08fSMed Ismail Bennani     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
12085fbb08fSMed Ismail Bennani       return llvm::makeArrayRef(g_history_options);
12185fbb08fSMed Ismail Bennani     }
12285fbb08fSMed Ismail Bennani 
12385fbb08fSMed Ismail Bennani     // Instance variables to hold the values for command options.
12485fbb08fSMed Ismail Bennani 
12585fbb08fSMed Ismail Bennani     OptionValueUInt64 m_start_idx;
12685fbb08fSMed Ismail Bennani     OptionValueUInt64 m_stop_idx;
12785fbb08fSMed Ismail Bennani     OptionValueUInt64 m_count;
12885fbb08fSMed Ismail Bennani     OptionValueBoolean m_clear;
12985fbb08fSMed Ismail Bennani   };
13085fbb08fSMed Ismail Bennani 
DoExecute(Args & command,CommandReturnObject & result)13185fbb08fSMed Ismail Bennani   bool DoExecute(Args &command, CommandReturnObject &result) override {
13285fbb08fSMed Ismail Bennani     if (m_options.m_clear.GetCurrentValue() &&
13385fbb08fSMed Ismail Bennani         m_options.m_clear.OptionWasSet()) {
13485fbb08fSMed Ismail Bennani       m_interpreter.GetCommandHistory().Clear();
13585fbb08fSMed Ismail Bennani       result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
13685fbb08fSMed Ismail Bennani     } else {
13785fbb08fSMed Ismail Bennani       if (m_options.m_start_idx.OptionWasSet() &&
13885fbb08fSMed Ismail Bennani           m_options.m_stop_idx.OptionWasSet() &&
13985fbb08fSMed Ismail Bennani           m_options.m_count.OptionWasSet()) {
14085fbb08fSMed Ismail Bennani         result.AppendError("--count, --start-index and --end-index cannot be "
14185fbb08fSMed Ismail Bennani                            "all specified in the same invocation");
14285fbb08fSMed Ismail Bennani         result.SetStatus(lldb::eReturnStatusFailed);
14385fbb08fSMed Ismail Bennani       } else {
14485fbb08fSMed Ismail Bennani         std::pair<bool, uint64_t> start_idx(
14585fbb08fSMed Ismail Bennani             m_options.m_start_idx.OptionWasSet(),
14685fbb08fSMed Ismail Bennani             m_options.m_start_idx.GetCurrentValue());
14785fbb08fSMed Ismail Bennani         std::pair<bool, uint64_t> stop_idx(
14885fbb08fSMed Ismail Bennani             m_options.m_stop_idx.OptionWasSet(),
14985fbb08fSMed Ismail Bennani             m_options.m_stop_idx.GetCurrentValue());
15085fbb08fSMed Ismail Bennani         std::pair<bool, uint64_t> count(m_options.m_count.OptionWasSet(),
15185fbb08fSMed Ismail Bennani                                         m_options.m_count.GetCurrentValue());
15285fbb08fSMed Ismail Bennani 
15385fbb08fSMed Ismail Bennani         const CommandHistory &history(m_interpreter.GetCommandHistory());
15485fbb08fSMed Ismail Bennani 
15585fbb08fSMed Ismail Bennani         if (start_idx.first && start_idx.second == UINT64_MAX) {
15685fbb08fSMed Ismail Bennani           if (count.first) {
15785fbb08fSMed Ismail Bennani             start_idx.second = history.GetSize() - count.second;
15885fbb08fSMed Ismail Bennani             stop_idx.second = history.GetSize() - 1;
15985fbb08fSMed Ismail Bennani           } else if (stop_idx.first) {
16085fbb08fSMed Ismail Bennani             start_idx.second = stop_idx.second;
16185fbb08fSMed Ismail Bennani             stop_idx.second = history.GetSize() - 1;
16285fbb08fSMed Ismail Bennani           } else {
16385fbb08fSMed Ismail Bennani             start_idx.second = 0;
16485fbb08fSMed Ismail Bennani             stop_idx.second = history.GetSize() - 1;
16585fbb08fSMed Ismail Bennani           }
16685fbb08fSMed Ismail Bennani         } else {
16785fbb08fSMed Ismail Bennani           if (!start_idx.first && !stop_idx.first && !count.first) {
16885fbb08fSMed Ismail Bennani             start_idx.second = 0;
16985fbb08fSMed Ismail Bennani             stop_idx.second = history.GetSize() - 1;
17085fbb08fSMed Ismail Bennani           } else if (start_idx.first) {
17185fbb08fSMed Ismail Bennani             if (count.first) {
17285fbb08fSMed Ismail Bennani               stop_idx.second = start_idx.second + count.second - 1;
17385fbb08fSMed Ismail Bennani             } else if (!stop_idx.first) {
17485fbb08fSMed Ismail Bennani               stop_idx.second = history.GetSize() - 1;
17585fbb08fSMed Ismail Bennani             }
17685fbb08fSMed Ismail Bennani           } else if (stop_idx.first) {
17785fbb08fSMed Ismail Bennani             if (count.first) {
17885fbb08fSMed Ismail Bennani               if (stop_idx.second >= count.second)
17985fbb08fSMed Ismail Bennani                 start_idx.second = stop_idx.second - count.second + 1;
18085fbb08fSMed Ismail Bennani               else
18185fbb08fSMed Ismail Bennani                 start_idx.second = 0;
18285fbb08fSMed Ismail Bennani             }
18385fbb08fSMed Ismail Bennani           } else /* if (count.first) */
18485fbb08fSMed Ismail Bennani           {
18585fbb08fSMed Ismail Bennani             start_idx.second = 0;
18685fbb08fSMed Ismail Bennani             stop_idx.second = count.second - 1;
18785fbb08fSMed Ismail Bennani           }
18885fbb08fSMed Ismail Bennani         }
18985fbb08fSMed Ismail Bennani         history.Dump(result.GetOutputStream(), start_idx.second,
19085fbb08fSMed Ismail Bennani                      stop_idx.second);
19185fbb08fSMed Ismail Bennani       }
19285fbb08fSMed Ismail Bennani     }
19385fbb08fSMed Ismail Bennani     return result.Succeeded();
19485fbb08fSMed Ismail Bennani   }
19585fbb08fSMed Ismail Bennani 
19685fbb08fSMed Ismail Bennani   CommandOptions m_options;
19785fbb08fSMed Ismail Bennani };
19885fbb08fSMed Ismail Bennani 
CommandObjectSession(CommandInterpreter & interpreter)1995bb742b1SMed Ismail Bennani CommandObjectSession::CommandObjectSession(CommandInterpreter &interpreter)
2005bb742b1SMed Ismail Bennani     : CommandObjectMultiword(interpreter, "session",
2015bb742b1SMed Ismail Bennani                              "Commands controlling LLDB session.",
2025bb742b1SMed Ismail Bennani                              "session <subcommand> [<command-options>]") {
2035bb742b1SMed Ismail Bennani   LoadSubCommand("save",
2045bb742b1SMed Ismail Bennani                  CommandObjectSP(new CommandObjectSessionSave(interpreter)));
20585fbb08fSMed Ismail Bennani   LoadSubCommand("history",
20685fbb08fSMed Ismail Bennani                  CommandObjectSP(new CommandObjectSessionHistory(interpreter)));
2075bb742b1SMed Ismail Bennani }
208