1//===-- Platform.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/Target/Platform.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/Breakpoint/BreakpointIDList.h"
17#include "lldb/Core/Error.h"
18#include "lldb/Core/Log.h"
19#include "lldb/Core/ModuleSpec.h"
20#include "lldb/Core/PluginManager.h"
21#include "lldb/Host/FileSpec.h"
22#include "lldb/Host/Host.h"
23#include "lldb/Target/Process.h"
24#include "lldb/Target/Target.h"
25#include "lldb/Utility/Utils.h"
26
27using namespace lldb;
28using namespace lldb_private;
29
30// Use a singleton function for g_local_platform_sp to avoid init
31// constructors since LLDB is often part of a shared library
32static PlatformSP&
33GetDefaultPlatformSP ()
34{
35    static PlatformSP g_default_platform_sp;
36    return g_default_platform_sp;
37}
38
39static Mutex &
40GetConnectedPlatformListMutex ()
41{
42    static Mutex g_remote_connected_platforms_mutex (Mutex::eMutexTypeRecursive);
43    return g_remote_connected_platforms_mutex;
44}
45static std::vector<PlatformSP> &
46GetConnectedPlatformList ()
47{
48    static std::vector<PlatformSP> g_remote_connected_platforms;
49    return g_remote_connected_platforms;
50}
51
52
53const char *
54Platform::GetHostPlatformName ()
55{
56    return "host";
57}
58
59//------------------------------------------------------------------
60/// Get the native host platform plug-in.
61///
62/// There should only be one of these for each host that LLDB runs
63/// upon that should be statically compiled in and registered using
64/// preprocessor macros or other similar build mechanisms.
65///
66/// This platform will be used as the default platform when launching
67/// or attaching to processes unless another platform is specified.
68//------------------------------------------------------------------
69PlatformSP
70Platform::GetDefaultPlatform ()
71{
72    return GetDefaultPlatformSP ();
73}
74
75void
76Platform::SetDefaultPlatform (const lldb::PlatformSP &platform_sp)
77{
78    // The native platform should use its static void Platform::Initialize()
79    // function to register itself as the native platform.
80    GetDefaultPlatformSP () = platform_sp;
81}
82
83Error
84Platform::GetFileWithUUID (const FileSpec &platform_file,
85                           const UUID *uuid_ptr,
86                           FileSpec &local_file)
87{
88    // Default to the local case
89    local_file = platform_file;
90    return Error();
91}
92
93FileSpecList
94Platform::LocateExecutableScriptingResources (Target *target, Module &module)
95{
96    return FileSpecList();
97}
98
99Platform*
100Platform::FindPlugin (Process *process, const ConstString &plugin_name)
101{
102    PlatformCreateInstance create_callback = NULL;
103    if (plugin_name)
104    {
105        create_callback  = PluginManager::GetPlatformCreateCallbackForPluginName (plugin_name);
106        if (create_callback)
107        {
108            ArchSpec arch;
109            if (process)
110            {
111                arch = process->GetTarget().GetArchitecture();
112            }
113            std::unique_ptr<Platform> instance_ap(create_callback(process, &arch));
114            if (instance_ap.get())
115                return instance_ap.release();
116        }
117    }
118    else
119    {
120        for (uint32_t idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex(idx)) != NULL; ++idx)
121        {
122            std::unique_ptr<Platform> instance_ap(create_callback(process, nullptr));
123            if (instance_ap.get())
124                return instance_ap.release();
125        }
126    }
127    return NULL;
128}
129
130Error
131Platform::GetSharedModule (const ModuleSpec &module_spec,
132                           ModuleSP &module_sp,
133                           const FileSpecList *module_search_paths_ptr,
134                           ModuleSP *old_module_sp_ptr,
135                           bool *did_create_ptr)
136{
137    // Don't do any path remapping for the default implementation
138    // of the platform GetSharedModule function, just call through
139    // to our static ModuleList function. Platform subclasses that
140    // implement remote debugging, might have a developer kits
141    // installed that have cached versions of the files for the
142    // remote target, or might implement a download and cache
143    // locally implementation.
144    const bool always_create = false;
145    return ModuleList::GetSharedModule (module_spec,
146                                        module_sp,
147                                        module_search_paths_ptr,
148                                        old_module_sp_ptr,
149                                        did_create_ptr,
150                                        always_create);
151}
152
153PlatformSP
154Platform::Create (const char *platform_name, Error &error)
155{
156    PlatformCreateInstance create_callback = NULL;
157    lldb::PlatformSP platform_sp;
158    if (platform_name && platform_name[0])
159    {
160        ConstString const_platform_name (platform_name);
161        create_callback = PluginManager::GetPlatformCreateCallbackForPluginName (const_platform_name);
162        if (create_callback)
163            platform_sp.reset(create_callback(true, NULL));
164        else
165            error.SetErrorStringWithFormat ("unable to find a plug-in for the platform named \"%s\"", platform_name);
166    }
167    else
168        error.SetErrorString ("invalid platform name");
169    return platform_sp;
170}
171
172
173PlatformSP
174Platform::Create (const ArchSpec &arch, ArchSpec *platform_arch_ptr, Error &error)
175{
176    lldb::PlatformSP platform_sp;
177    if (arch.IsValid())
178    {
179        uint32_t idx;
180        PlatformCreateInstance create_callback;
181        // First try exact arch matches across all platform plug-ins
182        bool exact = true;
183        for (idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex (idx)); ++idx)
184        {
185            if (create_callback)
186            {
187                platform_sp.reset(create_callback(false, &arch));
188                if (platform_sp && platform_sp->IsCompatibleArchitecture(arch, exact, platform_arch_ptr))
189                    return platform_sp;
190            }
191        }
192        // Next try compatible arch matches across all platform plug-ins
193        exact = false;
194        for (idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex (idx)); ++idx)
195        {
196            if (create_callback)
197            {
198                platform_sp.reset(create_callback(false, &arch));
199                if (platform_sp && platform_sp->IsCompatibleArchitecture(arch, exact, platform_arch_ptr))
200                    return platform_sp;
201            }
202        }
203    }
204    else
205        error.SetErrorString ("invalid platform name");
206    if (platform_arch_ptr)
207        platform_arch_ptr->Clear();
208    platform_sp.reset();
209    return platform_sp;
210}
211
212uint32_t
213Platform::GetNumConnectedRemotePlatforms ()
214{
215    Mutex::Locker locker (GetConnectedPlatformListMutex ());
216    return GetConnectedPlatformList().size();
217}
218
219PlatformSP
220Platform::GetConnectedRemotePlatformAtIndex (uint32_t idx)
221{
222    PlatformSP platform_sp;
223    {
224        Mutex::Locker locker (GetConnectedPlatformListMutex ());
225        if (idx < GetConnectedPlatformList().size())
226            platform_sp = GetConnectedPlatformList ()[idx];
227    }
228    return platform_sp;
229}
230
231//------------------------------------------------------------------
232/// Default Constructor
233//------------------------------------------------------------------
234Platform::Platform (bool is_host) :
235    m_is_host (is_host),
236    m_os_version_set_while_connected (false),
237    m_system_arch_set_while_connected (false),
238    m_sdk_sysroot (),
239    m_sdk_build (),
240    m_working_dir (),
241    m_remote_url (),
242    m_name (),
243    m_major_os_version (UINT32_MAX),
244    m_minor_os_version (UINT32_MAX),
245    m_update_os_version (UINT32_MAX),
246    m_system_arch(),
247    m_uid_map_mutex (Mutex::eMutexTypeNormal),
248    m_gid_map_mutex (Mutex::eMutexTypeNormal),
249    m_uid_map(),
250    m_gid_map(),
251    m_max_uid_name_len (0),
252    m_max_gid_name_len (0),
253    m_supports_rsync (false),
254    m_rsync_opts (),
255    m_rsync_prefix (),
256    m_supports_ssh (false),
257    m_ssh_opts (),
258    m_ignores_remote_hostname (false),
259    m_trap_handlers(),
260    m_calculated_trap_handlers (false)
261{
262    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
263    if (log)
264        log->Printf ("%p Platform::Platform()", this);
265}
266
267//------------------------------------------------------------------
268/// Destructor.
269///
270/// The destructor is virtual since this class is designed to be
271/// inherited from by the plug-in instance.
272//------------------------------------------------------------------
273Platform::~Platform()
274{
275    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
276    if (log)
277        log->Printf ("%p Platform::~Platform()", this);
278}
279
280void
281Platform::GetStatus (Stream &strm)
282{
283    uint32_t major = UINT32_MAX;
284    uint32_t minor = UINT32_MAX;
285    uint32_t update = UINT32_MAX;
286    std::string s;
287    strm.Printf ("  Platform: %s\n", GetPluginName().GetCString());
288
289    ArchSpec arch (GetSystemArchitecture());
290    if (arch.IsValid())
291    {
292        if (!arch.GetTriple().str().empty())
293        strm.Printf("    Triple: %s\n", arch.GetTriple().str().c_str());
294    }
295
296    if (GetOSVersion(major, minor, update))
297    {
298        strm.Printf("OS Version: %u", major);
299        if (minor != UINT32_MAX)
300            strm.Printf(".%u", minor);
301        if (update != UINT32_MAX)
302            strm.Printf(".%u", update);
303
304        if (GetOSBuildString (s))
305            strm.Printf(" (%s)", s.c_str());
306
307        strm.EOL();
308    }
309
310    if (GetOSKernelDescription (s))
311        strm.Printf("    Kernel: %s\n", s.c_str());
312
313    if (IsHost())
314    {
315        strm.Printf("  Hostname: %s\n", GetHostname());
316    }
317    else
318    {
319        const bool is_connected = IsConnected();
320        if (is_connected)
321            strm.Printf("  Hostname: %s\n", GetHostname());
322        strm.Printf(" Connected: %s\n", is_connected ? "yes" : "no");
323    }
324
325    if (GetWorkingDirectory())
326    {
327        strm.Printf("WorkingDir: %s\n", GetWorkingDirectory().GetCString());
328    }
329    if (!IsConnected())
330        return;
331
332    std::string specific_info(GetPlatformSpecificConnectionInformation());
333
334    if (specific_info.empty() == false)
335        strm.Printf("Platform-specific connection: %s\n", specific_info.c_str());
336}
337
338
339bool
340Platform::GetOSVersion (uint32_t &major,
341                        uint32_t &minor,
342                        uint32_t &update)
343{
344    bool success = m_major_os_version != UINT32_MAX;
345    if (IsHost())
346    {
347        if (!success)
348        {
349            // We have a local host platform
350            success = Host::GetOSVersion (m_major_os_version,
351                                          m_minor_os_version,
352                                          m_update_os_version);
353            m_os_version_set_while_connected = success;
354        }
355    }
356    else
357    {
358        // We have a remote platform. We can only fetch the remote
359        // OS version if we are connected, and we don't want to do it
360        // more than once.
361
362        const bool is_connected = IsConnected();
363
364        bool fetch = false;
365        if (success)
366        {
367            // We have valid OS version info, check to make sure it wasn't
368            // manually set prior to connecting. If it was manually set prior
369            // to connecting, then lets fetch the actual OS version info
370            // if we are now connected.
371            if (is_connected && !m_os_version_set_while_connected)
372                fetch = true;
373        }
374        else
375        {
376            // We don't have valid OS version info, fetch it if we are connected
377            fetch = is_connected;
378        }
379
380        if (fetch)
381        {
382            success = GetRemoteOSVersion ();
383            m_os_version_set_while_connected = success;
384        }
385    }
386
387    if (success)
388    {
389        major = m_major_os_version;
390        minor = m_minor_os_version;
391        update = m_update_os_version;
392    }
393    return success;
394}
395
396bool
397Platform::GetOSBuildString (std::string &s)
398{
399    if (IsHost())
400        return Host::GetOSBuildString (s);
401    else
402        return GetRemoteOSBuildString (s);
403}
404
405bool
406Platform::GetOSKernelDescription (std::string &s)
407{
408    if (IsHost())
409        return Host::GetOSKernelDescription (s);
410    else
411        return GetRemoteOSKernelDescription (s);
412}
413
414ConstString
415Platform::GetWorkingDirectory ()
416{
417    if (IsHost())
418    {
419        char cwd[PATH_MAX];
420        if (getcwd(cwd, sizeof(cwd)))
421            return ConstString(cwd);
422        else
423            return ConstString();
424    }
425    else
426    {
427        if (!m_working_dir)
428            m_working_dir = GetRemoteWorkingDirectory();
429        return m_working_dir;
430    }
431}
432
433
434struct RecurseCopyBaton
435{
436    const FileSpec& dst;
437    Platform *platform_ptr;
438    Error error;
439};
440
441
442static FileSpec::EnumerateDirectoryResult
443RecurseCopy_Callback (void *baton,
444                      FileSpec::FileType file_type,
445                      const FileSpec &src)
446{
447    RecurseCopyBaton* rc_baton = (RecurseCopyBaton*)baton;
448    switch (file_type)
449    {
450        case FileSpec::eFileTypePipe:
451        case FileSpec::eFileTypeSocket:
452            // we have no way to copy pipes and sockets - ignore them and continue
453            return FileSpec::eEnumerateDirectoryResultNext;
454            break;
455
456        case FileSpec::eFileTypeDirectory:
457            {
458                // make the new directory and get in there
459                FileSpec dst_dir = rc_baton->dst;
460                if (!dst_dir.GetFilename())
461                    dst_dir.GetFilename() = src.GetLastPathComponent();
462                std::string dst_dir_path (dst_dir.GetPath());
463                Error error = rc_baton->platform_ptr->MakeDirectory(dst_dir_path.c_str(), lldb::eFilePermissionsDirectoryDefault);
464                if (error.Fail())
465                {
466                    rc_baton->error.SetErrorStringWithFormat("unable to setup directory %s on remote end", dst_dir_path.c_str());
467                    return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
468                }
469
470                // now recurse
471                std::string src_dir_path (src.GetPath());
472
473                // Make a filespec that only fills in the directory of a FileSpec so
474                // when we enumerate we can quickly fill in the filename for dst copies
475                FileSpec recurse_dst;
476                recurse_dst.GetDirectory().SetCString(dst_dir.GetPath().c_str());
477                RecurseCopyBaton rc_baton2 = { recurse_dst, rc_baton->platform_ptr, Error() };
478                FileSpec::EnumerateDirectory(src_dir_path.c_str(), true, true, true, RecurseCopy_Callback, &rc_baton2);
479                if (rc_baton2.error.Fail())
480                {
481                    rc_baton->error.SetErrorString(rc_baton2.error.AsCString());
482                    return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
483                }
484                return FileSpec::eEnumerateDirectoryResultNext;
485            }
486            break;
487
488        case FileSpec::eFileTypeSymbolicLink:
489            {
490                // copy the file and keep going
491                FileSpec dst_file = rc_baton->dst;
492                if (!dst_file.GetFilename())
493                    dst_file.GetFilename() = src.GetFilename();
494
495                char buf[PATH_MAX];
496
497                rc_baton->error = Host::Readlink (src.GetPath().c_str(), buf, sizeof(buf));
498
499                if (rc_baton->error.Fail())
500                    return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
501
502                rc_baton->error = rc_baton->platform_ptr->CreateSymlink(dst_file.GetPath().c_str(), buf);
503
504                if (rc_baton->error.Fail())
505                    return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
506
507                return FileSpec::eEnumerateDirectoryResultNext;
508            }
509            break;
510        case FileSpec::eFileTypeRegular:
511            {
512                // copy the file and keep going
513                FileSpec dst_file = rc_baton->dst;
514                if (!dst_file.GetFilename())
515                    dst_file.GetFilename() = src.GetFilename();
516                Error err = rc_baton->platform_ptr->PutFile(src, dst_file);
517                if (err.Fail())
518                {
519                    rc_baton->error.SetErrorString(err.AsCString());
520                    return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
521                }
522                return FileSpec::eEnumerateDirectoryResultNext;
523            }
524            break;
525
526        case FileSpec::eFileTypeInvalid:
527        case FileSpec::eFileTypeOther:
528        case FileSpec::eFileTypeUnknown:
529            rc_baton->error.SetErrorStringWithFormat("invalid file detected during copy: %s", src.GetPath().c_str());
530            return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
531            break;
532    }
533}
534
535Error
536Platform::Install (const FileSpec& src, const FileSpec& dst)
537{
538    Error error;
539
540    Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
541    if (log)
542        log->Printf ("Platform::Install (src='%s', dst='%s')", src.GetPath().c_str(), dst.GetPath().c_str());
543    FileSpec fixed_dst(dst);
544
545    if (!fixed_dst.GetFilename())
546        fixed_dst.GetFilename() = src.GetFilename();
547
548    ConstString working_dir = GetWorkingDirectory();
549
550    if (dst)
551    {
552        if (dst.GetDirectory())
553        {
554            const char first_dst_dir_char = dst.GetDirectory().GetCString()[0];
555            if (first_dst_dir_char == '/' || first_dst_dir_char  == '\\')
556            {
557                fixed_dst.GetDirectory() = dst.GetDirectory();
558            }
559            // If the fixed destination file doesn't have a directory yet,
560            // then we must have a relative path. We will resolve this relative
561            // path against the platform's working directory
562            if (!fixed_dst.GetDirectory())
563            {
564                FileSpec relative_spec;
565                std::string path;
566                if (working_dir)
567                {
568                    relative_spec.SetFile(working_dir.GetCString(), false);
569                    relative_spec.AppendPathComponent(dst.GetPath().c_str());
570                    fixed_dst.GetDirectory() = relative_spec.GetDirectory();
571                }
572                else
573                {
574                    error.SetErrorStringWithFormat("platform working directory must be valid for relative path '%s'", dst.GetPath().c_str());
575                    return error;
576                }
577            }
578        }
579        else
580        {
581            if (working_dir)
582            {
583                fixed_dst.GetDirectory() = working_dir;
584            }
585            else
586            {
587                error.SetErrorStringWithFormat("platform working directory must be valid for relative path '%s'", dst.GetPath().c_str());
588                return error;
589            }
590        }
591    }
592    else
593    {
594        if (working_dir)
595        {
596            fixed_dst.GetDirectory() = working_dir;
597        }
598        else
599        {
600            error.SetErrorStringWithFormat("platform working directory must be valid when destination directory is empty");
601            return error;
602        }
603    }
604
605    if (log)
606        log->Printf ("Platform::Install (src='%s', dst='%s') fixed_dst='%s'", src.GetPath().c_str(), dst.GetPath().c_str(), fixed_dst.GetPath().c_str());
607
608    if (GetSupportsRSync())
609    {
610        error = PutFile(src, dst);
611    }
612    else
613    {
614        switch (src.GetFileType())
615        {
616            case FileSpec::eFileTypeDirectory:
617                {
618                    if (GetFileExists (fixed_dst))
619                        Unlink (fixed_dst.GetPath().c_str());
620                    uint32_t permissions = src.GetPermissions();
621                    if (permissions == 0)
622                        permissions = eFilePermissionsDirectoryDefault;
623                    std::string dst_dir_path(fixed_dst.GetPath());
624                    error = MakeDirectory(dst_dir_path.c_str(), permissions);
625                    if (error.Success())
626                    {
627                        // Make a filespec that only fills in the directory of a FileSpec so
628                        // when we enumerate we can quickly fill in the filename for dst copies
629                        FileSpec recurse_dst;
630                        recurse_dst.GetDirectory().SetCString(dst_dir_path.c_str());
631                        std::string src_dir_path (src.GetPath());
632                        RecurseCopyBaton baton = { recurse_dst, this, Error() };
633                        FileSpec::EnumerateDirectory(src_dir_path.c_str(), true, true, true, RecurseCopy_Callback, &baton);
634                        return baton.error;
635                    }
636                }
637                break;
638
639            case FileSpec::eFileTypeRegular:
640                if (GetFileExists (fixed_dst))
641                    Unlink (fixed_dst.GetPath().c_str());
642                error = PutFile(src, fixed_dst);
643                break;
644
645            case FileSpec::eFileTypeSymbolicLink:
646                {
647                    if (GetFileExists (fixed_dst))
648                        Unlink (fixed_dst.GetPath().c_str());
649                    char buf[PATH_MAX];
650                    error = Host::Readlink(src.GetPath().c_str(), buf, sizeof(buf));
651                    if (error.Success())
652                        error = CreateSymlink(dst.GetPath().c_str(), buf);
653                }
654                break;
655            case FileSpec::eFileTypePipe:
656                error.SetErrorString("platform install doesn't handle pipes");
657                break;
658            case FileSpec::eFileTypeSocket:
659                error.SetErrorString("platform install doesn't handle sockets");
660                break;
661            case FileSpec::eFileTypeInvalid:
662            case FileSpec::eFileTypeUnknown:
663            case FileSpec::eFileTypeOther:
664                error.SetErrorString("platform install doesn't handle non file or directory items");
665                break;
666        }
667    }
668    return error;
669}
670
671bool
672Platform::SetWorkingDirectory (const ConstString &path)
673{
674    if (IsHost())
675    {
676        Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
677        if (log)
678            log->Printf("Platform::SetWorkingDirectory('%s')", path.GetCString());
679#ifdef _WIN32
680        // Not implemented on Windows
681        return false;
682#else
683        if (path)
684        {
685            if (chdir(path.GetCString()) == 0)
686                return true;
687        }
688        return false;
689#endif
690    }
691    else
692    {
693        m_working_dir.Clear();
694        return SetRemoteWorkingDirectory(path);
695    }
696}
697
698Error
699Platform::MakeDirectory (const char *path, uint32_t permissions)
700{
701    if (IsHost())
702        return Host::MakeDirectory (path, permissions);
703    else
704    {
705        Error error;
706        error.SetErrorStringWithFormat("remote platform %s doesn't support %s", GetPluginName().GetCString(), __PRETTY_FUNCTION__);
707        return error;
708    }
709}
710
711Error
712Platform::GetFilePermissions (const char *path, uint32_t &file_permissions)
713{
714    if (IsHost())
715        return Host::GetFilePermissions(path, file_permissions);
716    else
717    {
718        Error error;
719        error.SetErrorStringWithFormat("remote platform %s doesn't support %s", GetPluginName().GetCString(), __PRETTY_FUNCTION__);
720        return error;
721    }
722}
723
724Error
725Platform::SetFilePermissions (const char *path, uint32_t file_permissions)
726{
727    if (IsHost())
728        return Host::SetFilePermissions(path, file_permissions);
729    else
730    {
731        Error error;
732        error.SetErrorStringWithFormat("remote platform %s doesn't support %s", GetPluginName().GetCString(), __PRETTY_FUNCTION__);
733        return error;
734    }
735}
736
737ConstString
738Platform::GetName ()
739{
740    return GetPluginName();
741}
742
743const char *
744Platform::GetHostname ()
745{
746    if (IsHost())
747        return "localhost";
748
749    if (m_name.empty())
750        return NULL;
751    return m_name.c_str();
752}
753
754bool
755Platform::SetRemoteWorkingDirectory(const ConstString &path)
756{
757    Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
758    if (log)
759        log->Printf("Platform::SetRemoteWorkingDirectory('%s')", path.GetCString());
760    m_working_dir = path;
761    return true;
762}
763
764const char *
765Platform::GetUserName (uint32_t uid)
766{
767    const char *user_name = GetCachedUserName(uid);
768    if (user_name)
769        return user_name;
770    if (IsHost())
771    {
772        std::string name;
773        if (Host::GetUserName(uid, name))
774            return SetCachedUserName (uid, name.c_str(), name.size());
775    }
776    return NULL;
777}
778
779const char *
780Platform::GetGroupName (uint32_t gid)
781{
782    const char *group_name = GetCachedGroupName(gid);
783    if (group_name)
784        return group_name;
785    if (IsHost())
786    {
787        std::string name;
788        if (Host::GetGroupName(gid, name))
789            return SetCachedGroupName (gid, name.c_str(), name.size());
790    }
791    return NULL;
792}
793
794bool
795Platform::SetOSVersion (uint32_t major,
796                        uint32_t minor,
797                        uint32_t update)
798{
799    if (IsHost())
800    {
801        // We don't need anyone setting the OS version for the host platform,
802        // we should be able to figure it out by calling Host::GetOSVersion(...).
803        return false;
804    }
805    else
806    {
807        // We have a remote platform, allow setting the target OS version if
808        // we aren't connected, since if we are connected, we should be able to
809        // request the remote OS version from the connected platform.
810        if (IsConnected())
811            return false;
812        else
813        {
814            // We aren't connected and we might want to set the OS version
815            // ahead of time before we connect so we can peruse files and
816            // use a local SDK or PDK cache of support files to disassemble
817            // or do other things.
818            m_major_os_version = major;
819            m_minor_os_version = minor;
820            m_update_os_version = update;
821            return true;
822        }
823    }
824    return false;
825}
826
827
828Error
829Platform::ResolveExecutable (const FileSpec &exe_file,
830                             const ArchSpec &exe_arch,
831                             lldb::ModuleSP &exe_module_sp,
832                             const FileSpecList *module_search_paths_ptr)
833{
834    Error error;
835    if (exe_file.Exists())
836    {
837        ModuleSpec module_spec (exe_file, exe_arch);
838        if (module_spec.GetArchitecture().IsValid())
839        {
840            error = ModuleList::GetSharedModule (module_spec,
841                                                 exe_module_sp,
842                                                 module_search_paths_ptr,
843                                                 NULL,
844                                                 NULL);
845        }
846        else
847        {
848            // No valid architecture was specified, ask the platform for
849            // the architectures that we should be using (in the correct order)
850            // and see if we can find a match that way
851            for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, module_spec.GetArchitecture()); ++idx)
852            {
853                error = ModuleList::GetSharedModule (module_spec,
854                                                     exe_module_sp,
855                                                     module_search_paths_ptr,
856                                                     NULL,
857                                                     NULL);
858                // Did we find an executable using one of the
859                if (error.Success() && exe_module_sp)
860                    break;
861            }
862        }
863    }
864    else
865    {
866        error.SetErrorStringWithFormat ("'%s' does not exist",
867                                        exe_file.GetPath().c_str());
868    }
869    return error;
870}
871
872Error
873Platform::ResolveSymbolFile (Target &target,
874                             const ModuleSpec &sym_spec,
875                             FileSpec &sym_file)
876{
877    Error error;
878    if (sym_spec.GetSymbolFileSpec().Exists())
879        sym_file = sym_spec.GetSymbolFileSpec();
880    else
881        error.SetErrorString("unable to resolve symbol file");
882    return error;
883
884}
885
886
887
888bool
889Platform::ResolveRemotePath (const FileSpec &platform_path,
890                             FileSpec &resolved_platform_path)
891{
892    resolved_platform_path = platform_path;
893    return resolved_platform_path.ResolvePath();
894}
895
896
897const ArchSpec &
898Platform::GetSystemArchitecture()
899{
900    if (IsHost())
901    {
902        if (!m_system_arch.IsValid())
903        {
904            // We have a local host platform
905            m_system_arch = Host::GetArchitecture();
906            m_system_arch_set_while_connected = m_system_arch.IsValid();
907        }
908    }
909    else
910    {
911        // We have a remote platform. We can only fetch the remote
912        // system architecture if we are connected, and we don't want to do it
913        // more than once.
914
915        const bool is_connected = IsConnected();
916
917        bool fetch = false;
918        if (m_system_arch.IsValid())
919        {
920            // We have valid OS version info, check to make sure it wasn't
921            // manually set prior to connecting. If it was manually set prior
922            // to connecting, then lets fetch the actual OS version info
923            // if we are now connected.
924            if (is_connected && !m_system_arch_set_while_connected)
925                fetch = true;
926        }
927        else
928        {
929            // We don't have valid OS version info, fetch it if we are connected
930            fetch = is_connected;
931        }
932
933        if (fetch)
934        {
935            m_system_arch = GetRemoteSystemArchitecture ();
936            m_system_arch_set_while_connected = m_system_arch.IsValid();
937        }
938    }
939    return m_system_arch;
940}
941
942
943Error
944Platform::ConnectRemote (Args& args)
945{
946    Error error;
947    if (IsHost())
948        error.SetErrorStringWithFormat ("The currently selected platform (%s) is the host platform and is always connected.", GetPluginName().GetCString());
949    else
950        error.SetErrorStringWithFormat ("Platform::ConnectRemote() is not supported by %s", GetPluginName().GetCString());
951    return error;
952}
953
954Error
955Platform::DisconnectRemote ()
956{
957    Error error;
958    if (IsHost())
959        error.SetErrorStringWithFormat ("The currently selected platform (%s) is the host platform and is always connected.", GetPluginName().GetCString());
960    else
961        error.SetErrorStringWithFormat ("Platform::DisconnectRemote() is not supported by %s", GetPluginName().GetCString());
962    return error;
963}
964
965bool
966Platform::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
967{
968    // Take care of the host case so that each subclass can just
969    // call this function to get the host functionality.
970    if (IsHost())
971        return Host::GetProcessInfo (pid, process_info);
972    return false;
973}
974
975uint32_t
976Platform::FindProcesses (const ProcessInstanceInfoMatch &match_info,
977                         ProcessInstanceInfoList &process_infos)
978{
979    // Take care of the host case so that each subclass can just
980    // call this function to get the host functionality.
981    uint32_t match_count = 0;
982    if (IsHost())
983        match_count = Host::FindProcesses (match_info, process_infos);
984    return match_count;
985}
986
987
988Error
989Platform::LaunchProcess (ProcessLaunchInfo &launch_info)
990{
991    Error error;
992    // Take care of the host case so that each subclass can just
993    // call this function to get the host functionality.
994    if (IsHost())
995    {
996        if (::getenv ("LLDB_LAUNCH_FLAG_LAUNCH_IN_TTY"))
997            launch_info.GetFlags().Set (eLaunchFlagLaunchInTTY);
998
999        if (launch_info.GetFlags().Test (eLaunchFlagLaunchInShell))
1000        {
1001            const bool is_localhost = true;
1002            const bool will_debug = launch_info.GetFlags().Test(eLaunchFlagDebug);
1003            const bool first_arg_is_full_shell_command = false;
1004            uint32_t num_resumes = GetResumeCountForLaunchInfo (launch_info);
1005            if (!launch_info.ConvertArgumentsForLaunchingInShell (error,
1006                                                                  is_localhost,
1007                                                                  will_debug,
1008                                                                  first_arg_is_full_shell_command,
1009                                                                  num_resumes))
1010                return error;
1011        }
1012
1013        error = Host::LaunchProcess (launch_info);
1014    }
1015    else
1016        error.SetErrorString ("base lldb_private::Platform class can't launch remote processes");
1017    return error;
1018}
1019
1020lldb::ProcessSP
1021Platform::DebugProcess (ProcessLaunchInfo &launch_info,
1022                        Debugger &debugger,
1023                        Target *target,       // Can be NULL, if NULL create a new target, else use existing one
1024                        Listener &listener,
1025                        Error &error)
1026{
1027    ProcessSP process_sp;
1028    // Make sure we stop at the entry point
1029    launch_info.GetFlags ().Set (eLaunchFlagDebug);
1030    // We always launch the process we are going to debug in a separate process
1031    // group, since then we can handle ^C interrupts ourselves w/o having to worry
1032    // about the target getting them as well.
1033    launch_info.SetLaunchInSeparateProcessGroup(true);
1034
1035    error = LaunchProcess (launch_info);
1036    if (error.Success())
1037    {
1038        if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
1039        {
1040            ProcessAttachInfo attach_info (launch_info);
1041            process_sp = Attach (attach_info, debugger, target, listener, error);
1042            if (process_sp)
1043            {
1044                launch_info.SetHijackListener(attach_info.GetHijackListener());
1045
1046                // Since we attached to the process, it will think it needs to detach
1047                // if the process object just goes away without an explicit call to
1048                // Process::Kill() or Process::Detach(), so let it know to kill the
1049                // process if this happens.
1050                process_sp->SetShouldDetach (false);
1051
1052                // If we didn't have any file actions, the pseudo terminal might
1053                // have been used where the slave side was given as the file to
1054                // open for stdin/out/err after we have already opened the master
1055                // so we can read/write stdin/out/err.
1056                int pty_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor();
1057                if (pty_fd != lldb_utility::PseudoTerminal::invalid_fd)
1058                {
1059                    process_sp->SetSTDIOFileDescriptor(pty_fd);
1060                }
1061            }
1062        }
1063    }
1064    return process_sp;
1065}
1066
1067
1068lldb::PlatformSP
1069Platform::GetPlatformForArchitecture (const ArchSpec &arch, ArchSpec *platform_arch_ptr)
1070{
1071    lldb::PlatformSP platform_sp;
1072    Error error;
1073    if (arch.IsValid())
1074        platform_sp = Platform::Create (arch, platform_arch_ptr, error);
1075    return platform_sp;
1076}
1077
1078
1079//------------------------------------------------------------------
1080/// Lets a platform answer if it is compatible with a given
1081/// architecture and the target triple contained within.
1082//------------------------------------------------------------------
1083bool
1084Platform::IsCompatibleArchitecture (const ArchSpec &arch, bool exact_arch_match, ArchSpec *compatible_arch_ptr)
1085{
1086    // If the architecture is invalid, we must answer true...
1087    if (arch.IsValid())
1088    {
1089        ArchSpec platform_arch;
1090        // Try for an exact architecture match first.
1091        if (exact_arch_match)
1092        {
1093            for (uint32_t arch_idx=0; GetSupportedArchitectureAtIndex (arch_idx, platform_arch); ++arch_idx)
1094            {
1095                if (arch.IsExactMatch(platform_arch))
1096                {
1097                    if (compatible_arch_ptr)
1098                        *compatible_arch_ptr = platform_arch;
1099                    return true;
1100                }
1101            }
1102        }
1103        else
1104        {
1105            for (uint32_t arch_idx=0; GetSupportedArchitectureAtIndex (arch_idx, platform_arch); ++arch_idx)
1106            {
1107                if (arch.IsCompatibleMatch(platform_arch))
1108                {
1109                    if (compatible_arch_ptr)
1110                        *compatible_arch_ptr = platform_arch;
1111                    return true;
1112                }
1113            }
1114        }
1115    }
1116    if (compatible_arch_ptr)
1117        compatible_arch_ptr->Clear();
1118    return false;
1119}
1120
1121Error
1122Platform::PutFile (const FileSpec& source,
1123                   const FileSpec& destination,
1124                   uint32_t uid,
1125                   uint32_t gid)
1126{
1127    Error error("unimplemented");
1128    return error;
1129}
1130
1131Error
1132Platform::GetFile (const FileSpec& source,
1133                   const FileSpec& destination)
1134{
1135    Error error("unimplemented");
1136    return error;
1137}
1138
1139Error
1140Platform::CreateSymlink (const char *src, // The name of the link is in src
1141                         const char *dst)// The symlink points to dst
1142{
1143    Error error("unimplemented");
1144    return error;
1145}
1146
1147bool
1148Platform::GetFileExists (const lldb_private::FileSpec& file_spec)
1149{
1150    return false;
1151}
1152
1153Error
1154Platform::Unlink (const char *path)
1155{
1156    Error error("unimplemented");
1157    return error;
1158}
1159
1160
1161
1162lldb_private::Error
1163Platform::RunShellCommand (const char *command,           // Shouldn't be NULL
1164                           const char *working_dir,       // Pass NULL to use the current working directory
1165                           int *status_ptr,               // Pass NULL if you don't want the process exit status
1166                           int *signo_ptr,                // Pass NULL if you don't want the signal that caused the process to exit
1167                           std::string *command_output,   // Pass NULL if you don't want the command output
1168                           uint32_t timeout_sec)          // Timeout in seconds to wait for shell program to finish
1169{
1170    if (IsHost())
1171        return Host::RunShellCommand (command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
1172    else
1173        return Error("unimplemented");
1174}
1175
1176
1177bool
1178Platform::CalculateMD5 (const FileSpec& file_spec,
1179                        uint64_t &low,
1180                        uint64_t &high)
1181{
1182    if (IsHost())
1183        return Host::CalculateMD5(file_spec, low, high);
1184    else
1185        return false;
1186}
1187
1188void
1189Platform::SetLocalCacheDirectory (const char* local)
1190{
1191    m_local_cache_directory.assign(local);
1192}
1193
1194const char*
1195Platform::GetLocalCacheDirectory ()
1196{
1197    return m_local_cache_directory.c_str();
1198}
1199
1200static OptionDefinition
1201g_rsync_option_table[] =
1202{
1203    {   LLDB_OPT_SET_ALL, false, "rsync"                  , 'r', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone         , "Enable rsync." },
1204    {   LLDB_OPT_SET_ALL, false, "rsync-opts"             , 'R', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCommandName  , "Platform-specific options required for rsync to work." },
1205    {   LLDB_OPT_SET_ALL, false, "rsync-prefix"           , 'P', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCommandName  , "Platform-specific rsync prefix put before the remote path." },
1206    {   LLDB_OPT_SET_ALL, false, "ignore-remote-hostname" , 'i', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone         , "Do not automatically fill in the remote hostname when composing the rsync command." },
1207};
1208
1209static OptionDefinition
1210g_ssh_option_table[] =
1211{
1212    {   LLDB_OPT_SET_ALL, false, "ssh"                    , 's', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone         , "Enable SSH." },
1213    {   LLDB_OPT_SET_ALL, false, "ssh-opts"               , 'S', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCommandName  , "Platform-specific options required for SSH to work." },
1214};
1215
1216static OptionDefinition
1217g_caching_option_table[] =
1218{
1219    {   LLDB_OPT_SET_ALL, false, "local-cache-dir"        , 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypePath         , "Path in which to store local copies of files." },
1220};
1221
1222OptionGroupPlatformRSync::OptionGroupPlatformRSync ()
1223{
1224}
1225
1226OptionGroupPlatformRSync::~OptionGroupPlatformRSync ()
1227{
1228}
1229
1230const lldb_private::OptionDefinition*
1231OptionGroupPlatformRSync::GetDefinitions ()
1232{
1233    return g_rsync_option_table;
1234}
1235
1236void
1237OptionGroupPlatformRSync::OptionParsingStarting (CommandInterpreter &interpreter)
1238{
1239    m_rsync = false;
1240    m_rsync_opts.clear();
1241    m_rsync_prefix.clear();
1242    m_ignores_remote_hostname = false;
1243}
1244
1245lldb_private::Error
1246OptionGroupPlatformRSync::SetOptionValue (CommandInterpreter &interpreter,
1247                uint32_t option_idx,
1248                const char *option_arg)
1249{
1250    Error error;
1251    char short_option = (char) GetDefinitions()[option_idx].short_option;
1252    switch (short_option)
1253    {
1254        case 'r':
1255            m_rsync = true;
1256            break;
1257
1258        case 'R':
1259            m_rsync_opts.assign(option_arg);
1260            break;
1261
1262        case 'P':
1263            m_rsync_prefix.assign(option_arg);
1264            break;
1265
1266        case 'i':
1267            m_ignores_remote_hostname = true;
1268            break;
1269
1270        default:
1271            error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
1272            break;
1273    }
1274
1275    return error;
1276}
1277
1278uint32_t
1279OptionGroupPlatformRSync::GetNumDefinitions ()
1280{
1281    return llvm::array_lengthof(g_rsync_option_table);
1282}
1283
1284lldb::BreakpointSP
1285Platform::SetThreadCreationBreakpoint (lldb_private::Target &target)
1286{
1287    return lldb::BreakpointSP();
1288}
1289
1290OptionGroupPlatformSSH::OptionGroupPlatformSSH ()
1291{
1292}
1293
1294OptionGroupPlatformSSH::~OptionGroupPlatformSSH ()
1295{
1296}
1297
1298const lldb_private::OptionDefinition*
1299OptionGroupPlatformSSH::GetDefinitions ()
1300{
1301    return g_ssh_option_table;
1302}
1303
1304void
1305OptionGroupPlatformSSH::OptionParsingStarting (CommandInterpreter &interpreter)
1306{
1307    m_ssh = false;
1308    m_ssh_opts.clear();
1309}
1310
1311lldb_private::Error
1312OptionGroupPlatformSSH::SetOptionValue (CommandInterpreter &interpreter,
1313                                          uint32_t option_idx,
1314                                          const char *option_arg)
1315{
1316    Error error;
1317    char short_option = (char) GetDefinitions()[option_idx].short_option;
1318    switch (short_option)
1319    {
1320        case 's':
1321            m_ssh = true;
1322            break;
1323
1324        case 'S':
1325            m_ssh_opts.assign(option_arg);
1326            break;
1327
1328        default:
1329            error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
1330            break;
1331    }
1332
1333    return error;
1334}
1335
1336uint32_t
1337OptionGroupPlatformSSH::GetNumDefinitions ()
1338{
1339    return llvm::array_lengthof(g_ssh_option_table);
1340}
1341
1342OptionGroupPlatformCaching::OptionGroupPlatformCaching ()
1343{
1344}
1345
1346OptionGroupPlatformCaching::~OptionGroupPlatformCaching ()
1347{
1348}
1349
1350const lldb_private::OptionDefinition*
1351OptionGroupPlatformCaching::GetDefinitions ()
1352{
1353    return g_caching_option_table;
1354}
1355
1356void
1357OptionGroupPlatformCaching::OptionParsingStarting (CommandInterpreter &interpreter)
1358{
1359    m_cache_dir.clear();
1360}
1361
1362lldb_private::Error
1363OptionGroupPlatformCaching::SetOptionValue (CommandInterpreter &interpreter,
1364                                        uint32_t option_idx,
1365                                        const char *option_arg)
1366{
1367    Error error;
1368    char short_option = (char) GetDefinitions()[option_idx].short_option;
1369    switch (short_option)
1370    {
1371        case 'c':
1372            m_cache_dir.assign(option_arg);
1373            break;
1374
1375        default:
1376            error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
1377            break;
1378    }
1379
1380    return error;
1381}
1382
1383uint32_t
1384OptionGroupPlatformCaching::GetNumDefinitions ()
1385{
1386    return llvm::array_lengthof(g_caching_option_table);
1387}
1388
1389size_t
1390Platform::GetEnvironment (StringList &environment)
1391{
1392    environment.Clear();
1393    return false;
1394}
1395
1396const std::vector<ConstString> &
1397Platform::GetTrapHandlerSymbolNames ()
1398{
1399    if (!m_calculated_trap_handlers)
1400    {
1401        CalculateTrapHandlerSymbolNames();
1402        m_calculated_trap_handlers = true;
1403    }
1404    return m_trap_handlers;
1405}
1406
1407