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