1 //===-- PlatformWindows.cpp -------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "PlatformWindows.h"
11 
12 // C Includes
13 #include <stdio.h>
14 #if defined (_WIN32)
15 #include "lldb/Host/windows/windows.h"
16 #include <winsock2.h>
17 #endif
18 
19 // C++ Includes
20 // Other libraries and framework includes
21 // Project includes
22 #include "lldb/Core/Error.h"
23 #include "lldb/Core/Debugger.h"
24 #include "lldb/Core/PluginManager.h"
25 #include "lldb/Host/HostInfo.h"
26 #include "lldb/Core/ModuleSpec.h"
27 #include "lldb/Core/Module.h"
28 #include "lldb/Breakpoint/BreakpointLocation.h"
29 #include "lldb/Breakpoint/BreakpointSite.h"
30 #include "lldb/Target/Process.h"
31 
32 using namespace lldb;
33 using namespace lldb_private;
34 
35 static uint32_t g_initialize_count = 0;
36 
37 namespace
38 {
39     class SupportedArchList
40     {
41     public:
42         SupportedArchList()
43         {
44             AddArch(ArchSpec("i686-pc-windows"));
45             AddArch(HostInfo::GetArchitecture(HostInfo::eArchKindDefault));
46             AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind32));
47             AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind64));
48             AddArch(ArchSpec("i386-pc-windows"));
49         }
50 
51         size_t Count() const { return m_archs.size(); }
52 
53         const ArchSpec& operator[](int idx) { return m_archs[idx]; }
54 
55     private:
56         void AddArch(const ArchSpec& spec)
57         {
58             auto iter = std::find_if(
59                 m_archs.begin(), m_archs.end(),
60                 [spec](const ArchSpec& rhs) { return spec.IsExactMatch(rhs); });
61             if (iter != m_archs.end())
62                 return;
63             if (spec.IsValid())
64                 m_archs.push_back(spec);
65         }
66 
67         std::vector<ArchSpec> m_archs;
68     };
69 } // anonymous namespace
70 
71 PlatformSP
72 PlatformWindows::CreateInstance (bool force, const lldb_private::ArchSpec *arch)
73 {
74     // The only time we create an instance is when we are creating a remote
75     // windows platform
76     const bool is_host = false;
77 
78     bool create = force;
79     if (create == false && arch && arch->IsValid())
80     {
81         const llvm::Triple &triple = arch->GetTriple();
82         switch (triple.getVendor())
83         {
84         case llvm::Triple::PC:
85             create = true;
86             break;
87 
88         case llvm::Triple::UnknownArch:
89             create = !arch->TripleVendorWasSpecified();
90             break;
91 
92         default:
93             break;
94         }
95 
96         if (create)
97         {
98             switch (triple.getOS())
99             {
100             case llvm::Triple::Win32:
101                 break;
102 
103             case llvm::Triple::UnknownOS:
104                 create = arch->TripleOSWasSpecified();
105                 break;
106 
107             default:
108                 create = false;
109                 break;
110             }
111         }
112     }
113     if (create)
114         return PlatformSP(new PlatformWindows (is_host));
115     return PlatformSP();
116 }
117 
118 lldb_private::ConstString
119 PlatformWindows::GetPluginNameStatic(bool is_host)
120 {
121     if (is_host)
122     {
123         static ConstString g_host_name(Platform::GetHostPlatformName ());
124         return g_host_name;
125     }
126     else
127     {
128         static ConstString g_remote_name("remote-windows");
129         return g_remote_name;
130     }
131 }
132 
133 const char *
134 PlatformWindows::GetPluginDescriptionStatic(bool is_host)
135 {
136     return is_host ?
137         "Local Windows user platform plug-in." :
138         "Remote Windows user platform plug-in.";
139 }
140 
141 lldb_private::ConstString
142 PlatformWindows::GetPluginName()
143 {
144     return GetPluginNameStatic(IsHost());
145 }
146 
147 void
148 PlatformWindows::Initialize()
149 {
150     Platform::Initialize ();
151 
152     if (g_initialize_count++ == 0)
153     {
154 #if defined (_WIN32)
155         WSADATA dummy;
156         WSAStartup(MAKEWORD(2,2), &dummy);
157         // Force a host flag to true for the default platform object.
158         PlatformSP default_platform_sp (new PlatformWindows(true));
159         default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
160         Platform::SetHostPlatform (default_platform_sp);
161 #endif
162         PluginManager::RegisterPlugin(PlatformWindows::GetPluginNameStatic(false),
163                                       PlatformWindows::GetPluginDescriptionStatic(false),
164                                       PlatformWindows::CreateInstance);
165     }
166 }
167 
168 void
169 PlatformWindows::Terminate( void )
170 {
171     if (g_initialize_count > 0)
172     {
173         if (--g_initialize_count == 0)
174         {
175 #ifdef _WIN32
176             WSACleanup();
177 #endif
178             PluginManager::UnregisterPlugin (PlatformWindows::CreateInstance);
179         }
180     }
181 
182     Platform::Terminate ();
183 }
184 
185 //------------------------------------------------------------------
186 /// Default Constructor
187 //------------------------------------------------------------------
188 PlatformWindows::PlatformWindows (bool is_host) :
189     Platform(is_host)
190 {
191 }
192 
193 //------------------------------------------------------------------
194 /// Destructor.
195 ///
196 /// The destructor is virtual since this class is designed to be
197 /// inherited from by the plug-in instance.
198 //------------------------------------------------------------------
199 PlatformWindows::~PlatformWindows() = default;
200 
201 bool
202 PlatformWindows::GetModuleSpec (const FileSpec& module_file_spec,
203                                 const ArchSpec& arch,
204                                 ModuleSpec &module_spec)
205 {
206     if (m_remote_platform_sp)
207         return m_remote_platform_sp->GetModuleSpec (module_file_spec, arch, module_spec);
208 
209     return Platform::GetModuleSpec (module_file_spec, arch, module_spec);
210 }
211 
212 Error
213 PlatformWindows::ResolveExecutable (const ModuleSpec &ms,
214                                     lldb::ModuleSP &exe_module_sp,
215                                     const FileSpecList *module_search_paths_ptr)
216 {
217     Error error;
218     // Nothing special to do here, just use the actual file and architecture
219 
220     char exe_path[PATH_MAX];
221     ModuleSpec resolved_module_spec(ms);
222 
223     if (IsHost())
224     {
225         // if we cant resolve the executable loation based on the current path variables
226         if (!resolved_module_spec.GetFileSpec().Exists())
227         {
228             resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path));
229             resolved_module_spec.GetFileSpec().SetFile(exe_path, true);
230         }
231 
232         if (!resolved_module_spec.GetFileSpec().Exists())
233             resolved_module_spec.GetFileSpec().ResolveExecutableLocation ();
234 
235         if (resolved_module_spec.GetFileSpec().Exists())
236             error.Clear();
237         else
238         {
239             ms.GetFileSpec().GetPath(exe_path, sizeof(exe_path));
240             error.SetErrorStringWithFormat("unable to find executable for '%s'", exe_path);
241         }
242     }
243     else
244     {
245         if (m_remote_platform_sp)
246         {
247             error = GetCachedExecutable (resolved_module_spec, exe_module_sp, nullptr, *m_remote_platform_sp);
248         }
249         else
250         {
251             // We may connect to a process and use the provided executable (Don't use local $PATH).
252             if (resolved_module_spec.GetFileSpec().Exists())
253                 error.Clear();
254             else
255                 error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", exe_path);
256         }
257     }
258 
259     if (error.Success())
260     {
261         if (resolved_module_spec.GetArchitecture().IsValid())
262         {
263             error = ModuleList::GetSharedModule(resolved_module_spec,
264                                                 exe_module_sp,
265                                                 nullptr,
266                                                 nullptr,
267                                                 nullptr);
268 
269             if (!exe_module_sp || exe_module_sp->GetObjectFile() == nullptr)
270             {
271                 exe_module_sp.reset();
272                 error.SetErrorStringWithFormat ("'%s' doesn't contain the architecture %s",
273                                                 resolved_module_spec.GetFileSpec().GetPath().c_str(),
274                                                 resolved_module_spec.GetArchitecture().GetArchitectureName());
275             }
276         }
277         else
278         {
279             // No valid architecture was specified, ask the platform for
280             // the architectures that we should be using (in the correct order)
281             // and see if we can find a match that way
282             StreamString arch_names;
283             for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, resolved_module_spec.GetArchitecture()); ++idx)
284             {
285                 error = ModuleList::GetSharedModule(resolved_module_spec,
286                                                     exe_module_sp,
287                                                     nullptr,
288                                                     nullptr,
289                                                     nullptr);
290                 // Did we find an executable using one of the
291                 if (error.Success())
292                 {
293                     if (exe_module_sp && exe_module_sp->GetObjectFile())
294                         break;
295                     else
296                         error.SetErrorToGenericError();
297                 }
298 
299                 if (idx > 0)
300                     arch_names.PutCString (", ");
301                 arch_names.PutCString (resolved_module_spec.GetArchitecture().GetArchitectureName());
302             }
303 
304             if (error.Fail() || !exe_module_sp)
305             {
306                 if (resolved_module_spec.GetFileSpec().Readable())
307                 {
308                     error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
309                                                     resolved_module_spec.GetFileSpec().GetPath().c_str(),
310                                                     GetPluginName().GetCString(),
311                                                     arch_names.GetString().c_str());
312                 }
313                 else
314                 {
315                     error.SetErrorStringWithFormat("'%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str());
316                 }
317             }
318         }
319     }
320 
321     return error;
322 }
323 
324 bool
325 PlatformWindows::GetRemoteOSVersion ()
326 {
327     if (m_remote_platform_sp)
328         return m_remote_platform_sp->GetOSVersion (m_major_os_version,
329                                                    m_minor_os_version,
330                                                    m_update_os_version);
331     return false;
332 }
333 
334 bool
335 PlatformWindows::GetRemoteOSBuildString (std::string &s)
336 {
337     if (m_remote_platform_sp)
338         return m_remote_platform_sp->GetRemoteOSBuildString (s);
339     s.clear();
340     return false;
341 }
342 
343 bool
344 PlatformWindows::GetRemoteOSKernelDescription (std::string &s)
345 {
346     if (m_remote_platform_sp)
347         return m_remote_platform_sp->GetRemoteOSKernelDescription (s);
348     s.clear();
349     return false;
350 }
351 
352 // Remote Platform subclasses need to override this function
353 ArchSpec
354 PlatformWindows::GetRemoteSystemArchitecture ()
355 {
356     if (m_remote_platform_sp)
357         return m_remote_platform_sp->GetRemoteSystemArchitecture ();
358     return ArchSpec();
359 }
360 
361 const char *
362 PlatformWindows::GetHostname ()
363 {
364     if (IsHost())
365         return Platform::GetHostname();
366 
367     if (m_remote_platform_sp)
368         return m_remote_platform_sp->GetHostname ();
369     return nullptr;
370 }
371 
372 bool
373 PlatformWindows::IsConnected () const
374 {
375     if (IsHost())
376         return true;
377     else if (m_remote_platform_sp)
378         return m_remote_platform_sp->IsConnected();
379     return false;
380 }
381 
382 Error
383 PlatformWindows::ConnectRemote (Args& args)
384 {
385     Error error;
386     if (IsHost())
387     {
388         error.SetErrorStringWithFormat ("can't connect to the host platform '%s', always connected", GetPluginName().AsCString() );
389     }
390     else
391     {
392         if (!m_remote_platform_sp)
393             m_remote_platform_sp = Platform::Create (ConstString("remote-gdb-server"), error);
394 
395         if (m_remote_platform_sp)
396         {
397             if (error.Success())
398             {
399                 if (m_remote_platform_sp)
400                 {
401                     error = m_remote_platform_sp->ConnectRemote (args);
402                 }
403                 else
404                 {
405                     error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>");
406                 }
407             }
408         }
409         else
410             error.SetErrorString ("failed to create a 'remote-gdb-server' platform");
411 
412         if (error.Fail())
413             m_remote_platform_sp.reset();
414     }
415 
416     return error;
417 }
418 
419 Error
420 PlatformWindows::DisconnectRemote ()
421 {
422     Error error;
423 
424     if (IsHost())
425     {
426         error.SetErrorStringWithFormat ("can't disconnect from the host platform '%s', always connected", GetPluginName().AsCString() );
427     }
428     else
429     {
430         if (m_remote_platform_sp)
431             error = m_remote_platform_sp->DisconnectRemote ();
432         else
433             error.SetErrorString ("the platform is not currently connected");
434     }
435     return error;
436 }
437 
438 bool
439 PlatformWindows::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
440 {
441     bool success = false;
442     if (IsHost())
443     {
444         success = Platform::GetProcessInfo (pid, process_info);
445     }
446     else if (m_remote_platform_sp)
447     {
448         success = m_remote_platform_sp->GetProcessInfo (pid, process_info);
449     }
450     return success;
451 }
452 
453 uint32_t
454 PlatformWindows::FindProcesses (const ProcessInstanceInfoMatch &match_info,
455                                ProcessInstanceInfoList &process_infos)
456 {
457     uint32_t match_count = 0;
458     if (IsHost())
459     {
460         // Let the base class figure out the host details
461         match_count = Platform::FindProcesses (match_info, process_infos);
462     }
463     else
464     {
465         // If we are remote, we can only return results if we are connected
466         if (m_remote_platform_sp)
467             match_count = m_remote_platform_sp->FindProcesses (match_info, process_infos);
468     }
469     return match_count;
470 }
471 
472 Error
473 PlatformWindows::LaunchProcess (ProcessLaunchInfo &launch_info)
474 {
475     Error error;
476     if (IsHost())
477     {
478         error = Platform::LaunchProcess (launch_info);
479     }
480     else
481     {
482         if (m_remote_platform_sp)
483             error = m_remote_platform_sp->LaunchProcess (launch_info);
484         else
485             error.SetErrorString ("the platform is not currently connected");
486     }
487     return error;
488 }
489 
490 ProcessSP
491 PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, Target *target, Error &error)
492 {
493     // Windows has special considerations that must be followed when launching or attaching to a process.  The
494     // key requirement is that when launching or attaching to a process, you must do it from the same the thread
495     // that will go into a permanent loop which will then receive debug events from the process.  In particular,
496     // this means we can't use any of LLDB's generic mechanisms to do it for us, because it doesn't have the
497     // special knowledge required for setting up the background thread or passing the right flags.
498     //
499     // Another problem is that that LLDB's standard model for debugging a process is to first launch it, have
500     // it stop at the entry point, and then attach to it.  In Windows this doesn't quite work, you have to
501     // specify as an argument to CreateProcess() that you're going to debug the process.  So we override DebugProcess
502     // here to handle this.  Launch operations go directly to the process plugin, and attach operations almost go
503     // directly to the process plugin (but we hijack the events first).  In essence, we encapsulate all the logic
504     // of Launching and Attaching in the process plugin, and PlatformWindows::DebugProcess is just a pass-through
505     // to get to the process plugin.
506 
507     if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
508     {
509         // This is a process attach.  Don't need to launch anything.
510         ProcessAttachInfo attach_info(launch_info);
511         return Attach(attach_info, debugger, target, error);
512     }
513     else
514     {
515         ProcessSP process_sp = target->CreateProcess(launch_info.GetListenerForProcess(debugger),
516                                                      launch_info.GetProcessPluginName(),
517                                                      nullptr);
518 
519         // We need to launch and attach to the process.
520         launch_info.GetFlags().Set(eLaunchFlagDebug);
521         if (process_sp)
522             error = process_sp->Launch(launch_info);
523 
524         return process_sp;
525     }
526 }
527 
528 lldb::ProcessSP
529 PlatformWindows::Attach(ProcessAttachInfo &attach_info,
530                         Debugger &debugger,
531                         Target *target,
532                         Error &error)
533 {
534     error.Clear();
535     lldb::ProcessSP process_sp;
536     if (!IsHost())
537     {
538         if (m_remote_platform_sp)
539             process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, error);
540         else
541             error.SetErrorString ("the platform is not currently connected");
542         return process_sp;
543     }
544 
545     if (target == nullptr)
546     {
547         TargetSP new_target_sp;
548         FileSpec emptyFileSpec;
549         ArchSpec emptyArchSpec;
550 
551         error = debugger.GetTargetList().CreateTarget(debugger,
552                                                       nullptr,
553                                                       nullptr,
554                                                       false,
555                                                       nullptr,
556                                                       new_target_sp);
557         target = new_target_sp.get();
558     }
559 
560     if (!target || error.Fail())
561         return process_sp;
562 
563     debugger.GetTargetList().SetSelectedTarget(target);
564 
565     const char *plugin_name = attach_info.GetProcessPluginName();
566     process_sp = target->CreateProcess(attach_info.GetListenerForProcess(debugger), plugin_name, nullptr);
567 
568     process_sp->HijackProcessEvents(attach_info.GetHijackListener());
569     if (process_sp)
570         error = process_sp->Attach (attach_info);
571 
572     return process_sp;
573 }
574 
575 const char *
576 PlatformWindows::GetUserName (uint32_t uid)
577 {
578     // Check the cache in Platform in case we have already looked this uid up
579     const char *user_name = Platform::GetUserName(uid);
580     if (user_name)
581         return user_name;
582 
583     if (IsRemote() && m_remote_platform_sp)
584         return m_remote_platform_sp->GetUserName(uid);
585     return nullptr;
586 }
587 
588 const char *
589 PlatformWindows::GetGroupName (uint32_t gid)
590 {
591     const char *group_name = Platform::GetGroupName(gid);
592     if (group_name)
593         return group_name;
594 
595     if (IsRemote() && m_remote_platform_sp)
596         return m_remote_platform_sp->GetGroupName(gid);
597     return nullptr;
598 }
599 
600 Error
601 PlatformWindows::GetFileWithUUID (const FileSpec &platform_file,
602                                   const UUID *uuid_ptr,
603                                   FileSpec &local_file)
604 {
605     if (IsRemote())
606     {
607         if (m_remote_platform_sp)
608             return m_remote_platform_sp->GetFileWithUUID (platform_file, uuid_ptr, local_file);
609     }
610 
611     // Default to the local case
612     local_file = platform_file;
613     return Error();
614 }
615 
616 Error
617 PlatformWindows::GetSharedModule (const ModuleSpec &module_spec,
618                                   Process* process,
619                                   ModuleSP &module_sp,
620                                   const FileSpecList *module_search_paths_ptr,
621                                   ModuleSP *old_module_sp_ptr,
622                                   bool *did_create_ptr)
623 {
624     Error error;
625     module_sp.reset();
626 
627     if (IsRemote())
628     {
629         // If we have a remote platform always, let it try and locate
630         // the shared module first.
631         if (m_remote_platform_sp)
632         {
633             error = m_remote_platform_sp->GetSharedModule (module_spec,
634                                                            process,
635                                                            module_sp,
636                                                            module_search_paths_ptr,
637                                                            old_module_sp_ptr,
638                                                            did_create_ptr);
639         }
640     }
641 
642     if (!module_sp)
643     {
644         // Fall back to the local platform and find the file locally
645         error = Platform::GetSharedModule (module_spec,
646                                            process,
647                                            module_sp,
648                                            module_search_paths_ptr,
649                                            old_module_sp_ptr,
650                                            did_create_ptr);
651     }
652     if (module_sp)
653         module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
654     return error;
655 }
656 
657 bool
658 PlatformWindows::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
659 {
660     static SupportedArchList architectures;
661 
662     if (idx >= architectures.Count())
663         return false;
664     arch = architectures[idx];
665     return true;
666 }
667 
668 void
669 PlatformWindows::GetStatus (Stream &strm)
670 {
671     Platform::GetStatus(strm);
672 
673 #ifdef _WIN32
674     uint32_t major;
675     uint32_t minor;
676     uint32_t update;
677     if (!HostInfo::GetOSVersion(major, minor, update))
678     {
679         strm << "Windows";
680         return;
681     }
682 
683     strm << "Host: Windows " << major
684          << '.' << minor
685          << " Build: " << update << '\n';
686 #endif
687 }
688 
689 bool
690 PlatformWindows::CanDebugProcess()
691 {
692     return true;
693 }
694 
695 size_t
696 PlatformWindows::GetEnvironment(StringList &env)
697 {
698     if (IsRemote())
699     {
700         if (m_remote_platform_sp)
701             return m_remote_platform_sp->GetEnvironment(env);
702         return 0;
703     }
704 
705     return Host::GetEnvironment(env);
706 }
707 
708 ConstString
709 PlatformWindows::GetFullNameForDylib (ConstString basename)
710 {
711     if (basename.IsEmpty())
712         return basename;
713 
714     StreamString stream;
715     stream.Printf("%s.dll", basename.GetCString());
716     return ConstString(stream.GetData());
717 }
718