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