xref: /openbsd-src/gnu/llvm/lldb/source/Commands/CommandObjectPlatform.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
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