]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/llvm/tools/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
Copy head (r256279) to stable/10 as part of the 10.0-RELEASE cycle.
[FreeBSD/stable/10.git] / contrib / llvm / tools / lldb / source / Plugins / Platform / FreeBSD / PlatformFreeBSD.cpp
1 //===-- PlatformFreeBSD.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/lldb-python.h"
11
12 #include "PlatformFreeBSD.h"
13
14 // C Includes
15 #include <stdio.h>
16 #include <sys/utsname.h>
17
18 // C++ Includes
19 // Other libraries and framework includes
20 // Project includes
21 #include "lldb/Core/Error.h"
22 #include "lldb/Core/Debugger.h"
23 #include "lldb/Core/Module.h"
24 #include "lldb/Core/ModuleSpec.h"
25 #include "lldb/Core/PluginManager.h"
26 #include "lldb/Host/Host.h"
27
28 using namespace lldb;
29 using namespace lldb_private;
30
31 Platform *
32 PlatformFreeBSD::CreateInstance (bool force, const lldb_private::ArchSpec *arch)
33 {
34     // The only time we create an instance is when we are creating a remote
35     // freebsd platform
36     const bool is_host = false;
37
38     bool create = force;
39     if (create == false && arch && arch->IsValid())
40     {
41         const llvm::Triple &triple = arch->GetTriple();
42         switch (triple.getVendor())
43         {
44             case llvm::Triple::PC:
45                 create = true;
46                 break;
47                 
48 #if defined(__FreeBSD__) || defined(__OpenBSD__)
49             // Only accept "unknown" for the vendor if the host is BSD and
50             // it "unknown" wasn't specified (it was just returned becasue it
51             // was NOT specified)
52             case llvm::Triple::UnknownArch:
53                 create = !arch->TripleVendorWasSpecified();
54                 break;
55 #endif
56             default:
57                 break;
58         }
59         
60         if (create)
61         {
62             switch (triple.getOS())
63             {
64                 case llvm::Triple::FreeBSD:
65                 case llvm::Triple::KFreeBSD:
66                     break;
67                     
68 #if defined(__FreeBSD__) || defined(__OpenBSD__)
69                 // Only accept "unknown" for the OS if the host is BSD and
70                 // it "unknown" wasn't specified (it was just returned becasue it
71                 // was NOT specified)
72                 case llvm::Triple::UnknownOS:
73                     create = arch->TripleOSWasSpecified();
74                     break;
75 #endif
76                 default:
77                     create = false;
78                     break;
79             }
80         }
81     }
82     if (create)
83         return new PlatformFreeBSD (is_host);
84     return NULL;
85
86 }
87
88 lldb_private::ConstString
89 PlatformFreeBSD::GetPluginNameStatic (bool is_host)
90 {
91     if (is_host)
92     {
93         static ConstString g_host_name(Platform::GetHostPlatformName ());
94         return g_host_name;
95     }
96     else
97     {
98         static ConstString g_remote_name("remote-freebsd");
99         return g_remote_name;
100     }
101 }
102
103 const char *
104 PlatformFreeBSD::GetDescriptionStatic (bool is_host)
105 {
106     if (is_host)
107         return "Local FreeBSD user platform plug-in.";
108     else
109         return "Remote FreeBSD user platform plug-in.";
110 }
111
112 static uint32_t g_initialize_count = 0;
113
114 void
115 PlatformFreeBSD::Initialize ()
116 {
117     if (g_initialize_count++ == 0)
118     {
119 #if defined (__FreeBSD__)
120         // Force a host flag to true for the default platform object.
121         PlatformSP default_platform_sp (new PlatformFreeBSD(true));
122         default_platform_sp->SetSystemArchitecture (Host::GetArchitecture());
123         Platform::SetDefaultPlatform (default_platform_sp);
124 #endif
125         PluginManager::RegisterPlugin(PlatformFreeBSD::GetPluginNameStatic(false),
126                                       PlatformFreeBSD::GetDescriptionStatic(false),
127                                       PlatformFreeBSD::CreateInstance);
128     }
129 }
130
131 void
132 PlatformFreeBSD::Terminate ()
133 {
134     if (g_initialize_count > 0 && --g_initialize_count == 0)
135         PluginManager::UnregisterPlugin (PlatformFreeBSD::CreateInstance);
136 }
137
138 //------------------------------------------------------------------
139 /// Default Constructor
140 //------------------------------------------------------------------
141 PlatformFreeBSD::PlatformFreeBSD (bool is_host) :
142 Platform(is_host)
143 {
144 }
145
146 //------------------------------------------------------------------
147 /// Destructor.
148 ///
149 /// The destructor is virtual since this class is designed to be
150 /// inherited from by the plug-in instance.
151 //------------------------------------------------------------------
152 PlatformFreeBSD::~PlatformFreeBSD()
153 {
154 }
155
156
157 Error
158 PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
159                                     const ArchSpec &exe_arch,
160                                     lldb::ModuleSP &exe_module_sp,
161                                     const FileSpecList *module_search_paths_ptr)
162 {
163     Error error;
164     // Nothing special to do here, just use the actual file and architecture
165
166     char exe_path[PATH_MAX];
167     FileSpec resolved_exe_file (exe_file);
168
169     if (IsHost())
170     {
171         // If we have "ls" as the exe_file, resolve the executable location based on
172         // the current path variables
173         if (!resolved_exe_file.Exists())
174         {
175             exe_file.GetPath(exe_path, sizeof(exe_path));
176             resolved_exe_file.SetFile(exe_path, true);
177         }
178
179         if (!resolved_exe_file.Exists())
180             resolved_exe_file.ResolveExecutableLocation ();
181
182         if (resolved_exe_file.Exists())
183             error.Clear();
184         else
185         {
186             exe_file.GetPath(exe_path, sizeof(exe_path));
187             error.SetErrorStringWithFormat("unable to find executable for '%s'", exe_path);
188         }
189     }
190     else
191     {
192         if (m_remote_platform_sp)
193         {
194             error = m_remote_platform_sp->ResolveExecutable (exe_file,
195                                                              exe_arch,
196                                                              exe_module_sp,
197                                                              module_search_paths_ptr);
198         }
199         else
200         {
201             // We may connect to a process and use the provided executable (Don't use local $PATH).
202             
203             // Resolve any executable within a bundle on MacOSX
204             Host::ResolveExecutableInBundle (resolved_exe_file);
205             
206             if (resolved_exe_file.Exists()) {
207                 error.Clear();
208             }
209             else
210             {
211                 exe_file.GetPath(exe_path, sizeof(exe_path));
212                 error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", exe_path);
213             }
214         }
215     }
216
217
218     if (error.Success())
219     {
220         ModuleSpec module_spec (resolved_exe_file, exe_arch);
221         if (module_spec.GetArchitecture().IsValid())
222         {
223             error = ModuleList::GetSharedModule (module_spec,
224                                                  exe_module_sp,
225                                                  module_search_paths_ptr,
226                                                  NULL,
227                                                  NULL);
228
229             if (!exe_module_sp || exe_module_sp->GetObjectFile() == NULL)
230             {
231                 exe_module_sp.reset();
232                 error.SetErrorStringWithFormat ("'%s' doesn't contain the architecture %s",
233                                                 exe_file.GetPath().c_str(),
234                                                 exe_arch.GetArchitectureName());
235             }
236         }
237         else
238         {
239             // No valid architecture was specified, ask the platform for
240             // the architectures that we should be using (in the correct order)
241             // and see if we can find a match that way
242             StreamString arch_names;
243             ArchSpec platform_arch;
244             for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, platform_arch); ++idx)
245             {
246                 error = ModuleList::GetSharedModule (module_spec,
247                                                      exe_module_sp,
248                                                      module_search_paths_ptr,
249                                                      NULL,
250                                                      NULL);
251                 // Did we find an executable using one of the
252                 if (error.Success())
253                 {
254                     if (exe_module_sp && exe_module_sp->GetObjectFile())
255                         break;
256                     else
257                         error.SetErrorToGenericError();
258                 }
259
260                 if (idx > 0)
261                     arch_names.PutCString (", ");
262                 arch_names.PutCString (platform_arch.GetArchitectureName());
263             }
264
265             if (error.Fail() || !exe_module_sp)
266             {
267                 error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
268                                                 exe_file.GetPath().c_str(),
269                                                 GetPluginName().GetCString(),
270                                                 arch_names.GetString().c_str());
271             }
272         }
273     }
274     else
275     {
276         error.SetErrorStringWithFormat ("'%s' does not exist",
277                                         exe_file.GetPath().c_str());
278     }
279
280     return error;
281 }
282
283 size_t
284 PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site)
285 {
286     ArchSpec arch = target.GetArchitecture();
287     const uint8_t *trap_opcode = NULL;
288     size_t trap_opcode_size = 0;
289
290     switch (arch.GetCore())
291     {
292     default:
293         assert(false && "Unhandled architecture in PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode()");
294         break;
295
296     case ArchSpec::eCore_x86_32_i386:
297     case ArchSpec::eCore_x86_64_x86_64:
298         {
299             static const uint8_t g_i386_opcode[] = { 0xCC };
300             trap_opcode = g_i386_opcode;
301             trap_opcode_size = sizeof(g_i386_opcode);
302         }
303         break;
304     }
305
306     if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
307         return trap_opcode_size;
308
309     return 0;
310 }
311
312 bool
313 PlatformFreeBSD::GetRemoteOSVersion ()
314 {
315     if (m_remote_platform_sp)
316         return m_remote_platform_sp->GetOSVersion (m_major_os_version,
317                                                    m_minor_os_version,
318                                                    m_update_os_version);
319     return false;
320 }
321
322 bool
323 PlatformFreeBSD::GetRemoteOSBuildString (std::string &s)
324 {
325     if (m_remote_platform_sp)
326         return m_remote_platform_sp->GetRemoteOSBuildString (s);
327     s.clear();
328     return false;
329 }
330
331 bool
332 PlatformFreeBSD::GetRemoteOSKernelDescription (std::string &s)
333 {
334     if (m_remote_platform_sp)
335         return m_remote_platform_sp->GetRemoteOSKernelDescription (s);
336     s.clear();
337     return false;
338 }
339
340 // Remote Platform subclasses need to override this function
341 ArchSpec
342 PlatformFreeBSD::GetRemoteSystemArchitecture ()
343 {
344     if (m_remote_platform_sp)
345         return m_remote_platform_sp->GetRemoteSystemArchitecture ();
346     return ArchSpec();
347 }
348
349
350 const char *
351 PlatformFreeBSD::GetHostname ()
352 {
353     if (IsHost())
354         return Platform::GetHostname();
355
356     if (m_remote_platform_sp)
357         return m_remote_platform_sp->GetHostname ();
358     return NULL;
359 }
360
361 bool
362 PlatformFreeBSD::IsConnected () const
363 {
364     if (IsHost())
365         return true;
366     else if (m_remote_platform_sp)
367         return m_remote_platform_sp->IsConnected();
368     return false;
369 }
370
371 Error
372 PlatformFreeBSD::ConnectRemote (Args& args)
373 {
374     Error error;
375     if (IsHost())
376     {
377         error.SetErrorStringWithFormat ("can't connect to the host platform '%s', always connected", GetPluginName().GetCString());
378     }
379     else
380     {
381         if (!m_remote_platform_sp)
382             m_remote_platform_sp = Platform::Create ("remote-gdb-server", error);
383
384         if (m_remote_platform_sp)
385         {
386             if (error.Success())
387             {
388                 if (m_remote_platform_sp)
389                 {
390                     error = m_remote_platform_sp->ConnectRemote (args);
391                 }
392                 else
393                 {
394                     error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>");
395                 }
396             }
397         }
398         else
399             error.SetErrorString ("failed to create a 'remote-gdb-server' platform");
400
401         if (error.Fail())
402             m_remote_platform_sp.reset();
403     }
404
405     return error;
406 }
407
408 Error
409 PlatformFreeBSD::DisconnectRemote ()
410 {
411     Error error;
412
413     if (IsHost())
414     {
415         error.SetErrorStringWithFormat ("can't disconnect from the host platform '%s', always connected", GetPluginName().GetCString());
416     }
417     else
418     {
419         if (m_remote_platform_sp)
420             error = m_remote_platform_sp->DisconnectRemote ();
421         else
422             error.SetErrorString ("the platform is not currently connected");
423     }
424     return error;
425 }
426
427 bool
428 PlatformFreeBSD::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
429 {
430     bool success = false;
431     if (IsHost())
432     {
433         success = Platform::GetProcessInfo (pid, process_info);
434     }
435     else if (m_remote_platform_sp) 
436     {
437         success = m_remote_platform_sp->GetProcessInfo (pid, process_info);
438     }
439     return success;
440 }
441
442
443
444 uint32_t
445 PlatformFreeBSD::FindProcesses (const ProcessInstanceInfoMatch &match_info,
446                                ProcessInstanceInfoList &process_infos)
447 {
448     uint32_t match_count = 0;
449     if (IsHost())
450     {
451         // Let the base class figure out the host details
452         match_count = Platform::FindProcesses (match_info, process_infos);
453     }
454     else
455     {
456         // If we are remote, we can only return results if we are connected
457         if (m_remote_platform_sp)
458             match_count = m_remote_platform_sp->FindProcesses (match_info, process_infos);
459     }
460     return match_count;
461 }
462
463 Error
464 PlatformFreeBSD::LaunchProcess (ProcessLaunchInfo &launch_info)
465 {
466     Error error;
467     if (IsHost())
468     {
469         error = Platform::LaunchProcess (launch_info);
470     }
471     else
472     {
473         if (m_remote_platform_sp)
474             error = m_remote_platform_sp->LaunchProcess (launch_info);
475         else
476             error.SetErrorString ("the platform is not currently connected");
477     }
478     return error;
479 }
480
481 lldb::ProcessSP
482 PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info,
483                         Debugger &debugger,
484                         Target *target,
485                         Listener &listener,
486                         Error &error)
487 {
488     lldb::ProcessSP process_sp;
489     if (IsHost())
490     {
491         if (target == NULL)
492         {
493             TargetSP new_target_sp;
494             ArchSpec emptyArchSpec;
495
496             error = debugger.GetTargetList().CreateTarget (debugger,
497                                                            NULL,
498                                                            emptyArchSpec,
499                                                            false,
500                                                            m_remote_platform_sp,
501                                                            new_target_sp);
502             target = new_target_sp.get();
503         }
504         else
505             error.Clear();
506
507         if (target && error.Success())
508         {
509             debugger.GetTargetList().SetSelectedTarget(target);
510             // The freebsd always currently uses the GDB remote debugger plug-in
511             // so even when debugging locally we are debugging remotely!
512             // Just like the darwin plugin.
513             process_sp = target->CreateProcess (listener, "gdb-remote", NULL);
514
515             if (process_sp)
516                 error = process_sp->Attach (attach_info);
517         }
518     }
519     else
520     {
521         if (m_remote_platform_sp)
522             process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, listener, error);
523         else
524             error.SetErrorString ("the platform is not currently connected");
525     }
526     return process_sp;
527 }
528
529 const char *
530 PlatformFreeBSD::GetUserName (uint32_t uid)
531 {
532     // Check the cache in Platform in case we have already looked this uid up
533     const char *user_name = Platform::GetUserName(uid);
534     if (user_name)
535         return user_name;
536
537     if (IsRemote() && m_remote_platform_sp)
538         return m_remote_platform_sp->GetUserName(uid);
539     return NULL;
540 }
541
542 const char *
543 PlatformFreeBSD::GetGroupName (uint32_t gid)
544 {
545     const char *group_name = Platform::GetGroupName(gid);
546     if (group_name)
547         return group_name;
548
549     if (IsRemote() && m_remote_platform_sp)
550         return m_remote_platform_sp->GetGroupName(gid);
551     return NULL;
552 }
553
554
555 // From PlatformMacOSX only
556 Error
557 PlatformFreeBSD::GetFile (const FileSpec &platform_file,
558                           const UUID *uuid_ptr,
559                           FileSpec &local_file)
560 {
561     if (IsRemote())
562     {
563         if (m_remote_platform_sp)
564             return m_remote_platform_sp->GetFile (platform_file, uuid_ptr, local_file);
565     }
566
567     // Default to the local case
568     local_file = platform_file;
569     return Error();
570 }
571
572 Error
573 PlatformFreeBSD::GetSharedModule (const ModuleSpec &module_spec,
574                                   ModuleSP &module_sp,
575                                   const FileSpecList *module_search_paths_ptr,
576                                   ModuleSP *old_module_sp_ptr,
577                                   bool *did_create_ptr)
578 {
579     Error error;
580     module_sp.reset();
581
582     if (IsRemote())
583     {
584         // If we have a remote platform always, let it try and locate
585         // the shared module first.
586         if (m_remote_platform_sp)
587         {
588             error = m_remote_platform_sp->GetSharedModule (module_spec,
589                                                            module_sp,
590                                                            module_search_paths_ptr,
591                                                            old_module_sp_ptr,
592                                                            did_create_ptr);
593         }
594     }
595
596     if (!module_sp)
597     {
598         // Fall back to the local platform and find the file locally
599         error = Platform::GetSharedModule (module_spec,
600                                            module_sp,
601                                            module_search_paths_ptr,
602                                            old_module_sp_ptr,
603                                            did_create_ptr);
604     }
605     if (module_sp)
606         module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
607     return error;
608 }
609
610
611 bool
612 PlatformFreeBSD::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
613 {
614     // From macosx;s plugin code. For FreeBSD we may want to support more archs.
615     if (idx == 0)
616     {
617         arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
618         return arch.IsValid();
619     }
620     else if (idx == 1)
621     {
622         ArchSpec platform_arch (Host::GetArchitecture (Host::eSystemDefaultArchitecture));
623         ArchSpec platform_arch64 (Host::GetArchitecture (Host::eSystemDefaultArchitecture64));
624         if (platform_arch.IsExactMatch(platform_arch64))
625         {
626             // This freebsd platform supports both 32 and 64 bit. Since we already
627             // returned the 64 bit arch for idx == 0, return the 32 bit arch
628             // for idx == 1
629             arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture32);
630             return arch.IsValid();
631         }
632     }
633     return false;
634 }
635
636 void
637 PlatformFreeBSD::GetStatus (Stream &strm)
638 {
639     struct utsname un;
640
641     if (uname(&un)) {
642         strm << "FreeBSD";
643         return;
644     }
645
646     strm << "Host: " << un.sysname << ' ' << un.release << ' ' << un.version << '\n';
647     Platform::GetStatus(strm);
648 }