1 //===-- PlatformWindows.cpp -----------------------------------------------===// 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 LLDB_PLUGIN_DEFINE(PlatformWindows) 31 32 static uint32_t g_initialize_count = 0; 33 34 namespace { 35 class SupportedArchList { 36 public: 37 SupportedArchList() { 38 AddArch(ArchSpec("i686-pc-windows")); 39 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKindDefault)); 40 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind32)); 41 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind64)); 42 AddArch(ArchSpec("i386-pc-windows")); 43 } 44 45 size_t Count() const { return m_archs.size(); } 46 47 const ArchSpec &operator[](int idx) { return m_archs[idx]; } 48 49 private: 50 void AddArch(const ArchSpec &spec) { 51 auto iter = std::find_if( 52 m_archs.begin(), m_archs.end(), 53 [spec](const ArchSpec &rhs) { return spec.IsExactMatch(rhs); }); 54 if (iter != m_archs.end()) 55 return; 56 if (spec.IsValid()) 57 m_archs.push_back(spec); 58 } 59 60 std::vector<ArchSpec> m_archs; 61 }; 62 } // anonymous namespace 63 64 PlatformSP PlatformWindows::CreateInstance(bool force, 65 const lldb_private::ArchSpec *arch) { 66 // The only time we create an instance is when we are creating a remote 67 // windows platform 68 const bool is_host = false; 69 70 bool create = force; 71 if (!create && arch && arch->IsValid()) { 72 const llvm::Triple &triple = arch->GetTriple(); 73 switch (triple.getVendor()) { 74 case llvm::Triple::PC: 75 create = true; 76 break; 77 78 case llvm::Triple::UnknownVendor: 79 create = !arch->TripleVendorWasSpecified(); 80 break; 81 82 default: 83 break; 84 } 85 86 if (create) { 87 switch (triple.getOS()) { 88 case llvm::Triple::Win32: 89 break; 90 91 case llvm::Triple::UnknownOS: 92 create = arch->TripleOSWasSpecified(); 93 break; 94 95 default: 96 create = false; 97 break; 98 } 99 } 100 } 101 if (create) 102 return PlatformSP(new PlatformWindows(is_host)); 103 return PlatformSP(); 104 } 105 106 lldb_private::ConstString PlatformWindows::GetPluginNameStatic(bool is_host) { 107 if (is_host) { 108 static ConstString g_host_name(Platform::GetHostPlatformName()); 109 return g_host_name; 110 } else { 111 static ConstString g_remote_name("remote-windows"); 112 return g_remote_name; 113 } 114 } 115 116 const char *PlatformWindows::GetPluginDescriptionStatic(bool is_host) { 117 return is_host ? "Local Windows user platform plug-in." 118 : "Remote Windows user platform plug-in."; 119 } 120 121 lldb_private::ConstString PlatformWindows::GetPluginName() { 122 return GetPluginNameStatic(IsHost()); 123 } 124 125 void PlatformWindows::Initialize() { 126 Platform::Initialize(); 127 128 if (g_initialize_count++ == 0) { 129 #if defined(_WIN32) 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() { 143 if (g_initialize_count > 0) { 144 if (--g_initialize_count == 0) { 145 PluginManager::UnregisterPlugin(PlatformWindows::CreateInstance); 146 } 147 } 148 149 Platform::Terminate(); 150 } 151 152 /// Default Constructor 153 PlatformWindows::PlatformWindows(bool is_host) : RemoteAwarePlatform(is_host) {} 154 155 /// Destructor. 156 /// 157 /// The destructor is virtual since this class is designed to be 158 /// inherited from by the plug-in instance. 159 PlatformWindows::~PlatformWindows() = default; 160 161 Status PlatformWindows::ResolveExecutable( 162 const ModuleSpec &ms, lldb::ModuleSP &exe_module_sp, 163 const FileSpecList *module_search_paths_ptr) { 164 Status error; 165 // Nothing special to do here, just use the actual file and architecture 166 167 char exe_path[PATH_MAX]; 168 ModuleSpec resolved_module_spec(ms); 169 170 if (IsHost()) { 171 // if we cant resolve the executable loation based on the current path 172 // variables 173 if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) { 174 resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path)); 175 resolved_module_spec.GetFileSpec().SetFile(exe_path, 176 FileSpec::Style::native); 177 FileSystem::Instance().Resolve(resolved_module_spec.GetFileSpec()); 178 } 179 180 if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) 181 FileSystem::Instance().ResolveExecutableLocation( 182 resolved_module_spec.GetFileSpec()); 183 184 if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) 185 error.Clear(); 186 else { 187 ms.GetFileSpec().GetPath(exe_path, sizeof(exe_path)); 188 error.SetErrorStringWithFormat("unable to find executable for '%s'", 189 exe_path); 190 } 191 } else { 192 if (m_remote_platform_sp) { 193 error = 194 GetCachedExecutable(resolved_module_spec, exe_module_sp, 195 module_search_paths_ptr, *m_remote_platform_sp); 196 } else { 197 // We may connect to a process and use the provided executable (Don't use 198 // local $PATH). 199 if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) 200 error.Clear(); 201 else 202 error.SetErrorStringWithFormat("the platform is not currently " 203 "connected, and '%s' doesn't exist in " 204 "the system root.", 205 exe_path); 206 } 207 } 208 209 if (error.Success()) { 210 if (resolved_module_spec.GetArchitecture().IsValid()) { 211 error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, 212 nullptr, nullptr, nullptr); 213 214 if (!exe_module_sp || exe_module_sp->GetObjectFile() == nullptr) { 215 exe_module_sp.reset(); 216 error.SetErrorStringWithFormat( 217 "'%s' doesn't contain the architecture %s", 218 resolved_module_spec.GetFileSpec().GetPath().c_str(), 219 resolved_module_spec.GetArchitecture().GetArchitectureName()); 220 } 221 } else { 222 // No valid architecture was specified, ask the platform for the 223 // architectures that we should be using (in the correct order) and see 224 // if we can find a match that way 225 StreamString arch_names; 226 for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( 227 idx, resolved_module_spec.GetArchitecture()); 228 ++idx) { 229 error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, 230 module_search_paths_ptr, nullptr, 231 nullptr); 232 // Did we find an executable using one of the 233 if (error.Success()) { 234 if (exe_module_sp && exe_module_sp->GetObjectFile()) 235 break; 236 else 237 error.SetErrorToGenericError(); 238 } 239 240 if (idx > 0) 241 arch_names.PutCString(", "); 242 arch_names.PutCString( 243 resolved_module_spec.GetArchitecture().GetArchitectureName()); 244 } 245 246 if (error.Fail() || !exe_module_sp) { 247 if (FileSystem::Instance().Readable( 248 resolved_module_spec.GetFileSpec())) { 249 error.SetErrorStringWithFormat( 250 "'%s' doesn't contain any '%s' platform architectures: %s", 251 resolved_module_spec.GetFileSpec().GetPath().c_str(), 252 GetPluginName().GetCString(), arch_names.GetData()); 253 } else { 254 error.SetErrorStringWithFormat( 255 "'%s' is not readable", 256 resolved_module_spec.GetFileSpec().GetPath().c_str()); 257 } 258 } 259 } 260 } 261 262 return error; 263 } 264 265 Status PlatformWindows::ConnectRemote(Args &args) { 266 Status error; 267 if (IsHost()) { 268 error.SetErrorStringWithFormat( 269 "can't connect to the host platform '%s', always connected", 270 GetPluginName().AsCString()); 271 } else { 272 if (!m_remote_platform_sp) 273 m_remote_platform_sp = 274 Platform::Create(ConstString("remote-gdb-server"), error); 275 276 if (m_remote_platform_sp) { 277 if (error.Success()) { 278 if (m_remote_platform_sp) { 279 error = m_remote_platform_sp->ConnectRemote(args); 280 } else { 281 error.SetErrorString( 282 "\"platform connect\" takes a single argument: <connect-url>"); 283 } 284 } 285 } else 286 error.SetErrorString("failed to create a 'remote-gdb-server' platform"); 287 288 if (error.Fail()) 289 m_remote_platform_sp.reset(); 290 } 291 292 return error; 293 } 294 295 Status PlatformWindows::DisconnectRemote() { 296 Status error; 297 298 if (IsHost()) { 299 error.SetErrorStringWithFormat( 300 "can't disconnect from the host platform '%s', always connected", 301 GetPluginName().AsCString()); 302 } else { 303 if (m_remote_platform_sp) 304 error = m_remote_platform_sp->DisconnectRemote(); 305 else 306 error.SetErrorString("the platform is not currently connected"); 307 } 308 return error; 309 } 310 311 ProcessSP PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info, 312 Debugger &debugger, Target *target, 313 Status &error) { 314 // Windows has special considerations that must be followed when launching or 315 // attaching to a process. The key requirement is that when launching or 316 // attaching to a process, you must do it from the same the thread that will 317 // go into a permanent loop which will then receive debug events from the 318 // process. In particular, this means we can't use any of LLDB's generic 319 // mechanisms to do it for us, because it doesn't have the special knowledge 320 // required for setting up the background thread or passing the right flags. 321 // 322 // Another problem is that that LLDB's standard model for debugging a process 323 // is to first launch it, have it stop at the entry point, and then attach to 324 // it. In Windows this doesn't quite work, you have to specify as an 325 // argument to CreateProcess() that you're going to debug the process. So we 326 // override DebugProcess here to handle this. Launch operations go directly 327 // to the process plugin, and attach operations almost go directly to the 328 // process plugin (but we hijack the events first). In essence, we 329 // encapsulate all the logic of Launching and Attaching in the process 330 // plugin, and PlatformWindows::DebugProcess is just a pass-through to get to 331 // the process plugin. 332 333 if (IsRemote()) { 334 if (m_remote_platform_sp) 335 return m_remote_platform_sp->DebugProcess(launch_info, debugger, target, 336 error); 337 else 338 error.SetErrorString("the platform is not currently connected"); 339 } 340 341 if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { 342 // This is a process attach. Don't need to launch anything. 343 ProcessAttachInfo attach_info(launch_info); 344 return Attach(attach_info, debugger, target, error); 345 } else { 346 ProcessSP process_sp = target->CreateProcess( 347 launch_info.GetListener(), launch_info.GetProcessPluginName(), nullptr); 348 349 // We need to launch and attach to the process. 350 launch_info.GetFlags().Set(eLaunchFlagDebug); 351 if (process_sp) 352 error = process_sp->Launch(launch_info); 353 354 return process_sp; 355 } 356 } 357 358 lldb::ProcessSP PlatformWindows::Attach(ProcessAttachInfo &attach_info, 359 Debugger &debugger, Target *target, 360 Status &error) { 361 error.Clear(); 362 lldb::ProcessSP process_sp; 363 if (!IsHost()) { 364 if (m_remote_platform_sp) 365 process_sp = 366 m_remote_platform_sp->Attach(attach_info, debugger, target, error); 367 else 368 error.SetErrorString("the platform is not currently connected"); 369 return process_sp; 370 } 371 372 if (target == nullptr) { 373 TargetSP new_target_sp; 374 FileSpec emptyFileSpec; 375 ArchSpec emptyArchSpec; 376 377 error = debugger.GetTargetList().CreateTarget( 378 debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp); 379 target = new_target_sp.get(); 380 } 381 382 if (!target || error.Fail()) 383 return process_sp; 384 385 debugger.GetTargetList().SetSelectedTarget(target); 386 387 const char *plugin_name = attach_info.GetProcessPluginName(); 388 process_sp = target->CreateProcess( 389 attach_info.GetListenerForProcess(debugger), plugin_name, nullptr); 390 391 process_sp->HijackProcessEvents(attach_info.GetHijackListener()); 392 if (process_sp) 393 error = process_sp->Attach(attach_info); 394 395 return process_sp; 396 } 397 398 bool PlatformWindows::GetSupportedArchitectureAtIndex(uint32_t idx, 399 ArchSpec &arch) { 400 static SupportedArchList architectures; 401 402 if (idx >= architectures.Count()) 403 return false; 404 arch = architectures[idx]; 405 return true; 406 } 407 408 void PlatformWindows::GetStatus(Stream &strm) { 409 Platform::GetStatus(strm); 410 411 #ifdef _WIN32 412 llvm::VersionTuple version = HostInfo::GetOSVersion(); 413 strm << " Host: Windows " << version.getAsString() << '\n'; 414 #endif 415 } 416 417 bool PlatformWindows::CanDebugProcess() { return true; } 418 419 ConstString PlatformWindows::GetFullNameForDylib(ConstString basename) { 420 if (basename.IsEmpty()) 421 return basename; 422 423 StreamString stream; 424 stream.Printf("%s.dll", basename.GetCString()); 425 return ConstString(stream.GetString()); 426 } 427