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 AddSimpleArgumentList(eArgTypeFilename); 45 } 46 47 ~CommandObjectCommandsSource() override = default; 48 49 std::optional<std::string> GetRepeatCommand(Args ¤t_command_args, 50 uint32_t index) override { 51 return std::string(""); 52 } 53 54 Options *GetOptions() override { return &m_options; } 55 56 protected: 57 class CommandOptions : public Options { 58 public: 59 CommandOptions() 60 : m_stop_on_error(true), m_silent_run(false), m_stop_on_continue(true), 61 m_cmd_relative_to_command_file(false) {} 62 63 ~CommandOptions() override = default; 64 65 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 66 ExecutionContext *execution_context) override { 67 Status error; 68 const int short_option = m_getopt_table[option_idx].val; 69 70 switch (short_option) { 71 case 'e': 72 error = m_stop_on_error.SetValueFromString(option_arg); 73 break; 74 75 case 'c': 76 error = m_stop_on_continue.SetValueFromString(option_arg); 77 break; 78 79 case 'C': 80 m_cmd_relative_to_command_file = true; 81 break; 82 83 case 's': 84 error = m_silent_run.SetValueFromString(option_arg); 85 break; 86 87 default: 88 llvm_unreachable("Unimplemented option"); 89 } 90 91 return error; 92 } 93 94 void OptionParsingStarting(ExecutionContext *execution_context) override { 95 m_stop_on_error.Clear(); 96 m_silent_run.Clear(); 97 m_stop_on_continue.Clear(); 98 m_cmd_relative_to_command_file.Clear(); 99 } 100 101 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 102 return llvm::ArrayRef(g_source_options); 103 } 104 105 // Instance variables to hold the values for command options. 106 107 OptionValueBoolean m_stop_on_error; 108 OptionValueBoolean m_silent_run; 109 OptionValueBoolean m_stop_on_continue; 110 OptionValueBoolean m_cmd_relative_to_command_file; 111 }; 112 113 void DoExecute(Args &command, CommandReturnObject &result) override { 114 if (command.GetArgumentCount() != 1) { 115 result.AppendErrorWithFormat( 116 "'%s' takes exactly one executable filename argument.\n", 117 GetCommandName().str().c_str()); 118 return; 119 } 120 121 FileSpec source_dir = {}; 122 if (m_options.m_cmd_relative_to_command_file) { 123 source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir(); 124 if (!source_dir) { 125 result.AppendError("command source -C can only be specified " 126 "from a command file"); 127 result.SetStatus(eReturnStatusFailed); 128 return; 129 } 130 } 131 132 FileSpec cmd_file(command[0].ref()); 133 if (source_dir) { 134 // Prepend the source_dir to the cmd_file path: 135 if (!cmd_file.IsRelative()) { 136 result.AppendError("command source -C can only be used " 137 "with a relative path."); 138 result.SetStatus(eReturnStatusFailed); 139 return; 140 } 141 cmd_file.MakeAbsolute(source_dir); 142 } 143 144 FileSystem::Instance().Resolve(cmd_file); 145 146 CommandInterpreterRunOptions options; 147 // If any options were set, then use them 148 if (m_options.m_stop_on_error.OptionWasSet() || 149 m_options.m_silent_run.OptionWasSet() || 150 m_options.m_stop_on_continue.OptionWasSet()) { 151 if (m_options.m_stop_on_continue.OptionWasSet()) 152 options.SetStopOnContinue( 153 m_options.m_stop_on_continue.GetCurrentValue()); 154 155 if (m_options.m_stop_on_error.OptionWasSet()) 156 options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue()); 157 158 // Individual silent setting is override for global command echo settings. 159 if (m_options.m_silent_run.GetCurrentValue()) { 160 options.SetSilent(true); 161 } else { 162 options.SetPrintResults(true); 163 options.SetPrintErrors(true); 164 options.SetEchoCommands(m_interpreter.GetEchoCommands()); 165 options.SetEchoCommentCommands(m_interpreter.GetEchoCommentCommands()); 166 } 167 } 168 169 m_interpreter.HandleCommandsFromFile(cmd_file, options, result); 170 } 171 172 CommandOptions m_options; 173 }; 174 175 #pragma mark CommandObjectCommandsAlias 176 // CommandObjectCommandsAlias 177 178 #define LLDB_OPTIONS_alias 179 #include "CommandOptions.inc" 180 181 static const char *g_python_command_instructions = 182 "Enter your Python command(s). Type 'DONE' to end.\n" 183 "You must define a Python function with this signature:\n" 184 "def my_command_impl(debugger, args, exe_ctx, result, internal_dict):\n"; 185 186 class CommandObjectCommandsAlias : public CommandObjectRaw { 187 protected: 188 class CommandOptions : public OptionGroup { 189 public: 190 CommandOptions() = default; 191 192 ~CommandOptions() override = default; 193 194 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 195 return llvm::ArrayRef(g_alias_options); 196 } 197 198 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, 199 ExecutionContext *execution_context) override { 200 Status error; 201 202 const int short_option = GetDefinitions()[option_idx].short_option; 203 std::string option_str(option_value); 204 205 switch (short_option) { 206 case 'h': 207 m_help.SetCurrentValue(option_str); 208 m_help.SetOptionWasSet(); 209 break; 210 211 case 'H': 212 m_long_help.SetCurrentValue(option_str); 213 m_long_help.SetOptionWasSet(); 214 break; 215 216 default: 217 llvm_unreachable("Unimplemented option"); 218 } 219 220 return error; 221 } 222 223 void OptionParsingStarting(ExecutionContext *execution_context) override { 224 m_help.Clear(); 225 m_long_help.Clear(); 226 } 227 228 OptionValueString m_help; 229 OptionValueString m_long_help; 230 }; 231 232 OptionGroupOptions m_option_group; 233 CommandOptions m_command_options; 234 235 public: 236 Options *GetOptions() override { return &m_option_group; } 237 238 CommandObjectCommandsAlias(CommandInterpreter &interpreter) 239 : CommandObjectRaw( 240 interpreter, "command alias", 241 "Define a custom command in terms of an existing command.") { 242 m_option_group.Append(&m_command_options); 243 m_option_group.Finalize(); 244 245 SetHelpLong( 246 "'alias' allows the user to create a short-cut or abbreviation for long \ 247 commands, multi-word commands, and commands that take particular options. \ 248 Below are some simple examples of how one might use the 'alias' command:" 249 R"( 250 251 (lldb) command alias sc script 252 253 Creates the abbreviation 'sc' for the 'script' command. 254 255 (lldb) command alias bp breakpoint 256 257 )" 258 " Creates the abbreviation 'bp' for the 'breakpoint' command. Since \ 259 breakpoint commands are two-word commands, the user would still need to \ 260 enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'." 261 R"( 262 263 (lldb) command alias bpl breakpoint list 264 265 Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'. 266 267 )" 268 "An alias can include some options for the command, with the values either \ 269 filled in at the time the alias is created, or specified as positional \ 270 arguments, to be filled in when the alias is invoked. The following example \ 271 shows how to create aliases with options:" 272 R"( 273 274 (lldb) command alias bfl breakpoint set -f %1 -l %2 275 276 )" 277 " Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \ 278 options already part of the alias. So if the user wants to set a breakpoint \ 279 by file and line without explicitly having to use the -f and -l options, the \ 280 user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \ 281 for the actual arguments that will be passed when the alias command is used. \ 282 The number in the placeholder refers to the position/order the actual value \ 283 occupies when the alias is used. All the occurrences of '%1' in the alias \ 284 will be replaced with the first argument, all the occurrences of '%2' in the \ 285 alias will be replaced with the second argument, and so on. This also allows \ 286 actual arguments to be used multiple times within an alias (see 'process \ 287 launch' example below)." 288 R"( 289 290 )" 291 "Note: the positional arguments must substitute as whole words in the resultant \ 292 command, so you can't at present do something like this to append the file extension \ 293 \".cpp\":" 294 R"( 295 296 (lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2 297 298 )" 299 "For more complex aliasing, use the \"command regex\" command instead. In the \ 300 'bfl' case above, the actual file value will be filled in with the first argument \ 301 following 'bfl' and the actual line number value will be filled in with the second \ 302 argument. The user would use this alias as follows:" 303 R"( 304 305 (lldb) command alias bfl breakpoint set -f %1 -l %2 306 (lldb) bfl my-file.c 137 307 308 This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'. 309 310 Another example: 311 312 (lldb) command alias pltty process launch -s -o %1 -e %1 313 (lldb) pltty /dev/tty0 314 315 Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0' 316 317 )" 318 "If the user always wanted to pass the same value to a particular option, the \ 319 alias could be defined with that value directly in the alias as a constant, \ 320 rather than using a positional placeholder:" 321 R"( 322 323 (lldb) command alias bl3 breakpoint set -f %1 -l 3 324 325 Always sets a breakpoint on line 3 of whatever file is indicated. 326 327 )" 328 329 "If the alias abbreviation or the full alias command collides with another \ 330 existing command, the command resolver will prefer to use the alias over any \ 331 other command as far as there is only one alias command match."); 332 333 CommandArgumentEntry arg1; 334 CommandArgumentEntry arg2; 335 CommandArgumentEntry arg3; 336 CommandArgumentData alias_arg; 337 CommandArgumentData cmd_arg; 338 CommandArgumentData options_arg; 339 340 // Define the first (and only) variant of this arg. 341 alias_arg.arg_type = eArgTypeAliasName; 342 alias_arg.arg_repetition = eArgRepeatPlain; 343 344 // There is only one variant this argument could be; put it into the 345 // argument entry. 346 arg1.push_back(alias_arg); 347 348 // Define the first (and only) variant of this arg. 349 cmd_arg.arg_type = eArgTypeCommandName; 350 cmd_arg.arg_repetition = eArgRepeatPlain; 351 352 // There is only one variant this argument could be; put it into the 353 // argument entry. 354 arg2.push_back(cmd_arg); 355 356 // Define the first (and only) variant of this arg. 357 options_arg.arg_type = eArgTypeAliasOptions; 358 options_arg.arg_repetition = eArgRepeatOptional; 359 360 // There is only one variant this argument could be; put it into the 361 // argument entry. 362 arg3.push_back(options_arg); 363 364 // Push the data for the first argument into the m_arguments vector. 365 m_arguments.push_back(arg1); 366 m_arguments.push_back(arg2); 367 m_arguments.push_back(arg3); 368 } 369 370 ~CommandObjectCommandsAlias() override = default; 371 372 protected: 373 void DoExecute(llvm::StringRef raw_command_line, 374 CommandReturnObject &result) override { 375 if (raw_command_line.empty()) { 376 result.AppendError("'command alias' requires at least two arguments"); 377 return; 378 } 379 380 ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext(); 381 m_option_group.NotifyOptionParsingStarting(&exe_ctx); 382 383 OptionsWithRaw args_with_suffix(raw_command_line); 384 385 if (args_with_suffix.HasArgs()) 386 if (!ParseOptionsAndNotify(args_with_suffix.GetArgs(), result, 387 m_option_group, exe_ctx)) 388 return; 389 390 llvm::StringRef raw_command_string = args_with_suffix.GetRawPart(); 391 Args args(raw_command_string); 392 393 if (args.GetArgumentCount() < 2) { 394 result.AppendError("'command alias' requires at least two arguments"); 395 return; 396 } 397 398 // Get the alias command. 399 400 auto alias_command = args[0].ref(); 401 if (alias_command.starts_with("-")) { 402 result.AppendError("aliases starting with a dash are not supported"); 403 if (alias_command == "--help" || alias_command == "--long-help") { 404 result.AppendWarning("if trying to pass options to 'command alias' add " 405 "a -- at the end of the options"); 406 } 407 return; 408 } 409 410 // Strip the new alias name off 'raw_command_string' (leave it on args, 411 // which gets passed to 'Execute', which does the stripping itself. 412 size_t pos = raw_command_string.find(alias_command); 413 if (pos == 0) { 414 raw_command_string = raw_command_string.substr(alias_command.size()); 415 pos = raw_command_string.find_first_not_of(' '); 416 if ((pos != std::string::npos) && (pos > 0)) 417 raw_command_string = raw_command_string.substr(pos); 418 } else { 419 result.AppendError("Error parsing command string. No alias created."); 420 return; 421 } 422 423 // Verify that the command is alias-able. 424 if (m_interpreter.CommandExists(alias_command)) { 425 result.AppendErrorWithFormat( 426 "'%s' is a permanent debugger command and cannot be redefined.\n", 427 args[0].c_str()); 428 return; 429 } 430 431 if (m_interpreter.UserMultiwordCommandExists(alias_command)) { 432 result.AppendErrorWithFormat( 433 "'%s' is a user container command and cannot be overwritten.\n" 434 "Delete it first with 'command container delete'\n", 435 args[0].c_str()); 436 return; 437 } 438 439 // Get CommandObject that is being aliased. The command name is read from 440 // the front of raw_command_string. raw_command_string is returned with the 441 // name of the command object stripped off the front. 442 llvm::StringRef original_raw_command_string = raw_command_string; 443 CommandObject *cmd_obj = 444 m_interpreter.GetCommandObjectForCommand(raw_command_string); 445 446 if (!cmd_obj) { 447 result.AppendErrorWithFormat("invalid command given to 'command alias'. " 448 "'%s' does not begin with a valid command." 449 " No alias created.", 450 original_raw_command_string.str().c_str()); 451 } else if (!cmd_obj->WantsRawCommandString()) { 452 // Note that args was initialized with the original command, and has not 453 // been updated to this point. Therefore can we pass it to the version of 454 // Execute that does not need/expect raw input in the alias. 455 HandleAliasingNormalCommand(args, result); 456 } else { 457 HandleAliasingRawCommand(alias_command, raw_command_string, *cmd_obj, 458 result); 459 } 460 } 461 462 bool HandleAliasingRawCommand(llvm::StringRef alias_command, 463 llvm::StringRef raw_command_string, 464 CommandObject &cmd_obj, 465 CommandReturnObject &result) { 466 // Verify & handle any options/arguments passed to the alias command 467 468 OptionArgVectorSP option_arg_vector_sp = 469 OptionArgVectorSP(new OptionArgVector); 470 471 const bool include_aliases = true; 472 // Look up the command using command's name first. This is to resolve 473 // aliases when you are making nested aliases. But if you don't find 474 // it that way, then it wasn't an alias and we can just use the object 475 // we were passed in. 476 CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact( 477 cmd_obj.GetCommandName(), include_aliases); 478 if (!cmd_obj_sp) 479 cmd_obj_sp = cmd_obj.shared_from_this(); 480 481 if (m_interpreter.AliasExists(alias_command) || 482 m_interpreter.UserCommandExists(alias_command)) { 483 result.AppendWarningWithFormat( 484 "Overwriting existing definition for '%s'.\n", 485 alias_command.str().c_str()); 486 } 487 if (CommandAlias *alias = m_interpreter.AddAlias( 488 alias_command, cmd_obj_sp, raw_command_string)) { 489 if (m_command_options.m_help.OptionWasSet()) 490 alias->SetHelp(m_command_options.m_help.GetCurrentValue()); 491 if (m_command_options.m_long_help.OptionWasSet()) 492 alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue()); 493 result.SetStatus(eReturnStatusSuccessFinishNoResult); 494 } else { 495 result.AppendError("Unable to create requested alias.\n"); 496 } 497 return result.Succeeded(); 498 } 499 500 bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) { 501 size_t argc = args.GetArgumentCount(); 502 503 if (argc < 2) { 504 result.AppendError("'command alias' requires at least two arguments"); 505 return false; 506 } 507 508 // Save these in std::strings since we're going to shift them off. 509 const std::string alias_command(std::string(args[0].ref())); 510 const std::string actual_command(std::string(args[1].ref())); 511 512 args.Shift(); // Shift the alias command word off the argument vector. 513 args.Shift(); // Shift the old command word off the argument vector. 514 515 // Verify that the command is alias'able, and get the appropriate command 516 // object. 517 518 if (m_interpreter.CommandExists(alias_command)) { 519 result.AppendErrorWithFormat( 520 "'%s' is a permanent debugger command and cannot be redefined.\n", 521 alias_command.c_str()); 522 return false; 523 } 524 525 if (m_interpreter.UserMultiwordCommandExists(alias_command)) { 526 result.AppendErrorWithFormat( 527 "'%s' is user container command and cannot be overwritten.\n" 528 "Delete it first with 'command container delete'", 529 alias_command.c_str()); 530 return false; 531 } 532 533 CommandObjectSP command_obj_sp( 534 m_interpreter.GetCommandSPExact(actual_command, true)); 535 CommandObjectSP subcommand_obj_sp; 536 bool use_subcommand = false; 537 if (!command_obj_sp) { 538 result.AppendErrorWithFormat("'%s' is not an existing command.\n", 539 actual_command.c_str()); 540 return false; 541 } 542 CommandObject *cmd_obj = command_obj_sp.get(); 543 CommandObject *sub_cmd_obj = nullptr; 544 OptionArgVectorSP option_arg_vector_sp = 545 OptionArgVectorSP(new OptionArgVector); 546 547 while (cmd_obj->IsMultiwordObject() && !args.empty()) { 548 auto sub_command = args[0].ref(); 549 assert(!sub_command.empty()); 550 subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command); 551 if (!subcommand_obj_sp) { 552 result.AppendErrorWithFormat( 553 "'%s' is not a valid sub-command of '%s'. " 554 "Unable to create alias.\n", 555 args[0].c_str(), actual_command.c_str()); 556 return false; 557 } 558 559 sub_cmd_obj = subcommand_obj_sp.get(); 560 use_subcommand = true; 561 args.Shift(); // Shift the sub_command word off the argument vector. 562 cmd_obj = sub_cmd_obj; 563 } 564 565 // Verify & handle any options/arguments passed to the alias command 566 567 std::string args_string; 568 569 if (!args.empty()) { 570 CommandObjectSP tmp_sp = 571 m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName()); 572 if (use_subcommand) 573 tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName()); 574 575 args.GetCommandString(args_string); 576 } 577 578 if (m_interpreter.AliasExists(alias_command) || 579 m_interpreter.UserCommandExists(alias_command)) { 580 result.AppendWarningWithFormat( 581 "Overwriting existing definition for '%s'.\n", alias_command.c_str()); 582 } 583 584 if (CommandAlias *alias = m_interpreter.AddAlias( 585 alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp, 586 args_string)) { 587 if (m_command_options.m_help.OptionWasSet()) 588 alias->SetHelp(m_command_options.m_help.GetCurrentValue()); 589 if (m_command_options.m_long_help.OptionWasSet()) 590 alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue()); 591 result.SetStatus(eReturnStatusSuccessFinishNoResult); 592 } else { 593 result.AppendError("Unable to create requested alias.\n"); 594 return false; 595 } 596 597 return result.Succeeded(); 598 } 599 }; 600 601 #pragma mark CommandObjectCommandsUnalias 602 // CommandObjectCommandsUnalias 603 604 class CommandObjectCommandsUnalias : public CommandObjectParsed { 605 public: 606 CommandObjectCommandsUnalias(CommandInterpreter &interpreter) 607 : CommandObjectParsed( 608 interpreter, "command unalias", 609 "Delete one or more custom commands defined by 'command alias'.", 610 nullptr) { 611 AddSimpleArgumentList(eArgTypeAliasName); 612 } 613 614 ~CommandObjectCommandsUnalias() override = default; 615 616 void 617 HandleArgumentCompletion(CompletionRequest &request, 618 OptionElementVector &opt_element_vector) override { 619 if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0) 620 return; 621 622 for (const auto &ent : m_interpreter.GetAliases()) { 623 request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp()); 624 } 625 } 626 627 protected: 628 void DoExecute(Args &args, CommandReturnObject &result) override { 629 CommandObject::CommandMap::iterator pos; 630 CommandObject *cmd_obj; 631 632 if (args.empty()) { 633 result.AppendError("must call 'unalias' with a valid alias"); 634 return; 635 } 636 637 auto command_name = args[0].ref(); 638 cmd_obj = m_interpreter.GetCommandObject(command_name); 639 if (!cmd_obj) { 640 result.AppendErrorWithFormat( 641 "'%s' is not a known command.\nTry 'help' to see a " 642 "current list of commands.\n", 643 args[0].c_str()); 644 return; 645 } 646 647 if (m_interpreter.CommandExists(command_name)) { 648 if (cmd_obj->IsRemovable()) { 649 result.AppendErrorWithFormat( 650 "'%s' is not an alias, it is a debugger command which can be " 651 "removed using the 'command delete' command.\n", 652 args[0].c_str()); 653 } else { 654 result.AppendErrorWithFormat( 655 "'%s' is a permanent debugger command and cannot be removed.\n", 656 args[0].c_str()); 657 } 658 return; 659 } 660 661 if (!m_interpreter.RemoveAlias(command_name)) { 662 if (m_interpreter.AliasExists(command_name)) 663 result.AppendErrorWithFormat( 664 "Error occurred while attempting to unalias '%s'.\n", 665 args[0].c_str()); 666 else 667 result.AppendErrorWithFormat("'%s' is not an existing alias.\n", 668 args[0].c_str()); 669 return; 670 } 671 672 result.SetStatus(eReturnStatusSuccessFinishNoResult); 673 } 674 }; 675 676 #pragma mark CommandObjectCommandsDelete 677 // CommandObjectCommandsDelete 678 679 class CommandObjectCommandsDelete : public CommandObjectParsed { 680 public: 681 CommandObjectCommandsDelete(CommandInterpreter &interpreter) 682 : CommandObjectParsed( 683 interpreter, "command delete", 684 "Delete one or more custom commands defined by 'command regex'.", 685 nullptr) { 686 AddSimpleArgumentList(eArgTypeCommandName); 687 } 688 689 ~CommandObjectCommandsDelete() override = default; 690 691 void 692 HandleArgumentCompletion(CompletionRequest &request, 693 OptionElementVector &opt_element_vector) override { 694 if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0) 695 return; 696 697 for (const auto &ent : m_interpreter.GetCommands()) { 698 if (ent.second->IsRemovable()) 699 request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp()); 700 } 701 } 702 703 protected: 704 void DoExecute(Args &args, CommandReturnObject &result) override { 705 CommandObject::CommandMap::iterator pos; 706 707 if (args.empty()) { 708 result.AppendErrorWithFormat("must call '%s' with one or more valid user " 709 "defined regular expression command names", 710 GetCommandName().str().c_str()); 711 return; 712 } 713 714 auto command_name = args[0].ref(); 715 if (!m_interpreter.CommandExists(command_name)) { 716 StreamString error_msg_stream; 717 const bool generate_upropos = true; 718 const bool generate_type_lookup = false; 719 CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage( 720 &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(), 721 generate_upropos, generate_type_lookup); 722 result.AppendError(error_msg_stream.GetString()); 723 return; 724 } 725 726 if (!m_interpreter.RemoveCommand(command_name)) { 727 result.AppendErrorWithFormat( 728 "'%s' is a permanent debugger command and cannot be removed.\n", 729 args[0].c_str()); 730 return; 731 } 732 733 result.SetStatus(eReturnStatusSuccessFinishNoResult); 734 } 735 }; 736 737 // CommandObjectCommandsAddRegex 738 739 #define LLDB_OPTIONS_regex 740 #include "CommandOptions.inc" 741 742 #pragma mark CommandObjectCommandsAddRegex 743 744 class CommandObjectCommandsAddRegex : public CommandObjectParsed, 745 public IOHandlerDelegateMultiline { 746 public: 747 CommandObjectCommandsAddRegex(CommandInterpreter &interpreter) 748 : CommandObjectParsed( 749 interpreter, "command regex", 750 "Define a custom command in terms of " 751 "existing commands by matching " 752 "regular expressions.", 753 "command regex <cmd-name> [s/<regex>/<subst>/ ...]"), 754 IOHandlerDelegateMultiline("", 755 IOHandlerDelegate::Completion::LLDBCommand) { 756 SetHelpLong( 757 R"( 758 )" 759 "This command allows the user to create powerful regular expression commands \ 760 with substitutions. The regular expressions and substitutions are specified \ 761 using the regular expression substitution format of:" 762 R"( 763 764 s/<regex>/<subst>/ 765 766 )" 767 "<regex> is a regular expression that can use parenthesis to capture regular \ 768 expression input and substitute the captured matches in the output using %1 \ 769 for the first match, %2 for the second, and so on." 770 R"( 771 772 )" 773 "The regular expressions can all be specified on the command line if more than \ 774 one argument is provided. If just the command name is provided on the command \ 775 line, then the regular expressions and substitutions can be entered on separate \ 776 lines, followed by an empty line to terminate the command definition." 777 R"( 778 779 EXAMPLES 780 781 )" 782 "The following example will define a regular expression command named 'f' that \ 783 will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \ 784 a number follows 'f':" 785 R"( 786 787 (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')"); 788 AddSimpleArgumentList(eArgTypeSEDStylePair, eArgRepeatOptional); 789 } 790 791 ~CommandObjectCommandsAddRegex() override = default; 792 793 protected: 794 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 795 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); 796 if (output_sp && interactive) { 797 output_sp->PutCString("Enter one or more sed substitution commands in " 798 "the form: 's/<regex>/<subst>/'.\nTerminate the " 799 "substitution list with an empty line.\n"); 800 output_sp->Flush(); 801 } 802 } 803 804 void IOHandlerInputComplete(IOHandler &io_handler, 805 std::string &data) override { 806 io_handler.SetIsDone(true); 807 if (m_regex_cmd_up) { 808 StringList lines; 809 if (lines.SplitIntoLines(data)) { 810 bool check_only = false; 811 for (const std::string &line : lines) { 812 Status error = AppendRegexSubstitution(line, check_only); 813 if (error.Fail()) { 814 if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) { 815 StreamSP out_stream = GetDebugger().GetAsyncOutputStream(); 816 out_stream->Printf("error: %s\n", error.AsCString()); 817 } 818 } 819 } 820 } 821 if (m_regex_cmd_up->HasRegexEntries()) { 822 CommandObjectSP cmd_sp(m_regex_cmd_up.release()); 823 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 824 } 825 } 826 } 827 828 void DoExecute(Args &command, CommandReturnObject &result) override { 829 const size_t argc = command.GetArgumentCount(); 830 if (argc == 0) { 831 result.AppendError("usage: 'command regex <command-name> " 832 "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n"); 833 return; 834 } 835 836 Status error; 837 auto name = command[0].ref(); 838 m_regex_cmd_up = std::make_unique<CommandObjectRegexCommand>( 839 m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 0, 840 true); 841 842 if (argc == 1) { 843 Debugger &debugger = GetDebugger(); 844 bool color_prompt = debugger.GetUseColor(); 845 const bool multiple_lines = true; // Get multiple lines 846 IOHandlerSP io_handler_sp(new IOHandlerEditline( 847 debugger, IOHandler::Type::Other, 848 "lldb-regex", // Name of input reader for history 849 llvm::StringRef("> "), // Prompt 850 llvm::StringRef(), // Continuation prompt 851 multiple_lines, color_prompt, 852 0, // Don't show line numbers 853 *this)); 854 855 if (io_handler_sp) { 856 debugger.RunIOHandlerAsync(io_handler_sp); 857 result.SetStatus(eReturnStatusSuccessFinishNoResult); 858 } 859 } else { 860 for (auto &entry : command.entries().drop_front()) { 861 bool check_only = false; 862 error = AppendRegexSubstitution(entry.ref(), check_only); 863 if (error.Fail()) 864 break; 865 } 866 867 if (error.Success()) { 868 AddRegexCommandToInterpreter(); 869 } 870 } 871 if (error.Fail()) { 872 result.AppendError(error.AsCString()); 873 } 874 } 875 876 Status AppendRegexSubstitution(const llvm::StringRef ®ex_sed, 877 bool check_only) { 878 Status error; 879 880 if (!m_regex_cmd_up) { 881 return Status::FromErrorStringWithFormat( 882 "invalid regular expression command object for: '%.*s'", 883 (int)regex_sed.size(), regex_sed.data()); 884 return error; 885 } 886 887 size_t regex_sed_size = regex_sed.size(); 888 889 if (regex_sed_size <= 1) { 890 return Status::FromErrorStringWithFormat( 891 "regular expression substitution string is too short: '%.*s'", 892 (int)regex_sed.size(), regex_sed.data()); 893 return error; 894 } 895 896 if (regex_sed[0] != 's') { 897 return Status::FromErrorStringWithFormat( 898 "regular expression substitution string " 899 "doesn't start with 's': '%.*s'", 900 (int)regex_sed.size(), regex_sed.data()); 901 return error; 902 } 903 const size_t first_separator_char_pos = 1; 904 // use the char that follows 's' as the regex separator character so we can 905 // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|" 906 const char separator_char = regex_sed[first_separator_char_pos]; 907 const size_t second_separator_char_pos = 908 regex_sed.find(separator_char, first_separator_char_pos + 1); 909 910 if (second_separator_char_pos == std::string::npos) { 911 return Status::FromErrorStringWithFormat( 912 "missing second '%c' separator char after '%.*s' in '%.*s'", 913 separator_char, 914 (int)(regex_sed.size() - first_separator_char_pos - 1), 915 regex_sed.data() + (first_separator_char_pos + 1), 916 (int)regex_sed.size(), regex_sed.data()); 917 return error; 918 } 919 920 const size_t third_separator_char_pos = 921 regex_sed.find(separator_char, second_separator_char_pos + 1); 922 923 if (third_separator_char_pos == std::string::npos) { 924 return Status::FromErrorStringWithFormat( 925 "missing third '%c' separator char after '%.*s' in '%.*s'", 926 separator_char, 927 (int)(regex_sed.size() - second_separator_char_pos - 1), 928 regex_sed.data() + (second_separator_char_pos + 1), 929 (int)regex_sed.size(), regex_sed.data()); 930 return error; 931 } 932 933 if (third_separator_char_pos != regex_sed_size - 1) { 934 // Make sure that everything that follows the last regex separator char 935 if (regex_sed.find_first_not_of("\t\n\v\f\r ", 936 third_separator_char_pos + 1) != 937 std::string::npos) { 938 return Status::FromErrorStringWithFormat( 939 "extra data found after the '%.*s' regular expression substitution " 940 "string: '%.*s'", 941 (int)third_separator_char_pos + 1, regex_sed.data(), 942 (int)(regex_sed.size() - third_separator_char_pos - 1), 943 regex_sed.data() + (third_separator_char_pos + 1)); 944 return error; 945 } 946 } else if (first_separator_char_pos + 1 == second_separator_char_pos) { 947 return Status::FromErrorStringWithFormat( 948 "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 949 separator_char, separator_char, separator_char, (int)regex_sed.size(), 950 regex_sed.data()); 951 return error; 952 } else if (second_separator_char_pos + 1 == third_separator_char_pos) { 953 return Status::FromErrorStringWithFormat( 954 "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 955 separator_char, separator_char, separator_char, (int)regex_sed.size(), 956 regex_sed.data()); 957 return error; 958 } 959 960 if (!check_only) { 961 std::string regex(std::string(regex_sed.substr( 962 first_separator_char_pos + 1, 963 second_separator_char_pos - first_separator_char_pos - 1))); 964 std::string subst(std::string(regex_sed.substr( 965 second_separator_char_pos + 1, 966 third_separator_char_pos - second_separator_char_pos - 1))); 967 m_regex_cmd_up->AddRegexCommand(regex, subst); 968 } 969 return error; 970 } 971 972 void AddRegexCommandToInterpreter() { 973 if (m_regex_cmd_up) { 974 if (m_regex_cmd_up->HasRegexEntries()) { 975 CommandObjectSP cmd_sp(m_regex_cmd_up.release()); 976 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 977 } 978 } 979 } 980 981 private: 982 std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up; 983 984 class CommandOptions : public Options { 985 public: 986 CommandOptions() = default; 987 988 ~CommandOptions() override = default; 989 990 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 991 ExecutionContext *execution_context) override { 992 Status error; 993 const int short_option = m_getopt_table[option_idx].val; 994 995 switch (short_option) { 996 case 'h': 997 m_help.assign(std::string(option_arg)); 998 break; 999 case 's': 1000 m_syntax.assign(std::string(option_arg)); 1001 break; 1002 default: 1003 llvm_unreachable("Unimplemented option"); 1004 } 1005 1006 return error; 1007 } 1008 1009 void OptionParsingStarting(ExecutionContext *execution_context) override { 1010 m_help.clear(); 1011 m_syntax.clear(); 1012 } 1013 1014 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1015 return llvm::ArrayRef(g_regex_options); 1016 } 1017 1018 llvm::StringRef GetHelp() { return m_help; } 1019 1020 llvm::StringRef GetSyntax() { return m_syntax; } 1021 1022 protected: 1023 // Instance variables to hold the values for command options. 1024 1025 std::string m_help; 1026 std::string m_syntax; 1027 }; 1028 1029 Options *GetOptions() override { return &m_options; } 1030 1031 CommandOptions m_options; 1032 }; 1033 1034 class CommandObjectPythonFunction : public CommandObjectRaw { 1035 public: 1036 CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name, 1037 std::string funct, std::string help, 1038 ScriptedCommandSynchronicity synch, 1039 CompletionType completion_type) 1040 : CommandObjectRaw(interpreter, name), m_function_name(funct), 1041 m_synchro(synch), m_completion_type(completion_type) { 1042 if (!help.empty()) 1043 SetHelp(help); 1044 else { 1045 StreamString stream; 1046 stream.Printf("For more information run 'help %s'", name.c_str()); 1047 SetHelp(stream.GetString()); 1048 } 1049 } 1050 1051 ~CommandObjectPythonFunction() override = default; 1052 1053 bool IsRemovable() const override { return true; } 1054 1055 const std::string &GetFunctionName() { return m_function_name; } 1056 1057 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1058 1059 llvm::StringRef GetHelpLong() override { 1060 if (m_fetched_help_long) 1061 return CommandObjectRaw::GetHelpLong(); 1062 1063 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1064 if (!scripter) 1065 return CommandObjectRaw::GetHelpLong(); 1066 1067 std::string docstring; 1068 m_fetched_help_long = 1069 scripter->GetDocumentationForItem(m_function_name.c_str(), docstring); 1070 if (!docstring.empty()) 1071 SetHelpLong(docstring); 1072 return CommandObjectRaw::GetHelpLong(); 1073 } 1074 1075 void 1076 HandleArgumentCompletion(CompletionRequest &request, 1077 OptionElementVector &opt_element_vector) override { 1078 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 1079 GetCommandInterpreter(), m_completion_type, request, nullptr); 1080 } 1081 1082 bool WantsCompletion() override { return true; } 1083 1084 protected: 1085 void DoExecute(llvm::StringRef raw_command_line, 1086 CommandReturnObject &result) override { 1087 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1088 1089 m_interpreter.IncreaseCommandUsage(*this); 1090 1091 Status error; 1092 1093 result.SetStatus(eReturnStatusInvalid); 1094 1095 if (!scripter || !scripter->RunScriptBasedCommand( 1096 m_function_name.c_str(), raw_command_line, m_synchro, 1097 result, error, m_exe_ctx)) { 1098 result.AppendError(error.AsCString()); 1099 } else { 1100 // Don't change the status if the command already set it... 1101 if (result.GetStatus() == eReturnStatusInvalid) { 1102 if (result.GetOutputData().empty()) 1103 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1104 else 1105 result.SetStatus(eReturnStatusSuccessFinishResult); 1106 } 1107 } 1108 } 1109 1110 private: 1111 std::string m_function_name; 1112 ScriptedCommandSynchronicity m_synchro; 1113 bool m_fetched_help_long = false; 1114 CompletionType m_completion_type = eNoCompletion; 1115 }; 1116 1117 /// This class implements a "raw" scripted command. lldb does no parsing of the 1118 /// command line, instead passing the line unaltered (except for backtick 1119 /// substitution). 1120 class CommandObjectScriptingObjectRaw : public CommandObjectRaw { 1121 public: 1122 CommandObjectScriptingObjectRaw(CommandInterpreter &interpreter, 1123 std::string name, 1124 StructuredData::GenericSP cmd_obj_sp, 1125 ScriptedCommandSynchronicity synch, 1126 CompletionType completion_type) 1127 : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp), 1128 m_synchro(synch), m_fetched_help_short(false), 1129 m_fetched_help_long(false), m_completion_type(completion_type) { 1130 StreamString stream; 1131 stream.Printf("For more information run 'help %s'", name.c_str()); 1132 SetHelp(stream.GetString()); 1133 if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter()) 1134 GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); 1135 } 1136 1137 ~CommandObjectScriptingObjectRaw() override = default; 1138 1139 void 1140 HandleArgumentCompletion(CompletionRequest &request, 1141 OptionElementVector &opt_element_vector) override { 1142 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 1143 GetCommandInterpreter(), m_completion_type, request, nullptr); 1144 } 1145 1146 bool WantsCompletion() override { return true; } 1147 1148 bool IsRemovable() const override { return true; } 1149 1150 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1151 1152 std::optional<std::string> GetRepeatCommand(Args &args, 1153 uint32_t index) override { 1154 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1155 if (!scripter) 1156 return std::nullopt; 1157 1158 return scripter->GetRepeatCommandForScriptedCommand(m_cmd_obj_sp, args); 1159 } 1160 1161 llvm::StringRef GetHelp() override { 1162 if (m_fetched_help_short) 1163 return CommandObjectRaw::GetHelp(); 1164 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1165 if (!scripter) 1166 return CommandObjectRaw::GetHelp(); 1167 std::string docstring; 1168 m_fetched_help_short = 1169 scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring); 1170 if (!docstring.empty()) 1171 SetHelp(docstring); 1172 1173 return CommandObjectRaw::GetHelp(); 1174 } 1175 1176 llvm::StringRef GetHelpLong() override { 1177 if (m_fetched_help_long) 1178 return CommandObjectRaw::GetHelpLong(); 1179 1180 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1181 if (!scripter) 1182 return CommandObjectRaw::GetHelpLong(); 1183 1184 std::string docstring; 1185 m_fetched_help_long = 1186 scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring); 1187 if (!docstring.empty()) 1188 SetHelpLong(docstring); 1189 return CommandObjectRaw::GetHelpLong(); 1190 } 1191 1192 protected: 1193 void DoExecute(llvm::StringRef raw_command_line, 1194 CommandReturnObject &result) override { 1195 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1196 1197 Status error; 1198 1199 result.SetStatus(eReturnStatusInvalid); 1200 1201 if (!scripter || 1202 !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line, 1203 m_synchro, result, error, m_exe_ctx)) { 1204 result.AppendError(error.AsCString()); 1205 } else { 1206 // Don't change the status if the command already set it... 1207 if (result.GetStatus() == eReturnStatusInvalid) { 1208 if (result.GetOutputData().empty()) 1209 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1210 else 1211 result.SetStatus(eReturnStatusSuccessFinishResult); 1212 } 1213 } 1214 } 1215 1216 private: 1217 StructuredData::GenericSP m_cmd_obj_sp; 1218 ScriptedCommandSynchronicity m_synchro; 1219 bool m_fetched_help_short : 1; 1220 bool m_fetched_help_long : 1; 1221 CompletionType m_completion_type = eNoCompletion; 1222 }; 1223 1224 1225 /// This command implements a lldb parsed scripted command. The command 1226 /// provides a definition of the options and arguments, and a option value 1227 /// setting callback, and then the command's execution function gets passed 1228 /// just the parsed arguments. 1229 /// Note, implementing a command in Python using these base interfaces is a bit 1230 /// of a pain, but it is much easier to export this low level interface, and 1231 /// then make it nicer on the Python side, than to try to do that in a 1232 /// script language neutral way. 1233 /// So I've also added a base class in Python that provides a table-driven 1234 /// way of defining the options and arguments, which automatically fills the 1235 /// option values, making them available as properties in Python. 1236 /// 1237 class CommandObjectScriptingObjectParsed : public CommandObjectParsed { 1238 private: 1239 class CommandOptions : public Options { 1240 public: 1241 CommandOptions(CommandInterpreter &interpreter, 1242 StructuredData::GenericSP cmd_obj_sp) : m_interpreter(interpreter), 1243 m_cmd_obj_sp(cmd_obj_sp) {} 1244 1245 ~CommandOptions() override = default; 1246 1247 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1248 ExecutionContext *execution_context) override { 1249 Status error; 1250 ScriptInterpreter *scripter = 1251 m_interpreter.GetDebugger().GetScriptInterpreter(); 1252 if (!scripter) { 1253 return Status::FromErrorString( 1254 "No script interpreter for SetOptionValue."); 1255 return error; 1256 } 1257 if (!m_cmd_obj_sp) { 1258 return Status::FromErrorString( 1259 "SetOptionValue called with empty cmd_obj."); 1260 return error; 1261 } 1262 if (!m_options_definition_up) { 1263 return Status::FromErrorString( 1264 "SetOptionValue called before options definitions " 1265 "were created."); 1266 return error; 1267 } 1268 // Pass the long option, since you aren't actually required to have a 1269 // short_option, and for those options the index or short option character 1270 // aren't meaningful on the python side. 1271 const char * long_option = 1272 m_options_definition_up.get()[option_idx].long_option; 1273 bool success = scripter->SetOptionValueForCommandObject(m_cmd_obj_sp, 1274 execution_context, long_option, option_arg); 1275 if (!success) 1276 return Status::FromErrorStringWithFormatv( 1277 "Error setting option: {0} to {1}", long_option, option_arg); 1278 return error; 1279 } 1280 1281 void OptionParsingStarting(ExecutionContext *execution_context) override { 1282 ScriptInterpreter *scripter = 1283 m_interpreter.GetDebugger().GetScriptInterpreter(); 1284 if (!scripter || !m_cmd_obj_sp) 1285 return; 1286 1287 scripter->OptionParsingStartedForCommandObject(m_cmd_obj_sp); 1288 } 1289 1290 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1291 if (!m_options_definition_up) 1292 return {}; 1293 return llvm::ArrayRef(m_options_definition_up.get(), m_num_options); 1294 } 1295 1296 static Status ParseUsageMaskFromArray(StructuredData::ObjectSP obj_sp, 1297 size_t counter, uint32_t &usage_mask) { 1298 // If the usage entry is not provided, we use LLDB_OPT_SET_ALL. 1299 // If the usage mask is a UINT, the option belongs to that group. 1300 // If the usage mask is a vector of UINT's, the option belongs to all the 1301 // groups listed. 1302 // If a subelement of the vector is a vector of two ints, then the option 1303 // belongs to the inclusive range from the first to the second element. 1304 Status error; 1305 if (!obj_sp) { 1306 usage_mask = LLDB_OPT_SET_ALL; 1307 return error; 1308 } 1309 1310 usage_mask = 0; 1311 1312 StructuredData::UnsignedInteger *uint_val = 1313 obj_sp->GetAsUnsignedInteger(); 1314 if (uint_val) { 1315 // If this is an integer, then this specifies a single group: 1316 uint32_t value = uint_val->GetValue(); 1317 if (value == 0) { 1318 return Status::FromErrorStringWithFormatv( 1319 "0 is not a valid group for option {0}", counter); 1320 } 1321 usage_mask = (1 << (value - 1)); 1322 return error; 1323 } 1324 // Otherwise it has to be an array: 1325 StructuredData::Array *array_val = obj_sp->GetAsArray(); 1326 if (!array_val) { 1327 return Status::FromErrorStringWithFormatv( 1328 "required field is not a array for option {0}", counter); 1329 } 1330 // This is the array ForEach for accumulating a group usage mask from 1331 // an array of string descriptions of groups. 1332 auto groups_accumulator 1333 = [counter, &usage_mask, &error] 1334 (StructuredData::Object *obj) -> bool { 1335 StructuredData::UnsignedInteger *int_val = obj->GetAsUnsignedInteger(); 1336 if (int_val) { 1337 uint32_t value = int_val->GetValue(); 1338 if (value == 0) { 1339 error = Status::FromErrorStringWithFormatv( 1340 "0 is not a valid group for element {0}", counter); 1341 return false; 1342 } 1343 usage_mask |= (1 << (value - 1)); 1344 return true; 1345 } 1346 StructuredData::Array *arr_val = obj->GetAsArray(); 1347 if (!arr_val) { 1348 error = Status::FromErrorStringWithFormatv( 1349 "Group element not an int or array of integers for element {0}", 1350 counter); 1351 return false; 1352 } 1353 size_t num_range_elem = arr_val->GetSize(); 1354 if (num_range_elem != 2) { 1355 error = Status::FromErrorStringWithFormatv( 1356 "Subranges of a group not a start and a stop for element {0}", 1357 counter); 1358 return false; 1359 } 1360 int_val = arr_val->GetItemAtIndex(0)->GetAsUnsignedInteger(); 1361 if (!int_val) { 1362 error = Status::FromErrorStringWithFormatv( 1363 "Start element of a subrange of a " 1364 "group not unsigned int for element {0}", 1365 counter); 1366 return false; 1367 } 1368 uint32_t start = int_val->GetValue(); 1369 int_val = arr_val->GetItemAtIndex(1)->GetAsUnsignedInteger(); 1370 if (!int_val) { 1371 error = Status::FromErrorStringWithFormatv( 1372 "End element of a subrange of a group" 1373 " not unsigned int for element {0}", 1374 counter); 1375 return false; 1376 } 1377 uint32_t end = int_val->GetValue(); 1378 if (start == 0 || end == 0 || start > end) { 1379 error = Status::FromErrorStringWithFormatv( 1380 "Invalid subrange of a group: {0} - " 1381 "{1} for element {2}", 1382 start, end, counter); 1383 return false; 1384 } 1385 for (uint32_t i = start; i <= end; i++) { 1386 usage_mask |= (1 << (i - 1)); 1387 } 1388 return true; 1389 }; 1390 array_val->ForEach(groups_accumulator); 1391 return error; 1392 } 1393 1394 1395 Status SetOptionsFromArray(StructuredData::Dictionary &options) { 1396 Status error; 1397 m_num_options = options.GetSize(); 1398 m_options_definition_up.reset(new OptionDefinition[m_num_options]); 1399 // We need to hand out pointers to contents of these vectors; we reserve 1400 // as much as we'll need up front so they don't get freed on resize... 1401 m_usage_container.resize(m_num_options); 1402 m_enum_storage.resize(m_num_options); 1403 m_enum_vector.resize(m_num_options); 1404 1405 size_t counter = 0; 1406 size_t short_opt_counter = 0; 1407 // This is the Array::ForEach function for adding option elements: 1408 auto add_element = [this, &error, &counter, &short_opt_counter] 1409 (llvm::StringRef long_option, StructuredData::Object *object) -> bool { 1410 StructuredData::Dictionary *opt_dict = object->GetAsDictionary(); 1411 if (!opt_dict) { 1412 error = Status::FromErrorString( 1413 "Value in options dictionary is not a dictionary"); 1414 return false; 1415 } 1416 OptionDefinition &option_def = m_options_definition_up.get()[counter]; 1417 1418 // We aren't exposing the validator yet, set it to null 1419 option_def.validator = nullptr; 1420 // We don't require usage masks, so set it to one group by default: 1421 option_def.usage_mask = 1; 1422 1423 // Now set the fields of the OptionDefinition Array from the dictionary: 1424 // 1425 // Note that I don't check for unknown fields in the option dictionaries 1426 // so a scriptor can add extra elements that are helpful when they go to 1427 // do "set_option_value" 1428 1429 // Usage Mask: 1430 StructuredData::ObjectSP obj_sp = opt_dict->GetValueForKey("groups"); 1431 if (obj_sp) { 1432 error = ParseUsageMaskFromArray(obj_sp, counter, 1433 option_def.usage_mask); 1434 if (error.Fail()) 1435 return false; 1436 } 1437 1438 // Required: 1439 option_def.required = false; 1440 obj_sp = opt_dict->GetValueForKey("required"); 1441 if (obj_sp) { 1442 StructuredData::Boolean *boolean_val = obj_sp->GetAsBoolean(); 1443 if (!boolean_val) { 1444 error = Status::FromErrorStringWithFormatv( 1445 "'required' field is not a boolean " 1446 "for option {0}", 1447 counter); 1448 return false; 1449 } 1450 option_def.required = boolean_val->GetValue(); 1451 } 1452 1453 // Short Option: 1454 int short_option; 1455 obj_sp = opt_dict->GetValueForKey("short_option"); 1456 if (obj_sp) { 1457 // The value is a string, so pull the 1458 llvm::StringRef short_str = obj_sp->GetStringValue(); 1459 if (short_str.empty()) { 1460 error = Status::FromErrorStringWithFormatv( 1461 "short_option field empty for " 1462 "option {0}", 1463 counter); 1464 return false; 1465 } else if (short_str.size() != 1) { 1466 error = Status::FromErrorStringWithFormatv( 1467 "short_option field has extra " 1468 "characters for option {0}", 1469 counter); 1470 return false; 1471 } 1472 short_option = (int) short_str[0]; 1473 } else { 1474 // If the short option is not provided, then we need a unique value 1475 // less than the lowest printable ASCII character. 1476 short_option = short_opt_counter++; 1477 } 1478 option_def.short_option = short_option; 1479 1480 // Long Option is the key from the outer dict: 1481 if (long_option.empty()) { 1482 error = Status::FromErrorStringWithFormatv( 1483 "empty long_option for option {0}", counter); 1484 return false; 1485 } 1486 auto inserted = g_string_storer.insert(long_option.str()); 1487 option_def.long_option = ((*(inserted.first)).data()); 1488 1489 // Value Type: 1490 obj_sp = opt_dict->GetValueForKey("value_type"); 1491 if (obj_sp) { 1492 StructuredData::UnsignedInteger *uint_val 1493 = obj_sp->GetAsUnsignedInteger(); 1494 if (!uint_val) { 1495 error = Status::FromErrorStringWithFormatv( 1496 "Value type must be an unsigned " 1497 "integer"); 1498 return false; 1499 } 1500 uint64_t val_type = uint_val->GetValue(); 1501 if (val_type >= eArgTypeLastArg) { 1502 error = 1503 Status::FromErrorStringWithFormatv("Value type {0} beyond the " 1504 "CommandArgumentType bounds", 1505 val_type); 1506 return false; 1507 } 1508 option_def.argument_type = (CommandArgumentType) val_type; 1509 option_def.option_has_arg = true; 1510 } else { 1511 option_def.argument_type = eArgTypeNone; 1512 option_def.option_has_arg = false; 1513 } 1514 1515 // Completion Type: 1516 obj_sp = opt_dict->GetValueForKey("completion_type"); 1517 if (obj_sp) { 1518 StructuredData::UnsignedInteger *uint_val = obj_sp->GetAsUnsignedInteger(); 1519 if (!uint_val) { 1520 error = Status::FromErrorStringWithFormatv( 1521 "Completion type must be an " 1522 "unsigned integer for option {0}", 1523 counter); 1524 return false; 1525 } 1526 uint64_t completion_type = uint_val->GetValue(); 1527 if (completion_type > eCustomCompletion) { 1528 error = Status::FromErrorStringWithFormatv( 1529 "Completion type for option {0} " 1530 "beyond the CompletionType bounds", 1531 completion_type); 1532 return false; 1533 } 1534 option_def.completion_type = (CommandArgumentType) completion_type; 1535 } else 1536 option_def.completion_type = eNoCompletion; 1537 1538 // Usage Text: 1539 std::string usage_text; 1540 obj_sp = opt_dict->GetValueForKey("help"); 1541 if (!obj_sp) { 1542 error = Status::FromErrorStringWithFormatv( 1543 "required usage missing from option " 1544 "{0}", 1545 counter); 1546 return false; 1547 } 1548 llvm::StringRef usage_stref; 1549 usage_stref = obj_sp->GetStringValue(); 1550 if (usage_stref.empty()) { 1551 error = Status::FromErrorStringWithFormatv( 1552 "empty usage text for option {0}", counter); 1553 return false; 1554 } 1555 m_usage_container[counter] = usage_stref.str().c_str(); 1556 option_def.usage_text = m_usage_container[counter].data(); 1557 1558 // Enum Values: 1559 1560 obj_sp = opt_dict->GetValueForKey("enum_values"); 1561 if (obj_sp) { 1562 StructuredData::Array *array = obj_sp->GetAsArray(); 1563 if (!array) { 1564 error = Status::FromErrorStringWithFormatv( 1565 "enum values must be an array for " 1566 "option {0}", 1567 counter); 1568 return false; 1569 } 1570 size_t num_elem = array->GetSize(); 1571 size_t enum_ctr = 0; 1572 m_enum_storage[counter] = std::vector<EnumValueStorage>(num_elem); 1573 std::vector<EnumValueStorage> &curr_elem = m_enum_storage[counter]; 1574 1575 // This is the Array::ForEach function for adding enum elements: 1576 // Since there are only two fields to specify the enum, use a simple 1577 // two element array with value first, usage second. 1578 // counter is only used for reporting so I pass it by value here. 1579 auto add_enum = [&enum_ctr, &curr_elem, counter, &error] 1580 (StructuredData::Object *object) -> bool { 1581 StructuredData::Array *enum_arr = object->GetAsArray(); 1582 if (!enum_arr) { 1583 error = Status::FromErrorStringWithFormatv( 1584 "Enum values for option {0} not " 1585 "an array", 1586 counter); 1587 return false; 1588 } 1589 size_t num_enum_elements = enum_arr->GetSize(); 1590 if (num_enum_elements != 2) { 1591 error = Status::FromErrorStringWithFormatv( 1592 "Wrong number of elements: {0} " 1593 "for enum {1} in option {2}", 1594 num_enum_elements, enum_ctr, counter); 1595 return false; 1596 } 1597 // Enum Value: 1598 StructuredData::ObjectSP obj_sp = enum_arr->GetItemAtIndex(0); 1599 llvm::StringRef val_stref = obj_sp->GetStringValue(); 1600 std::string value_cstr_str = val_stref.str().c_str(); 1601 1602 // Enum Usage: 1603 obj_sp = enum_arr->GetItemAtIndex(1); 1604 if (!obj_sp) { 1605 error = Status::FromErrorStringWithFormatv( 1606 "No usage for enum {0} in option " 1607 "{1}", 1608 enum_ctr, counter); 1609 return false; 1610 } 1611 llvm::StringRef usage_stref = obj_sp->GetStringValue(); 1612 std::string usage_cstr_str = usage_stref.str().c_str(); 1613 curr_elem[enum_ctr] = EnumValueStorage(value_cstr_str, 1614 usage_cstr_str, enum_ctr); 1615 1616 enum_ctr++; 1617 return true; 1618 }; // end of add_enum 1619 1620 array->ForEach(add_enum); 1621 if (!error.Success()) 1622 return false; 1623 // We have to have a vector of elements to set in the options, make 1624 // that here: 1625 for (auto &elem : curr_elem) 1626 m_enum_vector[counter].emplace_back(elem.element); 1627 1628 option_def.enum_values = llvm::ArrayRef(m_enum_vector[counter]); 1629 } 1630 counter++; 1631 return true; 1632 }; // end of add_element 1633 1634 options.ForEach(add_element); 1635 return error; 1636 } 1637 1638 size_t GetNumOptions() { return m_num_options; } 1639 1640 private: 1641 struct EnumValueStorage { 1642 EnumValueStorage() { 1643 element.string_value = "value not set"; 1644 element.usage = "usage not set"; 1645 element.value = 0; 1646 } 1647 1648 EnumValueStorage(std::string in_str_val, std::string in_usage, 1649 size_t in_value) : value(std::move(in_str_val)), usage(std::move(in_usage)) { 1650 SetElement(in_value); 1651 } 1652 1653 EnumValueStorage(const EnumValueStorage &in) : value(in.value), 1654 usage(in.usage) { 1655 SetElement(in.element.value); 1656 } 1657 1658 EnumValueStorage &operator=(const EnumValueStorage &in) { 1659 value = in.value; 1660 usage = in.usage; 1661 SetElement(in.element.value); 1662 return *this; 1663 } 1664 1665 void SetElement(size_t in_value) { 1666 element.value = in_value; 1667 element.string_value = value.data(); 1668 element.usage = usage.data(); 1669 } 1670 1671 std::string value; 1672 std::string usage; 1673 OptionEnumValueElement element; 1674 }; 1675 // We have to provide char * values for the long option, usage and enum 1676 // values, that's what the option definitions hold. 1677 // The long option strings are quite likely to be reused in other added 1678 // commands, so those are stored in a global set: g_string_storer. 1679 // But the usages are much less likely to be reused, so those are stored in 1680 // a vector in the command instance. It gets resized to the correct size 1681 // and then filled with null-terminated strings in the std::string, so the 1682 // are valid C-strings that won't move around. 1683 // The enum values and descriptions are treated similarly - these aren't 1684 // all that common so it's not worth the effort to dedup them. 1685 size_t m_num_options = 0; 1686 std::unique_ptr<OptionDefinition> m_options_definition_up; 1687 std::vector<std::vector<EnumValueStorage>> m_enum_storage; 1688 std::vector<std::vector<OptionEnumValueElement>> m_enum_vector; 1689 std::vector<std::string> m_usage_container; 1690 CommandInterpreter &m_interpreter; 1691 StructuredData::GenericSP m_cmd_obj_sp; 1692 static std::unordered_set<std::string> g_string_storer; 1693 }; 1694 1695 public: 1696 static CommandObjectSP Create(CommandInterpreter &interpreter, 1697 std::string name, 1698 StructuredData::GenericSP cmd_obj_sp, 1699 ScriptedCommandSynchronicity synch, 1700 CommandReturnObject &result) { 1701 CommandObjectSP new_cmd_sp(new CommandObjectScriptingObjectParsed( 1702 interpreter, name, cmd_obj_sp, synch)); 1703 1704 CommandObjectScriptingObjectParsed *parsed_cmd 1705 = static_cast<CommandObjectScriptingObjectParsed *>(new_cmd_sp.get()); 1706 // Now check all the failure modes, and report if found. 1707 Status opt_error = parsed_cmd->GetOptionsError(); 1708 Status arg_error = parsed_cmd->GetArgsError(); 1709 1710 if (opt_error.Fail()) 1711 result.AppendErrorWithFormat("failed to parse option definitions: %s", 1712 opt_error.AsCString()); 1713 if (arg_error.Fail()) 1714 result.AppendErrorWithFormat("%sfailed to parse argument definitions: %s", 1715 opt_error.Fail() ? ", also " : "", 1716 arg_error.AsCString()); 1717 1718 if (!result.Succeeded()) 1719 return {}; 1720 1721 return new_cmd_sp; 1722 } 1723 1724 CommandObjectScriptingObjectParsed(CommandInterpreter &interpreter, 1725 std::string name, 1726 StructuredData::GenericSP cmd_obj_sp, 1727 ScriptedCommandSynchronicity synch) 1728 : CommandObjectParsed(interpreter, name.c_str()), 1729 m_cmd_obj_sp(cmd_obj_sp), m_synchro(synch), 1730 m_options(interpreter, cmd_obj_sp), m_fetched_help_short(false), 1731 m_fetched_help_long(false) { 1732 StreamString stream; 1733 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1734 if (!scripter) { 1735 m_options_error = Status::FromErrorString("No script interpreter"); 1736 return; 1737 } 1738 1739 // Set the flags: 1740 GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); 1741 1742 // Now set up the options definitions from the options: 1743 StructuredData::ObjectSP options_object_sp 1744 = scripter->GetOptionsForCommandObject(cmd_obj_sp); 1745 // It's okay not to have an options dict. 1746 if (options_object_sp) { 1747 // The options come as a dictionary of dictionaries. The key of the 1748 // outer dict is the long option name (since that's required). The 1749 // value holds all the other option specification bits. 1750 StructuredData::Dictionary *options_dict 1751 = options_object_sp->GetAsDictionary(); 1752 // but if it exists, it has to be an array. 1753 if (options_dict) { 1754 m_options_error = m_options.SetOptionsFromArray(*(options_dict)); 1755 // If we got an error don't bother with the arguments... 1756 if (m_options_error.Fail()) 1757 return; 1758 } else { 1759 m_options_error = Status::FromErrorString("Options array not an array"); 1760 return; 1761 } 1762 } 1763 // Then fetch the args. Since the arguments can have usage masks you need 1764 // an array of arrays. 1765 StructuredData::ObjectSP args_object_sp 1766 = scripter->GetArgumentsForCommandObject(cmd_obj_sp); 1767 if (args_object_sp) { 1768 StructuredData::Array *args_array = args_object_sp->GetAsArray(); 1769 if (!args_array) { 1770 m_args_error = 1771 Status::FromErrorString("Argument specification is not an array"); 1772 return; 1773 } 1774 size_t counter = 0; 1775 1776 // This is the Array::ForEach function that handles the 1777 // CommandArgumentEntry arrays one by one: 1778 auto arg_array_adder = [this, &counter] (StructuredData::Object *object) 1779 -> bool { 1780 // This is the Array::ForEach function to add argument entries: 1781 CommandArgumentEntry this_entry; 1782 size_t elem_counter = 0; 1783 auto args_adder = [this, counter, &elem_counter, &this_entry] 1784 (StructuredData::Object *object) -> bool { 1785 // The arguments definition has three fields, the argument type, the 1786 // repeat and the usage mask. 1787 CommandArgumentType arg_type = eArgTypeNone; 1788 ArgumentRepetitionType arg_repetition = eArgRepeatOptional; 1789 uint32_t arg_opt_set_association; 1790 1791 auto report_error = [this, elem_counter, 1792 counter](const char *err_txt) -> bool { 1793 m_args_error = Status::FromErrorStringWithFormatv( 1794 "Element {0} of arguments " 1795 "list element {1}: %s.", 1796 elem_counter, counter, err_txt); 1797 return false; 1798 }; 1799 1800 StructuredData::Dictionary *arg_dict = object->GetAsDictionary(); 1801 if (!arg_dict) { 1802 report_error("is not a dictionary."); 1803 return false; 1804 } 1805 // Argument Type: 1806 StructuredData::ObjectSP obj_sp 1807 = arg_dict->GetValueForKey("arg_type"); 1808 if (obj_sp) { 1809 StructuredData::UnsignedInteger *uint_val 1810 = obj_sp->GetAsUnsignedInteger(); 1811 if (!uint_val) { 1812 report_error("value type must be an unsigned integer"); 1813 return false; 1814 } 1815 uint64_t arg_type_int = uint_val->GetValue(); 1816 if (arg_type_int >= eArgTypeLastArg) { 1817 report_error("value type beyond ArgumentRepetitionType bounds"); 1818 return false; 1819 } 1820 arg_type = (CommandArgumentType) arg_type_int; 1821 } 1822 // Repeat Value: 1823 obj_sp = arg_dict->GetValueForKey("repeat"); 1824 std::optional<ArgumentRepetitionType> repeat; 1825 if (obj_sp) { 1826 llvm::StringRef repeat_str = obj_sp->GetStringValue(); 1827 if (repeat_str.empty()) { 1828 report_error("repeat value is empty"); 1829 return false; 1830 } 1831 repeat = ArgRepetitionFromString(repeat_str); 1832 if (!repeat) { 1833 report_error("invalid repeat value"); 1834 return false; 1835 } 1836 arg_repetition = *repeat; 1837 } 1838 1839 // Usage Mask: 1840 obj_sp = arg_dict->GetValueForKey("groups"); 1841 m_args_error = CommandOptions::ParseUsageMaskFromArray(obj_sp, 1842 counter, arg_opt_set_association); 1843 this_entry.emplace_back(arg_type, arg_repetition, 1844 arg_opt_set_association); 1845 elem_counter++; 1846 return true; 1847 }; 1848 StructuredData::Array *args_array = object->GetAsArray(); 1849 if (!args_array) { 1850 m_args_error = 1851 Status::FromErrorStringWithFormatv("Argument definition element " 1852 "{0} is not an array", 1853 counter); 1854 } 1855 1856 args_array->ForEach(args_adder); 1857 if (m_args_error.Fail()) 1858 return false; 1859 if (this_entry.empty()) { 1860 m_args_error = 1861 Status::FromErrorStringWithFormatv("Argument definition element " 1862 "{0} is empty", 1863 counter); 1864 return false; 1865 } 1866 m_arguments.push_back(this_entry); 1867 counter++; 1868 return true; 1869 }; // end of arg_array_adder 1870 // Here we actually parse the args definition: 1871 args_array->ForEach(arg_array_adder); 1872 } 1873 } 1874 1875 ~CommandObjectScriptingObjectParsed() override = default; 1876 1877 Status GetOptionsError() { return m_options_error; } 1878 Status GetArgsError() { return m_args_error; } 1879 bool WantsCompletion() override { return true; } 1880 1881 bool IsRemovable() const override { return true; } 1882 1883 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1884 1885 std::optional<std::string> GetRepeatCommand(Args &args, 1886 uint32_t index) override { 1887 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1888 if (!scripter) 1889 return std::nullopt; 1890 1891 return scripter->GetRepeatCommandForScriptedCommand(m_cmd_obj_sp, args); 1892 } 1893 1894 llvm::StringRef GetHelp() override { 1895 if (m_fetched_help_short) 1896 return CommandObjectParsed::GetHelp(); 1897 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1898 if (!scripter) 1899 return CommandObjectParsed::GetHelp(); 1900 std::string docstring; 1901 m_fetched_help_short = 1902 scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring); 1903 if (!docstring.empty()) 1904 SetHelp(docstring); 1905 1906 return CommandObjectParsed::GetHelp(); 1907 } 1908 1909 llvm::StringRef GetHelpLong() override { 1910 if (m_fetched_help_long) 1911 return CommandObjectParsed::GetHelpLong(); 1912 1913 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1914 if (!scripter) 1915 return CommandObjectParsed::GetHelpLong(); 1916 1917 std::string docstring; 1918 m_fetched_help_long = 1919 scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring); 1920 if (!docstring.empty()) 1921 SetHelpLong(docstring); 1922 return CommandObjectParsed::GetHelpLong(); 1923 } 1924 1925 Options *GetOptions() override { 1926 // CommandObjectParsed requires that a command with no options return 1927 // nullptr. 1928 if (m_options.GetNumOptions() == 0) 1929 return nullptr; 1930 return &m_options; 1931 } 1932 1933 protected: 1934 void DoExecute(Args &args, 1935 CommandReturnObject &result) override { 1936 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1937 1938 Status error; 1939 1940 result.SetStatus(eReturnStatusInvalid); 1941 1942 if (!scripter || 1943 !scripter->RunScriptBasedParsedCommand(m_cmd_obj_sp, args, 1944 m_synchro, result, error, m_exe_ctx)) { 1945 result.AppendError(error.AsCString()); 1946 } else { 1947 // Don't change the status if the command already set it... 1948 if (result.GetStatus() == eReturnStatusInvalid) { 1949 if (result.GetOutputData().empty()) 1950 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1951 else 1952 result.SetStatus(eReturnStatusSuccessFinishResult); 1953 } 1954 } 1955 } 1956 1957 private: 1958 StructuredData::GenericSP m_cmd_obj_sp; 1959 ScriptedCommandSynchronicity m_synchro; 1960 CommandOptions m_options; 1961 Status m_options_error; 1962 Status m_args_error; 1963 bool m_fetched_help_short : 1; 1964 bool m_fetched_help_long : 1; 1965 }; 1966 1967 std::unordered_set<std::string> 1968 CommandObjectScriptingObjectParsed::CommandOptions::g_string_storer; 1969 1970 // CommandObjectCommandsScriptImport 1971 #define LLDB_OPTIONS_script_import 1972 #include "CommandOptions.inc" 1973 1974 class CommandObjectCommandsScriptImport : public CommandObjectParsed { 1975 public: 1976 CommandObjectCommandsScriptImport(CommandInterpreter &interpreter) 1977 : CommandObjectParsed(interpreter, "command script import", 1978 "Import a scripting module in LLDB.", nullptr) { 1979 AddSimpleArgumentList(eArgTypeFilename, eArgRepeatPlus); 1980 } 1981 1982 ~CommandObjectCommandsScriptImport() override = default; 1983 1984 Options *GetOptions() override { return &m_options; } 1985 1986 protected: 1987 class CommandOptions : public Options { 1988 public: 1989 CommandOptions() = default; 1990 1991 ~CommandOptions() override = default; 1992 1993 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1994 ExecutionContext *execution_context) override { 1995 Status error; 1996 const int short_option = m_getopt_table[option_idx].val; 1997 1998 switch (short_option) { 1999 case 'r': 2000 // NO-OP 2001 break; 2002 case 'c': 2003 relative_to_command_file = true; 2004 break; 2005 case 's': 2006 silent = true; 2007 break; 2008 default: 2009 llvm_unreachable("Unimplemented option"); 2010 } 2011 2012 return error; 2013 } 2014 2015 void OptionParsingStarting(ExecutionContext *execution_context) override { 2016 relative_to_command_file = false; 2017 } 2018 2019 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 2020 return llvm::ArrayRef(g_script_import_options); 2021 } 2022 bool relative_to_command_file = false; 2023 bool silent = false; 2024 }; 2025 2026 void DoExecute(Args &command, CommandReturnObject &result) override { 2027 if (command.empty()) { 2028 result.AppendError("command script import needs one or more arguments"); 2029 return; 2030 } 2031 2032 FileSpec source_dir = {}; 2033 if (m_options.relative_to_command_file) { 2034 source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir(); 2035 if (!source_dir) { 2036 result.AppendError("command script import -c can only be specified " 2037 "from a command file"); 2038 return; 2039 } 2040 } 2041 2042 for (auto &entry : command.entries()) { 2043 Status error; 2044 2045 LoadScriptOptions options; 2046 options.SetInitSession(true); 2047 options.SetSilent(m_options.silent); 2048 2049 // FIXME: this is necessary because CommandObject::CheckRequirements() 2050 // assumes that commands won't ever be recursively invoked, but it's 2051 // actually possible to craft a Python script that does other "command 2052 // script imports" in __lldb_init_module the real fix is to have 2053 // recursive commands possible with a CommandInvocation object separate 2054 // from the CommandObject itself, so that recursive command invocations 2055 // won't stomp on each other (wrt to execution contents, options, and 2056 // more) 2057 m_exe_ctx.Clear(); 2058 if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule( 2059 entry.c_str(), options, error, /*module_sp=*/nullptr, 2060 source_dir)) { 2061 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2062 } else { 2063 result.AppendErrorWithFormat("module importing failed: %s", 2064 error.AsCString()); 2065 } 2066 } 2067 } 2068 2069 CommandOptions m_options; 2070 }; 2071 2072 #define LLDB_OPTIONS_script_add 2073 #include "CommandOptions.inc" 2074 2075 class CommandObjectCommandsScriptAdd : public CommandObjectParsed, 2076 public IOHandlerDelegateMultiline { 2077 public: 2078 CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) 2079 : CommandObjectParsed(interpreter, "command script add", 2080 "Add a scripted function as an LLDB command.", 2081 "Add a scripted function as an lldb command. " 2082 "If you provide a single argument, the command " 2083 "will be added at the root level of the command " 2084 "hierarchy. If there are more arguments they " 2085 "must be a path to a user-added container " 2086 "command, and the last element will be the new " 2087 "command name."), 2088 IOHandlerDelegateMultiline("DONE") { 2089 AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus); 2090 } 2091 2092 ~CommandObjectCommandsScriptAdd() override = default; 2093 2094 Options *GetOptions() override { return &m_options; } 2095 2096 void 2097 HandleArgumentCompletion(CompletionRequest &request, 2098 OptionElementVector &opt_element_vector) override { 2099 CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request, 2100 opt_element_vector); 2101 } 2102 2103 protected: 2104 class CommandOptions : public Options { 2105 public: 2106 CommandOptions() = default; 2107 2108 ~CommandOptions() override = default; 2109 2110 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 2111 ExecutionContext *execution_context) override { 2112 Status error; 2113 const int short_option = m_getopt_table[option_idx].val; 2114 2115 switch (short_option) { 2116 case 'f': 2117 if (!option_arg.empty()) 2118 m_funct_name = std::string(option_arg); 2119 break; 2120 case 'c': 2121 if (!option_arg.empty()) 2122 m_class_name = std::string(option_arg); 2123 break; 2124 case 'h': 2125 if (!option_arg.empty()) 2126 m_short_help = std::string(option_arg); 2127 break; 2128 case 'o': 2129 m_overwrite_lazy = eLazyBoolYes; 2130 break; 2131 case 'p': 2132 m_parsed_command = true; 2133 break; 2134 case 's': 2135 m_synchronicity = 2136 (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum( 2137 option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 2138 if (!error.Success()) 2139 return Status::FromErrorStringWithFormat( 2140 "unrecognized value for synchronicity '%s'", 2141 option_arg.str().c_str()); 2142 break; 2143 case 'C': { 2144 Status error; 2145 OptionDefinition definition = GetDefinitions()[option_idx]; 2146 lldb::CompletionType completion_type = 2147 static_cast<lldb::CompletionType>(OptionArgParser::ToOptionEnum( 2148 option_arg, definition.enum_values, eNoCompletion, error)); 2149 if (!error.Success()) 2150 return Status::FromErrorStringWithFormat( 2151 "unrecognized value for command completion type '%s'", 2152 option_arg.str().c_str()); 2153 m_completion_type = completion_type; 2154 } break; 2155 default: 2156 llvm_unreachable("Unimplemented option"); 2157 } 2158 2159 return error; 2160 } 2161 2162 void OptionParsingStarting(ExecutionContext *execution_context) override { 2163 m_class_name.clear(); 2164 m_funct_name.clear(); 2165 m_short_help.clear(); 2166 m_completion_type = eNoCompletion; 2167 m_overwrite_lazy = eLazyBoolCalculate; 2168 m_synchronicity = eScriptedCommandSynchronicitySynchronous; 2169 m_parsed_command = false; 2170 } 2171 2172 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 2173 return llvm::ArrayRef(g_script_add_options); 2174 } 2175 2176 // Instance variables to hold the values for command options. 2177 2178 std::string m_class_name; 2179 std::string m_funct_name; 2180 std::string m_short_help; 2181 LazyBool m_overwrite_lazy = eLazyBoolCalculate; 2182 ScriptedCommandSynchronicity m_synchronicity = 2183 eScriptedCommandSynchronicitySynchronous; 2184 CompletionType m_completion_type = eNoCompletion; 2185 bool m_parsed_command = false; 2186 }; 2187 2188 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 2189 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); 2190 if (output_sp && interactive) { 2191 output_sp->PutCString(g_python_command_instructions); 2192 output_sp->Flush(); 2193 } 2194 } 2195 2196 void IOHandlerInputComplete(IOHandler &io_handler, 2197 std::string &data) override { 2198 StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); 2199 2200 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 2201 if (interpreter) { 2202 StringList lines; 2203 lines.SplitIntoLines(data); 2204 if (lines.GetSize() > 0) { 2205 std::string funct_name_str; 2206 if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) { 2207 if (funct_name_str.empty()) { 2208 error_sp->Printf("error: unable to obtain a function name, didn't " 2209 "add python command.\n"); 2210 error_sp->Flush(); 2211 } else { 2212 // everything should be fine now, let's add this alias 2213 2214 CommandObjectSP command_obj_sp(new CommandObjectPythonFunction( 2215 m_interpreter, m_cmd_name, funct_name_str, m_short_help, 2216 m_synchronicity, m_completion_type)); 2217 if (!m_container) { 2218 Status error = m_interpreter.AddUserCommand( 2219 m_cmd_name, command_obj_sp, m_overwrite); 2220 if (error.Fail()) { 2221 error_sp->Printf("error: unable to add selected command: '%s'", 2222 error.AsCString()); 2223 error_sp->Flush(); 2224 } 2225 } else { 2226 llvm::Error llvm_error = m_container->LoadUserSubcommand( 2227 m_cmd_name, command_obj_sp, m_overwrite); 2228 if (llvm_error) { 2229 error_sp->Printf("error: unable to add selected command: '%s'", 2230 llvm::toString(std::move(llvm_error)).c_str()); 2231 error_sp->Flush(); 2232 } 2233 } 2234 } 2235 } else { 2236 error_sp->Printf( 2237 "error: unable to create function, didn't add python command\n"); 2238 error_sp->Flush(); 2239 } 2240 } else { 2241 error_sp->Printf("error: empty function, didn't add python command\n"); 2242 error_sp->Flush(); 2243 } 2244 } else { 2245 error_sp->Printf( 2246 "error: script interpreter missing, didn't add python command\n"); 2247 error_sp->Flush(); 2248 } 2249 2250 io_handler.SetIsDone(true); 2251 } 2252 2253 void DoExecute(Args &command, CommandReturnObject &result) override { 2254 if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) { 2255 result.AppendError("only scripting language supported for scripted " 2256 "commands is currently Python"); 2257 return; 2258 } 2259 2260 if (command.GetArgumentCount() == 0) { 2261 result.AppendError("'command script add' requires at least one argument"); 2262 return; 2263 } 2264 // Store the options in case we get multi-line input, also figure out the 2265 // default if not user supplied: 2266 switch (m_options.m_overwrite_lazy) { 2267 case eLazyBoolCalculate: 2268 m_overwrite = !GetDebugger().GetCommandInterpreter().GetRequireCommandOverwrite(); 2269 break; 2270 case eLazyBoolYes: 2271 m_overwrite = true; 2272 break; 2273 case eLazyBoolNo: 2274 m_overwrite = false; 2275 } 2276 2277 Status path_error; 2278 m_container = GetCommandInterpreter().VerifyUserMultiwordCmdPath( 2279 command, true, path_error); 2280 2281 if (path_error.Fail()) { 2282 result.AppendErrorWithFormat("error in command path: %s", 2283 path_error.AsCString()); 2284 return; 2285 } 2286 2287 if (!m_container) { 2288 // This is getting inserted into the root of the interpreter. 2289 m_cmd_name = std::string(command[0].ref()); 2290 } else { 2291 size_t num_args = command.GetArgumentCount(); 2292 m_cmd_name = std::string(command[num_args - 1].ref()); 2293 } 2294 2295 m_short_help.assign(m_options.m_short_help); 2296 m_synchronicity = m_options.m_synchronicity; 2297 m_completion_type = m_options.m_completion_type; 2298 2299 // Handle the case where we prompt for the script code first: 2300 if (m_options.m_class_name.empty() && m_options.m_funct_name.empty()) { 2301 m_interpreter.GetPythonCommandsFromIOHandler(" ", // Prompt 2302 *this); // IOHandlerDelegate 2303 return; 2304 } 2305 2306 CommandObjectSP new_cmd_sp; 2307 if (m_options.m_class_name.empty()) { 2308 new_cmd_sp.reset(new CommandObjectPythonFunction( 2309 m_interpreter, m_cmd_name, m_options.m_funct_name, 2310 m_options.m_short_help, m_synchronicity, m_completion_type)); 2311 } else { 2312 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 2313 if (!interpreter) { 2314 result.AppendError("cannot find ScriptInterpreter"); 2315 return; 2316 } 2317 2318 auto cmd_obj_sp = interpreter->CreateScriptCommandObject( 2319 m_options.m_class_name.c_str()); 2320 if (!cmd_obj_sp) { 2321 result.AppendErrorWithFormatv("cannot create helper object for: " 2322 "'{0}'", m_options.m_class_name); 2323 return; 2324 } 2325 2326 if (m_options.m_parsed_command) { 2327 new_cmd_sp = CommandObjectScriptingObjectParsed::Create(m_interpreter, 2328 m_cmd_name, cmd_obj_sp, m_synchronicity, result); 2329 if (!result.Succeeded()) 2330 return; 2331 } else 2332 new_cmd_sp.reset(new CommandObjectScriptingObjectRaw( 2333 m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity, 2334 m_completion_type)); 2335 } 2336 2337 // Assume we're going to succeed... 2338 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2339 if (!m_container) { 2340 Status add_error = 2341 m_interpreter.AddUserCommand(m_cmd_name, new_cmd_sp, m_overwrite); 2342 if (add_error.Fail()) 2343 result.AppendErrorWithFormat("cannot add command: %s", 2344 add_error.AsCString()); 2345 } else { 2346 llvm::Error llvm_error = 2347 m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite); 2348 if (llvm_error) 2349 result.AppendErrorWithFormat( 2350 "cannot add command: %s", 2351 llvm::toString(std::move(llvm_error)).c_str()); 2352 } 2353 } 2354 2355 CommandOptions m_options; 2356 std::string m_cmd_name; 2357 CommandObjectMultiword *m_container = nullptr; 2358 std::string m_short_help; 2359 bool m_overwrite = false; 2360 ScriptedCommandSynchronicity m_synchronicity = 2361 eScriptedCommandSynchronicitySynchronous; 2362 CompletionType m_completion_type = eNoCompletion; 2363 }; 2364 2365 // CommandObjectCommandsScriptList 2366 2367 class CommandObjectCommandsScriptList : public CommandObjectParsed { 2368 public: 2369 CommandObjectCommandsScriptList(CommandInterpreter &interpreter) 2370 : CommandObjectParsed(interpreter, "command script list", 2371 "List defined top-level scripted commands.", 2372 nullptr) {} 2373 2374 ~CommandObjectCommandsScriptList() override = default; 2375 2376 void DoExecute(Args &command, CommandReturnObject &result) override { 2377 m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef); 2378 2379 result.SetStatus(eReturnStatusSuccessFinishResult); 2380 } 2381 }; 2382 2383 // CommandObjectCommandsScriptClear 2384 2385 class CommandObjectCommandsScriptClear : public CommandObjectParsed { 2386 public: 2387 CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) 2388 : CommandObjectParsed(interpreter, "command script clear", 2389 "Delete all scripted commands.", nullptr) {} 2390 2391 ~CommandObjectCommandsScriptClear() override = default; 2392 2393 protected: 2394 void DoExecute(Args &command, CommandReturnObject &result) override { 2395 m_interpreter.RemoveAllUser(); 2396 2397 result.SetStatus(eReturnStatusSuccessFinishResult); 2398 } 2399 }; 2400 2401 // CommandObjectCommandsScriptDelete 2402 2403 class CommandObjectCommandsScriptDelete : public CommandObjectParsed { 2404 public: 2405 CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) 2406 : CommandObjectParsed( 2407 interpreter, "command script delete", 2408 "Delete a scripted command by specifying the path to the command.", 2409 nullptr) { 2410 AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus); 2411 } 2412 2413 ~CommandObjectCommandsScriptDelete() override = default; 2414 2415 void 2416 HandleArgumentCompletion(CompletionRequest &request, 2417 OptionElementVector &opt_element_vector) override { 2418 lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs( 2419 m_interpreter, request, opt_element_vector); 2420 } 2421 2422 protected: 2423 void DoExecute(Args &command, CommandReturnObject &result) override { 2424 2425 llvm::StringRef root_cmd = command[0].ref(); 2426 size_t num_args = command.GetArgumentCount(); 2427 2428 if (root_cmd.empty()) { 2429 result.AppendErrorWithFormat("empty root command name"); 2430 return; 2431 } 2432 if (!m_interpreter.HasUserCommands() && 2433 !m_interpreter.HasUserMultiwordCommands()) { 2434 result.AppendErrorWithFormat("can only delete user defined commands, " 2435 "but no user defined commands found"); 2436 return; 2437 } 2438 2439 CommandObjectSP cmd_sp = m_interpreter.GetCommandSPExact(root_cmd); 2440 if (!cmd_sp) { 2441 result.AppendErrorWithFormat("command '%s' not found.", 2442 command[0].c_str()); 2443 return; 2444 } 2445 if (!cmd_sp->IsUserCommand()) { 2446 result.AppendErrorWithFormat("command '%s' is not a user command.", 2447 command[0].c_str()); 2448 return; 2449 } 2450 if (cmd_sp->GetAsMultiwordCommand() && num_args == 1) { 2451 result.AppendErrorWithFormat("command '%s' is a multi-word command.\n " 2452 "Delete with \"command container delete\"", 2453 command[0].c_str()); 2454 return; 2455 } 2456 2457 if (command.GetArgumentCount() == 1) { 2458 m_interpreter.RemoveUser(root_cmd); 2459 result.SetStatus(eReturnStatusSuccessFinishResult); 2460 return; 2461 } 2462 // We're deleting a command from a multiword command. Verify the command 2463 // path: 2464 Status error; 2465 CommandObjectMultiword *container = 2466 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 2467 error); 2468 if (error.Fail()) { 2469 result.AppendErrorWithFormat("could not resolve command path: %s", 2470 error.AsCString()); 2471 return; 2472 } 2473 if (!container) { 2474 // This means that command only had a leaf command, so the container is 2475 // the root. That should have been handled above. 2476 result.AppendErrorWithFormat("could not find a container for '%s'", 2477 command[0].c_str()); 2478 return; 2479 } 2480 const char *leaf_cmd = command[num_args - 1].c_str(); 2481 llvm::Error llvm_error = 2482 container->RemoveUserSubcommand(leaf_cmd, 2483 /* multiword not okay */ false); 2484 if (llvm_error) { 2485 result.AppendErrorWithFormat( 2486 "could not delete command '%s': %s", leaf_cmd, 2487 llvm::toString(std::move(llvm_error)).c_str()); 2488 return; 2489 } 2490 2491 Stream &out_stream = result.GetOutputStream(); 2492 2493 out_stream << "Deleted command:"; 2494 for (size_t idx = 0; idx < num_args; idx++) { 2495 out_stream << ' '; 2496 out_stream << command[idx].c_str(); 2497 } 2498 out_stream << '\n'; 2499 result.SetStatus(eReturnStatusSuccessFinishResult); 2500 } 2501 }; 2502 2503 #pragma mark CommandObjectMultiwordCommandsScript 2504 2505 // CommandObjectMultiwordCommandsScript 2506 2507 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword { 2508 public: 2509 CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter) 2510 : CommandObjectMultiword( 2511 interpreter, "command script", 2512 "Commands for managing custom " 2513 "commands implemented by " 2514 "interpreter scripts.", 2515 "command script <subcommand> [<subcommand-options>]") { 2516 LoadSubCommand("add", CommandObjectSP( 2517 new CommandObjectCommandsScriptAdd(interpreter))); 2518 LoadSubCommand( 2519 "delete", 2520 CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter))); 2521 LoadSubCommand( 2522 "clear", 2523 CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter))); 2524 LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList( 2525 interpreter))); 2526 LoadSubCommand( 2527 "import", 2528 CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter))); 2529 } 2530 2531 ~CommandObjectMultiwordCommandsScript() override = default; 2532 }; 2533 2534 #pragma mark CommandObjectCommandContainer 2535 #define LLDB_OPTIONS_container_add 2536 #include "CommandOptions.inc" 2537 2538 class CommandObjectCommandsContainerAdd : public CommandObjectParsed { 2539 public: 2540 CommandObjectCommandsContainerAdd(CommandInterpreter &interpreter) 2541 : CommandObjectParsed( 2542 interpreter, "command container add", 2543 "Add a container command to lldb. Adding to built-" 2544 "in container commands is not allowed.", 2545 "command container add [[path1]...] container-name") { 2546 AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus); 2547 } 2548 2549 ~CommandObjectCommandsContainerAdd() override = default; 2550 2551 Options *GetOptions() override { return &m_options; } 2552 2553 void 2554 HandleArgumentCompletion(CompletionRequest &request, 2555 OptionElementVector &opt_element_vector) override { 2556 lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs( 2557 m_interpreter, request, opt_element_vector); 2558 } 2559 2560 protected: 2561 class CommandOptions : public Options { 2562 public: 2563 CommandOptions() = default; 2564 2565 ~CommandOptions() override = default; 2566 2567 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 2568 ExecutionContext *execution_context) override { 2569 Status error; 2570 const int short_option = m_getopt_table[option_idx].val; 2571 2572 switch (short_option) { 2573 case 'h': 2574 if (!option_arg.empty()) 2575 m_short_help = std::string(option_arg); 2576 break; 2577 case 'o': 2578 m_overwrite = true; 2579 break; 2580 case 'H': 2581 if (!option_arg.empty()) 2582 m_long_help = std::string(option_arg); 2583 break; 2584 default: 2585 llvm_unreachable("Unimplemented option"); 2586 } 2587 2588 return error; 2589 } 2590 2591 void OptionParsingStarting(ExecutionContext *execution_context) override { 2592 m_short_help.clear(); 2593 m_long_help.clear(); 2594 m_overwrite = false; 2595 } 2596 2597 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 2598 return llvm::ArrayRef(g_container_add_options); 2599 } 2600 2601 // Instance variables to hold the values for command options. 2602 2603 std::string m_short_help; 2604 std::string m_long_help; 2605 bool m_overwrite = false; 2606 }; 2607 void DoExecute(Args &command, CommandReturnObject &result) override { 2608 size_t num_args = command.GetArgumentCount(); 2609 2610 if (num_args == 0) { 2611 result.AppendError("no command was specified"); 2612 return; 2613 } 2614 2615 if (num_args == 1) { 2616 // We're adding this as a root command, so use the interpreter. 2617 const char *cmd_name = command.GetArgumentAtIndex(0); 2618 auto cmd_sp = CommandObjectSP(new CommandObjectMultiword( 2619 GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(), 2620 m_options.m_long_help.c_str())); 2621 cmd_sp->GetAsMultiwordCommand()->SetRemovable(true); 2622 Status add_error = GetCommandInterpreter().AddUserCommand( 2623 cmd_name, cmd_sp, m_options.m_overwrite); 2624 if (add_error.Fail()) { 2625 result.AppendErrorWithFormat("error adding command: %s", 2626 add_error.AsCString()); 2627 return; 2628 } 2629 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2630 return; 2631 } 2632 2633 // We're adding this to a subcommand, first find the subcommand: 2634 Status path_error; 2635 CommandObjectMultiword *add_to_me = 2636 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 2637 path_error); 2638 2639 if (!add_to_me) { 2640 result.AppendErrorWithFormat("error adding command: %s", 2641 path_error.AsCString()); 2642 return; 2643 } 2644 2645 const char *cmd_name = command.GetArgumentAtIndex(num_args - 1); 2646 auto cmd_sp = CommandObjectSP(new CommandObjectMultiword( 2647 GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(), 2648 m_options.m_long_help.c_str())); 2649 llvm::Error llvm_error = 2650 add_to_me->LoadUserSubcommand(cmd_name, cmd_sp, m_options.m_overwrite); 2651 if (llvm_error) { 2652 result.AppendErrorWithFormat("error adding subcommand: %s", 2653 llvm::toString(std::move(llvm_error)).c_str()); 2654 return; 2655 } 2656 2657 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2658 } 2659 2660 private: 2661 CommandOptions m_options; 2662 }; 2663 2664 #define LLDB_OPTIONS_multiword_delete 2665 #include "CommandOptions.inc" 2666 class CommandObjectCommandsContainerDelete : public CommandObjectParsed { 2667 public: 2668 CommandObjectCommandsContainerDelete(CommandInterpreter &interpreter) 2669 : CommandObjectParsed( 2670 interpreter, "command container delete", 2671 "Delete a container command previously added to " 2672 "lldb.", 2673 "command container delete [[path1] ...] container-cmd") { 2674 AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus); 2675 } 2676 2677 ~CommandObjectCommandsContainerDelete() override = default; 2678 2679 void 2680 HandleArgumentCompletion(CompletionRequest &request, 2681 OptionElementVector &opt_element_vector) override { 2682 lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs( 2683 m_interpreter, request, opt_element_vector); 2684 } 2685 2686 protected: 2687 void DoExecute(Args &command, CommandReturnObject &result) override { 2688 size_t num_args = command.GetArgumentCount(); 2689 2690 if (num_args == 0) { 2691 result.AppendError("No command was specified."); 2692 return; 2693 } 2694 2695 if (num_args == 1) { 2696 // We're removing a root command, so we need to delete it from the 2697 // interpreter. 2698 const char *cmd_name = command.GetArgumentAtIndex(0); 2699 // Let's do a little more work here so we can do better error reporting. 2700 CommandInterpreter &interp = GetCommandInterpreter(); 2701 CommandObjectSP cmd_sp = interp.GetCommandSPExact(cmd_name); 2702 if (!cmd_sp) { 2703 result.AppendErrorWithFormat("container command %s doesn't exist.", 2704 cmd_name); 2705 return; 2706 } 2707 if (!cmd_sp->IsUserCommand()) { 2708 result.AppendErrorWithFormat( 2709 "container command %s is not a user command", cmd_name); 2710 return; 2711 } 2712 if (!cmd_sp->GetAsMultiwordCommand()) { 2713 result.AppendErrorWithFormat("command %s is not a container command", 2714 cmd_name); 2715 return; 2716 } 2717 2718 bool did_remove = GetCommandInterpreter().RemoveUserMultiword(cmd_name); 2719 if (!did_remove) { 2720 result.AppendErrorWithFormat("error removing command %s.", cmd_name); 2721 return; 2722 } 2723 2724 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2725 return; 2726 } 2727 2728 // We're removing a subcommand, first find the subcommand's owner: 2729 Status path_error; 2730 CommandObjectMultiword *container = 2731 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 2732 path_error); 2733 2734 if (!container) { 2735 result.AppendErrorWithFormat("error removing container command: %s", 2736 path_error.AsCString()); 2737 return; 2738 } 2739 const char *leaf = command.GetArgumentAtIndex(num_args - 1); 2740 llvm::Error llvm_error = 2741 container->RemoveUserSubcommand(leaf, /* multiword okay */ true); 2742 if (llvm_error) { 2743 result.AppendErrorWithFormat("error removing container command: %s", 2744 llvm::toString(std::move(llvm_error)).c_str()); 2745 return; 2746 } 2747 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2748 } 2749 }; 2750 2751 class CommandObjectCommandContainer : public CommandObjectMultiword { 2752 public: 2753 CommandObjectCommandContainer(CommandInterpreter &interpreter) 2754 : CommandObjectMultiword( 2755 interpreter, "command container", 2756 "Commands for adding container commands to lldb. " 2757 "Container commands are containers for other commands. You can " 2758 "add nested container commands by specifying a command path, " 2759 "but you can't add commands into the built-in command hierarchy.", 2760 "command container <subcommand> [<subcommand-options>]") { 2761 LoadSubCommand("add", CommandObjectSP(new CommandObjectCommandsContainerAdd( 2762 interpreter))); 2763 LoadSubCommand( 2764 "delete", 2765 CommandObjectSP(new CommandObjectCommandsContainerDelete(interpreter))); 2766 } 2767 2768 ~CommandObjectCommandContainer() override = default; 2769 }; 2770 2771 #pragma mark CommandObjectMultiwordCommands 2772 2773 // CommandObjectMultiwordCommands 2774 2775 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands( 2776 CommandInterpreter &interpreter) 2777 : CommandObjectMultiword(interpreter, "command", 2778 "Commands for managing custom LLDB commands.", 2779 "command <subcommand> [<subcommand-options>]") { 2780 LoadSubCommand("source", 2781 CommandObjectSP(new CommandObjectCommandsSource(interpreter))); 2782 LoadSubCommand("alias", 2783 CommandObjectSP(new CommandObjectCommandsAlias(interpreter))); 2784 LoadSubCommand("unalias", CommandObjectSP( 2785 new CommandObjectCommandsUnalias(interpreter))); 2786 LoadSubCommand("delete", 2787 CommandObjectSP(new CommandObjectCommandsDelete(interpreter))); 2788 LoadSubCommand("container", CommandObjectSP(new CommandObjectCommandContainer( 2789 interpreter))); 2790 LoadSubCommand( 2791 "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter))); 2792 LoadSubCommand( 2793 "script", 2794 CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter))); 2795 } 2796 2797 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default; 2798