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