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