1 //===-- CommandObjectCommands.cpp -----------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "CommandObjectCommands.h" 10 #include "CommandObjectHelp.h" 11 #include "CommandObjectRegexCommand.h" 12 #include "lldb/Core/Debugger.h" 13 #include "lldb/Core/IOHandler.h" 14 #include "lldb/Interpreter/CommandHistory.h" 15 #include "lldb/Interpreter/CommandInterpreter.h" 16 #include "lldb/Interpreter/CommandReturnObject.h" 17 #include "lldb/Interpreter/OptionArgParser.h" 18 #include "lldb/Interpreter/OptionValueBoolean.h" 19 #include "lldb/Interpreter/OptionValueString.h" 20 #include "lldb/Interpreter/OptionValueUInt64.h" 21 #include "lldb/Interpreter/Options.h" 22 #include "lldb/Interpreter/ScriptInterpreter.h" 23 #include "lldb/Utility/Args.h" 24 #include "lldb/Utility/StringList.h" 25 #include "llvm/ADT/StringRef.h" 26 27 using namespace lldb; 28 using namespace lldb_private; 29 30 // CommandObjectCommandsSource 31 32 #define LLDB_OPTIONS_source 33 #include "CommandOptions.inc" 34 35 class CommandObjectCommandsSource : public CommandObjectParsed { 36 public: 37 CommandObjectCommandsSource(CommandInterpreter &interpreter) 38 : CommandObjectParsed( 39 interpreter, "command source", 40 "Read and execute LLDB commands from the file <filename>.", 41 nullptr), 42 m_options() { 43 CommandArgumentEntry arg; 44 CommandArgumentData file_arg; 45 46 // Define the first (and only) variant of this arg. 47 file_arg.arg_type = eArgTypeFilename; 48 file_arg.arg_repetition = eArgRepeatPlain; 49 50 // There is only one variant this argument could be; put it into the 51 // argument entry. 52 arg.push_back(file_arg); 53 54 // Push the data for the first argument into the m_arguments vector. 55 m_arguments.push_back(arg); 56 } 57 58 ~CommandObjectCommandsSource() override = default; 59 60 const char *GetRepeatCommand(Args ¤t_command_args, 61 uint32_t index) override { 62 return ""; 63 } 64 65 void 66 HandleArgumentCompletion(CompletionRequest &request, 67 OptionElementVector &opt_element_vector) override { 68 CommandCompletions::InvokeCommonCompletionCallbacks( 69 GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, 70 request, nullptr); 71 } 72 73 Options *GetOptions() override { return &m_options; } 74 75 protected: 76 class CommandOptions : public Options { 77 public: 78 CommandOptions() 79 : Options(), m_stop_on_error(true), m_silent_run(false), 80 m_stop_on_continue(true), 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::makeArrayRef(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 bool 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 false; 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 false; 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 false; 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 return result.Succeeded(); 190 } 191 192 CommandOptions m_options; 193 }; 194 195 #pragma mark CommandObjectCommandsAlias 196 // CommandObjectCommandsAlias 197 198 #define LLDB_OPTIONS_alias 199 #include "CommandOptions.inc" 200 201 static const char *g_python_command_instructions = 202 "Enter your Python command(s). Type 'DONE' to end.\n" 203 "You must define a Python function with this signature:\n" 204 "def my_command_impl(debugger, args, result, internal_dict):\n"; 205 206 class CommandObjectCommandsAlias : public CommandObjectRaw { 207 protected: 208 class CommandOptions : public OptionGroup { 209 public: 210 CommandOptions() : OptionGroup(), m_help(), m_long_help() {} 211 212 ~CommandOptions() override = default; 213 214 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 215 return llvm::makeArrayRef(g_alias_options); 216 } 217 218 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, 219 ExecutionContext *execution_context) override { 220 Status error; 221 222 const int short_option = GetDefinitions()[option_idx].short_option; 223 std::string option_str(option_value); 224 225 switch (short_option) { 226 case 'h': 227 m_help.SetCurrentValue(option_str); 228 m_help.SetOptionWasSet(); 229 break; 230 231 case 'H': 232 m_long_help.SetCurrentValue(option_str); 233 m_long_help.SetOptionWasSet(); 234 break; 235 236 default: 237 llvm_unreachable("Unimplemented option"); 238 } 239 240 return error; 241 } 242 243 void OptionParsingStarting(ExecutionContext *execution_context) override { 244 m_help.Clear(); 245 m_long_help.Clear(); 246 } 247 248 OptionValueString m_help; 249 OptionValueString m_long_help; 250 }; 251 252 OptionGroupOptions m_option_group; 253 CommandOptions m_command_options; 254 255 public: 256 Options *GetOptions() override { return &m_option_group; } 257 258 CommandObjectCommandsAlias(CommandInterpreter &interpreter) 259 : CommandObjectRaw( 260 interpreter, "command alias", 261 "Define a custom command in terms of an existing command."), 262 m_option_group(), m_command_options() { 263 m_option_group.Append(&m_command_options); 264 m_option_group.Finalize(); 265 266 SetHelpLong( 267 "'alias' allows the user to create a short-cut or abbreviation for long \ 268 commands, multi-word commands, and commands that take particular options. \ 269 Below are some simple examples of how one might use the 'alias' command:" 270 R"( 271 272 (lldb) command alias sc script 273 274 Creates the abbreviation 'sc' for the 'script' command. 275 276 (lldb) command alias bp breakpoint 277 278 )" 279 " Creates the abbreviation 'bp' for the 'breakpoint' command. Since \ 280 breakpoint commands are two-word commands, the user would still need to \ 281 enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'." 282 R"( 283 284 (lldb) command alias bpl breakpoint list 285 286 Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'. 287 288 )" 289 "An alias can include some options for the command, with the values either \ 290 filled in at the time the alias is created, or specified as positional \ 291 arguments, to be filled in when the alias is invoked. The following example \ 292 shows how to create aliases with options:" 293 R"( 294 295 (lldb) command alias bfl breakpoint set -f %1 -l %2 296 297 )" 298 " Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \ 299 options already part of the alias. So if the user wants to set a breakpoint \ 300 by file and line without explicitly having to use the -f and -l options, the \ 301 user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \ 302 for the actual arguments that will be passed when the alias command is used. \ 303 The number in the placeholder refers to the position/order the actual value \ 304 occupies when the alias is used. All the occurrences of '%1' in the alias \ 305 will be replaced with the first argument, all the occurrences of '%2' in the \ 306 alias will be replaced with the second argument, and so on. This also allows \ 307 actual arguments to be used multiple times within an alias (see 'process \ 308 launch' example below)." 309 R"( 310 311 )" 312 "Note: the positional arguments must substitute as whole words in the resultant \ 313 command, so you can't at present do something like this to append the file extension \ 314 \".cpp\":" 315 R"( 316 317 (lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2 318 319 )" 320 "For more complex aliasing, use the \"command regex\" command instead. In the \ 321 'bfl' case above, the actual file value will be filled in with the first argument \ 322 following 'bfl' and the actual line number value will be filled in with the second \ 323 argument. The user would use this alias as follows:" 324 R"( 325 326 (lldb) command alias bfl breakpoint set -f %1 -l %2 327 (lldb) bfl my-file.c 137 328 329 This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'. 330 331 Another example: 332 333 (lldb) command alias pltty process launch -s -o %1 -e %1 334 (lldb) pltty /dev/tty0 335 336 Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0' 337 338 )" 339 "If the user always wanted to pass the same value to a particular option, the \ 340 alias could be defined with that value directly in the alias as a constant, \ 341 rather than using a positional placeholder:" 342 R"( 343 344 (lldb) command alias bl3 breakpoint set -f %1 -l 3 345 346 Always sets a breakpoint on line 3 of whatever file is indicated.)"); 347 348 CommandArgumentEntry arg1; 349 CommandArgumentEntry arg2; 350 CommandArgumentEntry arg3; 351 CommandArgumentData alias_arg; 352 CommandArgumentData cmd_arg; 353 CommandArgumentData options_arg; 354 355 // Define the first (and only) variant of this arg. 356 alias_arg.arg_type = eArgTypeAliasName; 357 alias_arg.arg_repetition = eArgRepeatPlain; 358 359 // There is only one variant this argument could be; put it into the 360 // argument entry. 361 arg1.push_back(alias_arg); 362 363 // Define the first (and only) variant of this arg. 364 cmd_arg.arg_type = eArgTypeCommandName; 365 cmd_arg.arg_repetition = eArgRepeatPlain; 366 367 // There is only one variant this argument could be; put it into the 368 // argument entry. 369 arg2.push_back(cmd_arg); 370 371 // Define the first (and only) variant of this arg. 372 options_arg.arg_type = eArgTypeAliasOptions; 373 options_arg.arg_repetition = eArgRepeatOptional; 374 375 // There is only one variant this argument could be; put it into the 376 // argument entry. 377 arg3.push_back(options_arg); 378 379 // Push the data for the first argument into the m_arguments vector. 380 m_arguments.push_back(arg1); 381 m_arguments.push_back(arg2); 382 m_arguments.push_back(arg3); 383 } 384 385 ~CommandObjectCommandsAlias() override = default; 386 387 protected: 388 bool DoExecute(llvm::StringRef raw_command_line, 389 CommandReturnObject &result) override { 390 if (raw_command_line.empty()) { 391 result.AppendError("'command alias' requires at least two arguments"); 392 return false; 393 } 394 395 ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext(); 396 m_option_group.NotifyOptionParsingStarting(&exe_ctx); 397 398 OptionsWithRaw args_with_suffix(raw_command_line); 399 400 if (args_with_suffix.HasArgs()) 401 if (!ParseOptionsAndNotify(args_with_suffix.GetArgs(), result, 402 m_option_group, exe_ctx)) 403 return false; 404 405 llvm::StringRef raw_command_string = args_with_suffix.GetRawPart(); 406 Args args(raw_command_string); 407 408 if (args.GetArgumentCount() < 2) { 409 result.AppendError("'command alias' requires at least two arguments"); 410 return false; 411 } 412 413 // Get the alias command. 414 415 auto alias_command = args[0].ref(); 416 if (alias_command.startswith("-")) { 417 result.AppendError("aliases starting with a dash are not supported"); 418 if (alias_command == "--help" || alias_command == "--long-help") { 419 result.AppendWarning("if trying to pass options to 'command alias' add " 420 "a -- at the end of the options"); 421 } 422 return false; 423 } 424 425 // Strip the new alias name off 'raw_command_string' (leave it on args, 426 // which gets passed to 'Execute', which does the stripping itself. 427 size_t pos = raw_command_string.find(alias_command); 428 if (pos == 0) { 429 raw_command_string = raw_command_string.substr(alias_command.size()); 430 pos = raw_command_string.find_first_not_of(' '); 431 if ((pos != std::string::npos) && (pos > 0)) 432 raw_command_string = raw_command_string.substr(pos); 433 } else { 434 result.AppendError("Error parsing command string. No alias created."); 435 return false; 436 } 437 438 // Verify that the command is alias-able. 439 if (m_interpreter.CommandExists(alias_command)) { 440 result.AppendErrorWithFormat( 441 "'%s' is a permanent debugger command and cannot be redefined.\n", 442 args[0].c_str()); 443 return false; 444 } 445 446 if (m_interpreter.UserMultiwordCommandExists(alias_command)) { 447 result.AppendErrorWithFormat( 448 "'%s' is a user container command and cannot be overwritten.\n" 449 "Delete it first with 'command container delete'\n", 450 args[0].c_str()); 451 return false; 452 } 453 454 // Get CommandObject that is being aliased. The command name is read from 455 // the front of raw_command_string. raw_command_string is returned with the 456 // name of the command object stripped off the front. 457 llvm::StringRef original_raw_command_string = raw_command_string; 458 CommandObject *cmd_obj = 459 m_interpreter.GetCommandObjectForCommand(raw_command_string); 460 461 if (!cmd_obj) { 462 result.AppendErrorWithFormat("invalid command given to 'command alias'. " 463 "'%s' does not begin with a valid command." 464 " No alias created.", 465 original_raw_command_string.str().c_str()); 466 return false; 467 } else if (!cmd_obj->WantsRawCommandString()) { 468 // Note that args was initialized with the original command, and has not 469 // been updated to this point. Therefore can we pass it to the version of 470 // Execute that does not need/expect raw input in the alias. 471 return HandleAliasingNormalCommand(args, result); 472 } else { 473 return HandleAliasingRawCommand(alias_command, raw_command_string, 474 *cmd_obj, result); 475 } 476 return result.Succeeded(); 477 } 478 479 bool HandleAliasingRawCommand(llvm::StringRef alias_command, 480 llvm::StringRef raw_command_string, 481 CommandObject &cmd_obj, 482 CommandReturnObject &result) { 483 // Verify & handle any options/arguments passed to the alias command 484 485 OptionArgVectorSP option_arg_vector_sp = 486 OptionArgVectorSP(new OptionArgVector); 487 488 const bool include_aliases = true; 489 if (CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact( 490 cmd_obj.GetCommandName(), include_aliases)) { 491 if (m_interpreter.AliasExists(alias_command) || 492 m_interpreter.UserCommandExists(alias_command)) { 493 result.AppendWarningWithFormat( 494 "Overwriting existing definition for '%s'.\n", 495 alias_command.str().c_str()); 496 } 497 if (CommandAlias *alias = m_interpreter.AddAlias( 498 alias_command, cmd_obj_sp, raw_command_string)) { 499 if (m_command_options.m_help.OptionWasSet()) 500 alias->SetHelp(m_command_options.m_help.GetCurrentValue()); 501 if (m_command_options.m_long_help.OptionWasSet()) 502 alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue()); 503 result.SetStatus(eReturnStatusSuccessFinishNoResult); 504 } else { 505 result.AppendError("Unable to create requested alias.\n"); 506 } 507 508 } else { 509 result.AppendError("Unable to create requested alias.\n"); 510 } 511 512 return result.Succeeded(); 513 } 514 515 bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) { 516 size_t argc = args.GetArgumentCount(); 517 518 if (argc < 2) { 519 result.AppendError("'command alias' requires at least two arguments"); 520 return false; 521 } 522 523 // Save these in std::strings since we're going to shift them off. 524 const std::string alias_command(std::string(args[0].ref())); 525 const std::string actual_command(std::string(args[1].ref())); 526 527 args.Shift(); // Shift the alias command word off the argument vector. 528 args.Shift(); // Shift the old command word off the argument vector. 529 530 // Verify that the command is alias'able, and get the appropriate command 531 // object. 532 533 if (m_interpreter.CommandExists(alias_command)) { 534 result.AppendErrorWithFormat( 535 "'%s' is a permanent debugger command and cannot be redefined.\n", 536 alias_command.c_str()); 537 return false; 538 } 539 540 if (m_interpreter.UserMultiwordCommandExists(alias_command)) { 541 result.AppendErrorWithFormat( 542 "'%s' is user container command and cannot be overwritten.\n" 543 "Delete it first with 'command container delete'", 544 alias_command.c_str()); 545 return false; 546 } 547 548 CommandObjectSP command_obj_sp( 549 m_interpreter.GetCommandSPExact(actual_command, true)); 550 CommandObjectSP subcommand_obj_sp; 551 bool use_subcommand = false; 552 if (!command_obj_sp) { 553 result.AppendErrorWithFormat("'%s' is not an existing command.\n", 554 actual_command.c_str()); 555 return false; 556 } 557 CommandObject *cmd_obj = command_obj_sp.get(); 558 CommandObject *sub_cmd_obj = nullptr; 559 OptionArgVectorSP option_arg_vector_sp = 560 OptionArgVectorSP(new OptionArgVector); 561 562 while (cmd_obj->IsMultiwordObject() && !args.empty()) { 563 auto sub_command = args[0].ref(); 564 assert(!sub_command.empty()); 565 subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command); 566 if (!subcommand_obj_sp) { 567 result.AppendErrorWithFormat( 568 "'%s' is not a valid sub-command of '%s'. " 569 "Unable to create alias.\n", 570 args[0].c_str(), actual_command.c_str()); 571 return false; 572 } 573 574 sub_cmd_obj = subcommand_obj_sp.get(); 575 use_subcommand = true; 576 args.Shift(); // Shift the sub_command word off the argument vector. 577 cmd_obj = sub_cmd_obj; 578 } 579 580 // Verify & handle any options/arguments passed to the alias command 581 582 std::string args_string; 583 584 if (!args.empty()) { 585 CommandObjectSP tmp_sp = 586 m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName()); 587 if (use_subcommand) 588 tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName()); 589 590 args.GetCommandString(args_string); 591 } 592 593 if (m_interpreter.AliasExists(alias_command) || 594 m_interpreter.UserCommandExists(alias_command)) { 595 result.AppendWarningWithFormat( 596 "Overwriting existing definition for '%s'.\n", alias_command.c_str()); 597 } 598 599 if (CommandAlias *alias = m_interpreter.AddAlias( 600 alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp, 601 args_string)) { 602 if (m_command_options.m_help.OptionWasSet()) 603 alias->SetHelp(m_command_options.m_help.GetCurrentValue()); 604 if (m_command_options.m_long_help.OptionWasSet()) 605 alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue()); 606 result.SetStatus(eReturnStatusSuccessFinishNoResult); 607 } else { 608 result.AppendError("Unable to create requested alias.\n"); 609 return false; 610 } 611 612 return result.Succeeded(); 613 } 614 }; 615 616 #pragma mark CommandObjectCommandsUnalias 617 // CommandObjectCommandsUnalias 618 619 class CommandObjectCommandsUnalias : public CommandObjectParsed { 620 public: 621 CommandObjectCommandsUnalias(CommandInterpreter &interpreter) 622 : CommandObjectParsed( 623 interpreter, "command unalias", 624 "Delete one or more custom commands defined by 'command alias'.", 625 nullptr) { 626 CommandArgumentEntry arg; 627 CommandArgumentData alias_arg; 628 629 // Define the first (and only) variant of this arg. 630 alias_arg.arg_type = eArgTypeAliasName; 631 alias_arg.arg_repetition = eArgRepeatPlain; 632 633 // There is only one variant this argument could be; put it into the 634 // argument entry. 635 arg.push_back(alias_arg); 636 637 // Push the data for the first argument into the m_arguments vector. 638 m_arguments.push_back(arg); 639 } 640 641 ~CommandObjectCommandsUnalias() override = default; 642 643 void 644 HandleArgumentCompletion(CompletionRequest &request, 645 OptionElementVector &opt_element_vector) override { 646 if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0) 647 return; 648 649 for (const auto &ent : m_interpreter.GetAliases()) { 650 request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp()); 651 } 652 } 653 654 protected: 655 bool DoExecute(Args &args, CommandReturnObject &result) override { 656 CommandObject::CommandMap::iterator pos; 657 CommandObject *cmd_obj; 658 659 if (args.empty()) { 660 result.AppendError("must call 'unalias' with a valid alias"); 661 return false; 662 } 663 664 auto command_name = args[0].ref(); 665 cmd_obj = m_interpreter.GetCommandObject(command_name); 666 if (!cmd_obj) { 667 result.AppendErrorWithFormat( 668 "'%s' is not a known command.\nTry 'help' to see a " 669 "current list of commands.\n", 670 args[0].c_str()); 671 return false; 672 } 673 674 if (m_interpreter.CommandExists(command_name)) { 675 if (cmd_obj->IsRemovable()) { 676 result.AppendErrorWithFormat( 677 "'%s' is not an alias, it is a debugger command which can be " 678 "removed using the 'command delete' command.\n", 679 args[0].c_str()); 680 } else { 681 result.AppendErrorWithFormat( 682 "'%s' is a permanent debugger command and cannot be removed.\n", 683 args[0].c_str()); 684 } 685 return false; 686 } 687 688 if (!m_interpreter.RemoveAlias(command_name)) { 689 if (m_interpreter.AliasExists(command_name)) 690 result.AppendErrorWithFormat( 691 "Error occurred while attempting to unalias '%s'.\n", 692 args[0].c_str()); 693 else 694 result.AppendErrorWithFormat("'%s' is not an existing alias.\n", 695 args[0].c_str()); 696 return false; 697 } 698 699 result.SetStatus(eReturnStatusSuccessFinishNoResult); 700 return result.Succeeded(); 701 } 702 }; 703 704 #pragma mark CommandObjectCommandsDelete 705 // CommandObjectCommandsDelete 706 707 class CommandObjectCommandsDelete : public CommandObjectParsed { 708 public: 709 CommandObjectCommandsDelete(CommandInterpreter &interpreter) 710 : CommandObjectParsed( 711 interpreter, "command delete", 712 "Delete one or more custom commands defined by 'command regex'.", 713 nullptr) { 714 CommandArgumentEntry arg; 715 CommandArgumentData alias_arg; 716 717 // Define the first (and only) variant of this arg. 718 alias_arg.arg_type = eArgTypeCommandName; 719 alias_arg.arg_repetition = eArgRepeatPlain; 720 721 // There is only one variant this argument could be; put it into the 722 // argument entry. 723 arg.push_back(alias_arg); 724 725 // Push the data for the first argument into the m_arguments vector. 726 m_arguments.push_back(arg); 727 } 728 729 ~CommandObjectCommandsDelete() override = default; 730 731 void 732 HandleArgumentCompletion(CompletionRequest &request, 733 OptionElementVector &opt_element_vector) override { 734 if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0) 735 return; 736 737 for (const auto &ent : m_interpreter.GetCommands()) { 738 if (ent.second->IsRemovable()) 739 request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp()); 740 } 741 } 742 743 protected: 744 bool DoExecute(Args &args, CommandReturnObject &result) override { 745 CommandObject::CommandMap::iterator pos; 746 747 if (args.empty()) { 748 result.AppendErrorWithFormat("must call '%s' with one or more valid user " 749 "defined regular expression command names", 750 GetCommandName().str().c_str()); 751 return false; 752 } 753 754 auto command_name = args[0].ref(); 755 if (!m_interpreter.CommandExists(command_name)) { 756 StreamString error_msg_stream; 757 const bool generate_upropos = true; 758 const bool generate_type_lookup = false; 759 CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage( 760 &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(), 761 generate_upropos, generate_type_lookup); 762 result.AppendError(error_msg_stream.GetString()); 763 return false; 764 } 765 766 if (!m_interpreter.RemoveCommand(command_name)) { 767 result.AppendErrorWithFormat( 768 "'%s' is a permanent debugger command and cannot be removed.\n", 769 args[0].c_str()); 770 return false; 771 } 772 773 result.SetStatus(eReturnStatusSuccessFinishNoResult); 774 return true; 775 } 776 }; 777 778 // CommandObjectCommandsAddRegex 779 780 #define LLDB_OPTIONS_regex 781 #include "CommandOptions.inc" 782 783 #pragma mark CommandObjectCommandsAddRegex 784 785 class CommandObjectCommandsAddRegex : public CommandObjectParsed, 786 public IOHandlerDelegateMultiline { 787 public: 788 CommandObjectCommandsAddRegex(CommandInterpreter &interpreter) 789 : CommandObjectParsed( 790 interpreter, "command regex", 791 "Define a custom command in terms of " 792 "existing commands by matching " 793 "regular expressions.", 794 "command regex <cmd-name> [s/<regex>/<subst>/ ...]"), 795 IOHandlerDelegateMultiline("", 796 IOHandlerDelegate::Completion::LLDBCommand), 797 m_options() { 798 SetHelpLong( 799 R"( 800 )" 801 "This command allows the user to create powerful regular expression commands \ 802 with substitutions. The regular expressions and substitutions are specified \ 803 using the regular expression substitution format of:" 804 R"( 805 806 s/<regex>/<subst>/ 807 808 )" 809 "<regex> is a regular expression that can use parenthesis to capture regular \ 810 expression input and substitute the captured matches in the output using %1 \ 811 for the first match, %2 for the second, and so on." 812 R"( 813 814 )" 815 "The regular expressions can all be specified on the command line if more than \ 816 one argument is provided. If just the command name is provided on the command \ 817 line, then the regular expressions and substitutions can be entered on separate \ 818 lines, followed by an empty line to terminate the command definition." 819 R"( 820 821 EXAMPLES 822 823 )" 824 "The following example will define a regular expression command named 'f' that \ 825 will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \ 826 a number follows 'f':" 827 R"( 828 829 (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')"); 830 } 831 832 ~CommandObjectCommandsAddRegex() override = default; 833 834 protected: 835 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 836 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); 837 if (output_sp && interactive) { 838 output_sp->PutCString("Enter one or more sed substitution commands in " 839 "the form: 's/<regex>/<subst>/'.\nTerminate the " 840 "substitution list with an empty line.\n"); 841 output_sp->Flush(); 842 } 843 } 844 845 void IOHandlerInputComplete(IOHandler &io_handler, 846 std::string &data) override { 847 io_handler.SetIsDone(true); 848 if (m_regex_cmd_up) { 849 StringList lines; 850 if (lines.SplitIntoLines(data)) { 851 bool check_only = false; 852 for (const std::string &line : lines) { 853 Status error = AppendRegexSubstitution(line, check_only); 854 if (error.Fail()) { 855 if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) { 856 StreamSP out_stream = GetDebugger().GetAsyncOutputStream(); 857 out_stream->Printf("error: %s\n", error.AsCString()); 858 } 859 } 860 } 861 } 862 if (m_regex_cmd_up->HasRegexEntries()) { 863 CommandObjectSP cmd_sp(m_regex_cmd_up.release()); 864 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 865 } 866 } 867 } 868 869 bool DoExecute(Args &command, CommandReturnObject &result) override { 870 const size_t argc = command.GetArgumentCount(); 871 if (argc == 0) { 872 result.AppendError("usage: 'command regex <command-name> " 873 "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n"); 874 return false; 875 } 876 877 Status error; 878 auto name = command[0].ref(); 879 m_regex_cmd_up = std::make_unique<CommandObjectRegexCommand>( 880 m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 10, 0, 881 true); 882 883 if (argc == 1) { 884 Debugger &debugger = GetDebugger(); 885 bool color_prompt = debugger.GetUseColor(); 886 const bool multiple_lines = true; // Get multiple lines 887 IOHandlerSP io_handler_sp(new IOHandlerEditline( 888 debugger, IOHandler::Type::Other, 889 "lldb-regex", // Name of input reader for history 890 llvm::StringRef("> "), // Prompt 891 llvm::StringRef(), // Continuation prompt 892 multiple_lines, color_prompt, 893 0, // Don't show line numbers 894 *this, nullptr)); 895 896 if (io_handler_sp) { 897 debugger.RunIOHandlerAsync(io_handler_sp); 898 result.SetStatus(eReturnStatusSuccessFinishNoResult); 899 } 900 } else { 901 for (auto &entry : command.entries().drop_front()) { 902 bool check_only = false; 903 error = AppendRegexSubstitution(entry.ref(), check_only); 904 if (error.Fail()) 905 break; 906 } 907 908 if (error.Success()) { 909 AddRegexCommandToInterpreter(); 910 } 911 } 912 if (error.Fail()) { 913 result.AppendError(error.AsCString()); 914 } 915 916 return result.Succeeded(); 917 } 918 919 Status AppendRegexSubstitution(const llvm::StringRef ®ex_sed, 920 bool check_only) { 921 Status error; 922 923 if (!m_regex_cmd_up) { 924 error.SetErrorStringWithFormat( 925 "invalid regular expression command object for: '%.*s'", 926 (int)regex_sed.size(), regex_sed.data()); 927 return error; 928 } 929 930 size_t regex_sed_size = regex_sed.size(); 931 932 if (regex_sed_size <= 1) { 933 error.SetErrorStringWithFormat( 934 "regular expression substitution string is too short: '%.*s'", 935 (int)regex_sed.size(), regex_sed.data()); 936 return error; 937 } 938 939 if (regex_sed[0] != 's') { 940 error.SetErrorStringWithFormat("regular expression substitution string " 941 "doesn't start with 's': '%.*s'", 942 (int)regex_sed.size(), regex_sed.data()); 943 return error; 944 } 945 const size_t first_separator_char_pos = 1; 946 // use the char that follows 's' as the regex separator character so we can 947 // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|" 948 const char separator_char = regex_sed[first_separator_char_pos]; 949 const size_t second_separator_char_pos = 950 regex_sed.find(separator_char, first_separator_char_pos + 1); 951 952 if (second_separator_char_pos == std::string::npos) { 953 error.SetErrorStringWithFormat( 954 "missing second '%c' separator char after '%.*s' in '%.*s'", 955 separator_char, 956 (int)(regex_sed.size() - first_separator_char_pos - 1), 957 regex_sed.data() + (first_separator_char_pos + 1), 958 (int)regex_sed.size(), regex_sed.data()); 959 return error; 960 } 961 962 const size_t third_separator_char_pos = 963 regex_sed.find(separator_char, second_separator_char_pos + 1); 964 965 if (third_separator_char_pos == std::string::npos) { 966 error.SetErrorStringWithFormat( 967 "missing third '%c' separator char after '%.*s' in '%.*s'", 968 separator_char, 969 (int)(regex_sed.size() - second_separator_char_pos - 1), 970 regex_sed.data() + (second_separator_char_pos + 1), 971 (int)regex_sed.size(), regex_sed.data()); 972 return error; 973 } 974 975 if (third_separator_char_pos != regex_sed_size - 1) { 976 // Make sure that everything that follows the last regex separator char 977 if (regex_sed.find_first_not_of("\t\n\v\f\r ", 978 third_separator_char_pos + 1) != 979 std::string::npos) { 980 error.SetErrorStringWithFormat( 981 "extra data found after the '%.*s' regular expression substitution " 982 "string: '%.*s'", 983 (int)third_separator_char_pos + 1, regex_sed.data(), 984 (int)(regex_sed.size() - third_separator_char_pos - 1), 985 regex_sed.data() + (third_separator_char_pos + 1)); 986 return error; 987 } 988 } else if (first_separator_char_pos + 1 == second_separator_char_pos) { 989 error.SetErrorStringWithFormat( 990 "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 991 separator_char, separator_char, separator_char, (int)regex_sed.size(), 992 regex_sed.data()); 993 return error; 994 } else if (second_separator_char_pos + 1 == third_separator_char_pos) { 995 error.SetErrorStringWithFormat( 996 "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 997 separator_char, separator_char, separator_char, (int)regex_sed.size(), 998 regex_sed.data()); 999 return error; 1000 } 1001 1002 if (!check_only) { 1003 std::string regex(std::string(regex_sed.substr( 1004 first_separator_char_pos + 1, 1005 second_separator_char_pos - first_separator_char_pos - 1))); 1006 std::string subst(std::string(regex_sed.substr( 1007 second_separator_char_pos + 1, 1008 third_separator_char_pos - second_separator_char_pos - 1))); 1009 m_regex_cmd_up->AddRegexCommand(regex, subst); 1010 } 1011 return error; 1012 } 1013 1014 void AddRegexCommandToInterpreter() { 1015 if (m_regex_cmd_up) { 1016 if (m_regex_cmd_up->HasRegexEntries()) { 1017 CommandObjectSP cmd_sp(m_regex_cmd_up.release()); 1018 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 1019 } 1020 } 1021 } 1022 1023 private: 1024 std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up; 1025 1026 class CommandOptions : public Options { 1027 public: 1028 CommandOptions() : Options() {} 1029 1030 ~CommandOptions() override = default; 1031 1032 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1033 ExecutionContext *execution_context) override { 1034 Status error; 1035 const int short_option = m_getopt_table[option_idx].val; 1036 1037 switch (short_option) { 1038 case 'h': 1039 m_help.assign(std::string(option_arg)); 1040 break; 1041 case 's': 1042 m_syntax.assign(std::string(option_arg)); 1043 break; 1044 default: 1045 llvm_unreachable("Unimplemented option"); 1046 } 1047 1048 return error; 1049 } 1050 1051 void OptionParsingStarting(ExecutionContext *execution_context) override { 1052 m_help.clear(); 1053 m_syntax.clear(); 1054 } 1055 1056 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1057 return llvm::makeArrayRef(g_regex_options); 1058 } 1059 1060 llvm::StringRef GetHelp() { return m_help; } 1061 1062 llvm::StringRef GetSyntax() { return m_syntax; } 1063 1064 protected: 1065 // Instance variables to hold the values for command options. 1066 1067 std::string m_help; 1068 std::string m_syntax; 1069 }; 1070 1071 Options *GetOptions() override { return &m_options; } 1072 1073 CommandOptions m_options; 1074 }; 1075 1076 class CommandObjectPythonFunction : public CommandObjectRaw { 1077 public: 1078 CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name, 1079 std::string funct, std::string help, 1080 ScriptedCommandSynchronicity synch) 1081 : CommandObjectRaw(interpreter, name), m_function_name(funct), 1082 m_synchro(synch), m_fetched_help_long(false) { 1083 if (!help.empty()) 1084 SetHelp(help); 1085 else { 1086 StreamString stream; 1087 stream.Printf("For more information run 'help %s'", name.c_str()); 1088 SetHelp(stream.GetString()); 1089 } 1090 } 1091 1092 ~CommandObjectPythonFunction() override = default; 1093 1094 bool IsRemovable() const override { return true; } 1095 1096 const std::string &GetFunctionName() { return m_function_name; } 1097 1098 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1099 1100 llvm::StringRef GetHelpLong() override { 1101 if (m_fetched_help_long) 1102 return CommandObjectRaw::GetHelpLong(); 1103 1104 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1105 if (!scripter) 1106 return CommandObjectRaw::GetHelpLong(); 1107 1108 std::string docstring; 1109 m_fetched_help_long = 1110 scripter->GetDocumentationForItem(m_function_name.c_str(), docstring); 1111 if (!docstring.empty()) 1112 SetHelpLong(docstring); 1113 return CommandObjectRaw::GetHelpLong(); 1114 } 1115 1116 protected: 1117 bool DoExecute(llvm::StringRef raw_command_line, 1118 CommandReturnObject &result) override { 1119 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1120 1121 Status error; 1122 1123 result.SetStatus(eReturnStatusInvalid); 1124 1125 if (!scripter || !scripter->RunScriptBasedCommand( 1126 m_function_name.c_str(), raw_command_line, m_synchro, 1127 result, error, m_exe_ctx)) { 1128 result.AppendError(error.AsCString()); 1129 } else { 1130 // Don't change the status if the command already set it... 1131 if (result.GetStatus() == eReturnStatusInvalid) { 1132 if (result.GetOutputData().empty()) 1133 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1134 else 1135 result.SetStatus(eReturnStatusSuccessFinishResult); 1136 } 1137 } 1138 1139 return result.Succeeded(); 1140 } 1141 1142 private: 1143 std::string m_function_name; 1144 ScriptedCommandSynchronicity m_synchro; 1145 bool m_fetched_help_long; 1146 }; 1147 1148 class CommandObjectScriptingObject : public CommandObjectRaw { 1149 public: 1150 CommandObjectScriptingObject(CommandInterpreter &interpreter, 1151 std::string name, 1152 StructuredData::GenericSP cmd_obj_sp, 1153 ScriptedCommandSynchronicity synch) 1154 : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp), 1155 m_synchro(synch), m_fetched_help_short(false), 1156 m_fetched_help_long(false) { 1157 StreamString stream; 1158 stream.Printf("For more information run 'help %s'", name.c_str()); 1159 SetHelp(stream.GetString()); 1160 if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter()) 1161 GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); 1162 } 1163 1164 ~CommandObjectScriptingObject() override = default; 1165 1166 bool IsRemovable() const override { return true; } 1167 1168 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1169 1170 llvm::StringRef GetHelp() override { 1171 if (m_fetched_help_short) 1172 return CommandObjectRaw::GetHelp(); 1173 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1174 if (!scripter) 1175 return CommandObjectRaw::GetHelp(); 1176 std::string docstring; 1177 m_fetched_help_short = 1178 scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring); 1179 if (!docstring.empty()) 1180 SetHelp(docstring); 1181 1182 return CommandObjectRaw::GetHelp(); 1183 } 1184 1185 llvm::StringRef GetHelpLong() override { 1186 if (m_fetched_help_long) 1187 return CommandObjectRaw::GetHelpLong(); 1188 1189 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1190 if (!scripter) 1191 return CommandObjectRaw::GetHelpLong(); 1192 1193 std::string docstring; 1194 m_fetched_help_long = 1195 scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring); 1196 if (!docstring.empty()) 1197 SetHelpLong(docstring); 1198 return CommandObjectRaw::GetHelpLong(); 1199 } 1200 1201 protected: 1202 bool DoExecute(llvm::StringRef raw_command_line, 1203 CommandReturnObject &result) override { 1204 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1205 1206 Status error; 1207 1208 result.SetStatus(eReturnStatusInvalid); 1209 1210 if (!scripter || 1211 !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line, 1212 m_synchro, result, error, m_exe_ctx)) { 1213 result.AppendError(error.AsCString()); 1214 } else { 1215 // Don't change the status if the command already set it... 1216 if (result.GetStatus() == eReturnStatusInvalid) { 1217 if (result.GetOutputData().empty()) 1218 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1219 else 1220 result.SetStatus(eReturnStatusSuccessFinishResult); 1221 } 1222 } 1223 1224 return result.Succeeded(); 1225 } 1226 1227 private: 1228 StructuredData::GenericSP m_cmd_obj_sp; 1229 ScriptedCommandSynchronicity m_synchro; 1230 bool m_fetched_help_short : 1; 1231 bool m_fetched_help_long : 1; 1232 }; 1233 1234 // CommandObjectCommandsScriptImport 1235 #define LLDB_OPTIONS_script_import 1236 #include "CommandOptions.inc" 1237 1238 class CommandObjectCommandsScriptImport : public CommandObjectParsed { 1239 public: 1240 CommandObjectCommandsScriptImport(CommandInterpreter &interpreter) 1241 : CommandObjectParsed(interpreter, "command script import", 1242 "Import a scripting module in LLDB.", nullptr), 1243 m_options() { 1244 CommandArgumentEntry arg1; 1245 CommandArgumentData cmd_arg; 1246 1247 // Define the first (and only) variant of this arg. 1248 cmd_arg.arg_type = eArgTypeFilename; 1249 cmd_arg.arg_repetition = eArgRepeatPlus; 1250 1251 // There is only one variant this argument could be; put it into the 1252 // argument entry. 1253 arg1.push_back(cmd_arg); 1254 1255 // Push the data for the first argument into the m_arguments vector. 1256 m_arguments.push_back(arg1); 1257 } 1258 1259 ~CommandObjectCommandsScriptImport() override = default; 1260 1261 void 1262 HandleArgumentCompletion(CompletionRequest &request, 1263 OptionElementVector &opt_element_vector) override { 1264 CommandCompletions::InvokeCommonCompletionCallbacks( 1265 GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, 1266 request, nullptr); 1267 } 1268 1269 Options *GetOptions() override { return &m_options; } 1270 1271 protected: 1272 class CommandOptions : public Options { 1273 public: 1274 CommandOptions() : Options() {} 1275 1276 ~CommandOptions() override = default; 1277 1278 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1279 ExecutionContext *execution_context) override { 1280 Status error; 1281 const int short_option = m_getopt_table[option_idx].val; 1282 1283 switch (short_option) { 1284 case 'r': 1285 // NO-OP 1286 break; 1287 case 'c': 1288 relative_to_command_file = true; 1289 break; 1290 case 's': 1291 silent = true; 1292 break; 1293 default: 1294 llvm_unreachable("Unimplemented option"); 1295 } 1296 1297 return error; 1298 } 1299 1300 void OptionParsingStarting(ExecutionContext *execution_context) override { 1301 relative_to_command_file = false; 1302 } 1303 1304 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1305 return llvm::makeArrayRef(g_script_import_options); 1306 } 1307 bool relative_to_command_file = false; 1308 bool silent = false; 1309 }; 1310 1311 bool DoExecute(Args &command, CommandReturnObject &result) override { 1312 if (command.empty()) { 1313 result.AppendError("command script import needs one or more arguments"); 1314 return false; 1315 } 1316 1317 FileSpec source_dir = {}; 1318 if (m_options.relative_to_command_file) { 1319 source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir(); 1320 if (!source_dir) { 1321 result.AppendError("command script import -c can only be specified " 1322 "from a command file"); 1323 return false; 1324 } 1325 } 1326 1327 for (auto &entry : command.entries()) { 1328 Status error; 1329 1330 LoadScriptOptions options; 1331 options.SetInitSession(true); 1332 options.SetSilent(m_options.silent); 1333 1334 // FIXME: this is necessary because CommandObject::CheckRequirements() 1335 // assumes that commands won't ever be recursively invoked, but it's 1336 // actually possible to craft a Python script that does other "command 1337 // script imports" in __lldb_init_module the real fix is to have 1338 // recursive commands possible with a CommandInvocation object separate 1339 // from the CommandObject itself, so that recursive command invocations 1340 // won't stomp on each other (wrt to execution contents, options, and 1341 // more) 1342 m_exe_ctx.Clear(); 1343 if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule( 1344 entry.c_str(), options, error, /*module_sp=*/nullptr, 1345 source_dir)) { 1346 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1347 } else { 1348 result.AppendErrorWithFormat("module importing failed: %s", 1349 error.AsCString()); 1350 } 1351 } 1352 1353 return result.Succeeded(); 1354 } 1355 1356 CommandOptions m_options; 1357 }; 1358 1359 // CommandObjectCommandsScriptAdd 1360 static constexpr OptionEnumValueElement g_script_synchro_type[] = { 1361 { 1362 eScriptedCommandSynchronicitySynchronous, 1363 "synchronous", 1364 "Run synchronous", 1365 }, 1366 { 1367 eScriptedCommandSynchronicityAsynchronous, 1368 "asynchronous", 1369 "Run asynchronous", 1370 }, 1371 { 1372 eScriptedCommandSynchronicityCurrentValue, 1373 "current", 1374 "Do not alter current setting", 1375 }, 1376 }; 1377 1378 static constexpr OptionEnumValues ScriptSynchroType() { 1379 return OptionEnumValues(g_script_synchro_type); 1380 } 1381 1382 #define LLDB_OPTIONS_script_add 1383 #include "CommandOptions.inc" 1384 1385 class CommandObjectCommandsScriptAdd : public CommandObjectParsed, 1386 public IOHandlerDelegateMultiline { 1387 public: 1388 CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) 1389 : CommandObjectParsed(interpreter, "command script add", 1390 "Add a scripted function as an LLDB command.", 1391 "Add a scripted function as an lldb command. " 1392 "If you provide a single argument, the command " 1393 "will be added at the root level of the command " 1394 "hierarchy. If there are more arguments they " 1395 "must be a path to a user-added container " 1396 "command, and the last element will be the new " 1397 "command name."), 1398 IOHandlerDelegateMultiline("DONE"), m_options() { 1399 CommandArgumentEntry arg1; 1400 CommandArgumentData cmd_arg; 1401 1402 // This is one or more command names, which form the path to the command 1403 // you want to add. 1404 cmd_arg.arg_type = eArgTypeCommand; 1405 cmd_arg.arg_repetition = eArgRepeatPlus; 1406 1407 // There is only one variant this argument could be; put it into the 1408 // argument entry. 1409 arg1.push_back(cmd_arg); 1410 1411 // Push the data for the first argument into the m_arguments vector. 1412 m_arguments.push_back(arg1); 1413 } 1414 1415 ~CommandObjectCommandsScriptAdd() override = default; 1416 1417 Options *GetOptions() override { return &m_options; } 1418 1419 void 1420 HandleArgumentCompletion(CompletionRequest &request, 1421 OptionElementVector &opt_element_vector) override { 1422 CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request, 1423 opt_element_vector); 1424 } 1425 1426 protected: 1427 class CommandOptions : public Options { 1428 public: 1429 CommandOptions() 1430 : Options(), m_class_name(), m_funct_name(), m_short_help() {} 1431 1432 ~CommandOptions() override = default; 1433 1434 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1435 ExecutionContext *execution_context) override { 1436 Status error; 1437 const int short_option = m_getopt_table[option_idx].val; 1438 1439 switch (short_option) { 1440 case 'f': 1441 if (!option_arg.empty()) 1442 m_funct_name = std::string(option_arg); 1443 break; 1444 case 'c': 1445 if (!option_arg.empty()) 1446 m_class_name = std::string(option_arg); 1447 break; 1448 case 'h': 1449 if (!option_arg.empty()) 1450 m_short_help = std::string(option_arg); 1451 break; 1452 case 'o': 1453 m_overwrite = true; 1454 break; 1455 case 's': 1456 m_synchronicity = 1457 (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum( 1458 option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 1459 if (!error.Success()) 1460 error.SetErrorStringWithFormat( 1461 "unrecognized value for synchronicity '%s'", 1462 option_arg.str().c_str()); 1463 break; 1464 default: 1465 llvm_unreachable("Unimplemented option"); 1466 } 1467 1468 return error; 1469 } 1470 1471 void OptionParsingStarting(ExecutionContext *execution_context) override { 1472 m_class_name.clear(); 1473 m_funct_name.clear(); 1474 m_short_help.clear(); 1475 m_overwrite = false; 1476 m_synchronicity = eScriptedCommandSynchronicitySynchronous; 1477 } 1478 1479 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1480 return llvm::makeArrayRef(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 bool m_overwrite; 1489 ScriptedCommandSynchronicity m_synchronicity = 1490 eScriptedCommandSynchronicitySynchronous; 1491 }; 1492 1493 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 1494 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); 1495 if (output_sp && interactive) { 1496 output_sp->PutCString(g_python_command_instructions); 1497 output_sp->Flush(); 1498 } 1499 } 1500 1501 void IOHandlerInputComplete(IOHandler &io_handler, 1502 std::string &data) override { 1503 StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); 1504 1505 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1506 if (interpreter) { 1507 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)); 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 bool 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 false; 1564 } 1565 1566 if (command.GetArgumentCount() == 0) { 1567 result.AppendError("'command script add' requires at least one argument"); 1568 return false; 1569 } 1570 // Store the options in case we get multi-line input 1571 m_overwrite = m_options.m_overwrite; 1572 Status path_error; 1573 m_container = GetCommandInterpreter().VerifyUserMultiwordCmdPath( 1574 command, true, path_error); 1575 1576 if (path_error.Fail()) { 1577 result.AppendErrorWithFormat("error in command path: %s", 1578 path_error.AsCString()); 1579 return false; 1580 } 1581 1582 if (!m_container) { 1583 // This is getting inserted into the root of the interpreter. 1584 m_cmd_name = std::string(command[0].ref()); 1585 } else { 1586 size_t num_args = command.GetArgumentCount(); 1587 m_cmd_name = std::string(command[num_args - 1].ref()); 1588 } 1589 1590 m_short_help.assign(m_options.m_short_help); 1591 m_synchronicity = m_options.m_synchronicity; 1592 1593 // Handle the case where we prompt for the script code first: 1594 if (m_options.m_class_name.empty() && m_options.m_funct_name.empty()) { 1595 m_interpreter.GetPythonCommandsFromIOHandler(" ", // Prompt 1596 *this); // IOHandlerDelegate 1597 return result.Succeeded(); 1598 } 1599 1600 CommandObjectSP new_cmd_sp; 1601 if (m_options.m_class_name.empty()) { 1602 new_cmd_sp.reset(new CommandObjectPythonFunction( 1603 m_interpreter, m_cmd_name, m_options.m_funct_name, 1604 m_options.m_short_help, m_synchronicity)); 1605 } else { 1606 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1607 if (!interpreter) { 1608 result.AppendError("cannot find ScriptInterpreter"); 1609 return false; 1610 } 1611 1612 auto cmd_obj_sp = interpreter->CreateScriptCommandObject( 1613 m_options.m_class_name.c_str()); 1614 if (!cmd_obj_sp) { 1615 result.AppendError("cannot create helper object"); 1616 return false; 1617 } 1618 1619 new_cmd_sp.reset(new CommandObjectScriptingObject( 1620 m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity)); 1621 } 1622 1623 // Assume we're going to succeed... 1624 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1625 if (!m_container) { 1626 Status add_error = 1627 m_interpreter.AddUserCommand(m_cmd_name, new_cmd_sp, m_overwrite); 1628 if (add_error.Fail()) 1629 result.AppendErrorWithFormat("cannot add command: %s", 1630 add_error.AsCString()); 1631 } else { 1632 llvm::Error llvm_error = 1633 m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite); 1634 if (llvm_error) 1635 result.AppendErrorWithFormat("cannot add command: %s", 1636 llvm::toString(std::move(llvm_error)).c_str()); 1637 } 1638 return result.Succeeded(); 1639 } 1640 1641 CommandOptions m_options; 1642 std::string m_cmd_name; 1643 CommandObjectMultiword *m_container = nullptr; 1644 std::string m_short_help; 1645 bool m_overwrite; 1646 ScriptedCommandSynchronicity m_synchronicity; 1647 }; 1648 1649 // CommandObjectCommandsScriptList 1650 1651 class CommandObjectCommandsScriptList : public CommandObjectParsed { 1652 public: 1653 CommandObjectCommandsScriptList(CommandInterpreter &interpreter) 1654 : CommandObjectParsed(interpreter, "command script list", 1655 "List defined top-level scripted commands.", 1656 nullptr) {} 1657 1658 ~CommandObjectCommandsScriptList() override = default; 1659 1660 bool DoExecute(Args &command, CommandReturnObject &result) override { 1661 if (command.GetArgumentCount() != 0) { 1662 result.AppendError("'command script list' doesn't take any arguments"); 1663 return false; 1664 } 1665 1666 m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef); 1667 1668 result.SetStatus(eReturnStatusSuccessFinishResult); 1669 1670 return true; 1671 } 1672 }; 1673 1674 // CommandObjectCommandsScriptClear 1675 1676 class CommandObjectCommandsScriptClear : public CommandObjectParsed { 1677 public: 1678 CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) 1679 : CommandObjectParsed(interpreter, "command script clear", 1680 "Delete all scripted commands.", nullptr) {} 1681 1682 ~CommandObjectCommandsScriptClear() override = default; 1683 1684 protected: 1685 bool DoExecute(Args &command, CommandReturnObject &result) override { 1686 if (command.GetArgumentCount() != 0) { 1687 result.AppendError("'command script clear' doesn't take any arguments"); 1688 return false; 1689 } 1690 1691 m_interpreter.RemoveAllUser(); 1692 1693 result.SetStatus(eReturnStatusSuccessFinishResult); 1694 1695 return true; 1696 } 1697 }; 1698 1699 // CommandObjectCommandsScriptDelete 1700 1701 class CommandObjectCommandsScriptDelete : public CommandObjectParsed { 1702 public: 1703 CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) 1704 : CommandObjectParsed( 1705 interpreter, "command script delete", 1706 "Delete a scripted command by specifying the path to the command.", 1707 nullptr) { 1708 CommandArgumentEntry arg1; 1709 CommandArgumentData cmd_arg; 1710 1711 // This is a list of command names forming the path to the command 1712 // to be deleted. 1713 cmd_arg.arg_type = eArgTypeCommand; 1714 cmd_arg.arg_repetition = eArgRepeatPlus; 1715 1716 // There is only one variant this argument could be; put it into the 1717 // argument entry. 1718 arg1.push_back(cmd_arg); 1719 1720 // Push the data for the first argument into the m_arguments vector. 1721 m_arguments.push_back(arg1); 1722 } 1723 1724 ~CommandObjectCommandsScriptDelete() override = default; 1725 1726 void 1727 HandleArgumentCompletion(CompletionRequest &request, 1728 OptionElementVector &opt_element_vector) override { 1729 CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request, 1730 opt_element_vector); 1731 } 1732 1733 protected: 1734 bool DoExecute(Args &command, CommandReturnObject &result) override { 1735 1736 llvm::StringRef root_cmd = command[0].ref(); 1737 size_t num_args = command.GetArgumentCount(); 1738 1739 if (root_cmd.empty()) { 1740 result.AppendErrorWithFormat("empty root command name"); 1741 return false; 1742 } 1743 if (!m_interpreter.HasUserCommands() && 1744 !m_interpreter.HasUserMultiwordCommands()) { 1745 result.AppendErrorWithFormat("can only delete user defined commands, " 1746 "but no user defined commands found"); 1747 return false; 1748 } 1749 1750 CommandObjectSP cmd_sp = m_interpreter.GetCommandSPExact(root_cmd); 1751 if (!cmd_sp) { 1752 result.AppendErrorWithFormat("command '%s' not found.", 1753 command[0].c_str()); 1754 return false; 1755 } 1756 if (!cmd_sp->IsUserCommand()) { 1757 result.AppendErrorWithFormat("command '%s' is not a user command.", 1758 command[0].c_str()); 1759 return false; 1760 } 1761 if (cmd_sp->GetAsMultiwordCommand() && num_args == 1) { 1762 result.AppendErrorWithFormat("command '%s' is a multi-word command.\n " 1763 "Delete with \"command container delete\"", 1764 command[0].c_str()); 1765 return false; 1766 } 1767 1768 if (command.GetArgumentCount() == 1) { 1769 m_interpreter.RemoveUser(root_cmd); 1770 result.SetStatus(eReturnStatusSuccessFinishResult); 1771 return true; 1772 } 1773 // We're deleting a command from a multiword command. Verify the command 1774 // path: 1775 Status error; 1776 CommandObjectMultiword *container = 1777 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 1778 error); 1779 if (error.Fail()) { 1780 result.AppendErrorWithFormat("could not resolve command path: %s", 1781 error.AsCString()); 1782 return false; 1783 } 1784 if (!container) { 1785 // This means that command only had a leaf command, so the container is 1786 // the root. That should have been handled above. 1787 result.AppendErrorWithFormat("could not find a container for '%s'", 1788 command[0].c_str()); 1789 return false; 1790 } 1791 const char *leaf_cmd = command[num_args - 1].c_str(); 1792 llvm::Error llvm_error = container->RemoveUserSubcommand(leaf_cmd, 1793 /* multiword not okay */ false); 1794 if (llvm_error) { 1795 result.AppendErrorWithFormat("could not delete command '%s': %s", 1796 leaf_cmd, 1797 llvm::toString(std::move(llvm_error)).c_str()); 1798 return false; 1799 } 1800 1801 Stream &out_stream = result.GetOutputStream(); 1802 1803 out_stream << "Deleted command:"; 1804 for (size_t idx = 0; idx < num_args; idx++) { 1805 out_stream << ' '; 1806 out_stream << command[idx].c_str(); 1807 } 1808 out_stream << '\n'; 1809 result.SetStatus(eReturnStatusSuccessFinishResult); 1810 return true; 1811 } 1812 }; 1813 1814 #pragma mark CommandObjectMultiwordCommandsScript 1815 1816 // CommandObjectMultiwordCommandsScript 1817 1818 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword { 1819 public: 1820 CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter) 1821 : CommandObjectMultiword( 1822 interpreter, "command script", 1823 "Commands for managing custom " 1824 "commands implemented by " 1825 "interpreter scripts.", 1826 "command script <subcommand> [<subcommand-options>]") { 1827 LoadSubCommand("add", CommandObjectSP( 1828 new CommandObjectCommandsScriptAdd(interpreter))); 1829 LoadSubCommand( 1830 "delete", 1831 CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter))); 1832 LoadSubCommand( 1833 "clear", 1834 CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter))); 1835 LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList( 1836 interpreter))); 1837 LoadSubCommand( 1838 "import", 1839 CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter))); 1840 } 1841 1842 ~CommandObjectMultiwordCommandsScript() override = default; 1843 }; 1844 1845 #pragma mark CommandObjectCommandContainer 1846 #define LLDB_OPTIONS_container_add 1847 #include "CommandOptions.inc" 1848 1849 class CommandObjectCommandsContainerAdd : public CommandObjectParsed { 1850 public: 1851 CommandObjectCommandsContainerAdd(CommandInterpreter &interpreter) 1852 : CommandObjectParsed( 1853 interpreter, "command container add", 1854 "Add a container command to lldb. Adding to built-" 1855 "in container commands is not allowed.", 1856 "command container add [[path1]...] container-name") { 1857 CommandArgumentEntry arg1; 1858 CommandArgumentData cmd_arg; 1859 1860 // This is one or more command names, which form the path to the command 1861 // you want to add. 1862 cmd_arg.arg_type = eArgTypeCommand; 1863 cmd_arg.arg_repetition = eArgRepeatPlus; 1864 1865 // There is only one variant this argument could be; put it into the 1866 // argument entry. 1867 arg1.push_back(cmd_arg); 1868 1869 // Push the data for the first argument into the m_arguments vector. 1870 m_arguments.push_back(arg1); 1871 } 1872 1873 ~CommandObjectCommandsContainerAdd() override = default; 1874 1875 Options *GetOptions() override { return &m_options; } 1876 1877 void 1878 HandleArgumentCompletion(CompletionRequest &request, 1879 OptionElementVector &opt_element_vector) override { 1880 CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request, 1881 opt_element_vector); 1882 } 1883 1884 protected: 1885 class CommandOptions : public Options { 1886 public: 1887 CommandOptions() : Options(), m_short_help(), m_long_help() {} 1888 1889 ~CommandOptions() override = default; 1890 1891 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1892 ExecutionContext *execution_context) override { 1893 Status error; 1894 const int short_option = m_getopt_table[option_idx].val; 1895 1896 switch (short_option) { 1897 case 'h': 1898 if (!option_arg.empty()) 1899 m_short_help = std::string(option_arg); 1900 break; 1901 case 'o': 1902 m_overwrite = true; 1903 break; 1904 case 'H': 1905 if (!option_arg.empty()) 1906 m_long_help = std::string(option_arg); 1907 break; 1908 default: 1909 llvm_unreachable("Unimplemented option"); 1910 } 1911 1912 return error; 1913 } 1914 1915 void OptionParsingStarting(ExecutionContext *execution_context) override { 1916 m_short_help.clear(); 1917 m_long_help.clear(); 1918 m_overwrite = false; 1919 } 1920 1921 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1922 return llvm::makeArrayRef(g_container_add_options); 1923 } 1924 1925 // Instance variables to hold the values for command options. 1926 1927 std::string m_short_help; 1928 std::string m_long_help; 1929 bool m_overwrite = false; 1930 }; 1931 bool DoExecute(Args &command, CommandReturnObject &result) override { 1932 size_t num_args = command.GetArgumentCount(); 1933 1934 if (num_args == 0) { 1935 result.AppendError("no command was specified"); 1936 return false; 1937 } 1938 1939 if (num_args == 1) { 1940 // We're adding this as a root command, so use the interpreter. 1941 const char *cmd_name = command.GetArgumentAtIndex(0); 1942 auto cmd_sp = CommandObjectSP(new CommandObjectMultiword( 1943 GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(), 1944 m_options.m_long_help.c_str())); 1945 cmd_sp->GetAsMultiwordCommand()->SetRemovable(true); 1946 Status add_error = GetCommandInterpreter().AddUserCommand( 1947 cmd_name, cmd_sp, m_options.m_overwrite); 1948 if (add_error.Fail()) { 1949 result.AppendErrorWithFormat("error adding command: %s", 1950 add_error.AsCString()); 1951 return false; 1952 } 1953 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1954 return true; 1955 } 1956 1957 // We're adding this to a subcommand, first find the subcommand: 1958 Status path_error; 1959 CommandObjectMultiword *add_to_me = 1960 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 1961 path_error); 1962 1963 if (!add_to_me) { 1964 result.AppendErrorWithFormat("error adding command: %s", 1965 path_error.AsCString()); 1966 return false; 1967 } 1968 1969 const char *cmd_name = command.GetArgumentAtIndex(num_args - 1); 1970 auto cmd_sp = CommandObjectSP(new CommandObjectMultiword( 1971 GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(), 1972 m_options.m_long_help.c_str())); 1973 llvm::Error llvm_error = 1974 add_to_me->LoadUserSubcommand(cmd_name, cmd_sp, m_options.m_overwrite); 1975 if (llvm_error) { 1976 result.AppendErrorWithFormat("error adding subcommand: %s", 1977 llvm::toString(std::move(llvm_error)).c_str()); 1978 return false; 1979 } 1980 1981 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1982 return true; 1983 } 1984 1985 private: 1986 CommandOptions m_options; 1987 }; 1988 1989 #define LLDB_OPTIONS_multiword_delete 1990 #include "CommandOptions.inc" 1991 class CommandObjectCommandsContainerDelete : public CommandObjectParsed { 1992 public: 1993 CommandObjectCommandsContainerDelete(CommandInterpreter &interpreter) 1994 : CommandObjectParsed( 1995 interpreter, "command container delete", 1996 "Delete a container command previously added to " 1997 "lldb.", 1998 "command container delete [[path1] ...] container-cmd") { 1999 CommandArgumentEntry arg1; 2000 CommandArgumentData cmd_arg; 2001 2002 // This is one or more command names, which form the path to the command 2003 // you want to add. 2004 cmd_arg.arg_type = eArgTypeCommand; 2005 cmd_arg.arg_repetition = eArgRepeatPlus; 2006 2007 // There is only one variant this argument could be; put it into the 2008 // argument entry. 2009 arg1.push_back(cmd_arg); 2010 2011 // Push the data for the first argument into the m_arguments vector. 2012 m_arguments.push_back(arg1); 2013 } 2014 2015 ~CommandObjectCommandsContainerDelete() override = default; 2016 2017 void 2018 HandleArgumentCompletion(CompletionRequest &request, 2019 OptionElementVector &opt_element_vector) override { 2020 CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request, 2021 opt_element_vector); 2022 } 2023 2024 protected: 2025 bool DoExecute(Args &command, CommandReturnObject &result) override { 2026 size_t num_args = command.GetArgumentCount(); 2027 2028 if (num_args == 0) { 2029 result.AppendError("No command was specified."); 2030 return false; 2031 } 2032 2033 if (num_args == 1) { 2034 // We're removing a root command, so we need to delete it from the 2035 // interpreter. 2036 const char *cmd_name = command.GetArgumentAtIndex(0); 2037 // Let's do a little more work here so we can do better error reporting. 2038 CommandInterpreter &interp = GetCommandInterpreter(); 2039 CommandObjectSP cmd_sp = interp.GetCommandSPExact(cmd_name); 2040 if (!cmd_sp) { 2041 result.AppendErrorWithFormat("container command %s doesn't exist.", 2042 cmd_name); 2043 return false; 2044 } 2045 if (!cmd_sp->IsUserCommand()) { 2046 result.AppendErrorWithFormat( 2047 "container command %s is not a user command", cmd_name); 2048 return false; 2049 } 2050 if (!cmd_sp->GetAsMultiwordCommand()) { 2051 result.AppendErrorWithFormat("command %s is not a container command", 2052 cmd_name); 2053 return false; 2054 } 2055 2056 bool did_remove = GetCommandInterpreter().RemoveUserMultiword(cmd_name); 2057 if (!did_remove) { 2058 result.AppendErrorWithFormat("error removing command %s.", cmd_name); 2059 return false; 2060 } 2061 2062 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2063 return true; 2064 } 2065 2066 // We're removing a subcommand, first find the subcommand's owner: 2067 Status path_error; 2068 CommandObjectMultiword *container = 2069 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 2070 path_error); 2071 2072 if (!container) { 2073 result.AppendErrorWithFormat("error removing container command: %s", 2074 path_error.AsCString()); 2075 return false; 2076 } 2077 const char *leaf = command.GetArgumentAtIndex(num_args - 1); 2078 llvm::Error llvm_error = 2079 container->RemoveUserSubcommand(leaf, /* multiword okay */ true); 2080 if (llvm_error) { 2081 result.AppendErrorWithFormat("error removing container command: %s", 2082 llvm::toString(std::move(llvm_error)).c_str()); 2083 return false; 2084 } 2085 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2086 return true; 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, but " 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