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