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