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/Core/DataBufferHeap.h" 24 #include "lldb/Core/DataExtractor.h" 25 #include "lldb/Core/StreamFile.h" 26 27 // Windows includes 28 #include <shellapi.h> 29 #include <TlHelp32.h> 30 31 using namespace lldb; 32 using namespace lldb_private; 33 34 namespace 35 { 36 bool GetTripleForProcess(const FileSpec &executable, llvm::Triple &triple) 37 { 38 // Open the PE File as a binary file, and parse just enough information to determine the 39 // machine type. 40 File imageBinary( 41 executable.GetPath().c_str(), 42 File::eOpenOptionRead, 43 lldb::eFilePermissionsUserRead); 44 imageBinary.SeekFromStart(0x3c); 45 int32_t peOffset = 0; 46 uint32_t peHead = 0; 47 uint16_t machineType = 0; 48 size_t readSize = sizeof(peOffset); 49 imageBinary.Read(&peOffset, readSize); 50 imageBinary.SeekFromStart(peOffset); 51 imageBinary.Read(&peHead, readSize); 52 if (peHead != 0x00004550) // "PE\0\0", little-endian 53 return false; // Error: Can't find PE header 54 readSize = 2; 55 imageBinary.Read(&machineType, readSize); 56 triple.setVendor(llvm::Triple::PC); 57 triple.setOS(llvm::Triple::Win32); 58 triple.setArch(llvm::Triple::UnknownArch); 59 if (machineType == 0x8664) 60 triple.setArch(llvm::Triple::x86_64); 61 else if (machineType == 0x14c) 62 triple.setArch(llvm::Triple::x86); 63 64 return true; 65 } 66 67 bool GetExecutableForProcess(const AutoHandle &handle, std::string &path) 68 { 69 // Get the process image path. MAX_PATH isn't long enough, paths can actually be up to 32KB. 70 std::vector<char> buffer(32768); 71 DWORD dwSize = buffer.size(); 72 if (!::QueryFullProcessImageNameA(handle.get(), 0, &buffer[0], &dwSize)) 73 return false; 74 path.assign(&buffer[0]); 75 return true; 76 } 77 78 void GetProcessExecutableAndTriple(const AutoHandle &handle, ProcessInstanceInfo &process) 79 { 80 // We may not have permissions to read the path from the process. So start off by 81 // setting the executable file to whatever Toolhelp32 gives us, and then try to 82 // enhance this with more detailed information, but fail gracefully. 83 std::string executable; 84 llvm::Triple triple; 85 triple.setVendor(llvm::Triple::PC); 86 triple.setOS(llvm::Triple::Win32); 87 triple.setArch(llvm::Triple::UnknownArch); 88 if (GetExecutableForProcess(handle, executable)) 89 { 90 FileSpec executableFile(executable.c_str(), false); 91 process.SetExecutableFile(executableFile, true); 92 GetTripleForProcess(executableFile, triple); 93 } 94 process.SetArchitecture(ArchSpec(triple)); 95 96 // TODO(zturner): Add the ability to get the process user name. 97 } 98 } 99 100 bool 101 Host::GetOSVersion(uint32_t &major, 102 uint32_t &minor, 103 uint32_t &update) 104 { 105 OSVERSIONINFOEX info; 106 107 ZeroMemory(&info, sizeof(OSVERSIONINFOEX)); 108 info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); 109 #pragma warning(push) 110 #pragma warning(disable: 4996) 111 // Starting with Microsoft SDK for Windows 8.1, this function is deprecated in favor of the 112 // new Windows Version Helper APIs. Since we don't specify a minimum SDK version, it's easier 113 // to simply disable the warning rather than try to support both APIs. 114 if (GetVersionEx((LPOSVERSIONINFO) &info) == 0) { 115 return false; 116 } 117 #pragma warning(pop) 118 119 major = (uint32_t) info.dwMajorVersion; 120 minor = (uint32_t) info.dwMinorVersion; 121 update = (uint32_t) info.wServicePackMajor; 122 123 return true; 124 } 125 126 Error 127 Host::MakeDirectory (const char* path, uint32_t mode) 128 { 129 // On Win32, the mode parameter is ignored, as Windows files and directories support a 130 // different permission model than POSIX. 131 Error error; 132 if (!::CreateDirectory(path, NULL)) 133 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 134 return error; 135 } 136 137 Error 138 Host::GetFilePermissions (const char* path, uint32_t &file_permissions) 139 { 140 Error error; 141 file_permissions = 0; 142 DWORD attrib = ::GetFileAttributes(path); 143 if (attrib == INVALID_FILE_ATTRIBUTES) 144 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 145 return error; 146 } 147 148 Error 149 Host::SetFilePermissions (const char* path, uint32_t file_permissions) 150 { 151 Error error; 152 error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__); 153 return error; 154 } 155 156 Error 157 Host::Symlink (const char *linkname, const char *target) 158 { 159 Error error; 160 DWORD attrib = ::GetFileAttributes(target); 161 if (attrib == INVALID_FILE_ATTRIBUTES) 162 { 163 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 164 return error; 165 } 166 bool is_directory = !!(attrib & FILE_ATTRIBUTE_DIRECTORY); 167 DWORD flag = is_directory ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0; 168 BOOL result = ::CreateSymbolicLink(linkname, target, flag); 169 if (!result) 170 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 171 return error; 172 } 173 174 Error 175 Host::Readlink (const char *path, char *buf, size_t buf_len) 176 { 177 Error error; 178 HANDLE h = ::CreateFile(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, NULL); 179 if (h == INVALID_HANDLE_VALUE) 180 { 181 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 182 return error; 183 } 184 185 // Subtract 1 from the path length since this function does not add a null terminator. 186 DWORD result = ::GetFinalPathNameByHandle(h, buf, buf_len-1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); 187 if (result == 0) 188 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 189 190 ::CloseHandle(h); 191 return error; 192 } 193 194 Error 195 Host::Unlink (const char *path) 196 { 197 Error error; 198 BOOL result = ::DeleteFile(path); 199 if (!result) 200 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 201 return error; 202 } 203 204 Error 205 Host::RemoveDirectory (const char* path, bool recurse) 206 { 207 Error error; 208 if (!recurse) 209 { 210 BOOL result = ::RemoveDirectory(path); 211 if (!result) 212 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 213 } 214 else 215 { 216 // SHFileOperation() accepts a list of paths, and so must be double-null-terminated to 217 // indicate the end of the list. 218 std::string path_buffer(path); 219 path_buffer.push_back(0); 220 221 SHFILEOPSTRUCT shfos = {0}; 222 shfos.wFunc = FO_DELETE; 223 shfos.pFrom = path_buffer.c_str(); 224 shfos.fFlags = FOF_NO_UI; 225 226 int result = ::SHFileOperation(&shfos); 227 // TODO(zturner): Correctly handle the intricacies of SHFileOperation return values. 228 if (result != 0) 229 error.SetErrorStringWithFormat("SHFileOperation failed"); 230 } 231 return error; 232 } 233 234 235 Error 236 Host::LaunchProcess (ProcessLaunchInfo &launch_info) 237 { 238 Error error; 239 assert(!"Not implemented yet!!!"); 240 return error; 241 } 242 243 lldb::DataBufferSP 244 Host::GetAuxvData(lldb_private::Process *process) 245 { 246 return 0; 247 } 248 249 std::string 250 Host::GetThreadName (lldb::pid_t pid, lldb::tid_t tid) 251 { 252 return std::string(); 253 } 254 255 lldb::tid_t 256 Host::GetCurrentThreadID() 257 { 258 return lldb::tid_t(::GetCurrentThreadId()); 259 } 260 261 lldb::thread_t 262 Host::GetCurrentThread () 263 { 264 return lldb::thread_t(::GetCurrentThread()); 265 } 266 267 bool 268 Host::ThreadCancel (lldb::thread_t thread, Error *error) 269 { 270 int err = ::TerminateThread((HANDLE)thread, 0); 271 return err == 0; 272 } 273 274 bool 275 Host::ThreadDetach (lldb::thread_t thread, Error *error) 276 { 277 return ThreadCancel(thread, error); 278 } 279 280 bool 281 Host::ThreadJoin (lldb::thread_t thread, thread_result_t *thread_result_ptr, Error *error) 282 { 283 WaitForSingleObject((HANDLE) thread, INFINITE); 284 return true; 285 } 286 287 lldb::thread_key_t 288 Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback) 289 { 290 return TlsAlloc(); 291 } 292 293 void* 294 Host::ThreadLocalStorageGet(lldb::thread_key_t key) 295 { 296 return ::TlsGetValue (key); 297 } 298 299 void 300 Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value) 301 { 302 ::TlsSetValue (key, value); 303 } 304 305 bool 306 Host::SetThreadName (lldb::pid_t pid, lldb::tid_t tid, const char *name) 307 { 308 return false; 309 } 310 311 bool 312 Host::SetShortThreadName (lldb::pid_t pid, lldb::tid_t tid, 313 const char *thread_name, size_t len) 314 { 315 return false; 316 } 317 318 void 319 Host::Kill(lldb::pid_t pid, int signo) 320 { 321 TerminateProcess((HANDLE) pid, 1); 322 } 323 324 uint32_t 325 Host::GetNumberCPUS() 326 { 327 static uint32_t g_num_cores = UINT32_MAX; 328 if (g_num_cores == UINT32_MAX) 329 { 330 SYSTEM_INFO system_info; 331 ::GetSystemInfo(&system_info); 332 g_num_cores = system_info.dwNumberOfProcessors; 333 } 334 return g_num_cores; 335 } 336 337 size_t 338 Host::GetPageSize() 339 { 340 static long g_pagesize = 0; 341 if (!g_pagesize) 342 { 343 SYSTEM_INFO systemInfo; 344 GetNativeSystemInfo(&systemInfo); 345 g_pagesize = systemInfo.dwPageSize; 346 } 347 return g_pagesize; 348 } 349 350 const char * 351 Host::GetSignalAsCString(int signo) 352 { 353 return NULL; 354 } 355 356 FileSpec 357 Host::GetModuleFileSpecForHostAddress (const void *host_addr) 358 { 359 FileSpec module_filespec; 360 361 HMODULE hmodule = NULL; 362 if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)host_addr, &hmodule)) 363 return module_filespec; 364 365 std::vector<char> buffer(MAX_PATH); 366 DWORD chars_copied = 0; 367 do { 368 chars_copied = ::GetModuleFileName(hmodule, &buffer[0], buffer.size()); 369 if (chars_copied == buffer.size() && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) 370 buffer.resize(buffer.size() * 2); 371 } while (chars_copied >= buffer.size()); 372 373 module_filespec.SetFile(&buffer[0], false); 374 return module_filespec; 375 } 376 377 void * 378 Host::DynamicLibraryOpen(const FileSpec &file_spec, uint32_t options, Error &error) 379 { 380 error.SetErrorString("not implemented"); 381 return NULL; 382 } 383 384 Error 385 Host::DynamicLibraryClose (void *opaque) 386 { 387 Error error; 388 error.SetErrorString("not implemented"); 389 return error; 390 } 391 392 void * 393 Host::DynamicLibraryGetSymbol(void *opaque, const char *symbol_name, Error &error) 394 { 395 error.SetErrorString("not implemented"); 396 return NULL; 397 } 398 399 const char * 400 Host::GetUserName (uint32_t uid, std::string &user_name) 401 { 402 return NULL; 403 } 404 405 const char * 406 Host::GetGroupName (uint32_t gid, std::string &group_name) 407 { 408 llvm_unreachable("Windows does not support group name"); 409 return NULL; 410 } 411 412 uint32_t 413 Host::GetUserID () 414 { 415 llvm_unreachable("Windows does not support uid"); 416 } 417 418 uint32_t 419 Host::GetGroupID () 420 { 421 llvm_unreachable("Windows does not support gid"); 422 return 0; 423 } 424 425 uint32_t 426 Host::GetEffectiveUserID () 427 { 428 llvm_unreachable("Windows does not support euid"); 429 return 0; 430 } 431 432 uint32_t 433 Host::GetEffectiveGroupID () 434 { 435 llvm_unreachable("Windows does not support egid"); 436 return 0; 437 } 438 439 uint32_t 440 Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos) 441 { 442 process_infos.Clear(); 443 444 AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)); 445 if (!snapshot.IsValid()) 446 return 0; 447 448 PROCESSENTRY32 pe = {0}; 449 pe.dwSize = sizeof(PROCESSENTRY32); 450 if (Process32First(snapshot.get(), &pe)) 451 { 452 do 453 { 454 AutoHandle handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID), nullptr); 455 456 ProcessInstanceInfo process; 457 process.SetExecutableFile(FileSpec(pe.szExeFile, false), true); 458 process.SetProcessID(pe.th32ProcessID); 459 process.SetParentProcessID(pe.th32ParentProcessID); 460 GetProcessExecutableAndTriple(handle, process); 461 462 if (match_info.MatchAllProcesses() || match_info.Matches(process)) 463 process_infos.Append(process); 464 } while (Process32Next(snapshot.get(), &pe)); 465 } 466 return process_infos.GetSize(); 467 } 468 469 bool 470 Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) 471 { 472 process_info.Clear(); 473 474 AutoHandle handle(::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid), 475 nullptr); 476 if (!handle.IsValid()) 477 return false; 478 479 process_info.SetProcessID(pid); 480 GetProcessExecutableAndTriple(handle, process_info); 481 482 // Need to read the PEB to get parent process and command line arguments. 483 return true; 484 } 485 486 lldb::thread_t 487 Host::StartMonitoringChildProcess 488 ( 489 Host::MonitorChildProcessCallback callback, 490 void *callback_baton, 491 lldb::pid_t pid, 492 bool monitor_signals 493 ) 494 { 495 return LLDB_INVALID_HOST_THREAD; 496 }