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