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