1 //===-- CommandObjectCommands.cpp -------------------------------*- 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 #include "llvm/ADT/StringRef.h" 10 11 #include "CommandObjectCommands.h" 12 #include "CommandObjectHelp.h" 13 #include "lldb/Core/Debugger.h" 14 #include "lldb/Core/IOHandler.h" 15 #include "lldb/Host/OptionParser.h" 16 #include "lldb/Interpreter/CommandHistory.h" 17 #include "lldb/Interpreter/CommandInterpreter.h" 18 #include "lldb/Interpreter/CommandObjectRegexCommand.h" 19 #include "lldb/Interpreter/CommandReturnObject.h" 20 #include "lldb/Interpreter/OptionArgParser.h" 21 #include "lldb/Interpreter/OptionValueBoolean.h" 22 #include "lldb/Interpreter/OptionValueString.h" 23 #include "lldb/Interpreter/OptionValueUInt64.h" 24 #include "lldb/Interpreter/Options.h" 25 #include "lldb/Interpreter/ScriptInterpreter.h" 26 #include "lldb/Utility/Args.h" 27 #include "lldb/Utility/StringList.h" 28 29 using namespace lldb; 30 using namespace lldb_private; 31 32 //------------------------------------------------------------------------- 33 // CommandObjectCommandsSource 34 //------------------------------------------------------------------------- 35 36 static constexpr OptionDefinition g_history_options[] = { 37 // clang-format off 38 { LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeUnsignedInteger, "How many history commands to print." }, 39 { LLDB_OPT_SET_1, false, "start-index", 's', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeUnsignedInteger, "Index at which to start printing history commands (or end to mean tail mode)." }, 40 { LLDB_OPT_SET_1, false, "end-index", 'e', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeUnsignedInteger, "Index at which to stop printing history commands." }, 41 { LLDB_OPT_SET_2, false, "clear", 'C', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeBoolean, "Clears the current command history." }, 42 // clang-format on 43 }; 44 45 class CommandObjectCommandsHistory : public CommandObjectParsed { 46 public: 47 CommandObjectCommandsHistory(CommandInterpreter &interpreter) 48 : CommandObjectParsed(interpreter, "command history", 49 "Dump the history of commands in this session.\n" 50 "Commands in the history list can be run again " 51 "using \"!<INDEX>\". \"!-<OFFSET>\" will re-run " 52 "the command that is <OFFSET> commands from the end" 53 " of the list (counting the current command).", 54 nullptr), 55 m_options() {} 56 57 ~CommandObjectCommandsHistory() override = default; 58 59 Options *GetOptions() override { return &m_options; } 60 61 protected: 62 class CommandOptions : public Options { 63 public: 64 CommandOptions() 65 : Options(), m_start_idx(0), m_stop_idx(0), m_count(0), m_clear(false) { 66 } 67 68 ~CommandOptions() override = default; 69 70 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 71 ExecutionContext *execution_context) override { 72 Status error; 73 const int short_option = m_getopt_table[option_idx].val; 74 75 switch (short_option) { 76 case 'c': 77 error = m_count.SetValueFromString(option_arg, eVarSetOperationAssign); 78 break; 79 case 's': 80 if (option_arg == "end") { 81 m_start_idx.SetCurrentValue(UINT64_MAX); 82 m_start_idx.SetOptionWasSet(); 83 } else 84 error = m_start_idx.SetValueFromString(option_arg, 85 eVarSetOperationAssign); 86 break; 87 case 'e': 88 error = 89 m_stop_idx.SetValueFromString(option_arg, eVarSetOperationAssign); 90 break; 91 case 'C': 92 m_clear.SetCurrentValue(true); 93 m_clear.SetOptionWasSet(); 94 break; 95 default: 96 error.SetErrorStringWithFormat("unrecognized option '%c'", 97 short_option); 98 break; 99 } 100 101 return error; 102 } 103 104 void OptionParsingStarting(ExecutionContext *execution_context) override { 105 m_start_idx.Clear(); 106 m_stop_idx.Clear(); 107 m_count.Clear(); 108 m_clear.Clear(); 109 } 110 111 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 112 return llvm::makeArrayRef(g_history_options); 113 } 114 115 // Instance variables to hold the values for command options. 116 117 OptionValueUInt64 m_start_idx; 118 OptionValueUInt64 m_stop_idx; 119 OptionValueUInt64 m_count; 120 OptionValueBoolean m_clear; 121 }; 122 123 bool DoExecute(Args &command, CommandReturnObject &result) override { 124 if (m_options.m_clear.GetCurrentValue() && 125 m_options.m_clear.OptionWasSet()) { 126 m_interpreter.GetCommandHistory().Clear(); 127 result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); 128 } else { 129 if (m_options.m_start_idx.OptionWasSet() && 130 m_options.m_stop_idx.OptionWasSet() && 131 m_options.m_count.OptionWasSet()) { 132 result.AppendError("--count, --start-index and --end-index cannot be " 133 "all specified in the same invocation"); 134 result.SetStatus(lldb::eReturnStatusFailed); 135 } else { 136 std::pair<bool, uint64_t> start_idx( 137 m_options.m_start_idx.OptionWasSet(), 138 m_options.m_start_idx.GetCurrentValue()); 139 std::pair<bool, uint64_t> stop_idx( 140 m_options.m_stop_idx.OptionWasSet(), 141 m_options.m_stop_idx.GetCurrentValue()); 142 std::pair<bool, uint64_t> count(m_options.m_count.OptionWasSet(), 143 m_options.m_count.GetCurrentValue()); 144 145 const CommandHistory &history(m_interpreter.GetCommandHistory()); 146 147 if (start_idx.first && start_idx.second == UINT64_MAX) { 148 if (count.first) { 149 start_idx.second = history.GetSize() - count.second; 150 stop_idx.second = history.GetSize() - 1; 151 } else if (stop_idx.first) { 152 start_idx.second = stop_idx.second; 153 stop_idx.second = history.GetSize() - 1; 154 } else { 155 start_idx.second = 0; 156 stop_idx.second = history.GetSize() - 1; 157 } 158 } else { 159 if (!start_idx.first && !stop_idx.first && !count.first) { 160 start_idx.second = 0; 161 stop_idx.second = history.GetSize() - 1; 162 } else if (start_idx.first) { 163 if (count.first) { 164 stop_idx.second = start_idx.second + count.second - 1; 165 } else if (!stop_idx.first) { 166 stop_idx.second = history.GetSize() - 1; 167 } 168 } else if (stop_idx.first) { 169 if (count.first) { 170 if (stop_idx.second >= count.second) 171 start_idx.second = stop_idx.second - count.second + 1; 172 else 173 start_idx.second = 0; 174 } 175 } else /* if (count.first) */ 176 { 177 start_idx.second = 0; 178 stop_idx.second = count.second - 1; 179 } 180 } 181 history.Dump(result.GetOutputStream(), start_idx.second, 182 stop_idx.second); 183 } 184 } 185 return result.Succeeded(); 186 } 187 188 CommandOptions m_options; 189 }; 190 191 //------------------------------------------------------------------------- 192 // CommandObjectCommandsSource 193 //------------------------------------------------------------------------- 194 195 static constexpr OptionDefinition g_source_options[] = { 196 // clang-format off 197 { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBoolean, "If true, stop executing commands on error." }, 198 { LLDB_OPT_SET_ALL, false, "stop-on-continue", 'c', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBoolean, "If true, stop executing commands on continue." }, 199 { LLDB_OPT_SET_ALL, false, "silent-run", 's', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBoolean, "If true don't echo commands while executing." }, 200 // clang-format on 201 }; 202 203 class CommandObjectCommandsSource : public CommandObjectParsed { 204 public: 205 CommandObjectCommandsSource(CommandInterpreter &interpreter) 206 : CommandObjectParsed( 207 interpreter, "command source", 208 "Read and execute LLDB commands from the file <filename>.", 209 nullptr), 210 m_options() { 211 CommandArgumentEntry arg; 212 CommandArgumentData file_arg; 213 214 // Define the first (and only) variant of this arg. 215 file_arg.arg_type = eArgTypeFilename; 216 file_arg.arg_repetition = eArgRepeatPlain; 217 218 // There is only one variant this argument could be; put it into the 219 // argument entry. 220 arg.push_back(file_arg); 221 222 // Push the data for the first argument into the m_arguments vector. 223 m_arguments.push_back(arg); 224 } 225 226 ~CommandObjectCommandsSource() override = default; 227 228 const char *GetRepeatCommand(Args ¤t_command_args, 229 uint32_t index) override { 230 return ""; 231 } 232 233 int HandleArgumentCompletion( 234 CompletionRequest &request, 235 OptionElementVector &opt_element_vector) override { 236 CommandCompletions::InvokeCommonCompletionCallbacks( 237 GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, 238 request, nullptr); 239 return request.GetNumberOfMatches(); 240 } 241 242 Options *GetOptions() override { return &m_options; } 243 244 protected: 245 class CommandOptions : public Options { 246 public: 247 CommandOptions() 248 : Options(), m_stop_on_error(true), m_silent_run(false), 249 m_stop_on_continue(true) {} 250 251 ~CommandOptions() override = default; 252 253 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 254 ExecutionContext *execution_context) override { 255 Status error; 256 const int short_option = m_getopt_table[option_idx].val; 257 258 switch (short_option) { 259 case 'e': 260 error = m_stop_on_error.SetValueFromString(option_arg); 261 break; 262 263 case 'c': 264 error = m_stop_on_continue.SetValueFromString(option_arg); 265 break; 266 267 case 's': 268 error = m_silent_run.SetValueFromString(option_arg); 269 break; 270 271 default: 272 error.SetErrorStringWithFormat("unrecognized option '%c'", 273 short_option); 274 break; 275 } 276 277 return error; 278 } 279 280 void OptionParsingStarting(ExecutionContext *execution_context) override { 281 m_stop_on_error.Clear(); 282 m_silent_run.Clear(); 283 m_stop_on_continue.Clear(); 284 } 285 286 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 287 return llvm::makeArrayRef(g_source_options); 288 } 289 290 // Instance variables to hold the values for command options. 291 292 OptionValueBoolean m_stop_on_error; 293 OptionValueBoolean m_silent_run; 294 OptionValueBoolean m_stop_on_continue; 295 }; 296 297 bool DoExecute(Args &command, CommandReturnObject &result) override { 298 if (command.GetArgumentCount() != 1) { 299 result.AppendErrorWithFormat( 300 "'%s' takes exactly one executable filename argument.\n", 301 GetCommandName().str().c_str()); 302 result.SetStatus(eReturnStatusFailed); 303 return false; 304 } 305 306 FileSpec cmd_file(command[0].ref); 307 FileSystem::Instance().Resolve(cmd_file); 308 ExecutionContext *exe_ctx = nullptr; // Just use the default context. 309 310 // If any options were set, then use them 311 if (m_options.m_stop_on_error.OptionWasSet() || 312 m_options.m_silent_run.OptionWasSet() || 313 m_options.m_stop_on_continue.OptionWasSet()) { 314 // Use user set settings 315 CommandInterpreterRunOptions options; 316 options.SetStopOnContinue(m_options.m_stop_on_continue.GetCurrentValue()); 317 options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue()); 318 319 // Individual silent setting is override for global command echo settings. 320 if (m_options.m_silent_run.GetCurrentValue()) { 321 options.SetSilent(true); 322 } else { 323 options.SetPrintResults(true); 324 options.SetEchoCommands(m_interpreter.GetEchoCommands()); 325 options.SetEchoCommentCommands(m_interpreter.GetEchoCommentCommands()); 326 } 327 328 m_interpreter.HandleCommandsFromFile(cmd_file, exe_ctx, options, result); 329 } else { 330 // No options were set, inherit any settings from nested "command source" 331 // commands, or set to sane default settings... 332 CommandInterpreterRunOptions options; 333 m_interpreter.HandleCommandsFromFile(cmd_file, exe_ctx, options, result); 334 } 335 return result.Succeeded(); 336 } 337 338 CommandOptions m_options; 339 }; 340 341 #pragma mark CommandObjectCommandsAlias 342 //------------------------------------------------------------------------- 343 // CommandObjectCommandsAlias 344 //------------------------------------------------------------------------- 345 346 static constexpr OptionDefinition g_alias_options[] = { 347 // clang-format off 348 { LLDB_OPT_SET_ALL, false, "help", 'h', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeHelpText, "Help text for this command" }, 349 { LLDB_OPT_SET_ALL, false, "long-help", 'H', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeHelpText, "Long help text for this command" }, 350 // clang-format on 351 }; 352 353 static const char *g_python_command_instructions = 354 "Enter your Python command(s). Type 'DONE' to end.\n" 355 "You must define a Python function with this signature:\n" 356 "def my_command_impl(debugger, args, result, internal_dict):\n"; 357 358 class CommandObjectCommandsAlias : public CommandObjectRaw { 359 protected: 360 class CommandOptions : public OptionGroup { 361 public: 362 CommandOptions() : OptionGroup(), m_help(), m_long_help() {} 363 364 ~CommandOptions() override = default; 365 366 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 367 return llvm::makeArrayRef(g_alias_options); 368 } 369 370 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, 371 ExecutionContext *execution_context) override { 372 Status error; 373 374 const int short_option = GetDefinitions()[option_idx].short_option; 375 std::string option_str(option_value); 376 377 switch (short_option) { 378 case 'h': 379 m_help.SetCurrentValue(option_str); 380 m_help.SetOptionWasSet(); 381 break; 382 383 case 'H': 384 m_long_help.SetCurrentValue(option_str); 385 m_long_help.SetOptionWasSet(); 386 break; 387 388 default: 389 error.SetErrorStringWithFormat("invalid short option character '%c'", 390 short_option); 391 break; 392 } 393 394 return error; 395 } 396 397 void OptionParsingStarting(ExecutionContext *execution_context) override { 398 m_help.Clear(); 399 m_long_help.Clear(); 400 } 401 402 OptionValueString m_help; 403 OptionValueString m_long_help; 404 }; 405 406 OptionGroupOptions m_option_group; 407 CommandOptions m_command_options; 408 409 public: 410 Options *GetOptions() override { return &m_option_group; } 411 412 CommandObjectCommandsAlias(CommandInterpreter &interpreter) 413 : CommandObjectRaw( 414 interpreter, "command alias", 415 "Define a custom command in terms of an existing command."), 416 m_option_group(), m_command_options() { 417 m_option_group.Append(&m_command_options); 418 m_option_group.Finalize(); 419 420 SetHelpLong( 421 "'alias' allows the user to create a short-cut or abbreviation for long \ 422 commands, multi-word commands, and commands that take particular options. \ 423 Below are some simple examples of how one might use the 'alias' command:" 424 R"( 425 426 (lldb) command alias sc script 427 428 Creates the abbreviation 'sc' for the 'script' command. 429 430 (lldb) command alias bp breakpoint 431 432 )" 433 " Creates the abbreviation 'bp' for the 'breakpoint' command. Since \ 434 breakpoint commands are two-word commands, the user would still need to \ 435 enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'." 436 R"( 437 438 (lldb) command alias bpl breakpoint list 439 440 Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'. 441 442 )" 443 "An alias can include some options for the command, with the values either \ 444 filled in at the time the alias is created, or specified as positional \ 445 arguments, to be filled in when the alias is invoked. The following example \ 446 shows how to create aliases with options:" 447 R"( 448 449 (lldb) command alias bfl breakpoint set -f %1 -l %2 450 451 )" 452 " Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \ 453 options already part of the alias. So if the user wants to set a breakpoint \ 454 by file and line without explicitly having to use the -f and -l options, the \ 455 user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \ 456 for the actual arguments that will be passed when the alias command is used. \ 457 The number in the placeholder refers to the position/order the actual value \ 458 occupies when the alias is used. All the occurrences of '%1' in the alias \ 459 will be replaced with the first argument, all the occurrences of '%2' in the \ 460 alias will be replaced with the second argument, and so on. This also allows \ 461 actual arguments to be used multiple times within an alias (see 'process \ 462 launch' example below)." 463 R"( 464 465 )" 466 "Note: the positional arguments must substitute as whole words in the resultant \ 467 command, so you can't at present do something like this to append the file extension \ 468 \".cpp\":" 469 R"( 470 471 (lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2 472 473 )" 474 "For more complex aliasing, use the \"command regex\" command instead. In the \ 475 'bfl' case above, the actual file value will be filled in with the first argument \ 476 following 'bfl' and the actual line number value will be filled in with the second \ 477 argument. The user would use this alias as follows:" 478 R"( 479 480 (lldb) command alias bfl breakpoint set -f %1 -l %2 481 (lldb) bfl my-file.c 137 482 483 This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'. 484 485 Another example: 486 487 (lldb) command alias pltty process launch -s -o %1 -e %1 488 (lldb) pltty /dev/tty0 489 490 Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0' 491 492 )" 493 "If the user always wanted to pass the same value to a particular option, the \ 494 alias could be defined with that value directly in the alias as a constant, \ 495 rather than using a positional placeholder:" 496 R"( 497 498 (lldb) command alias bl3 breakpoint set -f %1 -l 3 499 500 Always sets a breakpoint on line 3 of whatever file is indicated.)"); 501 502 CommandArgumentEntry arg1; 503 CommandArgumentEntry arg2; 504 CommandArgumentEntry arg3; 505 CommandArgumentData alias_arg; 506 CommandArgumentData cmd_arg; 507 CommandArgumentData options_arg; 508 509 // Define the first (and only) variant of this arg. 510 alias_arg.arg_type = eArgTypeAliasName; 511 alias_arg.arg_repetition = eArgRepeatPlain; 512 513 // There is only one variant this argument could be; put it into the 514 // argument entry. 515 arg1.push_back(alias_arg); 516 517 // Define the first (and only) variant of this arg. 518 cmd_arg.arg_type = eArgTypeCommandName; 519 cmd_arg.arg_repetition = eArgRepeatPlain; 520 521 // There is only one variant this argument could be; put it into the 522 // argument entry. 523 arg2.push_back(cmd_arg); 524 525 // Define the first (and only) variant of this arg. 526 options_arg.arg_type = eArgTypeAliasOptions; 527 options_arg.arg_repetition = eArgRepeatOptional; 528 529 // There is only one variant this argument could be; put it into the 530 // argument entry. 531 arg3.push_back(options_arg); 532 533 // Push the data for the first argument into the m_arguments vector. 534 m_arguments.push_back(arg1); 535 m_arguments.push_back(arg2); 536 m_arguments.push_back(arg3); 537 } 538 539 ~CommandObjectCommandsAlias() override = default; 540 541 protected: 542 bool DoExecute(llvm::StringRef raw_command_line, 543 CommandReturnObject &result) override { 544 if (raw_command_line.empty()) { 545 result.AppendError("'command alias' requires at least two arguments"); 546 return false; 547 } 548 549 ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext(); 550 m_option_group.NotifyOptionParsingStarting(&exe_ctx); 551 552 OptionsWithRaw args_with_suffix(raw_command_line); 553 const char *remainder = args_with_suffix.GetRawPart().c_str(); 554 555 if (args_with_suffix.HasArgs()) 556 if (!ParseOptionsAndNotify(args_with_suffix.GetArgs(), result, 557 m_option_group, exe_ctx)) 558 return false; 559 560 llvm::StringRef raw_command_string(remainder); 561 Args args(raw_command_string); 562 563 if (args.GetArgumentCount() < 2) { 564 result.AppendError("'command alias' requires at least two arguments"); 565 result.SetStatus(eReturnStatusFailed); 566 return false; 567 } 568 569 // Get the alias command. 570 571 auto alias_command = args[0].ref; 572 if (alias_command.startswith("-")) { 573 result.AppendError("aliases starting with a dash are not supported"); 574 if (alias_command == "--help" || alias_command == "--long-help") { 575 result.AppendWarning("if trying to pass options to 'command alias' add " 576 "a -- at the end of the options"); 577 } 578 result.SetStatus(eReturnStatusFailed); 579 return false; 580 } 581 582 // Strip the new alias name off 'raw_command_string' (leave it on args, 583 // which gets passed to 'Execute', which does the stripping itself. 584 size_t pos = raw_command_string.find(alias_command); 585 if (pos == 0) { 586 raw_command_string = raw_command_string.substr(alias_command.size()); 587 pos = raw_command_string.find_first_not_of(' '); 588 if ((pos != std::string::npos) && (pos > 0)) 589 raw_command_string = raw_command_string.substr(pos); 590 } else { 591 result.AppendError("Error parsing command string. No alias created."); 592 result.SetStatus(eReturnStatusFailed); 593 return false; 594 } 595 596 // Verify that the command is alias-able. 597 if (m_interpreter.CommandExists(alias_command)) { 598 result.AppendErrorWithFormat( 599 "'%s' is a permanent debugger command and cannot be redefined.\n", 600 args[0].c_str()); 601 result.SetStatus(eReturnStatusFailed); 602 return false; 603 } 604 605 // Get CommandObject that is being aliased. The command name is read from 606 // the front of raw_command_string. raw_command_string is returned with the 607 // name of the command object stripped off the front. 608 llvm::StringRef original_raw_command_string = raw_command_string; 609 CommandObject *cmd_obj = 610 m_interpreter.GetCommandObjectForCommand(raw_command_string); 611 612 if (!cmd_obj) { 613 result.AppendErrorWithFormat("invalid command given to 'command alias'. " 614 "'%s' does not begin with a valid command." 615 " No alias created.", 616 original_raw_command_string.str().c_str()); 617 result.SetStatus(eReturnStatusFailed); 618 return false; 619 } else if (!cmd_obj->WantsRawCommandString()) { 620 // Note that args was initialized with the original command, and has not 621 // been updated to this point. Therefore can we pass it to the version of 622 // Execute that does not need/expect raw input in the alias. 623 return HandleAliasingNormalCommand(args, result); 624 } else { 625 return HandleAliasingRawCommand(alias_command, raw_command_string, 626 *cmd_obj, result); 627 } 628 return result.Succeeded(); 629 } 630 631 bool HandleAliasingRawCommand(llvm::StringRef alias_command, 632 llvm::StringRef raw_command_string, 633 CommandObject &cmd_obj, 634 CommandReturnObject &result) { 635 // Verify & handle any options/arguments passed to the alias command 636 637 OptionArgVectorSP option_arg_vector_sp = 638 OptionArgVectorSP(new OptionArgVector); 639 640 if (CommandObjectSP cmd_obj_sp = 641 m_interpreter.GetCommandSPExact(cmd_obj.GetCommandName(), false)) { 642 if (m_interpreter.AliasExists(alias_command) || 643 m_interpreter.UserCommandExists(alias_command)) { 644 result.AppendWarningWithFormat( 645 "Overwriting existing definition for '%s'.\n", 646 alias_command.str().c_str()); 647 } 648 if (CommandAlias *alias = m_interpreter.AddAlias( 649 alias_command, cmd_obj_sp, raw_command_string)) { 650 if (m_command_options.m_help.OptionWasSet()) 651 alias->SetHelp(m_command_options.m_help.GetCurrentValue()); 652 if (m_command_options.m_long_help.OptionWasSet()) 653 alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue()); 654 result.SetStatus(eReturnStatusSuccessFinishNoResult); 655 } else { 656 result.AppendError("Unable to create requested alias.\n"); 657 result.SetStatus(eReturnStatusFailed); 658 } 659 660 } else { 661 result.AppendError("Unable to create requested alias.\n"); 662 result.SetStatus(eReturnStatusFailed); 663 } 664 665 return result.Succeeded(); 666 } 667 668 bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) { 669 size_t argc = args.GetArgumentCount(); 670 671 if (argc < 2) { 672 result.AppendError("'command alias' requires at least two arguments"); 673 result.SetStatus(eReturnStatusFailed); 674 return false; 675 } 676 677 // Save these in std::strings since we're going to shift them off. 678 const std::string alias_command(args[0].ref); 679 const std::string actual_command(args[1].ref); 680 681 args.Shift(); // Shift the alias command word off the argument vector. 682 args.Shift(); // Shift the old command word off the argument vector. 683 684 // Verify that the command is alias'able, and get the appropriate command 685 // object. 686 687 if (m_interpreter.CommandExists(alias_command)) { 688 result.AppendErrorWithFormat( 689 "'%s' is a permanent debugger command and cannot be redefined.\n", 690 alias_command.c_str()); 691 result.SetStatus(eReturnStatusFailed); 692 return false; 693 } 694 695 CommandObjectSP command_obj_sp( 696 m_interpreter.GetCommandSPExact(actual_command, true)); 697 CommandObjectSP subcommand_obj_sp; 698 bool use_subcommand = false; 699 if (!command_obj_sp) { 700 result.AppendErrorWithFormat("'%s' is not an existing command.\n", 701 actual_command.c_str()); 702 result.SetStatus(eReturnStatusFailed); 703 return false; 704 } 705 CommandObject *cmd_obj = command_obj_sp.get(); 706 CommandObject *sub_cmd_obj = nullptr; 707 OptionArgVectorSP option_arg_vector_sp = 708 OptionArgVectorSP(new OptionArgVector); 709 710 while (cmd_obj->IsMultiwordObject() && !args.empty()) { 711 auto sub_command = args[0].ref; 712 assert(!sub_command.empty()); 713 subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command); 714 if (!subcommand_obj_sp) { 715 result.AppendErrorWithFormat( 716 "'%s' is not a valid sub-command of '%s'. " 717 "Unable to create alias.\n", 718 args[0].c_str(), actual_command.c_str()); 719 result.SetStatus(eReturnStatusFailed); 720 return false; 721 } 722 723 sub_cmd_obj = subcommand_obj_sp.get(); 724 use_subcommand = true; 725 args.Shift(); // Shift the sub_command word off the argument vector. 726 cmd_obj = sub_cmd_obj; 727 } 728 729 // Verify & handle any options/arguments passed to the alias command 730 731 std::string args_string; 732 733 if (!args.empty()) { 734 CommandObjectSP tmp_sp = 735 m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName(), false); 736 if (use_subcommand) 737 tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName(), 738 false); 739 740 args.GetCommandString(args_string); 741 } 742 743 if (m_interpreter.AliasExists(alias_command) || 744 m_interpreter.UserCommandExists(alias_command)) { 745 result.AppendWarningWithFormat( 746 "Overwriting existing definition for '%s'.\n", alias_command.c_str()); 747 } 748 749 if (CommandAlias *alias = m_interpreter.AddAlias( 750 alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp, 751 args_string)) { 752 if (m_command_options.m_help.OptionWasSet()) 753 alias->SetHelp(m_command_options.m_help.GetCurrentValue()); 754 if (m_command_options.m_long_help.OptionWasSet()) 755 alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue()); 756 result.SetStatus(eReturnStatusSuccessFinishNoResult); 757 } else { 758 result.AppendError("Unable to create requested alias.\n"); 759 result.SetStatus(eReturnStatusFailed); 760 return false; 761 } 762 763 return result.Succeeded(); 764 } 765 }; 766 767 #pragma mark CommandObjectCommandsUnalias 768 //------------------------------------------------------------------------- 769 // CommandObjectCommandsUnalias 770 //------------------------------------------------------------------------- 771 772 class CommandObjectCommandsUnalias : public CommandObjectParsed { 773 public: 774 CommandObjectCommandsUnalias(CommandInterpreter &interpreter) 775 : CommandObjectParsed( 776 interpreter, "command unalias", 777 "Delete one or more custom commands defined by 'command alias'.", 778 nullptr) { 779 CommandArgumentEntry arg; 780 CommandArgumentData alias_arg; 781 782 // Define the first (and only) variant of this arg. 783 alias_arg.arg_type = eArgTypeAliasName; 784 alias_arg.arg_repetition = eArgRepeatPlain; 785 786 // There is only one variant this argument could be; put it into the 787 // argument entry. 788 arg.push_back(alias_arg); 789 790 // Push the data for the first argument into the m_arguments vector. 791 m_arguments.push_back(arg); 792 } 793 794 ~CommandObjectCommandsUnalias() override = default; 795 796 protected: 797 bool DoExecute(Args &args, CommandReturnObject &result) override { 798 CommandObject::CommandMap::iterator pos; 799 CommandObject *cmd_obj; 800 801 if (args.empty()) { 802 result.AppendError("must call 'unalias' with a valid alias"); 803 result.SetStatus(eReturnStatusFailed); 804 return false; 805 } 806 807 auto command_name = args[0].ref; 808 cmd_obj = m_interpreter.GetCommandObject(command_name); 809 if (!cmd_obj) { 810 result.AppendErrorWithFormat( 811 "'%s' is not a known command.\nTry 'help' to see a " 812 "current list of commands.\n", 813 args[0].c_str()); 814 result.SetStatus(eReturnStatusFailed); 815 return false; 816 } 817 818 if (m_interpreter.CommandExists(command_name)) { 819 if (cmd_obj->IsRemovable()) { 820 result.AppendErrorWithFormat( 821 "'%s' is not an alias, it is a debugger command which can be " 822 "removed using the 'command delete' command.\n", 823 args[0].c_str()); 824 } else { 825 result.AppendErrorWithFormat( 826 "'%s' is a permanent debugger command and cannot be removed.\n", 827 args[0].c_str()); 828 } 829 result.SetStatus(eReturnStatusFailed); 830 return false; 831 } 832 833 if (!m_interpreter.RemoveAlias(command_name)) { 834 if (m_interpreter.AliasExists(command_name)) 835 result.AppendErrorWithFormat( 836 "Error occurred while attempting to unalias '%s'.\n", 837 args[0].c_str()); 838 else 839 result.AppendErrorWithFormat("'%s' is not an existing alias.\n", 840 args[0].c_str()); 841 result.SetStatus(eReturnStatusFailed); 842 return false; 843 } 844 845 result.SetStatus(eReturnStatusSuccessFinishNoResult); 846 return result.Succeeded(); 847 } 848 }; 849 850 #pragma mark CommandObjectCommandsDelete 851 //------------------------------------------------------------------------- 852 // CommandObjectCommandsDelete 853 //------------------------------------------------------------------------- 854 855 class CommandObjectCommandsDelete : public CommandObjectParsed { 856 public: 857 CommandObjectCommandsDelete(CommandInterpreter &interpreter) 858 : CommandObjectParsed( 859 interpreter, "command delete", 860 "Delete one or more custom commands defined by 'command regex'.", 861 nullptr) { 862 CommandArgumentEntry arg; 863 CommandArgumentData alias_arg; 864 865 // Define the first (and only) variant of this arg. 866 alias_arg.arg_type = eArgTypeCommandName; 867 alias_arg.arg_repetition = eArgRepeatPlain; 868 869 // There is only one variant this argument could be; put it into the 870 // argument entry. 871 arg.push_back(alias_arg); 872 873 // Push the data for the first argument into the m_arguments vector. 874 m_arguments.push_back(arg); 875 } 876 877 ~CommandObjectCommandsDelete() override = default; 878 879 protected: 880 bool DoExecute(Args &args, CommandReturnObject &result) override { 881 CommandObject::CommandMap::iterator pos; 882 883 if (args.empty()) { 884 result.AppendErrorWithFormat("must call '%s' with one or more valid user " 885 "defined regular expression command names", 886 GetCommandName().str().c_str()); 887 result.SetStatus(eReturnStatusFailed); 888 } 889 890 auto command_name = args[0].ref; 891 if (!m_interpreter.CommandExists(command_name)) { 892 StreamString error_msg_stream; 893 const bool generate_upropos = true; 894 const bool generate_type_lookup = false; 895 CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage( 896 &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(), 897 generate_upropos, generate_type_lookup); 898 result.AppendError(error_msg_stream.GetString()); 899 result.SetStatus(eReturnStatusFailed); 900 return false; 901 } 902 903 if (!m_interpreter.RemoveCommand(command_name)) { 904 result.AppendErrorWithFormat( 905 "'%s' is a permanent debugger command and cannot be removed.\n", 906 args[0].c_str()); 907 result.SetStatus(eReturnStatusFailed); 908 return false; 909 } 910 911 result.SetStatus(eReturnStatusSuccessFinishNoResult); 912 return true; 913 } 914 }; 915 916 //------------------------------------------------------------------------- 917 // CommandObjectCommandsAddRegex 918 //------------------------------------------------------------------------- 919 920 static constexpr OptionDefinition g_regex_options[] = { 921 // clang-format off 922 { LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeNone, "The help text to display for this command." }, 923 { LLDB_OPT_SET_1, false, "syntax", 's', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeNone, "A syntax string showing the typical usage syntax." }, 924 // clang-format on 925 }; 926 927 #pragma mark CommandObjectCommandsAddRegex 928 929 class CommandObjectCommandsAddRegex : public CommandObjectParsed, 930 public IOHandlerDelegateMultiline { 931 public: 932 CommandObjectCommandsAddRegex(CommandInterpreter &interpreter) 933 : CommandObjectParsed( 934 interpreter, "command regex", "Define a custom command in terms of " 935 "existing commands by matching " 936 "regular expressions.", 937 "command regex <cmd-name> [s/<regex>/<subst>/ ...]"), 938 IOHandlerDelegateMultiline("", 939 IOHandlerDelegate::Completion::LLDBCommand), 940 m_options() { 941 SetHelpLong( 942 R"( 943 )" 944 "This command allows the user to create powerful regular expression commands \ 945 with substitutions. The regular expressions and substitutions are specified \ 946 using the regular expression substitution format of:" 947 R"( 948 949 s/<regex>/<subst>/ 950 951 )" 952 "<regex> is a regular expression that can use parenthesis to capture regular \ 953 expression input and substitute the captured matches in the output using %1 \ 954 for the first match, %2 for the second, and so on." 955 R"( 956 957 )" 958 "The regular expressions can all be specified on the command line if more than \ 959 one argument is provided. If just the command name is provided on the command \ 960 line, then the regular expressions and substitutions can be entered on separate \ 961 lines, followed by an empty line to terminate the command definition." 962 R"( 963 964 EXAMPLES 965 966 )" 967 "The following example will define a regular expression command named 'f' that \ 968 will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \ 969 a number follows 'f':" 970 R"( 971 972 (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')"); 973 } 974 975 ~CommandObjectCommandsAddRegex() override = default; 976 977 protected: 978 void IOHandlerActivated(IOHandler &io_handler) override { 979 StreamFileSP output_sp(io_handler.GetOutputStreamFile()); 980 if (output_sp) { 981 output_sp->PutCString("Enter one of more sed substitution commands in " 982 "the form: 's/<regex>/<subst>/'.\nTerminate the " 983 "substitution list with an empty line.\n"); 984 output_sp->Flush(); 985 } 986 } 987 988 void IOHandlerInputComplete(IOHandler &io_handler, 989 std::string &data) override { 990 io_handler.SetIsDone(true); 991 if (m_regex_cmd_up) { 992 StringList lines; 993 if (lines.SplitIntoLines(data)) { 994 const size_t num_lines = lines.GetSize(); 995 bool check_only = false; 996 for (size_t i = 0; i < num_lines; ++i) { 997 llvm::StringRef bytes_strref(lines[i]); 998 Status error = AppendRegexSubstitution(bytes_strref, check_only); 999 if (error.Fail()) { 1000 if (!m_interpreter.GetDebugger() 1001 .GetCommandInterpreter() 1002 .GetBatchCommandMode()) { 1003 StreamSP out_stream = 1004 m_interpreter.GetDebugger().GetAsyncOutputStream(); 1005 out_stream->Printf("error: %s\n", error.AsCString()); 1006 } 1007 } 1008 } 1009 } 1010 if (m_regex_cmd_up->HasRegexEntries()) { 1011 CommandObjectSP cmd_sp(m_regex_cmd_up.release()); 1012 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 1013 } 1014 } 1015 } 1016 1017 bool DoExecute(Args &command, CommandReturnObject &result) override { 1018 const size_t argc = command.GetArgumentCount(); 1019 if (argc == 0) { 1020 result.AppendError("usage: 'command regex <command-name> " 1021 "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n"); 1022 result.SetStatus(eReturnStatusFailed); 1023 return false; 1024 } 1025 1026 Status error; 1027 auto name = command[0].ref; 1028 m_regex_cmd_up = llvm::make_unique<CommandObjectRegexCommand>( 1029 m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 10, 0, 1030 true); 1031 1032 if (argc == 1) { 1033 Debugger &debugger = m_interpreter.GetDebugger(); 1034 bool color_prompt = debugger.GetUseColor(); 1035 const bool multiple_lines = true; // Get multiple lines 1036 IOHandlerSP io_handler_sp(new IOHandlerEditline( 1037 debugger, IOHandler::Type::Other, 1038 "lldb-regex", // Name of input reader for history 1039 llvm::StringRef("> "), // Prompt 1040 llvm::StringRef(), // Continuation prompt 1041 multiple_lines, color_prompt, 1042 0, // Don't show line numbers 1043 *this, nullptr)); 1044 1045 if (io_handler_sp) { 1046 debugger.PushIOHandler(io_handler_sp); 1047 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1048 } 1049 } else { 1050 for (auto &entry : command.entries().drop_front()) { 1051 bool check_only = false; 1052 error = AppendRegexSubstitution(entry.ref, check_only); 1053 if (error.Fail()) 1054 break; 1055 } 1056 1057 if (error.Success()) { 1058 AddRegexCommandToInterpreter(); 1059 } 1060 } 1061 if (error.Fail()) { 1062 result.AppendError(error.AsCString()); 1063 result.SetStatus(eReturnStatusFailed); 1064 } 1065 1066 return result.Succeeded(); 1067 } 1068 1069 Status AppendRegexSubstitution(const llvm::StringRef ®ex_sed, 1070 bool check_only) { 1071 Status error; 1072 1073 if (!m_regex_cmd_up) { 1074 error.SetErrorStringWithFormat( 1075 "invalid regular expression command object for: '%.*s'", 1076 (int)regex_sed.size(), regex_sed.data()); 1077 return error; 1078 } 1079 1080 size_t regex_sed_size = regex_sed.size(); 1081 1082 if (regex_sed_size <= 1) { 1083 error.SetErrorStringWithFormat( 1084 "regular expression substitution string is too short: '%.*s'", 1085 (int)regex_sed.size(), regex_sed.data()); 1086 return error; 1087 } 1088 1089 if (regex_sed[0] != 's') { 1090 error.SetErrorStringWithFormat("regular expression substitution string " 1091 "doesn't start with 's': '%.*s'", 1092 (int)regex_sed.size(), regex_sed.data()); 1093 return error; 1094 } 1095 const size_t first_separator_char_pos = 1; 1096 // use the char that follows 's' as the regex separator character so we can 1097 // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|" 1098 const char separator_char = regex_sed[first_separator_char_pos]; 1099 const size_t second_separator_char_pos = 1100 regex_sed.find(separator_char, first_separator_char_pos + 1); 1101 1102 if (second_separator_char_pos == std::string::npos) { 1103 error.SetErrorStringWithFormat( 1104 "missing second '%c' separator char after '%.*s' in '%.*s'", 1105 separator_char, 1106 (int)(regex_sed.size() - first_separator_char_pos - 1), 1107 regex_sed.data() + (first_separator_char_pos + 1), 1108 (int)regex_sed.size(), regex_sed.data()); 1109 return error; 1110 } 1111 1112 const size_t third_separator_char_pos = 1113 regex_sed.find(separator_char, second_separator_char_pos + 1); 1114 1115 if (third_separator_char_pos == std::string::npos) { 1116 error.SetErrorStringWithFormat( 1117 "missing third '%c' separator char after '%.*s' in '%.*s'", 1118 separator_char, 1119 (int)(regex_sed.size() - second_separator_char_pos - 1), 1120 regex_sed.data() + (second_separator_char_pos + 1), 1121 (int)regex_sed.size(), regex_sed.data()); 1122 return error; 1123 } 1124 1125 if (third_separator_char_pos != regex_sed_size - 1) { 1126 // Make sure that everything that follows the last regex separator char 1127 if (regex_sed.find_first_not_of("\t\n\v\f\r ", 1128 third_separator_char_pos + 1) != 1129 std::string::npos) { 1130 error.SetErrorStringWithFormat( 1131 "extra data found after the '%.*s' regular expression substitution " 1132 "string: '%.*s'", 1133 (int)third_separator_char_pos + 1, regex_sed.data(), 1134 (int)(regex_sed.size() - third_separator_char_pos - 1), 1135 regex_sed.data() + (third_separator_char_pos + 1)); 1136 return error; 1137 } 1138 } else if (first_separator_char_pos + 1 == second_separator_char_pos) { 1139 error.SetErrorStringWithFormat( 1140 "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 1141 separator_char, separator_char, separator_char, (int)regex_sed.size(), 1142 regex_sed.data()); 1143 return error; 1144 } else if (second_separator_char_pos + 1 == third_separator_char_pos) { 1145 error.SetErrorStringWithFormat( 1146 "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 1147 separator_char, separator_char, separator_char, (int)regex_sed.size(), 1148 regex_sed.data()); 1149 return error; 1150 } 1151 1152 if (!check_only) { 1153 std::string regex(regex_sed.substr(first_separator_char_pos + 1, 1154 second_separator_char_pos - 1155 first_separator_char_pos - 1)); 1156 std::string subst(regex_sed.substr(second_separator_char_pos + 1, 1157 third_separator_char_pos - 1158 second_separator_char_pos - 1)); 1159 m_regex_cmd_up->AddRegexCommand(regex.c_str(), subst.c_str()); 1160 } 1161 return error; 1162 } 1163 1164 void AddRegexCommandToInterpreter() { 1165 if (m_regex_cmd_up) { 1166 if (m_regex_cmd_up->HasRegexEntries()) { 1167 CommandObjectSP cmd_sp(m_regex_cmd_up.release()); 1168 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 1169 } 1170 } 1171 } 1172 1173 private: 1174 std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up; 1175 1176 class CommandOptions : public Options { 1177 public: 1178 CommandOptions() : Options() {} 1179 1180 ~CommandOptions() override = default; 1181 1182 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1183 ExecutionContext *execution_context) override { 1184 Status error; 1185 const int short_option = m_getopt_table[option_idx].val; 1186 1187 switch (short_option) { 1188 case 'h': 1189 m_help.assign(option_arg); 1190 break; 1191 case 's': 1192 m_syntax.assign(option_arg); 1193 break; 1194 default: 1195 error.SetErrorStringWithFormat("unrecognized option '%c'", 1196 short_option); 1197 break; 1198 } 1199 1200 return error; 1201 } 1202 1203 void OptionParsingStarting(ExecutionContext *execution_context) override { 1204 m_help.clear(); 1205 m_syntax.clear(); 1206 } 1207 1208 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1209 return llvm::makeArrayRef(g_regex_options); 1210 } 1211 1212 // TODO: Convert these functions to return StringRefs. 1213 const char *GetHelp() { 1214 return (m_help.empty() ? nullptr : m_help.c_str()); 1215 } 1216 1217 const char *GetSyntax() { 1218 return (m_syntax.empty() ? nullptr : m_syntax.c_str()); 1219 } 1220 1221 protected: 1222 // Instance variables to hold the values for command options. 1223 1224 std::string m_help; 1225 std::string m_syntax; 1226 }; 1227 1228 Options *GetOptions() override { return &m_options; } 1229 1230 CommandOptions m_options; 1231 }; 1232 1233 class CommandObjectPythonFunction : public CommandObjectRaw { 1234 public: 1235 CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name, 1236 std::string funct, std::string help, 1237 ScriptedCommandSynchronicity synch) 1238 : CommandObjectRaw(interpreter, name), 1239 m_function_name(funct), m_synchro(synch), m_fetched_help_long(false) { 1240 if (!help.empty()) 1241 SetHelp(help); 1242 else { 1243 StreamString stream; 1244 stream.Printf("For more information run 'help %s'", name.c_str()); 1245 SetHelp(stream.GetString()); 1246 } 1247 } 1248 1249 ~CommandObjectPythonFunction() override = default; 1250 1251 bool IsRemovable() const override { return true; } 1252 1253 const std::string &GetFunctionName() { return m_function_name; } 1254 1255 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1256 1257 llvm::StringRef GetHelpLong() override { 1258 if (m_fetched_help_long) 1259 return CommandObjectRaw::GetHelpLong(); 1260 1261 ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter(); 1262 if (!scripter) 1263 return CommandObjectRaw::GetHelpLong(); 1264 1265 std::string docstring; 1266 m_fetched_help_long = 1267 scripter->GetDocumentationForItem(m_function_name.c_str(), docstring); 1268 if (!docstring.empty()) 1269 SetHelpLong(docstring); 1270 return CommandObjectRaw::GetHelpLong(); 1271 } 1272 1273 protected: 1274 bool DoExecute(llvm::StringRef raw_command_line, 1275 CommandReturnObject &result) override { 1276 ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter(); 1277 1278 Status error; 1279 1280 result.SetStatus(eReturnStatusInvalid); 1281 1282 if (!scripter || 1283 !scripter->RunScriptBasedCommand(m_function_name.c_str(), 1284 raw_command_line, m_synchro, result, 1285 error, m_exe_ctx)) { 1286 result.AppendError(error.AsCString()); 1287 result.SetStatus(eReturnStatusFailed); 1288 } else { 1289 // Don't change the status if the command already set it... 1290 if (result.GetStatus() == eReturnStatusInvalid) { 1291 if (result.GetOutputData().empty()) 1292 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1293 else 1294 result.SetStatus(eReturnStatusSuccessFinishResult); 1295 } 1296 } 1297 1298 return result.Succeeded(); 1299 } 1300 1301 private: 1302 std::string m_function_name; 1303 ScriptedCommandSynchronicity m_synchro; 1304 bool m_fetched_help_long; 1305 }; 1306 1307 class CommandObjectScriptingObject : public CommandObjectRaw { 1308 public: 1309 CommandObjectScriptingObject(CommandInterpreter &interpreter, 1310 std::string name, 1311 StructuredData::GenericSP cmd_obj_sp, 1312 ScriptedCommandSynchronicity synch) 1313 : CommandObjectRaw(interpreter, name), 1314 m_cmd_obj_sp(cmd_obj_sp), m_synchro(synch), m_fetched_help_short(false), 1315 m_fetched_help_long(false) { 1316 StreamString stream; 1317 stream.Printf("For more information run 'help %s'", name.c_str()); 1318 SetHelp(stream.GetString()); 1319 if (ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter()) 1320 GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); 1321 } 1322 1323 ~CommandObjectScriptingObject() override = default; 1324 1325 bool IsRemovable() const override { return true; } 1326 1327 StructuredData::GenericSP GetImplementingObject() { return m_cmd_obj_sp; } 1328 1329 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1330 1331 llvm::StringRef GetHelp() override { 1332 if (m_fetched_help_short) 1333 return CommandObjectRaw::GetHelp(); 1334 ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter(); 1335 if (!scripter) 1336 return CommandObjectRaw::GetHelp(); 1337 std::string docstring; 1338 m_fetched_help_short = 1339 scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring); 1340 if (!docstring.empty()) 1341 SetHelp(docstring); 1342 1343 return CommandObjectRaw::GetHelp(); 1344 } 1345 1346 llvm::StringRef GetHelpLong() override { 1347 if (m_fetched_help_long) 1348 return CommandObjectRaw::GetHelpLong(); 1349 1350 ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter(); 1351 if (!scripter) 1352 return CommandObjectRaw::GetHelpLong(); 1353 1354 std::string docstring; 1355 m_fetched_help_long = 1356 scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring); 1357 if (!docstring.empty()) 1358 SetHelpLong(docstring); 1359 return CommandObjectRaw::GetHelpLong(); 1360 } 1361 1362 protected: 1363 bool DoExecute(llvm::StringRef raw_command_line, 1364 CommandReturnObject &result) override { 1365 ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter(); 1366 1367 Status error; 1368 1369 result.SetStatus(eReturnStatusInvalid); 1370 1371 if (!scripter || 1372 !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line, 1373 m_synchro, result, error, m_exe_ctx)) { 1374 result.AppendError(error.AsCString()); 1375 result.SetStatus(eReturnStatusFailed); 1376 } else { 1377 // Don't change the status if the command already set it... 1378 if (result.GetStatus() == eReturnStatusInvalid) { 1379 if (result.GetOutputData().empty()) 1380 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1381 else 1382 result.SetStatus(eReturnStatusSuccessFinishResult); 1383 } 1384 } 1385 1386 return result.Succeeded(); 1387 } 1388 1389 private: 1390 StructuredData::GenericSP m_cmd_obj_sp; 1391 ScriptedCommandSynchronicity m_synchro; 1392 bool m_fetched_help_short : 1; 1393 bool m_fetched_help_long : 1; 1394 }; 1395 1396 //------------------------------------------------------------------------- 1397 // CommandObjectCommandsScriptImport 1398 //------------------------------------------------------------------------- 1399 1400 static constexpr OptionDefinition g_script_import_options[] = { 1401 // clang-format off 1402 { LLDB_OPT_SET_1, false, "allow-reload", 'r', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Allow the script to be loaded even if it was already loaded before. This argument exists for backwards compatibility, but reloading is always allowed, whether you specify it or not." }, 1403 // clang-format on 1404 }; 1405 1406 class CommandObjectCommandsScriptImport : public CommandObjectParsed { 1407 public: 1408 CommandObjectCommandsScriptImport(CommandInterpreter &interpreter) 1409 : CommandObjectParsed(interpreter, "command script import", 1410 "Import a scripting module in LLDB.", nullptr), 1411 m_options() { 1412 CommandArgumentEntry arg1; 1413 CommandArgumentData cmd_arg; 1414 1415 // Define the first (and only) variant of this arg. 1416 cmd_arg.arg_type = eArgTypeFilename; 1417 cmd_arg.arg_repetition = eArgRepeatPlus; 1418 1419 // There is only one variant this argument could be; put it into the 1420 // argument entry. 1421 arg1.push_back(cmd_arg); 1422 1423 // Push the data for the first argument into the m_arguments vector. 1424 m_arguments.push_back(arg1); 1425 } 1426 1427 ~CommandObjectCommandsScriptImport() override = default; 1428 1429 int HandleArgumentCompletion( 1430 CompletionRequest &request, 1431 OptionElementVector &opt_element_vector) override { 1432 CommandCompletions::InvokeCommonCompletionCallbacks( 1433 GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, 1434 request, nullptr); 1435 return request.GetNumberOfMatches(); 1436 } 1437 1438 Options *GetOptions() override { return &m_options; } 1439 1440 protected: 1441 class CommandOptions : public Options { 1442 public: 1443 CommandOptions() : Options() {} 1444 1445 ~CommandOptions() override = default; 1446 1447 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1448 ExecutionContext *execution_context) override { 1449 Status error; 1450 const int short_option = m_getopt_table[option_idx].val; 1451 1452 switch (short_option) { 1453 case 'r': 1454 m_allow_reload = true; 1455 break; 1456 default: 1457 error.SetErrorStringWithFormat("unrecognized option '%c'", 1458 short_option); 1459 break; 1460 } 1461 1462 return error; 1463 } 1464 1465 void OptionParsingStarting(ExecutionContext *execution_context) override { 1466 m_allow_reload = true; 1467 } 1468 1469 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1470 return llvm::makeArrayRef(g_script_import_options); 1471 } 1472 1473 // Instance variables to hold the values for command options. 1474 1475 bool m_allow_reload; 1476 }; 1477 1478 bool DoExecute(Args &command, CommandReturnObject &result) override { 1479 if (m_interpreter.GetDebugger().GetScriptLanguage() != 1480 lldb::eScriptLanguagePython) { 1481 result.AppendError("only scripting language supported for module " 1482 "importing is currently Python"); 1483 result.SetStatus(eReturnStatusFailed); 1484 return false; 1485 } 1486 1487 if (command.empty()) { 1488 result.AppendError("command script import needs one or more arguments"); 1489 result.SetStatus(eReturnStatusFailed); 1490 return false; 1491 } 1492 1493 for (auto &entry : command.entries()) { 1494 Status error; 1495 1496 const bool init_session = true; 1497 // FIXME: this is necessary because CommandObject::CheckRequirements() 1498 // assumes that commands won't ever be recursively invoked, but it's 1499 // actually possible to craft a Python script that does other "command 1500 // script imports" in __lldb_init_module the real fix is to have 1501 // recursive commands possible with a CommandInvocation object separate 1502 // from the CommandObject itself, so that recursive command invocations 1503 // won't stomp on each other (wrt to execution contents, options, and 1504 // more) 1505 m_exe_ctx.Clear(); 1506 if (m_interpreter.GetScriptInterpreter()->LoadScriptingModule( 1507 entry.c_str(), m_options.m_allow_reload, init_session, error)) { 1508 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1509 } else { 1510 result.AppendErrorWithFormat("module importing failed: %s", 1511 error.AsCString()); 1512 result.SetStatus(eReturnStatusFailed); 1513 } 1514 } 1515 1516 return result.Succeeded(); 1517 } 1518 1519 CommandOptions m_options; 1520 }; 1521 1522 //------------------------------------------------------------------------- 1523 // CommandObjectCommandsScriptAdd 1524 //------------------------------------------------------------------------- 1525 static constexpr OptionEnumValueElement g_script_synchro_type[] = { 1526 {eScriptedCommandSynchronicitySynchronous, "synchronous", 1527 "Run synchronous"}, 1528 {eScriptedCommandSynchronicityAsynchronous, "asynchronous", 1529 "Run asynchronous"}, 1530 {eScriptedCommandSynchronicityCurrentValue, "current", 1531 "Do not alter current setting"} }; 1532 1533 static constexpr OptionEnumValues ScriptSynchroType() { 1534 return OptionEnumValues(g_script_synchro_type); 1535 } 1536 1537 static constexpr OptionDefinition g_script_add_options[] = { 1538 // clang-format off 1539 { LLDB_OPT_SET_1, false, "function", 'f', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypePythonFunction, "Name of the Python function to bind to this command name." }, 1540 { LLDB_OPT_SET_2, false, "class", 'c', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypePythonClass, "Name of the Python class to bind to this command name." }, 1541 { LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeHelpText, "The help text to display for this command." }, 1542 { LLDB_OPT_SET_ALL, false, "synchronicity", 's', OptionParser::eRequiredArgument, nullptr, ScriptSynchroType(), 0, eArgTypeScriptedCommandSynchronicity, "Set the synchronicity of this command's executions with regard to LLDB event system." }, 1543 // clang-format on 1544 }; 1545 1546 class CommandObjectCommandsScriptAdd : public CommandObjectParsed, 1547 public IOHandlerDelegateMultiline { 1548 public: 1549 CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) 1550 : CommandObjectParsed(interpreter, "command script add", 1551 "Add a scripted function as an LLDB command.", 1552 nullptr), 1553 IOHandlerDelegateMultiline("DONE"), m_options() { 1554 CommandArgumentEntry arg1; 1555 CommandArgumentData cmd_arg; 1556 1557 // Define the first (and only) variant of this arg. 1558 cmd_arg.arg_type = eArgTypeCommandName; 1559 cmd_arg.arg_repetition = eArgRepeatPlain; 1560 1561 // There is only one variant this argument could be; put it into the 1562 // argument entry. 1563 arg1.push_back(cmd_arg); 1564 1565 // Push the data for the first argument into the m_arguments vector. 1566 m_arguments.push_back(arg1); 1567 } 1568 1569 ~CommandObjectCommandsScriptAdd() override = default; 1570 1571 Options *GetOptions() override { return &m_options; } 1572 1573 protected: 1574 class CommandOptions : public Options { 1575 public: 1576 CommandOptions() 1577 : Options(), m_class_name(), m_funct_name(), m_short_help(), 1578 m_synchronicity(eScriptedCommandSynchronicitySynchronous) {} 1579 1580 ~CommandOptions() override = default; 1581 1582 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1583 ExecutionContext *execution_context) override { 1584 Status error; 1585 const int short_option = m_getopt_table[option_idx].val; 1586 1587 switch (short_option) { 1588 case 'f': 1589 if (!option_arg.empty()) 1590 m_funct_name = option_arg; 1591 break; 1592 case 'c': 1593 if (!option_arg.empty()) 1594 m_class_name = option_arg; 1595 break; 1596 case 'h': 1597 if (!option_arg.empty()) 1598 m_short_help = option_arg; 1599 break; 1600 case 's': 1601 m_synchronicity = 1602 (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum( 1603 option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 1604 if (!error.Success()) 1605 error.SetErrorStringWithFormat( 1606 "unrecognized value for synchronicity '%s'", 1607 option_arg.str().c_str()); 1608 break; 1609 default: 1610 error.SetErrorStringWithFormat("unrecognized option '%c'", 1611 short_option); 1612 break; 1613 } 1614 1615 return error; 1616 } 1617 1618 void OptionParsingStarting(ExecutionContext *execution_context) override { 1619 m_class_name.clear(); 1620 m_funct_name.clear(); 1621 m_short_help.clear(); 1622 m_synchronicity = eScriptedCommandSynchronicitySynchronous; 1623 } 1624 1625 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1626 return llvm::makeArrayRef(g_script_add_options); 1627 } 1628 1629 // Instance variables to hold the values for command options. 1630 1631 std::string m_class_name; 1632 std::string m_funct_name; 1633 std::string m_short_help; 1634 ScriptedCommandSynchronicity m_synchronicity; 1635 }; 1636 1637 void IOHandlerActivated(IOHandler &io_handler) override { 1638 StreamFileSP output_sp(io_handler.GetOutputStreamFile()); 1639 if (output_sp) { 1640 output_sp->PutCString(g_python_command_instructions); 1641 output_sp->Flush(); 1642 } 1643 } 1644 1645 void IOHandlerInputComplete(IOHandler &io_handler, 1646 std::string &data) override { 1647 StreamFileSP error_sp = io_handler.GetErrorStreamFile(); 1648 1649 ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); 1650 if (interpreter) { 1651 1652 StringList lines; 1653 lines.SplitIntoLines(data); 1654 if (lines.GetSize() > 0) { 1655 std::string funct_name_str; 1656 if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) { 1657 if (funct_name_str.empty()) { 1658 error_sp->Printf("error: unable to obtain a function name, didn't " 1659 "add python command.\n"); 1660 error_sp->Flush(); 1661 } else { 1662 // everything should be fine now, let's add this alias 1663 1664 CommandObjectSP command_obj_sp(new CommandObjectPythonFunction( 1665 m_interpreter, m_cmd_name, funct_name_str, m_short_help, 1666 m_synchronicity)); 1667 1668 if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp, 1669 true)) { 1670 error_sp->Printf("error: unable to add selected command, didn't " 1671 "add python command.\n"); 1672 error_sp->Flush(); 1673 } 1674 } 1675 } else { 1676 error_sp->Printf( 1677 "error: unable to create function, didn't add python command.\n"); 1678 error_sp->Flush(); 1679 } 1680 } else { 1681 error_sp->Printf("error: empty function, didn't add python command.\n"); 1682 error_sp->Flush(); 1683 } 1684 } else { 1685 error_sp->Printf( 1686 "error: script interpreter missing, didn't add python command.\n"); 1687 error_sp->Flush(); 1688 } 1689 1690 io_handler.SetIsDone(true); 1691 } 1692 1693 protected: 1694 bool DoExecute(Args &command, CommandReturnObject &result) override { 1695 if (m_interpreter.GetDebugger().GetScriptLanguage() != 1696 lldb::eScriptLanguagePython) { 1697 result.AppendError("only scripting language supported for scripted " 1698 "commands is currently Python"); 1699 result.SetStatus(eReturnStatusFailed); 1700 return false; 1701 } 1702 1703 if (command.GetArgumentCount() != 1) { 1704 result.AppendError("'command script add' requires one argument"); 1705 result.SetStatus(eReturnStatusFailed); 1706 return false; 1707 } 1708 1709 // Store the options in case we get multi-line input 1710 m_cmd_name = command[0].ref; 1711 m_short_help.assign(m_options.m_short_help); 1712 m_synchronicity = m_options.m_synchronicity; 1713 1714 if (m_options.m_class_name.empty()) { 1715 if (m_options.m_funct_name.empty()) { 1716 m_interpreter.GetPythonCommandsFromIOHandler( 1717 " ", // Prompt 1718 *this, // IOHandlerDelegate 1719 true, // Run IOHandler in async mode 1720 nullptr); // Baton for the "io_handler" that will be passed back 1721 // into our IOHandlerDelegate functions 1722 } else { 1723 CommandObjectSP new_cmd(new CommandObjectPythonFunction( 1724 m_interpreter, m_cmd_name, m_options.m_funct_name, 1725 m_options.m_short_help, m_synchronicity)); 1726 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { 1727 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1728 } else { 1729 result.AppendError("cannot add command"); 1730 result.SetStatus(eReturnStatusFailed); 1731 } 1732 } 1733 } else { 1734 ScriptInterpreter *interpreter = 1735 GetCommandInterpreter().GetScriptInterpreter(); 1736 if (!interpreter) { 1737 result.AppendError("cannot find ScriptInterpreter"); 1738 result.SetStatus(eReturnStatusFailed); 1739 return false; 1740 } 1741 1742 auto cmd_obj_sp = interpreter->CreateScriptCommandObject( 1743 m_options.m_class_name.c_str()); 1744 if (!cmd_obj_sp) { 1745 result.AppendError("cannot create helper object"); 1746 result.SetStatus(eReturnStatusFailed); 1747 return false; 1748 } 1749 1750 CommandObjectSP new_cmd(new CommandObjectScriptingObject( 1751 m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity)); 1752 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { 1753 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1754 } else { 1755 result.AppendError("cannot add command"); 1756 result.SetStatus(eReturnStatusFailed); 1757 } 1758 } 1759 1760 return result.Succeeded(); 1761 } 1762 1763 CommandOptions m_options; 1764 std::string m_cmd_name; 1765 std::string m_short_help; 1766 ScriptedCommandSynchronicity m_synchronicity; 1767 }; 1768 1769 //------------------------------------------------------------------------- 1770 // CommandObjectCommandsScriptList 1771 //------------------------------------------------------------------------- 1772 1773 class CommandObjectCommandsScriptList : public CommandObjectParsed { 1774 public: 1775 CommandObjectCommandsScriptList(CommandInterpreter &interpreter) 1776 : CommandObjectParsed(interpreter, "command script list", 1777 "List defined scripted commands.", nullptr) {} 1778 1779 ~CommandObjectCommandsScriptList() override = default; 1780 1781 bool DoExecute(Args &command, CommandReturnObject &result) override { 1782 m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef); 1783 1784 result.SetStatus(eReturnStatusSuccessFinishResult); 1785 1786 return true; 1787 } 1788 }; 1789 1790 //------------------------------------------------------------------------- 1791 // CommandObjectCommandsScriptClear 1792 //------------------------------------------------------------------------- 1793 1794 class CommandObjectCommandsScriptClear : public CommandObjectParsed { 1795 public: 1796 CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) 1797 : CommandObjectParsed(interpreter, "command script clear", 1798 "Delete all scripted commands.", nullptr) {} 1799 1800 ~CommandObjectCommandsScriptClear() override = default; 1801 1802 protected: 1803 bool DoExecute(Args &command, CommandReturnObject &result) override { 1804 m_interpreter.RemoveAllUser(); 1805 1806 result.SetStatus(eReturnStatusSuccessFinishResult); 1807 1808 return true; 1809 } 1810 }; 1811 1812 //------------------------------------------------------------------------- 1813 // CommandObjectCommandsScriptDelete 1814 //------------------------------------------------------------------------- 1815 1816 class CommandObjectCommandsScriptDelete : public CommandObjectParsed { 1817 public: 1818 CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) 1819 : CommandObjectParsed(interpreter, "command script delete", 1820 "Delete a scripted command.", nullptr) { 1821 CommandArgumentEntry arg1; 1822 CommandArgumentData cmd_arg; 1823 1824 // Define the first (and only) variant of this arg. 1825 cmd_arg.arg_type = eArgTypeCommandName; 1826 cmd_arg.arg_repetition = eArgRepeatPlain; 1827 1828 // There is only one variant this argument could be; put it into the 1829 // argument entry. 1830 arg1.push_back(cmd_arg); 1831 1832 // Push the data for the first argument into the m_arguments vector. 1833 m_arguments.push_back(arg1); 1834 } 1835 1836 ~CommandObjectCommandsScriptDelete() override = default; 1837 1838 protected: 1839 bool DoExecute(Args &command, CommandReturnObject &result) override { 1840 1841 if (command.GetArgumentCount() != 1) { 1842 result.AppendError("'command script delete' requires one argument"); 1843 result.SetStatus(eReturnStatusFailed); 1844 return false; 1845 } 1846 1847 auto cmd_name = command[0].ref; 1848 1849 if (cmd_name.empty() || !m_interpreter.HasUserCommands() || 1850 !m_interpreter.UserCommandExists(cmd_name)) { 1851 result.AppendErrorWithFormat("command %s not found", command[0].c_str()); 1852 result.SetStatus(eReturnStatusFailed); 1853 return false; 1854 } 1855 1856 m_interpreter.RemoveUser(cmd_name); 1857 result.SetStatus(eReturnStatusSuccessFinishResult); 1858 return true; 1859 } 1860 }; 1861 1862 #pragma mark CommandObjectMultiwordCommandsScript 1863 1864 //------------------------------------------------------------------------- 1865 // CommandObjectMultiwordCommandsScript 1866 //------------------------------------------------------------------------- 1867 1868 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword { 1869 public: 1870 CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter) 1871 : CommandObjectMultiword( 1872 interpreter, "command script", "Commands for managing custom " 1873 "commands implemented by " 1874 "interpreter scripts.", 1875 "command script <subcommand> [<subcommand-options>]") { 1876 LoadSubCommand("add", CommandObjectSP( 1877 new CommandObjectCommandsScriptAdd(interpreter))); 1878 LoadSubCommand( 1879 "delete", 1880 CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter))); 1881 LoadSubCommand( 1882 "clear", 1883 CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter))); 1884 LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList( 1885 interpreter))); 1886 LoadSubCommand( 1887 "import", 1888 CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter))); 1889 } 1890 1891 ~CommandObjectMultiwordCommandsScript() override = default; 1892 }; 1893 1894 #pragma mark CommandObjectMultiwordCommands 1895 1896 //------------------------------------------------------------------------- 1897 // CommandObjectMultiwordCommands 1898 //------------------------------------------------------------------------- 1899 1900 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands( 1901 CommandInterpreter &interpreter) 1902 : CommandObjectMultiword(interpreter, "command", 1903 "Commands for managing custom LLDB commands.", 1904 "command <subcommand> [<subcommand-options>]") { 1905 LoadSubCommand("source", 1906 CommandObjectSP(new CommandObjectCommandsSource(interpreter))); 1907 LoadSubCommand("alias", 1908 CommandObjectSP(new CommandObjectCommandsAlias(interpreter))); 1909 LoadSubCommand("unalias", CommandObjectSP( 1910 new CommandObjectCommandsUnalias(interpreter))); 1911 LoadSubCommand("delete", 1912 CommandObjectSP(new CommandObjectCommandsDelete(interpreter))); 1913 LoadSubCommand( 1914 "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter))); 1915 LoadSubCommand("history", CommandObjectSP( 1916 new CommandObjectCommandsHistory(interpreter))); 1917 LoadSubCommand( 1918 "script", 1919 CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter))); 1920 } 1921 1922 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default; 1923