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