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