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