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 <cstdio> 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/PluginManager.h" 22 #include "lldb/Host/HostInfo.h" 23 #include "lldb/Target/Process.h" 24 #include "lldb/Utility/Status.h" 25 26 using namespace lldb; 27 using namespace lldb_private; 28 29 LLDB_PLUGIN_DEFINE(PlatformWindows) 30 31 static uint32_t g_initialize_count = 0; 32 33 namespace { 34 class SupportedArchList { 35 public: 36 SupportedArchList() { 37 AddArch(ArchSpec("i686-pc-windows")); 38 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKindDefault)); 39 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind32)); 40 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind64)); 41 AddArch(ArchSpec("i386-pc-windows")); 42 } 43 44 size_t Count() const { return m_archs.size(); } 45 46 const ArchSpec &operator[](int idx) { return m_archs[idx]; } 47 48 private: 49 void AddArch(const ArchSpec &spec) { 50 if (llvm::any_of(m_archs, [spec](const ArchSpec &rhs) { 51 return spec.IsExactMatch(rhs); 52 })) 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 void PlatformWindows::Initialize() { 120 Platform::Initialize(); 121 122 if (g_initialize_count++ == 0) { 123 #if defined(_WIN32) 124 // Force a host flag to true for the default platform object. 125 PlatformSP default_platform_sp(new PlatformWindows(true)); 126 default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); 127 Platform::SetHostPlatform(default_platform_sp); 128 #endif 129 PluginManager::RegisterPlugin( 130 PlatformWindows::GetPluginNameStatic(false), 131 PlatformWindows::GetPluginDescriptionStatic(false), 132 PlatformWindows::CreateInstance); 133 } 134 } 135 136 void PlatformWindows::Terminate() { 137 if (g_initialize_count > 0) { 138 if (--g_initialize_count == 0) { 139 PluginManager::UnregisterPlugin(PlatformWindows::CreateInstance); 140 } 141 } 142 143 Platform::Terminate(); 144 } 145 146 /// Default Constructor 147 PlatformWindows::PlatformWindows(bool is_host) : RemoteAwarePlatform(is_host) {} 148 149 Status PlatformWindows::ConnectRemote(Args &args) { 150 Status error; 151 if (IsHost()) { 152 error.SetErrorStringWithFormatv( 153 "can't connect to the host platform '{0}', always connected", 154 GetPluginName()); 155 } else { 156 if (!m_remote_platform_sp) 157 m_remote_platform_sp = 158 Platform::Create(ConstString("remote-gdb-server"), error); 159 160 if (m_remote_platform_sp) { 161 if (error.Success()) { 162 if (m_remote_platform_sp) { 163 error = m_remote_platform_sp->ConnectRemote(args); 164 } else { 165 error.SetErrorString( 166 "\"platform connect\" takes a single argument: <connect-url>"); 167 } 168 } 169 } else 170 error.SetErrorString("failed to create a 'remote-gdb-server' platform"); 171 172 if (error.Fail()) 173 m_remote_platform_sp.reset(); 174 } 175 176 return error; 177 } 178 179 Status PlatformWindows::DisconnectRemote() { 180 Status error; 181 182 if (IsHost()) { 183 error.SetErrorStringWithFormatv( 184 "can't disconnect from the host platform '{0}', always connected", 185 GetPluginName()); 186 } else { 187 if (m_remote_platform_sp) 188 error = m_remote_platform_sp->DisconnectRemote(); 189 else 190 error.SetErrorString("the platform is not currently connected"); 191 } 192 return error; 193 } 194 195 ProcessSP PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info, 196 Debugger &debugger, Target &target, 197 Status &error) { 198 // Windows has special considerations that must be followed when launching or 199 // attaching to a process. The key requirement is that when launching or 200 // attaching to a process, you must do it from the same the thread that will 201 // go into a permanent loop which will then receive debug events from the 202 // process. In particular, this means we can't use any of LLDB's generic 203 // mechanisms to do it for us, because it doesn't have the special knowledge 204 // required for setting up the background thread or passing the right flags. 205 // 206 // Another problem is that that LLDB's standard model for debugging a process 207 // is to first launch it, have it stop at the entry point, and then attach to 208 // it. In Windows this doesn't quite work, you have to specify as an 209 // argument to CreateProcess() that you're going to debug the process. So we 210 // override DebugProcess here to handle this. Launch operations go directly 211 // to the process plugin, and attach operations almost go directly to the 212 // process plugin (but we hijack the events first). In essence, we 213 // encapsulate all the logic of Launching and Attaching in the process 214 // plugin, and PlatformWindows::DebugProcess is just a pass-through to get to 215 // the process plugin. 216 217 if (IsRemote()) { 218 if (m_remote_platform_sp) 219 return m_remote_platform_sp->DebugProcess(launch_info, debugger, target, 220 error); 221 else 222 error.SetErrorString("the platform is not currently connected"); 223 } 224 225 if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { 226 // This is a process attach. Don't need to launch anything. 227 ProcessAttachInfo attach_info(launch_info); 228 return Attach(attach_info, debugger, &target, error); 229 } else { 230 ProcessSP process_sp = target.CreateProcess( 231 launch_info.GetListener(), launch_info.GetProcessPluginName(), nullptr, 232 false); 233 234 // We need to launch and attach to the process. 235 launch_info.GetFlags().Set(eLaunchFlagDebug); 236 if (process_sp) 237 error = process_sp->Launch(launch_info); 238 239 return process_sp; 240 } 241 } 242 243 lldb::ProcessSP PlatformWindows::Attach(ProcessAttachInfo &attach_info, 244 Debugger &debugger, Target *target, 245 Status &error) { 246 error.Clear(); 247 lldb::ProcessSP process_sp; 248 if (!IsHost()) { 249 if (m_remote_platform_sp) 250 process_sp = 251 m_remote_platform_sp->Attach(attach_info, debugger, target, error); 252 else 253 error.SetErrorString("the platform is not currently connected"); 254 return process_sp; 255 } 256 257 if (target == nullptr) { 258 TargetSP new_target_sp; 259 FileSpec emptyFileSpec; 260 ArchSpec emptyArchSpec; 261 262 error = debugger.GetTargetList().CreateTarget( 263 debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp); 264 target = new_target_sp.get(); 265 } 266 267 if (!target || error.Fail()) 268 return process_sp; 269 270 const char *plugin_name = attach_info.GetProcessPluginName(); 271 process_sp = target->CreateProcess( 272 attach_info.GetListenerForProcess(debugger), plugin_name, nullptr, false); 273 274 process_sp->HijackProcessEvents(attach_info.GetHijackListener()); 275 if (process_sp) 276 error = process_sp->Attach(attach_info); 277 278 return process_sp; 279 } 280 281 bool PlatformWindows::GetSupportedArchitectureAtIndex(uint32_t idx, 282 ArchSpec &arch) { 283 static SupportedArchList architectures; 284 285 if (idx >= architectures.Count()) 286 return false; 287 arch = architectures[idx]; 288 return true; 289 } 290 291 void PlatformWindows::GetStatus(Stream &strm) { 292 Platform::GetStatus(strm); 293 294 #ifdef _WIN32 295 llvm::VersionTuple version = HostInfo::GetOSVersion(); 296 strm << " Host: Windows " << version.getAsString() << '\n'; 297 #endif 298 } 299 300 bool PlatformWindows::CanDebugProcess() { return true; } 301 302 ConstString PlatformWindows::GetFullNameForDylib(ConstString basename) { 303 if (basename.IsEmpty()) 304 return basename; 305 306 StreamString stream; 307 stream.Printf("%s.dll", basename.GetCString()); 308 return ConstString(stream.GetString()); 309 } 310 311 size_t 312 PlatformWindows::GetSoftwareBreakpointTrapOpcode(Target &target, 313 BreakpointSite *bp_site) { 314 ArchSpec arch = target.GetArchitecture(); 315 assert(arch.IsValid()); 316 const uint8_t *trap_opcode = nullptr; 317 size_t trap_opcode_size = 0; 318 319 switch (arch.GetMachine()) { 320 case llvm::Triple::aarch64: { 321 static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, 0xd4}; // brk #0xf000 322 trap_opcode = g_aarch64_opcode; 323 trap_opcode_size = sizeof(g_aarch64_opcode); 324 325 if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) 326 return trap_opcode_size; 327 return 0; 328 } break; 329 330 case llvm::Triple::arm: 331 case llvm::Triple::thumb: { 332 static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe 333 trap_opcode = g_thumb_opcode; 334 trap_opcode_size = sizeof(g_thumb_opcode); 335 336 if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) 337 return trap_opcode_size; 338 return 0; 339 } break; 340 341 default: 342 return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site); 343 } 344 } 345