1 //===-- PlatformWindows.cpp -------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "PlatformWindows.h"
15 #include "lldb/Host/windows/windows.h"
20 // Other libraries and framework includes
22 #include "lldb/Breakpoint/BreakpointLocation.h"
23 #include "lldb/Breakpoint/BreakpointSite.h"
24 #include "lldb/Core/Debugger.h"
25 #include "lldb/Core/Error.h"
26 #include "lldb/Core/Module.h"
27 #include "lldb/Core/ModuleSpec.h"
28 #include "lldb/Core/PluginManager.h"
29 #include "lldb/Host/HostInfo.h"
30 #include "lldb/Target/Process.h"
33 using namespace lldb_private;
35 static uint32_t g_initialize_count = 0;
38 class SupportedArchList {
41 AddArch(ArchSpec("i686-pc-windows"));
42 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKindDefault));
43 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind32));
44 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind64));
45 AddArch(ArchSpec("i386-pc-windows"));
48 size_t Count() const { return m_archs.size(); }
50 const ArchSpec &operator[](int idx) { return m_archs[idx]; }
53 void AddArch(const ArchSpec &spec) {
54 auto iter = std::find_if(
55 m_archs.begin(), m_archs.end(),
56 [spec](const ArchSpec &rhs) { return spec.IsExactMatch(rhs); });
57 if (iter != m_archs.end())
60 m_archs.push_back(spec);
63 std::vector<ArchSpec> m_archs;
65 } // anonymous namespace
67 PlatformSP PlatformWindows::CreateInstance(bool force,
68 const lldb_private::ArchSpec *arch) {
69 // The only time we create an instance is when we are creating a remote
71 const bool is_host = false;
74 if (create == false && arch && arch->IsValid()) {
75 const llvm::Triple &triple = arch->GetTriple();
76 switch (triple.getVendor()) {
77 case llvm::Triple::PC:
81 case llvm::Triple::UnknownArch:
82 create = !arch->TripleVendorWasSpecified();
90 switch (triple.getOS()) {
91 case llvm::Triple::Win32:
94 case llvm::Triple::UnknownOS:
95 create = arch->TripleOSWasSpecified();
105 return PlatformSP(new PlatformWindows(is_host));
109 lldb_private::ConstString PlatformWindows::GetPluginNameStatic(bool is_host) {
111 static ConstString g_host_name(Platform::GetHostPlatformName());
114 static ConstString g_remote_name("remote-windows");
115 return g_remote_name;
119 const char *PlatformWindows::GetPluginDescriptionStatic(bool is_host) {
120 return is_host ? "Local Windows user platform plug-in."
121 : "Remote Windows user platform plug-in.";
124 lldb_private::ConstString PlatformWindows::GetPluginName() {
125 return GetPluginNameStatic(IsHost());
128 void PlatformWindows::Initialize() {
129 Platform::Initialize();
131 if (g_initialize_count++ == 0) {
134 WSAStartup(MAKEWORD(2, 2), &dummy);
135 // Force a host flag to true for the default platform object.
136 PlatformSP default_platform_sp(new PlatformWindows(true));
137 default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
138 Platform::SetHostPlatform(default_platform_sp);
140 PluginManager::RegisterPlugin(
141 PlatformWindows::GetPluginNameStatic(false),
142 PlatformWindows::GetPluginDescriptionStatic(false),
143 PlatformWindows::CreateInstance);
147 void PlatformWindows::Terminate(void) {
148 if (g_initialize_count > 0) {
149 if (--g_initialize_count == 0) {
153 PluginManager::UnregisterPlugin(PlatformWindows::CreateInstance);
157 Platform::Terminate();
160 //------------------------------------------------------------------
161 /// Default Constructor
162 //------------------------------------------------------------------
163 PlatformWindows::PlatformWindows(bool is_host) : Platform(is_host) {}
165 //------------------------------------------------------------------
168 /// The destructor is virtual since this class is designed to be
169 /// inherited from by the plug-in instance.
170 //------------------------------------------------------------------
171 PlatformWindows::~PlatformWindows() = default;
173 bool PlatformWindows::GetModuleSpec(const FileSpec &module_file_spec,
174 const ArchSpec &arch,
175 ModuleSpec &module_spec) {
176 if (m_remote_platform_sp)
177 return m_remote_platform_sp->GetModuleSpec(module_file_spec, arch,
180 return Platform::GetModuleSpec(module_file_spec, arch, module_spec);
183 Error PlatformWindows::ResolveExecutable(
184 const ModuleSpec &ms, lldb::ModuleSP &exe_module_sp,
185 const FileSpecList *module_search_paths_ptr) {
187 // Nothing special to do here, just use the actual file and architecture
189 char exe_path[PATH_MAX];
190 ModuleSpec resolved_module_spec(ms);
193 // if we cant resolve the executable loation based on the current path
195 if (!resolved_module_spec.GetFileSpec().Exists()) {
196 resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path));
197 resolved_module_spec.GetFileSpec().SetFile(exe_path, true);
200 if (!resolved_module_spec.GetFileSpec().Exists())
201 resolved_module_spec.GetFileSpec().ResolveExecutableLocation();
203 if (resolved_module_spec.GetFileSpec().Exists())
206 ms.GetFileSpec().GetPath(exe_path, sizeof(exe_path));
207 error.SetErrorStringWithFormat("unable to find executable for '%s'",
211 if (m_remote_platform_sp) {
212 error = GetCachedExecutable(resolved_module_spec, exe_module_sp, nullptr,
213 *m_remote_platform_sp);
215 // We may connect to a process and use the provided executable (Don't use
217 if (resolved_module_spec.GetFileSpec().Exists())
220 error.SetErrorStringWithFormat("the platform is not currently "
221 "connected, and '%s' doesn't exist in "
227 if (error.Success()) {
228 if (resolved_module_spec.GetArchitecture().IsValid()) {
229 error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
230 nullptr, nullptr, nullptr);
232 if (!exe_module_sp || exe_module_sp->GetObjectFile() == nullptr) {
233 exe_module_sp.reset();
234 error.SetErrorStringWithFormat(
235 "'%s' doesn't contain the architecture %s",
236 resolved_module_spec.GetFileSpec().GetPath().c_str(),
237 resolved_module_spec.GetArchitecture().GetArchitectureName());
240 // No valid architecture was specified, ask the platform for
241 // the architectures that we should be using (in the correct order)
242 // and see if we can find a match that way
243 StreamString arch_names;
244 for (uint32_t idx = 0; GetSupportedArchitectureAtIndex(
245 idx, resolved_module_spec.GetArchitecture());
247 error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
248 nullptr, nullptr, nullptr);
249 // Did we find an executable using one of the
250 if (error.Success()) {
251 if (exe_module_sp && exe_module_sp->GetObjectFile())
254 error.SetErrorToGenericError();
258 arch_names.PutCString(", ");
259 arch_names.PutCString(
260 resolved_module_spec.GetArchitecture().GetArchitectureName());
263 if (error.Fail() || !exe_module_sp) {
264 if (resolved_module_spec.GetFileSpec().Readable()) {
265 error.SetErrorStringWithFormat(
266 "'%s' doesn't contain any '%s' platform architectures: %s",
267 resolved_module_spec.GetFileSpec().GetPath().c_str(),
268 GetPluginName().GetCString(), arch_names.GetData());
270 error.SetErrorStringWithFormat(
271 "'%s' is not readable",
272 resolved_module_spec.GetFileSpec().GetPath().c_str());
281 bool PlatformWindows::GetRemoteOSVersion() {
282 if (m_remote_platform_sp)
283 return m_remote_platform_sp->GetOSVersion(
284 m_major_os_version, m_minor_os_version, m_update_os_version);
288 bool PlatformWindows::GetRemoteOSBuildString(std::string &s) {
289 if (m_remote_platform_sp)
290 return m_remote_platform_sp->GetRemoteOSBuildString(s);
295 bool PlatformWindows::GetRemoteOSKernelDescription(std::string &s) {
296 if (m_remote_platform_sp)
297 return m_remote_platform_sp->GetRemoteOSKernelDescription(s);
302 // Remote Platform subclasses need to override this function
303 ArchSpec PlatformWindows::GetRemoteSystemArchitecture() {
304 if (m_remote_platform_sp)
305 return m_remote_platform_sp->GetRemoteSystemArchitecture();
309 const char *PlatformWindows::GetHostname() {
311 return Platform::GetHostname();
313 if (m_remote_platform_sp)
314 return m_remote_platform_sp->GetHostname();
318 bool PlatformWindows::IsConnected() const {
321 else if (m_remote_platform_sp)
322 return m_remote_platform_sp->IsConnected();
326 Error PlatformWindows::ConnectRemote(Args &args) {
329 error.SetErrorStringWithFormat(
330 "can't connect to the host platform '%s', always connected",
331 GetPluginName().AsCString());
333 if (!m_remote_platform_sp)
334 m_remote_platform_sp =
335 Platform::Create(ConstString("remote-gdb-server"), error);
337 if (m_remote_platform_sp) {
338 if (error.Success()) {
339 if (m_remote_platform_sp) {
340 error = m_remote_platform_sp->ConnectRemote(args);
342 error.SetErrorString(
343 "\"platform connect\" takes a single argument: <connect-url>");
347 error.SetErrorString("failed to create a 'remote-gdb-server' platform");
350 m_remote_platform_sp.reset();
356 Error PlatformWindows::DisconnectRemote() {
360 error.SetErrorStringWithFormat(
361 "can't disconnect from the host platform '%s', always connected",
362 GetPluginName().AsCString());
364 if (m_remote_platform_sp)
365 error = m_remote_platform_sp->DisconnectRemote();
367 error.SetErrorString("the platform is not currently connected");
372 bool PlatformWindows::GetProcessInfo(lldb::pid_t pid,
373 ProcessInstanceInfo &process_info) {
374 bool success = false;
376 success = Platform::GetProcessInfo(pid, process_info);
377 } else if (m_remote_platform_sp) {
378 success = m_remote_platform_sp->GetProcessInfo(pid, process_info);
384 PlatformWindows::FindProcesses(const ProcessInstanceInfoMatch &match_info,
385 ProcessInstanceInfoList &process_infos) {
386 uint32_t match_count = 0;
388 // Let the base class figure out the host details
389 match_count = Platform::FindProcesses(match_info, process_infos);
391 // If we are remote, we can only return results if we are connected
392 if (m_remote_platform_sp)
394 m_remote_platform_sp->FindProcesses(match_info, process_infos);
399 Error PlatformWindows::LaunchProcess(ProcessLaunchInfo &launch_info) {
402 error = Platform::LaunchProcess(launch_info);
404 if (m_remote_platform_sp)
405 error = m_remote_platform_sp->LaunchProcess(launch_info);
407 error.SetErrorString("the platform is not currently connected");
412 ProcessSP PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info,
413 Debugger &debugger, Target *target,
415 // Windows has special considerations that must be followed when launching or
416 // attaching to a process. The
417 // key requirement is that when launching or attaching to a process, you must
418 // do it from the same the thread
419 // that will go into a permanent loop which will then receive debug events
420 // from the process. In particular,
421 // this means we can't use any of LLDB's generic mechanisms to do it for us,
422 // because it doesn't have the
423 // special knowledge required for setting up the background thread or passing
426 // Another problem is that that LLDB's standard model for debugging a process
427 // is to first launch it, have
428 // it stop at the entry point, and then attach to it. In Windows this doesn't
429 // quite work, you have to
430 // specify as an argument to CreateProcess() that you're going to debug the
431 // process. So we override DebugProcess
432 // here to handle this. Launch operations go directly to the process plugin,
433 // and attach operations almost go
434 // directly to the process plugin (but we hijack the events first). In
435 // essence, we encapsulate all the logic
436 // of Launching and Attaching in the process plugin, and
437 // PlatformWindows::DebugProcess is just a pass-through
438 // to get to the process plugin.
440 if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) {
441 // This is a process attach. Don't need to launch anything.
442 ProcessAttachInfo attach_info(launch_info);
443 return Attach(attach_info, debugger, target, error);
445 ProcessSP process_sp =
446 target->CreateProcess(launch_info.GetListenerForProcess(debugger),
447 launch_info.GetProcessPluginName(), nullptr);
449 // We need to launch and attach to the process.
450 launch_info.GetFlags().Set(eLaunchFlagDebug);
452 error = process_sp->Launch(launch_info);
458 lldb::ProcessSP PlatformWindows::Attach(ProcessAttachInfo &attach_info,
459 Debugger &debugger, Target *target,
462 lldb::ProcessSP process_sp;
464 if (m_remote_platform_sp)
466 m_remote_platform_sp->Attach(attach_info, debugger, target, error);
468 error.SetErrorString("the platform is not currently connected");
472 if (target == nullptr) {
473 TargetSP new_target_sp;
474 FileSpec emptyFileSpec;
475 ArchSpec emptyArchSpec;
477 error = debugger.GetTargetList().CreateTarget(debugger, "", "", false,
478 nullptr, new_target_sp);
479 target = new_target_sp.get();
482 if (!target || error.Fail())
485 debugger.GetTargetList().SetSelectedTarget(target);
487 const char *plugin_name = attach_info.GetProcessPluginName();
488 process_sp = target->CreateProcess(
489 attach_info.GetListenerForProcess(debugger), plugin_name, nullptr);
491 process_sp->HijackProcessEvents(attach_info.GetHijackListener());
493 error = process_sp->Attach(attach_info);
498 const char *PlatformWindows::GetUserName(uint32_t uid) {
499 // Check the cache in Platform in case we have already looked this uid up
500 const char *user_name = Platform::GetUserName(uid);
504 if (IsRemote() && m_remote_platform_sp)
505 return m_remote_platform_sp->GetUserName(uid);
509 const char *PlatformWindows::GetGroupName(uint32_t gid) {
510 const char *group_name = Platform::GetGroupName(gid);
514 if (IsRemote() && m_remote_platform_sp)
515 return m_remote_platform_sp->GetGroupName(gid);
519 Error PlatformWindows::GetFileWithUUID(const FileSpec &platform_file,
520 const UUID *uuid_ptr,
521 FileSpec &local_file) {
523 if (m_remote_platform_sp)
524 return m_remote_platform_sp->GetFileWithUUID(platform_file, uuid_ptr,
528 // Default to the local case
529 local_file = platform_file;
533 Error PlatformWindows::GetSharedModule(
534 const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
535 const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr,
536 bool *did_create_ptr) {
541 // If we have a remote platform always, let it try and locate
542 // the shared module first.
543 if (m_remote_platform_sp) {
544 error = m_remote_platform_sp->GetSharedModule(
545 module_spec, process, module_sp, module_search_paths_ptr,
546 old_module_sp_ptr, did_create_ptr);
551 // Fall back to the local platform and find the file locally
552 error = Platform::GetSharedModule(module_spec, process, module_sp,
553 module_search_paths_ptr,
554 old_module_sp_ptr, did_create_ptr);
557 module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
561 bool PlatformWindows::GetSupportedArchitectureAtIndex(uint32_t idx,
563 static SupportedArchList architectures;
565 if (idx >= architectures.Count())
567 arch = architectures[idx];
571 void PlatformWindows::GetStatus(Stream &strm) {
572 Platform::GetStatus(strm);
578 if (!HostInfo::GetOSVersion(major, minor, update)) {
583 strm << "Host: Windows " << major << '.' << minor << " Build: " << update
588 bool PlatformWindows::CanDebugProcess() { return true; }
590 size_t PlatformWindows::GetEnvironment(StringList &env) {
592 if (m_remote_platform_sp)
593 return m_remote_platform_sp->GetEnvironment(env);
597 return Host::GetEnvironment(env);
600 ConstString PlatformWindows::GetFullNameForDylib(ConstString basename) {
601 if (basename.IsEmpty())
605 stream.Printf("%s.dll", basename.GetCString());
606 return ConstString(stream.GetString());