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