]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Commands/CommandObjectPlatform.cpp
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Commands / CommandObjectPlatform.cpp
1 //===-- CommandObjectPlatform.cpp -------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 // C Includes
11 // C++ Includes
12 #include <mutex>
13 // Other libraries and framework includes
14 // Project includes
15 #include "CommandObjectPlatform.h"
16 #include "lldb/Core/Debugger.h"
17 #include "lldb/Core/Module.h"
18 #include "lldb/Core/PluginManager.h"
19 #include "lldb/Host/OptionParser.h"
20 #include "lldb/Host/StringConvert.h"
21 #include "lldb/Interpreter/CommandInterpreter.h"
22 #include "lldb/Interpreter/CommandOptionValidators.h"
23 #include "lldb/Interpreter/CommandReturnObject.h"
24 #include "lldb/Interpreter/OptionGroupFile.h"
25 #include "lldb/Interpreter/OptionGroupPlatform.h"
26 #include "lldb/Target/ExecutionContext.h"
27 #include "lldb/Target/Platform.h"
28 #include "lldb/Target/Process.h"
29 #include "lldb/Utility/Args.h"
30 #include "lldb/Utility/DataExtractor.h"
31
32 #include "llvm/ADT/SmallString.h"
33 #include "llvm/Support/Threading.h"
34
35 using namespace lldb;
36 using namespace lldb_private;
37
38 static mode_t ParsePermissionString(const char *) = delete;
39
40 static mode_t ParsePermissionString(llvm::StringRef permissions) {
41   if (permissions.size() != 9)
42     return (mode_t)(-1);
43   bool user_r, user_w, user_x, group_r, group_w, group_x, world_r, world_w,
44       world_x;
45
46   user_r = (permissions[0] == 'r');
47   user_w = (permissions[1] == 'w');
48   user_x = (permissions[2] == 'x');
49
50   group_r = (permissions[3] == 'r');
51   group_w = (permissions[4] == 'w');
52   group_x = (permissions[5] == 'x');
53
54   world_r = (permissions[6] == 'r');
55   world_w = (permissions[7] == 'w');
56   world_x = (permissions[8] == 'x');
57
58   mode_t user, group, world;
59   user = (user_r ? 4 : 0) | (user_w ? 2 : 0) | (user_x ? 1 : 0);
60   group = (group_r ? 4 : 0) | (group_w ? 2 : 0) | (group_x ? 1 : 0);
61   world = (world_r ? 4 : 0) | (world_w ? 2 : 0) | (world_x ? 1 : 0);
62
63   return user | group | world;
64 }
65
66 static OptionDefinition g_permissions_options[] = {
67     // clang-format off
68   {LLDB_OPT_SET_ALL, false, "permissions-value",   'v', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePermissionsNumber, "Give out the numeric value for permissions (e.g. 757)"},
69   {LLDB_OPT_SET_ALL, false, "permissions-string",  's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePermissionsString, "Give out the string value for permissions (e.g. rwxr-xr--)."},
70   {LLDB_OPT_SET_ALL, false, "user-read",           'r', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,              "Allow user to read."},
71   {LLDB_OPT_SET_ALL, false, "user-write",          'w', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,              "Allow user to write."},
72   {LLDB_OPT_SET_ALL, false, "user-exec",           'x', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,              "Allow user to execute."},
73   {LLDB_OPT_SET_ALL, false, "group-read",          'R', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,              "Allow group to read."},
74   {LLDB_OPT_SET_ALL, false, "group-write",         'W', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,              "Allow group to write."},
75   {LLDB_OPT_SET_ALL, false, "group-exec",          'X', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,              "Allow group to execute."},
76   {LLDB_OPT_SET_ALL, false, "world-read",          'd', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,              "Allow world to read."},
77   {LLDB_OPT_SET_ALL, false, "world-write",         't', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,              "Allow world to write."},
78   {LLDB_OPT_SET_ALL, false, "world-exec",          'e', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,              "Allow world to execute."},
79     // clang-format on
80 };
81
82 class OptionPermissions : public OptionGroup {
83 public:
84   OptionPermissions() {}
85
86   ~OptionPermissions() override = default;
87
88   lldb_private::Status
89   SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
90                  ExecutionContext *execution_context) override {
91     Status error;
92     char short_option = (char)GetDefinitions()[option_idx].short_option;
93     switch (short_option) {
94     case 'v': {
95       if (option_arg.getAsInteger(8, m_permissions)) {
96         m_permissions = 0777;
97         error.SetErrorStringWithFormat("invalid value for permissions: %s",
98                                        option_arg.str().c_str());
99       }
100
101     } break;
102     case 's': {
103       mode_t perms = ParsePermissionString(option_arg);
104       if (perms == (mode_t)-1)
105         error.SetErrorStringWithFormat("invalid value for permissions: %s",
106                                        option_arg.str().c_str());
107       else
108         m_permissions = perms;
109     } break;
110     case 'r':
111       m_permissions |= lldb::eFilePermissionsUserRead;
112       break;
113     case 'w':
114       m_permissions |= lldb::eFilePermissionsUserWrite;
115       break;
116     case 'x':
117       m_permissions |= lldb::eFilePermissionsUserExecute;
118       break;
119     case 'R':
120       m_permissions |= lldb::eFilePermissionsGroupRead;
121       break;
122     case 'W':
123       m_permissions |= lldb::eFilePermissionsGroupWrite;
124       break;
125     case 'X':
126       m_permissions |= lldb::eFilePermissionsGroupExecute;
127       break;
128     case 'd':
129       m_permissions |= lldb::eFilePermissionsWorldRead;
130       break;
131     case 't':
132       m_permissions |= lldb::eFilePermissionsWorldWrite;
133       break;
134     case 'e':
135       m_permissions |= lldb::eFilePermissionsWorldExecute;
136       break;
137     default:
138       error.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
139       break;
140     }
141
142     return error;
143   }
144
145   void OptionParsingStarting(ExecutionContext *execution_context) override {
146     m_permissions = 0;
147   }
148
149   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
150     return llvm::makeArrayRef(g_permissions_options);
151   }
152
153   // Instance variables to hold the values for command options.
154
155   uint32_t m_permissions;
156
157 private:
158   DISALLOW_COPY_AND_ASSIGN(OptionPermissions);
159 };
160
161 //----------------------------------------------------------------------
162 // "platform select <platform-name>"
163 //----------------------------------------------------------------------
164 class CommandObjectPlatformSelect : public CommandObjectParsed {
165 public:
166   CommandObjectPlatformSelect(CommandInterpreter &interpreter)
167       : CommandObjectParsed(interpreter, "platform select",
168                             "Create a platform if needed and select it as the "
169                             "current platform.",
170                             "platform select <platform-name>", 0),
171         m_option_group(),
172         m_platform_options(
173             false) // Don't include the "--platform" option by passing false
174   {
175     m_option_group.Append(&m_platform_options, LLDB_OPT_SET_ALL, 1);
176     m_option_group.Finalize();
177   }
178
179   ~CommandObjectPlatformSelect() override = default;
180
181   int HandleCompletion(CompletionRequest &request) override {
182     CommandCompletions::PlatformPluginNames(GetCommandInterpreter(), request,
183                                             nullptr);
184     return request.GetNumberOfMatches();
185   }
186
187   Options *GetOptions() override { return &m_option_group; }
188
189 protected:
190   bool DoExecute(Args &args, CommandReturnObject &result) override {
191     if (args.GetArgumentCount() == 1) {
192       const char *platform_name = args.GetArgumentAtIndex(0);
193       if (platform_name && platform_name[0]) {
194         const bool select = true;
195         m_platform_options.SetPlatformName(platform_name);
196         Status error;
197         ArchSpec platform_arch;
198         PlatformSP platform_sp(m_platform_options.CreatePlatformWithOptions(
199             m_interpreter, ArchSpec(), select, error, platform_arch));
200         if (platform_sp) {
201           m_interpreter.GetDebugger().GetPlatformList().SetSelectedPlatform(
202               platform_sp);
203
204           platform_sp->GetStatus(result.GetOutputStream());
205           result.SetStatus(eReturnStatusSuccessFinishResult);
206         } else {
207           result.AppendError(error.AsCString());
208           result.SetStatus(eReturnStatusFailed);
209         }
210       } else {
211         result.AppendError("invalid platform name");
212         result.SetStatus(eReturnStatusFailed);
213       }
214     } else {
215       result.AppendError(
216           "platform create takes a platform name as an argument\n");
217       result.SetStatus(eReturnStatusFailed);
218     }
219     return result.Succeeded();
220   }
221
222   OptionGroupOptions m_option_group;
223   OptionGroupPlatform m_platform_options;
224 };
225
226 //----------------------------------------------------------------------
227 // "platform list"
228 //----------------------------------------------------------------------
229 class CommandObjectPlatformList : public CommandObjectParsed {
230 public:
231   CommandObjectPlatformList(CommandInterpreter &interpreter)
232       : CommandObjectParsed(interpreter, "platform list",
233                             "List all platforms that are available.", nullptr,
234                             0) {}
235
236   ~CommandObjectPlatformList() override = default;
237
238 protected:
239   bool DoExecute(Args &args, CommandReturnObject &result) override {
240     Stream &ostrm = result.GetOutputStream();
241     ostrm.Printf("Available platforms:\n");
242
243     PlatformSP host_platform_sp(Platform::GetHostPlatform());
244     ostrm.Printf("%s: %s\n", host_platform_sp->GetPluginName().GetCString(),
245                  host_platform_sp->GetDescription());
246
247     uint32_t idx;
248     for (idx = 0; 1; ++idx) {
249       const char *plugin_name =
250           PluginManager::GetPlatformPluginNameAtIndex(idx);
251       if (plugin_name == nullptr)
252         break;
253       const char *plugin_desc =
254           PluginManager::GetPlatformPluginDescriptionAtIndex(idx);
255       if (plugin_desc == nullptr)
256         break;
257       ostrm.Printf("%s: %s\n", plugin_name, plugin_desc);
258     }
259
260     if (idx == 0) {
261       result.AppendError("no platforms are available\n");
262       result.SetStatus(eReturnStatusFailed);
263     } else
264       result.SetStatus(eReturnStatusSuccessFinishResult);
265     return result.Succeeded();
266   }
267 };
268
269 //----------------------------------------------------------------------
270 // "platform status"
271 //----------------------------------------------------------------------
272 class CommandObjectPlatformStatus : public CommandObjectParsed {
273 public:
274   CommandObjectPlatformStatus(CommandInterpreter &interpreter)
275       : CommandObjectParsed(interpreter, "platform status",
276                             "Display status for the current platform.", nullptr,
277                             0) {}
278
279   ~CommandObjectPlatformStatus() override = default;
280
281 protected:
282   bool DoExecute(Args &args, CommandReturnObject &result) override {
283     Stream &ostrm = result.GetOutputStream();
284
285     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
286     PlatformSP platform_sp;
287     if (target) {
288       platform_sp = target->GetPlatform();
289     }
290     if (!platform_sp) {
291       platform_sp =
292           m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
293     }
294     if (platform_sp) {
295       platform_sp->GetStatus(ostrm);
296       result.SetStatus(eReturnStatusSuccessFinishResult);
297     } else {
298       result.AppendError("no platform is currently selected\n");
299       result.SetStatus(eReturnStatusFailed);
300     }
301     return result.Succeeded();
302   }
303 };
304
305 //----------------------------------------------------------------------
306 // "platform connect <connect-url>"
307 //----------------------------------------------------------------------
308 class CommandObjectPlatformConnect : public CommandObjectParsed {
309 public:
310   CommandObjectPlatformConnect(CommandInterpreter &interpreter)
311       : CommandObjectParsed(
312             interpreter, "platform connect",
313             "Select the current platform by providing a connection URL.",
314             "platform connect <connect-url>", 0) {}
315
316   ~CommandObjectPlatformConnect() override = default;
317
318 protected:
319   bool DoExecute(Args &args, CommandReturnObject &result) override {
320     Stream &ostrm = result.GetOutputStream();
321
322     PlatformSP platform_sp(
323         m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
324     if (platform_sp) {
325       Status error(platform_sp->ConnectRemote(args));
326       if (error.Success()) {
327         platform_sp->GetStatus(ostrm);
328         result.SetStatus(eReturnStatusSuccessFinishResult);
329
330         platform_sp->ConnectToWaitingProcesses(m_interpreter.GetDebugger(),
331                                                error);
332         if (error.Fail()) {
333           result.AppendError(error.AsCString());
334           result.SetStatus(eReturnStatusFailed);
335         }
336       } else {
337         result.AppendErrorWithFormat("%s\n", error.AsCString());
338         result.SetStatus(eReturnStatusFailed);
339       }
340     } else {
341       result.AppendError("no platform is currently selected\n");
342       result.SetStatus(eReturnStatusFailed);
343     }
344     return result.Succeeded();
345   }
346
347   Options *GetOptions() override {
348     PlatformSP platform_sp(
349         m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
350     OptionGroupOptions *m_platform_options = nullptr;
351     if (platform_sp) {
352       m_platform_options = platform_sp->GetConnectionOptions(m_interpreter);
353       if (m_platform_options != nullptr && !m_platform_options->m_did_finalize)
354         m_platform_options->Finalize();
355     }
356     return m_platform_options;
357   }
358 };
359
360 //----------------------------------------------------------------------
361 // "platform disconnect"
362 //----------------------------------------------------------------------
363 class CommandObjectPlatformDisconnect : public CommandObjectParsed {
364 public:
365   CommandObjectPlatformDisconnect(CommandInterpreter &interpreter)
366       : CommandObjectParsed(interpreter, "platform disconnect",
367                             "Disconnect from the current platform.",
368                             "platform disconnect", 0) {}
369
370   ~CommandObjectPlatformDisconnect() override = default;
371
372 protected:
373   bool DoExecute(Args &args, CommandReturnObject &result) override {
374     PlatformSP platform_sp(
375         m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
376     if (platform_sp) {
377       if (args.GetArgumentCount() == 0) {
378         Status error;
379
380         if (platform_sp->IsConnected()) {
381           // Cache the instance name if there is one since we are about to
382           // disconnect and the name might go with it.
383           const char *hostname_cstr = platform_sp->GetHostname();
384           std::string hostname;
385           if (hostname_cstr)
386             hostname.assign(hostname_cstr);
387
388           error = platform_sp->DisconnectRemote();
389           if (error.Success()) {
390             Stream &ostrm = result.GetOutputStream();
391             if (hostname.empty())
392               ostrm.Printf("Disconnected from \"%s\"\n",
393                            platform_sp->GetPluginName().GetCString());
394             else
395               ostrm.Printf("Disconnected from \"%s\"\n", hostname.c_str());
396             result.SetStatus(eReturnStatusSuccessFinishResult);
397           } else {
398             result.AppendErrorWithFormat("%s", error.AsCString());
399             result.SetStatus(eReturnStatusFailed);
400           }
401         } else {
402           // Not connected...
403           result.AppendErrorWithFormat(
404               "not connected to '%s'",
405               platform_sp->GetPluginName().GetCString());
406           result.SetStatus(eReturnStatusFailed);
407         }
408       } else {
409         // Bad args
410         result.AppendError(
411             "\"platform disconnect\" doesn't take any arguments");
412         result.SetStatus(eReturnStatusFailed);
413       }
414     } else {
415       result.AppendError("no platform is currently selected");
416       result.SetStatus(eReturnStatusFailed);
417     }
418     return result.Succeeded();
419   }
420 };
421
422 //----------------------------------------------------------------------
423 // "platform settings"
424 //----------------------------------------------------------------------
425 class CommandObjectPlatformSettings : public CommandObjectParsed {
426 public:
427   CommandObjectPlatformSettings(CommandInterpreter &interpreter)
428       : CommandObjectParsed(interpreter, "platform settings",
429                             "Set settings for the current target's platform, "
430                             "or for a platform by name.",
431                             "platform settings", 0),
432         m_options(),
433         m_option_working_dir(LLDB_OPT_SET_1, false, "working-dir", 'w', 0,
434                              eArgTypePath,
435                              "The working directory for the platform.") {
436     m_options.Append(&m_option_working_dir, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
437   }
438
439   ~CommandObjectPlatformSettings() override = default;
440
441 protected:
442   bool DoExecute(Args &args, CommandReturnObject &result) override {
443     PlatformSP platform_sp(
444         m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
445     if (platform_sp) {
446       if (m_option_working_dir.GetOptionValue().OptionWasSet())
447         platform_sp->SetWorkingDirectory(
448             m_option_working_dir.GetOptionValue().GetCurrentValue());
449     } else {
450       result.AppendError("no platform is currently selected");
451       result.SetStatus(eReturnStatusFailed);
452     }
453     return result.Succeeded();
454   }
455
456   Options *GetOptions() override {
457     if (!m_options.DidFinalize())
458       m_options.Finalize();
459     return &m_options;
460   }
461
462 protected:
463   OptionGroupOptions m_options;
464   OptionGroupFile m_option_working_dir;
465 };
466
467 //----------------------------------------------------------------------
468 // "platform mkdir"
469 //----------------------------------------------------------------------
470 class CommandObjectPlatformMkDir : public CommandObjectParsed {
471 public:
472   CommandObjectPlatformMkDir(CommandInterpreter &interpreter)
473       : CommandObjectParsed(interpreter, "platform mkdir",
474                             "Make a new directory on the remote end.", nullptr,
475                             0),
476         m_options() {}
477
478   ~CommandObjectPlatformMkDir() override = default;
479
480   bool DoExecute(Args &args, CommandReturnObject &result) override {
481     PlatformSP platform_sp(
482         m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
483     if (platform_sp) {
484       std::string cmd_line;
485       args.GetCommandString(cmd_line);
486       uint32_t mode;
487       const OptionPermissions *options_permissions =
488           (const OptionPermissions *)m_options.GetGroupWithOption('r');
489       if (options_permissions)
490         mode = options_permissions->m_permissions;
491       else
492         mode = lldb::eFilePermissionsUserRWX | lldb::eFilePermissionsGroupRWX |
493                lldb::eFilePermissionsWorldRX;
494       Status error =
495           platform_sp->MakeDirectory(FileSpec{cmd_line, false}, mode);
496       if (error.Success()) {
497         result.SetStatus(eReturnStatusSuccessFinishResult);
498       } else {
499         result.AppendError(error.AsCString());
500         result.SetStatus(eReturnStatusFailed);
501       }
502     } else {
503       result.AppendError("no platform currently selected\n");
504       result.SetStatus(eReturnStatusFailed);
505     }
506     return result.Succeeded();
507   }
508
509   Options *GetOptions() override {
510     if (!m_options.DidFinalize()) {
511       m_options.Append(new OptionPermissions());
512       m_options.Finalize();
513     }
514     return &m_options;
515   }
516
517   OptionGroupOptions m_options;
518 };
519
520 //----------------------------------------------------------------------
521 // "platform fopen"
522 //----------------------------------------------------------------------
523 class CommandObjectPlatformFOpen : public CommandObjectParsed {
524 public:
525   CommandObjectPlatformFOpen(CommandInterpreter &interpreter)
526       : CommandObjectParsed(interpreter, "platform file open",
527                             "Open a file on the remote end.", nullptr, 0),
528         m_options() {}
529
530   ~CommandObjectPlatformFOpen() override = default;
531
532   bool DoExecute(Args &args, CommandReturnObject &result) override {
533     PlatformSP platform_sp(
534         m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
535     if (platform_sp) {
536       Status error;
537       std::string cmd_line;
538       args.GetCommandString(cmd_line);
539       mode_t perms;
540       const OptionPermissions *options_permissions =
541           (const OptionPermissions *)m_options.GetGroupWithOption('r');
542       if (options_permissions)
543         perms = options_permissions->m_permissions;
544       else
545         perms = lldb::eFilePermissionsUserRW | lldb::eFilePermissionsGroupRW |
546                 lldb::eFilePermissionsWorldRead;
547       lldb::user_id_t fd = platform_sp->OpenFile(
548           FileSpec(cmd_line, false),
549           File::eOpenOptionRead | File::eOpenOptionWrite |
550               File::eOpenOptionAppend | File::eOpenOptionCanCreate,
551           perms, error);
552       if (error.Success()) {
553         result.AppendMessageWithFormat("File Descriptor = %" PRIu64 "\n", fd);
554         result.SetStatus(eReturnStatusSuccessFinishResult);
555       } else {
556         result.AppendError(error.AsCString());
557         result.SetStatus(eReturnStatusFailed);
558       }
559     } else {
560       result.AppendError("no platform currently selected\n");
561       result.SetStatus(eReturnStatusFailed);
562     }
563     return result.Succeeded();
564   }
565
566   Options *GetOptions() override {
567     if (!m_options.DidFinalize()) {
568       m_options.Append(new OptionPermissions());
569       m_options.Finalize();
570     }
571     return &m_options;
572   }
573
574   OptionGroupOptions m_options;
575 };
576
577 //----------------------------------------------------------------------
578 // "platform fclose"
579 //----------------------------------------------------------------------
580 class CommandObjectPlatformFClose : public CommandObjectParsed {
581 public:
582   CommandObjectPlatformFClose(CommandInterpreter &interpreter)
583       : CommandObjectParsed(interpreter, "platform file close",
584                             "Close a file on the remote end.", nullptr, 0) {}
585
586   ~CommandObjectPlatformFClose() override = default;
587
588   bool DoExecute(Args &args, CommandReturnObject &result) override {
589     PlatformSP platform_sp(
590         m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
591     if (platform_sp) {
592       std::string cmd_line;
593       args.GetCommandString(cmd_line);
594       const lldb::user_id_t fd =
595           StringConvert::ToUInt64(cmd_line.c_str(), UINT64_MAX);
596       Status error;
597       bool success = platform_sp->CloseFile(fd, error);
598       if (success) {
599         result.AppendMessageWithFormat("file %" PRIu64 " closed.\n", fd);
600         result.SetStatus(eReturnStatusSuccessFinishResult);
601       } else {
602         result.AppendError(error.AsCString());
603         result.SetStatus(eReturnStatusFailed);
604       }
605     } else {
606       result.AppendError("no platform currently selected\n");
607       result.SetStatus(eReturnStatusFailed);
608     }
609     return result.Succeeded();
610   }
611 };
612
613 //----------------------------------------------------------------------
614 // "platform fread"
615 //----------------------------------------------------------------------
616
617 static OptionDefinition g_platform_fread_options[] = {
618     // clang-format off
619   { LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeIndex, "Offset into the file at which to start reading." },
620   { LLDB_OPT_SET_1, false, "count",  'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "Number of bytes to read from the file." },
621     // clang-format on
622 };
623
624 class CommandObjectPlatformFRead : public CommandObjectParsed {
625 public:
626   CommandObjectPlatformFRead(CommandInterpreter &interpreter)
627       : CommandObjectParsed(interpreter, "platform file read",
628                             "Read data from a file on the remote end.", nullptr,
629                             0),
630         m_options() {}
631
632   ~CommandObjectPlatformFRead() override = default;
633
634   bool DoExecute(Args &args, CommandReturnObject &result) override {
635     PlatformSP platform_sp(
636         m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
637     if (platform_sp) {
638       std::string cmd_line;
639       args.GetCommandString(cmd_line);
640       const lldb::user_id_t fd =
641           StringConvert::ToUInt64(cmd_line.c_str(), UINT64_MAX);
642       std::string buffer(m_options.m_count, 0);
643       Status error;
644       uint32_t retcode = platform_sp->ReadFile(
645           fd, m_options.m_offset, &buffer[0], m_options.m_count, error);
646       result.AppendMessageWithFormat("Return = %d\n", retcode);
647       result.AppendMessageWithFormat("Data = \"%s\"\n", buffer.c_str());
648       result.SetStatus(eReturnStatusSuccessFinishResult);
649     } else {
650       result.AppendError("no platform currently selected\n");
651       result.SetStatus(eReturnStatusFailed);
652     }
653     return result.Succeeded();
654   }
655
656   Options *GetOptions() override { return &m_options; }
657
658 protected:
659   class CommandOptions : public Options {
660   public:
661     CommandOptions() : Options() {}
662
663     ~CommandOptions() override = default;
664
665     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
666                           ExecutionContext *execution_context) override {
667       Status error;
668       char short_option = (char)m_getopt_table[option_idx].val;
669
670       switch (short_option) {
671       case 'o':
672         if (option_arg.getAsInteger(0, m_offset))
673           error.SetErrorStringWithFormat("invalid offset: '%s'",
674                                          option_arg.str().c_str());
675         break;
676       case 'c':
677         if (option_arg.getAsInteger(0, m_count))
678           error.SetErrorStringWithFormat("invalid offset: '%s'",
679                                          option_arg.str().c_str());
680         break;
681       default:
682         error.SetErrorStringWithFormat("unrecognized option '%c'",
683                                        short_option);
684         break;
685       }
686
687       return error;
688     }
689
690     void OptionParsingStarting(ExecutionContext *execution_context) override {
691       m_offset = 0;
692       m_count = 1;
693     }
694
695     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
696       return llvm::makeArrayRef(g_platform_fread_options);
697     }
698
699     // Instance variables to hold the values for command options.
700
701     uint32_t m_offset;
702     uint32_t m_count;
703   };
704
705   CommandOptions m_options;
706 };
707
708 //----------------------------------------------------------------------
709 // "platform fwrite"
710 //----------------------------------------------------------------------
711
712 static OptionDefinition g_platform_fwrite_options[] = {
713     // clang-format off
714   { LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeIndex, "Offset into the file at which to start reading." },
715   { LLDB_OPT_SET_1, false, "data",   'd', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeValue, "Text to write to the file." },
716     // clang-format on
717 };
718
719 class CommandObjectPlatformFWrite : public CommandObjectParsed {
720 public:
721   CommandObjectPlatformFWrite(CommandInterpreter &interpreter)
722       : CommandObjectParsed(interpreter, "platform file write",
723                             "Write data to a file on the remote end.", nullptr,
724                             0),
725         m_options() {}
726
727   ~CommandObjectPlatformFWrite() override = default;
728
729   bool DoExecute(Args &args, CommandReturnObject &result) override {
730     PlatformSP platform_sp(
731         m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
732     if (platform_sp) {
733       std::string cmd_line;
734       args.GetCommandString(cmd_line);
735       Status error;
736       const lldb::user_id_t fd =
737           StringConvert::ToUInt64(cmd_line.c_str(), UINT64_MAX);
738       uint32_t retcode =
739           platform_sp->WriteFile(fd, m_options.m_offset, &m_options.m_data[0],
740                                  m_options.m_data.size(), error);
741       result.AppendMessageWithFormat("Return = %d\n", retcode);
742       result.SetStatus(eReturnStatusSuccessFinishResult);
743     } else {
744       result.AppendError("no platform currently selected\n");
745       result.SetStatus(eReturnStatusFailed);
746     }
747     return result.Succeeded();
748   }
749
750   Options *GetOptions() override { return &m_options; }
751
752 protected:
753   class CommandOptions : public Options {
754   public:
755     CommandOptions() : Options() {}
756
757     ~CommandOptions() override = default;
758
759     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
760                           ExecutionContext *execution_context) override {
761       Status error;
762       char short_option = (char)m_getopt_table[option_idx].val;
763
764       switch (short_option) {
765       case 'o':
766         if (option_arg.getAsInteger(0, m_offset))
767           error.SetErrorStringWithFormat("invalid offset: '%s'",
768                                          option_arg.str().c_str());
769         break;
770       case 'd':
771         m_data.assign(option_arg);
772         break;
773       default:
774         error.SetErrorStringWithFormat("unrecognized option '%c'",
775                                        short_option);
776         break;
777       }
778
779       return error;
780     }
781
782     void OptionParsingStarting(ExecutionContext *execution_context) override {
783       m_offset = 0;
784       m_data.clear();
785     }
786
787     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
788       return llvm::makeArrayRef(g_platform_fwrite_options);
789     }
790
791     // Instance variables to hold the values for command options.
792
793     uint32_t m_offset;
794     std::string m_data;
795   };
796
797   CommandOptions m_options;
798 };
799
800 class CommandObjectPlatformFile : public CommandObjectMultiword {
801 public:
802   //------------------------------------------------------------------
803   // Constructors and Destructors
804   //------------------------------------------------------------------
805   CommandObjectPlatformFile(CommandInterpreter &interpreter)
806       : CommandObjectMultiword(
807             interpreter, "platform file",
808             "Commands to access files on the current platform.",
809             "platform file [open|close|read|write] ...") {
810     LoadSubCommand(
811         "open", CommandObjectSP(new CommandObjectPlatformFOpen(interpreter)));
812     LoadSubCommand(
813         "close", CommandObjectSP(new CommandObjectPlatformFClose(interpreter)));
814     LoadSubCommand(
815         "read", CommandObjectSP(new CommandObjectPlatformFRead(interpreter)));
816     LoadSubCommand(
817         "write", CommandObjectSP(new CommandObjectPlatformFWrite(interpreter)));
818   }
819
820   ~CommandObjectPlatformFile() override = default;
821
822 private:
823   //------------------------------------------------------------------
824   // For CommandObjectPlatform only
825   //------------------------------------------------------------------
826   DISALLOW_COPY_AND_ASSIGN(CommandObjectPlatformFile);
827 };
828
829 //----------------------------------------------------------------------
830 // "platform get-file remote-file-path host-file-path"
831 //----------------------------------------------------------------------
832 class CommandObjectPlatformGetFile : public CommandObjectParsed {
833 public:
834   CommandObjectPlatformGetFile(CommandInterpreter &interpreter)
835       : CommandObjectParsed(
836             interpreter, "platform get-file",
837             "Transfer a file from the remote end to the local host.",
838             "platform get-file <remote-file-spec> <local-file-spec>", 0) {
839     SetHelpLong(
840         R"(Examples:
841
842 (lldb) platform get-file /the/remote/file/path /the/local/file/path
843
844     Transfer a file from the remote end with file path /the/remote/file/path to the local host.)");
845
846     CommandArgumentEntry arg1, arg2;
847     CommandArgumentData file_arg_remote, file_arg_host;
848
849     // Define the first (and only) variant of this arg.
850     file_arg_remote.arg_type = eArgTypeFilename;
851     file_arg_remote.arg_repetition = eArgRepeatPlain;
852     // There is only one variant this argument could be; put it into the
853     // argument entry.
854     arg1.push_back(file_arg_remote);
855
856     // Define the second (and only) variant of this arg.
857     file_arg_host.arg_type = eArgTypeFilename;
858     file_arg_host.arg_repetition = eArgRepeatPlain;
859     // There is only one variant this argument could be; put it into the
860     // argument entry.
861     arg2.push_back(file_arg_host);
862
863     // Push the data for the first and the second arguments into the
864     // m_arguments vector.
865     m_arguments.push_back(arg1);
866     m_arguments.push_back(arg2);
867   }
868
869   ~CommandObjectPlatformGetFile() override = default;
870
871   bool DoExecute(Args &args, CommandReturnObject &result) override {
872     // If the number of arguments is incorrect, issue an error message.
873     if (args.GetArgumentCount() != 2) {
874       result.GetErrorStream().Printf("error: required arguments missing; "
875                                      "specify both the source and destination "
876                                      "file paths\n");
877       result.SetStatus(eReturnStatusFailed);
878       return false;
879     }
880
881     PlatformSP platform_sp(
882         m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
883     if (platform_sp) {
884       const char *remote_file_path = args.GetArgumentAtIndex(0);
885       const char *local_file_path = args.GetArgumentAtIndex(1);
886       Status error = platform_sp->GetFile(FileSpec(remote_file_path, false),
887                                           FileSpec(local_file_path, false));
888       if (error.Success()) {
889         result.AppendMessageWithFormat(
890             "successfully get-file from %s (remote) to %s (host)\n",
891             remote_file_path, local_file_path);
892         result.SetStatus(eReturnStatusSuccessFinishResult);
893       } else {
894         result.AppendMessageWithFormat("get-file failed: %s\n",
895                                        error.AsCString());
896         result.SetStatus(eReturnStatusFailed);
897       }
898     } else {
899       result.AppendError("no platform currently selected\n");
900       result.SetStatus(eReturnStatusFailed);
901     }
902     return result.Succeeded();
903   }
904 };
905
906 //----------------------------------------------------------------------
907 // "platform get-size remote-file-path"
908 //----------------------------------------------------------------------
909 class CommandObjectPlatformGetSize : public CommandObjectParsed {
910 public:
911   CommandObjectPlatformGetSize(CommandInterpreter &interpreter)
912       : CommandObjectParsed(interpreter, "platform get-size",
913                             "Get the file size from the remote end.",
914                             "platform get-size <remote-file-spec>", 0) {
915     SetHelpLong(
916         R"(Examples:
917
918 (lldb) platform get-size /the/remote/file/path
919
920     Get the file size from the remote end with path /the/remote/file/path.)");
921
922     CommandArgumentEntry arg1;
923     CommandArgumentData file_arg_remote;
924
925     // Define the first (and only) variant of this arg.
926     file_arg_remote.arg_type = eArgTypeFilename;
927     file_arg_remote.arg_repetition = eArgRepeatPlain;
928     // There is only one variant this argument could be; put it into the
929     // argument entry.
930     arg1.push_back(file_arg_remote);
931
932     // Push the data for the first argument into the m_arguments vector.
933     m_arguments.push_back(arg1);
934   }
935
936   ~CommandObjectPlatformGetSize() override = default;
937
938   bool DoExecute(Args &args, CommandReturnObject &result) override {
939     // If the number of arguments is incorrect, issue an error message.
940     if (args.GetArgumentCount() != 1) {
941       result.GetErrorStream().Printf("error: required argument missing; "
942                                      "specify the source file path as the only "
943                                      "argument\n");
944       result.SetStatus(eReturnStatusFailed);
945       return false;
946     }
947
948     PlatformSP platform_sp(
949         m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
950     if (platform_sp) {
951       std::string remote_file_path(args.GetArgumentAtIndex(0));
952       user_id_t size =
953           platform_sp->GetFileSize(FileSpec(remote_file_path, false));
954       if (size != UINT64_MAX) {
955         result.AppendMessageWithFormat("File size of %s (remote): %" PRIu64
956                                        "\n",
957                                        remote_file_path.c_str(), size);
958         result.SetStatus(eReturnStatusSuccessFinishResult);
959       } else {
960         result.AppendMessageWithFormat(
961             "Error getting file size of %s (remote)\n",
962             remote_file_path.c_str());
963         result.SetStatus(eReturnStatusFailed);
964       }
965     } else {
966       result.AppendError("no platform currently selected\n");
967       result.SetStatus(eReturnStatusFailed);
968     }
969     return result.Succeeded();
970   }
971 };
972
973 //----------------------------------------------------------------------
974 // "platform put-file"
975 //----------------------------------------------------------------------
976 class CommandObjectPlatformPutFile : public CommandObjectParsed {
977 public:
978   CommandObjectPlatformPutFile(CommandInterpreter &interpreter)
979       : CommandObjectParsed(
980             interpreter, "platform put-file",
981             "Transfer a file from this system to the remote end.", nullptr, 0) {
982   }
983
984   ~CommandObjectPlatformPutFile() override = default;
985
986   bool DoExecute(Args &args, CommandReturnObject &result) override {
987     const char *src = args.GetArgumentAtIndex(0);
988     const char *dst = args.GetArgumentAtIndex(1);
989
990     FileSpec src_fs(src, true);
991     FileSpec dst_fs(dst ? dst : src_fs.GetFilename().GetCString(), false);
992
993     PlatformSP platform_sp(
994         m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
995     if (platform_sp) {
996       Status error(platform_sp->PutFile(src_fs, dst_fs));
997       if (error.Success()) {
998         result.SetStatus(eReturnStatusSuccessFinishNoResult);
999       } else {
1000         result.AppendError(error.AsCString());
1001         result.SetStatus(eReturnStatusFailed);
1002       }
1003     } else {
1004       result.AppendError("no platform currently selected\n");
1005       result.SetStatus(eReturnStatusFailed);
1006     }
1007     return result.Succeeded();
1008   }
1009 };
1010
1011 //----------------------------------------------------------------------
1012 // "platform process launch"
1013 //----------------------------------------------------------------------
1014 class CommandObjectPlatformProcessLaunch : public CommandObjectParsed {
1015 public:
1016   CommandObjectPlatformProcessLaunch(CommandInterpreter &interpreter)
1017       : CommandObjectParsed(interpreter, "platform process launch",
1018                             "Launch a new process on a remote platform.",
1019                             "platform process launch program",
1020                             eCommandRequiresTarget | eCommandTryTargetAPILock),
1021         m_options() {}
1022
1023   ~CommandObjectPlatformProcessLaunch() override = default;
1024
1025   Options *GetOptions() override { return &m_options; }
1026
1027 protected:
1028   bool DoExecute(Args &args, CommandReturnObject &result) override {
1029     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
1030     PlatformSP platform_sp;
1031     if (target) {
1032       platform_sp = target->GetPlatform();
1033     }
1034     if (!platform_sp) {
1035       platform_sp =
1036           m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
1037     }
1038
1039     if (platform_sp) {
1040       Status error;
1041       const size_t argc = args.GetArgumentCount();
1042       Target *target = m_exe_ctx.GetTargetPtr();
1043       Module *exe_module = target->GetExecutableModulePointer();
1044       if (exe_module) {
1045         m_options.launch_info.GetExecutableFile() = exe_module->GetFileSpec();
1046         llvm::SmallString<PATH_MAX> exe_path;
1047         m_options.launch_info.GetExecutableFile().GetPath(exe_path);
1048         if (!exe_path.empty())
1049           m_options.launch_info.GetArguments().AppendArgument(exe_path);
1050         m_options.launch_info.GetArchitecture() = exe_module->GetArchitecture();
1051       }
1052
1053       if (argc > 0) {
1054         if (m_options.launch_info.GetExecutableFile()) {
1055           // We already have an executable file, so we will use this and all
1056           // arguments to this function are extra arguments
1057           m_options.launch_info.GetArguments().AppendArguments(args);
1058         } else {
1059           // We don't have any file yet, so the first argument is our
1060           // executable, and the rest are program arguments
1061           const bool first_arg_is_executable = true;
1062           m_options.launch_info.SetArguments(args, first_arg_is_executable);
1063         }
1064       }
1065
1066       if (m_options.launch_info.GetExecutableFile()) {
1067         Debugger &debugger = m_interpreter.GetDebugger();
1068
1069         if (argc == 0)
1070           target->GetRunArguments(m_options.launch_info.GetArguments());
1071
1072         ProcessSP process_sp(platform_sp->DebugProcess(
1073             m_options.launch_info, debugger, target, error));
1074         if (process_sp && process_sp->IsAlive()) {
1075           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1076           return true;
1077         }
1078
1079         if (error.Success())
1080           result.AppendError("process launch failed");
1081         else
1082           result.AppendError(error.AsCString());
1083         result.SetStatus(eReturnStatusFailed);
1084       } else {
1085         result.AppendError("'platform process launch' uses the current target "
1086                            "file and arguments, or the executable and its "
1087                            "arguments can be specified in this command");
1088         result.SetStatus(eReturnStatusFailed);
1089         return false;
1090       }
1091     } else {
1092       result.AppendError("no platform is selected\n");
1093     }
1094     return result.Succeeded();
1095   }
1096
1097 protected:
1098   ProcessLaunchCommandOptions m_options;
1099 };
1100
1101 //----------------------------------------------------------------------
1102 // "platform process list"
1103 //----------------------------------------------------------------------
1104
1105 OptionDefinition g_platform_process_list_options[] = {
1106     // clang-format off
1107   { LLDB_OPT_SET_1,             false, "pid",         'p', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePid,               "List the process info for a specific process ID." },
1108   { LLDB_OPT_SET_2,             true,  "name",        'n', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeProcessName,       "Find processes with executable basenames that match a string." },
1109   { LLDB_OPT_SET_3,             true,  "ends-with",   'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeProcessName,       "Find processes with executable basenames that end with a string." },
1110   { LLDB_OPT_SET_4,             true,  "starts-with", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeProcessName,       "Find processes with executable basenames that start with a string." },
1111   { LLDB_OPT_SET_5,             true,  "contains",    'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeProcessName,       "Find processes with executable basenames that contain a string." },
1112   { LLDB_OPT_SET_6,             true,  "regex",       'r', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeRegularExpression, "Find processes with executable basenames that match a regular expression." },
1113   { LLDB_OPT_SET_FROM_TO(2, 6), false, "parent",      'P', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePid,               "Find processes that have a matching parent process ID." },
1114   { LLDB_OPT_SET_FROM_TO(2, 6), false, "uid",         'u', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger,   "Find processes that have a matching user ID." },
1115   { LLDB_OPT_SET_FROM_TO(2, 6), false, "euid",        'U', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger,   "Find processes that have a matching effective user ID." },
1116   { LLDB_OPT_SET_FROM_TO(2, 6), false, "gid",         'g', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger,   "Find processes that have a matching group ID." },
1117   { LLDB_OPT_SET_FROM_TO(2, 6), false, "egid",        'G', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger,   "Find processes that have a matching effective group ID." },
1118   { LLDB_OPT_SET_FROM_TO(2, 6), false, "arch",        'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeArchitecture,      "Find processes that have a matching architecture." },
1119   { LLDB_OPT_SET_FROM_TO(1, 6), false, "show-args",   'A', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,              "Show process arguments instead of the process executable basename." },
1120   { LLDB_OPT_SET_FROM_TO(1, 6), false, "verbose",     'v', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,              "Enable verbose output." },
1121     // clang-format on
1122 };
1123
1124 class CommandObjectPlatformProcessList : public CommandObjectParsed {
1125 public:
1126   CommandObjectPlatformProcessList(CommandInterpreter &interpreter)
1127       : CommandObjectParsed(interpreter, "platform process list",
1128                             "List processes on a remote platform by name, pid, "
1129                             "or many other matching attributes.",
1130                             "platform process list", 0),
1131         m_options() {}
1132
1133   ~CommandObjectPlatformProcessList() override = default;
1134
1135   Options *GetOptions() override { return &m_options; }
1136
1137 protected:
1138   bool DoExecute(Args &args, CommandReturnObject &result) override {
1139     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
1140     PlatformSP platform_sp;
1141     if (target) {
1142       platform_sp = target->GetPlatform();
1143     }
1144     if (!platform_sp) {
1145       platform_sp =
1146           m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
1147     }
1148
1149     if (platform_sp) {
1150       Status error;
1151       if (args.GetArgumentCount() == 0) {
1152         if (platform_sp) {
1153           Stream &ostrm = result.GetOutputStream();
1154
1155           lldb::pid_t pid =
1156               m_options.match_info.GetProcessInfo().GetProcessID();
1157           if (pid != LLDB_INVALID_PROCESS_ID) {
1158             ProcessInstanceInfo proc_info;
1159             if (platform_sp->GetProcessInfo(pid, proc_info)) {
1160               ProcessInstanceInfo::DumpTableHeader(ostrm, platform_sp.get(),
1161                                                    m_options.show_args,
1162                                                    m_options.verbose);
1163               proc_info.DumpAsTableRow(ostrm, platform_sp.get(),
1164                                        m_options.show_args, m_options.verbose);
1165               result.SetStatus(eReturnStatusSuccessFinishResult);
1166             } else {
1167               result.AppendErrorWithFormat(
1168                   "no process found with pid = %" PRIu64 "\n", pid);
1169               result.SetStatus(eReturnStatusFailed);
1170             }
1171           } else {
1172             ProcessInstanceInfoList proc_infos;
1173             const uint32_t matches =
1174                 platform_sp->FindProcesses(m_options.match_info, proc_infos);
1175             const char *match_desc = nullptr;
1176             const char *match_name =
1177                 m_options.match_info.GetProcessInfo().GetName();
1178             if (match_name && match_name[0]) {
1179               switch (m_options.match_info.GetNameMatchType()) {
1180               case NameMatch::Ignore:
1181                 break;
1182               case NameMatch::Equals:
1183                 match_desc = "matched";
1184                 break;
1185               case NameMatch::Contains:
1186                 match_desc = "contained";
1187                 break;
1188               case NameMatch::StartsWith:
1189                 match_desc = "started with";
1190                 break;
1191               case NameMatch::EndsWith:
1192                 match_desc = "ended with";
1193                 break;
1194               case NameMatch::RegularExpression:
1195                 match_desc = "matched the regular expression";
1196                 break;
1197               }
1198             }
1199
1200             if (matches == 0) {
1201               if (match_desc)
1202                 result.AppendErrorWithFormat(
1203                     "no processes were found that %s \"%s\" on the \"%s\" "
1204                     "platform\n",
1205                     match_desc, match_name,
1206                     platform_sp->GetPluginName().GetCString());
1207               else
1208                 result.AppendErrorWithFormat(
1209                     "no processes were found on the \"%s\" platform\n",
1210                     platform_sp->GetPluginName().GetCString());
1211               result.SetStatus(eReturnStatusFailed);
1212             } else {
1213               result.AppendMessageWithFormat(
1214                   "%u matching process%s found on \"%s\"", matches,
1215                   matches > 1 ? "es were" : " was",
1216                   platform_sp->GetName().GetCString());
1217               if (match_desc)
1218                 result.AppendMessageWithFormat(" whose name %s \"%s\"",
1219                                                match_desc, match_name);
1220               result.AppendMessageWithFormat("\n");
1221               ProcessInstanceInfo::DumpTableHeader(ostrm, platform_sp.get(),
1222                                                    m_options.show_args,
1223                                                    m_options.verbose);
1224               for (uint32_t i = 0; i < matches; ++i) {
1225                 proc_infos.GetProcessInfoAtIndex(i).DumpAsTableRow(
1226                     ostrm, platform_sp.get(), m_options.show_args,
1227                     m_options.verbose);
1228               }
1229             }
1230           }
1231         }
1232       } else {
1233         result.AppendError("invalid args: process list takes only options\n");
1234         result.SetStatus(eReturnStatusFailed);
1235       }
1236     } else {
1237       result.AppendError("no platform is selected\n");
1238       result.SetStatus(eReturnStatusFailed);
1239     }
1240     return result.Succeeded();
1241   }
1242
1243   class CommandOptions : public Options {
1244   public:
1245     CommandOptions()
1246         : Options(), match_info(), show_args(false), verbose(false) {
1247       static llvm::once_flag g_once_flag;
1248       llvm::call_once(g_once_flag, []() {
1249         PosixPlatformCommandOptionValidator *posix_validator =
1250             new PosixPlatformCommandOptionValidator();
1251         for (auto &Option : g_platform_process_list_options) {
1252           switch (Option.short_option) {
1253           case 'u':
1254           case 'U':
1255           case 'g':
1256           case 'G':
1257             Option.validator = posix_validator;
1258             break;
1259           default:
1260             break;
1261           }
1262         }
1263       });
1264     }
1265
1266     ~CommandOptions() override = default;
1267
1268     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1269                           ExecutionContext *execution_context) override {
1270       Status error;
1271       const int short_option = m_getopt_table[option_idx].val;
1272       bool success = false;
1273
1274       uint32_t id = LLDB_INVALID_PROCESS_ID;
1275       success = !option_arg.getAsInteger(0, id);
1276       switch (short_option) {
1277       case 'p': {
1278         match_info.GetProcessInfo().SetProcessID(id);
1279         if (!success)
1280           error.SetErrorStringWithFormat("invalid process ID string: '%s'",
1281                                          option_arg.str().c_str());
1282         break;
1283       }
1284       case 'P':
1285         match_info.GetProcessInfo().SetParentProcessID(id);
1286         if (!success)
1287           error.SetErrorStringWithFormat(
1288               "invalid parent process ID string: '%s'",
1289               option_arg.str().c_str());
1290         break;
1291
1292       case 'u':
1293         match_info.GetProcessInfo().SetUserID(success ? id : UINT32_MAX);
1294         if (!success)
1295           error.SetErrorStringWithFormat("invalid user ID string: '%s'",
1296                                          option_arg.str().c_str());
1297         break;
1298
1299       case 'U':
1300         match_info.GetProcessInfo().SetEffectiveUserID(success ? id
1301                                                                : UINT32_MAX);
1302         if (!success)
1303           error.SetErrorStringWithFormat(
1304               "invalid effective user ID string: '%s'",
1305               option_arg.str().c_str());
1306         break;
1307
1308       case 'g':
1309         match_info.GetProcessInfo().SetGroupID(success ? id : UINT32_MAX);
1310         if (!success)
1311           error.SetErrorStringWithFormat("invalid group ID string: '%s'",
1312                                          option_arg.str().c_str());
1313         break;
1314
1315       case 'G':
1316         match_info.GetProcessInfo().SetEffectiveGroupID(success ? id
1317                                                                 : UINT32_MAX);
1318         if (!success)
1319           error.SetErrorStringWithFormat(
1320               "invalid effective group ID string: '%s'",
1321               option_arg.str().c_str());
1322         break;
1323
1324       case 'a': {
1325         TargetSP target_sp =
1326             execution_context ? execution_context->GetTargetSP() : TargetSP();
1327         DebuggerSP debugger_sp =
1328             target_sp ? target_sp->GetDebugger().shared_from_this()
1329                       : DebuggerSP();
1330         PlatformSP platform_sp =
1331             debugger_sp ? debugger_sp->GetPlatformList().GetSelectedPlatform()
1332                         : PlatformSP();
1333         match_info.GetProcessInfo().GetArchitecture() =
1334             Platform::GetAugmentedArchSpec(platform_sp.get(), option_arg);
1335       } break;
1336
1337       case 'n':
1338         match_info.GetProcessInfo().GetExecutableFile().SetFile(
1339             option_arg, false, FileSpec::Style::native);
1340         match_info.SetNameMatchType(NameMatch::Equals);
1341         break;
1342
1343       case 'e':
1344         match_info.GetProcessInfo().GetExecutableFile().SetFile(
1345             option_arg, false, FileSpec::Style::native);
1346         match_info.SetNameMatchType(NameMatch::EndsWith);
1347         break;
1348
1349       case 's':
1350         match_info.GetProcessInfo().GetExecutableFile().SetFile(
1351             option_arg, false, FileSpec::Style::native);
1352         match_info.SetNameMatchType(NameMatch::StartsWith);
1353         break;
1354
1355       case 'c':
1356         match_info.GetProcessInfo().GetExecutableFile().SetFile(
1357             option_arg, false, FileSpec::Style::native);
1358         match_info.SetNameMatchType(NameMatch::Contains);
1359         break;
1360
1361       case 'r':
1362         match_info.GetProcessInfo().GetExecutableFile().SetFile(
1363             option_arg, false, FileSpec::Style::native);
1364         match_info.SetNameMatchType(NameMatch::RegularExpression);
1365         break;
1366
1367       case 'A':
1368         show_args = true;
1369         break;
1370
1371       case 'v':
1372         verbose = true;
1373         break;
1374
1375       default:
1376         error.SetErrorStringWithFormat("unrecognized option '%c'",
1377                                        short_option);
1378         break;
1379       }
1380
1381       return error;
1382     }
1383
1384     void OptionParsingStarting(ExecutionContext *execution_context) override {
1385       match_info.Clear();
1386       show_args = false;
1387       verbose = false;
1388     }
1389
1390     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1391       return llvm::makeArrayRef(g_platform_process_list_options);
1392     }
1393
1394     // Instance variables to hold the values for command options.
1395
1396     ProcessInstanceInfoMatch match_info;
1397     bool show_args;
1398     bool verbose;
1399   };
1400
1401   CommandOptions m_options;
1402 };
1403
1404 //----------------------------------------------------------------------
1405 // "platform process info"
1406 //----------------------------------------------------------------------
1407 class CommandObjectPlatformProcessInfo : public CommandObjectParsed {
1408 public:
1409   CommandObjectPlatformProcessInfo(CommandInterpreter &interpreter)
1410       : CommandObjectParsed(
1411             interpreter, "platform process info",
1412             "Get detailed information for one or more process by process ID.",
1413             "platform process info <pid> [<pid> <pid> ...]", 0) {
1414     CommandArgumentEntry arg;
1415     CommandArgumentData pid_args;
1416
1417     // Define the first (and only) variant of this arg.
1418     pid_args.arg_type = eArgTypePid;
1419     pid_args.arg_repetition = eArgRepeatStar;
1420
1421     // There is only one variant this argument could be; put it into the
1422     // argument entry.
1423     arg.push_back(pid_args);
1424
1425     // Push the data for the first argument into the m_arguments vector.
1426     m_arguments.push_back(arg);
1427   }
1428
1429   ~CommandObjectPlatformProcessInfo() override = default;
1430
1431 protected:
1432   bool DoExecute(Args &args, CommandReturnObject &result) override {
1433     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
1434     PlatformSP platform_sp;
1435     if (target) {
1436       platform_sp = target->GetPlatform();
1437     }
1438     if (!platform_sp) {
1439       platform_sp =
1440           m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
1441     }
1442
1443     if (platform_sp) {
1444       const size_t argc = args.GetArgumentCount();
1445       if (argc > 0) {
1446         Status error;
1447
1448         if (platform_sp->IsConnected()) {
1449           Stream &ostrm = result.GetOutputStream();
1450           for (auto &entry : args.entries()) {
1451             lldb::pid_t pid;
1452             if (entry.ref.getAsInteger(0, pid)) {
1453               result.AppendErrorWithFormat("invalid process ID argument '%s'",
1454                                            entry.ref.str().c_str());
1455               result.SetStatus(eReturnStatusFailed);
1456               break;
1457             } else {
1458               ProcessInstanceInfo proc_info;
1459               if (platform_sp->GetProcessInfo(pid, proc_info)) {
1460                 ostrm.Printf("Process information for process %" PRIu64 ":\n",
1461                              pid);
1462                 proc_info.Dump(ostrm, platform_sp.get());
1463               } else {
1464                 ostrm.Printf("error: no process information is available for "
1465                              "process %" PRIu64 "\n",
1466                              pid);
1467               }
1468               ostrm.EOL();
1469             }
1470           }
1471         } else {
1472           // Not connected...
1473           result.AppendErrorWithFormat(
1474               "not connected to '%s'",
1475               platform_sp->GetPluginName().GetCString());
1476           result.SetStatus(eReturnStatusFailed);
1477         }
1478       } else {
1479         // No args
1480         result.AppendError("one or more process id(s) must be specified");
1481         result.SetStatus(eReturnStatusFailed);
1482       }
1483     } else {
1484       result.AppendError("no platform is currently selected");
1485       result.SetStatus(eReturnStatusFailed);
1486     }
1487     return result.Succeeded();
1488   }
1489 };
1490
1491 static OptionDefinition g_platform_process_attach_options[] = {
1492     // clang-format off
1493   { LLDB_OPT_SET_ALL, false, "plugin",  'P', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePlugin,      "Name of the process plugin you want to use." },
1494   { LLDB_OPT_SET_1,   false, "pid",     'p', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePid,         "The process ID of an existing process to attach to." },
1495   { LLDB_OPT_SET_2,   false, "name",    'n', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeProcessName, "The name of the process to attach to." },
1496   { LLDB_OPT_SET_2,   false, "waitfor", 'w', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,        "Wait for the process with <process-name> to launch." },
1497     // clang-format on
1498 };
1499
1500 class CommandObjectPlatformProcessAttach : public CommandObjectParsed {
1501 public:
1502   class CommandOptions : public Options {
1503   public:
1504     CommandOptions() : Options() {
1505       // Keep default values of all options in one place: OptionParsingStarting
1506       // ()
1507       OptionParsingStarting(nullptr);
1508     }
1509
1510     ~CommandOptions() override = default;
1511
1512     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1513                           ExecutionContext *execution_context) override {
1514       Status error;
1515       char short_option = (char)m_getopt_table[option_idx].val;
1516       switch (short_option) {
1517       case 'p': {
1518         lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
1519         if (option_arg.getAsInteger(0, pid)) {
1520           error.SetErrorStringWithFormat("invalid process ID '%s'",
1521                                          option_arg.str().c_str());
1522         } else {
1523           attach_info.SetProcessID(pid);
1524         }
1525       } break;
1526
1527       case 'P':
1528         attach_info.SetProcessPluginName(option_arg);
1529         break;
1530
1531       case 'n':
1532         attach_info.GetExecutableFile().SetFile(option_arg, false,
1533                                                 FileSpec::Style::native);
1534         break;
1535
1536       case 'w':
1537         attach_info.SetWaitForLaunch(true);
1538         break;
1539
1540       default:
1541         error.SetErrorStringWithFormat("invalid short option character '%c'",
1542                                        short_option);
1543         break;
1544       }
1545       return error;
1546     }
1547
1548     void OptionParsingStarting(ExecutionContext *execution_context) override {
1549       attach_info.Clear();
1550     }
1551
1552     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1553       return llvm::makeArrayRef(g_platform_process_attach_options);
1554     }
1555
1556     bool HandleOptionArgumentCompletion(
1557         CompletionRequest &request, OptionElementVector &opt_element_vector,
1558         int opt_element_index, CommandInterpreter &interpreter) override {
1559       int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;
1560       int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
1561
1562       // We are only completing the name option for now...
1563
1564       if (GetDefinitions()[opt_defs_index].short_option == 'n') {
1565         // Are we in the name?
1566
1567         // Look to see if there is a -P argument provided, and if so use that
1568         // plugin, otherwise use the default plugin.
1569
1570         const char *partial_name = nullptr;
1571         partial_name = request.GetParsedLine().GetArgumentAtIndex(opt_arg_pos);
1572
1573         PlatformSP platform_sp(interpreter.GetPlatform(true));
1574         if (platform_sp) {
1575           ProcessInstanceInfoList process_infos;
1576           ProcessInstanceInfoMatch match_info;
1577           if (partial_name) {
1578             match_info.GetProcessInfo().GetExecutableFile().SetFile(
1579                 partial_name, false, FileSpec::Style::native);
1580             match_info.SetNameMatchType(NameMatch::StartsWith);
1581           }
1582           platform_sp->FindProcesses(match_info, process_infos);
1583           const uint32_t num_matches = process_infos.GetSize();
1584           if (num_matches > 0) {
1585             for (uint32_t i = 0; i < num_matches; ++i) {
1586               request.AddCompletion(llvm::StringRef(
1587                   process_infos.GetProcessNameAtIndex(i),
1588                   process_infos.GetProcessNameLengthAtIndex(i)));
1589             }
1590           }
1591         }
1592       }
1593
1594       return false;
1595     }
1596
1597     // Options table: Required for subclasses of Options.
1598
1599     static OptionDefinition g_option_table[];
1600
1601     // Instance variables to hold the values for command options.
1602
1603     ProcessAttachInfo attach_info;
1604   };
1605
1606   CommandObjectPlatformProcessAttach(CommandInterpreter &interpreter)
1607       : CommandObjectParsed(interpreter, "platform process attach",
1608                             "Attach to a process.",
1609                             "platform process attach <cmd-options>"),
1610         m_options() {}
1611
1612   ~CommandObjectPlatformProcessAttach() override = default;
1613
1614   bool DoExecute(Args &command, CommandReturnObject &result) override {
1615     PlatformSP platform_sp(
1616         m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
1617     if (platform_sp) {
1618       Status err;
1619       ProcessSP remote_process_sp = platform_sp->Attach(
1620           m_options.attach_info, m_interpreter.GetDebugger(), nullptr, err);
1621       if (err.Fail()) {
1622         result.AppendError(err.AsCString());
1623         result.SetStatus(eReturnStatusFailed);
1624       } else if (!remote_process_sp) {
1625         result.AppendError("could not attach: unknown reason");
1626         result.SetStatus(eReturnStatusFailed);
1627       } else
1628         result.SetStatus(eReturnStatusSuccessFinishResult);
1629     } else {
1630       result.AppendError("no platform is currently selected");
1631       result.SetStatus(eReturnStatusFailed);
1632     }
1633     return result.Succeeded();
1634   }
1635
1636   Options *GetOptions() override { return &m_options; }
1637
1638 protected:
1639   CommandOptions m_options;
1640 };
1641
1642 class CommandObjectPlatformProcess : public CommandObjectMultiword {
1643 public:
1644   //------------------------------------------------------------------
1645   // Constructors and Destructors
1646   //------------------------------------------------------------------
1647   CommandObjectPlatformProcess(CommandInterpreter &interpreter)
1648       : CommandObjectMultiword(interpreter, "platform process",
1649                                "Commands to query, launch and attach to "
1650                                "processes on the current platform.",
1651                                "platform process [attach|launch|list] ...") {
1652     LoadSubCommand(
1653         "attach",
1654         CommandObjectSP(new CommandObjectPlatformProcessAttach(interpreter)));
1655     LoadSubCommand(
1656         "launch",
1657         CommandObjectSP(new CommandObjectPlatformProcessLaunch(interpreter)));
1658     LoadSubCommand("info", CommandObjectSP(new CommandObjectPlatformProcessInfo(
1659                                interpreter)));
1660     LoadSubCommand("list", CommandObjectSP(new CommandObjectPlatformProcessList(
1661                                interpreter)));
1662   }
1663
1664   ~CommandObjectPlatformProcess() override = default;
1665
1666 private:
1667   //------------------------------------------------------------------
1668   // For CommandObjectPlatform only
1669   //------------------------------------------------------------------
1670   DISALLOW_COPY_AND_ASSIGN(CommandObjectPlatformProcess);
1671 };
1672
1673 //----------------------------------------------------------------------
1674 // "platform shell"
1675 //----------------------------------------------------------------------
1676 static OptionDefinition g_platform_shell_options[] = {
1677     // clang-format off
1678   { LLDB_OPT_SET_ALL, false, "timeout", 't', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeValue, "Seconds to wait for the remote host to finish running the command." },
1679     // clang-format on
1680 };
1681
1682 class CommandObjectPlatformShell : public CommandObjectRaw {
1683 public:
1684   class CommandOptions : public Options {
1685   public:
1686     CommandOptions() : Options() {}
1687
1688     ~CommandOptions() override = default;
1689
1690     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1691       return llvm::makeArrayRef(g_platform_shell_options);
1692     }
1693
1694     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1695                           ExecutionContext *execution_context) override {
1696       Status error;
1697
1698       const char short_option = (char)GetDefinitions()[option_idx].short_option;
1699
1700       switch (short_option) {
1701       case 't':
1702         uint32_t timeout_sec;
1703         if (option_arg.getAsInteger(10, timeout_sec))
1704           error.SetErrorStringWithFormat(
1705               "could not convert \"%s\" to a numeric value.",
1706               option_arg.str().c_str());
1707         else
1708           timeout = std::chrono::seconds(timeout_sec);
1709         break;
1710       default:
1711         error.SetErrorStringWithFormat("invalid short option character '%c'",
1712                                        short_option);
1713         break;
1714       }
1715
1716       return error;
1717     }
1718
1719     void OptionParsingStarting(ExecutionContext *execution_context) override {}
1720
1721     Timeout<std::micro> timeout = std::chrono::seconds(10);
1722   };
1723
1724   CommandObjectPlatformShell(CommandInterpreter &interpreter)
1725       : CommandObjectRaw(interpreter, "platform shell",
1726                          "Run a shell command on the current platform.",
1727                          "platform shell <shell-command>", 0),
1728         m_options() {}
1729
1730   ~CommandObjectPlatformShell() override = default;
1731
1732   Options *GetOptions() override { return &m_options; }
1733
1734   bool DoExecute(llvm::StringRef raw_command_line,
1735                  CommandReturnObject &result) override {
1736     ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
1737     m_options.NotifyOptionParsingStarting(&exe_ctx);
1738
1739
1740     // Print out an usage syntax on an empty command line.
1741     if (raw_command_line.empty()) {
1742       result.GetOutputStream().Printf("%s\n", this->GetSyntax().str().c_str());
1743       return true;
1744     }
1745
1746     OptionsWithRaw args(raw_command_line);
1747     const char *expr = args.GetRawPart().c_str();
1748
1749     if (args.HasArgs())
1750       if (!ParseOptions(args.GetArgs(), result))
1751         return false;
1752
1753     PlatformSP platform_sp(
1754         m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
1755     Status error;
1756     if (platform_sp) {
1757       FileSpec working_dir{};
1758       std::string output;
1759       int status = -1;
1760       int signo = -1;
1761       error = (platform_sp->RunShellCommand(expr, working_dir, &status, &signo,
1762                                             &output, m_options.timeout));
1763       if (!output.empty())
1764         result.GetOutputStream().PutCString(output);
1765       if (status > 0) {
1766         if (signo > 0) {
1767           const char *signo_cstr = Host::GetSignalAsCString(signo);
1768           if (signo_cstr)
1769             result.GetOutputStream().Printf(
1770                 "error: command returned with status %i and signal %s\n",
1771                 status, signo_cstr);
1772           else
1773             result.GetOutputStream().Printf(
1774                 "error: command returned with status %i and signal %i\n",
1775                 status, signo);
1776         } else
1777           result.GetOutputStream().Printf(
1778               "error: command returned with status %i\n", status);
1779       }
1780     } else {
1781       result.GetOutputStream().Printf(
1782           "error: cannot run remote shell commands without a platform\n");
1783       error.SetErrorString(
1784           "error: cannot run remote shell commands without a platform");
1785     }
1786
1787     if (error.Fail()) {
1788       result.AppendError(error.AsCString());
1789       result.SetStatus(eReturnStatusFailed);
1790     } else {
1791       result.SetStatus(eReturnStatusSuccessFinishResult);
1792     }
1793     return true;
1794   }
1795
1796   CommandOptions m_options;
1797 };
1798
1799 //----------------------------------------------------------------------
1800 // "platform install" - install a target to a remote end
1801 //----------------------------------------------------------------------
1802 class CommandObjectPlatformInstall : public CommandObjectParsed {
1803 public:
1804   CommandObjectPlatformInstall(CommandInterpreter &interpreter)
1805       : CommandObjectParsed(
1806             interpreter, "platform target-install",
1807             "Install a target (bundle or executable file) to the remote end.",
1808             "platform target-install <local-thing> <remote-sandbox>", 0) {}
1809
1810   ~CommandObjectPlatformInstall() override = default;
1811
1812   bool DoExecute(Args &args, CommandReturnObject &result) override {
1813     if (args.GetArgumentCount() != 2) {
1814       result.AppendError("platform target-install takes two arguments");
1815       result.SetStatus(eReturnStatusFailed);
1816       return false;
1817     }
1818     // TODO: move the bulk of this code over to the platform itself
1819     FileSpec src(args.GetArgumentAtIndex(0), true);
1820     FileSpec dst(args.GetArgumentAtIndex(1), false);
1821     if (!src.Exists()) {
1822       result.AppendError("source location does not exist or is not accessible");
1823       result.SetStatus(eReturnStatusFailed);
1824       return false;
1825     }
1826     PlatformSP platform_sp(
1827         m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
1828     if (!platform_sp) {
1829       result.AppendError("no platform currently selected");
1830       result.SetStatus(eReturnStatusFailed);
1831       return false;
1832     }
1833
1834     Status error = platform_sp->Install(src, dst);
1835     if (error.Success()) {
1836       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1837     } else {
1838       result.AppendErrorWithFormat("install failed: %s", error.AsCString());
1839       result.SetStatus(eReturnStatusFailed);
1840     }
1841     return result.Succeeded();
1842   }
1843 };
1844
1845 CommandObjectPlatform::CommandObjectPlatform(CommandInterpreter &interpreter)
1846     : CommandObjectMultiword(
1847           interpreter, "platform", "Commands to manage and create platforms.",
1848           "platform [connect|disconnect|info|list|status|select] ...") {
1849   LoadSubCommand("select",
1850                  CommandObjectSP(new CommandObjectPlatformSelect(interpreter)));
1851   LoadSubCommand("list",
1852                  CommandObjectSP(new CommandObjectPlatformList(interpreter)));
1853   LoadSubCommand("status",
1854                  CommandObjectSP(new CommandObjectPlatformStatus(interpreter)));
1855   LoadSubCommand("connect", CommandObjectSP(
1856                                 new CommandObjectPlatformConnect(interpreter)));
1857   LoadSubCommand(
1858       "disconnect",
1859       CommandObjectSP(new CommandObjectPlatformDisconnect(interpreter)));
1860   LoadSubCommand("settings", CommandObjectSP(new CommandObjectPlatformSettings(
1861                                  interpreter)));
1862   LoadSubCommand("mkdir",
1863                  CommandObjectSP(new CommandObjectPlatformMkDir(interpreter)));
1864   LoadSubCommand("file",
1865                  CommandObjectSP(new CommandObjectPlatformFile(interpreter)));
1866   LoadSubCommand("get-file", CommandObjectSP(new CommandObjectPlatformGetFile(
1867                                  interpreter)));
1868   LoadSubCommand("get-size", CommandObjectSP(new CommandObjectPlatformGetSize(
1869                                  interpreter)));
1870   LoadSubCommand("put-file", CommandObjectSP(new CommandObjectPlatformPutFile(
1871                                  interpreter)));
1872   LoadSubCommand("process", CommandObjectSP(
1873                                 new CommandObjectPlatformProcess(interpreter)));
1874   LoadSubCommand("shell",
1875                  CommandObjectSP(new CommandObjectPlatformShell(interpreter)));
1876   LoadSubCommand(
1877       "target-install",
1878       CommandObjectSP(new CommandObjectPlatformInstall(interpreter)));
1879 }
1880
1881 CommandObjectPlatform::~CommandObjectPlatform() = default;