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 const char *GetRepeatCommand(Args ¤t_command_args, 60 uint32_t index) override { 61 return ""; 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() {} 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() {} 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), m_fetched_help_long(false) { 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; 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() {} 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() {} 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 = true; 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 = false; 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 bool m_overwrite; 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 1503 StringList lines; 1504 lines.SplitIntoLines(data); 1505 if (lines.GetSize() > 0) { 1506 std::string funct_name_str; 1507 if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) { 1508 if (funct_name_str.empty()) { 1509 error_sp->Printf("error: unable to obtain a function name, didn't " 1510 "add python command.\n"); 1511 error_sp->Flush(); 1512 } else { 1513 // everything should be fine now, let's add this alias 1514 1515 CommandObjectSP command_obj_sp(new CommandObjectPythonFunction( 1516 m_interpreter, m_cmd_name, funct_name_str, m_short_help, 1517 m_synchronicity)); 1518 if (!m_container) { 1519 Status error = m_interpreter.AddUserCommand( 1520 m_cmd_name, command_obj_sp, m_overwrite); 1521 if (error.Fail()) { 1522 error_sp->Printf("error: unable to add selected command: '%s'", 1523 error.AsCString()); 1524 error_sp->Flush(); 1525 } 1526 } else { 1527 llvm::Error llvm_error = m_container->LoadUserSubcommand( 1528 m_cmd_name, command_obj_sp, m_overwrite); 1529 if (llvm_error) { 1530 error_sp->Printf("error: unable to add selected command: '%s'", 1531 llvm::toString(std::move(llvm_error)).c_str()); 1532 error_sp->Flush(); 1533 } 1534 } 1535 } 1536 } else { 1537 error_sp->Printf( 1538 "error: unable to create function, didn't add python command\n"); 1539 error_sp->Flush(); 1540 } 1541 } else { 1542 error_sp->Printf("error: empty function, didn't add python command\n"); 1543 error_sp->Flush(); 1544 } 1545 } else { 1546 error_sp->Printf( 1547 "error: script interpreter missing, didn't add python command\n"); 1548 error_sp->Flush(); 1549 } 1550 1551 io_handler.SetIsDone(true); 1552 } 1553 1554 bool DoExecute(Args &command, CommandReturnObject &result) override { 1555 if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) { 1556 result.AppendError("only scripting language supported for scripted " 1557 "commands is currently Python"); 1558 return false; 1559 } 1560 1561 if (command.GetArgumentCount() == 0) { 1562 result.AppendError("'command script add' requires at least one argument"); 1563 return false; 1564 } 1565 // Store the options in case we get multi-line input 1566 m_overwrite = m_options.m_overwrite; 1567 Status path_error; 1568 m_container = GetCommandInterpreter().VerifyUserMultiwordCmdPath( 1569 command, true, path_error); 1570 1571 if (path_error.Fail()) { 1572 result.AppendErrorWithFormat("error in command path: %s", 1573 path_error.AsCString()); 1574 return false; 1575 } 1576 1577 if (!m_container) { 1578 // This is getting inserted into the root of the interpreter. 1579 m_cmd_name = std::string(command[0].ref()); 1580 } else { 1581 size_t num_args = command.GetArgumentCount(); 1582 m_cmd_name = std::string(command[num_args - 1].ref()); 1583 } 1584 1585 m_short_help.assign(m_options.m_short_help); 1586 m_synchronicity = m_options.m_synchronicity; 1587 1588 // Handle the case where we prompt for the script code first: 1589 if (m_options.m_class_name.empty() && m_options.m_funct_name.empty()) { 1590 m_interpreter.GetPythonCommandsFromIOHandler(" ", // Prompt 1591 *this); // IOHandlerDelegate 1592 return result.Succeeded(); 1593 } 1594 1595 CommandObjectSP new_cmd_sp; 1596 if (m_options.m_class_name.empty()) { 1597 new_cmd_sp.reset(new CommandObjectPythonFunction( 1598 m_interpreter, m_cmd_name, m_options.m_funct_name, 1599 m_options.m_short_help, m_synchronicity)); 1600 } else { 1601 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1602 if (!interpreter) { 1603 result.AppendError("cannot find ScriptInterpreter"); 1604 return false; 1605 } 1606 1607 auto cmd_obj_sp = interpreter->CreateScriptCommandObject( 1608 m_options.m_class_name.c_str()); 1609 if (!cmd_obj_sp) { 1610 result.AppendError("cannot create helper object"); 1611 return false; 1612 } 1613 1614 new_cmd_sp.reset(new CommandObjectScriptingObject( 1615 m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity)); 1616 } 1617 1618 // Assume we're going to succeed... 1619 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1620 if (!m_container) { 1621 Status add_error = 1622 m_interpreter.AddUserCommand(m_cmd_name, new_cmd_sp, m_overwrite); 1623 if (add_error.Fail()) 1624 result.AppendErrorWithFormat("cannot add command: %s", 1625 add_error.AsCString()); 1626 } else { 1627 llvm::Error llvm_error = 1628 m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite); 1629 if (llvm_error) 1630 result.AppendErrorWithFormat("cannot add command: %s", 1631 llvm::toString(std::move(llvm_error)).c_str()); 1632 } 1633 return result.Succeeded(); 1634 } 1635 1636 CommandOptions m_options; 1637 std::string m_cmd_name; 1638 CommandObjectMultiword *m_container = nullptr; 1639 std::string m_short_help; 1640 bool m_overwrite; 1641 ScriptedCommandSynchronicity m_synchronicity; 1642 }; 1643 1644 // CommandObjectCommandsScriptList 1645 1646 class CommandObjectCommandsScriptList : public CommandObjectParsed { 1647 public: 1648 CommandObjectCommandsScriptList(CommandInterpreter &interpreter) 1649 : CommandObjectParsed(interpreter, "command script list", 1650 "List defined top-level scripted commands.", 1651 nullptr) {} 1652 1653 ~CommandObjectCommandsScriptList() override = default; 1654 1655 bool DoExecute(Args &command, CommandReturnObject &result) override { 1656 if (command.GetArgumentCount() != 0) { 1657 result.AppendError("'command script list' doesn't take any arguments"); 1658 return false; 1659 } 1660 1661 m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef); 1662 1663 result.SetStatus(eReturnStatusSuccessFinishResult); 1664 1665 return true; 1666 } 1667 }; 1668 1669 // CommandObjectCommandsScriptClear 1670 1671 class CommandObjectCommandsScriptClear : public CommandObjectParsed { 1672 public: 1673 CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) 1674 : CommandObjectParsed(interpreter, "command script clear", 1675 "Delete all scripted commands.", nullptr) {} 1676 1677 ~CommandObjectCommandsScriptClear() override = default; 1678 1679 protected: 1680 bool DoExecute(Args &command, CommandReturnObject &result) override { 1681 if (command.GetArgumentCount() != 0) { 1682 result.AppendError("'command script clear' doesn't take any arguments"); 1683 return false; 1684 } 1685 1686 m_interpreter.RemoveAllUser(); 1687 1688 result.SetStatus(eReturnStatusSuccessFinishResult); 1689 1690 return true; 1691 } 1692 }; 1693 1694 // CommandObjectCommandsScriptDelete 1695 1696 class CommandObjectCommandsScriptDelete : public CommandObjectParsed { 1697 public: 1698 CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) 1699 : CommandObjectParsed( 1700 interpreter, "command script delete", 1701 "Delete a scripted command by specifying the path to the command.", 1702 nullptr) { 1703 CommandArgumentEntry arg1; 1704 CommandArgumentData cmd_arg; 1705 1706 // This is a list of command names forming the path to the command 1707 // to be deleted. 1708 cmd_arg.arg_type = eArgTypeCommand; 1709 cmd_arg.arg_repetition = eArgRepeatPlus; 1710 1711 // There is only one variant this argument could be; put it into the 1712 // argument entry. 1713 arg1.push_back(cmd_arg); 1714 1715 // Push the data for the first argument into the m_arguments vector. 1716 m_arguments.push_back(arg1); 1717 } 1718 1719 ~CommandObjectCommandsScriptDelete() override = default; 1720 1721 void 1722 HandleArgumentCompletion(CompletionRequest &request, 1723 OptionElementVector &opt_element_vector) override { 1724 CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request, 1725 opt_element_vector); 1726 } 1727 1728 protected: 1729 bool DoExecute(Args &command, CommandReturnObject &result) override { 1730 1731 llvm::StringRef root_cmd = command[0].ref(); 1732 size_t num_args = command.GetArgumentCount(); 1733 1734 if (root_cmd.empty()) { 1735 result.AppendErrorWithFormat("empty root command name"); 1736 return false; 1737 } 1738 if (!m_interpreter.HasUserCommands() && 1739 !m_interpreter.HasUserMultiwordCommands()) { 1740 result.AppendErrorWithFormat("can only delete user defined commands, " 1741 "but no user defined commands found"); 1742 return false; 1743 } 1744 1745 CommandObjectSP cmd_sp = m_interpreter.GetCommandSPExact(root_cmd); 1746 if (!cmd_sp) { 1747 result.AppendErrorWithFormat("command '%s' not found.", 1748 command[0].c_str()); 1749 return false; 1750 } 1751 if (!cmd_sp->IsUserCommand()) { 1752 result.AppendErrorWithFormat("command '%s' is not a user command.", 1753 command[0].c_str()); 1754 return false; 1755 } 1756 if (cmd_sp->GetAsMultiwordCommand() && num_args == 1) { 1757 result.AppendErrorWithFormat("command '%s' is a multi-word command.\n " 1758 "Delete with \"command container delete\"", 1759 command[0].c_str()); 1760 return false; 1761 } 1762 1763 if (command.GetArgumentCount() == 1) { 1764 m_interpreter.RemoveUser(root_cmd); 1765 result.SetStatus(eReturnStatusSuccessFinishResult); 1766 return true; 1767 } 1768 // We're deleting a command from a multiword command. Verify the command 1769 // path: 1770 Status error; 1771 CommandObjectMultiword *container = 1772 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 1773 error); 1774 if (error.Fail()) { 1775 result.AppendErrorWithFormat("could not resolve command path: %s", 1776 error.AsCString()); 1777 return false; 1778 } 1779 if (!container) { 1780 // This means that command only had a leaf command, so the container is 1781 // the root. That should have been handled above. 1782 result.AppendErrorWithFormat("could not find a container for '%s'", 1783 command[0].c_str()); 1784 return false; 1785 } 1786 const char *leaf_cmd = command[num_args - 1].c_str(); 1787 llvm::Error llvm_error = container->RemoveUserSubcommand(leaf_cmd, 1788 /* multiword not okay */ false); 1789 if (llvm_error) { 1790 result.AppendErrorWithFormat("could not delete command '%s': %s", 1791 leaf_cmd, 1792 llvm::toString(std::move(llvm_error)).c_str()); 1793 return false; 1794 } 1795 1796 Stream &out_stream = result.GetOutputStream(); 1797 1798 out_stream << "Deleted command:"; 1799 for (size_t idx = 0; idx < num_args; idx++) { 1800 out_stream << ' '; 1801 out_stream << command[idx].c_str(); 1802 } 1803 out_stream << '\n'; 1804 result.SetStatus(eReturnStatusSuccessFinishResult); 1805 return true; 1806 } 1807 }; 1808 1809 #pragma mark CommandObjectMultiwordCommandsScript 1810 1811 // CommandObjectMultiwordCommandsScript 1812 1813 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword { 1814 public: 1815 CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter) 1816 : CommandObjectMultiword( 1817 interpreter, "command script", 1818 "Commands for managing custom " 1819 "commands implemented by " 1820 "interpreter scripts.", 1821 "command script <subcommand> [<subcommand-options>]") { 1822 LoadSubCommand("add", CommandObjectSP( 1823 new CommandObjectCommandsScriptAdd(interpreter))); 1824 LoadSubCommand( 1825 "delete", 1826 CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter))); 1827 LoadSubCommand( 1828 "clear", 1829 CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter))); 1830 LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList( 1831 interpreter))); 1832 LoadSubCommand( 1833 "import", 1834 CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter))); 1835 } 1836 1837 ~CommandObjectMultiwordCommandsScript() override = default; 1838 }; 1839 1840 #pragma mark CommandObjectCommandContainer 1841 #define LLDB_OPTIONS_container_add 1842 #include "CommandOptions.inc" 1843 1844 class CommandObjectCommandsContainerAdd : public CommandObjectParsed { 1845 public: 1846 CommandObjectCommandsContainerAdd(CommandInterpreter &interpreter) 1847 : CommandObjectParsed( 1848 interpreter, "command container add", 1849 "Add a container command to lldb. Adding to built-" 1850 "in container commands is not allowed.", 1851 "command container add [[path1]...] container-name") { 1852 CommandArgumentEntry arg1; 1853 CommandArgumentData cmd_arg; 1854 1855 // This is one or more command names, which form the path to the command 1856 // you want to add. 1857 cmd_arg.arg_type = eArgTypeCommand; 1858 cmd_arg.arg_repetition = eArgRepeatPlus; 1859 1860 // There is only one variant this argument could be; put it into the 1861 // argument entry. 1862 arg1.push_back(cmd_arg); 1863 1864 // Push the data for the first argument into the m_arguments vector. 1865 m_arguments.push_back(arg1); 1866 } 1867 1868 ~CommandObjectCommandsContainerAdd() override = default; 1869 1870 Options *GetOptions() override { return &m_options; } 1871 1872 void 1873 HandleArgumentCompletion(CompletionRequest &request, 1874 OptionElementVector &opt_element_vector) override { 1875 CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request, 1876 opt_element_vector); 1877 } 1878 1879 protected: 1880 class CommandOptions : public Options { 1881 public: 1882 CommandOptions() {} 1883 1884 ~CommandOptions() override = default; 1885 1886 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1887 ExecutionContext *execution_context) override { 1888 Status error; 1889 const int short_option = m_getopt_table[option_idx].val; 1890 1891 switch (short_option) { 1892 case 'h': 1893 if (!option_arg.empty()) 1894 m_short_help = std::string(option_arg); 1895 break; 1896 case 'o': 1897 m_overwrite = true; 1898 break; 1899 case 'H': 1900 if (!option_arg.empty()) 1901 m_long_help = std::string(option_arg); 1902 break; 1903 default: 1904 llvm_unreachable("Unimplemented option"); 1905 } 1906 1907 return error; 1908 } 1909 1910 void OptionParsingStarting(ExecutionContext *execution_context) override { 1911 m_short_help.clear(); 1912 m_long_help.clear(); 1913 m_overwrite = false; 1914 } 1915 1916 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1917 return llvm::makeArrayRef(g_container_add_options); 1918 } 1919 1920 // Instance variables to hold the values for command options. 1921 1922 std::string m_short_help; 1923 std::string m_long_help; 1924 bool m_overwrite = false; 1925 }; 1926 bool DoExecute(Args &command, CommandReturnObject &result) override { 1927 size_t num_args = command.GetArgumentCount(); 1928 1929 if (num_args == 0) { 1930 result.AppendError("no command was specified"); 1931 return false; 1932 } 1933 1934 if (num_args == 1) { 1935 // We're adding this as a root command, so use the interpreter. 1936 const char *cmd_name = command.GetArgumentAtIndex(0); 1937 auto cmd_sp = CommandObjectSP(new CommandObjectMultiword( 1938 GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(), 1939 m_options.m_long_help.c_str())); 1940 cmd_sp->GetAsMultiwordCommand()->SetRemovable(true); 1941 Status add_error = GetCommandInterpreter().AddUserCommand( 1942 cmd_name, cmd_sp, m_options.m_overwrite); 1943 if (add_error.Fail()) { 1944 result.AppendErrorWithFormat("error adding command: %s", 1945 add_error.AsCString()); 1946 return false; 1947 } 1948 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1949 return true; 1950 } 1951 1952 // We're adding this to a subcommand, first find the subcommand: 1953 Status path_error; 1954 CommandObjectMultiword *add_to_me = 1955 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 1956 path_error); 1957 1958 if (!add_to_me) { 1959 result.AppendErrorWithFormat("error adding command: %s", 1960 path_error.AsCString()); 1961 return false; 1962 } 1963 1964 const char *cmd_name = command.GetArgumentAtIndex(num_args - 1); 1965 auto cmd_sp = CommandObjectSP(new CommandObjectMultiword( 1966 GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(), 1967 m_options.m_long_help.c_str())); 1968 llvm::Error llvm_error = 1969 add_to_me->LoadUserSubcommand(cmd_name, cmd_sp, m_options.m_overwrite); 1970 if (llvm_error) { 1971 result.AppendErrorWithFormat("error adding subcommand: %s", 1972 llvm::toString(std::move(llvm_error)).c_str()); 1973 return false; 1974 } 1975 1976 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1977 return true; 1978 } 1979 1980 private: 1981 CommandOptions m_options; 1982 }; 1983 1984 #define LLDB_OPTIONS_multiword_delete 1985 #include "CommandOptions.inc" 1986 class CommandObjectCommandsContainerDelete : public CommandObjectParsed { 1987 public: 1988 CommandObjectCommandsContainerDelete(CommandInterpreter &interpreter) 1989 : CommandObjectParsed( 1990 interpreter, "command container delete", 1991 "Delete a container command previously added to " 1992 "lldb.", 1993 "command container delete [[path1] ...] container-cmd") { 1994 CommandArgumentEntry arg1; 1995 CommandArgumentData cmd_arg; 1996 1997 // This is one or more command names, which form the path to the command 1998 // you want to add. 1999 cmd_arg.arg_type = eArgTypeCommand; 2000 cmd_arg.arg_repetition = eArgRepeatPlus; 2001 2002 // There is only one variant this argument could be; put it into the 2003 // argument entry. 2004 arg1.push_back(cmd_arg); 2005 2006 // Push the data for the first argument into the m_arguments vector. 2007 m_arguments.push_back(arg1); 2008 } 2009 2010 ~CommandObjectCommandsContainerDelete() override = default; 2011 2012 void 2013 HandleArgumentCompletion(CompletionRequest &request, 2014 OptionElementVector &opt_element_vector) override { 2015 CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request, 2016 opt_element_vector); 2017 } 2018 2019 protected: 2020 bool DoExecute(Args &command, CommandReturnObject &result) override { 2021 size_t num_args = command.GetArgumentCount(); 2022 2023 if (num_args == 0) { 2024 result.AppendError("No command was specified."); 2025 return false; 2026 } 2027 2028 if (num_args == 1) { 2029 // We're removing a root command, so we need to delete it from the 2030 // interpreter. 2031 const char *cmd_name = command.GetArgumentAtIndex(0); 2032 // Let's do a little more work here so we can do better error reporting. 2033 CommandInterpreter &interp = GetCommandInterpreter(); 2034 CommandObjectSP cmd_sp = interp.GetCommandSPExact(cmd_name); 2035 if (!cmd_sp) { 2036 result.AppendErrorWithFormat("container command %s doesn't exist.", 2037 cmd_name); 2038 return false; 2039 } 2040 if (!cmd_sp->IsUserCommand()) { 2041 result.AppendErrorWithFormat( 2042 "container command %s is not a user command", cmd_name); 2043 return false; 2044 } 2045 if (!cmd_sp->GetAsMultiwordCommand()) { 2046 result.AppendErrorWithFormat("command %s is not a container command", 2047 cmd_name); 2048 return false; 2049 } 2050 2051 bool did_remove = GetCommandInterpreter().RemoveUserMultiword(cmd_name); 2052 if (!did_remove) { 2053 result.AppendErrorWithFormat("error removing command %s.", cmd_name); 2054 return false; 2055 } 2056 2057 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2058 return true; 2059 } 2060 2061 // We're removing a subcommand, first find the subcommand's owner: 2062 Status path_error; 2063 CommandObjectMultiword *container = 2064 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 2065 path_error); 2066 2067 if (!container) { 2068 result.AppendErrorWithFormat("error removing container command: %s", 2069 path_error.AsCString()); 2070 return false; 2071 } 2072 const char *leaf = command.GetArgumentAtIndex(num_args - 1); 2073 llvm::Error llvm_error = 2074 container->RemoveUserSubcommand(leaf, /* multiword okay */ true); 2075 if (llvm_error) { 2076 result.AppendErrorWithFormat("error removing container command: %s", 2077 llvm::toString(std::move(llvm_error)).c_str()); 2078 return false; 2079 } 2080 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2081 return true; 2082 } 2083 }; 2084 2085 class CommandObjectCommandContainer : public CommandObjectMultiword { 2086 public: 2087 CommandObjectCommandContainer(CommandInterpreter &interpreter) 2088 : CommandObjectMultiword( 2089 interpreter, "command container", 2090 "Commands for adding container commands to lldb. " 2091 "Container commands are containers for other commands. You can" 2092 "add nested container commands by specifying a command path, but " 2093 "but you can't add commands into the built-in command hierarchy.", 2094 "command container <subcommand> [<subcommand-options>]") { 2095 LoadSubCommand("add", CommandObjectSP(new CommandObjectCommandsContainerAdd( 2096 interpreter))); 2097 LoadSubCommand( 2098 "delete", 2099 CommandObjectSP(new CommandObjectCommandsContainerDelete(interpreter))); 2100 } 2101 2102 ~CommandObjectCommandContainer() override = default; 2103 }; 2104 2105 #pragma mark CommandObjectMultiwordCommands 2106 2107 // CommandObjectMultiwordCommands 2108 2109 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands( 2110 CommandInterpreter &interpreter) 2111 : CommandObjectMultiword(interpreter, "command", 2112 "Commands for managing custom LLDB commands.", 2113 "command <subcommand> [<subcommand-options>]") { 2114 LoadSubCommand("source", 2115 CommandObjectSP(new CommandObjectCommandsSource(interpreter))); 2116 LoadSubCommand("alias", 2117 CommandObjectSP(new CommandObjectCommandsAlias(interpreter))); 2118 LoadSubCommand("unalias", CommandObjectSP( 2119 new CommandObjectCommandsUnalias(interpreter))); 2120 LoadSubCommand("delete", 2121 CommandObjectSP(new CommandObjectCommandsDelete(interpreter))); 2122 LoadSubCommand("container", CommandObjectSP(new CommandObjectCommandContainer( 2123 interpreter))); 2124 LoadSubCommand( 2125 "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter))); 2126 LoadSubCommand( 2127 "script", 2128 CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter))); 2129 } 2130 2131 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default; 2132