Platform.cpp revision cb8977d726be451df9978a74088435667fa37da2
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/Core/Error.h"
17#include "lldb/Core/PluginManager.h"
18#include "lldb/Host/FileSpec.h"
19#include "lldb/Host/Host.h"
20#include "lldb/Target/Target.h"
21
22using namespace lldb;
23using namespace lldb_private;
24
25// Use a singleton function for g_local_platform_sp to avoid init
26// constructors since LLDB is often part of a shared library
27static PlatformSP&
28GetDefaultPlatformSP ()
29{
30    static PlatformSP g_default_platform_sp;
31    return g_default_platform_sp;
32}
33
34static Mutex &
35GetConnectedPlatformListMutex ()
36{
37    static Mutex g_remote_connected_platforms_mutex (Mutex::eMutexTypeRecursive);
38    return g_remote_connected_platforms_mutex;
39}
40static std::vector<PlatformSP> &
41GetConnectedPlatformList ()
42{
43    static std::vector<PlatformSP> g_remote_connected_platforms;
44    return g_remote_connected_platforms;
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::GetDefaultPlatform ()
59{
60    return GetDefaultPlatformSP ();
61}
62
63void
64Platform::SetDefaultPlatform (const lldb::PlatformSP &platform_sp)
65{
66    // The native platform should use its static void Platform::Initialize()
67    // function to register itself as the native platform.
68    GetDefaultPlatformSP () = platform_sp;
69}
70
71Error
72Platform::GetFile (const FileSpec &platform_file,
73                   const UUID *uuid_ptr,
74                   FileSpec &local_file)
75{
76    // Default to the local case
77    local_file = platform_file;
78    return Error();
79}
80
81
82PlatformSP
83Platform::Create (const char *platform_name, Error &error)
84{
85    PlatformCreateInstance create_callback = NULL;
86    lldb::PlatformSP platform_sp;
87    if (platform_name && platform_name[0])
88    {
89        create_callback = PluginManager::GetPlatformCreateCallbackForPluginName (platform_name);
90        if (create_callback)
91            platform_sp.reset(create_callback());
92        else
93            error.SetErrorStringWithFormat ("unable to find a plug-in for the platform named \"%s\"", platform_name);
94    }
95    else
96        error.SetErrorString ("invalid platform name");
97    return platform_sp;
98}
99
100uint32_t
101Platform::GetNumConnectedRemotePlatforms ()
102{
103    Mutex::Locker locker (GetConnectedPlatformListMutex ());
104    return GetConnectedPlatformList().size();
105}
106
107PlatformSP
108Platform::GetConnectedRemotePlatformAtIndex (uint32_t idx)
109{
110    PlatformSP platform_sp;
111    {
112        Mutex::Locker locker (GetConnectedPlatformListMutex ());
113        if (idx < GetConnectedPlatformList().size())
114            platform_sp = GetConnectedPlatformList ()[idx];
115    }
116    return platform_sp;
117}
118
119//------------------------------------------------------------------
120/// Default Constructor
121//------------------------------------------------------------------
122Platform::Platform (bool is_host) :
123    m_is_host (is_host),
124    m_is_connected (is_host), // If this is the default host platform, then we are always connected
125    m_os_version_set_while_connected (false),
126    m_system_arch_set_while_connected (false),
127    m_remote_url (),
128    m_remote_instance_name (),
129    m_major_os_version (UINT32_MAX),
130    m_minor_os_version (UINT32_MAX),
131    m_update_os_version (UINT32_MAX)
132{
133}
134
135//------------------------------------------------------------------
136/// Destructor.
137///
138/// The destructor is virtual since this class is designed to be
139/// inherited from by the plug-in instance.
140//------------------------------------------------------------------
141Platform::~Platform()
142{
143}
144
145
146bool
147Platform::GetOSVersion (uint32_t &major,
148                        uint32_t &minor,
149                        uint32_t &update)
150{
151    bool success = m_major_os_version != UINT32_MAX;
152    if (IsHost())
153    {
154        if (!success)
155        {
156            // We have a local host platform
157            success = Host::GetOSVersion (m_major_os_version,
158                                          m_minor_os_version,
159                                          m_update_os_version);
160            m_os_version_set_while_connected = success;
161        }
162    }
163    else
164    {
165        // We have a remote platform. We can only fetch the remote
166        // OS version if we are connected, and we don't want to do it
167        // more than once.
168
169        const bool is_connected = IsConnected();
170
171        bool fetch_os_version = false;
172        if (success)
173        {
174            // We have valid OS version info, check to make sure it wasn't
175            // manually set prior to connecting. If it was manually set prior
176            // to connecting, then lets fetch the actual OS version info
177            // if we are now connected.
178            if (is_connected && !m_os_version_set_while_connected)
179                fetch_os_version = true;
180        }
181        else
182        {
183            // We don't have valid OS version info, fetch it if we are connected
184            fetch_os_version = is_connected;
185        }
186
187        if (fetch_os_version)
188        {
189            success = FetchRemoteOSVersion ();
190            m_os_version_set_while_connected = success;
191        }
192    }
193
194    if (success)
195    {
196        major = m_major_os_version;
197        minor = m_minor_os_version;
198        update = m_update_os_version;
199    }
200    return success;
201}
202
203bool
204Platform::SetOSVersion (uint32_t major,
205                        uint32_t minor,
206                        uint32_t update)
207{
208    if (IsHost())
209    {
210        // We don't need anyone setting the OS version for the host platform,
211        // we should be able to figure it out by calling Host::GetOSVersion(...).
212        return false;
213    }
214    else
215    {
216        // We have a remote platform, allow setting the target OS version if
217        // we aren't connected, since if we are connected, we should be able to
218        // request the remote OS version from the connected platform.
219        if (IsConnected())
220            return false;
221        else
222        {
223            // We aren't connected and we might want to set the OS version
224            // ahead of time before we connect so we can peruse files and
225            // use a local SDK or PDK cache of support files to disassemble
226            // or do other things.
227            m_major_os_version = major;
228            m_minor_os_version = minor;
229            m_update_os_version = update;
230            return true;
231        }
232    }
233    return false;
234}
235
236
237Error
238Platform::ResolveExecutable (const FileSpec &exe_file,
239                             const ArchSpec &exe_arch,
240                             lldb::ModuleSP &exe_module_sp)
241{
242    Error error;
243    if (exe_file.Exists())
244    {
245        if (exe_arch.IsValid())
246        {
247            error = ModuleList::GetSharedModule (exe_file,
248                                                 exe_arch,
249                                                 NULL,
250                                                 NULL,
251                                                 0,
252                                                 exe_module_sp,
253                                                 NULL,
254                                                 NULL);
255        }
256        else
257        {
258            // No valid architecture was specified, ask the platform for
259            // the architectures that we should be using (in the correct order)
260            // and see if we can find a match that way
261            ArchSpec platform_arch;
262            for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, platform_arch); ++idx)
263            {
264                error = ModuleList::GetSharedModule (exe_file,
265                                                     platform_arch,
266                                                     NULL,
267                                                     NULL,
268                                                     0,
269                                                     exe_module_sp,
270                                                     NULL,
271                                                     NULL);
272                // Did we find an executable using one of the
273                if (error.Success() && exe_module_sp)
274                    break;
275            }
276        }
277    }
278    else
279    {
280        error.SetErrorStringWithFormat ("'%s%s%s' does not exist",
281                                        exe_file.GetDirectory().AsCString(""),
282                                        exe_file.GetDirectory() ? "/" : "",
283                                        exe_file.GetFilename().AsCString(""));
284    }
285    return error;
286}
287
288
289const ArchSpec &
290Platform::GetSystemArchitecture()
291{
292    if (IsHost())
293    {
294        if (!m_system_arch.IsValid())
295        {
296            // We have a local host platform
297            m_system_arch = Host::GetArchitecture();
298            m_system_arch_set_while_connected = m_system_arch.IsValid();
299        }
300    }
301    else
302    {
303        // We have a remote platform. We can only fetch the remote
304        // system architecture if we are connected, and we don't want to do it
305        // more than once.
306
307        const bool is_connected = IsConnected();
308
309        bool fetch = false;
310        if (m_system_arch.IsValid())
311        {
312            // We have valid OS version info, check to make sure it wasn't
313            // manually set prior to connecting. If it was manually set prior
314            // to connecting, then lets fetch the actual OS version info
315            // if we are now connected.
316            if (is_connected && !m_system_arch_set_while_connected)
317                fetch = true;
318        }
319        else
320        {
321            // We don't have valid OS version info, fetch it if we are connected
322            fetch = is_connected;
323        }
324
325        if (fetch)
326        {
327            m_system_arch = FetchRemoteSystemArchitecture ();
328            m_system_arch_set_while_connected = m_system_arch.IsValid();
329        }
330    }
331    return m_system_arch;
332}
333
334
335Error
336Platform::ConnectRemote (Args& args)
337{
338    Error error;
339    if (IsHost())
340        error.SetErrorStringWithFormat ("The currently selected platform (%s) is the host platform and is always connected.", GetShortPluginName());
341    else
342        error.SetErrorStringWithFormat ("Platform::ConnectRemote() is not supported by %s", GetShortPluginName());
343    return error;
344}
345
346Error
347Platform::DisconnectRemote ()
348{
349    Error error;
350    if (IsHost())
351        error.SetErrorStringWithFormat ("The currently selected platform (%s) is the host platform and is always connected.", GetShortPluginName());
352    else
353        error.SetErrorStringWithFormat ("Platform::DisconnectRemote() is not supported by %s", GetShortPluginName());
354    return error;
355}
356