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) : RemoteAwarePlatform(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 Status PlatformWindows::ResolveExecutable( 169 const ModuleSpec &ms, lldb::ModuleSP &exe_module_sp, 170 const FileSpecList *module_search_paths_ptr) { 171 Status error; 172 // Nothing special to do here, just use the actual file and architecture 173 174 char exe_path[PATH_MAX]; 175 ModuleSpec resolved_module_spec(ms); 176 177 if (IsHost()) { 178 // if we cant resolve the executable loation based on the current path 179 // variables 180 if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) { 181 resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path)); 182 resolved_module_spec.GetFileSpec().SetFile(exe_path, 183 FileSpec::Style::native); 184 FileSystem::Instance().Resolve(resolved_module_spec.GetFileSpec()); 185 } 186 187 if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) 188 FileSystem::Instance().ResolveExecutableLocation( 189 resolved_module_spec.GetFileSpec()); 190 191 if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) 192 error.Clear(); 193 else { 194 ms.GetFileSpec().GetPath(exe_path, sizeof(exe_path)); 195 error.SetErrorStringWithFormat("unable to find executable for '%s'", 196 exe_path); 197 } 198 } else { 199 if (m_remote_platform_sp) { 200 error = 201 GetCachedExecutable(resolved_module_spec, exe_module_sp, 202 module_search_paths_ptr, *m_remote_platform_sp); 203 } else { 204 // We may connect to a process and use the provided executable (Don't use 205 // local $PATH). 206 if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) 207 error.Clear(); 208 else 209 error.SetErrorStringWithFormat("the platform is not currently " 210 "connected, and '%s' doesn't exist in " 211 "the system root.", 212 exe_path); 213 } 214 } 215 216 if (error.Success()) { 217 if (resolved_module_spec.GetArchitecture().IsValid()) { 218 error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, 219 nullptr, nullptr, nullptr); 220 221 if (!exe_module_sp || exe_module_sp->GetObjectFile() == nullptr) { 222 exe_module_sp.reset(); 223 error.SetErrorStringWithFormat( 224 "'%s' doesn't contain the architecture %s", 225 resolved_module_spec.GetFileSpec().GetPath().c_str(), 226 resolved_module_spec.GetArchitecture().GetArchitectureName()); 227 } 228 } else { 229 // No valid architecture was specified, ask the platform for the 230 // architectures that we should be using (in the correct order) and see 231 // if we can find a match that way 232 StreamString arch_names; 233 for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( 234 idx, resolved_module_spec.GetArchitecture()); 235 ++idx) { 236 error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, 237 module_search_paths_ptr, nullptr, 238 nullptr); 239 // Did we find an executable using one of the 240 if (error.Success()) { 241 if (exe_module_sp && exe_module_sp->GetObjectFile()) 242 break; 243 else 244 error.SetErrorToGenericError(); 245 } 246 247 if (idx > 0) 248 arch_names.PutCString(", "); 249 arch_names.PutCString( 250 resolved_module_spec.GetArchitecture().GetArchitectureName()); 251 } 252 253 if (error.Fail() || !exe_module_sp) { 254 if (FileSystem::Instance().Readable( 255 resolved_module_spec.GetFileSpec())) { 256 error.SetErrorStringWithFormat( 257 "'%s' doesn't contain any '%s' platform architectures: %s", 258 resolved_module_spec.GetFileSpec().GetPath().c_str(), 259 GetPluginName().GetCString(), arch_names.GetData()); 260 } else { 261 error.SetErrorStringWithFormat( 262 "'%s' is not readable", 263 resolved_module_spec.GetFileSpec().GetPath().c_str()); 264 } 265 } 266 } 267 } 268 269 return error; 270 } 271 272 Status PlatformWindows::ConnectRemote(Args &args) { 273 Status error; 274 if (IsHost()) { 275 error.SetErrorStringWithFormat( 276 "can't connect to the host platform '%s', always connected", 277 GetPluginName().AsCString()); 278 } else { 279 if (!m_remote_platform_sp) 280 m_remote_platform_sp = 281 Platform::Create(ConstString("remote-gdb-server"), error); 282 283 if (m_remote_platform_sp) { 284 if (error.Success()) { 285 if (m_remote_platform_sp) { 286 error = m_remote_platform_sp->ConnectRemote(args); 287 } else { 288 error.SetErrorString( 289 "\"platform connect\" takes a single argument: <connect-url>"); 290 } 291 } 292 } else 293 error.SetErrorString("failed to create a 'remote-gdb-server' platform"); 294 295 if (error.Fail()) 296 m_remote_platform_sp.reset(); 297 } 298 299 return error; 300 } 301 302 Status PlatformWindows::DisconnectRemote() { 303 Status error; 304 305 if (IsHost()) { 306 error.SetErrorStringWithFormat( 307 "can't disconnect from the host platform '%s', always connected", 308 GetPluginName().AsCString()); 309 } else { 310 if (m_remote_platform_sp) 311 error = m_remote_platform_sp->DisconnectRemote(); 312 else 313 error.SetErrorString("the platform is not currently connected"); 314 } 315 return error; 316 } 317 318 ProcessSP PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info, 319 Debugger &debugger, Target *target, 320 Status &error) { 321 // Windows has special considerations that must be followed when launching or 322 // attaching to a process. The key requirement is that when launching or 323 // attaching to a process, you must do it from the same the thread that will 324 // go into a permanent loop which will then receive debug events from the 325 // process. In particular, this means we can't use any of LLDB's generic 326 // mechanisms to do it for us, because it doesn't have the special knowledge 327 // required for setting up the background thread or passing the right flags. 328 // 329 // Another problem is that that LLDB's standard model for debugging a process 330 // is to first launch it, have it stop at the entry point, and then attach to 331 // it. In Windows this doesn't quite work, you have to specify as an 332 // argument to CreateProcess() that you're going to debug the process. So we 333 // override DebugProcess here to handle this. Launch operations go directly 334 // to the process plugin, and attach operations almost go directly to the 335 // process plugin (but we hijack the events first). In essence, we 336 // encapsulate all the logic of Launching and Attaching in the process 337 // plugin, and PlatformWindows::DebugProcess is just a pass-through to get to 338 // the process plugin. 339 340 if (IsRemote()) { 341 if (m_remote_platform_sp) 342 return m_remote_platform_sp->DebugProcess(launch_info, debugger, target, 343 error); 344 else 345 error.SetErrorString("the platform is not currently connected"); 346 } 347 348 if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { 349 // This is a process attach. Don't need to launch anything. 350 ProcessAttachInfo attach_info(launch_info); 351 return Attach(attach_info, debugger, target, error); 352 } else { 353 ProcessSP process_sp = target->CreateProcess( 354 launch_info.GetListener(), launch_info.GetProcessPluginName(), nullptr); 355 356 // We need to launch and attach to the process. 357 launch_info.GetFlags().Set(eLaunchFlagDebug); 358 if (process_sp) 359 error = process_sp->Launch(launch_info); 360 361 return process_sp; 362 } 363 } 364 365 lldb::ProcessSP PlatformWindows::Attach(ProcessAttachInfo &attach_info, 366 Debugger &debugger, Target *target, 367 Status &error) { 368 error.Clear(); 369 lldb::ProcessSP process_sp; 370 if (!IsHost()) { 371 if (m_remote_platform_sp) 372 process_sp = 373 m_remote_platform_sp->Attach(attach_info, debugger, target, error); 374 else 375 error.SetErrorString("the platform is not currently connected"); 376 return process_sp; 377 } 378 379 if (target == nullptr) { 380 TargetSP new_target_sp; 381 FileSpec emptyFileSpec; 382 ArchSpec emptyArchSpec; 383 384 error = debugger.GetTargetList().CreateTarget( 385 debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp); 386 target = new_target_sp.get(); 387 } 388 389 if (!target || error.Fail()) 390 return process_sp; 391 392 debugger.GetTargetList().SetSelectedTarget(target); 393 394 const char *plugin_name = attach_info.GetProcessPluginName(); 395 process_sp = target->CreateProcess( 396 attach_info.GetListenerForProcess(debugger), plugin_name, nullptr); 397 398 process_sp->HijackProcessEvents(attach_info.GetHijackListener()); 399 if (process_sp) 400 error = process_sp->Attach(attach_info); 401 402 return process_sp; 403 } 404 405 bool PlatformWindows::GetSupportedArchitectureAtIndex(uint32_t idx, 406 ArchSpec &arch) { 407 static SupportedArchList architectures; 408 409 if (idx >= architectures.Count()) 410 return false; 411 arch = architectures[idx]; 412 return true; 413 } 414 415 void PlatformWindows::GetStatus(Stream &strm) { 416 Platform::GetStatus(strm); 417 418 #ifdef _WIN32 419 llvm::VersionTuple version = HostInfo::GetOSVersion(); 420 strm << " Host: Windows " << version.getAsString() << '\n'; 421 #endif 422 } 423 424 bool PlatformWindows::CanDebugProcess() { return true; } 425 426 ConstString PlatformWindows::GetFullNameForDylib(ConstString basename) { 427 if (basename.IsEmpty()) 428 return basename; 429 430 StreamString stream; 431 stream.Printf("%s.dll", basename.GetCString()); 432 return ConstString(stream.GetString()); 433 } 434