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