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 } 684