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