CommandObjectPlatform.cpp revision 263363
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#include "lldb/Utility/Utils.h"
30
31using namespace lldb;
32using namespace lldb_private;
33
34static mode_t
35ParsePermissionString(const char* permissions)
36{
37    if (strlen(permissions) != 9)
38        return (mode_t)(-1);
39    bool user_r,user_w,user_x,
40    group_r,group_w,group_x,
41    world_r,world_w,world_x;
42
43    user_r = (permissions[0] == 'r');
44    user_w = (permissions[1] == 'w');
45    user_x = (permissions[2] == 'x');
46
47    group_r = (permissions[3] == 'r');
48    group_w = (permissions[4] == 'w');
49    group_x = (permissions[5] == 'x');
50
51    world_r = (permissions[6] == 'r');
52    world_w = (permissions[7] == 'w');
53    world_x = (permissions[8] == 'x');
54
55    mode_t user,group,world;
56    user = (user_r ? 4 : 0) | (user_w ? 2 : 0) | (user_x ? 1 : 0);
57    group = (group_r ? 4 : 0) | (group_w ? 2 : 0) | (group_x ? 1 : 0);
58    world = (world_r ? 4 : 0) | (world_w ? 2 : 0) | (world_x ? 1 : 0);
59
60    return user | group | world;
61}
62
63static OptionDefinition
64g_permissions_options[] =
65{
66    {   LLDB_OPT_SET_ALL, false, "permissions-value", 'v', OptionParser::eRequiredArgument,       NULL, 0, eArgTypePermissionsNumber         , "Give out the numeric value for permissions (e.g. 757)" },
67    {   LLDB_OPT_SET_ALL, false, "permissions-string",'s', OptionParser::eRequiredArgument, NULL, 0, eArgTypePermissionsString  , "Give out the string value for permissions (e.g. rwxr-xr--)." },
68    {   LLDB_OPT_SET_ALL, false, "user-read", 'r', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone         , "Allow user to read." },
69    {   LLDB_OPT_SET_ALL, false, "user-write", 'w', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone         , "Allow user to write." },
70    {   LLDB_OPT_SET_ALL, false, "user-exec", 'x', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone         , "Allow user to execute." },
71
72    {   LLDB_OPT_SET_ALL, false, "group-read", 'R', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone         , "Allow group to read." },
73    {   LLDB_OPT_SET_ALL, false, "group-write", 'W', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone         , "Allow group to write." },
74    {   LLDB_OPT_SET_ALL, false, "group-exec", 'X', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone         , "Allow group to execute." },
75
76    {   LLDB_OPT_SET_ALL, false, "world-read", 'd', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone         , "Allow world to read." },
77    {   LLDB_OPT_SET_ALL, false, "world-write", 't', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone         , "Allow world to write." },
78    {   LLDB_OPT_SET_ALL, false, "world-exec", 'e', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone         , "Allow world to execute." },
79
80};
81
82class OptionPermissions : public lldb_private::OptionGroup
83{
84public:
85    OptionPermissions ()
86    {
87    }
88
89    virtual
90    ~OptionPermissions ()
91    {
92    }
93
94    virtual lldb_private::Error
95    SetOptionValue (CommandInterpreter &interpreter,
96                    uint32_t option_idx,
97                    const char *option_arg)
98    {
99        Error error;
100        char short_option = (char) GetDefinitions()[option_idx].short_option;
101        switch (short_option)
102        {
103            case 'v':
104            {
105                bool ok;
106                uint32_t perms = Args::StringToUInt32(option_arg, 777, 8, &ok);
107                if (!ok)
108                    error.SetErrorStringWithFormat("invalid value for permissions: %s", option_arg);
109                else
110                    m_permissions = perms;
111            }
112                break;
113            case 's':
114            {
115                mode_t perms = ParsePermissionString(option_arg);
116                if (perms == (mode_t)-1)
117                    error.SetErrorStringWithFormat("invalid value for permissions: %s", option_arg);
118                else
119                    m_permissions = perms;
120            }
121            case 'r':
122                m_permissions |= File::ePermissionsUserRead;
123                break;
124            case 'w':
125                m_permissions |= File::ePermissionsUserWrite;
126                break;
127            case 'x':
128                m_permissions |= File::ePermissionsUserExecute;
129                break;
130            case 'R':
131                m_permissions |= File::ePermissionsGroupRead;
132                break;
133            case 'W':
134                m_permissions |= File::ePermissionsGroupWrite;
135                break;
136            case 'X':
137                m_permissions |= File::ePermissionsGroupExecute;
138                break;
139            case 'd':
140                m_permissions |= File::ePermissionsWorldRead;
141                break;
142            case 't':
143                m_permissions |= File::ePermissionsWorldWrite;
144                break;
145            case 'e':
146                m_permissions |= File::ePermissionsWorldExecute;
147                break;
148
149            default:
150                error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
151                break;
152        }
153
154        return error;
155    }
156
157    void
158    OptionParsingStarting (CommandInterpreter &interpreter)
159    {
160        m_permissions = 0;
161    }
162
163    virtual uint32_t
164    GetNumDefinitions ()
165    {
166        return llvm::array_lengthof(g_permissions_options);
167    }
168
169    const lldb_private::OptionDefinition*
170    GetDefinitions ()
171    {
172        return g_permissions_options;
173    }
174
175    // Instance variables to hold the values for command options.
176
177    uint32_t m_permissions;
178private:
179    DISALLOW_COPY_AND_ASSIGN(OptionPermissions);
180};
181
182//----------------------------------------------------------------------
183// "platform select <platform-name>"
184//----------------------------------------------------------------------
185class CommandObjectPlatformSelect : public CommandObjectParsed
186{
187public:
188    CommandObjectPlatformSelect (CommandInterpreter &interpreter) :
189        CommandObjectParsed (interpreter,
190                             "platform select",
191                             "Create a platform if needed and select it as the current platform.",
192                             "platform select <platform-name>",
193                             0),
194        m_option_group (interpreter),
195        m_platform_options (false) // Don't include the "--platform" option by passing false
196    {
197        m_option_group.Append (&m_platform_options, LLDB_OPT_SET_ALL, 1);
198        m_option_group.Finalize();
199    }
200
201    virtual
202    ~CommandObjectPlatformSelect ()
203    {
204    }
205
206    virtual int
207    HandleCompletion (Args &input,
208                      int &cursor_index,
209                      int &cursor_char_position,
210                      int match_start_point,
211                      int max_return_elements,
212                      bool &word_complete,
213                      StringList &matches)
214    {
215        std::string completion_str (input.GetArgumentAtIndex(cursor_index));
216        completion_str.erase (cursor_char_position);
217
218        CommandCompletions::PlatformPluginNames (m_interpreter,
219                                                 completion_str.c_str(),
220                                                 match_start_point,
221                                                 max_return_elements,
222                                                 NULL,
223                                                 word_complete,
224                                                 matches);
225        return matches.GetSize();
226    }
227
228    virtual Options *
229    GetOptions ()
230    {
231        return &m_option_group;
232    }
233
234protected:
235    virtual bool
236    DoExecute (Args& args, CommandReturnObject &result)
237    {
238        if (args.GetArgumentCount() == 1)
239        {
240            const char *platform_name = args.GetArgumentAtIndex (0);
241            if (platform_name && platform_name[0])
242            {
243                const bool select = true;
244                m_platform_options.SetPlatformName (platform_name);
245                Error error;
246                ArchSpec platform_arch;
247                PlatformSP platform_sp (m_platform_options.CreatePlatformWithOptions (m_interpreter, ArchSpec(), select, error, platform_arch));
248                if (platform_sp)
249                {
250                    platform_sp->GetStatus (result.GetOutputStream());
251                    result.SetStatus (eReturnStatusSuccessFinishResult);
252                }
253                else
254                {
255                    result.AppendError(error.AsCString());
256                    result.SetStatus (eReturnStatusFailed);
257                }
258            }
259            else
260            {
261                result.AppendError ("invalid platform name");
262                result.SetStatus (eReturnStatusFailed);
263            }
264        }
265        else
266        {
267            result.AppendError ("platform create takes a platform name as an argument\n");
268            result.SetStatus (eReturnStatusFailed);
269        }
270        return result.Succeeded();
271    }
272
273    OptionGroupOptions m_option_group;
274    OptionGroupPlatform m_platform_options;
275};
276
277//----------------------------------------------------------------------
278// "platform list"
279//----------------------------------------------------------------------
280class CommandObjectPlatformList : public CommandObjectParsed
281{
282public:
283    CommandObjectPlatformList (CommandInterpreter &interpreter) :
284        CommandObjectParsed (interpreter,
285                             "platform list",
286                             "List all platforms that are available.",
287                             NULL,
288                             0)
289    {
290    }
291
292    virtual
293    ~CommandObjectPlatformList ()
294    {
295    }
296
297protected:
298    virtual bool
299    DoExecute (Args& args, CommandReturnObject &result)
300    {
301        Stream &ostrm = result.GetOutputStream();
302        ostrm.Printf("Available platforms:\n");
303
304        PlatformSP host_platform_sp (Platform::GetDefaultPlatform());
305        ostrm.Printf ("%s: %s\n",
306                      host_platform_sp->GetPluginName().GetCString(),
307                      host_platform_sp->GetDescription());
308
309        uint32_t idx;
310        for (idx = 0; 1; ++idx)
311        {
312            const char *plugin_name = PluginManager::GetPlatformPluginNameAtIndex (idx);
313            if (plugin_name == NULL)
314                break;
315            const char *plugin_desc = PluginManager::GetPlatformPluginDescriptionAtIndex (idx);
316            if (plugin_desc == NULL)
317                break;
318            ostrm.Printf("%s: %s\n", plugin_name, plugin_desc);
319        }
320
321        if (idx == 0)
322        {
323            result.AppendError ("no platforms are available\n");
324            result.SetStatus (eReturnStatusFailed);
325        }
326        else
327            result.SetStatus (eReturnStatusSuccessFinishResult);
328        return result.Succeeded();
329    }
330};
331
332//----------------------------------------------------------------------
333// "platform status"
334//----------------------------------------------------------------------
335class CommandObjectPlatformStatus : public CommandObjectParsed
336{
337public:
338    CommandObjectPlatformStatus (CommandInterpreter &interpreter) :
339        CommandObjectParsed (interpreter,
340                             "platform status",
341                             "Display status for the currently selected platform.",
342                             NULL,
343                             0)
344    {
345    }
346
347    virtual
348    ~CommandObjectPlatformStatus ()
349    {
350    }
351
352protected:
353    virtual bool
354    DoExecute (Args& args, CommandReturnObject &result)
355    {
356        Stream &ostrm = result.GetOutputStream();
357
358        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
359        PlatformSP platform_sp;
360        if (target)
361        {
362            platform_sp = target->GetPlatform();
363        }
364        if (!platform_sp)
365        {
366            platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
367        }
368        if (platform_sp)
369        {
370            platform_sp->GetStatus (ostrm);
371            result.SetStatus (eReturnStatusSuccessFinishResult);
372        }
373        else
374        {
375            result.AppendError ("no platform us currently selected\n");
376            result.SetStatus (eReturnStatusFailed);
377        }
378        return result.Succeeded();
379    }
380};
381
382//----------------------------------------------------------------------
383// "platform connect <connect-url>"
384//----------------------------------------------------------------------
385class CommandObjectPlatformConnect : public CommandObjectParsed
386{
387public:
388    CommandObjectPlatformConnect (CommandInterpreter &interpreter) :
389        CommandObjectParsed (interpreter,
390                             "platform connect",
391                             "Connect a platform by name to be the currently selected platform.",
392                             "platform connect <connect-url>",
393                             0)
394    {
395    }
396
397    virtual
398    ~CommandObjectPlatformConnect ()
399    {
400    }
401
402protected:
403    virtual bool
404    DoExecute (Args& args, CommandReturnObject &result)
405    {
406        Stream &ostrm = result.GetOutputStream();
407
408        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
409        if (platform_sp)
410        {
411            Error error (platform_sp->ConnectRemote (args));
412            if (error.Success())
413            {
414                platform_sp->GetStatus (ostrm);
415                result.SetStatus (eReturnStatusSuccessFinishResult);
416            }
417            else
418            {
419                result.AppendErrorWithFormat ("%s\n", error.AsCString());
420                result.SetStatus (eReturnStatusFailed);
421            }
422        }
423        else
424        {
425            result.AppendError ("no platform is currently selected\n");
426            result.SetStatus (eReturnStatusFailed);
427        }
428        return result.Succeeded();
429    }
430
431    virtual Options *
432    GetOptions ()
433    {
434        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
435        OptionGroupOptions* m_platform_options = NULL;
436        if (platform_sp)
437        {
438            m_platform_options = platform_sp->GetConnectionOptions(m_interpreter);
439            if (m_platform_options != NULL && !m_platform_options->m_did_finalize)
440                m_platform_options->Finalize();
441        }
442        return m_platform_options;
443    }
444
445};
446
447//----------------------------------------------------------------------
448// "platform disconnect"
449//----------------------------------------------------------------------
450class CommandObjectPlatformDisconnect : public CommandObjectParsed
451{
452public:
453    CommandObjectPlatformDisconnect (CommandInterpreter &interpreter) :
454        CommandObjectParsed (interpreter,
455                             "platform disconnect",
456                             "Disconnect a platform by name to be the currently selected platform.",
457                             "platform disconnect",
458                             0)
459    {
460    }
461
462    virtual
463    ~CommandObjectPlatformDisconnect ()
464    {
465    }
466
467protected:
468    virtual bool
469    DoExecute (Args& args, CommandReturnObject &result)
470    {
471        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
472        if (platform_sp)
473        {
474            if (args.GetArgumentCount() == 0)
475            {
476                Error error;
477
478                if (platform_sp->IsConnected())
479                {
480                    // Cache the instance name if there is one since we are
481                    // about to disconnect and the name might go with it.
482                    const char *hostname_cstr = platform_sp->GetHostname();
483                    std::string hostname;
484                    if (hostname_cstr)
485                        hostname.assign (hostname_cstr);
486
487                    error = platform_sp->DisconnectRemote ();
488                    if (error.Success())
489                    {
490                        Stream &ostrm = result.GetOutputStream();
491                        if (hostname.empty())
492                            ostrm.Printf ("Disconnected from \"%s\"\n", platform_sp->GetPluginName().GetCString());
493                        else
494                            ostrm.Printf ("Disconnected from \"%s\"\n", hostname.c_str());
495                        result.SetStatus (eReturnStatusSuccessFinishResult);
496                    }
497                    else
498                    {
499                        result.AppendErrorWithFormat ("%s", error.AsCString());
500                        result.SetStatus (eReturnStatusFailed);
501                    }
502                }
503                else
504                {
505                    // Not connected...
506                    result.AppendErrorWithFormat ("not connected to '%s'", platform_sp->GetPluginName().GetCString());
507                    result.SetStatus (eReturnStatusFailed);
508                }
509            }
510            else
511            {
512                // Bad args
513                result.AppendError ("\"platform disconnect\" doesn't take any arguments");
514                result.SetStatus (eReturnStatusFailed);
515            }
516        }
517        else
518        {
519            result.AppendError ("no platform is currently selected");
520            result.SetStatus (eReturnStatusFailed);
521        }
522        return result.Succeeded();
523    }
524};
525
526//----------------------------------------------------------------------
527// "platform mkdir"
528//----------------------------------------------------------------------
529class CommandObjectPlatformMkDir : public CommandObjectParsed
530{
531public:
532    CommandObjectPlatformMkDir (CommandInterpreter &interpreter) :
533    CommandObjectParsed (interpreter,
534                         "platform mkdir",
535                         "Make a new directory on the remote end.",
536                         NULL,
537                         0),
538    m_options(interpreter)
539    {
540    }
541
542    virtual
543    ~CommandObjectPlatformMkDir ()
544    {
545    }
546
547    virtual bool
548    DoExecute (Args& args, CommandReturnObject &result)
549    {
550        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
551        if (platform_sp)
552        {
553            std::string cmd_line;
554            args.GetCommandString(cmd_line);
555            mode_t perms;
556            const OptionPermissions* options_permissions = (OptionPermissions*)m_options.GetGroupWithOption('r');
557            if (options_permissions)
558                perms = options_permissions->m_permissions;
559            else
560                perms = 0000700 | 0000070 | 0000007;
561            uint32_t retcode = platform_sp->MakeDirectory(cmd_line,perms);
562            result.AppendMessageWithFormat("Status = %d\n",retcode);
563            result.SetStatus (eReturnStatusSuccessFinishResult);
564        }
565        else
566        {
567            result.AppendError ("no platform currently selected\n");
568            result.SetStatus (eReturnStatusFailed);
569        }
570        return result.Succeeded();
571    }
572
573    virtual Options *
574    GetOptions ()
575    {
576        if (m_options.DidFinalize() == false)
577        {
578            m_options.Append(new OptionPermissions());
579            m_options.Finalize();
580        }
581        return &m_options;
582    }
583    OptionGroupOptions m_options;
584
585};
586
587//----------------------------------------------------------------------
588// "platform fopen"
589//----------------------------------------------------------------------
590class CommandObjectPlatformFOpen : public CommandObjectParsed
591{
592public:
593    CommandObjectPlatformFOpen (CommandInterpreter &interpreter) :
594    CommandObjectParsed (interpreter,
595                         "platform file open",
596                         "Open a file on the remote end.",
597                         NULL,
598                         0),
599    m_options(interpreter)
600    {
601    }
602
603    virtual
604    ~CommandObjectPlatformFOpen ()
605    {
606    }
607
608    virtual bool
609    DoExecute (Args& args, CommandReturnObject &result)
610    {
611        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
612        if (platform_sp)
613        {
614            Error error;
615            std::string cmd_line;
616            args.GetCommandString(cmd_line);
617            mode_t perms;
618            const OptionPermissions* options_permissions = (OptionPermissions*)m_options.GetGroupWithOption('r');
619            if (options_permissions)
620                perms = options_permissions->m_permissions;
621            else
622                perms = 0000700 | 0000070 | 0000007;
623            lldb::user_id_t fd = platform_sp->OpenFile(FileSpec(cmd_line.c_str(),false),
624                                                       File::eOpenOptionRead | File::eOpenOptionWrite |
625                                                       File::eOpenOptionAppend | File::eOpenOptionCanCreate,
626                                                       perms,
627                                                       error);
628            if (error.Success())
629            {
630                result.AppendMessageWithFormat("File Descriptor = %" PRIu64 "\n",fd);
631                result.SetStatus (eReturnStatusSuccessFinishResult);
632            }
633            else
634            {
635                result.AppendError(error.AsCString());
636                result.SetStatus (eReturnStatusFailed);
637            }
638        }
639        else
640        {
641            result.AppendError ("no platform currently selected\n");
642            result.SetStatus (eReturnStatusFailed);
643        }
644        return result.Succeeded();
645    }
646    virtual Options *
647    GetOptions ()
648    {
649        if (m_options.DidFinalize() == false)
650        {
651            m_options.Append(new OptionPermissions());
652            m_options.Finalize();
653        }
654        return &m_options;
655    }
656    OptionGroupOptions m_options;
657};
658
659//----------------------------------------------------------------------
660// "platform fclose"
661//----------------------------------------------------------------------
662class CommandObjectPlatformFClose : public CommandObjectParsed
663{
664public:
665    CommandObjectPlatformFClose (CommandInterpreter &interpreter) :
666    CommandObjectParsed (interpreter,
667                         "platform file close",
668                         "Close a file on the remote end.",
669                         NULL,
670                         0)
671    {
672    }
673
674    virtual
675    ~CommandObjectPlatformFClose ()
676    {
677    }
678
679    virtual bool
680    DoExecute (Args& args, CommandReturnObject &result)
681    {
682        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
683        if (platform_sp)
684        {
685            std::string cmd_line;
686            args.GetCommandString(cmd_line);
687            const lldb::user_id_t fd = Args::StringToUInt64(cmd_line.c_str(), UINT64_MAX);
688            Error error;
689            bool success = platform_sp->CloseFile(fd, error);
690            if (success)
691            {
692                result.AppendMessageWithFormat("file %" PRIu64 " closed.\n", fd);
693                result.SetStatus (eReturnStatusSuccessFinishResult);
694            }
695            else
696            {
697                result.AppendError(error.AsCString());
698                result.SetStatus (eReturnStatusFailed);
699            }
700        }
701        else
702        {
703            result.AppendError ("no platform currently selected\n");
704            result.SetStatus (eReturnStatusFailed);
705        }
706        return result.Succeeded();
707    }
708};
709
710//----------------------------------------------------------------------
711// "platform fread"
712//----------------------------------------------------------------------
713class CommandObjectPlatformFRead : public CommandObjectParsed
714{
715public:
716    CommandObjectPlatformFRead (CommandInterpreter &interpreter) :
717    CommandObjectParsed (interpreter,
718                         "platform file read",
719                         "Read data from a file on the remote end.",
720                         NULL,
721                         0),
722    m_options (interpreter)
723    {
724    }
725
726    virtual
727    ~CommandObjectPlatformFRead ()
728    {
729    }
730
731    virtual bool
732    DoExecute (Args& args, CommandReturnObject &result)
733    {
734        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
735        if (platform_sp)
736        {
737            std::string cmd_line;
738            args.GetCommandString(cmd_line);
739            const lldb::user_id_t fd = Args::StringToUInt64(cmd_line.c_str(), UINT64_MAX);
740            std::string buffer(m_options.m_count,0);
741            Error error;
742            uint32_t retcode = platform_sp->ReadFile(fd, m_options.m_offset, &buffer[0], m_options.m_count, error);
743            result.AppendMessageWithFormat("Return = %d\n",retcode);
744            result.AppendMessageWithFormat("Data = \"%s\"\n",buffer.c_str());
745            result.SetStatus (eReturnStatusSuccessFinishResult);
746        }
747        else
748        {
749            result.AppendError ("no platform currently selected\n");
750            result.SetStatus (eReturnStatusFailed);
751        }
752        return result.Succeeded();
753    }
754    virtual Options *
755    GetOptions ()
756    {
757        return &m_options;
758    }
759
760protected:
761    class CommandOptions : public Options
762    {
763    public:
764
765        CommandOptions (CommandInterpreter &interpreter) :
766        Options (interpreter)
767        {
768        }
769
770        virtual
771        ~CommandOptions ()
772        {
773        }
774
775        virtual Error
776        SetOptionValue (uint32_t option_idx, const char *option_arg)
777        {
778            Error error;
779            char short_option = (char) m_getopt_table[option_idx].val;
780            bool success = false;
781
782            switch (short_option)
783            {
784                case 'o':
785                    m_offset = Args::StringToUInt32(option_arg, 0, 0, &success);
786                    if (!success)
787                        error.SetErrorStringWithFormat("invalid offset: '%s'", option_arg);
788                    break;
789                case 'c':
790                    m_count = Args::StringToUInt32(option_arg, 0, 0, &success);
791                    if (!success)
792                        error.SetErrorStringWithFormat("invalid offset: '%s'", option_arg);
793                    break;
794
795                default:
796                    error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
797                    break;
798            }
799
800            return error;
801        }
802
803        void
804        OptionParsingStarting ()
805        {
806            m_offset = 0;
807            m_count = 1;
808        }
809
810        const OptionDefinition*
811        GetDefinitions ()
812        {
813            return g_option_table;
814        }
815
816        // Options table: Required for subclasses of Options.
817
818        static OptionDefinition g_option_table[];
819
820        // Instance variables to hold the values for command options.
821
822        uint32_t m_offset;
823        uint32_t m_count;
824    };
825    CommandOptions m_options;
826};
827OptionDefinition
828CommandObjectPlatformFRead::CommandOptions::g_option_table[] =
829{
830    {   LLDB_OPT_SET_1, false, "offset"           , 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeIndex        , "Offset into the file at which to start reading." },
831    {   LLDB_OPT_SET_1, false, "count"            , 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCount        , "Number of bytes to read from the file." },
832    {  0              , false, NULL               ,  0 , 0                , NULL, 0, eArgTypeNone         , NULL }
833};
834
835
836//----------------------------------------------------------------------
837// "platform fwrite"
838//----------------------------------------------------------------------
839class CommandObjectPlatformFWrite : public CommandObjectParsed
840{
841public:
842    CommandObjectPlatformFWrite (CommandInterpreter &interpreter) :
843    CommandObjectParsed (interpreter,
844                         "platform file write",
845                         "Write data to a file on the remote end.",
846                         NULL,
847                         0),
848    m_options (interpreter)
849    {
850    }
851
852    virtual
853    ~CommandObjectPlatformFWrite ()
854    {
855    }
856
857    virtual bool
858    DoExecute (Args& args, CommandReturnObject &result)
859    {
860        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
861        if (platform_sp)
862        {
863            std::string cmd_line;
864            args.GetCommandString(cmd_line);
865            Error error;
866            const lldb::user_id_t fd = Args::StringToUInt64(cmd_line.c_str(), UINT64_MAX);
867            uint32_t retcode = platform_sp->WriteFile (fd,
868                                                       m_options.m_offset,
869                                                       &m_options.m_data[0],
870                                                       m_options.m_data.size(),
871                                                       error);
872            result.AppendMessageWithFormat("Return = %d\n",retcode);
873            result.SetStatus (eReturnStatusSuccessFinishResult);
874        }
875        else
876        {
877            result.AppendError ("no platform currently selected\n");
878            result.SetStatus (eReturnStatusFailed);
879        }
880        return result.Succeeded();
881    }
882    virtual Options *
883    GetOptions ()
884    {
885        return &m_options;
886    }
887
888protected:
889    class CommandOptions : public Options
890    {
891    public:
892
893        CommandOptions (CommandInterpreter &interpreter) :
894        Options (interpreter)
895        {
896        }
897
898        virtual
899        ~CommandOptions ()
900        {
901        }
902
903        virtual Error
904        SetOptionValue (uint32_t option_idx, const char *option_arg)
905        {
906            Error error;
907            char short_option = (char) m_getopt_table[option_idx].val;
908            bool success = false;
909
910            switch (short_option)
911            {
912                case 'o':
913                    m_offset = Args::StringToUInt32(option_arg, 0, 0, &success);
914                    if (!success)
915                        error.SetErrorStringWithFormat("invalid offset: '%s'", option_arg);
916                    break;
917                case 'd':
918                    m_data.assign(option_arg);
919                    break;
920
921                default:
922                    error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
923                    break;
924            }
925
926            return error;
927        }
928
929        void
930        OptionParsingStarting ()
931        {
932            m_offset = 0;
933            m_data.clear();
934        }
935
936        const OptionDefinition*
937        GetDefinitions ()
938        {
939            return g_option_table;
940        }
941
942        // Options table: Required for subclasses of Options.
943
944        static OptionDefinition g_option_table[];
945
946        // Instance variables to hold the values for command options.
947
948        uint32_t m_offset;
949        std::string m_data;
950    };
951    CommandOptions m_options;
952};
953OptionDefinition
954CommandObjectPlatformFWrite::CommandOptions::g_option_table[] =
955{
956    {   LLDB_OPT_SET_1, false, "offset"           , 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeIndex        , "Offset into the file at which to start reading." },
957    {   LLDB_OPT_SET_1, false, "data"            , 'd', OptionParser::eRequiredArgument, NULL, 0, eArgTypeValue        , "Text to write to the file." },
958    {  0              , false, NULL               ,  0 , 0                , NULL, 0, eArgTypeNone         , NULL }
959};
960
961class CommandObjectPlatformFile : public CommandObjectMultiword
962{
963public:
964    //------------------------------------------------------------------
965    // Constructors and Destructors
966    //------------------------------------------------------------------
967    CommandObjectPlatformFile (CommandInterpreter &interpreter) :
968    CommandObjectMultiword (interpreter,
969                            "platform file",
970                            "A set of commands to manage file access through a platform",
971                            "platform file [open|close|read|write] ...")
972    {
973        LoadSubCommand ("open", CommandObjectSP (new CommandObjectPlatformFOpen  (interpreter)));
974        LoadSubCommand ("close", CommandObjectSP (new CommandObjectPlatformFClose  (interpreter)));
975        LoadSubCommand ("read", CommandObjectSP (new CommandObjectPlatformFRead  (interpreter)));
976        LoadSubCommand ("write", CommandObjectSP (new CommandObjectPlatformFWrite  (interpreter)));
977    }
978
979    virtual
980    ~CommandObjectPlatformFile ()
981    {
982    }
983
984private:
985    //------------------------------------------------------------------
986    // For CommandObjectPlatform only
987    //------------------------------------------------------------------
988    DISALLOW_COPY_AND_ASSIGN (CommandObjectPlatformFile);
989};
990
991//----------------------------------------------------------------------
992// "platform get-file remote-file-path host-file-path"
993//----------------------------------------------------------------------
994class CommandObjectPlatformGetFile : public CommandObjectParsed
995{
996public:
997    CommandObjectPlatformGetFile (CommandInterpreter &interpreter) :
998    CommandObjectParsed (interpreter,
999                         "platform get-file",
1000                         "Transfer a file from the remote end to the local host.",
1001                         "platform get-file <remote-file-spec> <local-file-spec>",
1002                         0)
1003    {
1004        SetHelpLong(
1005"Examples: \n\
1006\n\
1007    platform get-file /the/remote/file/path /the/local/file/path\n\
1008    # Transfer a file from the remote end with file path /the/remote/file/path to the local host.\n");
1009
1010        CommandArgumentEntry arg1, arg2;
1011        CommandArgumentData file_arg_remote, file_arg_host;
1012
1013        // Define the first (and only) variant of this arg.
1014        file_arg_remote.arg_type = eArgTypeFilename;
1015        file_arg_remote.arg_repetition = eArgRepeatPlain;
1016        // There is only one variant this argument could be; put it into the argument entry.
1017        arg1.push_back (file_arg_remote);
1018
1019        // Define the second (and only) variant of this arg.
1020        file_arg_host.arg_type = eArgTypeFilename;
1021        file_arg_host.arg_repetition = eArgRepeatPlain;
1022        // There is only one variant this argument could be; put it into the argument entry.
1023        arg2.push_back (file_arg_host);
1024
1025        // Push the data for the first and the second arguments into the m_arguments vector.
1026        m_arguments.push_back (arg1);
1027        m_arguments.push_back (arg2);
1028    }
1029
1030    virtual
1031    ~CommandObjectPlatformGetFile ()
1032    {
1033    }
1034
1035    virtual bool
1036    DoExecute (Args& args, CommandReturnObject &result)
1037    {
1038        // If the number of arguments is incorrect, issue an error message.
1039        if (args.GetArgumentCount() != 2)
1040        {
1041            result.GetErrorStream().Printf("error: required arguments missing; specify both the source and destination file paths\n");
1042            result.SetStatus(eReturnStatusFailed);
1043            return false;
1044        }
1045
1046        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
1047        if (platform_sp)
1048        {
1049            const char *remote_file_path = args.GetArgumentAtIndex(0);
1050            const char *local_file_path = args.GetArgumentAtIndex(1);
1051            Error error = platform_sp->GetFile(FileSpec(remote_file_path, false),
1052                                               FileSpec(local_file_path, false));
1053            if (error.Success())
1054            {
1055                result.AppendMessageWithFormat("successfully get-file from %s (remote) to %s (host)\n",
1056                                               remote_file_path, local_file_path);
1057                result.SetStatus (eReturnStatusSuccessFinishResult);
1058            }
1059            else
1060            {
1061                result.AppendMessageWithFormat("get-file failed: %s\n", error.AsCString());
1062                result.SetStatus (eReturnStatusFailed);
1063            }
1064        }
1065        else
1066        {
1067            result.AppendError ("no platform currently selected\n");
1068            result.SetStatus (eReturnStatusFailed);
1069        }
1070        return result.Succeeded();
1071    }
1072};
1073
1074//----------------------------------------------------------------------
1075// "platform get-size remote-file-path"
1076//----------------------------------------------------------------------
1077class CommandObjectPlatformGetSize : public CommandObjectParsed
1078{
1079public:
1080    CommandObjectPlatformGetSize (CommandInterpreter &interpreter) :
1081    CommandObjectParsed (interpreter,
1082                         "platform get-size",
1083                         "Get the file size from the remote end.",
1084                         "platform get-size <remote-file-spec>",
1085                         0)
1086    {
1087        SetHelpLong(
1088"Examples: \n\
1089\n\
1090    platform get-size /the/remote/file/path\n\
1091    # Get the file size from the remote end with path /the/remote/file/path.\n");
1092
1093        CommandArgumentEntry arg1;
1094        CommandArgumentData file_arg_remote;
1095
1096        // Define the first (and only) variant of this arg.
1097        file_arg_remote.arg_type = eArgTypeFilename;
1098        file_arg_remote.arg_repetition = eArgRepeatPlain;
1099        // There is only one variant this argument could be; put it into the argument entry.
1100        arg1.push_back (file_arg_remote);
1101
1102        // Push the data for the first argument into the m_arguments vector.
1103        m_arguments.push_back (arg1);
1104    }
1105
1106    virtual
1107    ~CommandObjectPlatformGetSize ()
1108    {
1109    }
1110
1111    virtual bool
1112    DoExecute (Args& args, CommandReturnObject &result)
1113    {
1114        // If the number of arguments is incorrect, issue an error message.
1115        if (args.GetArgumentCount() != 1)
1116        {
1117            result.GetErrorStream().Printf("error: required argument missing; specify the source file path as the only argument\n");
1118            result.SetStatus(eReturnStatusFailed);
1119            return false;
1120        }
1121
1122        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
1123        if (platform_sp)
1124        {
1125            std::string remote_file_path(args.GetArgumentAtIndex(0));
1126            user_id_t size = platform_sp->GetFileSize(FileSpec(remote_file_path.c_str(), false));
1127            if (size != UINT64_MAX)
1128            {
1129                result.AppendMessageWithFormat("File size of %s (remote): %" PRIu64 "\n", remote_file_path.c_str(), size);
1130                result.SetStatus (eReturnStatusSuccessFinishResult);
1131            }
1132            else
1133            {
1134                result.AppendMessageWithFormat("Eroor getting file size of %s (remote)\n", remote_file_path.c_str());
1135                result.SetStatus (eReturnStatusFailed);
1136            }
1137        }
1138        else
1139        {
1140            result.AppendError ("no platform currently selected\n");
1141            result.SetStatus (eReturnStatusFailed);
1142        }
1143        return result.Succeeded();
1144    }
1145};
1146
1147//----------------------------------------------------------------------
1148// "platform put-file"
1149//----------------------------------------------------------------------
1150class CommandObjectPlatformPutFile : public CommandObjectParsed
1151{
1152public:
1153    CommandObjectPlatformPutFile (CommandInterpreter &interpreter) :
1154    CommandObjectParsed (interpreter,
1155                         "platform put-file",
1156                         "Transfer a file from this system to the remote end.",
1157                         NULL,
1158                         0)
1159    {
1160    }
1161
1162    virtual
1163    ~CommandObjectPlatformPutFile ()
1164    {
1165    }
1166
1167    virtual bool
1168    DoExecute (Args& args, CommandReturnObject &result)
1169    {
1170        const char* src = args.GetArgumentAtIndex(0);
1171        const char* dst = args.GetArgumentAtIndex(1);
1172
1173        FileSpec src_fs(src, true);
1174        FileSpec dst_fs(dst, false);
1175
1176        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
1177        if (platform_sp)
1178        {
1179            Error error (platform_sp->PutFile(src_fs, dst_fs));
1180            if (error.Success())
1181            {
1182                result.SetStatus (eReturnStatusSuccessFinishNoResult);
1183            }
1184            else
1185            {
1186                result.AppendError (error.AsCString());
1187                result.SetStatus (eReturnStatusFailed);
1188            }
1189        }
1190        else
1191        {
1192            result.AppendError ("no platform currently selected\n");
1193            result.SetStatus (eReturnStatusFailed);
1194        }
1195        return result.Succeeded();
1196    }
1197};
1198
1199//----------------------------------------------------------------------
1200// "platform process launch"
1201//----------------------------------------------------------------------
1202class CommandObjectPlatformProcessLaunch : public CommandObjectParsed
1203{
1204public:
1205    CommandObjectPlatformProcessLaunch (CommandInterpreter &interpreter) :
1206        CommandObjectParsed (interpreter,
1207                             "platform process launch",
1208                             "Launch a new process on a remote platform.",
1209                             "platform process launch program",
1210                             eFlagRequiresTarget | eFlagTryTargetAPILock),
1211        m_options (interpreter)
1212    {
1213    }
1214
1215    virtual
1216    ~CommandObjectPlatformProcessLaunch ()
1217    {
1218    }
1219
1220    virtual Options *
1221    GetOptions ()
1222    {
1223        return &m_options;
1224    }
1225
1226protected:
1227    virtual bool
1228    DoExecute (Args& args, CommandReturnObject &result)
1229    {
1230        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
1231        PlatformSP platform_sp;
1232        if (target)
1233        {
1234            platform_sp = target->GetPlatform();
1235        }
1236        if (!platform_sp)
1237        {
1238            platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
1239        }
1240
1241        if (platform_sp)
1242        {
1243            Error error;
1244            const size_t argc = args.GetArgumentCount();
1245            Target *target = m_exe_ctx.GetTargetPtr();
1246            Module *exe_module = target->GetExecutableModulePointer();
1247            if (exe_module)
1248            {
1249                m_options.launch_info.GetExecutableFile () = exe_module->GetFileSpec();
1250                char exe_path[PATH_MAX];
1251                if (m_options.launch_info.GetExecutableFile ().GetPath (exe_path, sizeof(exe_path)))
1252                    m_options.launch_info.GetArguments().AppendArgument (exe_path);
1253                m_options.launch_info.GetArchitecture() = exe_module->GetArchitecture();
1254            }
1255
1256            if (argc > 0)
1257            {
1258                if (m_options.launch_info.GetExecutableFile ())
1259                {
1260                    // We already have an executable file, so we will use this
1261                    // and all arguments to this function are extra arguments
1262                    m_options.launch_info.GetArguments().AppendArguments (args);
1263                }
1264                else
1265                {
1266                    // We don't have any file yet, so the first argument is our
1267                    // executable, and the rest are program arguments
1268                    const bool first_arg_is_executable = true;
1269                    m_options.launch_info.SetArguments (args, first_arg_is_executable);
1270                }
1271            }
1272
1273            if (m_options.launch_info.GetExecutableFile ())
1274            {
1275                Debugger &debugger = m_interpreter.GetDebugger();
1276
1277                if (argc == 0)
1278                    target->GetRunArguments(m_options.launch_info.GetArguments());
1279
1280                ProcessSP process_sp (platform_sp->DebugProcess (m_options.launch_info,
1281                                                                 debugger,
1282                                                                 target,
1283                                                                 debugger.GetListener(),
1284                                                                 error));
1285                if (process_sp && process_sp->IsAlive())
1286                {
1287                    result.SetStatus (eReturnStatusSuccessFinishNoResult);
1288                    return true;
1289                }
1290
1291                if (error.Success())
1292                    result.AppendError ("process launch failed");
1293                else
1294                    result.AppendError (error.AsCString());
1295                result.SetStatus (eReturnStatusFailed);
1296            }
1297            else
1298            {
1299                result.AppendError ("'platform process launch' uses the current target file and arguments, or the executable and its arguments can be specified in this command");
1300                result.SetStatus (eReturnStatusFailed);
1301                return false;
1302            }
1303        }
1304        else
1305        {
1306            result.AppendError ("no platform is selected\n");
1307        }
1308        return result.Succeeded();
1309    }
1310
1311protected:
1312    ProcessLaunchCommandOptions m_options;
1313};
1314
1315
1316
1317//----------------------------------------------------------------------
1318// "platform process list"
1319//----------------------------------------------------------------------
1320class CommandObjectPlatformProcessList : public CommandObjectParsed
1321{
1322public:
1323    CommandObjectPlatformProcessList (CommandInterpreter &interpreter) :
1324        CommandObjectParsed (interpreter,
1325                             "platform process list",
1326                             "List processes on a remote platform by name, pid, or many other matching attributes.",
1327                             "platform process list",
1328                             0),
1329        m_options (interpreter)
1330    {
1331    }
1332
1333    virtual
1334    ~CommandObjectPlatformProcessList ()
1335    {
1336    }
1337
1338    virtual Options *
1339    GetOptions ()
1340    {
1341        return &m_options;
1342    }
1343
1344protected:
1345    virtual bool
1346    DoExecute (Args& args, CommandReturnObject &result)
1347    {
1348        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
1349        PlatformSP platform_sp;
1350        if (target)
1351        {
1352            platform_sp = target->GetPlatform();
1353        }
1354        if (!platform_sp)
1355        {
1356            platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
1357        }
1358
1359        if (platform_sp)
1360        {
1361            Error error;
1362            if (args.GetArgumentCount() == 0)
1363            {
1364
1365                if (platform_sp)
1366                {
1367                    Stream &ostrm = result.GetOutputStream();
1368
1369                    lldb::pid_t pid = m_options.match_info.GetProcessInfo().GetProcessID();
1370                    if (pid != LLDB_INVALID_PROCESS_ID)
1371                    {
1372                        ProcessInstanceInfo proc_info;
1373                        if (platform_sp->GetProcessInfo (pid, proc_info))
1374                        {
1375                            ProcessInstanceInfo::DumpTableHeader (ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
1376                            proc_info.DumpAsTableRow(ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
1377                            result.SetStatus (eReturnStatusSuccessFinishResult);
1378                        }
1379                        else
1380                        {
1381                            result.AppendErrorWithFormat ("no process found with pid = %" PRIu64 "\n", pid);
1382                            result.SetStatus (eReturnStatusFailed);
1383                        }
1384                    }
1385                    else
1386                    {
1387                        ProcessInstanceInfoList proc_infos;
1388                        const uint32_t matches = platform_sp->FindProcesses (m_options.match_info, proc_infos);
1389                        const char *match_desc = NULL;
1390                        const char *match_name = m_options.match_info.GetProcessInfo().GetName();
1391                        if (match_name && match_name[0])
1392                        {
1393                            switch (m_options.match_info.GetNameMatchType())
1394                            {
1395                                case eNameMatchIgnore: break;
1396                                case eNameMatchEquals: match_desc = "matched"; break;
1397                                case eNameMatchContains: match_desc = "contained"; break;
1398                                case eNameMatchStartsWith: match_desc = "started with"; break;
1399                                case eNameMatchEndsWith: match_desc = "ended with"; break;
1400                                case eNameMatchRegularExpression: match_desc = "matched the regular expression"; break;
1401                            }
1402                        }
1403
1404                        if (matches == 0)
1405                        {
1406                            if (match_desc)
1407                                result.AppendErrorWithFormat ("no processes were found that %s \"%s\" on the \"%s\" platform\n",
1408                                                              match_desc,
1409                                                              match_name,
1410                                                              platform_sp->GetPluginName().GetCString());
1411                            else
1412                                result.AppendErrorWithFormat ("no processes were found on the \"%s\" platform\n", platform_sp->GetPluginName().GetCString());
1413                            result.SetStatus (eReturnStatusFailed);
1414                        }
1415                        else
1416                        {
1417                            result.AppendMessageWithFormat ("%u matching process%s found on \"%s\"",
1418                                                            matches,
1419                                                            matches > 1 ? "es were" : " was",
1420                                                            platform_sp->GetName().GetCString());
1421                            if (match_desc)
1422                                result.AppendMessageWithFormat (" whose name %s \"%s\"",
1423                                                                match_desc,
1424                                                                match_name);
1425                            result.AppendMessageWithFormat ("\n");
1426                            ProcessInstanceInfo::DumpTableHeader (ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
1427                            for (uint32_t i=0; i<matches; ++i)
1428                            {
1429                                proc_infos.GetProcessInfoAtIndex(i).DumpAsTableRow(ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
1430                            }
1431                        }
1432                    }
1433                }
1434            }
1435            else
1436            {
1437                result.AppendError ("invalid args: process list takes only options\n");
1438                result.SetStatus (eReturnStatusFailed);
1439            }
1440        }
1441        else
1442        {
1443            result.AppendError ("no platform is selected\n");
1444            result.SetStatus (eReturnStatusFailed);
1445        }
1446        return result.Succeeded();
1447    }
1448
1449    class CommandOptions : public Options
1450    {
1451    public:
1452
1453        CommandOptions (CommandInterpreter &interpreter) :
1454            Options (interpreter),
1455            match_info ()
1456        {
1457        }
1458
1459        virtual
1460        ~CommandOptions ()
1461        {
1462        }
1463
1464        virtual Error
1465        SetOptionValue (uint32_t option_idx, const char *option_arg)
1466        {
1467            Error error;
1468            const int short_option = m_getopt_table[option_idx].val;
1469            bool success = false;
1470
1471            switch (short_option)
1472            {
1473                case 'p':
1474                    match_info.GetProcessInfo().SetProcessID (Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success));
1475                    if (!success)
1476                        error.SetErrorStringWithFormat("invalid process ID string: '%s'", option_arg);
1477                    break;
1478
1479                case 'P':
1480                    match_info.GetProcessInfo().SetParentProcessID (Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success));
1481                    if (!success)
1482                        error.SetErrorStringWithFormat("invalid parent process ID string: '%s'", option_arg);
1483                    break;
1484
1485                case 'u':
1486                    match_info.GetProcessInfo().SetUserID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
1487                    if (!success)
1488                        error.SetErrorStringWithFormat("invalid user ID string: '%s'", option_arg);
1489                    break;
1490
1491                case 'U':
1492                    match_info.GetProcessInfo().SetEffectiveUserID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
1493                    if (!success)
1494                        error.SetErrorStringWithFormat("invalid effective user ID string: '%s'", option_arg);
1495                    break;
1496
1497                case 'g':
1498                    match_info.GetProcessInfo().SetGroupID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
1499                    if (!success)
1500                        error.SetErrorStringWithFormat("invalid group ID string: '%s'", option_arg);
1501                    break;
1502
1503                case 'G':
1504                    match_info.GetProcessInfo().SetEffectiveGroupID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
1505                    if (!success)
1506                        error.SetErrorStringWithFormat("invalid effective group ID string: '%s'", option_arg);
1507                    break;
1508
1509                case 'a':
1510                    match_info.GetProcessInfo().GetArchitecture().SetTriple (option_arg, m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform().get());
1511                    break;
1512
1513                case 'n':
1514                    match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
1515                    match_info.SetNameMatchType (eNameMatchEquals);
1516                    break;
1517
1518                case 'e':
1519                    match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
1520                    match_info.SetNameMatchType (eNameMatchEndsWith);
1521                    break;
1522
1523                case 's':
1524                    match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
1525                    match_info.SetNameMatchType (eNameMatchStartsWith);
1526                    break;
1527
1528                case 'c':
1529                    match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
1530                    match_info.SetNameMatchType (eNameMatchContains);
1531                    break;
1532
1533                case 'r':
1534                    match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
1535                    match_info.SetNameMatchType (eNameMatchRegularExpression);
1536                    break;
1537
1538                case 'A':
1539                    show_args = true;
1540                    break;
1541
1542                case 'v':
1543                    verbose = true;
1544                    break;
1545
1546                default:
1547                    error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
1548                    break;
1549            }
1550
1551            return error;
1552        }
1553
1554        void
1555        OptionParsingStarting ()
1556        {
1557            match_info.Clear();
1558            show_args = false;
1559            verbose = false;
1560        }
1561
1562        const OptionDefinition*
1563        GetDefinitions ()
1564        {
1565            return g_option_table;
1566        }
1567
1568        // Options table: Required for subclasses of Options.
1569
1570        static OptionDefinition g_option_table[];
1571
1572        // Instance variables to hold the values for command options.
1573
1574        ProcessInstanceInfoMatch match_info;
1575        bool show_args;
1576        bool verbose;
1577    };
1578    CommandOptions m_options;
1579};
1580
1581OptionDefinition
1582CommandObjectPlatformProcessList::CommandOptions::g_option_table[] =
1583{
1584{ LLDB_OPT_SET_1            , false, "pid"        , 'p', OptionParser::eRequiredArgument, NULL, 0, eArgTypePid              , "List the process info for a specific process ID." },
1585{ LLDB_OPT_SET_2            , true , "name"       , 'n', OptionParser::eRequiredArgument, NULL, 0, eArgTypeProcessName      , "Find processes with executable basenames that match a string." },
1586{ LLDB_OPT_SET_3            , true , "ends-with"  , 'e', OptionParser::eRequiredArgument, NULL, 0, eArgTypeProcessName      , "Find processes with executable basenames that end with a string." },
1587{ LLDB_OPT_SET_4            , true , "starts-with", 's', OptionParser::eRequiredArgument, NULL, 0, eArgTypeProcessName      , "Find processes with executable basenames that start with a string." },
1588{ LLDB_OPT_SET_5            , true , "contains"   , 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeProcessName      , "Find processes with executable basenames that contain a string." },
1589{ LLDB_OPT_SET_6            , true , "regex"      , 'r', OptionParser::eRequiredArgument, NULL, 0, eArgTypeRegularExpression, "Find processes with executable basenames that match a regular expression." },
1590{ LLDB_OPT_SET_FROM_TO(2, 6), false, "parent"     , 'P', OptionParser::eRequiredArgument, NULL, 0, eArgTypePid              , "Find processes that have a matching parent process ID." },
1591{ LLDB_OPT_SET_FROM_TO(2, 6), false, "uid"        , 'u', OptionParser::eRequiredArgument, NULL, 0, eArgTypeUnsignedInteger  , "Find processes that have a matching user ID." },
1592{ LLDB_OPT_SET_FROM_TO(2, 6), false, "euid"       , 'U', OptionParser::eRequiredArgument, NULL, 0, eArgTypeUnsignedInteger  , "Find processes that have a matching effective user ID." },
1593{ LLDB_OPT_SET_FROM_TO(2, 6), false, "gid"        , 'g', OptionParser::eRequiredArgument, NULL, 0, eArgTypeUnsignedInteger  , "Find processes that have a matching group ID." },
1594{ LLDB_OPT_SET_FROM_TO(2, 6), false, "egid"       , 'G', OptionParser::eRequiredArgument, NULL, 0, eArgTypeUnsignedInteger  , "Find processes that have a matching effective group ID." },
1595{ LLDB_OPT_SET_FROM_TO(2, 6), false, "arch"       , 'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeArchitecture     , "Find processes that have a matching architecture." },
1596{ LLDB_OPT_SET_FROM_TO(1, 6), false, "show-args"  , 'A', OptionParser::eNoArgument      , NULL, 0, eArgTypeNone             , "Show process arguments instead of the process executable basename." },
1597{ LLDB_OPT_SET_FROM_TO(1, 6), false, "verbose"    , 'v', OptionParser::eNoArgument      , NULL, 0, eArgTypeNone             , "Enable verbose output." },
1598{ 0                         , false, NULL         ,  0 , 0                , NULL, 0, eArgTypeNone             , NULL }
1599};
1600
1601//----------------------------------------------------------------------
1602// "platform process info"
1603//----------------------------------------------------------------------
1604class CommandObjectPlatformProcessInfo : public CommandObjectParsed
1605{
1606public:
1607    CommandObjectPlatformProcessInfo (CommandInterpreter &interpreter) :
1608    CommandObjectParsed (interpreter,
1609                         "platform process info",
1610                         "Get detailed information for one or more process by process ID.",
1611                         "platform process info <pid> [<pid> <pid> ...]",
1612                         0)
1613    {
1614        CommandArgumentEntry arg;
1615        CommandArgumentData pid_args;
1616
1617        // Define the first (and only) variant of this arg.
1618        pid_args.arg_type = eArgTypePid;
1619        pid_args.arg_repetition = eArgRepeatStar;
1620
1621        // There is only one variant this argument could be; put it into the argument entry.
1622        arg.push_back (pid_args);
1623
1624        // Push the data for the first argument into the m_arguments vector.
1625        m_arguments.push_back (arg);
1626    }
1627
1628    virtual
1629    ~CommandObjectPlatformProcessInfo ()
1630    {
1631    }
1632
1633protected:
1634    virtual bool
1635    DoExecute (Args& args, CommandReturnObject &result)
1636    {
1637        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
1638        PlatformSP platform_sp;
1639        if (target)
1640        {
1641            platform_sp = target->GetPlatform();
1642        }
1643        if (!platform_sp)
1644        {
1645            platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
1646        }
1647
1648        if (platform_sp)
1649        {
1650            const size_t argc = args.GetArgumentCount();
1651            if (argc > 0)
1652            {
1653                Error error;
1654
1655                if (platform_sp->IsConnected())
1656                {
1657                    Stream &ostrm = result.GetOutputStream();
1658                    bool success;
1659                    for (size_t i=0; i<argc; ++ i)
1660                    {
1661                        const char *arg = args.GetArgumentAtIndex(i);
1662                        lldb::pid_t pid = Args::StringToUInt32 (arg, LLDB_INVALID_PROCESS_ID, 0, &success);
1663                        if (success)
1664                        {
1665                            ProcessInstanceInfo proc_info;
1666                            if (platform_sp->GetProcessInfo (pid, proc_info))
1667                            {
1668                                ostrm.Printf ("Process information for process %" PRIu64 ":\n", pid);
1669                                proc_info.Dump (ostrm, platform_sp.get());
1670                            }
1671                            else
1672                            {
1673                                ostrm.Printf ("error: no process information is available for process %" PRIu64 "\n", pid);
1674                            }
1675                            ostrm.EOL();
1676                        }
1677                        else
1678                        {
1679                            result.AppendErrorWithFormat ("invalid process ID argument '%s'", arg);
1680                            result.SetStatus (eReturnStatusFailed);
1681                            break;
1682                        }
1683                    }
1684                }
1685                else
1686                {
1687                    // Not connected...
1688                    result.AppendErrorWithFormat ("not connected to '%s'", platform_sp->GetPluginName().GetCString());
1689                    result.SetStatus (eReturnStatusFailed);
1690                }
1691            }
1692            else
1693            {
1694                // No args
1695                result.AppendError ("one or more process id(s) must be specified");
1696                result.SetStatus (eReturnStatusFailed);
1697            }
1698        }
1699        else
1700        {
1701            result.AppendError ("no platform is currently selected");
1702            result.SetStatus (eReturnStatusFailed);
1703        }
1704        return result.Succeeded();
1705    }
1706};
1707
1708class CommandObjectPlatformProcessAttach : public CommandObjectParsed
1709{
1710public:
1711
1712    class CommandOptions : public Options
1713    {
1714    public:
1715
1716        CommandOptions (CommandInterpreter &interpreter) :
1717        Options(interpreter)
1718        {
1719            // Keep default values of all options in one place: OptionParsingStarting ()
1720            OptionParsingStarting ();
1721        }
1722
1723        ~CommandOptions ()
1724        {
1725        }
1726
1727        Error
1728        SetOptionValue (uint32_t option_idx, const char *option_arg)
1729        {
1730            Error error;
1731            char short_option = (char) m_getopt_table[option_idx].val;
1732            bool success = false;
1733            switch (short_option)
1734            {
1735                case 'p':
1736                {
1737                    lldb::pid_t pid = Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success);
1738                    if (!success || pid == LLDB_INVALID_PROCESS_ID)
1739                    {
1740                        error.SetErrorStringWithFormat("invalid process ID '%s'", option_arg);
1741                    }
1742                    else
1743                    {
1744                        attach_info.SetProcessID (pid);
1745                    }
1746                }
1747                    break;
1748
1749                case 'P':
1750                    attach_info.SetProcessPluginName (option_arg);
1751                    break;
1752
1753                case 'n':
1754                    attach_info.GetExecutableFile().SetFile(option_arg, false);
1755                    break;
1756
1757                case 'w':
1758                    attach_info.SetWaitForLaunch(true);
1759                    break;
1760
1761                default:
1762                    error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
1763                    break;
1764            }
1765            return error;
1766        }
1767
1768        void
1769        OptionParsingStarting ()
1770        {
1771            attach_info.Clear();
1772        }
1773
1774        const OptionDefinition*
1775        GetDefinitions ()
1776        {
1777            return g_option_table;
1778        }
1779
1780        virtual bool
1781        HandleOptionArgumentCompletion (Args &input,
1782                                        int cursor_index,
1783                                        int char_pos,
1784                                        OptionElementVector &opt_element_vector,
1785                                        int opt_element_index,
1786                                        int match_start_point,
1787                                        int max_return_elements,
1788                                        bool &word_complete,
1789                                        StringList &matches)
1790        {
1791            int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;
1792            int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
1793
1794            // We are only completing the name option for now...
1795
1796            const OptionDefinition *opt_defs = GetDefinitions();
1797            if (opt_defs[opt_defs_index].short_option == 'n')
1798            {
1799                // Are we in the name?
1800
1801                // Look to see if there is a -P argument provided, and if so use that plugin, otherwise
1802                // use the default plugin.
1803
1804                const char *partial_name = NULL;
1805                partial_name = input.GetArgumentAtIndex(opt_arg_pos);
1806
1807                PlatformSP platform_sp (m_interpreter.GetPlatform (true));
1808                if (platform_sp)
1809                {
1810                    ProcessInstanceInfoList process_infos;
1811                    ProcessInstanceInfoMatch match_info;
1812                    if (partial_name)
1813                    {
1814                        match_info.GetProcessInfo().GetExecutableFile().SetFile(partial_name, false);
1815                        match_info.SetNameMatchType(eNameMatchStartsWith);
1816                    }
1817                    platform_sp->FindProcesses (match_info, process_infos);
1818                    const uint32_t num_matches = process_infos.GetSize();
1819                    if (num_matches > 0)
1820                    {
1821                        for (uint32_t i=0; i<num_matches; ++i)
1822                        {
1823                            matches.AppendString (process_infos.GetProcessNameAtIndex(i),
1824                                                  process_infos.GetProcessNameLengthAtIndex(i));
1825                        }
1826                    }
1827                }
1828            }
1829
1830            return false;
1831        }
1832
1833        // Options table: Required for subclasses of Options.
1834
1835        static OptionDefinition g_option_table[];
1836
1837        // Instance variables to hold the values for command options.
1838
1839        ProcessAttachInfo attach_info;
1840    };
1841
1842    CommandObjectPlatformProcessAttach (CommandInterpreter &interpreter) :
1843    CommandObjectParsed (interpreter,
1844                         "platform process attach",
1845                         "Attach to a process.",
1846                         "platform process attach <cmd-options>"),
1847    m_options (interpreter)
1848    {
1849    }
1850
1851    ~CommandObjectPlatformProcessAttach ()
1852    {
1853    }
1854
1855    bool
1856    DoExecute (Args& command,
1857             CommandReturnObject &result)
1858    {
1859        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
1860        if (platform_sp)
1861        {
1862            Error err;
1863            ProcessSP remote_process_sp =
1864            platform_sp->Attach(m_options.attach_info, m_interpreter.GetDebugger(), NULL, m_interpreter.GetDebugger().GetListener(), err);
1865            if (err.Fail())
1866            {
1867                result.AppendError(err.AsCString());
1868                result.SetStatus (eReturnStatusFailed);
1869            }
1870            else if (remote_process_sp.get() == NULL)
1871            {
1872                result.AppendError("could not attach: unknown reason");
1873                result.SetStatus (eReturnStatusFailed);
1874            }
1875            else
1876                result.SetStatus (eReturnStatusSuccessFinishResult);
1877        }
1878        else
1879        {
1880            result.AppendError ("no platform is currently selected");
1881            result.SetStatus (eReturnStatusFailed);
1882        }
1883        return result.Succeeded();
1884    }
1885
1886    Options *
1887    GetOptions ()
1888    {
1889        return &m_options;
1890    }
1891
1892protected:
1893
1894    CommandOptions m_options;
1895};
1896
1897
1898OptionDefinition
1899CommandObjectPlatformProcessAttach::CommandOptions::g_option_table[] =
1900{
1901    { LLDB_OPT_SET_ALL, false, "plugin", 'P', OptionParser::eRequiredArgument, NULL, 0, eArgTypePlugin,        "Name of the process plugin you want to use."},
1902    { LLDB_OPT_SET_1,   false, "pid",    'p', OptionParser::eRequiredArgument, NULL, 0, eArgTypePid,           "The process ID of an existing process to attach to."},
1903    { LLDB_OPT_SET_2,   false, "name",   'n', OptionParser::eRequiredArgument, NULL, 0, eArgTypeProcessName,  "The name of the process to attach to."},
1904    { LLDB_OPT_SET_2,   false, "waitfor",'w', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone,              "Wait for the the process with <process-name> to launch."},
1905    { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
1906};
1907
1908
1909class CommandObjectPlatformProcess : public CommandObjectMultiword
1910{
1911public:
1912    //------------------------------------------------------------------
1913    // Constructors and Destructors
1914    //------------------------------------------------------------------
1915     CommandObjectPlatformProcess (CommandInterpreter &interpreter) :
1916        CommandObjectMultiword (interpreter,
1917                                "platform process",
1918                                "A set of commands to query, launch and attach to platform processes",
1919                                "platform process [attach|launch|list] ...")
1920    {
1921        LoadSubCommand ("attach", CommandObjectSP (new CommandObjectPlatformProcessAttach (interpreter)));
1922        LoadSubCommand ("launch", CommandObjectSP (new CommandObjectPlatformProcessLaunch (interpreter)));
1923        LoadSubCommand ("info"  , CommandObjectSP (new CommandObjectPlatformProcessInfo (interpreter)));
1924        LoadSubCommand ("list"  , CommandObjectSP (new CommandObjectPlatformProcessList (interpreter)));
1925
1926    }
1927
1928    virtual
1929    ~CommandObjectPlatformProcess ()
1930    {
1931    }
1932
1933private:
1934    //------------------------------------------------------------------
1935    // For CommandObjectPlatform only
1936    //------------------------------------------------------------------
1937    DISALLOW_COPY_AND_ASSIGN (CommandObjectPlatformProcess);
1938};
1939
1940//----------------------------------------------------------------------
1941// "platform shell"
1942//----------------------------------------------------------------------
1943class CommandObjectPlatformShell : public CommandObjectRaw
1944{
1945public:
1946
1947    class CommandOptions : public Options
1948    {
1949    public:
1950
1951        CommandOptions (CommandInterpreter &interpreter) :
1952        Options(interpreter),
1953        timeout(10)
1954        {
1955        }
1956
1957        virtual
1958        ~CommandOptions ()
1959        {
1960        }
1961
1962        virtual uint32_t
1963        GetNumDefinitions ()
1964        {
1965            return 1;
1966        }
1967
1968        virtual const OptionDefinition*
1969        GetDefinitions ()
1970        {
1971            return g_option_table;
1972        }
1973
1974        virtual Error
1975        SetOptionValue (uint32_t option_idx,
1976                        const char *option_value)
1977        {
1978            Error error;
1979
1980            const char short_option = (char) g_option_table[option_idx].short_option;
1981
1982            switch (short_option)
1983            {
1984                case 't':
1985                {
1986                    bool success;
1987                    timeout = Args::StringToUInt32(option_value, 10, 10, &success);
1988                    if (!success)
1989                        error.SetErrorStringWithFormat("could not convert \"%s\" to a numeric value.", option_value);
1990                    break;
1991                }
1992                default:
1993                    error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
1994                    break;
1995            }
1996
1997            return error;
1998        }
1999
2000        virtual void
2001        OptionParsingStarting ()
2002        {
2003        }
2004
2005        // Options table: Required for subclasses of Options.
2006
2007        static OptionDefinition g_option_table[];
2008        uint32_t timeout;
2009    };
2010
2011    CommandObjectPlatformShell (CommandInterpreter &interpreter) :
2012    CommandObjectRaw (interpreter,
2013                      "platform shell",
2014                      "Run a shell command on a the selected platform.",
2015                      "platform shell <shell-command>",
2016                      0),
2017    m_options(interpreter)
2018    {
2019    }
2020
2021    virtual
2022    ~CommandObjectPlatformShell ()
2023    {
2024    }
2025
2026    virtual
2027    Options *
2028    GetOptions ()
2029    {
2030        return &m_options;
2031    }
2032
2033    virtual bool
2034    DoExecute (const char *raw_command_line, CommandReturnObject &result)
2035    {
2036        m_options.NotifyOptionParsingStarting();
2037
2038        const char* expr = NULL;
2039
2040        // Print out an usage syntax on an empty command line.
2041        if (raw_command_line[0] == '\0')
2042        {
2043            result.GetOutputStream().Printf("%s\n", this->GetSyntax());
2044            return true;
2045        }
2046
2047        if (raw_command_line[0] == '-')
2048        {
2049            // We have some options and these options MUST end with --.
2050            const char *end_options = NULL;
2051            const char *s = raw_command_line;
2052            while (s && s[0])
2053            {
2054                end_options = ::strstr (s, "--");
2055                if (end_options)
2056                {
2057                    end_options += 2; // Get past the "--"
2058                    if (::isspace (end_options[0]))
2059                    {
2060                        expr = end_options;
2061                        while (::isspace (*expr))
2062                            ++expr;
2063                        break;
2064                    }
2065                }
2066                s = end_options;
2067            }
2068
2069            if (end_options)
2070            {
2071                Args args (raw_command_line, end_options - raw_command_line);
2072                if (!ParseOptions (args, result))
2073                    return false;
2074            }
2075        }
2076
2077        if (expr == NULL)
2078            expr = raw_command_line;
2079
2080        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
2081        Error error;
2082        if (platform_sp)
2083        {
2084            const char *working_dir = NULL;
2085            std::string output;
2086            int status = -1;
2087            int signo = -1;
2088            error = (platform_sp->RunShellCommand (expr, working_dir, &status, &signo, &output, m_options.timeout));
2089            if (!output.empty())
2090                result.GetOutputStream().PutCString(output.c_str());
2091            if (status > 0)
2092            {
2093                if (signo > 0)
2094                {
2095                    const char *signo_cstr = Host::GetSignalAsCString(signo);
2096                    if (signo_cstr)
2097                        result.GetOutputStream().Printf("error: command returned with status %i and signal %s\n", status, signo_cstr);
2098                    else
2099                        result.GetOutputStream().Printf("error: command returned with status %i and signal %i\n", status, signo);
2100                }
2101                else
2102                    result.GetOutputStream().Printf("error: command returned with status %i\n", status);
2103            }
2104        }
2105        else
2106        {
2107            result.GetOutputStream().Printf("error: cannot run remote shell commands without a platform\n");
2108            error.SetErrorString("error: cannot run remote shell commands without a platform");
2109        }
2110
2111        if (error.Fail())
2112        {
2113            result.AppendError(error.AsCString());
2114            result.SetStatus (eReturnStatusFailed);
2115        }
2116        else
2117        {
2118            result.SetStatus (eReturnStatusSuccessFinishResult);
2119        }
2120        return true;
2121    }
2122    CommandOptions m_options;
2123};
2124
2125OptionDefinition
2126CommandObjectPlatformShell::CommandOptions::g_option_table[] =
2127{
2128    { LLDB_OPT_SET_ALL, false, "timeout",      't', OptionParser::eRequiredArgument, NULL, 0, eArgTypeValue,    "Seconds to wait for the remote host to finish running the command."},
2129    { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
2130};
2131
2132struct RecurseCopyBaton
2133{
2134    const std::string& destination;
2135    const PlatformSP& platform_sp;
2136    Error error;
2137};
2138
2139
2140static FileSpec::EnumerateDirectoryResult
2141RecurseCopy_Callback (void *baton,
2142                      FileSpec::FileType file_type,
2143                      const FileSpec &spec)
2144{
2145    RecurseCopyBaton* rc_baton = (RecurseCopyBaton*)baton;
2146    switch (file_type)
2147    {
2148        case FileSpec::eFileTypePipe:
2149        case FileSpec::eFileTypeSocket:
2150            // we have no way to copy pipes and sockets - ignore them and continue
2151            return FileSpec::eEnumerateDirectoryResultNext;
2152            break;
2153
2154        case FileSpec::eFileTypeSymbolicLink:
2155            // what to do for symlinks?
2156            return FileSpec::eEnumerateDirectoryResultNext;
2157            break;
2158
2159        case FileSpec::eFileTypeDirectory:
2160        {
2161            // make the new directory and get in there
2162            FileSpec new_directory(rc_baton->destination.c_str(),false);
2163            new_directory.AppendPathComponent(spec.GetLastPathComponent());
2164            uint32_t errcode = rc_baton->platform_sp->MakeDirectory(new_directory, 0777);
2165            std::string new_directory_path (new_directory.GetPath());
2166            if (errcode != 0)
2167            {
2168                rc_baton->error.SetErrorStringWithFormat("unable to setup directory %s on remote end",new_directory_path.c_str());
2169                return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
2170            }
2171
2172            // now recurse
2173            std::string local_path (spec.GetPath());
2174            RecurseCopyBaton rc_baton2 = { new_directory_path, rc_baton->platform_sp, Error() };
2175            FileSpec::EnumerateDirectory(local_path.c_str(), true, true, true, RecurseCopy_Callback, &rc_baton2);
2176            if (rc_baton2.error.Fail())
2177            {
2178                rc_baton->error.SetErrorString(rc_baton2.error.AsCString());
2179                return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
2180            }
2181            return FileSpec::eEnumerateDirectoryResultNext;
2182        }
2183            break;
2184
2185        case FileSpec::eFileTypeRegular:
2186        {
2187            // copy the file and keep going
2188            std::string dest(rc_baton->destination);
2189            dest.append(spec.GetFilename().GetCString());
2190            Error err = rc_baton->platform_sp->PutFile(spec, FileSpec(dest.c_str(), false));
2191            if (err.Fail())
2192            {
2193                rc_baton->error.SetErrorString(err.AsCString());
2194                return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
2195            }
2196            return FileSpec::eEnumerateDirectoryResultNext;
2197        }
2198            break;
2199
2200        case FileSpec::eFileTypeInvalid:
2201        case FileSpec::eFileTypeOther:
2202        case FileSpec::eFileTypeUnknown:
2203            rc_baton->error.SetErrorStringWithFormat("invalid file detected during copy: %s/%s", spec.GetDirectory().GetCString(), spec.GetFilename().GetCString());
2204            return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
2205            break;
2206    }
2207}
2208
2209//----------------------------------------------------------------------
2210// "platform install" - install a target to a remote end
2211//----------------------------------------------------------------------
2212class CommandObjectPlatformInstall : public CommandObjectParsed
2213{
2214public:
2215    CommandObjectPlatformInstall (CommandInterpreter &interpreter) :
2216    CommandObjectParsed (interpreter,
2217                         "platform target-install",
2218                         "Install a target (bundle or executable file) to the remote end.",
2219                         "platform target-install <local-thing> <remote-sandbox>",
2220                         0)
2221    {
2222    }
2223
2224    virtual
2225    ~CommandObjectPlatformInstall ()
2226    {
2227    }
2228
2229    virtual bool
2230    DoExecute (Args& args, CommandReturnObject &result)
2231    {
2232        if (args.GetArgumentCount() != 2)
2233        {
2234            result.AppendError("platform target-install takes two arguments");
2235            result.SetStatus(eReturnStatusFailed);
2236            return false;
2237        }
2238        // TODO: move the bulk of this code over to the platform itself
2239        std::string local_thing(args.GetArgumentAtIndex(0));
2240        std::string remote_sandbox(args.GetArgumentAtIndex(1));
2241        FileSpec source(local_thing.c_str(), true);
2242        if (source.Exists() == false)
2243        {
2244            result.AppendError("source location does not exist or is not accessible");
2245            result.SetStatus(eReturnStatusFailed);
2246            return false;
2247        }
2248        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
2249        if (!platform_sp)
2250        {
2251            result.AppendError ("no platform currently selected");
2252            result.SetStatus (eReturnStatusFailed);
2253            return false;
2254        }
2255        FileSpec::FileType source_type(source.GetFileType());
2256        if (source_type == FileSpec::eFileTypeDirectory)
2257        {
2258            if (platform_sp->GetSupportsRSync())
2259            {
2260                FileSpec remote_folder(remote_sandbox.c_str(), false);
2261                Error rsync_err = platform_sp->PutFile(source, remote_folder);
2262                if (rsync_err.Success())
2263                {
2264                    result.SetStatus(eReturnStatusSuccessFinishResult);
2265                    return result.Succeeded();
2266                }
2267            }
2268            FileSpec remote_folder(remote_sandbox.c_str(), false);
2269            remote_folder.AppendPathComponent(source.GetLastPathComponent());
2270            // TODO: default permissions are bad
2271            uint32_t errcode = platform_sp->MakeDirectory(remote_folder, 0777);
2272            if (errcode != 0)
2273            {
2274                result.AppendError("unable to setup target directory on remote end");
2275                result.SetStatus(eReturnStatusSuccessFinishNoResult);
2276                return result.Succeeded();
2277            }
2278            // now recurse
2279            std::string remote_folder_path (remote_folder.GetPath());
2280            Error err = RecurseCopy(source,remote_folder_path,platform_sp);
2281            if (err.Fail())
2282            {
2283                result.AppendError(err.AsCString());
2284                result.SetStatus(eReturnStatusFailed);
2285            }
2286            else
2287                result.SetStatus(eReturnStatusSuccessFinishResult);
2288            return result.Succeeded();
2289        }
2290        else if (source_type == FileSpec::eFileTypeRegular)
2291        {
2292            // just a plain file - push it to remote and be done
2293            remote_sandbox.append(source.GetFilename().GetCString());
2294            FileSpec destination(remote_sandbox.c_str(),false);
2295            Error err = platform_sp->PutFile(source, destination);
2296            if (err.Success())
2297                result.SetStatus(eReturnStatusSuccessFinishResult);
2298            else
2299            {
2300                result.AppendError(err.AsCString());
2301                result.SetStatus(eReturnStatusFailed);
2302            }
2303            return result.Succeeded();
2304        }
2305        else
2306        {
2307            result.AppendError("source is not a known type of file");
2308            result.SetStatus(eReturnStatusFailed);
2309            return result.Succeeded();
2310        }
2311    }
2312private:
2313
2314    Error
2315    RecurseCopy (const FileSpec& source,
2316                 const std::string& destination,
2317                 const PlatformSP& platform_sp)
2318    {
2319        std::string source_path (source.GetPath());
2320        RecurseCopyBaton baton = { destination, platform_sp, Error() };
2321        FileSpec::EnumerateDirectory(source_path.c_str(), true, true, true, RecurseCopy_Callback, &baton);
2322        return baton.error;
2323    }
2324};
2325
2326//----------------------------------------------------------------------
2327// CommandObjectPlatform constructor
2328//----------------------------------------------------------------------
2329CommandObjectPlatform::CommandObjectPlatform(CommandInterpreter &interpreter) :
2330    CommandObjectMultiword (interpreter,
2331                            "platform",
2332                            "A set of commands to manage and create platforms.",
2333                            "platform [connect|disconnect|info|list|status|select] ...")
2334{
2335    LoadSubCommand ("select", CommandObjectSP (new CommandObjectPlatformSelect  (interpreter)));
2336    LoadSubCommand ("list"  , CommandObjectSP (new CommandObjectPlatformList    (interpreter)));
2337    LoadSubCommand ("status", CommandObjectSP (new CommandObjectPlatformStatus  (interpreter)));
2338    LoadSubCommand ("connect", CommandObjectSP (new CommandObjectPlatformConnect  (interpreter)));
2339    LoadSubCommand ("disconnect", CommandObjectSP (new CommandObjectPlatformDisconnect  (interpreter)));
2340#ifdef LLDB_CONFIGURATION_DEBUG
2341    LoadSubCommand ("mkdir", CommandObjectSP (new CommandObjectPlatformMkDir  (interpreter)));
2342    LoadSubCommand ("file", CommandObjectSP (new CommandObjectPlatformFile  (interpreter)));
2343    LoadSubCommand ("get-file", CommandObjectSP (new CommandObjectPlatformGetFile  (interpreter)));
2344    LoadSubCommand ("get-size", CommandObjectSP (new CommandObjectPlatformGetSize  (interpreter)));
2345    LoadSubCommand ("put-file", CommandObjectSP (new CommandObjectPlatformPutFile  (interpreter)));
2346#endif
2347    LoadSubCommand ("process", CommandObjectSP (new CommandObjectPlatformProcess  (interpreter)));
2348    LoadSubCommand ("shell", CommandObjectSP (new CommandObjectPlatformShell  (interpreter)));
2349    LoadSubCommand ("target-install", CommandObjectSP (new CommandObjectPlatformInstall  (interpreter)));
2350}
2351
2352
2353//----------------------------------------------------------------------
2354// Destructor
2355//----------------------------------------------------------------------
2356CommandObjectPlatform::~CommandObjectPlatform()
2357{
2358}
2359