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