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