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/Breakpoint/BreakpointLocation.h" 23 #include "lldb/Breakpoint/BreakpointSite.h" 24 #include "lldb/Core/Debugger.h" 25 #include "lldb/Core/Module.h" 26 #include "lldb/Core/ModuleSpec.h" 27 #include "lldb/Core/PluginManager.h" 28 #include "lldb/Host/HostInfo.h" 29 #include "lldb/Target/Process.h" 30 #include "lldb/Utility/Status.h" 31 32 using namespace lldb; 33 using namespace lldb_private; 34 35 static uint32_t g_initialize_count = 0; 36 37 namespace { 38 class SupportedArchList { 39 public: 40 SupportedArchList() { 41 AddArch(ArchSpec("i686-pc-windows")); 42 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKindDefault)); 43 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind32)); 44 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind64)); 45 AddArch(ArchSpec("i386-pc-windows")); 46 } 47 48 size_t Count() const { return m_archs.size(); } 49 50 const ArchSpec &operator[](int idx) { return m_archs[idx]; } 51 52 private: 53 void AddArch(const ArchSpec &spec) { 54 auto iter = std::find_if( 55 m_archs.begin(), m_archs.end(), 56 [spec](const ArchSpec &rhs) { return spec.IsExactMatch(rhs); }); 57 if (iter != m_archs.end()) 58 return; 59 if (spec.IsValid()) 60 m_archs.push_back(spec); 61 } 62 63 std::vector<ArchSpec> m_archs; 64 }; 65 } // anonymous namespace 66 67 PlatformSP PlatformWindows::CreateInstance(bool force, 68 const lldb_private::ArchSpec *arch) { 69 // The only time we create an instance is when we are creating a remote 70 // windows platform 71 const bool is_host = false; 72 73 bool create = force; 74 if (create == false && arch && arch->IsValid()) { 75 const llvm::Triple &triple = arch->GetTriple(); 76 switch (triple.getVendor()) { 77 case llvm::Triple::PC: 78 create = true; 79 break; 80 81 case llvm::Triple::UnknownArch: 82 create = !arch->TripleVendorWasSpecified(); 83 break; 84 85 default: 86 break; 87 } 88 89 if (create) { 90 switch (triple.getOS()) { 91 case llvm::Triple::Win32: 92 break; 93 94 case llvm::Triple::UnknownOS: 95 create = arch->TripleOSWasSpecified(); 96 break; 97 98 default: 99 create = false; 100 break; 101 } 102 } 103 } 104 if (create) 105 return PlatformSP(new PlatformWindows(is_host)); 106 return PlatformSP(); 107 } 108 109 lldb_private::ConstString PlatformWindows::GetPluginNameStatic(bool is_host) { 110 if (is_host) { 111 static ConstString g_host_name(Platform::GetHostPlatformName()); 112 return g_host_name; 113 } else { 114 static ConstString g_remote_name("remote-windows"); 115 return g_remote_name; 116 } 117 } 118 119 const char *PlatformWindows::GetPluginDescriptionStatic(bool is_host) { 120 return is_host ? "Local Windows user platform plug-in." 121 : "Remote Windows user platform plug-in."; 122 } 123 124 lldb_private::ConstString PlatformWindows::GetPluginName() { 125 return GetPluginNameStatic(IsHost()); 126 } 127 128 void PlatformWindows::Initialize() { 129 Platform::Initialize(); 130 131 if (g_initialize_count++ == 0) { 132 #if defined(_WIN32) 133 WSADATA dummy; 134 WSAStartup(MAKEWORD(2, 2), &dummy); 135 // Force a host flag to true for the default platform object. 136 PlatformSP default_platform_sp(new PlatformWindows(true)); 137 default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); 138 Platform::SetHostPlatform(default_platform_sp); 139 #endif 140 PluginManager::RegisterPlugin( 141 PlatformWindows::GetPluginNameStatic(false), 142 PlatformWindows::GetPluginDescriptionStatic(false), 143 PlatformWindows::CreateInstance); 144 } 145 } 146 147 void PlatformWindows::Terminate(void) { 148 if (g_initialize_count > 0) { 149 if (--g_initialize_count == 0) { 150 #ifdef _WIN32 151 WSACleanup(); 152 #endif 153 PluginManager::UnregisterPlugin(PlatformWindows::CreateInstance); 154 } 155 } 156 157 Platform::Terminate(); 158 } 159 160 //------------------------------------------------------------------ 161 /// Default Constructor 162 //------------------------------------------------------------------ 163 PlatformWindows::PlatformWindows(bool is_host) : Platform(is_host) {} 164 165 //------------------------------------------------------------------ 166 /// Destructor. 167 /// 168 /// The destructor is virtual since this class is designed to be 169 /// inherited from by the plug-in instance. 170 //------------------------------------------------------------------ 171 PlatformWindows::~PlatformWindows() = default; 172 173 bool PlatformWindows::GetModuleSpec(const FileSpec &module_file_spec, 174 const ArchSpec &arch, 175 ModuleSpec &module_spec) { 176 if (m_remote_platform_sp) 177 return m_remote_platform_sp->GetModuleSpec(module_file_spec, arch, 178 module_spec); 179 180 return Platform::GetModuleSpec(module_file_spec, arch, module_spec); 181 } 182 183 Status PlatformWindows::ResolveExecutable( 184 const ModuleSpec &ms, lldb::ModuleSP &exe_module_sp, 185 const FileSpecList *module_search_paths_ptr) { 186 Status error; 187 // Nothing special to do here, just use the actual file and architecture 188 189 char exe_path[PATH_MAX]; 190 ModuleSpec resolved_module_spec(ms); 191 192 if (IsHost()) { 193 // if we cant resolve the executable loation based on the current path 194 // variables 195 if (!resolved_module_spec.GetFileSpec().Exists()) { 196 resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path)); 197 resolved_module_spec.GetFileSpec().SetFile(exe_path, true, 198 FileSpec::Style::native); 199 } 200 201 if (!resolved_module_spec.GetFileSpec().Exists()) 202 resolved_module_spec.GetFileSpec().ResolveExecutableLocation(); 203 204 if (resolved_module_spec.GetFileSpec().Exists()) 205 error.Clear(); 206 else { 207 ms.GetFileSpec().GetPath(exe_path, sizeof(exe_path)); 208 error.SetErrorStringWithFormat("unable to find executable for '%s'", 209 exe_path); 210 } 211 } else { 212 if (m_remote_platform_sp) { 213 error = GetCachedExecutable(resolved_module_spec, exe_module_sp, nullptr, 214 *m_remote_platform_sp); 215 } else { 216 // We may connect to a process and use the provided executable (Don't use 217 // local $PATH). 218 if (resolved_module_spec.GetFileSpec().Exists()) 219 error.Clear(); 220 else 221 error.SetErrorStringWithFormat("the platform is not currently " 222 "connected, and '%s' doesn't exist in " 223 "the system root.", 224 exe_path); 225 } 226 } 227 228 if (error.Success()) { 229 if (resolved_module_spec.GetArchitecture().IsValid()) { 230 error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, 231 nullptr, nullptr, nullptr); 232 233 if (!exe_module_sp || exe_module_sp->GetObjectFile() == nullptr) { 234 exe_module_sp.reset(); 235 error.SetErrorStringWithFormat( 236 "'%s' doesn't contain the architecture %s", 237 resolved_module_spec.GetFileSpec().GetPath().c_str(), 238 resolved_module_spec.GetArchitecture().GetArchitectureName()); 239 } 240 } else { 241 // No valid architecture was specified, ask the platform for the 242 // architectures that we should be using (in the correct order) and see 243 // if we can find a match that way 244 StreamString arch_names; 245 for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( 246 idx, resolved_module_spec.GetArchitecture()); 247 ++idx) { 248 error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, 249 nullptr, nullptr, nullptr); 250 // Did we find an executable using one of the 251 if (error.Success()) { 252 if (exe_module_sp && exe_module_sp->GetObjectFile()) 253 break; 254 else 255 error.SetErrorToGenericError(); 256 } 257 258 if (idx > 0) 259 arch_names.PutCString(", "); 260 arch_names.PutCString( 261 resolved_module_spec.GetArchitecture().GetArchitectureName()); 262 } 263 264 if (error.Fail() || !exe_module_sp) { 265 if (resolved_module_spec.GetFileSpec().Readable()) { 266 error.SetErrorStringWithFormat( 267 "'%s' doesn't contain any '%s' platform architectures: %s", 268 resolved_module_spec.GetFileSpec().GetPath().c_str(), 269 GetPluginName().GetCString(), arch_names.GetData()); 270 } else { 271 error.SetErrorStringWithFormat( 272 "'%s' is not readable", 273 resolved_module_spec.GetFileSpec().GetPath().c_str()); 274 } 275 } 276 } 277 } 278 279 return error; 280 } 281 282 bool PlatformWindows::GetRemoteOSVersion() { 283 if (m_remote_platform_sp) 284 return m_remote_platform_sp->GetOSVersion( 285 m_major_os_version, m_minor_os_version, m_update_os_version); 286 return false; 287 } 288 289 bool PlatformWindows::GetRemoteOSBuildString(std::string &s) { 290 if (m_remote_platform_sp) 291 return m_remote_platform_sp->GetRemoteOSBuildString(s); 292 s.clear(); 293 return false; 294 } 295 296 bool PlatformWindows::GetRemoteOSKernelDescription(std::string &s) { 297 if (m_remote_platform_sp) 298 return m_remote_platform_sp->GetRemoteOSKernelDescription(s); 299 s.clear(); 300 return false; 301 } 302 303 // Remote Platform subclasses need to override this function 304 ArchSpec PlatformWindows::GetRemoteSystemArchitecture() { 305 if (m_remote_platform_sp) 306 return m_remote_platform_sp->GetRemoteSystemArchitecture(); 307 return ArchSpec(); 308 } 309 310 const char *PlatformWindows::GetHostname() { 311 if (IsHost()) 312 return Platform::GetHostname(); 313 314 if (m_remote_platform_sp) 315 return m_remote_platform_sp->GetHostname(); 316 return nullptr; 317 } 318 319 bool PlatformWindows::IsConnected() const { 320 if (IsHost()) 321 return true; 322 else if (m_remote_platform_sp) 323 return m_remote_platform_sp->IsConnected(); 324 return false; 325 } 326 327 Status PlatformWindows::ConnectRemote(Args &args) { 328 Status error; 329 if (IsHost()) { 330 error.SetErrorStringWithFormat( 331 "can't connect to the host platform '%s', always connected", 332 GetPluginName().AsCString()); 333 } else { 334 if (!m_remote_platform_sp) 335 m_remote_platform_sp = 336 Platform::Create(ConstString("remote-gdb-server"), error); 337 338 if (m_remote_platform_sp) { 339 if (error.Success()) { 340 if (m_remote_platform_sp) { 341 error = m_remote_platform_sp->ConnectRemote(args); 342 } else { 343 error.SetErrorString( 344 "\"platform connect\" takes a single argument: <connect-url>"); 345 } 346 } 347 } else 348 error.SetErrorString("failed to create a 'remote-gdb-server' platform"); 349 350 if (error.Fail()) 351 m_remote_platform_sp.reset(); 352 } 353 354 return error; 355 } 356 357 Status PlatformWindows::DisconnectRemote() { 358 Status error; 359 360 if (IsHost()) { 361 error.SetErrorStringWithFormat( 362 "can't disconnect from the host platform '%s', always connected", 363 GetPluginName().AsCString()); 364 } else { 365 if (m_remote_platform_sp) 366 error = m_remote_platform_sp->DisconnectRemote(); 367 else 368 error.SetErrorString("the platform is not currently connected"); 369 } 370 return error; 371 } 372 373 bool PlatformWindows::GetProcessInfo(lldb::pid_t pid, 374 ProcessInstanceInfo &process_info) { 375 bool success = false; 376 if (IsHost()) { 377 success = Platform::GetProcessInfo(pid, process_info); 378 } else if (m_remote_platform_sp) { 379 success = m_remote_platform_sp->GetProcessInfo(pid, process_info); 380 } 381 return success; 382 } 383 384 uint32_t 385 PlatformWindows::FindProcesses(const ProcessInstanceInfoMatch &match_info, 386 ProcessInstanceInfoList &process_infos) { 387 uint32_t match_count = 0; 388 if (IsHost()) { 389 // Let the base class figure out the host details 390 match_count = Platform::FindProcesses(match_info, process_infos); 391 } else { 392 // If we are remote, we can only return results if we are connected 393 if (m_remote_platform_sp) 394 match_count = 395 m_remote_platform_sp->FindProcesses(match_info, process_infos); 396 } 397 return match_count; 398 } 399 400 Status PlatformWindows::LaunchProcess(ProcessLaunchInfo &launch_info) { 401 Status error; 402 if (IsHost()) { 403 error = Platform::LaunchProcess(launch_info); 404 } else { 405 if (m_remote_platform_sp) 406 error = m_remote_platform_sp->LaunchProcess(launch_info); 407 else 408 error.SetErrorString("the platform is not currently connected"); 409 } 410 return error; 411 } 412 413 ProcessSP PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info, 414 Debugger &debugger, Target *target, 415 Status &error) { 416 // Windows has special considerations that must be followed when launching or 417 // attaching to a process. The key requirement is that when launching or 418 // attaching to a process, you must do it from the same the thread that will 419 // go into a permanent loop which will then receive debug events from the 420 // process. In particular, this means we can't use any of LLDB's generic 421 // mechanisms to do it for us, because it doesn't have the special knowledge 422 // required for setting up the background thread or passing the right flags. 423 // 424 // Another problem is that that LLDB's standard model for debugging a process 425 // is to first launch it, have it stop at the entry point, and then attach to 426 // it. In Windows this doesn't quite work, you have to specify as an 427 // argument to CreateProcess() that you're going to debug the process. So we 428 // override DebugProcess here to handle this. Launch operations go directly 429 // to the process plugin, and attach operations almost go directly to the 430 // process plugin (but we hijack the events first). In essence, we 431 // encapsulate all the logic of Launching and Attaching in the process 432 // plugin, and PlatformWindows::DebugProcess is just a pass-through to get to 433 // the process plugin. 434 435 if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { 436 // This is a process attach. Don't need to launch anything. 437 ProcessAttachInfo attach_info(launch_info); 438 return Attach(attach_info, debugger, target, error); 439 } else { 440 ProcessSP process_sp = 441 target->CreateProcess(launch_info.GetListenerForProcess(debugger), 442 launch_info.GetProcessPluginName(), nullptr); 443 444 // We need to launch and attach to the process. 445 launch_info.GetFlags().Set(eLaunchFlagDebug); 446 if (process_sp) 447 error = process_sp->Launch(launch_info); 448 449 return process_sp; 450 } 451 } 452 453 lldb::ProcessSP PlatformWindows::Attach(ProcessAttachInfo &attach_info, 454 Debugger &debugger, Target *target, 455 Status &error) { 456 error.Clear(); 457 lldb::ProcessSP process_sp; 458 if (!IsHost()) { 459 if (m_remote_platform_sp) 460 process_sp = 461 m_remote_platform_sp->Attach(attach_info, debugger, target, error); 462 else 463 error.SetErrorString("the platform is not currently connected"); 464 return process_sp; 465 } 466 467 if (target == nullptr) { 468 TargetSP new_target_sp; 469 FileSpec emptyFileSpec; 470 ArchSpec emptyArchSpec; 471 472 error = debugger.GetTargetList().CreateTarget(debugger, "", "", false, 473 nullptr, new_target_sp); 474 target = new_target_sp.get(); 475 } 476 477 if (!target || error.Fail()) 478 return process_sp; 479 480 debugger.GetTargetList().SetSelectedTarget(target); 481 482 const char *plugin_name = attach_info.GetProcessPluginName(); 483 process_sp = target->CreateProcess( 484 attach_info.GetListenerForProcess(debugger), plugin_name, nullptr); 485 486 process_sp->HijackProcessEvents(attach_info.GetHijackListener()); 487 if (process_sp) 488 error = process_sp->Attach(attach_info); 489 490 return process_sp; 491 } 492 493 const char *PlatformWindows::GetUserName(uint32_t uid) { 494 // Check the cache in Platform in case we have already looked this uid up 495 const char *user_name = Platform::GetUserName(uid); 496 if (user_name) 497 return user_name; 498 499 if (IsRemote() && m_remote_platform_sp) 500 return m_remote_platform_sp->GetUserName(uid); 501 return nullptr; 502 } 503 504 const char *PlatformWindows::GetGroupName(uint32_t gid) { 505 const char *group_name = Platform::GetGroupName(gid); 506 if (group_name) 507 return group_name; 508 509 if (IsRemote() && m_remote_platform_sp) 510 return m_remote_platform_sp->GetGroupName(gid); 511 return nullptr; 512 } 513 514 Status PlatformWindows::GetFileWithUUID(const FileSpec &platform_file, 515 const UUID *uuid_ptr, 516 FileSpec &local_file) { 517 if (IsRemote()) { 518 if (m_remote_platform_sp) 519 return m_remote_platform_sp->GetFileWithUUID(platform_file, uuid_ptr, 520 local_file); 521 } 522 523 // Default to the local case 524 local_file = platform_file; 525 return Status(); 526 } 527 528 Status PlatformWindows::GetSharedModule( 529 const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, 530 const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr, 531 bool *did_create_ptr) { 532 Status error; 533 module_sp.reset(); 534 535 if (IsRemote()) { 536 // If we have a remote platform always, let it try and locate the shared 537 // module first. 538 if (m_remote_platform_sp) { 539 error = m_remote_platform_sp->GetSharedModule( 540 module_spec, process, module_sp, module_search_paths_ptr, 541 old_module_sp_ptr, did_create_ptr); 542 } 543 } 544 545 if (!module_sp) { 546 // Fall back to the local platform and find the file locally 547 error = Platform::GetSharedModule(module_spec, process, module_sp, 548 module_search_paths_ptr, 549 old_module_sp_ptr, did_create_ptr); 550 } 551 if (module_sp) 552 module_sp->SetPlatformFileSpec(module_spec.GetFileSpec()); 553 return error; 554 } 555 556 bool PlatformWindows::GetSupportedArchitectureAtIndex(uint32_t idx, 557 ArchSpec &arch) { 558 static SupportedArchList architectures; 559 560 if (idx >= architectures.Count()) 561 return false; 562 arch = architectures[idx]; 563 return true; 564 } 565 566 void PlatformWindows::GetStatus(Stream &strm) { 567 Platform::GetStatus(strm); 568 569 #ifdef _WIN32 570 uint32_t major; 571 uint32_t minor; 572 uint32_t update; 573 if (!HostInfo::GetOSVersion(major, minor, update)) { 574 strm << "Windows"; 575 return; 576 } 577 578 strm << "Host: Windows " << major << '.' << minor << " Build: " << update 579 << '\n'; 580 #endif 581 } 582 583 bool PlatformWindows::CanDebugProcess() { return true; } 584 585 Environment PlatformWindows::GetEnvironment() { 586 if (IsRemote()) { 587 if (m_remote_platform_sp) 588 return m_remote_platform_sp->GetEnvironment(); 589 return Environment(); 590 } 591 592 return Host::GetEnvironment(); 593 } 594 595 ConstString PlatformWindows::GetFullNameForDylib(ConstString basename) { 596 if (basename.IsEmpty()) 597 return basename; 598 599 StreamString stream; 600 stream.Printf("%s.dll", basename.GetCString()); 601 return ConstString(stream.GetString()); 602 } 603