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