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