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 size_t
325 PlatformWindows::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site)
326 {
327     ArchSpec arch = target.GetArchitecture();
328     const uint8_t *trap_opcode = nullptr;
329     size_t trap_opcode_size = 0;
330 
331     switch (arch.GetMachine())
332     {
333     case llvm::Triple::x86:
334     case llvm::Triple::x86_64:
335         {
336             static const uint8_t g_i386_opcode[] = { 0xCC };
337             trap_opcode = g_i386_opcode;
338             trap_opcode_size = sizeof(g_i386_opcode);
339         }
340         break;
341 
342     case llvm::Triple::hexagon:
343         {
344             static const uint8_t g_hex_opcode[] = { 0x0c, 0xdb, 0x00, 0x54 };
345             trap_opcode = g_hex_opcode;
346             trap_opcode_size = sizeof(g_hex_opcode);
347         }
348         break;
349     default:
350         llvm_unreachable("Unhandled architecture in PlatformWindows::GetSoftwareBreakpointTrapOpcode()");
351         break;
352     }
353 
354     if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
355         return trap_opcode_size;
356 
357     return 0;
358 }
359 
360 bool
361 PlatformWindows::GetRemoteOSVersion ()
362 {
363     if (m_remote_platform_sp)
364         return m_remote_platform_sp->GetOSVersion (m_major_os_version,
365                                                    m_minor_os_version,
366                                                    m_update_os_version);
367     return false;
368 }
369 
370 bool
371 PlatformWindows::GetRemoteOSBuildString (std::string &s)
372 {
373     if (m_remote_platform_sp)
374         return m_remote_platform_sp->GetRemoteOSBuildString (s);
375     s.clear();
376     return false;
377 }
378 
379 bool
380 PlatformWindows::GetRemoteOSKernelDescription (std::string &s)
381 {
382     if (m_remote_platform_sp)
383         return m_remote_platform_sp->GetRemoteOSKernelDescription (s);
384     s.clear();
385     return false;
386 }
387 
388 // Remote Platform subclasses need to override this function
389 ArchSpec
390 PlatformWindows::GetRemoteSystemArchitecture ()
391 {
392     if (m_remote_platform_sp)
393         return m_remote_platform_sp->GetRemoteSystemArchitecture ();
394     return ArchSpec();
395 }
396 
397 const char *
398 PlatformWindows::GetHostname ()
399 {
400     if (IsHost())
401         return Platform::GetHostname();
402 
403     if (m_remote_platform_sp)
404         return m_remote_platform_sp->GetHostname ();
405     return nullptr;
406 }
407 
408 bool
409 PlatformWindows::IsConnected () const
410 {
411     if (IsHost())
412         return true;
413     else if (m_remote_platform_sp)
414         return m_remote_platform_sp->IsConnected();
415     return false;
416 }
417 
418 Error
419 PlatformWindows::ConnectRemote (Args& args)
420 {
421     Error error;
422     if (IsHost())
423     {
424         error.SetErrorStringWithFormat ("can't connect to the host platform '%s', always connected", GetPluginName().AsCString() );
425     }
426     else
427     {
428         if (!m_remote_platform_sp)
429             m_remote_platform_sp = Platform::Create (ConstString("remote-gdb-server"), error);
430 
431         if (m_remote_platform_sp)
432         {
433             if (error.Success())
434             {
435                 if (m_remote_platform_sp)
436                 {
437                     error = m_remote_platform_sp->ConnectRemote (args);
438                 }
439                 else
440                 {
441                     error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>");
442                 }
443             }
444         }
445         else
446             error.SetErrorString ("failed to create a 'remote-gdb-server' platform");
447 
448         if (error.Fail())
449             m_remote_platform_sp.reset();
450     }
451 
452     return error;
453 }
454 
455 Error
456 PlatformWindows::DisconnectRemote ()
457 {
458     Error error;
459 
460     if (IsHost())
461     {
462         error.SetErrorStringWithFormat ("can't disconnect from the host platform '%s', always connected", GetPluginName().AsCString() );
463     }
464     else
465     {
466         if (m_remote_platform_sp)
467             error = m_remote_platform_sp->DisconnectRemote ();
468         else
469             error.SetErrorString ("the platform is not currently connected");
470     }
471     return error;
472 }
473 
474 bool
475 PlatformWindows::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
476 {
477     bool success = false;
478     if (IsHost())
479     {
480         success = Platform::GetProcessInfo (pid, process_info);
481     }
482     else if (m_remote_platform_sp)
483     {
484         success = m_remote_platform_sp->GetProcessInfo (pid, process_info);
485     }
486     return success;
487 }
488 
489 uint32_t
490 PlatformWindows::FindProcesses (const ProcessInstanceInfoMatch &match_info,
491                                ProcessInstanceInfoList &process_infos)
492 {
493     uint32_t match_count = 0;
494     if (IsHost())
495     {
496         // Let the base class figure out the host details
497         match_count = Platform::FindProcesses (match_info, process_infos);
498     }
499     else
500     {
501         // If we are remote, we can only return results if we are connected
502         if (m_remote_platform_sp)
503             match_count = m_remote_platform_sp->FindProcesses (match_info, process_infos);
504     }
505     return match_count;
506 }
507 
508 Error
509 PlatformWindows::LaunchProcess (ProcessLaunchInfo &launch_info)
510 {
511     Error error;
512     if (IsHost())
513     {
514         error = Platform::LaunchProcess (launch_info);
515     }
516     else
517     {
518         if (m_remote_platform_sp)
519             error = m_remote_platform_sp->LaunchProcess (launch_info);
520         else
521             error.SetErrorString ("the platform is not currently connected");
522     }
523     return error;
524 }
525 
526 ProcessSP
527 PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, Target *target, Error &error)
528 {
529     // Windows has special considerations that must be followed when launching or attaching to a process.  The
530     // key requirement is that when launching or attaching to a process, you must do it from the same the thread
531     // that will go into a permanent loop which will then receive debug events from the process.  In particular,
532     // this means we can't use any of LLDB's generic mechanisms to do it for us, because it doesn't have the
533     // special knowledge required for setting up the background thread or passing the right flags.
534     //
535     // Another problem is that that LLDB's standard model for debugging a process is to first launch it, have
536     // it stop at the entry point, and then attach to it.  In Windows this doesn't quite work, you have to
537     // specify as an argument to CreateProcess() that you're going to debug the process.  So we override DebugProcess
538     // here to handle this.  Launch operations go directly to the process plugin, and attach operations almost go
539     // directly to the process plugin (but we hijack the events first).  In essence, we encapsulate all the logic
540     // of Launching and Attaching in the process plugin, and PlatformWindows::DebugProcess is just a pass-through
541     // to get to the process plugin.
542 
543     if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
544     {
545         // This is a process attach.  Don't need to launch anything.
546         ProcessAttachInfo attach_info(launch_info);
547         return Attach(attach_info, debugger, target, error);
548     }
549     else
550     {
551         ProcessSP process_sp = target->CreateProcess(launch_info.GetListenerForProcess(debugger),
552                                                      launch_info.GetProcessPluginName(),
553                                                      nullptr);
554 
555         // We need to launch and attach to the process.
556         launch_info.GetFlags().Set(eLaunchFlagDebug);
557         if (process_sp)
558             error = process_sp->Launch(launch_info);
559 
560         return process_sp;
561     }
562 }
563 
564 lldb::ProcessSP
565 PlatformWindows::Attach(ProcessAttachInfo &attach_info,
566                         Debugger &debugger,
567                         Target *target,
568                         Error &error)
569 {
570     error.Clear();
571     lldb::ProcessSP process_sp;
572     if (!IsHost())
573     {
574         if (m_remote_platform_sp)
575             process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, error);
576         else
577             error.SetErrorString ("the platform is not currently connected");
578         return process_sp;
579     }
580 
581     if (target == nullptr)
582     {
583         TargetSP new_target_sp;
584         FileSpec emptyFileSpec;
585         ArchSpec emptyArchSpec;
586 
587         error = debugger.GetTargetList().CreateTarget(debugger,
588                                                       nullptr,
589                                                       nullptr,
590                                                       false,
591                                                       nullptr,
592                                                       new_target_sp);
593         target = new_target_sp.get();
594     }
595 
596     if (!target || error.Fail())
597         return process_sp;
598 
599     debugger.GetTargetList().SetSelectedTarget(target);
600 
601     const char *plugin_name = attach_info.GetProcessPluginName();
602     process_sp = target->CreateProcess(attach_info.GetListenerForProcess(debugger), plugin_name, nullptr);
603 
604     process_sp->HijackProcessEvents(attach_info.GetHijackListener().get());
605     if (process_sp)
606         error = process_sp->Attach (attach_info);
607 
608     return process_sp;
609 }
610 
611 const char *
612 PlatformWindows::GetUserName (uint32_t uid)
613 {
614     // Check the cache in Platform in case we have already looked this uid up
615     const char *user_name = Platform::GetUserName(uid);
616     if (user_name)
617         return user_name;
618 
619     if (IsRemote() && m_remote_platform_sp)
620         return m_remote_platform_sp->GetUserName(uid);
621     return nullptr;
622 }
623 
624 const char *
625 PlatformWindows::GetGroupName (uint32_t gid)
626 {
627     const char *group_name = Platform::GetGroupName(gid);
628     if (group_name)
629         return group_name;
630 
631     if (IsRemote() && m_remote_platform_sp)
632         return m_remote_platform_sp->GetGroupName(gid);
633     return nullptr;
634 }
635 
636 Error
637 PlatformWindows::GetFileWithUUID (const FileSpec &platform_file,
638                                   const UUID *uuid_ptr,
639                                   FileSpec &local_file)
640 {
641     if (IsRemote())
642     {
643         if (m_remote_platform_sp)
644             return m_remote_platform_sp->GetFileWithUUID (platform_file, uuid_ptr, local_file);
645     }
646 
647     // Default to the local case
648     local_file = platform_file;
649     return Error();
650 }
651 
652 Error
653 PlatformWindows::GetSharedModule (const ModuleSpec &module_spec,
654                                   Process* process,
655                                   ModuleSP &module_sp,
656                                   const FileSpecList *module_search_paths_ptr,
657                                   ModuleSP *old_module_sp_ptr,
658                                   bool *did_create_ptr)
659 {
660     Error error;
661     module_sp.reset();
662 
663     if (IsRemote())
664     {
665         // If we have a remote platform always, let it try and locate
666         // the shared module first.
667         if (m_remote_platform_sp)
668         {
669             error = m_remote_platform_sp->GetSharedModule (module_spec,
670                                                            process,
671                                                            module_sp,
672                                                            module_search_paths_ptr,
673                                                            old_module_sp_ptr,
674                                                            did_create_ptr);
675         }
676     }
677 
678     if (!module_sp)
679     {
680         // Fall back to the local platform and find the file locally
681         error = Platform::GetSharedModule (module_spec,
682                                            process,
683                                            module_sp,
684                                            module_search_paths_ptr,
685                                            old_module_sp_ptr,
686                                            did_create_ptr);
687     }
688     if (module_sp)
689         module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
690     return error;
691 }
692 
693 bool
694 PlatformWindows::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
695 {
696     static SupportedArchList architectures;
697 
698     if (idx >= architectures.Count())
699         return false;
700     arch = architectures[idx];
701     return true;
702 }
703 
704 void
705 PlatformWindows::GetStatus (Stream &strm)
706 {
707     Platform::GetStatus(strm);
708 
709 #ifdef _WIN32
710     uint32_t major;
711     uint32_t minor;
712     uint32_t update;
713     if (!HostInfo::GetOSVersion(major, minor, update))
714     {
715         strm << "Windows";
716         return;
717     }
718 
719     strm << "Host: Windows " << major
720          << '.' << minor
721          << " Build: " << update << '\n';
722 #endif
723 }
724 
725 bool
726 PlatformWindows::CanDebugProcess()
727 {
728     return true;
729 }
730 
731 size_t
732 PlatformWindows::GetEnvironment(StringList &env)
733 {
734     if (IsRemote())
735     {
736         if (m_remote_platform_sp)
737             return m_remote_platform_sp->GetEnvironment(env);
738         return 0;
739     }
740 
741     return Host::GetEnvironment(env);
742 }
743 
744 ConstString
745 PlatformWindows::GetFullNameForDylib (ConstString basename)
746 {
747     if (basename.IsEmpty())
748         return basename;
749 
750     StreamString stream;
751     stream.Printf("%s.dll", basename.GetCString());
752     return ConstString(stream.GetData());
753 }
754