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