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