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