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