• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- Platform.h ----------------------------------------------*- 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 #ifndef liblldb_Platform_h_
11 #define liblldb_Platform_h_
12 
13 // C Includes
14 // C++ Includes
15 #include <map>
16 #include <string>
17 #include <vector>
18 
19 // Other libraries and framework includes
20 // Project includes
21 #include "lldb/lldb-public.h"
22 #include "lldb/Core/ArchSpec.h"
23 #include "lldb/Core/ConstString.h"
24 #include "lldb/Core/PluginInterface.h"
25 #include "lldb/Host/Mutex.h"
26 
27 namespace lldb_private {
28 
29     //----------------------------------------------------------------------
30     /// @class Platform Platform.h "lldb/Target/Platform.h"
31     /// @brief A plug-in interface definition class for debug platform that
32     /// includes many platform abilities such as:
33     ///     @li getting platform information such as supported architectures,
34     ///         supported binary file formats and more
35     ///     @li launching new processes
36     ///     @li attaching to existing processes
37     ///     @li download/upload files
38     ///     @li execute shell commands
39     ///     @li listing and getting info for existing processes
40     ///     @li attaching and possibly debugging the platform's kernel
41     //----------------------------------------------------------------------
42     class Platform : public PluginInterface
43     {
44     public:
45 
46         //------------------------------------------------------------------
47         /// Get the native host platform plug-in.
48         ///
49         /// There should only be one of these for each host that LLDB runs
50         /// upon that should be statically compiled in and registered using
51         /// preprocessor macros or other similar build mechanisms in a
52         /// PlatformSubclass::Initialize() function.
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         static lldb::PlatformSP
58         GetDefaultPlatform ();
59 
60         static lldb::PlatformSP
61         GetPlatformForArchitecture (const ArchSpec &arch,
62                                     ArchSpec *platform_arch_ptr);
63 
64         static const char *
65         GetHostPlatformName ();
66 
67         static void
68         SetDefaultPlatform (const lldb::PlatformSP &platform_sp);
69 
70         static lldb::PlatformSP
71         Create (const char *platform_name, Error &error);
72 
73         static lldb::PlatformSP
74         Create (const ArchSpec &arch, ArchSpec *platform_arch_ptr, Error &error);
75 
76         static uint32_t
77         GetNumConnectedRemotePlatforms ();
78 
79         static lldb::PlatformSP
80         GetConnectedRemotePlatformAtIndex (uint32_t idx);
81 
82         //------------------------------------------------------------------
83         /// Default Constructor
84         //------------------------------------------------------------------
85         Platform (bool is_host_platform);
86 
87         //------------------------------------------------------------------
88         /// Destructor.
89         ///
90         /// The destructor is virtual since this class is designed to be
91         /// inherited from by the plug-in instance.
92         //------------------------------------------------------------------
93         virtual
94         ~Platform();
95 
96         //------------------------------------------------------------------
97         /// Find a platform plugin for a given process.
98         ///
99         /// Scans the installed Platform plug-ins and tries to find
100         /// an instance that can be used for \a process
101         ///
102         /// @param[in] process
103         ///     The process for which to try and locate a platform
104         ///     plug-in instance.
105         ///
106         /// @param[in] plugin_name
107         ///     An optional name of a specific platform plug-in that
108         ///     should be used. If NULL, pick the best plug-in.
109         //------------------------------------------------------------------
110         static Platform*
111         FindPlugin (Process *process, const ConstString &plugin_name);
112 
113         //------------------------------------------------------------------
114         /// Set the target's executable based off of the existing
115         /// architecture information in \a target given a path to an
116         /// executable \a exe_file.
117         ///
118         /// Each platform knows the architectures that it supports and can
119         /// select the correct architecture slice within \a exe_file by
120         /// inspecting the architecture in \a target. If the target had an
121         /// architecture specified, then in can try and obey that request
122         /// and optionally fail if the architecture doesn't match up.
123         /// If no architecture is specified, the platform should select the
124         /// default architecture from \a exe_file. Any application bundles
125         /// or executable wrappers can also be inspected for the actual
126         /// application binary within the bundle that should be used.
127         ///
128         /// @return
129         ///     Returns \b true if this Platform plug-in was able to find
130         ///     a suitable executable, \b false otherwise.
131         //------------------------------------------------------------------
132         virtual Error
133         ResolveExecutable (const FileSpec &exe_file,
134                            const ArchSpec &arch,
135                            lldb::ModuleSP &module_sp,
136                            const FileSpecList *module_search_paths_ptr);
137 
138 
139         //------------------------------------------------------------------
140         /// Find a symbol file given a symbol file module specification.
141         ///
142         /// Each platform might have tricks to find symbol files for an
143         /// executable given information in a symbol file ModuleSpec. Some
144         /// platforms might also support symbol files that are bundles and
145         /// know how to extract the right symbol file given a bundle.
146         ///
147         /// @param[in] target
148         ///     The target in which we are trying to resolve the symbol file.
149         ///     The target has a list of modules that we might be able to
150         ///     use in order to help find the right symbol file. If the
151         ///     "m_file" or "m_platform_file" entries in the \a sym_spec
152         ///     are filled in, then we might be able to locate a module in
153         ///     the target, extract its UUID and locate a symbol file.
154         ///     If just the "m_uuid" is specified, then we might be able
155         ///     to find the module in the target that matches that UUID
156         ///     and pair the symbol file along with it. If just "m_symbol_file"
157         ///     is specified, we can use a variety of tricks to locate the
158         ///     symbols in an SDK, PDK, or other development kit location.
159         ///
160         /// @param[in] sym_spec
161         ///     A module spec that describes some information about the
162         ///     symbol file we are trying to resolve. The ModuleSpec might
163         ///     contain the following:
164         ///     m_file - A full or partial path to an executable from the
165         ///              target (might be empty).
166         ///     m_platform_file - Another executable hint that contains
167         ///                       the path to the file as known on the
168         ///                       local/remote platform.
169         ///     m_symbol_file - A full or partial path to a symbol file
170         ///                     or symbol bundle that should be used when
171         ///                     trying to resolve the symbol file.
172         ///     m_arch - The architecture we are looking for when resolving
173         ///              the symbol file.
174         ///     m_uuid - The UUID of the executable and symbol file. This
175         ///              can often be used to match up an exectuable with
176         ///              a symbol file, or resolve an symbol file in a
177         ///              symbol file bundle.
178         ///
179         /// @param[out] sym_file
180         ///     The resolved symbol file spec if the returned error
181         ///     indicates succes.
182         ///
183         /// @return
184         ///     Returns an error that describes success or failure.
185         //------------------------------------------------------------------
186         virtual Error
187         ResolveSymbolFile (Target &target,
188                            const ModuleSpec &sym_spec,
189                            FileSpec &sym_file);
190 
191         //------------------------------------------------------------------
192         /// Resolves the FileSpec to a (possibly) remote path. Remote
193         /// platforms must override this to resolve to a path on the remote
194         /// side.
195         //------------------------------------------------------------------
196         virtual bool
197         ResolveRemotePath (const FileSpec &platform_path,
198                            FileSpec &resolved_platform_path);
199 
200         bool
201         GetOSVersion (uint32_t &major,
202                       uint32_t &minor,
203                       uint32_t &update);
204 
205         bool
206         SetOSVersion (uint32_t major,
207                       uint32_t minor,
208                       uint32_t update);
209 
210         bool
211         GetOSBuildString (std::string &s);
212 
213         bool
214         GetOSKernelDescription (std::string &s);
215 
216         // Returns the the hostname if we are connected, else the short plugin
217         // name.
218         ConstString
219         GetName ();
220 
221         virtual const char *
222         GetHostname ();
223 
224         virtual const char *
225         GetDescription () = 0;
226 
227         //------------------------------------------------------------------
228         /// Report the current status for this platform.
229         ///
230         /// The returned string usually involves returning the OS version
231         /// (if available), and any SDK directory that might be being used
232         /// for local file caching, and if connected a quick blurb about
233         /// what this platform is connected to.
234         //------------------------------------------------------------------
235         virtual void
236         GetStatus (Stream &strm);
237 
238         //------------------------------------------------------------------
239         // Subclasses must be able to fetch the current OS version
240         //
241         // Remote classes must be connected for this to succeed. Local
242         // subclasses don't need to override this function as it will just
243         // call the Host::GetOSVersion().
244         //------------------------------------------------------------------
245         virtual bool
GetRemoteOSVersion()246         GetRemoteOSVersion ()
247         {
248             return false;
249         }
250 
251         virtual bool
GetRemoteOSBuildString(std::string & s)252         GetRemoteOSBuildString (std::string &s)
253         {
254             s.clear();
255             return false;
256         }
257 
258         virtual bool
GetRemoteOSKernelDescription(std::string & s)259         GetRemoteOSKernelDescription (std::string &s)
260         {
261             s.clear();
262             return false;
263         }
264 
265         // Remote Platform subclasses need to override this function
266         virtual ArchSpec
GetRemoteSystemArchitecture()267         GetRemoteSystemArchitecture ()
268         {
269             return ArchSpec(); // Return an invalid architecture
270         }
271 
272         virtual const char *
273         GetUserName (uint32_t uid);
274 
275         virtual const char *
276         GetGroupName (uint32_t gid);
277 
278         //------------------------------------------------------------------
279         /// Locate a file for a platform.
280         ///
281         /// The default implementation of this function will return the same
282         /// file patch in \a local_file as was in \a platform_file.
283         ///
284         /// @param[in] platform_file
285         ///     The platform file path to locate and cache locally.
286         ///
287         /// @param[in] uuid_ptr
288         ///     If we know the exact UUID of the file we are looking for, it
289         ///     can be specified. If it is not specified, we might now know
290         ///     the exact file. The UUID is usually some sort of MD5 checksum
291         ///     for the file and is sometimes known by dynamic linkers/loaders.
292         ///     If the UUID is known, it is best to supply it to platform
293         ///     file queries to ensure we are finding the correct file, not
294         ///     just a file at the correct path.
295         ///
296         /// @param[out] local_file
297         ///     A locally cached version of the platform file. For platforms
298         ///     that describe the current host computer, this will just be
299         ///     the same file. For remote platforms, this file might come from
300         ///     and SDK directory, or might need to be sync'ed over to the
301         ///     current machine for efficient debugging access.
302         ///
303         /// @return
304         ///     An error object.
305         //------------------------------------------------------------------
306         virtual Error
307         GetFile (const FileSpec &platform_file,
308                  const UUID *uuid_ptr,
309                  FileSpec &local_file);
310 
311         //----------------------------------------------------------------------
312         // Locate the scripting resource given a module specification.
313         //
314         // Locating the file should happen only on the local computer or using
315         // the current computers global settings.
316         //----------------------------------------------------------------------
317         virtual FileSpecList
318         LocateExecutableScriptingResources (Target *target,
319                                             Module &module);
320 
321         virtual Error
322         GetSharedModule (const ModuleSpec &module_spec,
323                          lldb::ModuleSP &module_sp,
324                          const FileSpecList *module_search_paths_ptr,
325                          lldb::ModuleSP *old_module_sp_ptr,
326                          bool *did_create_ptr);
327 
328         virtual Error
329         ConnectRemote (Args& args);
330 
331         virtual Error
332         DisconnectRemote ();
333 
334         //------------------------------------------------------------------
335         /// Get the platform's supported architectures in the order in which
336         /// they should be searched.
337         ///
338         /// @param[in] idx
339         ///     A zero based architecture index
340         ///
341         /// @param[out] arch
342         ///     A copy of the archgitecture at index if the return value is
343         ///     \b true.
344         ///
345         /// @return
346         ///     \b true if \a arch was filled in and is valid, \b false
347         ///     otherwise.
348         //------------------------------------------------------------------
349         virtual bool
350         GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) = 0;
351 
352         virtual size_t
353         GetSoftwareBreakpointTrapOpcode (Target &target,
354                                          BreakpointSite *bp_site) = 0;
355 
356         //------------------------------------------------------------------
357         /// Launch a new process on a platform, not necessarily for
358         /// debugging, it could be just for running the process.
359         //------------------------------------------------------------------
360         virtual Error
361         LaunchProcess (ProcessLaunchInfo &launch_info);
362 
363         //------------------------------------------------------------------
364         /// Lets a platform answer if it is compatible with a given
365         /// architecture and the target triple contained within.
366         //------------------------------------------------------------------
367         virtual bool
368         IsCompatibleArchitecture (const ArchSpec &arch,
369                                   bool exact_arch_match,
370                                   ArchSpec *compatible_arch_ptr);
371 
372         //------------------------------------------------------------------
373         /// Not all platforms will support debugging a process by spawning
374         /// somehow halted for a debugger (specified using the
375         /// "eLaunchFlagDebug" launch flag) and then attaching. If your
376         /// platform doesn't support this, override this function and return
377         /// false.
378         //------------------------------------------------------------------
379         virtual bool
CanDebugProcess()380         CanDebugProcess ()
381         {
382             return true;
383         }
384 
385         //------------------------------------------------------------------
386         /// Subclasses should NOT need to implement this function as it uses
387         /// the Platform::LaunchProcess() followed by Platform::Attach ()
388         //------------------------------------------------------------------
389         lldb::ProcessSP
390         DebugProcess (ProcessLaunchInfo &launch_info,
391                       Debugger &debugger,
392                       Target *target,       // Can be NULL, if NULL create a new target, else use existing one
393                       Listener &listener,
394                       Error &error);
395 
396         //------------------------------------------------------------------
397         /// Attach to an existing process using a process ID.
398         ///
399         /// Each platform subclass needs to implement this function and
400         /// attempt to attach to the process with the process ID of \a pid.
401         /// The platform subclass should return an appropriate ProcessSP
402         /// subclass that is attached to the process, or an empty shared
403         /// pointer with an appriopriate error.
404         ///
405         /// @param[in] pid
406         ///     The process ID that we should attempt to attach to.
407         ///
408         /// @return
409         ///     An appropriate ProcessSP containing a valid shared pointer
410         ///     to the default Process subclass for the platform that is
411         ///     attached to the process, or an empty shared pointer with an
412         ///     appriopriate error fill into the \a error object.
413         //------------------------------------------------------------------
414         virtual lldb::ProcessSP
415         Attach (ProcessAttachInfo &attach_info,
416                 Debugger &debugger,
417                 Target *target,       // Can be NULL, if NULL create a new target, else use existing one
418                 Listener &listener,
419                 Error &error) = 0;
420 
421         //------------------------------------------------------------------
422         /// Attach to an existing process by process name.
423         ///
424         /// This function is not meant to be overridden by Process
425         /// subclasses. It will first call
426         /// Process::WillAttach (const char *) and if that returns \b
427         /// true, Process::DoAttach (const char *) will be called to
428         /// actually do the attach. If DoAttach returns \b true, then
429         /// Process::DidAttach() will be called.
430         ///
431         /// @param[in] process_name
432         ///     A process name to match against the current process list.
433         ///
434         /// @return
435         ///     Returns \a pid if attaching was successful, or
436         ///     LLDB_INVALID_PROCESS_ID if attaching fails.
437         //------------------------------------------------------------------
438 //        virtual lldb::ProcessSP
439 //        Attach (const char *process_name,
440 //                bool wait_for_launch,
441 //                Error &error) = 0;
442 
443         //------------------------------------------------------------------
444         // The base class Platform will take care of the host platform.
445         // Subclasses will need to fill in the remote case.
446         //------------------------------------------------------------------
447         virtual uint32_t
448         FindProcesses (const ProcessInstanceInfoMatch &match_info,
449                        ProcessInstanceInfoList &proc_infos);
450 
451         virtual bool
452         GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &proc_info);
453 
454         //------------------------------------------------------------------
455         // Set a breakpoint on all functions that can end up creating a thread
456         // for this platform. This is needed when running expressions and
457         // also for process control.
458         //------------------------------------------------------------------
459         virtual lldb::BreakpointSP
460         SetThreadCreationBreakpoint (Target &target);
461 
462 
463         const std::string &
GetRemoteURL()464         GetRemoteURL () const
465         {
466             return m_remote_url;
467         }
468 
469         bool
IsHost()470         IsHost () const
471         {
472             return m_is_host;    // Is this the default host platform?
473         }
474 
475         bool
IsRemote()476         IsRemote () const
477         {
478             return !m_is_host;
479         }
480 
481         virtual bool
IsConnected()482         IsConnected () const
483         {
484             // Remote subclasses should override this function
485             return IsHost();
486         }
487 
488         const ArchSpec &
489         GetSystemArchitecture();
490 
491         void
SetSystemArchitecture(const ArchSpec & arch)492         SetSystemArchitecture (const ArchSpec &arch)
493         {
494             m_system_arch = arch;
495             if (IsHost())
496                 m_os_version_set_while_connected = m_system_arch.IsValid();
497         }
498 
499         // Used for column widths
500         size_t
GetMaxUserIDNameLength()501         GetMaxUserIDNameLength() const
502         {
503             return m_max_uid_name_len;
504         }
505         // Used for column widths
506         size_t
GetMaxGroupIDNameLength()507         GetMaxGroupIDNameLength() const
508         {
509             return m_max_gid_name_len;
510         }
511 
512         const ConstString &
GetSDKRootDirectory()513         GetSDKRootDirectory () const
514         {
515             return m_sdk_sysroot;
516         }
517 
518         void
SetSDKRootDirectory(const ConstString & dir)519         SetSDKRootDirectory (const ConstString &dir)
520         {
521             m_sdk_sysroot = dir;
522         }
523 
524         const ConstString &
GetSDKBuild()525         GetSDKBuild () const
526         {
527             return m_sdk_build;
528         }
529 
530         void
SetSDKBuild(const ConstString & sdk_build)531         SetSDKBuild (const ConstString &sdk_build)
532         {
533             m_sdk_build = sdk_build;
534         }
535 
536         // There may be modules that we don't want to find by default for operations like "setting breakpoint by name".
537         // The platform will return "true" from this call if the passed in module happens to be one of these.
538 
539         virtual bool
ModuleIsExcludedForNonModuleSpecificSearches(Target & target,const lldb::ModuleSP & module_sp)540         ModuleIsExcludedForNonModuleSpecificSearches (Target &target, const lldb::ModuleSP &module_sp)
541         {
542             return false;
543         }
544 
545         virtual size_t
546         GetEnvironment (StringList &environment);
547 
548     protected:
549         bool m_is_host;
550         // Set to true when we are able to actually set the OS version while
551         // being connected. For remote platforms, we might set the version ahead
552         // of time before we actually connect and this version might change when
553         // we actually connect to a remote platform. For the host platform this
554         // will be set to the once we call Host::GetOSVersion().
555         bool m_os_version_set_while_connected;
556         bool m_system_arch_set_while_connected;
557         ConstString m_sdk_sysroot; // the root location of where the SDK files are all located
558         ConstString m_sdk_build;
559         std::string m_remote_url;
560         std::string m_name;
561         uint32_t m_major_os_version;
562         uint32_t m_minor_os_version;
563         uint32_t m_update_os_version;
564         ArchSpec m_system_arch; // The architecture of the kernel or the remote platform
565         typedef std::map<uint32_t, ConstString> IDToNameMap;
566         Mutex m_uid_map_mutex;
567         Mutex m_gid_map_mutex;
568         IDToNameMap m_uid_map;
569         IDToNameMap m_gid_map;
570         size_t m_max_uid_name_len;
571         size_t m_max_gid_name_len;
572 
573         const char *
GetCachedUserName(uint32_t uid)574         GetCachedUserName (uint32_t uid)
575         {
576             Mutex::Locker locker (m_uid_map_mutex);
577             IDToNameMap::iterator pos = m_uid_map.find (uid);
578             if (pos != m_uid_map.end())
579             {
580                 // return the empty string if our string is NULL
581                 // so we can tell when things were in the negative
582                 // cached (didn't find a valid user name, don't keep
583                 // trying)
584                 return pos->second.AsCString("");
585             }
586             return NULL;
587         }
588 
589         const char *
SetCachedUserName(uint32_t uid,const char * name,size_t name_len)590         SetCachedUserName (uint32_t uid, const char *name, size_t name_len)
591         {
592             Mutex::Locker locker (m_uid_map_mutex);
593             ConstString const_name (name);
594             m_uid_map[uid] = const_name;
595             if (m_max_uid_name_len < name_len)
596                 m_max_uid_name_len = name_len;
597             // Const strings lives forever in our const string pool, so we can return the const char *
598             return const_name.GetCString();
599         }
600 
601         void
SetUserNameNotFound(uint32_t uid)602         SetUserNameNotFound (uint32_t uid)
603         {
604             Mutex::Locker locker (m_uid_map_mutex);
605             m_uid_map[uid] = ConstString();
606         }
607 
608 
609         void
ClearCachedUserNames()610         ClearCachedUserNames ()
611         {
612             Mutex::Locker locker (m_uid_map_mutex);
613             m_uid_map.clear();
614         }
615 
616         const char *
GetCachedGroupName(uint32_t gid)617         GetCachedGroupName (uint32_t gid)
618         {
619             Mutex::Locker locker (m_gid_map_mutex);
620             IDToNameMap::iterator pos = m_gid_map.find (gid);
621             if (pos != m_gid_map.end())
622             {
623                 // return the empty string if our string is NULL
624                 // so we can tell when things were in the negative
625                 // cached (didn't find a valid group name, don't keep
626                 // trying)
627                 return pos->second.AsCString("");
628             }
629             return NULL;
630         }
631 
632         const char *
SetCachedGroupName(uint32_t gid,const char * name,size_t name_len)633         SetCachedGroupName (uint32_t gid, const char *name, size_t name_len)
634         {
635             Mutex::Locker locker (m_gid_map_mutex);
636             ConstString const_name (name);
637             m_gid_map[gid] = const_name;
638             if (m_max_gid_name_len < name_len)
639                 m_max_gid_name_len = name_len;
640             // Const strings lives forever in our const string pool, so we can return the const char *
641             return const_name.GetCString();
642         }
643 
644         void
SetGroupNameNotFound(uint32_t gid)645         SetGroupNameNotFound (uint32_t gid)
646         {
647             Mutex::Locker locker (m_gid_map_mutex);
648             m_gid_map[gid] = ConstString();
649         }
650 
651         void
ClearCachedGroupNames()652         ClearCachedGroupNames ()
653         {
654             Mutex::Locker locker (m_gid_map_mutex);
655             m_gid_map.clear();
656         }
657 
658     private:
659         DISALLOW_COPY_AND_ASSIGN (Platform);
660     };
661 
662 
663     class PlatformList
664     {
665     public:
PlatformList()666         PlatformList() :
667             m_mutex (Mutex::eMutexTypeRecursive),
668             m_platforms (),
669             m_selected_platform_sp()
670         {
671         }
672 
~PlatformList()673         ~PlatformList()
674         {
675         }
676 
677         void
Append(const lldb::PlatformSP & platform_sp,bool set_selected)678         Append (const lldb::PlatformSP &platform_sp, bool set_selected)
679         {
680             Mutex::Locker locker (m_mutex);
681             m_platforms.push_back (platform_sp);
682             if (set_selected)
683                 m_selected_platform_sp = m_platforms.back();
684         }
685 
686         size_t
GetSize()687         GetSize()
688         {
689             Mutex::Locker locker (m_mutex);
690             return m_platforms.size();
691         }
692 
693         lldb::PlatformSP
GetAtIndex(uint32_t idx)694         GetAtIndex (uint32_t idx)
695         {
696             lldb::PlatformSP platform_sp;
697             {
698                 Mutex::Locker locker (m_mutex);
699                 if (idx < m_platforms.size())
700                     platform_sp = m_platforms[idx];
701             }
702             return platform_sp;
703         }
704 
705         //------------------------------------------------------------------
706         /// Select the active platform.
707         ///
708         /// In order to debug remotely, other platform's can be remotely
709         /// connected to and set as the selected platform for any subsequent
710         /// debugging. This allows connection to remote targets and allows
711         /// the ability to discover process info, launch and attach to remote
712         /// processes.
713         //------------------------------------------------------------------
714         lldb::PlatformSP
GetSelectedPlatform()715         GetSelectedPlatform ()
716         {
717             Mutex::Locker locker (m_mutex);
718             if (!m_selected_platform_sp && !m_platforms.empty())
719                 m_selected_platform_sp = m_platforms.front();
720 
721             return m_selected_platform_sp;
722         }
723 
724         void
SetSelectedPlatform(const lldb::PlatformSP & platform_sp)725         SetSelectedPlatform (const lldb::PlatformSP &platform_sp)
726         {
727             if (platform_sp)
728             {
729                 Mutex::Locker locker (m_mutex);
730                 const size_t num_platforms = m_platforms.size();
731                 for (size_t idx=0; idx<num_platforms; ++idx)
732                 {
733                     if (m_platforms[idx].get() == platform_sp.get())
734                     {
735                         m_selected_platform_sp = m_platforms[idx];
736                         return;
737                     }
738                 }
739                 m_platforms.push_back (platform_sp);
740                 m_selected_platform_sp = m_platforms.back();
741             }
742         }
743 
744     protected:
745         typedef std::vector<lldb::PlatformSP> collection;
746         mutable Mutex m_mutex;
747         collection m_platforms;
748         lldb::PlatformSP m_selected_platform_sp;
749 
750     private:
751         DISALLOW_COPY_AND_ASSIGN (PlatformList);
752     };
753 } // namespace lldb_private
754 
755 #endif  // liblldb_Platform_h_
756