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