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(arg_type: eArgTypePath, repetition_type: 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, output_file: 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(value: option_arg, op: 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(value: option_arg, |
84 | op: eVarSetOperationAssign); |
85 | break; |
86 | case 'e': |
87 | error = |
88 | m_stop_idx.SetValueFromString(value: option_arg, op: 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(in_string: "--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(stream&: result.GetOutputStream(), start_idx: start_idx.second, |
179 | stop_idx: 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(cmd_name: "save" , |
192 | command_obj: CommandObjectSP(new CommandObjectSessionSave(interpreter))); |
193 | LoadSubCommand(cmd_name: "history" , |
194 | command_obj: CommandObjectSP(new CommandObjectSessionHistory(interpreter))); |
195 | } |
196 | |