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