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