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 m_interpreter.IncreaseCommandUsage(*this); 1127 1128 Status error; 1129 1130 result.SetStatus(eReturnStatusInvalid); 1131 1132 if (!scripter || !scripter->RunScriptBasedCommand( 1133 m_function_name.c_str(), raw_command_line, m_synchro, 1134 result, error, m_exe_ctx)) { 1135 result.AppendError(error.AsCString()); 1136 } else { 1137 // Don't change the status if the command already set it... 1138 if (result.GetStatus() == eReturnStatusInvalid) { 1139 if (result.GetOutputData().empty()) 1140 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1141 else 1142 result.SetStatus(eReturnStatusSuccessFinishResult); 1143 } 1144 } 1145 } 1146 1147 private: 1148 std::string m_function_name; 1149 ScriptedCommandSynchronicity m_synchro; 1150 bool m_fetched_help_long = false; 1151 CompletionType m_completion_type = eNoCompletion; 1152 }; 1153 1154 class CommandObjectScriptingObject : public CommandObjectRaw { 1155 public: 1156 CommandObjectScriptingObject(CommandInterpreter &interpreter, 1157 std::string name, 1158 StructuredData::GenericSP cmd_obj_sp, 1159 ScriptedCommandSynchronicity synch, 1160 CompletionType completion_type) 1161 : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp), 1162 m_synchro(synch), m_fetched_help_short(false), 1163 m_fetched_help_long(false), m_completion_type(completion_type) { 1164 StreamString stream; 1165 stream.Printf("For more information run 'help %s'", name.c_str()); 1166 SetHelp(stream.GetString()); 1167 if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter()) 1168 GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); 1169 } 1170 1171 ~CommandObjectScriptingObject() override = default; 1172 1173 void 1174 HandleArgumentCompletion(CompletionRequest &request, 1175 OptionElementVector &opt_element_vector) override { 1176 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 1177 GetCommandInterpreter(), m_completion_type, request, nullptr); 1178 } 1179 1180 bool WantsCompletion() override { return true; } 1181 1182 bool IsRemovable() const override { return true; } 1183 1184 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1185 1186 llvm::StringRef GetHelp() override { 1187 if (m_fetched_help_short) 1188 return CommandObjectRaw::GetHelp(); 1189 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1190 if (!scripter) 1191 return CommandObjectRaw::GetHelp(); 1192 std::string docstring; 1193 m_fetched_help_short = 1194 scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring); 1195 if (!docstring.empty()) 1196 SetHelp(docstring); 1197 1198 return CommandObjectRaw::GetHelp(); 1199 } 1200 1201 llvm::StringRef GetHelpLong() override { 1202 if (m_fetched_help_long) 1203 return CommandObjectRaw::GetHelpLong(); 1204 1205 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1206 if (!scripter) 1207 return CommandObjectRaw::GetHelpLong(); 1208 1209 std::string docstring; 1210 m_fetched_help_long = 1211 scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring); 1212 if (!docstring.empty()) 1213 SetHelpLong(docstring); 1214 return CommandObjectRaw::GetHelpLong(); 1215 } 1216 1217 protected: 1218 void DoExecute(llvm::StringRef raw_command_line, 1219 CommandReturnObject &result) override { 1220 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1221 1222 Status error; 1223 1224 result.SetStatus(eReturnStatusInvalid); 1225 1226 if (!scripter || 1227 !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line, 1228 m_synchro, result, error, m_exe_ctx)) { 1229 result.AppendError(error.AsCString()); 1230 } else { 1231 // Don't change the status if the command already set it... 1232 if (result.GetStatus() == eReturnStatusInvalid) { 1233 if (result.GetOutputData().empty()) 1234 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1235 else 1236 result.SetStatus(eReturnStatusSuccessFinishResult); 1237 } 1238 } 1239 } 1240 1241 private: 1242 StructuredData::GenericSP m_cmd_obj_sp; 1243 ScriptedCommandSynchronicity m_synchro; 1244 bool m_fetched_help_short : 1; 1245 bool m_fetched_help_long : 1; 1246 CompletionType m_completion_type = eNoCompletion; 1247 }; 1248 1249 // CommandObjectCommandsScriptImport 1250 #define LLDB_OPTIONS_script_import 1251 #include "CommandOptions.inc" 1252 1253 class CommandObjectCommandsScriptImport : public CommandObjectParsed { 1254 public: 1255 CommandObjectCommandsScriptImport(CommandInterpreter &interpreter) 1256 : CommandObjectParsed(interpreter, "command script import", 1257 "Import a scripting module in LLDB.", nullptr) { 1258 CommandArgumentEntry arg1; 1259 CommandArgumentData cmd_arg; 1260 1261 // Define the first (and only) variant of this arg. 1262 cmd_arg.arg_type = eArgTypeFilename; 1263 cmd_arg.arg_repetition = eArgRepeatPlus; 1264 1265 // There is only one variant this argument could be; put it into the 1266 // argument entry. 1267 arg1.push_back(cmd_arg); 1268 1269 // Push the data for the first argument into the m_arguments vector. 1270 m_arguments.push_back(arg1); 1271 } 1272 1273 ~CommandObjectCommandsScriptImport() override = default; 1274 1275 void 1276 HandleArgumentCompletion(CompletionRequest &request, 1277 OptionElementVector &opt_element_vector) override { 1278 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 1279 GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr); 1280 } 1281 1282 Options *GetOptions() override { return &m_options; } 1283 1284 protected: 1285 class CommandOptions : public Options { 1286 public: 1287 CommandOptions() = default; 1288 1289 ~CommandOptions() override = default; 1290 1291 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1292 ExecutionContext *execution_context) override { 1293 Status error; 1294 const int short_option = m_getopt_table[option_idx].val; 1295 1296 switch (short_option) { 1297 case 'r': 1298 // NO-OP 1299 break; 1300 case 'c': 1301 relative_to_command_file = true; 1302 break; 1303 case 's': 1304 silent = true; 1305 break; 1306 default: 1307 llvm_unreachable("Unimplemented option"); 1308 } 1309 1310 return error; 1311 } 1312 1313 void OptionParsingStarting(ExecutionContext *execution_context) override { 1314 relative_to_command_file = false; 1315 } 1316 1317 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1318 return llvm::ArrayRef(g_script_import_options); 1319 } 1320 bool relative_to_command_file = false; 1321 bool silent = false; 1322 }; 1323 1324 void DoExecute(Args &command, CommandReturnObject &result) override { 1325 if (command.empty()) { 1326 result.AppendError("command script import needs one or more arguments"); 1327 return; 1328 } 1329 1330 FileSpec source_dir = {}; 1331 if (m_options.relative_to_command_file) { 1332 source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir(); 1333 if (!source_dir) { 1334 result.AppendError("command script import -c can only be specified " 1335 "from a command file"); 1336 return; 1337 } 1338 } 1339 1340 for (auto &entry : command.entries()) { 1341 Status error; 1342 1343 LoadScriptOptions options; 1344 options.SetInitSession(true); 1345 options.SetSilent(m_options.silent); 1346 1347 // FIXME: this is necessary because CommandObject::CheckRequirements() 1348 // assumes that commands won't ever be recursively invoked, but it's 1349 // actually possible to craft a Python script that does other "command 1350 // script imports" in __lldb_init_module the real fix is to have 1351 // recursive commands possible with a CommandInvocation object separate 1352 // from the CommandObject itself, so that recursive command invocations 1353 // won't stomp on each other (wrt to execution contents, options, and 1354 // more) 1355 m_exe_ctx.Clear(); 1356 if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule( 1357 entry.c_str(), options, error, /*module_sp=*/nullptr, 1358 source_dir)) { 1359 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1360 } else { 1361 result.AppendErrorWithFormat("module importing failed: %s", 1362 error.AsCString()); 1363 } 1364 } 1365 } 1366 1367 CommandOptions m_options; 1368 }; 1369 1370 #define LLDB_OPTIONS_script_add 1371 #include "CommandOptions.inc" 1372 1373 class CommandObjectCommandsScriptAdd : public CommandObjectParsed, 1374 public IOHandlerDelegateMultiline { 1375 public: 1376 CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) 1377 : CommandObjectParsed(interpreter, "command script add", 1378 "Add a scripted function as an LLDB command.", 1379 "Add a scripted function as an lldb command. " 1380 "If you provide a single argument, the command " 1381 "will be added at the root level of the command " 1382 "hierarchy. If there are more arguments they " 1383 "must be a path to a user-added container " 1384 "command, and the last element will be the new " 1385 "command name."), 1386 IOHandlerDelegateMultiline("DONE") { 1387 CommandArgumentEntry arg1; 1388 CommandArgumentData cmd_arg; 1389 1390 // This is one or more command names, which form the path to the command 1391 // you want to add. 1392 cmd_arg.arg_type = eArgTypeCommand; 1393 cmd_arg.arg_repetition = eArgRepeatPlus; 1394 1395 // There is only one variant this argument could be; put it into the 1396 // argument entry. 1397 arg1.push_back(cmd_arg); 1398 1399 // Push the data for the first argument into the m_arguments vector. 1400 m_arguments.push_back(arg1); 1401 } 1402 1403 ~CommandObjectCommandsScriptAdd() override = default; 1404 1405 Options *GetOptions() override { return &m_options; } 1406 1407 void 1408 HandleArgumentCompletion(CompletionRequest &request, 1409 OptionElementVector &opt_element_vector) override { 1410 CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request, 1411 opt_element_vector); 1412 } 1413 1414 protected: 1415 class CommandOptions : public Options { 1416 public: 1417 CommandOptions() = default; 1418 1419 ~CommandOptions() override = default; 1420 1421 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1422 ExecutionContext *execution_context) override { 1423 Status error; 1424 const int short_option = m_getopt_table[option_idx].val; 1425 1426 switch (short_option) { 1427 case 'f': 1428 if (!option_arg.empty()) 1429 m_funct_name = std::string(option_arg); 1430 break; 1431 case 'c': 1432 if (!option_arg.empty()) 1433 m_class_name = std::string(option_arg); 1434 break; 1435 case 'h': 1436 if (!option_arg.empty()) 1437 m_short_help = std::string(option_arg); 1438 break; 1439 case 'o': 1440 m_overwrite_lazy = eLazyBoolYes; 1441 break; 1442 case 's': 1443 m_synchronicity = 1444 (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum( 1445 option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 1446 if (!error.Success()) 1447 error.SetErrorStringWithFormat( 1448 "unrecognized value for synchronicity '%s'", 1449 option_arg.str().c_str()); 1450 break; 1451 case 'C': { 1452 Status error; 1453 OptionDefinition definition = GetDefinitions()[option_idx]; 1454 lldb::CompletionType completion_type = 1455 static_cast<lldb::CompletionType>(OptionArgParser::ToOptionEnum( 1456 option_arg, definition.enum_values, eNoCompletion, error)); 1457 if (!error.Success()) 1458 error.SetErrorStringWithFormat( 1459 "unrecognized value for command completion type '%s'", 1460 option_arg.str().c_str()); 1461 m_completion_type = completion_type; 1462 } break; 1463 default: 1464 llvm_unreachable("Unimplemented option"); 1465 } 1466 1467 return error; 1468 } 1469 1470 void OptionParsingStarting(ExecutionContext *execution_context) override { 1471 m_class_name.clear(); 1472 m_funct_name.clear(); 1473 m_short_help.clear(); 1474 m_completion_type = eNoCompletion; 1475 m_overwrite_lazy = eLazyBoolCalculate; 1476 m_synchronicity = eScriptedCommandSynchronicitySynchronous; 1477 } 1478 1479 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1480 return llvm::ArrayRef(g_script_add_options); 1481 } 1482 1483 // Instance variables to hold the values for command options. 1484 1485 std::string m_class_name; 1486 std::string m_funct_name; 1487 std::string m_short_help; 1488 LazyBool m_overwrite_lazy = eLazyBoolCalculate; 1489 ScriptedCommandSynchronicity m_synchronicity = 1490 eScriptedCommandSynchronicitySynchronous; 1491 CompletionType m_completion_type = eNoCompletion; 1492 }; 1493 1494 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 1495 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); 1496 if (output_sp && interactive) { 1497 output_sp->PutCString(g_python_command_instructions); 1498 output_sp->Flush(); 1499 } 1500 } 1501 1502 void IOHandlerInputComplete(IOHandler &io_handler, 1503 std::string &data) override { 1504 StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); 1505 1506 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1507 if (interpreter) { 1508 StringList lines; 1509 lines.SplitIntoLines(data); 1510 if (lines.GetSize() > 0) { 1511 std::string funct_name_str; 1512 if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) { 1513 if (funct_name_str.empty()) { 1514 error_sp->Printf("error: unable to obtain a function name, didn't " 1515 "add python command.\n"); 1516 error_sp->Flush(); 1517 } else { 1518 // everything should be fine now, let's add this alias 1519 1520 CommandObjectSP command_obj_sp(new CommandObjectPythonFunction( 1521 m_interpreter, m_cmd_name, funct_name_str, m_short_help, 1522 m_synchronicity, m_completion_type)); 1523 if (!m_container) { 1524 Status error = m_interpreter.AddUserCommand( 1525 m_cmd_name, command_obj_sp, m_overwrite); 1526 if (error.Fail()) { 1527 error_sp->Printf("error: unable to add selected command: '%s'", 1528 error.AsCString()); 1529 error_sp->Flush(); 1530 } 1531 } else { 1532 llvm::Error llvm_error = m_container->LoadUserSubcommand( 1533 m_cmd_name, command_obj_sp, m_overwrite); 1534 if (llvm_error) { 1535 error_sp->Printf("error: unable to add selected command: '%s'", 1536 llvm::toString(std::move(llvm_error)).c_str()); 1537 error_sp->Flush(); 1538 } 1539 } 1540 } 1541 } else { 1542 error_sp->Printf( 1543 "error: unable to create function, didn't add python command\n"); 1544 error_sp->Flush(); 1545 } 1546 } else { 1547 error_sp->Printf("error: empty function, didn't add python command\n"); 1548 error_sp->Flush(); 1549 } 1550 } else { 1551 error_sp->Printf( 1552 "error: script interpreter missing, didn't add python command\n"); 1553 error_sp->Flush(); 1554 } 1555 1556 io_handler.SetIsDone(true); 1557 } 1558 1559 void DoExecute(Args &command, CommandReturnObject &result) override { 1560 if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) { 1561 result.AppendError("only scripting language supported for scripted " 1562 "commands is currently Python"); 1563 return; 1564 } 1565 1566 if (command.GetArgumentCount() == 0) { 1567 result.AppendError("'command script add' requires at least one argument"); 1568 return; 1569 } 1570 // Store the options in case we get multi-line input, also figure out the 1571 // default if not user supplied: 1572 switch (m_options.m_overwrite_lazy) { 1573 case eLazyBoolCalculate: 1574 m_overwrite = !GetDebugger().GetCommandInterpreter().GetRequireCommandOverwrite(); 1575 break; 1576 case eLazyBoolYes: 1577 m_overwrite = true; 1578 break; 1579 case eLazyBoolNo: 1580 m_overwrite = false; 1581 } 1582 1583 Status path_error; 1584 m_container = GetCommandInterpreter().VerifyUserMultiwordCmdPath( 1585 command, true, path_error); 1586 1587 if (path_error.Fail()) { 1588 result.AppendErrorWithFormat("error in command path: %s", 1589 path_error.AsCString()); 1590 return; 1591 } 1592 1593 if (!m_container) { 1594 // This is getting inserted into the root of the interpreter. 1595 m_cmd_name = std::string(command[0].ref()); 1596 } else { 1597 size_t num_args = command.GetArgumentCount(); 1598 m_cmd_name = std::string(command[num_args - 1].ref()); 1599 } 1600 1601 m_short_help.assign(m_options.m_short_help); 1602 m_synchronicity = m_options.m_synchronicity; 1603 m_completion_type = m_options.m_completion_type; 1604 1605 // Handle the case where we prompt for the script code first: 1606 if (m_options.m_class_name.empty() && m_options.m_funct_name.empty()) { 1607 m_interpreter.GetPythonCommandsFromIOHandler(" ", // Prompt 1608 *this); // IOHandlerDelegate 1609 return; 1610 } 1611 1612 CommandObjectSP new_cmd_sp; 1613 if (m_options.m_class_name.empty()) { 1614 new_cmd_sp.reset(new CommandObjectPythonFunction( 1615 m_interpreter, m_cmd_name, m_options.m_funct_name, 1616 m_options.m_short_help, m_synchronicity, m_completion_type)); 1617 } else { 1618 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1619 if (!interpreter) { 1620 result.AppendError("cannot find ScriptInterpreter"); 1621 return; 1622 } 1623 1624 auto cmd_obj_sp = interpreter->CreateScriptCommandObject( 1625 m_options.m_class_name.c_str()); 1626 if (!cmd_obj_sp) { 1627 result.AppendErrorWithFormatv("cannot create helper object for: " 1628 "'{0}'", m_options.m_class_name); 1629 return; 1630 } 1631 1632 new_cmd_sp.reset(new CommandObjectScriptingObject( 1633 m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity, 1634 m_completion_type)); 1635 } 1636 1637 // Assume we're going to succeed... 1638 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1639 if (!m_container) { 1640 Status add_error = 1641 m_interpreter.AddUserCommand(m_cmd_name, new_cmd_sp, m_overwrite); 1642 if (add_error.Fail()) 1643 result.AppendErrorWithFormat("cannot add command: %s", 1644 add_error.AsCString()); 1645 } else { 1646 llvm::Error llvm_error = 1647 m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite); 1648 if (llvm_error) 1649 result.AppendErrorWithFormat( 1650 "cannot add command: %s", 1651 llvm::toString(std::move(llvm_error)).c_str()); 1652 } 1653 } 1654 1655 CommandOptions m_options; 1656 std::string m_cmd_name; 1657 CommandObjectMultiword *m_container = nullptr; 1658 std::string m_short_help; 1659 bool m_overwrite = false; 1660 ScriptedCommandSynchronicity m_synchronicity = 1661 eScriptedCommandSynchronicitySynchronous; 1662 CompletionType m_completion_type = eNoCompletion; 1663 }; 1664 1665 // CommandObjectCommandsScriptList 1666 1667 class CommandObjectCommandsScriptList : public CommandObjectParsed { 1668 public: 1669 CommandObjectCommandsScriptList(CommandInterpreter &interpreter) 1670 : CommandObjectParsed(interpreter, "command script list", 1671 "List defined top-level scripted commands.", 1672 nullptr) {} 1673 1674 ~CommandObjectCommandsScriptList() override = default; 1675 1676 void DoExecute(Args &command, CommandReturnObject &result) override { 1677 m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef); 1678 1679 result.SetStatus(eReturnStatusSuccessFinishResult); 1680 } 1681 }; 1682 1683 // CommandObjectCommandsScriptClear 1684 1685 class CommandObjectCommandsScriptClear : public CommandObjectParsed { 1686 public: 1687 CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) 1688 : CommandObjectParsed(interpreter, "command script clear", 1689 "Delete all scripted commands.", nullptr) {} 1690 1691 ~CommandObjectCommandsScriptClear() override = default; 1692 1693 protected: 1694 void DoExecute(Args &command, CommandReturnObject &result) override { 1695 m_interpreter.RemoveAllUser(); 1696 1697 result.SetStatus(eReturnStatusSuccessFinishResult); 1698 } 1699 }; 1700 1701 // CommandObjectCommandsScriptDelete 1702 1703 class CommandObjectCommandsScriptDelete : public CommandObjectParsed { 1704 public: 1705 CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) 1706 : CommandObjectParsed( 1707 interpreter, "command script delete", 1708 "Delete a scripted command by specifying the path to the command.", 1709 nullptr) { 1710 CommandArgumentEntry arg1; 1711 CommandArgumentData cmd_arg; 1712 1713 // This is a list of command names forming the path to the command 1714 // to be deleted. 1715 cmd_arg.arg_type = eArgTypeCommand; 1716 cmd_arg.arg_repetition = eArgRepeatPlus; 1717 1718 // There is only one variant this argument could be; put it into the 1719 // argument entry. 1720 arg1.push_back(cmd_arg); 1721 1722 // Push the data for the first argument into the m_arguments vector. 1723 m_arguments.push_back(arg1); 1724 } 1725 1726 ~CommandObjectCommandsScriptDelete() override = default; 1727 1728 void 1729 HandleArgumentCompletion(CompletionRequest &request, 1730 OptionElementVector &opt_element_vector) override { 1731 lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs( 1732 m_interpreter, request, opt_element_vector); 1733 } 1734 1735 protected: 1736 void DoExecute(Args &command, CommandReturnObject &result) override { 1737 1738 llvm::StringRef root_cmd = command[0].ref(); 1739 size_t num_args = command.GetArgumentCount(); 1740 1741 if (root_cmd.empty()) { 1742 result.AppendErrorWithFormat("empty root command name"); 1743 return; 1744 } 1745 if (!m_interpreter.HasUserCommands() && 1746 !m_interpreter.HasUserMultiwordCommands()) { 1747 result.AppendErrorWithFormat("can only delete user defined commands, " 1748 "but no user defined commands found"); 1749 return; 1750 } 1751 1752 CommandObjectSP cmd_sp = m_interpreter.GetCommandSPExact(root_cmd); 1753 if (!cmd_sp) { 1754 result.AppendErrorWithFormat("command '%s' not found.", 1755 command[0].c_str()); 1756 return; 1757 } 1758 if (!cmd_sp->IsUserCommand()) { 1759 result.AppendErrorWithFormat("command '%s' is not a user command.", 1760 command[0].c_str()); 1761 return; 1762 } 1763 if (cmd_sp->GetAsMultiwordCommand() && num_args == 1) { 1764 result.AppendErrorWithFormat("command '%s' is a multi-word command.\n " 1765 "Delete with \"command container delete\"", 1766 command[0].c_str()); 1767 return; 1768 } 1769 1770 if (command.GetArgumentCount() == 1) { 1771 m_interpreter.RemoveUser(root_cmd); 1772 result.SetStatus(eReturnStatusSuccessFinishResult); 1773 return; 1774 } 1775 // We're deleting a command from a multiword command. Verify the command 1776 // path: 1777 Status error; 1778 CommandObjectMultiword *container = 1779 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 1780 error); 1781 if (error.Fail()) { 1782 result.AppendErrorWithFormat("could not resolve command path: %s", 1783 error.AsCString()); 1784 return; 1785 } 1786 if (!container) { 1787 // This means that command only had a leaf command, so the container is 1788 // the root. That should have been handled above. 1789 result.AppendErrorWithFormat("could not find a container for '%s'", 1790 command[0].c_str()); 1791 return; 1792 } 1793 const char *leaf_cmd = command[num_args - 1].c_str(); 1794 llvm::Error llvm_error = 1795 container->RemoveUserSubcommand(leaf_cmd, 1796 /* multiword not okay */ false); 1797 if (llvm_error) { 1798 result.AppendErrorWithFormat( 1799 "could not delete command '%s': %s", leaf_cmd, 1800 llvm::toString(std::move(llvm_error)).c_str()); 1801 return; 1802 } 1803 1804 Stream &out_stream = result.GetOutputStream(); 1805 1806 out_stream << "Deleted command:"; 1807 for (size_t idx = 0; idx < num_args; idx++) { 1808 out_stream << ' '; 1809 out_stream << command[idx].c_str(); 1810 } 1811 out_stream << '\n'; 1812 result.SetStatus(eReturnStatusSuccessFinishResult); 1813 } 1814 }; 1815 1816 #pragma mark CommandObjectMultiwordCommandsScript 1817 1818 // CommandObjectMultiwordCommandsScript 1819 1820 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword { 1821 public: 1822 CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter) 1823 : CommandObjectMultiword( 1824 interpreter, "command script", 1825 "Commands for managing custom " 1826 "commands implemented by " 1827 "interpreter scripts.", 1828 "command script <subcommand> [<subcommand-options>]") { 1829 LoadSubCommand("add", CommandObjectSP( 1830 new CommandObjectCommandsScriptAdd(interpreter))); 1831 LoadSubCommand( 1832 "delete", 1833 CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter))); 1834 LoadSubCommand( 1835 "clear", 1836 CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter))); 1837 LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList( 1838 interpreter))); 1839 LoadSubCommand( 1840 "import", 1841 CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter))); 1842 } 1843 1844 ~CommandObjectMultiwordCommandsScript() override = default; 1845 }; 1846 1847 #pragma mark CommandObjectCommandContainer 1848 #define LLDB_OPTIONS_container_add 1849 #include "CommandOptions.inc" 1850 1851 class CommandObjectCommandsContainerAdd : public CommandObjectParsed { 1852 public: 1853 CommandObjectCommandsContainerAdd(CommandInterpreter &interpreter) 1854 : CommandObjectParsed( 1855 interpreter, "command container add", 1856 "Add a container command to lldb. Adding to built-" 1857 "in container commands is not allowed.", 1858 "command container add [[path1]...] container-name") { 1859 CommandArgumentEntry arg1; 1860 CommandArgumentData cmd_arg; 1861 1862 // This is one or more command names, which form the path to the command 1863 // you want to add. 1864 cmd_arg.arg_type = eArgTypeCommand; 1865 cmd_arg.arg_repetition = eArgRepeatPlus; 1866 1867 // There is only one variant this argument could be; put it into the 1868 // argument entry. 1869 arg1.push_back(cmd_arg); 1870 1871 // Push the data for the first argument into the m_arguments vector. 1872 m_arguments.push_back(arg1); 1873 } 1874 1875 ~CommandObjectCommandsContainerAdd() override = default; 1876 1877 Options *GetOptions() override { return &m_options; } 1878 1879 void 1880 HandleArgumentCompletion(CompletionRequest &request, 1881 OptionElementVector &opt_element_vector) override { 1882 lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs( 1883 m_interpreter, request, opt_element_vector); 1884 } 1885 1886 protected: 1887 class CommandOptions : public Options { 1888 public: 1889 CommandOptions() = default; 1890 1891 ~CommandOptions() override = default; 1892 1893 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1894 ExecutionContext *execution_context) override { 1895 Status error; 1896 const int short_option = m_getopt_table[option_idx].val; 1897 1898 switch (short_option) { 1899 case 'h': 1900 if (!option_arg.empty()) 1901 m_short_help = std::string(option_arg); 1902 break; 1903 case 'o': 1904 m_overwrite = true; 1905 break; 1906 case 'H': 1907 if (!option_arg.empty()) 1908 m_long_help = std::string(option_arg); 1909 break; 1910 default: 1911 llvm_unreachable("Unimplemented option"); 1912 } 1913 1914 return error; 1915 } 1916 1917 void OptionParsingStarting(ExecutionContext *execution_context) override { 1918 m_short_help.clear(); 1919 m_long_help.clear(); 1920 m_overwrite = false; 1921 } 1922 1923 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1924 return llvm::ArrayRef(g_container_add_options); 1925 } 1926 1927 // Instance variables to hold the values for command options. 1928 1929 std::string m_short_help; 1930 std::string m_long_help; 1931 bool m_overwrite = false; 1932 }; 1933 void DoExecute(Args &command, CommandReturnObject &result) override { 1934 size_t num_args = command.GetArgumentCount(); 1935 1936 if (num_args == 0) { 1937 result.AppendError("no command was specified"); 1938 return; 1939 } 1940 1941 if (num_args == 1) { 1942 // We're adding this as a root command, so use the interpreter. 1943 const char *cmd_name = command.GetArgumentAtIndex(0); 1944 auto cmd_sp = CommandObjectSP(new CommandObjectMultiword( 1945 GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(), 1946 m_options.m_long_help.c_str())); 1947 cmd_sp->GetAsMultiwordCommand()->SetRemovable(true); 1948 Status add_error = GetCommandInterpreter().AddUserCommand( 1949 cmd_name, cmd_sp, m_options.m_overwrite); 1950 if (add_error.Fail()) { 1951 result.AppendErrorWithFormat("error adding command: %s", 1952 add_error.AsCString()); 1953 return; 1954 } 1955 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1956 return; 1957 } 1958 1959 // We're adding this to a subcommand, first find the subcommand: 1960 Status path_error; 1961 CommandObjectMultiword *add_to_me = 1962 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 1963 path_error); 1964 1965 if (!add_to_me) { 1966 result.AppendErrorWithFormat("error adding command: %s", 1967 path_error.AsCString()); 1968 return; 1969 } 1970 1971 const char *cmd_name = command.GetArgumentAtIndex(num_args - 1); 1972 auto cmd_sp = CommandObjectSP(new CommandObjectMultiword( 1973 GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(), 1974 m_options.m_long_help.c_str())); 1975 llvm::Error llvm_error = 1976 add_to_me->LoadUserSubcommand(cmd_name, cmd_sp, m_options.m_overwrite); 1977 if (llvm_error) { 1978 result.AppendErrorWithFormat("error adding subcommand: %s", 1979 llvm::toString(std::move(llvm_error)).c_str()); 1980 return; 1981 } 1982 1983 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1984 } 1985 1986 private: 1987 CommandOptions m_options; 1988 }; 1989 1990 #define LLDB_OPTIONS_multiword_delete 1991 #include "CommandOptions.inc" 1992 class CommandObjectCommandsContainerDelete : public CommandObjectParsed { 1993 public: 1994 CommandObjectCommandsContainerDelete(CommandInterpreter &interpreter) 1995 : CommandObjectParsed( 1996 interpreter, "command container delete", 1997 "Delete a container command previously added to " 1998 "lldb.", 1999 "command container delete [[path1] ...] container-cmd") { 2000 CommandArgumentEntry arg1; 2001 CommandArgumentData cmd_arg; 2002 2003 // This is one or more command names, which form the path to the command 2004 // you want to add. 2005 cmd_arg.arg_type = eArgTypeCommand; 2006 cmd_arg.arg_repetition = eArgRepeatPlus; 2007 2008 // There is only one variant this argument could be; put it into the 2009 // argument entry. 2010 arg1.push_back(cmd_arg); 2011 2012 // Push the data for the first argument into the m_arguments vector. 2013 m_arguments.push_back(arg1); 2014 } 2015 2016 ~CommandObjectCommandsContainerDelete() override = default; 2017 2018 void 2019 HandleArgumentCompletion(CompletionRequest &request, 2020 OptionElementVector &opt_element_vector) override { 2021 lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs( 2022 m_interpreter, request, opt_element_vector); 2023 } 2024 2025 protected: 2026 void DoExecute(Args &command, CommandReturnObject &result) override { 2027 size_t num_args = command.GetArgumentCount(); 2028 2029 if (num_args == 0) { 2030 result.AppendError("No command was specified."); 2031 return; 2032 } 2033 2034 if (num_args == 1) { 2035 // We're removing a root command, so we need to delete it from the 2036 // interpreter. 2037 const char *cmd_name = command.GetArgumentAtIndex(0); 2038 // Let's do a little more work here so we can do better error reporting. 2039 CommandInterpreter &interp = GetCommandInterpreter(); 2040 CommandObjectSP cmd_sp = interp.GetCommandSPExact(cmd_name); 2041 if (!cmd_sp) { 2042 result.AppendErrorWithFormat("container command %s doesn't exist.", 2043 cmd_name); 2044 return; 2045 } 2046 if (!cmd_sp->IsUserCommand()) { 2047 result.AppendErrorWithFormat( 2048 "container command %s is not a user command", cmd_name); 2049 return; 2050 } 2051 if (!cmd_sp->GetAsMultiwordCommand()) { 2052 result.AppendErrorWithFormat("command %s is not a container command", 2053 cmd_name); 2054 return; 2055 } 2056 2057 bool did_remove = GetCommandInterpreter().RemoveUserMultiword(cmd_name); 2058 if (!did_remove) { 2059 result.AppendErrorWithFormat("error removing command %s.", cmd_name); 2060 return; 2061 } 2062 2063 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2064 return; 2065 } 2066 2067 // We're removing a subcommand, first find the subcommand's owner: 2068 Status path_error; 2069 CommandObjectMultiword *container = 2070 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 2071 path_error); 2072 2073 if (!container) { 2074 result.AppendErrorWithFormat("error removing container command: %s", 2075 path_error.AsCString()); 2076 return; 2077 } 2078 const char *leaf = command.GetArgumentAtIndex(num_args - 1); 2079 llvm::Error llvm_error = 2080 container->RemoveUserSubcommand(leaf, /* multiword okay */ true); 2081 if (llvm_error) { 2082 result.AppendErrorWithFormat("error removing container command: %s", 2083 llvm::toString(std::move(llvm_error)).c_str()); 2084 return; 2085 } 2086 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2087 } 2088 }; 2089 2090 class CommandObjectCommandContainer : public CommandObjectMultiword { 2091 public: 2092 CommandObjectCommandContainer(CommandInterpreter &interpreter) 2093 : CommandObjectMultiword( 2094 interpreter, "command container", 2095 "Commands for adding container commands to lldb. " 2096 "Container commands are containers for other commands. You can " 2097 "add nested container commands by specifying a command path, " 2098 "but you can't add commands into the built-in command hierarchy.", 2099 "command container <subcommand> [<subcommand-options>]") { 2100 LoadSubCommand("add", CommandObjectSP(new CommandObjectCommandsContainerAdd( 2101 interpreter))); 2102 LoadSubCommand( 2103 "delete", 2104 CommandObjectSP(new CommandObjectCommandsContainerDelete(interpreter))); 2105 } 2106 2107 ~CommandObjectCommandContainer() override = default; 2108 }; 2109 2110 #pragma mark CommandObjectMultiwordCommands 2111 2112 // CommandObjectMultiwordCommands 2113 2114 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands( 2115 CommandInterpreter &interpreter) 2116 : CommandObjectMultiword(interpreter, "command", 2117 "Commands for managing custom LLDB commands.", 2118 "command <subcommand> [<subcommand-options>]") { 2119 LoadSubCommand("source", 2120 CommandObjectSP(new CommandObjectCommandsSource(interpreter))); 2121 LoadSubCommand("alias", 2122 CommandObjectSP(new CommandObjectCommandsAlias(interpreter))); 2123 LoadSubCommand("unalias", CommandObjectSP( 2124 new CommandObjectCommandsUnalias(interpreter))); 2125 LoadSubCommand("delete", 2126 CommandObjectSP(new CommandObjectCommandsDelete(interpreter))); 2127 LoadSubCommand("container", CommandObjectSP(new CommandObjectCommandContainer( 2128 interpreter))); 2129 LoadSubCommand( 2130 "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter))); 2131 LoadSubCommand( 2132 "script", 2133 CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter))); 2134 } 2135 2136 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default; 2137