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 28 using namespace lldb; 29 using namespace lldb_private; 30 31 // CommandObjectCommandsSource 32 33 #define LLDB_OPTIONS_source 34 #include "CommandOptions.inc" 35 36 class CommandObjectCommandsSource : public CommandObjectParsed { 37 public: 38 CommandObjectCommandsSource(CommandInterpreter &interpreter) 39 : CommandObjectParsed( 40 interpreter, "command source", 41 "Read and execute LLDB commands from the file <filename>.", 42 nullptr) { 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 llvm::Optional<std::string> GetRepeatCommand(Args ¤t_command_args, 61 uint32_t index) override { 62 return std::string(""); 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 : 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::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() = default; 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.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 if (CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact( 489 cmd_obj.GetCommandName(), include_aliases)) { 490 if (m_interpreter.AliasExists(alias_command) || 491 m_interpreter.UserCommandExists(alias_command)) { 492 result.AppendWarningWithFormat( 493 "Overwriting existing definition for '%s'.\n", 494 alias_command.str().c_str()); 495 } 496 if (CommandAlias *alias = m_interpreter.AddAlias( 497 alias_command, cmd_obj_sp, raw_command_string)) { 498 if (m_command_options.m_help.OptionWasSet()) 499 alias->SetHelp(m_command_options.m_help.GetCurrentValue()); 500 if (m_command_options.m_long_help.OptionWasSet()) 501 alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue()); 502 result.SetStatus(eReturnStatusSuccessFinishNoResult); 503 } else { 504 result.AppendError("Unable to create requested alias.\n"); 505 } 506 507 } else { 508 result.AppendError("Unable to create requested alias.\n"); 509 } 510 511 return result.Succeeded(); 512 } 513 514 bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) { 515 size_t argc = args.GetArgumentCount(); 516 517 if (argc < 2) { 518 result.AppendError("'command alias' requires at least two arguments"); 519 return false; 520 } 521 522 // Save these in std::strings since we're going to shift them off. 523 const std::string alias_command(std::string(args[0].ref())); 524 const std::string actual_command(std::string(args[1].ref())); 525 526 args.Shift(); // Shift the alias command word off the argument vector. 527 args.Shift(); // Shift the old command word off the argument vector. 528 529 // Verify that the command is alias'able, and get the appropriate command 530 // object. 531 532 if (m_interpreter.CommandExists(alias_command)) { 533 result.AppendErrorWithFormat( 534 "'%s' is a permanent debugger command and cannot be redefined.\n", 535 alias_command.c_str()); 536 return false; 537 } 538 539 if (m_interpreter.UserMultiwordCommandExists(alias_command)) { 540 result.AppendErrorWithFormat( 541 "'%s' is user container command and cannot be overwritten.\n" 542 "Delete it first with 'command container delete'", 543 alias_command.c_str()); 544 return false; 545 } 546 547 CommandObjectSP command_obj_sp( 548 m_interpreter.GetCommandSPExact(actual_command, true)); 549 CommandObjectSP subcommand_obj_sp; 550 bool use_subcommand = false; 551 if (!command_obj_sp) { 552 result.AppendErrorWithFormat("'%s' is not an existing command.\n", 553 actual_command.c_str()); 554 return false; 555 } 556 CommandObject *cmd_obj = command_obj_sp.get(); 557 CommandObject *sub_cmd_obj = nullptr; 558 OptionArgVectorSP option_arg_vector_sp = 559 OptionArgVectorSP(new OptionArgVector); 560 561 while (cmd_obj->IsMultiwordObject() && !args.empty()) { 562 auto sub_command = args[0].ref(); 563 assert(!sub_command.empty()); 564 subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command); 565 if (!subcommand_obj_sp) { 566 result.AppendErrorWithFormat( 567 "'%s' is not a valid sub-command of '%s'. " 568 "Unable to create alias.\n", 569 args[0].c_str(), actual_command.c_str()); 570 return false; 571 } 572 573 sub_cmd_obj = subcommand_obj_sp.get(); 574 use_subcommand = true; 575 args.Shift(); // Shift the sub_command word off the argument vector. 576 cmd_obj = sub_cmd_obj; 577 } 578 579 // Verify & handle any options/arguments passed to the alias command 580 581 std::string args_string; 582 583 if (!args.empty()) { 584 CommandObjectSP tmp_sp = 585 m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName()); 586 if (use_subcommand) 587 tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName()); 588 589 args.GetCommandString(args_string); 590 } 591 592 if (m_interpreter.AliasExists(alias_command) || 593 m_interpreter.UserCommandExists(alias_command)) { 594 result.AppendWarningWithFormat( 595 "Overwriting existing definition for '%s'.\n", alias_command.c_str()); 596 } 597 598 if (CommandAlias *alias = m_interpreter.AddAlias( 599 alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp, 600 args_string)) { 601 if (m_command_options.m_help.OptionWasSet()) 602 alias->SetHelp(m_command_options.m_help.GetCurrentValue()); 603 if (m_command_options.m_long_help.OptionWasSet()) 604 alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue()); 605 result.SetStatus(eReturnStatusSuccessFinishNoResult); 606 } else { 607 result.AppendError("Unable to create requested alias.\n"); 608 return false; 609 } 610 611 return result.Succeeded(); 612 } 613 }; 614 615 #pragma mark CommandObjectCommandsUnalias 616 // CommandObjectCommandsUnalias 617 618 class CommandObjectCommandsUnalias : public CommandObjectParsed { 619 public: 620 CommandObjectCommandsUnalias(CommandInterpreter &interpreter) 621 : CommandObjectParsed( 622 interpreter, "command unalias", 623 "Delete one or more custom commands defined by 'command alias'.", 624 nullptr) { 625 CommandArgumentEntry arg; 626 CommandArgumentData alias_arg; 627 628 // Define the first (and only) variant of this arg. 629 alias_arg.arg_type = eArgTypeAliasName; 630 alias_arg.arg_repetition = eArgRepeatPlain; 631 632 // There is only one variant this argument could be; put it into the 633 // argument entry. 634 arg.push_back(alias_arg); 635 636 // Push the data for the first argument into the m_arguments vector. 637 m_arguments.push_back(arg); 638 } 639 640 ~CommandObjectCommandsUnalias() override = default; 641 642 void 643 HandleArgumentCompletion(CompletionRequest &request, 644 OptionElementVector &opt_element_vector) override { 645 if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0) 646 return; 647 648 for (const auto &ent : m_interpreter.GetAliases()) { 649 request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp()); 650 } 651 } 652 653 protected: 654 bool DoExecute(Args &args, CommandReturnObject &result) override { 655 CommandObject::CommandMap::iterator pos; 656 CommandObject *cmd_obj; 657 658 if (args.empty()) { 659 result.AppendError("must call 'unalias' with a valid alias"); 660 return false; 661 } 662 663 auto command_name = args[0].ref(); 664 cmd_obj = m_interpreter.GetCommandObject(command_name); 665 if (!cmd_obj) { 666 result.AppendErrorWithFormat( 667 "'%s' is not a known command.\nTry 'help' to see a " 668 "current list of commands.\n", 669 args[0].c_str()); 670 return false; 671 } 672 673 if (m_interpreter.CommandExists(command_name)) { 674 if (cmd_obj->IsRemovable()) { 675 result.AppendErrorWithFormat( 676 "'%s' is not an alias, it is a debugger command which can be " 677 "removed using the 'command delete' command.\n", 678 args[0].c_str()); 679 } else { 680 result.AppendErrorWithFormat( 681 "'%s' is a permanent debugger command and cannot be removed.\n", 682 args[0].c_str()); 683 } 684 return false; 685 } 686 687 if (!m_interpreter.RemoveAlias(command_name)) { 688 if (m_interpreter.AliasExists(command_name)) 689 result.AppendErrorWithFormat( 690 "Error occurred while attempting to unalias '%s'.\n", 691 args[0].c_str()); 692 else 693 result.AppendErrorWithFormat("'%s' is not an existing alias.\n", 694 args[0].c_str()); 695 return false; 696 } 697 698 result.SetStatus(eReturnStatusSuccessFinishNoResult); 699 return result.Succeeded(); 700 } 701 }; 702 703 #pragma mark CommandObjectCommandsDelete 704 // CommandObjectCommandsDelete 705 706 class CommandObjectCommandsDelete : public CommandObjectParsed { 707 public: 708 CommandObjectCommandsDelete(CommandInterpreter &interpreter) 709 : CommandObjectParsed( 710 interpreter, "command delete", 711 "Delete one or more custom commands defined by 'command regex'.", 712 nullptr) { 713 CommandArgumentEntry arg; 714 CommandArgumentData alias_arg; 715 716 // Define the first (and only) variant of this arg. 717 alias_arg.arg_type = eArgTypeCommandName; 718 alias_arg.arg_repetition = eArgRepeatPlain; 719 720 // There is only one variant this argument could be; put it into the 721 // argument entry. 722 arg.push_back(alias_arg); 723 724 // Push the data for the first argument into the m_arguments vector. 725 m_arguments.push_back(arg); 726 } 727 728 ~CommandObjectCommandsDelete() override = default; 729 730 void 731 HandleArgumentCompletion(CompletionRequest &request, 732 OptionElementVector &opt_element_vector) override { 733 if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0) 734 return; 735 736 for (const auto &ent : m_interpreter.GetCommands()) { 737 if (ent.second->IsRemovable()) 738 request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp()); 739 } 740 } 741 742 protected: 743 bool DoExecute(Args &args, CommandReturnObject &result) override { 744 CommandObject::CommandMap::iterator pos; 745 746 if (args.empty()) { 747 result.AppendErrorWithFormat("must call '%s' with one or more valid user " 748 "defined regular expression command names", 749 GetCommandName().str().c_str()); 750 return false; 751 } 752 753 auto command_name = args[0].ref(); 754 if (!m_interpreter.CommandExists(command_name)) { 755 StreamString error_msg_stream; 756 const bool generate_upropos = true; 757 const bool generate_type_lookup = false; 758 CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage( 759 &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(), 760 generate_upropos, generate_type_lookup); 761 result.AppendError(error_msg_stream.GetString()); 762 return false; 763 } 764 765 if (!m_interpreter.RemoveCommand(command_name)) { 766 result.AppendErrorWithFormat( 767 "'%s' is a permanent debugger command and cannot be removed.\n", 768 args[0].c_str()); 769 return false; 770 } 771 772 result.SetStatus(eReturnStatusSuccessFinishNoResult); 773 return true; 774 } 775 }; 776 777 // CommandObjectCommandsAddRegex 778 779 #define LLDB_OPTIONS_regex 780 #include "CommandOptions.inc" 781 782 #pragma mark CommandObjectCommandsAddRegex 783 784 class CommandObjectCommandsAddRegex : public CommandObjectParsed, 785 public IOHandlerDelegateMultiline { 786 public: 787 CommandObjectCommandsAddRegex(CommandInterpreter &interpreter) 788 : CommandObjectParsed( 789 interpreter, "command regex", 790 "Define a custom command in terms of " 791 "existing commands by matching " 792 "regular expressions.", 793 "command regex <cmd-name> [s/<regex>/<subst>/ ...]"), 794 IOHandlerDelegateMultiline("", 795 IOHandlerDelegate::Completion::LLDBCommand) { 796 SetHelpLong( 797 R"( 798 )" 799 "This command allows the user to create powerful regular expression commands \ 800 with substitutions. The regular expressions and substitutions are specified \ 801 using the regular expression substitution format of:" 802 R"( 803 804 s/<regex>/<subst>/ 805 806 )" 807 "<regex> is a regular expression that can use parenthesis to capture regular \ 808 expression input and substitute the captured matches in the output using %1 \ 809 for the first match, %2 for the second, and so on." 810 R"( 811 812 )" 813 "The regular expressions can all be specified on the command line if more than \ 814 one argument is provided. If just the command name is provided on the command \ 815 line, then the regular expressions and substitutions can be entered on separate \ 816 lines, followed by an empty line to terminate the command definition." 817 R"( 818 819 EXAMPLES 820 821 )" 822 "The following example will define a regular expression command named 'f' that \ 823 will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \ 824 a number follows 'f':" 825 R"( 826 827 (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')"); 828 CommandArgumentData thread_arg{eArgTypeSEDStylePair, eArgRepeatOptional}; 829 m_arguments.push_back({thread_arg}); 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() = default; 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) { 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 = false; 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 CommandArgumentEntry arg1; 1244 CommandArgumentData cmd_arg; 1245 1246 // Define the first (and only) variant of this arg. 1247 cmd_arg.arg_type = eArgTypeFilename; 1248 cmd_arg.arg_repetition = eArgRepeatPlus; 1249 1250 // There is only one variant this argument could be; put it into the 1251 // argument entry. 1252 arg1.push_back(cmd_arg); 1253 1254 // Push the data for the first argument into the m_arguments vector. 1255 m_arguments.push_back(arg1); 1256 } 1257 1258 ~CommandObjectCommandsScriptImport() override = default; 1259 1260 void 1261 HandleArgumentCompletion(CompletionRequest &request, 1262 OptionElementVector &opt_element_vector) override { 1263 CommandCompletions::InvokeCommonCompletionCallbacks( 1264 GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, 1265 request, nullptr); 1266 } 1267 1268 Options *GetOptions() override { return &m_options; } 1269 1270 protected: 1271 class CommandOptions : public Options { 1272 public: 1273 CommandOptions() = default; 1274 1275 ~CommandOptions() override = default; 1276 1277 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1278 ExecutionContext *execution_context) override { 1279 Status error; 1280 const int short_option = m_getopt_table[option_idx].val; 1281 1282 switch (short_option) { 1283 case 'r': 1284 // NO-OP 1285 break; 1286 case 'c': 1287 relative_to_command_file = true; 1288 break; 1289 case 's': 1290 silent = true; 1291 break; 1292 default: 1293 llvm_unreachable("Unimplemented option"); 1294 } 1295 1296 return error; 1297 } 1298 1299 void OptionParsingStarting(ExecutionContext *execution_context) override { 1300 relative_to_command_file = false; 1301 } 1302 1303 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1304 return llvm::makeArrayRef(g_script_import_options); 1305 } 1306 bool relative_to_command_file = false; 1307 bool silent = false; 1308 }; 1309 1310 bool DoExecute(Args &command, CommandReturnObject &result) override { 1311 if (command.empty()) { 1312 result.AppendError("command script import needs one or more arguments"); 1313 return false; 1314 } 1315 1316 FileSpec source_dir = {}; 1317 if (m_options.relative_to_command_file) { 1318 source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir(); 1319 if (!source_dir) { 1320 result.AppendError("command script import -c can only be specified " 1321 "from a command file"); 1322 return false; 1323 } 1324 } 1325 1326 for (auto &entry : command.entries()) { 1327 Status error; 1328 1329 LoadScriptOptions options; 1330 options.SetInitSession(true); 1331 options.SetSilent(m_options.silent); 1332 1333 // FIXME: this is necessary because CommandObject::CheckRequirements() 1334 // assumes that commands won't ever be recursively invoked, but it's 1335 // actually possible to craft a Python script that does other "command 1336 // script imports" in __lldb_init_module the real fix is to have 1337 // recursive commands possible with a CommandInvocation object separate 1338 // from the CommandObject itself, so that recursive command invocations 1339 // won't stomp on each other (wrt to execution contents, options, and 1340 // more) 1341 m_exe_ctx.Clear(); 1342 if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule( 1343 entry.c_str(), options, error, /*module_sp=*/nullptr, 1344 source_dir)) { 1345 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1346 } else { 1347 result.AppendErrorWithFormat("module importing failed: %s", 1348 error.AsCString()); 1349 } 1350 } 1351 1352 return result.Succeeded(); 1353 } 1354 1355 CommandOptions m_options; 1356 }; 1357 1358 #define LLDB_OPTIONS_script_add 1359 #include "CommandOptions.inc" 1360 1361 class CommandObjectCommandsScriptAdd : public CommandObjectParsed, 1362 public IOHandlerDelegateMultiline { 1363 public: 1364 CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) 1365 : CommandObjectParsed(interpreter, "command script add", 1366 "Add a scripted function as an LLDB command.", 1367 "Add a scripted function as an lldb command. " 1368 "If you provide a single argument, the command " 1369 "will be added at the root level of the command " 1370 "hierarchy. If there are more arguments they " 1371 "must be a path to a user-added container " 1372 "command, and the last element will be the new " 1373 "command name."), 1374 IOHandlerDelegateMultiline("DONE") { 1375 CommandArgumentEntry arg1; 1376 CommandArgumentData cmd_arg; 1377 1378 // This is one or more command names, which form the path to the command 1379 // you want to add. 1380 cmd_arg.arg_type = eArgTypeCommand; 1381 cmd_arg.arg_repetition = eArgRepeatPlus; 1382 1383 // There is only one variant this argument could be; put it into the 1384 // argument entry. 1385 arg1.push_back(cmd_arg); 1386 1387 // Push the data for the first argument into the m_arguments vector. 1388 m_arguments.push_back(arg1); 1389 } 1390 1391 ~CommandObjectCommandsScriptAdd() override = default; 1392 1393 Options *GetOptions() override { return &m_options; } 1394 1395 void 1396 HandleArgumentCompletion(CompletionRequest &request, 1397 OptionElementVector &opt_element_vector) override { 1398 CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request, 1399 opt_element_vector); 1400 } 1401 1402 protected: 1403 class CommandOptions : public Options { 1404 public: 1405 CommandOptions() = default; 1406 1407 ~CommandOptions() override = default; 1408 1409 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1410 ExecutionContext *execution_context) override { 1411 Status error; 1412 const int short_option = m_getopt_table[option_idx].val; 1413 1414 switch (short_option) { 1415 case 'f': 1416 if (!option_arg.empty()) 1417 m_funct_name = std::string(option_arg); 1418 break; 1419 case 'c': 1420 if (!option_arg.empty()) 1421 m_class_name = std::string(option_arg); 1422 break; 1423 case 'h': 1424 if (!option_arg.empty()) 1425 m_short_help = std::string(option_arg); 1426 break; 1427 case 'o': 1428 m_overwrite_lazy = eLazyBoolYes; 1429 break; 1430 case 's': 1431 m_synchronicity = 1432 (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum( 1433 option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 1434 if (!error.Success()) 1435 error.SetErrorStringWithFormat( 1436 "unrecognized value for synchronicity '%s'", 1437 option_arg.str().c_str()); 1438 break; 1439 default: 1440 llvm_unreachable("Unimplemented option"); 1441 } 1442 1443 return error; 1444 } 1445 1446 void OptionParsingStarting(ExecutionContext *execution_context) override { 1447 m_class_name.clear(); 1448 m_funct_name.clear(); 1449 m_short_help.clear(); 1450 m_overwrite_lazy = eLazyBoolCalculate; 1451 m_synchronicity = eScriptedCommandSynchronicitySynchronous; 1452 } 1453 1454 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1455 return llvm::makeArrayRef(g_script_add_options); 1456 } 1457 1458 // Instance variables to hold the values for command options. 1459 1460 std::string m_class_name; 1461 std::string m_funct_name; 1462 std::string m_short_help; 1463 LazyBool m_overwrite_lazy = eLazyBoolCalculate; 1464 ScriptedCommandSynchronicity m_synchronicity = 1465 eScriptedCommandSynchronicitySynchronous; 1466 }; 1467 1468 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 1469 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); 1470 if (output_sp && interactive) { 1471 output_sp->PutCString(g_python_command_instructions); 1472 output_sp->Flush(); 1473 } 1474 } 1475 1476 void IOHandlerInputComplete(IOHandler &io_handler, 1477 std::string &data) override { 1478 StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); 1479 1480 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1481 if (interpreter) { 1482 StringList lines; 1483 lines.SplitIntoLines(data); 1484 if (lines.GetSize() > 0) { 1485 std::string funct_name_str; 1486 if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) { 1487 if (funct_name_str.empty()) { 1488 error_sp->Printf("error: unable to obtain a function name, didn't " 1489 "add python command.\n"); 1490 error_sp->Flush(); 1491 } else { 1492 // everything should be fine now, let's add this alias 1493 1494 CommandObjectSP command_obj_sp(new CommandObjectPythonFunction( 1495 m_interpreter, m_cmd_name, funct_name_str, m_short_help, 1496 m_synchronicity)); 1497 if (!m_container) { 1498 Status error = m_interpreter.AddUserCommand( 1499 m_cmd_name, command_obj_sp, m_overwrite); 1500 if (error.Fail()) { 1501 error_sp->Printf("error: unable to add selected command: '%s'", 1502 error.AsCString()); 1503 error_sp->Flush(); 1504 } 1505 } else { 1506 llvm::Error llvm_error = m_container->LoadUserSubcommand( 1507 m_cmd_name, command_obj_sp, m_overwrite); 1508 if (llvm_error) { 1509 error_sp->Printf("error: unable to add selected command: '%s'", 1510 llvm::toString(std::move(llvm_error)).c_str()); 1511 error_sp->Flush(); 1512 } 1513 } 1514 } 1515 } else { 1516 error_sp->Printf( 1517 "error: unable to create function, didn't add python command\n"); 1518 error_sp->Flush(); 1519 } 1520 } else { 1521 error_sp->Printf("error: empty function, didn't add python command\n"); 1522 error_sp->Flush(); 1523 } 1524 } else { 1525 error_sp->Printf( 1526 "error: script interpreter missing, didn't add python command\n"); 1527 error_sp->Flush(); 1528 } 1529 1530 io_handler.SetIsDone(true); 1531 } 1532 1533 bool DoExecute(Args &command, CommandReturnObject &result) override { 1534 if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) { 1535 result.AppendError("only scripting language supported for scripted " 1536 "commands is currently Python"); 1537 return false; 1538 } 1539 1540 if (command.GetArgumentCount() == 0) { 1541 result.AppendError("'command script add' requires at least one argument"); 1542 return false; 1543 } 1544 // Store the options in case we get multi-line input, also figure out the 1545 // default if not user supplied: 1546 switch (m_options.m_overwrite_lazy) { 1547 case eLazyBoolCalculate: 1548 m_overwrite = !GetDebugger().GetCommandInterpreter().GetRequireCommandOverwrite(); 1549 break; 1550 case eLazyBoolYes: 1551 m_overwrite = true; 1552 break; 1553 case eLazyBoolNo: 1554 m_overwrite = false; 1555 } 1556 1557 Status path_error; 1558 m_container = GetCommandInterpreter().VerifyUserMultiwordCmdPath( 1559 command, true, path_error); 1560 1561 if (path_error.Fail()) { 1562 result.AppendErrorWithFormat("error in command path: %s", 1563 path_error.AsCString()); 1564 return false; 1565 } 1566 1567 if (!m_container) { 1568 // This is getting inserted into the root of the interpreter. 1569 m_cmd_name = std::string(command[0].ref()); 1570 } else { 1571 size_t num_args = command.GetArgumentCount(); 1572 m_cmd_name = std::string(command[num_args - 1].ref()); 1573 } 1574 1575 m_short_help.assign(m_options.m_short_help); 1576 m_synchronicity = m_options.m_synchronicity; 1577 1578 // Handle the case where we prompt for the script code first: 1579 if (m_options.m_class_name.empty() && m_options.m_funct_name.empty()) { 1580 m_interpreter.GetPythonCommandsFromIOHandler(" ", // Prompt 1581 *this); // IOHandlerDelegate 1582 return result.Succeeded(); 1583 } 1584 1585 CommandObjectSP new_cmd_sp; 1586 if (m_options.m_class_name.empty()) { 1587 new_cmd_sp.reset(new CommandObjectPythonFunction( 1588 m_interpreter, m_cmd_name, m_options.m_funct_name, 1589 m_options.m_short_help, m_synchronicity)); 1590 } else { 1591 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1592 if (!interpreter) { 1593 result.AppendError("cannot find ScriptInterpreter"); 1594 return false; 1595 } 1596 1597 auto cmd_obj_sp = interpreter->CreateScriptCommandObject( 1598 m_options.m_class_name.c_str()); 1599 if (!cmd_obj_sp) { 1600 result.AppendError("cannot create helper object"); 1601 return false; 1602 } 1603 1604 new_cmd_sp.reset(new CommandObjectScriptingObject( 1605 m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity)); 1606 } 1607 1608 // Assume we're going to succeed... 1609 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1610 if (!m_container) { 1611 Status add_error = 1612 m_interpreter.AddUserCommand(m_cmd_name, new_cmd_sp, m_overwrite); 1613 if (add_error.Fail()) 1614 result.AppendErrorWithFormat("cannot add command: %s", 1615 add_error.AsCString()); 1616 } else { 1617 llvm::Error llvm_error = 1618 m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite); 1619 if (llvm_error) 1620 result.AppendErrorWithFormat("cannot add command: %s", 1621 llvm::toString(std::move(llvm_error)).c_str()); 1622 } 1623 return result.Succeeded(); 1624 } 1625 1626 CommandOptions m_options; 1627 std::string m_cmd_name; 1628 CommandObjectMultiword *m_container = nullptr; 1629 std::string m_short_help; 1630 bool m_overwrite = false; 1631 ScriptedCommandSynchronicity m_synchronicity = 1632 eScriptedCommandSynchronicitySynchronous; 1633 }; 1634 1635 // CommandObjectCommandsScriptList 1636 1637 class CommandObjectCommandsScriptList : public CommandObjectParsed { 1638 public: 1639 CommandObjectCommandsScriptList(CommandInterpreter &interpreter) 1640 : CommandObjectParsed(interpreter, "command script list", 1641 "List defined top-level scripted commands.", 1642 nullptr) {} 1643 1644 ~CommandObjectCommandsScriptList() override = default; 1645 1646 bool DoExecute(Args &command, CommandReturnObject &result) override { 1647 m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef); 1648 1649 result.SetStatus(eReturnStatusSuccessFinishResult); 1650 1651 return true; 1652 } 1653 }; 1654 1655 // CommandObjectCommandsScriptClear 1656 1657 class CommandObjectCommandsScriptClear : public CommandObjectParsed { 1658 public: 1659 CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) 1660 : CommandObjectParsed(interpreter, "command script clear", 1661 "Delete all scripted commands.", nullptr) {} 1662 1663 ~CommandObjectCommandsScriptClear() override = default; 1664 1665 protected: 1666 bool DoExecute(Args &command, CommandReturnObject &result) override { 1667 m_interpreter.RemoveAllUser(); 1668 1669 result.SetStatus(eReturnStatusSuccessFinishResult); 1670 1671 return true; 1672 } 1673 }; 1674 1675 // CommandObjectCommandsScriptDelete 1676 1677 class CommandObjectCommandsScriptDelete : public CommandObjectParsed { 1678 public: 1679 CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) 1680 : CommandObjectParsed( 1681 interpreter, "command script delete", 1682 "Delete a scripted command by specifying the path to the command.", 1683 nullptr) { 1684 CommandArgumentEntry arg1; 1685 CommandArgumentData cmd_arg; 1686 1687 // This is a list of command names forming the path to the command 1688 // to be deleted. 1689 cmd_arg.arg_type = eArgTypeCommand; 1690 cmd_arg.arg_repetition = eArgRepeatPlus; 1691 1692 // There is only one variant this argument could be; put it into the 1693 // argument entry. 1694 arg1.push_back(cmd_arg); 1695 1696 // Push the data for the first argument into the m_arguments vector. 1697 m_arguments.push_back(arg1); 1698 } 1699 1700 ~CommandObjectCommandsScriptDelete() override = default; 1701 1702 void 1703 HandleArgumentCompletion(CompletionRequest &request, 1704 OptionElementVector &opt_element_vector) override { 1705 CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request, 1706 opt_element_vector); 1707 } 1708 1709 protected: 1710 bool DoExecute(Args &command, CommandReturnObject &result) override { 1711 1712 llvm::StringRef root_cmd = command[0].ref(); 1713 size_t num_args = command.GetArgumentCount(); 1714 1715 if (root_cmd.empty()) { 1716 result.AppendErrorWithFormat("empty root command name"); 1717 return false; 1718 } 1719 if (!m_interpreter.HasUserCommands() && 1720 !m_interpreter.HasUserMultiwordCommands()) { 1721 result.AppendErrorWithFormat("can only delete user defined commands, " 1722 "but no user defined commands found"); 1723 return false; 1724 } 1725 1726 CommandObjectSP cmd_sp = m_interpreter.GetCommandSPExact(root_cmd); 1727 if (!cmd_sp) { 1728 result.AppendErrorWithFormat("command '%s' not found.", 1729 command[0].c_str()); 1730 return false; 1731 } 1732 if (!cmd_sp->IsUserCommand()) { 1733 result.AppendErrorWithFormat("command '%s' is not a user command.", 1734 command[0].c_str()); 1735 return false; 1736 } 1737 if (cmd_sp->GetAsMultiwordCommand() && num_args == 1) { 1738 result.AppendErrorWithFormat("command '%s' is a multi-word command.\n " 1739 "Delete with \"command container delete\"", 1740 command[0].c_str()); 1741 return false; 1742 } 1743 1744 if (command.GetArgumentCount() == 1) { 1745 m_interpreter.RemoveUser(root_cmd); 1746 result.SetStatus(eReturnStatusSuccessFinishResult); 1747 return true; 1748 } 1749 // We're deleting a command from a multiword command. Verify the command 1750 // path: 1751 Status error; 1752 CommandObjectMultiword *container = 1753 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 1754 error); 1755 if (error.Fail()) { 1756 result.AppendErrorWithFormat("could not resolve command path: %s", 1757 error.AsCString()); 1758 return false; 1759 } 1760 if (!container) { 1761 // This means that command only had a leaf command, so the container is 1762 // the root. That should have been handled above. 1763 result.AppendErrorWithFormat("could not find a container for '%s'", 1764 command[0].c_str()); 1765 return false; 1766 } 1767 const char *leaf_cmd = command[num_args - 1].c_str(); 1768 llvm::Error llvm_error = container->RemoveUserSubcommand(leaf_cmd, 1769 /* multiword not okay */ false); 1770 if (llvm_error) { 1771 result.AppendErrorWithFormat("could not delete command '%s': %s", 1772 leaf_cmd, 1773 llvm::toString(std::move(llvm_error)).c_str()); 1774 return false; 1775 } 1776 1777 Stream &out_stream = result.GetOutputStream(); 1778 1779 out_stream << "Deleted command:"; 1780 for (size_t idx = 0; idx < num_args; idx++) { 1781 out_stream << ' '; 1782 out_stream << command[idx].c_str(); 1783 } 1784 out_stream << '\n'; 1785 result.SetStatus(eReturnStatusSuccessFinishResult); 1786 return true; 1787 } 1788 }; 1789 1790 #pragma mark CommandObjectMultiwordCommandsScript 1791 1792 // CommandObjectMultiwordCommandsScript 1793 1794 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword { 1795 public: 1796 CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter) 1797 : CommandObjectMultiword( 1798 interpreter, "command script", 1799 "Commands for managing custom " 1800 "commands implemented by " 1801 "interpreter scripts.", 1802 "command script <subcommand> [<subcommand-options>]") { 1803 LoadSubCommand("add", CommandObjectSP( 1804 new CommandObjectCommandsScriptAdd(interpreter))); 1805 LoadSubCommand( 1806 "delete", 1807 CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter))); 1808 LoadSubCommand( 1809 "clear", 1810 CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter))); 1811 LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList( 1812 interpreter))); 1813 LoadSubCommand( 1814 "import", 1815 CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter))); 1816 } 1817 1818 ~CommandObjectMultiwordCommandsScript() override = default; 1819 }; 1820 1821 #pragma mark CommandObjectCommandContainer 1822 #define LLDB_OPTIONS_container_add 1823 #include "CommandOptions.inc" 1824 1825 class CommandObjectCommandsContainerAdd : public CommandObjectParsed { 1826 public: 1827 CommandObjectCommandsContainerAdd(CommandInterpreter &interpreter) 1828 : CommandObjectParsed( 1829 interpreter, "command container add", 1830 "Add a container command to lldb. Adding to built-" 1831 "in container commands is not allowed.", 1832 "command container add [[path1]...] container-name") { 1833 CommandArgumentEntry arg1; 1834 CommandArgumentData cmd_arg; 1835 1836 // This is one or more command names, which form the path to the command 1837 // you want to add. 1838 cmd_arg.arg_type = eArgTypeCommand; 1839 cmd_arg.arg_repetition = eArgRepeatPlus; 1840 1841 // There is only one variant this argument could be; put it into the 1842 // argument entry. 1843 arg1.push_back(cmd_arg); 1844 1845 // Push the data for the first argument into the m_arguments vector. 1846 m_arguments.push_back(arg1); 1847 } 1848 1849 ~CommandObjectCommandsContainerAdd() override = default; 1850 1851 Options *GetOptions() override { return &m_options; } 1852 1853 void 1854 HandleArgumentCompletion(CompletionRequest &request, 1855 OptionElementVector &opt_element_vector) override { 1856 CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request, 1857 opt_element_vector); 1858 } 1859 1860 protected: 1861 class CommandOptions : public Options { 1862 public: 1863 CommandOptions() = default; 1864 1865 ~CommandOptions() override = default; 1866 1867 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1868 ExecutionContext *execution_context) override { 1869 Status error; 1870 const int short_option = m_getopt_table[option_idx].val; 1871 1872 switch (short_option) { 1873 case 'h': 1874 if (!option_arg.empty()) 1875 m_short_help = std::string(option_arg); 1876 break; 1877 case 'o': 1878 m_overwrite = true; 1879 break; 1880 case 'H': 1881 if (!option_arg.empty()) 1882 m_long_help = std::string(option_arg); 1883 break; 1884 default: 1885 llvm_unreachable("Unimplemented option"); 1886 } 1887 1888 return error; 1889 } 1890 1891 void OptionParsingStarting(ExecutionContext *execution_context) override { 1892 m_short_help.clear(); 1893 m_long_help.clear(); 1894 m_overwrite = false; 1895 } 1896 1897 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1898 return llvm::makeArrayRef(g_container_add_options); 1899 } 1900 1901 // Instance variables to hold the values for command options. 1902 1903 std::string m_short_help; 1904 std::string m_long_help; 1905 bool m_overwrite = false; 1906 }; 1907 bool DoExecute(Args &command, CommandReturnObject &result) override { 1908 size_t num_args = command.GetArgumentCount(); 1909 1910 if (num_args == 0) { 1911 result.AppendError("no command was specified"); 1912 return false; 1913 } 1914 1915 if (num_args == 1) { 1916 // We're adding this as a root command, so use the interpreter. 1917 const char *cmd_name = command.GetArgumentAtIndex(0); 1918 auto cmd_sp = CommandObjectSP(new CommandObjectMultiword( 1919 GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(), 1920 m_options.m_long_help.c_str())); 1921 cmd_sp->GetAsMultiwordCommand()->SetRemovable(true); 1922 Status add_error = GetCommandInterpreter().AddUserCommand( 1923 cmd_name, cmd_sp, m_options.m_overwrite); 1924 if (add_error.Fail()) { 1925 result.AppendErrorWithFormat("error adding command: %s", 1926 add_error.AsCString()); 1927 return false; 1928 } 1929 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1930 return true; 1931 } 1932 1933 // We're adding this to a subcommand, first find the subcommand: 1934 Status path_error; 1935 CommandObjectMultiword *add_to_me = 1936 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 1937 path_error); 1938 1939 if (!add_to_me) { 1940 result.AppendErrorWithFormat("error adding command: %s", 1941 path_error.AsCString()); 1942 return false; 1943 } 1944 1945 const char *cmd_name = command.GetArgumentAtIndex(num_args - 1); 1946 auto cmd_sp = CommandObjectSP(new CommandObjectMultiword( 1947 GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(), 1948 m_options.m_long_help.c_str())); 1949 llvm::Error llvm_error = 1950 add_to_me->LoadUserSubcommand(cmd_name, cmd_sp, m_options.m_overwrite); 1951 if (llvm_error) { 1952 result.AppendErrorWithFormat("error adding subcommand: %s", 1953 llvm::toString(std::move(llvm_error)).c_str()); 1954 return false; 1955 } 1956 1957 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1958 return true; 1959 } 1960 1961 private: 1962 CommandOptions m_options; 1963 }; 1964 1965 #define LLDB_OPTIONS_multiword_delete 1966 #include "CommandOptions.inc" 1967 class CommandObjectCommandsContainerDelete : public CommandObjectParsed { 1968 public: 1969 CommandObjectCommandsContainerDelete(CommandInterpreter &interpreter) 1970 : CommandObjectParsed( 1971 interpreter, "command container delete", 1972 "Delete a container command previously added to " 1973 "lldb.", 1974 "command container delete [[path1] ...] container-cmd") { 1975 CommandArgumentEntry arg1; 1976 CommandArgumentData cmd_arg; 1977 1978 // This is one or more command names, which form the path to the command 1979 // you want to add. 1980 cmd_arg.arg_type = eArgTypeCommand; 1981 cmd_arg.arg_repetition = eArgRepeatPlus; 1982 1983 // There is only one variant this argument could be; put it into the 1984 // argument entry. 1985 arg1.push_back(cmd_arg); 1986 1987 // Push the data for the first argument into the m_arguments vector. 1988 m_arguments.push_back(arg1); 1989 } 1990 1991 ~CommandObjectCommandsContainerDelete() override = default; 1992 1993 void 1994 HandleArgumentCompletion(CompletionRequest &request, 1995 OptionElementVector &opt_element_vector) override { 1996 CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request, 1997 opt_element_vector); 1998 } 1999 2000 protected: 2001 bool DoExecute(Args &command, CommandReturnObject &result) override { 2002 size_t num_args = command.GetArgumentCount(); 2003 2004 if (num_args == 0) { 2005 result.AppendError("No command was specified."); 2006 return false; 2007 } 2008 2009 if (num_args == 1) { 2010 // We're removing a root command, so we need to delete it from the 2011 // interpreter. 2012 const char *cmd_name = command.GetArgumentAtIndex(0); 2013 // Let's do a little more work here so we can do better error reporting. 2014 CommandInterpreter &interp = GetCommandInterpreter(); 2015 CommandObjectSP cmd_sp = interp.GetCommandSPExact(cmd_name); 2016 if (!cmd_sp) { 2017 result.AppendErrorWithFormat("container command %s doesn't exist.", 2018 cmd_name); 2019 return false; 2020 } 2021 if (!cmd_sp->IsUserCommand()) { 2022 result.AppendErrorWithFormat( 2023 "container command %s is not a user command", cmd_name); 2024 return false; 2025 } 2026 if (!cmd_sp->GetAsMultiwordCommand()) { 2027 result.AppendErrorWithFormat("command %s is not a container command", 2028 cmd_name); 2029 return false; 2030 } 2031 2032 bool did_remove = GetCommandInterpreter().RemoveUserMultiword(cmd_name); 2033 if (!did_remove) { 2034 result.AppendErrorWithFormat("error removing command %s.", cmd_name); 2035 return false; 2036 } 2037 2038 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2039 return true; 2040 } 2041 2042 // We're removing a subcommand, first find the subcommand's owner: 2043 Status path_error; 2044 CommandObjectMultiword *container = 2045 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 2046 path_error); 2047 2048 if (!container) { 2049 result.AppendErrorWithFormat("error removing container command: %s", 2050 path_error.AsCString()); 2051 return false; 2052 } 2053 const char *leaf = command.GetArgumentAtIndex(num_args - 1); 2054 llvm::Error llvm_error = 2055 container->RemoveUserSubcommand(leaf, /* multiword okay */ true); 2056 if (llvm_error) { 2057 result.AppendErrorWithFormat("error removing container command: %s", 2058 llvm::toString(std::move(llvm_error)).c_str()); 2059 return false; 2060 } 2061 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2062 return true; 2063 } 2064 }; 2065 2066 class CommandObjectCommandContainer : public CommandObjectMultiword { 2067 public: 2068 CommandObjectCommandContainer(CommandInterpreter &interpreter) 2069 : CommandObjectMultiword( 2070 interpreter, "command container", 2071 "Commands for adding container commands to lldb. " 2072 "Container commands are containers for other commands. You can " 2073 "add nested container commands by specifying a command path, " 2074 "but you can't add commands into the built-in command hierarchy.", 2075 "command container <subcommand> [<subcommand-options>]") { 2076 LoadSubCommand("add", CommandObjectSP(new CommandObjectCommandsContainerAdd( 2077 interpreter))); 2078 LoadSubCommand( 2079 "delete", 2080 CommandObjectSP(new CommandObjectCommandsContainerDelete(interpreter))); 2081 } 2082 2083 ~CommandObjectCommandContainer() override = default; 2084 }; 2085 2086 #pragma mark CommandObjectMultiwordCommands 2087 2088 // CommandObjectMultiwordCommands 2089 2090 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands( 2091 CommandInterpreter &interpreter) 2092 : CommandObjectMultiword(interpreter, "command", 2093 "Commands for managing custom LLDB commands.", 2094 "command <subcommand> [<subcommand-options>]") { 2095 LoadSubCommand("source", 2096 CommandObjectSP(new CommandObjectCommandsSource(interpreter))); 2097 LoadSubCommand("alias", 2098 CommandObjectSP(new CommandObjectCommandsAlias(interpreter))); 2099 LoadSubCommand("unalias", CommandObjectSP( 2100 new CommandObjectCommandsUnalias(interpreter))); 2101 LoadSubCommand("delete", 2102 CommandObjectSP(new CommandObjectCommandsDelete(interpreter))); 2103 LoadSubCommand("container", CommandObjectSP(new CommandObjectCommandContainer( 2104 interpreter))); 2105 LoadSubCommand( 2106 "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter))); 2107 LoadSubCommand( 2108 "script", 2109 CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter))); 2110 } 2111 2112 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default; 2113