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 const char * 89 PlatformFreeBSD::GetPluginNameStatic() 90 { 91 return "plugin.platform.freebsd"; 92 } 93 94 const char * 95 PlatformFreeBSD::GetShortPluginNameStatic (bool is_host) 96 { 97 if (is_host) 98 return Platform::GetHostPlatformName (); 99 else 100 return "remote-freebsd"; 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::GetShortPluginNameStatic(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 loation 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 // Resolve any executable within a bundle on MacOSX 183 //Host::ResolveExecutableInBundle (resolved_exe_file); 184 185 if (resolved_exe_file.Exists()) 186 error.Clear(); 187 else 188 { 189 exe_file.GetPath(exe_path, sizeof(exe_path)); 190 error.SetErrorStringWithFormat("unable to find executable for '%s'", exe_path); 191 } 192 } 193 else 194 { 195 if (m_remote_platform_sp) 196 { 197 error = m_remote_platform_sp->ResolveExecutable (exe_file, 198 exe_arch, 199 exe_module_sp, 200 module_search_paths_ptr); 201 } 202 else 203 { 204 // We may connect to a process and use the provided executable (Don't use local $PATH). 205 206 // Resolve any executable within a bundle on MacOSX 207 Host::ResolveExecutableInBundle (resolved_exe_file); 208 209 if (resolved_exe_file.Exists()) { 210 error.Clear(); 211 } 212 else 213 { 214 exe_file.GetPath(exe_path, sizeof(exe_path)); 215 error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", exe_path); 216 } 217 } 218 } 219 220 221 if (error.Success()) 222 { 223 ModuleSpec module_spec (resolved_exe_file, exe_arch); 224 if (module_spec.GetArchitecture().IsValid()) 225 { 226 error = ModuleList::GetSharedModule (module_spec, 227 exe_module_sp, 228 module_search_paths_ptr, 229 NULL, 230 NULL); 231 232 if (!exe_module_sp || exe_module_sp->GetObjectFile() == NULL) 233 { 234 exe_module_sp.reset(); 235 error.SetErrorStringWithFormat ("'%s%s%s' doesn't contain the architecture %s", 236 exe_file.GetDirectory().AsCString(""), 237 exe_file.GetDirectory() ? "/" : "", 238 exe_file.GetFilename().AsCString(""), 239 exe_arch.GetArchitectureName()); 240 } 241 } 242 else 243 { 244 // No valid architecture was specified, ask the platform for 245 // the architectures that we should be using (in the correct order) 246 // and see if we can find a match that way 247 StreamString arch_names; 248 ArchSpec platform_arch; 249 for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, platform_arch); ++idx) 250 { 251 error = ModuleList::GetSharedModule (module_spec, 252 exe_module_sp, 253 module_search_paths_ptr, 254 NULL, 255 NULL); 256 // Did we find an executable using one of the 257 if (error.Success()) 258 { 259 if (exe_module_sp && exe_module_sp->GetObjectFile()) 260 break; 261 else 262 error.SetErrorToGenericError(); 263 } 264 265 if (idx > 0) 266 arch_names.PutCString (", "); 267 arch_names.PutCString (platform_arch.GetArchitectureName()); 268 } 269 270 if (error.Fail() || !exe_module_sp) 271 { 272 error.SetErrorStringWithFormat ("'%s%s%s' doesn't contain any '%s' platform architectures: %s", 273 exe_file.GetDirectory().AsCString(""), 274 exe_file.GetDirectory() ? "/" : "", 275 exe_file.GetFilename().AsCString(""), 276 GetShortPluginName(), 277 arch_names.GetString().c_str()); 278 } 279 } 280 } 281 else 282 { 283 error.SetErrorStringWithFormat ("'%s%s%s' does not exist", 284 exe_file.GetDirectory().AsCString(""), 285 exe_file.GetDirectory() ? "/" : "", 286 exe_file.GetFilename().AsCString("")); 287 } 288 289 return error; 290 } 291 292 size_t 293 PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site) 294 { 295 ArchSpec arch = target.GetArchitecture(); 296 const uint8_t *trap_opcode = NULL; 297 size_t trap_opcode_size = 0; 298 299 switch (arch.GetCore()) 300 { 301 default: 302 assert(false && "Unhandled architecture in PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode()"); 303 break; 304 305 case ArchSpec::eCore_x86_32_i386: 306 case ArchSpec::eCore_x86_64_x86_64: 307 { 308 static const uint8_t g_i386_opcode[] = { 0xCC }; 309 trap_opcode = g_i386_opcode; 310 trap_opcode_size = sizeof(g_i386_opcode); 311 } 312 break; 313 } 314 315 if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) 316 return trap_opcode_size; 317 318 return 0; 319 } 320 321 bool 322 PlatformFreeBSD::GetRemoteOSVersion () 323 { 324 if (m_remote_platform_sp) 325 return m_remote_platform_sp->GetOSVersion (m_major_os_version, 326 m_minor_os_version, 327 m_update_os_version); 328 return false; 329 } 330 331 bool 332 PlatformFreeBSD::GetRemoteOSBuildString (std::string &s) 333 { 334 if (m_remote_platform_sp) 335 return m_remote_platform_sp->GetRemoteOSBuildString (s); 336 s.clear(); 337 return false; 338 } 339 340 bool 341 PlatformFreeBSD::GetRemoteOSKernelDescription (std::string &s) 342 { 343 if (m_remote_platform_sp) 344 return m_remote_platform_sp->GetRemoteOSKernelDescription (s); 345 s.clear(); 346 return false; 347 } 348 349 // Remote Platform subclasses need to override this function 350 ArchSpec 351 PlatformFreeBSD::GetRemoteSystemArchitecture () 352 { 353 if (m_remote_platform_sp) 354 return m_remote_platform_sp->GetRemoteSystemArchitecture (); 355 return ArchSpec(); 356 } 357 358 359 const char * 360 PlatformFreeBSD::GetHostname () 361 { 362 if (IsHost()) 363 return Platform::GetHostname(); 364 365 if (m_remote_platform_sp) 366 return m_remote_platform_sp->GetHostname (); 367 return NULL; 368 } 369 370 bool 371 PlatformFreeBSD::IsConnected () const 372 { 373 if (IsHost()) 374 return true; 375 else if (m_remote_platform_sp) 376 return m_remote_platform_sp->IsConnected(); 377 return false; 378 } 379 380 Error 381 PlatformFreeBSD::ConnectRemote (Args& args) 382 { 383 Error error; 384 if (IsHost()) 385 { 386 error.SetErrorStringWithFormat ("can't connect to the host platform '%s', always connected", GetShortPluginName()); 387 } 388 else 389 { 390 if (!m_remote_platform_sp) 391 m_remote_platform_sp = Platform::Create ("remote-gdb-server", error); 392 393 if (m_remote_platform_sp) 394 { 395 if (error.Success()) 396 { 397 if (m_remote_platform_sp) 398 { 399 error = m_remote_platform_sp->ConnectRemote (args); 400 } 401 else 402 { 403 error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>"); 404 } 405 } 406 } 407 else 408 error.SetErrorString ("failed to create a 'remote-gdb-server' platform"); 409 410 if (error.Fail()) 411 m_remote_platform_sp.reset(); 412 } 413 414 return error; 415 } 416 417 Error 418 PlatformFreeBSD::DisconnectRemote () 419 { 420 Error error; 421 422 if (IsHost()) 423 { 424 error.SetErrorStringWithFormat ("can't disconnect from the host platform '%s', always connected", GetShortPluginName()); 425 } 426 else 427 { 428 if (m_remote_platform_sp) 429 error = m_remote_platform_sp->DisconnectRemote (); 430 else 431 error.SetErrorString ("the platform is not currently connected"); 432 } 433 return error; 434 } 435 436 bool 437 PlatformFreeBSD::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) 438 { 439 bool success = false; 440 if (IsHost()) 441 { 442 success = Platform::GetProcessInfo (pid, process_info); 443 } 444 else if (m_remote_platform_sp) 445 { 446 success = m_remote_platform_sp->GetProcessInfo (pid, process_info); 447 } 448 return success; 449 } 450 451 452 453 uint32_t 454 PlatformFreeBSD::FindProcesses (const ProcessInstanceInfoMatch &match_info, 455 ProcessInstanceInfoList &process_infos) 456 { 457 uint32_t match_count = 0; 458 if (IsHost()) 459 { 460 // Let the base class figure out the host details 461 match_count = Platform::FindProcesses (match_info, process_infos); 462 } 463 else 464 { 465 // If we are remote, we can only return results if we are connected 466 if (m_remote_platform_sp) 467 match_count = m_remote_platform_sp->FindProcesses (match_info, process_infos); 468 } 469 return match_count; 470 } 471 472 Error 473 PlatformFreeBSD::LaunchProcess (ProcessLaunchInfo &launch_info) 474 { 475 Error error; 476 if (IsHost()) 477 { 478 error = Platform::LaunchProcess (launch_info); 479 } 480 else 481 { 482 if (m_remote_platform_sp) 483 error = m_remote_platform_sp->LaunchProcess (launch_info); 484 else 485 error.SetErrorString ("the platform is not currently connected"); 486 } 487 return error; 488 } 489 490 lldb::ProcessSP 491 PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info, 492 Debugger &debugger, 493 Target *target, 494 Listener &listener, 495 Error &error) 496 { 497 lldb::ProcessSP process_sp; 498 if (IsHost()) 499 { 500 if (target == NULL) 501 { 502 TargetSP new_target_sp; 503 ArchSpec emptyArchSpec; 504 505 error = debugger.GetTargetList().CreateTarget (debugger, 506 NULL, 507 emptyArchSpec, 508 false, 509 m_remote_platform_sp, 510 new_target_sp); 511 target = new_target_sp.get(); 512 } 513 else 514 error.Clear(); 515 516 if (target && error.Success()) 517 { 518 debugger.GetTargetList().SetSelectedTarget(target); 519 // The freebsd always currently uses the GDB remote debugger plug-in 520 // so even when debugging locally we are debugging remotely! 521 // Just like the darwin plugin. 522 process_sp = target->CreateProcess (listener, "gdb-remote", NULL); 523 524 if (process_sp) 525 error = process_sp->Attach (attach_info); 526 } 527 } 528 else 529 { 530 if (m_remote_platform_sp) 531 process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, listener, error); 532 else 533 error.SetErrorString ("the platform is not currently connected"); 534 } 535 return process_sp; 536 } 537 538 const char * 539 PlatformFreeBSD::GetUserName (uint32_t uid) 540 { 541 // Check the cache in Platform in case we have already looked this uid up 542 const char *user_name = Platform::GetUserName(uid); 543 if (user_name) 544 return user_name; 545 546 if (IsRemote() && m_remote_platform_sp) 547 return m_remote_platform_sp->GetUserName(uid); 548 return NULL; 549 } 550 551 const char * 552 PlatformFreeBSD::GetGroupName (uint32_t gid) 553 { 554 const char *group_name = Platform::GetGroupName(gid); 555 if (group_name) 556 return group_name; 557 558 if (IsRemote() && m_remote_platform_sp) 559 return m_remote_platform_sp->GetGroupName(gid); 560 return NULL; 561 } 562 563 564 // From PlatformMacOSX only 565 Error 566 PlatformFreeBSD::GetFile (const FileSpec &platform_file, 567 const UUID *uuid_ptr, 568 FileSpec &local_file) 569 { 570 if (IsRemote()) 571 { 572 if (m_remote_platform_sp) 573 return m_remote_platform_sp->GetFile (platform_file, uuid_ptr, local_file); 574 } 575 576 // Default to the local case 577 local_file = platform_file; 578 return Error(); 579 } 580 581 Error 582 PlatformFreeBSD::GetSharedModule (const ModuleSpec &module_spec, 583 ModuleSP &module_sp, 584 const FileSpecList *module_search_paths_ptr, 585 ModuleSP *old_module_sp_ptr, 586 bool *did_create_ptr) 587 { 588 Error error; 589 module_sp.reset(); 590 591 if (IsRemote()) 592 { 593 // If we have a remote platform always, let it try and locate 594 // the shared module first. 595 if (m_remote_platform_sp) 596 { 597 error = m_remote_platform_sp->GetSharedModule (module_spec, 598 module_sp, 599 module_search_paths_ptr, 600 old_module_sp_ptr, 601 did_create_ptr); 602 } 603 } 604 605 if (!module_sp) 606 { 607 // Fall back to the local platform and find the file locally 608 error = Platform::GetSharedModule (module_spec, 609 module_sp, 610 module_search_paths_ptr, 611 old_module_sp_ptr, 612 did_create_ptr); 613 } 614 if (module_sp) 615 module_sp->SetPlatformFileSpec(module_spec.GetFileSpec()); 616 return error; 617 } 618 619 620 bool 621 PlatformFreeBSD::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) 622 { 623 // From macosx;s plugin code. For FreeBSD we may want to support more archs. 624 if (idx == 0) 625 { 626 arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture); 627 return arch.IsValid(); 628 } 629 else if (idx == 1) 630 { 631 ArchSpec platform_arch (Host::GetArchitecture (Host::eSystemDefaultArchitecture)); 632 ArchSpec platform_arch64 (Host::GetArchitecture (Host::eSystemDefaultArchitecture64)); 633 if (platform_arch.IsExactMatch(platform_arch64)) 634 { 635 // This freebsd platform supports both 32 and 64 bit. Since we already 636 // returned the 64 bit arch for idx == 0, return the 32 bit arch 637 // for idx == 1 638 arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture32); 639 return arch.IsValid(); 640 } 641 } 642 return false; 643 } 644 645 void 646 PlatformFreeBSD::GetStatus (Stream &strm) 647 { 648 struct utsname un; 649 650 if (uname(&un)) { 651 strm << "FreeBSD"; 652 return; 653 } 654 655 strm << "Host: " << un.sysname << ' ' << un.release << ' ' << un.version << '\n'; 656 Platform::GetStatus(strm); 657 } 658