1dda28197Spatrick //===-- CommandObjectPlatform.cpp -----------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "CommandObjectPlatform.h"
10be691f3bSpatrick #include "CommandOptionsProcessLaunch.h"
11061da546Spatrick #include "lldb/Core/Debugger.h"
12061da546Spatrick #include "lldb/Core/Module.h"
13061da546Spatrick #include "lldb/Core/PluginManager.h"
14061da546Spatrick #include "lldb/Host/OptionParser.h"
15061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
16*f6aab3d8Srobert #include "lldb/Interpreter/CommandOptionArgumentTable.h"
17061da546Spatrick #include "lldb/Interpreter/CommandOptionValidators.h"
18061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
19061da546Spatrick #include "lldb/Interpreter/OptionGroupFile.h"
20061da546Spatrick #include "lldb/Interpreter/OptionGroupPlatform.h"
21061da546Spatrick #include "lldb/Target/ExecutionContext.h"
22061da546Spatrick #include "lldb/Target/Platform.h"
23061da546Spatrick #include "lldb/Target/Process.h"
24061da546Spatrick #include "lldb/Utility/Args.h"
25061da546Spatrick
26061da546Spatrick #include "llvm/ADT/SmallString.h"
27061da546Spatrick
28061da546Spatrick using namespace lldb;
29061da546Spatrick using namespace lldb_private;
30061da546Spatrick
31061da546Spatrick static mode_t ParsePermissionString(const char *) = delete;
32061da546Spatrick
ParsePermissionString(llvm::StringRef permissions)33061da546Spatrick static mode_t ParsePermissionString(llvm::StringRef permissions) {
34061da546Spatrick if (permissions.size() != 9)
35061da546Spatrick return (mode_t)(-1);
36061da546Spatrick bool user_r, user_w, user_x, group_r, group_w, group_x, world_r, world_w,
37061da546Spatrick world_x;
38061da546Spatrick
39061da546Spatrick user_r = (permissions[0] == 'r');
40061da546Spatrick user_w = (permissions[1] == 'w');
41061da546Spatrick user_x = (permissions[2] == 'x');
42061da546Spatrick
43061da546Spatrick group_r = (permissions[3] == 'r');
44061da546Spatrick group_w = (permissions[4] == 'w');
45061da546Spatrick group_x = (permissions[5] == 'x');
46061da546Spatrick
47061da546Spatrick world_r = (permissions[6] == 'r');
48061da546Spatrick world_w = (permissions[7] == 'w');
49061da546Spatrick world_x = (permissions[8] == 'x');
50061da546Spatrick
51061da546Spatrick mode_t user, group, world;
52061da546Spatrick user = (user_r ? 4 : 0) | (user_w ? 2 : 0) | (user_x ? 1 : 0);
53061da546Spatrick group = (group_r ? 4 : 0) | (group_w ? 2 : 0) | (group_x ? 1 : 0);
54061da546Spatrick world = (world_r ? 4 : 0) | (world_w ? 2 : 0) | (world_x ? 1 : 0);
55061da546Spatrick
56061da546Spatrick return user | group | world;
57061da546Spatrick }
58061da546Spatrick
59061da546Spatrick #define LLDB_OPTIONS_permissions
60061da546Spatrick #include "CommandOptions.inc"
61061da546Spatrick
62061da546Spatrick class OptionPermissions : public OptionGroup {
63061da546Spatrick public:
64be691f3bSpatrick OptionPermissions() = default;
65061da546Spatrick
66061da546Spatrick ~OptionPermissions() override = default;
67061da546Spatrick
68061da546Spatrick lldb_private::Status
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)69061da546Spatrick SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
70061da546Spatrick ExecutionContext *execution_context) override {
71061da546Spatrick Status error;
72061da546Spatrick char short_option = (char)GetDefinitions()[option_idx].short_option;
73061da546Spatrick switch (short_option) {
74061da546Spatrick case 'v': {
75061da546Spatrick if (option_arg.getAsInteger(8, m_permissions)) {
76061da546Spatrick m_permissions = 0777;
77061da546Spatrick error.SetErrorStringWithFormat("invalid value for permissions: %s",
78061da546Spatrick option_arg.str().c_str());
79061da546Spatrick }
80061da546Spatrick
81061da546Spatrick } break;
82061da546Spatrick case 's': {
83061da546Spatrick mode_t perms = ParsePermissionString(option_arg);
84061da546Spatrick if (perms == (mode_t)-1)
85061da546Spatrick error.SetErrorStringWithFormat("invalid value for permissions: %s",
86061da546Spatrick option_arg.str().c_str());
87061da546Spatrick else
88061da546Spatrick m_permissions = perms;
89061da546Spatrick } break;
90061da546Spatrick case 'r':
91061da546Spatrick m_permissions |= lldb::eFilePermissionsUserRead;
92061da546Spatrick break;
93061da546Spatrick case 'w':
94061da546Spatrick m_permissions |= lldb::eFilePermissionsUserWrite;
95061da546Spatrick break;
96061da546Spatrick case 'x':
97061da546Spatrick m_permissions |= lldb::eFilePermissionsUserExecute;
98061da546Spatrick break;
99061da546Spatrick case 'R':
100061da546Spatrick m_permissions |= lldb::eFilePermissionsGroupRead;
101061da546Spatrick break;
102061da546Spatrick case 'W':
103061da546Spatrick m_permissions |= lldb::eFilePermissionsGroupWrite;
104061da546Spatrick break;
105061da546Spatrick case 'X':
106061da546Spatrick m_permissions |= lldb::eFilePermissionsGroupExecute;
107061da546Spatrick break;
108061da546Spatrick case 'd':
109061da546Spatrick m_permissions |= lldb::eFilePermissionsWorldRead;
110061da546Spatrick break;
111061da546Spatrick case 't':
112061da546Spatrick m_permissions |= lldb::eFilePermissionsWorldWrite;
113061da546Spatrick break;
114061da546Spatrick case 'e':
115061da546Spatrick m_permissions |= lldb::eFilePermissionsWorldExecute;
116061da546Spatrick break;
117061da546Spatrick default:
118061da546Spatrick llvm_unreachable("Unimplemented option");
119061da546Spatrick }
120061da546Spatrick
121061da546Spatrick return error;
122061da546Spatrick }
123061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)124061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
125061da546Spatrick m_permissions = 0;
126061da546Spatrick }
127061da546Spatrick
GetDefinitions()128061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
129*f6aab3d8Srobert return llvm::ArrayRef(g_permissions_options);
130061da546Spatrick }
131061da546Spatrick
132061da546Spatrick // Instance variables to hold the values for command options.
133061da546Spatrick
134061da546Spatrick uint32_t m_permissions;
135061da546Spatrick
136061da546Spatrick private:
137dda28197Spatrick OptionPermissions(const OptionPermissions &) = delete;
138dda28197Spatrick const OptionPermissions &operator=(const OptionPermissions &) = delete;
139061da546Spatrick };
140061da546Spatrick
141061da546Spatrick // "platform select <platform-name>"
142061da546Spatrick class CommandObjectPlatformSelect : public CommandObjectParsed {
143061da546Spatrick public:
CommandObjectPlatformSelect(CommandInterpreter & interpreter)144061da546Spatrick CommandObjectPlatformSelect(CommandInterpreter &interpreter)
145061da546Spatrick : CommandObjectParsed(interpreter, "platform select",
146061da546Spatrick "Create a platform if needed and select it as the "
147061da546Spatrick "current platform.",
148061da546Spatrick "platform select <platform-name>", 0),
149061da546Spatrick m_platform_options(
150061da546Spatrick false) // Don't include the "--platform" option by passing false
151061da546Spatrick {
152061da546Spatrick m_option_group.Append(&m_platform_options, LLDB_OPT_SET_ALL, 1);
153061da546Spatrick m_option_group.Finalize();
154*f6aab3d8Srobert CommandArgumentData platform_arg{eArgTypePlatform, eArgRepeatPlain};
155*f6aab3d8Srobert m_arguments.push_back({platform_arg});
156061da546Spatrick }
157061da546Spatrick
158061da546Spatrick ~CommandObjectPlatformSelect() override = default;
159061da546Spatrick
HandleCompletion(CompletionRequest & request)160061da546Spatrick void HandleCompletion(CompletionRequest &request) override {
161061da546Spatrick CommandCompletions::PlatformPluginNames(GetCommandInterpreter(), request,
162061da546Spatrick nullptr);
163061da546Spatrick }
164061da546Spatrick
GetOptions()165061da546Spatrick Options *GetOptions() override { return &m_option_group; }
166061da546Spatrick
167061da546Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)168061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
169061da546Spatrick if (args.GetArgumentCount() == 1) {
170061da546Spatrick const char *platform_name = args.GetArgumentAtIndex(0);
171061da546Spatrick if (platform_name && platform_name[0]) {
172061da546Spatrick const bool select = true;
173061da546Spatrick m_platform_options.SetPlatformName(platform_name);
174061da546Spatrick Status error;
175061da546Spatrick ArchSpec platform_arch;
176061da546Spatrick PlatformSP platform_sp(m_platform_options.CreatePlatformWithOptions(
177061da546Spatrick m_interpreter, ArchSpec(), select, error, platform_arch));
178061da546Spatrick if (platform_sp) {
179061da546Spatrick GetDebugger().GetPlatformList().SetSelectedPlatform(platform_sp);
180061da546Spatrick
181061da546Spatrick platform_sp->GetStatus(result.GetOutputStream());
182061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
183061da546Spatrick } else {
184061da546Spatrick result.AppendError(error.AsCString());
185061da546Spatrick }
186061da546Spatrick } else {
187061da546Spatrick result.AppendError("invalid platform name");
188061da546Spatrick }
189061da546Spatrick } else {
190061da546Spatrick result.AppendError(
191061da546Spatrick "platform create takes a platform name as an argument\n");
192061da546Spatrick }
193061da546Spatrick return result.Succeeded();
194061da546Spatrick }
195061da546Spatrick
196061da546Spatrick OptionGroupOptions m_option_group;
197061da546Spatrick OptionGroupPlatform m_platform_options;
198061da546Spatrick };
199061da546Spatrick
200061da546Spatrick // "platform list"
201061da546Spatrick class CommandObjectPlatformList : public CommandObjectParsed {
202061da546Spatrick public:
CommandObjectPlatformList(CommandInterpreter & interpreter)203061da546Spatrick CommandObjectPlatformList(CommandInterpreter &interpreter)
204061da546Spatrick : CommandObjectParsed(interpreter, "platform list",
205061da546Spatrick "List all platforms that are available.", nullptr,
206061da546Spatrick 0) {}
207061da546Spatrick
208061da546Spatrick ~CommandObjectPlatformList() override = default;
209061da546Spatrick
210061da546Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)211061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
212061da546Spatrick Stream &ostrm = result.GetOutputStream();
213061da546Spatrick ostrm.Printf("Available platforms:\n");
214061da546Spatrick
215061da546Spatrick PlatformSP host_platform_sp(Platform::GetHostPlatform());
216*f6aab3d8Srobert ostrm.Format("{0}: {1}\n", host_platform_sp->GetPluginName(),
217061da546Spatrick host_platform_sp->GetDescription());
218061da546Spatrick
219061da546Spatrick uint32_t idx;
220061da546Spatrick for (idx = 0; true; ++idx) {
221*f6aab3d8Srobert llvm::StringRef plugin_name =
222061da546Spatrick PluginManager::GetPlatformPluginNameAtIndex(idx);
223*f6aab3d8Srobert if (plugin_name.empty())
224061da546Spatrick break;
225*f6aab3d8Srobert llvm::StringRef plugin_desc =
226061da546Spatrick PluginManager::GetPlatformPluginDescriptionAtIndex(idx);
227*f6aab3d8Srobert ostrm.Format("{0}: {1}\n", plugin_name, plugin_desc);
228061da546Spatrick }
229061da546Spatrick
230061da546Spatrick if (idx == 0) {
231061da546Spatrick result.AppendError("no platforms are available\n");
232061da546Spatrick } else
233061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
234061da546Spatrick return result.Succeeded();
235061da546Spatrick }
236061da546Spatrick };
237061da546Spatrick
238061da546Spatrick // "platform status"
239061da546Spatrick class CommandObjectPlatformStatus : public CommandObjectParsed {
240061da546Spatrick public:
CommandObjectPlatformStatus(CommandInterpreter & interpreter)241061da546Spatrick CommandObjectPlatformStatus(CommandInterpreter &interpreter)
242061da546Spatrick : CommandObjectParsed(interpreter, "platform status",
243061da546Spatrick "Display status for the current platform.", nullptr,
244061da546Spatrick 0) {}
245061da546Spatrick
246061da546Spatrick ~CommandObjectPlatformStatus() override = default;
247061da546Spatrick
248061da546Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)249061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
250061da546Spatrick Stream &ostrm = result.GetOutputStream();
251061da546Spatrick
252061da546Spatrick Target *target = GetDebugger().GetSelectedTarget().get();
253061da546Spatrick PlatformSP platform_sp;
254061da546Spatrick if (target) {
255061da546Spatrick platform_sp = target->GetPlatform();
256061da546Spatrick }
257061da546Spatrick if (!platform_sp) {
258061da546Spatrick platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();
259061da546Spatrick }
260061da546Spatrick if (platform_sp) {
261061da546Spatrick platform_sp->GetStatus(ostrm);
262061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
263061da546Spatrick } else {
264061da546Spatrick result.AppendError("no platform is currently selected\n");
265061da546Spatrick }
266061da546Spatrick return result.Succeeded();
267061da546Spatrick }
268061da546Spatrick };
269061da546Spatrick
270061da546Spatrick // "platform connect <connect-url>"
271061da546Spatrick class CommandObjectPlatformConnect : public CommandObjectParsed {
272061da546Spatrick public:
CommandObjectPlatformConnect(CommandInterpreter & interpreter)273061da546Spatrick CommandObjectPlatformConnect(CommandInterpreter &interpreter)
274061da546Spatrick : CommandObjectParsed(
275061da546Spatrick interpreter, "platform connect",
276061da546Spatrick "Select the current platform by providing a connection URL.",
277*f6aab3d8Srobert "platform connect <connect-url>", 0) {
278*f6aab3d8Srobert CommandArgumentData platform_arg{eArgTypeConnectURL, eArgRepeatPlain};
279*f6aab3d8Srobert m_arguments.push_back({platform_arg});
280*f6aab3d8Srobert }
281061da546Spatrick
282061da546Spatrick ~CommandObjectPlatformConnect() override = default;
283061da546Spatrick
284061da546Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)285061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
286061da546Spatrick Stream &ostrm = result.GetOutputStream();
287061da546Spatrick
288061da546Spatrick PlatformSP platform_sp(
289061da546Spatrick GetDebugger().GetPlatformList().GetSelectedPlatform());
290061da546Spatrick if (platform_sp) {
291061da546Spatrick Status error(platform_sp->ConnectRemote(args));
292061da546Spatrick if (error.Success()) {
293061da546Spatrick platform_sp->GetStatus(ostrm);
294061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
295061da546Spatrick
296061da546Spatrick platform_sp->ConnectToWaitingProcesses(GetDebugger(), error);
297061da546Spatrick if (error.Fail()) {
298061da546Spatrick result.AppendError(error.AsCString());
299061da546Spatrick }
300061da546Spatrick } else {
301061da546Spatrick result.AppendErrorWithFormat("%s\n", error.AsCString());
302061da546Spatrick }
303061da546Spatrick } else {
304061da546Spatrick result.AppendError("no platform is currently selected\n");
305061da546Spatrick }
306061da546Spatrick return result.Succeeded();
307061da546Spatrick }
308061da546Spatrick
GetOptions()309061da546Spatrick Options *GetOptions() override {
310061da546Spatrick PlatformSP platform_sp(
311061da546Spatrick GetDebugger().GetPlatformList().GetSelectedPlatform());
312061da546Spatrick OptionGroupOptions *m_platform_options = nullptr;
313061da546Spatrick if (platform_sp) {
314061da546Spatrick m_platform_options = platform_sp->GetConnectionOptions(m_interpreter);
315061da546Spatrick if (m_platform_options != nullptr && !m_platform_options->m_did_finalize)
316061da546Spatrick m_platform_options->Finalize();
317061da546Spatrick }
318061da546Spatrick return m_platform_options;
319061da546Spatrick }
320061da546Spatrick };
321061da546Spatrick
322061da546Spatrick // "platform disconnect"
323061da546Spatrick class CommandObjectPlatformDisconnect : public CommandObjectParsed {
324061da546Spatrick public:
CommandObjectPlatformDisconnect(CommandInterpreter & interpreter)325061da546Spatrick CommandObjectPlatformDisconnect(CommandInterpreter &interpreter)
326061da546Spatrick : CommandObjectParsed(interpreter, "platform disconnect",
327061da546Spatrick "Disconnect from the current platform.",
328061da546Spatrick "platform disconnect", 0) {}
329061da546Spatrick
330061da546Spatrick ~CommandObjectPlatformDisconnect() override = default;
331061da546Spatrick
332061da546Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)333061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
334061da546Spatrick PlatformSP platform_sp(
335061da546Spatrick GetDebugger().GetPlatformList().GetSelectedPlatform());
336061da546Spatrick if (platform_sp) {
337061da546Spatrick if (args.GetArgumentCount() == 0) {
338061da546Spatrick Status error;
339061da546Spatrick
340061da546Spatrick if (platform_sp->IsConnected()) {
341061da546Spatrick // Cache the instance name if there is one since we are about to
342061da546Spatrick // disconnect and the name might go with it.
343061da546Spatrick const char *hostname_cstr = platform_sp->GetHostname();
344061da546Spatrick std::string hostname;
345061da546Spatrick if (hostname_cstr)
346061da546Spatrick hostname.assign(hostname_cstr);
347061da546Spatrick
348061da546Spatrick error = platform_sp->DisconnectRemote();
349061da546Spatrick if (error.Success()) {
350061da546Spatrick Stream &ostrm = result.GetOutputStream();
351061da546Spatrick if (hostname.empty())
352*f6aab3d8Srobert ostrm.Format("Disconnected from \"{0}\"\n",
353*f6aab3d8Srobert platform_sp->GetPluginName());
354061da546Spatrick else
355061da546Spatrick ostrm.Printf("Disconnected from \"%s\"\n", hostname.c_str());
356061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
357061da546Spatrick } else {
358061da546Spatrick result.AppendErrorWithFormat("%s", error.AsCString());
359061da546Spatrick }
360061da546Spatrick } else {
361061da546Spatrick // Not connected...
362*f6aab3d8Srobert result.AppendErrorWithFormatv("not connected to '{0}'",
363*f6aab3d8Srobert platform_sp->GetPluginName());
364061da546Spatrick }
365061da546Spatrick } else {
366061da546Spatrick // Bad args
367061da546Spatrick result.AppendError(
368061da546Spatrick "\"platform disconnect\" doesn't take any arguments");
369061da546Spatrick }
370061da546Spatrick } else {
371061da546Spatrick result.AppendError("no platform is currently selected");
372061da546Spatrick }
373061da546Spatrick return result.Succeeded();
374061da546Spatrick }
375061da546Spatrick };
376061da546Spatrick
377061da546Spatrick // "platform settings"
378061da546Spatrick class CommandObjectPlatformSettings : public CommandObjectParsed {
379061da546Spatrick public:
CommandObjectPlatformSettings(CommandInterpreter & interpreter)380061da546Spatrick CommandObjectPlatformSettings(CommandInterpreter &interpreter)
381061da546Spatrick : CommandObjectParsed(interpreter, "platform settings",
382*f6aab3d8Srobert "Set settings for the current target's platform.",
383061da546Spatrick "platform settings", 0),
384be691f3bSpatrick m_option_working_dir(LLDB_OPT_SET_1, false, "working-dir", 'w',
385be691f3bSpatrick CommandCompletions::eRemoteDiskDirectoryCompletion,
386061da546Spatrick eArgTypePath,
387061da546Spatrick "The working directory for the platform.") {
388061da546Spatrick m_options.Append(&m_option_working_dir, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
389061da546Spatrick }
390061da546Spatrick
391061da546Spatrick ~CommandObjectPlatformSettings() override = default;
392061da546Spatrick
393061da546Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)394061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
395061da546Spatrick PlatformSP platform_sp(
396061da546Spatrick GetDebugger().GetPlatformList().GetSelectedPlatform());
397061da546Spatrick if (platform_sp) {
398061da546Spatrick if (m_option_working_dir.GetOptionValue().OptionWasSet())
399061da546Spatrick platform_sp->SetWorkingDirectory(
400061da546Spatrick m_option_working_dir.GetOptionValue().GetCurrentValue());
401061da546Spatrick } else {
402061da546Spatrick result.AppendError("no platform is currently selected");
403061da546Spatrick }
404061da546Spatrick return result.Succeeded();
405061da546Spatrick }
406061da546Spatrick
GetOptions()407061da546Spatrick Options *GetOptions() override {
408061da546Spatrick if (!m_options.DidFinalize())
409061da546Spatrick m_options.Finalize();
410061da546Spatrick return &m_options;
411061da546Spatrick }
412061da546Spatrick
413061da546Spatrick OptionGroupOptions m_options;
414061da546Spatrick OptionGroupFile m_option_working_dir;
415061da546Spatrick };
416061da546Spatrick
417061da546Spatrick // "platform mkdir"
418061da546Spatrick class CommandObjectPlatformMkDir : public CommandObjectParsed {
419061da546Spatrick public:
CommandObjectPlatformMkDir(CommandInterpreter & interpreter)420061da546Spatrick CommandObjectPlatformMkDir(CommandInterpreter &interpreter)
421061da546Spatrick : CommandObjectParsed(interpreter, "platform mkdir",
422061da546Spatrick "Make a new directory on the remote end.", nullptr,
423*f6aab3d8Srobert 0) {
424*f6aab3d8Srobert CommandArgumentData thread_arg{eArgTypePath, eArgRepeatPlain};
425*f6aab3d8Srobert m_arguments.push_back({thread_arg});
426*f6aab3d8Srobert }
427061da546Spatrick
428061da546Spatrick ~CommandObjectPlatformMkDir() override = default;
429061da546Spatrick
DoExecute(Args & args,CommandReturnObject & result)430061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
431061da546Spatrick PlatformSP platform_sp(
432061da546Spatrick GetDebugger().GetPlatformList().GetSelectedPlatform());
433061da546Spatrick if (platform_sp) {
434061da546Spatrick std::string cmd_line;
435061da546Spatrick args.GetCommandString(cmd_line);
436061da546Spatrick uint32_t mode;
437061da546Spatrick const OptionPermissions *options_permissions =
438061da546Spatrick (const OptionPermissions *)m_options.GetGroupWithOption('r');
439061da546Spatrick if (options_permissions)
440061da546Spatrick mode = options_permissions->m_permissions;
441061da546Spatrick else
442061da546Spatrick mode = lldb::eFilePermissionsUserRWX | lldb::eFilePermissionsGroupRWX |
443061da546Spatrick lldb::eFilePermissionsWorldRX;
444061da546Spatrick Status error = platform_sp->MakeDirectory(FileSpec(cmd_line), mode);
445061da546Spatrick if (error.Success()) {
446061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
447061da546Spatrick } else {
448061da546Spatrick result.AppendError(error.AsCString());
449061da546Spatrick }
450061da546Spatrick } else {
451061da546Spatrick result.AppendError("no platform currently selected\n");
452061da546Spatrick }
453061da546Spatrick return result.Succeeded();
454061da546Spatrick }
455061da546Spatrick
GetOptions()456061da546Spatrick Options *GetOptions() override {
457061da546Spatrick if (!m_options.DidFinalize()) {
458*f6aab3d8Srobert m_options.Append(&m_option_permissions);
459061da546Spatrick m_options.Finalize();
460061da546Spatrick }
461061da546Spatrick return &m_options;
462061da546Spatrick }
463061da546Spatrick
464*f6aab3d8Srobert OptionPermissions m_option_permissions;
465061da546Spatrick OptionGroupOptions m_options;
466061da546Spatrick };
467061da546Spatrick
468061da546Spatrick // "platform fopen"
469061da546Spatrick class CommandObjectPlatformFOpen : public CommandObjectParsed {
470061da546Spatrick public:
CommandObjectPlatformFOpen(CommandInterpreter & interpreter)471061da546Spatrick CommandObjectPlatformFOpen(CommandInterpreter &interpreter)
472061da546Spatrick : CommandObjectParsed(interpreter, "platform file open",
473*f6aab3d8Srobert "Open a file on the remote end.", nullptr, 0) {
474*f6aab3d8Srobert CommandArgumentData path_arg{eArgTypePath, eArgRepeatPlain};
475*f6aab3d8Srobert m_arguments.push_back({path_arg});
476*f6aab3d8Srobert }
477061da546Spatrick
478061da546Spatrick ~CommandObjectPlatformFOpen() override = default;
479061da546Spatrick
480be691f3bSpatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)481be691f3bSpatrick HandleArgumentCompletion(CompletionRequest &request,
482be691f3bSpatrick OptionElementVector &opt_element_vector) override {
483be691f3bSpatrick if (request.GetCursorIndex() == 0)
484be691f3bSpatrick CommandCompletions::InvokeCommonCompletionCallbacks(
485be691f3bSpatrick GetCommandInterpreter(),
486be691f3bSpatrick CommandCompletions::eRemoteDiskFileCompletion, request, nullptr);
487be691f3bSpatrick }
488be691f3bSpatrick
DoExecute(Args & args,CommandReturnObject & result)489061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
490061da546Spatrick PlatformSP platform_sp(
491061da546Spatrick GetDebugger().GetPlatformList().GetSelectedPlatform());
492061da546Spatrick if (platform_sp) {
493061da546Spatrick Status error;
494061da546Spatrick std::string cmd_line;
495061da546Spatrick args.GetCommandString(cmd_line);
496061da546Spatrick mode_t perms;
497061da546Spatrick const OptionPermissions *options_permissions =
498061da546Spatrick (const OptionPermissions *)m_options.GetGroupWithOption('r');
499061da546Spatrick if (options_permissions)
500061da546Spatrick perms = options_permissions->m_permissions;
501061da546Spatrick else
502061da546Spatrick perms = lldb::eFilePermissionsUserRW | lldb::eFilePermissionsGroupRW |
503061da546Spatrick lldb::eFilePermissionsWorldRead;
504061da546Spatrick lldb::user_id_t fd = platform_sp->OpenFile(
505061da546Spatrick FileSpec(cmd_line),
506*f6aab3d8Srobert File::eOpenOptionReadWrite | File::eOpenOptionCanCreate,
507061da546Spatrick perms, error);
508061da546Spatrick if (error.Success()) {
509061da546Spatrick result.AppendMessageWithFormat("File Descriptor = %" PRIu64 "\n", fd);
510061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
511061da546Spatrick } else {
512061da546Spatrick result.AppendError(error.AsCString());
513061da546Spatrick }
514061da546Spatrick } else {
515061da546Spatrick result.AppendError("no platform currently selected\n");
516061da546Spatrick }
517061da546Spatrick return result.Succeeded();
518061da546Spatrick }
519061da546Spatrick
GetOptions()520061da546Spatrick Options *GetOptions() override {
521061da546Spatrick if (!m_options.DidFinalize()) {
522*f6aab3d8Srobert m_options.Append(&m_option_permissions);
523061da546Spatrick m_options.Finalize();
524061da546Spatrick }
525061da546Spatrick return &m_options;
526061da546Spatrick }
527061da546Spatrick
528*f6aab3d8Srobert OptionPermissions m_option_permissions;
529061da546Spatrick OptionGroupOptions m_options;
530061da546Spatrick };
531061da546Spatrick
532061da546Spatrick // "platform fclose"
533061da546Spatrick class CommandObjectPlatformFClose : public CommandObjectParsed {
534061da546Spatrick public:
CommandObjectPlatformFClose(CommandInterpreter & interpreter)535061da546Spatrick CommandObjectPlatformFClose(CommandInterpreter &interpreter)
536061da546Spatrick : CommandObjectParsed(interpreter, "platform file close",
537*f6aab3d8Srobert "Close a file on the remote end.", nullptr, 0) {
538*f6aab3d8Srobert CommandArgumentData path_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
539*f6aab3d8Srobert m_arguments.push_back({path_arg});
540*f6aab3d8Srobert }
541061da546Spatrick
542061da546Spatrick ~CommandObjectPlatformFClose() override = default;
543061da546Spatrick
DoExecute(Args & args,CommandReturnObject & result)544061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
545061da546Spatrick PlatformSP platform_sp(
546061da546Spatrick GetDebugger().GetPlatformList().GetSelectedPlatform());
547061da546Spatrick if (platform_sp) {
548061da546Spatrick std::string cmd_line;
549061da546Spatrick args.GetCommandString(cmd_line);
550dda28197Spatrick lldb::user_id_t fd;
551dda28197Spatrick if (!llvm::to_integer(cmd_line, fd)) {
552dda28197Spatrick result.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.\n",
553dda28197Spatrick cmd_line);
554dda28197Spatrick return result.Succeeded();
555dda28197Spatrick }
556061da546Spatrick Status error;
557061da546Spatrick bool success = platform_sp->CloseFile(fd, error);
558061da546Spatrick if (success) {
559061da546Spatrick result.AppendMessageWithFormat("file %" PRIu64 " closed.\n", fd);
560061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
561061da546Spatrick } else {
562061da546Spatrick result.AppendError(error.AsCString());
563061da546Spatrick }
564061da546Spatrick } else {
565061da546Spatrick result.AppendError("no platform currently selected\n");
566061da546Spatrick }
567061da546Spatrick return result.Succeeded();
568061da546Spatrick }
569061da546Spatrick };
570061da546Spatrick
571061da546Spatrick // "platform fread"
572061da546Spatrick
573061da546Spatrick #define LLDB_OPTIONS_platform_fread
574061da546Spatrick #include "CommandOptions.inc"
575061da546Spatrick
576061da546Spatrick class CommandObjectPlatformFRead : public CommandObjectParsed {
577061da546Spatrick public:
CommandObjectPlatformFRead(CommandInterpreter & interpreter)578061da546Spatrick CommandObjectPlatformFRead(CommandInterpreter &interpreter)
579061da546Spatrick : CommandObjectParsed(interpreter, "platform file read",
580061da546Spatrick "Read data from a file on the remote end.", nullptr,
581*f6aab3d8Srobert 0) {
582*f6aab3d8Srobert CommandArgumentData path_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
583*f6aab3d8Srobert m_arguments.push_back({path_arg});
584*f6aab3d8Srobert }
585061da546Spatrick
586061da546Spatrick ~CommandObjectPlatformFRead() override = default;
587061da546Spatrick
DoExecute(Args & args,CommandReturnObject & result)588061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
589061da546Spatrick PlatformSP platform_sp(
590061da546Spatrick GetDebugger().GetPlatformList().GetSelectedPlatform());
591061da546Spatrick if (platform_sp) {
592061da546Spatrick std::string cmd_line;
593061da546Spatrick args.GetCommandString(cmd_line);
594dda28197Spatrick lldb::user_id_t fd;
595dda28197Spatrick if (!llvm::to_integer(cmd_line, fd)) {
596dda28197Spatrick result.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.\n",
597dda28197Spatrick cmd_line);
598dda28197Spatrick return result.Succeeded();
599dda28197Spatrick }
600061da546Spatrick std::string buffer(m_options.m_count, 0);
601061da546Spatrick Status error;
602*f6aab3d8Srobert uint64_t retcode = platform_sp->ReadFile(
603061da546Spatrick fd, m_options.m_offset, &buffer[0], m_options.m_count, error);
604*f6aab3d8Srobert if (retcode != UINT64_MAX) {
605*f6aab3d8Srobert result.AppendMessageWithFormat("Return = %" PRIu64 "\n", retcode);
606061da546Spatrick result.AppendMessageWithFormat("Data = \"%s\"\n", buffer.c_str());
607061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
608061da546Spatrick } else {
609*f6aab3d8Srobert result.AppendError(error.AsCString());
610*f6aab3d8Srobert }
611*f6aab3d8Srobert } else {
612061da546Spatrick result.AppendError("no platform currently selected\n");
613061da546Spatrick }
614061da546Spatrick return result.Succeeded();
615061da546Spatrick }
616061da546Spatrick
GetOptions()617061da546Spatrick Options *GetOptions() override { return &m_options; }
618061da546Spatrick
619061da546Spatrick protected:
620061da546Spatrick class CommandOptions : public Options {
621061da546Spatrick public:
622*f6aab3d8Srobert CommandOptions() = default;
623061da546Spatrick
624061da546Spatrick ~CommandOptions() override = default;
625061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)626061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
627061da546Spatrick ExecutionContext *execution_context) override {
628061da546Spatrick Status error;
629061da546Spatrick char short_option = (char)m_getopt_table[option_idx].val;
630061da546Spatrick
631061da546Spatrick switch (short_option) {
632061da546Spatrick case 'o':
633061da546Spatrick if (option_arg.getAsInteger(0, m_offset))
634061da546Spatrick error.SetErrorStringWithFormat("invalid offset: '%s'",
635061da546Spatrick option_arg.str().c_str());
636061da546Spatrick break;
637061da546Spatrick case 'c':
638061da546Spatrick if (option_arg.getAsInteger(0, m_count))
639061da546Spatrick error.SetErrorStringWithFormat("invalid offset: '%s'",
640061da546Spatrick option_arg.str().c_str());
641061da546Spatrick break;
642061da546Spatrick default:
643061da546Spatrick llvm_unreachable("Unimplemented option");
644061da546Spatrick }
645061da546Spatrick
646061da546Spatrick return error;
647061da546Spatrick }
648061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)649061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
650061da546Spatrick m_offset = 0;
651061da546Spatrick m_count = 1;
652061da546Spatrick }
653061da546Spatrick
GetDefinitions()654061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
655*f6aab3d8Srobert return llvm::ArrayRef(g_platform_fread_options);
656061da546Spatrick }
657061da546Spatrick
658061da546Spatrick // Instance variables to hold the values for command options.
659061da546Spatrick
660061da546Spatrick uint32_t m_offset;
661061da546Spatrick uint32_t m_count;
662061da546Spatrick };
663061da546Spatrick
664061da546Spatrick CommandOptions m_options;
665061da546Spatrick };
666061da546Spatrick
667061da546Spatrick // "platform fwrite"
668061da546Spatrick
669061da546Spatrick #define LLDB_OPTIONS_platform_fwrite
670061da546Spatrick #include "CommandOptions.inc"
671061da546Spatrick
672061da546Spatrick class CommandObjectPlatformFWrite : public CommandObjectParsed {
673061da546Spatrick public:
CommandObjectPlatformFWrite(CommandInterpreter & interpreter)674061da546Spatrick CommandObjectPlatformFWrite(CommandInterpreter &interpreter)
675061da546Spatrick : CommandObjectParsed(interpreter, "platform file write",
676061da546Spatrick "Write data to a file on the remote end.", nullptr,
677*f6aab3d8Srobert 0) {
678*f6aab3d8Srobert CommandArgumentData path_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
679*f6aab3d8Srobert m_arguments.push_back({path_arg});
680*f6aab3d8Srobert }
681061da546Spatrick
682061da546Spatrick ~CommandObjectPlatformFWrite() override = default;
683061da546Spatrick
DoExecute(Args & args,CommandReturnObject & result)684061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
685061da546Spatrick PlatformSP platform_sp(
686061da546Spatrick GetDebugger().GetPlatformList().GetSelectedPlatform());
687061da546Spatrick if (platform_sp) {
688061da546Spatrick std::string cmd_line;
689061da546Spatrick args.GetCommandString(cmd_line);
690061da546Spatrick Status error;
691dda28197Spatrick lldb::user_id_t fd;
692dda28197Spatrick if (!llvm::to_integer(cmd_line, fd)) {
693dda28197Spatrick result.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.",
694dda28197Spatrick cmd_line);
695dda28197Spatrick return result.Succeeded();
696dda28197Spatrick }
697*f6aab3d8Srobert uint64_t retcode =
698061da546Spatrick platform_sp->WriteFile(fd, m_options.m_offset, &m_options.m_data[0],
699061da546Spatrick m_options.m_data.size(), error);
700*f6aab3d8Srobert if (retcode != UINT64_MAX) {
701*f6aab3d8Srobert result.AppendMessageWithFormat("Return = %" PRIu64 "\n", retcode);
702061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
703061da546Spatrick } else {
704*f6aab3d8Srobert result.AppendError(error.AsCString());
705*f6aab3d8Srobert }
706*f6aab3d8Srobert } else {
707061da546Spatrick result.AppendError("no platform currently selected\n");
708061da546Spatrick }
709061da546Spatrick return result.Succeeded();
710061da546Spatrick }
711061da546Spatrick
GetOptions()712061da546Spatrick Options *GetOptions() override { return &m_options; }
713061da546Spatrick
714061da546Spatrick protected:
715061da546Spatrick class CommandOptions : public Options {
716061da546Spatrick public:
717*f6aab3d8Srobert CommandOptions() = default;
718061da546Spatrick
719061da546Spatrick ~CommandOptions() override = default;
720061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)721061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
722061da546Spatrick ExecutionContext *execution_context) override {
723061da546Spatrick Status error;
724061da546Spatrick char short_option = (char)m_getopt_table[option_idx].val;
725061da546Spatrick
726061da546Spatrick switch (short_option) {
727061da546Spatrick case 'o':
728061da546Spatrick if (option_arg.getAsInteger(0, m_offset))
729061da546Spatrick error.SetErrorStringWithFormat("invalid offset: '%s'",
730061da546Spatrick option_arg.str().c_str());
731061da546Spatrick break;
732061da546Spatrick case 'd':
733dda28197Spatrick m_data.assign(std::string(option_arg));
734061da546Spatrick break;
735061da546Spatrick default:
736061da546Spatrick llvm_unreachable("Unimplemented option");
737061da546Spatrick }
738061da546Spatrick
739061da546Spatrick return error;
740061da546Spatrick }
741061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)742061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
743061da546Spatrick m_offset = 0;
744061da546Spatrick m_data.clear();
745061da546Spatrick }
746061da546Spatrick
GetDefinitions()747061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
748*f6aab3d8Srobert return llvm::ArrayRef(g_platform_fwrite_options);
749061da546Spatrick }
750061da546Spatrick
751061da546Spatrick // Instance variables to hold the values for command options.
752061da546Spatrick
753061da546Spatrick uint32_t m_offset;
754061da546Spatrick std::string m_data;
755061da546Spatrick };
756061da546Spatrick
757061da546Spatrick CommandOptions m_options;
758061da546Spatrick };
759061da546Spatrick
760061da546Spatrick class CommandObjectPlatformFile : public CommandObjectMultiword {
761061da546Spatrick public:
762061da546Spatrick // Constructors and Destructors
CommandObjectPlatformFile(CommandInterpreter & interpreter)763061da546Spatrick CommandObjectPlatformFile(CommandInterpreter &interpreter)
764061da546Spatrick : CommandObjectMultiword(
765061da546Spatrick interpreter, "platform file",
766061da546Spatrick "Commands to access files on the current platform.",
767061da546Spatrick "platform file [open|close|read|write] ...") {
768061da546Spatrick LoadSubCommand(
769061da546Spatrick "open", CommandObjectSP(new CommandObjectPlatformFOpen(interpreter)));
770061da546Spatrick LoadSubCommand(
771061da546Spatrick "close", CommandObjectSP(new CommandObjectPlatformFClose(interpreter)));
772061da546Spatrick LoadSubCommand(
773061da546Spatrick "read", CommandObjectSP(new CommandObjectPlatformFRead(interpreter)));
774061da546Spatrick LoadSubCommand(
775061da546Spatrick "write", CommandObjectSP(new CommandObjectPlatformFWrite(interpreter)));
776061da546Spatrick }
777061da546Spatrick
778061da546Spatrick ~CommandObjectPlatformFile() override = default;
779061da546Spatrick
780061da546Spatrick private:
781061da546Spatrick // For CommandObjectPlatform only
782dda28197Spatrick CommandObjectPlatformFile(const CommandObjectPlatformFile &) = delete;
783dda28197Spatrick const CommandObjectPlatformFile &
784dda28197Spatrick operator=(const CommandObjectPlatformFile &) = delete;
785061da546Spatrick };
786061da546Spatrick
787061da546Spatrick // "platform get-file remote-file-path host-file-path"
788061da546Spatrick class CommandObjectPlatformGetFile : public CommandObjectParsed {
789061da546Spatrick public:
CommandObjectPlatformGetFile(CommandInterpreter & interpreter)790061da546Spatrick CommandObjectPlatformGetFile(CommandInterpreter &interpreter)
791061da546Spatrick : CommandObjectParsed(
792061da546Spatrick interpreter, "platform get-file",
793061da546Spatrick "Transfer a file from the remote end to the local host.",
794061da546Spatrick "platform get-file <remote-file-spec> <local-file-spec>", 0) {
795061da546Spatrick SetHelpLong(
796061da546Spatrick R"(Examples:
797061da546Spatrick
798061da546Spatrick (lldb) platform get-file /the/remote/file/path /the/local/file/path
799061da546Spatrick
800061da546Spatrick Transfer a file from the remote end with file path /the/remote/file/path to the local host.)");
801061da546Spatrick
802061da546Spatrick CommandArgumentEntry arg1, arg2;
803061da546Spatrick CommandArgumentData file_arg_remote, file_arg_host;
804061da546Spatrick
805061da546Spatrick // Define the first (and only) variant of this arg.
806061da546Spatrick file_arg_remote.arg_type = eArgTypeFilename;
807061da546Spatrick file_arg_remote.arg_repetition = eArgRepeatPlain;
808061da546Spatrick // There is only one variant this argument could be; put it into the
809061da546Spatrick // argument entry.
810061da546Spatrick arg1.push_back(file_arg_remote);
811061da546Spatrick
812061da546Spatrick // Define the second (and only) variant of this arg.
813061da546Spatrick file_arg_host.arg_type = eArgTypeFilename;
814061da546Spatrick file_arg_host.arg_repetition = eArgRepeatPlain;
815061da546Spatrick // There is only one variant this argument could be; put it into the
816061da546Spatrick // argument entry.
817061da546Spatrick arg2.push_back(file_arg_host);
818061da546Spatrick
819061da546Spatrick // Push the data for the first and the second arguments into the
820061da546Spatrick // m_arguments vector.
821061da546Spatrick m_arguments.push_back(arg1);
822061da546Spatrick m_arguments.push_back(arg2);
823061da546Spatrick }
824061da546Spatrick
825061da546Spatrick ~CommandObjectPlatformGetFile() override = default;
826061da546Spatrick
827be691f3bSpatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)828be691f3bSpatrick HandleArgumentCompletion(CompletionRequest &request,
829be691f3bSpatrick OptionElementVector &opt_element_vector) override {
830be691f3bSpatrick if (request.GetCursorIndex() == 0)
831be691f3bSpatrick CommandCompletions::InvokeCommonCompletionCallbacks(
832be691f3bSpatrick GetCommandInterpreter(),
833be691f3bSpatrick CommandCompletions::eRemoteDiskFileCompletion, request, nullptr);
834be691f3bSpatrick else if (request.GetCursorIndex() == 1)
835be691f3bSpatrick CommandCompletions::InvokeCommonCompletionCallbacks(
836be691f3bSpatrick GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
837be691f3bSpatrick request, nullptr);
838be691f3bSpatrick }
839be691f3bSpatrick
DoExecute(Args & args,CommandReturnObject & result)840061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
841061da546Spatrick // If the number of arguments is incorrect, issue an error message.
842061da546Spatrick if (args.GetArgumentCount() != 2) {
843be691f3bSpatrick result.AppendError("required arguments missing; specify both the "
844be691f3bSpatrick "source and destination file paths");
845061da546Spatrick return false;
846061da546Spatrick }
847061da546Spatrick
848061da546Spatrick PlatformSP platform_sp(
849061da546Spatrick GetDebugger().GetPlatformList().GetSelectedPlatform());
850061da546Spatrick if (platform_sp) {
851061da546Spatrick const char *remote_file_path = args.GetArgumentAtIndex(0);
852061da546Spatrick const char *local_file_path = args.GetArgumentAtIndex(1);
853061da546Spatrick Status error = platform_sp->GetFile(FileSpec(remote_file_path),
854061da546Spatrick FileSpec(local_file_path));
855061da546Spatrick if (error.Success()) {
856061da546Spatrick result.AppendMessageWithFormat(
857061da546Spatrick "successfully get-file from %s (remote) to %s (host)\n",
858061da546Spatrick remote_file_path, local_file_path);
859061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
860061da546Spatrick } else {
861061da546Spatrick result.AppendMessageWithFormat("get-file failed: %s\n",
862061da546Spatrick error.AsCString());
863061da546Spatrick }
864061da546Spatrick } else {
865061da546Spatrick result.AppendError("no platform currently selected\n");
866061da546Spatrick }
867061da546Spatrick return result.Succeeded();
868061da546Spatrick }
869061da546Spatrick };
870061da546Spatrick
871061da546Spatrick // "platform get-size remote-file-path"
872061da546Spatrick class CommandObjectPlatformGetSize : public CommandObjectParsed {
873061da546Spatrick public:
CommandObjectPlatformGetSize(CommandInterpreter & interpreter)874061da546Spatrick CommandObjectPlatformGetSize(CommandInterpreter &interpreter)
875061da546Spatrick : CommandObjectParsed(interpreter, "platform get-size",
876061da546Spatrick "Get the file size from the remote end.",
877061da546Spatrick "platform get-size <remote-file-spec>", 0) {
878061da546Spatrick SetHelpLong(
879061da546Spatrick R"(Examples:
880061da546Spatrick
881061da546Spatrick (lldb) platform get-size /the/remote/file/path
882061da546Spatrick
883061da546Spatrick Get the file size from the remote end with path /the/remote/file/path.)");
884061da546Spatrick
885061da546Spatrick CommandArgumentEntry arg1;
886061da546Spatrick CommandArgumentData file_arg_remote;
887061da546Spatrick
888061da546Spatrick // Define the first (and only) variant of this arg.
889061da546Spatrick file_arg_remote.arg_type = eArgTypeFilename;
890061da546Spatrick file_arg_remote.arg_repetition = eArgRepeatPlain;
891061da546Spatrick // There is only one variant this argument could be; put it into the
892061da546Spatrick // argument entry.
893061da546Spatrick arg1.push_back(file_arg_remote);
894061da546Spatrick
895061da546Spatrick // Push the data for the first argument into the m_arguments vector.
896061da546Spatrick m_arguments.push_back(arg1);
897061da546Spatrick }
898061da546Spatrick
899061da546Spatrick ~CommandObjectPlatformGetSize() override = default;
900061da546Spatrick
901be691f3bSpatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)902be691f3bSpatrick HandleArgumentCompletion(CompletionRequest &request,
903be691f3bSpatrick OptionElementVector &opt_element_vector) override {
904be691f3bSpatrick if (request.GetCursorIndex() != 0)
905be691f3bSpatrick return;
906be691f3bSpatrick
907be691f3bSpatrick CommandCompletions::InvokeCommonCompletionCallbacks(
908be691f3bSpatrick GetCommandInterpreter(), CommandCompletions::eRemoteDiskFileCompletion,
909be691f3bSpatrick request, nullptr);
910be691f3bSpatrick }
911be691f3bSpatrick
DoExecute(Args & args,CommandReturnObject & result)912061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
913061da546Spatrick // If the number of arguments is incorrect, issue an error message.
914061da546Spatrick if (args.GetArgumentCount() != 1) {
915be691f3bSpatrick result.AppendError("required argument missing; specify the source file "
916be691f3bSpatrick "path as the only argument");
917061da546Spatrick return false;
918061da546Spatrick }
919061da546Spatrick
920061da546Spatrick PlatformSP platform_sp(
921061da546Spatrick GetDebugger().GetPlatformList().GetSelectedPlatform());
922061da546Spatrick if (platform_sp) {
923061da546Spatrick std::string remote_file_path(args.GetArgumentAtIndex(0));
924061da546Spatrick user_id_t size = platform_sp->GetFileSize(FileSpec(remote_file_path));
925061da546Spatrick if (size != UINT64_MAX) {
926061da546Spatrick result.AppendMessageWithFormat("File size of %s (remote): %" PRIu64
927061da546Spatrick "\n",
928061da546Spatrick remote_file_path.c_str(), size);
929061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
930061da546Spatrick } else {
931061da546Spatrick result.AppendMessageWithFormat(
932061da546Spatrick "Error getting file size of %s (remote)\n",
933061da546Spatrick remote_file_path.c_str());
934061da546Spatrick }
935061da546Spatrick } else {
936061da546Spatrick result.AppendError("no platform currently selected\n");
937061da546Spatrick }
938061da546Spatrick return result.Succeeded();
939061da546Spatrick }
940061da546Spatrick };
941061da546Spatrick
942*f6aab3d8Srobert // "platform get-permissions remote-file-path"
943*f6aab3d8Srobert class CommandObjectPlatformGetPermissions : public CommandObjectParsed {
944*f6aab3d8Srobert public:
CommandObjectPlatformGetPermissions(CommandInterpreter & interpreter)945*f6aab3d8Srobert CommandObjectPlatformGetPermissions(CommandInterpreter &interpreter)
946*f6aab3d8Srobert : CommandObjectParsed(interpreter, "platform get-permissions",
947*f6aab3d8Srobert "Get the file permission bits from the remote end.",
948*f6aab3d8Srobert "platform get-permissions <remote-file-spec>", 0) {
949*f6aab3d8Srobert SetHelpLong(
950*f6aab3d8Srobert R"(Examples:
951*f6aab3d8Srobert
952*f6aab3d8Srobert (lldb) platform get-permissions /the/remote/file/path
953*f6aab3d8Srobert
954*f6aab3d8Srobert Get the file permissions from the remote end with path /the/remote/file/path.)");
955*f6aab3d8Srobert
956*f6aab3d8Srobert CommandArgumentEntry arg1;
957*f6aab3d8Srobert CommandArgumentData file_arg_remote;
958*f6aab3d8Srobert
959*f6aab3d8Srobert // Define the first (and only) variant of this arg.
960*f6aab3d8Srobert file_arg_remote.arg_type = eArgTypeFilename;
961*f6aab3d8Srobert file_arg_remote.arg_repetition = eArgRepeatPlain;
962*f6aab3d8Srobert // There is only one variant this argument could be; put it into the
963*f6aab3d8Srobert // argument entry.
964*f6aab3d8Srobert arg1.push_back(file_arg_remote);
965*f6aab3d8Srobert
966*f6aab3d8Srobert // Push the data for the first argument into the m_arguments vector.
967*f6aab3d8Srobert m_arguments.push_back(arg1);
968*f6aab3d8Srobert }
969*f6aab3d8Srobert
970*f6aab3d8Srobert ~CommandObjectPlatformGetPermissions() override = default;
971*f6aab3d8Srobert
972*f6aab3d8Srobert void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)973*f6aab3d8Srobert HandleArgumentCompletion(CompletionRequest &request,
974*f6aab3d8Srobert OptionElementVector &opt_element_vector) override {
975*f6aab3d8Srobert if (request.GetCursorIndex() != 0)
976*f6aab3d8Srobert return;
977*f6aab3d8Srobert
978*f6aab3d8Srobert CommandCompletions::InvokeCommonCompletionCallbacks(
979*f6aab3d8Srobert GetCommandInterpreter(), CommandCompletions::eRemoteDiskFileCompletion,
980*f6aab3d8Srobert request, nullptr);
981*f6aab3d8Srobert }
982*f6aab3d8Srobert
DoExecute(Args & args,CommandReturnObject & result)983*f6aab3d8Srobert bool DoExecute(Args &args, CommandReturnObject &result) override {
984*f6aab3d8Srobert // If the number of arguments is incorrect, issue an error message.
985*f6aab3d8Srobert if (args.GetArgumentCount() != 1) {
986*f6aab3d8Srobert result.AppendError("required argument missing; specify the source file "
987*f6aab3d8Srobert "path as the only argument");
988*f6aab3d8Srobert return false;
989*f6aab3d8Srobert }
990*f6aab3d8Srobert
991*f6aab3d8Srobert PlatformSP platform_sp(
992*f6aab3d8Srobert GetDebugger().GetPlatformList().GetSelectedPlatform());
993*f6aab3d8Srobert if (platform_sp) {
994*f6aab3d8Srobert std::string remote_file_path(args.GetArgumentAtIndex(0));
995*f6aab3d8Srobert uint32_t permissions;
996*f6aab3d8Srobert Status error = platform_sp->GetFilePermissions(FileSpec(remote_file_path),
997*f6aab3d8Srobert permissions);
998*f6aab3d8Srobert if (error.Success()) {
999*f6aab3d8Srobert result.AppendMessageWithFormat(
1000*f6aab3d8Srobert "File permissions of %s (remote): 0o%04" PRIo32 "\n",
1001*f6aab3d8Srobert remote_file_path.c_str(), permissions);
1002*f6aab3d8Srobert result.SetStatus(eReturnStatusSuccessFinishResult);
1003*f6aab3d8Srobert } else
1004*f6aab3d8Srobert result.AppendError(error.AsCString());
1005*f6aab3d8Srobert } else {
1006*f6aab3d8Srobert result.AppendError("no platform currently selected\n");
1007*f6aab3d8Srobert }
1008*f6aab3d8Srobert return result.Succeeded();
1009*f6aab3d8Srobert }
1010*f6aab3d8Srobert };
1011*f6aab3d8Srobert
1012*f6aab3d8Srobert // "platform file-exists remote-file-path"
1013*f6aab3d8Srobert class CommandObjectPlatformFileExists : public CommandObjectParsed {
1014*f6aab3d8Srobert public:
CommandObjectPlatformFileExists(CommandInterpreter & interpreter)1015*f6aab3d8Srobert CommandObjectPlatformFileExists(CommandInterpreter &interpreter)
1016*f6aab3d8Srobert : CommandObjectParsed(interpreter, "platform file-exists",
1017*f6aab3d8Srobert "Check if the file exists on the remote end.",
1018*f6aab3d8Srobert "platform file-exists <remote-file-spec>", 0) {
1019*f6aab3d8Srobert SetHelpLong(
1020*f6aab3d8Srobert R"(Examples:
1021*f6aab3d8Srobert
1022*f6aab3d8Srobert (lldb) platform file-exists /the/remote/file/path
1023*f6aab3d8Srobert
1024*f6aab3d8Srobert Check if /the/remote/file/path exists on the remote end.)");
1025*f6aab3d8Srobert
1026*f6aab3d8Srobert CommandArgumentEntry arg1;
1027*f6aab3d8Srobert CommandArgumentData file_arg_remote;
1028*f6aab3d8Srobert
1029*f6aab3d8Srobert // Define the first (and only) variant of this arg.
1030*f6aab3d8Srobert file_arg_remote.arg_type = eArgTypeFilename;
1031*f6aab3d8Srobert file_arg_remote.arg_repetition = eArgRepeatPlain;
1032*f6aab3d8Srobert // There is only one variant this argument could be; put it into the
1033*f6aab3d8Srobert // argument entry.
1034*f6aab3d8Srobert arg1.push_back(file_arg_remote);
1035*f6aab3d8Srobert
1036*f6aab3d8Srobert // Push the data for the first argument into the m_arguments vector.
1037*f6aab3d8Srobert m_arguments.push_back(arg1);
1038*f6aab3d8Srobert }
1039*f6aab3d8Srobert
1040*f6aab3d8Srobert ~CommandObjectPlatformFileExists() override = default;
1041*f6aab3d8Srobert
1042*f6aab3d8Srobert void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1043*f6aab3d8Srobert HandleArgumentCompletion(CompletionRequest &request,
1044*f6aab3d8Srobert OptionElementVector &opt_element_vector) override {
1045*f6aab3d8Srobert if (request.GetCursorIndex() != 0)
1046*f6aab3d8Srobert return;
1047*f6aab3d8Srobert
1048*f6aab3d8Srobert CommandCompletions::InvokeCommonCompletionCallbacks(
1049*f6aab3d8Srobert GetCommandInterpreter(), CommandCompletions::eRemoteDiskFileCompletion,
1050*f6aab3d8Srobert request, nullptr);
1051*f6aab3d8Srobert }
1052*f6aab3d8Srobert
DoExecute(Args & args,CommandReturnObject & result)1053*f6aab3d8Srobert bool DoExecute(Args &args, CommandReturnObject &result) override {
1054*f6aab3d8Srobert // If the number of arguments is incorrect, issue an error message.
1055*f6aab3d8Srobert if (args.GetArgumentCount() != 1) {
1056*f6aab3d8Srobert result.AppendError("required argument missing; specify the source file "
1057*f6aab3d8Srobert "path as the only argument");
1058*f6aab3d8Srobert return false;
1059*f6aab3d8Srobert }
1060*f6aab3d8Srobert
1061*f6aab3d8Srobert PlatformSP platform_sp(
1062*f6aab3d8Srobert GetDebugger().GetPlatformList().GetSelectedPlatform());
1063*f6aab3d8Srobert if (platform_sp) {
1064*f6aab3d8Srobert std::string remote_file_path(args.GetArgumentAtIndex(0));
1065*f6aab3d8Srobert bool exists = platform_sp->GetFileExists(FileSpec(remote_file_path));
1066*f6aab3d8Srobert result.AppendMessageWithFormat(
1067*f6aab3d8Srobert "File %s (remote) %s\n",
1068*f6aab3d8Srobert remote_file_path.c_str(), exists ? "exists" : "does not exist");
1069*f6aab3d8Srobert result.SetStatus(eReturnStatusSuccessFinishResult);
1070*f6aab3d8Srobert } else {
1071*f6aab3d8Srobert result.AppendError("no platform currently selected\n");
1072*f6aab3d8Srobert }
1073*f6aab3d8Srobert return result.Succeeded();
1074*f6aab3d8Srobert }
1075*f6aab3d8Srobert };
1076*f6aab3d8Srobert
1077061da546Spatrick // "platform put-file"
1078061da546Spatrick class CommandObjectPlatformPutFile : public CommandObjectParsed {
1079061da546Spatrick public:
CommandObjectPlatformPutFile(CommandInterpreter & interpreter)1080061da546Spatrick CommandObjectPlatformPutFile(CommandInterpreter &interpreter)
1081061da546Spatrick : CommandObjectParsed(
1082061da546Spatrick interpreter, "platform put-file",
1083*f6aab3d8Srobert "Transfer a file from this system to the remote end.",
1084*f6aab3d8Srobert "platform put-file <source> [<destination>]", 0) {
1085*f6aab3d8Srobert SetHelpLong(
1086*f6aab3d8Srobert R"(Examples:
1087*f6aab3d8Srobert
1088*f6aab3d8Srobert (lldb) platform put-file /source/foo.txt /destination/bar.txt
1089*f6aab3d8Srobert
1090*f6aab3d8Srobert (lldb) platform put-file /source/foo.txt
1091*f6aab3d8Srobert
1092*f6aab3d8Srobert Relative source file paths are resolved against lldb's local working directory.
1093*f6aab3d8Srobert
1094*f6aab3d8Srobert Omitting the destination places the file in the platform working directory.)");
1095*f6aab3d8Srobert CommandArgumentData source_arg{eArgTypePath, eArgRepeatPlain};
1096*f6aab3d8Srobert CommandArgumentData path_arg{eArgTypePath, eArgRepeatOptional};
1097*f6aab3d8Srobert m_arguments.push_back({source_arg});
1098*f6aab3d8Srobert m_arguments.push_back({path_arg});
1099061da546Spatrick }
1100061da546Spatrick
1101061da546Spatrick ~CommandObjectPlatformPutFile() override = default;
1102061da546Spatrick
1103be691f3bSpatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1104be691f3bSpatrick HandleArgumentCompletion(CompletionRequest &request,
1105be691f3bSpatrick OptionElementVector &opt_element_vector) override {
1106be691f3bSpatrick if (request.GetCursorIndex() == 0)
1107be691f3bSpatrick CommandCompletions::InvokeCommonCompletionCallbacks(
1108be691f3bSpatrick GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
1109be691f3bSpatrick request, nullptr);
1110be691f3bSpatrick else if (request.GetCursorIndex() == 1)
1111be691f3bSpatrick CommandCompletions::InvokeCommonCompletionCallbacks(
1112be691f3bSpatrick GetCommandInterpreter(),
1113be691f3bSpatrick CommandCompletions::eRemoteDiskFileCompletion, request, nullptr);
1114be691f3bSpatrick }
1115be691f3bSpatrick
DoExecute(Args & args,CommandReturnObject & result)1116061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
1117061da546Spatrick const char *src = args.GetArgumentAtIndex(0);
1118061da546Spatrick const char *dst = args.GetArgumentAtIndex(1);
1119061da546Spatrick
1120061da546Spatrick FileSpec src_fs(src);
1121061da546Spatrick FileSystem::Instance().Resolve(src_fs);
1122061da546Spatrick FileSpec dst_fs(dst ? dst : src_fs.GetFilename().GetCString());
1123061da546Spatrick
1124061da546Spatrick PlatformSP platform_sp(
1125061da546Spatrick GetDebugger().GetPlatformList().GetSelectedPlatform());
1126061da546Spatrick if (platform_sp) {
1127061da546Spatrick Status error(platform_sp->PutFile(src_fs, dst_fs));
1128061da546Spatrick if (error.Success()) {
1129061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1130061da546Spatrick } else {
1131061da546Spatrick result.AppendError(error.AsCString());
1132061da546Spatrick }
1133061da546Spatrick } else {
1134061da546Spatrick result.AppendError("no platform currently selected\n");
1135061da546Spatrick }
1136061da546Spatrick return result.Succeeded();
1137061da546Spatrick }
1138061da546Spatrick };
1139061da546Spatrick
1140061da546Spatrick // "platform process launch"
1141061da546Spatrick class CommandObjectPlatformProcessLaunch : public CommandObjectParsed {
1142061da546Spatrick public:
CommandObjectPlatformProcessLaunch(CommandInterpreter & interpreter)1143061da546Spatrick CommandObjectPlatformProcessLaunch(CommandInterpreter &interpreter)
1144061da546Spatrick : CommandObjectParsed(interpreter, "platform process launch",
1145061da546Spatrick "Launch a new process on a remote platform.",
1146061da546Spatrick "platform process launch program",
1147*f6aab3d8Srobert eCommandRequiresTarget | eCommandTryTargetAPILock) {
1148be691f3bSpatrick m_all_options.Append(&m_options);
1149be691f3bSpatrick m_all_options.Finalize();
1150*f6aab3d8Srobert CommandArgumentData run_arg_arg{eArgTypeRunArgs, eArgRepeatStar};
1151*f6aab3d8Srobert m_arguments.push_back({run_arg_arg});
1152be691f3bSpatrick }
1153061da546Spatrick
1154061da546Spatrick ~CommandObjectPlatformProcessLaunch() override = default;
1155061da546Spatrick
GetOptions()1156be691f3bSpatrick Options *GetOptions() override { return &m_all_options; }
1157061da546Spatrick
1158061da546Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)1159061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
1160061da546Spatrick Target *target = GetDebugger().GetSelectedTarget().get();
1161061da546Spatrick PlatformSP platform_sp;
1162061da546Spatrick if (target) {
1163061da546Spatrick platform_sp = target->GetPlatform();
1164061da546Spatrick }
1165061da546Spatrick if (!platform_sp) {
1166061da546Spatrick platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();
1167061da546Spatrick }
1168061da546Spatrick
1169061da546Spatrick if (platform_sp) {
1170061da546Spatrick Status error;
1171061da546Spatrick const size_t argc = args.GetArgumentCount();
1172061da546Spatrick Target *target = m_exe_ctx.GetTargetPtr();
1173061da546Spatrick Module *exe_module = target->GetExecutableModulePointer();
1174061da546Spatrick if (exe_module) {
1175061da546Spatrick m_options.launch_info.GetExecutableFile() = exe_module->GetFileSpec();
1176061da546Spatrick llvm::SmallString<128> exe_path;
1177061da546Spatrick m_options.launch_info.GetExecutableFile().GetPath(exe_path);
1178061da546Spatrick if (!exe_path.empty())
1179061da546Spatrick m_options.launch_info.GetArguments().AppendArgument(exe_path);
1180061da546Spatrick m_options.launch_info.GetArchitecture() = exe_module->GetArchitecture();
1181061da546Spatrick }
1182061da546Spatrick
1183061da546Spatrick if (argc > 0) {
1184061da546Spatrick if (m_options.launch_info.GetExecutableFile()) {
1185061da546Spatrick // We already have an executable file, so we will use this and all
1186061da546Spatrick // arguments to this function are extra arguments
1187061da546Spatrick m_options.launch_info.GetArguments().AppendArguments(args);
1188061da546Spatrick } else {
1189061da546Spatrick // We don't have any file yet, so the first argument is our
1190061da546Spatrick // executable, and the rest are program arguments
1191061da546Spatrick const bool first_arg_is_executable = true;
1192061da546Spatrick m_options.launch_info.SetArguments(args, first_arg_is_executable);
1193061da546Spatrick }
1194061da546Spatrick }
1195061da546Spatrick
1196061da546Spatrick if (m_options.launch_info.GetExecutableFile()) {
1197061da546Spatrick Debugger &debugger = GetDebugger();
1198061da546Spatrick
1199061da546Spatrick if (argc == 0)
1200061da546Spatrick target->GetRunArguments(m_options.launch_info.GetArguments());
1201061da546Spatrick
1202061da546Spatrick ProcessSP process_sp(platform_sp->DebugProcess(
1203*f6aab3d8Srobert m_options.launch_info, debugger, *target, error));
1204061da546Spatrick if (process_sp && process_sp->IsAlive()) {
1205061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1206061da546Spatrick return true;
1207061da546Spatrick }
1208061da546Spatrick
1209061da546Spatrick if (error.Success())
1210061da546Spatrick result.AppendError("process launch failed");
1211061da546Spatrick else
1212061da546Spatrick result.AppendError(error.AsCString());
1213061da546Spatrick } else {
1214061da546Spatrick result.AppendError("'platform process launch' uses the current target "
1215061da546Spatrick "file and arguments, or the executable and its "
1216061da546Spatrick "arguments can be specified in this command");
1217061da546Spatrick return false;
1218061da546Spatrick }
1219061da546Spatrick } else {
1220061da546Spatrick result.AppendError("no platform is selected\n");
1221061da546Spatrick }
1222061da546Spatrick return result.Succeeded();
1223061da546Spatrick }
1224061da546Spatrick
1225be691f3bSpatrick CommandOptionsProcessLaunch m_options;
1226be691f3bSpatrick OptionGroupOptions m_all_options;
1227061da546Spatrick };
1228061da546Spatrick
1229061da546Spatrick // "platform process list"
1230061da546Spatrick
1231061da546Spatrick static PosixPlatformCommandOptionValidator posix_validator;
1232061da546Spatrick #define LLDB_OPTIONS_platform_process_list
1233061da546Spatrick #include "CommandOptions.inc"
1234061da546Spatrick
1235061da546Spatrick class CommandObjectPlatformProcessList : public CommandObjectParsed {
1236061da546Spatrick public:
CommandObjectPlatformProcessList(CommandInterpreter & interpreter)1237061da546Spatrick CommandObjectPlatformProcessList(CommandInterpreter &interpreter)
1238061da546Spatrick : CommandObjectParsed(interpreter, "platform process list",
1239061da546Spatrick "List processes on a remote platform by name, pid, "
1240061da546Spatrick "or many other matching attributes.",
1241*f6aab3d8Srobert "platform process list", 0) {}
1242061da546Spatrick
1243061da546Spatrick ~CommandObjectPlatformProcessList() override = default;
1244061da546Spatrick
GetOptions()1245061da546Spatrick Options *GetOptions() override { return &m_options; }
1246061da546Spatrick
1247061da546Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)1248061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
1249061da546Spatrick Target *target = GetDebugger().GetSelectedTarget().get();
1250061da546Spatrick PlatformSP platform_sp;
1251061da546Spatrick if (target) {
1252061da546Spatrick platform_sp = target->GetPlatform();
1253061da546Spatrick }
1254061da546Spatrick if (!platform_sp) {
1255061da546Spatrick platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();
1256061da546Spatrick }
1257061da546Spatrick
1258061da546Spatrick if (platform_sp) {
1259061da546Spatrick Status error;
1260061da546Spatrick if (platform_sp) {
1261061da546Spatrick Stream &ostrm = result.GetOutputStream();
1262061da546Spatrick
1263*f6aab3d8Srobert lldb::pid_t pid = m_options.match_info.GetProcessInfo().GetProcessID();
1264061da546Spatrick if (pid != LLDB_INVALID_PROCESS_ID) {
1265061da546Spatrick ProcessInstanceInfo proc_info;
1266061da546Spatrick if (platform_sp->GetProcessInfo(pid, proc_info)) {
1267061da546Spatrick ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,
1268061da546Spatrick m_options.verbose);
1269061da546Spatrick proc_info.DumpAsTableRow(ostrm, platform_sp->GetUserIDResolver(),
1270061da546Spatrick m_options.show_args, m_options.verbose);
1271061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1272061da546Spatrick } else {
1273061da546Spatrick result.AppendErrorWithFormat(
1274061da546Spatrick "no process found with pid = %" PRIu64 "\n", pid);
1275061da546Spatrick }
1276061da546Spatrick } else {
1277061da546Spatrick ProcessInstanceInfoList proc_infos;
1278061da546Spatrick const uint32_t matches =
1279061da546Spatrick platform_sp->FindProcesses(m_options.match_info, proc_infos);
1280061da546Spatrick const char *match_desc = nullptr;
1281061da546Spatrick const char *match_name =
1282061da546Spatrick m_options.match_info.GetProcessInfo().GetName();
1283061da546Spatrick if (match_name && match_name[0]) {
1284061da546Spatrick switch (m_options.match_info.GetNameMatchType()) {
1285061da546Spatrick case NameMatch::Ignore:
1286061da546Spatrick break;
1287061da546Spatrick case NameMatch::Equals:
1288061da546Spatrick match_desc = "matched";
1289061da546Spatrick break;
1290061da546Spatrick case NameMatch::Contains:
1291061da546Spatrick match_desc = "contained";
1292061da546Spatrick break;
1293061da546Spatrick case NameMatch::StartsWith:
1294061da546Spatrick match_desc = "started with";
1295061da546Spatrick break;
1296061da546Spatrick case NameMatch::EndsWith:
1297061da546Spatrick match_desc = "ended with";
1298061da546Spatrick break;
1299061da546Spatrick case NameMatch::RegularExpression:
1300061da546Spatrick match_desc = "matched the regular expression";
1301061da546Spatrick break;
1302061da546Spatrick }
1303061da546Spatrick }
1304061da546Spatrick
1305061da546Spatrick if (matches == 0) {
1306061da546Spatrick if (match_desc)
1307*f6aab3d8Srobert result.AppendErrorWithFormatv(
1308*f6aab3d8Srobert "no processes were found that {0} \"{1}\" on the \"{2}\" "
1309061da546Spatrick "platform\n",
1310*f6aab3d8Srobert match_desc, match_name, platform_sp->GetName());
1311061da546Spatrick else
1312*f6aab3d8Srobert result.AppendErrorWithFormatv(
1313*f6aab3d8Srobert "no processes were found on the \"{0}\" platform\n",
1314*f6aab3d8Srobert platform_sp->GetName());
1315061da546Spatrick } else {
1316*f6aab3d8Srobert result.AppendMessageWithFormatv(
1317*f6aab3d8Srobert "{0} matching process{1} found on \"{2}\"", matches,
1318*f6aab3d8Srobert matches > 1 ? "es were" : " was", platform_sp->GetName());
1319061da546Spatrick if (match_desc)
1320061da546Spatrick result.AppendMessageWithFormat(" whose name %s \"%s\"",
1321061da546Spatrick match_desc, match_name);
1322061da546Spatrick result.AppendMessageWithFormat("\n");
1323061da546Spatrick ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,
1324061da546Spatrick m_options.verbose);
1325061da546Spatrick for (uint32_t i = 0; i < matches; ++i) {
1326dda28197Spatrick proc_infos[i].DumpAsTableRow(
1327*f6aab3d8Srobert ostrm, platform_sp->GetUserIDResolver(), m_options.show_args,
1328*f6aab3d8Srobert m_options.verbose);
1329061da546Spatrick }
1330061da546Spatrick }
1331061da546Spatrick }
1332061da546Spatrick }
1333061da546Spatrick } else {
1334061da546Spatrick result.AppendError("no platform is selected\n");
1335061da546Spatrick }
1336061da546Spatrick return result.Succeeded();
1337061da546Spatrick }
1338061da546Spatrick
1339061da546Spatrick class CommandOptions : public Options {
1340061da546Spatrick public:
1341*f6aab3d8Srobert CommandOptions() = default;
1342061da546Spatrick
1343061da546Spatrick ~CommandOptions() override = default;
1344061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1345061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1346061da546Spatrick ExecutionContext *execution_context) override {
1347061da546Spatrick Status error;
1348061da546Spatrick const int short_option = m_getopt_table[option_idx].val;
1349061da546Spatrick bool success = false;
1350061da546Spatrick
1351061da546Spatrick uint32_t id = LLDB_INVALID_PROCESS_ID;
1352061da546Spatrick success = !option_arg.getAsInteger(0, id);
1353061da546Spatrick switch (short_option) {
1354061da546Spatrick case 'p': {
1355061da546Spatrick match_info.GetProcessInfo().SetProcessID(id);
1356061da546Spatrick if (!success)
1357061da546Spatrick error.SetErrorStringWithFormat("invalid process ID string: '%s'",
1358061da546Spatrick option_arg.str().c_str());
1359061da546Spatrick break;
1360061da546Spatrick }
1361061da546Spatrick case 'P':
1362061da546Spatrick match_info.GetProcessInfo().SetParentProcessID(id);
1363061da546Spatrick if (!success)
1364061da546Spatrick error.SetErrorStringWithFormat(
1365061da546Spatrick "invalid parent process ID string: '%s'",
1366061da546Spatrick option_arg.str().c_str());
1367061da546Spatrick break;
1368061da546Spatrick
1369061da546Spatrick case 'u':
1370061da546Spatrick match_info.GetProcessInfo().SetUserID(success ? id : UINT32_MAX);
1371061da546Spatrick if (!success)
1372061da546Spatrick error.SetErrorStringWithFormat("invalid user ID string: '%s'",
1373061da546Spatrick option_arg.str().c_str());
1374061da546Spatrick break;
1375061da546Spatrick
1376061da546Spatrick case 'U':
1377061da546Spatrick match_info.GetProcessInfo().SetEffectiveUserID(success ? id
1378061da546Spatrick : UINT32_MAX);
1379061da546Spatrick if (!success)
1380061da546Spatrick error.SetErrorStringWithFormat(
1381061da546Spatrick "invalid effective user ID string: '%s'",
1382061da546Spatrick option_arg.str().c_str());
1383061da546Spatrick break;
1384061da546Spatrick
1385061da546Spatrick case 'g':
1386061da546Spatrick match_info.GetProcessInfo().SetGroupID(success ? id : UINT32_MAX);
1387061da546Spatrick if (!success)
1388061da546Spatrick error.SetErrorStringWithFormat("invalid group ID string: '%s'",
1389061da546Spatrick option_arg.str().c_str());
1390061da546Spatrick break;
1391061da546Spatrick
1392061da546Spatrick case 'G':
1393061da546Spatrick match_info.GetProcessInfo().SetEffectiveGroupID(success ? id
1394061da546Spatrick : UINT32_MAX);
1395061da546Spatrick if (!success)
1396061da546Spatrick error.SetErrorStringWithFormat(
1397061da546Spatrick "invalid effective group ID string: '%s'",
1398061da546Spatrick option_arg.str().c_str());
1399061da546Spatrick break;
1400061da546Spatrick
1401061da546Spatrick case 'a': {
1402061da546Spatrick TargetSP target_sp =
1403061da546Spatrick execution_context ? execution_context->GetTargetSP() : TargetSP();
1404061da546Spatrick DebuggerSP debugger_sp =
1405061da546Spatrick target_sp ? target_sp->GetDebugger().shared_from_this()
1406061da546Spatrick : DebuggerSP();
1407061da546Spatrick PlatformSP platform_sp =
1408061da546Spatrick debugger_sp ? debugger_sp->GetPlatformList().GetSelectedPlatform()
1409061da546Spatrick : PlatformSP();
1410061da546Spatrick match_info.GetProcessInfo().GetArchitecture() =
1411061da546Spatrick Platform::GetAugmentedArchSpec(platform_sp.get(), option_arg);
1412061da546Spatrick } break;
1413061da546Spatrick
1414061da546Spatrick case 'n':
1415061da546Spatrick match_info.GetProcessInfo().GetExecutableFile().SetFile(
1416061da546Spatrick option_arg, FileSpec::Style::native);
1417061da546Spatrick match_info.SetNameMatchType(NameMatch::Equals);
1418061da546Spatrick break;
1419061da546Spatrick
1420061da546Spatrick case 'e':
1421061da546Spatrick match_info.GetProcessInfo().GetExecutableFile().SetFile(
1422061da546Spatrick option_arg, FileSpec::Style::native);
1423061da546Spatrick match_info.SetNameMatchType(NameMatch::EndsWith);
1424061da546Spatrick break;
1425061da546Spatrick
1426061da546Spatrick case 's':
1427061da546Spatrick match_info.GetProcessInfo().GetExecutableFile().SetFile(
1428061da546Spatrick option_arg, FileSpec::Style::native);
1429061da546Spatrick match_info.SetNameMatchType(NameMatch::StartsWith);
1430061da546Spatrick break;
1431061da546Spatrick
1432061da546Spatrick case 'c':
1433061da546Spatrick match_info.GetProcessInfo().GetExecutableFile().SetFile(
1434061da546Spatrick option_arg, FileSpec::Style::native);
1435061da546Spatrick match_info.SetNameMatchType(NameMatch::Contains);
1436061da546Spatrick break;
1437061da546Spatrick
1438061da546Spatrick case 'r':
1439061da546Spatrick match_info.GetProcessInfo().GetExecutableFile().SetFile(
1440061da546Spatrick option_arg, FileSpec::Style::native);
1441061da546Spatrick match_info.SetNameMatchType(NameMatch::RegularExpression);
1442061da546Spatrick break;
1443061da546Spatrick
1444061da546Spatrick case 'A':
1445061da546Spatrick show_args = true;
1446061da546Spatrick break;
1447061da546Spatrick
1448061da546Spatrick case 'v':
1449061da546Spatrick verbose = true;
1450061da546Spatrick break;
1451061da546Spatrick
1452061da546Spatrick case 'x':
1453061da546Spatrick match_info.SetMatchAllUsers(true);
1454061da546Spatrick break;
1455061da546Spatrick
1456061da546Spatrick default:
1457061da546Spatrick llvm_unreachable("Unimplemented option");
1458061da546Spatrick }
1459061da546Spatrick
1460061da546Spatrick return error;
1461061da546Spatrick }
1462061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)1463061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
1464061da546Spatrick match_info.Clear();
1465061da546Spatrick show_args = false;
1466061da546Spatrick verbose = false;
1467061da546Spatrick }
1468061da546Spatrick
GetDefinitions()1469061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1470*f6aab3d8Srobert return llvm::ArrayRef(g_platform_process_list_options);
1471061da546Spatrick }
1472061da546Spatrick
1473061da546Spatrick // Instance variables to hold the values for command options.
1474061da546Spatrick
1475061da546Spatrick ProcessInstanceInfoMatch match_info;
1476be691f3bSpatrick bool show_args = false;
1477be691f3bSpatrick bool verbose = false;
1478061da546Spatrick };
1479061da546Spatrick
1480061da546Spatrick CommandOptions m_options;
1481061da546Spatrick };
1482061da546Spatrick
1483061da546Spatrick // "platform process info"
1484061da546Spatrick class CommandObjectPlatformProcessInfo : public CommandObjectParsed {
1485061da546Spatrick public:
CommandObjectPlatformProcessInfo(CommandInterpreter & interpreter)1486061da546Spatrick CommandObjectPlatformProcessInfo(CommandInterpreter &interpreter)
1487061da546Spatrick : CommandObjectParsed(
1488061da546Spatrick interpreter, "platform process info",
1489061da546Spatrick "Get detailed information for one or more process by process ID.",
1490061da546Spatrick "platform process info <pid> [<pid> <pid> ...]", 0) {
1491061da546Spatrick CommandArgumentEntry arg;
1492061da546Spatrick CommandArgumentData pid_args;
1493061da546Spatrick
1494061da546Spatrick // Define the first (and only) variant of this arg.
1495061da546Spatrick pid_args.arg_type = eArgTypePid;
1496061da546Spatrick pid_args.arg_repetition = eArgRepeatStar;
1497061da546Spatrick
1498061da546Spatrick // There is only one variant this argument could be; put it into the
1499061da546Spatrick // argument entry.
1500061da546Spatrick arg.push_back(pid_args);
1501061da546Spatrick
1502061da546Spatrick // Push the data for the first argument into the m_arguments vector.
1503061da546Spatrick m_arguments.push_back(arg);
1504061da546Spatrick }
1505061da546Spatrick
1506061da546Spatrick ~CommandObjectPlatformProcessInfo() override = default;
1507061da546Spatrick
1508be691f3bSpatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1509be691f3bSpatrick HandleArgumentCompletion(CompletionRequest &request,
1510be691f3bSpatrick OptionElementVector &opt_element_vector) override {
1511be691f3bSpatrick CommandCompletions::InvokeCommonCompletionCallbacks(
1512be691f3bSpatrick GetCommandInterpreter(), CommandCompletions::eProcessIDCompletion,
1513be691f3bSpatrick request, nullptr);
1514be691f3bSpatrick }
1515be691f3bSpatrick
1516061da546Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)1517061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
1518061da546Spatrick Target *target = GetDebugger().GetSelectedTarget().get();
1519061da546Spatrick PlatformSP platform_sp;
1520061da546Spatrick if (target) {
1521061da546Spatrick platform_sp = target->GetPlatform();
1522061da546Spatrick }
1523061da546Spatrick if (!platform_sp) {
1524061da546Spatrick platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();
1525061da546Spatrick }
1526061da546Spatrick
1527061da546Spatrick if (platform_sp) {
1528061da546Spatrick const size_t argc = args.GetArgumentCount();
1529061da546Spatrick if (argc > 0) {
1530061da546Spatrick Status error;
1531061da546Spatrick
1532061da546Spatrick if (platform_sp->IsConnected()) {
1533061da546Spatrick Stream &ostrm = result.GetOutputStream();
1534061da546Spatrick for (auto &entry : args.entries()) {
1535061da546Spatrick lldb::pid_t pid;
1536061da546Spatrick if (entry.ref().getAsInteger(0, pid)) {
1537061da546Spatrick result.AppendErrorWithFormat("invalid process ID argument '%s'",
1538061da546Spatrick entry.ref().str().c_str());
1539061da546Spatrick break;
1540061da546Spatrick } else {
1541061da546Spatrick ProcessInstanceInfo proc_info;
1542061da546Spatrick if (platform_sp->GetProcessInfo(pid, proc_info)) {
1543061da546Spatrick ostrm.Printf("Process information for process %" PRIu64 ":\n",
1544061da546Spatrick pid);
1545061da546Spatrick proc_info.Dump(ostrm, platform_sp->GetUserIDResolver());
1546061da546Spatrick } else {
1547061da546Spatrick ostrm.Printf("error: no process information is available for "
1548061da546Spatrick "process %" PRIu64 "\n",
1549061da546Spatrick pid);
1550061da546Spatrick }
1551061da546Spatrick ostrm.EOL();
1552061da546Spatrick }
1553061da546Spatrick }
1554061da546Spatrick } else {
1555061da546Spatrick // Not connected...
1556*f6aab3d8Srobert result.AppendErrorWithFormatv("not connected to '{0}'",
1557*f6aab3d8Srobert platform_sp->GetPluginName());
1558061da546Spatrick }
1559061da546Spatrick } else {
1560061da546Spatrick // No args
1561061da546Spatrick result.AppendError("one or more process id(s) must be specified");
1562061da546Spatrick }
1563061da546Spatrick } else {
1564061da546Spatrick result.AppendError("no platform is currently selected");
1565061da546Spatrick }
1566061da546Spatrick return result.Succeeded();
1567061da546Spatrick }
1568061da546Spatrick };
1569061da546Spatrick
1570061da546Spatrick #define LLDB_OPTIONS_platform_process_attach
1571061da546Spatrick #include "CommandOptions.inc"
1572061da546Spatrick
1573061da546Spatrick class CommandObjectPlatformProcessAttach : public CommandObjectParsed {
1574061da546Spatrick public:
1575061da546Spatrick class CommandOptions : public Options {
1576061da546Spatrick public:
CommandOptions()1577*f6aab3d8Srobert CommandOptions() {
1578061da546Spatrick // Keep default values of all options in one place: OptionParsingStarting
1579061da546Spatrick // ()
1580061da546Spatrick OptionParsingStarting(nullptr);
1581061da546Spatrick }
1582061da546Spatrick
1583061da546Spatrick ~CommandOptions() override = default;
1584061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1585061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1586061da546Spatrick ExecutionContext *execution_context) override {
1587061da546Spatrick Status error;
1588061da546Spatrick char short_option = (char)m_getopt_table[option_idx].val;
1589061da546Spatrick switch (short_option) {
1590061da546Spatrick case 'p': {
1591061da546Spatrick lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
1592061da546Spatrick if (option_arg.getAsInteger(0, pid)) {
1593061da546Spatrick error.SetErrorStringWithFormat("invalid process ID '%s'",
1594061da546Spatrick option_arg.str().c_str());
1595061da546Spatrick } else {
1596061da546Spatrick attach_info.SetProcessID(pid);
1597061da546Spatrick }
1598061da546Spatrick } break;
1599061da546Spatrick
1600061da546Spatrick case 'P':
1601061da546Spatrick attach_info.SetProcessPluginName(option_arg);
1602061da546Spatrick break;
1603061da546Spatrick
1604061da546Spatrick case 'n':
1605061da546Spatrick attach_info.GetExecutableFile().SetFile(option_arg,
1606061da546Spatrick FileSpec::Style::native);
1607061da546Spatrick break;
1608061da546Spatrick
1609061da546Spatrick case 'w':
1610061da546Spatrick attach_info.SetWaitForLaunch(true);
1611061da546Spatrick break;
1612061da546Spatrick
1613061da546Spatrick default:
1614061da546Spatrick llvm_unreachable("Unimplemented option");
1615061da546Spatrick }
1616061da546Spatrick return error;
1617061da546Spatrick }
1618061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)1619061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
1620061da546Spatrick attach_info.Clear();
1621061da546Spatrick }
1622061da546Spatrick
GetDefinitions()1623061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1624*f6aab3d8Srobert return llvm::ArrayRef(g_platform_process_attach_options);
1625061da546Spatrick }
1626061da546Spatrick
1627061da546Spatrick // Options table: Required for subclasses of Options.
1628061da546Spatrick
1629061da546Spatrick static OptionDefinition g_option_table[];
1630061da546Spatrick
1631061da546Spatrick // Instance variables to hold the values for command options.
1632061da546Spatrick
1633061da546Spatrick ProcessAttachInfo attach_info;
1634061da546Spatrick };
1635061da546Spatrick
CommandObjectPlatformProcessAttach(CommandInterpreter & interpreter)1636061da546Spatrick CommandObjectPlatformProcessAttach(CommandInterpreter &interpreter)
1637061da546Spatrick : CommandObjectParsed(interpreter, "platform process attach",
1638061da546Spatrick "Attach to a process.",
1639*f6aab3d8Srobert "platform process attach <cmd-options>") {}
1640061da546Spatrick
1641061da546Spatrick ~CommandObjectPlatformProcessAttach() override = default;
1642061da546Spatrick
DoExecute(Args & command,CommandReturnObject & result)1643061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1644061da546Spatrick PlatformSP platform_sp(
1645061da546Spatrick GetDebugger().GetPlatformList().GetSelectedPlatform());
1646061da546Spatrick if (platform_sp) {
1647061da546Spatrick Status err;
1648061da546Spatrick ProcessSP remote_process_sp = platform_sp->Attach(
1649061da546Spatrick m_options.attach_info, GetDebugger(), nullptr, err);
1650061da546Spatrick if (err.Fail()) {
1651061da546Spatrick result.AppendError(err.AsCString());
1652061da546Spatrick } else if (!remote_process_sp) {
1653061da546Spatrick result.AppendError("could not attach: unknown reason");
1654061da546Spatrick } else
1655061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1656061da546Spatrick } else {
1657061da546Spatrick result.AppendError("no platform is currently selected");
1658061da546Spatrick }
1659061da546Spatrick return result.Succeeded();
1660061da546Spatrick }
1661061da546Spatrick
GetOptions()1662061da546Spatrick Options *GetOptions() override { return &m_options; }
1663061da546Spatrick
1664061da546Spatrick protected:
1665061da546Spatrick CommandOptions m_options;
1666061da546Spatrick };
1667061da546Spatrick
1668061da546Spatrick class CommandObjectPlatformProcess : public CommandObjectMultiword {
1669061da546Spatrick public:
1670061da546Spatrick // Constructors and Destructors
CommandObjectPlatformProcess(CommandInterpreter & interpreter)1671061da546Spatrick CommandObjectPlatformProcess(CommandInterpreter &interpreter)
1672061da546Spatrick : CommandObjectMultiword(interpreter, "platform process",
1673061da546Spatrick "Commands to query, launch and attach to "
1674061da546Spatrick "processes on the current platform.",
1675061da546Spatrick "platform process [attach|launch|list] ...") {
1676061da546Spatrick LoadSubCommand(
1677061da546Spatrick "attach",
1678061da546Spatrick CommandObjectSP(new CommandObjectPlatformProcessAttach(interpreter)));
1679061da546Spatrick LoadSubCommand(
1680061da546Spatrick "launch",
1681061da546Spatrick CommandObjectSP(new CommandObjectPlatformProcessLaunch(interpreter)));
1682061da546Spatrick LoadSubCommand("info", CommandObjectSP(new CommandObjectPlatformProcessInfo(
1683061da546Spatrick interpreter)));
1684061da546Spatrick LoadSubCommand("list", CommandObjectSP(new CommandObjectPlatformProcessList(
1685061da546Spatrick interpreter)));
1686061da546Spatrick }
1687061da546Spatrick
1688061da546Spatrick ~CommandObjectPlatformProcess() override = default;
1689061da546Spatrick
1690061da546Spatrick private:
1691061da546Spatrick // For CommandObjectPlatform only
1692dda28197Spatrick CommandObjectPlatformProcess(const CommandObjectPlatformProcess &) = delete;
1693dda28197Spatrick const CommandObjectPlatformProcess &
1694dda28197Spatrick operator=(const CommandObjectPlatformProcess &) = delete;
1695061da546Spatrick };
1696061da546Spatrick
1697061da546Spatrick // "platform shell"
1698061da546Spatrick #define LLDB_OPTIONS_platform_shell
1699061da546Spatrick #include "CommandOptions.inc"
1700061da546Spatrick
1701061da546Spatrick class CommandObjectPlatformShell : public CommandObjectRaw {
1702061da546Spatrick public:
1703061da546Spatrick class CommandOptions : public Options {
1704061da546Spatrick public:
1705*f6aab3d8Srobert CommandOptions() = default;
1706061da546Spatrick
1707061da546Spatrick ~CommandOptions() override = default;
1708061da546Spatrick
GetDefinitions()1709061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1710*f6aab3d8Srobert return llvm::ArrayRef(g_platform_shell_options);
1711061da546Spatrick }
1712061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1713061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1714061da546Spatrick ExecutionContext *execution_context) override {
1715061da546Spatrick Status error;
1716061da546Spatrick
1717061da546Spatrick const char short_option = (char)GetDefinitions()[option_idx].short_option;
1718061da546Spatrick
1719061da546Spatrick switch (short_option) {
1720dda28197Spatrick case 'h':
1721dda28197Spatrick m_use_host_platform = true;
1722dda28197Spatrick break;
1723061da546Spatrick case 't':
1724061da546Spatrick uint32_t timeout_sec;
1725061da546Spatrick if (option_arg.getAsInteger(10, timeout_sec))
1726061da546Spatrick error.SetErrorStringWithFormat(
1727061da546Spatrick "could not convert \"%s\" to a numeric value.",
1728061da546Spatrick option_arg.str().c_str());
1729061da546Spatrick else
1730dda28197Spatrick m_timeout = std::chrono::seconds(timeout_sec);
1731061da546Spatrick break;
1732be691f3bSpatrick case 's': {
1733be691f3bSpatrick if (option_arg.empty()) {
1734be691f3bSpatrick error.SetErrorStringWithFormat(
1735be691f3bSpatrick "missing shell interpreter path for option -i|--interpreter.");
1736be691f3bSpatrick return error;
1737be691f3bSpatrick }
1738be691f3bSpatrick
1739be691f3bSpatrick m_shell_interpreter = option_arg.str();
1740be691f3bSpatrick break;
1741be691f3bSpatrick }
1742061da546Spatrick default:
1743061da546Spatrick llvm_unreachable("Unimplemented option");
1744061da546Spatrick }
1745061da546Spatrick
1746061da546Spatrick return error;
1747061da546Spatrick }
1748061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)1749dda28197Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
1750dda28197Spatrick m_timeout.reset();
1751dda28197Spatrick m_use_host_platform = false;
1752be691f3bSpatrick m_shell_interpreter.clear();
1753dda28197Spatrick }
1754061da546Spatrick
1755dda28197Spatrick Timeout<std::micro> m_timeout = std::chrono::seconds(10);
1756dda28197Spatrick bool m_use_host_platform;
1757be691f3bSpatrick std::string m_shell_interpreter;
1758061da546Spatrick };
1759061da546Spatrick
CommandObjectPlatformShell(CommandInterpreter & interpreter)1760061da546Spatrick CommandObjectPlatformShell(CommandInterpreter &interpreter)
1761061da546Spatrick : CommandObjectRaw(interpreter, "platform shell",
1762061da546Spatrick "Run a shell command on the current platform.",
1763*f6aab3d8Srobert "platform shell <shell-command>", 0) {
1764*f6aab3d8Srobert CommandArgumentData thread_arg{eArgTypeNone, eArgRepeatStar};
1765*f6aab3d8Srobert m_arguments.push_back({thread_arg});
1766*f6aab3d8Srobert }
1767061da546Spatrick
1768061da546Spatrick ~CommandObjectPlatformShell() override = default;
1769061da546Spatrick
GetOptions()1770061da546Spatrick Options *GetOptions() override { return &m_options; }
1771061da546Spatrick
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)1772061da546Spatrick bool DoExecute(llvm::StringRef raw_command_line,
1773061da546Spatrick CommandReturnObject &result) override {
1774061da546Spatrick ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
1775061da546Spatrick m_options.NotifyOptionParsingStarting(&exe_ctx);
1776061da546Spatrick
1777061da546Spatrick // Print out an usage syntax on an empty command line.
1778061da546Spatrick if (raw_command_line.empty()) {
1779061da546Spatrick result.GetOutputStream().Printf("%s\n", this->GetSyntax().str().c_str());
1780061da546Spatrick return true;
1781061da546Spatrick }
1782061da546Spatrick
1783dda28197Spatrick const bool is_alias = !raw_command_line.contains("platform");
1784061da546Spatrick OptionsWithRaw args(raw_command_line);
1785061da546Spatrick
1786061da546Spatrick if (args.HasArgs())
1787061da546Spatrick if (!ParseOptions(args.GetArgs(), result))
1788061da546Spatrick return false;
1789061da546Spatrick
1790dda28197Spatrick if (args.GetRawPart().empty()) {
1791dda28197Spatrick result.GetOutputStream().Printf("%s <shell-command>\n",
1792dda28197Spatrick is_alias ? "shell" : "platform shell");
1793dda28197Spatrick return false;
1794dda28197Spatrick }
1795dda28197Spatrick
1796be691f3bSpatrick llvm::StringRef cmd = args.GetRawPart();
1797be691f3bSpatrick
1798061da546Spatrick PlatformSP platform_sp(
1799dda28197Spatrick m_options.m_use_host_platform
1800dda28197Spatrick ? Platform::GetHostPlatform()
1801dda28197Spatrick : GetDebugger().GetPlatformList().GetSelectedPlatform());
1802061da546Spatrick Status error;
1803061da546Spatrick if (platform_sp) {
1804061da546Spatrick FileSpec working_dir{};
1805061da546Spatrick std::string output;
1806061da546Spatrick int status = -1;
1807061da546Spatrick int signo = -1;
1808be691f3bSpatrick error = (platform_sp->RunShellCommand(m_options.m_shell_interpreter, cmd,
1809be691f3bSpatrick working_dir, &status, &signo,
1810dda28197Spatrick &output, m_options.m_timeout));
1811061da546Spatrick if (!output.empty())
1812061da546Spatrick result.GetOutputStream().PutCString(output);
1813061da546Spatrick if (status > 0) {
1814061da546Spatrick if (signo > 0) {
1815061da546Spatrick const char *signo_cstr = Host::GetSignalAsCString(signo);
1816061da546Spatrick if (signo_cstr)
1817061da546Spatrick result.GetOutputStream().Printf(
1818061da546Spatrick "error: command returned with status %i and signal %s\n",
1819061da546Spatrick status, signo_cstr);
1820061da546Spatrick else
1821061da546Spatrick result.GetOutputStream().Printf(
1822061da546Spatrick "error: command returned with status %i and signal %i\n",
1823061da546Spatrick status, signo);
1824061da546Spatrick } else
1825061da546Spatrick result.GetOutputStream().Printf(
1826061da546Spatrick "error: command returned with status %i\n", status);
1827061da546Spatrick }
1828061da546Spatrick } else {
1829061da546Spatrick result.GetOutputStream().Printf(
1830061da546Spatrick "error: cannot run remote shell commands without a platform\n");
1831061da546Spatrick error.SetErrorString(
1832061da546Spatrick "error: cannot run remote shell commands without a platform");
1833061da546Spatrick }
1834061da546Spatrick
1835061da546Spatrick if (error.Fail()) {
1836061da546Spatrick result.AppendError(error.AsCString());
1837061da546Spatrick } else {
1838061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1839061da546Spatrick }
1840061da546Spatrick return true;
1841061da546Spatrick }
1842061da546Spatrick
1843061da546Spatrick CommandOptions m_options;
1844061da546Spatrick };
1845061da546Spatrick
1846061da546Spatrick // "platform install" - install a target to a remote end
1847061da546Spatrick class CommandObjectPlatformInstall : public CommandObjectParsed {
1848061da546Spatrick public:
CommandObjectPlatformInstall(CommandInterpreter & interpreter)1849061da546Spatrick CommandObjectPlatformInstall(CommandInterpreter &interpreter)
1850061da546Spatrick : CommandObjectParsed(
1851061da546Spatrick interpreter, "platform target-install",
1852061da546Spatrick "Install a target (bundle or executable file) to the remote end.",
1853*f6aab3d8Srobert "platform target-install <local-thing> <remote-sandbox>", 0) {
1854*f6aab3d8Srobert CommandArgumentData local_arg{eArgTypePath, eArgRepeatPlain};
1855*f6aab3d8Srobert CommandArgumentData remote_arg{eArgTypePath, eArgRepeatPlain};
1856*f6aab3d8Srobert m_arguments.push_back({local_arg});
1857*f6aab3d8Srobert m_arguments.push_back({remote_arg});
1858*f6aab3d8Srobert }
1859061da546Spatrick
1860061da546Spatrick ~CommandObjectPlatformInstall() override = default;
1861061da546Spatrick
1862be691f3bSpatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1863be691f3bSpatrick HandleArgumentCompletion(CompletionRequest &request,
1864be691f3bSpatrick OptionElementVector &opt_element_vector) override {
1865be691f3bSpatrick if (request.GetCursorIndex())
1866be691f3bSpatrick return;
1867be691f3bSpatrick CommandCompletions::InvokeCommonCompletionCallbacks(
1868be691f3bSpatrick GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
1869be691f3bSpatrick request, nullptr);
1870be691f3bSpatrick }
1871be691f3bSpatrick
DoExecute(Args & args,CommandReturnObject & result)1872061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
1873061da546Spatrick if (args.GetArgumentCount() != 2) {
1874061da546Spatrick result.AppendError("platform target-install takes two arguments");
1875061da546Spatrick return false;
1876061da546Spatrick }
1877061da546Spatrick // TODO: move the bulk of this code over to the platform itself
1878061da546Spatrick FileSpec src(args.GetArgumentAtIndex(0));
1879061da546Spatrick FileSystem::Instance().Resolve(src);
1880061da546Spatrick FileSpec dst(args.GetArgumentAtIndex(1));
1881061da546Spatrick if (!FileSystem::Instance().Exists(src)) {
1882061da546Spatrick result.AppendError("source location does not exist or is not accessible");
1883061da546Spatrick return false;
1884061da546Spatrick }
1885061da546Spatrick PlatformSP platform_sp(
1886061da546Spatrick GetDebugger().GetPlatformList().GetSelectedPlatform());
1887061da546Spatrick if (!platform_sp) {
1888061da546Spatrick result.AppendError("no platform currently selected");
1889061da546Spatrick return false;
1890061da546Spatrick }
1891061da546Spatrick
1892061da546Spatrick Status error = platform_sp->Install(src, dst);
1893061da546Spatrick if (error.Success()) {
1894061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1895061da546Spatrick } else {
1896061da546Spatrick result.AppendErrorWithFormat("install failed: %s", error.AsCString());
1897061da546Spatrick }
1898061da546Spatrick return result.Succeeded();
1899061da546Spatrick }
1900061da546Spatrick };
1901061da546Spatrick
CommandObjectPlatform(CommandInterpreter & interpreter)1902061da546Spatrick CommandObjectPlatform::CommandObjectPlatform(CommandInterpreter &interpreter)
1903061da546Spatrick : CommandObjectMultiword(
1904061da546Spatrick interpreter, "platform", "Commands to manage and create platforms.",
1905061da546Spatrick "platform [connect|disconnect|info|list|status|select] ...") {
1906061da546Spatrick LoadSubCommand("select",
1907061da546Spatrick CommandObjectSP(new CommandObjectPlatformSelect(interpreter)));
1908061da546Spatrick LoadSubCommand("list",
1909061da546Spatrick CommandObjectSP(new CommandObjectPlatformList(interpreter)));
1910061da546Spatrick LoadSubCommand("status",
1911061da546Spatrick CommandObjectSP(new CommandObjectPlatformStatus(interpreter)));
1912061da546Spatrick LoadSubCommand("connect", CommandObjectSP(
1913061da546Spatrick new CommandObjectPlatformConnect(interpreter)));
1914061da546Spatrick LoadSubCommand(
1915061da546Spatrick "disconnect",
1916061da546Spatrick CommandObjectSP(new CommandObjectPlatformDisconnect(interpreter)));
1917061da546Spatrick LoadSubCommand("settings", CommandObjectSP(new CommandObjectPlatformSettings(
1918061da546Spatrick interpreter)));
1919061da546Spatrick LoadSubCommand("mkdir",
1920061da546Spatrick CommandObjectSP(new CommandObjectPlatformMkDir(interpreter)));
1921061da546Spatrick LoadSubCommand("file",
1922061da546Spatrick CommandObjectSP(new CommandObjectPlatformFile(interpreter)));
1923*f6aab3d8Srobert LoadSubCommand("file-exists",
1924*f6aab3d8Srobert CommandObjectSP(new CommandObjectPlatformFileExists(interpreter)));
1925061da546Spatrick LoadSubCommand("get-file", CommandObjectSP(new CommandObjectPlatformGetFile(
1926061da546Spatrick interpreter)));
1927*f6aab3d8Srobert LoadSubCommand("get-permissions",
1928*f6aab3d8Srobert CommandObjectSP(new CommandObjectPlatformGetPermissions(interpreter)));
1929061da546Spatrick LoadSubCommand("get-size", CommandObjectSP(new CommandObjectPlatformGetSize(
1930061da546Spatrick interpreter)));
1931061da546Spatrick LoadSubCommand("put-file", CommandObjectSP(new CommandObjectPlatformPutFile(
1932061da546Spatrick interpreter)));
1933061da546Spatrick LoadSubCommand("process", CommandObjectSP(
1934061da546Spatrick new CommandObjectPlatformProcess(interpreter)));
1935061da546Spatrick LoadSubCommand("shell",
1936061da546Spatrick CommandObjectSP(new CommandObjectPlatformShell(interpreter)));
1937061da546Spatrick LoadSubCommand(
1938061da546Spatrick "target-install",
1939061da546Spatrick CommandObjectSP(new CommandObjectPlatformInstall(interpreter)));
1940061da546Spatrick }
1941061da546Spatrick
1942061da546Spatrick CommandObjectPlatform::~CommandObjectPlatform() = default;
1943