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