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