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