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                     target->GetRunArguments(m_options.launch_info.GetArguments());
430 
431                 ProcessSP process_sp (platform_sp->DebugProcess (m_options.launch_info,
432                                                                  debugger,
433                                                                  target,
434                                                                  debugger.GetListener(),
435                                                                  error));
436                 if (process_sp && process_sp->IsAlive())
437                 {
438                     result.SetStatus (eReturnStatusSuccessFinishNoResult);
439                     return true;
440                 }
441 
442                 if (error.Success())
443                     result.AppendError ("process launch failed");
444                 else
445                     result.AppendError (error.AsCString());
446                 result.SetStatus (eReturnStatusFailed);
447             }
448             else
449             {
450                 result.AppendError ("'platform process launch' uses the current target file and arguments, or the executable and its arguments can be specified in this command");
451                 result.SetStatus (eReturnStatusFailed);
452                 return false;
453             }
454         }
455         else
456         {
457             result.AppendError ("no platform is selected\n");
458         }
459         return result.Succeeded();
460     }
461 
462 protected:
463     ProcessLaunchCommandOptions m_options;
464 };
465 
466 
467 
468 //----------------------------------------------------------------------
469 // "platform process list"
470 //----------------------------------------------------------------------
471 class CommandObjectPlatformProcessList : public CommandObjectParsed
472 {
473 public:
474     CommandObjectPlatformProcessList (CommandInterpreter &interpreter) :
475         CommandObjectParsed (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 Options *
490     GetOptions ()
491     {
492         return &m_options;
493     }
494 
495 protected:
496     virtual bool
497     DoExecute (Args& args, CommandReturnObject &result)
498     {
499         PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
500 
501         if (platform_sp)
502         {
503             Error error;
504             if (args.GetArgumentCount() == 0)
505             {
506 
507                 if (platform_sp)
508                 {
509                     Stream &ostrm = result.GetOutputStream();
510 
511                     lldb::pid_t pid = m_options.match_info.GetProcessInfo().GetProcessID();
512                     if (pid != LLDB_INVALID_PROCESS_ID)
513                     {
514                         ProcessInstanceInfo proc_info;
515                         if (platform_sp->GetProcessInfo (pid, proc_info))
516                         {
517                             ProcessInstanceInfo::DumpTableHeader (ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
518                             proc_info.DumpAsTableRow(ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
519                             result.SetStatus (eReturnStatusSuccessFinishResult);
520                         }
521                         else
522                         {
523                             result.AppendErrorWithFormat ("no process found with pid = %llu\n", pid);
524                             result.SetStatus (eReturnStatusFailed);
525                         }
526                     }
527                     else
528                     {
529                         ProcessInstanceInfoList proc_infos;
530                         const uint32_t matches = platform_sp->FindProcesses (m_options.match_info, proc_infos);
531                         const char *match_desc = NULL;
532                         const char *match_name = m_options.match_info.GetProcessInfo().GetName();
533                         if (match_name && match_name[0])
534                         {
535                             switch (m_options.match_info.GetNameMatchType())
536                             {
537                                 case eNameMatchIgnore: break;
538                                 case eNameMatchEquals: match_desc = "matched"; break;
539                                 case eNameMatchContains: match_desc = "contained"; break;
540                                 case eNameMatchStartsWith: match_desc = "started with"; break;
541                                 case eNameMatchEndsWith: match_desc = "ended with"; break;
542                                 case eNameMatchRegularExpression: match_desc = "matched the regular expression"; break;
543                             }
544                         }
545 
546                         if (matches == 0)
547                         {
548                             if (match_desc)
549                                 result.AppendErrorWithFormat ("no processes were found that %s \"%s\" on the \"%s\" platform\n",
550                                                               match_desc,
551                                                               match_name,
552                                                               platform_sp->GetShortPluginName());
553                             else
554                                 result.AppendErrorWithFormat ("no processes were found on the \"%s\" platform\n", platform_sp->GetShortPluginName());
555                             result.SetStatus (eReturnStatusFailed);
556                         }
557                         else
558                         {
559                             result.AppendMessageWithFormat ("%u matching process%s found on \"%s\"",
560                                                             matches,
561                                                             matches > 1 ? "es were" : " was",
562                                                             platform_sp->GetName());
563                             if (match_desc)
564                                 result.AppendMessageWithFormat (" whose name %s \"%s\"",
565                                                                 match_desc,
566                                                                 match_name);
567                             result.AppendMessageWithFormat ("\n");
568                             ProcessInstanceInfo::DumpTableHeader (ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
569                             for (uint32_t i=0; i<matches; ++i)
570                             {
571                                 proc_infos.GetProcessInfoAtIndex(i).DumpAsTableRow(ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
572                             }
573                         }
574                     }
575                 }
576             }
577             else
578             {
579                 result.AppendError ("invalid args: process list takes only options\n");
580                 result.SetStatus (eReturnStatusFailed);
581             }
582         }
583         else
584         {
585             result.AppendError ("no platform is selected\n");
586             result.SetStatus (eReturnStatusFailed);
587         }
588         return result.Succeeded();
589     }
590 
591     class CommandOptions : public Options
592     {
593     public:
594 
595         CommandOptions (CommandInterpreter &interpreter) :
596             Options (interpreter),
597             match_info ()
598         {
599         }
600 
601         virtual
602         ~CommandOptions ()
603         {
604         }
605 
606         virtual Error
607         SetOptionValue (uint32_t option_idx, const char *option_arg)
608         {
609             Error error;
610             char short_option = (char) m_getopt_table[option_idx].val;
611             bool success = false;
612 
613             switch (short_option)
614             {
615                 case 'p':
616                     match_info.GetProcessInfo().SetProcessID (Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success));
617                     if (!success)
618                         error.SetErrorStringWithFormat("invalid process ID string: '%s'", option_arg);
619                     break;
620 
621                 case 'P':
622                     match_info.GetProcessInfo().SetParentProcessID (Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success));
623                     if (!success)
624                         error.SetErrorStringWithFormat("invalid parent process ID string: '%s'", option_arg);
625                     break;
626 
627                 case 'u':
628                     match_info.GetProcessInfo().SetUserID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
629                     if (!success)
630                         error.SetErrorStringWithFormat("invalid user ID string: '%s'", option_arg);
631                     break;
632 
633                 case 'U':
634                     match_info.GetProcessInfo().SetEffectiveUserID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
635                     if (!success)
636                         error.SetErrorStringWithFormat("invalid effective user ID string: '%s'", option_arg);
637                     break;
638 
639                 case 'g':
640                     match_info.GetProcessInfo().SetGroupID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
641                     if (!success)
642                         error.SetErrorStringWithFormat("invalid group ID string: '%s'", option_arg);
643                     break;
644 
645                 case 'G':
646                     match_info.GetProcessInfo().SetEffectiveGroupID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
647                     if (!success)
648                         error.SetErrorStringWithFormat("invalid effective group ID string: '%s'", option_arg);
649                     break;
650 
651                 case 'a':
652                     match_info.GetProcessInfo().GetArchitecture().SetTriple (option_arg, m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform().get());
653                     break;
654 
655                 case 'n':
656                     match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
657                     match_info.SetNameMatchType (eNameMatchEquals);
658                     break;
659 
660                 case 'e':
661                     match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
662                     match_info.SetNameMatchType (eNameMatchEndsWith);
663                     break;
664 
665                 case 's':
666                     match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
667                     match_info.SetNameMatchType (eNameMatchStartsWith);
668                     break;
669 
670                 case 'c':
671                     match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
672                     match_info.SetNameMatchType (eNameMatchContains);
673                     break;
674 
675                 case 'r':
676                     match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
677                     match_info.SetNameMatchType (eNameMatchRegularExpression);
678                     break;
679 
680                 case 'A':
681                     show_args = true;
682                     break;
683 
684                 case 'v':
685                     verbose = true;
686                     break;
687 
688                 default:
689                     error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
690                     break;
691             }
692 
693             return error;
694         }
695 
696         void
697         OptionParsingStarting ()
698         {
699             match_info.Clear();
700             show_args = false;
701             verbose = false;
702         }
703 
704         const OptionDefinition*
705         GetDefinitions ()
706         {
707             return g_option_table;
708         }
709 
710         // Options table: Required for subclasses of Options.
711 
712         static OptionDefinition g_option_table[];
713 
714         // Instance variables to hold the values for command options.
715 
716         ProcessInstanceInfoMatch match_info;
717         bool show_args;
718         bool verbose;
719     };
720     CommandOptions m_options;
721 };
722 
723 OptionDefinition
724 CommandObjectPlatformProcessList::CommandOptions::g_option_table[] =
725 {
726 {   LLDB_OPT_SET_1, false, "pid"              , 'p', required_argument, NULL, 0, eArgTypePid          , "List the process info for a specific process ID." },
727 {   LLDB_OPT_SET_2, true , "name"             , 'n', required_argument, NULL, 0, eArgTypeProcessName  , "Find processes with executable basenames that match a string." },
728 {   LLDB_OPT_SET_3, true , "ends-with"        , 'e', required_argument, NULL, 0, eArgTypeNone         , "Find processes with executable basenames that end with a string." },
729 {   LLDB_OPT_SET_4, true , "starts-with"      , 's', required_argument, NULL, 0, eArgTypeNone         , "Find processes with executable basenames that start with a string." },
730 {   LLDB_OPT_SET_5, true , "contains"         , 'c', required_argument, NULL, 0, eArgTypeNone         , "Find processes with executable basenames that contain a string." },
731 {   LLDB_OPT_SET_6, true , "regex"            , 'r', required_argument, NULL, 0, eArgTypeNone         , "Find processes with executable basenames that match a regular expression." },
732 {  ~LLDB_OPT_SET_1, false, "parent"           , 'P', required_argument, NULL, 0, eArgTypePid          , "Find processes that have a matching parent process ID." },
733 {  ~LLDB_OPT_SET_1, false, "uid"              , 'u', required_argument, NULL, 0, eArgTypeNone         , "Find processes that have a matching user ID." },
734 {  ~LLDB_OPT_SET_1, false, "euid"             , 'U', required_argument, NULL, 0, eArgTypeNone         , "Find processes that have a matching effective user ID." },
735 {  ~LLDB_OPT_SET_1, false, "gid"              , 'g', required_argument, NULL, 0, eArgTypeNone         , "Find processes that have a matching group ID." },
736 {  ~LLDB_OPT_SET_1, false, "egid"             , 'G', required_argument, NULL, 0, eArgTypeNone         , "Find processes that have a matching effective group ID." },
737 {  ~LLDB_OPT_SET_1, false, "arch"             , 'a', required_argument, NULL, 0, eArgTypeArchitecture , "Find processes that have a matching architecture." },
738 { LLDB_OPT_SET_ALL, false, "show-args"        , 'A', no_argument      , NULL, 0, eArgTypeNone         , "Show process arguments instead of the process executable basename." },
739 { LLDB_OPT_SET_ALL, false, "verbose"          , 'v', no_argument      , NULL, 0, eArgTypeNone         , "Enable verbose output." },
740 {  0              , false, NULL               ,  0 , 0                , NULL, 0, eArgTypeNone         , NULL }
741 };
742 
743 //----------------------------------------------------------------------
744 // "platform process info"
745 //----------------------------------------------------------------------
746 class CommandObjectPlatformProcessInfo : public CommandObjectParsed
747 {
748 public:
749     CommandObjectPlatformProcessInfo (CommandInterpreter &interpreter) :
750     CommandObjectParsed (interpreter,
751                          "platform process info",
752                          "Get detailed information for one or more process by process ID.",
753                          "platform process info <pid> [<pid> <pid> ...]",
754                          0)
755     {
756         CommandArgumentEntry arg;
757         CommandArgumentData pid_args;
758 
759         // Define the first (and only) variant of this arg.
760         pid_args.arg_type = eArgTypePid;
761         pid_args.arg_repetition = eArgRepeatStar;
762 
763         // There is only one variant this argument could be; put it into the argument entry.
764         arg.push_back (pid_args);
765 
766         // Push the data for the first argument into the m_arguments vector.
767         m_arguments.push_back (arg);
768     }
769 
770     virtual
771     ~CommandObjectPlatformProcessInfo ()
772     {
773     }
774 
775 protected:
776     virtual bool
777     DoExecute (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 CommandObjectRaw
876 {
877 public:
878     CommandObjectPlatformShell (CommandInterpreter &interpreter) :
879         CommandObjectRaw (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 protected:
893     virtual bool
894     DoExecute (const char *raw_command_line, CommandReturnObject &result)
895     {
896         // TODO: Implement "Platform::RunShellCommand()" and switch over to using
897         // the current platform when it is in the interface.
898         const char *working_dir = NULL;
899         std::string output;
900         int status = -1;
901         int signo = -1;
902         Error error (Host::RunShellCommand (raw_command_line, working_dir, &status, &signo, &output, 10));
903         if (!output.empty())
904             result.GetOutputStream().PutCString(output.c_str());
905         if (status > 0)
906         {
907             if (signo > 0)
908             {
909                 const char *signo_cstr = Host::GetSignalAsCString(signo);
910                 if (signo_cstr)
911                     result.GetOutputStream().Printf("error: command returned with status %i and signal %s\n", status, signo_cstr);
912                 else
913                     result.GetOutputStream().Printf("error: command returned with status %i and signal %i\n", status, signo);
914             }
915             else
916                 result.GetOutputStream().Printf("error: command returned with status %i\n", status);
917         }
918 
919         if (error.Fail())
920         {
921             result.AppendError(error.AsCString());
922             result.SetStatus (eReturnStatusFailed);
923         }
924         else
925         {
926             result.SetStatus (eReturnStatusSuccessFinishResult);
927         }
928         return true;
929     }
930 };
931 
932 //----------------------------------------------------------------------
933 // CommandObjectPlatform constructor
934 //----------------------------------------------------------------------
935 CommandObjectPlatform::CommandObjectPlatform(CommandInterpreter &interpreter) :
936     CommandObjectMultiword (interpreter,
937                             "platform",
938                             "A set of commands to manage and create platforms.",
939                             "platform [connect|disconnect|info|list|status|select] ...")
940 {
941     LoadSubCommand ("select", CommandObjectSP (new CommandObjectPlatformSelect  (interpreter)));
942     LoadSubCommand ("list"  , CommandObjectSP (new CommandObjectPlatformList    (interpreter)));
943     LoadSubCommand ("status", CommandObjectSP (new CommandObjectPlatformStatus  (interpreter)));
944     LoadSubCommand ("connect", CommandObjectSP (new CommandObjectPlatformConnect  (interpreter)));
945     LoadSubCommand ("disconnect", CommandObjectSP (new CommandObjectPlatformDisconnect  (interpreter)));
946     LoadSubCommand ("process", CommandObjectSP (new CommandObjectPlatformProcess  (interpreter)));
947     LoadSubCommand ("shell", CommandObjectSP (new CommandObjectPlatformShell  (interpreter)));
948 }
949 
950 
951 //----------------------------------------------------------------------
952 // Destructor
953 //----------------------------------------------------------------------
954 CommandObjectPlatform::~CommandObjectPlatform()
955 {
956 }
957