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