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