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