[Go to site: main page, start]

LLDB mainline
windows/Host.cpp
Go to the documentation of this file.
1//===-- source/Host/windows/Host.cpp --------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
11#include <cstdio>
12
14#include "lldb/Host/Host.h"
15#include "lldb/Host/HostInfo.h"
19#include "lldb/Utility/Log.h"
21#include "lldb/Utility/Status.h"
24
25#include "llvm/ADT/StringRef.h"
26#include "llvm/Support/ConvertUTF.h"
27
28// Windows includes
29#include <tlhelp32.h>
30
31using namespace lldb;
32using namespace lldb_private;
33
34using llvm::sys::windows::UTF8ToUTF16;
35
36static bool GetTripleForProcess(const FileSpec &executable,
37 llvm::Triple &triple) {
38 // Open the PE File as a binary file, and parse just enough information to
39 // determine the machine type.
40 auto imageBinaryP = FileSystem::Instance().Open(
41 executable, File::eOpenOptionReadOnly, lldb::eFilePermissionsUserRead);
42 if (!imageBinaryP)
43 return llvm::errorToBool(imageBinaryP.takeError());
44 File &imageBinary = *imageBinaryP.get();
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; // Status: 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 else if (machineType == 0x1c4)
65 triple.setArch(llvm::Triple::arm);
66 else if (machineType == 0xaa64)
67 triple.setArch(llvm::Triple::aarch64);
68
69 return true;
70}
71
72static bool GetExecutableForProcess(const AutoHandle &handle,
73 std::string &path) {
74 // Get the process image path. MAX_PATH isn't long enough, paths can
75 // actually be up to 32KB.
76 std::vector<wchar_t> buffer(PATH_MAX);
77 DWORD dwSize = buffer.size();
78 if (!::QueryFullProcessImageNameW(handle.get(), 0, &buffer[0], &dwSize))
79 return false;
80 return llvm::convertWideToUTF8(buffer.data(), path);
81}
82
83static void GetProcessExecutableAndTriple(const AutoHandle &handle,
84 ProcessInstanceInfo &process) {
85 // We may not have permissions to read the path from the process. So start
86 // off by setting the executable file to whatever Toolhelp32 gives us, and
87 // then try to enhance this with more detailed information, but fail
88 // gracefully.
89 std::string executable;
90 llvm::Triple triple;
91 triple.setVendor(llvm::Triple::PC);
92 triple.setOS(llvm::Triple::Win32);
93 triple.setArch(llvm::Triple::UnknownArch);
94 if (GetExecutableForProcess(handle, executable)) {
95 FileSpec executableFile(executable.c_str());
96 process.SetExecutableFile(executableFile, true);
97 GetTripleForProcess(executableFile, triple);
98 }
99 process.SetArchitecture(ArchSpec(triple));
100
101 // TODO(zturner): Add the ability to get the process user name.
102}
103
106}
107
108void Host::Kill(lldb::pid_t pid, int signo) {
109 AutoHandle handle(::OpenProcess(PROCESS_TERMINATE, FALSE, pid), nullptr);
110 if (handle.IsValid())
111 ::TerminateProcess(handle.get(), 1);
112}
113
114const char *Host::GetSignalAsCString(int signo) { return nullptr; }
115
116FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) {
117 FileSpec module_filespec;
118
119 HMODULE hmodule = nullptr;
120 if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
121 (LPCTSTR)host_addr, &hmodule))
122 return module_filespec;
123
124 std::vector<wchar_t> buffer(PATH_MAX);
125 DWORD chars_copied = 0;
126 do {
127 chars_copied = ::GetModuleFileNameW(hmodule, &buffer[0], buffer.size());
128 if (chars_copied == buffer.size() &&
129 ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
130 buffer.resize(buffer.size() * 2);
131 } while (chars_copied >= buffer.size());
132 std::string path;
133 if (!llvm::convertWideToUTF8(buffer.data(), path))
134 return module_filespec;
135 module_filespec.SetFile(path, FileSpec::Style::native);
136 return module_filespec;
137}
138
139// CreateToolhelp32Snapshot walks a process list that other processes are
140// concurrently modifying, and fails with ERROR_BAD_LENGTH when it loses that
141// race. The documented remedy is to retry.
143 constexpr int max_attempts = 10;
144 for (int attempt = 0; attempt < max_attempts; ++attempt) {
145 HANDLE snapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
146 if (snapshot != INVALID_HANDLE_VALUE ||
147 ::GetLastError() != ERROR_BAD_LENGTH)
148 return snapshot;
149 }
150 return INVALID_HANDLE_VALUE;
151}
152
153uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
154 ProcessInstanceInfoList &process_infos) {
155 process_infos.clear();
156
157 AutoHandle snapshot(CreateProcessSnapshot());
158 if (!snapshot.IsValid())
159 return 0;
160
161 PROCESSENTRY32W pe = {};
162 pe.dwSize = sizeof(PROCESSENTRY32W);
163 if (Process32FirstW(snapshot.get(), &pe)) {
164 do {
165 AutoHandle handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE,
166 pe.th32ProcessID),
167 nullptr);
168
169 ProcessInstanceInfo process;
170 std::string exeFile;
171 llvm::convertWideToUTF8(pe.szExeFile, exeFile);
172 process.SetExecutableFile(FileSpec(exeFile), true);
173 process.SetProcessID(pe.th32ProcessID);
174 process.SetParentProcessID(pe.th32ParentProcessID);
175 GetProcessExecutableAndTriple(handle, process);
176
177 if (match_info.MatchAllProcesses() || match_info.Matches(process))
178 process_infos.push_back(process);
179 } while (Process32NextW(snapshot.get(), &pe));
180 }
181 return process_infos.size();
182}
183
185 process_info.Clear();
186
187 AutoHandle handle(
188 ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid),
189 nullptr);
190 if (!handle.IsValid())
191 return false;
192
193 process_info.SetProcessID(pid);
194 GetProcessExecutableAndTriple(handle, process_info);
195
196 AutoHandle snapshot(CreateProcessSnapshot());
197 if (!snapshot.IsValid())
198 return false;
199
200 PROCESSENTRY32W pe;
201 pe.dwSize = sizeof(PROCESSENTRY32W);
202 if (!Process32FirstW(snapshot.get(), &pe))
203 return false;
204
205 do {
206 if (pe.th32ProcessID == pid) {
207 process_info.SetParentProcessID(pe.th32ParentProcessID);
208 return true;
209 }
210 } while (Process32NextW(snapshot.get(), &pe));
211
212 return false;
213}
214
215llvm::Expected<HostThread> Host::StartMonitoringChildProcess(
216 const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid) {
217 return HostThread();
218}
219
222 if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) {
223 FileSpec expand_tool_spec = HostInfo::GetSupportExeDir();
224 if (!expand_tool_spec) {
226 "could not find support executable directory for "
227 "the lldb-argdumper tool");
228 return error;
229 }
230 expand_tool_spec.AppendPathComponent("lldb-argdumper.exe");
231 if (!FileSystem::Instance().Exists(expand_tool_spec)) {
232 error = Status::FromErrorString("could not find the lldb-argdumper tool");
233 return error;
234 }
235
236 std::string quoted_cmd_string;
237 launch_info.GetArguments().GetQuotedCommandString(quoted_cmd_string);
238 std::replace(quoted_cmd_string.begin(), quoted_cmd_string.end(), '\\', '/');
239 StreamString expand_command;
240
241 expand_command.Printf("\"%s\" %s", expand_tool_spec.GetPath().c_str(),
242 quoted_cmd_string.c_str());
243
244 int status;
245 std::string output;
246 std::string command = expand_command.GetString().str();
248 command.c_str(), launch_info.GetWorkingDirectory(), &status, nullptr,
249 &output, nullptr, std::chrono::seconds(10));
250
251 if (e.Fail())
252 return e;
253
254 if (status != 0) {
256 "lldb-argdumper exited with error %d", status);
257 return error;
258 }
259
260 auto data_sp = StructuredData::ParseJSON(output);
261 if (!data_sp) {
262 error = Status::FromErrorString("invalid JSON");
263 return error;
264 }
265
266 auto dict_sp = data_sp->GetAsDictionary();
267 if (!dict_sp) {
268 error = Status::FromErrorString("invalid JSON");
269 return error;
270 }
271
272 auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
273 if (!args_sp) {
274 error = Status::FromErrorString("invalid JSON");
275 return error;
276 }
277
278 auto args_array_sp = args_sp->GetAsArray();
279 if (!args_array_sp) {
280 error = Status::FromErrorString("invalid JSON");
281 return error;
282 }
283
284 launch_info.GetArguments().Clear();
285
286 for (size_t i = 0; i < args_array_sp->GetSize(); i++) {
287 auto item_sp = args_array_sp->GetItemAtIndex(i);
288 if (!item_sp)
289 continue;
290 auto str_sp = item_sp->GetAsString();
291 if (!str_sp)
292 continue;
293
294 launch_info.GetArguments().AppendArgument(str_sp->GetValue());
295 }
296 }
297
298 return error;
299}
300
302 Environment env;
303 // The environment block on Windows is a contiguous buffer of NULL terminated
304 // strings, where the end of the environment block is indicated by two
305 // consecutive NULLs.
306 LPWCH environment_block = ::GetEnvironmentStringsW();
307 while (*environment_block != L'\0') {
308 std::string current_var;
309 auto current_var_size = wcslen(environment_block) + 1;
310 if (!llvm::convertWideToUTF8(environment_block, current_var)) {
311 environment_block += current_var_size;
312 continue;
313 }
314 if (current_var[0] != '=')
315 env.insert(current_var);
316
317 environment_block += current_var_size;
318 }
319 return env;
320}
321
322void Host::SystemLog(Severity severity, llvm::StringRef message) {
323 if (message.empty())
324 return;
325
326 std::string log_msg;
327 llvm::raw_string_ostream stream(log_msg);
328
329 switch (severity) {
331 stream << "[Warning] ";
332 break;
334 stream << "[Error] ";
335 break;
337 stream << "[Info] ";
338 break;
339 }
340
341 stream << message;
342 stream.flush();
343
344 OutputDebugStringA(log_msg.c_str());
345}
static llvm::raw_ostream & error(Stream &strm)
void * HANDLE
An architecture specification class.
Definition ArchSpec.h:32
void AppendArgument(llvm::StringRef arg_str, char quote_char='\0')
Appends a new argument to the end of the list argument list.
Definition Args.cpp:332
bool GetQuotedCommandString(std::string &command) const
Definition Args.cpp:232
void Clear()
Clear the arguments.
Definition Args.cpp:388
std::pair< iterator, bool > insert(llvm::StringRef KeyEqValue)
Definition Environment.h:72
A file utility class.
Definition FileSpec.h:56
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
Definition FileSpec.cpp:174
void AppendPathComponent(llvm::StringRef component)
Definition FileSpec.cpp:454
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition FileSpec.cpp:380
int Open(const char *path, int flags, int mode=0600)
Wraps open in a platform-independent way.
static FileSystem & Instance()
An abstract base class for files.
Definition FileBase.h:34
Status Read(void *buf, size_t &num_bytes) override
Read bytes from a file from the current file position into buf.
Definition File.cpp:99
virtual off_t SeekFromStart(off_t offset, Status *error_ptr=nullptr)
Seek to an offset relative to the beginning of the file.
Definition File.cpp:123
bool Test(ValueType bit) const
Test a single flag bit.
Definition Flags.h:96
static void SystemLog(lldb::Severity severity, llvm::StringRef message)
Emit the given message to the operating system log.
static Status ShellExpandArguments(ProcessLaunchInfo &launch_info)
Perform expansion of the command-line for this launch info This can potentially involve wildcard expa...
Definition aix/Host.cpp:216
static lldb::thread_t GetCurrentThread()
Get the thread token (the one returned by ThreadCreate when the thread was created) for the calling t...
static Environment GetEnvironment()
static Status RunShellCommand(llvm::StringRef command, const FileSpec &working_dir, int *status_ptr, int *signo_ptr, std::string *command_output, std::string *error_output, const Timeout< std::micro > &timeout, bool run_in_shell=true)
Run a shell command.
static uint32_t FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &proc_infos)
Definition aix/Host.cpp:169
static bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info)
Definition aix/Host.cpp:211
static FileSpec GetModuleFileSpecForHostAddress(const void *host_addr)
Given an address in the current process (the process that is running the LLDB code),...
std::function< void(lldb::pid_t pid, int signal, int status)> MonitorChildProcessCallback
Definition Host.h:88
static llvm::Expected< HostThread > StartMonitoringChildProcess(const MonitorChildProcessCallback &callback, lldb::pid_t pid)
Start monitoring a child process.
static void Kill(lldb::pid_t pid, int signo)
static const char * GetSignalAsCString(int signo)
void SetExecutableFile(const FileSpec &exe_file, bool add_exe_file_as_first_arg)
void SetArchitecture(const ArchSpec &arch)
Definition ProcessInfo.h:64
void SetProcessID(lldb::pid_t pid)
Definition ProcessInfo.h:68
bool Matches(const ProcessInstanceInfo &proc_info) const
void SetParentProcessID(lldb::pid_t pid)
const FileSpec & GetWorkingDirectory() const
An error handling class.
Definition Status.h:118
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Definition Status.cpp:106
static Status FromErrorString(const char *str)
Definition Status.h:141
bool Fail() const
Test for error condition.
Definition Status.cpp:293
llvm::StringRef GetString() const
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
static ObjectSP ParseJSON(llvm::StringRef json_text)
A class that represents a running process on the host machine.
std::vector< ProcessInstanceInfo > ProcessInstanceInfoList
Definition Host.h:32
Severity
Used for expressing severity in logs and diagnostics.
pthread_t thread_t
Definition lldb-types.h:58
uint64_t pid_t
Definition lldb-types.h:84
static void GetProcessExecutableAndTriple(const AutoHandle &handle, ProcessInstanceInfo &process)
static bool GetTripleForProcess(const FileSpec &executable, llvm::Triple &triple)
static HANDLE CreateProcessSnapshot()
static bool GetExecutableForProcess(const AutoHandle &handle, std::string &path)
#define PATH_MAX