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