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/Interpreter/Args.h"
21 #include "lldb/Interpreter/CommandInterpreter.h"
22 #include "lldb/Interpreter/CommandReturnObject.h"
23 #include "lldb/Interpreter/OptionGroupPlatform.h"
24 #include "lldb/Target/ExecutionContext.h"
25 #include "lldb/Target/Platform.h"
26 #include "lldb/Target/Process.h"
27 
28 using namespace lldb;
29 using namespace lldb_private;
30 
31 
32 //----------------------------------------------------------------------
33 // "platform select <platform-name>"
34 //----------------------------------------------------------------------
35 class CommandObjectPlatformSelect : public CommandObjectParsed
36 {
37 public:
38     CommandObjectPlatformSelect (CommandInterpreter &interpreter) :
39         CommandObjectParsed (interpreter,
40                              "platform select",
41                              "Create a platform if needed and select it as the current platform.",
42                              "platform select <platform-name>",
43                              0),
44         m_option_group (interpreter),
45         m_platform_options (false) // Don't include the "--platform" option by passing false
46     {
47         m_option_group.Append (&m_platform_options, LLDB_OPT_SET_ALL, 1);
48         m_option_group.Finalize();
49     }
50 
51     virtual
52     ~CommandObjectPlatformSelect ()
53     {
54     }
55 
56     virtual int
57     HandleCompletion (Args &input,
58                       int &cursor_index,
59                       int &cursor_char_position,
60                       int match_start_point,
61                       int max_return_elements,
62                       bool &word_complete,
63                       StringList &matches)
64     {
65         std::string completion_str (input.GetArgumentAtIndex(cursor_index));
66         completion_str.erase (cursor_char_position);
67 
68         CommandCompletions::PlatformPluginNames (m_interpreter,
69                                                  completion_str.c_str(),
70                                                  match_start_point,
71                                                  max_return_elements,
72                                                  NULL,
73                                                  word_complete,
74                                                  matches);
75         return matches.GetSize();
76     }
77 
78     virtual Options *
79     GetOptions ()
80     {
81         return &m_option_group;
82     }
83 
84 protected:
85     virtual bool
86     DoExecute (Args& args, CommandReturnObject &result)
87     {
88         if (args.GetArgumentCount() == 1)
89         {
90             const char *platform_name = args.GetArgumentAtIndex (0);
91             if (platform_name && platform_name[0])
92             {
93                 const bool select = true;
94                 m_platform_options.SetPlatformName (platform_name);
95                 Error error;
96                 ArchSpec platform_arch;
97                 PlatformSP platform_sp (m_platform_options.CreatePlatformWithOptions (m_interpreter, ArchSpec(), select, error, platform_arch));
98                 if (platform_sp)
99                 {
100                     platform_sp->GetStatus (result.GetOutputStream());
101                     result.SetStatus (eReturnStatusSuccessFinishResult);
102                 }
103                 else
104                 {
105                     result.AppendError(error.AsCString());
106                     result.SetStatus (eReturnStatusFailed);
107                 }
108             }
109             else
110             {
111                 result.AppendError ("invalid platform name");
112                 result.SetStatus (eReturnStatusFailed);
113             }
114         }
115         else
116         {
117             result.AppendError ("platform create takes a platform name as an argument\n");
118             result.SetStatus (eReturnStatusFailed);
119         }
120         return result.Succeeded();
121     }
122 
123     OptionGroupOptions m_option_group;
124     OptionGroupPlatform m_platform_options;
125 };
126 
127 //----------------------------------------------------------------------
128 // "platform list"
129 //----------------------------------------------------------------------
130 class CommandObjectPlatformList : public CommandObjectParsed
131 {
132 public:
133     CommandObjectPlatformList (CommandInterpreter &interpreter) :
134         CommandObjectParsed (interpreter,
135                              "platform list",
136                              "List all platforms that are available.",
137                              NULL,
138                              0)
139     {
140     }
141 
142     virtual
143     ~CommandObjectPlatformList ()
144     {
145     }
146 
147 protected:
148     virtual bool
149     DoExecute (Args& args, CommandReturnObject &result)
150     {
151         Stream &ostrm = result.GetOutputStream();
152         ostrm.Printf("Available platforms:\n");
153 
154         PlatformSP host_platform_sp (Platform::GetDefaultPlatform());
155         ostrm.Printf ("%s: %s\n",
156                       host_platform_sp->GetShortPluginName(),
157                       host_platform_sp->GetDescription());
158 
159         uint32_t idx;
160         for (idx = 0; 1; ++idx)
161         {
162             const char *plugin_name = PluginManager::GetPlatformPluginNameAtIndex (idx);
163             if (plugin_name == NULL)
164                 break;
165             const char *plugin_desc = PluginManager::GetPlatformPluginDescriptionAtIndex (idx);
166             if (plugin_desc == NULL)
167                 break;
168             ostrm.Printf("%s: %s\n", plugin_name, plugin_desc);
169         }
170 
171         if (idx == 0)
172         {
173             result.AppendError ("no platforms are available\n");
174             result.SetStatus (eReturnStatusFailed);
175         }
176         else
177             result.SetStatus (eReturnStatusSuccessFinishResult);
178         return result.Succeeded();
179     }
180 };
181 
182 //----------------------------------------------------------------------
183 // "platform status"
184 //----------------------------------------------------------------------
185 class CommandObjectPlatformStatus : public CommandObjectParsed
186 {
187 public:
188     CommandObjectPlatformStatus (CommandInterpreter &interpreter) :
189         CommandObjectParsed (interpreter,
190                              "platform status",
191                              "Display status for the currently selected platform.",
192                              NULL,
193                              0)
194     {
195     }
196 
197     virtual
198     ~CommandObjectPlatformStatus ()
199     {
200     }
201 
202 protected:
203     virtual bool
204     DoExecute (Args& args, CommandReturnObject &result)
205     {
206         Stream &ostrm = result.GetOutputStream();
207 
208         PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
209         if (platform_sp)
210         {
211             platform_sp->GetStatus (ostrm);
212             result.SetStatus (eReturnStatusSuccessFinishResult);
213         }
214         else
215         {
216             result.AppendError ("no platform us currently selected\n");
217             result.SetStatus (eReturnStatusFailed);
218         }
219         return result.Succeeded();
220     }
221 };
222 
223 //----------------------------------------------------------------------
224 // "platform connect <connect-url>"
225 //----------------------------------------------------------------------
226 class CommandObjectPlatformConnect : public CommandObjectParsed
227 {
228 public:
229     CommandObjectPlatformConnect (CommandInterpreter &interpreter) :
230         CommandObjectParsed (interpreter,
231                              "platform connect",
232                              "Connect a platform by name to be the currently selected platform.",
233                              "platform connect <connect-url>",
234                              0)
235     {
236     }
237 
238     virtual
239     ~CommandObjectPlatformConnect ()
240     {
241     }
242 
243 protected:
244     virtual bool
245     DoExecute (Args& args, CommandReturnObject &result)
246     {
247         Stream &ostrm = result.GetOutputStream();
248 
249         PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
250         if (platform_sp)
251         {
252             Error error (platform_sp->ConnectRemote (args));
253             if (error.Success())
254             {
255                 platform_sp->GetStatus (ostrm);
256                 result.SetStatus (eReturnStatusSuccessFinishResult);
257             }
258             else
259             {
260                 result.AppendErrorWithFormat ("%s\n", error.AsCString());
261                 result.SetStatus (eReturnStatusFailed);
262             }
263         }
264         else
265         {
266             result.AppendError ("no platform us currently selected\n");
267             result.SetStatus (eReturnStatusFailed);
268         }
269         return result.Succeeded();
270     }
271 };
272 
273 //----------------------------------------------------------------------
274 // "platform disconnect"
275 //----------------------------------------------------------------------
276 class CommandObjectPlatformDisconnect : public CommandObjectParsed
277 {
278 public:
279     CommandObjectPlatformDisconnect (CommandInterpreter &interpreter) :
280         CommandObjectParsed (interpreter,
281                              "platform disconnect",
282                              "Disconnect a platform by name to be the currently selected platform.",
283                              "platform disconnect",
284                              0)
285     {
286     }
287 
288     virtual
289     ~CommandObjectPlatformDisconnect ()
290     {
291     }
292 
293 protected:
294     virtual bool
295     DoExecute (Args& args, CommandReturnObject &result)
296     {
297         PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
298         if (platform_sp)
299         {
300             if (args.GetArgumentCount() == 0)
301             {
302                 Error error;
303 
304                 if (platform_sp->IsConnected())
305                 {
306                     // Cache the instance name if there is one since we are
307                     // about to disconnect and the name might go with it.
308                     const char *hostname_cstr = platform_sp->GetHostname();
309                     std::string hostname;
310                     if (hostname_cstr)
311                         hostname.assign (hostname_cstr);
312 
313                     error = platform_sp->DisconnectRemote ();
314                     if (error.Success())
315                     {
316                         Stream &ostrm = result.GetOutputStream();
317                         if (hostname.empty())
318                             ostrm.Printf ("Disconnected from \"%s\"\n", platform_sp->GetShortPluginName());
319                         else
320                             ostrm.Printf ("Disconnected from \"%s\"\n", hostname.c_str());
321                         result.SetStatus (eReturnStatusSuccessFinishResult);
322                     }
323                     else
324                     {
325                         result.AppendErrorWithFormat ("%s", error.AsCString());
326                         result.SetStatus (eReturnStatusFailed);
327                     }
328                 }
329                 else
330                 {
331                     // Not connected...
332                     result.AppendErrorWithFormat ("not connected to '%s'", platform_sp->GetShortPluginName());
333                     result.SetStatus (eReturnStatusFailed);
334                 }
335             }
336             else
337             {
338                 // Bad args
339                 result.AppendError ("\"platform disconnect\" doesn't take any arguments");
340                 result.SetStatus (eReturnStatusFailed);
341             }
342         }
343         else
344         {
345             result.AppendError ("no platform is currently selected");
346             result.SetStatus (eReturnStatusFailed);
347         }
348         return result.Succeeded();
349     }
350 };
351 //----------------------------------------------------------------------
352 // "platform process launch"
353 //----------------------------------------------------------------------
354 class CommandObjectPlatformProcessLaunch : public CommandObjectParsed
355 {
356 public:
357     CommandObjectPlatformProcessLaunch (CommandInterpreter &interpreter) :
358         CommandObjectParsed (interpreter,
359                              "platform process launch",
360                              "Launch a new process on a remote platform.",
361                              "platform process launch program",
362                              0),
363         m_options (interpreter)
364     {
365     }
366 
367     virtual
368     ~CommandObjectPlatformProcessLaunch ()
369     {
370     }
371 
372     virtual Options *
373     GetOptions ()
374     {
375         return &m_options;
376     }
377 
378 protected:
379     virtual bool
380     DoExecute (Args& args, CommandReturnObject &result)
381     {
382         PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
383 
384         if (platform_sp)
385         {
386             Error error;
387             const uint32_t argc = args.GetArgumentCount();
388             Target *target = m_interpreter.GetExecutionContext().GetTargetPtr();
389             if (target == NULL)
390             {
391                 result.AppendError ("invalid target, create a debug target using the 'target create' command");
392                 result.SetStatus (eReturnStatusFailed);
393                 return false;
394             }
395 
396             Module *exe_module = target->GetExecutableModulePointer();
397             if (exe_module)
398             {
399                 m_options.launch_info.GetExecutableFile () = exe_module->GetFileSpec();
400                 char exe_path[PATH_MAX];
401                 if (m_options.launch_info.GetExecutableFile ().GetPath (exe_path, sizeof(exe_path)))
402                     m_options.launch_info.GetArguments().AppendArgument (exe_path);
403                 m_options.launch_info.GetArchitecture() = exe_module->GetArchitecture();
404             }
405 
406             if (argc > 0)
407             {
408                 if (m_options.launch_info.GetExecutableFile ())
409                 {
410                     // We already have an executable file, so we will use this
411                     // and all arguments to this function are extra arguments
412                     m_options.launch_info.GetArguments().AppendArguments (args);
413                 }
414                 else
415                 {
416                     // We don't have any file yet, so the first argument is our
417                     // executable, and the rest are program arguments
418                     const bool first_arg_is_executable = true;
419                     m_options.launch_info.SetArguments (args, first_arg_is_executable);
420                 }
421             }
422 
423             if (m_options.launch_info.GetExecutableFile ())
424             {
425                 Debugger &debugger = m_interpreter.GetDebugger();
426 
427                 if (argc == 0)
428                     target->GetRunArguments(m_options.launch_info.GetArguments());
429 
430                 ProcessSP process_sp (platform_sp->DebugProcess (m_options.launch_info,
431                                                                  debugger,
432                                                                  target,
433                                                                  debugger.GetListener(),
434                                                                  error));
435                 if (process_sp && process_sp->IsAlive())
436                 {
437                     result.SetStatus (eReturnStatusSuccessFinishNoResult);
438                     return true;
439                 }
440 
441                 if (error.Success())
442                     result.AppendError ("process launch failed");
443                 else
444                     result.AppendError (error.AsCString());
445                 result.SetStatus (eReturnStatusFailed);
446             }
447             else
448             {
449                 result.AppendError ("'platform process launch' uses the current target file and arguments, or the executable and its arguments can be specified in this command");
450                 result.SetStatus (eReturnStatusFailed);
451                 return false;
452             }
453         }
454         else
455         {
456             result.AppendError ("no platform is selected\n");
457         }
458         return result.Succeeded();
459     }
460 
461 protected:
462     ProcessLaunchCommandOptions m_options;
463 };
464 
465 
466 
467 //----------------------------------------------------------------------
468 // "platform process list"
469 //----------------------------------------------------------------------
470 class CommandObjectPlatformProcessList : public CommandObjectParsed
471 {
472 public:
473     CommandObjectPlatformProcessList (CommandInterpreter &interpreter) :
474         CommandObjectParsed (interpreter,
475                              "platform process list",
476                              "List processes on a remote platform by name, pid, or many other matching attributes.",
477                              "platform process list",
478                              0),
479         m_options (interpreter)
480     {
481     }
482 
483     virtual
484     ~CommandObjectPlatformProcessList ()
485     {
486     }
487 
488     virtual Options *
489     GetOptions ()
490     {
491         return &m_options;
492     }
493 
494 protected:
495     virtual bool
496     DoExecute (Args& args, CommandReturnObject &result)
497     {
498         PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
499 
500         if (platform_sp)
501         {
502             Error error;
503             if (args.GetArgumentCount() == 0)
504             {
505 
506                 if (platform_sp)
507                 {
508                     Stream &ostrm = result.GetOutputStream();
509 
510                     lldb::pid_t pid = m_options.match_info.GetProcessInfo().GetProcessID();
511                     if (pid != LLDB_INVALID_PROCESS_ID)
512                     {
513                         ProcessInstanceInfo proc_info;
514                         if (platform_sp->GetProcessInfo (pid, proc_info))
515                         {
516                             ProcessInstanceInfo::DumpTableHeader (ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
517                             proc_info.DumpAsTableRow(ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
518                             result.SetStatus (eReturnStatusSuccessFinishResult);
519                         }
520                         else
521                         {
522                             result.AppendErrorWithFormat ("no process found with pid = %llu\n", pid);
523                             result.SetStatus (eReturnStatusFailed);
524                         }
525                     }
526                     else
527                     {
528                         ProcessInstanceInfoList proc_infos;
529                         const uint32_t matches = platform_sp->FindProcesses (m_options.match_info, proc_infos);
530                         const char *match_desc = NULL;
531                         const char *match_name = m_options.match_info.GetProcessInfo().GetName();
532                         if (match_name && match_name[0])
533                         {
534                             switch (m_options.match_info.GetNameMatchType())
535                             {
536                                 case eNameMatchIgnore: break;
537                                 case eNameMatchEquals: match_desc = "matched"; break;
538                                 case eNameMatchContains: match_desc = "contained"; break;
539                                 case eNameMatchStartsWith: match_desc = "started with"; break;
540                                 case eNameMatchEndsWith: match_desc = "ended with"; break;
541                                 case eNameMatchRegularExpression: match_desc = "matched the regular expression"; break;
542                             }
543                         }
544 
545                         if (matches == 0)
546                         {
547                             if (match_desc)
548                                 result.AppendErrorWithFormat ("no processes were found that %s \"%s\" on the \"%s\" platform\n",
549                                                               match_desc,
550                                                               match_name,
551                                                               platform_sp->GetShortPluginName());
552                             else
553                                 result.AppendErrorWithFormat ("no processes were found on the \"%s\" platform\n", platform_sp->GetShortPluginName());
554                             result.SetStatus (eReturnStatusFailed);
555                         }
556                         else
557                         {
558                             result.AppendMessageWithFormat ("%u matching process%s found on \"%s\"",
559                                                             matches,
560                                                             matches > 1 ? "es were" : " was",
561                                                             platform_sp->GetName());
562                             if (match_desc)
563                                 result.AppendMessageWithFormat (" whose name %s \"%s\"",
564                                                                 match_desc,
565                                                                 match_name);
566                             result.AppendMessageWithFormat ("\n");
567                             ProcessInstanceInfo::DumpTableHeader (ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
568                             for (uint32_t i=0; i<matches; ++i)
569                             {
570                                 proc_infos.GetProcessInfoAtIndex(i).DumpAsTableRow(ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
571                             }
572                         }
573                     }
574                 }
575             }
576             else
577             {
578                 result.AppendError ("invalid args: process list takes only options\n");
579                 result.SetStatus (eReturnStatusFailed);
580             }
581         }
582         else
583         {
584             result.AppendError ("no platform is selected\n");
585             result.SetStatus (eReturnStatusFailed);
586         }
587         return result.Succeeded();
588     }
589 
590     class CommandOptions : public Options
591     {
592     public:
593 
594         CommandOptions (CommandInterpreter &interpreter) :
595             Options (interpreter),
596             match_info ()
597         {
598         }
599 
600         virtual
601         ~CommandOptions ()
602         {
603         }
604 
605         virtual Error
606         SetOptionValue (uint32_t option_idx, const char *option_arg)
607         {
608             Error error;
609             char short_option = (char) m_getopt_table[option_idx].val;
610             bool success = false;
611 
612             switch (short_option)
613             {
614                 case 'p':
615                     match_info.GetProcessInfo().SetProcessID (Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success));
616                     if (!success)
617                         error.SetErrorStringWithFormat("invalid process ID string: '%s'", option_arg);
618                     break;
619 
620                 case 'P':
621                     match_info.GetProcessInfo().SetParentProcessID (Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success));
622                     if (!success)
623                         error.SetErrorStringWithFormat("invalid parent process ID string: '%s'", option_arg);
624                     break;
625 
626                 case 'u':
627                     match_info.GetProcessInfo().SetUserID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
628                     if (!success)
629                         error.SetErrorStringWithFormat("invalid user ID string: '%s'", option_arg);
630                     break;
631 
632                 case 'U':
633                     match_info.GetProcessInfo().SetEffectiveUserID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
634                     if (!success)
635                         error.SetErrorStringWithFormat("invalid effective user ID string: '%s'", option_arg);
636                     break;
637 
638                 case 'g':
639                     match_info.GetProcessInfo().SetGroupID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
640                     if (!success)
641                         error.SetErrorStringWithFormat("invalid group ID string: '%s'", option_arg);
642                     break;
643 
644                 case 'G':
645                     match_info.GetProcessInfo().SetEffectiveGroupID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
646                     if (!success)
647                         error.SetErrorStringWithFormat("invalid effective group ID string: '%s'", option_arg);
648                     break;
649 
650                 case 'a':
651                     match_info.GetProcessInfo().GetArchitecture().SetTriple (option_arg, m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform().get());
652                     break;
653 
654                 case 'n':
655                     match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
656                     match_info.SetNameMatchType (eNameMatchEquals);
657                     break;
658 
659                 case 'e':
660                     match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
661                     match_info.SetNameMatchType (eNameMatchEndsWith);
662                     break;
663 
664                 case 's':
665                     match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
666                     match_info.SetNameMatchType (eNameMatchStartsWith);
667                     break;
668 
669                 case 'c':
670                     match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
671                     match_info.SetNameMatchType (eNameMatchContains);
672                     break;
673 
674                 case 'r':
675                     match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
676                     match_info.SetNameMatchType (eNameMatchRegularExpression);
677                     break;
678 
679                 case 'A':
680                     show_args = true;
681                     break;
682 
683                 case 'v':
684                     verbose = true;
685                     break;
686 
687                 default:
688                     error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
689                     break;
690             }
691 
692             return error;
693         }
694 
695         void
696         OptionParsingStarting ()
697         {
698             match_info.Clear();
699             show_args = false;
700             verbose = false;
701         }
702 
703         const OptionDefinition*
704         GetDefinitions ()
705         {
706             return g_option_table;
707         }
708 
709         // Options table: Required for subclasses of Options.
710 
711         static OptionDefinition g_option_table[];
712 
713         // Instance variables to hold the values for command options.
714 
715         ProcessInstanceInfoMatch match_info;
716         bool show_args;
717         bool verbose;
718     };
719     CommandOptions m_options;
720 };
721 
722 OptionDefinition
723 CommandObjectPlatformProcessList::CommandOptions::g_option_table[] =
724 {
725 {   LLDB_OPT_SET_1, false, "pid"              , 'p', required_argument, NULL, 0, eArgTypePid          , "List the process info for a specific process ID." },
726 {   LLDB_OPT_SET_2, true , "name"             , 'n', required_argument, NULL, 0, eArgTypeProcessName  , "Find processes with executable basenames that match a string." },
727 {   LLDB_OPT_SET_3, true , "ends-with"        , 'e', required_argument, NULL, 0, eArgTypeNone         , "Find processes with executable basenames that end with a string." },
728 {   LLDB_OPT_SET_4, true , "starts-with"      , 's', required_argument, NULL, 0, eArgTypeNone         , "Find processes with executable basenames that start with a string." },
729 {   LLDB_OPT_SET_5, true , "contains"         , 'c', required_argument, NULL, 0, eArgTypeNone         , "Find processes with executable basenames that contain a string." },
730 {   LLDB_OPT_SET_6, true , "regex"            , 'r', required_argument, NULL, 0, eArgTypeNone         , "Find processes with executable basenames that match a regular expression." },
731 {  ~LLDB_OPT_SET_1, false, "parent"           , 'P', required_argument, NULL, 0, eArgTypePid          , "Find processes that have a matching parent process ID." },
732 {  ~LLDB_OPT_SET_1, false, "uid"              , 'u', required_argument, NULL, 0, eArgTypeNone         , "Find processes that have a matching user ID." },
733 {  ~LLDB_OPT_SET_1, false, "euid"             , 'U', required_argument, NULL, 0, eArgTypeNone         , "Find processes that have a matching effective user ID." },
734 {  ~LLDB_OPT_SET_1, false, "gid"              , 'g', required_argument, NULL, 0, eArgTypeNone         , "Find processes that have a matching group ID." },
735 {  ~LLDB_OPT_SET_1, false, "egid"             , 'G', required_argument, NULL, 0, eArgTypeNone         , "Find processes that have a matching effective group ID." },
736 {  ~LLDB_OPT_SET_1, false, "arch"             , 'a', required_argument, NULL, 0, eArgTypeArchitecture , "Find processes that have a matching architecture." },
737 { LLDB_OPT_SET_ALL, false, "show-args"        , 'A', no_argument      , NULL, 0, eArgTypeNone         , "Show process arguments instead of the process executable basename." },
738 { LLDB_OPT_SET_ALL, false, "verbose"          , 'v', no_argument      , NULL, 0, eArgTypeNone         , "Enable verbose output." },
739 {  0              , false, NULL               ,  0 , 0                , NULL, 0, eArgTypeNone         , NULL }
740 };
741 
742 //----------------------------------------------------------------------
743 // "platform process info"
744 //----------------------------------------------------------------------
745 class CommandObjectPlatformProcessInfo : public CommandObjectParsed
746 {
747 public:
748     CommandObjectPlatformProcessInfo (CommandInterpreter &interpreter) :
749     CommandObjectParsed (interpreter,
750                          "platform process info",
751                          "Get detailed information for one or more process by process ID.",
752                          "platform process info <pid> [<pid> <pid> ...]",
753                          0)
754     {
755         CommandArgumentEntry arg;
756         CommandArgumentData pid_args;
757 
758         // Define the first (and only) variant of this arg.
759         pid_args.arg_type = eArgTypePid;
760         pid_args.arg_repetition = eArgRepeatStar;
761 
762         // There is only one variant this argument could be; put it into the argument entry.
763         arg.push_back (pid_args);
764 
765         // Push the data for the first argument into the m_arguments vector.
766         m_arguments.push_back (arg);
767     }
768 
769     virtual
770     ~CommandObjectPlatformProcessInfo ()
771     {
772     }
773 
774 protected:
775     virtual bool
776     DoExecute (Args& args, CommandReturnObject &result)
777     {
778         PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
779         if (platform_sp)
780         {
781             const size_t argc = args.GetArgumentCount();
782             if (argc > 0)
783             {
784                 Error error;
785 
786                 if (platform_sp->IsConnected())
787                 {
788                     Stream &ostrm = result.GetOutputStream();
789                     bool success;
790                     for (size_t i=0; i<argc; ++ i)
791                     {
792                         const char *arg = args.GetArgumentAtIndex(i);
793                         lldb::pid_t pid = Args::StringToUInt32 (arg, LLDB_INVALID_PROCESS_ID, 0, &success);
794                         if (success)
795                         {
796                             ProcessInstanceInfo proc_info;
797                             if (platform_sp->GetProcessInfo (pid, proc_info))
798                             {
799                                 ostrm.Printf ("Process information for process %llu:\n", pid);
800                                 proc_info.Dump (ostrm, platform_sp.get());
801                             }
802                             else
803                             {
804                                 ostrm.Printf ("error: no process information is available for process %llu\n", pid);
805                             }
806                             ostrm.EOL();
807                         }
808                         else
809                         {
810                             result.AppendErrorWithFormat ("invalid process ID argument '%s'", arg);
811                             result.SetStatus (eReturnStatusFailed);
812                             break;
813                         }
814                     }
815                 }
816                 else
817                 {
818                     // Not connected...
819                     result.AppendErrorWithFormat ("not connected to '%s'", platform_sp->GetShortPluginName());
820                     result.SetStatus (eReturnStatusFailed);
821                 }
822             }
823             else
824             {
825                 // No args
826                 result.AppendError ("one or more process id(s) must be specified");
827                 result.SetStatus (eReturnStatusFailed);
828             }
829         }
830         else
831         {
832             result.AppendError ("no platform is currently selected");
833             result.SetStatus (eReturnStatusFailed);
834         }
835         return result.Succeeded();
836     }
837 };
838 
839 
840 
841 
842 class CommandObjectPlatformProcess : public CommandObjectMultiword
843 {
844 public:
845     //------------------------------------------------------------------
846     // Constructors and Destructors
847     //------------------------------------------------------------------
848      CommandObjectPlatformProcess (CommandInterpreter &interpreter) :
849         CommandObjectMultiword (interpreter,
850                                 "platform process",
851                                 "A set of commands to query, launch and attach to platform processes",
852                                 "platform process [attach|launch|list] ...")
853     {
854 //        LoadSubCommand ("attach", CommandObjectSP (new CommandObjectPlatformProcessAttach (interpreter)));
855         LoadSubCommand ("launch", CommandObjectSP (new CommandObjectPlatformProcessLaunch (interpreter)));
856         LoadSubCommand ("info"  , CommandObjectSP (new CommandObjectPlatformProcessInfo (interpreter)));
857         LoadSubCommand ("list"  , CommandObjectSP (new CommandObjectPlatformProcessList (interpreter)));
858 
859     }
860 
861     virtual
862     ~CommandObjectPlatformProcess ()
863     {
864     }
865 
866 private:
867     //------------------------------------------------------------------
868     // For CommandObjectPlatform only
869     //------------------------------------------------------------------
870     DISALLOW_COPY_AND_ASSIGN (CommandObjectPlatformProcess);
871 };
872 
873 
874 class CommandObjectPlatformShell : public CommandObjectRaw
875 {
876 public:
877     CommandObjectPlatformShell (CommandInterpreter &interpreter) :
878         CommandObjectRaw (interpreter,
879                          "platform shell",
880                          "Run a shell command on a the selected platform.",
881                          "platform shell <shell-command>",
882                          0)
883     {
884     }
885 
886     virtual
887     ~CommandObjectPlatformShell ()
888     {
889     }
890 
891 protected:
892     virtual bool
893     DoExecute (const char *raw_command_line, CommandReturnObject &result)
894     {
895         // TODO: Implement "Platform::RunShellCommand()" and switch over to using
896         // the current platform when it is in the interface.
897         const char *working_dir = NULL;
898         std::string output;
899         int status = -1;
900         int signo = -1;
901         Error error (Host::RunShellCommand (raw_command_line, working_dir, &status, &signo, &output, 10));
902         if (!output.empty())
903             result.GetOutputStream().PutCString(output.c_str());
904         if (status > 0)
905         {
906             if (signo > 0)
907             {
908                 const char *signo_cstr = Host::GetSignalAsCString(signo);
909                 if (signo_cstr)
910                     result.GetOutputStream().Printf("error: command returned with status %i and signal %s\n", status, signo_cstr);
911                 else
912                     result.GetOutputStream().Printf("error: command returned with status %i and signal %i\n", status, signo);
913             }
914             else
915                 result.GetOutputStream().Printf("error: command returned with status %i\n", status);
916         }
917 
918         if (error.Fail())
919         {
920             result.AppendError(error.AsCString());
921             result.SetStatus (eReturnStatusFailed);
922         }
923         else
924         {
925             result.SetStatus (eReturnStatusSuccessFinishResult);
926         }
927         return true;
928     }
929 };
930 
931 //----------------------------------------------------------------------
932 // CommandObjectPlatform constructor
933 //----------------------------------------------------------------------
934 CommandObjectPlatform::CommandObjectPlatform(CommandInterpreter &interpreter) :
935     CommandObjectMultiword (interpreter,
936                             "platform",
937                             "A set of commands to manage and create platforms.",
938                             "platform [connect|disconnect|info|list|status|select] ...")
939 {
940     LoadSubCommand ("select", CommandObjectSP (new CommandObjectPlatformSelect  (interpreter)));
941     LoadSubCommand ("list"  , CommandObjectSP (new CommandObjectPlatformList    (interpreter)));
942     LoadSubCommand ("status", CommandObjectSP (new CommandObjectPlatformStatus  (interpreter)));
943     LoadSubCommand ("connect", CommandObjectSP (new CommandObjectPlatformConnect  (interpreter)));
944     LoadSubCommand ("disconnect", CommandObjectSP (new CommandObjectPlatformDisconnect  (interpreter)));
945     LoadSubCommand ("process", CommandObjectSP (new CommandObjectPlatformProcess  (interpreter)));
946     LoadSubCommand ("shell", CommandObjectSP (new CommandObjectPlatformShell  (interpreter)));
947 }
948 
949 
950 //----------------------------------------------------------------------
951 // Destructor
952 //----------------------------------------------------------------------
953 CommandObjectPlatform::~CommandObjectPlatform()
954 {
955 }
956