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)
328   bool RemoveCommand(llvm::StringRef cmd);
329 
330   bool RemoveAlias(llvm::StringRef alias_name);
331 
332   bool GetAliasFullName(llvm::StringRef cmd, std::string &full_name) const;
333 
334   bool RemoveUserMultiword(llvm::StringRef multiword_name);
335 
336   // Do we want to allow top-level user multiword commands to be deleted?
RemoveAllUserMultiword()337   void RemoveAllUserMultiword() { m_user_mw_dict.clear(); }
338 
339   bool RemoveUser(llvm::StringRef alias_name);
340 
RemoveAllUser()341   void RemoveAllUser() { m_user_dict.clear(); }
342 
343   const CommandAlias *GetAlias(llvm::StringRef alias_name) const;
344 
345   CommandObject *BuildAliasResult(llvm::StringRef alias_name,
346                                   std::string &raw_input_string,
347                                   std::string &alias_result,
348                                   CommandReturnObject &result);
349 
350   bool HandleCommand(const char *command_line, LazyBool add_to_history,
351                      const ExecutionContext &override_context,
352                      CommandReturnObject &result);
353 
354   bool HandleCommand(const char *command_line, LazyBool add_to_history,
355                      CommandReturnObject &result);
356 
357   bool WasInterrupted() const;
358 
359   /// Execute a list of commands in sequence.
360   ///
361   /// \param[in] commands
362   ///    The list of commands to execute.
363   /// \param[in,out] context
364   ///    The execution context in which to run the commands.
365   /// \param[in] options
366   ///    This object holds the options used to control when to stop, whether to
367   ///    execute commands,
368   ///    etc.
369   /// \param[out] result
370   ///    This is marked as succeeding with no output if all commands execute
371   ///    safely,
372   ///    and failed with some explanation if we aborted executing the commands
373   ///    at some point.
374   void HandleCommands(const StringList &commands,
375                       const ExecutionContext &context,
376                       const CommandInterpreterRunOptions &options,
377                       CommandReturnObject &result);
378 
379   void HandleCommands(const StringList &commands,
380                       const CommandInterpreterRunOptions &options,
381                       CommandReturnObject &result);
382 
383   /// Execute a list of commands from a file.
384   ///
385   /// \param[in] file
386   ///    The file from which to read in commands.
387   /// \param[in,out] context
388   ///    The execution context in which to run the commands.
389   /// \param[in] options
390   ///    This object holds the options used to control when to stop, whether to
391   ///    execute commands,
392   ///    etc.
393   /// \param[out] result
394   ///    This is marked as succeeding with no output if all commands execute
395   ///    safely,
396   ///    and failed with some explanation if we aborted executing the commands
397   ///    at some point.
398   void HandleCommandsFromFile(FileSpec &file, const ExecutionContext &context,
399                               const CommandInterpreterRunOptions &options,
400                               CommandReturnObject &result);
401 
402   void HandleCommandsFromFile(FileSpec &file,
403                               const CommandInterpreterRunOptions &options,
404                               CommandReturnObject &result);
405 
406   CommandObject *GetCommandObjectForCommand(llvm::StringRef &command_line);
407 
408   /// Returns the auto-suggestion string that should be added to the given
409   /// command line.
410   std::optional<std::string> GetAutoSuggestionForCommand(llvm::StringRef line);
411 
412   // This handles command line completion.
413   void HandleCompletion(CompletionRequest &request);
414 
415   // This version just returns matches, and doesn't compute the substring. It
416   // is here so the Help command can call it for the first argument.
417   void HandleCompletionMatches(CompletionRequest &request);
418 
419   int GetCommandNamesMatchingPartialString(const char *cmd_cstr,
420                                            bool include_aliases,
421                                            StringList &matches,
422                                            StringList &descriptions);
423 
424   void GetHelp(CommandReturnObject &result,
425                uint32_t types = eCommandTypesAllThem);
426 
427   void GetAliasHelp(const char *alias_name, StreamString &help_string);
428 
429   void OutputFormattedHelpText(Stream &strm, llvm::StringRef prefix,
430                                llvm::StringRef help_text);
431 
432   void OutputFormattedHelpText(Stream &stream, llvm::StringRef command_word,
433                                llvm::StringRef separator,
434                                llvm::StringRef help_text, size_t max_word_len);
435 
436   // this mimics OutputFormattedHelpText but it does perform a much simpler
437   // formatting, basically ensuring line alignment. This is only good if you
438   // have some complicated layout for your help text and want as little help as
439   // reasonable in properly displaying it. Most of the times, you simply want
440   // to type some text and have it printed in a reasonable way on screen. If
441   // so, use OutputFormattedHelpText
442   void OutputHelpText(Stream &stream, llvm::StringRef command_word,
443                       llvm::StringRef separator, llvm::StringRef help_text,
444                       uint32_t max_word_len);
445 
GetDebugger()446   Debugger &GetDebugger() { return m_debugger; }
447 
448   ExecutionContext GetExecutionContext() const;
449 
450   lldb::PlatformSP GetPlatform(bool prefer_target_platform);
451 
452   const char *ProcessEmbeddedScriptCommands(const char *arg);
453 
454   void UpdatePrompt(llvm::StringRef prompt);
455 
456   bool Confirm(llvm::StringRef message, bool default_answer);
457 
458   void LoadCommandDictionary();
459 
460   void Initialize();
461 
462   void Clear();
463 
464   bool HasCommands() const;
465 
466   bool HasAliases() const;
467 
468   bool HasUserCommands() const;
469 
470   bool HasUserMultiwordCommands() const;
471 
472   bool HasAliasOptions() const;
473 
474   void BuildAliasCommandArgs(CommandObject *alias_cmd_obj,
475                              const char *alias_name, Args &cmd_args,
476                              std::string &raw_input_string,
477                              CommandReturnObject &result);
478 
479   /// Picks the number out of a string of the form "%NNN", otherwise return 0.
480   int GetOptionArgumentPosition(const char *in_string);
481 
SkipLLDBInitFiles(bool skip_lldbinit_files)482   void SkipLLDBInitFiles(bool skip_lldbinit_files) {
483     m_skip_lldbinit_files = skip_lldbinit_files;
484   }
485 
SkipAppInitFiles(bool skip_app_init_files)486   void SkipAppInitFiles(bool skip_app_init_files) {
487     m_skip_app_init_files = skip_app_init_files;
488   }
489 
490   bool GetSynchronous();
491 
492   void FindCommandsForApropos(llvm::StringRef word, StringList &commands_found,
493                               StringList &commands_help,
494                               bool search_builtin_commands,
495                               bool search_user_commands,
496                               bool search_alias_commands,
497                               bool search_user_mw_commands);
498 
GetBatchCommandMode()499   bool GetBatchCommandMode() { return m_batch_command_mode; }
500 
SetBatchCommandMode(bool value)501   bool SetBatchCommandMode(bool value) {
502     const bool old_value = m_batch_command_mode;
503     m_batch_command_mode = value;
504     return old_value;
505   }
506 
ChildrenTruncated()507   void ChildrenTruncated() {
508     if (m_truncation_warning == eNoOmission)
509       m_truncation_warning = eUnwarnedOmission;
510   }
511 
SetReachedMaximumDepth()512   void SetReachedMaximumDepth() {
513     if (m_max_depth_warning == eNoOmission)
514       m_max_depth_warning = eUnwarnedOmission;
515   }
516 
PrintWarningsIfNecessary(Stream & s,const std::string & cmd_name)517   void PrintWarningsIfNecessary(Stream &s, const std::string &cmd_name) {
518     if (m_truncation_warning == eUnwarnedOmission) {
519       s.Printf("*** Some of the displayed variables have more members than the "
520                "debugger will show by default. To show all of them, you can "
521                "either use the --show-all-children option to %s or raise the "
522                "limit by changing the target.max-children-count setting.\n",
523                cmd_name.c_str());
524       m_truncation_warning = eWarnedOmission;
525     }
526 
527     if (m_max_depth_warning == eUnwarnedOmission) {
528       s.Printf("*** Some of the displayed variables have a greater depth of "
529                "members than the debugger will show by default. To increase "
530                "the limit, use the --depth option to %s, or raise the limit by "
531                "changing the target.max-children-depth setting.\n",
532                cmd_name.c_str());
533       m_max_depth_warning = eWarnedOmission;
534     }
535   }
536 
GetCommandHistory()537   CommandHistory &GetCommandHistory() { return m_command_history; }
538 
539   bool IsActive();
540 
541   CommandInterpreterRunResult
542   RunCommandInterpreter(CommandInterpreterRunOptions &options);
543 
544   void GetLLDBCommandsFromIOHandler(const char *prompt,
545                                     IOHandlerDelegate &delegate,
546                                     void *baton = nullptr);
547 
548   void GetPythonCommandsFromIOHandler(const char *prompt,
549                                       IOHandlerDelegate &delegate,
550                                       void *baton = nullptr);
551 
552   const char *GetCommandPrefix();
553 
554   // Properties
555   bool GetExpandRegexAliases() const;
556 
557   bool GetPromptOnQuit() const;
558   void SetPromptOnQuit(bool enable);
559 
560   bool GetSaveSessionOnQuit() const;
561   void SetSaveSessionOnQuit(bool enable);
562 
563   bool GetOpenTranscriptInEditor() const;
564   void SetOpenTranscriptInEditor(bool enable);
565 
566   FileSpec GetSaveSessionDirectory() const;
567   void SetSaveSessionDirectory(llvm::StringRef path);
568 
569   bool GetEchoCommands() const;
570   void SetEchoCommands(bool enable);
571 
572   bool GetEchoCommentCommands() const;
573   void SetEchoCommentCommands(bool enable);
574 
575   bool GetRepeatPreviousCommand() const;
576 
577   bool GetRequireCommandOverwrite() const;
578 
GetUserCommands()579   const CommandObject::CommandMap &GetUserCommands() const {
580     return m_user_dict;
581   }
582 
GetUserMultiwordCommands()583   const CommandObject::CommandMap &GetUserMultiwordCommands() const {
584     return m_user_mw_dict;
585   }
586 
GetCommands()587   const CommandObject::CommandMap &GetCommands() const {
588     return m_command_dict;
589   }
590 
GetAliases()591   const CommandObject::CommandMap &GetAliases() const { return m_alias_dict; }
592 
593   /// Specify if the command interpreter should allow that the user can
594   /// specify a custom exit code when calling 'quit'.
595   void AllowExitCodeOnQuit(bool allow);
596 
597   /// Sets the exit code for the quit command.
598   /// \param[in] exit_code
599   ///     The exit code that the driver should return on exit.
600   /// \return True if the exit code was successfully set; false if the
601   ///         interpreter doesn't allow custom exit codes.
602   /// \see AllowExitCodeOnQuit
603   [[nodiscard]] bool SetQuitExitCode(int exit_code);
604 
605   /// Returns the exit code that the user has specified when running the
606   /// 'quit' command.
607   /// \param[out] exited
608   ///     Set to true if the user has called quit with a custom exit code.
609   int GetQuitExitCode(bool &exited) const;
610 
611   void ResolveCommand(const char *command_line, CommandReturnObject &result);
612 
613   bool GetStopCmdSourceOnError() const;
614 
615   lldb::IOHandlerSP
616   GetIOHandler(bool force_create = false,
617                CommandInterpreterRunOptions *options = nullptr);
618 
619   bool GetSpaceReplPrompts() const;
620 
621   /// Save the current debugger session transcript to a file on disk.
622   /// \param output_file
623   ///     The file path to which the session transcript will be written. Since
624   ///     the argument is optional, an arbitrary temporary file will be create
625   ///     when no argument is passed.
626   /// \param result
627   ///     This is used to pass function output and error messages.
628   /// \return \b true if the session transcript was successfully written to
629   /// disk, \b false otherwise.
630   bool SaveTranscript(CommandReturnObject &result,
631                       std::optional<std::string> output_file = std::nullopt);
632 
633   FileSpec GetCurrentSourceDir();
634 
635   bool IsInteractive();
636 
637   bool IOHandlerInterrupt(IOHandler &io_handler) override;
638 
639 protected:
640   friend class Debugger;
641 
642   // IOHandlerDelegate functions
643   void IOHandlerInputComplete(IOHandler &io_handler,
644                               std::string &line) override;
645 
IOHandlerGetControlSequence(char ch)646   ConstString IOHandlerGetControlSequence(char ch) override {
647     if (ch == 'd')
648       return ConstString("quit\n");
649     return ConstString();
650   }
651 
652   void GetProcessOutput();
653 
654   bool DidProcessStopAbnormally() const;
655 
656   void SetSynchronous(bool value);
657 
658   lldb::CommandObjectSP GetCommandSP(llvm::StringRef cmd,
659                                      bool include_aliases = true,
660                                      bool exact = true,
661                                      StringList *matches = nullptr,
662                                      StringList *descriptions = nullptr) const;
663 
664 private:
665   void OverrideExecutionContext(const ExecutionContext &override_context);
666 
667   void RestoreExecutionContext();
668 
669   Status PreprocessCommand(std::string &command);
670 
671   void SourceInitFile(FileSpec file, CommandReturnObject &result);
672 
673   // Completely resolves aliases and abbreviations, returning a pointer to the
674   // final command object and updating command_line to the fully substituted
675   // and translated command.
676   CommandObject *ResolveCommandImpl(std::string &command_line,
677                                     CommandReturnObject &result);
678 
679   void FindCommandsForApropos(llvm::StringRef word, StringList &commands_found,
680                               StringList &commands_help,
681                               const CommandObject::CommandMap &command_map);
682 
683   // An interruptible wrapper around the stream output
684   void PrintCommandOutput(IOHandler &io_handler, llvm::StringRef str,
685                           bool is_stdout);
686 
687   bool EchoCommandNonInteractive(llvm::StringRef line,
688                                  const Flags &io_handler_flags) const;
689 
690   // A very simple state machine which models the command handling transitions
691   enum class CommandHandlingState {
692     eIdle,
693     eInProgress,
694     eInterrupted,
695   };
696 
697   std::atomic<CommandHandlingState> m_command_state{
698       CommandHandlingState::eIdle};
699 
700   int m_iohandler_nesting_level = 0;
701 
702   void StartHandlingCommand();
703   void FinishHandlingCommand();
704   bool InterruptCommand();
705 
706   Debugger &m_debugger; // The debugger session that this interpreter is
707                         // associated with
708   // Execution contexts that were temporarily set by some of HandleCommand*
709   // overloads.
710   std::stack<ExecutionContext> m_overriden_exe_contexts;
711   bool m_synchronous_execution;
712   bool m_skip_lldbinit_files;
713   bool m_skip_app_init_files;
714   CommandObject::CommandMap m_command_dict; // Stores basic built-in commands
715                                             // (they cannot be deleted, removed
716                                             // or overwritten).
717   CommandObject::CommandMap
718       m_alias_dict; // Stores user aliases/abbreviations for commands
719   CommandObject::CommandMap m_user_dict; // Stores user-defined commands
720   CommandObject::CommandMap
721       m_user_mw_dict; // Stores user-defined multiword commands
722   CommandHistory m_command_history;
723   std::string m_repeat_command; // Stores the command that will be executed for
724                                 // an empty command string.
725   lldb::IOHandlerSP m_command_io_handler_sp;
726   char m_comment_char;
727   bool m_batch_command_mode;
728   /// Whether we truncated a value's list of children and whether the user has
729   /// been told.
730   ChildrenOmissionWarningStatus m_truncation_warning;
731   /// Whether we reached the maximum child nesting depth and whether the user
732   /// has been told.
733   ChildrenOmissionWarningStatus m_max_depth_warning;
734 
735   // FIXME: Stop using this to control adding to the history and then replace
736   // this with m_command_source_dirs.size().
737   uint32_t m_command_source_depth;
738   /// A stack of directory paths. When not empty, the last one is the directory
739   /// of the file that's currently sourced.
740   std::vector<FileSpec> m_command_source_dirs;
741   std::vector<uint32_t> m_command_source_flags;
742   CommandInterpreterRunResult m_result;
743 
744   // The exit code the user has requested when calling the 'quit' command.
745   // No value means the user hasn't set a custom exit code so far.
746   std::optional<int> m_quit_exit_code;
747   // If the driver is accepts custom exit codes for the 'quit' command.
748   bool m_allow_exit_code = false;
749 
750   StreamString m_transcript_stream;
751 };
752 
753 } // namespace lldb_private
754 
755 #endif // LLDB_INTERPRETER_COMMANDINTERPRETER_H
756