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