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   CommandInterpreterRunResult() = default;
38 
GetNumErrors()39   uint32_t GetNumErrors() const { return m_num_errors; }
40 
GetResult()41   lldb::CommandInterpreterResult GetResult() const { return m_result; }
42 
IsResult(lldb::CommandInterpreterResult result)43   bool IsResult(lldb::CommandInterpreterResult result) {
44     return m_result == result;
45   }
46 
47 protected:
48   friend CommandInterpreter;
49 
IncrementNumberOfErrors()50   void IncrementNumberOfErrors() { m_num_errors++; }
51 
SetResult(lldb::CommandInterpreterResult result)52   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.
CommandInterpreterRunOptions(LazyBool stop_on_continue,LazyBool stop_on_error,LazyBool stop_on_crash,LazyBool echo_commands,LazyBool echo_comments,LazyBool print_results,LazyBool print_errors,LazyBool add_to_history)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         m_print_errors(print_errors), m_add_to_history(add_to_history) {}
103 
104   CommandInterpreterRunOptions() = default;
105 
SetSilent(bool silent)106   void SetSilent(bool silent) {
107     LazyBool value = silent ? eLazyBoolNo : eLazyBoolYes;
108 
109     m_print_results = value;
110     m_print_errors = value;
111     m_echo_commands = value;
112     m_echo_comment_commands = value;
113     m_add_to_history = value;
114   }
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.
GetStopOnContinue()120   bool GetStopOnContinue() const { return DefaultToNo(m_stop_on_continue); }
121 
SetStopOnContinue(bool stop_on_continue)122   void SetStopOnContinue(bool stop_on_continue) {
123     m_stop_on_continue = stop_on_continue ? eLazyBoolYes : eLazyBoolNo;
124   }
125 
GetStopOnError()126   bool GetStopOnError() const { return DefaultToNo(m_stop_on_error); }
127 
SetStopOnError(bool stop_on_error)128   void SetStopOnError(bool stop_on_error) {
129     m_stop_on_error = stop_on_error ? eLazyBoolYes : eLazyBoolNo;
130   }
131 
GetStopOnCrash()132   bool GetStopOnCrash() const { return DefaultToNo(m_stop_on_crash); }
133 
SetStopOnCrash(bool stop_on_crash)134   void SetStopOnCrash(bool stop_on_crash) {
135     m_stop_on_crash = stop_on_crash ? eLazyBoolYes : eLazyBoolNo;
136   }
137 
GetEchoCommands()138   bool GetEchoCommands() const { return DefaultToYes(m_echo_commands); }
139 
SetEchoCommands(bool echo_commands)140   void SetEchoCommands(bool echo_commands) {
141     m_echo_commands = echo_commands ? eLazyBoolYes : eLazyBoolNo;
142   }
143 
GetEchoCommentCommands()144   bool GetEchoCommentCommands() const {
145     return DefaultToYes(m_echo_comment_commands);
146   }
147 
SetEchoCommentCommands(bool echo_comments)148   void SetEchoCommentCommands(bool echo_comments) {
149     m_echo_comment_commands = echo_comments ? eLazyBoolYes : eLazyBoolNo;
150   }
151 
GetPrintResults()152   bool GetPrintResults() const { return DefaultToYes(m_print_results); }
153 
SetPrintResults(bool print_results)154   void SetPrintResults(bool print_results) {
155     m_print_results = print_results ? eLazyBoolYes : eLazyBoolNo;
156   }
157 
GetPrintErrors()158   bool GetPrintErrors() const { return DefaultToYes(m_print_errors); }
159 
SetPrintErrors(bool print_errors)160   void SetPrintErrors(bool print_errors) {
161     m_print_errors = print_errors ? eLazyBoolYes : eLazyBoolNo;
162   }
163 
GetAddToHistory()164   bool GetAddToHistory() const { return DefaultToYes(m_add_to_history); }
165 
SetAddToHistory(bool add_to_history)166   void SetAddToHistory(bool add_to_history) {
167     m_add_to_history = add_to_history ? eLazyBoolYes : eLazyBoolNo;
168   }
169 
GetAutoHandleEvents()170   bool GetAutoHandleEvents() const {
171     return DefaultToYes(m_auto_handle_events);
172   }
173 
SetAutoHandleEvents(bool auto_handle_events)174   void SetAutoHandleEvents(bool auto_handle_events) {
175     m_auto_handle_events = auto_handle_events ? eLazyBoolYes : eLazyBoolNo;
176   }
177 
GetSpawnThread()178   bool GetSpawnThread() const { return DefaultToNo(m_spawn_thread); }
179 
SetSpawnThread(bool spawn_thread)180   void SetSpawnThread(bool spawn_thread) {
181     m_spawn_thread = spawn_thread ? eLazyBoolYes : eLazyBoolNo;
182   }
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:
DefaultToYes(LazyBool flag)196   static bool DefaultToYes(LazyBool flag) {
197     switch (flag) {
198     case eLazyBoolNo:
199       return false;
200     default:
201       return true;
202     }
203   }
204 
DefaultToNo(LazyBool flag)205   static bool DefaultToNo(LazyBool flag) {
206     switch (flag) {
207     case eLazyBoolYes:
208       return true;
209     default:
210       return false;
211     }
212   }
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   ~CommandInterpreter() override = default;
254 
255   // These two functions fill out the Broadcaster interface:
256 
257   static ConstString &GetStaticBroadcasterClass();
258 
GetBroadcasterClass()259   ConstString &GetBroadcasterClass() const override {
260     return GetStaticBroadcasterClass();
261   }
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?
RemoveAllUserMultiword()338   void RemoveAllUserMultiword() { m_user_mw_dict.clear(); }
339 
340   bool RemoveUser(llvm::StringRef alias_name);
341 
RemoveAllUser()342   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 
GetDebugger()448   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 
SkipLLDBInitFiles(bool skip_lldbinit_files)484   void SkipLLDBInitFiles(bool skip_lldbinit_files) {
485     m_skip_lldbinit_files = skip_lldbinit_files;
486   }
487 
SkipAppInitFiles(bool skip_app_init_files)488   void SkipAppInitFiles(bool skip_app_init_files) {
489     m_skip_app_init_files = skip_app_init_files;
490   }
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 
GetBatchCommandMode()501   bool GetBatchCommandMode() { return m_batch_command_mode; }
502 
SetBatchCommandMode(bool value)503   bool SetBatchCommandMode(bool value) {
504     const bool old_value = m_batch_command_mode;
505     m_batch_command_mode = value;
506     return old_value;
507   }
508 
ChildrenTruncated()509   void ChildrenTruncated() {
510     if (m_truncation_warning == eNoOmission)
511       m_truncation_warning = eUnwarnedOmission;
512   }
513 
SetReachedMaximumDepth()514   void SetReachedMaximumDepth() {
515     if (m_max_depth_warning == eNoOmission)
516       m_max_depth_warning = eUnwarnedOmission;
517   }
518 
PrintWarningsIfNecessary(Stream & s,const std::string & cmd_name)519   void PrintWarningsIfNecessary(Stream &s, const std::string &cmd_name) {
520     if (m_truncation_warning == eUnwarnedOmission) {
521       s.Printf("*** Some of the displayed variables have more members than the "
522                "debugger will show by default. To show all of them, you can "
523                "either use the --show-all-children option to %s or raise the "
524                "limit by changing the target.max-children-count setting.\n",
525                cmd_name.c_str());
526       m_truncation_warning = eWarnedOmission;
527     }
528 
529     if (m_max_depth_warning == eUnwarnedOmission) {
530       s.Printf("*** Some of the displayed variables have a greater depth of "
531                "members than the debugger will show by default. To increase "
532                "the limit, use the --depth option to %s, or raise the limit by "
533                "changing the target.max-children-depth setting.\n",
534                cmd_name.c_str());
535       m_max_depth_warning = eWarnedOmission;
536     }
537   }
538 
GetCommandHistory()539   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 
GetUserCommands()581   const CommandObject::CommandMap &GetUserCommands() const {
582     return m_user_dict;
583   }
584 
GetUserMultiwordCommands()585   const CommandObject::CommandMap &GetUserMultiwordCommands() const {
586     return m_user_mw_dict;
587   }
588 
GetCommands()589   const CommandObject::CommandMap &GetCommands() const {
590     return m_command_dict;
591   }
592 
GetAliases()593   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 
IOHandlerGetControlSequence(char ch)655   llvm::StringRef IOHandlerGetControlSequence(char ch) override {
656     static constexpr llvm::StringLiteral control_sequence("quit\n");
657     if (ch == 'd')
658       return control_sequence;
659     return {};
660   }
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
763