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