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