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