1 //===-- PlatformFreeBSD.cpp -------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "PlatformFreeBSD.h"
11 #include "lldb/Host/Config.h"
15 #ifndef LLDB_DISABLE_POSIX
16 #include <sys/utsname.h>
20 // Other libraries and framework 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"
34 using namespace lldb_private;
35 using namespace lldb_private::platform_freebsd;
37 PlatformSP PlatformFreeBSD::CreateInstance(bool force, const ArchSpec *arch) {
38 // The only time we create an instance is when we are creating a remote
40 const bool is_host = false;
43 if (create == false && arch && arch->IsValid()) {
44 const llvm::Triple &triple = arch->GetTriple();
45 switch (triple.getOS()) {
46 case llvm::Triple::FreeBSD:
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
54 case llvm::Triple::OSType::UnknownOS:
55 create = !arch->TripleOSWasSpecified();
63 return PlatformSP(new PlatformFreeBSD(is_host));
67 ConstString PlatformFreeBSD::GetPluginNameStatic(bool is_host) {
69 static ConstString g_host_name(Platform::GetHostPlatformName());
72 static ConstString g_remote_name("remote-freebsd");
77 const char *PlatformFreeBSD::GetDescriptionStatic(bool is_host) {
79 return "Local FreeBSD user platform plug-in.";
81 return "Remote FreeBSD user platform plug-in.";
84 static uint32_t g_initialize_count = 0;
86 void PlatformFreeBSD::Initialize() {
87 Platform::Initialize();
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);
96 PluginManager::RegisterPlugin(PlatformFreeBSD::GetPluginNameStatic(false),
97 PlatformFreeBSD::GetDescriptionStatic(false),
98 PlatformFreeBSD::CreateInstance);
102 void PlatformFreeBSD::Terminate() {
103 if (g_initialize_count > 0 && --g_initialize_count == 0)
104 PluginManager::UnregisterPlugin(PlatformFreeBSD::CreateInstance);
106 Platform::Terminate();
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,
116 return Platform::GetModuleSpec(module_file_spec, arch, module_spec);
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) {
125 return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr,
126 command_output, timeout_sec);
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);
133 return Error("unable to run a remote command without a platform");
137 Error PlatformFreeBSD::ResolveExecutable(
138 const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp,
139 const FileSpecList *module_search_paths_ptr) {
141 // Nothing special to do here, just use the actual file and architecture
143 char exe_path[PATH_MAX];
144 ModuleSpec resolved_module_spec(module_spec);
147 // If we have "ls" as the module_spec's file, resolve the executable
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);
155 if (!resolved_module_spec.GetFileSpec().Exists())
156 resolved_module_spec.GetFileSpec().ResolveExecutableLocation();
158 if (resolved_module_spec.GetFileSpec().Exists())
161 error.SetErrorStringWithFormat(
162 "unable to find executable for '%s'",
163 resolved_module_spec.GetFileSpec().GetPath().c_str());
166 if (m_remote_platform_sp) {
168 GetCachedExecutable(resolved_module_spec, exe_module_sp,
169 module_search_paths_ptr, *m_remote_platform_sp);
171 // We may connect to a process and use the provided executable (Don't use
174 // Resolve any executable within a bundle on MacOSX
175 Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
177 if (resolved_module_spec.GetFileSpec().Exists()) {
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());
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);
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());
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());
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())
216 error.SetErrorToGenericError();
220 arch_names.PutCString(", ");
221 arch_names.PutCString(
222 resolved_module_spec.GetArchitecture().GetArchitectureName());
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());
232 error.SetErrorStringWithFormat(
233 "'%s' is not readable",
234 resolved_module_spec.GetFileSpec().GetPath().c_str());
243 // From PlatformMacOSX only
244 Error PlatformFreeBSD::GetFileWithUUID(const FileSpec &platform_file,
245 const UUID *uuid_ptr,
246 FileSpec &local_file) {
248 if (m_remote_platform_sp)
249 return m_remote_platform_sp->GetFileWithUUID(platform_file, uuid_ptr,
253 // Default to the local case
254 local_file = platform_file;
258 //------------------------------------------------------------------
259 /// Default Constructor
260 //------------------------------------------------------------------
261 PlatformFreeBSD::PlatformFreeBSD(bool is_host)
262 : Platform(is_host), m_remote_platform_sp() {}
264 //------------------------------------------------------------------
267 /// The destructor is virtual since this class is designed to be
268 /// inherited from by the plug-in instance.
269 //------------------------------------------------------------------
270 PlatformFreeBSD::~PlatformFreeBSD() {}
272 // TODO:VK: inherit PlatformPOSIX
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);
281 bool PlatformFreeBSD::GetRemoteOSBuildString(std::string &s) {
282 if (m_remote_platform_sp)
283 return m_remote_platform_sp->GetRemoteOSBuildString(s);
288 bool PlatformFreeBSD::GetRemoteOSKernelDescription(std::string &s) {
289 if (m_remote_platform_sp)
290 return m_remote_platform_sp->GetRemoteOSKernelDescription(s);
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();
302 const char *PlatformFreeBSD::GetHostname() {
304 return Platform::GetHostname();
306 if (m_remote_platform_sp)
307 return m_remote_platform_sp->GetHostname();
311 bool PlatformFreeBSD::IsConnected() const {
314 else if (m_remote_platform_sp)
315 return m_remote_platform_sp->IsConnected();
319 Error PlatformFreeBSD::ConnectRemote(Args &args) {
322 error.SetErrorStringWithFormat(
323 "can't connect to the host platform '%s', always connected",
324 GetPluginName().GetCString());
326 if (!m_remote_platform_sp)
327 m_remote_platform_sp =
328 Platform::Create(ConstString("remote-gdb-server"), error);
330 if (m_remote_platform_sp) {
331 if (error.Success()) {
332 if (m_remote_platform_sp) {
333 error = m_remote_platform_sp->ConnectRemote(args);
335 error.SetErrorString(
336 "\"platform connect\" takes a single argument: <connect-url>");
340 error.SetErrorString("failed to create a 'remote-gdb-server' platform");
343 m_remote_platform_sp.reset();
349 Error PlatformFreeBSD::DisconnectRemote() {
353 error.SetErrorStringWithFormat(
354 "can't disconnect from the host platform '%s', always connected",
355 GetPluginName().GetCString());
357 if (m_remote_platform_sp)
358 error = m_remote_platform_sp->DisconnectRemote();
360 error.SetErrorString("the platform is not currently connected");
365 bool PlatformFreeBSD::GetProcessInfo(lldb::pid_t pid,
366 ProcessInstanceInfo &process_info) {
367 bool success = false;
369 success = Platform::GetProcessInfo(pid, process_info);
370 } else if (m_remote_platform_sp) {
371 success = m_remote_platform_sp->GetProcessInfo(pid, process_info);
377 PlatformFreeBSD::FindProcesses(const ProcessInstanceInfoMatch &match_info,
378 ProcessInstanceInfoList &process_infos) {
379 uint32_t match_count = 0;
381 // Let the base class figure out the host details
382 match_count = Platform::FindProcesses(match_info, process_infos);
384 // If we are remote, we can only return results if we are connected
385 if (m_remote_platform_sp)
387 m_remote_platform_sp->FindProcesses(match_info, process_infos);
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);
398 if (IsRemote() && m_remote_platform_sp)
399 return m_remote_platform_sp->GetUserName(uid);
403 const char *PlatformFreeBSD::GetGroupName(uint32_t gid) {
404 const char *group_name = Platform::GetGroupName(gid);
408 if (IsRemote() && m_remote_platform_sp)
409 return m_remote_platform_sp->GetGroupName(gid);
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) {
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);
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);
437 module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
441 bool PlatformFreeBSD::GetSupportedArchitectureAtIndex(uint32_t idx,
444 ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
445 if (hostArch.GetTriple().isOSFreeBSD()) {
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();
458 if (m_remote_platform_sp)
459 return m_remote_platform_sp->GetSupportedArchitectureAtIndex(idx, arch);
462 // Set the OS to FreeBSD
463 triple.setOS(llvm::Triple::FreeBSD);
464 // Set the architecture
467 triple.setArchName("x86_64");
470 triple.setArchName("i386");
473 triple.setArchName("aarch64");
476 triple.setArchName("arm");
479 triple.setArchName("mips64");
482 triple.setArchName("mips");
485 triple.setArchName("ppc64");
488 triple.setArchName("ppc");
493 // Leave the vendor as "llvm::Triple:UnknownVendor" and don't specify the
495 // calling triple.SetVendorName("unknown") so that it is a "unspecified
497 // This means when someone calls triple.GetVendorName() it will return an
499 // which indicates that the vendor can be set when two architectures are
502 // Now set the triple into "arch" and return true
503 arch.SetTriple(triple);
509 void PlatformFreeBSD::GetStatus(Stream &strm) {
510 #ifndef LLDB_DISABLE_POSIX
515 ::memset(&un, 0, sizeof(utsname));
516 if (uname(&un) == -1)
517 strm << "FreeBSD" << '\n';
519 strm << un.sysname << ' ' << un.release;
520 if (un.nodename[0] != '\0')
521 strm << " (" << un.nodename << ')';
524 // Dump a common information about the platform status.
525 strm << "Host: " << un.sysname << ' ' << un.release << ' ' << un.version
529 Platform::GetStatus(strm);
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;
541 addr_class = bp_loc_sp->GetAddress().GetAddressClass();
542 if (addr_class == eAddressClassUnknown &&
543 (bp_loc_sp->GetAddress().GetFileAddress() & 1))
544 addr_class = eAddressClassCodeAlternateISA;
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
555 return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site);
559 void PlatformFreeBSD::CalculateTrapHandlerSymbolNames() {
560 m_trap_handlers.push_back(ConstString("_sigtramp"));
563 Error PlatformFreeBSD::LaunchProcess(ProcessLaunchInfo &launch_info) {
566 error = Platform::LaunchProcess(launch_info);
568 if (m_remote_platform_sp)
569 error = m_remote_platform_sp->LaunchProcess(launch_info);
571 error.SetErrorString("the platform is not currently connected");
576 lldb::ProcessSP PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info,
577 Debugger &debugger, Target *target,
579 lldb::ProcessSP process_sp;
581 if (target == NULL) {
582 TargetSP new_target_sp;
583 ArchSpec emptyArchSpec;
585 error = debugger.GetTargetList().CreateTarget(debugger, "", emptyArchSpec,
586 false, m_remote_platform_sp,
588 target = new_target_sp.get();
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);
601 error = process_sp->Attach(attach_info);
604 if (m_remote_platform_sp)
606 m_remote_platform_sp->Attach(attach_info, debugger, target, error);
608 error.SetErrorString("the platform is not currently connected");