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