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 29using namespace lldb; 30using namespace lldb_private; 31 32// CommandObjectCommandsSource 33 34#define LLDB_OPTIONS_source 35#include "CommandOptions.inc" 36 37class CommandObjectCommandsSource : public CommandObjectParsed { 38public: 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 75protected: 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 200static 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 205class CommandObjectCommandsAlias : public CommandObjectRaw { 206protected: 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 254public: 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 \ 266commands, multi-word commands, and commands that take particular options. \ 267Below 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 \ 278breakpoint commands are two-word commands, the user would still need to \ 279enter 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 \ 288filled in at the time the alias is created, or specified as positional \ 289arguments, to be filled in when the alias is invoked. The following example \ 290shows 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 \ 297options already part of the alias. So if the user wants to set a breakpoint \ 298by file and line without explicitly having to use the -f and -l options, the \ 299user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \ 300for the actual arguments that will be passed when the alias command is used. \ 301The number in the placeholder refers to the position/order the actual value \ 302occupies when the alias is used. All the occurrences of '%1' in the alias \ 303will be replaced with the first argument, all the occurrences of '%2' in the \ 304alias will be replaced with the second argument, and so on. This also allows \ 305actual arguments to be used multiple times within an alias (see 'process \ 306launch' example below)." 307 R"( 308 309)" 310 "Note: the positional arguments must substitute as whole words in the resultant \ 311command, 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 \ 320following 'bfl' and the actual line number value will be filled in with the second \ 321argument. 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 327This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'. 328 329Another 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 \ 338alias could be defined with that value directly in the alias as a constant, \ 339rather 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 385protected: 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 617class CommandObjectCommandsUnalias : public CommandObjectParsed { 618public: 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 652protected: 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 704class CommandObjectCommandsDelete : public CommandObjectParsed { 705public: 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 740protected: 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 781class CommandObjectCommandsAddRegex : public CommandObjectParsed, 782 public IOHandlerDelegateMultiline { 783public: 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 \ 797with substitutions. The regular expressions and substitutions are specified \ 798using 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 \ 805expression input and substitute the captured matches in the output using %1 \ 806for 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 \ 811one argument is provided. If just the command name is provided on the command \ 812line, then the regular expressions and substitutions can be entered on separate \ 813lines, followed by an empty line to terminate the command definition." 814 R"( 815 816EXAMPLES 817 818)" 819 "The following example will define a regular expression command named 'f' that \ 820will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \ 821a 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 831protected: 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 1018private: 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 1071class CommandObjectPythonFunction : public CommandObjectRaw { 1072public: 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 1121protected: 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 1145private: 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 1152class CommandObjectScriptingObject : public CommandObjectRaw { 1153public: 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 1215protected: 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 1239private: 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 1251class CommandObjectCommandsScriptImport : public CommandObjectParsed { 1252public: 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 1282protected: 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 1371class CommandObjectCommandsScriptAdd : public CommandObjectParsed, 1372 public IOHandlerDelegateMultiline { 1373public: 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 1412protected: 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 1664class CommandObjectCommandsScriptList : public CommandObjectParsed { 1665public: 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 1682class CommandObjectCommandsScriptClear : public CommandObjectParsed { 1683public: 1684 CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) 1685 : CommandObjectParsed(interpreter, "command script clear", 1686 "Delete all scripted commands.", nullptr) {} 1687 1688 ~CommandObjectCommandsScriptClear() override = default; 1689 1690protected: 1691 void DoExecute(Args &command, CommandReturnObject &result) override { 1692 m_interpreter.RemoveAllUser(); 1693 1694 result.SetStatus(eReturnStatusSuccessFinishResult); 1695 } 1696}; 1697 1698// CommandObjectCommandsScriptDelete 1699 1700class CommandObjectCommandsScriptDelete : public CommandObjectParsed { 1701public: 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 1732protected: 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 1816class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword { 1817public: 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 1847class CommandObjectCommandsContainerAdd : public CommandObjectParsed { 1848public: 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 1882protected: 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 1982private: 1983 CommandOptions m_options; 1984}; 1985 1986#define LLDB_OPTIONS_multiword_delete 1987#include "CommandOptions.inc" 1988class CommandObjectCommandsContainerDelete : public CommandObjectParsed { 1989public: 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 2021protected: 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 2086class CommandObjectCommandContainer : public CommandObjectMultiword { 2087public: 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 2110CommandObjectMultiwordCommands::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 2132CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default; 2133