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