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/Host/HostInfo.h"
24 #include "lldb/Core/DataBufferHeap.h"
25 #include "lldb/Core/DataExtractor.h"
26 #include "lldb/Core/StreamFile.h"
27 #include "lldb/Core/StructuredData.h"
28 
29 #include "llvm/Support/ConvertUTF.h"
30 
31 // Windows includes
32 #include <TlHelp32.h>
33 
34 using namespace lldb;
35 using namespace lldb_private;
36 
37 namespace
38 {
39     bool GetTripleForProcess(const FileSpec &executable, llvm::Triple &triple)
40     {
41         // Open the PE File as a binary file, and parse just enough information to determine the
42         // machine type.
43         File imageBinary(
44             executable.GetPath().c_str(),
45             File::eOpenOptionRead,
46             lldb::eFilePermissionsUserRead);
47         imageBinary.SeekFromStart(0x3c);
48         int32_t peOffset = 0;
49         uint32_t peHead = 0;
50         uint16_t machineType = 0;
51         size_t readSize = sizeof(peOffset);
52         imageBinary.Read(&peOffset, readSize);
53         imageBinary.SeekFromStart(peOffset);
54         imageBinary.Read(&peHead, readSize);
55         if (peHead != 0x00004550) // "PE\0\0", little-endian
56             return false;       // Error: Can't find PE header
57         readSize = 2;
58         imageBinary.Read(&machineType, readSize);
59         triple.setVendor(llvm::Triple::PC);
60         triple.setOS(llvm::Triple::Win32);
61         triple.setArch(llvm::Triple::UnknownArch);
62         if (machineType == 0x8664)
63             triple.setArch(llvm::Triple::x86_64);
64         else if (machineType == 0x14c)
65             triple.setArch(llvm::Triple::x86);
66 
67         return true;
68     }
69 
70     bool GetExecutableForProcess(const AutoHandle &handle, std::string &path)
71     {
72         // Get the process image path.  MAX_PATH isn't long enough, paths can actually be up to 32KB.
73         std::vector<wchar_t> buffer(PATH_MAX);
74         DWORD dwSize = buffer.size();
75         if (!::QueryFullProcessImageNameW(handle.get(), 0, &buffer[0], &dwSize))
76             return false;
77         return llvm::convertWideToUTF8(buffer.data(), path);
78     }
79 
80     void GetProcessExecutableAndTriple(const AutoHandle &handle, ProcessInstanceInfo &process)
81     {
82         // We may not have permissions to read the path from the process.  So start off by
83         // setting the executable file to whatever Toolhelp32 gives us, and then try to
84         // enhance this with more detailed information, but fail gracefully.
85         std::string executable;
86         llvm::Triple triple;
87         triple.setVendor(llvm::Triple::PC);
88         triple.setOS(llvm::Triple::Win32);
89         triple.setArch(llvm::Triple::UnknownArch);
90         if (GetExecutableForProcess(handle, executable))
91         {
92             FileSpec executableFile(executable.c_str(), false);
93             process.SetExecutableFile(executableFile, true);
94             GetTripleForProcess(executableFile, triple);
95         }
96         process.SetArchitecture(ArchSpec(triple));
97 
98         // TODO(zturner): Add the ability to get the process user name.
99     }
100 }
101 
102 lldb::DataBufferSP
103 Host::GetAuxvData(lldb_private::Process *process)
104 {
105     return 0;
106 }
107 
108 lldb::tid_t
109 Host::GetCurrentThreadID()
110 {
111     return lldb::tid_t(::GetCurrentThreadId());
112 }
113 
114 lldb::thread_t
115 Host::GetCurrentThread ()
116 {
117     return lldb::thread_t(::GetCurrentThread());
118 }
119 
120 lldb::thread_key_t
121 Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback)
122 {
123     return TlsAlloc();
124 }
125 
126 void*
127 Host::ThreadLocalStorageGet(lldb::thread_key_t key)
128 {
129     return ::TlsGetValue (key);
130 }
131 
132 void
133 Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value)
134 {
135    ::TlsSetValue (key, value);
136 }
137 
138 void
139 Host::Kill(lldb::pid_t pid, int signo)
140 {
141     TerminateProcess((HANDLE) pid, 1);
142 }
143 
144 
145 const char *
146 Host::GetSignalAsCString(int signo)
147 {
148     return NULL;
149 }
150 
151 FileSpec
152 Host::GetModuleFileSpecForHostAddress (const void *host_addr)
153 {
154     FileSpec module_filespec;
155 
156     HMODULE hmodule = NULL;
157     if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)host_addr, &hmodule))
158         return module_filespec;
159 
160     std::vector<wchar_t> buffer(PATH_MAX);
161     DWORD chars_copied = 0;
162     do {
163         chars_copied = ::GetModuleFileNameW(hmodule, &buffer[0], buffer.size());
164         if (chars_copied == buffer.size() && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
165             buffer.resize(buffer.size() * 2);
166     } while (chars_copied >= buffer.size());
167     std::string path;
168     if (!llvm::convertWideToUTF8(buffer.data(), path))
169         return module_filespec;
170     module_filespec.SetFile(path, false);
171     return module_filespec;
172 }
173 
174 uint32_t
175 Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
176 {
177     process_infos.Clear();
178 
179     AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
180     if (!snapshot.IsValid())
181         return 0;
182 
183     PROCESSENTRY32W pe = {0};
184     pe.dwSize = sizeof(PROCESSENTRY32W);
185     if (Process32FirstW(snapshot.get(), &pe))
186     {
187         do
188         {
189             AutoHandle handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID), nullptr);
190 
191             ProcessInstanceInfo process;
192             std::string exeFile;
193             llvm::convertWideToUTF8(pe.szExeFile, exeFile);
194             process.SetExecutableFile(FileSpec(exeFile, false), true);
195             process.SetProcessID(pe.th32ProcessID);
196             process.SetParentProcessID(pe.th32ParentProcessID);
197             GetProcessExecutableAndTriple(handle, process);
198 
199             if (match_info.MatchAllProcesses() || match_info.Matches(process))
200                 process_infos.Append(process);
201         } while (Process32NextW(snapshot.get(), &pe));
202     }
203     return process_infos.GetSize();
204 }
205 
206 bool
207 Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
208 {
209     process_info.Clear();
210 
211     AutoHandle handle(::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid),
212                       nullptr);
213     if (!handle.IsValid())
214         return false;
215 
216     process_info.SetProcessID(pid);
217     GetProcessExecutableAndTriple(handle, process_info);
218 
219     // Need to read the PEB to get parent process and command line arguments.
220     return true;
221 }
222 
223 HostThread
224 Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, void *callback_baton, lldb::pid_t pid, bool monitor_signals)
225 {
226     return HostThread();
227 }
228 
229 Error
230 Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
231 {
232     Error error;
233     if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments))
234     {
235         FileSpec expand_tool_spec;
236         if (!HostInfo::GetLLDBPath(lldb::ePathTypeSupportExecutableDir, expand_tool_spec))
237         {
238             error.SetErrorString("could not find support executable directory for the lldb-argdumper tool");
239             return error;
240         }
241         expand_tool_spec.AppendPathComponent("lldb-argdumper.exe");
242         if (!expand_tool_spec.Exists())
243         {
244             error.SetErrorString("could not find the lldb-argdumper tool");
245             return error;
246         }
247 
248         std::string quoted_cmd_string;
249         launch_info.GetArguments().GetQuotedCommandString(quoted_cmd_string);
250         std::replace(quoted_cmd_string.begin(), quoted_cmd_string.end(), '\\', '/');
251         StreamString expand_command;
252 
253         expand_command.Printf("\"%s\" %s",
254                               expand_tool_spec.GetPath().c_str(),
255                               quoted_cmd_string.c_str());
256 
257         int status;
258         std::string output;
259         RunShellCommand(expand_command.GetData(), launch_info.GetWorkingDirectory(), &status, nullptr, &output, 10);
260 
261         if (status != 0)
262         {
263             error.SetErrorStringWithFormat("lldb-argdumper exited with error %d", status);
264             return error;
265         }
266 
267         auto data_sp = StructuredData::ParseJSON(output);
268         if (!data_sp)
269         {
270             error.SetErrorString("invalid JSON");
271             return error;
272         }
273 
274         auto dict_sp = data_sp->GetAsDictionary();
275         if (!data_sp)
276         {
277             error.SetErrorString("invalid JSON");
278             return error;
279         }
280 
281         auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
282         if (!args_sp)
283         {
284             error.SetErrorString("invalid JSON");
285             return error;
286         }
287 
288         auto args_array_sp = args_sp->GetAsArray();
289         if (!args_array_sp)
290         {
291             error.SetErrorString("invalid JSON");
292             return error;
293         }
294 
295         launch_info.GetArguments().Clear();
296 
297         for (size_t i = 0;
298              i < args_array_sp->GetSize();
299              i++)
300         {
301             auto item_sp = args_array_sp->GetItemAtIndex(i);
302             if (!item_sp)
303                 continue;
304             auto str_sp = item_sp->GetAsString();
305             if (!str_sp)
306                 continue;
307 
308             launch_info.GetArguments().AppendArgument(str_sp->GetValue().c_str());
309         }
310     }
311 
312     return error;
313 }
314 
315 size_t
316 Host::GetEnvironment(StringList &env)
317 {
318     // The environment block on Windows is a contiguous buffer of NULL terminated strings,
319     // where the end of the environment block is indicated by two consecutive NULLs.
320     LPWCH environment_block = ::GetEnvironmentStringsW();
321     env.Clear();
322     while (*environment_block != L'\0')
323     {
324         std::string current_var;
325         auto current_var_size = wcslen(environment_block) + 1;
326         if (!llvm::convertWideToUTF8(environment_block, current_var))
327         {
328             environment_block += current_var_size;
329             continue;
330         }
331         if (current_var[0] != '=')
332             env.AppendString(current_var);
333 
334         environment_block += current_var_size;
335     }
336     return env.GetSize();
337 }
338