blob: e4a6ebe07f1cfbe776acbf9c837ea465d40b2fd1 [file] [log] [blame]
Virgile Bellob2f1fb22013-08-23 12:44:05 +00001//===-- 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
Zachary Turner310035a2014-07-08 04:52:15 +000011#include "lldb/Host/windows/AutoHandle.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000012#include "lldb/Host/windows/windows.h"
13#include <stdio.h>
Virgile Bellob2f1fb22013-08-23 12:44:05 +000014
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
Virgile Bellob2f1fb22013-08-23 12:44:05 +000022#include "lldb/Core/DataBufferHeap.h"
23#include "lldb/Core/DataExtractor.h"
Zachary Turner310035a2014-07-08 04:52:15 +000024#include "lldb/Core/StreamFile.h"
Enrico Granatad02d1e02015-02-20 22:43:17 +000025#include "lldb/Core/StructuredData.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000026#include "lldb/Host/Host.h"
27#include "lldb/Host/HostInfo.h"
Zachary Turner310035a2014-07-08 04:52:15 +000028
Zachary Turner190fadc2016-03-22 17:58:09 +000029#include "llvm/Support/ConvertUTF.h"
30
Zachary Turner310035a2014-07-08 04:52:15 +000031// Windows includes
32#include <TlHelp32.h>
Virgile Bellob2f1fb22013-08-23 12:44:05 +000033
34using namespace lldb;
35using namespace lldb_private;
36
Kate Stoneb9c1b512016-09-06 20:57:50 +000037namespace {
38bool 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; // Error: 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);
Zachary Turner310035a2014-07-08 04:52:15 +000063
Kate Stoneb9c1b512016-09-06 20:57:50 +000064 return true;
Zachary Turner310035a2014-07-08 04:52:15 +000065}
66
Kate Stoneb9c1b512016-09-06 20:57:50 +000067bool 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);
Virgile Bellob2f1fb22013-08-23 12:44:05 +000075}
76
Kate Stoneb9c1b512016-09-06 20:57:50 +000077void 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}
Virgile Bellob2f1fb22013-08-23 12:44:05 +000098}
99
Kate Stoneb9c1b512016-09-06 20:57:50 +0000100lldb::DataBufferSP Host::GetAuxvData(lldb_private::Process *process) {
101 return 0;
102}
103
104lldb::tid_t Host::GetCurrentThreadID() {
105 return lldb::tid_t(::GetCurrentThreadId());
106}
107
108lldb::thread_t Host::GetCurrentThread() {
109 return lldb::thread_t(::GetCurrentThread());
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000110}
111
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000112lldb::thread_key_t
Kate Stoneb9c1b512016-09-06 20:57:50 +0000113Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback) {
114 return TlsAlloc();
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000115}
116
Kate Stoneb9c1b512016-09-06 20:57:50 +0000117void *Host::ThreadLocalStorageGet(lldb::thread_key_t key) {
118 return ::TlsGetValue(key);
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000119}
120
Kate Stoneb9c1b512016-09-06 20:57:50 +0000121void Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value) {
122 ::TlsSetValue(key, value);
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000123}
124
Kate Stoneb9c1b512016-09-06 20:57:50 +0000125void Host::Kill(lldb::pid_t pid, int signo) {
126 TerminateProcess((HANDLE)pid, 1);
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000127}
128
Kate Stoneb9c1b512016-09-06 20:57:50 +0000129const char *Host::GetSignalAsCString(int signo) { return NULL; }
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000130
Kate Stoneb9c1b512016-09-06 20:57:50 +0000131FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) {
132 FileSpec module_filespec;
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000133
Kate Stoneb9c1b512016-09-06 20:57:50 +0000134 HMODULE hmodule = NULL;
135 if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
136 (LPCTSTR)host_addr, &hmodule))
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000137 return module_filespec;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000138
139 std::vector<wchar_t> buffer(PATH_MAX);
140 DWORD chars_copied = 0;
141 do {
142 chars_copied = ::GetModuleFileNameW(hmodule, &buffer[0], buffer.size());
143 if (chars_copied == buffer.size() &&
144 ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
145 buffer.resize(buffer.size() * 2);
146 } while (chars_copied >= buffer.size());
147 std::string path;
148 if (!llvm::convertWideToUTF8(buffer.data(), path))
149 return module_filespec;
150 module_filespec.SetFile(path, false);
151 return module_filespec;
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000152}
153
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info,
155 ProcessInstanceInfoList &process_infos) {
156 process_infos.Clear();
Zachary Turner310035a2014-07-08 04:52:15 +0000157
Kate Stoneb9c1b512016-09-06 20:57:50 +0000158 AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
159 if (!snapshot.IsValid())
160 return 0;
Zachary Turner310035a2014-07-08 04:52:15 +0000161
Kate Stoneb9c1b512016-09-06 20:57:50 +0000162 PROCESSENTRY32W pe = {0};
163 pe.dwSize = sizeof(PROCESSENTRY32W);
164 if (Process32FirstW(snapshot.get(), &pe)) {
165 do {
166 AutoHandle handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE,
167 pe.th32ProcessID),
168 nullptr);
Zachary Turner310035a2014-07-08 04:52:15 +0000169
Kate Stoneb9c1b512016-09-06 20:57:50 +0000170 ProcessInstanceInfo process;
171 std::string exeFile;
172 llvm::convertWideToUTF8(pe.szExeFile, exeFile);
173 process.SetExecutableFile(FileSpec(exeFile, false), true);
174 process.SetProcessID(pe.th32ProcessID);
175 process.SetParentProcessID(pe.th32ParentProcessID);
176 GetProcessExecutableAndTriple(handle, process);
Zachary Turner310035a2014-07-08 04:52:15 +0000177
Kate Stoneb9c1b512016-09-06 20:57:50 +0000178 if (match_info.MatchAllProcesses() || match_info.Matches(process))
179 process_infos.Append(process);
180 } while (Process32NextW(snapshot.get(), &pe));
181 }
182 return process_infos.GetSize();
183}
184
185bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
186 process_info.Clear();
187
188 AutoHandle handle(
189 ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid),
190 nullptr);
191 if (!handle.IsValid())
192 return false;
193
194 process_info.SetProcessID(pid);
195 GetProcessExecutableAndTriple(handle, process_info);
196
197 // Need to read the PEB to get parent process and command line arguments.
198 return true;
199}
200
201HostThread Host::StartMonitoringChildProcess(
202 const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid,
203 bool monitor_signals) {
204 return HostThread();
205}
206
207Error Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
208 Error error;
209 if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) {
210 FileSpec expand_tool_spec;
211 if (!HostInfo::GetLLDBPath(lldb::ePathTypeSupportExecutableDir,
212 expand_tool_spec)) {
213 error.SetErrorString("could not find support executable directory for "
214 "the lldb-argdumper tool");
215 return error;
Zachary Turner310035a2014-07-08 04:52:15 +0000216 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000217 expand_tool_spec.AppendPathComponent("lldb-argdumper.exe");
218 if (!expand_tool_spec.Exists()) {
219 error.SetErrorString("could not find the lldb-argdumper tool");
220 return error;
Enrico Granata83a14372015-02-20 21:48:38 +0000221 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000222
223 std::string quoted_cmd_string;
224 launch_info.GetArguments().GetQuotedCommandString(quoted_cmd_string);
225 std::replace(quoted_cmd_string.begin(), quoted_cmd_string.end(), '\\', '/');
226 StreamString expand_command;
227
228 expand_command.Printf("\"%s\" %s", expand_tool_spec.GetPath().c_str(),
229 quoted_cmd_string.c_str());
230
231 int status;
232 std::string output;
233 RunShellCommand(expand_command.GetData(), launch_info.GetWorkingDirectory(),
234 &status, nullptr, &output, 10);
235
236 if (status != 0) {
237 error.SetErrorStringWithFormat("lldb-argdumper exited with error %d",
238 status);
239 return error;
240 }
241
242 auto data_sp = StructuredData::ParseJSON(output);
243 if (!data_sp) {
244 error.SetErrorString("invalid JSON");
245 return error;
246 }
247
248 auto dict_sp = data_sp->GetAsDictionary();
249 if (!data_sp) {
250 error.SetErrorString("invalid JSON");
251 return error;
252 }
253
254 auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
255 if (!args_sp) {
256 error.SetErrorString("invalid JSON");
257 return error;
258 }
259
260 auto args_array_sp = args_sp->GetAsArray();
261 if (!args_array_sp) {
262 error.SetErrorString("invalid JSON");
263 return error;
264 }
265
266 launch_info.GetArguments().Clear();
267
268 for (size_t i = 0; i < args_array_sp->GetSize(); i++) {
269 auto item_sp = args_array_sp->GetItemAtIndex(i);
270 if (!item_sp)
271 continue;
272 auto str_sp = item_sp->GetAsString();
273 if (!str_sp)
274 continue;
275
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000276 launch_info.GetArguments().AppendArgument(str_sp->GetValue());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000277 }
278 }
279
280 return error;
Enrico Granata83a14372015-02-20 21:48:38 +0000281}
Zachary Turner279a2b72015-05-22 19:34:17 +0000282
Kate Stoneb9c1b512016-09-06 20:57:50 +0000283size_t Host::GetEnvironment(StringList &env) {
284 // The environment block on Windows is a contiguous buffer of NULL terminated
285 // strings,
286 // where the end of the environment block is indicated by two consecutive
287 // NULLs.
288 LPWCH environment_block = ::GetEnvironmentStringsW();
289 env.Clear();
290 while (*environment_block != L'\0') {
291 std::string current_var;
292 auto current_var_size = wcslen(environment_block) + 1;
293 if (!llvm::convertWideToUTF8(environment_block, current_var)) {
294 environment_block += current_var_size;
295 continue;
Zachary Turner279a2b72015-05-22 19:34:17 +0000296 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000297 if (current_var[0] != '=')
298 env.AppendString(current_var);
299
300 environment_block += current_var_size;
301 }
302 return env.GetSize();
Zachary Turner279a2b72015-05-22 19:34:17 +0000303}