1 //===-- source/Host/windows/Host.cpp ----------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
12 #include "lldb/Host/windows/windows.h"
13 #include "lldb/Host/windows/AutoHandle.h"
16 // Other libraries and framework includes
18 #include "lldb/Core/Error.h"
19 #include "lldb/Core/Log.h"
20 #include "lldb/Target/Process.h"
22 #include "lldb/Host/Host.h"
23 #include "lldb/Host/HostInfo.h"
24 #include "lldb/Core/DataBufferHeap.h"
25 #include "lldb/Core/DataExtractor.h"
26 #include "lldb/Core/StreamFile.h"
27 #include "lldb/Core/StructuredData.h"
33 using namespace lldb_private;
37 bool GetTripleForProcess(const FileSpec &executable, llvm::Triple &triple)
39 // Open the PE File as a binary file, and parse just enough information to determine the
42 executable.GetPath().c_str(),
43 File::eOpenOptionRead,
44 lldb::eFilePermissionsUserRead);
45 imageBinary.SeekFromStart(0x3c);
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; // Error: Can't find PE header
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);
68 bool GetExecutableForProcess(const AutoHandle &handle, std::string &path)
70 // Get the process image path. MAX_PATH isn't long enough, paths can actually be up to 32KB.
71 std::vector<char> buffer(32768);
72 DWORD dwSize = buffer.size();
73 if (!::QueryFullProcessImageNameA(handle.get(), 0, &buffer[0], &dwSize))
75 path.assign(&buffer[0]);
79 void GetProcessExecutableAndTriple(const AutoHandle &handle, ProcessInstanceInfo &process)
81 // We may not have permissions to read the path from the process. So start off by
82 // setting the executable file to whatever Toolhelp32 gives us, and then try to
83 // enhance this with more detailed information, but fail gracefully.
84 std::string executable;
86 triple.setVendor(llvm::Triple::PC);
87 triple.setOS(llvm::Triple::Win32);
88 triple.setArch(llvm::Triple::UnknownArch);
89 if (GetExecutableForProcess(handle, executable))
91 FileSpec executableFile(executable.c_str(), false);
92 process.SetExecutableFile(executableFile, true);
93 GetTripleForProcess(executableFile, triple);
95 process.SetArchitecture(ArchSpec(triple));
97 // TODO(zturner): Add the ability to get the process user name.
102 Host::GetAuxvData(lldb_private::Process *process)
108 Host::GetCurrentThreadID()
110 return lldb::tid_t(::GetCurrentThreadId());
114 Host::GetCurrentThread ()
116 return lldb::thread_t(::GetCurrentThread());
120 Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback)
126 Host::ThreadLocalStorageGet(lldb::thread_key_t key)
128 return ::TlsGetValue (key);
132 Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value)
134 ::TlsSetValue (key, value);
138 Host::Kill(lldb::pid_t pid, int signo)
140 TerminateProcess((HANDLE) pid, 1);
145 Host::GetSignalAsCString(int signo)
151 Host::GetModuleFileSpecForHostAddress (const void *host_addr)
153 FileSpec module_filespec;
155 HMODULE hmodule = NULL;
156 if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)host_addr, &hmodule))
157 return module_filespec;
159 std::vector<char> buffer(MAX_PATH);
160 DWORD chars_copied = 0;
162 chars_copied = ::GetModuleFileName(hmodule, &buffer[0], buffer.size());
163 if (chars_copied == buffer.size() && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
164 buffer.resize(buffer.size() * 2);
165 } while (chars_copied >= buffer.size());
167 module_filespec.SetFile(&buffer[0], false);
168 return module_filespec;
172 Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
174 process_infos.Clear();
176 AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
177 if (!snapshot.IsValid())
180 PROCESSENTRY32 pe = {0};
181 pe.dwSize = sizeof(PROCESSENTRY32);
182 if (Process32First(snapshot.get(), &pe))
186 AutoHandle handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID), nullptr);
188 ProcessInstanceInfo process;
189 process.SetExecutableFile(FileSpec(pe.szExeFile, false), true);
190 process.SetProcessID(pe.th32ProcessID);
191 process.SetParentProcessID(pe.th32ParentProcessID);
192 GetProcessExecutableAndTriple(handle, process);
194 if (match_info.MatchAllProcesses() || match_info.Matches(process))
195 process_infos.Append(process);
196 } while (Process32Next(snapshot.get(), &pe));
198 return process_infos.GetSize();
202 Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
204 process_info.Clear();
206 AutoHandle handle(::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid),
208 if (!handle.IsValid())
211 process_info.SetProcessID(pid);
212 GetProcessExecutableAndTriple(handle, process_info);
214 // Need to read the PEB to get parent process and command line arguments.
219 Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, void *callback_baton, lldb::pid_t pid, bool monitor_signals)
225 Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
228 if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments))
230 FileSpec expand_tool_spec;
231 if (!HostInfo::GetLLDBPath(lldb::ePathTypeSupportExecutableDir, expand_tool_spec))
233 error.SetErrorString("could not find support executable directory for the lldb-argdumper tool");
236 expand_tool_spec.AppendPathComponent("lldb-argdumper.exe");
237 if (!expand_tool_spec.Exists())
239 error.SetErrorString("could not find the lldb-argdumper tool");
243 std::string quoted_cmd_string;
244 launch_info.GetArguments().GetQuotedCommandString(quoted_cmd_string);
245 std::replace(quoted_cmd_string.begin(), quoted_cmd_string.end(), '\\', '/');
246 StreamString expand_command;
248 expand_command.Printf("\"%s\" %s",
249 expand_tool_spec.GetPath().c_str(),
250 quoted_cmd_string.c_str());
254 RunShellCommand(expand_command.GetData(), launch_info.GetWorkingDirectory(), &status, nullptr, &output, 10);
258 error.SetErrorStringWithFormat("lldb-argdumper exited with error %d", status);
262 auto data_sp = StructuredData::ParseJSON(output);
265 error.SetErrorString("invalid JSON");
269 auto dict_sp = data_sp->GetAsDictionary();
272 error.SetErrorString("invalid JSON");
276 auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
279 error.SetErrorString("invalid JSON");
283 auto args_array_sp = args_sp->GetAsArray();
286 error.SetErrorString("invalid JSON");
290 launch_info.GetArguments().Clear();
293 i < args_array_sp->GetSize();
296 auto item_sp = args_array_sp->GetItemAtIndex(i);
299 auto str_sp = item_sp->GetAsString();
303 launch_info.GetArguments().AppendArgument(str_sp->GetValue().c_str());
311 Host::GetEnvironment(StringList &env)
313 // The environment block on Windows is a contiguous buffer of NULL terminated strings,
314 // where the end of the environment block is indicated by two consecutive NULLs.
315 LPCH environment_block = ::GetEnvironmentStrings();
317 while (*environment_block != '\0')
319 llvm::StringRef current_var(environment_block);
320 if (current_var[0] != '=')
321 env.AppendString(current_var);
323 environment_block += current_var.size()+1;
325 return env.GetSize();