Path: blob/main/contrib/llvm-project/lldb/source/Commands/CommandObjectPlatform.cpp
39587 views
//===-- CommandObjectPlatform.cpp -----------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "CommandObjectPlatform.h"9#include "CommandOptionsProcessAttach.h"10#include "CommandOptionsProcessLaunch.h"11#include "lldb/Core/Debugger.h"12#include "lldb/Core/Module.h"13#include "lldb/Core/PluginManager.h"14#include "lldb/Host/OptionParser.h"15#include "lldb/Interpreter/CommandInterpreter.h"16#include "lldb/Interpreter/CommandOptionArgumentTable.h"17#include "lldb/Interpreter/CommandOptionValidators.h"18#include "lldb/Interpreter/CommandReturnObject.h"19#include "lldb/Interpreter/OptionGroupFile.h"20#include "lldb/Interpreter/OptionGroupPlatform.h"21#include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"22#include "lldb/Target/ExecutionContext.h"23#include "lldb/Target/Platform.h"24#include "lldb/Target/Process.h"25#include "lldb/Utility/Args.h"26#include "lldb/Utility/ScriptedMetadata.h"27#include "lldb/Utility/State.h"2829#include "llvm/ADT/SmallString.h"3031using namespace lldb;32using namespace lldb_private;3334static mode_t ParsePermissionString(const char *) = delete;3536static mode_t ParsePermissionString(llvm::StringRef permissions) {37if (permissions.size() != 9)38return (mode_t)(-1);39bool user_r, user_w, user_x, group_r, group_w, group_x, world_r, world_w,40world_x;4142user_r = (permissions[0] == 'r');43user_w = (permissions[1] == 'w');44user_x = (permissions[2] == 'x');4546group_r = (permissions[3] == 'r');47group_w = (permissions[4] == 'w');48group_x = (permissions[5] == 'x');4950world_r = (permissions[6] == 'r');51world_w = (permissions[7] == 'w');52world_x = (permissions[8] == 'x');5354mode_t user, group, world;55user = (user_r ? 4 : 0) | (user_w ? 2 : 0) | (user_x ? 1 : 0);56group = (group_r ? 4 : 0) | (group_w ? 2 : 0) | (group_x ? 1 : 0);57world = (world_r ? 4 : 0) | (world_w ? 2 : 0) | (world_x ? 1 : 0);5859return user | group | world;60}6162#define LLDB_OPTIONS_permissions63#include "CommandOptions.inc"6465class OptionPermissions : public OptionGroup {66public:67OptionPermissions() = default;6869~OptionPermissions() override = default;7071lldb_private::Status72SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,73ExecutionContext *execution_context) override {74Status error;75char short_option = (char)GetDefinitions()[option_idx].short_option;76switch (short_option) {77case 'v': {78if (option_arg.getAsInteger(8, m_permissions)) {79m_permissions = 0777;80error.SetErrorStringWithFormat("invalid value for permissions: %s",81option_arg.str().c_str());82}8384} break;85case 's': {86mode_t perms = ParsePermissionString(option_arg);87if (perms == (mode_t)-1)88error.SetErrorStringWithFormat("invalid value for permissions: %s",89option_arg.str().c_str());90else91m_permissions = perms;92} break;93case 'r':94m_permissions |= lldb::eFilePermissionsUserRead;95break;96case 'w':97m_permissions |= lldb::eFilePermissionsUserWrite;98break;99case 'x':100m_permissions |= lldb::eFilePermissionsUserExecute;101break;102case 'R':103m_permissions |= lldb::eFilePermissionsGroupRead;104break;105case 'W':106m_permissions |= lldb::eFilePermissionsGroupWrite;107break;108case 'X':109m_permissions |= lldb::eFilePermissionsGroupExecute;110break;111case 'd':112m_permissions |= lldb::eFilePermissionsWorldRead;113break;114case 't':115m_permissions |= lldb::eFilePermissionsWorldWrite;116break;117case 'e':118m_permissions |= lldb::eFilePermissionsWorldExecute;119break;120default:121llvm_unreachable("Unimplemented option");122}123124return error;125}126127void OptionParsingStarting(ExecutionContext *execution_context) override {128m_permissions = 0;129}130131llvm::ArrayRef<OptionDefinition> GetDefinitions() override {132return llvm::ArrayRef(g_permissions_options);133}134135// Instance variables to hold the values for command options.136137uint32_t m_permissions;138139private:140OptionPermissions(const OptionPermissions &) = delete;141const OptionPermissions &operator=(const OptionPermissions &) = delete;142};143144// "platform select <platform-name>"145class CommandObjectPlatformSelect : public CommandObjectParsed {146public:147CommandObjectPlatformSelect(CommandInterpreter &interpreter)148: CommandObjectParsed(interpreter, "platform select",149"Create a platform if needed and select it as the "150"current platform.",151"platform select <platform-name>", 0),152m_platform_options(153false) // Don't include the "--platform" option by passing false154{155m_option_group.Append(&m_platform_options, LLDB_OPT_SET_ALL, 1);156m_option_group.Finalize();157AddSimpleArgumentList(eArgTypePlatform);158}159160~CommandObjectPlatformSelect() override = default;161162void HandleCompletion(CompletionRequest &request) override {163lldb_private::CommandCompletions::PlatformPluginNames(164GetCommandInterpreter(), request, nullptr);165}166167Options *GetOptions() override { return &m_option_group; }168169protected:170void DoExecute(Args &args, CommandReturnObject &result) override {171if (args.GetArgumentCount() == 1) {172const char *platform_name = args.GetArgumentAtIndex(0);173if (platform_name && platform_name[0]) {174const bool select = true;175m_platform_options.SetPlatformName(platform_name);176Status error;177ArchSpec platform_arch;178PlatformSP platform_sp(m_platform_options.CreatePlatformWithOptions(179m_interpreter, ArchSpec(), select, error, platform_arch));180if (platform_sp) {181GetDebugger().GetPlatformList().SetSelectedPlatform(platform_sp);182183platform_sp->GetStatus(result.GetOutputStream());184result.SetStatus(eReturnStatusSuccessFinishResult);185} else {186result.AppendError(error.AsCString());187}188} else {189result.AppendError("invalid platform name");190}191} else {192result.AppendError(193"platform create takes a platform name as an argument\n");194}195}196197OptionGroupOptions m_option_group;198OptionGroupPlatform m_platform_options;199};200201// "platform list"202class CommandObjectPlatformList : public CommandObjectParsed {203public:204CommandObjectPlatformList(CommandInterpreter &interpreter)205: CommandObjectParsed(interpreter, "platform list",206"List all platforms that are available.", nullptr,2070) {}208209~CommandObjectPlatformList() override = default;210211protected:212void DoExecute(Args &args, CommandReturnObject &result) override {213Stream &ostrm = result.GetOutputStream();214ostrm.Printf("Available platforms:\n");215216PlatformSP host_platform_sp(Platform::GetHostPlatform());217ostrm.Format("{0}: {1}\n", host_platform_sp->GetPluginName(),218host_platform_sp->GetDescription());219220uint32_t idx;221for (idx = 0; true; ++idx) {222llvm::StringRef plugin_name =223PluginManager::GetPlatformPluginNameAtIndex(idx);224if (plugin_name.empty())225break;226llvm::StringRef plugin_desc =227PluginManager::GetPlatformPluginDescriptionAtIndex(idx);228ostrm.Format("{0}: {1}\n", plugin_name, plugin_desc);229}230231if (idx == 0) {232result.AppendError("no platforms are available\n");233} else234result.SetStatus(eReturnStatusSuccessFinishResult);235}236};237238// "platform status"239class CommandObjectPlatformStatus : public CommandObjectParsed {240public:241CommandObjectPlatformStatus(CommandInterpreter &interpreter)242: CommandObjectParsed(interpreter, "platform status",243"Display status for the current platform.", nullptr,2440) {}245246~CommandObjectPlatformStatus() override = default;247248protected:249void DoExecute(Args &args, CommandReturnObject &result) override {250Stream &ostrm = result.GetOutputStream();251252Target *target = GetDebugger().GetSelectedTarget().get();253PlatformSP platform_sp;254if (target) {255platform_sp = target->GetPlatform();256}257if (!platform_sp) {258platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();259}260if (platform_sp) {261platform_sp->GetStatus(ostrm);262result.SetStatus(eReturnStatusSuccessFinishResult);263} else {264result.AppendError("no platform is currently selected\n");265}266}267};268269// "platform connect <connect-url>"270class CommandObjectPlatformConnect : public CommandObjectParsed {271public:272CommandObjectPlatformConnect(CommandInterpreter &interpreter)273: CommandObjectParsed(274interpreter, "platform connect",275"Select the current platform by providing a connection URL.",276"platform connect <connect-url>", 0) {277AddSimpleArgumentList(eArgTypeConnectURL);278}279280~CommandObjectPlatformConnect() override = default;281282protected:283void DoExecute(Args &args, CommandReturnObject &result) override {284Stream &ostrm = result.GetOutputStream();285286PlatformSP platform_sp(287GetDebugger().GetPlatformList().GetSelectedPlatform());288if (platform_sp) {289Status error(platform_sp->ConnectRemote(args));290if (error.Success()) {291platform_sp->GetStatus(ostrm);292result.SetStatus(eReturnStatusSuccessFinishResult);293294platform_sp->ConnectToWaitingProcesses(GetDebugger(), error);295if (error.Fail()) {296result.AppendError(error.AsCString());297}298} else {299result.AppendErrorWithFormat("%s\n", error.AsCString());300}301} else {302result.AppendError("no platform is currently selected\n");303}304}305306Options *GetOptions() override {307PlatformSP platform_sp(308GetDebugger().GetPlatformList().GetSelectedPlatform());309OptionGroupOptions *m_platform_options = nullptr;310if (platform_sp) {311m_platform_options = platform_sp->GetConnectionOptions(m_interpreter);312if (m_platform_options != nullptr && !m_platform_options->m_did_finalize)313m_platform_options->Finalize();314}315return m_platform_options;316}317};318319// "platform disconnect"320class CommandObjectPlatformDisconnect : public CommandObjectParsed {321public:322CommandObjectPlatformDisconnect(CommandInterpreter &interpreter)323: CommandObjectParsed(interpreter, "platform disconnect",324"Disconnect from the current platform.",325"platform disconnect", 0) {}326327~CommandObjectPlatformDisconnect() override = default;328329protected:330void DoExecute(Args &args, CommandReturnObject &result) override {331PlatformSP platform_sp(332GetDebugger().GetPlatformList().GetSelectedPlatform());333if (platform_sp) {334if (args.GetArgumentCount() == 0) {335Status error;336337if (platform_sp->IsConnected()) {338// Cache the instance name if there is one since we are about to339// disconnect and the name might go with it.340const char *hostname_cstr = platform_sp->GetHostname();341std::string hostname;342if (hostname_cstr)343hostname.assign(hostname_cstr);344345error = platform_sp->DisconnectRemote();346if (error.Success()) {347Stream &ostrm = result.GetOutputStream();348if (hostname.empty())349ostrm.Format("Disconnected from \"{0}\"\n",350platform_sp->GetPluginName());351else352ostrm.Printf("Disconnected from \"%s\"\n", hostname.c_str());353result.SetStatus(eReturnStatusSuccessFinishResult);354} else {355result.AppendErrorWithFormat("%s", error.AsCString());356}357} else {358// Not connected...359result.AppendErrorWithFormatv("not connected to '{0}'",360platform_sp->GetPluginName());361}362} else {363// Bad args364result.AppendError(365"\"platform disconnect\" doesn't take any arguments");366}367} else {368result.AppendError("no platform is currently selected");369}370}371};372373// "platform settings"374class CommandObjectPlatformSettings : public CommandObjectParsed {375public:376CommandObjectPlatformSettings(CommandInterpreter &interpreter)377: CommandObjectParsed(interpreter, "platform settings",378"Set settings for the current target's platform.",379"platform settings", 0),380m_option_working_dir(LLDB_OPT_SET_1, false, "working-dir", 'w',381lldb::eRemoteDiskDirectoryCompletion, eArgTypePath,382"The working directory for the platform.") {383m_options.Append(&m_option_working_dir, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);384}385386~CommandObjectPlatformSettings() override = default;387388protected:389void DoExecute(Args &args, CommandReturnObject &result) override {390PlatformSP platform_sp(391GetDebugger().GetPlatformList().GetSelectedPlatform());392if (platform_sp) {393if (m_option_working_dir.GetOptionValue().OptionWasSet())394platform_sp->SetWorkingDirectory(395m_option_working_dir.GetOptionValue().GetCurrentValue());396} else {397result.AppendError("no platform is currently selected");398}399}400401Options *GetOptions() override {402if (!m_options.DidFinalize())403m_options.Finalize();404return &m_options;405}406407OptionGroupOptions m_options;408OptionGroupFile m_option_working_dir;409};410411// "platform mkdir"412class CommandObjectPlatformMkDir : public CommandObjectParsed {413public:414CommandObjectPlatformMkDir(CommandInterpreter &interpreter)415: CommandObjectParsed(interpreter, "platform mkdir",416"Make a new directory on the remote end.", nullptr,4170) {418AddSimpleArgumentList(eArgTypeRemotePath);419}420421~CommandObjectPlatformMkDir() override = default;422423void DoExecute(Args &args, CommandReturnObject &result) override {424PlatformSP platform_sp(425GetDebugger().GetPlatformList().GetSelectedPlatform());426if (platform_sp) {427std::string cmd_line;428args.GetCommandString(cmd_line);429uint32_t mode;430const OptionPermissions *options_permissions =431(const OptionPermissions *)m_options.GetGroupWithOption('r');432if (options_permissions)433mode = options_permissions->m_permissions;434else435mode = lldb::eFilePermissionsUserRWX | lldb::eFilePermissionsGroupRWX |436lldb::eFilePermissionsWorldRX;437Status error = platform_sp->MakeDirectory(FileSpec(cmd_line), mode);438if (error.Success()) {439result.SetStatus(eReturnStatusSuccessFinishResult);440} else {441result.AppendError(error.AsCString());442}443} else {444result.AppendError("no platform currently selected\n");445}446}447448Options *GetOptions() override {449if (!m_options.DidFinalize()) {450m_options.Append(&m_option_permissions);451m_options.Finalize();452}453return &m_options;454}455456OptionPermissions m_option_permissions;457OptionGroupOptions m_options;458};459460// "platform fopen"461class CommandObjectPlatformFOpen : public CommandObjectParsed {462public:463CommandObjectPlatformFOpen(CommandInterpreter &interpreter)464: CommandObjectParsed(interpreter, "platform file open",465"Open a file on the remote end.", nullptr, 0) {466AddSimpleArgumentList(eArgTypeRemotePath);467}468469~CommandObjectPlatformFOpen() override = default;470471void DoExecute(Args &args, CommandReturnObject &result) override {472PlatformSP platform_sp(473GetDebugger().GetPlatformList().GetSelectedPlatform());474if (platform_sp) {475Status error;476std::string cmd_line;477args.GetCommandString(cmd_line);478mode_t perms;479const OptionPermissions *options_permissions =480(const OptionPermissions *)m_options.GetGroupWithOption('r');481if (options_permissions)482perms = options_permissions->m_permissions;483else484perms = lldb::eFilePermissionsUserRW | lldb::eFilePermissionsGroupRW |485lldb::eFilePermissionsWorldRead;486lldb::user_id_t fd = platform_sp->OpenFile(487FileSpec(cmd_line),488File::eOpenOptionReadWrite | File::eOpenOptionCanCreate,489perms, error);490if (error.Success()) {491result.AppendMessageWithFormat("File Descriptor = %" PRIu64 "\n", fd);492result.SetStatus(eReturnStatusSuccessFinishResult);493} else {494result.AppendError(error.AsCString());495}496} else {497result.AppendError("no platform currently selected\n");498}499}500501Options *GetOptions() override {502if (!m_options.DidFinalize()) {503m_options.Append(&m_option_permissions);504m_options.Finalize();505}506return &m_options;507}508509OptionPermissions m_option_permissions;510OptionGroupOptions m_options;511};512513// "platform fclose"514class CommandObjectPlatformFClose : public CommandObjectParsed {515public:516CommandObjectPlatformFClose(CommandInterpreter &interpreter)517: CommandObjectParsed(interpreter, "platform file close",518"Close a file on the remote end.", nullptr, 0) {519AddSimpleArgumentList(eArgTypeUnsignedInteger);520}521522~CommandObjectPlatformFClose() override = default;523524void DoExecute(Args &args, CommandReturnObject &result) override {525PlatformSP platform_sp(526GetDebugger().GetPlatformList().GetSelectedPlatform());527if (platform_sp) {528std::string cmd_line;529args.GetCommandString(cmd_line);530lldb::user_id_t fd;531if (!llvm::to_integer(cmd_line, fd)) {532result.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.\n",533cmd_line);534return;535}536Status error;537bool success = platform_sp->CloseFile(fd, error);538if (success) {539result.AppendMessageWithFormat("file %" PRIu64 " closed.\n", fd);540result.SetStatus(eReturnStatusSuccessFinishResult);541} else {542result.AppendError(error.AsCString());543}544} else {545result.AppendError("no platform currently selected\n");546}547}548};549550// "platform fread"551552#define LLDB_OPTIONS_platform_fread553#include "CommandOptions.inc"554555class CommandObjectPlatformFRead : public CommandObjectParsed {556public:557CommandObjectPlatformFRead(CommandInterpreter &interpreter)558: CommandObjectParsed(interpreter, "platform file read",559"Read data from a file on the remote end.", nullptr,5600) {561AddSimpleArgumentList(eArgTypeUnsignedInteger);562}563564~CommandObjectPlatformFRead() override = default;565566void DoExecute(Args &args, CommandReturnObject &result) override {567PlatformSP platform_sp(568GetDebugger().GetPlatformList().GetSelectedPlatform());569if (platform_sp) {570std::string cmd_line;571args.GetCommandString(cmd_line);572lldb::user_id_t fd;573if (!llvm::to_integer(cmd_line, fd)) {574result.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.\n",575cmd_line);576return;577}578std::string buffer(m_options.m_count, 0);579Status error;580uint64_t retcode = platform_sp->ReadFile(581fd, m_options.m_offset, &buffer[0], m_options.m_count, error);582if (retcode != UINT64_MAX) {583result.AppendMessageWithFormat("Return = %" PRIu64 "\n", retcode);584result.AppendMessageWithFormat("Data = \"%s\"\n", buffer.c_str());585result.SetStatus(eReturnStatusSuccessFinishResult);586} else {587result.AppendError(error.AsCString());588}589} else {590result.AppendError("no platform currently selected\n");591}592}593594Options *GetOptions() override { return &m_options; }595596protected:597class CommandOptions : public Options {598public:599CommandOptions() = default;600601~CommandOptions() override = default;602603Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,604ExecutionContext *execution_context) override {605Status error;606char short_option = (char)m_getopt_table[option_idx].val;607608switch (short_option) {609case 'o':610if (option_arg.getAsInteger(0, m_offset))611error.SetErrorStringWithFormat("invalid offset: '%s'",612option_arg.str().c_str());613break;614case 'c':615if (option_arg.getAsInteger(0, m_count))616error.SetErrorStringWithFormat("invalid offset: '%s'",617option_arg.str().c_str());618break;619default:620llvm_unreachable("Unimplemented option");621}622623return error;624}625626void OptionParsingStarting(ExecutionContext *execution_context) override {627m_offset = 0;628m_count = 1;629}630631llvm::ArrayRef<OptionDefinition> GetDefinitions() override {632return llvm::ArrayRef(g_platform_fread_options);633}634635// Instance variables to hold the values for command options.636637uint32_t m_offset;638uint32_t m_count;639};640641CommandOptions m_options;642};643644// "platform fwrite"645646#define LLDB_OPTIONS_platform_fwrite647#include "CommandOptions.inc"648649class CommandObjectPlatformFWrite : public CommandObjectParsed {650public:651CommandObjectPlatformFWrite(CommandInterpreter &interpreter)652: CommandObjectParsed(interpreter, "platform file write",653"Write data to a file on the remote end.", nullptr,6540) {655AddSimpleArgumentList(eArgTypeUnsignedInteger);656}657658~CommandObjectPlatformFWrite() override = default;659660void DoExecute(Args &args, CommandReturnObject &result) override {661PlatformSP platform_sp(662GetDebugger().GetPlatformList().GetSelectedPlatform());663if (platform_sp) {664std::string cmd_line;665args.GetCommandString(cmd_line);666Status error;667lldb::user_id_t fd;668if (!llvm::to_integer(cmd_line, fd)) {669result.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.",670cmd_line);671return;672}673uint64_t retcode =674platform_sp->WriteFile(fd, m_options.m_offset, &m_options.m_data[0],675m_options.m_data.size(), error);676if (retcode != UINT64_MAX) {677result.AppendMessageWithFormat("Return = %" PRIu64 "\n", retcode);678result.SetStatus(eReturnStatusSuccessFinishResult);679} else {680result.AppendError(error.AsCString());681}682} else {683result.AppendError("no platform currently selected\n");684}685}686687Options *GetOptions() override { return &m_options; }688689protected:690class CommandOptions : public Options {691public:692CommandOptions() = default;693694~CommandOptions() override = default;695696Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,697ExecutionContext *execution_context) override {698Status error;699char short_option = (char)m_getopt_table[option_idx].val;700701switch (short_option) {702case 'o':703if (option_arg.getAsInteger(0, m_offset))704error.SetErrorStringWithFormat("invalid offset: '%s'",705option_arg.str().c_str());706break;707case 'd':708m_data.assign(std::string(option_arg));709break;710default:711llvm_unreachable("Unimplemented option");712}713714return error;715}716717void OptionParsingStarting(ExecutionContext *execution_context) override {718m_offset = 0;719m_data.clear();720}721722llvm::ArrayRef<OptionDefinition> GetDefinitions() override {723return llvm::ArrayRef(g_platform_fwrite_options);724}725726// Instance variables to hold the values for command options.727728uint32_t m_offset;729std::string m_data;730};731732CommandOptions m_options;733};734735class CommandObjectPlatformFile : public CommandObjectMultiword {736public:737// Constructors and Destructors738CommandObjectPlatformFile(CommandInterpreter &interpreter)739: CommandObjectMultiword(740interpreter, "platform file",741"Commands to access files on the current platform.",742"platform file [open|close|read|write] ...") {743LoadSubCommand(744"open", CommandObjectSP(new CommandObjectPlatformFOpen(interpreter)));745LoadSubCommand(746"close", CommandObjectSP(new CommandObjectPlatformFClose(interpreter)));747LoadSubCommand(748"read", CommandObjectSP(new CommandObjectPlatformFRead(interpreter)));749LoadSubCommand(750"write", CommandObjectSP(new CommandObjectPlatformFWrite(interpreter)));751}752753~CommandObjectPlatformFile() override = default;754755private:756// For CommandObjectPlatform only757CommandObjectPlatformFile(const CommandObjectPlatformFile &) = delete;758const CommandObjectPlatformFile &759operator=(const CommandObjectPlatformFile &) = delete;760};761762// "platform get-file remote-file-path host-file-path"763class CommandObjectPlatformGetFile : public CommandObjectParsed {764public:765CommandObjectPlatformGetFile(CommandInterpreter &interpreter)766: CommandObjectParsed(767interpreter, "platform get-file",768"Transfer a file from the remote end to the local host.",769"platform get-file <remote-file-spec> <local-file-spec>", 0) {770SetHelpLong(771R"(Examples:772773(lldb) platform get-file /the/remote/file/path /the/local/file/path774775Transfer a file from the remote end with file path /the/remote/file/path to the local host.)");776777CommandArgumentEntry arg1, arg2;778CommandArgumentData file_arg_remote, file_arg_host;779780// Define the first (and only) variant of this arg.781file_arg_remote.arg_type = eArgTypeRemoteFilename;782file_arg_remote.arg_repetition = eArgRepeatPlain;783// There is only one variant this argument could be; put it into the784// argument entry.785arg1.push_back(file_arg_remote);786787// Define the second (and only) variant of this arg.788file_arg_host.arg_type = eArgTypeFilename;789file_arg_host.arg_repetition = eArgRepeatPlain;790// There is only one variant this argument could be; put it into the791// argument entry.792arg2.push_back(file_arg_host);793794// Push the data for the first and the second arguments into the795// m_arguments vector.796m_arguments.push_back(arg1);797m_arguments.push_back(arg2);798}799800~CommandObjectPlatformGetFile() override = default;801802void803HandleArgumentCompletion(CompletionRequest &request,804OptionElementVector &opt_element_vector) override {805if (request.GetCursorIndex() == 0)806lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(807GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion, request,808nullptr);809else if (request.GetCursorIndex() == 1)810lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(811GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr);812}813814void DoExecute(Args &args, CommandReturnObject &result) override {815// If the number of arguments is incorrect, issue an error message.816if (args.GetArgumentCount() != 2) {817result.AppendError("required arguments missing; specify both the "818"source and destination file paths");819return;820}821822PlatformSP platform_sp(823GetDebugger().GetPlatformList().GetSelectedPlatform());824if (platform_sp) {825const char *remote_file_path = args.GetArgumentAtIndex(0);826const char *local_file_path = args.GetArgumentAtIndex(1);827Status error = platform_sp->GetFile(FileSpec(remote_file_path),828FileSpec(local_file_path));829if (error.Success()) {830result.AppendMessageWithFormat(831"successfully get-file from %s (remote) to %s (host)\n",832remote_file_path, local_file_path);833result.SetStatus(eReturnStatusSuccessFinishResult);834} else {835result.AppendMessageWithFormat("get-file failed: %s\n",836error.AsCString());837}838} else {839result.AppendError("no platform currently selected\n");840}841}842};843844// "platform get-size remote-file-path"845class CommandObjectPlatformGetSize : public CommandObjectParsed {846public:847CommandObjectPlatformGetSize(CommandInterpreter &interpreter)848: CommandObjectParsed(interpreter, "platform get-size",849"Get the file size from the remote end.",850"platform get-size <remote-file-spec>", 0) {851SetHelpLong(852R"(Examples:853854(lldb) platform get-size /the/remote/file/path855856Get the file size from the remote end with path /the/remote/file/path.)");857858AddSimpleArgumentList(eArgTypeRemoteFilename);859}860861~CommandObjectPlatformGetSize() override = default;862863void DoExecute(Args &args, CommandReturnObject &result) override {864// If the number of arguments is incorrect, issue an error message.865if (args.GetArgumentCount() != 1) {866result.AppendError("required argument missing; specify the source file "867"path as the only argument");868return;869}870871PlatformSP platform_sp(872GetDebugger().GetPlatformList().GetSelectedPlatform());873if (platform_sp) {874std::string remote_file_path(args.GetArgumentAtIndex(0));875user_id_t size = platform_sp->GetFileSize(FileSpec(remote_file_path));876if (size != UINT64_MAX) {877result.AppendMessageWithFormat("File size of %s (remote): %" PRIu64878"\n",879remote_file_path.c_str(), size);880result.SetStatus(eReturnStatusSuccessFinishResult);881} else {882result.AppendMessageWithFormat(883"Error getting file size of %s (remote)\n",884remote_file_path.c_str());885}886} else {887result.AppendError("no platform currently selected\n");888}889}890};891892// "platform get-permissions remote-file-path"893class CommandObjectPlatformGetPermissions : public CommandObjectParsed {894public:895CommandObjectPlatformGetPermissions(CommandInterpreter &interpreter)896: CommandObjectParsed(interpreter, "platform get-permissions",897"Get the file permission bits from the remote end.",898"platform get-permissions <remote-file-spec>", 0) {899SetHelpLong(900R"(Examples:901902(lldb) platform get-permissions /the/remote/file/path903904Get the file permissions from the remote end with path /the/remote/file/path.)");905906AddSimpleArgumentList(eArgTypeRemoteFilename);907}908909~CommandObjectPlatformGetPermissions() override = default;910911void DoExecute(Args &args, CommandReturnObject &result) override {912// If the number of arguments is incorrect, issue an error message.913if (args.GetArgumentCount() != 1) {914result.AppendError("required argument missing; specify the source file "915"path as the only argument");916return;917}918919PlatformSP platform_sp(920GetDebugger().GetPlatformList().GetSelectedPlatform());921if (platform_sp) {922std::string remote_file_path(args.GetArgumentAtIndex(0));923uint32_t permissions;924Status error = platform_sp->GetFilePermissions(FileSpec(remote_file_path),925permissions);926if (error.Success()) {927result.AppendMessageWithFormat(928"File permissions of %s (remote): 0o%04" PRIo32 "\n",929remote_file_path.c_str(), permissions);930result.SetStatus(eReturnStatusSuccessFinishResult);931} else932result.AppendError(error.AsCString());933} else {934result.AppendError("no platform currently selected\n");935}936}937};938939// "platform file-exists remote-file-path"940class CommandObjectPlatformFileExists : public CommandObjectParsed {941public:942CommandObjectPlatformFileExists(CommandInterpreter &interpreter)943: CommandObjectParsed(interpreter, "platform file-exists",944"Check if the file exists on the remote end.",945"platform file-exists <remote-file-spec>", 0) {946SetHelpLong(947R"(Examples:948949(lldb) platform file-exists /the/remote/file/path950951Check if /the/remote/file/path exists on the remote end.)");952953AddSimpleArgumentList(eArgTypeRemoteFilename);954}955956~CommandObjectPlatformFileExists() override = default;957958void DoExecute(Args &args, CommandReturnObject &result) override {959// If the number of arguments is incorrect, issue an error message.960if (args.GetArgumentCount() != 1) {961result.AppendError("required argument missing; specify the source file "962"path as the only argument");963return;964}965966PlatformSP platform_sp(967GetDebugger().GetPlatformList().GetSelectedPlatform());968if (platform_sp) {969std::string remote_file_path(args.GetArgumentAtIndex(0));970bool exists = platform_sp->GetFileExists(FileSpec(remote_file_path));971result.AppendMessageWithFormat(972"File %s (remote) %s\n",973remote_file_path.c_str(), exists ? "exists" : "does not exist");974result.SetStatus(eReturnStatusSuccessFinishResult);975} else {976result.AppendError("no platform currently selected\n");977}978}979};980981// "platform put-file"982class CommandObjectPlatformPutFile : public CommandObjectParsed {983public:984CommandObjectPlatformPutFile(CommandInterpreter &interpreter)985: CommandObjectParsed(986interpreter, "platform put-file",987"Transfer a file from this system to the remote end.",988"platform put-file <source> [<destination>]", 0) {989SetHelpLong(990R"(Examples:991992(lldb) platform put-file /source/foo.txt /destination/bar.txt993994(lldb) platform put-file /source/foo.txt995996Relative source file paths are resolved against lldb's local working directory.997998Omitting the destination places the file in the platform working directory.)");999CommandArgumentData source_arg{eArgTypePath, eArgRepeatPlain};1000CommandArgumentData path_arg{eArgTypeRemotePath, eArgRepeatOptional};1001m_arguments.push_back({source_arg});1002m_arguments.push_back({path_arg});1003}10041005~CommandObjectPlatformPutFile() override = default;10061007void1008HandleArgumentCompletion(CompletionRequest &request,1009OptionElementVector &opt_element_vector) override {1010if (request.GetCursorIndex() == 0)1011lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(1012GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr);1013else if (request.GetCursorIndex() == 1)1014lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(1015GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion, request,1016nullptr);1017}10181019void DoExecute(Args &args, CommandReturnObject &result) override {1020const char *src = args.GetArgumentAtIndex(0);1021const char *dst = args.GetArgumentAtIndex(1);10221023FileSpec src_fs(src);1024FileSystem::Instance().Resolve(src_fs);1025FileSpec dst_fs(dst ? dst : src_fs.GetFilename().GetCString());10261027PlatformSP platform_sp(1028GetDebugger().GetPlatformList().GetSelectedPlatform());1029if (platform_sp) {1030Status error(platform_sp->PutFile(src_fs, dst_fs));1031if (error.Success()) {1032result.SetStatus(eReturnStatusSuccessFinishNoResult);1033} else {1034result.AppendError(error.AsCString());1035}1036} else {1037result.AppendError("no platform currently selected\n");1038}1039}1040};10411042// "platform process launch"1043class CommandObjectPlatformProcessLaunch : public CommandObjectParsed {1044public:1045CommandObjectPlatformProcessLaunch(CommandInterpreter &interpreter)1046: CommandObjectParsed(interpreter, "platform process launch",1047"Launch a new process on a remote platform.",1048"platform process launch program",1049eCommandRequiresTarget | eCommandTryTargetAPILock),1050m_class_options("scripted process", true, 'C', 'k', 'v', 0) {1051m_all_options.Append(&m_options);1052m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2,1053LLDB_OPT_SET_ALL);1054m_all_options.Finalize();1055AddSimpleArgumentList(eArgTypeRunArgs, eArgRepeatStar);1056}10571058void1059HandleArgumentCompletion(CompletionRequest &request,1060OptionElementVector &opt_element_vector) override {1061// I didn't make a type for RemoteRunArgs, but since we're going to run1062// this on the remote system we should use the remote completer.1063lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(1064GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion, request,1065nullptr);1066}10671068~CommandObjectPlatformProcessLaunch() override = default;10691070Options *GetOptions() override { return &m_all_options; }10711072protected:1073void DoExecute(Args &args, CommandReturnObject &result) override {1074Target *target = GetDebugger().GetSelectedTarget().get();1075PlatformSP platform_sp;1076if (target) {1077platform_sp = target->GetPlatform();1078}1079if (!platform_sp) {1080platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();1081}10821083if (platform_sp) {1084Status error;1085const size_t argc = args.GetArgumentCount();1086Target *target = m_exe_ctx.GetTargetPtr();1087Module *exe_module = target->GetExecutableModulePointer();1088if (exe_module) {1089m_options.launch_info.GetExecutableFile() = exe_module->GetFileSpec();1090llvm::SmallString<128> exe_path;1091m_options.launch_info.GetExecutableFile().GetPath(exe_path);1092if (!exe_path.empty())1093m_options.launch_info.GetArguments().AppendArgument(exe_path);1094m_options.launch_info.GetArchitecture() = exe_module->GetArchitecture();1095}10961097if (!m_class_options.GetName().empty()) {1098m_options.launch_info.SetProcessPluginName("ScriptedProcess");1099ScriptedMetadataSP metadata_sp = std::make_shared<ScriptedMetadata>(1100m_class_options.GetName(), m_class_options.GetStructuredData());1101m_options.launch_info.SetScriptedMetadata(metadata_sp);1102target->SetProcessLaunchInfo(m_options.launch_info);1103}11041105if (argc > 0) {1106if (m_options.launch_info.GetExecutableFile()) {1107// We already have an executable file, so we will use this and all1108// arguments to this function are extra arguments1109m_options.launch_info.GetArguments().AppendArguments(args);1110} else {1111// We don't have any file yet, so the first argument is our1112// executable, and the rest are program arguments1113const bool first_arg_is_executable = true;1114m_options.launch_info.SetArguments(args, first_arg_is_executable);1115}1116}11171118if (m_options.launch_info.GetExecutableFile()) {1119Debugger &debugger = GetDebugger();11201121if (argc == 0) {1122// If no arguments were given to the command, use target.run-args.1123Args target_run_args;1124target->GetRunArguments(target_run_args);1125m_options.launch_info.GetArguments().AppendArguments(target_run_args);1126}11271128ProcessSP process_sp(platform_sp->DebugProcess(1129m_options.launch_info, debugger, *target, error));11301131if (!process_sp && error.Success()) {1132result.AppendError("failed to launch or debug process");1133return;1134} else if (!error.Success()) {1135result.AppendError(error.AsCString());1136return;1137}11381139const bool synchronous_execution =1140debugger.GetCommandInterpreter().GetSynchronous();1141auto launch_info = m_options.launch_info;1142bool rebroadcast_first_stop =1143!synchronous_execution &&1144launch_info.GetFlags().Test(eLaunchFlagStopAtEntry);11451146EventSP first_stop_event_sp;1147StateType state = process_sp->WaitForProcessToStop(1148std::nullopt, &first_stop_event_sp, rebroadcast_first_stop,1149launch_info.GetHijackListener());1150process_sp->RestoreProcessEvents();11511152if (rebroadcast_first_stop) {1153assert(first_stop_event_sp);1154process_sp->BroadcastEvent(first_stop_event_sp);1155return;1156}11571158switch (state) {1159case eStateStopped: {1160if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry))1161break;1162if (synchronous_execution) {1163// Now we have handled the stop-from-attach, and we are just1164// switching to a synchronous resume. So we should switch to the1165// SyncResume hijacker.1166process_sp->ResumeSynchronous(&result.GetOutputStream());1167} else {1168error = process_sp->Resume();1169if (!error.Success()) {1170result.AppendErrorWithFormat(1171"process resume at entry point failed: %s",1172error.AsCString());1173}1174}1175} break;1176default:1177result.AppendErrorWithFormat(1178"initial process state wasn't stopped: %s",1179StateAsCString(state));1180break;1181}11821183if (process_sp && process_sp->IsAlive()) {1184result.SetStatus(eReturnStatusSuccessFinishNoResult);1185return;1186}1187} else {1188result.AppendError("'platform process launch' uses the current target "1189"file and arguments, or the executable and its "1190"arguments can be specified in this command");1191return;1192}1193} else {1194result.AppendError("no platform is selected\n");1195}1196}11971198CommandOptionsProcessLaunch m_options;1199OptionGroupPythonClassWithDict m_class_options;1200OptionGroupOptions m_all_options;1201};12021203// "platform process list"12041205static PosixPlatformCommandOptionValidator posix_validator;1206#define LLDB_OPTIONS_platform_process_list1207#include "CommandOptions.inc"12081209class CommandObjectPlatformProcessList : public CommandObjectParsed {1210public:1211CommandObjectPlatformProcessList(CommandInterpreter &interpreter)1212: CommandObjectParsed(interpreter, "platform process list",1213"List processes on a remote platform by name, pid, "1214"or many other matching attributes.",1215"platform process list", 0) {}12161217~CommandObjectPlatformProcessList() override = default;12181219Options *GetOptions() override { return &m_options; }12201221protected:1222void DoExecute(Args &args, CommandReturnObject &result) override {1223Target *target = GetDebugger().GetSelectedTarget().get();1224PlatformSP platform_sp;1225if (target) {1226platform_sp = target->GetPlatform();1227}1228if (!platform_sp) {1229platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();1230}12311232if (platform_sp) {1233Status error;1234if (platform_sp) {1235Stream &ostrm = result.GetOutputStream();12361237lldb::pid_t pid = m_options.match_info.GetProcessInfo().GetProcessID();1238if (pid != LLDB_INVALID_PROCESS_ID) {1239ProcessInstanceInfo proc_info;1240if (platform_sp->GetProcessInfo(pid, proc_info)) {1241ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,1242m_options.verbose);1243proc_info.DumpAsTableRow(ostrm, platform_sp->GetUserIDResolver(),1244m_options.show_args, m_options.verbose);1245result.SetStatus(eReturnStatusSuccessFinishResult);1246} else {1247result.AppendErrorWithFormat(1248"no process found with pid = %" PRIu64 "\n", pid);1249}1250} else {1251ProcessInstanceInfoList proc_infos;1252const uint32_t matches =1253platform_sp->FindProcesses(m_options.match_info, proc_infos);1254const char *match_desc = nullptr;1255const char *match_name =1256m_options.match_info.GetProcessInfo().GetName();1257if (match_name && match_name[0]) {1258switch (m_options.match_info.GetNameMatchType()) {1259case NameMatch::Ignore:1260break;1261case NameMatch::Equals:1262match_desc = "matched";1263break;1264case NameMatch::Contains:1265match_desc = "contained";1266break;1267case NameMatch::StartsWith:1268match_desc = "started with";1269break;1270case NameMatch::EndsWith:1271match_desc = "ended with";1272break;1273case NameMatch::RegularExpression:1274match_desc = "matched the regular expression";1275break;1276}1277}12781279if (matches == 0) {1280if (match_desc)1281result.AppendErrorWithFormatv(1282"no processes were found that {0} \"{1}\" on the \"{2}\" "1283"platform\n",1284match_desc, match_name, platform_sp->GetName());1285else1286result.AppendErrorWithFormatv(1287"no processes were found on the \"{0}\" platform\n",1288platform_sp->GetName());1289} else {1290result.AppendMessageWithFormatv(1291"{0} matching process{1} found on \"{2}\"", matches,1292matches > 1 ? "es were" : " was", platform_sp->GetName());1293if (match_desc)1294result.AppendMessageWithFormat(" whose name %s \"%s\"",1295match_desc, match_name);1296result.AppendMessageWithFormat("\n");1297ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,1298m_options.verbose);1299for (uint32_t i = 0; i < matches; ++i) {1300proc_infos[i].DumpAsTableRow(1301ostrm, platform_sp->GetUserIDResolver(), m_options.show_args,1302m_options.verbose);1303}1304}1305}1306}1307} else {1308result.AppendError("no platform is selected\n");1309}1310}13111312class CommandOptions : public Options {1313public:1314CommandOptions() = default;13151316~CommandOptions() override = default;13171318Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,1319ExecutionContext *execution_context) override {1320Status error;1321const int short_option = m_getopt_table[option_idx].val;1322bool success = false;13231324uint32_t id = LLDB_INVALID_PROCESS_ID;1325success = !option_arg.getAsInteger(0, id);1326switch (short_option) {1327case 'p': {1328match_info.GetProcessInfo().SetProcessID(id);1329if (!success)1330error.SetErrorStringWithFormat("invalid process ID string: '%s'",1331option_arg.str().c_str());1332break;1333}1334case 'P':1335match_info.GetProcessInfo().SetParentProcessID(id);1336if (!success)1337error.SetErrorStringWithFormat(1338"invalid parent process ID string: '%s'",1339option_arg.str().c_str());1340break;13411342case 'u':1343match_info.GetProcessInfo().SetUserID(success ? id : UINT32_MAX);1344if (!success)1345error.SetErrorStringWithFormat("invalid user ID string: '%s'",1346option_arg.str().c_str());1347break;13481349case 'U':1350match_info.GetProcessInfo().SetEffectiveUserID(success ? id1351: UINT32_MAX);1352if (!success)1353error.SetErrorStringWithFormat(1354"invalid effective user ID string: '%s'",1355option_arg.str().c_str());1356break;13571358case 'g':1359match_info.GetProcessInfo().SetGroupID(success ? id : UINT32_MAX);1360if (!success)1361error.SetErrorStringWithFormat("invalid group ID string: '%s'",1362option_arg.str().c_str());1363break;13641365case 'G':1366match_info.GetProcessInfo().SetEffectiveGroupID(success ? id1367: UINT32_MAX);1368if (!success)1369error.SetErrorStringWithFormat(1370"invalid effective group ID string: '%s'",1371option_arg.str().c_str());1372break;13731374case 'a': {1375TargetSP target_sp =1376execution_context ? execution_context->GetTargetSP() : TargetSP();1377DebuggerSP debugger_sp =1378target_sp ? target_sp->GetDebugger().shared_from_this()1379: DebuggerSP();1380PlatformSP platform_sp =1381debugger_sp ? debugger_sp->GetPlatformList().GetSelectedPlatform()1382: PlatformSP();1383match_info.GetProcessInfo().GetArchitecture() =1384Platform::GetAugmentedArchSpec(platform_sp.get(), option_arg);1385} break;13861387case 'n':1388match_info.GetProcessInfo().GetExecutableFile().SetFile(1389option_arg, FileSpec::Style::native);1390match_info.SetNameMatchType(NameMatch::Equals);1391break;13921393case 'e':1394match_info.GetProcessInfo().GetExecutableFile().SetFile(1395option_arg, FileSpec::Style::native);1396match_info.SetNameMatchType(NameMatch::EndsWith);1397break;13981399case 's':1400match_info.GetProcessInfo().GetExecutableFile().SetFile(1401option_arg, FileSpec::Style::native);1402match_info.SetNameMatchType(NameMatch::StartsWith);1403break;14041405case 'c':1406match_info.GetProcessInfo().GetExecutableFile().SetFile(1407option_arg, FileSpec::Style::native);1408match_info.SetNameMatchType(NameMatch::Contains);1409break;14101411case 'r':1412match_info.GetProcessInfo().GetExecutableFile().SetFile(1413option_arg, FileSpec::Style::native);1414match_info.SetNameMatchType(NameMatch::RegularExpression);1415break;14161417case 'A':1418show_args = true;1419break;14201421case 'v':1422verbose = true;1423break;14241425case 'x':1426match_info.SetMatchAllUsers(true);1427break;14281429default:1430llvm_unreachable("Unimplemented option");1431}14321433return error;1434}14351436void OptionParsingStarting(ExecutionContext *execution_context) override {1437match_info.Clear();1438show_args = false;1439verbose = false;1440}14411442llvm::ArrayRef<OptionDefinition> GetDefinitions() override {1443return llvm::ArrayRef(g_platform_process_list_options);1444}14451446// Instance variables to hold the values for command options.14471448ProcessInstanceInfoMatch match_info;1449bool show_args = false;1450bool verbose = false;1451};14521453CommandOptions m_options;1454};14551456// "platform process info"1457class CommandObjectPlatformProcessInfo : public CommandObjectParsed {1458public:1459CommandObjectPlatformProcessInfo(CommandInterpreter &interpreter)1460: CommandObjectParsed(1461interpreter, "platform process info",1462"Get detailed information for one or more process by process ID.",1463"platform process info <pid> [<pid> <pid> ...]", 0) {1464AddSimpleArgumentList(eArgTypePid, eArgRepeatStar);1465}14661467~CommandObjectPlatformProcessInfo() override = default;14681469protected:1470void DoExecute(Args &args, CommandReturnObject &result) override {1471Target *target = GetDebugger().GetSelectedTarget().get();1472PlatformSP platform_sp;1473if (target) {1474platform_sp = target->GetPlatform();1475}1476if (!platform_sp) {1477platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();1478}14791480if (platform_sp) {1481const size_t argc = args.GetArgumentCount();1482if (argc > 0) {1483Status error;14841485if (platform_sp->IsConnected()) {1486Stream &ostrm = result.GetOutputStream();1487for (auto &entry : args.entries()) {1488lldb::pid_t pid;1489if (entry.ref().getAsInteger(0, pid)) {1490result.AppendErrorWithFormat("invalid process ID argument '%s'",1491entry.ref().str().c_str());1492break;1493} else {1494ProcessInstanceInfo proc_info;1495if (platform_sp->GetProcessInfo(pid, proc_info)) {1496ostrm.Printf("Process information for process %" PRIu64 ":\n",1497pid);1498proc_info.Dump(ostrm, platform_sp->GetUserIDResolver());1499} else {1500ostrm.Printf("error: no process information is available for "1501"process %" PRIu64 "\n",1502pid);1503}1504ostrm.EOL();1505}1506}1507} else {1508// Not connected...1509result.AppendErrorWithFormatv("not connected to '{0}'",1510platform_sp->GetPluginName());1511}1512} else {1513// No args1514result.AppendError("one or more process id(s) must be specified");1515}1516} else {1517result.AppendError("no platform is currently selected");1518}1519}1520};15211522#define LLDB_OPTIONS_platform_process_attach1523#include "CommandOptions.inc"15241525class CommandObjectPlatformProcessAttach : public CommandObjectParsed {1526public:1527CommandObjectPlatformProcessAttach(CommandInterpreter &interpreter)1528: CommandObjectParsed(interpreter, "platform process attach",1529"Attach to a process.",1530"platform process attach <cmd-options>"),1531m_class_options("scripted process", true, 'C', 'k', 'v', 0) {1532m_all_options.Append(&m_options);1533m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2,1534LLDB_OPT_SET_ALL);1535m_all_options.Finalize();1536}15371538~CommandObjectPlatformProcessAttach() override = default;15391540void DoExecute(Args &command, CommandReturnObject &result) override {1541PlatformSP platform_sp(1542GetDebugger().GetPlatformList().GetSelectedPlatform());1543if (platform_sp) {15441545if (!m_class_options.GetName().empty()) {1546m_options.attach_info.SetProcessPluginName("ScriptedProcess");1547ScriptedMetadataSP metadata_sp = std::make_shared<ScriptedMetadata>(1548m_class_options.GetName(), m_class_options.GetStructuredData());1549m_options.attach_info.SetScriptedMetadata(metadata_sp);1550}15511552Status err;1553ProcessSP remote_process_sp = platform_sp->Attach(1554m_options.attach_info, GetDebugger(), nullptr, err);1555if (err.Fail()) {1556result.AppendError(err.AsCString());1557} else if (!remote_process_sp) {1558result.AppendError("could not attach: unknown reason");1559} else1560result.SetStatus(eReturnStatusSuccessFinishResult);1561} else {1562result.AppendError("no platform is currently selected");1563}1564}15651566Options *GetOptions() override { return &m_all_options; }15671568protected:1569CommandOptionsProcessAttach m_options;1570OptionGroupPythonClassWithDict m_class_options;1571OptionGroupOptions m_all_options;1572};15731574class CommandObjectPlatformProcess : public CommandObjectMultiword {1575public:1576// Constructors and Destructors1577CommandObjectPlatformProcess(CommandInterpreter &interpreter)1578: CommandObjectMultiword(interpreter, "platform process",1579"Commands to query, launch and attach to "1580"processes on the current platform.",1581"platform process [attach|launch|list] ...") {1582LoadSubCommand(1583"attach",1584CommandObjectSP(new CommandObjectPlatformProcessAttach(interpreter)));1585LoadSubCommand(1586"launch",1587CommandObjectSP(new CommandObjectPlatformProcessLaunch(interpreter)));1588LoadSubCommand("info", CommandObjectSP(new CommandObjectPlatformProcessInfo(1589interpreter)));1590LoadSubCommand("list", CommandObjectSP(new CommandObjectPlatformProcessList(1591interpreter)));1592}15931594~CommandObjectPlatformProcess() override = default;15951596private:1597// For CommandObjectPlatform only1598CommandObjectPlatformProcess(const CommandObjectPlatformProcess &) = delete;1599const CommandObjectPlatformProcess &1600operator=(const CommandObjectPlatformProcess &) = delete;1601};16021603// "platform shell"1604#define LLDB_OPTIONS_platform_shell1605#include "CommandOptions.inc"16061607class CommandObjectPlatformShell : public CommandObjectRaw {1608public:1609class CommandOptions : public Options {1610public:1611CommandOptions() = default;16121613~CommandOptions() override = default;16141615llvm::ArrayRef<OptionDefinition> GetDefinitions() override {1616return llvm::ArrayRef(g_platform_shell_options);1617}16181619Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,1620ExecutionContext *execution_context) override {1621Status error;16221623const char short_option = (char)GetDefinitions()[option_idx].short_option;16241625switch (short_option) {1626case 'h':1627m_use_host_platform = true;1628break;1629case 't':1630uint32_t timeout_sec;1631if (option_arg.getAsInteger(10, timeout_sec))1632error.SetErrorStringWithFormat(1633"could not convert \"%s\" to a numeric value.",1634option_arg.str().c_str());1635else1636m_timeout = std::chrono::seconds(timeout_sec);1637break;1638case 's': {1639if (option_arg.empty()) {1640error.SetErrorStringWithFormat(1641"missing shell interpreter path for option -i|--interpreter.");1642return error;1643}16441645m_shell_interpreter = option_arg.str();1646break;1647}1648default:1649llvm_unreachable("Unimplemented option");1650}16511652return error;1653}16541655void OptionParsingStarting(ExecutionContext *execution_context) override {1656m_timeout.reset();1657m_use_host_platform = false;1658m_shell_interpreter.clear();1659}16601661Timeout<std::micro> m_timeout = std::chrono::seconds(10);1662bool m_use_host_platform;1663std::string m_shell_interpreter;1664};16651666CommandObjectPlatformShell(CommandInterpreter &interpreter)1667: CommandObjectRaw(interpreter, "platform shell",1668"Run a shell command on the current platform.",1669"platform shell <shell-command>", 0) {1670AddSimpleArgumentList(eArgTypeNone, eArgRepeatStar);1671}16721673~CommandObjectPlatformShell() override = default;16741675Options *GetOptions() override { return &m_options; }16761677void DoExecute(llvm::StringRef raw_command_line,1678CommandReturnObject &result) override {1679ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();1680m_options.NotifyOptionParsingStarting(&exe_ctx);16811682// Print out an usage syntax on an empty command line.1683if (raw_command_line.empty()) {1684result.GetOutputStream().Printf("%s\n", this->GetSyntax().str().c_str());1685return;1686}16871688const bool is_alias = !raw_command_line.contains("platform");1689OptionsWithRaw args(raw_command_line);16901691if (args.HasArgs())1692if (!ParseOptions(args.GetArgs(), result))1693return;16941695if (args.GetRawPart().empty()) {1696result.GetOutputStream().Printf("%s <shell-command>\n",1697is_alias ? "shell" : "platform shell");1698return;1699}17001701llvm::StringRef cmd = args.GetRawPart();17021703PlatformSP platform_sp(1704m_options.m_use_host_platform1705? Platform::GetHostPlatform()1706: GetDebugger().GetPlatformList().GetSelectedPlatform());1707Status error;1708if (platform_sp) {1709FileSpec working_dir{};1710std::string output;1711int status = -1;1712int signo = -1;1713error = (platform_sp->RunShellCommand(m_options.m_shell_interpreter, cmd,1714working_dir, &status, &signo,1715&output, m_options.m_timeout));1716if (!output.empty())1717result.GetOutputStream().PutCString(output);1718if (status > 0) {1719if (signo > 0) {1720const char *signo_cstr = Host::GetSignalAsCString(signo);1721if (signo_cstr)1722result.GetOutputStream().Printf(1723"error: command returned with status %i and signal %s\n",1724status, signo_cstr);1725else1726result.GetOutputStream().Printf(1727"error: command returned with status %i and signal %i\n",1728status, signo);1729} else1730result.GetOutputStream().Printf(1731"error: command returned with status %i\n", status);1732}1733} else {1734result.GetOutputStream().Printf(1735"error: cannot run remote shell commands without a platform\n");1736error.SetErrorString(1737"error: cannot run remote shell commands without a platform");1738}17391740if (error.Fail()) {1741result.AppendError(error.AsCString());1742} else {1743result.SetStatus(eReturnStatusSuccessFinishResult);1744}1745}17461747CommandOptions m_options;1748};17491750// "platform install" - install a target to a remote end1751class CommandObjectPlatformInstall : public CommandObjectParsed {1752public:1753CommandObjectPlatformInstall(CommandInterpreter &interpreter)1754: CommandObjectParsed(1755interpreter, "platform target-install",1756"Install a target (bundle or executable file) to the remote end.",1757"platform target-install <local-thing> <remote-sandbox>", 0) {1758CommandArgumentData local_arg{eArgTypePath, eArgRepeatPlain};1759CommandArgumentData remote_arg{eArgTypeRemotePath, eArgRepeatPlain};1760m_arguments.push_back({local_arg});1761m_arguments.push_back({remote_arg});1762}17631764~CommandObjectPlatformInstall() override = default;17651766void1767HandleArgumentCompletion(CompletionRequest &request,1768OptionElementVector &opt_element_vector) override {1769if (request.GetCursorIndex())1770return;1771lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(1772GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr);1773}17741775void DoExecute(Args &args, CommandReturnObject &result) override {1776if (args.GetArgumentCount() != 2) {1777result.AppendError("platform target-install takes two arguments");1778return;1779}1780// TODO: move the bulk of this code over to the platform itself1781FileSpec src(args.GetArgumentAtIndex(0));1782FileSystem::Instance().Resolve(src);1783FileSpec dst(args.GetArgumentAtIndex(1));1784if (!FileSystem::Instance().Exists(src)) {1785result.AppendError("source location does not exist or is not accessible");1786return;1787}1788PlatformSP platform_sp(1789GetDebugger().GetPlatformList().GetSelectedPlatform());1790if (!platform_sp) {1791result.AppendError("no platform currently selected");1792return;1793}17941795Status error = platform_sp->Install(src, dst);1796if (error.Success()) {1797result.SetStatus(eReturnStatusSuccessFinishNoResult);1798} else {1799result.AppendErrorWithFormat("install failed: %s", error.AsCString());1800}1801}1802};18031804CommandObjectPlatform::CommandObjectPlatform(CommandInterpreter &interpreter)1805: CommandObjectMultiword(1806interpreter, "platform", "Commands to manage and create platforms.",1807"platform [connect|disconnect|info|list|status|select] ...") {1808LoadSubCommand("select",1809CommandObjectSP(new CommandObjectPlatformSelect(interpreter)));1810LoadSubCommand("list",1811CommandObjectSP(new CommandObjectPlatformList(interpreter)));1812LoadSubCommand("status",1813CommandObjectSP(new CommandObjectPlatformStatus(interpreter)));1814LoadSubCommand("connect", CommandObjectSP(1815new CommandObjectPlatformConnect(interpreter)));1816LoadSubCommand(1817"disconnect",1818CommandObjectSP(new CommandObjectPlatformDisconnect(interpreter)));1819LoadSubCommand("settings", CommandObjectSP(new CommandObjectPlatformSettings(1820interpreter)));1821LoadSubCommand("mkdir",1822CommandObjectSP(new CommandObjectPlatformMkDir(interpreter)));1823LoadSubCommand("file",1824CommandObjectSP(new CommandObjectPlatformFile(interpreter)));1825LoadSubCommand("file-exists",1826CommandObjectSP(new CommandObjectPlatformFileExists(interpreter)));1827LoadSubCommand("get-file", CommandObjectSP(new CommandObjectPlatformGetFile(1828interpreter)));1829LoadSubCommand("get-permissions",1830CommandObjectSP(new CommandObjectPlatformGetPermissions(interpreter)));1831LoadSubCommand("get-size", CommandObjectSP(new CommandObjectPlatformGetSize(1832interpreter)));1833LoadSubCommand("put-file", CommandObjectSP(new CommandObjectPlatformPutFile(1834interpreter)));1835LoadSubCommand("process", CommandObjectSP(1836new CommandObjectPlatformProcess(interpreter)));1837LoadSubCommand("shell",1838CommandObjectSP(new CommandObjectPlatformShell(interpreter)));1839LoadSubCommand(1840"target-install",1841CommandObjectSP(new CommandObjectPlatformInstall(interpreter)));1842}18431844CommandObjectPlatform::~CommandObjectPlatform() = default;184518461847