xref: /openbsd-src/gnu/llvm/lldb/source/Host/windows/Host.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
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