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 
29 using namespace lldb;
30 using 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
34 static PlatformSP&
35 GetHostPlatformSP ()
36 {
37     static PlatformSP g_platform_sp;
38     return g_platform_sp;
39 }
40 
41 const char *
42 Platform::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 //------------------------------------------------------------------
57 PlatformSP
58 Platform::GetHostPlatform ()
59 {
60     return GetHostPlatformSP ();
61 }
62 
63 static std::vector<PlatformSP> &
64 GetPlatformList()
65 {
66     static std::vector<PlatformSP> g_platform_list;
67     return g_platform_list;
68 }
69 
70 static Mutex &
71 GetPlatformListMutex ()
72 {
73     static Mutex g_mutex(Mutex::eMutexTypeRecursive);
74     return g_mutex;
75 }
76 
77 void
78 Platform::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 
91 Error
92 Platform::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 
101 FileSpecList
102 Platform::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 
138 Error
139 Platform::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 
161 PlatformSP
162 Platform::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 
180 PlatformSP
181 Platform::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 
210 PlatformSP
211 Platform::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 //------------------------------------------------------------------
276 Platform::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 //------------------------------------------------------------------
316 Platform::~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 
323 void
324 Platform::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 
382 bool
383 Platform::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 
437 bool
438 Platform::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 
452 bool
453 Platform::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 
465 ConstString
466 Platform::GetWorkingDirectory ()
467 {
468     if (IsHost())
469     {
470         char cwd[PATH_MAX];
471         if (getcwd(cwd, sizeof(cwd)))
472             return ConstString(cwd);
473         else
474             return ConstString();
475     }
476     else
477     {
478         if (!m_working_dir)
479             m_working_dir = GetRemoteWorkingDirectory();
480         return m_working_dir;
481     }
482 }
483 
484 
485 struct RecurseCopyBaton
486 {
487     const FileSpec& dst;
488     Platform *platform_ptr;
489     Error error;
490 };
491 
492 
493 static FileSpec::EnumerateDirectoryResult
494 RecurseCopy_Callback (void *baton,
495                       FileSpec::FileType file_type,
496                       const FileSpec &src)
497 {
498     RecurseCopyBaton* rc_baton = (RecurseCopyBaton*)baton;
499     switch (file_type)
500     {
501         case FileSpec::eFileTypePipe:
502         case FileSpec::eFileTypeSocket:
503             // we have no way to copy pipes and sockets - ignore them and continue
504             return FileSpec::eEnumerateDirectoryResultNext;
505             break;
506 
507         case FileSpec::eFileTypeDirectory:
508             {
509                 // make the new directory and get in there
510                 FileSpec dst_dir = rc_baton->dst;
511                 if (!dst_dir.GetFilename())
512                     dst_dir.GetFilename() = src.GetLastPathComponent();
513                 std::string dst_dir_path (dst_dir.GetPath());
514                 Error error = rc_baton->platform_ptr->MakeDirectory(dst_dir_path.c_str(), lldb::eFilePermissionsDirectoryDefault);
515                 if (error.Fail())
516                 {
517                     rc_baton->error.SetErrorStringWithFormat("unable to setup directory %s on remote end", dst_dir_path.c_str());
518                     return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
519                 }
520 
521                 // now recurse
522                 std::string src_dir_path (src.GetPath());
523 
524                 // Make a filespec that only fills in the directory of a FileSpec so
525                 // when we enumerate we can quickly fill in the filename for dst copies
526                 FileSpec recurse_dst;
527                 recurse_dst.GetDirectory().SetCString(dst_dir.GetPath().c_str());
528                 RecurseCopyBaton rc_baton2 = { recurse_dst, rc_baton->platform_ptr, Error() };
529                 FileSpec::EnumerateDirectory(src_dir_path.c_str(), true, true, true, RecurseCopy_Callback, &rc_baton2);
530                 if (rc_baton2.error.Fail())
531                 {
532                     rc_baton->error.SetErrorString(rc_baton2.error.AsCString());
533                     return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
534                 }
535                 return FileSpec::eEnumerateDirectoryResultNext;
536             }
537             break;
538 
539         case FileSpec::eFileTypeSymbolicLink:
540             {
541                 // copy the file and keep going
542                 FileSpec dst_file = rc_baton->dst;
543                 if (!dst_file.GetFilename())
544                     dst_file.GetFilename() = src.GetFilename();
545 
546                 char buf[PATH_MAX];
547 
548                 rc_baton->error = FileSystem::Readlink(src.GetPath().c_str(), buf, sizeof(buf));
549 
550                 if (rc_baton->error.Fail())
551                     return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
552 
553                 rc_baton->error = rc_baton->platform_ptr->CreateSymlink(dst_file.GetPath().c_str(), buf);
554 
555                 if (rc_baton->error.Fail())
556                     return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
557 
558                 return FileSpec::eEnumerateDirectoryResultNext;
559             }
560             break;
561         case FileSpec::eFileTypeRegular:
562             {
563                 // copy the file and keep going
564                 FileSpec dst_file = rc_baton->dst;
565                 if (!dst_file.GetFilename())
566                     dst_file.GetFilename() = src.GetFilename();
567                 Error err = rc_baton->platform_ptr->PutFile(src, dst_file);
568                 if (err.Fail())
569                 {
570                     rc_baton->error.SetErrorString(err.AsCString());
571                     return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
572                 }
573                 return FileSpec::eEnumerateDirectoryResultNext;
574             }
575             break;
576 
577         case FileSpec::eFileTypeInvalid:
578         case FileSpec::eFileTypeOther:
579         case FileSpec::eFileTypeUnknown:
580             rc_baton->error.SetErrorStringWithFormat("invalid file detected during copy: %s", src.GetPath().c_str());
581             return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
582             break;
583     }
584     llvm_unreachable("Unhandled FileSpec::FileType!");
585 }
586 
587 Error
588 Platform::Install (const FileSpec& src, const FileSpec& dst)
589 {
590     Error error;
591 
592     Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
593     if (log)
594         log->Printf ("Platform::Install (src='%s', dst='%s')", src.GetPath().c_str(), dst.GetPath().c_str());
595     FileSpec fixed_dst(dst);
596 
597     if (!fixed_dst.GetFilename())
598         fixed_dst.GetFilename() = src.GetFilename();
599 
600     ConstString working_dir = GetWorkingDirectory();
601 
602     if (dst)
603     {
604         if (dst.GetDirectory())
605         {
606             const char first_dst_dir_char = dst.GetDirectory().GetCString()[0];
607             if (first_dst_dir_char == '/' || first_dst_dir_char  == '\\')
608             {
609                 fixed_dst.GetDirectory() = dst.GetDirectory();
610             }
611             // If the fixed destination file doesn't have a directory yet,
612             // then we must have a relative path. We will resolve this relative
613             // path against the platform's working directory
614             if (!fixed_dst.GetDirectory())
615             {
616                 FileSpec relative_spec;
617                 std::string path;
618                 if (working_dir)
619                 {
620                     relative_spec.SetFile(working_dir.GetCString(), false);
621                     relative_spec.AppendPathComponent(dst.GetPath().c_str());
622                     fixed_dst.GetDirectory() = relative_spec.GetDirectory();
623                 }
624                 else
625                 {
626                     error.SetErrorStringWithFormat("platform working directory must be valid for relative path '%s'", dst.GetPath().c_str());
627                     return error;
628                 }
629             }
630         }
631         else
632         {
633             if (working_dir)
634             {
635                 fixed_dst.GetDirectory() = working_dir;
636             }
637             else
638             {
639                 error.SetErrorStringWithFormat("platform working directory must be valid for relative path '%s'", dst.GetPath().c_str());
640                 return error;
641             }
642         }
643     }
644     else
645     {
646         if (working_dir)
647         {
648             fixed_dst.GetDirectory() = working_dir;
649         }
650         else
651         {
652             error.SetErrorStringWithFormat("platform working directory must be valid when destination directory is empty");
653             return error;
654         }
655     }
656 
657     if (log)
658         log->Printf ("Platform::Install (src='%s', dst='%s') fixed_dst='%s'", src.GetPath().c_str(), dst.GetPath().c_str(), fixed_dst.GetPath().c_str());
659 
660     if (GetSupportsRSync())
661     {
662         error = PutFile(src, dst);
663     }
664     else
665     {
666         switch (src.GetFileType())
667         {
668             case FileSpec::eFileTypeDirectory:
669                 {
670                     if (GetFileExists (fixed_dst))
671                         Unlink (fixed_dst.GetPath().c_str());
672                     uint32_t permissions = src.GetPermissions();
673                     if (permissions == 0)
674                         permissions = eFilePermissionsDirectoryDefault;
675                     std::string dst_dir_path(fixed_dst.GetPath());
676                     error = MakeDirectory(dst_dir_path.c_str(), permissions);
677                     if (error.Success())
678                     {
679                         // Make a filespec that only fills in the directory of a FileSpec so
680                         // when we enumerate we can quickly fill in the filename for dst copies
681                         FileSpec recurse_dst;
682                         recurse_dst.GetDirectory().SetCString(dst_dir_path.c_str());
683                         std::string src_dir_path (src.GetPath());
684                         RecurseCopyBaton baton = { recurse_dst, this, Error() };
685                         FileSpec::EnumerateDirectory(src_dir_path.c_str(), true, true, true, RecurseCopy_Callback, &baton);
686                         return baton.error;
687                     }
688                 }
689                 break;
690 
691             case FileSpec::eFileTypeRegular:
692                 if (GetFileExists (fixed_dst))
693                     Unlink (fixed_dst.GetPath().c_str());
694                 error = PutFile(src, fixed_dst);
695                 break;
696 
697             case FileSpec::eFileTypeSymbolicLink:
698                 {
699                     if (GetFileExists (fixed_dst))
700                         Unlink (fixed_dst.GetPath().c_str());
701                     char buf[PATH_MAX];
702                     error = FileSystem::Readlink(src.GetPath().c_str(), buf, sizeof(buf));
703                     if (error.Success())
704                         error = CreateSymlink(dst.GetPath().c_str(), buf);
705                 }
706                 break;
707             case FileSpec::eFileTypePipe:
708                 error.SetErrorString("platform install doesn't handle pipes");
709                 break;
710             case FileSpec::eFileTypeSocket:
711                 error.SetErrorString("platform install doesn't handle sockets");
712                 break;
713             case FileSpec::eFileTypeInvalid:
714             case FileSpec::eFileTypeUnknown:
715             case FileSpec::eFileTypeOther:
716                 error.SetErrorString("platform install doesn't handle non file or directory items");
717                 break;
718         }
719     }
720     return error;
721 }
722 
723 bool
724 Platform::SetWorkingDirectory (const ConstString &path)
725 {
726     if (IsHost())
727     {
728         Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
729         if (log)
730             log->Printf("Platform::SetWorkingDirectory('%s')", path.GetCString());
731 #ifdef _WIN32
732         // Not implemented on Windows
733         return false;
734 #else
735         if (path)
736         {
737             if (chdir(path.GetCString()) == 0)
738                 return true;
739         }
740         return false;
741 #endif
742     }
743     else
744     {
745         m_working_dir.Clear();
746         return SetRemoteWorkingDirectory(path);
747     }
748 }
749 
750 Error
751 Platform::MakeDirectory (const char *path, uint32_t permissions)
752 {
753     if (IsHost())
754         return FileSystem::MakeDirectory(path, permissions);
755     else
756     {
757         Error error;
758         error.SetErrorStringWithFormat("remote platform %s doesn't support %s", GetPluginName().GetCString(), __PRETTY_FUNCTION__);
759         return error;
760     }
761 }
762 
763 Error
764 Platform::GetFilePermissions (const char *path, uint32_t &file_permissions)
765 {
766     if (IsHost())
767         return FileSystem::GetFilePermissions(path, file_permissions);
768     else
769     {
770         Error error;
771         error.SetErrorStringWithFormat("remote platform %s doesn't support %s", GetPluginName().GetCString(), __PRETTY_FUNCTION__);
772         return error;
773     }
774 }
775 
776 Error
777 Platform::SetFilePermissions (const char *path, uint32_t file_permissions)
778 {
779     if (IsHost())
780         return FileSystem::SetFilePermissions(path, file_permissions);
781     else
782     {
783         Error error;
784         error.SetErrorStringWithFormat("remote platform %s doesn't support %s", GetPluginName().GetCString(), __PRETTY_FUNCTION__);
785         return error;
786     }
787 }
788 
789 ConstString
790 Platform::GetName ()
791 {
792     return GetPluginName();
793 }
794 
795 const char *
796 Platform::GetHostname ()
797 {
798     if (IsHost())
799         return "127.0.0.1";
800 
801     if (m_name.empty())
802         return NULL;
803     return m_name.c_str();
804 }
805 
806 bool
807 Platform::SetRemoteWorkingDirectory(const ConstString &path)
808 {
809     Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
810     if (log)
811         log->Printf("Platform::SetRemoteWorkingDirectory('%s')", path.GetCString());
812     m_working_dir = path;
813     return true;
814 }
815 
816 const char *
817 Platform::GetUserName (uint32_t uid)
818 {
819 #if !defined(LLDB_DISABLE_POSIX)
820     const char *user_name = GetCachedUserName(uid);
821     if (user_name)
822         return user_name;
823     if (IsHost())
824     {
825         std::string name;
826         if (HostInfo::LookupUserName(uid, name))
827             return SetCachedUserName (uid, name.c_str(), name.size());
828     }
829 #endif
830     return NULL;
831 }
832 
833 const char *
834 Platform::GetGroupName (uint32_t gid)
835 {
836 #if !defined(LLDB_DISABLE_POSIX)
837     const char *group_name = GetCachedGroupName(gid);
838     if (group_name)
839         return group_name;
840     if (IsHost())
841     {
842         std::string name;
843         if (HostInfo::LookupGroupName(gid, name))
844             return SetCachedGroupName (gid, name.c_str(), name.size());
845     }
846 #endif
847     return NULL;
848 }
849 
850 bool
851 Platform::SetOSVersion (uint32_t major,
852                         uint32_t minor,
853                         uint32_t update)
854 {
855     if (IsHost())
856     {
857         // We don't need anyone setting the OS version for the host platform,
858         // we should be able to figure it out by calling HostInfo::GetOSVersion(...).
859         return false;
860     }
861     else
862     {
863         // We have a remote platform, allow setting the target OS version if
864         // we aren't connected, since if we are connected, we should be able to
865         // request the remote OS version from the connected platform.
866         if (IsConnected())
867             return false;
868         else
869         {
870             // We aren't connected and we might want to set the OS version
871             // ahead of time before we connect so we can peruse files and
872             // use a local SDK or PDK cache of support files to disassemble
873             // or do other things.
874             m_major_os_version = major;
875             m_minor_os_version = minor;
876             m_update_os_version = update;
877             return true;
878         }
879     }
880     return false;
881 }
882 
883 
884 Error
885 Platform::ResolveExecutable (const FileSpec &exe_file,
886                              const ArchSpec &exe_arch,
887                              lldb::ModuleSP &exe_module_sp,
888                              const FileSpecList *module_search_paths_ptr)
889 {
890     Error error;
891     if (exe_file.Exists())
892     {
893         ModuleSpec module_spec (exe_file, exe_arch);
894         if (module_spec.GetArchitecture().IsValid())
895         {
896             error = ModuleList::GetSharedModule (module_spec,
897                                                  exe_module_sp,
898                                                  module_search_paths_ptr,
899                                                  NULL,
900                                                  NULL);
901         }
902         else
903         {
904             // No valid architecture was specified, ask the platform for
905             // the architectures that we should be using (in the correct order)
906             // and see if we can find a match that way
907             for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, module_spec.GetArchitecture()); ++idx)
908             {
909                 error = ModuleList::GetSharedModule (module_spec,
910                                                      exe_module_sp,
911                                                      module_search_paths_ptr,
912                                                      NULL,
913                                                      NULL);
914                 // Did we find an executable using one of the
915                 if (error.Success() && exe_module_sp)
916                     break;
917             }
918         }
919     }
920     else
921     {
922         error.SetErrorStringWithFormat ("'%s' does not exist",
923                                         exe_file.GetPath().c_str());
924     }
925     return error;
926 }
927 
928 Error
929 Platform::ResolveSymbolFile (Target &target,
930                              const ModuleSpec &sym_spec,
931                              FileSpec &sym_file)
932 {
933     Error error;
934     if (sym_spec.GetSymbolFileSpec().Exists())
935         sym_file = sym_spec.GetSymbolFileSpec();
936     else
937         error.SetErrorString("unable to resolve symbol file");
938     return error;
939 
940 }
941 
942 
943 
944 bool
945 Platform::ResolveRemotePath (const FileSpec &platform_path,
946                              FileSpec &resolved_platform_path)
947 {
948     resolved_platform_path = platform_path;
949     return resolved_platform_path.ResolvePath();
950 }
951 
952 
953 const ArchSpec &
954 Platform::GetSystemArchitecture()
955 {
956     if (IsHost())
957     {
958         if (!m_system_arch.IsValid())
959         {
960             // We have a local host platform
961             m_system_arch = HostInfo::GetArchitecture();
962             m_system_arch_set_while_connected = m_system_arch.IsValid();
963         }
964     }
965     else
966     {
967         // We have a remote platform. We can only fetch the remote
968         // system architecture if we are connected, and we don't want to do it
969         // more than once.
970 
971         const bool is_connected = IsConnected();
972 
973         bool fetch = false;
974         if (m_system_arch.IsValid())
975         {
976             // We have valid OS version info, check to make sure it wasn't
977             // manually set prior to connecting. If it was manually set prior
978             // to connecting, then lets fetch the actual OS version info
979             // if we are now connected.
980             if (is_connected && !m_system_arch_set_while_connected)
981                 fetch = true;
982         }
983         else
984         {
985             // We don't have valid OS version info, fetch it if we are connected
986             fetch = is_connected;
987         }
988 
989         if (fetch)
990         {
991             m_system_arch = GetRemoteSystemArchitecture ();
992             m_system_arch_set_while_connected = m_system_arch.IsValid();
993         }
994     }
995     return m_system_arch;
996 }
997 
998 
999 Error
1000 Platform::ConnectRemote (Args& args)
1001 {
1002     Error error;
1003     if (IsHost())
1004         error.SetErrorStringWithFormat ("The currently selected platform (%s) is the host platform and is always connected.", GetPluginName().GetCString());
1005     else
1006         error.SetErrorStringWithFormat ("Platform::ConnectRemote() is not supported by %s", GetPluginName().GetCString());
1007     return error;
1008 }
1009 
1010 Error
1011 Platform::DisconnectRemote ()
1012 {
1013     Error error;
1014     if (IsHost())
1015         error.SetErrorStringWithFormat ("The currently selected platform (%s) is the host platform and is always connected.", GetPluginName().GetCString());
1016     else
1017         error.SetErrorStringWithFormat ("Platform::DisconnectRemote() is not supported by %s", GetPluginName().GetCString());
1018     return error;
1019 }
1020 
1021 bool
1022 Platform::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
1023 {
1024     // Take care of the host case so that each subclass can just
1025     // call this function to get the host functionality.
1026     if (IsHost())
1027         return Host::GetProcessInfo (pid, process_info);
1028     return false;
1029 }
1030 
1031 uint32_t
1032 Platform::FindProcesses (const ProcessInstanceInfoMatch &match_info,
1033                          ProcessInstanceInfoList &process_infos)
1034 {
1035     // Take care of the host case so that each subclass can just
1036     // call this function to get the host functionality.
1037     uint32_t match_count = 0;
1038     if (IsHost())
1039         match_count = Host::FindProcesses (match_info, process_infos);
1040     return match_count;
1041 }
1042 
1043 
1044 Error
1045 Platform::LaunchProcess (ProcessLaunchInfo &launch_info)
1046 {
1047     Error error;
1048     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
1049     if (log)
1050         log->Printf ("Platform::%s()", __FUNCTION__);
1051 
1052     // Take care of the host case so that each subclass can just
1053     // call this function to get the host functionality.
1054     if (IsHost())
1055     {
1056         if (::getenv ("LLDB_LAUNCH_FLAG_LAUNCH_IN_TTY"))
1057             launch_info.GetFlags().Set (eLaunchFlagLaunchInTTY);
1058 
1059         if (launch_info.GetFlags().Test (eLaunchFlagLaunchInShell))
1060         {
1061             const bool is_localhost = true;
1062             const bool will_debug = launch_info.GetFlags().Test(eLaunchFlagDebug);
1063             const bool first_arg_is_full_shell_command = false;
1064             uint32_t num_resumes = GetResumeCountForLaunchInfo (launch_info);
1065             if (log)
1066             {
1067                 const FileSpec &shell = launch_info.GetShell();
1068                 const char *shell_str = (shell) ? shell.GetPath().c_str() : "<null>";
1069                 log->Printf ("Platform::%s GetResumeCountForLaunchInfo() returned %" PRIu32 ", shell is '%s'",
1070                              __FUNCTION__,
1071                              num_resumes,
1072                              shell_str);
1073             }
1074 
1075             if (!launch_info.ConvertArgumentsForLaunchingInShell (error,
1076                                                                   is_localhost,
1077                                                                   will_debug,
1078                                                                   first_arg_is_full_shell_command,
1079                                                                   num_resumes))
1080                 return error;
1081         }
1082 
1083         if (log)
1084             log->Printf ("Platform::%s final launch_info resume count: %" PRIu32, __FUNCTION__, launch_info.GetResumeCount ());
1085 
1086         error = Host::LaunchProcess (launch_info);
1087     }
1088     else
1089         error.SetErrorString ("base lldb_private::Platform class can't launch remote processes");
1090     return error;
1091 }
1092 
1093 lldb::ProcessSP
1094 Platform::DebugProcess (ProcessLaunchInfo &launch_info,
1095                         Debugger &debugger,
1096                         Target *target,       // Can be NULL, if NULL create a new target, else use existing one
1097                         Listener &listener,
1098                         Error &error)
1099 {
1100     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
1101     if (log)
1102         log->Printf ("Platform::%s entered (target %p)", __FUNCTION__, static_cast<void*>(target));
1103 
1104     ProcessSP process_sp;
1105     // Make sure we stop at the entry point
1106     launch_info.GetFlags ().Set (eLaunchFlagDebug);
1107     // We always launch the process we are going to debug in a separate process
1108     // group, since then we can handle ^C interrupts ourselves w/o having to worry
1109     // about the target getting them as well.
1110     launch_info.SetLaunchInSeparateProcessGroup(true);
1111 
1112     error = LaunchProcess (launch_info);
1113     if (error.Success())
1114     {
1115         if (log)
1116             log->Printf ("Platform::%s LaunchProcess() call succeeded (pid=%" PRIu64 ")", __FUNCTION__, launch_info.GetProcessID ());
1117         if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
1118         {
1119             ProcessAttachInfo attach_info (launch_info);
1120             process_sp = Attach (attach_info, debugger, target, listener, error);
1121             if (process_sp)
1122             {
1123                 if (log)
1124                     log->Printf ("Platform::%s Attach() succeeded, Process plugin: %s", __FUNCTION__, process_sp->GetPluginName ().AsCString ());
1125                 launch_info.SetHijackListener(attach_info.GetHijackListener());
1126 
1127                 // Since we attached to the process, it will think it needs to detach
1128                 // if the process object just goes away without an explicit call to
1129                 // Process::Kill() or Process::Detach(), so let it know to kill the
1130                 // process if this happens.
1131                 process_sp->SetShouldDetach (false);
1132 
1133                 // If we didn't have any file actions, the pseudo terminal might
1134                 // have been used where the slave side was given as the file to
1135                 // open for stdin/out/err after we have already opened the master
1136                 // so we can read/write stdin/out/err.
1137                 int pty_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor();
1138                 if (pty_fd != lldb_utility::PseudoTerminal::invalid_fd)
1139                 {
1140                     process_sp->SetSTDIOFileDescriptor(pty_fd);
1141                 }
1142             }
1143             else
1144             {
1145                 if (log)
1146                     log->Printf ("Platform::%s Attach() failed: %s", __FUNCTION__, error.AsCString ());
1147             }
1148         }
1149         else
1150         {
1151             if (log)
1152                 log->Printf ("Platform::%s LaunchProcess() returned launch_info with invalid process id", __FUNCTION__);
1153         }
1154     }
1155     else
1156     {
1157         if (log)
1158             log->Printf ("Platform::%s LaunchProcess() failed: %s", __FUNCTION__, error.AsCString ());
1159     }
1160 
1161     return process_sp;
1162 }
1163 
1164 
1165 lldb::PlatformSP
1166 Platform::GetPlatformForArchitecture (const ArchSpec &arch, ArchSpec *platform_arch_ptr)
1167 {
1168     lldb::PlatformSP platform_sp;
1169     Error error;
1170     if (arch.IsValid())
1171         platform_sp = Platform::Create (arch, platform_arch_ptr, error);
1172     return platform_sp;
1173 }
1174 
1175 
1176 //------------------------------------------------------------------
1177 /// Lets a platform answer if it is compatible with a given
1178 /// architecture and the target triple contained within.
1179 //------------------------------------------------------------------
1180 bool
1181 Platform::IsCompatibleArchitecture (const ArchSpec &arch, bool exact_arch_match, ArchSpec *compatible_arch_ptr)
1182 {
1183     // If the architecture is invalid, we must answer true...
1184     if (arch.IsValid())
1185     {
1186         ArchSpec platform_arch;
1187         // Try for an exact architecture match first.
1188         if (exact_arch_match)
1189         {
1190             for (uint32_t arch_idx=0; GetSupportedArchitectureAtIndex (arch_idx, platform_arch); ++arch_idx)
1191             {
1192                 if (arch.IsExactMatch(platform_arch))
1193                 {
1194                     if (compatible_arch_ptr)
1195                         *compatible_arch_ptr = platform_arch;
1196                     return true;
1197                 }
1198             }
1199         }
1200         else
1201         {
1202             for (uint32_t arch_idx=0; GetSupportedArchitectureAtIndex (arch_idx, platform_arch); ++arch_idx)
1203             {
1204                 if (arch.IsCompatibleMatch(platform_arch))
1205                 {
1206                     if (compatible_arch_ptr)
1207                         *compatible_arch_ptr = platform_arch;
1208                     return true;
1209                 }
1210             }
1211         }
1212     }
1213     if (compatible_arch_ptr)
1214         compatible_arch_ptr->Clear();
1215     return false;
1216 }
1217 
1218 Error
1219 Platform::PutFile (const FileSpec& source,
1220                    const FileSpec& destination,
1221                    uint32_t uid,
1222                    uint32_t gid)
1223 {
1224     Error error("unimplemented");
1225     return error;
1226 }
1227 
1228 Error
1229 Platform::GetFile (const FileSpec& source,
1230                    const FileSpec& destination)
1231 {
1232     Error error("unimplemented");
1233     return error;
1234 }
1235 
1236 Error
1237 Platform::CreateSymlink (const char *src, // The name of the link is in src
1238                          const char *dst)// The symlink points to dst
1239 {
1240     Error error("unimplemented");
1241     return error;
1242 }
1243 
1244 bool
1245 Platform::GetFileExists (const lldb_private::FileSpec& file_spec)
1246 {
1247     return false;
1248 }
1249 
1250 Error
1251 Platform::Unlink (const char *path)
1252 {
1253     Error error("unimplemented");
1254     return error;
1255 }
1256 
1257 
1258 
1259 lldb_private::Error
1260 Platform::RunShellCommand (const char *command,           // Shouldn't be NULL
1261                            const char *working_dir,       // Pass NULL to use the current working directory
1262                            int *status_ptr,               // Pass NULL if you don't want the process exit status
1263                            int *signo_ptr,                // Pass NULL if you don't want the signal that caused the process to exit
1264                            std::string *command_output,   // Pass NULL if you don't want the command output
1265                            uint32_t timeout_sec)          // Timeout in seconds to wait for shell program to finish
1266 {
1267     if (IsHost())
1268         return Host::RunShellCommand (command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
1269     else
1270         return Error("unimplemented");
1271 }
1272 
1273 
1274 bool
1275 Platform::CalculateMD5 (const FileSpec& file_spec,
1276                         uint64_t &low,
1277                         uint64_t &high)
1278 {
1279     if (IsHost())
1280         return FileSystem::CalculateMD5(file_spec, low, high);
1281     else
1282         return false;
1283 }
1284 
1285 Error
1286 Platform::LaunchNativeProcess (
1287     ProcessLaunchInfo &launch_info,
1288     lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
1289     NativeProcessProtocolSP &process_sp)
1290 {
1291     // Platforms should override this implementation if they want to
1292     // support lldb-gdbserver.
1293     return Error("unimplemented");
1294 }
1295 
1296 Error
1297 Platform::AttachNativeProcess (lldb::pid_t pid,
1298                                lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
1299                                NativeProcessProtocolSP &process_sp)
1300 {
1301     // Platforms should override this implementation if they want to
1302     // support lldb-gdbserver.
1303     return Error("unimplemented");
1304 }
1305 
1306 void
1307 Platform::SetLocalCacheDirectory (const char* local)
1308 {
1309     m_local_cache_directory.assign(local);
1310 }
1311 
1312 const char*
1313 Platform::GetLocalCacheDirectory ()
1314 {
1315     return m_local_cache_directory.c_str();
1316 }
1317 
1318 static OptionDefinition
1319 g_rsync_option_table[] =
1320 {
1321     {   LLDB_OPT_SET_ALL, false, "rsync"                  , 'r', OptionParser::eNoArgument,       NULL, NULL, 0, eArgTypeNone         , "Enable rsync." },
1322     {   LLDB_OPT_SET_ALL, false, "rsync-opts"             , 'R', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCommandName  , "Platform-specific options required for rsync to work." },
1323     {   LLDB_OPT_SET_ALL, false, "rsync-prefix"           , 'P', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCommandName  , "Platform-specific rsync prefix put before the remote path." },
1324     {   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." },
1325 };
1326 
1327 static OptionDefinition
1328 g_ssh_option_table[] =
1329 {
1330     {   LLDB_OPT_SET_ALL, false, "ssh"                    , 's', OptionParser::eNoArgument,       NULL, NULL, 0, eArgTypeNone         , "Enable SSH." },
1331     {   LLDB_OPT_SET_ALL, false, "ssh-opts"               , 'S', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCommandName  , "Platform-specific options required for SSH to work." },
1332 };
1333 
1334 static OptionDefinition
1335 g_caching_option_table[] =
1336 {
1337     {   LLDB_OPT_SET_ALL, false, "local-cache-dir"        , 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePath         , "Path in which to store local copies of files." },
1338 };
1339 
1340 OptionGroupPlatformRSync::OptionGroupPlatformRSync ()
1341 {
1342 }
1343 
1344 OptionGroupPlatformRSync::~OptionGroupPlatformRSync ()
1345 {
1346 }
1347 
1348 const lldb_private::OptionDefinition*
1349 OptionGroupPlatformRSync::GetDefinitions ()
1350 {
1351     return g_rsync_option_table;
1352 }
1353 
1354 void
1355 OptionGroupPlatformRSync::OptionParsingStarting (CommandInterpreter &interpreter)
1356 {
1357     m_rsync = false;
1358     m_rsync_opts.clear();
1359     m_rsync_prefix.clear();
1360     m_ignores_remote_hostname = false;
1361 }
1362 
1363 lldb_private::Error
1364 OptionGroupPlatformRSync::SetOptionValue (CommandInterpreter &interpreter,
1365                 uint32_t option_idx,
1366                 const char *option_arg)
1367 {
1368     Error error;
1369     char short_option = (char) GetDefinitions()[option_idx].short_option;
1370     switch (short_option)
1371     {
1372         case 'r':
1373             m_rsync = true;
1374             break;
1375 
1376         case 'R':
1377             m_rsync_opts.assign(option_arg);
1378             break;
1379 
1380         case 'P':
1381             m_rsync_prefix.assign(option_arg);
1382             break;
1383 
1384         case 'i':
1385             m_ignores_remote_hostname = true;
1386             break;
1387 
1388         default:
1389             error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
1390             break;
1391     }
1392 
1393     return error;
1394 }
1395 
1396 uint32_t
1397 OptionGroupPlatformRSync::GetNumDefinitions ()
1398 {
1399     return llvm::array_lengthof(g_rsync_option_table);
1400 }
1401 
1402 lldb::BreakpointSP
1403 Platform::SetThreadCreationBreakpoint (lldb_private::Target &target)
1404 {
1405     return lldb::BreakpointSP();
1406 }
1407 
1408 OptionGroupPlatformSSH::OptionGroupPlatformSSH ()
1409 {
1410 }
1411 
1412 OptionGroupPlatformSSH::~OptionGroupPlatformSSH ()
1413 {
1414 }
1415 
1416 const lldb_private::OptionDefinition*
1417 OptionGroupPlatformSSH::GetDefinitions ()
1418 {
1419     return g_ssh_option_table;
1420 }
1421 
1422 void
1423 OptionGroupPlatformSSH::OptionParsingStarting (CommandInterpreter &interpreter)
1424 {
1425     m_ssh = false;
1426     m_ssh_opts.clear();
1427 }
1428 
1429 lldb_private::Error
1430 OptionGroupPlatformSSH::SetOptionValue (CommandInterpreter &interpreter,
1431                                           uint32_t option_idx,
1432                                           const char *option_arg)
1433 {
1434     Error error;
1435     char short_option = (char) GetDefinitions()[option_idx].short_option;
1436     switch (short_option)
1437     {
1438         case 's':
1439             m_ssh = true;
1440             break;
1441 
1442         case 'S':
1443             m_ssh_opts.assign(option_arg);
1444             break;
1445 
1446         default:
1447             error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
1448             break;
1449     }
1450 
1451     return error;
1452 }
1453 
1454 uint32_t
1455 OptionGroupPlatformSSH::GetNumDefinitions ()
1456 {
1457     return llvm::array_lengthof(g_ssh_option_table);
1458 }
1459 
1460 OptionGroupPlatformCaching::OptionGroupPlatformCaching ()
1461 {
1462 }
1463 
1464 OptionGroupPlatformCaching::~OptionGroupPlatformCaching ()
1465 {
1466 }
1467 
1468 const lldb_private::OptionDefinition*
1469 OptionGroupPlatformCaching::GetDefinitions ()
1470 {
1471     return g_caching_option_table;
1472 }
1473 
1474 void
1475 OptionGroupPlatformCaching::OptionParsingStarting (CommandInterpreter &interpreter)
1476 {
1477     m_cache_dir.clear();
1478 }
1479 
1480 lldb_private::Error
1481 OptionGroupPlatformCaching::SetOptionValue (CommandInterpreter &interpreter,
1482                                         uint32_t option_idx,
1483                                         const char *option_arg)
1484 {
1485     Error error;
1486     char short_option = (char) GetDefinitions()[option_idx].short_option;
1487     switch (short_option)
1488     {
1489         case 'c':
1490             m_cache_dir.assign(option_arg);
1491             break;
1492 
1493         default:
1494             error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
1495             break;
1496     }
1497 
1498     return error;
1499 }
1500 
1501 uint32_t
1502 OptionGroupPlatformCaching::GetNumDefinitions ()
1503 {
1504     return llvm::array_lengthof(g_caching_option_table);
1505 }
1506 
1507 size_t
1508 Platform::GetEnvironment (StringList &environment)
1509 {
1510     environment.Clear();
1511     return false;
1512 }
1513 
1514 const std::vector<ConstString> &
1515 Platform::GetTrapHandlerSymbolNames ()
1516 {
1517     if (!m_calculated_trap_handlers)
1518     {
1519         Mutex::Locker locker (m_trap_handler_mutex);
1520         if (!m_calculated_trap_handlers)
1521         {
1522             CalculateTrapHandlerSymbolNames();
1523             m_calculated_trap_handlers = true;
1524         }
1525     }
1526     return m_trap_handlers;
1527 }
1528 
1529