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 } 828 829 ~CommandObjectCommandsAddRegex() override = default; 830 831 protected: 832 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 833 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); 834 if (output_sp && interactive) { 835 output_sp->PutCString("Enter one or more sed substitution commands in " 836 "the form: 's/<regex>/<subst>/'.\nTerminate the " 837 "substitution list with an empty line.\n"); 838 output_sp->Flush(); 839 } 840 } 841 842 void IOHandlerInputComplete(IOHandler &io_handler, 843 std::string &data) override { 844 io_handler.SetIsDone(true); 845 if (m_regex_cmd_up) { 846 StringList lines; 847 if (lines.SplitIntoLines(data)) { 848 bool check_only = false; 849 for (const std::string &line : lines) { 850 Status error = AppendRegexSubstitution(line, check_only); 851 if (error.Fail()) { 852 if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) { 853 StreamSP out_stream = GetDebugger().GetAsyncOutputStream(); 854 out_stream->Printf("error: %s\n", error.AsCString()); 855 } 856 } 857 } 858 } 859 if (m_regex_cmd_up->HasRegexEntries()) { 860 CommandObjectSP cmd_sp(m_regex_cmd_up.release()); 861 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 862 } 863 } 864 } 865 866 bool DoExecute(Args &command, CommandReturnObject &result) override { 867 const size_t argc = command.GetArgumentCount(); 868 if (argc == 0) { 869 result.AppendError("usage: 'command regex <command-name> " 870 "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n"); 871 return false; 872 } 873 874 Status error; 875 auto name = command[0].ref(); 876 m_regex_cmd_up = std::make_unique<CommandObjectRegexCommand>( 877 m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 10, 0, 878 true); 879 880 if (argc == 1) { 881 Debugger &debugger = GetDebugger(); 882 bool color_prompt = debugger.GetUseColor(); 883 const bool multiple_lines = true; // Get multiple lines 884 IOHandlerSP io_handler_sp(new IOHandlerEditline( 885 debugger, IOHandler::Type::Other, 886 "lldb-regex", // Name of input reader for history 887 llvm::StringRef("> "), // Prompt 888 llvm::StringRef(), // Continuation prompt 889 multiple_lines, color_prompt, 890 0, // Don't show line numbers 891 *this, nullptr)); 892 893 if (io_handler_sp) { 894 debugger.RunIOHandlerAsync(io_handler_sp); 895 result.SetStatus(eReturnStatusSuccessFinishNoResult); 896 } 897 } else { 898 for (auto &entry : command.entries().drop_front()) { 899 bool check_only = false; 900 error = AppendRegexSubstitution(entry.ref(), check_only); 901 if (error.Fail()) 902 break; 903 } 904 905 if (error.Success()) { 906 AddRegexCommandToInterpreter(); 907 } 908 } 909 if (error.Fail()) { 910 result.AppendError(error.AsCString()); 911 } 912 913 return result.Succeeded(); 914 } 915 916 Status AppendRegexSubstitution(const llvm::StringRef ®ex_sed, 917 bool check_only) { 918 Status error; 919 920 if (!m_regex_cmd_up) { 921 error.SetErrorStringWithFormat( 922 "invalid regular expression command object for: '%.*s'", 923 (int)regex_sed.size(), regex_sed.data()); 924 return error; 925 } 926 927 size_t regex_sed_size = regex_sed.size(); 928 929 if (regex_sed_size <= 1) { 930 error.SetErrorStringWithFormat( 931 "regular expression substitution string is too short: '%.*s'", 932 (int)regex_sed.size(), regex_sed.data()); 933 return error; 934 } 935 936 if (regex_sed[0] != 's') { 937 error.SetErrorStringWithFormat("regular expression substitution string " 938 "doesn't start with 's': '%.*s'", 939 (int)regex_sed.size(), regex_sed.data()); 940 return error; 941 } 942 const size_t first_separator_char_pos = 1; 943 // use the char that follows 's' as the regex separator character so we can 944 // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|" 945 const char separator_char = regex_sed[first_separator_char_pos]; 946 const size_t second_separator_char_pos = 947 regex_sed.find(separator_char, first_separator_char_pos + 1); 948 949 if (second_separator_char_pos == std::string::npos) { 950 error.SetErrorStringWithFormat( 951 "missing second '%c' separator char after '%.*s' in '%.*s'", 952 separator_char, 953 (int)(regex_sed.size() - first_separator_char_pos - 1), 954 regex_sed.data() + (first_separator_char_pos + 1), 955 (int)regex_sed.size(), regex_sed.data()); 956 return error; 957 } 958 959 const size_t third_separator_char_pos = 960 regex_sed.find(separator_char, second_separator_char_pos + 1); 961 962 if (third_separator_char_pos == std::string::npos) { 963 error.SetErrorStringWithFormat( 964 "missing third '%c' separator char after '%.*s' in '%.*s'", 965 separator_char, 966 (int)(regex_sed.size() - second_separator_char_pos - 1), 967 regex_sed.data() + (second_separator_char_pos + 1), 968 (int)regex_sed.size(), regex_sed.data()); 969 return error; 970 } 971 972 if (third_separator_char_pos != regex_sed_size - 1) { 973 // Make sure that everything that follows the last regex separator char 974 if (regex_sed.find_first_not_of("\t\n\v\f\r ", 975 third_separator_char_pos + 1) != 976 std::string::npos) { 977 error.SetErrorStringWithFormat( 978 "extra data found after the '%.*s' regular expression substitution " 979 "string: '%.*s'", 980 (int)third_separator_char_pos + 1, regex_sed.data(), 981 (int)(regex_sed.size() - third_separator_char_pos - 1), 982 regex_sed.data() + (third_separator_char_pos + 1)); 983 return error; 984 } 985 } else if (first_separator_char_pos + 1 == second_separator_char_pos) { 986 error.SetErrorStringWithFormat( 987 "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 988 separator_char, separator_char, separator_char, (int)regex_sed.size(), 989 regex_sed.data()); 990 return error; 991 } else if (second_separator_char_pos + 1 == third_separator_char_pos) { 992 error.SetErrorStringWithFormat( 993 "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 994 separator_char, separator_char, separator_char, (int)regex_sed.size(), 995 regex_sed.data()); 996 return error; 997 } 998 999 if (!check_only) { 1000 std::string regex(std::string(regex_sed.substr( 1001 first_separator_char_pos + 1, 1002 second_separator_char_pos - first_separator_char_pos - 1))); 1003 std::string subst(std::string(regex_sed.substr( 1004 second_separator_char_pos + 1, 1005 third_separator_char_pos - second_separator_char_pos - 1))); 1006 m_regex_cmd_up->AddRegexCommand(regex, subst); 1007 } 1008 return error; 1009 } 1010 1011 void AddRegexCommandToInterpreter() { 1012 if (m_regex_cmd_up) { 1013 if (m_regex_cmd_up->HasRegexEntries()) { 1014 CommandObjectSP cmd_sp(m_regex_cmd_up.release()); 1015 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 1016 } 1017 } 1018 } 1019 1020 private: 1021 std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up; 1022 1023 class CommandOptions : public Options { 1024 public: 1025 CommandOptions() = default; 1026 1027 ~CommandOptions() override = default; 1028 1029 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1030 ExecutionContext *execution_context) override { 1031 Status error; 1032 const int short_option = m_getopt_table[option_idx].val; 1033 1034 switch (short_option) { 1035 case 'h': 1036 m_help.assign(std::string(option_arg)); 1037 break; 1038 case 's': 1039 m_syntax.assign(std::string(option_arg)); 1040 break; 1041 default: 1042 llvm_unreachable("Unimplemented option"); 1043 } 1044 1045 return error; 1046 } 1047 1048 void OptionParsingStarting(ExecutionContext *execution_context) override { 1049 m_help.clear(); 1050 m_syntax.clear(); 1051 } 1052 1053 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1054 return llvm::makeArrayRef(g_regex_options); 1055 } 1056 1057 llvm::StringRef GetHelp() { return m_help; } 1058 1059 llvm::StringRef GetSyntax() { return m_syntax; } 1060 1061 protected: 1062 // Instance variables to hold the values for command options. 1063 1064 std::string m_help; 1065 std::string m_syntax; 1066 }; 1067 1068 Options *GetOptions() override { return &m_options; } 1069 1070 CommandOptions m_options; 1071 }; 1072 1073 class CommandObjectPythonFunction : public CommandObjectRaw { 1074 public: 1075 CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name, 1076 std::string funct, std::string help, 1077 ScriptedCommandSynchronicity synch) 1078 : CommandObjectRaw(interpreter, name), m_function_name(funct), 1079 m_synchro(synch) { 1080 if (!help.empty()) 1081 SetHelp(help); 1082 else { 1083 StreamString stream; 1084 stream.Printf("For more information run 'help %s'", name.c_str()); 1085 SetHelp(stream.GetString()); 1086 } 1087 } 1088 1089 ~CommandObjectPythonFunction() override = default; 1090 1091 bool IsRemovable() const override { return true; } 1092 1093 const std::string &GetFunctionName() { return m_function_name; } 1094 1095 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1096 1097 llvm::StringRef GetHelpLong() override { 1098 if (m_fetched_help_long) 1099 return CommandObjectRaw::GetHelpLong(); 1100 1101 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1102 if (!scripter) 1103 return CommandObjectRaw::GetHelpLong(); 1104 1105 std::string docstring; 1106 m_fetched_help_long = 1107 scripter->GetDocumentationForItem(m_function_name.c_str(), docstring); 1108 if (!docstring.empty()) 1109 SetHelpLong(docstring); 1110 return CommandObjectRaw::GetHelpLong(); 1111 } 1112 1113 protected: 1114 bool DoExecute(llvm::StringRef raw_command_line, 1115 CommandReturnObject &result) override { 1116 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1117 1118 Status error; 1119 1120 result.SetStatus(eReturnStatusInvalid); 1121 1122 if (!scripter || !scripter->RunScriptBasedCommand( 1123 m_function_name.c_str(), raw_command_line, m_synchro, 1124 result, error, m_exe_ctx)) { 1125 result.AppendError(error.AsCString()); 1126 } else { 1127 // Don't change the status if the command already set it... 1128 if (result.GetStatus() == eReturnStatusInvalid) { 1129 if (result.GetOutputData().empty()) 1130 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1131 else 1132 result.SetStatus(eReturnStatusSuccessFinishResult); 1133 } 1134 } 1135 1136 return result.Succeeded(); 1137 } 1138 1139 private: 1140 std::string m_function_name; 1141 ScriptedCommandSynchronicity m_synchro; 1142 bool m_fetched_help_long = false; 1143 }; 1144 1145 class CommandObjectScriptingObject : public CommandObjectRaw { 1146 public: 1147 CommandObjectScriptingObject(CommandInterpreter &interpreter, 1148 std::string name, 1149 StructuredData::GenericSP cmd_obj_sp, 1150 ScriptedCommandSynchronicity synch) 1151 : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp), 1152 m_synchro(synch), m_fetched_help_short(false), 1153 m_fetched_help_long(false) { 1154 StreamString stream; 1155 stream.Printf("For more information run 'help %s'", name.c_str()); 1156 SetHelp(stream.GetString()); 1157 if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter()) 1158 GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); 1159 } 1160 1161 ~CommandObjectScriptingObject() override = default; 1162 1163 bool IsRemovable() const override { return true; } 1164 1165 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1166 1167 llvm::StringRef GetHelp() override { 1168 if (m_fetched_help_short) 1169 return CommandObjectRaw::GetHelp(); 1170 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1171 if (!scripter) 1172 return CommandObjectRaw::GetHelp(); 1173 std::string docstring; 1174 m_fetched_help_short = 1175 scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring); 1176 if (!docstring.empty()) 1177 SetHelp(docstring); 1178 1179 return CommandObjectRaw::GetHelp(); 1180 } 1181 1182 llvm::StringRef GetHelpLong() override { 1183 if (m_fetched_help_long) 1184 return CommandObjectRaw::GetHelpLong(); 1185 1186 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1187 if (!scripter) 1188 return CommandObjectRaw::GetHelpLong(); 1189 1190 std::string docstring; 1191 m_fetched_help_long = 1192 scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring); 1193 if (!docstring.empty()) 1194 SetHelpLong(docstring); 1195 return CommandObjectRaw::GetHelpLong(); 1196 } 1197 1198 protected: 1199 bool DoExecute(llvm::StringRef raw_command_line, 1200 CommandReturnObject &result) override { 1201 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1202 1203 Status error; 1204 1205 result.SetStatus(eReturnStatusInvalid); 1206 1207 if (!scripter || 1208 !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line, 1209 m_synchro, result, error, m_exe_ctx)) { 1210 result.AppendError(error.AsCString()); 1211 } else { 1212 // Don't change the status if the command already set it... 1213 if (result.GetStatus() == eReturnStatusInvalid) { 1214 if (result.GetOutputData().empty()) 1215 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1216 else 1217 result.SetStatus(eReturnStatusSuccessFinishResult); 1218 } 1219 } 1220 1221 return result.Succeeded(); 1222 } 1223 1224 private: 1225 StructuredData::GenericSP m_cmd_obj_sp; 1226 ScriptedCommandSynchronicity m_synchro; 1227 bool m_fetched_help_short : 1; 1228 bool m_fetched_help_long : 1; 1229 }; 1230 1231 // CommandObjectCommandsScriptImport 1232 #define LLDB_OPTIONS_script_import 1233 #include "CommandOptions.inc" 1234 1235 class CommandObjectCommandsScriptImport : public CommandObjectParsed { 1236 public: 1237 CommandObjectCommandsScriptImport(CommandInterpreter &interpreter) 1238 : CommandObjectParsed(interpreter, "command script import", 1239 "Import a scripting module in LLDB.", nullptr) { 1240 CommandArgumentEntry arg1; 1241 CommandArgumentData cmd_arg; 1242 1243 // Define the first (and only) variant of this arg. 1244 cmd_arg.arg_type = eArgTypeFilename; 1245 cmd_arg.arg_repetition = eArgRepeatPlus; 1246 1247 // There is only one variant this argument could be; put it into the 1248 // argument entry. 1249 arg1.push_back(cmd_arg); 1250 1251 // Push the data for the first argument into the m_arguments vector. 1252 m_arguments.push_back(arg1); 1253 } 1254 1255 ~CommandObjectCommandsScriptImport() override = default; 1256 1257 void 1258 HandleArgumentCompletion(CompletionRequest &request, 1259 OptionElementVector &opt_element_vector) override { 1260 CommandCompletions::InvokeCommonCompletionCallbacks( 1261 GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, 1262 request, nullptr); 1263 } 1264 1265 Options *GetOptions() override { return &m_options; } 1266 1267 protected: 1268 class CommandOptions : public Options { 1269 public: 1270 CommandOptions() = default; 1271 1272 ~CommandOptions() override = default; 1273 1274 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1275 ExecutionContext *execution_context) override { 1276 Status error; 1277 const int short_option = m_getopt_table[option_idx].val; 1278 1279 switch (short_option) { 1280 case 'r': 1281 // NO-OP 1282 break; 1283 case 'c': 1284 relative_to_command_file = true; 1285 break; 1286 case 's': 1287 silent = true; 1288 break; 1289 default: 1290 llvm_unreachable("Unimplemented option"); 1291 } 1292 1293 return error; 1294 } 1295 1296 void OptionParsingStarting(ExecutionContext *execution_context) override { 1297 relative_to_command_file = false; 1298 } 1299 1300 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1301 return llvm::makeArrayRef(g_script_import_options); 1302 } 1303 bool relative_to_command_file = false; 1304 bool silent = false; 1305 }; 1306 1307 bool DoExecute(Args &command, CommandReturnObject &result) override { 1308 if (command.empty()) { 1309 result.AppendError("command script import needs one or more arguments"); 1310 return false; 1311 } 1312 1313 FileSpec source_dir = {}; 1314 if (m_options.relative_to_command_file) { 1315 source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir(); 1316 if (!source_dir) { 1317 result.AppendError("command script import -c can only be specified " 1318 "from a command file"); 1319 return false; 1320 } 1321 } 1322 1323 for (auto &entry : command.entries()) { 1324 Status error; 1325 1326 LoadScriptOptions options; 1327 options.SetInitSession(true); 1328 options.SetSilent(m_options.silent); 1329 1330 // FIXME: this is necessary because CommandObject::CheckRequirements() 1331 // assumes that commands won't ever be recursively invoked, but it's 1332 // actually possible to craft a Python script that does other "command 1333 // script imports" in __lldb_init_module the real fix is to have 1334 // recursive commands possible with a CommandInvocation object separate 1335 // from the CommandObject itself, so that recursive command invocations 1336 // won't stomp on each other (wrt to execution contents, options, and 1337 // more) 1338 m_exe_ctx.Clear(); 1339 if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule( 1340 entry.c_str(), options, error, /*module_sp=*/nullptr, 1341 source_dir)) { 1342 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1343 } else { 1344 result.AppendErrorWithFormat("module importing failed: %s", 1345 error.AsCString()); 1346 } 1347 } 1348 1349 return result.Succeeded(); 1350 } 1351 1352 CommandOptions m_options; 1353 }; 1354 1355 // CommandObjectCommandsScriptAdd 1356 static constexpr OptionEnumValueElement g_script_synchro_type[] = { 1357 { 1358 eScriptedCommandSynchronicitySynchronous, 1359 "synchronous", 1360 "Run synchronous", 1361 }, 1362 { 1363 eScriptedCommandSynchronicityAsynchronous, 1364 "asynchronous", 1365 "Run asynchronous", 1366 }, 1367 { 1368 eScriptedCommandSynchronicityCurrentValue, 1369 "current", 1370 "Do not alter current setting", 1371 }, 1372 }; 1373 1374 static constexpr OptionEnumValues ScriptSynchroType() { 1375 return OptionEnumValues(g_script_synchro_type); 1376 } 1377 1378 #define LLDB_OPTIONS_script_add 1379 #include "CommandOptions.inc" 1380 1381 class CommandObjectCommandsScriptAdd : public CommandObjectParsed, 1382 public IOHandlerDelegateMultiline { 1383 public: 1384 CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) 1385 : CommandObjectParsed(interpreter, "command script add", 1386 "Add a scripted function as an LLDB command.", 1387 "Add a scripted function as an lldb command. " 1388 "If you provide a single argument, the command " 1389 "will be added at the root level of the command " 1390 "hierarchy. If there are more arguments they " 1391 "must be a path to a user-added container " 1392 "command, and the last element will be the new " 1393 "command name."), 1394 IOHandlerDelegateMultiline("DONE") { 1395 CommandArgumentEntry arg1; 1396 CommandArgumentData cmd_arg; 1397 1398 // This is one or more command names, which form the path to the command 1399 // you want to add. 1400 cmd_arg.arg_type = eArgTypeCommand; 1401 cmd_arg.arg_repetition = eArgRepeatPlus; 1402 1403 // There is only one variant this argument could be; put it into the 1404 // argument entry. 1405 arg1.push_back(cmd_arg); 1406 1407 // Push the data for the first argument into the m_arguments vector. 1408 m_arguments.push_back(arg1); 1409 } 1410 1411 ~CommandObjectCommandsScriptAdd() override = default; 1412 1413 Options *GetOptions() override { return &m_options; } 1414 1415 void 1416 HandleArgumentCompletion(CompletionRequest &request, 1417 OptionElementVector &opt_element_vector) override { 1418 CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request, 1419 opt_element_vector); 1420 } 1421 1422 protected: 1423 class CommandOptions : public Options { 1424 public: 1425 CommandOptions() = default; 1426 1427 ~CommandOptions() override = default; 1428 1429 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1430 ExecutionContext *execution_context) override { 1431 Status error; 1432 const int short_option = m_getopt_table[option_idx].val; 1433 1434 switch (short_option) { 1435 case 'f': 1436 if (!option_arg.empty()) 1437 m_funct_name = std::string(option_arg); 1438 break; 1439 case 'c': 1440 if (!option_arg.empty()) 1441 m_class_name = std::string(option_arg); 1442 break; 1443 case 'h': 1444 if (!option_arg.empty()) 1445 m_short_help = std::string(option_arg); 1446 break; 1447 case 'o': 1448 m_overwrite_lazy = eLazyBoolYes; 1449 break; 1450 case 's': 1451 m_synchronicity = 1452 (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum( 1453 option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 1454 if (!error.Success()) 1455 error.SetErrorStringWithFormat( 1456 "unrecognized value for synchronicity '%s'", 1457 option_arg.str().c_str()); 1458 break; 1459 default: 1460 llvm_unreachable("Unimplemented option"); 1461 } 1462 1463 return error; 1464 } 1465 1466 void OptionParsingStarting(ExecutionContext *execution_context) override { 1467 m_class_name.clear(); 1468 m_funct_name.clear(); 1469 m_short_help.clear(); 1470 m_overwrite_lazy = eLazyBoolCalculate; 1471 m_synchronicity = eScriptedCommandSynchronicitySynchronous; 1472 } 1473 1474 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1475 return llvm::makeArrayRef(g_script_add_options); 1476 } 1477 1478 // Instance variables to hold the values for command options. 1479 1480 std::string m_class_name; 1481 std::string m_funct_name; 1482 std::string m_short_help; 1483 LazyBool m_overwrite_lazy = eLazyBoolCalculate; 1484 ScriptedCommandSynchronicity m_synchronicity = 1485 eScriptedCommandSynchronicitySynchronous; 1486 }; 1487 1488 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 1489 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); 1490 if (output_sp && interactive) { 1491 output_sp->PutCString(g_python_command_instructions); 1492 output_sp->Flush(); 1493 } 1494 } 1495 1496 void IOHandlerInputComplete(IOHandler &io_handler, 1497 std::string &data) override { 1498 StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); 1499 1500 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1501 if (interpreter) { 1502 StringList lines; 1503 lines.SplitIntoLines(data); 1504 if (lines.GetSize() > 0) { 1505 std::string funct_name_str; 1506 if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) { 1507 if (funct_name_str.empty()) { 1508 error_sp->Printf("error: unable to obtain a function name, didn't " 1509 "add python command.\n"); 1510 error_sp->Flush(); 1511 } else { 1512 // everything should be fine now, let's add this alias 1513 1514 CommandObjectSP command_obj_sp(new CommandObjectPythonFunction( 1515 m_interpreter, m_cmd_name, funct_name_str, m_short_help, 1516 m_synchronicity)); 1517 if (!m_container) { 1518 Status error = m_interpreter.AddUserCommand( 1519 m_cmd_name, command_obj_sp, m_overwrite); 1520 if (error.Fail()) { 1521 error_sp->Printf("error: unable to add selected command: '%s'", 1522 error.AsCString()); 1523 error_sp->Flush(); 1524 } 1525 } else { 1526 llvm::Error llvm_error = m_container->LoadUserSubcommand( 1527 m_cmd_name, command_obj_sp, m_overwrite); 1528 if (llvm_error) { 1529 error_sp->Printf("error: unable to add selected command: '%s'", 1530 llvm::toString(std::move(llvm_error)).c_str()); 1531 error_sp->Flush(); 1532 } 1533 } 1534 } 1535 } else { 1536 error_sp->Printf( 1537 "error: unable to create function, didn't add python command\n"); 1538 error_sp->Flush(); 1539 } 1540 } else { 1541 error_sp->Printf("error: empty function, didn't add python command\n"); 1542 error_sp->Flush(); 1543 } 1544 } else { 1545 error_sp->Printf( 1546 "error: script interpreter missing, didn't add python command\n"); 1547 error_sp->Flush(); 1548 } 1549 1550 io_handler.SetIsDone(true); 1551 } 1552 1553 bool DoExecute(Args &command, CommandReturnObject &result) override { 1554 if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) { 1555 result.AppendError("only scripting language supported for scripted " 1556 "commands is currently Python"); 1557 return false; 1558 } 1559 1560 if (command.GetArgumentCount() == 0) { 1561 result.AppendError("'command script add' requires at least one argument"); 1562 return false; 1563 } 1564 // Store the options in case we get multi-line input, also figure out the 1565 // default if not user supplied: 1566 switch (m_options.m_overwrite_lazy) { 1567 case eLazyBoolCalculate: 1568 m_overwrite = !GetDebugger().GetCommandInterpreter().GetRequireCommandOverwrite(); 1569 break; 1570 case eLazyBoolYes: 1571 m_overwrite = true; 1572 break; 1573 case eLazyBoolNo: 1574 m_overwrite = false; 1575 } 1576 1577 Status path_error; 1578 m_container = GetCommandInterpreter().VerifyUserMultiwordCmdPath( 1579 command, true, path_error); 1580 1581 if (path_error.Fail()) { 1582 result.AppendErrorWithFormat("error in command path: %s", 1583 path_error.AsCString()); 1584 return false; 1585 } 1586 1587 if (!m_container) { 1588 // This is getting inserted into the root of the interpreter. 1589 m_cmd_name = std::string(command[0].ref()); 1590 } else { 1591 size_t num_args = command.GetArgumentCount(); 1592 m_cmd_name = std::string(command[num_args - 1].ref()); 1593 } 1594 1595 m_short_help.assign(m_options.m_short_help); 1596 m_synchronicity = m_options.m_synchronicity; 1597 1598 // Handle the case where we prompt for the script code first: 1599 if (m_options.m_class_name.empty() && m_options.m_funct_name.empty()) { 1600 m_interpreter.GetPythonCommandsFromIOHandler(" ", // Prompt 1601 *this); // IOHandlerDelegate 1602 return result.Succeeded(); 1603 } 1604 1605 CommandObjectSP new_cmd_sp; 1606 if (m_options.m_class_name.empty()) { 1607 new_cmd_sp.reset(new CommandObjectPythonFunction( 1608 m_interpreter, m_cmd_name, m_options.m_funct_name, 1609 m_options.m_short_help, m_synchronicity)); 1610 } else { 1611 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1612 if (!interpreter) { 1613 result.AppendError("cannot find ScriptInterpreter"); 1614 return false; 1615 } 1616 1617 auto cmd_obj_sp = interpreter->CreateScriptCommandObject( 1618 m_options.m_class_name.c_str()); 1619 if (!cmd_obj_sp) { 1620 result.AppendError("cannot create helper object"); 1621 return false; 1622 } 1623 1624 new_cmd_sp.reset(new CommandObjectScriptingObject( 1625 m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity)); 1626 } 1627 1628 // Assume we're going to succeed... 1629 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1630 if (!m_container) { 1631 Status add_error = 1632 m_interpreter.AddUserCommand(m_cmd_name, new_cmd_sp, m_overwrite); 1633 if (add_error.Fail()) 1634 result.AppendErrorWithFormat("cannot add command: %s", 1635 add_error.AsCString()); 1636 } else { 1637 llvm::Error llvm_error = 1638 m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite); 1639 if (llvm_error) 1640 result.AppendErrorWithFormat("cannot add command: %s", 1641 llvm::toString(std::move(llvm_error)).c_str()); 1642 } 1643 return result.Succeeded(); 1644 } 1645 1646 CommandOptions m_options; 1647 std::string m_cmd_name; 1648 CommandObjectMultiword *m_container = nullptr; 1649 std::string m_short_help; 1650 bool m_overwrite = false; 1651 ScriptedCommandSynchronicity m_synchronicity = 1652 eScriptedCommandSynchronicitySynchronous; 1653 }; 1654 1655 // CommandObjectCommandsScriptList 1656 1657 class CommandObjectCommandsScriptList : public CommandObjectParsed { 1658 public: 1659 CommandObjectCommandsScriptList(CommandInterpreter &interpreter) 1660 : CommandObjectParsed(interpreter, "command script list", 1661 "List defined top-level scripted commands.", 1662 nullptr) {} 1663 1664 ~CommandObjectCommandsScriptList() override = default; 1665 1666 bool DoExecute(Args &command, CommandReturnObject &result) override { 1667 if (command.GetArgumentCount() != 0) { 1668 result.AppendError("'command script list' doesn't take any arguments"); 1669 return false; 1670 } 1671 1672 m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef); 1673 1674 result.SetStatus(eReturnStatusSuccessFinishResult); 1675 1676 return true; 1677 } 1678 }; 1679 1680 // CommandObjectCommandsScriptClear 1681 1682 class CommandObjectCommandsScriptClear : public CommandObjectParsed { 1683 public: 1684 CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) 1685 : CommandObjectParsed(interpreter, "command script clear", 1686 "Delete all scripted commands.", nullptr) {} 1687 1688 ~CommandObjectCommandsScriptClear() override = default; 1689 1690 protected: 1691 bool DoExecute(Args &command, CommandReturnObject &result) override { 1692 if (command.GetArgumentCount() != 0) { 1693 result.AppendError("'command script clear' doesn't take any arguments"); 1694 return false; 1695 } 1696 1697 m_interpreter.RemoveAllUser(); 1698 1699 result.SetStatus(eReturnStatusSuccessFinishResult); 1700 1701 return true; 1702 } 1703 }; 1704 1705 // CommandObjectCommandsScriptDelete 1706 1707 class CommandObjectCommandsScriptDelete : public CommandObjectParsed { 1708 public: 1709 CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) 1710 : CommandObjectParsed( 1711 interpreter, "command script delete", 1712 "Delete a scripted command by specifying the path to the command.", 1713 nullptr) { 1714 CommandArgumentEntry arg1; 1715 CommandArgumentData cmd_arg; 1716 1717 // This is a list of command names forming the path to the command 1718 // to be deleted. 1719 cmd_arg.arg_type = eArgTypeCommand; 1720 cmd_arg.arg_repetition = eArgRepeatPlus; 1721 1722 // There is only one variant this argument could be; put it into the 1723 // argument entry. 1724 arg1.push_back(cmd_arg); 1725 1726 // Push the data for the first argument into the m_arguments vector. 1727 m_arguments.push_back(arg1); 1728 } 1729 1730 ~CommandObjectCommandsScriptDelete() override = default; 1731 1732 void 1733 HandleArgumentCompletion(CompletionRequest &request, 1734 OptionElementVector &opt_element_vector) override { 1735 CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request, 1736 opt_element_vector); 1737 } 1738 1739 protected: 1740 bool DoExecute(Args &command, CommandReturnObject &result) override { 1741 1742 llvm::StringRef root_cmd = command[0].ref(); 1743 size_t num_args = command.GetArgumentCount(); 1744 1745 if (root_cmd.empty()) { 1746 result.AppendErrorWithFormat("empty root command name"); 1747 return false; 1748 } 1749 if (!m_interpreter.HasUserCommands() && 1750 !m_interpreter.HasUserMultiwordCommands()) { 1751 result.AppendErrorWithFormat("can only delete user defined commands, " 1752 "but no user defined commands found"); 1753 return false; 1754 } 1755 1756 CommandObjectSP cmd_sp = m_interpreter.GetCommandSPExact(root_cmd); 1757 if (!cmd_sp) { 1758 result.AppendErrorWithFormat("command '%s' not found.", 1759 command[0].c_str()); 1760 return false; 1761 } 1762 if (!cmd_sp->IsUserCommand()) { 1763 result.AppendErrorWithFormat("command '%s' is not a user command.", 1764 command[0].c_str()); 1765 return false; 1766 } 1767 if (cmd_sp->GetAsMultiwordCommand() && num_args == 1) { 1768 result.AppendErrorWithFormat("command '%s' is a multi-word command.\n " 1769 "Delete with \"command container delete\"", 1770 command[0].c_str()); 1771 return false; 1772 } 1773 1774 if (command.GetArgumentCount() == 1) { 1775 m_interpreter.RemoveUser(root_cmd); 1776 result.SetStatus(eReturnStatusSuccessFinishResult); 1777 return true; 1778 } 1779 // We're deleting a command from a multiword command. Verify the command 1780 // path: 1781 Status error; 1782 CommandObjectMultiword *container = 1783 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 1784 error); 1785 if (error.Fail()) { 1786 result.AppendErrorWithFormat("could not resolve command path: %s", 1787 error.AsCString()); 1788 return false; 1789 } 1790 if (!container) { 1791 // This means that command only had a leaf command, so the container is 1792 // the root. That should have been handled above. 1793 result.AppendErrorWithFormat("could not find a container for '%s'", 1794 command[0].c_str()); 1795 return false; 1796 } 1797 const char *leaf_cmd = command[num_args - 1].c_str(); 1798 llvm::Error llvm_error = container->RemoveUserSubcommand(leaf_cmd, 1799 /* multiword not okay */ false); 1800 if (llvm_error) { 1801 result.AppendErrorWithFormat("could not delete command '%s': %s", 1802 leaf_cmd, 1803 llvm::toString(std::move(llvm_error)).c_str()); 1804 return false; 1805 } 1806 1807 Stream &out_stream = result.GetOutputStream(); 1808 1809 out_stream << "Deleted command:"; 1810 for (size_t idx = 0; idx < num_args; idx++) { 1811 out_stream << ' '; 1812 out_stream << command[idx].c_str(); 1813 } 1814 out_stream << '\n'; 1815 result.SetStatus(eReturnStatusSuccessFinishResult); 1816 return true; 1817 } 1818 }; 1819 1820 #pragma mark CommandObjectMultiwordCommandsScript 1821 1822 // CommandObjectMultiwordCommandsScript 1823 1824 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword { 1825 public: 1826 CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter) 1827 : CommandObjectMultiword( 1828 interpreter, "command script", 1829 "Commands for managing custom " 1830 "commands implemented by " 1831 "interpreter scripts.", 1832 "command script <subcommand> [<subcommand-options>]") { 1833 LoadSubCommand("add", CommandObjectSP( 1834 new CommandObjectCommandsScriptAdd(interpreter))); 1835 LoadSubCommand( 1836 "delete", 1837 CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter))); 1838 LoadSubCommand( 1839 "clear", 1840 CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter))); 1841 LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList( 1842 interpreter))); 1843 LoadSubCommand( 1844 "import", 1845 CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter))); 1846 } 1847 1848 ~CommandObjectMultiwordCommandsScript() override = default; 1849 }; 1850 1851 #pragma mark CommandObjectCommandContainer 1852 #define LLDB_OPTIONS_container_add 1853 #include "CommandOptions.inc" 1854 1855 class CommandObjectCommandsContainerAdd : public CommandObjectParsed { 1856 public: 1857 CommandObjectCommandsContainerAdd(CommandInterpreter &interpreter) 1858 : CommandObjectParsed( 1859 interpreter, "command container add", 1860 "Add a container command to lldb. Adding to built-" 1861 "in container commands is not allowed.", 1862 "command container add [[path1]...] container-name") { 1863 CommandArgumentEntry arg1; 1864 CommandArgumentData cmd_arg; 1865 1866 // This is one or more command names, which form the path to the command 1867 // you want to add. 1868 cmd_arg.arg_type = eArgTypeCommand; 1869 cmd_arg.arg_repetition = eArgRepeatPlus; 1870 1871 // There is only one variant this argument could be; put it into the 1872 // argument entry. 1873 arg1.push_back(cmd_arg); 1874 1875 // Push the data for the first argument into the m_arguments vector. 1876 m_arguments.push_back(arg1); 1877 } 1878 1879 ~CommandObjectCommandsContainerAdd() override = default; 1880 1881 Options *GetOptions() override { return &m_options; } 1882 1883 void 1884 HandleArgumentCompletion(CompletionRequest &request, 1885 OptionElementVector &opt_element_vector) override { 1886 CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request, 1887 opt_element_vector); 1888 } 1889 1890 protected: 1891 class CommandOptions : public Options { 1892 public: 1893 CommandOptions() = default; 1894 1895 ~CommandOptions() override = default; 1896 1897 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1898 ExecutionContext *execution_context) override { 1899 Status error; 1900 const int short_option = m_getopt_table[option_idx].val; 1901 1902 switch (short_option) { 1903 case 'h': 1904 if (!option_arg.empty()) 1905 m_short_help = std::string(option_arg); 1906 break; 1907 case 'o': 1908 m_overwrite = true; 1909 break; 1910 case 'H': 1911 if (!option_arg.empty()) 1912 m_long_help = std::string(option_arg); 1913 break; 1914 default: 1915 llvm_unreachable("Unimplemented option"); 1916 } 1917 1918 return error; 1919 } 1920 1921 void OptionParsingStarting(ExecutionContext *execution_context) override { 1922 m_short_help.clear(); 1923 m_long_help.clear(); 1924 m_overwrite = false; 1925 } 1926 1927 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1928 return llvm::makeArrayRef(g_container_add_options); 1929 } 1930 1931 // Instance variables to hold the values for command options. 1932 1933 std::string m_short_help; 1934 std::string m_long_help; 1935 bool m_overwrite = false; 1936 }; 1937 bool DoExecute(Args &command, CommandReturnObject &result) override { 1938 size_t num_args = command.GetArgumentCount(); 1939 1940 if (num_args == 0) { 1941 result.AppendError("no command was specified"); 1942 return false; 1943 } 1944 1945 if (num_args == 1) { 1946 // We're adding this as a root command, so use the interpreter. 1947 const char *cmd_name = command.GetArgumentAtIndex(0); 1948 auto cmd_sp = CommandObjectSP(new CommandObjectMultiword( 1949 GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(), 1950 m_options.m_long_help.c_str())); 1951 cmd_sp->GetAsMultiwordCommand()->SetRemovable(true); 1952 Status add_error = GetCommandInterpreter().AddUserCommand( 1953 cmd_name, cmd_sp, m_options.m_overwrite); 1954 if (add_error.Fail()) { 1955 result.AppendErrorWithFormat("error adding command: %s", 1956 add_error.AsCString()); 1957 return false; 1958 } 1959 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1960 return true; 1961 } 1962 1963 // We're adding this to a subcommand, first find the subcommand: 1964 Status path_error; 1965 CommandObjectMultiword *add_to_me = 1966 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 1967 path_error); 1968 1969 if (!add_to_me) { 1970 result.AppendErrorWithFormat("error adding command: %s", 1971 path_error.AsCString()); 1972 return false; 1973 } 1974 1975 const char *cmd_name = command.GetArgumentAtIndex(num_args - 1); 1976 auto cmd_sp = CommandObjectSP(new CommandObjectMultiword( 1977 GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(), 1978 m_options.m_long_help.c_str())); 1979 llvm::Error llvm_error = 1980 add_to_me->LoadUserSubcommand(cmd_name, cmd_sp, m_options.m_overwrite); 1981 if (llvm_error) { 1982 result.AppendErrorWithFormat("error adding subcommand: %s", 1983 llvm::toString(std::move(llvm_error)).c_str()); 1984 return false; 1985 } 1986 1987 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1988 return true; 1989 } 1990 1991 private: 1992 CommandOptions m_options; 1993 }; 1994 1995 #define LLDB_OPTIONS_multiword_delete 1996 #include "CommandOptions.inc" 1997 class CommandObjectCommandsContainerDelete : public CommandObjectParsed { 1998 public: 1999 CommandObjectCommandsContainerDelete(CommandInterpreter &interpreter) 2000 : CommandObjectParsed( 2001 interpreter, "command container delete", 2002 "Delete a container command previously added to " 2003 "lldb.", 2004 "command container delete [[path1] ...] container-cmd") { 2005 CommandArgumentEntry arg1; 2006 CommandArgumentData cmd_arg; 2007 2008 // This is one or more command names, which form the path to the command 2009 // you want to add. 2010 cmd_arg.arg_type = eArgTypeCommand; 2011 cmd_arg.arg_repetition = eArgRepeatPlus; 2012 2013 // There is only one variant this argument could be; put it into the 2014 // argument entry. 2015 arg1.push_back(cmd_arg); 2016 2017 // Push the data for the first argument into the m_arguments vector. 2018 m_arguments.push_back(arg1); 2019 } 2020 2021 ~CommandObjectCommandsContainerDelete() override = default; 2022 2023 void 2024 HandleArgumentCompletion(CompletionRequest &request, 2025 OptionElementVector &opt_element_vector) override { 2026 CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request, 2027 opt_element_vector); 2028 } 2029 2030 protected: 2031 bool DoExecute(Args &command, CommandReturnObject &result) override { 2032 size_t num_args = command.GetArgumentCount(); 2033 2034 if (num_args == 0) { 2035 result.AppendError("No command was specified."); 2036 return false; 2037 } 2038 2039 if (num_args == 1) { 2040 // We're removing a root command, so we need to delete it from the 2041 // interpreter. 2042 const char *cmd_name = command.GetArgumentAtIndex(0); 2043 // Let's do a little more work here so we can do better error reporting. 2044 CommandInterpreter &interp = GetCommandInterpreter(); 2045 CommandObjectSP cmd_sp = interp.GetCommandSPExact(cmd_name); 2046 if (!cmd_sp) { 2047 result.AppendErrorWithFormat("container command %s doesn't exist.", 2048 cmd_name); 2049 return false; 2050 } 2051 if (!cmd_sp->IsUserCommand()) { 2052 result.AppendErrorWithFormat( 2053 "container command %s is not a user command", cmd_name); 2054 return false; 2055 } 2056 if (!cmd_sp->GetAsMultiwordCommand()) { 2057 result.AppendErrorWithFormat("command %s is not a container command", 2058 cmd_name); 2059 return false; 2060 } 2061 2062 bool did_remove = GetCommandInterpreter().RemoveUserMultiword(cmd_name); 2063 if (!did_remove) { 2064 result.AppendErrorWithFormat("error removing command %s.", cmd_name); 2065 return false; 2066 } 2067 2068 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2069 return true; 2070 } 2071 2072 // We're removing a subcommand, first find the subcommand's owner: 2073 Status path_error; 2074 CommandObjectMultiword *container = 2075 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 2076 path_error); 2077 2078 if (!container) { 2079 result.AppendErrorWithFormat("error removing container command: %s", 2080 path_error.AsCString()); 2081 return false; 2082 } 2083 const char *leaf = command.GetArgumentAtIndex(num_args - 1); 2084 llvm::Error llvm_error = 2085 container->RemoveUserSubcommand(leaf, /* multiword okay */ true); 2086 if (llvm_error) { 2087 result.AppendErrorWithFormat("error removing container command: %s", 2088 llvm::toString(std::move(llvm_error)).c_str()); 2089 return false; 2090 } 2091 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2092 return true; 2093 } 2094 }; 2095 2096 class CommandObjectCommandContainer : public CommandObjectMultiword { 2097 public: 2098 CommandObjectCommandContainer(CommandInterpreter &interpreter) 2099 : CommandObjectMultiword( 2100 interpreter, "command container", 2101 "Commands for adding container commands to lldb. " 2102 "Container commands are containers for other commands. You can " 2103 "add nested container commands by specifying a command path, " 2104 "but you can't add commands into the built-in command hierarchy.", 2105 "command container <subcommand> [<subcommand-options>]") { 2106 LoadSubCommand("add", CommandObjectSP(new CommandObjectCommandsContainerAdd( 2107 interpreter))); 2108 LoadSubCommand( 2109 "delete", 2110 CommandObjectSP(new CommandObjectCommandsContainerDelete(interpreter))); 2111 } 2112 2113 ~CommandObjectCommandContainer() override = default; 2114 }; 2115 2116 #pragma mark CommandObjectMultiwordCommands 2117 2118 // CommandObjectMultiwordCommands 2119 2120 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands( 2121 CommandInterpreter &interpreter) 2122 : CommandObjectMultiword(interpreter, "command", 2123 "Commands for managing custom LLDB commands.", 2124 "command <subcommand> [<subcommand-options>]") { 2125 LoadSubCommand("source", 2126 CommandObjectSP(new CommandObjectCommandsSource(interpreter))); 2127 LoadSubCommand("alias", 2128 CommandObjectSP(new CommandObjectCommandsAlias(interpreter))); 2129 LoadSubCommand("unalias", CommandObjectSP( 2130 new CommandObjectCommandsUnalias(interpreter))); 2131 LoadSubCommand("delete", 2132 CommandObjectSP(new CommandObjectCommandsDelete(interpreter))); 2133 LoadSubCommand("container", CommandObjectSP(new CommandObjectCommandContainer( 2134 interpreter))); 2135 LoadSubCommand( 2136 "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter))); 2137 LoadSubCommand( 2138 "script", 2139 CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter))); 2140 } 2141 2142 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default; 2143