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