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