CommandObjectPlatform.cpp revision 36da2aa6dc5ad9994b638ed09eb81c44cc05540b
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
30using namespace lldb;
31using namespace lldb_private;
32
33
34//----------------------------------------------------------------------
35// "platform select <platform-name>"
36//----------------------------------------------------------------------
37class CommandObjectPlatformSelect : public CommandObjectParsed
38{
39public:
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
86protected:
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//----------------------------------------------------------------------
132class CommandObjectPlatformList : public CommandObjectParsed
133{
134public:
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
149protected:
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//----------------------------------------------------------------------
187class CommandObjectPlatformStatus : public CommandObjectParsed
188{
189public:
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
204protected:
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//----------------------------------------------------------------------
228class CommandObjectPlatformConnect : public CommandObjectParsed
229{
230public:
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
245protected:
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//----------------------------------------------------------------------
278class CommandObjectPlatformDisconnect : public CommandObjectParsed
279{
280public:
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
295protected:
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//----------------------------------------------------------------------
356class CommandObjectPlatformProcessLaunch : public CommandObjectParsed
357{
358public:
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
380protected:
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
456protected:
457    ProcessLaunchCommandOptions m_options;
458};
459
460
461
462//----------------------------------------------------------------------
463// "platform process list"
464//----------------------------------------------------------------------
465class CommandObjectPlatformProcessList : public CommandObjectParsed
466{
467public:
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
489protected:
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
717OptionDefinition
718CommandObjectPlatformProcessList::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//----------------------------------------------------------------------
740class CommandObjectPlatformProcessInfo : public CommandObjectParsed
741{
742public:
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
769protected:
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
837class CommandObjectPlatformProcess : public CommandObjectMultiword
838{
839public:
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
861private:
862    //------------------------------------------------------------------
863    // For CommandObjectPlatform only
864    //------------------------------------------------------------------
865    DISALLOW_COPY_AND_ASSIGN (CommandObjectPlatformProcess);
866};
867
868
869class CommandObjectPlatformShell : public CommandObjectRaw
870{
871public:
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
886protected:
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//----------------------------------------------------------------------
929CommandObjectPlatform::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//----------------------------------------------------------------------
948CommandObjectPlatform::~CommandObjectPlatform()
949{
950}
951