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