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