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 lldb::ProcessSP
530 PlatformWindows::Attach(ProcessAttachInfo &attach_info,
531                         Debugger &debugger,
532                         Target *target,
533                         Error &error)
534 {
535     lldb::ProcessSP process_sp;
536     if (IsHost())
537     {
538         if (target == NULL)
539         {
540             TargetSP new_target_sp;
541             FileSpec emptyFileSpec;
542             ArchSpec emptyArchSpec;
543 
544             error = debugger.GetTargetList().CreateTarget (debugger,
545                                                            NULL,
546                                                            NULL,
547                                                            false,
548                                                            NULL,
549                                                            new_target_sp);
550             target = new_target_sp.get();
551         }
552         else
553             error.Clear();
554 
555         if (target && error.Success())
556         {
557             debugger.GetTargetList().SetSelectedTarget(target);
558             // The Windows platform always currently uses the GDB remote debugger plug-in
559             // so even when debugging locally we are debugging remotely!
560             // Just like the darwin plugin.
561             process_sp = target->CreateProcess (attach_info.GetListenerForProcess(debugger), "gdb-remote", NULL);
562 
563             if (process_sp)
564                 error = process_sp->Attach (attach_info);
565         }
566     }
567     else
568     {
569         if (m_remote_platform_sp)
570             process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, error);
571         else
572             error.SetErrorString ("the platform is not currently connected");
573     }
574     return process_sp;
575 }
576 
577 const char *
578 PlatformWindows::GetUserName (uint32_t uid)
579 {
580     // Check the cache in Platform in case we have already looked this uid up
581     const char *user_name = Platform::GetUserName(uid);
582     if (user_name)
583         return user_name;
584 
585     if (IsRemote() && m_remote_platform_sp)
586         return m_remote_platform_sp->GetUserName(uid);
587     return NULL;
588 }
589 
590 const char *
591 PlatformWindows::GetGroupName (uint32_t gid)
592 {
593     const char *group_name = Platform::GetGroupName(gid);
594     if (group_name)
595         return group_name;
596 
597     if (IsRemote() && m_remote_platform_sp)
598         return m_remote_platform_sp->GetGroupName(gid);
599     return NULL;
600 }
601 
602 Error
603 PlatformWindows::GetFileWithUUID (const FileSpec &platform_file,
604                                   const UUID *uuid_ptr,
605                                   FileSpec &local_file)
606 {
607     if (IsRemote())
608     {
609         if (m_remote_platform_sp)
610             return m_remote_platform_sp->GetFileWithUUID (platform_file, uuid_ptr, local_file);
611     }
612 
613     // Default to the local case
614     local_file = platform_file;
615     return Error();
616 }
617 
618 Error
619 PlatformWindows::GetSharedModule (const ModuleSpec &module_spec,
620                                   Process* process,
621                                   ModuleSP &module_sp,
622                                   const FileSpecList *module_search_paths_ptr,
623                                   ModuleSP *old_module_sp_ptr,
624                                   bool *did_create_ptr)
625 {
626     Error error;
627     module_sp.reset();
628 
629     if (IsRemote())
630     {
631         // If we have a remote platform always, let it try and locate
632         // the shared module first.
633         if (m_remote_platform_sp)
634         {
635             error = m_remote_platform_sp->GetSharedModule (module_spec,
636                                                            process,
637                                                            module_sp,
638                                                            module_search_paths_ptr,
639                                                            old_module_sp_ptr,
640                                                            did_create_ptr);
641         }
642     }
643 
644     if (!module_sp)
645     {
646         // Fall back to the local platform and find the file locally
647         error = Platform::GetSharedModule (module_spec,
648                                            process,
649                                            module_sp,
650                                            module_search_paths_ptr,
651                                            old_module_sp_ptr,
652                                            did_create_ptr);
653     }
654     if (module_sp)
655         module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
656     return error;
657 }
658 
659 bool
660 PlatformWindows::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
661 {
662     static SupportedArchList architectures;
663 
664     if (idx >= architectures.Count())
665         return false;
666     arch = architectures[idx];
667     return true;
668 }
669 
670 void
671 PlatformWindows::GetStatus (Stream &strm)
672 {
673     Platform::GetStatus(strm);
674 
675 #ifdef _WIN32
676     uint32_t major;
677     uint32_t minor;
678     uint32_t update;
679     if (!HostInfo::GetOSVersion(major, minor, update))
680     {
681         strm << "Windows";
682         return;
683     }
684 
685     strm << "Host: Windows " << major
686          << '.' << minor
687          << " Build: " << update << '\n';
688 #endif
689 }
690