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.c_str())) { 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.c_str())) { 732 result.AppendErrorWithFormat( 733 "'%s' is a permanent debugger command and cannot be redefined.\n", 734 alias_command.c_str()); 735 result.SetStatus(eReturnStatusFailed); 736 } else { 737 CommandObjectSP command_obj_sp( 738 m_interpreter.GetCommandSPExact(actual_command, 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.c_str()) || 784 m_interpreter.UserCommandExists(alias_command.c_str())) { 785 result.AppendWarningWithFormat( 786 "Overwriting existing definition for '%s'.\n", 787 alias_command.c_str()); 788 } 789 790 if (CommandAlias *alias = m_interpreter.AddAlias( 791 alias_command.c_str(), 792 use_subcommand ? subcommand_obj_sp : command_obj_sp, 793 args_string.c_str())) { 794 if (m_command_options.m_help.OptionWasSet()) 795 alias->SetHelp(m_command_options.m_help.GetCurrentValue()); 796 if (m_command_options.m_long_help.OptionWasSet()) 797 alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue()); 798 result.SetStatus(eReturnStatusSuccessFinishNoResult); 799 } else { 800 result.AppendError("Unable to create requested alias.\n"); 801 result.SetStatus(eReturnStatusFailed); 802 return false; 803 } 804 } else { 805 result.AppendErrorWithFormat("'%s' is not an existing command.\n", 806 actual_command.c_str()); 807 result.SetStatus(eReturnStatusFailed); 808 return false; 809 } 810 } 811 812 return result.Succeeded(); 813 } 814 }; 815 816 #pragma mark CommandObjectCommandsUnalias 817 //------------------------------------------------------------------------- 818 // CommandObjectCommandsUnalias 819 //------------------------------------------------------------------------- 820 821 class CommandObjectCommandsUnalias : public CommandObjectParsed { 822 public: 823 CommandObjectCommandsUnalias(CommandInterpreter &interpreter) 824 : CommandObjectParsed( 825 interpreter, "command unalias", 826 "Delete one or more custom commands defined by 'command alias'.", 827 nullptr) { 828 CommandArgumentEntry arg; 829 CommandArgumentData alias_arg; 830 831 // Define the first (and only) variant of this arg. 832 alias_arg.arg_type = eArgTypeAliasName; 833 alias_arg.arg_repetition = eArgRepeatPlain; 834 835 // There is only one variant this argument could be; put it into the 836 // argument entry. 837 arg.push_back(alias_arg); 838 839 // Push the data for the first argument into the m_arguments vector. 840 m_arguments.push_back(arg); 841 } 842 843 ~CommandObjectCommandsUnalias() override = default; 844 845 protected: 846 bool DoExecute(Args &args, CommandReturnObject &result) override { 847 CommandObject::CommandMap::iterator pos; 848 CommandObject *cmd_obj; 849 850 if (args.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 (size_t arg_idx = 1; arg_idx < argc; ++arg_idx) { 1100 llvm::StringRef arg_strref(command.GetArgumentAtIndex(arg_idx)); 1101 bool check_only = false; 1102 error = AppendRegexSubstitution(arg_strref, check_only); 1103 if (error.Fail()) 1104 break; 1105 } 1106 1107 if (error.Success()) { 1108 AddRegexCommandToInterpreter(); 1109 } 1110 } 1111 if (error.Fail()) { 1112 result.AppendError(error.AsCString()); 1113 result.SetStatus(eReturnStatusFailed); 1114 } 1115 1116 return result.Succeeded(); 1117 } 1118 1119 Error AppendRegexSubstitution(const llvm::StringRef ®ex_sed, 1120 bool check_only) { 1121 Error error; 1122 1123 if (!m_regex_cmd_ap) { 1124 error.SetErrorStringWithFormat( 1125 "invalid regular expression command object for: '%.*s'", 1126 (int)regex_sed.size(), regex_sed.data()); 1127 return error; 1128 } 1129 1130 size_t regex_sed_size = regex_sed.size(); 1131 1132 if (regex_sed_size <= 1) { 1133 error.SetErrorStringWithFormat( 1134 "regular expression substitution string is too short: '%.*s'", 1135 (int)regex_sed.size(), regex_sed.data()); 1136 return error; 1137 } 1138 1139 if (regex_sed[0] != 's') { 1140 error.SetErrorStringWithFormat("regular expression substitution string " 1141 "doesn't start with 's': '%.*s'", 1142 (int)regex_sed.size(), regex_sed.data()); 1143 return error; 1144 } 1145 const size_t first_separator_char_pos = 1; 1146 // use the char that follows 's' as the regex separator character 1147 // so we can have "s/<regex>/<subst>/" or "s|<regex>|<subst>|" 1148 const char separator_char = regex_sed[first_separator_char_pos]; 1149 const size_t second_separator_char_pos = 1150 regex_sed.find(separator_char, first_separator_char_pos + 1); 1151 1152 if (second_separator_char_pos == std::string::npos) { 1153 error.SetErrorStringWithFormat( 1154 "missing second '%c' separator char after '%.*s' in '%.*s'", 1155 separator_char, 1156 (int)(regex_sed.size() - first_separator_char_pos - 1), 1157 regex_sed.data() + (first_separator_char_pos + 1), 1158 (int)regex_sed.size(), regex_sed.data()); 1159 return error; 1160 } 1161 1162 const size_t third_separator_char_pos = 1163 regex_sed.find(separator_char, second_separator_char_pos + 1); 1164 1165 if (third_separator_char_pos == std::string::npos) { 1166 error.SetErrorStringWithFormat( 1167 "missing third '%c' separator char after '%.*s' in '%.*s'", 1168 separator_char, 1169 (int)(regex_sed.size() - second_separator_char_pos - 1), 1170 regex_sed.data() + (second_separator_char_pos + 1), 1171 (int)regex_sed.size(), regex_sed.data()); 1172 return error; 1173 } 1174 1175 if (third_separator_char_pos != regex_sed_size - 1) { 1176 // Make sure that everything that follows the last regex 1177 // separator char 1178 if (regex_sed.find_first_not_of("\t\n\v\f\r ", 1179 third_separator_char_pos + 1) != 1180 std::string::npos) { 1181 error.SetErrorStringWithFormat( 1182 "extra data found after the '%.*s' regular expression substitution " 1183 "string: '%.*s'", 1184 (int)third_separator_char_pos + 1, regex_sed.data(), 1185 (int)(regex_sed.size() - third_separator_char_pos - 1), 1186 regex_sed.data() + (third_separator_char_pos + 1)); 1187 return error; 1188 } 1189 } else if (first_separator_char_pos + 1 == second_separator_char_pos) { 1190 error.SetErrorStringWithFormat( 1191 "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 1192 separator_char, separator_char, separator_char, (int)regex_sed.size(), 1193 regex_sed.data()); 1194 return error; 1195 } else if (second_separator_char_pos + 1 == third_separator_char_pos) { 1196 error.SetErrorStringWithFormat( 1197 "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 1198 separator_char, separator_char, separator_char, (int)regex_sed.size(), 1199 regex_sed.data()); 1200 return error; 1201 } 1202 1203 if (!check_only) { 1204 std::string regex(regex_sed.substr(first_separator_char_pos + 1, 1205 second_separator_char_pos - 1206 first_separator_char_pos - 1)); 1207 std::string subst(regex_sed.substr(second_separator_char_pos + 1, 1208 third_separator_char_pos - 1209 second_separator_char_pos - 1)); 1210 m_regex_cmd_ap->AddRegexCommand(regex.c_str(), subst.c_str()); 1211 } 1212 return error; 1213 } 1214 1215 void AddRegexCommandToInterpreter() { 1216 if (m_regex_cmd_ap) { 1217 if (m_regex_cmd_ap->HasRegexEntries()) { 1218 CommandObjectSP cmd_sp(m_regex_cmd_ap.release()); 1219 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 1220 } 1221 } 1222 } 1223 1224 private: 1225 std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_ap; 1226 1227 class CommandOptions : public Options { 1228 public: 1229 CommandOptions() : Options() {} 1230 1231 ~CommandOptions() override = default; 1232 1233 Error SetOptionValue(uint32_t option_idx, const char *option_arg, 1234 ExecutionContext *execution_context) override { 1235 Error error; 1236 const int short_option = m_getopt_table[option_idx].val; 1237 1238 switch (short_option) { 1239 case 'h': 1240 m_help.assign(option_arg); 1241 break; 1242 case 's': 1243 m_syntax.assign(option_arg); 1244 break; 1245 default: 1246 error.SetErrorStringWithFormat("unrecognized option '%c'", 1247 short_option); 1248 break; 1249 } 1250 1251 return error; 1252 } 1253 1254 void OptionParsingStarting(ExecutionContext *execution_context) override { 1255 m_help.clear(); 1256 m_syntax.clear(); 1257 } 1258 1259 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1260 return llvm::makeArrayRef(g_regex_options); 1261 } 1262 1263 // TODO: Convert these functions to return StringRefs. 1264 const char *GetHelp() { 1265 return (m_help.empty() ? nullptr : m_help.c_str()); 1266 } 1267 1268 const char *GetSyntax() { 1269 return (m_syntax.empty() ? nullptr : m_syntax.c_str()); 1270 } 1271 1272 protected: 1273 // Instance variables to hold the values for command options. 1274 1275 std::string m_help; 1276 std::string m_syntax; 1277 }; 1278 1279 Options *GetOptions() override { return &m_options; } 1280 1281 CommandOptions m_options; 1282 }; 1283 1284 class CommandObjectPythonFunction : public CommandObjectRaw { 1285 public: 1286 CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name, 1287 std::string funct, std::string help, 1288 ScriptedCommandSynchronicity synch) 1289 : CommandObjectRaw(interpreter, name), 1290 m_function_name(funct), m_synchro(synch), m_fetched_help_long(false) { 1291 if (!help.empty()) 1292 SetHelp(help.c_str()); 1293 else { 1294 StreamString stream; 1295 stream.Printf("For more information run 'help %s'", name.c_str()); 1296 SetHelp(stream.GetData()); 1297 } 1298 } 1299 1300 ~CommandObjectPythonFunction() override = default; 1301 1302 bool IsRemovable() const override { return true; } 1303 1304 const std::string &GetFunctionName() { return m_function_name; } 1305 1306 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1307 1308 const char *GetHelpLong() override { 1309 if (!m_fetched_help_long) { 1310 ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter(); 1311 if (scripter) { 1312 std::string docstring; 1313 m_fetched_help_long = scripter->GetDocumentationForItem( 1314 m_function_name.c_str(), docstring); 1315 if (!docstring.empty()) 1316 SetHelpLong(docstring.c_str()); 1317 } 1318 } 1319 return CommandObjectRaw::GetHelpLong(); 1320 } 1321 1322 protected: 1323 bool DoExecute(const char *raw_command_line, 1324 CommandReturnObject &result) override { 1325 ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter(); 1326 1327 Error error; 1328 1329 result.SetStatus(eReturnStatusInvalid); 1330 1331 if (!scripter || 1332 !scripter->RunScriptBasedCommand(m_function_name.c_str(), 1333 raw_command_line, m_synchro, result, 1334 error, m_exe_ctx)) { 1335 result.AppendError(error.AsCString()); 1336 result.SetStatus(eReturnStatusFailed); 1337 } else { 1338 // Don't change the status if the command already set it... 1339 if (result.GetStatus() == eReturnStatusInvalid) { 1340 if (result.GetOutputData() == nullptr || 1341 result.GetOutputData()[0] == '\0') 1342 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1343 else 1344 result.SetStatus(eReturnStatusSuccessFinishResult); 1345 } 1346 } 1347 1348 return result.Succeeded(); 1349 } 1350 1351 private: 1352 std::string m_function_name; 1353 ScriptedCommandSynchronicity m_synchro; 1354 bool m_fetched_help_long; 1355 }; 1356 1357 class CommandObjectScriptingObject : public CommandObjectRaw { 1358 public: 1359 CommandObjectScriptingObject(CommandInterpreter &interpreter, 1360 std::string name, 1361 StructuredData::GenericSP cmd_obj_sp, 1362 ScriptedCommandSynchronicity synch) 1363 : CommandObjectRaw(interpreter, name), 1364 m_cmd_obj_sp(cmd_obj_sp), m_synchro(synch), m_fetched_help_short(false), 1365 m_fetched_help_long(false) { 1366 StreamString stream; 1367 stream.Printf("For more information run 'help %s'", name.c_str()); 1368 SetHelp(stream.GetData()); 1369 if (ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter()) 1370 GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); 1371 } 1372 1373 ~CommandObjectScriptingObject() override = default; 1374 1375 bool IsRemovable() const override { return true; } 1376 1377 StructuredData::GenericSP GetImplementingObject() { return m_cmd_obj_sp; } 1378 1379 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1380 1381 const char *GetHelp() override { 1382 if (!m_fetched_help_short) { 1383 ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter(); 1384 if (scripter) { 1385 std::string docstring; 1386 m_fetched_help_short = 1387 scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring); 1388 if (!docstring.empty()) 1389 SetHelp(docstring.c_str()); 1390 } 1391 } 1392 return CommandObjectRaw::GetHelp(); 1393 } 1394 1395 const char *GetHelpLong() override { 1396 if (!m_fetched_help_long) { 1397 ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter(); 1398 if (scripter) { 1399 std::string docstring; 1400 m_fetched_help_long = 1401 scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring); 1402 if (!docstring.empty()) 1403 SetHelpLong(docstring.c_str()); 1404 } 1405 } 1406 return CommandObjectRaw::GetHelpLong(); 1407 } 1408 1409 protected: 1410 bool DoExecute(const char *raw_command_line, 1411 CommandReturnObject &result) override { 1412 ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter(); 1413 1414 Error error; 1415 1416 result.SetStatus(eReturnStatusInvalid); 1417 1418 if (!scripter || 1419 !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line, 1420 m_synchro, result, error, m_exe_ctx)) { 1421 result.AppendError(error.AsCString()); 1422 result.SetStatus(eReturnStatusFailed); 1423 } else { 1424 // Don't change the status if the command already set it... 1425 if (result.GetStatus() == eReturnStatusInvalid) { 1426 if (result.GetOutputData() == nullptr || 1427 result.GetOutputData()[0] == '\0') 1428 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1429 else 1430 result.SetStatus(eReturnStatusSuccessFinishResult); 1431 } 1432 } 1433 1434 return result.Succeeded(); 1435 } 1436 1437 private: 1438 StructuredData::GenericSP m_cmd_obj_sp; 1439 ScriptedCommandSynchronicity m_synchro; 1440 bool m_fetched_help_short : 1; 1441 bool m_fetched_help_long : 1; 1442 }; 1443 1444 //------------------------------------------------------------------------- 1445 // CommandObjectCommandsScriptImport 1446 //------------------------------------------------------------------------- 1447 1448 OptionDefinition g_script_import_options[] = { 1449 // clang-format off 1450 { 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." }, 1451 // clang-format on 1452 }; 1453 1454 class CommandObjectCommandsScriptImport : public CommandObjectParsed { 1455 public: 1456 CommandObjectCommandsScriptImport(CommandInterpreter &interpreter) 1457 : CommandObjectParsed(interpreter, "command script import", 1458 "Import a scripting module in LLDB.", nullptr), 1459 m_options() { 1460 CommandArgumentEntry arg1; 1461 CommandArgumentData cmd_arg; 1462 1463 // Define the first (and only) variant of this arg. 1464 cmd_arg.arg_type = eArgTypeFilename; 1465 cmd_arg.arg_repetition = eArgRepeatPlus; 1466 1467 // There is only one variant this argument could be; put it into the 1468 // argument entry. 1469 arg1.push_back(cmd_arg); 1470 1471 // Push the data for the first argument into the m_arguments vector. 1472 m_arguments.push_back(arg1); 1473 } 1474 1475 ~CommandObjectCommandsScriptImport() override = default; 1476 1477 int HandleArgumentCompletion(Args &input, int &cursor_index, 1478 int &cursor_char_position, 1479 OptionElementVector &opt_element_vector, 1480 int match_start_point, int max_return_elements, 1481 bool &word_complete, 1482 StringList &matches) override { 1483 std::string completion_str(input.GetArgumentAtIndex(cursor_index)); 1484 completion_str.erase(cursor_char_position); 1485 1486 CommandCompletions::InvokeCommonCompletionCallbacks( 1487 GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, 1488 completion_str.c_str(), match_start_point, max_return_elements, nullptr, 1489 word_complete, matches); 1490 return matches.GetSize(); 1491 } 1492 1493 Options *GetOptions() override { return &m_options; } 1494 1495 protected: 1496 class CommandOptions : public Options { 1497 public: 1498 CommandOptions() : Options() {} 1499 1500 ~CommandOptions() override = default; 1501 1502 Error SetOptionValue(uint32_t option_idx, const char *option_arg, 1503 ExecutionContext *execution_context) override { 1504 Error error; 1505 const int short_option = m_getopt_table[option_idx].val; 1506 1507 switch (short_option) { 1508 case 'r': 1509 m_allow_reload = true; 1510 break; 1511 default: 1512 error.SetErrorStringWithFormat("unrecognized option '%c'", 1513 short_option); 1514 break; 1515 } 1516 1517 return error; 1518 } 1519 1520 void OptionParsingStarting(ExecutionContext *execution_context) override { 1521 m_allow_reload = true; 1522 } 1523 1524 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1525 return llvm::makeArrayRef(g_script_import_options); 1526 } 1527 1528 // Instance variables to hold the values for command options. 1529 1530 bool m_allow_reload; 1531 }; 1532 1533 bool DoExecute(Args &command, CommandReturnObject &result) override { 1534 if (m_interpreter.GetDebugger().GetScriptLanguage() != 1535 lldb::eScriptLanguagePython) { 1536 result.AppendError("only scripting language supported for module " 1537 "importing is currently Python"); 1538 result.SetStatus(eReturnStatusFailed); 1539 return false; 1540 } 1541 1542 if (command.empty()) { 1543 result.AppendError("command script import needs one or more arguments"); 1544 result.SetStatus(eReturnStatusFailed); 1545 return false; 1546 } 1547 1548 for (auto &entry : command.entries()) { 1549 Error error; 1550 1551 const bool init_session = true; 1552 // FIXME: this is necessary because CommandObject::CheckRequirements() 1553 // assumes that commands won't ever be recursively invoked, but it's 1554 // actually possible to craft a Python script that does other "command 1555 // script imports" in __lldb_init_module the real fix is to have recursive 1556 // commands possible with a CommandInvocation object separate from the 1557 // CommandObject itself, so that recursive command invocations won't stomp 1558 // on each other (wrt to execution contents, options, and more) 1559 m_exe_ctx.Clear(); 1560 if (m_interpreter.GetScriptInterpreter()->LoadScriptingModule( 1561 entry.c_str(), m_options.m_allow_reload, init_session, error)) { 1562 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1563 } else { 1564 result.AppendErrorWithFormat("module importing failed: %s", 1565 error.AsCString()); 1566 result.SetStatus(eReturnStatusFailed); 1567 } 1568 } 1569 1570 return result.Succeeded(); 1571 } 1572 1573 CommandOptions m_options; 1574 }; 1575 1576 //------------------------------------------------------------------------- 1577 // CommandObjectCommandsScriptAdd 1578 //------------------------------------------------------------------------- 1579 1580 static OptionEnumValueElement g_script_synchro_type[] = { 1581 {eScriptedCommandSynchronicitySynchronous, "synchronous", 1582 "Run synchronous"}, 1583 {eScriptedCommandSynchronicityAsynchronous, "asynchronous", 1584 "Run asynchronous"}, 1585 {eScriptedCommandSynchronicityCurrentValue, "current", 1586 "Do not alter current setting"}, 1587 {0, nullptr, nullptr}}; 1588 1589 static OptionDefinition g_script_add_options[] = { 1590 // clang-format off 1591 { LLDB_OPT_SET_1, false, "function", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonFunction, "Name of the Python function to bind to this command name." }, 1592 { LLDB_OPT_SET_2, false, "class", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonClass, "Name of the Python class to bind to this command name." }, 1593 { LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeHelpText, "The help text to display for this command." }, 1594 { LLDB_OPT_SET_ALL, false, "synchronicity", 's', OptionParser::eRequiredArgument, nullptr, g_script_synchro_type, 0, eArgTypeScriptedCommandSynchronicity, "Set the synchronicity of this command's executions with regard to LLDB event system." }, 1595 // clang-format on 1596 }; 1597 1598 class CommandObjectCommandsScriptAdd : public CommandObjectParsed, 1599 public IOHandlerDelegateMultiline { 1600 public: 1601 CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) 1602 : CommandObjectParsed(interpreter, "command script add", 1603 "Add a scripted function as an LLDB command.", 1604 nullptr), 1605 IOHandlerDelegateMultiline("DONE"), m_options() { 1606 CommandArgumentEntry arg1; 1607 CommandArgumentData cmd_arg; 1608 1609 // Define the first (and only) variant of this arg. 1610 cmd_arg.arg_type = eArgTypeCommandName; 1611 cmd_arg.arg_repetition = eArgRepeatPlain; 1612 1613 // There is only one variant this argument could be; put it into the 1614 // argument entry. 1615 arg1.push_back(cmd_arg); 1616 1617 // Push the data for the first argument into the m_arguments vector. 1618 m_arguments.push_back(arg1); 1619 } 1620 1621 ~CommandObjectCommandsScriptAdd() override = default; 1622 1623 Options *GetOptions() override { return &m_options; } 1624 1625 protected: 1626 class CommandOptions : public Options { 1627 public: 1628 CommandOptions() 1629 : Options(), m_class_name(), m_funct_name(), m_short_help(), 1630 m_synchronicity(eScriptedCommandSynchronicitySynchronous) {} 1631 1632 ~CommandOptions() override = default; 1633 1634 Error SetOptionValue(uint32_t option_idx, const char *option_arg, 1635 ExecutionContext *execution_context) override { 1636 Error error; 1637 const int short_option = m_getopt_table[option_idx].val; 1638 1639 switch (short_option) { 1640 case 'f': 1641 if (option_arg) 1642 m_funct_name.assign(option_arg); 1643 break; 1644 case 'c': 1645 if (option_arg) 1646 m_class_name.assign(option_arg); 1647 break; 1648 case 'h': 1649 if (option_arg) 1650 m_short_help.assign(option_arg); 1651 break; 1652 case 's': 1653 m_synchronicity = 1654 (ScriptedCommandSynchronicity)Args::StringToOptionEnum( 1655 llvm::StringRef::withNullAsEmpty(option_arg), 1656 GetDefinitions()[option_idx].enum_values, 0, error); 1657 if (!error.Success()) 1658 error.SetErrorStringWithFormat( 1659 "unrecognized value for synchronicity '%s'", option_arg); 1660 break; 1661 default: 1662 error.SetErrorStringWithFormat("unrecognized option '%c'", 1663 short_option); 1664 break; 1665 } 1666 1667 return error; 1668 } 1669 1670 void OptionParsingStarting(ExecutionContext *execution_context) override { 1671 m_class_name.clear(); 1672 m_funct_name.clear(); 1673 m_short_help.clear(); 1674 m_synchronicity = eScriptedCommandSynchronicitySynchronous; 1675 } 1676 1677 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1678 return llvm::makeArrayRef(g_script_add_options); 1679 } 1680 1681 // Instance variables to hold the values for command options. 1682 1683 std::string m_class_name; 1684 std::string m_funct_name; 1685 std::string m_short_help; 1686 ScriptedCommandSynchronicity m_synchronicity; 1687 }; 1688 1689 void IOHandlerActivated(IOHandler &io_handler) override { 1690 StreamFileSP output_sp(io_handler.GetOutputStreamFile()); 1691 if (output_sp) { 1692 output_sp->PutCString(g_python_command_instructions); 1693 output_sp->Flush(); 1694 } 1695 } 1696 1697 void IOHandlerInputComplete(IOHandler &io_handler, 1698 std::string &data) override { 1699 StreamFileSP error_sp = io_handler.GetErrorStreamFile(); 1700 1701 ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); 1702 if (interpreter) { 1703 1704 StringList lines; 1705 lines.SplitIntoLines(data); 1706 if (lines.GetSize() > 0) { 1707 std::string funct_name_str; 1708 if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) { 1709 if (funct_name_str.empty()) { 1710 error_sp->Printf("error: unable to obtain a function name, didn't " 1711 "add python command.\n"); 1712 error_sp->Flush(); 1713 } else { 1714 // everything should be fine now, let's add this alias 1715 1716 CommandObjectSP command_obj_sp(new CommandObjectPythonFunction( 1717 m_interpreter, m_cmd_name, funct_name_str.c_str(), m_short_help, 1718 m_synchronicity)); 1719 1720 if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp, 1721 true)) { 1722 error_sp->Printf("error: unable to add selected command, didn't " 1723 "add python command.\n"); 1724 error_sp->Flush(); 1725 } 1726 } 1727 } else { 1728 error_sp->Printf( 1729 "error: unable to create function, didn't add python command.\n"); 1730 error_sp->Flush(); 1731 } 1732 } else { 1733 error_sp->Printf("error: empty function, didn't add python command.\n"); 1734 error_sp->Flush(); 1735 } 1736 } else { 1737 error_sp->Printf( 1738 "error: script interpreter missing, didn't add python command.\n"); 1739 error_sp->Flush(); 1740 } 1741 1742 io_handler.SetIsDone(true); 1743 } 1744 1745 protected: 1746 bool DoExecute(Args &command, CommandReturnObject &result) override { 1747 if (m_interpreter.GetDebugger().GetScriptLanguage() != 1748 lldb::eScriptLanguagePython) { 1749 result.AppendError("only scripting language supported for scripted " 1750 "commands is currently Python"); 1751 result.SetStatus(eReturnStatusFailed); 1752 return false; 1753 } 1754 1755 if (command.GetArgumentCount() != 1) { 1756 result.AppendError("'command script add' requires one argument"); 1757 result.SetStatus(eReturnStatusFailed); 1758 return false; 1759 } 1760 1761 // Store the options in case we get multi-line input 1762 m_cmd_name = command.GetArgumentAtIndex(0); 1763 m_short_help.assign(m_options.m_short_help); 1764 m_synchronicity = m_options.m_synchronicity; 1765 1766 if (m_options.m_class_name.empty()) { 1767 if (m_options.m_funct_name.empty()) { 1768 m_interpreter.GetPythonCommandsFromIOHandler( 1769 " ", // Prompt 1770 *this, // IOHandlerDelegate 1771 true, // Run IOHandler in async mode 1772 nullptr); // Baton for the "io_handler" that will be passed back 1773 // into our IOHandlerDelegate functions 1774 } else { 1775 CommandObjectSP new_cmd(new CommandObjectPythonFunction( 1776 m_interpreter, m_cmd_name, m_options.m_funct_name, 1777 m_options.m_short_help, m_synchronicity)); 1778 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { 1779 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1780 } else { 1781 result.AppendError("cannot add command"); 1782 result.SetStatus(eReturnStatusFailed); 1783 } 1784 } 1785 } else { 1786 ScriptInterpreter *interpreter = 1787 GetCommandInterpreter().GetScriptInterpreter(); 1788 if (!interpreter) { 1789 result.AppendError("cannot find ScriptInterpreter"); 1790 result.SetStatus(eReturnStatusFailed); 1791 return false; 1792 } 1793 1794 auto cmd_obj_sp = interpreter->CreateScriptCommandObject( 1795 m_options.m_class_name.c_str()); 1796 if (!cmd_obj_sp) { 1797 result.AppendError("cannot create helper object"); 1798 result.SetStatus(eReturnStatusFailed); 1799 return false; 1800 } 1801 1802 CommandObjectSP new_cmd(new CommandObjectScriptingObject( 1803 m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity)); 1804 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { 1805 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1806 } else { 1807 result.AppendError("cannot add command"); 1808 result.SetStatus(eReturnStatusFailed); 1809 } 1810 } 1811 1812 return result.Succeeded(); 1813 } 1814 1815 CommandOptions m_options; 1816 std::string m_cmd_name; 1817 std::string m_short_help; 1818 ScriptedCommandSynchronicity m_synchronicity; 1819 }; 1820 1821 //------------------------------------------------------------------------- 1822 // CommandObjectCommandsScriptList 1823 //------------------------------------------------------------------------- 1824 1825 class CommandObjectCommandsScriptList : public CommandObjectParsed { 1826 public: 1827 CommandObjectCommandsScriptList(CommandInterpreter &interpreter) 1828 : CommandObjectParsed(interpreter, "command script list", 1829 "List defined scripted commands.", nullptr) {} 1830 1831 ~CommandObjectCommandsScriptList() override = default; 1832 1833 bool DoExecute(Args &command, CommandReturnObject &result) override { 1834 m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef); 1835 1836 result.SetStatus(eReturnStatusSuccessFinishResult); 1837 1838 return true; 1839 } 1840 }; 1841 1842 //------------------------------------------------------------------------- 1843 // CommandObjectCommandsScriptClear 1844 //------------------------------------------------------------------------- 1845 1846 class CommandObjectCommandsScriptClear : public CommandObjectParsed { 1847 public: 1848 CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) 1849 : CommandObjectParsed(interpreter, "command script clear", 1850 "Delete all scripted commands.", nullptr) {} 1851 1852 ~CommandObjectCommandsScriptClear() override = default; 1853 1854 protected: 1855 bool DoExecute(Args &command, CommandReturnObject &result) override { 1856 m_interpreter.RemoveAllUser(); 1857 1858 result.SetStatus(eReturnStatusSuccessFinishResult); 1859 1860 return true; 1861 } 1862 }; 1863 1864 //------------------------------------------------------------------------- 1865 // CommandObjectCommandsScriptDelete 1866 //------------------------------------------------------------------------- 1867 1868 class CommandObjectCommandsScriptDelete : public CommandObjectParsed { 1869 public: 1870 CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) 1871 : CommandObjectParsed(interpreter, "command script delete", 1872 "Delete a scripted command.", nullptr) { 1873 CommandArgumentEntry arg1; 1874 CommandArgumentData cmd_arg; 1875 1876 // Define the first (and only) variant of this arg. 1877 cmd_arg.arg_type = eArgTypeCommandName; 1878 cmd_arg.arg_repetition = eArgRepeatPlain; 1879 1880 // There is only one variant this argument could be; put it into the 1881 // argument entry. 1882 arg1.push_back(cmd_arg); 1883 1884 // Push the data for the first argument into the m_arguments vector. 1885 m_arguments.push_back(arg1); 1886 } 1887 1888 ~CommandObjectCommandsScriptDelete() override = default; 1889 1890 protected: 1891 bool DoExecute(Args &command, CommandReturnObject &result) override { 1892 1893 if (command.GetArgumentCount() != 1) { 1894 result.AppendError("'command script delete' requires one argument"); 1895 result.SetStatus(eReturnStatusFailed); 1896 return false; 1897 } 1898 1899 const char *cmd_name = command.GetArgumentAtIndex(0); 1900 1901 if (cmd_name && *cmd_name && m_interpreter.HasUserCommands() && 1902 m_interpreter.UserCommandExists(cmd_name)) { 1903 m_interpreter.RemoveUser(cmd_name); 1904 result.SetStatus(eReturnStatusSuccessFinishResult); 1905 } else { 1906 result.AppendErrorWithFormat("command %s not found", cmd_name); 1907 result.SetStatus(eReturnStatusFailed); 1908 } 1909 1910 return result.Succeeded(); 1911 } 1912 }; 1913 1914 #pragma mark CommandObjectMultiwordCommandsScript 1915 1916 //------------------------------------------------------------------------- 1917 // CommandObjectMultiwordCommandsScript 1918 //------------------------------------------------------------------------- 1919 1920 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword { 1921 public: 1922 CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter) 1923 : CommandObjectMultiword( 1924 interpreter, "command script", "Commands for managing custom " 1925 "commands implemented by " 1926 "interpreter scripts.", 1927 "command script <subcommand> [<subcommand-options>]") { 1928 LoadSubCommand("add", CommandObjectSP( 1929 new CommandObjectCommandsScriptAdd(interpreter))); 1930 LoadSubCommand( 1931 "delete", 1932 CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter))); 1933 LoadSubCommand( 1934 "clear", 1935 CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter))); 1936 LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList( 1937 interpreter))); 1938 LoadSubCommand( 1939 "import", 1940 CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter))); 1941 } 1942 1943 ~CommandObjectMultiwordCommandsScript() override = default; 1944 }; 1945 1946 #pragma mark CommandObjectMultiwordCommands 1947 1948 //------------------------------------------------------------------------- 1949 // CommandObjectMultiwordCommands 1950 //------------------------------------------------------------------------- 1951 1952 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands( 1953 CommandInterpreter &interpreter) 1954 : CommandObjectMultiword(interpreter, "command", 1955 "Commands for managing custom LLDB commands.", 1956 "command <subcommand> [<subcommand-options>]") { 1957 LoadSubCommand("source", 1958 CommandObjectSP(new CommandObjectCommandsSource(interpreter))); 1959 LoadSubCommand("alias", 1960 CommandObjectSP(new CommandObjectCommandsAlias(interpreter))); 1961 LoadSubCommand("unalias", CommandObjectSP( 1962 new CommandObjectCommandsUnalias(interpreter))); 1963 LoadSubCommand("delete", 1964 CommandObjectSP(new CommandObjectCommandsDelete(interpreter))); 1965 LoadSubCommand( 1966 "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter))); 1967 LoadSubCommand("history", CommandObjectSP( 1968 new CommandObjectCommandsHistory(interpreter))); 1969 LoadSubCommand( 1970 "script", 1971 CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter))); 1972 } 1973 1974 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default; 1975