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