brintos

brintos / llvm-project-archived public Read only

0
0
Text · 107.5 KiB · a3293f0 Raw
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 &current_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 &regex_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