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