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