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