1dda28197Spatrick //===-- source/Host/windows/Host.cpp --------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Host/windows/AutoHandle.h"
10061da546Spatrick #include "lldb/Host/windows/windows.h"
11be691f3bSpatrick #include <cstdio>
12061da546Spatrick
13061da546Spatrick #include "lldb/Host/FileSystem.h"
14061da546Spatrick #include "lldb/Host/Host.h"
15061da546Spatrick #include "lldb/Host/HostInfo.h"
16061da546Spatrick #include "lldb/Host/ProcessLaunchInfo.h"
17061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
18061da546Spatrick #include "lldb/Utility/DataExtractor.h"
19061da546Spatrick #include "lldb/Utility/Log.h"
20061da546Spatrick #include "lldb/Utility/ProcessInfo.h"
21061da546Spatrick #include "lldb/Utility/Status.h"
22061da546Spatrick #include "lldb/Utility/StreamString.h"
23061da546Spatrick #include "lldb/Utility/StructuredData.h"
24061da546Spatrick
25061da546Spatrick #include "llvm/Support/ConvertUTF.h"
26061da546Spatrick
27061da546Spatrick // Windows includes
28061da546Spatrick #include <tlhelp32.h>
29061da546Spatrick
30061da546Spatrick using namespace lldb;
31061da546Spatrick using namespace lldb_private;
32061da546Spatrick
GetTripleForProcess(const FileSpec & executable,llvm::Triple & triple)33*f6aab3d8Srobert static bool GetTripleForProcess(const FileSpec &executable,
34*f6aab3d8Srobert llvm::Triple &triple) {
35061da546Spatrick // Open the PE File as a binary file, and parse just enough information to
36061da546Spatrick // determine the machine type.
37061da546Spatrick auto imageBinaryP = FileSystem::Instance().Open(
38*f6aab3d8Srobert executable, File::eOpenOptionReadOnly, lldb::eFilePermissionsUserRead);
39061da546Spatrick if (!imageBinaryP)
40061da546Spatrick return llvm::errorToBool(imageBinaryP.takeError());
41061da546Spatrick File &imageBinary = *imageBinaryP.get();
42061da546Spatrick imageBinary.SeekFromStart(0x3c);
43061da546Spatrick int32_t peOffset = 0;
44061da546Spatrick uint32_t peHead = 0;
45061da546Spatrick uint16_t machineType = 0;
46061da546Spatrick size_t readSize = sizeof(peOffset);
47061da546Spatrick imageBinary.Read(&peOffset, readSize);
48061da546Spatrick imageBinary.SeekFromStart(peOffset);
49061da546Spatrick imageBinary.Read(&peHead, readSize);
50061da546Spatrick if (peHead != 0x00004550) // "PE\0\0", little-endian
51061da546Spatrick return false; // Status: Can't find PE header
52061da546Spatrick readSize = 2;
53061da546Spatrick imageBinary.Read(&machineType, readSize);
54061da546Spatrick triple.setVendor(llvm::Triple::PC);
55061da546Spatrick triple.setOS(llvm::Triple::Win32);
56061da546Spatrick triple.setArch(llvm::Triple::UnknownArch);
57061da546Spatrick if (machineType == 0x8664)
58061da546Spatrick triple.setArch(llvm::Triple::x86_64);
59061da546Spatrick else if (machineType == 0x14c)
60061da546Spatrick triple.setArch(llvm::Triple::x86);
61061da546Spatrick else if (machineType == 0x1c4)
62061da546Spatrick triple.setArch(llvm::Triple::arm);
63061da546Spatrick else if (machineType == 0xaa64)
64061da546Spatrick triple.setArch(llvm::Triple::aarch64);
65061da546Spatrick
66061da546Spatrick return true;
67061da546Spatrick }
68061da546Spatrick
GetExecutableForProcess(const AutoHandle & handle,std::string & path)69*f6aab3d8Srobert static bool GetExecutableForProcess(const AutoHandle &handle,
70*f6aab3d8Srobert std::string &path) {
71061da546Spatrick // Get the process image path. MAX_PATH isn't long enough, paths can
72061da546Spatrick // actually be up to 32KB.
73061da546Spatrick std::vector<wchar_t> buffer(PATH_MAX);
74061da546Spatrick DWORD dwSize = buffer.size();
75061da546Spatrick if (!::QueryFullProcessImageNameW(handle.get(), 0, &buffer[0], &dwSize))
76061da546Spatrick return false;
77061da546Spatrick return llvm::convertWideToUTF8(buffer.data(), path);
78061da546Spatrick }
79061da546Spatrick
GetProcessExecutableAndTriple(const AutoHandle & handle,ProcessInstanceInfo & process)80*f6aab3d8Srobert static void GetProcessExecutableAndTriple(const AutoHandle &handle,
81061da546Spatrick ProcessInstanceInfo &process) {
82061da546Spatrick // We may not have permissions to read the path from the process. So start
83061da546Spatrick // off by setting the executable file to whatever Toolhelp32 gives us, and
84061da546Spatrick // then try to enhance this with more detailed information, but fail
85061da546Spatrick // gracefully.
86061da546Spatrick std::string executable;
87061da546Spatrick llvm::Triple triple;
88061da546Spatrick triple.setVendor(llvm::Triple::PC);
89061da546Spatrick triple.setOS(llvm::Triple::Win32);
90061da546Spatrick triple.setArch(llvm::Triple::UnknownArch);
91061da546Spatrick if (GetExecutableForProcess(handle, executable)) {
92061da546Spatrick FileSpec executableFile(executable.c_str());
93061da546Spatrick process.SetExecutableFile(executableFile, true);
94061da546Spatrick GetTripleForProcess(executableFile, triple);
95061da546Spatrick }
96061da546Spatrick process.SetArchitecture(ArchSpec(triple));
97061da546Spatrick
98061da546Spatrick // TODO(zturner): Add the ability to get the process user name.
99061da546Spatrick }
100061da546Spatrick
GetCurrentThread()101061da546Spatrick lldb::thread_t Host::GetCurrentThread() {
102061da546Spatrick return lldb::thread_t(::GetCurrentThread());
103061da546Spatrick }
104061da546Spatrick
Kill(lldb::pid_t pid,int signo)105061da546Spatrick void Host::Kill(lldb::pid_t pid, int signo) {
106061da546Spatrick TerminateProcess((HANDLE)pid, 1);
107061da546Spatrick }
108061da546Spatrick
GetSignalAsCString(int signo)109061da546Spatrick const char *Host::GetSignalAsCString(int signo) { return NULL; }
110061da546Spatrick
GetModuleFileSpecForHostAddress(const void * host_addr)111061da546Spatrick FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) {
112061da546Spatrick FileSpec module_filespec;
113061da546Spatrick
114061da546Spatrick HMODULE hmodule = NULL;
115061da546Spatrick if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
116061da546Spatrick (LPCTSTR)host_addr, &hmodule))
117061da546Spatrick return module_filespec;
118061da546Spatrick
119061da546Spatrick std::vector<wchar_t> buffer(PATH_MAX);
120061da546Spatrick DWORD chars_copied = 0;
121061da546Spatrick do {
122061da546Spatrick chars_copied = ::GetModuleFileNameW(hmodule, &buffer[0], buffer.size());
123061da546Spatrick if (chars_copied == buffer.size() &&
124061da546Spatrick ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
125061da546Spatrick buffer.resize(buffer.size() * 2);
126061da546Spatrick } while (chars_copied >= buffer.size());
127061da546Spatrick std::string path;
128061da546Spatrick if (!llvm::convertWideToUTF8(buffer.data(), path))
129061da546Spatrick return module_filespec;
130061da546Spatrick module_filespec.SetFile(path, FileSpec::Style::native);
131061da546Spatrick return module_filespec;
132061da546Spatrick }
133061da546Spatrick
FindProcessesImpl(const ProcessInstanceInfoMatch & match_info,ProcessInstanceInfoList & process_infos)134dda28197Spatrick uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
135061da546Spatrick ProcessInstanceInfoList &process_infos) {
136dda28197Spatrick process_infos.clear();
137061da546Spatrick
138061da546Spatrick AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
139061da546Spatrick if (!snapshot.IsValid())
140061da546Spatrick return 0;
141061da546Spatrick
142061da546Spatrick PROCESSENTRY32W pe = {};
143061da546Spatrick pe.dwSize = sizeof(PROCESSENTRY32W);
144061da546Spatrick if (Process32FirstW(snapshot.get(), &pe)) {
145061da546Spatrick do {
146061da546Spatrick AutoHandle handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE,
147061da546Spatrick pe.th32ProcessID),
148061da546Spatrick nullptr);
149061da546Spatrick
150061da546Spatrick ProcessInstanceInfo process;
151061da546Spatrick std::string exeFile;
152061da546Spatrick llvm::convertWideToUTF8(pe.szExeFile, exeFile);
153061da546Spatrick process.SetExecutableFile(FileSpec(exeFile), true);
154061da546Spatrick process.SetProcessID(pe.th32ProcessID);
155061da546Spatrick process.SetParentProcessID(pe.th32ParentProcessID);
156061da546Spatrick GetProcessExecutableAndTriple(handle, process);
157061da546Spatrick
158061da546Spatrick if (match_info.MatchAllProcesses() || match_info.Matches(process))
159dda28197Spatrick process_infos.push_back(process);
160061da546Spatrick } while (Process32NextW(snapshot.get(), &pe));
161061da546Spatrick }
162dda28197Spatrick return process_infos.size();
163061da546Spatrick }
164061da546Spatrick
GetProcessInfo(lldb::pid_t pid,ProcessInstanceInfo & process_info)165061da546Spatrick bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
166061da546Spatrick process_info.Clear();
167061da546Spatrick
168061da546Spatrick AutoHandle handle(
169061da546Spatrick ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid),
170061da546Spatrick nullptr);
171061da546Spatrick if (!handle.IsValid())
172061da546Spatrick return false;
173061da546Spatrick
174061da546Spatrick process_info.SetProcessID(pid);
175061da546Spatrick GetProcessExecutableAndTriple(handle, process_info);
176061da546Spatrick
177061da546Spatrick // Need to read the PEB to get parent process and command line arguments.
178061da546Spatrick
179061da546Spatrick AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
180061da546Spatrick if (!snapshot.IsValid())
181061da546Spatrick return false;
182061da546Spatrick
183061da546Spatrick PROCESSENTRY32W pe;
184061da546Spatrick pe.dwSize = sizeof(PROCESSENTRY32W);
185061da546Spatrick if (Process32FirstW(snapshot.get(), &pe)) {
186061da546Spatrick do {
187061da546Spatrick if (pe.th32ProcessID == pid) {
188061da546Spatrick process_info.SetParentProcessID(pe.th32ParentProcessID);
189061da546Spatrick return true;
190061da546Spatrick }
191061da546Spatrick } while (Process32NextW(snapshot.get(), &pe));
192061da546Spatrick }
193061da546Spatrick
194061da546Spatrick return false;
195061da546Spatrick }
196061da546Spatrick
StartMonitoringChildProcess(const Host::MonitorChildProcessCallback & callback,lldb::pid_t pid)197061da546Spatrick llvm::Expected<HostThread> Host::StartMonitoringChildProcess(
198*f6aab3d8Srobert const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid) {
199061da546Spatrick return HostThread();
200061da546Spatrick }
201061da546Spatrick
ShellExpandArguments(ProcessLaunchInfo & launch_info)202061da546Spatrick Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
203061da546Spatrick Status error;
204061da546Spatrick if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) {
205061da546Spatrick FileSpec expand_tool_spec = HostInfo::GetSupportExeDir();
206061da546Spatrick if (!expand_tool_spec) {
207061da546Spatrick error.SetErrorString("could not find support executable directory for "
208061da546Spatrick "the lldb-argdumper tool");
209061da546Spatrick return error;
210061da546Spatrick }
211061da546Spatrick expand_tool_spec.AppendPathComponent("lldb-argdumper.exe");
212061da546Spatrick if (!FileSystem::Instance().Exists(expand_tool_spec)) {
213061da546Spatrick error.SetErrorString("could not find the lldb-argdumper tool");
214061da546Spatrick return error;
215061da546Spatrick }
216061da546Spatrick
217061da546Spatrick std::string quoted_cmd_string;
218061da546Spatrick launch_info.GetArguments().GetQuotedCommandString(quoted_cmd_string);
219061da546Spatrick std::replace(quoted_cmd_string.begin(), quoted_cmd_string.end(), '\\', '/');
220061da546Spatrick StreamString expand_command;
221061da546Spatrick
222061da546Spatrick expand_command.Printf("\"%s\" %s", expand_tool_spec.GetPath().c_str(),
223061da546Spatrick quoted_cmd_string.c_str());
224061da546Spatrick
225061da546Spatrick int status;
226061da546Spatrick std::string output;
227dda28197Spatrick std::string command = expand_command.GetString().str();
228061da546Spatrick Status e =
229061da546Spatrick RunShellCommand(command.c_str(), launch_info.GetWorkingDirectory(),
230061da546Spatrick &status, nullptr, &output, std::chrono::seconds(10));
231061da546Spatrick
232061da546Spatrick if (e.Fail())
233061da546Spatrick return e;
234061da546Spatrick
235061da546Spatrick if (status != 0) {
236061da546Spatrick error.SetErrorStringWithFormat("lldb-argdumper exited with error %d",
237061da546Spatrick status);
238061da546Spatrick return error;
239061da546Spatrick }
240061da546Spatrick
241061da546Spatrick auto data_sp = StructuredData::ParseJSON(output);
242061da546Spatrick if (!data_sp) {
243061da546Spatrick error.SetErrorString("invalid JSON");
244061da546Spatrick return error;
245061da546Spatrick }
246061da546Spatrick
247061da546Spatrick auto dict_sp = data_sp->GetAsDictionary();
248*f6aab3d8Srobert if (!dict_sp) {
249061da546Spatrick error.SetErrorString("invalid JSON");
250061da546Spatrick return error;
251061da546Spatrick }
252061da546Spatrick
253061da546Spatrick auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
254061da546Spatrick if (!args_sp) {
255061da546Spatrick error.SetErrorString("invalid JSON");
256061da546Spatrick return error;
257061da546Spatrick }
258061da546Spatrick
259061da546Spatrick auto args_array_sp = args_sp->GetAsArray();
260061da546Spatrick if (!args_array_sp) {
261061da546Spatrick error.SetErrorString("invalid JSON");
262061da546Spatrick return error;
263061da546Spatrick }
264061da546Spatrick
265061da546Spatrick launch_info.GetArguments().Clear();
266061da546Spatrick
267061da546Spatrick for (size_t i = 0; i < args_array_sp->GetSize(); i++) {
268061da546Spatrick auto item_sp = args_array_sp->GetItemAtIndex(i);
269061da546Spatrick if (!item_sp)
270061da546Spatrick continue;
271061da546Spatrick auto str_sp = item_sp->GetAsString();
272061da546Spatrick if (!str_sp)
273061da546Spatrick continue;
274061da546Spatrick
275061da546Spatrick launch_info.GetArguments().AppendArgument(str_sp->GetValue());
276061da546Spatrick }
277061da546Spatrick }
278061da546Spatrick
279061da546Spatrick return error;
280061da546Spatrick }
281061da546Spatrick
GetEnvironment()282061da546Spatrick Environment Host::GetEnvironment() {
283061da546Spatrick Environment env;
284061da546Spatrick // The environment block on Windows is a contiguous buffer of NULL terminated
285061da546Spatrick // strings, where the end of the environment block is indicated by two
286061da546Spatrick // consecutive NULLs.
287061da546Spatrick LPWCH environment_block = ::GetEnvironmentStringsW();
288061da546Spatrick while (*environment_block != L'\0') {
289061da546Spatrick std::string current_var;
290061da546Spatrick auto current_var_size = wcslen(environment_block) + 1;
291061da546Spatrick if (!llvm::convertWideToUTF8(environment_block, current_var)) {
292061da546Spatrick environment_block += current_var_size;
293061da546Spatrick continue;
294061da546Spatrick }
295061da546Spatrick if (current_var[0] != '=')
296061da546Spatrick env.insert(current_var);
297061da546Spatrick
298061da546Spatrick environment_block += current_var_size;
299061da546Spatrick }
300061da546Spatrick return env;
301061da546Spatrick }
302