PlatformDarwin.cpp revision 2d9adb73af7520bec430e0585ca40467828e6ed1
1//===-- PlatformDarwin.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 "PlatformDarwin.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/Breakpoint/BreakpointLocation.h"
17#include "lldb/Core/Debugger.h"
18#include "lldb/Core/Error.h"
19#include "lldb/Host/Host.h"
20#include "lldb/Target/Target.h"
21
22using namespace lldb;
23using namespace lldb_private;
24
25
26//------------------------------------------------------------------
27/// Default Constructor
28//------------------------------------------------------------------
29PlatformDarwin::PlatformDarwin (bool is_host) :
30    Platform(is_host),  // This is the local host platform
31    m_remote_platform_sp ()
32{
33}
34
35//------------------------------------------------------------------
36/// Destructor.
37///
38/// The destructor is virtual since this class is designed to be
39/// inherited from by the plug-in instance.
40//------------------------------------------------------------------
41PlatformDarwin::~PlatformDarwin()
42{
43}
44
45
46Error
47PlatformDarwin::ResolveExecutable (const FileSpec &exe_file,
48                                   const ArchSpec &exe_arch,
49                                   lldb::ModuleSP &exe_module_sp)
50{
51    Error error;
52    // Nothing special to do here, just use the actual file and architecture
53
54    char exe_path[PATH_MAX];
55    FileSpec resolved_exe_file (exe_file);
56
57    if (IsHost())
58    {
59        // If we have "ls" as the exe_file, resolve the executable loation based on
60        // the current path variables
61        if (!resolved_exe_file.Exists())
62        {
63            exe_file.GetPath (exe_path, sizeof(exe_path));
64            resolved_exe_file.SetFile(exe_path, true);
65        }
66
67        if (!resolved_exe_file.Exists())
68            resolved_exe_file.ResolveExecutableLocation ();
69
70        // Resolve any executable within a bundle on MacOSX
71        Host::ResolveExecutableInBundle (resolved_exe_file);
72
73        if (resolved_exe_file.Exists())
74            error.Clear();
75        else
76        {
77            exe_file.GetPath (exe_path, sizeof(exe_path));
78            error.SetErrorStringWithFormat ("enable to find executable for '%s'", exe_path);
79        }
80    }
81    else
82    {
83        if (m_remote_platform_sp)
84        {
85            error = m_remote_platform_sp->ResolveExecutable (exe_file,
86                                                             exe_arch,
87                                                             exe_module_sp);
88        }
89        else
90        {
91            // We may connect to a process and use the provided executable (Don't use local $PATH).
92
93            // Resolve any executable within a bundle on MacOSX
94            Host::ResolveExecutableInBundle (resolved_exe_file);
95
96            if (resolved_exe_file.Exists())
97                error.Clear();
98            else
99                error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", resolved_exe_file.GetFilename().AsCString(""));
100        }
101    }
102
103
104    if (error.Success())
105    {
106        if (exe_arch.IsValid())
107        {
108            error = ModuleList::GetSharedModule (resolved_exe_file,
109                                                 exe_arch,
110                                                 NULL,
111                                                 NULL,
112                                                 0,
113                                                 exe_module_sp,
114                                                 NULL,
115                                                 NULL);
116
117            if (exe_module_sp->GetObjectFile() == NULL)
118            {
119                exe_module_sp.reset();
120                error.SetErrorStringWithFormat ("'%s%s%s' doesn't contain the architecture %s",
121                                                exe_file.GetDirectory().AsCString(""),
122                                                exe_file.GetDirectory() ? "/" : "",
123                                                exe_file.GetFilename().AsCString(""),
124                                                exe_arch.GetArchitectureName());
125            }
126        }
127        else
128        {
129            // No valid architecture was specified, ask the platform for
130            // the architectures that we should be using (in the correct order)
131            // and see if we can find a match that way
132            StreamString arch_names;
133            ArchSpec platform_arch;
134            for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, platform_arch); ++idx)
135            {
136                error = ModuleList::GetSharedModule (resolved_exe_file,
137                                                     platform_arch,
138                                                     NULL,
139                                                     NULL,
140                                                     0,
141                                                     exe_module_sp,
142                                                     NULL,
143                                                     NULL);
144                // Did we find an executable using one of the
145                if (error.Success())
146                {
147                    if (exe_module_sp && exe_module_sp->GetObjectFile())
148                        break;
149                    else
150                        error.SetErrorToGenericError();
151                }
152
153                if (idx > 0)
154                    arch_names.PutCString (", ");
155                arch_names.PutCString (platform_arch.GetArchitectureName());
156            }
157
158            if (error.Fail() || !exe_module_sp)
159            {
160                error.SetErrorStringWithFormat ("'%s%s%s' doesn't contain any '%s' platform architectures: %s",
161                                                exe_file.GetDirectory().AsCString(""),
162                                                exe_file.GetDirectory() ? "/" : "",
163                                                exe_file.GetFilename().AsCString(""),
164                                                GetShortPluginName(),
165                                                arch_names.GetString().c_str());
166            }
167        }
168    }
169
170    return error;
171}
172
173
174size_t
175PlatformDarwin::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site)
176{
177    const uint8_t *trap_opcode = NULL;
178    uint32_t trap_opcode_size = 0;
179    bool bp_is_thumb = false;
180
181    llvm::Triple::ArchType machine = target.GetArchitecture().GetMachine();
182    switch (machine)
183    {
184    case llvm::Triple::x86:
185    case llvm::Triple::x86_64:
186        {
187            static const uint8_t g_i386_breakpoint_opcode[] = { 0xCC };
188            trap_opcode = g_i386_breakpoint_opcode;
189            trap_opcode_size = sizeof(g_i386_breakpoint_opcode);
190        }
191        break;
192
193    case llvm::Triple::thumb:
194        bp_is_thumb = true; // Fall through...
195    case llvm::Triple::arm:
196        {
197            static const uint8_t g_arm_breakpoint_opcode[] = { 0xFE, 0xDE, 0xFF, 0xE7 };
198            static const uint8_t g_thumb_breakpooint_opcode[] = { 0xFE, 0xDE };
199
200            // Auto detect arm/thumb if it wasn't explicitly specified
201            if (!bp_is_thumb)
202            {
203                lldb::BreakpointLocationSP bp_loc_sp (bp_site->GetOwnerAtIndex (0));
204                if (bp_loc_sp)
205                    bp_is_thumb = bp_loc_sp->GetAddress().GetAddressClass () == eAddressClassCodeAlternateISA;
206            }
207            if (bp_is_thumb)
208            {
209                trap_opcode = g_thumb_breakpooint_opcode;
210                trap_opcode_size = sizeof(g_thumb_breakpooint_opcode);
211                break;
212            }
213            trap_opcode = g_arm_breakpoint_opcode;
214            trap_opcode_size = sizeof(g_arm_breakpoint_opcode);
215        }
216        break;
217
218    case llvm::Triple::ppc:
219    case llvm::Triple::ppc64:
220        {
221            static const uint8_t g_ppc_breakpoint_opcode[] = { 0x7F, 0xC0, 0x00, 0x08 };
222            trap_opcode = g_ppc_breakpoint_opcode;
223            trap_opcode_size = sizeof(g_ppc_breakpoint_opcode);
224        }
225        break;
226
227    default:
228        assert(!"Unhandled architecture in PlatformDarwin::GetSoftwareBreakpointTrapOpcode()");
229        break;
230    }
231
232    if (trap_opcode && trap_opcode_size)
233    {
234        if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
235            return trap_opcode_size;
236    }
237    return 0;
238
239}
240
241bool
242PlatformDarwin::GetRemoteOSVersion ()
243{
244    if (m_remote_platform_sp)
245        return m_remote_platform_sp->GetOSVersion (m_major_os_version,
246                                                   m_minor_os_version,
247                                                   m_update_os_version);
248    return false;
249}
250
251bool
252PlatformDarwin::GetRemoteOSBuildString (std::string &s)
253{
254    if (m_remote_platform_sp)
255        return m_remote_platform_sp->GetRemoteOSBuildString (s);
256    s.clear();
257    return false;
258}
259
260bool
261PlatformDarwin::GetRemoteOSKernelDescription (std::string &s)
262{
263    if (m_remote_platform_sp)
264        return m_remote_platform_sp->GetRemoteOSKernelDescription (s);
265    s.clear();
266    return false;
267}
268
269// Remote Platform subclasses need to override this function
270ArchSpec
271PlatformDarwin::GetRemoteSystemArchitecture ()
272{
273    if (m_remote_platform_sp)
274        return m_remote_platform_sp->GetRemoteSystemArchitecture ();
275    return ArchSpec();
276}
277
278
279const char *
280PlatformDarwin::GetHostname ()
281{
282    if (IsHost())
283        return Platform::GetHostname();
284
285    if (m_remote_platform_sp)
286        return m_remote_platform_sp->GetHostname ();
287    return NULL;
288}
289
290bool
291PlatformDarwin::IsConnected () const
292{
293    if (IsHost())
294        return true;
295    else if (m_remote_platform_sp)
296        return m_remote_platform_sp->IsConnected();
297    return false;
298}
299
300Error
301PlatformDarwin::ConnectRemote (Args& args)
302{
303    Error error;
304    if (IsHost())
305    {
306        error.SetErrorStringWithFormat ("can't connect to the host platform '%s', always connected", GetShortPluginName());
307    }
308    else
309    {
310        if (!m_remote_platform_sp)
311            m_remote_platform_sp = Platform::Create ("remote-gdb-server", error);
312
313        if (m_remote_platform_sp)
314        {
315            if (error.Success())
316            {
317                if (m_remote_platform_sp)
318                {
319                    error = m_remote_platform_sp->ConnectRemote (args);
320                }
321                else
322                {
323                    error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>");
324                }
325            }
326        }
327        else
328            error.SetErrorString ("failed to create a 'remote-gdb-server' platform");
329
330        if (error.Fail())
331            m_remote_platform_sp.reset();
332    }
333
334    return error;
335}
336
337Error
338PlatformDarwin::DisconnectRemote ()
339{
340    Error error;
341
342    if (IsHost())
343    {
344        error.SetErrorStringWithFormat ("can't disconnect from the host platform '%s', always connected", GetShortPluginName());
345    }
346    else
347    {
348        if (m_remote_platform_sp)
349            error = m_remote_platform_sp->DisconnectRemote ();
350        else
351            error.SetErrorString ("the platform is not currently connected");
352    }
353    return error;
354}
355
356
357bool
358PlatformDarwin::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
359{
360    bool sucess = false;
361    if (IsHost())
362    {
363        sucess = Platform::GetProcessInfo (pid, process_info);
364    }
365    else
366    {
367        if (m_remote_platform_sp)
368            sucess = m_remote_platform_sp->GetProcessInfo (pid, process_info);
369    }
370    return sucess;
371}
372
373
374
375uint32_t
376PlatformDarwin::FindProcesses (const ProcessInstanceInfoMatch &match_info,
377                               ProcessInstanceInfoList &process_infos)
378{
379    uint32_t match_count = 0;
380    if (IsHost())
381    {
382        // Let the base class figure out the host details
383        match_count = Platform::FindProcesses (match_info, process_infos);
384    }
385    else
386    {
387        // If we are remote, we can only return results if we are connected
388        if (m_remote_platform_sp)
389            match_count = m_remote_platform_sp->FindProcesses (match_info, process_infos);
390    }
391    return match_count;
392}
393
394Error
395PlatformDarwin::LaunchProcess (ProcessLaunchInfo &launch_info)
396{
397    Error error;
398    if (IsHost())
399    {
400        error = Platform::LaunchProcess (launch_info);
401    }
402    else
403    {
404        if (m_remote_platform_sp)
405            error = m_remote_platform_sp->LaunchProcess (launch_info);
406        else
407            error.SetErrorString ("the platform is not currently connected");
408    }
409    return error;
410}
411
412lldb::ProcessSP
413PlatformDarwin::Attach (lldb::pid_t pid,
414                        Debugger &debugger,
415                        Target *target,
416                        Listener &listener,
417                        Error &error)
418{
419    lldb::ProcessSP process_sp;
420    if (IsHost())
421    {
422        if (target == NULL)
423        {
424            TargetSP new_target_sp;
425            FileSpec emptyFileSpec;
426
427            error = debugger.GetTargetList().CreateTarget (debugger,
428                                                           emptyFileSpec,
429                                                           NULL,
430                                                           false,
431                                                           NULL,
432                                                           new_target_sp);
433            target = new_target_sp.get();
434        }
435        else
436            error.Clear();
437
438        if (target && error.Success())
439        {
440            debugger.GetTargetList().SetSelectedTarget(target);
441            // The darwin always currently uses the GDB remote debugger plug-in
442            // so even when debugging locally we are debugging remotely!
443            process_sp = target->CreateProcess (listener, "gdb-remote");
444
445            if (process_sp)
446                error = process_sp->Attach (pid, 2);
447        }
448    }
449    else
450    {
451        if (m_remote_platform_sp)
452            process_sp = m_remote_platform_sp->Attach (pid, debugger, target, listener, error);
453        else
454            error.SetErrorString ("the platform is not currently connected");
455    }
456    return process_sp;
457}
458
459const char *
460PlatformDarwin::GetUserName (uint32_t uid)
461{
462    // Check the cache in Platform in case we have already looked this uid up
463    const char *user_name = Platform::GetUserName(uid);
464    if (user_name)
465        return user_name;
466
467    if (IsRemote() && m_remote_platform_sp)
468        return m_remote_platform_sp->GetUserName(uid);
469    return NULL;
470}
471
472const char *
473PlatformDarwin::GetGroupName (uint32_t gid)
474{
475    const char *group_name = Platform::GetGroupName(gid);
476    if (group_name)
477        return group_name;
478
479    if (IsRemote() && m_remote_platform_sp)
480        return m_remote_platform_sp->GetGroupName(gid);
481    return NULL;
482}
483
484bool
485PlatformDarwin::ModuleIsExcludedForNonModuleSpecificSearches (lldb_private::Target &target, const lldb::ModuleSP &module_sp)
486{
487    ObjectFile *obj_file = module_sp->GetObjectFile();
488    if (!obj_file)
489        return false;
490
491    ObjectFile::Type obj_type = obj_file->GetType();
492    if (obj_type == ObjectFile::eTypeDynamicLinker)
493        return true;
494    else
495        return false;
496}
497