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