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