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