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