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 auto iter = std::find_if( 51 m_archs.begin(), m_archs.end(), 52 [spec](const ArchSpec &rhs) { return spec.IsExactMatch(rhs); }); 53 if (iter != m_archs.end()) 54 return; 55 if (spec.IsValid()) 56 m_archs.push_back(spec); 57 } 58 59 std::vector<ArchSpec> m_archs; 60 }; 61 } // anonymous namespace 62 63 PlatformSP PlatformWindows::CreateInstance(bool force, 64 const lldb_private::ArchSpec *arch) { 65 // The only time we create an instance is when we are creating a remote 66 // windows platform 67 const bool is_host = false; 68 69 bool create = force; 70 if (!create && arch && arch->IsValid()) { 71 const llvm::Triple &triple = arch->GetTriple(); 72 switch (triple.getVendor()) { 73 case llvm::Triple::PC: 74 create = true; 75 break; 76 77 case llvm::Triple::UnknownVendor: 78 create = !arch->TripleVendorWasSpecified(); 79 break; 80 81 default: 82 break; 83 } 84 85 if (create) { 86 switch (triple.getOS()) { 87 case llvm::Triple::Win32: 88 break; 89 90 case llvm::Triple::UnknownOS: 91 create = arch->TripleOSWasSpecified(); 92 break; 93 94 default: 95 create = false; 96 break; 97 } 98 } 99 } 100 if (create) 101 return PlatformSP(new PlatformWindows(is_host)); 102 return PlatformSP(); 103 } 104 105 lldb_private::ConstString PlatformWindows::GetPluginNameStatic(bool is_host) { 106 if (is_host) { 107 static ConstString g_host_name(Platform::GetHostPlatformName()); 108 return g_host_name; 109 } else { 110 static ConstString g_remote_name("remote-windows"); 111 return g_remote_name; 112 } 113 } 114 115 const char *PlatformWindows::GetPluginDescriptionStatic(bool is_host) { 116 return is_host ? "Local Windows user platform plug-in." 117 : "Remote Windows user platform plug-in."; 118 } 119 120 void PlatformWindows::Initialize() { 121 Platform::Initialize(); 122 123 if (g_initialize_count++ == 0) { 124 #if defined(_WIN32) 125 // Force a host flag to true for the default platform object. 126 PlatformSP default_platform_sp(new PlatformWindows(true)); 127 default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); 128 Platform::SetHostPlatform(default_platform_sp); 129 #endif 130 PluginManager::RegisterPlugin( 131 PlatformWindows::GetPluginNameStatic(false), 132 PlatformWindows::GetPluginDescriptionStatic(false), 133 PlatformWindows::CreateInstance); 134 } 135 } 136 137 void PlatformWindows::Terminate() { 138 if (g_initialize_count > 0) { 139 if (--g_initialize_count == 0) { 140 PluginManager::UnregisterPlugin(PlatformWindows::CreateInstance); 141 } 142 } 143 144 Platform::Terminate(); 145 } 146 147 /// Default Constructor 148 PlatformWindows::PlatformWindows(bool is_host) : RemoteAwarePlatform(is_host) {} 149 150 Status PlatformWindows::ConnectRemote(Args &args) { 151 Status error; 152 if (IsHost()) { 153 error.SetErrorStringWithFormatv( 154 "can't connect to the host platform '{0}', always connected", 155 GetPluginName()); 156 } else { 157 if (!m_remote_platform_sp) 158 m_remote_platform_sp = 159 Platform::Create(ConstString("remote-gdb-server"), error); 160 161 if (m_remote_platform_sp) { 162 if (error.Success()) { 163 if (m_remote_platform_sp) { 164 error = m_remote_platform_sp->ConnectRemote(args); 165 } else { 166 error.SetErrorString( 167 "\"platform connect\" takes a single argument: <connect-url>"); 168 } 169 } 170 } else 171 error.SetErrorString("failed to create a 'remote-gdb-server' platform"); 172 173 if (error.Fail()) 174 m_remote_platform_sp.reset(); 175 } 176 177 return error; 178 } 179 180 Status PlatformWindows::DisconnectRemote() { 181 Status error; 182 183 if (IsHost()) { 184 error.SetErrorStringWithFormatv( 185 "can't disconnect from the host platform '{0}', always connected", 186 GetPluginName()); 187 } else { 188 if (m_remote_platform_sp) 189 error = m_remote_platform_sp->DisconnectRemote(); 190 else 191 error.SetErrorString("the platform is not currently connected"); 192 } 193 return error; 194 } 195 196 ProcessSP PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info, 197 Debugger &debugger, Target &target, 198 Status &error) { 199 // Windows has special considerations that must be followed when launching or 200 // attaching to a process. The key requirement is that when launching or 201 // attaching to a process, you must do it from the same the thread that will 202 // go into a permanent loop which will then receive debug events from the 203 // process. In particular, this means we can't use any of LLDB's generic 204 // mechanisms to do it for us, because it doesn't have the special knowledge 205 // required for setting up the background thread or passing the right flags. 206 // 207 // Another problem is that that LLDB's standard model for debugging a process 208 // is to first launch it, have it stop at the entry point, and then attach to 209 // it. In Windows this doesn't quite work, you have to specify as an 210 // argument to CreateProcess() that you're going to debug the process. So we 211 // override DebugProcess here to handle this. Launch operations go directly 212 // to the process plugin, and attach operations almost go directly to the 213 // process plugin (but we hijack the events first). In essence, we 214 // encapsulate all the logic of Launching and Attaching in the process 215 // plugin, and PlatformWindows::DebugProcess is just a pass-through to get to 216 // the process plugin. 217 218 if (IsRemote()) { 219 if (m_remote_platform_sp) 220 return m_remote_platform_sp->DebugProcess(launch_info, debugger, target, 221 error); 222 else 223 error.SetErrorString("the platform is not currently connected"); 224 } 225 226 if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { 227 // This is a process attach. Don't need to launch anything. 228 ProcessAttachInfo attach_info(launch_info); 229 return Attach(attach_info, debugger, &target, error); 230 } else { 231 ProcessSP process_sp = target.CreateProcess( 232 launch_info.GetListener(), launch_info.GetProcessPluginName(), nullptr, 233 false); 234 235 // We need to launch and attach to the process. 236 launch_info.GetFlags().Set(eLaunchFlagDebug); 237 if (process_sp) 238 error = process_sp->Launch(launch_info); 239 240 return process_sp; 241 } 242 } 243 244 lldb::ProcessSP PlatformWindows::Attach(ProcessAttachInfo &attach_info, 245 Debugger &debugger, Target *target, 246 Status &error) { 247 error.Clear(); 248 lldb::ProcessSP process_sp; 249 if (!IsHost()) { 250 if (m_remote_platform_sp) 251 process_sp = 252 m_remote_platform_sp->Attach(attach_info, debugger, target, error); 253 else 254 error.SetErrorString("the platform is not currently connected"); 255 return process_sp; 256 } 257 258 if (target == nullptr) { 259 TargetSP new_target_sp; 260 FileSpec emptyFileSpec; 261 ArchSpec emptyArchSpec; 262 263 error = debugger.GetTargetList().CreateTarget( 264 debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp); 265 target = new_target_sp.get(); 266 } 267 268 if (!target || error.Fail()) 269 return process_sp; 270 271 const char *plugin_name = attach_info.GetProcessPluginName(); 272 process_sp = target->CreateProcess( 273 attach_info.GetListenerForProcess(debugger), plugin_name, nullptr, false); 274 275 process_sp->HijackProcessEvents(attach_info.GetHijackListener()); 276 if (process_sp) 277 error = process_sp->Attach(attach_info); 278 279 return process_sp; 280 } 281 282 bool PlatformWindows::GetSupportedArchitectureAtIndex(uint32_t idx, 283 ArchSpec &arch) { 284 static SupportedArchList architectures; 285 286 if (idx >= architectures.Count()) 287 return false; 288 arch = architectures[idx]; 289 return true; 290 } 291 292 void PlatformWindows::GetStatus(Stream &strm) { 293 Platform::GetStatus(strm); 294 295 #ifdef _WIN32 296 llvm::VersionTuple version = HostInfo::GetOSVersion(); 297 strm << " Host: Windows " << version.getAsString() << '\n'; 298 #endif 299 } 300 301 bool PlatformWindows::CanDebugProcess() { return true; } 302 303 ConstString PlatformWindows::GetFullNameForDylib(ConstString basename) { 304 if (basename.IsEmpty()) 305 return basename; 306 307 StreamString stream; 308 stream.Printf("%s.dll", basename.GetCString()); 309 return ConstString(stream.GetString()); 310 } 311 312 size_t 313 PlatformWindows::GetSoftwareBreakpointTrapOpcode(Target &target, 314 BreakpointSite *bp_site) { 315 ArchSpec arch = target.GetArchitecture(); 316 assert(arch.IsValid()); 317 const uint8_t *trap_opcode = nullptr; 318 size_t trap_opcode_size = 0; 319 320 switch (arch.GetMachine()) { 321 case llvm::Triple::aarch64: { 322 static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, 0xd4}; // brk #0xf000 323 trap_opcode = g_aarch64_opcode; 324 trap_opcode_size = sizeof(g_aarch64_opcode); 325 326 if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) 327 return trap_opcode_size; 328 return 0; 329 } break; 330 331 case llvm::Triple::arm: 332 case llvm::Triple::thumb: { 333 static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe 334 trap_opcode = g_thumb_opcode; 335 trap_opcode_size = sizeof(g_thumb_opcode); 336 337 if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) 338 return trap_opcode_size; 339 return 0; 340 } break; 341 342 default: 343 return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site); 344 } 345 } 346