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