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