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 default: 295 llvm_unreachable("Unhandled architecture in PlatformWindows::GetSoftwareBreakpointTrapOpcode()"); 296 break; 297 } 298 299 if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) 300 return trap_opcode_size; 301 302 return 0; 303 } 304 305 bool 306 PlatformWindows::GetRemoteOSVersion () 307 { 308 if (m_remote_platform_sp) 309 return m_remote_platform_sp->GetOSVersion (m_major_os_version, 310 m_minor_os_version, 311 m_update_os_version); 312 return false; 313 } 314 315 bool 316 PlatformWindows::GetRemoteOSBuildString (std::string &s) 317 { 318 if (m_remote_platform_sp) 319 return m_remote_platform_sp->GetRemoteOSBuildString (s); 320 s.clear(); 321 return false; 322 } 323 324 bool 325 PlatformWindows::GetRemoteOSKernelDescription (std::string &s) 326 { 327 if (m_remote_platform_sp) 328 return m_remote_platform_sp->GetRemoteOSKernelDescription (s); 329 s.clear(); 330 return false; 331 } 332 333 // Remote Platform subclasses need to override this function 334 ArchSpec 335 PlatformWindows::GetRemoteSystemArchitecture () 336 { 337 if (m_remote_platform_sp) 338 return m_remote_platform_sp->GetRemoteSystemArchitecture (); 339 return ArchSpec(); 340 } 341 342 const char * 343 PlatformWindows::GetHostname () 344 { 345 if (IsHost()) 346 return Platform::GetHostname(); 347 348 if (m_remote_platform_sp) 349 return m_remote_platform_sp->GetHostname (); 350 return NULL; 351 } 352 353 bool 354 PlatformWindows::IsConnected () const 355 { 356 if (IsHost()) 357 return true; 358 else if (m_remote_platform_sp) 359 return m_remote_platform_sp->IsConnected(); 360 return false; 361 } 362 363 Error 364 PlatformWindows::ConnectRemote (Args& args) 365 { 366 Error error; 367 if (IsHost()) 368 { 369 error.SetErrorStringWithFormat ("can't connect to the host platform '%s', always connected", GetPluginName().AsCString() ); 370 } 371 else 372 { 373 if (!m_remote_platform_sp) 374 m_remote_platform_sp = Platform::Create ("remote-gdb-server", error); 375 376 if (m_remote_platform_sp) 377 { 378 if (error.Success()) 379 { 380 if (m_remote_platform_sp) 381 { 382 error = m_remote_platform_sp->ConnectRemote (args); 383 } 384 else 385 { 386 error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>"); 387 } 388 } 389 } 390 else 391 error.SetErrorString ("failed to create a 'remote-gdb-server' platform"); 392 393 if (error.Fail()) 394 m_remote_platform_sp.reset(); 395 } 396 397 return error; 398 } 399 400 Error 401 PlatformWindows::DisconnectRemote () 402 { 403 Error error; 404 405 if (IsHost()) 406 { 407 error.SetErrorStringWithFormat ("can't disconnect from the host platform '%s', always connected", GetPluginName().AsCString() ); 408 } 409 else 410 { 411 if (m_remote_platform_sp) 412 error = m_remote_platform_sp->DisconnectRemote (); 413 else 414 error.SetErrorString ("the platform is not currently connected"); 415 } 416 return error; 417 } 418 419 bool 420 PlatformWindows::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) 421 { 422 bool success = false; 423 if (IsHost()) 424 { 425 success = Platform::GetProcessInfo (pid, process_info); 426 } 427 else if (m_remote_platform_sp) 428 { 429 success = m_remote_platform_sp->GetProcessInfo (pid, process_info); 430 } 431 return success; 432 } 433 434 uint32_t 435 PlatformWindows::FindProcesses (const ProcessInstanceInfoMatch &match_info, 436 ProcessInstanceInfoList &process_infos) 437 { 438 uint32_t match_count = 0; 439 if (IsHost()) 440 { 441 // Let the base class figure out the host details 442 match_count = Platform::FindProcesses (match_info, process_infos); 443 } 444 else 445 { 446 // If we are remote, we can only return results if we are connected 447 if (m_remote_platform_sp) 448 match_count = m_remote_platform_sp->FindProcesses (match_info, process_infos); 449 } 450 return match_count; 451 } 452 453 Error 454 PlatformWindows::LaunchProcess (ProcessLaunchInfo &launch_info) 455 { 456 Error error; 457 if (IsHost()) 458 { 459 error = Platform::LaunchProcess (launch_info); 460 } 461 else 462 { 463 if (m_remote_platform_sp) 464 error = m_remote_platform_sp->LaunchProcess (launch_info); 465 else 466 error.SetErrorString ("the platform is not currently connected"); 467 } 468 return error; 469 } 470 471 lldb::ProcessSP 472 PlatformWindows::Attach(ProcessAttachInfo &attach_info, 473 Debugger &debugger, 474 Target *target, 475 Listener &listener, 476 Error &error) 477 { 478 lldb::ProcessSP process_sp; 479 if (IsHost()) 480 { 481 if (target == NULL) 482 { 483 TargetSP new_target_sp; 484 FileSpec emptyFileSpec; 485 ArchSpec emptyArchSpec; 486 487 error = debugger.GetTargetList().CreateTarget (debugger, 488 NULL, 489 NULL, 490 false, 491 NULL, 492 new_target_sp); 493 target = new_target_sp.get(); 494 } 495 else 496 error.Clear(); 497 498 if (target && error.Success()) 499 { 500 debugger.GetTargetList().SetSelectedTarget(target); 501 // The Windows platform always currently uses the GDB remote debugger plug-in 502 // so even when debugging locally we are debugging remotely! 503 // Just like the darwin plugin. 504 process_sp = target->CreateProcess (listener, "gdb-remote", NULL); 505 506 if (process_sp) 507 error = process_sp->Attach (attach_info); 508 } 509 } 510 else 511 { 512 if (m_remote_platform_sp) 513 process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, listener, error); 514 else 515 error.SetErrorString ("the platform is not currently connected"); 516 } 517 return process_sp; 518 } 519 520 const char * 521 PlatformWindows::GetUserName (uint32_t uid) 522 { 523 // Check the cache in Platform in case we have already looked this uid up 524 const char *user_name = Platform::GetUserName(uid); 525 if (user_name) 526 return user_name; 527 528 if (IsRemote() && m_remote_platform_sp) 529 return m_remote_platform_sp->GetUserName(uid); 530 return NULL; 531 } 532 533 const char * 534 PlatformWindows::GetGroupName (uint32_t gid) 535 { 536 const char *group_name = Platform::GetGroupName(gid); 537 if (group_name) 538 return group_name; 539 540 if (IsRemote() && m_remote_platform_sp) 541 return m_remote_platform_sp->GetGroupName(gid); 542 return NULL; 543 } 544 545 Error 546 PlatformWindows::GetFileWithUUID (const FileSpec &platform_file, 547 const UUID *uuid_ptr, 548 FileSpec &local_file) 549 { 550 if (IsRemote()) 551 { 552 if (m_remote_platform_sp) 553 return m_remote_platform_sp->GetFileWithUUID (platform_file, uuid_ptr, local_file); 554 } 555 556 // Default to the local case 557 local_file = platform_file; 558 return Error(); 559 } 560 561 Error 562 PlatformWindows::GetSharedModule (const ModuleSpec &module_spec, 563 ModuleSP &module_sp, 564 const FileSpecList *module_search_paths_ptr, 565 ModuleSP *old_module_sp_ptr, 566 bool *did_create_ptr) 567 { 568 Error error; 569 module_sp.reset(); 570 571 if (IsRemote()) 572 { 573 // If we have a remote platform always, let it try and locate 574 // the shared module first. 575 if (m_remote_platform_sp) 576 { 577 error = m_remote_platform_sp->GetSharedModule (module_spec, 578 module_sp, 579 module_search_paths_ptr, 580 old_module_sp_ptr, 581 did_create_ptr); 582 } 583 } 584 585 if (!module_sp) 586 { 587 // Fall back to the local platform and find the file locally 588 error = Platform::GetSharedModule (module_spec, 589 module_sp, 590 module_search_paths_ptr, 591 old_module_sp_ptr, 592 did_create_ptr); 593 } 594 if (module_sp) 595 module_sp->SetPlatformFileSpec(module_spec.GetFileSpec()); 596 return error; 597 } 598 599 bool 600 PlatformWindows::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) 601 { 602 // From macosx;s plugin code. For FreeBSD we may want to support more archs. 603 if (idx == 0) 604 { 605 arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture); 606 return arch.IsValid(); 607 } 608 else if (idx == 1) 609 { 610 ArchSpec platform_arch (Host::GetArchitecture (Host::eSystemDefaultArchitecture)); 611 ArchSpec platform_arch64 (Host::GetArchitecture (Host::eSystemDefaultArchitecture64)); 612 if (platform_arch.IsExactMatch(platform_arch64)) 613 { 614 // This freebsd platform supports both 32 and 64 bit. Since we already 615 // returned the 64 bit arch for idx == 0, return the 32 bit arch 616 // for idx == 1 617 arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture32); 618 return arch.IsValid(); 619 } 620 } 621 return false; 622 } 623 624 void 625 PlatformWindows::GetStatus (Stream &strm) 626 { 627 Platform::GetStatus(strm); 628 629 #ifdef _WIN32 630 OSVERSIONINFO info; 631 632 ZeroMemory(&info, sizeof(OSVERSIONINFO)); 633 info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 634 635 if (GetVersionEx(&info) == 0) 636 { 637 strm << "Windows"; 638 return; 639 } 640 641 strm << "Host: Windows " << (int) info.dwMajorVersion 642 << '.' << (int) info.dwMinorVersion 643 << " Build: " << (int) info.dwBuildNumber << '\n'; 644 #endif 645 } 646