1 //===-- source/Host/windows/Host.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 // C Includes
11 #include <stdio.h>
12 #include "lldb/Host/windows/windows.h"
13 #include "lldb/Host/windows/AutoHandle.h"
14 
15 // C++ Includes
16 // Other libraries and framework includes
17 // Project includes
18 #include "lldb/Core/Error.h"
19 #include "lldb/Core/Log.h"
20 #include "lldb/Target/Process.h"
21 
22 #include "lldb/Host/Host.h"
23 #include "lldb/Core/DataBufferHeap.h"
24 #include "lldb/Core/DataExtractor.h"
25 #include "lldb/Core/StreamFile.h"
26 
27 // Windows includes
28 #include <shellapi.h>
29 #include <TlHelp32.h>
30 
31 using namespace lldb;
32 using namespace lldb_private;
33 
34 namespace
35 {
36     bool GetTripleForProcess(const FileSpec &executable, llvm::Triple &triple)
37     {
38         // Open the PE File as a binary file, and parse just enough information to determine the
39         // machine type.
40         File imageBinary(
41             executable.GetPath().c_str(),
42             File::eOpenOptionRead,
43             lldb::eFilePermissionsUserRead);
44         imageBinary.SeekFromStart(0x3c);
45         int32_t peOffset = 0;
46         uint32_t peHead = 0;
47         uint16_t machineType = 0;
48         size_t readSize = sizeof(peOffset);
49         imageBinary.Read(&peOffset, readSize);
50         imageBinary.SeekFromStart(peOffset);
51         imageBinary.Read(&peHead, readSize);
52         if (peHead != 0x00004550) // "PE\0\0", little-endian
53             return false;       // Error: Can't find PE header
54         readSize = 2;
55         imageBinary.Read(&machineType, readSize);
56         triple.setVendor(llvm::Triple::PC);
57         triple.setOS(llvm::Triple::Win32);
58         triple.setArch(llvm::Triple::UnknownArch);
59         if (machineType == 0x8664)
60             triple.setArch(llvm::Triple::x86_64);
61         else if (machineType == 0x14c)
62             triple.setArch(llvm::Triple::x86);
63 
64         return true;
65     }
66 
67     bool GetExecutableForProcess(const AutoHandle &handle, std::string &path)
68     {
69         // Get the process image path.  MAX_PATH isn't long enough, paths can actually be up to 32KB.
70         std::vector<char> buffer(32768);
71         DWORD dwSize = buffer.size();
72         if (!::QueryFullProcessImageNameA(handle.get(), 0, &buffer[0], &dwSize))
73             return false;
74         path.assign(&buffer[0]);
75         return true;
76     }
77 
78     void GetProcessExecutableAndTriple(const AutoHandle &handle, ProcessInstanceInfo &process)
79     {
80         // We may not have permissions to read the path from the process.  So start off by
81         // setting the executable file to whatever Toolhelp32 gives us, and then try to
82         // enhance this with more detailed information, but fail gracefully.
83         std::string executable;
84         llvm::Triple triple;
85         triple.setVendor(llvm::Triple::PC);
86         triple.setOS(llvm::Triple::Win32);
87         triple.setArch(llvm::Triple::UnknownArch);
88         if (GetExecutableForProcess(handle, executable))
89         {
90             FileSpec executableFile(executable.c_str(), false);
91             process.SetExecutableFile(executableFile, true);
92             GetTripleForProcess(executableFile, triple);
93         }
94         process.SetArchitecture(ArchSpec(triple));
95 
96         // TODO(zturner): Add the ability to get the process user name.
97     }
98 }
99 
100 bool
101 Host::GetOSVersion(uint32_t &major,
102                    uint32_t &minor,
103                    uint32_t &update)
104 {
105     OSVERSIONINFOEX info;
106 
107     ZeroMemory(&info, sizeof(OSVERSIONINFOEX));
108     info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
109 #pragma warning(push)
110 #pragma warning(disable: 4996)
111     // Starting with Microsoft SDK for Windows 8.1, this function is deprecated in favor of the
112     // new Windows Version Helper APIs.  Since we don't specify a minimum SDK version, it's easier
113     // to simply disable the warning rather than try to support both APIs.
114     if (GetVersionEx((LPOSVERSIONINFO) &info) == 0) {
115         return false;
116     }
117 #pragma warning(pop)
118 
119     major = (uint32_t) info.dwMajorVersion;
120     minor = (uint32_t) info.dwMinorVersion;
121     update = (uint32_t) info.wServicePackMajor;
122 
123     return true;
124 }
125 
126 Error
127 Host::MakeDirectory (const char* path, uint32_t mode)
128 {
129     // On Win32, the mode parameter is ignored, as Windows files and directories support a
130     // different permission model than POSIX.
131     Error error;
132     if (!::CreateDirectory(path, NULL))
133         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
134     return error;
135 }
136 
137 Error
138 Host::GetFilePermissions (const char* path, uint32_t &file_permissions)
139 {
140     Error error;
141     file_permissions = 0;
142     DWORD attrib = ::GetFileAttributes(path);
143     if (attrib == INVALID_FILE_ATTRIBUTES)
144         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
145     return error;
146 }
147 
148 Error
149 Host::SetFilePermissions (const char* path, uint32_t file_permissions)
150 {
151     Error error;
152     error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
153     return error;
154 }
155 
156 Error
157 Host::Symlink (const char *linkname, const char *target)
158 {
159     Error error;
160     DWORD attrib = ::GetFileAttributes(target);
161     if (attrib == INVALID_FILE_ATTRIBUTES)
162     {
163         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
164         return error;
165     }
166     bool is_directory = !!(attrib & FILE_ATTRIBUTE_DIRECTORY);
167     DWORD flag = is_directory ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
168     BOOL result = ::CreateSymbolicLink(linkname, target, flag);
169     if (!result)
170         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
171     return error;
172 }
173 
174 Error
175 Host::Readlink (const char *path, char *buf, size_t buf_len)
176 {
177     Error error;
178     HANDLE h = ::CreateFile(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, NULL);
179     if (h == INVALID_HANDLE_VALUE)
180     {
181         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
182         return error;
183     }
184 
185     // Subtract 1 from the path length since this function does not add a null terminator.
186     DWORD result = ::GetFinalPathNameByHandle(h, buf, buf_len-1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
187     if (result == 0)
188         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
189 
190     ::CloseHandle(h);
191     return error;
192 }
193 
194 Error
195 Host::Unlink (const char *path)
196 {
197     Error error;
198     BOOL result = ::DeleteFile(path);
199     if (!result)
200         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
201     return error;
202 }
203 
204 Error
205 Host::RemoveDirectory (const char* path, bool recurse)
206 {
207     Error error;
208     if (!recurse)
209     {
210         BOOL result = ::RemoveDirectory(path);
211         if (!result)
212             error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
213     }
214     else
215     {
216         // SHFileOperation() accepts a list of paths, and so must be double-null-terminated to
217         // indicate the end of the list.
218         std::string path_buffer(path);
219         path_buffer.push_back(0);
220 
221         SHFILEOPSTRUCT shfos = {0};
222         shfos.wFunc = FO_DELETE;
223         shfos.pFrom = path_buffer.c_str();
224         shfos.fFlags = FOF_NO_UI;
225 
226         int result = ::SHFileOperation(&shfos);
227         // TODO(zturner): Correctly handle the intricacies of SHFileOperation return values.
228         if (result != 0)
229             error.SetErrorStringWithFormat("SHFileOperation failed");
230     }
231     return error;
232 }
233 
234 
235 Error
236 Host::LaunchProcess (ProcessLaunchInfo &launch_info)
237 {
238     Error error;
239     assert(!"Not implemented yet!!!");
240     return error;
241 }
242 
243 lldb::DataBufferSP
244 Host::GetAuxvData(lldb_private::Process *process)
245 {
246     return 0;
247 }
248 
249 std::string
250 Host::GetThreadName (lldb::pid_t pid, lldb::tid_t tid)
251 {
252     return std::string();
253 }
254 
255 lldb::tid_t
256 Host::GetCurrentThreadID()
257 {
258     return lldb::tid_t(::GetCurrentThreadId());
259 }
260 
261 lldb::thread_t
262 Host::GetCurrentThread ()
263 {
264     return lldb::thread_t(::GetCurrentThread());
265 }
266 
267 bool
268 Host::ThreadCancel (lldb::thread_t thread, Error *error)
269 {
270     int err = ::TerminateThread((HANDLE)thread, 0);
271     return err == 0;
272 }
273 
274 bool
275 Host::ThreadDetach (lldb::thread_t thread, Error *error)
276 {
277     return ThreadCancel(thread, error);
278 }
279 
280 bool
281 Host::ThreadJoin (lldb::thread_t thread, thread_result_t *thread_result_ptr, Error *error)
282 {
283     WaitForSingleObject((HANDLE) thread, INFINITE);
284     return true;
285 }
286 
287 lldb::thread_key_t
288 Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback)
289 {
290     return TlsAlloc();
291 }
292 
293 void*
294 Host::ThreadLocalStorageGet(lldb::thread_key_t key)
295 {
296     return ::TlsGetValue (key);
297 }
298 
299 void
300 Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value)
301 {
302    ::TlsSetValue (key, value);
303 }
304 
305 bool
306 Host::SetThreadName (lldb::pid_t pid, lldb::tid_t tid, const char *name)
307 {
308     return false;
309 }
310 
311 bool
312 Host::SetShortThreadName (lldb::pid_t pid, lldb::tid_t tid,
313                           const char *thread_name, size_t len)
314 {
315     return false;
316 }
317 
318 void
319 Host::Kill(lldb::pid_t pid, int signo)
320 {
321     TerminateProcess((HANDLE) pid, 1);
322 }
323 
324 uint32_t
325 Host::GetNumberCPUS()
326 {
327     static uint32_t g_num_cores = UINT32_MAX;
328     if (g_num_cores == UINT32_MAX)
329     {
330         SYSTEM_INFO system_info;
331         ::GetSystemInfo(&system_info);
332         g_num_cores = system_info.dwNumberOfProcessors;
333     }
334     return g_num_cores;
335 }
336 
337 size_t
338 Host::GetPageSize()
339 {
340     static long g_pagesize = 0;
341     if (!g_pagesize)
342     {
343         SYSTEM_INFO systemInfo;
344         GetNativeSystemInfo(&systemInfo);
345         g_pagesize = systemInfo.dwPageSize;
346     }
347     return g_pagesize;
348 }
349 
350 const char *
351 Host::GetSignalAsCString(int signo)
352 {
353     return NULL;
354 }
355 
356 FileSpec
357 Host::GetModuleFileSpecForHostAddress (const void *host_addr)
358 {
359     FileSpec module_filespec;
360 
361     HMODULE hmodule = NULL;
362     if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)host_addr, &hmodule))
363         return module_filespec;
364 
365     std::vector<char> buffer(MAX_PATH);
366     DWORD chars_copied = 0;
367     do {
368         chars_copied = ::GetModuleFileName(hmodule, &buffer[0], buffer.size());
369         if (chars_copied == buffer.size() && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
370             buffer.resize(buffer.size() * 2);
371     } while (chars_copied >= buffer.size());
372 
373     module_filespec.SetFile(&buffer[0], false);
374     return module_filespec;
375 }
376 
377 void *
378 Host::DynamicLibraryOpen(const FileSpec &file_spec, uint32_t options, Error &error)
379 {
380     error.SetErrorString("not implemented");
381     return NULL;
382 }
383 
384 Error
385 Host::DynamicLibraryClose (void *opaque)
386 {
387     Error error;
388     error.SetErrorString("not implemented");
389     return error;
390 }
391 
392 void *
393 Host::DynamicLibraryGetSymbol(void *opaque, const char *symbol_name, Error &error)
394 {
395     error.SetErrorString("not implemented");
396     return NULL;
397 }
398 
399 const char *
400 Host::GetUserName (uint32_t uid, std::string &user_name)
401 {
402     return NULL;
403 }
404 
405 const char *
406 Host::GetGroupName (uint32_t gid, std::string &group_name)
407 {
408     llvm_unreachable("Windows does not support group name");
409     return NULL;
410 }
411 
412 uint32_t
413 Host::GetUserID ()
414 {
415     llvm_unreachable("Windows does not support uid");
416 }
417 
418 uint32_t
419 Host::GetGroupID ()
420 {
421     llvm_unreachable("Windows does not support gid");
422     return 0;
423 }
424 
425 uint32_t
426 Host::GetEffectiveUserID ()
427 {
428     llvm_unreachable("Windows does not support euid");
429     return 0;
430 }
431 
432 uint32_t
433 Host::GetEffectiveGroupID ()
434 {
435     llvm_unreachable("Windows does not support egid");
436     return 0;
437 }
438 
439 uint32_t
440 Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
441 {
442     process_infos.Clear();
443 
444     AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
445     if (!snapshot.IsValid())
446         return 0;
447 
448     PROCESSENTRY32 pe = {0};
449     pe.dwSize = sizeof(PROCESSENTRY32);
450     if (Process32First(snapshot.get(), &pe))
451     {
452         do
453         {
454             AutoHandle handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID), nullptr);
455 
456             ProcessInstanceInfo process;
457             process.SetExecutableFile(FileSpec(pe.szExeFile, false), true);
458             process.SetProcessID(pe.th32ProcessID);
459             process.SetParentProcessID(pe.th32ParentProcessID);
460             GetProcessExecutableAndTriple(handle, process);
461 
462             if (match_info.MatchAllProcesses() || match_info.Matches(process))
463                 process_infos.Append(process);
464         } while (Process32Next(snapshot.get(), &pe));
465     }
466     return process_infos.GetSize();
467 }
468 
469 bool
470 Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
471 {
472     process_info.Clear();
473 
474     AutoHandle handle(::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid),
475                       nullptr);
476     if (!handle.IsValid())
477         return false;
478 
479     process_info.SetProcessID(pid);
480     GetProcessExecutableAndTriple(handle, process_info);
481 
482     // Need to read the PEB to get parent process and command line arguments.
483     return true;
484 }
485 
486 lldb::thread_t
487 Host::StartMonitoringChildProcess
488 (
489     Host::MonitorChildProcessCallback callback,
490     void *callback_baton,
491     lldb::pid_t pid,
492     bool monitor_signals
493 )
494 {
495     return LLDB_INVALID_HOST_THREAD;
496 }