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