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/CommandOptionArgumentTable.h" 17 #include "lldb/Interpreter/CommandReturnObject.h" 18 #include "lldb/Interpreter/OptionArgParser.h" 19 #include "lldb/Interpreter/OptionValueBoolean.h" 20 #include "lldb/Interpreter/OptionValueString.h" 21 #include "lldb/Interpreter/OptionValueUInt64.h" 22 #include "lldb/Interpreter/Options.h" 23 #include "lldb/Interpreter/ScriptInterpreter.h" 24 #include "lldb/Utility/Args.h" 25 #include "lldb/Utility/StringList.h" 26 #include "llvm/ADT/StringRef.h" 27 #include <optional> 28 29 using namespace lldb; 30 using namespace lldb_private; 31 32 // CommandObjectCommandsSource 33 34 #define LLDB_OPTIONS_source 35 #include "CommandOptions.inc" 36 37 class CommandObjectCommandsSource : public CommandObjectParsed { 38 public: 39 CommandObjectCommandsSource(CommandInterpreter &interpreter) 40 : CommandObjectParsed( 41 interpreter, "command source", 42 "Read and execute LLDB commands from the file <filename>.", 43 nullptr) { 44 CommandArgumentEntry arg; 45 CommandArgumentData file_arg; 46 47 // Define the first (and only) variant of this arg. 48 file_arg.arg_type = eArgTypeFilename; 49 file_arg.arg_repetition = eArgRepeatPlain; 50 51 // There is only one variant this argument could be; put it into the 52 // argument entry. 53 arg.push_back(file_arg); 54 55 // Push the data for the first argument into the m_arguments vector. 56 m_arguments.push_back(arg); 57 } 58 59 ~CommandObjectCommandsSource() override = default; 60 61 std::optional<std::string> GetRepeatCommand(Args ¤t_command_args, 62 uint32_t index) override { 63 return std::string(""); 64 } 65 66 void 67 HandleArgumentCompletion(CompletionRequest &request, 68 OptionElementVector &opt_element_vector) override { 69 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 70 GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr); 71 } 72 73 Options *GetOptions() override { return &m_options; } 74 75 protected: 76 class CommandOptions : public Options { 77 public: 78 CommandOptions() 79 : m_stop_on_error(true), m_silent_run(false), m_stop_on_continue(true), 80 m_cmd_relative_to_command_file(false) {} 81 82 ~CommandOptions() override = default; 83 84 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 85 ExecutionContext *execution_context) override { 86 Status error; 87 const int short_option = m_getopt_table[option_idx].val; 88 89 switch (short_option) { 90 case 'e': 91 error = m_stop_on_error.SetValueFromString(option_arg); 92 break; 93 94 case 'c': 95 error = m_stop_on_continue.SetValueFromString(option_arg); 96 break; 97 98 case 'C': 99 m_cmd_relative_to_command_file = true; 100 break; 101 102 case 's': 103 error = m_silent_run.SetValueFromString(option_arg); 104 break; 105 106 default: 107 llvm_unreachable("Unimplemented option"); 108 } 109 110 return error; 111 } 112 113 void OptionParsingStarting(ExecutionContext *execution_context) override { 114 m_stop_on_error.Clear(); 115 m_silent_run.Clear(); 116 m_stop_on_continue.Clear(); 117 m_cmd_relative_to_command_file.Clear(); 118 } 119 120 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 121 return llvm::ArrayRef(g_source_options); 122 } 123 124 // Instance variables to hold the values for command options. 125 126 OptionValueBoolean m_stop_on_error; 127 OptionValueBoolean m_silent_run; 128 OptionValueBoolean m_stop_on_continue; 129 OptionValueBoolean m_cmd_relative_to_command_file; 130 }; 131 132 void DoExecute(Args &command, CommandReturnObject &result) override { 133 if (command.GetArgumentCount() != 1) { 134 result.AppendErrorWithFormat( 135 "'%s' takes exactly one executable filename argument.\n", 136 GetCommandName().str().c_str()); 137 return; 138 } 139 140 FileSpec source_dir = {}; 141 if (m_options.m_cmd_relative_to_command_file) { 142 source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir(); 143 if (!source_dir) { 144 result.AppendError("command source -C can only be specified " 145 "from a command file"); 146 result.SetStatus(eReturnStatusFailed); 147 return; 148 } 149 } 150 151 FileSpec cmd_file(command[0].ref()); 152 if (source_dir) { 153 // Prepend the source_dir to the cmd_file path: 154 if (!cmd_file.IsRelative()) { 155 result.AppendError("command source -C can only be used " 156 "with a relative path."); 157 result.SetStatus(eReturnStatusFailed); 158 return; 159 } 160 cmd_file.MakeAbsolute(source_dir); 161 } 162 163 FileSystem::Instance().Resolve(cmd_file); 164 165 CommandInterpreterRunOptions options; 166 // If any options were set, then use them 167 if (m_options.m_stop_on_error.OptionWasSet() || 168 m_options.m_silent_run.OptionWasSet() || 169 m_options.m_stop_on_continue.OptionWasSet()) { 170 if (m_options.m_stop_on_continue.OptionWasSet()) 171 options.SetStopOnContinue( 172 m_options.m_stop_on_continue.GetCurrentValue()); 173 174 if (m_options.m_stop_on_error.OptionWasSet()) 175 options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue()); 176 177 // Individual silent setting is override for global command echo settings. 178 if (m_options.m_silent_run.GetCurrentValue()) { 179 options.SetSilent(true); 180 } else { 181 options.SetPrintResults(true); 182 options.SetPrintErrors(true); 183 options.SetEchoCommands(m_interpreter.GetEchoCommands()); 184 options.SetEchoCommentCommands(m_interpreter.GetEchoCommentCommands()); 185 } 186 } 187 188 m_interpreter.HandleCommandsFromFile(cmd_file, options, result); 189 } 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, exe_ctx, 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::ArrayRef(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 void 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; 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; 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; 409 } 410 411 // Get the alias command. 412 413 auto alias_command = args[0].ref(); 414 if (alias_command.starts_with("-")) { 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; 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; 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; 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; 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 } else if (!cmd_obj->WantsRawCommandString()) { 465 // Note that args was initialized with the original command, and has not 466 // been updated to this point. Therefore can we pass it to the version of 467 // Execute that does not need/expect raw input in the alias. 468 HandleAliasingNormalCommand(args, result); 469 } else { 470 HandleAliasingRawCommand(alias_command, raw_command_string, *cmd_obj, 471 result); 472 } 473 } 474 475 bool HandleAliasingRawCommand(llvm::StringRef alias_command, 476 llvm::StringRef raw_command_string, 477 CommandObject &cmd_obj, 478 CommandReturnObject &result) { 479 // Verify & handle any options/arguments passed to the alias command 480 481 OptionArgVectorSP option_arg_vector_sp = 482 OptionArgVectorSP(new OptionArgVector); 483 484 const bool include_aliases = true; 485 // Look up the command using command's name first. This is to resolve 486 // aliases when you are making nested aliases. But if you don't find 487 // it that way, then it wasn't an alias and we can just use the object 488 // we were passed in. 489 CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact( 490 cmd_obj.GetCommandName(), include_aliases); 491 if (!cmd_obj_sp) 492 cmd_obj_sp = cmd_obj.shared_from_this(); 493 494 if (m_interpreter.AliasExists(alias_command) || 495 m_interpreter.UserCommandExists(alias_command)) { 496 result.AppendWarningWithFormat( 497 "Overwriting existing definition for '%s'.\n", 498 alias_command.str().c_str()); 499 } 500 if (CommandAlias *alias = m_interpreter.AddAlias( 501 alias_command, cmd_obj_sp, raw_command_string)) { 502 if (m_command_options.m_help.OptionWasSet()) 503 alias->SetHelp(m_command_options.m_help.GetCurrentValue()); 504 if (m_command_options.m_long_help.OptionWasSet()) 505 alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue()); 506 result.SetStatus(eReturnStatusSuccessFinishNoResult); 507 } else { 508 result.AppendError("Unable to create requested alias.\n"); 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 void 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; 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; 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; 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; 695 } 696 697 result.SetStatus(eReturnStatusSuccessFinishNoResult); 698 } 699 }; 700 701 #pragma mark CommandObjectCommandsDelete 702 // CommandObjectCommandsDelete 703 704 class CommandObjectCommandsDelete : public CommandObjectParsed { 705 public: 706 CommandObjectCommandsDelete(CommandInterpreter &interpreter) 707 : CommandObjectParsed( 708 interpreter, "command delete", 709 "Delete one or more custom commands defined by 'command regex'.", 710 nullptr) { 711 CommandArgumentEntry arg; 712 CommandArgumentData alias_arg; 713 714 // Define the first (and only) variant of this arg. 715 alias_arg.arg_type = eArgTypeCommandName; 716 alias_arg.arg_repetition = eArgRepeatPlain; 717 718 // There is only one variant this argument could be; put it into the 719 // argument entry. 720 arg.push_back(alias_arg); 721 722 // Push the data for the first argument into the m_arguments vector. 723 m_arguments.push_back(arg); 724 } 725 726 ~CommandObjectCommandsDelete() override = default; 727 728 void 729 HandleArgumentCompletion(CompletionRequest &request, 730 OptionElementVector &opt_element_vector) override { 731 if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0) 732 return; 733 734 for (const auto &ent : m_interpreter.GetCommands()) { 735 if (ent.second->IsRemovable()) 736 request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp()); 737 } 738 } 739 740 protected: 741 void DoExecute(Args &args, CommandReturnObject &result) override { 742 CommandObject::CommandMap::iterator pos; 743 744 if (args.empty()) { 745 result.AppendErrorWithFormat("must call '%s' with one or more valid user " 746 "defined regular expression command names", 747 GetCommandName().str().c_str()); 748 return; 749 } 750 751 auto command_name = args[0].ref(); 752 if (!m_interpreter.CommandExists(command_name)) { 753 StreamString error_msg_stream; 754 const bool generate_upropos = true; 755 const bool generate_type_lookup = false; 756 CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage( 757 &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(), 758 generate_upropos, generate_type_lookup); 759 result.AppendError(error_msg_stream.GetString()); 760 return; 761 } 762 763 if (!m_interpreter.RemoveCommand(command_name)) { 764 result.AppendErrorWithFormat( 765 "'%s' is a permanent debugger command and cannot be removed.\n", 766 args[0].c_str()); 767 return; 768 } 769 770 result.SetStatus(eReturnStatusSuccessFinishNoResult); 771 } 772 }; 773 774 // CommandObjectCommandsAddRegex 775 776 #define LLDB_OPTIONS_regex 777 #include "CommandOptions.inc" 778 779 #pragma mark CommandObjectCommandsAddRegex 780 781 class CommandObjectCommandsAddRegex : public CommandObjectParsed, 782 public IOHandlerDelegateMultiline { 783 public: 784 CommandObjectCommandsAddRegex(CommandInterpreter &interpreter) 785 : CommandObjectParsed( 786 interpreter, "command regex", 787 "Define a custom command in terms of " 788 "existing commands by matching " 789 "regular expressions.", 790 "command regex <cmd-name> [s/<regex>/<subst>/ ...]"), 791 IOHandlerDelegateMultiline("", 792 IOHandlerDelegate::Completion::LLDBCommand) { 793 SetHelpLong( 794 R"( 795 )" 796 "This command allows the user to create powerful regular expression commands \ 797 with substitutions. The regular expressions and substitutions are specified \ 798 using the regular expression substitution format of:" 799 R"( 800 801 s/<regex>/<subst>/ 802 803 )" 804 "<regex> is a regular expression that can use parenthesis to capture regular \ 805 expression input and substitute the captured matches in the output using %1 \ 806 for the first match, %2 for the second, and so on." 807 R"( 808 809 )" 810 "The regular expressions can all be specified on the command line if more than \ 811 one argument is provided. If just the command name is provided on the command \ 812 line, then the regular expressions and substitutions can be entered on separate \ 813 lines, followed by an empty line to terminate the command definition." 814 R"( 815 816 EXAMPLES 817 818 )" 819 "The following example will define a regular expression command named 'f' that \ 820 will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \ 821 a number follows 'f':" 822 R"( 823 824 (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')"); 825 CommandArgumentData thread_arg{eArgTypeSEDStylePair, eArgRepeatOptional}; 826 m_arguments.push_back({thread_arg}); 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 void 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; 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(), 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)); 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 914 Status AppendRegexSubstitution(const llvm::StringRef ®ex_sed, 915 bool check_only) { 916 Status error; 917 918 if (!m_regex_cmd_up) { 919 error.SetErrorStringWithFormat( 920 "invalid regular expression command object for: '%.*s'", 921 (int)regex_sed.size(), regex_sed.data()); 922 return error; 923 } 924 925 size_t regex_sed_size = regex_sed.size(); 926 927 if (regex_sed_size <= 1) { 928 error.SetErrorStringWithFormat( 929 "regular expression substitution string is too short: '%.*s'", 930 (int)regex_sed.size(), regex_sed.data()); 931 return error; 932 } 933 934 if (regex_sed[0] != 's') { 935 error.SetErrorStringWithFormat("regular expression substitution string " 936 "doesn't start with 's': '%.*s'", 937 (int)regex_sed.size(), regex_sed.data()); 938 return error; 939 } 940 const size_t first_separator_char_pos = 1; 941 // use the char that follows 's' as the regex separator character so we can 942 // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|" 943 const char separator_char = regex_sed[first_separator_char_pos]; 944 const size_t second_separator_char_pos = 945 regex_sed.find(separator_char, first_separator_char_pos + 1); 946 947 if (second_separator_char_pos == std::string::npos) { 948 error.SetErrorStringWithFormat( 949 "missing second '%c' separator char after '%.*s' in '%.*s'", 950 separator_char, 951 (int)(regex_sed.size() - first_separator_char_pos - 1), 952 regex_sed.data() + (first_separator_char_pos + 1), 953 (int)regex_sed.size(), regex_sed.data()); 954 return error; 955 } 956 957 const size_t third_separator_char_pos = 958 regex_sed.find(separator_char, second_separator_char_pos + 1); 959 960 if (third_separator_char_pos == std::string::npos) { 961 error.SetErrorStringWithFormat( 962 "missing third '%c' separator char after '%.*s' in '%.*s'", 963 separator_char, 964 (int)(regex_sed.size() - second_separator_char_pos - 1), 965 regex_sed.data() + (second_separator_char_pos + 1), 966 (int)regex_sed.size(), regex_sed.data()); 967 return error; 968 } 969 970 if (third_separator_char_pos != regex_sed_size - 1) { 971 // Make sure that everything that follows the last regex separator char 972 if (regex_sed.find_first_not_of("\t\n\v\f\r ", 973 third_separator_char_pos + 1) != 974 std::string::npos) { 975 error.SetErrorStringWithFormat( 976 "extra data found after the '%.*s' regular expression substitution " 977 "string: '%.*s'", 978 (int)third_separator_char_pos + 1, regex_sed.data(), 979 (int)(regex_sed.size() - third_separator_char_pos - 1), 980 regex_sed.data() + (third_separator_char_pos + 1)); 981 return error; 982 } 983 } else if (first_separator_char_pos + 1 == second_separator_char_pos) { 984 error.SetErrorStringWithFormat( 985 "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 986 separator_char, separator_char, separator_char, (int)regex_sed.size(), 987 regex_sed.data()); 988 return error; 989 } else if (second_separator_char_pos + 1 == third_separator_char_pos) { 990 error.SetErrorStringWithFormat( 991 "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 992 separator_char, separator_char, separator_char, (int)regex_sed.size(), 993 regex_sed.data()); 994 return error; 995 } 996 997 if (!check_only) { 998 std::string regex(std::string(regex_sed.substr( 999 first_separator_char_pos + 1, 1000 second_separator_char_pos - first_separator_char_pos - 1))); 1001 std::string subst(std::string(regex_sed.substr( 1002 second_separator_char_pos + 1, 1003 third_separator_char_pos - second_separator_char_pos - 1))); 1004 m_regex_cmd_up->AddRegexCommand(regex, subst); 1005 } 1006 return error; 1007 } 1008 1009 void AddRegexCommandToInterpreter() { 1010 if (m_regex_cmd_up) { 1011 if (m_regex_cmd_up->HasRegexEntries()) { 1012 CommandObjectSP cmd_sp(m_regex_cmd_up.release()); 1013 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 1014 } 1015 } 1016 } 1017 1018 private: 1019 std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up; 1020 1021 class CommandOptions : public Options { 1022 public: 1023 CommandOptions() = default; 1024 1025 ~CommandOptions() override = default; 1026 1027 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1028 ExecutionContext *execution_context) override { 1029 Status error; 1030 const int short_option = m_getopt_table[option_idx].val; 1031 1032 switch (short_option) { 1033 case 'h': 1034 m_help.assign(std::string(option_arg)); 1035 break; 1036 case 's': 1037 m_syntax.assign(std::string(option_arg)); 1038 break; 1039 default: 1040 llvm_unreachable("Unimplemented option"); 1041 } 1042 1043 return error; 1044 } 1045 1046 void OptionParsingStarting(ExecutionContext *execution_context) override { 1047 m_help.clear(); 1048 m_syntax.clear(); 1049 } 1050 1051 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1052 return llvm::ArrayRef(g_regex_options); 1053 } 1054 1055 llvm::StringRef GetHelp() { return m_help; } 1056 1057 llvm::StringRef GetSyntax() { return m_syntax; } 1058 1059 protected: 1060 // Instance variables to hold the values for command options. 1061 1062 std::string m_help; 1063 std::string m_syntax; 1064 }; 1065 1066 Options *GetOptions() override { return &m_options; } 1067 1068 CommandOptions m_options; 1069 }; 1070 1071 class CommandObjectPythonFunction : public CommandObjectRaw { 1072 public: 1073 CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name, 1074 std::string funct, std::string help, 1075 ScriptedCommandSynchronicity synch, 1076 CompletionType completion_type) 1077 : CommandObjectRaw(interpreter, name), m_function_name(funct), 1078 m_synchro(synch), m_completion_type(completion_type) { 1079 if (!help.empty()) 1080 SetHelp(help); 1081 else { 1082 StreamString stream; 1083 stream.Printf("For more information run 'help %s'", name.c_str()); 1084 SetHelp(stream.GetString()); 1085 } 1086 } 1087 1088 ~CommandObjectPythonFunction() override = default; 1089 1090 bool IsRemovable() const override { return true; } 1091 1092 const std::string &GetFunctionName() { return m_function_name; } 1093 1094 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1095 1096 llvm::StringRef GetHelpLong() override { 1097 if (m_fetched_help_long) 1098 return CommandObjectRaw::GetHelpLong(); 1099 1100 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1101 if (!scripter) 1102 return CommandObjectRaw::GetHelpLong(); 1103 1104 std::string docstring; 1105 m_fetched_help_long = 1106 scripter->GetDocumentationForItem(m_function_name.c_str(), docstring); 1107 if (!docstring.empty()) 1108 SetHelpLong(docstring); 1109 return CommandObjectRaw::GetHelpLong(); 1110 } 1111 1112 void 1113 HandleArgumentCompletion(CompletionRequest &request, 1114 OptionElementVector &opt_element_vector) override { 1115 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 1116 GetCommandInterpreter(), m_completion_type, request, nullptr); 1117 } 1118 1119 bool WantsCompletion() override { return true; } 1120 1121 protected: 1122 void DoExecute(llvm::StringRef raw_command_line, 1123 CommandReturnObject &result) override { 1124 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1125 1126 Status error; 1127 1128 result.SetStatus(eReturnStatusInvalid); 1129 1130 if (!scripter || !scripter->RunScriptBasedCommand( 1131 m_function_name.c_str(), raw_command_line, m_synchro, 1132 result, error, m_exe_ctx)) { 1133 result.AppendError(error.AsCString()); 1134 } else { 1135 // Don't change the status if the command already set it... 1136 if (result.GetStatus() == eReturnStatusInvalid) { 1137 if (result.GetOutputData().empty()) 1138 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1139 else 1140 result.SetStatus(eReturnStatusSuccessFinishResult); 1141 } 1142 } 1143 } 1144 1145 private: 1146 std::string m_function_name; 1147 ScriptedCommandSynchronicity m_synchro; 1148 bool m_fetched_help_long = false; 1149 CompletionType m_completion_type = eNoCompletion; 1150 }; 1151 1152 class CommandObjectScriptingObject : public CommandObjectRaw { 1153 public: 1154 CommandObjectScriptingObject(CommandInterpreter &interpreter, 1155 std::string name, 1156 StructuredData::GenericSP cmd_obj_sp, 1157 ScriptedCommandSynchronicity synch, 1158 CompletionType completion_type) 1159 : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp), 1160 m_synchro(synch), m_fetched_help_short(false), 1161 m_fetched_help_long(false), m_completion_type(completion_type) { 1162 StreamString stream; 1163 stream.Printf("For more information run 'help %s'", name.c_str()); 1164 SetHelp(stream.GetString()); 1165 if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter()) 1166 GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); 1167 } 1168 1169 ~CommandObjectScriptingObject() override = default; 1170 1171 void 1172 HandleArgumentCompletion(CompletionRequest &request, 1173 OptionElementVector &opt_element_vector) override { 1174 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 1175 GetCommandInterpreter(), m_completion_type, request, nullptr); 1176 } 1177 1178 bool WantsCompletion() override { return true; } 1179 1180 bool IsRemovable() const override { return true; } 1181 1182 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1183 1184 llvm::StringRef GetHelp() override { 1185 if (m_fetched_help_short) 1186 return CommandObjectRaw::GetHelp(); 1187 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1188 if (!scripter) 1189 return CommandObjectRaw::GetHelp(); 1190 std::string docstring; 1191 m_fetched_help_short = 1192 scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring); 1193 if (!docstring.empty()) 1194 SetHelp(docstring); 1195 1196 return CommandObjectRaw::GetHelp(); 1197 } 1198 1199 llvm::StringRef GetHelpLong() override { 1200 if (m_fetched_help_long) 1201 return CommandObjectRaw::GetHelpLong(); 1202 1203 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1204 if (!scripter) 1205 return CommandObjectRaw::GetHelpLong(); 1206 1207 std::string docstring; 1208 m_fetched_help_long = 1209 scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring); 1210 if (!docstring.empty()) 1211 SetHelpLong(docstring); 1212 return CommandObjectRaw::GetHelpLong(); 1213 } 1214 1215 protected: 1216 void DoExecute(llvm::StringRef raw_command_line, 1217 CommandReturnObject &result) override { 1218 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1219 1220 Status error; 1221 1222 result.SetStatus(eReturnStatusInvalid); 1223 1224 if (!scripter || 1225 !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line, 1226 m_synchro, result, error, m_exe_ctx)) { 1227 result.AppendError(error.AsCString()); 1228 } else { 1229 // Don't change the status if the command already set it... 1230 if (result.GetStatus() == eReturnStatusInvalid) { 1231 if (result.GetOutputData().empty()) 1232 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1233 else 1234 result.SetStatus(eReturnStatusSuccessFinishResult); 1235 } 1236 } 1237 } 1238 1239 private: 1240 StructuredData::GenericSP m_cmd_obj_sp; 1241 ScriptedCommandSynchronicity m_synchro; 1242 bool m_fetched_help_short : 1; 1243 bool m_fetched_help_long : 1; 1244 CompletionType m_completion_type = eNoCompletion; 1245 }; 1246 1247 // CommandObjectCommandsScriptImport 1248 #define LLDB_OPTIONS_script_import 1249 #include "CommandOptions.inc" 1250 1251 class CommandObjectCommandsScriptImport : public CommandObjectParsed { 1252 public: 1253 CommandObjectCommandsScriptImport(CommandInterpreter &interpreter) 1254 : CommandObjectParsed(interpreter, "command script import", 1255 "Import a scripting module in LLDB.", nullptr) { 1256 CommandArgumentEntry arg1; 1257 CommandArgumentData cmd_arg; 1258 1259 // Define the first (and only) variant of this arg. 1260 cmd_arg.arg_type = eArgTypeFilename; 1261 cmd_arg.arg_repetition = eArgRepeatPlus; 1262 1263 // There is only one variant this argument could be; put it into the 1264 // argument entry. 1265 arg1.push_back(cmd_arg); 1266 1267 // Push the data for the first argument into the m_arguments vector. 1268 m_arguments.push_back(arg1); 1269 } 1270 1271 ~CommandObjectCommandsScriptImport() override = default; 1272 1273 void 1274 HandleArgumentCompletion(CompletionRequest &request, 1275 OptionElementVector &opt_element_vector) override { 1276 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 1277 GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr); 1278 } 1279 1280 Options *GetOptions() override { return &m_options; } 1281 1282 protected: 1283 class CommandOptions : public Options { 1284 public: 1285 CommandOptions() = default; 1286 1287 ~CommandOptions() override = default; 1288 1289 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1290 ExecutionContext *execution_context) override { 1291 Status error; 1292 const int short_option = m_getopt_table[option_idx].val; 1293 1294 switch (short_option) { 1295 case 'r': 1296 // NO-OP 1297 break; 1298 case 'c': 1299 relative_to_command_file = true; 1300 break; 1301 case 's': 1302 silent = true; 1303 break; 1304 default: 1305 llvm_unreachable("Unimplemented option"); 1306 } 1307 1308 return error; 1309 } 1310 1311 void OptionParsingStarting(ExecutionContext *execution_context) override { 1312 relative_to_command_file = false; 1313 } 1314 1315 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1316 return llvm::ArrayRef(g_script_import_options); 1317 } 1318 bool relative_to_command_file = false; 1319 bool silent = false; 1320 }; 1321 1322 void DoExecute(Args &command, CommandReturnObject &result) override { 1323 if (command.empty()) { 1324 result.AppendError("command script import needs one or more arguments"); 1325 return; 1326 } 1327 1328 FileSpec source_dir = {}; 1329 if (m_options.relative_to_command_file) { 1330 source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir(); 1331 if (!source_dir) { 1332 result.AppendError("command script import -c can only be specified " 1333 "from a command file"); 1334 return; 1335 } 1336 } 1337 1338 for (auto &entry : command.entries()) { 1339 Status error; 1340 1341 LoadScriptOptions options; 1342 options.SetInitSession(true); 1343 options.SetSilent(m_options.silent); 1344 1345 // FIXME: this is necessary because CommandObject::CheckRequirements() 1346 // assumes that commands won't ever be recursively invoked, but it's 1347 // actually possible to craft a Python script that does other "command 1348 // script imports" in __lldb_init_module the real fix is to have 1349 // recursive commands possible with a CommandInvocation object separate 1350 // from the CommandObject itself, so that recursive command invocations 1351 // won't stomp on each other (wrt to execution contents, options, and 1352 // more) 1353 m_exe_ctx.Clear(); 1354 if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule( 1355 entry.c_str(), options, error, /*module_sp=*/nullptr, 1356 source_dir)) { 1357 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1358 } else { 1359 result.AppendErrorWithFormat("module importing failed: %s", 1360 error.AsCString()); 1361 } 1362 } 1363 } 1364 1365 CommandOptions m_options; 1366 }; 1367 1368 #define LLDB_OPTIONS_script_add 1369 #include "CommandOptions.inc" 1370 1371 class CommandObjectCommandsScriptAdd : public CommandObjectParsed, 1372 public IOHandlerDelegateMultiline { 1373 public: 1374 CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) 1375 : CommandObjectParsed(interpreter, "command script add", 1376 "Add a scripted function as an LLDB command.", 1377 "Add a scripted function as an lldb command. " 1378 "If you provide a single argument, the command " 1379 "will be added at the root level of the command " 1380 "hierarchy. If there are more arguments they " 1381 "must be a path to a user-added container " 1382 "command, and the last element will be the new " 1383 "command name."), 1384 IOHandlerDelegateMultiline("DONE") { 1385 CommandArgumentEntry arg1; 1386 CommandArgumentData cmd_arg; 1387 1388 // This is one or more command names, which form the path to the command 1389 // you want to add. 1390 cmd_arg.arg_type = eArgTypeCommand; 1391 cmd_arg.arg_repetition = eArgRepeatPlus; 1392 1393 // There is only one variant this argument could be; put it into the 1394 // argument entry. 1395 arg1.push_back(cmd_arg); 1396 1397 // Push the data for the first argument into the m_arguments vector. 1398 m_arguments.push_back(arg1); 1399 } 1400 1401 ~CommandObjectCommandsScriptAdd() override = default; 1402 1403 Options *GetOptions() override { return &m_options; } 1404 1405 void 1406 HandleArgumentCompletion(CompletionRequest &request, 1407 OptionElementVector &opt_element_vector) override { 1408 CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request, 1409 opt_element_vector); 1410 } 1411 1412 protected: 1413 class CommandOptions : public Options { 1414 public: 1415 CommandOptions() = default; 1416 1417 ~CommandOptions() override = default; 1418 1419 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1420 ExecutionContext *execution_context) override { 1421 Status error; 1422 const int short_option = m_getopt_table[option_idx].val; 1423 1424 switch (short_option) { 1425 case 'f': 1426 if (!option_arg.empty()) 1427 m_funct_name = std::string(option_arg); 1428 break; 1429 case 'c': 1430 if (!option_arg.empty()) 1431 m_class_name = std::string(option_arg); 1432 break; 1433 case 'h': 1434 if (!option_arg.empty()) 1435 m_short_help = std::string(option_arg); 1436 break; 1437 case 'o': 1438 m_overwrite_lazy = eLazyBoolYes; 1439 break; 1440 case 's': 1441 m_synchronicity = 1442 (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum( 1443 option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 1444 if (!error.Success()) 1445 error.SetErrorStringWithFormat( 1446 "unrecognized value for synchronicity '%s'", 1447 option_arg.str().c_str()); 1448 break; 1449 case 'C': { 1450 Status error; 1451 OptionDefinition definition = GetDefinitions()[option_idx]; 1452 lldb::CompletionType completion_type = 1453 static_cast<lldb::CompletionType>(OptionArgParser::ToOptionEnum( 1454 option_arg, definition.enum_values, eNoCompletion, error)); 1455 if (!error.Success()) 1456 error.SetErrorStringWithFormat( 1457 "unrecognized value for command completion type '%s'", 1458 option_arg.str().c_str()); 1459 m_completion_type = completion_type; 1460 } break; 1461 default: 1462 llvm_unreachable("Unimplemented option"); 1463 } 1464 1465 return error; 1466 } 1467 1468 void OptionParsingStarting(ExecutionContext *execution_context) override { 1469 m_class_name.clear(); 1470 m_funct_name.clear(); 1471 m_short_help.clear(); 1472 m_completion_type = eNoCompletion; 1473 m_overwrite_lazy = eLazyBoolCalculate; 1474 m_synchronicity = eScriptedCommandSynchronicitySynchronous; 1475 } 1476 1477 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1478 return llvm::ArrayRef(g_script_add_options); 1479 } 1480 1481 // Instance variables to hold the values for command options. 1482 1483 std::string m_class_name; 1484 std::string m_funct_name; 1485 std::string m_short_help; 1486 LazyBool m_overwrite_lazy = eLazyBoolCalculate; 1487 ScriptedCommandSynchronicity m_synchronicity = 1488 eScriptedCommandSynchronicitySynchronous; 1489 CompletionType m_completion_type = eNoCompletion; 1490 }; 1491 1492 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 1493 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); 1494 if (output_sp && interactive) { 1495 output_sp->PutCString(g_python_command_instructions); 1496 output_sp->Flush(); 1497 } 1498 } 1499 1500 void IOHandlerInputComplete(IOHandler &io_handler, 1501 std::string &data) override { 1502 StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); 1503 1504 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1505 if (interpreter) { 1506 StringList lines; 1507 lines.SplitIntoLines(data); 1508 if (lines.GetSize() > 0) { 1509 std::string funct_name_str; 1510 if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) { 1511 if (funct_name_str.empty()) { 1512 error_sp->Printf("error: unable to obtain a function name, didn't " 1513 "add python command.\n"); 1514 error_sp->Flush(); 1515 } else { 1516 // everything should be fine now, let's add this alias 1517 1518 CommandObjectSP command_obj_sp(new CommandObjectPythonFunction( 1519 m_interpreter, m_cmd_name, funct_name_str, m_short_help, 1520 m_synchronicity, m_completion_type)); 1521 if (!m_container) { 1522 Status error = m_interpreter.AddUserCommand( 1523 m_cmd_name, command_obj_sp, m_overwrite); 1524 if (error.Fail()) { 1525 error_sp->Printf("error: unable to add selected command: '%s'", 1526 error.AsCString()); 1527 error_sp->Flush(); 1528 } 1529 } else { 1530 llvm::Error llvm_error = m_container->LoadUserSubcommand( 1531 m_cmd_name, command_obj_sp, m_overwrite); 1532 if (llvm_error) { 1533 error_sp->Printf("error: unable to add selected command: '%s'", 1534 llvm::toString(std::move(llvm_error)).c_str()); 1535 error_sp->Flush(); 1536 } 1537 } 1538 } 1539 } else { 1540 error_sp->Printf( 1541 "error: unable to create function, didn't add python command\n"); 1542 error_sp->Flush(); 1543 } 1544 } else { 1545 error_sp->Printf("error: empty function, didn't add python command\n"); 1546 error_sp->Flush(); 1547 } 1548 } else { 1549 error_sp->Printf( 1550 "error: script interpreter missing, didn't add python command\n"); 1551 error_sp->Flush(); 1552 } 1553 1554 io_handler.SetIsDone(true); 1555 } 1556 1557 void DoExecute(Args &command, CommandReturnObject &result) override { 1558 if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) { 1559 result.AppendError("only scripting language supported for scripted " 1560 "commands is currently Python"); 1561 return; 1562 } 1563 1564 if (command.GetArgumentCount() == 0) { 1565 result.AppendError("'command script add' requires at least one argument"); 1566 return; 1567 } 1568 // Store the options in case we get multi-line input, also figure out the 1569 // default if not user supplied: 1570 switch (m_options.m_overwrite_lazy) { 1571 case eLazyBoolCalculate: 1572 m_overwrite = !GetDebugger().GetCommandInterpreter().GetRequireCommandOverwrite(); 1573 break; 1574 case eLazyBoolYes: 1575 m_overwrite = true; 1576 break; 1577 case eLazyBoolNo: 1578 m_overwrite = false; 1579 } 1580 1581 Status path_error; 1582 m_container = GetCommandInterpreter().VerifyUserMultiwordCmdPath( 1583 command, true, path_error); 1584 1585 if (path_error.Fail()) { 1586 result.AppendErrorWithFormat("error in command path: %s", 1587 path_error.AsCString()); 1588 return; 1589 } 1590 1591 if (!m_container) { 1592 // This is getting inserted into the root of the interpreter. 1593 m_cmd_name = std::string(command[0].ref()); 1594 } else { 1595 size_t num_args = command.GetArgumentCount(); 1596 m_cmd_name = std::string(command[num_args - 1].ref()); 1597 } 1598 1599 m_short_help.assign(m_options.m_short_help); 1600 m_synchronicity = m_options.m_synchronicity; 1601 m_completion_type = m_options.m_completion_type; 1602 1603 // Handle the case where we prompt for the script code first: 1604 if (m_options.m_class_name.empty() && m_options.m_funct_name.empty()) { 1605 m_interpreter.GetPythonCommandsFromIOHandler(" ", // Prompt 1606 *this); // IOHandlerDelegate 1607 return; 1608 } 1609 1610 CommandObjectSP new_cmd_sp; 1611 if (m_options.m_class_name.empty()) { 1612 new_cmd_sp.reset(new CommandObjectPythonFunction( 1613 m_interpreter, m_cmd_name, m_options.m_funct_name, 1614 m_options.m_short_help, m_synchronicity, m_completion_type)); 1615 } else { 1616 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1617 if (!interpreter) { 1618 result.AppendError("cannot find ScriptInterpreter"); 1619 return; 1620 } 1621 1622 auto cmd_obj_sp = interpreter->CreateScriptCommandObject( 1623 m_options.m_class_name.c_str()); 1624 if (!cmd_obj_sp) { 1625 result.AppendErrorWithFormatv("cannot create helper object for: " 1626 "'{0}'", m_options.m_class_name); 1627 return; 1628 } 1629 1630 new_cmd_sp.reset(new CommandObjectScriptingObject( 1631 m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity, 1632 m_completion_type)); 1633 } 1634 1635 // Assume we're going to succeed... 1636 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1637 if (!m_container) { 1638 Status add_error = 1639 m_interpreter.AddUserCommand(m_cmd_name, new_cmd_sp, m_overwrite); 1640 if (add_error.Fail()) 1641 result.AppendErrorWithFormat("cannot add command: %s", 1642 add_error.AsCString()); 1643 } else { 1644 llvm::Error llvm_error = 1645 m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite); 1646 if (llvm_error) 1647 result.AppendErrorWithFormat("cannot add command: %s", 1648 llvm::toString(std::move(llvm_error)).c_str()); 1649 } 1650 } 1651 1652 CommandOptions m_options; 1653 std::string m_cmd_name; 1654 CommandObjectMultiword *m_container = nullptr; 1655 std::string m_short_help; 1656 bool m_overwrite = false; 1657 ScriptedCommandSynchronicity m_synchronicity = 1658 eScriptedCommandSynchronicitySynchronous; 1659 CompletionType m_completion_type = eNoCompletion; 1660 }; 1661 1662 // CommandObjectCommandsScriptList 1663 1664 class CommandObjectCommandsScriptList : public CommandObjectParsed { 1665 public: 1666 CommandObjectCommandsScriptList(CommandInterpreter &interpreter) 1667 : CommandObjectParsed(interpreter, "command script list", 1668 "List defined top-level scripted commands.", 1669 nullptr) {} 1670 1671 ~CommandObjectCommandsScriptList() override = default; 1672 1673 void DoExecute(Args &command, CommandReturnObject &result) override { 1674 m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef); 1675 1676 result.SetStatus(eReturnStatusSuccessFinishResult); 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 void DoExecute(Args &command, CommandReturnObject &result) override { 1692 m_interpreter.RemoveAllUser(); 1693 1694 result.SetStatus(eReturnStatusSuccessFinishResult); 1695 } 1696 }; 1697 1698 // CommandObjectCommandsScriptDelete 1699 1700 class CommandObjectCommandsScriptDelete : public CommandObjectParsed { 1701 public: 1702 CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) 1703 : CommandObjectParsed( 1704 interpreter, "command script delete", 1705 "Delete a scripted command by specifying the path to the command.", 1706 nullptr) { 1707 CommandArgumentEntry arg1; 1708 CommandArgumentData cmd_arg; 1709 1710 // This is a list of command names forming the path to the command 1711 // to be deleted. 1712 cmd_arg.arg_type = eArgTypeCommand; 1713 cmd_arg.arg_repetition = eArgRepeatPlus; 1714 1715 // There is only one variant this argument could be; put it into the 1716 // argument entry. 1717 arg1.push_back(cmd_arg); 1718 1719 // Push the data for the first argument into the m_arguments vector. 1720 m_arguments.push_back(arg1); 1721 } 1722 1723 ~CommandObjectCommandsScriptDelete() override = default; 1724 1725 void 1726 HandleArgumentCompletion(CompletionRequest &request, 1727 OptionElementVector &opt_element_vector) override { 1728 lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs( 1729 m_interpreter, request, opt_element_vector); 1730 } 1731 1732 protected: 1733 void DoExecute(Args &command, CommandReturnObject &result) override { 1734 1735 llvm::StringRef root_cmd = command[0].ref(); 1736 size_t num_args = command.GetArgumentCount(); 1737 1738 if (root_cmd.empty()) { 1739 result.AppendErrorWithFormat("empty root command name"); 1740 return; 1741 } 1742 if (!m_interpreter.HasUserCommands() && 1743 !m_interpreter.HasUserMultiwordCommands()) { 1744 result.AppendErrorWithFormat("can only delete user defined commands, " 1745 "but no user defined commands found"); 1746 return; 1747 } 1748 1749 CommandObjectSP cmd_sp = m_interpreter.GetCommandSPExact(root_cmd); 1750 if (!cmd_sp) { 1751 result.AppendErrorWithFormat("command '%s' not found.", 1752 command[0].c_str()); 1753 return; 1754 } 1755 if (!cmd_sp->IsUserCommand()) { 1756 result.AppendErrorWithFormat("command '%s' is not a user command.", 1757 command[0].c_str()); 1758 return; 1759 } 1760 if (cmd_sp->GetAsMultiwordCommand() && num_args == 1) { 1761 result.AppendErrorWithFormat("command '%s' is a multi-word command.\n " 1762 "Delete with \"command container delete\"", 1763 command[0].c_str()); 1764 return; 1765 } 1766 1767 if (command.GetArgumentCount() == 1) { 1768 m_interpreter.RemoveUser(root_cmd); 1769 result.SetStatus(eReturnStatusSuccessFinishResult); 1770 return; 1771 } 1772 // We're deleting a command from a multiword command. Verify the command 1773 // path: 1774 Status error; 1775 CommandObjectMultiword *container = 1776 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 1777 error); 1778 if (error.Fail()) { 1779 result.AppendErrorWithFormat("could not resolve command path: %s", 1780 error.AsCString()); 1781 return; 1782 } 1783 if (!container) { 1784 // This means that command only had a leaf command, so the container is 1785 // the root. That should have been handled above. 1786 result.AppendErrorWithFormat("could not find a container for '%s'", 1787 command[0].c_str()); 1788 return; 1789 } 1790 const char *leaf_cmd = command[num_args - 1].c_str(); 1791 llvm::Error llvm_error = container->RemoveUserSubcommand(leaf_cmd, 1792 /* multiword not okay */ false); 1793 if (llvm_error) { 1794 result.AppendErrorWithFormat("could not delete command '%s': %s", 1795 leaf_cmd, 1796 llvm::toString(std::move(llvm_error)).c_str()); 1797 return; 1798 } 1799 1800 Stream &out_stream = result.GetOutputStream(); 1801 1802 out_stream << "Deleted command:"; 1803 for (size_t idx = 0; idx < num_args; idx++) { 1804 out_stream << ' '; 1805 out_stream << command[idx].c_str(); 1806 } 1807 out_stream << '\n'; 1808 result.SetStatus(eReturnStatusSuccessFinishResult); 1809 } 1810 }; 1811 1812 #pragma mark CommandObjectMultiwordCommandsScript 1813 1814 // CommandObjectMultiwordCommandsScript 1815 1816 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword { 1817 public: 1818 CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter) 1819 : CommandObjectMultiword( 1820 interpreter, "command script", 1821 "Commands for managing custom " 1822 "commands implemented by " 1823 "interpreter scripts.", 1824 "command script <subcommand> [<subcommand-options>]") { 1825 LoadSubCommand("add", CommandObjectSP( 1826 new CommandObjectCommandsScriptAdd(interpreter))); 1827 LoadSubCommand( 1828 "delete", 1829 CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter))); 1830 LoadSubCommand( 1831 "clear", 1832 CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter))); 1833 LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList( 1834 interpreter))); 1835 LoadSubCommand( 1836 "import", 1837 CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter))); 1838 } 1839 1840 ~CommandObjectMultiwordCommandsScript() override = default; 1841 }; 1842 1843 #pragma mark CommandObjectCommandContainer 1844 #define LLDB_OPTIONS_container_add 1845 #include "CommandOptions.inc" 1846 1847 class CommandObjectCommandsContainerAdd : public CommandObjectParsed { 1848 public: 1849 CommandObjectCommandsContainerAdd(CommandInterpreter &interpreter) 1850 : CommandObjectParsed( 1851 interpreter, "command container add", 1852 "Add a container command to lldb. Adding to built-" 1853 "in container commands is not allowed.", 1854 "command container add [[path1]...] container-name") { 1855 CommandArgumentEntry arg1; 1856 CommandArgumentData cmd_arg; 1857 1858 // This is one or more command names, which form the path to the command 1859 // you want to add. 1860 cmd_arg.arg_type = eArgTypeCommand; 1861 cmd_arg.arg_repetition = eArgRepeatPlus; 1862 1863 // There is only one variant this argument could be; put it into the 1864 // argument entry. 1865 arg1.push_back(cmd_arg); 1866 1867 // Push the data for the first argument into the m_arguments vector. 1868 m_arguments.push_back(arg1); 1869 } 1870 1871 ~CommandObjectCommandsContainerAdd() override = default; 1872 1873 Options *GetOptions() override { return &m_options; } 1874 1875 void 1876 HandleArgumentCompletion(CompletionRequest &request, 1877 OptionElementVector &opt_element_vector) override { 1878 lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs( 1879 m_interpreter, request, opt_element_vector); 1880 } 1881 1882 protected: 1883 class CommandOptions : public Options { 1884 public: 1885 CommandOptions() = default; 1886 1887 ~CommandOptions() override = default; 1888 1889 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1890 ExecutionContext *execution_context) override { 1891 Status error; 1892 const int short_option = m_getopt_table[option_idx].val; 1893 1894 switch (short_option) { 1895 case 'h': 1896 if (!option_arg.empty()) 1897 m_short_help = std::string(option_arg); 1898 break; 1899 case 'o': 1900 m_overwrite = true; 1901 break; 1902 case 'H': 1903 if (!option_arg.empty()) 1904 m_long_help = std::string(option_arg); 1905 break; 1906 default: 1907 llvm_unreachable("Unimplemented option"); 1908 } 1909 1910 return error; 1911 } 1912 1913 void OptionParsingStarting(ExecutionContext *execution_context) override { 1914 m_short_help.clear(); 1915 m_long_help.clear(); 1916 m_overwrite = false; 1917 } 1918 1919 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1920 return llvm::ArrayRef(g_container_add_options); 1921 } 1922 1923 // Instance variables to hold the values for command options. 1924 1925 std::string m_short_help; 1926 std::string m_long_help; 1927 bool m_overwrite = false; 1928 }; 1929 void DoExecute(Args &command, CommandReturnObject &result) override { 1930 size_t num_args = command.GetArgumentCount(); 1931 1932 if (num_args == 0) { 1933 result.AppendError("no command was specified"); 1934 return; 1935 } 1936 1937 if (num_args == 1) { 1938 // We're adding this as a root command, so use the interpreter. 1939 const char *cmd_name = command.GetArgumentAtIndex(0); 1940 auto cmd_sp = CommandObjectSP(new CommandObjectMultiword( 1941 GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(), 1942 m_options.m_long_help.c_str())); 1943 cmd_sp->GetAsMultiwordCommand()->SetRemovable(true); 1944 Status add_error = GetCommandInterpreter().AddUserCommand( 1945 cmd_name, cmd_sp, m_options.m_overwrite); 1946 if (add_error.Fail()) { 1947 result.AppendErrorWithFormat("error adding command: %s", 1948 add_error.AsCString()); 1949 return; 1950 } 1951 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1952 return; 1953 } 1954 1955 // We're adding this to a subcommand, first find the subcommand: 1956 Status path_error; 1957 CommandObjectMultiword *add_to_me = 1958 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 1959 path_error); 1960 1961 if (!add_to_me) { 1962 result.AppendErrorWithFormat("error adding command: %s", 1963 path_error.AsCString()); 1964 return; 1965 } 1966 1967 const char *cmd_name = command.GetArgumentAtIndex(num_args - 1); 1968 auto cmd_sp = CommandObjectSP(new CommandObjectMultiword( 1969 GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(), 1970 m_options.m_long_help.c_str())); 1971 llvm::Error llvm_error = 1972 add_to_me->LoadUserSubcommand(cmd_name, cmd_sp, m_options.m_overwrite); 1973 if (llvm_error) { 1974 result.AppendErrorWithFormat("error adding subcommand: %s", 1975 llvm::toString(std::move(llvm_error)).c_str()); 1976 return; 1977 } 1978 1979 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1980 } 1981 1982 private: 1983 CommandOptions m_options; 1984 }; 1985 1986 #define LLDB_OPTIONS_multiword_delete 1987 #include "CommandOptions.inc" 1988 class CommandObjectCommandsContainerDelete : public CommandObjectParsed { 1989 public: 1990 CommandObjectCommandsContainerDelete(CommandInterpreter &interpreter) 1991 : CommandObjectParsed( 1992 interpreter, "command container delete", 1993 "Delete a container command previously added to " 1994 "lldb.", 1995 "command container delete [[path1] ...] container-cmd") { 1996 CommandArgumentEntry arg1; 1997 CommandArgumentData cmd_arg; 1998 1999 // This is one or more command names, which form the path to the command 2000 // you want to add. 2001 cmd_arg.arg_type = eArgTypeCommand; 2002 cmd_arg.arg_repetition = eArgRepeatPlus; 2003 2004 // There is only one variant this argument could be; put it into the 2005 // argument entry. 2006 arg1.push_back(cmd_arg); 2007 2008 // Push the data for the first argument into the m_arguments vector. 2009 m_arguments.push_back(arg1); 2010 } 2011 2012 ~CommandObjectCommandsContainerDelete() override = default; 2013 2014 void 2015 HandleArgumentCompletion(CompletionRequest &request, 2016 OptionElementVector &opt_element_vector) override { 2017 lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs( 2018 m_interpreter, request, opt_element_vector); 2019 } 2020 2021 protected: 2022 void DoExecute(Args &command, CommandReturnObject &result) override { 2023 size_t num_args = command.GetArgumentCount(); 2024 2025 if (num_args == 0) { 2026 result.AppendError("No command was specified."); 2027 return; 2028 } 2029 2030 if (num_args == 1) { 2031 // We're removing a root command, so we need to delete it from the 2032 // interpreter. 2033 const char *cmd_name = command.GetArgumentAtIndex(0); 2034 // Let's do a little more work here so we can do better error reporting. 2035 CommandInterpreter &interp = GetCommandInterpreter(); 2036 CommandObjectSP cmd_sp = interp.GetCommandSPExact(cmd_name); 2037 if (!cmd_sp) { 2038 result.AppendErrorWithFormat("container command %s doesn't exist.", 2039 cmd_name); 2040 return; 2041 } 2042 if (!cmd_sp->IsUserCommand()) { 2043 result.AppendErrorWithFormat( 2044 "container command %s is not a user command", cmd_name); 2045 return; 2046 } 2047 if (!cmd_sp->GetAsMultiwordCommand()) { 2048 result.AppendErrorWithFormat("command %s is not a container command", 2049 cmd_name); 2050 return; 2051 } 2052 2053 bool did_remove = GetCommandInterpreter().RemoveUserMultiword(cmd_name); 2054 if (!did_remove) { 2055 result.AppendErrorWithFormat("error removing command %s.", cmd_name); 2056 return; 2057 } 2058 2059 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2060 return; 2061 } 2062 2063 // We're removing a subcommand, first find the subcommand's owner: 2064 Status path_error; 2065 CommandObjectMultiword *container = 2066 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 2067 path_error); 2068 2069 if (!container) { 2070 result.AppendErrorWithFormat("error removing container command: %s", 2071 path_error.AsCString()); 2072 return; 2073 } 2074 const char *leaf = command.GetArgumentAtIndex(num_args - 1); 2075 llvm::Error llvm_error = 2076 container->RemoveUserSubcommand(leaf, /* multiword okay */ true); 2077 if (llvm_error) { 2078 result.AppendErrorWithFormat("error removing container command: %s", 2079 llvm::toString(std::move(llvm_error)).c_str()); 2080 return; 2081 } 2082 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2083 } 2084 }; 2085 2086 class CommandObjectCommandContainer : public CommandObjectMultiword { 2087 public: 2088 CommandObjectCommandContainer(CommandInterpreter &interpreter) 2089 : CommandObjectMultiword( 2090 interpreter, "command container", 2091 "Commands for adding container commands to lldb. " 2092 "Container commands are containers for other commands. You can " 2093 "add nested container commands by specifying a command path, " 2094 "but you can't add commands into the built-in command hierarchy.", 2095 "command container <subcommand> [<subcommand-options>]") { 2096 LoadSubCommand("add", CommandObjectSP(new CommandObjectCommandsContainerAdd( 2097 interpreter))); 2098 LoadSubCommand( 2099 "delete", 2100 CommandObjectSP(new CommandObjectCommandsContainerDelete(interpreter))); 2101 } 2102 2103 ~CommandObjectCommandContainer() override = default; 2104 }; 2105 2106 #pragma mark CommandObjectMultiwordCommands 2107 2108 // CommandObjectMultiwordCommands 2109 2110 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands( 2111 CommandInterpreter &interpreter) 2112 : CommandObjectMultiword(interpreter, "command", 2113 "Commands for managing custom LLDB commands.", 2114 "command <subcommand> [<subcommand-options>]") { 2115 LoadSubCommand("source", 2116 CommandObjectSP(new CommandObjectCommandsSource(interpreter))); 2117 LoadSubCommand("alias", 2118 CommandObjectSP(new CommandObjectCommandsAlias(interpreter))); 2119 LoadSubCommand("unalias", CommandObjectSP( 2120 new CommandObjectCommandsUnalias(interpreter))); 2121 LoadSubCommand("delete", 2122 CommandObjectSP(new CommandObjectCommandsDelete(interpreter))); 2123 LoadSubCommand("container", CommandObjectSP(new CommandObjectCommandContainer( 2124 interpreter))); 2125 LoadSubCommand( 2126 "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter))); 2127 LoadSubCommand( 2128 "script", 2129 CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter))); 2130 } 2131 2132 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default; 2133