blob: 5439467708b5a2fa1e6f917dcb84b7b8d23a2c07 [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
11#include <stdio.h>
12#include "lldb/Host/windows/windows.h"
Zachary Turner310035a2014-07-08 04:52:15 +000013#include "lldb/Host/windows/AutoHandle.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
22#include "lldb/Host/Host.h"
Zachary Turnerfc21d412015-02-21 04:45:12 +000023#include "lldb/Host/HostInfo.h"
Virgile Bellob2f1fb22013-08-23 12:44:05 +000024#include "lldb/Core/DataBufferHeap.h"
25#include "lldb/Core/DataExtractor.h"
Zachary Turner310035a2014-07-08 04:52:15 +000026#include "lldb/Core/StreamFile.h"
Enrico Granatad02d1e02015-02-20 22:43:17 +000027#include "lldb/Core/StructuredData.h"
Zachary Turner310035a2014-07-08 04:52:15 +000028
29// Windows includes
30#include <TlHelp32.h>
Virgile Bellob2f1fb22013-08-23 12:44:05 +000031
32using namespace lldb;
33using namespace lldb_private;
34
Zachary Turner310035a2014-07-08 04:52:15 +000035namespace
36{
37 bool GetTripleForProcess(const FileSpec &executable, llvm::Triple &triple)
38 {
39 // Open the PE File as a binary file, and parse just enough information to determine the
40 // machine type.
41 File imageBinary(
42 executable.GetPath().c_str(),
43 File::eOpenOptionRead,
44 lldb::eFilePermissionsUserRead);
45 imageBinary.SeekFromStart(0x3c);
46 int32_t peOffset = 0;
47 uint32_t peHead = 0;
48 uint16_t machineType = 0;
49 size_t readSize = sizeof(peOffset);
50 imageBinary.Read(&peOffset, readSize);
51 imageBinary.SeekFromStart(peOffset);
52 imageBinary.Read(&peHead, readSize);
53 if (peHead != 0x00004550) // "PE\0\0", little-endian
54 return false; // Error: Can't find PE header
55 readSize = 2;
56 imageBinary.Read(&machineType, readSize);
57 triple.setVendor(llvm::Triple::PC);
58 triple.setOS(llvm::Triple::Win32);
59 triple.setArch(llvm::Triple::UnknownArch);
60 if (machineType == 0x8664)
61 triple.setArch(llvm::Triple::x86_64);
62 else if (machineType == 0x14c)
63 triple.setArch(llvm::Triple::x86);
64
65 return true;
66 }
67
68 bool GetExecutableForProcess(const AutoHandle &handle, std::string &path)
69 {
70 // Get the process image path. MAX_PATH isn't long enough, paths can actually be up to 32KB.
71 std::vector<char> buffer(32768);
72 DWORD dwSize = buffer.size();
73 if (!::QueryFullProcessImageNameA(handle.get(), 0, &buffer[0], &dwSize))
74 return false;
75 path.assign(&buffer[0]);
76 return true;
77 }
78
79 void GetProcessExecutableAndTriple(const AutoHandle &handle, ProcessInstanceInfo &process)
80 {
81 // We may not have permissions to read the path from the process. So start off by
82 // setting the executable file to whatever Toolhelp32 gives us, and then try 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 {
91 FileSpec executableFile(executable.c_str(), false);
92 process.SetExecutableFile(executableFile, true);
93 GetTripleForProcess(executableFile, triple);
94 }
95 process.SetArchitecture(ArchSpec(triple));
96
97 // TODO(zturner): Add the ability to get the process user name.
98 }
99}
100
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000101lldb::DataBufferSP
102Host::GetAuxvData(lldb_private::Process *process)
103{
104 return 0;
105}
106
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000107lldb::tid_t
108Host::GetCurrentThreadID()
109{
110 return lldb::tid_t(::GetCurrentThreadId());
111}
112
113lldb::thread_t
114Host::GetCurrentThread ()
115{
116 return lldb::thread_t(::GetCurrentThread());
117}
118
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000119lldb::thread_key_t
120Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback)
121{
122 return TlsAlloc();
123}
124
125void*
126Host::ThreadLocalStorageGet(lldb::thread_key_t key)
127{
128 return ::TlsGetValue (key);
129}
130
131void
132Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value)
133{
134 ::TlsSetValue (key, value);
135}
136
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000137void
138Host::Kill(lldb::pid_t pid, int signo)
139{
140 TerminateProcess((HANDLE) pid, 1);
141}
142
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000143
144const char *
145Host::GetSignalAsCString(int signo)
146{
147 return NULL;
148}
149
150FileSpec
151Host::GetModuleFileSpecForHostAddress (const void *host_addr)
152{
153 FileSpec module_filespec;
Zachary Turnerc9bf0c72014-07-18 20:36:08 +0000154
155 HMODULE hmodule = NULL;
156 if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)host_addr, &hmodule))
157 return module_filespec;
158
159 std::vector<char> buffer(MAX_PATH);
160 DWORD chars_copied = 0;
161 do {
162 chars_copied = ::GetModuleFileName(hmodule, &buffer[0], buffer.size());
163 if (chars_copied == buffer.size() && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
164 buffer.resize(buffer.size() * 2);
165 } while (chars_copied >= buffer.size());
166
167 module_filespec.SetFile(&buffer[0], false);
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000168 return module_filespec;
169}
170
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000171uint32_t
Zachary Turner310035a2014-07-08 04:52:15 +0000172Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
173{
174 process_infos.Clear();
175
176 AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
177 if (!snapshot.IsValid())
178 return 0;
179
180 PROCESSENTRY32 pe = {0};
181 pe.dwSize = sizeof(PROCESSENTRY32);
182 if (Process32First(snapshot.get(), &pe))
183 {
184 do
185 {
186 AutoHandle handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID), nullptr);
187
188 ProcessInstanceInfo process;
189 process.SetExecutableFile(FileSpec(pe.szExeFile, false), true);
190 process.SetProcessID(pe.th32ProcessID);
191 process.SetParentProcessID(pe.th32ParentProcessID);
192 GetProcessExecutableAndTriple(handle, process);
193
194 if (match_info.MatchAllProcesses() || match_info.Matches(process))
195 process_infos.Append(process);
196 } while (Process32Next(snapshot.get(), &pe));
197 }
198 return process_infos.GetSize();
199}
200
201bool
202Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
203{
204 process_info.Clear();
205
206 AutoHandle handle(::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid),
207 nullptr);
208 if (!handle.IsValid())
209 return false;
210
211 process_info.SetProcessID(pid);
212 GetProcessExecutableAndTriple(handle, process_info);
213
214 // Need to read the PEB to get parent process and command line arguments.
215 return true;
216}
217
Zachary Turner39de3112014-09-09 20:54:56 +0000218HostThread
219Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, void *callback_baton, lldb::pid_t pid, bool monitor_signals)
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000220{
Zachary Turner39de3112014-09-09 20:54:56 +0000221 return HostThread();
Enrico Granata83a14372015-02-20 21:48:38 +0000222}
223
224Error
Enrico Granatab38ef8c2015-02-20 22:20:30 +0000225Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
Enrico Granata83a14372015-02-20 21:48:38 +0000226{
227 Error error;
Enrico Granatab38ef8c2015-02-20 22:20:30 +0000228 if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments))
Enrico Granata83a14372015-02-20 21:48:38 +0000229 {
Enrico Granatab38ef8c2015-02-20 22:20:30 +0000230 FileSpec expand_tool_spec;
231 if (!HostInfo::GetLLDBPath(lldb::ePathTypeSupportExecutableDir, expand_tool_spec))
Enrico Granata83a14372015-02-20 21:48:38 +0000232 {
Todd Fiala15c0fba2015-10-29 05:07:12 +0000233 error.SetErrorString("could not find support executable directory for the lldb-argdumper tool");
Enrico Granata83a14372015-02-20 21:48:38 +0000234 return error;
235 }
Todd Fiala15c0fba2015-10-29 05:07:12 +0000236 expand_tool_spec.AppendPathComponent("lldb-argdumper.exe");
Enrico Granatab38ef8c2015-02-20 22:20:30 +0000237 if (!expand_tool_spec.Exists())
Enrico Granata83a14372015-02-20 21:48:38 +0000238 {
Todd Fiala15c0fba2015-10-29 05:07:12 +0000239 error.SetErrorString("could not find the lldb-argdumper tool");
Enrico Granata83a14372015-02-20 21:48:38 +0000240 return error;
241 }
242
243 std::string quoted_cmd_string;
244 launch_info.GetArguments().GetQuotedCommandString(quoted_cmd_string);
245 std::replace(quoted_cmd_string.begin(), quoted_cmd_string.end(), '\\', '/');
Enrico Granatab38ef8c2015-02-20 22:20:30 +0000246 StreamString expand_command;
Enrico Granata83a14372015-02-20 21:48:38 +0000247
Enrico Granatab38ef8c2015-02-20 22:20:30 +0000248 expand_command.Printf("%s %s",
249 expand_tool_spec.GetPath().c_str(),
250 quoted_cmd_string.c_str());
Enrico Granata83a14372015-02-20 21:48:38 +0000251
252 int status;
253 std::string output;
Enrico Granatab38ef8c2015-02-20 22:20:30 +0000254 RunShellCommand(expand_command.GetData(), launch_info.GetWorkingDirectory(), &status, nullptr, &output, 10);
Enrico Granata83a14372015-02-20 21:48:38 +0000255
256 if (status != 0)
257 {
Todd Fiala15c0fba2015-10-29 05:07:12 +0000258 error.SetErrorStringWithFormat("lldb-argdumper exited with error %d", status);
Enrico Granata83a14372015-02-20 21:48:38 +0000259 return error;
260 }
261
262 auto data_sp = StructuredData::ParseJSON(output);
263 if (!data_sp)
264 {
265 error.SetErrorString("invalid JSON");
266 return error;
267 }
268
269 auto dict_sp = data_sp->GetAsDictionary();
270 if (!data_sp)
271 {
272 error.SetErrorString("invalid JSON");
273 return error;
274 }
275
276 auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
277 if (!args_sp)
278 {
279 error.SetErrorString("invalid JSON");
280 return error;
281 }
282
283 auto args_array_sp = args_sp->GetAsArray();
284 if (!args_array_sp)
285 {
286 error.SetErrorString("invalid JSON");
287 return error;
288 }
289
290 launch_info.GetArguments().Clear();
291
292 for (size_t i = 0;
293 i < args_array_sp->GetSize();
294 i++)
295 {
296 auto item_sp = args_array_sp->GetItemAtIndex(i);
297 if (!item_sp)
298 continue;
299 auto str_sp = item_sp->GetAsString();
300 if (!str_sp)
301 continue;
302
303 launch_info.GetArguments().AppendArgument(str_sp->GetValue().c_str());
304 }
305 }
306
307 return error;
308}
Zachary Turner279a2b72015-05-22 19:34:17 +0000309
310size_t
311Host::GetEnvironment(StringList &env)
312{
313 // The environment block on Windows is a contiguous buffer of NULL terminated strings,
314 // where the end of the environment block is indicated by two consecutive NULLs.
315 LPCH environment_block = ::GetEnvironmentStrings();
316 env.Clear();
317 while (*environment_block != '\0')
318 {
319 llvm::StringRef current_var(environment_block);
320 if (current_var[0] != '=')
321 env.AppendString(current_var);
322
323 environment_block += current_var.size()+1;
324 }
325 return env.GetSize();
326}