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