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