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