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, llvm::StringRef(), llvm::StringRef(), generate_apropos, 950 generate_type_lookup); 951 result.AppendError(error_msg_stream.GetString()); 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.GetString()); 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().empty()) 1336 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1337 else 1338 result.SetStatus(eReturnStatusSuccessFinishResult); 1339 } 1340 } 1341 1342 return result.Succeeded(); 1343 } 1344 1345 private: 1346 std::string m_function_name; 1347 ScriptedCommandSynchronicity m_synchro; 1348 bool m_fetched_help_long; 1349 }; 1350 1351 class CommandObjectScriptingObject : public CommandObjectRaw { 1352 public: 1353 CommandObjectScriptingObject(CommandInterpreter &interpreter, 1354 std::string name, 1355 StructuredData::GenericSP cmd_obj_sp, 1356 ScriptedCommandSynchronicity synch) 1357 : CommandObjectRaw(interpreter, name), 1358 m_cmd_obj_sp(cmd_obj_sp), m_synchro(synch), m_fetched_help_short(false), 1359 m_fetched_help_long(false) { 1360 StreamString stream; 1361 stream.Printf("For more information run 'help %s'", name.c_str()); 1362 SetHelp(stream.GetString()); 1363 if (ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter()) 1364 GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); 1365 } 1366 1367 ~CommandObjectScriptingObject() override = default; 1368 1369 bool IsRemovable() const override { return true; } 1370 1371 StructuredData::GenericSP GetImplementingObject() { return m_cmd_obj_sp; } 1372 1373 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1374 1375 llvm::StringRef GetHelp() override { 1376 if (m_fetched_help_short) 1377 return CommandObjectRaw::GetHelp(); 1378 ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter(); 1379 if (!scripter) 1380 return CommandObjectRaw::GetHelp(); 1381 std::string docstring; 1382 m_fetched_help_short = 1383 scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring); 1384 if (!docstring.empty()) 1385 SetHelp(docstring); 1386 1387 return CommandObjectRaw::GetHelp(); 1388 } 1389 1390 llvm::StringRef GetHelpLong() override { 1391 if (m_fetched_help_long) 1392 return CommandObjectRaw::GetHelpLong(); 1393 1394 ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter(); 1395 if (!scripter) 1396 return CommandObjectRaw::GetHelpLong(); 1397 1398 std::string docstring; 1399 m_fetched_help_long = 1400 scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring); 1401 if (!docstring.empty()) 1402 SetHelpLong(docstring); 1403 return CommandObjectRaw::GetHelpLong(); 1404 } 1405 1406 protected: 1407 bool DoExecute(const char *raw_command_line, 1408 CommandReturnObject &result) override { 1409 ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter(); 1410 1411 Error error; 1412 1413 result.SetStatus(eReturnStatusInvalid); 1414 1415 if (!scripter || 1416 !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line, 1417 m_synchro, result, error, m_exe_ctx)) { 1418 result.AppendError(error.AsCString()); 1419 result.SetStatus(eReturnStatusFailed); 1420 } else { 1421 // Don't change the status if the command already set it... 1422 if (result.GetStatus() == eReturnStatusInvalid) { 1423 if (result.GetOutputData().empty()) 1424 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1425 else 1426 result.SetStatus(eReturnStatusSuccessFinishResult); 1427 } 1428 } 1429 1430 return result.Succeeded(); 1431 } 1432 1433 private: 1434 StructuredData::GenericSP m_cmd_obj_sp; 1435 ScriptedCommandSynchronicity m_synchro; 1436 bool m_fetched_help_short : 1; 1437 bool m_fetched_help_long : 1; 1438 }; 1439 1440 //------------------------------------------------------------------------- 1441 // CommandObjectCommandsScriptImport 1442 //------------------------------------------------------------------------- 1443 1444 OptionDefinition g_script_import_options[] = { 1445 // clang-format off 1446 { 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." }, 1447 // clang-format on 1448 }; 1449 1450 class CommandObjectCommandsScriptImport : public CommandObjectParsed { 1451 public: 1452 CommandObjectCommandsScriptImport(CommandInterpreter &interpreter) 1453 : CommandObjectParsed(interpreter, "command script import", 1454 "Import a scripting module in LLDB.", nullptr), 1455 m_options() { 1456 CommandArgumentEntry arg1; 1457 CommandArgumentData cmd_arg; 1458 1459 // Define the first (and only) variant of this arg. 1460 cmd_arg.arg_type = eArgTypeFilename; 1461 cmd_arg.arg_repetition = eArgRepeatPlus; 1462 1463 // There is only one variant this argument could be; put it into the 1464 // argument entry. 1465 arg1.push_back(cmd_arg); 1466 1467 // Push the data for the first argument into the m_arguments vector. 1468 m_arguments.push_back(arg1); 1469 } 1470 1471 ~CommandObjectCommandsScriptImport() override = default; 1472 1473 int HandleArgumentCompletion(Args &input, int &cursor_index, 1474 int &cursor_char_position, 1475 OptionElementVector &opt_element_vector, 1476 int match_start_point, int max_return_elements, 1477 bool &word_complete, 1478 StringList &matches) override { 1479 llvm::StringRef completion_str = input[cursor_index].ref; 1480 completion_str = completion_str.take_front(cursor_char_position); 1481 1482 CommandCompletions::InvokeCommonCompletionCallbacks( 1483 GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, 1484 completion_str, match_start_point, max_return_elements, nullptr, 1485 word_complete, matches); 1486 return matches.GetSize(); 1487 } 1488 1489 Options *GetOptions() override { return &m_options; } 1490 1491 protected: 1492 class CommandOptions : public Options { 1493 public: 1494 CommandOptions() : Options() {} 1495 1496 ~CommandOptions() override = default; 1497 1498 Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1499 ExecutionContext *execution_context) override { 1500 Error error; 1501 const int short_option = m_getopt_table[option_idx].val; 1502 1503 switch (short_option) { 1504 case 'r': 1505 m_allow_reload = true; 1506 break; 1507 default: 1508 error.SetErrorStringWithFormat("unrecognized option '%c'", 1509 short_option); 1510 break; 1511 } 1512 1513 return error; 1514 } 1515 1516 void OptionParsingStarting(ExecutionContext *execution_context) override { 1517 m_allow_reload = true; 1518 } 1519 1520 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1521 return llvm::makeArrayRef(g_script_import_options); 1522 } 1523 1524 // Instance variables to hold the values for command options. 1525 1526 bool m_allow_reload; 1527 }; 1528 1529 bool DoExecute(Args &command, CommandReturnObject &result) override { 1530 if (m_interpreter.GetDebugger().GetScriptLanguage() != 1531 lldb::eScriptLanguagePython) { 1532 result.AppendError("only scripting language supported for module " 1533 "importing is currently Python"); 1534 result.SetStatus(eReturnStatusFailed); 1535 return false; 1536 } 1537 1538 if (command.empty()) { 1539 result.AppendError("command script import needs one or more arguments"); 1540 result.SetStatus(eReturnStatusFailed); 1541 return false; 1542 } 1543 1544 for (auto &entry : command.entries()) { 1545 Error error; 1546 1547 const bool init_session = true; 1548 // FIXME: this is necessary because CommandObject::CheckRequirements() 1549 // assumes that commands won't ever be recursively invoked, but it's 1550 // actually possible to craft a Python script that does other "command 1551 // script imports" in __lldb_init_module the real fix is to have recursive 1552 // commands possible with a CommandInvocation object separate from the 1553 // CommandObject itself, so that recursive command invocations won't stomp 1554 // on each other (wrt to execution contents, options, and more) 1555 m_exe_ctx.Clear(); 1556 if (m_interpreter.GetScriptInterpreter()->LoadScriptingModule( 1557 entry.c_str(), m_options.m_allow_reload, init_session, error)) { 1558 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1559 } else { 1560 result.AppendErrorWithFormat("module importing failed: %s", 1561 error.AsCString()); 1562 result.SetStatus(eReturnStatusFailed); 1563 } 1564 } 1565 1566 return result.Succeeded(); 1567 } 1568 1569 CommandOptions m_options; 1570 }; 1571 1572 //------------------------------------------------------------------------- 1573 // CommandObjectCommandsScriptAdd 1574 //------------------------------------------------------------------------- 1575 1576 static OptionEnumValueElement g_script_synchro_type[] = { 1577 {eScriptedCommandSynchronicitySynchronous, "synchronous", 1578 "Run synchronous"}, 1579 {eScriptedCommandSynchronicityAsynchronous, "asynchronous", 1580 "Run asynchronous"}, 1581 {eScriptedCommandSynchronicityCurrentValue, "current", 1582 "Do not alter current setting"}, 1583 {0, nullptr, nullptr}}; 1584 1585 static OptionDefinition g_script_add_options[] = { 1586 // clang-format off 1587 { LLDB_OPT_SET_1, false, "function", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonFunction, "Name of the Python function to bind to this command name." }, 1588 { LLDB_OPT_SET_2, false, "class", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonClass, "Name of the Python class to bind to this command name." }, 1589 { LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeHelpText, "The help text to display for this command." }, 1590 { 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." }, 1591 // clang-format on 1592 }; 1593 1594 class CommandObjectCommandsScriptAdd : public CommandObjectParsed, 1595 public IOHandlerDelegateMultiline { 1596 public: 1597 CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) 1598 : CommandObjectParsed(interpreter, "command script add", 1599 "Add a scripted function as an LLDB command.", 1600 nullptr), 1601 IOHandlerDelegateMultiline("DONE"), m_options() { 1602 CommandArgumentEntry arg1; 1603 CommandArgumentData cmd_arg; 1604 1605 // Define the first (and only) variant of this arg. 1606 cmd_arg.arg_type = eArgTypeCommandName; 1607 cmd_arg.arg_repetition = eArgRepeatPlain; 1608 1609 // There is only one variant this argument could be; put it into the 1610 // argument entry. 1611 arg1.push_back(cmd_arg); 1612 1613 // Push the data for the first argument into the m_arguments vector. 1614 m_arguments.push_back(arg1); 1615 } 1616 1617 ~CommandObjectCommandsScriptAdd() override = default; 1618 1619 Options *GetOptions() override { return &m_options; } 1620 1621 protected: 1622 class CommandOptions : public Options { 1623 public: 1624 CommandOptions() 1625 : Options(), m_class_name(), m_funct_name(), m_short_help(), 1626 m_synchronicity(eScriptedCommandSynchronicitySynchronous) {} 1627 1628 ~CommandOptions() override = default; 1629 1630 Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1631 ExecutionContext *execution_context) override { 1632 Error error; 1633 const int short_option = m_getopt_table[option_idx].val; 1634 1635 switch (short_option) { 1636 case 'f': 1637 if (!option_arg.empty()) 1638 m_funct_name = option_arg; 1639 break; 1640 case 'c': 1641 if (!option_arg.empty()) 1642 m_class_name = option_arg; 1643 break; 1644 case 'h': 1645 if (!option_arg.empty()) 1646 m_short_help = option_arg; 1647 break; 1648 case 's': 1649 m_synchronicity = 1650 (ScriptedCommandSynchronicity)Args::StringToOptionEnum( 1651 option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 1652 if (!error.Success()) 1653 error.SetErrorStringWithFormat( 1654 "unrecognized value for synchronicity '%s'", 1655 option_arg.str().c_str()); 1656 break; 1657 default: 1658 error.SetErrorStringWithFormat("unrecognized option '%c'", 1659 short_option); 1660 break; 1661 } 1662 1663 return error; 1664 } 1665 1666 void OptionParsingStarting(ExecutionContext *execution_context) override { 1667 m_class_name.clear(); 1668 m_funct_name.clear(); 1669 m_short_help.clear(); 1670 m_synchronicity = eScriptedCommandSynchronicitySynchronous; 1671 } 1672 1673 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1674 return llvm::makeArrayRef(g_script_add_options); 1675 } 1676 1677 // Instance variables to hold the values for command options. 1678 1679 std::string m_class_name; 1680 std::string m_funct_name; 1681 std::string m_short_help; 1682 ScriptedCommandSynchronicity m_synchronicity; 1683 }; 1684 1685 void IOHandlerActivated(IOHandler &io_handler) override { 1686 StreamFileSP output_sp(io_handler.GetOutputStreamFile()); 1687 if (output_sp) { 1688 output_sp->PutCString(g_python_command_instructions); 1689 output_sp->Flush(); 1690 } 1691 } 1692 1693 void IOHandlerInputComplete(IOHandler &io_handler, 1694 std::string &data) override { 1695 StreamFileSP error_sp = io_handler.GetErrorStreamFile(); 1696 1697 ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); 1698 if (interpreter) { 1699 1700 StringList lines; 1701 lines.SplitIntoLines(data); 1702 if (lines.GetSize() > 0) { 1703 std::string funct_name_str; 1704 if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) { 1705 if (funct_name_str.empty()) { 1706 error_sp->Printf("error: unable to obtain a function name, didn't " 1707 "add python command.\n"); 1708 error_sp->Flush(); 1709 } else { 1710 // everything should be fine now, let's add this alias 1711 1712 CommandObjectSP command_obj_sp(new CommandObjectPythonFunction( 1713 m_interpreter, m_cmd_name, funct_name_str, m_short_help, 1714 m_synchronicity)); 1715 1716 if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp, 1717 true)) { 1718 error_sp->Printf("error: unable to add selected command, didn't " 1719 "add python command.\n"); 1720 error_sp->Flush(); 1721 } 1722 } 1723 } else { 1724 error_sp->Printf( 1725 "error: unable to create function, didn't add python command.\n"); 1726 error_sp->Flush(); 1727 } 1728 } else { 1729 error_sp->Printf("error: empty function, didn't add python command.\n"); 1730 error_sp->Flush(); 1731 } 1732 } else { 1733 error_sp->Printf( 1734 "error: script interpreter missing, didn't add python command.\n"); 1735 error_sp->Flush(); 1736 } 1737 1738 io_handler.SetIsDone(true); 1739 } 1740 1741 protected: 1742 bool DoExecute(Args &command, CommandReturnObject &result) override { 1743 if (m_interpreter.GetDebugger().GetScriptLanguage() != 1744 lldb::eScriptLanguagePython) { 1745 result.AppendError("only scripting language supported for scripted " 1746 "commands is currently Python"); 1747 result.SetStatus(eReturnStatusFailed); 1748 return false; 1749 } 1750 1751 if (command.GetArgumentCount() != 1) { 1752 result.AppendError("'command script add' requires one argument"); 1753 result.SetStatus(eReturnStatusFailed); 1754 return false; 1755 } 1756 1757 // Store the options in case we get multi-line input 1758 m_cmd_name = command.GetArgumentAtIndex(0); 1759 m_short_help.assign(m_options.m_short_help); 1760 m_synchronicity = m_options.m_synchronicity; 1761 1762 if (m_options.m_class_name.empty()) { 1763 if (m_options.m_funct_name.empty()) { 1764 m_interpreter.GetPythonCommandsFromIOHandler( 1765 " ", // Prompt 1766 *this, // IOHandlerDelegate 1767 true, // Run IOHandler in async mode 1768 nullptr); // Baton for the "io_handler" that will be passed back 1769 // into our IOHandlerDelegate functions 1770 } else { 1771 CommandObjectSP new_cmd(new CommandObjectPythonFunction( 1772 m_interpreter, m_cmd_name, m_options.m_funct_name, 1773 m_options.m_short_help, m_synchronicity)); 1774 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { 1775 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1776 } else { 1777 result.AppendError("cannot add command"); 1778 result.SetStatus(eReturnStatusFailed); 1779 } 1780 } 1781 } else { 1782 ScriptInterpreter *interpreter = 1783 GetCommandInterpreter().GetScriptInterpreter(); 1784 if (!interpreter) { 1785 result.AppendError("cannot find ScriptInterpreter"); 1786 result.SetStatus(eReturnStatusFailed); 1787 return false; 1788 } 1789 1790 auto cmd_obj_sp = interpreter->CreateScriptCommandObject( 1791 m_options.m_class_name.c_str()); 1792 if (!cmd_obj_sp) { 1793 result.AppendError("cannot create helper object"); 1794 result.SetStatus(eReturnStatusFailed); 1795 return false; 1796 } 1797 1798 CommandObjectSP new_cmd(new CommandObjectScriptingObject( 1799 m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity)); 1800 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { 1801 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1802 } else { 1803 result.AppendError("cannot add command"); 1804 result.SetStatus(eReturnStatusFailed); 1805 } 1806 } 1807 1808 return result.Succeeded(); 1809 } 1810 1811 CommandOptions m_options; 1812 std::string m_cmd_name; 1813 std::string m_short_help; 1814 ScriptedCommandSynchronicity m_synchronicity; 1815 }; 1816 1817 //------------------------------------------------------------------------- 1818 // CommandObjectCommandsScriptList 1819 //------------------------------------------------------------------------- 1820 1821 class CommandObjectCommandsScriptList : public CommandObjectParsed { 1822 public: 1823 CommandObjectCommandsScriptList(CommandInterpreter &interpreter) 1824 : CommandObjectParsed(interpreter, "command script list", 1825 "List defined scripted commands.", nullptr) {} 1826 1827 ~CommandObjectCommandsScriptList() override = default; 1828 1829 bool DoExecute(Args &command, CommandReturnObject &result) override { 1830 m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef); 1831 1832 result.SetStatus(eReturnStatusSuccessFinishResult); 1833 1834 return true; 1835 } 1836 }; 1837 1838 //------------------------------------------------------------------------- 1839 // CommandObjectCommandsScriptClear 1840 //------------------------------------------------------------------------- 1841 1842 class CommandObjectCommandsScriptClear : public CommandObjectParsed { 1843 public: 1844 CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) 1845 : CommandObjectParsed(interpreter, "command script clear", 1846 "Delete all scripted commands.", nullptr) {} 1847 1848 ~CommandObjectCommandsScriptClear() override = default; 1849 1850 protected: 1851 bool DoExecute(Args &command, CommandReturnObject &result) override { 1852 m_interpreter.RemoveAllUser(); 1853 1854 result.SetStatus(eReturnStatusSuccessFinishResult); 1855 1856 return true; 1857 } 1858 }; 1859 1860 //------------------------------------------------------------------------- 1861 // CommandObjectCommandsScriptDelete 1862 //------------------------------------------------------------------------- 1863 1864 class CommandObjectCommandsScriptDelete : public CommandObjectParsed { 1865 public: 1866 CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) 1867 : CommandObjectParsed(interpreter, "command script delete", 1868 "Delete a scripted command.", nullptr) { 1869 CommandArgumentEntry arg1; 1870 CommandArgumentData cmd_arg; 1871 1872 // Define the first (and only) variant of this arg. 1873 cmd_arg.arg_type = eArgTypeCommandName; 1874 cmd_arg.arg_repetition = eArgRepeatPlain; 1875 1876 // There is only one variant this argument could be; put it into the 1877 // argument entry. 1878 arg1.push_back(cmd_arg); 1879 1880 // Push the data for the first argument into the m_arguments vector. 1881 m_arguments.push_back(arg1); 1882 } 1883 1884 ~CommandObjectCommandsScriptDelete() override = default; 1885 1886 protected: 1887 bool DoExecute(Args &command, CommandReturnObject &result) override { 1888 1889 if (command.GetArgumentCount() != 1) { 1890 result.AppendError("'command script delete' requires one argument"); 1891 result.SetStatus(eReturnStatusFailed); 1892 return false; 1893 } 1894 1895 const char *cmd_name = command.GetArgumentAtIndex(0); 1896 1897 if (cmd_name && *cmd_name && m_interpreter.HasUserCommands() && 1898 m_interpreter.UserCommandExists(cmd_name)) { 1899 m_interpreter.RemoveUser(cmd_name); 1900 result.SetStatus(eReturnStatusSuccessFinishResult); 1901 } else { 1902 result.AppendErrorWithFormat("command %s not found", cmd_name); 1903 result.SetStatus(eReturnStatusFailed); 1904 } 1905 1906 return result.Succeeded(); 1907 } 1908 }; 1909 1910 #pragma mark CommandObjectMultiwordCommandsScript 1911 1912 //------------------------------------------------------------------------- 1913 // CommandObjectMultiwordCommandsScript 1914 //------------------------------------------------------------------------- 1915 1916 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword { 1917 public: 1918 CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter) 1919 : CommandObjectMultiword( 1920 interpreter, "command script", "Commands for managing custom " 1921 "commands implemented by " 1922 "interpreter scripts.", 1923 "command script <subcommand> [<subcommand-options>]") { 1924 LoadSubCommand("add", CommandObjectSP( 1925 new CommandObjectCommandsScriptAdd(interpreter))); 1926 LoadSubCommand( 1927 "delete", 1928 CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter))); 1929 LoadSubCommand( 1930 "clear", 1931 CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter))); 1932 LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList( 1933 interpreter))); 1934 LoadSubCommand( 1935 "import", 1936 CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter))); 1937 } 1938 1939 ~CommandObjectMultiwordCommandsScript() override = default; 1940 }; 1941 1942 #pragma mark CommandObjectMultiwordCommands 1943 1944 //------------------------------------------------------------------------- 1945 // CommandObjectMultiwordCommands 1946 //------------------------------------------------------------------------- 1947 1948 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands( 1949 CommandInterpreter &interpreter) 1950 : CommandObjectMultiword(interpreter, "command", 1951 "Commands for managing custom LLDB commands.", 1952 "command <subcommand> [<subcommand-options>]") { 1953 LoadSubCommand("source", 1954 CommandObjectSP(new CommandObjectCommandsSource(interpreter))); 1955 LoadSubCommand("alias", 1956 CommandObjectSP(new CommandObjectCommandsAlias(interpreter))); 1957 LoadSubCommand("unalias", CommandObjectSP( 1958 new CommandObjectCommandsUnalias(interpreter))); 1959 LoadSubCommand("delete", 1960 CommandObjectSP(new CommandObjectCommandsDelete(interpreter))); 1961 LoadSubCommand( 1962 "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter))); 1963 LoadSubCommand("history", CommandObjectSP( 1964 new CommandObjectCommandsHistory(interpreter))); 1965 LoadSubCommand( 1966 "script", 1967 CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter))); 1968 } 1969 1970 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default; 1971