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