blob: 7f705967d987abed713333f4467cc1e32fe3e82d [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"
23#include "lldb/Core/DataBufferHeap.h"
24#include "lldb/Core/DataExtractor.h"
Zachary Turner310035a2014-07-08 04:52:15 +000025#include "lldb/Core/StreamFile.h"
Enrico Granatad02d1e02015-02-20 22:43:17 +000026#include "lldb/Core/StructuredData.h"
Zachary Turner310035a2014-07-08 04:52:15 +000027
28// Windows includes
29#include <TlHelp32.h>
Virgile Bellob2f1fb22013-08-23 12:44:05 +000030
31using namespace lldb;
32using namespace lldb_private;
33
Zachary Turner310035a2014-07-08 04:52:15 +000034namespace
35{
36 bool GetTripleForProcess(const FileSpec &executable, llvm::Triple &triple)
37 {
38 // Open the PE File as a binary file, and parse just enough information to determine the
39 // machine type.
40 File imageBinary(
41 executable.GetPath().c_str(),
42 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);
63
64 return true;
65 }
66
67 bool GetExecutableForProcess(const AutoHandle &handle, std::string &path)
68 {
69 // Get the process image path. MAX_PATH isn't long enough, paths can actually be up to 32KB.
70 std::vector<char> buffer(32768);
71 DWORD dwSize = buffer.size();
72 if (!::QueryFullProcessImageNameA(handle.get(), 0, &buffer[0], &dwSize))
73 return false;
74 path.assign(&buffer[0]);
75 return true;
76 }
77
78 void GetProcessExecutableAndTriple(const AutoHandle &handle, ProcessInstanceInfo &process)
79 {
80 // We may not have permissions to read the path from the process. So start off by
81 // setting the executable file to whatever Toolhelp32 gives us, and then try to
82 // enhance this with more detailed information, but fail gracefully.
83 std::string executable;
84 llvm::Triple triple;
85 triple.setVendor(llvm::Triple::PC);
86 triple.setOS(llvm::Triple::Win32);
87 triple.setArch(llvm::Triple::UnknownArch);
88 if (GetExecutableForProcess(handle, executable))
89 {
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
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000100lldb::DataBufferSP
101Host::GetAuxvData(lldb_private::Process *process)
102{
103 return 0;
104}
105
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000106lldb::tid_t
107Host::GetCurrentThreadID()
108{
109 return lldb::tid_t(::GetCurrentThreadId());
110}
111
112lldb::thread_t
113Host::GetCurrentThread ()
114{
115 return lldb::thread_t(::GetCurrentThread());
116}
117
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000118lldb::thread_key_t
119Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback)
120{
121 return TlsAlloc();
122}
123
124void*
125Host::ThreadLocalStorageGet(lldb::thread_key_t key)
126{
127 return ::TlsGetValue (key);
128}
129
130void
131Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value)
132{
133 ::TlsSetValue (key, value);
134}
135
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000136void
137Host::Kill(lldb::pid_t pid, int signo)
138{
139 TerminateProcess((HANDLE) pid, 1);
140}
141
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000142
143const char *
144Host::GetSignalAsCString(int signo)
145{
146 return NULL;
147}
148
149FileSpec
150Host::GetModuleFileSpecForHostAddress (const void *host_addr)
151{
152 FileSpec module_filespec;
Zachary Turnerc9bf0c72014-07-18 20:36:08 +0000153
154 HMODULE hmodule = NULL;
155 if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)host_addr, &hmodule))
156 return module_filespec;
157
158 std::vector<char> buffer(MAX_PATH);
159 DWORD chars_copied = 0;
160 do {
161 chars_copied = ::GetModuleFileName(hmodule, &buffer[0], buffer.size());
162 if (chars_copied == buffer.size() && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
163 buffer.resize(buffer.size() * 2);
164 } while (chars_copied >= buffer.size());
165
166 module_filespec.SetFile(&buffer[0], false);
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000167 return module_filespec;
168}
169
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000170uint32_t
Zachary Turner310035a2014-07-08 04:52:15 +0000171Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
172{
173 process_infos.Clear();
174
175 AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
176 if (!snapshot.IsValid())
177 return 0;
178
179 PROCESSENTRY32 pe = {0};
180 pe.dwSize = sizeof(PROCESSENTRY32);
181 if (Process32First(snapshot.get(), &pe))
182 {
183 do
184 {
185 AutoHandle handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID), nullptr);
186
187 ProcessInstanceInfo process;
188 process.SetExecutableFile(FileSpec(pe.szExeFile, false), true);
189 process.SetProcessID(pe.th32ProcessID);
190 process.SetParentProcessID(pe.th32ParentProcessID);
191 GetProcessExecutableAndTriple(handle, process);
192
193 if (match_info.MatchAllProcesses() || match_info.Matches(process))
194 process_infos.Append(process);
195 } while (Process32Next(snapshot.get(), &pe));
196 }
197 return process_infos.GetSize();
198}
199
200bool
201Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
202{
203 process_info.Clear();
204
205 AutoHandle handle(::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid),
206 nullptr);
207 if (!handle.IsValid())
208 return false;
209
210 process_info.SetProcessID(pid);
211 GetProcessExecutableAndTriple(handle, process_info);
212
213 // Need to read the PEB to get parent process and command line arguments.
214 return true;
215}
216
Zachary Turner39de3112014-09-09 20:54:56 +0000217HostThread
218Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, void *callback_baton, lldb::pid_t pid, bool monitor_signals)
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000219{
Zachary Turner39de3112014-09-09 20:54:56 +0000220 return HostThread();
Enrico Granata83a14372015-02-20 21:48:38 +0000221}
222
223Error
Enrico Granatab38ef8c2015-02-20 22:20:30 +0000224Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
Enrico Granata83a14372015-02-20 21:48:38 +0000225{
226 Error error;
Enrico Granatab38ef8c2015-02-20 22:20:30 +0000227 if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments))
Enrico Granata83a14372015-02-20 21:48:38 +0000228 {
Enrico Granatab38ef8c2015-02-20 22:20:30 +0000229 FileSpec expand_tool_spec;
230 if (!HostInfo::GetLLDBPath(lldb::ePathTypeSupportExecutableDir, expand_tool_spec))
Enrico Granata83a14372015-02-20 21:48:38 +0000231 {
232 error.SetErrorString("could not find argdumper tool");
233 return error;
234 }
Enrico Granatab38ef8c2015-02-20 22:20:30 +0000235 expand_tool_spec.AppendPathComponent("argdumper.exe");
236 if (!expand_tool_spec.Exists())
Enrico Granata83a14372015-02-20 21:48:38 +0000237 {
238 error.SetErrorString("could not find argdumper tool");
239 return error;
240 }
241
242 std::string quoted_cmd_string;
243 launch_info.GetArguments().GetQuotedCommandString(quoted_cmd_string);
244 std::replace(quoted_cmd_string.begin(), quoted_cmd_string.end(), '\\', '/');
Enrico Granatab38ef8c2015-02-20 22:20:30 +0000245 StreamString expand_command;
Enrico Granata83a14372015-02-20 21:48:38 +0000246
Enrico Granatab38ef8c2015-02-20 22:20:30 +0000247 expand_command.Printf("%s %s",
248 expand_tool_spec.GetPath().c_str(),
249 quoted_cmd_string.c_str());
Enrico Granata83a14372015-02-20 21:48:38 +0000250
251 int status;
252 std::string output;
Enrico Granatab38ef8c2015-02-20 22:20:30 +0000253 RunShellCommand(expand_command.GetData(), launch_info.GetWorkingDirectory(), &status, nullptr, &output, 10);
Enrico Granata83a14372015-02-20 21:48:38 +0000254
255 if (status != 0)
256 {
257 error.SetErrorStringWithFormat("argdumper exited with error %d", status);
258 return error;
259 }
260
261 auto data_sp = StructuredData::ParseJSON(output);
262 if (!data_sp)
263 {
264 error.SetErrorString("invalid JSON");
265 return error;
266 }
267
268 auto dict_sp = data_sp->GetAsDictionary();
269 if (!data_sp)
270 {
271 error.SetErrorString("invalid JSON");
272 return error;
273 }
274
275 auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
276 if (!args_sp)
277 {
278 error.SetErrorString("invalid JSON");
279 return error;
280 }
281
282 auto args_array_sp = args_sp->GetAsArray();
283 if (!args_array_sp)
284 {
285 error.SetErrorString("invalid JSON");
286 return error;
287 }
288
289 launch_info.GetArguments().Clear();
290
291 for (size_t i = 0;
292 i < args_array_sp->GetSize();
293 i++)
294 {
295 auto item_sp = args_array_sp->GetItemAtIndex(i);
296 if (!item_sp)
297 continue;
298 auto str_sp = item_sp->GetAsString();
299 if (!str_sp)
300 continue;
301
302 launch_info.GetArguments().AppendArgument(str_sp->GetValue().c_str());
303 }
304 }
305
306 return error;
307}