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