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