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