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