1 //===-- source/Host/windows/Host.cpp ----------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // C Includes 11 #include "lldb/Host/windows/AutoHandle.h" 12 #include "lldb/Host/windows/windows.h" 13 #include <stdio.h> 14 15 // C++ Includes 16 // Other libraries and framework includes 17 // Project includes 18 #include "lldb/Core/Error.h" 19 #include "lldb/Core/Log.h" 20 #include "lldb/Target/Process.h" 21 22 #include "lldb/Core/DataBufferHeap.h" 23 #include "lldb/Core/DataExtractor.h" 24 #include "lldb/Core/StreamFile.h" 25 #include "lldb/Core/StructuredData.h" 26 #include "lldb/Host/Host.h" 27 #include "lldb/Host/HostInfo.h" 28 29 #include "llvm/Support/ConvertUTF.h" 30 31 // Windows includes 32 #include <TlHelp32.h> 33 34 using namespace lldb; 35 using namespace lldb_private; 36 37 namespace { 38 bool GetTripleForProcess(const FileSpec &executable, llvm::Triple &triple) { 39 // Open the PE File as a binary file, and parse just enough information to 40 // determine the 41 // machine type. 42 File imageBinary(executable.GetPath().c_str(), File::eOpenOptionRead, 43 lldb::eFilePermissionsUserRead); 44 imageBinary.SeekFromStart(0x3c); 45 int32_t peOffset = 0; 46 uint32_t peHead = 0; 47 uint16_t machineType = 0; 48 size_t readSize = sizeof(peOffset); 49 imageBinary.Read(&peOffset, readSize); 50 imageBinary.SeekFromStart(peOffset); 51 imageBinary.Read(&peHead, readSize); 52 if (peHead != 0x00004550) // "PE\0\0", little-endian 53 return false; // Error: Can't find PE header 54 readSize = 2; 55 imageBinary.Read(&machineType, readSize); 56 triple.setVendor(llvm::Triple::PC); 57 triple.setOS(llvm::Triple::Win32); 58 triple.setArch(llvm::Triple::UnknownArch); 59 if (machineType == 0x8664) 60 triple.setArch(llvm::Triple::x86_64); 61 else if (machineType == 0x14c) 62 triple.setArch(llvm::Triple::x86); 63 64 return true; 65 } 66 67 bool GetExecutableForProcess(const AutoHandle &handle, std::string &path) { 68 // Get the process image path. MAX_PATH isn't long enough, paths can actually 69 // be up to 32KB. 70 std::vector<wchar_t> buffer(PATH_MAX); 71 DWORD dwSize = buffer.size(); 72 if (!::QueryFullProcessImageNameW(handle.get(), 0, &buffer[0], &dwSize)) 73 return false; 74 return llvm::convertWideToUTF8(buffer.data(), path); 75 } 76 77 void GetProcessExecutableAndTriple(const AutoHandle &handle, 78 ProcessInstanceInfo &process) { 79 // We may not have permissions to read the path from the process. So start 80 // off by 81 // setting the executable file to whatever Toolhelp32 gives us, and then try 82 // to 83 // enhance this with more detailed information, but fail gracefully. 84 std::string executable; 85 llvm::Triple triple; 86 triple.setVendor(llvm::Triple::PC); 87 triple.setOS(llvm::Triple::Win32); 88 triple.setArch(llvm::Triple::UnknownArch); 89 if (GetExecutableForProcess(handle, executable)) { 90 FileSpec executableFile(executable.c_str(), false); 91 process.SetExecutableFile(executableFile, true); 92 GetTripleForProcess(executableFile, triple); 93 } 94 process.SetArchitecture(ArchSpec(triple)); 95 96 // TODO(zturner): Add the ability to get the process user name. 97 } 98 } 99 100 lldb::DataBufferSP Host::GetAuxvData(lldb_private::Process *process) { 101 return 0; 102 } 103 104 lldb::tid_t Host::GetCurrentThreadID() { 105 return lldb::tid_t(::GetCurrentThreadId()); 106 } 107 108 lldb::thread_t Host::GetCurrentThread() { 109 return lldb::thread_t(::GetCurrentThread()); 110 } 111 112 lldb::thread_key_t 113 Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback) { 114 return TlsAlloc(); 115 } 116 117 void *Host::ThreadLocalStorageGet(lldb::thread_key_t key) { 118 return ::TlsGetValue(key); 119 } 120 121 void Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value) { 122 ::TlsSetValue(key, value); 123 } 124 125 void Host::Kill(lldb::pid_t pid, int signo) { 126 TerminateProcess((HANDLE)pid, 1); 127 } 128 129 const char *Host::GetSignalAsCString(int signo) { return NULL; } 130 131 FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { 132 FileSpec module_filespec; 133 134 HMODULE hmodule = NULL; 135 if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, 136 (LPCTSTR)host_addr, &hmodule)) 137 return module_filespec; 138 139 std::vector<wchar_t> buffer(PATH_MAX); 140 DWORD chars_copied = 0; 141 do { 142 chars_copied = ::GetModuleFileNameW(hmodule, &buffer[0], buffer.size()); 143 if (chars_copied == buffer.size() && 144 ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) 145 buffer.resize(buffer.size() * 2); 146 } while (chars_copied >= buffer.size()); 147 std::string path; 148 if (!llvm::convertWideToUTF8(buffer.data(), path)) 149 return module_filespec; 150 module_filespec.SetFile(path, false); 151 return module_filespec; 152 } 153 154 uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, 155 ProcessInstanceInfoList &process_infos) { 156 process_infos.Clear(); 157 158 AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)); 159 if (!snapshot.IsValid()) 160 return 0; 161 162 PROCESSENTRY32W pe = {}; 163 pe.dwSize = sizeof(PROCESSENTRY32W); 164 if (Process32FirstW(snapshot.get(), &pe)) { 165 do { 166 AutoHandle handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, 167 pe.th32ProcessID), 168 nullptr); 169 170 ProcessInstanceInfo process; 171 std::string exeFile; 172 llvm::convertWideToUTF8(pe.szExeFile, exeFile); 173 process.SetExecutableFile(FileSpec(exeFile, false), true); 174 process.SetProcessID(pe.th32ProcessID); 175 process.SetParentProcessID(pe.th32ParentProcessID); 176 GetProcessExecutableAndTriple(handle, process); 177 178 if (match_info.MatchAllProcesses() || match_info.Matches(process)) 179 process_infos.Append(process); 180 } while (Process32NextW(snapshot.get(), &pe)); 181 } 182 return process_infos.GetSize(); 183 } 184 185 bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { 186 process_info.Clear(); 187 188 AutoHandle handle( 189 ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid), 190 nullptr); 191 if (!handle.IsValid()) 192 return false; 193 194 process_info.SetProcessID(pid); 195 GetProcessExecutableAndTriple(handle, process_info); 196 197 // Need to read the PEB to get parent process and command line arguments. 198 return true; 199 } 200 201 HostThread Host::StartMonitoringChildProcess( 202 const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid, 203 bool monitor_signals) { 204 return HostThread(); 205 } 206 207 Error Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) { 208 Error error; 209 if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) { 210 FileSpec expand_tool_spec; 211 if (!HostInfo::GetLLDBPath(lldb::ePathTypeSupportExecutableDir, 212 expand_tool_spec)) { 213 error.SetErrorString("could not find support executable directory for " 214 "the lldb-argdumper tool"); 215 return error; 216 } 217 expand_tool_spec.AppendPathComponent("lldb-argdumper.exe"); 218 if (!expand_tool_spec.Exists()) { 219 error.SetErrorString("could not find the lldb-argdumper tool"); 220 return error; 221 } 222 223 std::string quoted_cmd_string; 224 launch_info.GetArguments().GetQuotedCommandString(quoted_cmd_string); 225 std::replace(quoted_cmd_string.begin(), quoted_cmd_string.end(), '\\', '/'); 226 StreamString expand_command; 227 228 expand_command.Printf("\"%s\" %s", expand_tool_spec.GetPath().c_str(), 229 quoted_cmd_string.c_str()); 230 231 int status; 232 std::string output; 233 RunShellCommand(expand_command.GetData(), launch_info.GetWorkingDirectory(), 234 &status, nullptr, &output, 10); 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 size_t Host::GetEnvironment(StringList &env) { 284 // The environment block on Windows is a contiguous buffer of NULL terminated 285 // strings, 286 // where the end of the environment block is indicated by two consecutive 287 // NULLs. 288 LPWCH environment_block = ::GetEnvironmentStringsW(); 289 env.Clear(); 290 while (*environment_block != L'\0') { 291 std::string current_var; 292 auto current_var_size = wcslen(environment_block) + 1; 293 if (!llvm::convertWideToUTF8(environment_block, current_var)) { 294 environment_block += current_var_size; 295 continue; 296 } 297 if (current_var[0] != '=') 298 env.AppendString(current_var); 299 300 environment_block += current_var_size; 301 } 302 return env.GetSize(); 303 } 304