1254721Semaste//===-- CommandObjectPlatform.cpp -------------------------------*- C++ -*-===//
2254721Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6254721Semaste//
7254721Semaste//===----------------------------------------------------------------------===//
8254721Semaste
9309124Sdim#include "CommandObjectPlatform.h"
10254721Semaste#include "lldb/Core/Debugger.h"
11254721Semaste#include "lldb/Core/Module.h"
12254721Semaste#include "lldb/Core/PluginManager.h"
13321369Sdim#include "lldb/Host/OptionParser.h"
14288943Sdim#include "lldb/Host/StringConvert.h"
15254721Semaste#include "lldb/Interpreter/CommandInterpreter.h"
16276479Sdim#include "lldb/Interpreter/CommandOptionValidators.h"
17254721Semaste#include "lldb/Interpreter/CommandReturnObject.h"
18258884Semaste#include "lldb/Interpreter/OptionGroupFile.h"
19254721Semaste#include "lldb/Interpreter/OptionGroupPlatform.h"
20254721Semaste#include "lldb/Target/ExecutionContext.h"
21254721Semaste#include "lldb/Target/Platform.h"
22254721Semaste#include "lldb/Target/Process.h"
23341825Sdim#include "lldb/Utility/Args.h"
24254721Semaste
25314564Sdim#include "llvm/ADT/SmallString.h"
26314564Sdim
27254721Semasteusing namespace lldb;
28254721Semasteusing namespace lldb_private;
29254721Semaste
30314564Sdimstatic mode_t ParsePermissionString(const char *) = delete;
31254721Semaste
32314564Sdimstatic mode_t ParsePermissionString(llvm::StringRef permissions) {
33314564Sdim  if (permissions.size() != 9)
34314564Sdim    return (mode_t)(-1);
35314564Sdim  bool user_r, user_w, user_x, group_r, group_w, group_x, world_r, world_w,
36314564Sdim      world_x;
37258054Semaste
38314564Sdim  user_r = (permissions[0] == 'r');
39314564Sdim  user_w = (permissions[1] == 'w');
40314564Sdim  user_x = (permissions[2] == 'x');
41258054Semaste
42314564Sdim  group_r = (permissions[3] == 'r');
43314564Sdim  group_w = (permissions[4] == 'w');
44314564Sdim  group_x = (permissions[5] == 'x');
45314564Sdim
46314564Sdim  world_r = (permissions[6] == 'r');
47314564Sdim  world_w = (permissions[7] == 'w');
48314564Sdim  world_x = (permissions[8] == 'x');
49314564Sdim
50314564Sdim  mode_t user, group, world;
51314564Sdim  user = (user_r ? 4 : 0) | (user_w ? 2 : 0) | (user_x ? 1 : 0);
52314564Sdim  group = (group_r ? 4 : 0) | (group_w ? 2 : 0) | (group_x ? 1 : 0);
53314564Sdim  world = (world_r ? 4 : 0) | (world_w ? 2 : 0) | (world_x ? 1 : 0);
54314564Sdim
55314564Sdim  return user | group | world;
56314564Sdim}
57314564Sdim
58360784Sdim#define LLDB_OPTIONS_permissions
59360784Sdim#include "CommandOptions.inc"
60258054Semaste
61314564Sdimclass OptionPermissions : public OptionGroup {
62258054Semastepublic:
63314564Sdim  OptionPermissions() {}
64309124Sdim
65314564Sdim  ~OptionPermissions() override = default;
66309124Sdim
67321369Sdim  lldb_private::Status
68314564Sdim  SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
69314564Sdim                 ExecutionContext *execution_context) override {
70321369Sdim    Status error;
71314564Sdim    char short_option = (char)GetDefinitions()[option_idx].short_option;
72314564Sdim    switch (short_option) {
73314564Sdim    case 'v': {
74314564Sdim      if (option_arg.getAsInteger(8, m_permissions)) {
75314564Sdim        m_permissions = 0777;
76314564Sdim        error.SetErrorStringWithFormat("invalid value for permissions: %s",
77314564Sdim                                       option_arg.str().c_str());
78314564Sdim      }
79314564Sdim
80314564Sdim    } break;
81314564Sdim    case 's': {
82314564Sdim      mode_t perms = ParsePermissionString(option_arg);
83314564Sdim      if (perms == (mode_t)-1)
84314564Sdim        error.SetErrorStringWithFormat("invalid value for permissions: %s",
85314564Sdim                                       option_arg.str().c_str());
86314564Sdim      else
87314564Sdim        m_permissions = perms;
88314564Sdim    } break;
89314564Sdim    case 'r':
90314564Sdim      m_permissions |= lldb::eFilePermissionsUserRead;
91314564Sdim      break;
92314564Sdim    case 'w':
93314564Sdim      m_permissions |= lldb::eFilePermissionsUserWrite;
94314564Sdim      break;
95314564Sdim    case 'x':
96314564Sdim      m_permissions |= lldb::eFilePermissionsUserExecute;
97314564Sdim      break;
98314564Sdim    case 'R':
99314564Sdim      m_permissions |= lldb::eFilePermissionsGroupRead;
100314564Sdim      break;
101314564Sdim    case 'W':
102314564Sdim      m_permissions |= lldb::eFilePermissionsGroupWrite;
103314564Sdim      break;
104314564Sdim    case 'X':
105314564Sdim      m_permissions |= lldb::eFilePermissionsGroupExecute;
106314564Sdim      break;
107314564Sdim    case 'd':
108314564Sdim      m_permissions |= lldb::eFilePermissionsWorldRead;
109314564Sdim      break;
110314564Sdim    case 't':
111314564Sdim      m_permissions |= lldb::eFilePermissionsWorldWrite;
112314564Sdim      break;
113314564Sdim    case 'e':
114314564Sdim      m_permissions |= lldb::eFilePermissionsWorldExecute;
115314564Sdim      break;
116314564Sdim    default:
117360784Sdim      llvm_unreachable("Unimplemented option");
118258054Semaste    }
119309124Sdim
120314564Sdim    return error;
121314564Sdim  }
122314564Sdim
123314564Sdim  void OptionParsingStarting(ExecutionContext *execution_context) override {
124314564Sdim    m_permissions = 0;
125314564Sdim  }
126314564Sdim
127314564Sdim  llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
128314564Sdim    return llvm::makeArrayRef(g_permissions_options);
129314564Sdim  }
130314564Sdim
131314564Sdim  // Instance variables to hold the values for command options.
132314564Sdim
133314564Sdim  uint32_t m_permissions;
134314564Sdim
135258054Semasteprivate:
136314564Sdim  DISALLOW_COPY_AND_ASSIGN(OptionPermissions);
137258054Semaste};
138258054Semaste
139254721Semaste// "platform select <platform-name>"
140314564Sdimclass CommandObjectPlatformSelect : public CommandObjectParsed {
141254721Semastepublic:
142314564Sdim  CommandObjectPlatformSelect(CommandInterpreter &interpreter)
143314564Sdim      : CommandObjectParsed(interpreter, "platform select",
144314564Sdim                            "Create a platform if needed and select it as the "
145314564Sdim                            "current platform.",
146314564Sdim                            "platform select <platform-name>", 0),
147314564Sdim        m_option_group(),
148314564Sdim        m_platform_options(
149314564Sdim            false) // Don't include the "--platform" option by passing false
150314564Sdim  {
151314564Sdim    m_option_group.Append(&m_platform_options, LLDB_OPT_SET_ALL, 1);
152314564Sdim    m_option_group.Finalize();
153314564Sdim  }
154254721Semaste
155314564Sdim  ~CommandObjectPlatformSelect() override = default;
156254721Semaste
157360784Sdim  void HandleCompletion(CompletionRequest &request) override {
158341825Sdim    CommandCompletions::PlatformPluginNames(GetCommandInterpreter(), request,
159341825Sdim                                            nullptr);
160314564Sdim  }
161254721Semaste
162314564Sdim  Options *GetOptions() override { return &m_option_group; }
163314564Sdim
164254721Semasteprotected:
165314564Sdim  bool DoExecute(Args &args, CommandReturnObject &result) override {
166314564Sdim    if (args.GetArgumentCount() == 1) {
167314564Sdim      const char *platform_name = args.GetArgumentAtIndex(0);
168314564Sdim      if (platform_name && platform_name[0]) {
169314564Sdim        const bool select = true;
170314564Sdim        m_platform_options.SetPlatformName(platform_name);
171321369Sdim        Status error;
172314564Sdim        ArchSpec platform_arch;
173314564Sdim        PlatformSP platform_sp(m_platform_options.CreatePlatformWithOptions(
174314564Sdim            m_interpreter, ArchSpec(), select, error, platform_arch));
175314564Sdim        if (platform_sp) {
176353358Sdim          GetDebugger().GetPlatformList().SetSelectedPlatform(platform_sp);
177288943Sdim
178314564Sdim          platform_sp->GetStatus(result.GetOutputStream());
179314564Sdim          result.SetStatus(eReturnStatusSuccessFinishResult);
180314564Sdim        } else {
181314564Sdim          result.AppendError(error.AsCString());
182314564Sdim          result.SetStatus(eReturnStatusFailed);
183254721Semaste        }
184314564Sdim      } else {
185314564Sdim        result.AppendError("invalid platform name");
186314564Sdim        result.SetStatus(eReturnStatusFailed);
187314564Sdim      }
188314564Sdim    } else {
189314564Sdim      result.AppendError(
190314564Sdim          "platform create takes a platform name as an argument\n");
191314564Sdim      result.SetStatus(eReturnStatusFailed);
192254721Semaste    }
193314564Sdim    return result.Succeeded();
194314564Sdim  }
195254721Semaste
196314564Sdim  OptionGroupOptions m_option_group;
197314564Sdim  OptionGroupPlatform m_platform_options;
198254721Semaste};
199254721Semaste
200254721Semaste// "platform list"
201314564Sdimclass CommandObjectPlatformList : public CommandObjectParsed {
202254721Semastepublic:
203314564Sdim  CommandObjectPlatformList(CommandInterpreter &interpreter)
204314564Sdim      : CommandObjectParsed(interpreter, "platform list",
205314564Sdim                            "List all platforms that are available.", nullptr,
206314564Sdim                            0) {}
207254721Semaste
208314564Sdim  ~CommandObjectPlatformList() override = default;
209254721Semaste
210254721Semasteprotected:
211314564Sdim  bool DoExecute(Args &args, CommandReturnObject &result) override {
212314564Sdim    Stream &ostrm = result.GetOutputStream();
213314564Sdim    ostrm.Printf("Available platforms:\n");
214254721Semaste
215314564Sdim    PlatformSP host_platform_sp(Platform::GetHostPlatform());
216314564Sdim    ostrm.Printf("%s: %s\n", host_platform_sp->GetPluginName().GetCString(),
217314564Sdim                 host_platform_sp->GetDescription());
218314564Sdim
219314564Sdim    uint32_t idx;
220353358Sdim    for (idx = 0; true; ++idx) {
221314564Sdim      const char *plugin_name =
222314564Sdim          PluginManager::GetPlatformPluginNameAtIndex(idx);
223314564Sdim      if (plugin_name == nullptr)
224314564Sdim        break;
225314564Sdim      const char *plugin_desc =
226314564Sdim          PluginManager::GetPlatformPluginDescriptionAtIndex(idx);
227314564Sdim      if (plugin_desc == nullptr)
228314564Sdim        break;
229314564Sdim      ostrm.Printf("%s: %s\n", plugin_name, plugin_desc);
230254721Semaste    }
231314564Sdim
232314564Sdim    if (idx == 0) {
233314564Sdim      result.AppendError("no platforms are available\n");
234314564Sdim      result.SetStatus(eReturnStatusFailed);
235314564Sdim    } else
236314564Sdim      result.SetStatus(eReturnStatusSuccessFinishResult);
237314564Sdim    return result.Succeeded();
238314564Sdim  }
239254721Semaste};
240254721Semaste
241254721Semaste// "platform status"
242314564Sdimclass CommandObjectPlatformStatus : public CommandObjectParsed {
243254721Semastepublic:
244314564Sdim  CommandObjectPlatformStatus(CommandInterpreter &interpreter)
245314564Sdim      : CommandObjectParsed(interpreter, "platform status",
246314564Sdim                            "Display status for the current platform.", nullptr,
247314564Sdim                            0) {}
248254721Semaste
249314564Sdim  ~CommandObjectPlatformStatus() override = default;
250254721Semaste
251254721Semasteprotected:
252314564Sdim  bool DoExecute(Args &args, CommandReturnObject &result) override {
253314564Sdim    Stream &ostrm = result.GetOutputStream();
254314564Sdim
255353358Sdim    Target *target = GetDebugger().GetSelectedTarget().get();
256314564Sdim    PlatformSP platform_sp;
257314564Sdim    if (target) {
258314564Sdim      platform_sp = target->GetPlatform();
259254721Semaste    }
260314564Sdim    if (!platform_sp) {
261353358Sdim      platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();
262314564Sdim    }
263314564Sdim    if (platform_sp) {
264314564Sdim      platform_sp->GetStatus(ostrm);
265314564Sdim      result.SetStatus(eReturnStatusSuccessFinishResult);
266314564Sdim    } else {
267327952Sdim      result.AppendError("no platform is currently selected\n");
268314564Sdim      result.SetStatus(eReturnStatusFailed);
269314564Sdim    }
270314564Sdim    return result.Succeeded();
271314564Sdim  }
272254721Semaste};
273254721Semaste
274254721Semaste// "platform connect <connect-url>"
275314564Sdimclass CommandObjectPlatformConnect : public CommandObjectParsed {
276254721Semastepublic:
277314564Sdim  CommandObjectPlatformConnect(CommandInterpreter &interpreter)
278314564Sdim      : CommandObjectParsed(
279314564Sdim            interpreter, "platform connect",
280314564Sdim            "Select the current platform by providing a connection URL.",
281314564Sdim            "platform connect <connect-url>", 0) {}
282254721Semaste
283314564Sdim  ~CommandObjectPlatformConnect() override = default;
284254721Semaste
285254721Semasteprotected:
286314564Sdim  bool DoExecute(Args &args, CommandReturnObject &result) override {
287314564Sdim    Stream &ostrm = result.GetOutputStream();
288296417Sdim
289314564Sdim    PlatformSP platform_sp(
290353358Sdim        GetDebugger().GetPlatformList().GetSelectedPlatform());
291314564Sdim    if (platform_sp) {
292321369Sdim      Status error(platform_sp->ConnectRemote(args));
293314564Sdim      if (error.Success()) {
294314564Sdim        platform_sp->GetStatus(ostrm);
295314564Sdim        result.SetStatus(eReturnStatusSuccessFinishResult);
296314564Sdim
297353358Sdim        platform_sp->ConnectToWaitingProcesses(GetDebugger(), error);
298314564Sdim        if (error.Fail()) {
299314564Sdim          result.AppendError(error.AsCString());
300314564Sdim          result.SetStatus(eReturnStatusFailed);
301254721Semaste        }
302314564Sdim      } else {
303314564Sdim        result.AppendErrorWithFormat("%s\n", error.AsCString());
304314564Sdim        result.SetStatus(eReturnStatusFailed);
305314564Sdim      }
306314564Sdim    } else {
307314564Sdim      result.AppendError("no platform is currently selected\n");
308314564Sdim      result.SetStatus(eReturnStatusFailed);
309254721Semaste    }
310314564Sdim    return result.Succeeded();
311314564Sdim  }
312314564Sdim
313314564Sdim  Options *GetOptions() override {
314314564Sdim    PlatformSP platform_sp(
315353358Sdim        GetDebugger().GetPlatformList().GetSelectedPlatform());
316314564Sdim    OptionGroupOptions *m_platform_options = nullptr;
317314564Sdim    if (platform_sp) {
318314564Sdim      m_platform_options = platform_sp->GetConnectionOptions(m_interpreter);
319314564Sdim      if (m_platform_options != nullptr && !m_platform_options->m_did_finalize)
320314564Sdim        m_platform_options->Finalize();
321258054Semaste    }
322314564Sdim    return m_platform_options;
323314564Sdim  }
324254721Semaste};
325254721Semaste
326254721Semaste// "platform disconnect"
327314564Sdimclass CommandObjectPlatformDisconnect : public CommandObjectParsed {
328254721Semastepublic:
329314564Sdim  CommandObjectPlatformDisconnect(CommandInterpreter &interpreter)
330314564Sdim      : CommandObjectParsed(interpreter, "platform disconnect",
331314564Sdim                            "Disconnect from the current platform.",
332314564Sdim                            "platform disconnect", 0) {}
333254721Semaste
334314564Sdim  ~CommandObjectPlatformDisconnect() override = default;
335254721Semaste
336254721Semasteprotected:
337314564Sdim  bool DoExecute(Args &args, CommandReturnObject &result) override {
338314564Sdim    PlatformSP platform_sp(
339353358Sdim        GetDebugger().GetPlatformList().GetSelectedPlatform());
340314564Sdim    if (platform_sp) {
341314564Sdim      if (args.GetArgumentCount() == 0) {
342321369Sdim        Status error;
343254721Semaste
344314564Sdim        if (platform_sp->IsConnected()) {
345341825Sdim          // Cache the instance name if there is one since we are about to
346341825Sdim          // disconnect and the name might go with it.
347314564Sdim          const char *hostname_cstr = platform_sp->GetHostname();
348314564Sdim          std::string hostname;
349314564Sdim          if (hostname_cstr)
350314564Sdim            hostname.assign(hostname_cstr);
351314564Sdim
352314564Sdim          error = platform_sp->DisconnectRemote();
353314564Sdim          if (error.Success()) {
354314564Sdim            Stream &ostrm = result.GetOutputStream();
355314564Sdim            if (hostname.empty())
356314564Sdim              ostrm.Printf("Disconnected from \"%s\"\n",
357314564Sdim                           platform_sp->GetPluginName().GetCString());
358254721Semaste            else
359314564Sdim              ostrm.Printf("Disconnected from \"%s\"\n", hostname.c_str());
360314564Sdim            result.SetStatus(eReturnStatusSuccessFinishResult);
361314564Sdim          } else {
362314564Sdim            result.AppendErrorWithFormat("%s", error.AsCString());
363314564Sdim            result.SetStatus(eReturnStatusFailed);
364314564Sdim          }
365314564Sdim        } else {
366314564Sdim          // Not connected...
367314564Sdim          result.AppendErrorWithFormat(
368314564Sdim              "not connected to '%s'",
369314564Sdim              platform_sp->GetPluginName().GetCString());
370314564Sdim          result.SetStatus(eReturnStatusFailed);
371254721Semaste        }
372314564Sdim      } else {
373314564Sdim        // Bad args
374314564Sdim        result.AppendError(
375314564Sdim            "\"platform disconnect\" doesn't take any arguments");
376314564Sdim        result.SetStatus(eReturnStatusFailed);
377314564Sdim      }
378314564Sdim    } else {
379314564Sdim      result.AppendError("no platform is currently selected");
380314564Sdim      result.SetStatus(eReturnStatusFailed);
381254721Semaste    }
382314564Sdim    return result.Succeeded();
383314564Sdim  }
384254721Semaste};
385258054Semaste
386258884Semaste// "platform settings"
387314564Sdimclass CommandObjectPlatformSettings : public CommandObjectParsed {
388258884Semastepublic:
389314564Sdim  CommandObjectPlatformSettings(CommandInterpreter &interpreter)
390314564Sdim      : CommandObjectParsed(interpreter, "platform settings",
391314564Sdim                            "Set settings for the current target's platform, "
392314564Sdim                            "or for a platform by name.",
393314564Sdim                            "platform settings", 0),
394314564Sdim        m_options(),
395314564Sdim        m_option_working_dir(LLDB_OPT_SET_1, false, "working-dir", 'w', 0,
396314564Sdim                             eArgTypePath,
397314564Sdim                             "The working directory for the platform.") {
398314564Sdim    m_options.Append(&m_option_working_dir, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
399314564Sdim  }
400309124Sdim
401314564Sdim  ~CommandObjectPlatformSettings() override = default;
402309124Sdim
403258884Semasteprotected:
404314564Sdim  bool DoExecute(Args &args, CommandReturnObject &result) override {
405314564Sdim    PlatformSP platform_sp(
406353358Sdim        GetDebugger().GetPlatformList().GetSelectedPlatform());
407314564Sdim    if (platform_sp) {
408314564Sdim      if (m_option_working_dir.GetOptionValue().OptionWasSet())
409314564Sdim        platform_sp->SetWorkingDirectory(
410314564Sdim            m_option_working_dir.GetOptionValue().GetCurrentValue());
411314564Sdim    } else {
412314564Sdim      result.AppendError("no platform is currently selected");
413314564Sdim      result.SetStatus(eReturnStatusFailed);
414258884Semaste    }
415314564Sdim    return result.Succeeded();
416314564Sdim  }
417309124Sdim
418314564Sdim  Options *GetOptions() override {
419314564Sdim    if (!m_options.DidFinalize())
420314564Sdim      m_options.Finalize();
421314564Sdim    return &m_options;
422314564Sdim  }
423314564Sdim
424258884Semasteprotected:
425314564Sdim  OptionGroupOptions m_options;
426314564Sdim  OptionGroupFile m_option_working_dir;
427258884Semaste};
428258884Semaste
429258054Semaste// "platform mkdir"
430314564Sdimclass CommandObjectPlatformMkDir : public CommandObjectParsed {
431258054Semastepublic:
432314564Sdim  CommandObjectPlatformMkDir(CommandInterpreter &interpreter)
433314564Sdim      : CommandObjectParsed(interpreter, "platform mkdir",
434314564Sdim                            "Make a new directory on the remote end.", nullptr,
435309124Sdim                            0),
436314564Sdim        m_options() {}
437309124Sdim
438314564Sdim  ~CommandObjectPlatformMkDir() override = default;
439309124Sdim
440314564Sdim  bool DoExecute(Args &args, CommandReturnObject &result) override {
441314564Sdim    PlatformSP platform_sp(
442353358Sdim        GetDebugger().GetPlatformList().GetSelectedPlatform());
443314564Sdim    if (platform_sp) {
444314564Sdim      std::string cmd_line;
445314564Sdim      args.GetCommandString(cmd_line);
446314564Sdim      uint32_t mode;
447314564Sdim      const OptionPermissions *options_permissions =
448314564Sdim          (const OptionPermissions *)m_options.GetGroupWithOption('r');
449314564Sdim      if (options_permissions)
450314564Sdim        mode = options_permissions->m_permissions;
451314564Sdim      else
452314564Sdim        mode = lldb::eFilePermissionsUserRWX | lldb::eFilePermissionsGroupRWX |
453314564Sdim               lldb::eFilePermissionsWorldRX;
454344779Sdim      Status error = platform_sp->MakeDirectory(FileSpec(cmd_line), mode);
455314564Sdim      if (error.Success()) {
456314564Sdim        result.SetStatus(eReturnStatusSuccessFinishResult);
457314564Sdim      } else {
458314564Sdim        result.AppendError(error.AsCString());
459314564Sdim        result.SetStatus(eReturnStatusFailed);
460314564Sdim      }
461314564Sdim    } else {
462314564Sdim      result.AppendError("no platform currently selected\n");
463314564Sdim      result.SetStatus(eReturnStatusFailed);
464258054Semaste    }
465314564Sdim    return result.Succeeded();
466314564Sdim  }
467314564Sdim
468314564Sdim  Options *GetOptions() override {
469314564Sdim    if (!m_options.DidFinalize()) {
470314564Sdim      m_options.Append(new OptionPermissions());
471314564Sdim      m_options.Finalize();
472258054Semaste    }
473314564Sdim    return &m_options;
474314564Sdim  }
475309124Sdim
476314564Sdim  OptionGroupOptions m_options;
477258054Semaste};
478258054Semaste
479258054Semaste// "platform fopen"
480314564Sdimclass CommandObjectPlatformFOpen : public CommandObjectParsed {
481258054Semastepublic:
482314564Sdim  CommandObjectPlatformFOpen(CommandInterpreter &interpreter)
483314564Sdim      : CommandObjectParsed(interpreter, "platform file open",
484314564Sdim                            "Open a file on the remote end.", nullptr, 0),
485314564Sdim        m_options() {}
486309124Sdim
487314564Sdim  ~CommandObjectPlatformFOpen() override = default;
488309124Sdim
489314564Sdim  bool DoExecute(Args &args, CommandReturnObject &result) override {
490314564Sdim    PlatformSP platform_sp(
491353358Sdim        GetDebugger().GetPlatformList().GetSelectedPlatform());
492314564Sdim    if (platform_sp) {
493321369Sdim      Status error;
494314564Sdim      std::string cmd_line;
495314564Sdim      args.GetCommandString(cmd_line);
496314564Sdim      mode_t perms;
497314564Sdim      const OptionPermissions *options_permissions =
498314564Sdim          (const OptionPermissions *)m_options.GetGroupWithOption('r');
499314564Sdim      if (options_permissions)
500314564Sdim        perms = options_permissions->m_permissions;
501314564Sdim      else
502314564Sdim        perms = lldb::eFilePermissionsUserRW | lldb::eFilePermissionsGroupRW |
503314564Sdim                lldb::eFilePermissionsWorldRead;
504314564Sdim      lldb::user_id_t fd = platform_sp->OpenFile(
505344779Sdim          FileSpec(cmd_line),
506314564Sdim          File::eOpenOptionRead | File::eOpenOptionWrite |
507314564Sdim              File::eOpenOptionAppend | File::eOpenOptionCanCreate,
508314564Sdim          perms, error);
509314564Sdim      if (error.Success()) {
510314564Sdim        result.AppendMessageWithFormat("File Descriptor = %" PRIu64 "\n", fd);
511314564Sdim        result.SetStatus(eReturnStatusSuccessFinishResult);
512314564Sdim      } else {
513314564Sdim        result.AppendError(error.AsCString());
514314564Sdim        result.SetStatus(eReturnStatusFailed);
515314564Sdim      }
516314564Sdim    } else {
517314564Sdim      result.AppendError("no platform currently selected\n");
518314564Sdim      result.SetStatus(eReturnStatusFailed);
519258054Semaste    }
520314564Sdim    return result.Succeeded();
521314564Sdim  }
522309124Sdim
523314564Sdim  Options *GetOptions() override {
524314564Sdim    if (!m_options.DidFinalize()) {
525314564Sdim      m_options.Append(new OptionPermissions());
526314564Sdim      m_options.Finalize();
527258054Semaste    }
528314564Sdim    return &m_options;
529314564Sdim  }
530309124Sdim
531314564Sdim  OptionGroupOptions m_options;
532258054Semaste};
533258054Semaste
534258054Semaste// "platform fclose"
535314564Sdimclass CommandObjectPlatformFClose : public CommandObjectParsed {
536258054Semastepublic:
537314564Sdim  CommandObjectPlatformFClose(CommandInterpreter &interpreter)
538314564Sdim      : CommandObjectParsed(interpreter, "platform file close",
539314564Sdim                            "Close a file on the remote end.", nullptr, 0) {}
540309124Sdim
541314564Sdim  ~CommandObjectPlatformFClose() override = default;
542309124Sdim
543314564Sdim  bool DoExecute(Args &args, CommandReturnObject &result) override {
544314564Sdim    PlatformSP platform_sp(
545353358Sdim        GetDebugger().GetPlatformList().GetSelectedPlatform());
546314564Sdim    if (platform_sp) {
547314564Sdim      std::string cmd_line;
548314564Sdim      args.GetCommandString(cmd_line);
549314564Sdim      const lldb::user_id_t fd =
550314564Sdim          StringConvert::ToUInt64(cmd_line.c_str(), UINT64_MAX);
551321369Sdim      Status error;
552314564Sdim      bool success = platform_sp->CloseFile(fd, error);
553314564Sdim      if (success) {
554314564Sdim        result.AppendMessageWithFormat("file %" PRIu64 " closed.\n", fd);
555314564Sdim        result.SetStatus(eReturnStatusSuccessFinishResult);
556314564Sdim      } else {
557314564Sdim        result.AppendError(error.AsCString());
558314564Sdim        result.SetStatus(eReturnStatusFailed);
559314564Sdim      }
560314564Sdim    } else {
561314564Sdim      result.AppendError("no platform currently selected\n");
562314564Sdim      result.SetStatus(eReturnStatusFailed);
563258054Semaste    }
564314564Sdim    return result.Succeeded();
565314564Sdim  }
566258054Semaste};
567258054Semaste
568258054Semaste// "platform fread"
569314564Sdim
570360784Sdim#define LLDB_OPTIONS_platform_fread
571360784Sdim#include "CommandOptions.inc"
572314564Sdim
573314564Sdimclass CommandObjectPlatformFRead : public CommandObjectParsed {
574258054Semastepublic:
575314564Sdim  CommandObjectPlatformFRead(CommandInterpreter &interpreter)
576314564Sdim      : CommandObjectParsed(interpreter, "platform file read",
577314564Sdim                            "Read data from a file on the remote end.", nullptr,
578309124Sdim                            0),
579314564Sdim        m_options() {}
580314564Sdim
581314564Sdim  ~CommandObjectPlatformFRead() override = default;
582314564Sdim
583314564Sdim  bool DoExecute(Args &args, CommandReturnObject &result) override {
584314564Sdim    PlatformSP platform_sp(
585353358Sdim        GetDebugger().GetPlatformList().GetSelectedPlatform());
586314564Sdim    if (platform_sp) {
587314564Sdim      std::string cmd_line;
588314564Sdim      args.GetCommandString(cmd_line);
589314564Sdim      const lldb::user_id_t fd =
590314564Sdim          StringConvert::ToUInt64(cmd_line.c_str(), UINT64_MAX);
591314564Sdim      std::string buffer(m_options.m_count, 0);
592321369Sdim      Status error;
593314564Sdim      uint32_t retcode = platform_sp->ReadFile(
594314564Sdim          fd, m_options.m_offset, &buffer[0], m_options.m_count, error);
595314564Sdim      result.AppendMessageWithFormat("Return = %d\n", retcode);
596314564Sdim      result.AppendMessageWithFormat("Data = \"%s\"\n", buffer.c_str());
597314564Sdim      result.SetStatus(eReturnStatusSuccessFinishResult);
598314564Sdim    } else {
599314564Sdim      result.AppendError("no platform currently selected\n");
600314564Sdim      result.SetStatus(eReturnStatusFailed);
601258054Semaste    }
602314564Sdim    return result.Succeeded();
603314564Sdim  }
604309124Sdim
605314564Sdim  Options *GetOptions() override { return &m_options; }
606309124Sdim
607314564Sdimprotected:
608314564Sdim  class CommandOptions : public Options {
609314564Sdim  public:
610314564Sdim    CommandOptions() : Options() {}
611314564Sdim
612314564Sdim    ~CommandOptions() override = default;
613314564Sdim
614321369Sdim    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
615321369Sdim                          ExecutionContext *execution_context) override {
616321369Sdim      Status error;
617314564Sdim      char short_option = (char)m_getopt_table[option_idx].val;
618314564Sdim
619314564Sdim      switch (short_option) {
620314564Sdim      case 'o':
621314564Sdim        if (option_arg.getAsInteger(0, m_offset))
622314564Sdim          error.SetErrorStringWithFormat("invalid offset: '%s'",
623314564Sdim                                         option_arg.str().c_str());
624314564Sdim        break;
625314564Sdim      case 'c':
626314564Sdim        if (option_arg.getAsInteger(0, m_count))
627314564Sdim          error.SetErrorStringWithFormat("invalid offset: '%s'",
628314564Sdim                                         option_arg.str().c_str());
629314564Sdim        break;
630314564Sdim      default:
631360784Sdim        llvm_unreachable("Unimplemented option");
632314564Sdim      }
633314564Sdim
634314564Sdim      return error;
635258054Semaste    }
636309124Sdim
637314564Sdim    void OptionParsingStarting(ExecutionContext *execution_context) override {
638314564Sdim      m_offset = 0;
639314564Sdim      m_count = 1;
640258054Semaste    }
641309124Sdim
642314564Sdim    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
643314564Sdim      return llvm::makeArrayRef(g_platform_fread_options);
644314564Sdim    }
645309124Sdim
646314564Sdim    // Instance variables to hold the values for command options.
647309124Sdim
648314564Sdim    uint32_t m_offset;
649314564Sdim    uint32_t m_count;
650314564Sdim  };
651309124Sdim
652314564Sdim  CommandOptions m_options;
653258054Semaste};
654258054Semaste
655258054Semaste// "platform fwrite"
656314564Sdim
657360784Sdim#define LLDB_OPTIONS_platform_fwrite
658360784Sdim#include "CommandOptions.inc"
659314564Sdim
660314564Sdimclass CommandObjectPlatformFWrite : public CommandObjectParsed {
661258054Semastepublic:
662314564Sdim  CommandObjectPlatformFWrite(CommandInterpreter &interpreter)
663314564Sdim      : CommandObjectParsed(interpreter, "platform file write",
664314564Sdim                            "Write data to a file on the remote end.", nullptr,
665309124Sdim                            0),
666314564Sdim        m_options() {}
667314564Sdim
668314564Sdim  ~CommandObjectPlatformFWrite() override = default;
669314564Sdim
670314564Sdim  bool DoExecute(Args &args, CommandReturnObject &result) override {
671314564Sdim    PlatformSP platform_sp(
672353358Sdim        GetDebugger().GetPlatformList().GetSelectedPlatform());
673314564Sdim    if (platform_sp) {
674314564Sdim      std::string cmd_line;
675314564Sdim      args.GetCommandString(cmd_line);
676321369Sdim      Status error;
677314564Sdim      const lldb::user_id_t fd =
678314564Sdim          StringConvert::ToUInt64(cmd_line.c_str(), UINT64_MAX);
679314564Sdim      uint32_t retcode =
680314564Sdim          platform_sp->WriteFile(fd, m_options.m_offset, &m_options.m_data[0],
681314564Sdim                                 m_options.m_data.size(), error);
682314564Sdim      result.AppendMessageWithFormat("Return = %d\n", retcode);
683314564Sdim      result.SetStatus(eReturnStatusSuccessFinishResult);
684314564Sdim    } else {
685314564Sdim      result.AppendError("no platform currently selected\n");
686314564Sdim      result.SetStatus(eReturnStatusFailed);
687258054Semaste    }
688314564Sdim    return result.Succeeded();
689314564Sdim  }
690309124Sdim
691314564Sdim  Options *GetOptions() override { return &m_options; }
692309124Sdim
693314564Sdimprotected:
694314564Sdim  class CommandOptions : public Options {
695314564Sdim  public:
696314564Sdim    CommandOptions() : Options() {}
697314564Sdim
698314564Sdim    ~CommandOptions() override = default;
699314564Sdim
700321369Sdim    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
701321369Sdim                          ExecutionContext *execution_context) override {
702321369Sdim      Status error;
703314564Sdim      char short_option = (char)m_getopt_table[option_idx].val;
704314564Sdim
705314564Sdim      switch (short_option) {
706314564Sdim      case 'o':
707314564Sdim        if (option_arg.getAsInteger(0, m_offset))
708314564Sdim          error.SetErrorStringWithFormat("invalid offset: '%s'",
709314564Sdim                                         option_arg.str().c_str());
710314564Sdim        break;
711314564Sdim      case 'd':
712314564Sdim        m_data.assign(option_arg);
713314564Sdim        break;
714314564Sdim      default:
715360784Sdim        llvm_unreachable("Unimplemented option");
716314564Sdim      }
717314564Sdim
718314564Sdim      return error;
719258054Semaste    }
720309124Sdim
721314564Sdim    void OptionParsingStarting(ExecutionContext *execution_context) override {
722314564Sdim      m_offset = 0;
723314564Sdim      m_data.clear();
724258054Semaste    }
725309124Sdim
726314564Sdim    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
727314564Sdim      return llvm::makeArrayRef(g_platform_fwrite_options);
728314564Sdim    }
729309124Sdim
730314564Sdim    // Instance variables to hold the values for command options.
731309124Sdim
732314564Sdim    uint32_t m_offset;
733314564Sdim    std::string m_data;
734314564Sdim  };
735309124Sdim
736314564Sdim  CommandOptions m_options;
737258054Semaste};
738258054Semaste
739314564Sdimclass CommandObjectPlatformFile : public CommandObjectMultiword {
740258054Semastepublic:
741314564Sdim  // Constructors and Destructors
742314564Sdim  CommandObjectPlatformFile(CommandInterpreter &interpreter)
743314564Sdim      : CommandObjectMultiword(
744314564Sdim            interpreter, "platform file",
745314564Sdim            "Commands to access files on the current platform.",
746314564Sdim            "platform file [open|close|read|write] ...") {
747314564Sdim    LoadSubCommand(
748314564Sdim        "open", CommandObjectSP(new CommandObjectPlatformFOpen(interpreter)));
749314564Sdim    LoadSubCommand(
750314564Sdim        "close", CommandObjectSP(new CommandObjectPlatformFClose(interpreter)));
751314564Sdim    LoadSubCommand(
752314564Sdim        "read", CommandObjectSP(new CommandObjectPlatformFRead(interpreter)));
753314564Sdim    LoadSubCommand(
754314564Sdim        "write", CommandObjectSP(new CommandObjectPlatformFWrite(interpreter)));
755314564Sdim  }
756309124Sdim
757314564Sdim  ~CommandObjectPlatformFile() override = default;
758309124Sdim
759258054Semasteprivate:
760314564Sdim  // For CommandObjectPlatform only
761314564Sdim  DISALLOW_COPY_AND_ASSIGN(CommandObjectPlatformFile);
762258054Semaste};
763258054Semaste
764258054Semaste// "platform get-file remote-file-path host-file-path"
765314564Sdimclass CommandObjectPlatformGetFile : public CommandObjectParsed {
766258054Semastepublic:
767314564Sdim  CommandObjectPlatformGetFile(CommandInterpreter &interpreter)
768314564Sdim      : CommandObjectParsed(
769314564Sdim            interpreter, "platform get-file",
770314564Sdim            "Transfer a file from the remote end to the local host.",
771314564Sdim            "platform get-file <remote-file-spec> <local-file-spec>", 0) {
772314564Sdim    SetHelpLong(
773314564Sdim        R"(Examples:
774258054Semaste
775288943Sdim(lldb) platform get-file /the/remote/file/path /the/local/file/path
776288943Sdim
777314564Sdim    Transfer a file from the remote end with file path /the/remote/file/path to the local host.)");
778288943Sdim
779314564Sdim    CommandArgumentEntry arg1, arg2;
780314564Sdim    CommandArgumentData file_arg_remote, file_arg_host;
781258054Semaste
782314564Sdim    // Define the first (and only) variant of this arg.
783314564Sdim    file_arg_remote.arg_type = eArgTypeFilename;
784314564Sdim    file_arg_remote.arg_repetition = eArgRepeatPlain;
785314564Sdim    // There is only one variant this argument could be; put it into the
786314564Sdim    // argument entry.
787314564Sdim    arg1.push_back(file_arg_remote);
788309124Sdim
789314564Sdim    // Define the second (and only) variant of this arg.
790314564Sdim    file_arg_host.arg_type = eArgTypeFilename;
791314564Sdim    file_arg_host.arg_repetition = eArgRepeatPlain;
792314564Sdim    // There is only one variant this argument could be; put it into the
793314564Sdim    // argument entry.
794314564Sdim    arg2.push_back(file_arg_host);
795309124Sdim
796341825Sdim    // Push the data for the first and the second arguments into the
797341825Sdim    // m_arguments vector.
798314564Sdim    m_arguments.push_back(arg1);
799314564Sdim    m_arguments.push_back(arg2);
800314564Sdim  }
801258054Semaste
802314564Sdim  ~CommandObjectPlatformGetFile() override = default;
803314564Sdim
804314564Sdim  bool DoExecute(Args &args, CommandReturnObject &result) override {
805314564Sdim    // If the number of arguments is incorrect, issue an error message.
806314564Sdim    if (args.GetArgumentCount() != 2) {
807314564Sdim      result.GetErrorStream().Printf("error: required arguments missing; "
808314564Sdim                                     "specify both the source and destination "
809314564Sdim                                     "file paths\n");
810314564Sdim      result.SetStatus(eReturnStatusFailed);
811314564Sdim      return false;
812258054Semaste    }
813314564Sdim
814314564Sdim    PlatformSP platform_sp(
815353358Sdim        GetDebugger().GetPlatformList().GetSelectedPlatform());
816314564Sdim    if (platform_sp) {
817314564Sdim      const char *remote_file_path = args.GetArgumentAtIndex(0);
818314564Sdim      const char *local_file_path = args.GetArgumentAtIndex(1);
819344779Sdim      Status error = platform_sp->GetFile(FileSpec(remote_file_path),
820344779Sdim                                          FileSpec(local_file_path));
821314564Sdim      if (error.Success()) {
822314564Sdim        result.AppendMessageWithFormat(
823314564Sdim            "successfully get-file from %s (remote) to %s (host)\n",
824314564Sdim            remote_file_path, local_file_path);
825314564Sdim        result.SetStatus(eReturnStatusSuccessFinishResult);
826314564Sdim      } else {
827314564Sdim        result.AppendMessageWithFormat("get-file failed: %s\n",
828314564Sdim                                       error.AsCString());
829314564Sdim        result.SetStatus(eReturnStatusFailed);
830314564Sdim      }
831314564Sdim    } else {
832314564Sdim      result.AppendError("no platform currently selected\n");
833314564Sdim      result.SetStatus(eReturnStatusFailed);
834314564Sdim    }
835314564Sdim    return result.Succeeded();
836314564Sdim  }
837258054Semaste};
838258054Semaste
839258054Semaste// "platform get-size remote-file-path"
840314564Sdimclass CommandObjectPlatformGetSize : public CommandObjectParsed {
841258054Semastepublic:
842314564Sdim  CommandObjectPlatformGetSize(CommandInterpreter &interpreter)
843314564Sdim      : CommandObjectParsed(interpreter, "platform get-size",
844314564Sdim                            "Get the file size from the remote end.",
845314564Sdim                            "platform get-size <remote-file-spec>", 0) {
846314564Sdim    SetHelpLong(
847314564Sdim        R"(Examples:
848258054Semaste
849288943Sdim(lldb) platform get-size /the/remote/file/path
850288943Sdim
851314564Sdim    Get the file size from the remote end with path /the/remote/file/path.)");
852288943Sdim
853314564Sdim    CommandArgumentEntry arg1;
854314564Sdim    CommandArgumentData file_arg_remote;
855309124Sdim
856314564Sdim    // Define the first (and only) variant of this arg.
857314564Sdim    file_arg_remote.arg_type = eArgTypeFilename;
858314564Sdim    file_arg_remote.arg_repetition = eArgRepeatPlain;
859314564Sdim    // There is only one variant this argument could be; put it into the
860314564Sdim    // argument entry.
861314564Sdim    arg1.push_back(file_arg_remote);
862309124Sdim
863314564Sdim    // Push the data for the first argument into the m_arguments vector.
864314564Sdim    m_arguments.push_back(arg1);
865314564Sdim  }
866258054Semaste
867314564Sdim  ~CommandObjectPlatformGetSize() override = default;
868314564Sdim
869314564Sdim  bool DoExecute(Args &args, CommandReturnObject &result) override {
870314564Sdim    // If the number of arguments is incorrect, issue an error message.
871314564Sdim    if (args.GetArgumentCount() != 1) {
872314564Sdim      result.GetErrorStream().Printf("error: required argument missing; "
873314564Sdim                                     "specify the source file path as the only "
874314564Sdim                                     "argument\n");
875314564Sdim      result.SetStatus(eReturnStatusFailed);
876314564Sdim      return false;
877258054Semaste    }
878314564Sdim
879314564Sdim    PlatformSP platform_sp(
880353358Sdim        GetDebugger().GetPlatformList().GetSelectedPlatform());
881314564Sdim    if (platform_sp) {
882314564Sdim      std::string remote_file_path(args.GetArgumentAtIndex(0));
883344779Sdim      user_id_t size = platform_sp->GetFileSize(FileSpec(remote_file_path));
884314564Sdim      if (size != UINT64_MAX) {
885314564Sdim        result.AppendMessageWithFormat("File size of %s (remote): %" PRIu64
886314564Sdim                                       "\n",
887314564Sdim                                       remote_file_path.c_str(), size);
888314564Sdim        result.SetStatus(eReturnStatusSuccessFinishResult);
889314564Sdim      } else {
890314564Sdim        result.AppendMessageWithFormat(
891314564Sdim            "Error getting file size of %s (remote)\n",
892314564Sdim            remote_file_path.c_str());
893314564Sdim        result.SetStatus(eReturnStatusFailed);
894314564Sdim      }
895314564Sdim    } else {
896314564Sdim      result.AppendError("no platform currently selected\n");
897314564Sdim      result.SetStatus(eReturnStatusFailed);
898314564Sdim    }
899314564Sdim    return result.Succeeded();
900314564Sdim  }
901258054Semaste};
902258054Semaste
903258054Semaste// "platform put-file"
904314564Sdimclass CommandObjectPlatformPutFile : public CommandObjectParsed {
905258054Semastepublic:
906314564Sdim  CommandObjectPlatformPutFile(CommandInterpreter &interpreter)
907314564Sdim      : CommandObjectParsed(
908314564Sdim            interpreter, "platform put-file",
909314564Sdim            "Transfer a file from this system to the remote end.", nullptr, 0) {
910314564Sdim  }
911309124Sdim
912314564Sdim  ~CommandObjectPlatformPutFile() override = default;
913309124Sdim
914314564Sdim  bool DoExecute(Args &args, CommandReturnObject &result) override {
915314564Sdim    const char *src = args.GetArgumentAtIndex(0);
916314564Sdim    const char *dst = args.GetArgumentAtIndex(1);
917258054Semaste
918344779Sdim    FileSpec src_fs(src);
919344779Sdim    FileSystem::Instance().Resolve(src_fs);
920344779Sdim    FileSpec dst_fs(dst ? dst : src_fs.GetFilename().GetCString());
921288943Sdim
922314564Sdim    PlatformSP platform_sp(
923353358Sdim        GetDebugger().GetPlatformList().GetSelectedPlatform());
924314564Sdim    if (platform_sp) {
925321369Sdim      Status error(platform_sp->PutFile(src_fs, dst_fs));
926314564Sdim      if (error.Success()) {
927314564Sdim        result.SetStatus(eReturnStatusSuccessFinishNoResult);
928314564Sdim      } else {
929314564Sdim        result.AppendError(error.AsCString());
930314564Sdim        result.SetStatus(eReturnStatusFailed);
931314564Sdim      }
932314564Sdim    } else {
933314564Sdim      result.AppendError("no platform currently selected\n");
934314564Sdim      result.SetStatus(eReturnStatusFailed);
935258054Semaste    }
936314564Sdim    return result.Succeeded();
937314564Sdim  }
938258054Semaste};
939258054Semaste
940254721Semaste// "platform process launch"
941314564Sdimclass CommandObjectPlatformProcessLaunch : public CommandObjectParsed {
942254721Semastepublic:
943314564Sdim  CommandObjectPlatformProcessLaunch(CommandInterpreter &interpreter)
944314564Sdim      : CommandObjectParsed(interpreter, "platform process launch",
945314564Sdim                            "Launch a new process on a remote platform.",
946314564Sdim                            "platform process launch program",
947314564Sdim                            eCommandRequiresTarget | eCommandTryTargetAPILock),
948314564Sdim        m_options() {}
949309124Sdim
950314564Sdim  ~CommandObjectPlatformProcessLaunch() override = default;
951309124Sdim
952314564Sdim  Options *GetOptions() override { return &m_options; }
953314564Sdim
954314564Sdimprotected:
955314564Sdim  bool DoExecute(Args &args, CommandReturnObject &result) override {
956353358Sdim    Target *target = GetDebugger().GetSelectedTarget().get();
957314564Sdim    PlatformSP platform_sp;
958314564Sdim    if (target) {
959314564Sdim      platform_sp = target->GetPlatform();
960254721Semaste    }
961314564Sdim    if (!platform_sp) {
962353358Sdim      platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();
963314564Sdim    }
964254721Semaste
965314564Sdim    if (platform_sp) {
966321369Sdim      Status error;
967314564Sdim      const size_t argc = args.GetArgumentCount();
968314564Sdim      Target *target = m_exe_ctx.GetTargetPtr();
969314564Sdim      Module *exe_module = target->GetExecutableModulePointer();
970314564Sdim      if (exe_module) {
971314564Sdim        m_options.launch_info.GetExecutableFile() = exe_module->GetFileSpec();
972344779Sdim        llvm::SmallString<128> exe_path;
973314564Sdim        m_options.launch_info.GetExecutableFile().GetPath(exe_path);
974314564Sdim        if (!exe_path.empty())
975314564Sdim          m_options.launch_info.GetArguments().AppendArgument(exe_path);
976314564Sdim        m_options.launch_info.GetArchitecture() = exe_module->GetArchitecture();
977314564Sdim      }
978254721Semaste
979314564Sdim      if (argc > 0) {
980314564Sdim        if (m_options.launch_info.GetExecutableFile()) {
981341825Sdim          // We already have an executable file, so we will use this and all
982341825Sdim          // arguments to this function are extra arguments
983314564Sdim          m_options.launch_info.GetArguments().AppendArguments(args);
984314564Sdim        } else {
985314564Sdim          // We don't have any file yet, so the first argument is our
986314564Sdim          // executable, and the rest are program arguments
987314564Sdim          const bool first_arg_is_executable = true;
988314564Sdim          m_options.launch_info.SetArguments(args, first_arg_is_executable);
989314564Sdim        }
990314564Sdim      }
991254721Semaste
992314564Sdim      if (m_options.launch_info.GetExecutableFile()) {
993353358Sdim        Debugger &debugger = GetDebugger();
994254721Semaste
995314564Sdim        if (argc == 0)
996314564Sdim          target->GetRunArguments(m_options.launch_info.GetArguments());
997314564Sdim
998314564Sdim        ProcessSP process_sp(platform_sp->DebugProcess(
999314564Sdim            m_options.launch_info, debugger, target, error));
1000314564Sdim        if (process_sp && process_sp->IsAlive()) {
1001314564Sdim          result.SetStatus(eReturnStatusSuccessFinishNoResult);
1002314564Sdim          return true;
1003254721Semaste        }
1004314564Sdim
1005314564Sdim        if (error.Success())
1006314564Sdim          result.AppendError("process launch failed");
1007254721Semaste        else
1008314564Sdim          result.AppendError(error.AsCString());
1009314564Sdim        result.SetStatus(eReturnStatusFailed);
1010314564Sdim      } else {
1011314564Sdim        result.AppendError("'platform process launch' uses the current target "
1012314564Sdim                           "file and arguments, or the executable and its "
1013314564Sdim                           "arguments can be specified in this command");
1014314564Sdim        result.SetStatus(eReturnStatusFailed);
1015314564Sdim        return false;
1016314564Sdim      }
1017314564Sdim    } else {
1018314564Sdim      result.AppendError("no platform is selected\n");
1019254721Semaste    }
1020314564Sdim    return result.Succeeded();
1021314564Sdim  }
1022314564Sdim
1023254721Semasteprotected:
1024314564Sdim  ProcessLaunchCommandOptions m_options;
1025254721Semaste};
1026254721Semaste
1027254721Semaste// "platform process list"
1028314564Sdim
1029360784Sdimstatic PosixPlatformCommandOptionValidator posix_validator;
1030360784Sdim#define LLDB_OPTIONS_platform_process_list
1031360784Sdim#include "CommandOptions.inc"
1032314564Sdim
1033314564Sdimclass CommandObjectPlatformProcessList : public CommandObjectParsed {
1034254721Semastepublic:
1035314564Sdim  CommandObjectPlatformProcessList(CommandInterpreter &interpreter)
1036314564Sdim      : CommandObjectParsed(interpreter, "platform process list",
1037314564Sdim                            "List processes on a remote platform by name, pid, "
1038314564Sdim                            "or many other matching attributes.",
1039314564Sdim                            "platform process list", 0),
1040314564Sdim        m_options() {}
1041309124Sdim
1042314564Sdim  ~CommandObjectPlatformProcessList() override = default;
1043309124Sdim
1044314564Sdim  Options *GetOptions() override { return &m_options; }
1045314564Sdim
1046314564Sdimprotected:
1047314564Sdim  bool DoExecute(Args &args, CommandReturnObject &result) override {
1048353358Sdim    Target *target = GetDebugger().GetSelectedTarget().get();
1049314564Sdim    PlatformSP platform_sp;
1050314564Sdim    if (target) {
1051314564Sdim      platform_sp = target->GetPlatform();
1052254721Semaste    }
1053314564Sdim    if (!platform_sp) {
1054353358Sdim      platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();
1055314564Sdim    }
1056254721Semaste
1057314564Sdim    if (platform_sp) {
1058321369Sdim      Status error;
1059314564Sdim      if (args.GetArgumentCount() == 0) {
1060314564Sdim        if (platform_sp) {
1061314564Sdim          Stream &ostrm = result.GetOutputStream();
1062254721Semaste
1063314564Sdim          lldb::pid_t pid =
1064314564Sdim              m_options.match_info.GetProcessInfo().GetProcessID();
1065314564Sdim          if (pid != LLDB_INVALID_PROCESS_ID) {
1066314564Sdim            ProcessInstanceInfo proc_info;
1067314564Sdim            if (platform_sp->GetProcessInfo(pid, proc_info)) {
1068353358Sdim              ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,
1069314564Sdim                                                   m_options.verbose);
1070353358Sdim              proc_info.DumpAsTableRow(ostrm, platform_sp->GetUserIDResolver(),
1071314564Sdim                                       m_options.show_args, m_options.verbose);
1072314564Sdim              result.SetStatus(eReturnStatusSuccessFinishResult);
1073314564Sdim            } else {
1074314564Sdim              result.AppendErrorWithFormat(
1075314564Sdim                  "no process found with pid = %" PRIu64 "\n", pid);
1076314564Sdim              result.SetStatus(eReturnStatusFailed);
1077254721Semaste            }
1078314564Sdim          } else {
1079314564Sdim            ProcessInstanceInfoList proc_infos;
1080314564Sdim            const uint32_t matches =
1081314564Sdim                platform_sp->FindProcesses(m_options.match_info, proc_infos);
1082314564Sdim            const char *match_desc = nullptr;
1083314564Sdim            const char *match_name =
1084314564Sdim                m_options.match_info.GetProcessInfo().GetName();
1085314564Sdim            if (match_name && match_name[0]) {
1086314564Sdim              switch (m_options.match_info.GetNameMatchType()) {
1087321369Sdim              case NameMatch::Ignore:
1088314564Sdim                break;
1089321369Sdim              case NameMatch::Equals:
1090314564Sdim                match_desc = "matched";
1091314564Sdim                break;
1092321369Sdim              case NameMatch::Contains:
1093314564Sdim                match_desc = "contained";
1094314564Sdim                break;
1095321369Sdim              case NameMatch::StartsWith:
1096314564Sdim                match_desc = "started with";
1097314564Sdim                break;
1098321369Sdim              case NameMatch::EndsWith:
1099314564Sdim                match_desc = "ended with";
1100314564Sdim                break;
1101321369Sdim              case NameMatch::RegularExpression:
1102314564Sdim                match_desc = "matched the regular expression";
1103314564Sdim                break;
1104314564Sdim              }
1105254721Semaste            }
1106314564Sdim
1107314564Sdim            if (matches == 0) {
1108314564Sdim              if (match_desc)
1109314564Sdim                result.AppendErrorWithFormat(
1110314564Sdim                    "no processes were found that %s \"%s\" on the \"%s\" "
1111314564Sdim                    "platform\n",
1112314564Sdim                    match_desc, match_name,
1113314564Sdim                    platform_sp->GetPluginName().GetCString());
1114314564Sdim              else
1115314564Sdim                result.AppendErrorWithFormat(
1116314564Sdim                    "no processes were found on the \"%s\" platform\n",
1117314564Sdim                    platform_sp->GetPluginName().GetCString());
1118314564Sdim              result.SetStatus(eReturnStatusFailed);
1119314564Sdim            } else {
1120314564Sdim              result.AppendMessageWithFormat(
1121314564Sdim                  "%u matching process%s found on \"%s\"", matches,
1122314564Sdim                  matches > 1 ? "es were" : " was",
1123314564Sdim                  platform_sp->GetName().GetCString());
1124314564Sdim              if (match_desc)
1125314564Sdim                result.AppendMessageWithFormat(" whose name %s \"%s\"",
1126314564Sdim                                               match_desc, match_name);
1127314564Sdim              result.AppendMessageWithFormat("\n");
1128353358Sdim              ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,
1129314564Sdim                                                   m_options.verbose);
1130314564Sdim              for (uint32_t i = 0; i < matches; ++i) {
1131314564Sdim                proc_infos.GetProcessInfoAtIndex(i).DumpAsTableRow(
1132353358Sdim                    ostrm, platform_sp->GetUserIDResolver(),
1133353358Sdim                    m_options.show_args, m_options.verbose);
1134314564Sdim              }
1135314564Sdim            }
1136314564Sdim          }
1137254721Semaste        }
1138314564Sdim      } else {
1139314564Sdim        result.AppendError("invalid args: process list takes only options\n");
1140314564Sdim        result.SetStatus(eReturnStatusFailed);
1141314564Sdim      }
1142314564Sdim    } else {
1143314564Sdim      result.AppendError("no platform is selected\n");
1144314564Sdim      result.SetStatus(eReturnStatusFailed);
1145314564Sdim    }
1146314564Sdim    return result.Succeeded();
1147314564Sdim  }
1148314564Sdim
1149314564Sdim  class CommandOptions : public Options {
1150314564Sdim  public:
1151314564Sdim    CommandOptions()
1152360784Sdim        : Options(), match_info(), show_args(false), verbose(false) {}
1153309124Sdim
1154314564Sdim    ~CommandOptions() override = default;
1155309124Sdim
1156321369Sdim    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1157321369Sdim                          ExecutionContext *execution_context) override {
1158321369Sdim      Status error;
1159314564Sdim      const int short_option = m_getopt_table[option_idx].val;
1160314564Sdim      bool success = false;
1161254721Semaste
1162314564Sdim      uint32_t id = LLDB_INVALID_PROCESS_ID;
1163314564Sdim      success = !option_arg.getAsInteger(0, id);
1164314564Sdim      switch (short_option) {
1165314564Sdim      case 'p': {
1166314564Sdim        match_info.GetProcessInfo().SetProcessID(id);
1167314564Sdim        if (!success)
1168314564Sdim          error.SetErrorStringWithFormat("invalid process ID string: '%s'",
1169314564Sdim                                         option_arg.str().c_str());
1170314564Sdim        break;
1171314564Sdim      }
1172314564Sdim      case 'P':
1173314564Sdim        match_info.GetProcessInfo().SetParentProcessID(id);
1174314564Sdim        if (!success)
1175314564Sdim          error.SetErrorStringWithFormat(
1176314564Sdim              "invalid parent process ID string: '%s'",
1177314564Sdim              option_arg.str().c_str());
1178314564Sdim        break;
1179254721Semaste
1180314564Sdim      case 'u':
1181314564Sdim        match_info.GetProcessInfo().SetUserID(success ? id : UINT32_MAX);
1182314564Sdim        if (!success)
1183314564Sdim          error.SetErrorStringWithFormat("invalid user ID string: '%s'",
1184314564Sdim                                         option_arg.str().c_str());
1185314564Sdim        break;
1186254721Semaste
1187314564Sdim      case 'U':
1188314564Sdim        match_info.GetProcessInfo().SetEffectiveUserID(success ? id
1189314564Sdim                                                               : UINT32_MAX);
1190314564Sdim        if (!success)
1191314564Sdim          error.SetErrorStringWithFormat(
1192314564Sdim              "invalid effective user ID string: '%s'",
1193314564Sdim              option_arg.str().c_str());
1194314564Sdim        break;
1195254721Semaste
1196314564Sdim      case 'g':
1197314564Sdim        match_info.GetProcessInfo().SetGroupID(success ? id : UINT32_MAX);
1198314564Sdim        if (!success)
1199314564Sdim          error.SetErrorStringWithFormat("invalid group ID string: '%s'",
1200314564Sdim                                         option_arg.str().c_str());
1201314564Sdim        break;
1202254721Semaste
1203314564Sdim      case 'G':
1204314564Sdim        match_info.GetProcessInfo().SetEffectiveGroupID(success ? id
1205314564Sdim                                                                : UINT32_MAX);
1206314564Sdim        if (!success)
1207314564Sdim          error.SetErrorStringWithFormat(
1208314564Sdim              "invalid effective group ID string: '%s'",
1209314564Sdim              option_arg.str().c_str());
1210314564Sdim        break;
1211254721Semaste
1212314564Sdim      case 'a': {
1213314564Sdim        TargetSP target_sp =
1214314564Sdim            execution_context ? execution_context->GetTargetSP() : TargetSP();
1215314564Sdim        DebuggerSP debugger_sp =
1216314564Sdim            target_sp ? target_sp->GetDebugger().shared_from_this()
1217314564Sdim                      : DebuggerSP();
1218314564Sdim        PlatformSP platform_sp =
1219314564Sdim            debugger_sp ? debugger_sp->GetPlatformList().GetSelectedPlatform()
1220314564Sdim                        : PlatformSP();
1221327952Sdim        match_info.GetProcessInfo().GetArchitecture() =
1222327952Sdim            Platform::GetAugmentedArchSpec(platform_sp.get(), option_arg);
1223314564Sdim      } break;
1224254721Semaste
1225314564Sdim      case 'n':
1226341825Sdim        match_info.GetProcessInfo().GetExecutableFile().SetFile(
1227344779Sdim            option_arg, FileSpec::Style::native);
1228321369Sdim        match_info.SetNameMatchType(NameMatch::Equals);
1229314564Sdim        break;
1230254721Semaste
1231314564Sdim      case 'e':
1232341825Sdim        match_info.GetProcessInfo().GetExecutableFile().SetFile(
1233344779Sdim            option_arg, FileSpec::Style::native);
1234321369Sdim        match_info.SetNameMatchType(NameMatch::EndsWith);
1235314564Sdim        break;
1236254721Semaste
1237314564Sdim      case 's':
1238341825Sdim        match_info.GetProcessInfo().GetExecutableFile().SetFile(
1239344779Sdim            option_arg, FileSpec::Style::native);
1240321369Sdim        match_info.SetNameMatchType(NameMatch::StartsWith);
1241314564Sdim        break;
1242254721Semaste
1243314564Sdim      case 'c':
1244341825Sdim        match_info.GetProcessInfo().GetExecutableFile().SetFile(
1245344779Sdim            option_arg, FileSpec::Style::native);
1246321369Sdim        match_info.SetNameMatchType(NameMatch::Contains);
1247314564Sdim        break;
1248254721Semaste
1249314564Sdim      case 'r':
1250341825Sdim        match_info.GetProcessInfo().GetExecutableFile().SetFile(
1251344779Sdim            option_arg, FileSpec::Style::native);
1252321369Sdim        match_info.SetNameMatchType(NameMatch::RegularExpression);
1253314564Sdim        break;
1254254721Semaste
1255314564Sdim      case 'A':
1256314564Sdim        show_args = true;
1257314564Sdim        break;
1258309124Sdim
1259314564Sdim      case 'v':
1260314564Sdim        verbose = true;
1261314564Sdim        break;
1262309124Sdim
1263360784Sdim      case 'x':
1264360784Sdim        match_info.SetMatchAllUsers(true);
1265360784Sdim        break;
1266360784Sdim
1267314564Sdim      default:
1268360784Sdim        llvm_unreachable("Unimplemented option");
1269314564Sdim      }
1270254721Semaste
1271314564Sdim      return error;
1272314564Sdim    }
1273314564Sdim
1274314564Sdim    void OptionParsingStarting(ExecutionContext *execution_context) override {
1275314564Sdim      match_info.Clear();
1276314564Sdim      show_args = false;
1277314564Sdim      verbose = false;
1278314564Sdim    }
1279314564Sdim
1280314564Sdim    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1281314564Sdim      return llvm::makeArrayRef(g_platform_process_list_options);
1282314564Sdim    }
1283314564Sdim
1284314564Sdim    // Instance variables to hold the values for command options.
1285314564Sdim
1286314564Sdim    ProcessInstanceInfoMatch match_info;
1287314564Sdim    bool show_args;
1288314564Sdim    bool verbose;
1289314564Sdim  };
1290314564Sdim
1291314564Sdim  CommandOptions m_options;
1292254721Semaste};
1293254721Semaste
1294254721Semaste// "platform process info"
1295314564Sdimclass CommandObjectPlatformProcessInfo : public CommandObjectParsed {
1296254721Semastepublic:
1297314564Sdim  CommandObjectPlatformProcessInfo(CommandInterpreter &interpreter)
1298314564Sdim      : CommandObjectParsed(
1299314564Sdim            interpreter, "platform process info",
1300314564Sdim            "Get detailed information for one or more process by process ID.",
1301314564Sdim            "platform process info <pid> [<pid> <pid> ...]", 0) {
1302314564Sdim    CommandArgumentEntry arg;
1303314564Sdim    CommandArgumentData pid_args;
1304309124Sdim
1305314564Sdim    // Define the first (and only) variant of this arg.
1306314564Sdim    pid_args.arg_type = eArgTypePid;
1307314564Sdim    pid_args.arg_repetition = eArgRepeatStar;
1308309124Sdim
1309314564Sdim    // There is only one variant this argument could be; put it into the
1310314564Sdim    // argument entry.
1311314564Sdim    arg.push_back(pid_args);
1312314564Sdim
1313314564Sdim    // Push the data for the first argument into the m_arguments vector.
1314314564Sdim    m_arguments.push_back(arg);
1315314564Sdim  }
1316314564Sdim
1317314564Sdim  ~CommandObjectPlatformProcessInfo() override = default;
1318314564Sdim
1319254721Semasteprotected:
1320314564Sdim  bool DoExecute(Args &args, CommandReturnObject &result) override {
1321353358Sdim    Target *target = GetDebugger().GetSelectedTarget().get();
1322314564Sdim    PlatformSP platform_sp;
1323314564Sdim    if (target) {
1324314564Sdim      platform_sp = target->GetPlatform();
1325314564Sdim    }
1326314564Sdim    if (!platform_sp) {
1327353358Sdim      platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();
1328314564Sdim    }
1329254721Semaste
1330314564Sdim    if (platform_sp) {
1331314564Sdim      const size_t argc = args.GetArgumentCount();
1332314564Sdim      if (argc > 0) {
1333321369Sdim        Status error;
1334314564Sdim
1335314564Sdim        if (platform_sp->IsConnected()) {
1336314564Sdim          Stream &ostrm = result.GetOutputStream();
1337314564Sdim          for (auto &entry : args.entries()) {
1338314564Sdim            lldb::pid_t pid;
1339360784Sdim            if (entry.ref().getAsInteger(0, pid)) {
1340314564Sdim              result.AppendErrorWithFormat("invalid process ID argument '%s'",
1341360784Sdim                                           entry.ref().str().c_str());
1342314564Sdim              result.SetStatus(eReturnStatusFailed);
1343314564Sdim              break;
1344314564Sdim            } else {
1345314564Sdim              ProcessInstanceInfo proc_info;
1346314564Sdim              if (platform_sp->GetProcessInfo(pid, proc_info)) {
1347314564Sdim                ostrm.Printf("Process information for process %" PRIu64 ":\n",
1348314564Sdim                             pid);
1349353358Sdim                proc_info.Dump(ostrm, platform_sp->GetUserIDResolver());
1350314564Sdim              } else {
1351314564Sdim                ostrm.Printf("error: no process information is available for "
1352314564Sdim                             "process %" PRIu64 "\n",
1353314564Sdim                             pid);
1354314564Sdim              }
1355314564Sdim              ostrm.EOL();
1356254721Semaste            }
1357314564Sdim          }
1358314564Sdim        } else {
1359314564Sdim          // Not connected...
1360314564Sdim          result.AppendErrorWithFormat(
1361314564Sdim              "not connected to '%s'",
1362314564Sdim              platform_sp->GetPluginName().GetCString());
1363314564Sdim          result.SetStatus(eReturnStatusFailed);
1364254721Semaste        }
1365314564Sdim      } else {
1366314564Sdim        // No args
1367314564Sdim        result.AppendError("one or more process id(s) must be specified");
1368314564Sdim        result.SetStatus(eReturnStatusFailed);
1369314564Sdim      }
1370314564Sdim    } else {
1371314564Sdim      result.AppendError("no platform is currently selected");
1372314564Sdim      result.SetStatus(eReturnStatusFailed);
1373254721Semaste    }
1374314564Sdim    return result.Succeeded();
1375314564Sdim  }
1376254721Semaste};
1377254721Semaste
1378360784Sdim#define LLDB_OPTIONS_platform_process_attach
1379360784Sdim#include "CommandOptions.inc"
1380314564Sdim
1381314564Sdimclass CommandObjectPlatformProcessAttach : public CommandObjectParsed {
1382258054Semastepublic:
1383314564Sdim  class CommandOptions : public Options {
1384314564Sdim  public:
1385314564Sdim    CommandOptions() : Options() {
1386314564Sdim      // Keep default values of all options in one place: OptionParsingStarting
1387314564Sdim      // ()
1388314564Sdim      OptionParsingStarting(nullptr);
1389314564Sdim    }
1390314564Sdim
1391314564Sdim    ~CommandOptions() override = default;
1392314564Sdim
1393321369Sdim    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1394321369Sdim                          ExecutionContext *execution_context) override {
1395321369Sdim      Status error;
1396314564Sdim      char short_option = (char)m_getopt_table[option_idx].val;
1397314564Sdim      switch (short_option) {
1398314564Sdim      case 'p': {
1399314564Sdim        lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
1400314564Sdim        if (option_arg.getAsInteger(0, pid)) {
1401314564Sdim          error.SetErrorStringWithFormat("invalid process ID '%s'",
1402314564Sdim                                         option_arg.str().c_str());
1403314564Sdim        } else {
1404314564Sdim          attach_info.SetProcessID(pid);
1405258054Semaste        }
1406314564Sdim      } break;
1407309124Sdim
1408314564Sdim      case 'P':
1409314564Sdim        attach_info.SetProcessPluginName(option_arg);
1410314564Sdim        break;
1411309124Sdim
1412314564Sdim      case 'n':
1413344779Sdim        attach_info.GetExecutableFile().SetFile(option_arg,
1414341825Sdim                                                FileSpec::Style::native);
1415314564Sdim        break;
1416314564Sdim
1417314564Sdim      case 'w':
1418314564Sdim        attach_info.SetWaitForLaunch(true);
1419314564Sdim        break;
1420314564Sdim
1421314564Sdim      default:
1422360784Sdim        llvm_unreachable("Unimplemented option");
1423314564Sdim      }
1424314564Sdim      return error;
1425258054Semaste    }
1426309124Sdim
1427314564Sdim    void OptionParsingStarting(ExecutionContext *execution_context) override {
1428314564Sdim      attach_info.Clear();
1429314564Sdim    }
1430309124Sdim
1431314564Sdim    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1432314564Sdim      return llvm::makeArrayRef(g_platform_process_attach_options);
1433314564Sdim    }
1434314564Sdim
1435360784Sdim    void HandleOptionArgumentCompletion(
1436341825Sdim        CompletionRequest &request, OptionElementVector &opt_element_vector,
1437341825Sdim        int opt_element_index, CommandInterpreter &interpreter) override {
1438314564Sdim      int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;
1439314564Sdim      int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
1440314564Sdim
1441314564Sdim      // We are only completing the name option for now...
1442314564Sdim
1443360784Sdim      // Are we in the name?
1444360784Sdim      if (GetDefinitions()[opt_defs_index].short_option != 'n')
1445360784Sdim        return;
1446314564Sdim
1447360784Sdim      // Look to see if there is a -P argument provided, and if so use that
1448360784Sdim      // plugin, otherwise use the default plugin.
1449314564Sdim
1450360784Sdim      const char *partial_name = nullptr;
1451360784Sdim      partial_name = request.GetParsedLine().GetArgumentAtIndex(opt_arg_pos);
1452314564Sdim
1453360784Sdim      PlatformSP platform_sp(interpreter.GetPlatform(true));
1454360784Sdim      if (!platform_sp)
1455360784Sdim        return;
1456360784Sdim
1457360784Sdim      ProcessInstanceInfoList process_infos;
1458360784Sdim      ProcessInstanceInfoMatch match_info;
1459360784Sdim      if (partial_name) {
1460360784Sdim        match_info.GetProcessInfo().GetExecutableFile().SetFile(
1461360784Sdim            partial_name, FileSpec::Style::native);
1462360784Sdim        match_info.SetNameMatchType(NameMatch::StartsWith);
1463314564Sdim      }
1464360784Sdim      platform_sp->FindProcesses(match_info, process_infos);
1465360784Sdim      const uint32_t num_matches = process_infos.GetSize();
1466360784Sdim      if (num_matches == 0)
1467360784Sdim        return;
1468314564Sdim
1469360784Sdim      for (uint32_t i = 0; i < num_matches; ++i) {
1470360784Sdim        request.AddCompletion(process_infos.GetProcessNameAtIndex(i));
1471360784Sdim      }
1472360784Sdim      return;
1473258054Semaste    }
1474314564Sdim
1475314564Sdim    // Options table: Required for subclasses of Options.
1476314564Sdim
1477314564Sdim    static OptionDefinition g_option_table[];
1478314564Sdim
1479314564Sdim    // Instance variables to hold the values for command options.
1480314564Sdim
1481314564Sdim    ProcessAttachInfo attach_info;
1482314564Sdim  };
1483314564Sdim
1484314564Sdim  CommandObjectPlatformProcessAttach(CommandInterpreter &interpreter)
1485314564Sdim      : CommandObjectParsed(interpreter, "platform process attach",
1486314564Sdim                            "Attach to a process.",
1487314564Sdim                            "platform process attach <cmd-options>"),
1488314564Sdim        m_options() {}
1489314564Sdim
1490314564Sdim  ~CommandObjectPlatformProcessAttach() override = default;
1491314564Sdim
1492314564Sdim  bool DoExecute(Args &command, CommandReturnObject &result) override {
1493314564Sdim    PlatformSP platform_sp(
1494353358Sdim        GetDebugger().GetPlatformList().GetSelectedPlatform());
1495314564Sdim    if (platform_sp) {
1496321369Sdim      Status err;
1497314564Sdim      ProcessSP remote_process_sp = platform_sp->Attach(
1498353358Sdim          m_options.attach_info, GetDebugger(), nullptr, err);
1499314564Sdim      if (err.Fail()) {
1500314564Sdim        result.AppendError(err.AsCString());
1501314564Sdim        result.SetStatus(eReturnStatusFailed);
1502314564Sdim      } else if (!remote_process_sp) {
1503314564Sdim        result.AppendError("could not attach: unknown reason");
1504314564Sdim        result.SetStatus(eReturnStatusFailed);
1505314564Sdim      } else
1506314564Sdim        result.SetStatus(eReturnStatusSuccessFinishResult);
1507314564Sdim    } else {
1508314564Sdim      result.AppendError("no platform is currently selected");
1509314564Sdim      result.SetStatus(eReturnStatusFailed);
1510258054Semaste    }
1511314564Sdim    return result.Succeeded();
1512314564Sdim  }
1513314564Sdim
1514314564Sdim  Options *GetOptions() override { return &m_options; }
1515314564Sdim
1516258054Semasteprotected:
1517314564Sdim  CommandOptions m_options;
1518258054Semaste};
1519254721Semaste
1520314564Sdimclass CommandObjectPlatformProcess : public CommandObjectMultiword {
1521254721Semastepublic:
1522314564Sdim  // Constructors and Destructors
1523314564Sdim  CommandObjectPlatformProcess(CommandInterpreter &interpreter)
1524314564Sdim      : CommandObjectMultiword(interpreter, "platform process",
1525314564Sdim                               "Commands to query, launch and attach to "
1526314564Sdim                               "processes on the current platform.",
1527314564Sdim                               "platform process [attach|launch|list] ...") {
1528314564Sdim    LoadSubCommand(
1529314564Sdim        "attach",
1530314564Sdim        CommandObjectSP(new CommandObjectPlatformProcessAttach(interpreter)));
1531314564Sdim    LoadSubCommand(
1532314564Sdim        "launch",
1533314564Sdim        CommandObjectSP(new CommandObjectPlatformProcessLaunch(interpreter)));
1534314564Sdim    LoadSubCommand("info", CommandObjectSP(new CommandObjectPlatformProcessInfo(
1535314564Sdim                               interpreter)));
1536314564Sdim    LoadSubCommand("list", CommandObjectSP(new CommandObjectPlatformProcessList(
1537314564Sdim                               interpreter)));
1538314564Sdim  }
1539254721Semaste
1540314564Sdim  ~CommandObjectPlatformProcess() override = default;
1541309124Sdim
1542254721Semasteprivate:
1543314564Sdim  // For CommandObjectPlatform only
1544314564Sdim  DISALLOW_COPY_AND_ASSIGN(CommandObjectPlatformProcess);
1545254721Semaste};
1546254721Semaste
1547258054Semaste// "platform shell"
1548360784Sdim#define LLDB_OPTIONS_platform_shell
1549360784Sdim#include "CommandOptions.inc"
1550314564Sdim
1551314564Sdimclass CommandObjectPlatformShell : public CommandObjectRaw {
1552254721Semastepublic:
1553314564Sdim  class CommandOptions : public Options {
1554314564Sdim  public:
1555341825Sdim    CommandOptions() : Options() {}
1556309124Sdim
1557314564Sdim    ~CommandOptions() override = default;
1558309124Sdim
1559314564Sdim    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1560314564Sdim      return llvm::makeArrayRef(g_platform_shell_options);
1561314564Sdim    }
1562309124Sdim
1563321369Sdim    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1564321369Sdim                          ExecutionContext *execution_context) override {
1565321369Sdim      Status error;
1566314564Sdim
1567314564Sdim      const char short_option = (char)GetDefinitions()[option_idx].short_option;
1568314564Sdim
1569314564Sdim      switch (short_option) {
1570314564Sdim      case 't':
1571341825Sdim        uint32_t timeout_sec;
1572341825Sdim        if (option_arg.getAsInteger(10, timeout_sec))
1573314564Sdim          error.SetErrorStringWithFormat(
1574314564Sdim              "could not convert \"%s\" to a numeric value.",
1575314564Sdim              option_arg.str().c_str());
1576341825Sdim        else
1577341825Sdim          timeout = std::chrono::seconds(timeout_sec);
1578314564Sdim        break;
1579314564Sdim      default:
1580360784Sdim        llvm_unreachable("Unimplemented option");
1581314564Sdim      }
1582314564Sdim
1583314564Sdim      return error;
1584254721Semaste    }
1585309124Sdim
1586314564Sdim    void OptionParsingStarting(ExecutionContext *execution_context) override {}
1587309124Sdim
1588341825Sdim    Timeout<std::micro> timeout = std::chrono::seconds(10);
1589314564Sdim  };
1590314564Sdim
1591314564Sdim  CommandObjectPlatformShell(CommandInterpreter &interpreter)
1592314564Sdim      : CommandObjectRaw(interpreter, "platform shell",
1593314564Sdim                         "Run a shell command on the current platform.",
1594314564Sdim                         "platform shell <shell-command>", 0),
1595314564Sdim        m_options() {}
1596314564Sdim
1597314564Sdim  ~CommandObjectPlatformShell() override = default;
1598314564Sdim
1599314564Sdim  Options *GetOptions() override { return &m_options; }
1600314564Sdim
1601341825Sdim  bool DoExecute(llvm::StringRef raw_command_line,
1602314564Sdim                 CommandReturnObject &result) override {
1603314564Sdim    ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
1604314564Sdim    m_options.NotifyOptionParsingStarting(&exe_ctx);
1605314564Sdim
1606314564Sdim    // Print out an usage syntax on an empty command line.
1607341825Sdim    if (raw_command_line.empty()) {
1608314564Sdim      result.GetOutputStream().Printf("%s\n", this->GetSyntax().str().c_str());
1609314564Sdim      return true;
1610258054Semaste    }
1611258054Semaste
1612341825Sdim    OptionsWithRaw args(raw_command_line);
1613341825Sdim    const char *expr = args.GetRawPart().c_str();
1614258054Semaste
1615341825Sdim    if (args.HasArgs())
1616341825Sdim      if (!ParseOptions(args.GetArgs(), result))
1617341825Sdim        return false;
1618254721Semaste
1619314564Sdim    PlatformSP platform_sp(
1620353358Sdim        GetDebugger().GetPlatformList().GetSelectedPlatform());
1621321369Sdim    Status error;
1622314564Sdim    if (platform_sp) {
1623314564Sdim      FileSpec working_dir{};
1624314564Sdim      std::string output;
1625314564Sdim      int status = -1;
1626314564Sdim      int signo = -1;
1627314564Sdim      error = (platform_sp->RunShellCommand(expr, working_dir, &status, &signo,
1628314564Sdim                                            &output, m_options.timeout));
1629314564Sdim      if (!output.empty())
1630314564Sdim        result.GetOutputStream().PutCString(output);
1631314564Sdim      if (status > 0) {
1632314564Sdim        if (signo > 0) {
1633314564Sdim          const char *signo_cstr = Host::GetSignalAsCString(signo);
1634314564Sdim          if (signo_cstr)
1635314564Sdim            result.GetOutputStream().Printf(
1636314564Sdim                "error: command returned with status %i and signal %s\n",
1637314564Sdim                status, signo_cstr);
1638314564Sdim          else
1639314564Sdim            result.GetOutputStream().Printf(
1640314564Sdim                "error: command returned with status %i and signal %i\n",
1641314564Sdim                status, signo);
1642314564Sdim        } else
1643314564Sdim          result.GetOutputStream().Printf(
1644314564Sdim              "error: command returned with status %i\n", status);
1645314564Sdim      }
1646314564Sdim    } else {
1647314564Sdim      result.GetOutputStream().Printf(
1648314564Sdim          "error: cannot run remote shell commands without a platform\n");
1649314564Sdim      error.SetErrorString(
1650314564Sdim          "error: cannot run remote shell commands without a platform");
1651254721Semaste    }
1652309124Sdim
1653314564Sdim    if (error.Fail()) {
1654314564Sdim      result.AppendError(error.AsCString());
1655314564Sdim      result.SetStatus(eReturnStatusFailed);
1656314564Sdim    } else {
1657314564Sdim      result.SetStatus(eReturnStatusSuccessFinishResult);
1658314564Sdim    }
1659314564Sdim    return true;
1660314564Sdim  }
1661254721Semaste
1662314564Sdim  CommandOptions m_options;
1663258054Semaste};
1664258054Semaste
1665258054Semaste// "platform install" - install a target to a remote end
1666314564Sdimclass CommandObjectPlatformInstall : public CommandObjectParsed {
1667258054Semastepublic:
1668314564Sdim  CommandObjectPlatformInstall(CommandInterpreter &interpreter)
1669314564Sdim      : CommandObjectParsed(
1670314564Sdim            interpreter, "platform target-install",
1671314564Sdim            "Install a target (bundle or executable file) to the remote end.",
1672314564Sdim            "platform target-install <local-thing> <remote-sandbox>", 0) {}
1673309124Sdim
1674314564Sdim  ~CommandObjectPlatformInstall() override = default;
1675309124Sdim
1676314564Sdim  bool DoExecute(Args &args, CommandReturnObject &result) override {
1677314564Sdim    if (args.GetArgumentCount() != 2) {
1678314564Sdim      result.AppendError("platform target-install takes two arguments");
1679314564Sdim      result.SetStatus(eReturnStatusFailed);
1680314564Sdim      return false;
1681258054Semaste    }
1682314564Sdim    // TODO: move the bulk of this code over to the platform itself
1683344779Sdim    FileSpec src(args.GetArgumentAtIndex(0));
1684344779Sdim    FileSystem::Instance().Resolve(src);
1685344779Sdim    FileSpec dst(args.GetArgumentAtIndex(1));
1686344779Sdim    if (!FileSystem::Instance().Exists(src)) {
1687314564Sdim      result.AppendError("source location does not exist or is not accessible");
1688314564Sdim      result.SetStatus(eReturnStatusFailed);
1689314564Sdim      return false;
1690314564Sdim    }
1691314564Sdim    PlatformSP platform_sp(
1692353358Sdim        GetDebugger().GetPlatformList().GetSelectedPlatform());
1693314564Sdim    if (!platform_sp) {
1694314564Sdim      result.AppendError("no platform currently selected");
1695314564Sdim      result.SetStatus(eReturnStatusFailed);
1696314564Sdim      return false;
1697314564Sdim    }
1698314564Sdim
1699321369Sdim    Status error = platform_sp->Install(src, dst);
1700314564Sdim    if (error.Success()) {
1701314564Sdim      result.SetStatus(eReturnStatusSuccessFinishNoResult);
1702314564Sdim    } else {
1703314564Sdim      result.AppendErrorWithFormat("install failed: %s", error.AsCString());
1704314564Sdim      result.SetStatus(eReturnStatusFailed);
1705314564Sdim    }
1706314564Sdim    return result.Succeeded();
1707314564Sdim  }
1708258054Semaste};
1709258054Semaste
1710309124SdimCommandObjectPlatform::CommandObjectPlatform(CommandInterpreter &interpreter)
1711314564Sdim    : CommandObjectMultiword(
1712314564Sdim          interpreter, "platform", "Commands to manage and create platforms.",
1713314564Sdim          "platform [connect|disconnect|info|list|status|select] ...") {
1714314564Sdim  LoadSubCommand("select",
1715314564Sdim                 CommandObjectSP(new CommandObjectPlatformSelect(interpreter)));
1716314564Sdim  LoadSubCommand("list",
1717314564Sdim                 CommandObjectSP(new CommandObjectPlatformList(interpreter)));
1718314564Sdim  LoadSubCommand("status",
1719314564Sdim                 CommandObjectSP(new CommandObjectPlatformStatus(interpreter)));
1720314564Sdim  LoadSubCommand("connect", CommandObjectSP(
1721314564Sdim                                new CommandObjectPlatformConnect(interpreter)));
1722314564Sdim  LoadSubCommand(
1723314564Sdim      "disconnect",
1724314564Sdim      CommandObjectSP(new CommandObjectPlatformDisconnect(interpreter)));
1725314564Sdim  LoadSubCommand("settings", CommandObjectSP(new CommandObjectPlatformSettings(
1726314564Sdim                                 interpreter)));
1727314564Sdim  LoadSubCommand("mkdir",
1728314564Sdim                 CommandObjectSP(new CommandObjectPlatformMkDir(interpreter)));
1729314564Sdim  LoadSubCommand("file",
1730314564Sdim                 CommandObjectSP(new CommandObjectPlatformFile(interpreter)));
1731314564Sdim  LoadSubCommand("get-file", CommandObjectSP(new CommandObjectPlatformGetFile(
1732314564Sdim                                 interpreter)));
1733314564Sdim  LoadSubCommand("get-size", CommandObjectSP(new CommandObjectPlatformGetSize(
1734314564Sdim                                 interpreter)));
1735314564Sdim  LoadSubCommand("put-file", CommandObjectSP(new CommandObjectPlatformPutFile(
1736314564Sdim                                 interpreter)));
1737314564Sdim  LoadSubCommand("process", CommandObjectSP(
1738314564Sdim                                new CommandObjectPlatformProcess(interpreter)));
1739314564Sdim  LoadSubCommand("shell",
1740314564Sdim                 CommandObjectSP(new CommandObjectPlatformShell(interpreter)));
1741314564Sdim  LoadSubCommand(
1742314564Sdim      "target-install",
1743314564Sdim      CommandObjectSP(new CommandObjectPlatformInstall(interpreter)));
1744254721Semaste}
1745254721Semaste
1746309124SdimCommandObjectPlatform::~CommandObjectPlatform() = default;
1747