/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/include/lldb/Interpreter/CommandInterpreter.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- CommandInterpreter.h ------------------------------------*- C++ -*-===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #ifndef LLDB_INTERPRETER_COMMANDINTERPRETER_H |
10 | | #define LLDB_INTERPRETER_COMMANDINTERPRETER_H |
11 | | |
12 | | #include "lldb/Core/Debugger.h" |
13 | | #include "lldb/Core/IOHandler.h" |
14 | | #include "lldb/Interpreter/CommandAlias.h" |
15 | | #include "lldb/Interpreter/CommandHistory.h" |
16 | | #include "lldb/Interpreter/CommandObject.h" |
17 | | #include "lldb/Interpreter/ScriptInterpreter.h" |
18 | | #include "lldb/Utility/Args.h" |
19 | | #include "lldb/Utility/Broadcaster.h" |
20 | | #include "lldb/Utility/CompletionRequest.h" |
21 | | #include "lldb/Utility/Event.h" |
22 | | #include "lldb/Utility/Log.h" |
23 | | #include "lldb/Utility/StreamString.h" |
24 | | #include "lldb/Utility/StringList.h" |
25 | | #include "lldb/lldb-forward.h" |
26 | | #include "lldb/lldb-private.h" |
27 | | |
28 | | #include <mutex> |
29 | | #include <optional> |
30 | | #include <stack> |
31 | | |
32 | | namespace lldb_private { |
33 | | class CommandInterpreter; |
34 | | |
35 | | class CommandInterpreterRunResult { |
36 | | public: |
37 | 6.58k | CommandInterpreterRunResult() = default; |
38 | | |
39 | 14 | uint32_t GetNumErrors() const { return m_num_errors; } |
40 | | |
41 | 930 | lldb::CommandInterpreterResult GetResult() const { return m_result; } |
42 | | |
43 | 7.21k | bool IsResult(lldb::CommandInterpreterResult result) { |
44 | 7.21k | return m_result == result; |
45 | 7.21k | } |
46 | | |
47 | | protected: |
48 | | friend CommandInterpreter; |
49 | | |
50 | 87 | void IncrementNumberOfErrors() { m_num_errors++; } |
51 | | |
52 | 158 | void SetResult(lldb::CommandInterpreterResult result) { m_result = result; } |
53 | | |
54 | | private: |
55 | | int m_num_errors = 0; |
56 | | lldb::CommandInterpreterResult m_result = |
57 | | lldb::eCommandInterpreterResultSuccess; |
58 | | }; |
59 | | |
60 | | class CommandInterpreterRunOptions { |
61 | | public: |
62 | | /// Construct a CommandInterpreterRunOptions object. This class is used to |
63 | | /// control all the instances where we run multiple commands, e.g. |
64 | | /// HandleCommands, HandleCommandsFromFile, RunCommandInterpreter. |
65 | | /// |
66 | | /// The meanings of the options in this object are: |
67 | | /// |
68 | | /// \param[in] stop_on_continue |
69 | | /// If \b true, execution will end on the first command that causes the |
70 | | /// process in the execution context to continue. If \b false, we won't |
71 | | /// check the execution status. |
72 | | /// \param[in] stop_on_error |
73 | | /// If \b true, execution will end on the first command that causes an |
74 | | /// error. |
75 | | /// \param[in] stop_on_crash |
76 | | /// If \b true, when a command causes the target to run, and the end of the |
77 | | /// run is a signal or exception, stop executing the commands. |
78 | | /// \param[in] echo_commands |
79 | | /// If \b true, echo the command before executing it. If \b false, execute |
80 | | /// silently. |
81 | | /// \param[in] echo_comments |
82 | | /// If \b true, echo command even if it is a pure comment line. If |
83 | | /// \b false, print no ouput in this case. This setting has an effect only |
84 | | /// if echo_commands is \b true. |
85 | | /// \param[in] print_results |
86 | | /// If \b true and the command succeeds, print the results of the command |
87 | | /// after executing it. If \b false, execute silently. |
88 | | /// \param[in] print_errors |
89 | | /// If \b true and the command fails, print the results of the command |
90 | | /// after executing it. If \b false, execute silently. |
91 | | /// \param[in] add_to_history |
92 | | /// If \b true add the commands to the command history. If \b false, don't |
93 | | /// add them. |
94 | | CommandInterpreterRunOptions(LazyBool stop_on_continue, |
95 | | LazyBool stop_on_error, LazyBool stop_on_crash, |
96 | | LazyBool echo_commands, LazyBool echo_comments, |
97 | | LazyBool print_results, LazyBool print_errors, |
98 | | LazyBool add_to_history) |
99 | | : m_stop_on_continue(stop_on_continue), m_stop_on_error(stop_on_error), |
100 | | m_stop_on_crash(stop_on_crash), m_echo_commands(echo_commands), |
101 | | m_echo_comment_commands(echo_comments), m_print_results(print_results), |
102 | 0 | m_print_errors(print_errors), m_add_to_history(add_to_history) {} |
103 | | |
104 | 1.44k | CommandInterpreterRunOptions() = default; |
105 | | |
106 | 376 | void SetSilent(bool silent) { |
107 | 376 | LazyBool value = silent ? eLazyBoolNo : eLazyBoolYes0 ; |
108 | | |
109 | 376 | m_print_results = value; |
110 | 376 | m_print_errors = value; |
111 | 376 | m_echo_commands = value; |
112 | 376 | m_echo_comment_commands = value; |
113 | 376 | m_add_to_history = value; |
114 | 376 | } |
115 | | // These return the default behaviors if the behavior is not |
116 | | // eLazyBoolCalculate. But I've also left the ivars public since for |
117 | | // different ways of running the interpreter you might want to force |
118 | | // different defaults... In that case, just grab the LazyBool ivars directly |
119 | | // and do what you want with eLazyBoolCalculate. |
120 | 21 | bool GetStopOnContinue() const { return DefaultToNo(m_stop_on_continue); } |
121 | | |
122 | 20 | void SetStopOnContinue(bool stop_on_continue) { |
123 | 20 | m_stop_on_continue = stop_on_continue ? eLazyBoolYes : eLazyBoolNo0 ; |
124 | 20 | } |
125 | | |
126 | 3 | bool GetStopOnError() const { return DefaultToNo(m_stop_on_error); } |
127 | | |
128 | 417 | void SetStopOnError(bool stop_on_error) { |
129 | 417 | m_stop_on_error = stop_on_error ? eLazyBoolYes411 : eLazyBoolNo6 ; |
130 | 417 | } |
131 | | |
132 | 901 | bool GetStopOnCrash() const { return DefaultToNo(m_stop_on_crash); } |
133 | | |
134 | 391 | void SetStopOnCrash(bool stop_on_crash) { |
135 | 391 | m_stop_on_crash = stop_on_crash ? eLazyBoolYes187 : eLazyBoolNo204 ; |
136 | 391 | } |
137 | | |
138 | 21 | bool GetEchoCommands() const { return DefaultToYes(m_echo_commands); } |
139 | | |
140 | 922 | void SetEchoCommands(bool echo_commands) { |
141 | 922 | m_echo_commands = echo_commands ? eLazyBoolYes895 : eLazyBoolNo27 ; |
142 | 922 | } |
143 | | |
144 | 0 | bool GetEchoCommentCommands() const { |
145 | 0 | return DefaultToYes(m_echo_comment_commands); |
146 | 0 | } |
147 | | |
148 | 504 | void SetEchoCommentCommands(bool echo_comments) { |
149 | 504 | m_echo_comment_commands = echo_comments ? eLazyBoolYes371 : eLazyBoolNo133 ; |
150 | 504 | } |
151 | | |
152 | 21 | bool GetPrintResults() const { return DefaultToYes(m_print_results); } |
153 | | |
154 | 532 | void SetPrintResults(bool print_results) { |
155 | 532 | m_print_results = print_results ? eLazyBoolYes531 : eLazyBoolNo1 ; |
156 | 532 | } |
157 | | |
158 | 3 | bool GetPrintErrors() const { return DefaultToYes(m_print_errors); } |
159 | | |
160 | 528 | void SetPrintErrors(bool print_errors) { |
161 | 528 | m_print_errors = print_errors ? eLazyBoolYes527 : eLazyBoolNo1 ; |
162 | 528 | } |
163 | | |
164 | 39 | bool GetAddToHistory() const { return DefaultToYes(m_add_to_history); } |
165 | | |
166 | 23 | void SetAddToHistory(bool add_to_history) { |
167 | 23 | m_add_to_history = add_to_history ? eLazyBoolYes0 : eLazyBoolNo; |
168 | 23 | } |
169 | | |
170 | 1.06k | bool GetAutoHandleEvents() const { |
171 | 1.06k | return DefaultToYes(m_auto_handle_events); |
172 | 1.06k | } |
173 | | |
174 | 529 | void SetAutoHandleEvents(bool auto_handle_events) { |
175 | 529 | m_auto_handle_events = auto_handle_events ? eLazyBoolYes528 : eLazyBoolNo1 ; |
176 | 529 | } |
177 | | |
178 | 531 | bool GetSpawnThread() const { return DefaultToNo(m_spawn_thread); } |
179 | | |
180 | 529 | void SetSpawnThread(bool spawn_thread) { |
181 | 529 | m_spawn_thread = spawn_thread ? eLazyBoolYes2 : eLazyBoolNo527 ; |
182 | 529 | } |
183 | | |
184 | | LazyBool m_stop_on_continue = eLazyBoolCalculate; |
185 | | LazyBool m_stop_on_error = eLazyBoolCalculate; |
186 | | LazyBool m_stop_on_crash = eLazyBoolCalculate; |
187 | | LazyBool m_echo_commands = eLazyBoolCalculate; |
188 | | LazyBool m_echo_comment_commands = eLazyBoolCalculate; |
189 | | LazyBool m_print_results = eLazyBoolCalculate; |
190 | | LazyBool m_print_errors = eLazyBoolCalculate; |
191 | | LazyBool m_add_to_history = eLazyBoolCalculate; |
192 | | LazyBool m_auto_handle_events; |
193 | | LazyBool m_spawn_thread; |
194 | | |
195 | | private: |
196 | 1.14k | static bool DefaultToYes(LazyBool flag) { |
197 | 1.14k | switch (flag) { |
198 | 54 | case eLazyBoolNo: |
199 | 54 | return false; |
200 | 1.09k | default: |
201 | 1.09k | return true; |
202 | 1.14k | } |
203 | 1.14k | } |
204 | | |
205 | 1.45k | static bool DefaultToNo(LazyBool flag) { |
206 | 1.45k | switch (flag) { |
207 | 23 | case eLazyBoolYes: |
208 | 23 | return true; |
209 | 1.43k | default: |
210 | 1.43k | return false; |
211 | 1.45k | } |
212 | 1.45k | } |
213 | | }; |
214 | | |
215 | | class CommandInterpreter : public Broadcaster, |
216 | | public Properties, |
217 | | public IOHandlerDelegate { |
218 | | public: |
219 | | enum { |
220 | | eBroadcastBitThreadShouldExit = (1 << 0), |
221 | | eBroadcastBitResetPrompt = (1 << 1), |
222 | | eBroadcastBitQuitCommandReceived = (1 << 2), // User entered quit |
223 | | eBroadcastBitAsynchronousOutputData = (1 << 3), |
224 | | eBroadcastBitAsynchronousErrorData = (1 << 4) |
225 | | }; |
226 | | |
227 | | /// Tristate boolean to manage children omission warnings. |
228 | | enum ChildrenOmissionWarningStatus { |
229 | | eNoOmission = 0, ///< No children were omitted. |
230 | | eUnwarnedOmission = 1, ///< Children omitted, and not yet notified. |
231 | | eWarnedOmission = 2 ///< Children omitted and notified. |
232 | | }; |
233 | | |
234 | | enum CommandTypes { |
235 | | eCommandTypesBuiltin = 0x0001, //< native commands such as "frame" |
236 | | eCommandTypesUserDef = 0x0002, //< scripted commands |
237 | | eCommandTypesUserMW = 0x0004, //< multiword commands (command containers) |
238 | | eCommandTypesAliases = 0x0008, //< aliases such as "po" |
239 | | eCommandTypesHidden = 0x0010, //< commands prefixed with an underscore |
240 | | eCommandTypesAllThem = 0xFFFF //< all commands |
241 | | }; |
242 | | |
243 | | // The CommandAlias and CommandInterpreter both have a hand in |
244 | | // substituting for alias commands. They work by writing special tokens |
245 | | // in the template form of the Alias command, and then detecting them when the |
246 | | // command is executed. These are the special tokens: |
247 | | static const char *g_no_argument; |
248 | | static const char *g_need_argument; |
249 | | static const char *g_argument; |
250 | | |
251 | | CommandInterpreter(Debugger &debugger, bool synchronous_execution); |
252 | | |
253 | 6.05k | ~CommandInterpreter() override = default; |
254 | | |
255 | | // These two functions fill out the Broadcaster interface: |
256 | | |
257 | | static ConstString &GetStaticBroadcasterClass(); |
258 | | |
259 | 530 | ConstString &GetBroadcasterClass() const override { |
260 | 530 | return GetStaticBroadcasterClass(); |
261 | 530 | } |
262 | | |
263 | | void SourceInitFileCwd(CommandReturnObject &result); |
264 | | void SourceInitFileHome(CommandReturnObject &result, bool is_repl); |
265 | | void SourceInitFileGlobal(CommandReturnObject &result); |
266 | | |
267 | | bool AddCommand(llvm::StringRef name, const lldb::CommandObjectSP &cmd_sp, |
268 | | bool can_replace); |
269 | | |
270 | | Status AddUserCommand(llvm::StringRef name, |
271 | | const lldb::CommandObjectSP &cmd_sp, bool can_replace); |
272 | | |
273 | | lldb::CommandObjectSP GetCommandSPExact(llvm::StringRef cmd, |
274 | | bool include_aliases = false) const; |
275 | | |
276 | | CommandObject *GetCommandObject(llvm::StringRef cmd, |
277 | | StringList *matches = nullptr, |
278 | | StringList *descriptions = nullptr) const; |
279 | | |
280 | | CommandObject *GetUserCommandObject(llvm::StringRef cmd, |
281 | | StringList *matches = nullptr, |
282 | | StringList *descriptions = nullptr) const; |
283 | | |
284 | | /// Determine whether a root level, built-in command with this name exists. |
285 | | bool CommandExists(llvm::StringRef cmd) const; |
286 | | |
287 | | /// Determine whether an alias command with this name exists |
288 | | bool AliasExists(llvm::StringRef cmd) const; |
289 | | |
290 | | /// Determine whether a root-level user command with this name exists. |
291 | | bool UserCommandExists(llvm::StringRef cmd) const; |
292 | | |
293 | | /// Determine whether a root-level user multiword command with this name |
294 | | /// exists. |
295 | | bool UserMultiwordCommandExists(llvm::StringRef cmd) const; |
296 | | |
297 | | /// Look up the command pointed to by path encoded in the arguments of |
298 | | /// the incoming command object. If all the path components exist |
299 | | /// and are all actual commands - not aliases, and the leaf command is a |
300 | | /// multiword command, return the command. Otherwise return nullptr, and put |
301 | | /// a useful diagnostic in the Status object. |
302 | | /// |
303 | | /// \param[in] path |
304 | | /// An Args object holding the path in its arguments |
305 | | /// \param[in] leaf_is_command |
306 | | /// If true, return the container of the leaf name rather than looking up |
307 | | /// the whole path as a leaf command. The leaf needn't exist in this case. |
308 | | /// \param[in,out] result |
309 | | /// If the path is not found, this error shows where we got off track. |
310 | | /// \return |
311 | | /// If found, a pointer to the CommandObjectMultiword pointed to by path, |
312 | | /// or to the container of the leaf element is is_leaf_command. |
313 | | /// Returns nullptr under two circumstances: |
314 | | /// 1) The command in not found (check error.Fail) |
315 | | /// 2) is_leaf is true and the path has only a leaf. We don't have a |
316 | | /// dummy "contains everything MWC, so we return null here, but |
317 | | /// in this case error.Success is true. |
318 | | |
319 | | CommandObjectMultiword *VerifyUserMultiwordCmdPath(Args &path, |
320 | | bool leaf_is_command, |
321 | | Status &result); |
322 | | |
323 | | CommandAlias *AddAlias(llvm::StringRef alias_name, |
324 | | lldb::CommandObjectSP &command_obj_sp, |
325 | | llvm::StringRef args_string = llvm::StringRef()); |
326 | | |
327 | | /// Remove a command if it is removable (python or regex command). If \b force |
328 | | /// is provided, the command is removed regardless of its removable status. |
329 | | bool RemoveCommand(llvm::StringRef cmd, bool force = false); |
330 | | |
331 | | bool RemoveAlias(llvm::StringRef alias_name); |
332 | | |
333 | | bool GetAliasFullName(llvm::StringRef cmd, std::string &full_name) const; |
334 | | |
335 | | bool RemoveUserMultiword(llvm::StringRef multiword_name); |
336 | | |
337 | | // Do we want to allow top-level user multiword commands to be deleted? |
338 | 0 | void RemoveAllUserMultiword() { m_user_mw_dict.clear(); } |
339 | | |
340 | | bool RemoveUser(llvm::StringRef alias_name); |
341 | | |
342 | 2 | void RemoveAllUser() { m_user_dict.clear(); } |
343 | | |
344 | | const CommandAlias *GetAlias(llvm::StringRef alias_name) const; |
345 | | |
346 | | CommandObject *BuildAliasResult(llvm::StringRef alias_name, |
347 | | std::string &raw_input_string, |
348 | | std::string &alias_result, |
349 | | CommandReturnObject &result); |
350 | | |
351 | | bool HandleCommand(const char *command_line, LazyBool add_to_history, |
352 | | const ExecutionContext &override_context, |
353 | | CommandReturnObject &result); |
354 | | |
355 | | bool HandleCommand(const char *command_line, LazyBool add_to_history, |
356 | | CommandReturnObject &result, |
357 | | bool force_repeat_command = false); |
358 | | |
359 | | bool InterruptCommand(); |
360 | | |
361 | | /// Execute a list of commands in sequence. |
362 | | /// |
363 | | /// \param[in] commands |
364 | | /// The list of commands to execute. |
365 | | /// \param[in,out] context |
366 | | /// The execution context in which to run the commands. |
367 | | /// \param[in] options |
368 | | /// This object holds the options used to control when to stop, whether to |
369 | | /// execute commands, |
370 | | /// etc. |
371 | | /// \param[out] result |
372 | | /// This is marked as succeeding with no output if all commands execute |
373 | | /// safely, |
374 | | /// and failed with some explanation if we aborted executing the commands |
375 | | /// at some point. |
376 | | void HandleCommands(const StringList &commands, |
377 | | const ExecutionContext &context, |
378 | | const CommandInterpreterRunOptions &options, |
379 | | CommandReturnObject &result); |
380 | | |
381 | | void HandleCommands(const StringList &commands, |
382 | | const CommandInterpreterRunOptions &options, |
383 | | CommandReturnObject &result); |
384 | | |
385 | | /// Execute a list of commands from a file. |
386 | | /// |
387 | | /// \param[in] file |
388 | | /// The file from which to read in commands. |
389 | | /// \param[in,out] context |
390 | | /// The execution context in which to run the commands. |
391 | | /// \param[in] options |
392 | | /// This object holds the options used to control when to stop, whether to |
393 | | /// execute commands, |
394 | | /// etc. |
395 | | /// \param[out] result |
396 | | /// This is marked as succeeding with no output if all commands execute |
397 | | /// safely, |
398 | | /// and failed with some explanation if we aborted executing the commands |
399 | | /// at some point. |
400 | | void HandleCommandsFromFile(FileSpec &file, const ExecutionContext &context, |
401 | | const CommandInterpreterRunOptions &options, |
402 | | CommandReturnObject &result); |
403 | | |
404 | | void HandleCommandsFromFile(FileSpec &file, |
405 | | const CommandInterpreterRunOptions &options, |
406 | | CommandReturnObject &result); |
407 | | |
408 | | CommandObject *GetCommandObjectForCommand(llvm::StringRef &command_line); |
409 | | |
410 | | /// Returns the auto-suggestion string that should be added to the given |
411 | | /// command line. |
412 | | std::optional<std::string> GetAutoSuggestionForCommand(llvm::StringRef line); |
413 | | |
414 | | // This handles command line completion. |
415 | | void HandleCompletion(CompletionRequest &request); |
416 | | |
417 | | // This version just returns matches, and doesn't compute the substring. It |
418 | | // is here so the Help command can call it for the first argument. |
419 | | void HandleCompletionMatches(CompletionRequest &request); |
420 | | |
421 | | int GetCommandNamesMatchingPartialString(const char *cmd_cstr, |
422 | | bool include_aliases, |
423 | | StringList &matches, |
424 | | StringList &descriptions); |
425 | | |
426 | | void GetHelp(CommandReturnObject &result, |
427 | | uint32_t types = eCommandTypesAllThem); |
428 | | |
429 | | void GetAliasHelp(const char *alias_name, StreamString &help_string); |
430 | | |
431 | | void OutputFormattedHelpText(Stream &strm, llvm::StringRef prefix, |
432 | | llvm::StringRef help_text); |
433 | | |
434 | | void OutputFormattedHelpText(Stream &stream, llvm::StringRef command_word, |
435 | | llvm::StringRef separator, |
436 | | llvm::StringRef help_text, size_t max_word_len); |
437 | | |
438 | | // this mimics OutputFormattedHelpText but it does perform a much simpler |
439 | | // formatting, basically ensuring line alignment. This is only good if you |
440 | | // have some complicated layout for your help text and want as little help as |
441 | | // reasonable in properly displaying it. Most of the times, you simply want |
442 | | // to type some text and have it printed in a reasonable way on screen. If |
443 | | // so, use OutputFormattedHelpText |
444 | | void OutputHelpText(Stream &stream, llvm::StringRef command_word, |
445 | | llvm::StringRef separator, llvm::StringRef help_text, |
446 | | uint32_t max_word_len); |
447 | | |
448 | 214k | Debugger &GetDebugger() { return m_debugger; } |
449 | | |
450 | | ExecutionContext GetExecutionContext() const; |
451 | | |
452 | | lldb::PlatformSP GetPlatform(bool prefer_target_platform); |
453 | | |
454 | | const char *ProcessEmbeddedScriptCommands(const char *arg); |
455 | | |
456 | | void UpdatePrompt(llvm::StringRef prompt); |
457 | | |
458 | | bool Confirm(llvm::StringRef message, bool default_answer); |
459 | | |
460 | | void LoadCommandDictionary(); |
461 | | |
462 | | void Initialize(); |
463 | | |
464 | | void Clear(); |
465 | | |
466 | | bool HasCommands() const; |
467 | | |
468 | | bool HasAliases() const; |
469 | | |
470 | | bool HasUserCommands() const; |
471 | | |
472 | | bool HasUserMultiwordCommands() const; |
473 | | |
474 | | bool HasAliasOptions() const; |
475 | | |
476 | | void BuildAliasCommandArgs(CommandObject *alias_cmd_obj, |
477 | | const char *alias_name, Args &cmd_args, |
478 | | std::string &raw_input_string, |
479 | | CommandReturnObject &result); |
480 | | |
481 | | /// Picks the number out of a string of the form "%NNN", otherwise return 0. |
482 | | int GetOptionArgumentPosition(const char *in_string); |
483 | | |
484 | 8.94k | void SkipLLDBInitFiles(bool skip_lldbinit_files) { |
485 | 8.94k | m_skip_lldbinit_files = skip_lldbinit_files; |
486 | 8.94k | } |
487 | | |
488 | 8.94k | void SkipAppInitFiles(bool skip_app_init_files) { |
489 | 8.94k | m_skip_app_init_files = skip_app_init_files; |
490 | 8.94k | } |
491 | | |
492 | | bool GetSynchronous(); |
493 | | |
494 | | void FindCommandsForApropos(llvm::StringRef word, StringList &commands_found, |
495 | | StringList &commands_help, |
496 | | bool search_builtin_commands, |
497 | | bool search_user_commands, |
498 | | bool search_alias_commands, |
499 | | bool search_user_mw_commands); |
500 | | |
501 | 6 | bool GetBatchCommandMode() { return m_batch_command_mode; } |
502 | | |
503 | 2 | bool SetBatchCommandMode(bool value) { |
504 | 2 | const bool old_value = m_batch_command_mode; |
505 | 2 | m_batch_command_mode = value; |
506 | 2 | return old_value; |
507 | 2 | } |
508 | | |
509 | 30 | void ChildrenTruncated() { |
510 | 30 | if (m_truncation_warning == eNoOmission) |
511 | 8 | m_truncation_warning = eUnwarnedOmission; |
512 | 30 | } |
513 | | |
514 | 0 | void SetReachedMaximumDepth() { |
515 | 0 | if (m_max_depth_warning == eNoOmission) |
516 | 0 | m_max_depth_warning = eUnwarnedOmission; |
517 | 0 | } |
518 | | |
519 | 3.95k | void PrintWarningsIfNecessary(Stream &s, const std::string &cmd_name) { |
520 | 3.95k | if (m_truncation_warning == eUnwarnedOmission) { |
521 | 4 | s.Printf("*** Some of the displayed variables have more members than the " |
522 | 4 | "debugger will show by default. To show all of them, you can " |
523 | 4 | "either use the --show-all-children option to %s or raise the " |
524 | 4 | "limit by changing the target.max-children-count setting.\n", |
525 | 4 | cmd_name.c_str()); |
526 | 4 | m_truncation_warning = eWarnedOmission; |
527 | 4 | } |
528 | | |
529 | 3.95k | if (m_max_depth_warning == eUnwarnedOmission) { |
530 | 0 | s.Printf("*** Some of the displayed variables have a greater depth of " |
531 | 0 | "members than the debugger will show by default. To increase " |
532 | 0 | "the limit, use the --depth option to %s, or raise the limit by " |
533 | 0 | "changing the target.max-children-depth setting.\n", |
534 | 0 | cmd_name.c_str()); |
535 | 0 | m_max_depth_warning = eWarnedOmission; |
536 | 0 | } |
537 | 3.95k | } |
538 | | |
539 | 20 | CommandHistory &GetCommandHistory() { return m_command_history; } |
540 | | |
541 | | bool IsActive(); |
542 | | |
543 | | CommandInterpreterRunResult |
544 | | RunCommandInterpreter(CommandInterpreterRunOptions &options); |
545 | | |
546 | | void GetLLDBCommandsFromIOHandler(const char *prompt, |
547 | | IOHandlerDelegate &delegate, |
548 | | void *baton = nullptr); |
549 | | |
550 | | void GetPythonCommandsFromIOHandler(const char *prompt, |
551 | | IOHandlerDelegate &delegate, |
552 | | void *baton = nullptr); |
553 | | |
554 | | const char *GetCommandPrefix(); |
555 | | |
556 | | // Properties |
557 | | bool GetExpandRegexAliases() const; |
558 | | |
559 | | bool GetPromptOnQuit() const; |
560 | | void SetPromptOnQuit(bool enable); |
561 | | |
562 | | bool GetSaveSessionOnQuit() const; |
563 | | void SetSaveSessionOnQuit(bool enable); |
564 | | |
565 | | bool GetOpenTranscriptInEditor() const; |
566 | | void SetOpenTranscriptInEditor(bool enable); |
567 | | |
568 | | FileSpec GetSaveSessionDirectory() const; |
569 | | void SetSaveSessionDirectory(llvm::StringRef path); |
570 | | |
571 | | bool GetEchoCommands() const; |
572 | | void SetEchoCommands(bool enable); |
573 | | |
574 | | bool GetEchoCommentCommands() const; |
575 | | void SetEchoCommentCommands(bool enable); |
576 | | |
577 | | bool GetRepeatPreviousCommand() const; |
578 | | |
579 | | bool GetRequireCommandOverwrite() const; |
580 | | |
581 | 2 | const CommandObject::CommandMap &GetUserCommands() const { |
582 | 2 | return m_user_dict; |
583 | 2 | } |
584 | | |
585 | 2 | const CommandObject::CommandMap &GetUserMultiwordCommands() const { |
586 | 2 | return m_user_mw_dict; |
587 | 2 | } |
588 | | |
589 | 1 | const CommandObject::CommandMap &GetCommands() const { |
590 | 1 | return m_command_dict; |
591 | 1 | } |
592 | | |
593 | 1 | const CommandObject::CommandMap &GetAliases() const { return m_alias_dict; } |
594 | | |
595 | | /// Specify if the command interpreter should allow that the user can |
596 | | /// specify a custom exit code when calling 'quit'. |
597 | | void AllowExitCodeOnQuit(bool allow); |
598 | | |
599 | | /// Sets the exit code for the quit command. |
600 | | /// \param[in] exit_code |
601 | | /// The exit code that the driver should return on exit. |
602 | | /// \return True if the exit code was successfully set; false if the |
603 | | /// interpreter doesn't allow custom exit codes. |
604 | | /// \see AllowExitCodeOnQuit |
605 | | [[nodiscard]] bool SetQuitExitCode(int exit_code); |
606 | | |
607 | | /// Returns the exit code that the user has specified when running the |
608 | | /// 'quit' command. |
609 | | /// \param[out] exited |
610 | | /// Set to true if the user has called quit with a custom exit code. |
611 | | int GetQuitExitCode(bool &exited) const; |
612 | | |
613 | | void ResolveCommand(const char *command_line, CommandReturnObject &result); |
614 | | |
615 | | bool GetStopCmdSourceOnError() const; |
616 | | |
617 | | lldb::IOHandlerSP |
618 | | GetIOHandler(bool force_create = false, |
619 | | CommandInterpreterRunOptions *options = nullptr); |
620 | | |
621 | | bool GetSpaceReplPrompts() const; |
622 | | |
623 | | /// Save the current debugger session transcript to a file on disk. |
624 | | /// \param output_file |
625 | | /// The file path to which the session transcript will be written. Since |
626 | | /// the argument is optional, an arbitrary temporary file will be create |
627 | | /// when no argument is passed. |
628 | | /// \param result |
629 | | /// This is used to pass function output and error messages. |
630 | | /// \return \b true if the session transcript was successfully written to |
631 | | /// disk, \b false otherwise. |
632 | | bool SaveTranscript(CommandReturnObject &result, |
633 | | std::optional<std::string> output_file = std::nullopt); |
634 | | |
635 | | FileSpec GetCurrentSourceDir(); |
636 | | |
637 | | bool IsInteractive(); |
638 | | |
639 | | bool IOHandlerInterrupt(IOHandler &io_handler) override; |
640 | | |
641 | | Status PreprocessCommand(std::string &command); |
642 | | Status PreprocessToken(std::string &token); |
643 | | |
644 | | protected: |
645 | | friend class Debugger; |
646 | | |
647 | | // This checks just the RunCommandInterpreter interruption state. It is only |
648 | | // meant to be used in Debugger::InterruptRequested |
649 | | bool WasInterrupted() const; |
650 | | |
651 | | // IOHandlerDelegate functions |
652 | | void IOHandlerInputComplete(IOHandler &io_handler, |
653 | | std::string &line) override; |
654 | | |
655 | 0 | llvm::StringRef IOHandlerGetControlSequence(char ch) override { |
656 | 0 | static constexpr llvm::StringLiteral control_sequence("quit\n"); |
657 | 0 | if (ch == 'd') |
658 | 0 | return control_sequence; |
659 | 0 | return {}; |
660 | 0 | } |
661 | | |
662 | | void GetProcessOutput(); |
663 | | |
664 | | bool DidProcessStopAbnormally() const; |
665 | | |
666 | | void SetSynchronous(bool value); |
667 | | |
668 | | lldb::CommandObjectSP GetCommandSP(llvm::StringRef cmd, |
669 | | bool include_aliases = true, |
670 | | bool exact = true, |
671 | | StringList *matches = nullptr, |
672 | | StringList *descriptions = nullptr) const; |
673 | | |
674 | | private: |
675 | | void OverrideExecutionContext(const ExecutionContext &override_context); |
676 | | |
677 | | void RestoreExecutionContext(); |
678 | | |
679 | | void SourceInitFile(FileSpec file, CommandReturnObject &result); |
680 | | |
681 | | // Completely resolves aliases and abbreviations, returning a pointer to the |
682 | | // final command object and updating command_line to the fully substituted |
683 | | // and translated command. |
684 | | CommandObject *ResolveCommandImpl(std::string &command_line, |
685 | | CommandReturnObject &result); |
686 | | |
687 | | void FindCommandsForApropos(llvm::StringRef word, StringList &commands_found, |
688 | | StringList &commands_help, |
689 | | const CommandObject::CommandMap &command_map); |
690 | | |
691 | | // An interruptible wrapper around the stream output |
692 | | void PrintCommandOutput(IOHandler &io_handler, llvm::StringRef str, |
693 | | bool is_stdout); |
694 | | |
695 | | bool EchoCommandNonInteractive(llvm::StringRef line, |
696 | | const Flags &io_handler_flags) const; |
697 | | |
698 | | // A very simple state machine which models the command handling transitions |
699 | | enum class CommandHandlingState { |
700 | | eIdle, |
701 | | eInProgress, |
702 | | eInterrupted, |
703 | | }; |
704 | | |
705 | | std::atomic<CommandHandlingState> m_command_state{ |
706 | | CommandHandlingState::eIdle}; |
707 | | |
708 | | int m_iohandler_nesting_level = 0; |
709 | | |
710 | | void StartHandlingCommand(); |
711 | | void FinishHandlingCommand(); |
712 | | |
713 | | Debugger &m_debugger; // The debugger session that this interpreter is |
714 | | // associated with |
715 | | // Execution contexts that were temporarily set by some of HandleCommand* |
716 | | // overloads. |
717 | | std::stack<ExecutionContext> m_overriden_exe_contexts; |
718 | | bool m_synchronous_execution; |
719 | | bool m_skip_lldbinit_files; |
720 | | bool m_skip_app_init_files; |
721 | | CommandObject::CommandMap m_command_dict; // Stores basic built-in commands |
722 | | // (they cannot be deleted, removed |
723 | | // or overwritten). |
724 | | CommandObject::CommandMap |
725 | | m_alias_dict; // Stores user aliases/abbreviations for commands |
726 | | CommandObject::CommandMap m_user_dict; // Stores user-defined commands |
727 | | CommandObject::CommandMap |
728 | | m_user_mw_dict; // Stores user-defined multiword commands |
729 | | CommandHistory m_command_history; |
730 | | std::string m_repeat_command; // Stores the command that will be executed for |
731 | | // an empty command string. |
732 | | lldb::IOHandlerSP m_command_io_handler_sp; |
733 | | char m_comment_char; |
734 | | bool m_batch_command_mode; |
735 | | /// Whether we truncated a value's list of children and whether the user has |
736 | | /// been told. |
737 | | ChildrenOmissionWarningStatus m_truncation_warning; |
738 | | /// Whether we reached the maximum child nesting depth and whether the user |
739 | | /// has been told. |
740 | | ChildrenOmissionWarningStatus m_max_depth_warning; |
741 | | |
742 | | // FIXME: Stop using this to control adding to the history and then replace |
743 | | // this with m_command_source_dirs.size(). |
744 | | uint32_t m_command_source_depth; |
745 | | /// A stack of directory paths. When not empty, the last one is the directory |
746 | | /// of the file that's currently sourced. |
747 | | std::vector<FileSpec> m_command_source_dirs; |
748 | | std::vector<uint32_t> m_command_source_flags; |
749 | | CommandInterpreterRunResult m_result; |
750 | | |
751 | | // The exit code the user has requested when calling the 'quit' command. |
752 | | // No value means the user hasn't set a custom exit code so far. |
753 | | std::optional<int> m_quit_exit_code; |
754 | | // If the driver is accepts custom exit codes for the 'quit' command. |
755 | | bool m_allow_exit_code = false; |
756 | | |
757 | | StreamString m_transcript_stream; |
758 | | }; |
759 | | |
760 | | } // namespace lldb_private |
761 | | |
762 | | #endif // LLDB_INTERPRETER_COMMANDINTERPRETER_H |