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 
13 #include "lldb/Host/FileSystem.h"
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/Support/ConvertUTF.h"
26 
27 // Windows includes
28 #include <tlhelp32.h>
29 
30 using namespace lldb;
31 using namespace lldb_private;
32 
33 static bool GetTripleForProcess(const FileSpec &executable,
34  llvm::Triple &triple) {
35  // Open the PE File as a binary file, and parse just enough information to
36  // determine the machine type.
37  auto imageBinaryP = FileSystem::Instance().Open(
38  executable, File::eOpenOptionReadOnly, lldb::eFilePermissionsUserRead);
39  if (!imageBinaryP)
40  return llvm::errorToBool(imageBinaryP.takeError());
41  File &imageBinary = *imageBinaryP.get();
42  imageBinary.SeekFromStart(0x3c);
43  int32_t peOffset = 0;
44  uint32_t peHead = 0;
45  uint16_t machineType = 0;
46  size_t readSize = sizeof(peOffset);
47  imageBinary.Read(&peOffset, readSize);
48  imageBinary.SeekFromStart(peOffset);
49  imageBinary.Read(&peHead, readSize);
50  if (peHead != 0x00004550) // "PE\0\0", little-endian
51  return false; // Status: Can't find PE header
52  readSize = 2;
53  imageBinary.Read(&machineType, readSize);
54  triple.setVendor(llvm::Triple::PC);
55  triple.setOS(llvm::Triple::Win32);
56  triple.setArch(llvm::Triple::UnknownArch);
57  if (machineType == 0x8664)
58  triple.setArch(llvm::Triple::x86_64);
59  else if (machineType == 0x14c)
60  triple.setArch(llvm::Triple::x86);
61  else if (machineType == 0x1c4)
62  triple.setArch(llvm::Triple::arm);
63  else if (machineType == 0xaa64)
64  triple.setArch(llvm::Triple::aarch64);
65 
66  return true;
67 }
68 
69 static bool GetExecutableForProcess(const AutoHandle &handle,
70  std::string &path) {
71  // Get the process image path. MAX_PATH isn't long enough, paths can
72  // actually be up to 32KB.
73  std::vector<wchar_t> buffer(PATH_MAX);
74  DWORD dwSize = buffer.size();
75  if (!::QueryFullProcessImageNameW(handle.get(), 0, &buffer[0], &dwSize))
76  return false;
77  return llvm::convertWideToUTF8(buffer.data(), path);
78 }
79 
80 static void GetProcessExecutableAndTriple(const AutoHandle &handle,
81  ProcessInstanceInfo &process) {
82  // We may not have permissions to read the path from the process. So start
83  // off by setting the executable file to whatever Toolhelp32 gives us, and
84  // then try to enhance this with more detailed information, but fail
85  // gracefully.
86  std::string executable;
87  llvm::Triple triple;
88  triple.setVendor(llvm::Triple::PC);
89  triple.setOS(llvm::Triple::Win32);
90  triple.setArch(llvm::Triple::UnknownArch);
91  if (GetExecutableForProcess(handle, executable)) {
92  FileSpec executableFile(executable.c_str());
93  process.SetExecutableFile(executableFile, true);
94  GetTripleForProcess(executableFile, triple);
95  }
96  process.SetArchitecture(ArchSpec(triple));
97 
98  // TODO(zturner): Add the ability to get the process user name.
99 }
100 
101 lldb::thread_t Host::GetCurrentThread() {
102  return lldb::thread_t(::GetCurrentThread());
103 }
104 
105 void Host::Kill(lldb::pid_t pid, int signo) {
106  TerminateProcess((HANDLE)pid, 1);
107 }
108 
109 const char *Host::GetSignalAsCString(int signo) { return NULL; }
110 
111 FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) {
112  FileSpec module_filespec;
113 
114  HMODULE hmodule = NULL;
115  if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
116  (LPCTSTR)host_addr, &hmodule))
117  return module_filespec;
118 
119  std::vector<wchar_t> buffer(PATH_MAX);
120  DWORD chars_copied = 0;
121  do {
122  chars_copied = ::GetModuleFileNameW(hmodule, &buffer[0], buffer.size());
123  if (chars_copied == buffer.size() &&
124  ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
125  buffer.resize(buffer.size() * 2);
126  } while (chars_copied >= buffer.size());
127  std::string path;
128  if (!llvm::convertWideToUTF8(buffer.data(), path))
129  return module_filespec;
130  module_filespec.SetFile(path, FileSpec::Style::native);
131  return module_filespec;
132 }
133 
134 uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
135  ProcessInstanceInfoList &process_infos) {
136  process_infos.clear();
137 
138  AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
139  if (!snapshot.IsValid())
140  return 0;
141 
142  PROCESSENTRY32W pe = {};
143  pe.dwSize = sizeof(PROCESSENTRY32W);
144  if (Process32FirstW(snapshot.get(), &pe)) {
145  do {
146  AutoHandle handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE,
147  pe.th32ProcessID),
148  nullptr);
149 
150  ProcessInstanceInfo process;
151  std::string exeFile;
152  llvm::convertWideToUTF8(pe.szExeFile, exeFile);
153  process.SetExecutableFile(FileSpec(exeFile), true);
154  process.SetProcessID(pe.th32ProcessID);
155  process.SetParentProcessID(pe.th32ParentProcessID);
156  GetProcessExecutableAndTriple(handle, process);
157 
158  if (match_info.MatchAllProcesses() || match_info.Matches(process))
159  process_infos.push_back(process);
160  } while (Process32NextW(snapshot.get(), &pe));
161  }
162  return process_infos.size();
163 }
164 
165 bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
166  process_info.Clear();
167 
168  AutoHandle handle(
169  ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid),
170  nullptr);
171  if (!handle.IsValid())
172  return false;
173 
174  process_info.SetProcessID(pid);
175  GetProcessExecutableAndTriple(handle, process_info);
176 
177  // Need to read the PEB to get parent process and command line arguments.
178 
179  AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
180  if (!snapshot.IsValid())
181  return false;
182 
183  PROCESSENTRY32W pe;
184  pe.dwSize = sizeof(PROCESSENTRY32W);
185  if (Process32FirstW(snapshot.get(), &pe)) {
186  do {
187  if (pe.th32ProcessID == pid) {
188  process_info.SetParentProcessID(pe.th32ParentProcessID);
189  return true;
190  }
191  } while (Process32NextW(snapshot.get(), &pe));
192  }
193 
194  return false;
195 }
196 
197 llvm::Expected<HostThread> Host::StartMonitoringChildProcess(
198  const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid,
199  bool monitor_signals) {
200  return HostThread();
201 }
202 
203 Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
204  Status error;
205  if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) {
206  FileSpec expand_tool_spec = HostInfo::GetSupportExeDir();
207  if (!expand_tool_spec) {
208  error.SetErrorString("could not find support executable directory for "
209  "the lldb-argdumper tool");
210  return error;
211  }
212  expand_tool_spec.AppendPathComponent("lldb-argdumper.exe");
213  if (!FileSystem::Instance().Exists(expand_tool_spec)) {
214  error.SetErrorString("could not find the lldb-argdumper tool");
215  return error;
216  }
217 
218  std::string quoted_cmd_string;
219  launch_info.GetArguments().GetQuotedCommandString(quoted_cmd_string);
220  std::replace(quoted_cmd_string.begin(), quoted_cmd_string.end(), '\\', '/');
221  StreamString expand_command;
222 
223  expand_command.Printf("\"%s\" %s", expand_tool_spec.GetPath().c_str(),
224  quoted_cmd_string.c_str());
225 
226  int status;
227  std::string output;
228  std::string command = expand_command.GetString().str();
229  Status e =
230  RunShellCommand(command.c_str(), launch_info.GetWorkingDirectory(),
231  &status, nullptr, &output, std::chrono::seconds(10));
232 
233  if (e.Fail())
234  return e;
235 
236  if (status != 0) {
237  error.SetErrorStringWithFormat("lldb-argdumper exited with error %d",
238  status);
239  return error;
240  }
241 
242  auto data_sp = StructuredData::ParseJSON(output);
243  if (!data_sp) {
244  error.SetErrorString("invalid JSON");
245  return error;
246  }
247 
248  auto dict_sp = data_sp->GetAsDictionary();
249  if (!data_sp) {
250  error.SetErrorString("invalid JSON");
251  return error;
252  }
253 
254  auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
255  if (!args_sp) {
256  error.SetErrorString("invalid JSON");
257  return error;
258  }
259 
260  auto args_array_sp = args_sp->GetAsArray();
261  if (!args_array_sp) {
262  error.SetErrorString("invalid JSON");
263  return error;
264  }
265 
266  launch_info.GetArguments().Clear();
267 
268  for (size_t i = 0; i < args_array_sp->GetSize(); i++) {
269  auto item_sp = args_array_sp->GetItemAtIndex(i);
270  if (!item_sp)
271  continue;
272  auto str_sp = item_sp->GetAsString();
273  if (!str_sp)
274  continue;
275 
276  launch_info.GetArguments().AppendArgument(str_sp->GetValue());
277  }
278  }
279 
280  return error;
281 }
282 
283 Environment Host::GetEnvironment() {
284  Environment env;
285  // The environment block on Windows is a contiguous buffer of NULL terminated
286  // strings, where the end of the environment block is indicated by two
287  // consecutive NULLs.
288  LPWCH environment_block = ::GetEnvironmentStringsW();
289  while (*environment_block != L'\0') {
290  std::string current_var;
291  auto current_var_size = wcslen(environment_block) + 1;
292  if (!llvm::convertWideToUTF8(environment_block, current_var)) {
293  environment_block += current_var_size;
294  continue;
295  }
296  if (current_var[0] != '=')
297  env.insert(current_var);
298 
299  environment_block += current_var_size;
300  }
301  return env;
302 }
lldb_private::ProcessInfo::GetArguments
Args & GetArguments()
Definition: ProcessInfo.h:75
lldb_private::ProcessInstanceInfo
Definition: ProcessInfo.h:108
GetTripleForProcess
static bool GetTripleForProcess(const FileSpec &executable, llvm::Triple &triple)
Definition: windows/Host.cpp:33
lldb_private::ArchSpec
Definition: ArchSpec.h:33
FileSystem.h
lldb_private::ProcessInfo::SetExecutableFile
void SetExecutableFile(const FileSpec &exe_file, bool add_exe_file_as_first_arg)
Definition: ProcessInfo.cpp:62
lldb_private::ProcessInfo::SetArchitecture
void SetArchitecture(const ArchSpec &arch)
Definition: ProcessInfo.h:65
lldb_private::Host::MonitorChildProcessCallback
std::function< bool(lldb::pid_t pid, bool exited, int signal, int status)> MonitorChildProcessCallback
Definition: Host.h:68
lldb_private::ProcessInstanceInfo::Clear
void Clear()
Definition: ProcessInfo.h:116
lldb_private::HostThread
Definition: HostThread.h:29
lldb_private::AutoHandle
Definition: AutoHandle.h:16
StructuredData.h
lldb_private::AutoHandle::get
HANDLE get() const
Definition: AutoHandle.h:28
Host.h
ProcessLaunchInfo.h
lldb_private::Args::AppendArgument
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:318
lldb_private::Args::Clear
void Clear()
Clear the arguments.
Definition: Args.cpp:374
lldb_private::ProcessInstanceInfoMatch
Definition: ProcessInfo.h:163
lldb_private::Flags::Test
bool Test(ValueType bit) const
Test a single flag bit.
Definition: Flags.h:96
lldb_private::ProcessLaunchInfo::GetFlags
Flags & GetFlags()
Definition: ProcessLaunchInfo.h:64
lldb_private::ProcessInfo::SetProcessID
void SetProcessID(lldb::pid_t pid)
Definition: ProcessInfo.h:69
lldb_private::Args::GetQuotedCommandString
bool GetQuotedCommandString(std::string &command) const
Definition: Args.cpp:224
lldb_private::ProcessInstanceInfoMatch::Matches
bool Matches(const ProcessInstanceInfo &proc_info) const
Definition: ProcessInfo.cpp:292
lldb_private::StreamString::GetString
llvm::StringRef GetString() const
Definition: StreamString.cpp:51
AutoHandle.h
lldb_private::Environment::insert
std::pair< iterator, bool > insert(llvm::StringRef KeyEqValue)
Definition: Environment.h:71
lldb_private::FileSpec
Definition: FileSpec.h:56
error
static llvm::raw_ostream & error(Stream &strm)
Definition: CommandReturnObject.cpp:17
ProcessInfo.h
lldb::thread_t
pthread_t thread_t
Definition: lldb-types.h:58
GetProcessExecutableAndTriple
static void GetProcessExecutableAndTriple(const AutoHandle &handle, ProcessInstanceInfo &process)
Definition: windows/Host.cpp:80
lldb_private::ProcessLaunchInfo
Definition: ProcessLaunchInfo.h:31
Log.h
lldb_private::File::SeekFromStart
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:128
lldb_private::Status::Fail
bool Fail() const
Test for error condition.
Definition: Status.cpp:182
StreamString.h
lldb_private::ProcessInstanceInfoMatch::MatchAllProcesses
bool MatchAllProcesses() const
Definition: ProcessInfo.cpp:299
lldb_private::StreamString
Definition: StreamString.h:23
lldb_private::File
Definition: File.h:35
GetExecutableForProcess
static bool GetExecutableForProcess(const AutoHandle &handle, std::string &path)
Definition: windows/Host.cpp:69
HostInfo.h
string
string(SUBSTRING ${p} 10 -1 pStripped) if($
Definition: Plugins/CMakeLists.txt:40
lldb_private::ProcessLaunchInfo::GetWorkingDirectory
const FileSpec & GetWorkingDirectory() const
Definition: ProcessLaunchInfo.cpp:124
lldb_private::Status
Definition: Status.h:44
uint32_t
lldb::pid_t
uint64_t pid_t
Definition: lldb-types.h:85
lldb_private::Environment
Definition: Environment.h:18
uint16_t
windows.h
DataExtractor.h
lldb_private::Stream::Printf
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:107
Status.h
lldb_private::FileSpec::AppendPathComponent
void AppendPathComponent(llvm::StringRef component)
Definition: FileSpec.cpp:433
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
lldb_private::File::Read
Status Read(void *buf, size_t &num_bytes) override
Read bytes from a file from the current file position into buf.
Definition: File.cpp:104
lldb_private::FileSpec::SetFile
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
Definition: FileSpec.cpp:172
PATH_MAX
#define PATH_MAX
Definition: windows/PosixApi.h:25
lldb_private::FileSpec::GetPath
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:346
lldb_private::ProcessInstanceInfoList
std::vector< ProcessInstanceInfo > ProcessInstanceInfoList
Definition: Host.h:30
lldb
Definition: SBAddress.h:15
lldb_private::ProcessInstanceInfo::SetParentProcessID
void SetParentProcessID(lldb::pid_t pid)
Definition: ProcessInfo.h:137
DataBufferHeap.h