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