brintos

brintos / llvm-project-archived public Read only

0
0
Text · 64.1 KiB · 4865c48 Raw
1843 lines · cpp
1//===-- CommandObjectPlatform.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 "CommandObjectPlatform.h"10#include "CommandOptionsProcessAttach.h"11#include "CommandOptionsProcessLaunch.h"12#include "lldb/Core/Debugger.h"13#include "lldb/Core/Module.h"14#include "lldb/Core/PluginManager.h"15#include "lldb/Host/OptionParser.h"16#include "lldb/Interpreter/CommandInterpreter.h"17#include "lldb/Interpreter/CommandOptionArgumentTable.h"18#include "lldb/Interpreter/CommandOptionValidators.h"19#include "lldb/Interpreter/CommandReturnObject.h"20#include "lldb/Interpreter/OptionGroupFile.h"21#include "lldb/Interpreter/OptionGroupPlatform.h"22#include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"23#include "lldb/Target/ExecutionContext.h"24#include "lldb/Target/Platform.h"25#include "lldb/Target/Process.h"26#include "lldb/Utility/Args.h"27#include "lldb/Utility/ScriptedMetadata.h"28#include "lldb/Utility/State.h"29 30#include "llvm/ADT/SmallString.h"31 32using namespace lldb;33using namespace lldb_private;34 35static mode_t ParsePermissionString(const char *) = delete;36 37static mode_t ParsePermissionString(llvm::StringRef permissions) {38  if (permissions.size() != 9)39    return (mode_t)(-1);40  bool user_r, user_w, user_x, group_r, group_w, group_x, world_r, world_w,41      world_x;42 43  user_r = (permissions[0] == 'r');44  user_w = (permissions[1] == 'w');45  user_x = (permissions[2] == 'x');46 47  group_r = (permissions[3] == 'r');48  group_w = (permissions[4] == 'w');49  group_x = (permissions[5] == 'x');50 51  world_r = (permissions[6] == 'r');52  world_w = (permissions[7] == 'w');53  world_x = (permissions[8] == 'x');54 55  mode_t user, group, world;56  user = (user_r ? 4 : 0) | (user_w ? 2 : 0) | (user_x ? 1 : 0);57  group = (group_r ? 4 : 0) | (group_w ? 2 : 0) | (group_x ? 1 : 0);58  world = (world_r ? 4 : 0) | (world_w ? 2 : 0) | (world_x ? 1 : 0);59 60  return user | group | world;61}62 63#define LLDB_OPTIONS_permissions64#include "CommandOptions.inc"65 66class OptionPermissions : public OptionGroup {67public:68  OptionPermissions() = default;69 70  ~OptionPermissions() override = default;71 72  lldb_private::Status73  SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,74                 ExecutionContext *execution_context) override {75    Status error;76    char short_option = (char)GetDefinitions()[option_idx].short_option;77    switch (short_option) {78    case 'v': {79      if (option_arg.getAsInteger(8, m_permissions)) {80        m_permissions = 0777;81        error = Status::FromErrorStringWithFormat(82            "invalid value for permissions: %s", option_arg.str().c_str());83      }84 85    } break;86    case 's': {87      mode_t perms = ParsePermissionString(option_arg);88      if (perms == (mode_t)-1)89        error = Status::FromErrorStringWithFormat(90            "invalid value for permissions: %s", option_arg.str().c_str());91      else92        m_permissions = perms;93    } break;94    case 'r':95      m_permissions |= lldb::eFilePermissionsUserRead;96      break;97    case 'w':98      m_permissions |= lldb::eFilePermissionsUserWrite;99      break;100    case 'x':101      m_permissions |= lldb::eFilePermissionsUserExecute;102      break;103    case 'R':104      m_permissions |= lldb::eFilePermissionsGroupRead;105      break;106    case 'W':107      m_permissions |= lldb::eFilePermissionsGroupWrite;108      break;109    case 'X':110      m_permissions |= lldb::eFilePermissionsGroupExecute;111      break;112    case 'd':113      m_permissions |= lldb::eFilePermissionsWorldRead;114      break;115    case 't':116      m_permissions |= lldb::eFilePermissionsWorldWrite;117      break;118    case 'e':119      m_permissions |= lldb::eFilePermissionsWorldExecute;120      break;121    default:122      llvm_unreachable("Unimplemented option");123    }124 125    return error;126  }127 128  void OptionParsingStarting(ExecutionContext *execution_context) override {129    m_permissions = 0;130  }131 132  llvm::ArrayRef<OptionDefinition> GetDefinitions() override {133    return llvm::ArrayRef(g_permissions_options);134  }135 136  // Instance variables to hold the values for command options.137 138  uint32_t m_permissions;139 140private:141  OptionPermissions(const OptionPermissions &) = delete;142  const OptionPermissions &operator=(const OptionPermissions &) = delete;143};144 145// "platform select <platform-name>"146class CommandObjectPlatformSelect : public CommandObjectParsed {147public:148  CommandObjectPlatformSelect(CommandInterpreter &interpreter)149      : CommandObjectParsed(interpreter, "platform select",150                            "Create a platform if needed and select it as the "151                            "current platform.",152                            "platform select <platform-name>", 0),153        m_platform_options(154            false) // Don't include the "--platform" option by passing false155  {156    m_option_group.Append(&m_platform_options, LLDB_OPT_SET_ALL, 1);157    m_option_group.Finalize();158    AddSimpleArgumentList(eArgTypePlatform);159  }160 161  ~CommandObjectPlatformSelect() override = default;162 163  void HandleCompletion(CompletionRequest &request) override {164    lldb_private::CommandCompletions::PlatformPluginNames(165        GetCommandInterpreter(), request, nullptr);166  }167 168  Options *GetOptions() override { return &m_option_group; }169 170protected:171  void DoExecute(Args &args, CommandReturnObject &result) override {172    if (args.GetArgumentCount() == 1) {173      const char *platform_name = args.GetArgumentAtIndex(0);174      if (platform_name && platform_name[0]) {175        const bool select = true;176        m_platform_options.SetPlatformName(platform_name);177        Status error;178        ArchSpec platform_arch;179        PlatformSP platform_sp(m_platform_options.CreatePlatformWithOptions(180            m_interpreter, ArchSpec(), select, error, platform_arch));181        if (platform_sp) {182          GetDebugger().GetPlatformList().SetSelectedPlatform(platform_sp);183 184          platform_sp->GetStatus(result.GetOutputStream());185          result.SetStatus(eReturnStatusSuccessFinishResult);186        } else {187          result.AppendError(error.AsCString());188        }189      } else {190        result.AppendError("invalid platform name");191      }192    } else {193      result.AppendError(194          "platform create takes a platform name as an argument\n");195    }196  }197 198  OptionGroupOptions m_option_group;199  OptionGroupPlatform m_platform_options;200};201 202// "platform list"203class CommandObjectPlatformList : public CommandObjectParsed {204public:205  CommandObjectPlatformList(CommandInterpreter &interpreter)206      : CommandObjectParsed(interpreter, "platform list",207                            "List all platforms that are available.", nullptr,208                            0) {}209 210  ~CommandObjectPlatformList() override = default;211 212protected:213  void DoExecute(Args &args, CommandReturnObject &result) override {214    Stream &ostrm = result.GetOutputStream();215    ostrm.Printf("Available platforms:\n");216 217    PlatformSP host_platform_sp(Platform::GetHostPlatform());218    ostrm.Format("{0}: {1}\n", host_platform_sp->GetPluginName(),219                 host_platform_sp->GetDescription());220 221    uint32_t idx;222    for (idx = 0; true; ++idx) {223      llvm::StringRef plugin_name =224          PluginManager::GetPlatformPluginNameAtIndex(idx);225      if (plugin_name.empty())226        break;227      llvm::StringRef plugin_desc =228          PluginManager::GetPlatformPluginDescriptionAtIndex(idx);229      ostrm.Format("{0}: {1}\n", plugin_name, plugin_desc);230    }231 232    if (idx == 0) {233      result.AppendError("no platforms are available\n");234    } else235      result.SetStatus(eReturnStatusSuccessFinishResult);236  }237};238 239// "platform status"240class CommandObjectPlatformStatus : public CommandObjectParsed {241public:242  CommandObjectPlatformStatus(CommandInterpreter &interpreter)243      : CommandObjectParsed(interpreter, "platform status",244                            "Display status for the current platform.", nullptr,245                            0) {}246 247  ~CommandObjectPlatformStatus() override = default;248 249protected:250  void DoExecute(Args &args, CommandReturnObject &result) override {251    Stream &ostrm = result.GetOutputStream();252 253    Target *target = GetDebugger().GetSelectedTarget().get();254    PlatformSP platform_sp;255    if (target) {256      platform_sp = target->GetPlatform();257    }258    if (!platform_sp) {259      platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();260    }261    if (platform_sp) {262      platform_sp->GetStatus(ostrm);263      result.SetStatus(eReturnStatusSuccessFinishResult);264    } else {265      result.AppendError("no platform is currently selected\n");266    }267  }268};269 270// "platform connect <connect-url>"271class CommandObjectPlatformConnect : public CommandObjectParsed {272public:273  CommandObjectPlatformConnect(CommandInterpreter &interpreter)274      : CommandObjectParsed(275            interpreter, "platform connect",276            "Select the current platform by providing a connection URL.",277            "platform connect <connect-url>", 0) {278    AddSimpleArgumentList(eArgTypeConnectURL);279  }280 281  ~CommandObjectPlatformConnect() override = default;282 283protected:284  void DoExecute(Args &args, CommandReturnObject &result) override {285    Stream &ostrm = result.GetOutputStream();286 287    PlatformSP platform_sp(288        GetDebugger().GetPlatformList().GetSelectedPlatform());289    if (platform_sp) {290      Status error(platform_sp->ConnectRemote(args));291      if (error.Success()) {292        platform_sp->GetStatus(ostrm);293        result.SetStatus(eReturnStatusSuccessFinishResult);294 295        platform_sp->ConnectToWaitingProcesses(GetDebugger(), error);296        if (error.Fail()) {297          result.AppendError(error.AsCString());298        }299      } else {300        result.AppendErrorWithFormat("%s\n", error.AsCString());301      }302    } else {303      result.AppendError("no platform is currently selected\n");304    }305  }306 307  Options *GetOptions() override {308    PlatformSP platform_sp(309        GetDebugger().GetPlatformList().GetSelectedPlatform());310    OptionGroupOptions *m_platform_options = nullptr;311    if (platform_sp) {312      m_platform_options = platform_sp->GetConnectionOptions(m_interpreter);313      if (m_platform_options != nullptr && !m_platform_options->m_did_finalize)314        m_platform_options->Finalize();315    }316    return m_platform_options;317  }318};319 320// "platform disconnect"321class CommandObjectPlatformDisconnect : public CommandObjectParsed {322public:323  CommandObjectPlatformDisconnect(CommandInterpreter &interpreter)324      : CommandObjectParsed(interpreter, "platform disconnect",325                            "Disconnect from the current platform.",326                            "platform disconnect", 0) {}327 328  ~CommandObjectPlatformDisconnect() override = default;329 330protected:331  void DoExecute(Args &args, CommandReturnObject &result) override {332    PlatformSP platform_sp(333        GetDebugger().GetPlatformList().GetSelectedPlatform());334    if (platform_sp) {335      if (args.GetArgumentCount() == 0) {336        Status error;337 338        if (platform_sp->IsConnected()) {339          // Cache the instance name if there is one since we are about to340          // disconnect and the name might go with it.341          const char *hostname_cstr = platform_sp->GetHostname();342          std::string hostname;343          if (hostname_cstr)344            hostname.assign(hostname_cstr);345 346          error = platform_sp->DisconnectRemote();347          if (error.Success()) {348            Stream &ostrm = result.GetOutputStream();349            if (hostname.empty())350              ostrm.Format("Disconnected from \"{0}\"\n",351                           platform_sp->GetPluginName());352            else353              ostrm.Printf("Disconnected from \"%s\"\n", hostname.c_str());354            result.SetStatus(eReturnStatusSuccessFinishResult);355          } else {356            result.AppendErrorWithFormat("%s", error.AsCString());357          }358        } else {359          // Not connected...360          result.AppendErrorWithFormatv("not connected to '{0}'",361                                        platform_sp->GetPluginName());362        }363      } else {364        // Bad args365        result.AppendError(366            "\"platform disconnect\" doesn't take any arguments");367      }368    } else {369      result.AppendError("no platform is currently selected");370    }371  }372};373 374// "platform settings"375class CommandObjectPlatformSettings : public CommandObjectParsed {376public:377  CommandObjectPlatformSettings(CommandInterpreter &interpreter)378      : CommandObjectParsed(interpreter, "platform settings",379                            "Set settings for the current target's platform.",380                            "platform settings", 0),381        m_option_working_dir(LLDB_OPT_SET_1, false, "working-dir", 'w',382                             lldb::eRemoteDiskDirectoryCompletion, eArgTypePath,383                             "The working directory for the platform.") {384    m_options.Append(&m_option_working_dir, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);385  }386 387  ~CommandObjectPlatformSettings() override = default;388 389protected:390  void DoExecute(Args &args, CommandReturnObject &result) override {391    PlatformSP platform_sp(392        GetDebugger().GetPlatformList().GetSelectedPlatform());393    if (platform_sp) {394      if (m_option_working_dir.GetOptionValue().OptionWasSet())395        platform_sp->SetWorkingDirectory(396            m_option_working_dir.GetOptionValue().GetCurrentValue());397    } else {398      result.AppendError("no platform is currently selected");399    }400  }401 402  Options *GetOptions() override {403    if (!m_options.DidFinalize())404      m_options.Finalize();405    return &m_options;406  }407 408  OptionGroupOptions m_options;409  OptionGroupFile m_option_working_dir;410};411 412// "platform mkdir"413class CommandObjectPlatformMkDir : public CommandObjectParsed {414public:415  CommandObjectPlatformMkDir(CommandInterpreter &interpreter)416      : CommandObjectParsed(interpreter, "platform mkdir",417                            "Make a new directory on the remote end.", nullptr,418                            0) {419    AddSimpleArgumentList(eArgTypeRemotePath);420  }421 422  ~CommandObjectPlatformMkDir() override = default;423 424  void DoExecute(Args &args, CommandReturnObject &result) override {425    PlatformSP platform_sp(426        GetDebugger().GetPlatformList().GetSelectedPlatform());427    if (platform_sp) {428      std::string cmd_line;429      args.GetCommandString(cmd_line);430      uint32_t mode;431      const OptionPermissions *options_permissions =432          (const OptionPermissions *)m_options.GetGroupWithOption('r');433      if (options_permissions)434        mode = options_permissions->m_permissions;435      else436        mode = lldb::eFilePermissionsUserRWX | lldb::eFilePermissionsGroupRWX |437               lldb::eFilePermissionsWorldRX;438      Status error = platform_sp->MakeDirectory(FileSpec(cmd_line), mode);439      if (error.Success()) {440        result.SetStatus(eReturnStatusSuccessFinishResult);441      } else {442        result.AppendError(error.AsCString());443      }444    } else {445      result.AppendError("no platform currently selected\n");446    }447  }448 449  Options *GetOptions() override {450    if (!m_options.DidFinalize()) {451      m_options.Append(&m_option_permissions);452      m_options.Finalize();453    }454    return &m_options;455  }456 457  OptionPermissions m_option_permissions;458  OptionGroupOptions m_options;459};460 461// "platform fopen"462class CommandObjectPlatformFOpen : public CommandObjectParsed {463public:464  CommandObjectPlatformFOpen(CommandInterpreter &interpreter)465      : CommandObjectParsed(interpreter, "platform file open",466                            "Open a file on the remote end.", nullptr, 0) {467    AddSimpleArgumentList(eArgTypeRemotePath);468  }469 470  ~CommandObjectPlatformFOpen() override = default;471 472  void DoExecute(Args &args, CommandReturnObject &result) override {473    PlatformSP platform_sp(474        GetDebugger().GetPlatformList().GetSelectedPlatform());475    if (platform_sp) {476      Status error;477      std::string cmd_line;478      args.GetCommandString(cmd_line);479      mode_t perms;480      const OptionPermissions *options_permissions =481          (const OptionPermissions *)m_options.GetGroupWithOption('r');482      if (options_permissions)483        perms = options_permissions->m_permissions;484      else485        perms = lldb::eFilePermissionsUserRW | lldb::eFilePermissionsGroupRW |486                lldb::eFilePermissionsWorldRead;487      lldb::user_id_t fd = platform_sp->OpenFile(488          FileSpec(cmd_line),489          File::eOpenOptionReadWrite | File::eOpenOptionCanCreate,490          perms, error);491      if (error.Success()) {492        result.AppendMessageWithFormat("File Descriptor = %" PRIu64 "\n", fd);493        result.SetStatus(eReturnStatusSuccessFinishResult);494      } else {495        result.AppendError(error.AsCString());496      }497    } else {498      result.AppendError("no platform currently selected\n");499    }500  }501 502  Options *GetOptions() override {503    if (!m_options.DidFinalize()) {504      m_options.Append(&m_option_permissions);505      m_options.Finalize();506    }507    return &m_options;508  }509 510  OptionPermissions m_option_permissions;511  OptionGroupOptions m_options;512};513 514// "platform fclose"515class CommandObjectPlatformFClose : public CommandObjectParsed {516public:517  CommandObjectPlatformFClose(CommandInterpreter &interpreter)518      : CommandObjectParsed(interpreter, "platform file close",519                            "Close a file on the remote end.", nullptr, 0) {520    AddSimpleArgumentList(eArgTypeUnsignedInteger);521  }522 523  ~CommandObjectPlatformFClose() override = default;524 525  void DoExecute(Args &args, CommandReturnObject &result) override {526    PlatformSP platform_sp(527        GetDebugger().GetPlatformList().GetSelectedPlatform());528    if (platform_sp) {529      std::string cmd_line;530      args.GetCommandString(cmd_line);531      lldb::user_id_t fd;532      if (!llvm::to_integer(cmd_line, fd)) {533        result.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.\n",534                                      cmd_line);535        return;536      }537      Status error;538      bool success = platform_sp->CloseFile(fd, error);539      if (success) {540        result.AppendMessageWithFormat("file %" PRIu64 " closed.\n", fd);541        result.SetStatus(eReturnStatusSuccessFinishResult);542      } else {543        result.AppendError(error.AsCString());544      }545    } else {546      result.AppendError("no platform currently selected\n");547    }548  }549};550 551// "platform fread"552 553#define LLDB_OPTIONS_platform_fread554#include "CommandOptions.inc"555 556class CommandObjectPlatformFRead : public CommandObjectParsed {557public:558  CommandObjectPlatformFRead(CommandInterpreter &interpreter)559      : CommandObjectParsed(interpreter, "platform file read",560                            "Read data from a file on the remote end.", nullptr,561                            0) {562    AddSimpleArgumentList(eArgTypeUnsignedInteger);563  }564 565  ~CommandObjectPlatformFRead() override = default;566 567  void DoExecute(Args &args, CommandReturnObject &result) override {568    PlatformSP platform_sp(569        GetDebugger().GetPlatformList().GetSelectedPlatform());570    if (platform_sp) {571      std::string cmd_line;572      args.GetCommandString(cmd_line);573      lldb::user_id_t fd;574      if (!llvm::to_integer(cmd_line, fd)) {575        result.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.\n",576                                      cmd_line);577        return;578      }579      std::string buffer(m_options.m_count, 0);580      Status error;581      uint64_t retcode = platform_sp->ReadFile(582          fd, m_options.m_offset, &buffer[0], m_options.m_count, error);583      if (retcode != UINT64_MAX) {584        result.AppendMessageWithFormat("Return = %" PRIu64 "\n", retcode);585        result.AppendMessageWithFormat("Data = \"%s\"\n", buffer.c_str());586        result.SetStatus(eReturnStatusSuccessFinishResult);587      } else {588        result.AppendError(error.AsCString());589      }590    } else {591      result.AppendError("no platform currently selected\n");592    }593  }594 595  Options *GetOptions() override { return &m_options; }596 597protected:598  class CommandOptions : public Options {599  public:600    CommandOptions() = default;601 602    ~CommandOptions() override = default;603 604    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,605                          ExecutionContext *execution_context) override {606      Status error;607      char short_option = (char)m_getopt_table[option_idx].val;608 609      switch (short_option) {610      case 'o':611        if (option_arg.getAsInteger(0, m_offset))612          error = Status::FromErrorStringWithFormat("invalid offset: '%s'",613                                                    option_arg.str().c_str());614        break;615      case 'c':616        if (option_arg.getAsInteger(0, m_count))617          error = Status::FromErrorStringWithFormat("invalid offset: '%s'",618                                                    option_arg.str().c_str());619        break;620      default:621        llvm_unreachable("Unimplemented option");622      }623 624      return error;625    }626 627    void OptionParsingStarting(ExecutionContext *execution_context) override {628      m_offset = 0;629      m_count = 1;630    }631 632    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {633      return llvm::ArrayRef(g_platform_fread_options);634    }635 636    // Instance variables to hold the values for command options.637 638    uint32_t m_offset;639    uint32_t m_count;640  };641 642  CommandOptions m_options;643};644 645// "platform fwrite"646 647#define LLDB_OPTIONS_platform_fwrite648#include "CommandOptions.inc"649 650class CommandObjectPlatformFWrite : public CommandObjectParsed {651public:652  CommandObjectPlatformFWrite(CommandInterpreter &interpreter)653      : CommandObjectParsed(interpreter, "platform file write",654                            "Write data to a file on the remote end.", nullptr,655                            0) {656    AddSimpleArgumentList(eArgTypeUnsignedInteger);657  }658 659  ~CommandObjectPlatformFWrite() override = default;660 661  void DoExecute(Args &args, CommandReturnObject &result) override {662    PlatformSP platform_sp(663        GetDebugger().GetPlatformList().GetSelectedPlatform());664    if (platform_sp) {665      std::string cmd_line;666      args.GetCommandString(cmd_line);667      Status error;668      lldb::user_id_t fd;669      if (!llvm::to_integer(cmd_line, fd)) {670        result.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.",671                                      cmd_line);672        return;673      }674      uint64_t retcode =675          platform_sp->WriteFile(fd, m_options.m_offset, &m_options.m_data[0],676                                 m_options.m_data.size(), error);677      if (retcode != UINT64_MAX) {678        result.AppendMessageWithFormat("Return = %" PRIu64 "\n", retcode);679        result.SetStatus(eReturnStatusSuccessFinishResult);680      } else {681        result.AppendError(error.AsCString());682      }683    } else {684      result.AppendError("no platform currently selected\n");685    }686  }687 688  Options *GetOptions() override { return &m_options; }689 690protected:691  class CommandOptions : public Options {692  public:693    CommandOptions() = default;694 695    ~CommandOptions() override = default;696 697    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,698                          ExecutionContext *execution_context) override {699      Status error;700      char short_option = (char)m_getopt_table[option_idx].val;701 702      switch (short_option) {703      case 'o':704        if (option_arg.getAsInteger(0, m_offset))705          error = Status::FromErrorStringWithFormat("invalid offset: '%s'",706                                                    option_arg.str().c_str());707        break;708      case 'd':709        m_data.assign(std::string(option_arg));710        break;711      default:712        llvm_unreachable("Unimplemented option");713      }714 715      return error;716    }717 718    void OptionParsingStarting(ExecutionContext *execution_context) override {719      m_offset = 0;720      m_data.clear();721    }722 723    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {724      return llvm::ArrayRef(g_platform_fwrite_options);725    }726 727    // Instance variables to hold the values for command options.728 729    uint32_t m_offset;730    std::string m_data;731  };732 733  CommandOptions m_options;734};735 736class CommandObjectPlatformFile : public CommandObjectMultiword {737public:738  // Constructors and Destructors739  CommandObjectPlatformFile(CommandInterpreter &interpreter)740      : CommandObjectMultiword(741            interpreter, "platform file",742            "Commands to access files on the current platform.",743            "platform file [open|close|read|write] ...") {744    LoadSubCommand(745        "open", CommandObjectSP(new CommandObjectPlatformFOpen(interpreter)));746    LoadSubCommand(747        "close", CommandObjectSP(new CommandObjectPlatformFClose(interpreter)));748    LoadSubCommand(749        "read", CommandObjectSP(new CommandObjectPlatformFRead(interpreter)));750    LoadSubCommand(751        "write", CommandObjectSP(new CommandObjectPlatformFWrite(interpreter)));752  }753 754  ~CommandObjectPlatformFile() override = default;755 756private:757  // For CommandObjectPlatform only758  CommandObjectPlatformFile(const CommandObjectPlatformFile &) = delete;759  const CommandObjectPlatformFile &760  operator=(const CommandObjectPlatformFile &) = delete;761};762 763// "platform get-file remote-file-path host-file-path"764class CommandObjectPlatformGetFile : public CommandObjectParsed {765public:766  CommandObjectPlatformGetFile(CommandInterpreter &interpreter)767      : CommandObjectParsed(768            interpreter, "platform get-file",769            "Transfer a file from the remote end to the local host.",770            "platform get-file <remote-file-spec> <local-file-spec>", 0) {771    SetHelpLong(772        R"(Examples:773 774(lldb) platform get-file /the/remote/file/path /the/local/file/path775 776    Transfer a file from the remote end with file path /the/remote/file/path to the local host.)");777 778    CommandArgumentEntry arg1, arg2;779    CommandArgumentData file_arg_remote, file_arg_host;780 781    // Define the first (and only) variant of this arg.782    file_arg_remote.arg_type = eArgTypeRemoteFilename;783    file_arg_remote.arg_repetition = eArgRepeatPlain;784    // There is only one variant this argument could be; put it into the785    // argument entry.786    arg1.push_back(file_arg_remote);787 788    // Define the second (and only) variant of this arg.789    file_arg_host.arg_type = eArgTypeFilename;790    file_arg_host.arg_repetition = eArgRepeatPlain;791    // There is only one variant this argument could be; put it into the792    // argument entry.793    arg2.push_back(file_arg_host);794 795    // Push the data for the first and the second arguments into the796    // m_arguments vector.797    m_arguments.push_back(arg1);798    m_arguments.push_back(arg2);799  }800 801  ~CommandObjectPlatformGetFile() override = default;802 803  void804  HandleArgumentCompletion(CompletionRequest &request,805                           OptionElementVector &opt_element_vector) override {806    if (request.GetCursorIndex() == 0)807      lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(808          GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion, request,809          nullptr);810    else if (request.GetCursorIndex() == 1)811      lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(812          GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr);813  }814 815  void DoExecute(Args &args, CommandReturnObject &result) override {816    // If the number of arguments is incorrect, issue an error message.817    if (args.GetArgumentCount() != 2) {818      result.AppendError("required arguments missing; specify both the "819                         "source and destination file paths");820      return;821    }822 823    PlatformSP platform_sp(824        GetDebugger().GetPlatformList().GetSelectedPlatform());825    if (platform_sp) {826      const char *remote_file_path = args.GetArgumentAtIndex(0);827      const char *local_file_path = args.GetArgumentAtIndex(1);828      Status error = platform_sp->GetFile(FileSpec(remote_file_path),829                                          FileSpec(local_file_path));830      if (error.Success()) {831        result.AppendMessageWithFormat(832            "successfully get-file from %s (remote) to %s (host)\n",833            remote_file_path, local_file_path);834        result.SetStatus(eReturnStatusSuccessFinishResult);835      } else {836        result.AppendMessageWithFormat("get-file failed: %s\n",837                                       error.AsCString());838      }839    } else {840      result.AppendError("no platform currently selected\n");841    }842  }843};844 845// "platform get-size remote-file-path"846class CommandObjectPlatformGetSize : public CommandObjectParsed {847public:848  CommandObjectPlatformGetSize(CommandInterpreter &interpreter)849      : CommandObjectParsed(interpreter, "platform get-size",850                            "Get the file size from the remote end.",851                            "platform get-size <remote-file-spec>", 0) {852    SetHelpLong(853        R"(Examples:854 855(lldb) platform get-size /the/remote/file/path856 857    Get the file size from the remote end with path /the/remote/file/path.)");858 859    AddSimpleArgumentList(eArgTypeRemoteFilename);860  }861 862  ~CommandObjectPlatformGetSize() override = default;863 864  void DoExecute(Args &args, CommandReturnObject &result) override {865    // If the number of arguments is incorrect, issue an error message.866    if (args.GetArgumentCount() != 1) {867      result.AppendError("required argument missing; specify the source file "868                         "path as the only argument");869      return;870    }871 872    PlatformSP platform_sp(873        GetDebugger().GetPlatformList().GetSelectedPlatform());874    if (platform_sp) {875      std::string remote_file_path(args.GetArgumentAtIndex(0));876      user_id_t size = platform_sp->GetFileSize(FileSpec(remote_file_path));877      if (size != UINT64_MAX) {878        result.AppendMessageWithFormat("File size of %s (remote): %" PRIu64879                                       "\n",880                                       remote_file_path.c_str(), size);881        result.SetStatus(eReturnStatusSuccessFinishResult);882      } else {883        result.AppendMessageWithFormat(884            "Error getting file size of %s (remote)\n",885            remote_file_path.c_str());886      }887    } else {888      result.AppendError("no platform currently selected\n");889    }890  }891};892 893// "platform get-permissions remote-file-path"894class CommandObjectPlatformGetPermissions : public CommandObjectParsed {895public:896  CommandObjectPlatformGetPermissions(CommandInterpreter &interpreter)897      : CommandObjectParsed(interpreter, "platform get-permissions",898                            "Get the file permission bits from the remote end.",899                            "platform get-permissions <remote-file-spec>", 0) {900    SetHelpLong(901        R"(Examples:902 903(lldb) platform get-permissions /the/remote/file/path904 905    Get the file permissions from the remote end with path /the/remote/file/path.)");906 907    AddSimpleArgumentList(eArgTypeRemoteFilename);908  }909 910  ~CommandObjectPlatformGetPermissions() override = default;911 912  void DoExecute(Args &args, CommandReturnObject &result) override {913    // If the number of arguments is incorrect, issue an error message.914    if (args.GetArgumentCount() != 1) {915      result.AppendError("required argument missing; specify the source file "916                         "path as the only argument");917      return;918    }919 920    PlatformSP platform_sp(921        GetDebugger().GetPlatformList().GetSelectedPlatform());922    if (platform_sp) {923      std::string remote_file_path(args.GetArgumentAtIndex(0));924      uint32_t permissions;925      Status error = platform_sp->GetFilePermissions(FileSpec(remote_file_path),926                                                     permissions);927      if (error.Success()) {928        result.AppendMessageWithFormat(929            "File permissions of %s (remote): 0o%04" PRIo32 "\n",930            remote_file_path.c_str(), permissions);931        result.SetStatus(eReturnStatusSuccessFinishResult);932      } else933        result.AppendError(error.AsCString());934    } else {935      result.AppendError("no platform currently selected\n");936    }937  }938};939 940// "platform file-exists remote-file-path"941class CommandObjectPlatformFileExists : public CommandObjectParsed {942public:943  CommandObjectPlatformFileExists(CommandInterpreter &interpreter)944      : CommandObjectParsed(interpreter, "platform file-exists",945                            "Check if the file exists on the remote end.",946                            "platform file-exists <remote-file-spec>", 0) {947    SetHelpLong(948        R"(Examples:949 950(lldb) platform file-exists /the/remote/file/path951 952    Check if /the/remote/file/path exists on the remote end.)");953 954    AddSimpleArgumentList(eArgTypeRemoteFilename);955  }956 957  ~CommandObjectPlatformFileExists() override = default;958 959  void DoExecute(Args &args, CommandReturnObject &result) override {960    // If the number of arguments is incorrect, issue an error message.961    if (args.GetArgumentCount() != 1) {962      result.AppendError("required argument missing; specify the source file "963                         "path as the only argument");964      return;965    }966 967    PlatformSP platform_sp(968        GetDebugger().GetPlatformList().GetSelectedPlatform());969    if (platform_sp) {970      std::string remote_file_path(args.GetArgumentAtIndex(0));971      bool exists = platform_sp->GetFileExists(FileSpec(remote_file_path));972      result.AppendMessageWithFormat(973          "File %s (remote) %s\n",974          remote_file_path.c_str(), exists ? "exists" : "does not exist");975      result.SetStatus(eReturnStatusSuccessFinishResult);976    } else {977      result.AppendError("no platform currently selected\n");978    }979  }980};981 982// "platform put-file"983class CommandObjectPlatformPutFile : public CommandObjectParsed {984public:985  CommandObjectPlatformPutFile(CommandInterpreter &interpreter)986      : CommandObjectParsed(987            interpreter, "platform put-file",988            "Transfer a file from this system to the remote end.",989            "platform put-file <source> [<destination>]", 0) {990    SetHelpLong(991        R"(Examples:992 993(lldb) platform put-file /source/foo.txt /destination/bar.txt994 995(lldb) platform put-file /source/foo.txt996 997    Relative source file paths are resolved against lldb's local working directory.998 999    Omitting the destination places the file in the platform working directory.)");1000    CommandArgumentData source_arg{eArgTypePath, eArgRepeatPlain};1001    CommandArgumentData path_arg{eArgTypeRemotePath, eArgRepeatOptional};1002    m_arguments.push_back({source_arg});1003    m_arguments.push_back({path_arg});1004  }1005 1006  ~CommandObjectPlatformPutFile() override = default;1007 1008  void1009  HandleArgumentCompletion(CompletionRequest &request,1010                           OptionElementVector &opt_element_vector) override {1011    if (request.GetCursorIndex() == 0)1012      lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(1013          GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr);1014    else if (request.GetCursorIndex() == 1)1015      lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(1016          GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion, request,1017          nullptr);1018  }1019 1020  void DoExecute(Args &args, CommandReturnObject &result) override {1021    const char *src = args.GetArgumentAtIndex(0);1022    const char *dst = args.GetArgumentAtIndex(1);1023 1024    FileSpec src_fs(src);1025    FileSystem::Instance().Resolve(src_fs);1026    FileSpec dst_fs(dst ? dst : src_fs.GetFilename().GetCString());1027 1028    PlatformSP platform_sp(1029        GetDebugger().GetPlatformList().GetSelectedPlatform());1030    if (platform_sp) {1031      Status error(platform_sp->PutFile(src_fs, dst_fs));1032      if (error.Success()) {1033        result.SetStatus(eReturnStatusSuccessFinishNoResult);1034      } else {1035        result.AppendError(error.AsCString());1036      }1037    } else {1038      result.AppendError("no platform currently selected\n");1039    }1040  }1041};1042 1043// "platform process launch"1044class CommandObjectPlatformProcessLaunch : public CommandObjectParsed {1045public:1046  CommandObjectPlatformProcessLaunch(CommandInterpreter &interpreter)1047      : CommandObjectParsed(interpreter, "platform process launch",1048                            "Launch a new process on a remote platform.",1049                            "platform process launch program",1050                            eCommandRequiresTarget | eCommandTryTargetAPILock),1051        m_class_options("scripted process", true, 'C', 'k', 'v', 0) {1052    m_all_options.Append(&m_options);1053    m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2,1054                         LLDB_OPT_SET_ALL);1055    m_all_options.Finalize();1056    AddSimpleArgumentList(eArgTypeRunArgs, eArgRepeatStar);1057  }1058 1059  void1060  HandleArgumentCompletion(CompletionRequest &request,1061                           OptionElementVector &opt_element_vector) override {1062    // I didn't make a type for RemoteRunArgs, but since we're going to run1063    // this on the remote system we should use the remote completer.1064    lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(1065        GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion, request,1066        nullptr);1067  }1068 1069  ~CommandObjectPlatformProcessLaunch() override = default;1070 1071  Options *GetOptions() override { return &m_all_options; }1072 1073protected:1074  void DoExecute(Args &args, CommandReturnObject &result) override {1075    Target *target = GetDebugger().GetSelectedTarget().get();1076    PlatformSP platform_sp;1077    if (target) {1078      platform_sp = target->GetPlatform();1079    }1080    if (!platform_sp) {1081      platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();1082    }1083 1084    if (platform_sp) {1085      Status error;1086      const size_t argc = args.GetArgumentCount();1087      Target *target = m_exe_ctx.GetTargetPtr();1088      Module *exe_module = target->GetExecutableModulePointer();1089      if (exe_module) {1090        m_options.launch_info.GetExecutableFile() = exe_module->GetFileSpec();1091        llvm::SmallString<128> exe_path;1092        m_options.launch_info.GetExecutableFile().GetPath(exe_path);1093        if (!exe_path.empty())1094          m_options.launch_info.GetArguments().AppendArgument(exe_path);1095        m_options.launch_info.GetArchitecture() = exe_module->GetArchitecture();1096      }1097 1098      if (!m_class_options.GetName().empty()) {1099        m_options.launch_info.SetProcessPluginName("ScriptedProcess");1100        ScriptedMetadataSP metadata_sp = std::make_shared<ScriptedMetadata>(1101            m_class_options.GetName(), m_class_options.GetStructuredData());1102        m_options.launch_info.SetScriptedMetadata(metadata_sp);1103        target->SetProcessLaunchInfo(m_options.launch_info);1104      }1105 1106      if (argc > 0) {1107        if (m_options.launch_info.GetExecutableFile()) {1108          // We already have an executable file, so we will use this and all1109          // arguments to this function are extra arguments1110          m_options.launch_info.GetArguments().AppendArguments(args);1111        } else {1112          // We don't have any file yet, so the first argument is our1113          // executable, and the rest are program arguments1114          const bool first_arg_is_executable = true;1115          m_options.launch_info.SetArguments(args, first_arg_is_executable);1116        }1117      }1118 1119      if (m_options.launch_info.GetExecutableFile()) {1120        Debugger &debugger = GetDebugger();1121 1122        if (argc == 0) {1123          // If no arguments were given to the command, use target.run-args.1124          Args target_run_args;1125          target->GetRunArguments(target_run_args);1126          m_options.launch_info.GetArguments().AppendArguments(target_run_args);1127        }1128 1129        ProcessSP process_sp(platform_sp->DebugProcess(1130            m_options.launch_info, debugger, *target, error));1131 1132        if (!process_sp && error.Success()) {1133          result.AppendError("failed to launch or debug process");1134          return;1135        } else if (!error.Success()) {1136          result.AppendError(error.AsCString());1137          return;1138        }1139 1140        const bool synchronous_execution =1141            debugger.GetCommandInterpreter().GetSynchronous();1142        auto launch_info = m_options.launch_info;1143        bool rebroadcast_first_stop =1144            !synchronous_execution &&1145            launch_info.GetFlags().Test(eLaunchFlagStopAtEntry);1146 1147        EventSP first_stop_event_sp;1148        StateType state = process_sp->WaitForProcessToStop(1149            std::nullopt, &first_stop_event_sp, rebroadcast_first_stop,1150            launch_info.GetHijackListener());1151        process_sp->RestoreProcessEvents();1152 1153        if (rebroadcast_first_stop) {1154          assert(first_stop_event_sp);1155          process_sp->BroadcastEvent(first_stop_event_sp);1156          return;1157        }1158 1159        switch (state) {1160        case eStateStopped: {1161          if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry))1162            break;1163          if (synchronous_execution) {1164            // Now we have handled the stop-from-attach, and we are just1165            // switching to a synchronous resume.  So we should switch to the1166            // SyncResume hijacker.1167            process_sp->ResumeSynchronous(&result.GetOutputStream());1168          } else {1169            error = process_sp->Resume();1170            if (!error.Success()) {1171              result.AppendErrorWithFormat(1172                  "process resume at entry point failed: %s",1173                  error.AsCString());1174            }1175          }1176        } break;1177        default:1178          result.AppendErrorWithFormat(1179              "initial process state wasn't stopped: %s",1180              StateAsCString(state));1181          break;1182        }1183 1184        if (process_sp && process_sp->IsAlive()) {1185          result.SetStatus(eReturnStatusSuccessFinishNoResult);1186          return;1187        }1188      } else {1189        result.AppendError("'platform process launch' uses the current target "1190                           "file and arguments, or the executable and its "1191                           "arguments can be specified in this command");1192        return;1193      }1194    } else {1195      result.AppendError("no platform is selected\n");1196    }1197  }1198 1199  CommandOptionsProcessLaunch m_options;1200  OptionGroupPythonClassWithDict m_class_options;1201  OptionGroupOptions m_all_options;1202};1203 1204// "platform process list"1205 1206static PosixPlatformCommandOptionValidator posix_validator;1207#define LLDB_OPTIONS_platform_process_list1208#include "CommandOptions.inc"1209 1210class CommandObjectPlatformProcessList : public CommandObjectParsed {1211public:1212  CommandObjectPlatformProcessList(CommandInterpreter &interpreter)1213      : CommandObjectParsed(interpreter, "platform process list",1214                            "List processes on a remote platform by name, pid, "1215                            "or many other matching attributes.",1216                            "platform process list", 0) {}1217 1218  ~CommandObjectPlatformProcessList() override = default;1219 1220  Options *GetOptions() override { return &m_options; }1221 1222protected:1223  void DoExecute(Args &args, CommandReturnObject &result) override {1224    Target *target = GetDebugger().GetSelectedTarget().get();1225    PlatformSP platform_sp;1226    if (target) {1227      platform_sp = target->GetPlatform();1228    }1229    if (!platform_sp) {1230      platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();1231    }1232 1233    if (platform_sp) {1234      Stream &ostrm = result.GetOutputStream();1235 1236      lldb::pid_t pid = m_options.match_info.GetProcessInfo().GetProcessID();1237      if (pid != LLDB_INVALID_PROCESS_ID) {1238        ProcessInstanceInfo proc_info;1239        if (platform_sp->GetProcessInfo(pid, proc_info)) {1240          ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,1241                                               m_options.verbose);1242          proc_info.DumpAsTableRow(ostrm, platform_sp->GetUserIDResolver(),1243                                   m_options.show_args, m_options.verbose);1244          result.SetStatus(eReturnStatusSuccessFinishResult);1245        } else {1246          result.AppendErrorWithFormat(1247              "no process found with pid = %" PRIu64 "\n", pid);1248        }1249      } else {1250        ProcessInstanceInfoList proc_infos;1251        const uint32_t matches =1252            platform_sp->FindProcesses(m_options.match_info, proc_infos);1253        const char *match_desc = nullptr;1254        const char *match_name =1255            m_options.match_info.GetProcessInfo().GetName();1256        if (match_name && match_name[0]) {1257          switch (m_options.match_info.GetNameMatchType()) {1258          case NameMatch::Ignore:1259            break;1260          case NameMatch::Equals:1261            match_desc = "matched";1262            break;1263          case NameMatch::Contains:1264            match_desc = "contained";1265            break;1266          case NameMatch::StartsWith:1267            match_desc = "started with";1268            break;1269          case NameMatch::EndsWith:1270            match_desc = "ended with";1271            break;1272          case NameMatch::RegularExpression:1273            match_desc = "matched the regular expression";1274            break;1275          }1276        }1277 1278        if (matches == 0) {1279          if (match_desc)1280            result.AppendErrorWithFormatv(1281                "no processes were found that {0} \"{1}\" on the \"{2}\" "1282                "platform\n",1283                match_desc, match_name, platform_sp->GetName());1284          else1285            result.AppendErrorWithFormatv(1286                "no processes were found on the \"{0}\" platform\n",1287                platform_sp->GetName());1288        } else {1289          result.AppendMessageWithFormatv(1290              "{0} matching process{1} found on \"{2}\"", matches,1291              matches > 1 ? "es were" : " was", platform_sp->GetName());1292          if (match_desc)1293            result.AppendMessageWithFormat(" whose name %s \"%s\"", match_desc,1294                                           match_name);1295          result.AppendMessageWithFormat("\n");1296          ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,1297                                               m_options.verbose);1298          for (uint32_t i = 0; i < matches; ++i) {1299            proc_infos[i].DumpAsTableRow(1300                ostrm, platform_sp->GetUserIDResolver(), m_options.show_args,1301                m_options.verbose);1302          }1303        }1304      }1305    } else {1306      result.AppendError("no platform is selected\n");1307    }1308  }1309 1310  class CommandOptions : public Options {1311  public:1312    CommandOptions() = default;1313 1314    ~CommandOptions() override = default;1315 1316    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,1317                          ExecutionContext *execution_context) override {1318      Status error;1319      const int short_option = m_getopt_table[option_idx].val;1320      bool success = false;1321 1322      uint32_t id = LLDB_INVALID_PROCESS_ID;1323      success = !option_arg.getAsInteger(0, id);1324      switch (short_option) {1325      case 'p': {1326        match_info.GetProcessInfo().SetProcessID(id);1327        if (!success)1328          error = Status::FromErrorStringWithFormat(1329              "invalid process ID string: '%s'", option_arg.str().c_str());1330        break;1331      }1332      case 'P':1333        match_info.GetProcessInfo().SetParentProcessID(id);1334        if (!success)1335          error = Status::FromErrorStringWithFormat(1336              "invalid parent process ID string: '%s'",1337              option_arg.str().c_str());1338        break;1339 1340      case 'u':1341        match_info.GetProcessInfo().SetUserID(success ? id : UINT32_MAX);1342        if (!success)1343          error = Status::FromErrorStringWithFormat(1344              "invalid user ID string: '%s'", option_arg.str().c_str());1345        break;1346 1347      case 'U':1348        match_info.GetProcessInfo().SetEffectiveUserID(success ? id1349                                                               : UINT32_MAX);1350        if (!success)1351          error = Status::FromErrorStringWithFormat(1352              "invalid effective user ID string: '%s'",1353              option_arg.str().c_str());1354        break;1355 1356      case 'g':1357        match_info.GetProcessInfo().SetGroupID(success ? id : UINT32_MAX);1358        if (!success)1359          error = Status::FromErrorStringWithFormat(1360              "invalid group ID string: '%s'", option_arg.str().c_str());1361        break;1362 1363      case 'G':1364        match_info.GetProcessInfo().SetEffectiveGroupID(success ? id1365                                                                : UINT32_MAX);1366        if (!success)1367          error = Status::FromErrorStringWithFormat(1368              "invalid effective group ID string: '%s'",1369              option_arg.str().c_str());1370        break;1371 1372      case 'a': {1373        TargetSP target_sp =1374            execution_context ? execution_context->GetTargetSP() : TargetSP();1375        DebuggerSP debugger_sp =1376            target_sp ? target_sp->GetDebugger().shared_from_this()1377                      : DebuggerSP();1378        PlatformSP platform_sp =1379            debugger_sp ? debugger_sp->GetPlatformList().GetSelectedPlatform()1380                        : PlatformSP();1381        match_info.GetProcessInfo().GetArchitecture() =1382            Platform::GetAugmentedArchSpec(platform_sp.get(), option_arg);1383      } break;1384 1385      case 'n':1386        match_info.GetProcessInfo().GetExecutableFile().SetFile(1387            option_arg, FileSpec::Style::native);1388        match_info.SetNameMatchType(NameMatch::Equals);1389        break;1390 1391      case 'e':1392        match_info.GetProcessInfo().GetExecutableFile().SetFile(1393            option_arg, FileSpec::Style::native);1394        match_info.SetNameMatchType(NameMatch::EndsWith);1395        break;1396 1397      case 's':1398        match_info.GetProcessInfo().GetExecutableFile().SetFile(1399            option_arg, FileSpec::Style::native);1400        match_info.SetNameMatchType(NameMatch::StartsWith);1401        break;1402 1403      case 'c':1404        match_info.GetProcessInfo().GetExecutableFile().SetFile(1405            option_arg, FileSpec::Style::native);1406        match_info.SetNameMatchType(NameMatch::Contains);1407        break;1408 1409      case 'r':1410        match_info.GetProcessInfo().GetExecutableFile().SetFile(1411            option_arg, FileSpec::Style::native);1412        match_info.SetNameMatchType(NameMatch::RegularExpression);1413        break;1414 1415      case 'A':1416        show_args = true;1417        break;1418 1419      case 'v':1420        verbose = true;1421        break;1422 1423      case 'x':1424        match_info.SetMatchAllUsers(true);1425        break;1426 1427      default:1428        llvm_unreachable("Unimplemented option");1429      }1430 1431      return error;1432    }1433 1434    void OptionParsingStarting(ExecutionContext *execution_context) override {1435      match_info.Clear();1436      show_args = false;1437      verbose = false;1438    }1439 1440    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {1441      return llvm::ArrayRef(g_platform_process_list_options);1442    }1443 1444    // Instance variables to hold the values for command options.1445 1446    ProcessInstanceInfoMatch match_info;1447    bool show_args = false;1448    bool verbose = false;1449  };1450 1451  CommandOptions m_options;1452};1453 1454// "platform process info"1455class CommandObjectPlatformProcessInfo : public CommandObjectParsed {1456public:1457  CommandObjectPlatformProcessInfo(CommandInterpreter &interpreter)1458      : CommandObjectParsed(1459            interpreter, "platform process info",1460            "Get detailed information for one or more process by process ID.",1461            "platform process info <pid> [<pid> <pid> ...]", 0) {1462    AddSimpleArgumentList(eArgTypePid, eArgRepeatStar);1463  }1464 1465  ~CommandObjectPlatformProcessInfo() override = default;1466 1467protected:1468  void DoExecute(Args &args, CommandReturnObject &result) override {1469    Target *target = GetDebugger().GetSelectedTarget().get();1470    PlatformSP platform_sp;1471    if (target) {1472      platform_sp = target->GetPlatform();1473    }1474    if (!platform_sp) {1475      platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();1476    }1477 1478    if (platform_sp) {1479      const size_t argc = args.GetArgumentCount();1480      if (argc > 0) {1481        Status error;1482 1483        if (platform_sp->IsConnected()) {1484          Stream &ostrm = result.GetOutputStream();1485          for (auto &entry : args.entries()) {1486            lldb::pid_t pid;1487            if (entry.ref().getAsInteger(0, pid)) {1488              result.AppendErrorWithFormat("invalid process ID argument '%s'",1489                                           entry.ref().str().c_str());1490              break;1491            } else {1492              ProcessInstanceInfo proc_info;1493              if (platform_sp->GetProcessInfo(pid, proc_info)) {1494                ostrm.Printf("Process information for process %" PRIu64 ":\n",1495                             pid);1496                proc_info.Dump(ostrm, platform_sp->GetUserIDResolver());1497              } else {1498                ostrm.Printf("error: no process information is available for "1499                             "process %" PRIu64 "\n",1500                             pid);1501              }1502              ostrm.EOL();1503            }1504          }1505        } else {1506          // Not connected...1507          result.AppendErrorWithFormatv("not connected to '{0}'",1508                                        platform_sp->GetPluginName());1509        }1510      } else {1511        // No args1512        result.AppendError("one or more process id(s) must be specified");1513      }1514    } else {1515      result.AppendError("no platform is currently selected");1516    }1517  }1518};1519 1520#define LLDB_OPTIONS_platform_process_attach1521#include "CommandOptions.inc"1522 1523class CommandObjectPlatformProcessAttach : public CommandObjectParsed {1524public:1525  CommandObjectPlatformProcessAttach(CommandInterpreter &interpreter)1526      : CommandObjectParsed(interpreter, "platform process attach",1527                            "Attach to a process.",1528                            "platform process attach <cmd-options>"),1529        m_class_options("scripted process", true, 'C', 'k', 'v', 0) {1530    m_all_options.Append(&m_options);1531    m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2,1532                         LLDB_OPT_SET_ALL);1533    m_all_options.Finalize();1534  }1535 1536  ~CommandObjectPlatformProcessAttach() override = default;1537 1538  void DoExecute(Args &command, CommandReturnObject &result) override {1539    PlatformSP platform_sp(1540        GetDebugger().GetPlatformList().GetSelectedPlatform());1541    if (platform_sp) {1542 1543      if (!m_class_options.GetName().empty()) {1544        m_options.attach_info.SetProcessPluginName("ScriptedProcess");1545        ScriptedMetadataSP metadata_sp = std::make_shared<ScriptedMetadata>(1546            m_class_options.GetName(), m_class_options.GetStructuredData());1547        m_options.attach_info.SetScriptedMetadata(metadata_sp);1548      }1549 1550      Status err;1551      ProcessSP remote_process_sp = platform_sp->Attach(1552          m_options.attach_info, GetDebugger(), nullptr, err);1553      if (err.Fail()) {1554        result.AppendError(err.AsCString());1555      } else if (!remote_process_sp) {1556        result.AppendError("could not attach: unknown reason");1557      } else1558        result.SetStatus(eReturnStatusSuccessFinishResult);1559    } else {1560      result.AppendError("no platform is currently selected");1561    }1562  }1563 1564  Options *GetOptions() override { return &m_all_options; }1565 1566protected:1567  CommandOptionsProcessAttach m_options;1568  OptionGroupPythonClassWithDict m_class_options;1569  OptionGroupOptions m_all_options;1570};1571 1572class CommandObjectPlatformProcess : public CommandObjectMultiword {1573public:1574  // Constructors and Destructors1575  CommandObjectPlatformProcess(CommandInterpreter &interpreter)1576      : CommandObjectMultiword(interpreter, "platform process",1577                               "Commands to query, launch and attach to "1578                               "processes on the current platform.",1579                               "platform process [attach|launch|list] ...") {1580    LoadSubCommand(1581        "attach",1582        CommandObjectSP(new CommandObjectPlatformProcessAttach(interpreter)));1583    LoadSubCommand(1584        "launch",1585        CommandObjectSP(new CommandObjectPlatformProcessLaunch(interpreter)));1586    LoadSubCommand("info", CommandObjectSP(new CommandObjectPlatformProcessInfo(1587                               interpreter)));1588    LoadSubCommand("list", CommandObjectSP(new CommandObjectPlatformProcessList(1589                               interpreter)));1590  }1591 1592  ~CommandObjectPlatformProcess() override = default;1593 1594private:1595  // For CommandObjectPlatform only1596  CommandObjectPlatformProcess(const CommandObjectPlatformProcess &) = delete;1597  const CommandObjectPlatformProcess &1598  operator=(const CommandObjectPlatformProcess &) = delete;1599};1600 1601// "platform shell"1602#define LLDB_OPTIONS_platform_shell1603#include "CommandOptions.inc"1604 1605class CommandObjectPlatformShell : public CommandObjectRaw {1606public:1607  class CommandOptions : public Options {1608  public:1609    CommandOptions() = default;1610 1611    ~CommandOptions() override = default;1612 1613    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {1614      return llvm::ArrayRef(g_platform_shell_options);1615    }1616 1617    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,1618                          ExecutionContext *execution_context) override {1619      Status error;1620 1621      const char short_option = (char)GetDefinitions()[option_idx].short_option;1622 1623      switch (short_option) {1624      case 'h':1625        m_use_host_platform = true;1626        break;1627      case 't':1628        uint32_t timeout_sec;1629        if (option_arg.getAsInteger(10, timeout_sec))1630          error = Status::FromErrorStringWithFormat(1631              "could not convert \"%s\" to a numeric value.",1632              option_arg.str().c_str());1633        else1634          m_timeout = std::chrono::seconds(timeout_sec);1635        break;1636      case 's': {1637        if (option_arg.empty()) {1638          error = Status::FromErrorStringWithFormat(1639              "missing shell interpreter path for option -i|--interpreter.");1640          return error;1641        }1642 1643        m_shell_interpreter = option_arg.str();1644        break;1645      }1646      default:1647        llvm_unreachable("Unimplemented option");1648      }1649 1650      return error;1651    }1652 1653    void OptionParsingStarting(ExecutionContext *execution_context) override {1654      m_timeout.reset();1655      m_use_host_platform = false;1656      m_shell_interpreter.clear();1657    }1658 1659    Timeout<std::micro> m_timeout = std::chrono::seconds(10);1660    bool m_use_host_platform;1661    std::string m_shell_interpreter;1662  };1663 1664  CommandObjectPlatformShell(CommandInterpreter &interpreter)1665      : CommandObjectRaw(interpreter, "platform shell",1666                         "Run a shell command on the current platform.",1667                         "platform shell <shell-command>", 0) {1668    AddSimpleArgumentList(eArgTypeNone, eArgRepeatStar);1669  }1670 1671  ~CommandObjectPlatformShell() override = default;1672 1673  Options *GetOptions() override { return &m_options; }1674 1675  void DoExecute(llvm::StringRef raw_command_line,1676                 CommandReturnObject &result) override {1677    ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();1678    m_options.NotifyOptionParsingStarting(&exe_ctx);1679 1680    // Print out an usage syntax on an empty command line.1681    if (raw_command_line.empty()) {1682      result.GetOutputStream().Printf("%s\n", this->GetSyntax().str().c_str());1683      return;1684    }1685 1686    const bool is_alias = !raw_command_line.contains("platform");1687    OptionsWithRaw args(raw_command_line);1688 1689    if (args.HasArgs())1690      if (!ParseOptions(args.GetArgs(), result))1691        return;1692 1693    if (args.GetRawPart().empty()) {1694      result.GetOutputStream().Printf("%s <shell-command>\n",1695                                      is_alias ? "shell" : "platform shell");1696      return;1697    }1698 1699    llvm::StringRef cmd = args.GetRawPart();1700 1701    PlatformSP platform_sp(1702        m_options.m_use_host_platform1703            ? Platform::GetHostPlatform()1704            : GetDebugger().GetPlatformList().GetSelectedPlatform());1705    Status error;1706    if (platform_sp) {1707      FileSpec working_dir{};1708      std::string output;1709      int status = -1;1710      int signo = -1;1711      error = (platform_sp->RunShellCommand(m_options.m_shell_interpreter, cmd,1712                                            working_dir, &status, &signo,1713                                            &output, m_options.m_timeout));1714      if (!output.empty())1715        result.GetOutputStream().PutCString(output);1716      if (status > 0) {1717        if (signo > 0) {1718          const char *signo_cstr = Host::GetSignalAsCString(signo);1719          if (signo_cstr)1720            result.GetOutputStream().Printf(1721                "error: command returned with status %i and signal %s\n",1722                status, signo_cstr);1723          else1724            result.GetOutputStream().Printf(1725                "error: command returned with status %i and signal %i\n",1726                status, signo);1727        } else1728          result.GetOutputStream().Printf(1729              "error: command returned with status %i\n", status);1730      }1731    } else {1732      result.GetOutputStream().Printf(1733          "error: cannot run remote shell commands without a platform\n");1734      error = Status::FromErrorString(1735          "error: cannot run remote shell commands without a platform");1736    }1737 1738    if (error.Fail()) {1739      result.AppendError(error.AsCString());1740    } else {1741      result.SetStatus(eReturnStatusSuccessFinishResult);1742    }1743  }1744 1745  CommandOptions m_options;1746};1747 1748// "platform install" - install a target to a remote end1749class CommandObjectPlatformInstall : public CommandObjectParsed {1750public:1751  CommandObjectPlatformInstall(CommandInterpreter &interpreter)1752      : CommandObjectParsed(1753            interpreter, "platform target-install",1754            "Install a target (bundle or executable file) to the remote end.",1755            "platform target-install <local-thing> <remote-sandbox>", 0) {1756    CommandArgumentData local_arg{eArgTypePath, eArgRepeatPlain};1757    CommandArgumentData remote_arg{eArgTypeRemotePath, eArgRepeatPlain};1758    m_arguments.push_back({local_arg});1759    m_arguments.push_back({remote_arg});1760  }1761 1762  ~CommandObjectPlatformInstall() override = default;1763 1764  void1765  HandleArgumentCompletion(CompletionRequest &request,1766                           OptionElementVector &opt_element_vector) override {1767    if (request.GetCursorIndex())1768      return;1769    lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(1770        GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr);1771  }1772 1773  void DoExecute(Args &args, CommandReturnObject &result) override {1774    if (args.GetArgumentCount() != 2) {1775      result.AppendError("platform target-install takes two arguments");1776      return;1777    }1778    // TODO: move the bulk of this code over to the platform itself1779    FileSpec src(args.GetArgumentAtIndex(0));1780    FileSystem::Instance().Resolve(src);1781    FileSpec dst(args.GetArgumentAtIndex(1));1782    if (!FileSystem::Instance().Exists(src)) {1783      result.AppendError("source location does not exist or is not accessible");1784      return;1785    }1786    PlatformSP platform_sp(1787        GetDebugger().GetPlatformList().GetSelectedPlatform());1788    if (!platform_sp) {1789      result.AppendError("no platform currently selected");1790      return;1791    }1792 1793    Status error = platform_sp->Install(src, dst);1794    if (error.Success()) {1795      result.SetStatus(eReturnStatusSuccessFinishNoResult);1796    } else {1797      result.AppendErrorWithFormat("install failed: %s", error.AsCString());1798    }1799  }1800};1801 1802CommandObjectPlatform::CommandObjectPlatform(CommandInterpreter &interpreter)1803    : CommandObjectMultiword(1804          interpreter, "platform", "Commands to manage and create platforms.",1805          "platform [connect|disconnect|info|list|status|select] ...") {1806  LoadSubCommand("select",1807                 CommandObjectSP(new CommandObjectPlatformSelect(interpreter)));1808  LoadSubCommand("list",1809                 CommandObjectSP(new CommandObjectPlatformList(interpreter)));1810  LoadSubCommand("status",1811                 CommandObjectSP(new CommandObjectPlatformStatus(interpreter)));1812  LoadSubCommand("connect", CommandObjectSP(1813                                new CommandObjectPlatformConnect(interpreter)));1814  LoadSubCommand(1815      "disconnect",1816      CommandObjectSP(new CommandObjectPlatformDisconnect(interpreter)));1817  LoadSubCommand("settings", CommandObjectSP(new CommandObjectPlatformSettings(1818                                 interpreter)));1819  LoadSubCommand("mkdir",1820                 CommandObjectSP(new CommandObjectPlatformMkDir(interpreter)));1821  LoadSubCommand("file",1822                 CommandObjectSP(new CommandObjectPlatformFile(interpreter)));1823  LoadSubCommand("file-exists",1824      CommandObjectSP(new CommandObjectPlatformFileExists(interpreter)));1825  LoadSubCommand("get-file", CommandObjectSP(new CommandObjectPlatformGetFile(1826                                 interpreter)));1827  LoadSubCommand("get-permissions",1828      CommandObjectSP(new CommandObjectPlatformGetPermissions(interpreter)));1829  LoadSubCommand("get-size", CommandObjectSP(new CommandObjectPlatformGetSize(1830                                 interpreter)));1831  LoadSubCommand("put-file", CommandObjectSP(new CommandObjectPlatformPutFile(1832                                 interpreter)));1833  LoadSubCommand("process", CommandObjectSP(1834                                new CommandObjectPlatformProcess(interpreter)));1835  LoadSubCommand("shell",1836                 CommandObjectSP(new CommandObjectPlatformShell(interpreter)));1837  LoadSubCommand(1838      "target-install",1839      CommandObjectSP(new CommandObjectPlatformInstall(interpreter)));1840}1841 1842CommandObjectPlatform::~CommandObjectPlatform() = default;1843