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