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/Host.h"
19 #include "lldb/Host/HostInfo.h"
20 #include "lldb/Target/Process.h"
21 #include "lldb/Utility/DataBufferHeap.h"
22 #include "lldb/Utility/DataExtractor.h"
23 #include "lldb/Utility/Log.h"
24 #include "lldb/Utility/Status.h"
25 #include "lldb/Utility/StructuredData.h"
26 
27 #include "llvm/Support/ConvertUTF.h"
28 
29 // Windows includes
30 #include <tlhelp32.h>
31 
32 using namespace lldb;
33 using namespace lldb_private;
34 
35 namespace {
36 bool GetTripleForProcess(const FileSpec &executable, llvm::Triple &triple) {
37   // Open the PE File as a binary file, and parse just enough information to
38   // determine the
39   // machine type.
40   File imageBinary(executable.GetPath().c_str(), File::eOpenOptionRead,
41                    lldb::eFilePermissionsUserRead);
42   imageBinary.SeekFromStart(0x3c);
43   int32_t peOffset = 0;
44   uint32_t peHead = 0;
45   uint16_t machineType = 0;
46   size_t readSize = sizeof(peOffset);
47   imageBinary.Read(&peOffset, readSize);
48   imageBinary.SeekFromStart(peOffset);
49   imageBinary.Read(&peHead, readSize);
50   if (peHead != 0x00004550) // "PE\0\0", little-endian
51     return false;           // Status: Can't find PE header
52   readSize = 2;
53   imageBinary.Read(&machineType, readSize);
54   triple.setVendor(llvm::Triple::PC);
55   triple.setOS(llvm::Triple::Win32);
56   triple.setArch(llvm::Triple::UnknownArch);
57   if (machineType == 0x8664)
58     triple.setArch(llvm::Triple::x86_64);
59   else if (machineType == 0x14c)
60     triple.setArch(llvm::Triple::x86);
61 
62   return true;
63 }
64 
65 bool GetExecutableForProcess(const AutoHandle &handle, std::string &path) {
66   // Get the process image path.  MAX_PATH isn't long enough, paths can actually
67   // be up to 32KB.
68   std::vector<wchar_t> buffer(PATH_MAX);
69   DWORD dwSize = buffer.size();
70   if (!::QueryFullProcessImageNameW(handle.get(), 0, &buffer[0], &dwSize))
71     return false;
72   return llvm::convertWideToUTF8(buffer.data(), path);
73 }
74 
75 void GetProcessExecutableAndTriple(const AutoHandle &handle,
76                                    ProcessInstanceInfo &process) {
77   // We may not have permissions to read the path from the process.  So start
78   // off by
79   // setting the executable file to whatever Toolhelp32 gives us, and then try
80   // to
81   // enhance this with more detailed information, but fail 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(), false);
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, false);
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, false), 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;
188     if (!HostInfo::GetLLDBPath(lldb::ePathTypeSupportExecutableDir,
189                                expand_tool_spec)) {
190       error.SetErrorString("could not find support executable directory for "
191                            "the lldb-argdumper tool");
192       return error;
193     }
194     expand_tool_spec.AppendPathComponent("lldb-argdumper.exe");
195     if (!expand_tool_spec.Exists()) {
196       error.SetErrorString("could not find the lldb-argdumper tool");
197       return error;
198     }
199 
200     std::string quoted_cmd_string;
201     launch_info.GetArguments().GetQuotedCommandString(quoted_cmd_string);
202     std::replace(quoted_cmd_string.begin(), quoted_cmd_string.end(), '\\', '/');
203     StreamString expand_command;
204 
205     expand_command.Printf("\"%s\" %s", expand_tool_spec.GetPath().c_str(),
206                           quoted_cmd_string.c_str());
207 
208     int status;
209     std::string output;
210     std::string command = expand_command.GetString();
211     RunShellCommand(command.c_str(), launch_info.GetWorkingDirectory(), &status,
212                     nullptr, &output, 10);
213 
214     if (status != 0) {
215       error.SetErrorStringWithFormat("lldb-argdumper exited with error %d",
216                                      status);
217       return error;
218     }
219 
220     auto data_sp = StructuredData::ParseJSON(output);
221     if (!data_sp) {
222       error.SetErrorString("invalid JSON");
223       return error;
224     }
225 
226     auto dict_sp = data_sp->GetAsDictionary();
227     if (!data_sp) {
228       error.SetErrorString("invalid JSON");
229       return error;
230     }
231 
232     auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
233     if (!args_sp) {
234       error.SetErrorString("invalid JSON");
235       return error;
236     }
237 
238     auto args_array_sp = args_sp->GetAsArray();
239     if (!args_array_sp) {
240       error.SetErrorString("invalid JSON");
241       return error;
242     }
243 
244     launch_info.GetArguments().Clear();
245 
246     for (size_t i = 0; i < args_array_sp->GetSize(); i++) {
247       auto item_sp = args_array_sp->GetItemAtIndex(i);
248       if (!item_sp)
249         continue;
250       auto str_sp = item_sp->GetAsString();
251       if (!str_sp)
252         continue;
253 
254       launch_info.GetArguments().AppendArgument(str_sp->GetValue());
255     }
256   }
257 
258   return error;
259 }
260 
261 Environment Host::GetEnvironment() {
262   Environment env;
263   // The environment block on Windows is a contiguous buffer of NULL terminated
264   // strings, where the end of the environment block is indicated by two
265   // consecutive NULLs.
266   LPWCH environment_block = ::GetEnvironmentStringsW();
267   while (*environment_block != L'\0') {
268     std::string current_var;
269     auto current_var_size = wcslen(environment_block) + 1;
270     if (!llvm::convertWideToUTF8(environment_block, current_var)) {
271       environment_block += current_var_size;
272       continue;
273     }
274     if (current_var[0] != '=')
275       env.insert(current_var);
276 
277     environment_block += current_var_size;
278   }
279   return env;
280 }
281