1//===- Win32/Process.cpp - Win32 Process Implementation ------- -*- 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// This file provides the Win32 specific implementation of the Process class. 11// 12//===----------------------------------------------------------------------===// 13 14#include "llvm/Support/Allocator.h" 15#include "llvm/Support/CommandLine.h" 16#include "llvm/Support/ConvertUTF.h" 17#include "llvm/Support/ErrorHandling.h" 18#include "llvm/Support/StringSaver.h" 19#include "llvm/Support/WindowsError.h" 20#include <malloc.h> 21 22// The Windows.h header must be after LLVM and standard headers. 23#include "WindowsSupport.h" 24 25#include <direct.h> 26#include <io.h> 27#include <psapi.h> 28#include <shellapi.h> 29 30#if !defined(__MINGW32__) 31 #pragma comment(lib, "psapi.lib") 32 #pragma comment(lib, "shell32.lib") 33#endif 34 35//===----------------------------------------------------------------------===// 36//=== WARNING: Implementation here must contain only Win32 specific code 37//=== and must not be UNIX code 38//===----------------------------------------------------------------------===// 39 40#ifdef __MINGW32__ 41// This ban should be lifted when MinGW 1.0+ has defined this value. 42# define _HEAPOK (-2) 43#endif 44 45using namespace llvm; 46 47// This function retrieves the page size using GetNativeSystemInfo() and is 48// present solely so it can be called once to initialize the self_process member 49// below. 50static unsigned computePageSize() { 51 // GetNativeSystemInfo() provides the physical page size which may differ 52 // from GetSystemInfo() in 32-bit applications running under WOW64. 53 SYSTEM_INFO info; 54 GetNativeSystemInfo(&info); 55 // FIXME: FileOffset in MapViewOfFile() should be aligned to not dwPageSize, 56 // but dwAllocationGranularity. 57 return static_cast<unsigned>(info.dwPageSize); 58} 59 60unsigned Process::getPageSize() { 61 static unsigned Ret = computePageSize(); 62 return Ret; 63} 64 65size_t 66Process::GetMallocUsage() 67{ 68 _HEAPINFO hinfo; 69 hinfo._pentry = NULL; 70 71 size_t size = 0; 72 73 while (_heapwalk(&hinfo) == _HEAPOK) 74 size += hinfo._size; 75 76 return size; 77} 78 79void Process::GetTimeUsage(TimePoint<> &elapsed, std::chrono::nanoseconds &user_time, 80 std::chrono::nanoseconds &sys_time) { 81 elapsed = std::chrono::system_clock::now();; 82 83 FILETIME ProcCreate, ProcExit, KernelTime, UserTime; 84 if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime, 85 &UserTime) == 0) 86 return; 87 88 user_time = toDuration(UserTime); 89 sys_time = toDuration(KernelTime); 90} 91 92// Some LLVM programs such as bugpoint produce core files as a normal part of 93// their operation. To prevent the disk from filling up, this configuration 94// item does what's necessary to prevent their generation. 95void Process::PreventCoreFiles() { 96 // Windows does have the concept of core files, called minidumps. However, 97 // disabling minidumps for a particular application extends past the lifetime 98 // of that application, which is the incorrect behavior for this API. 99 // Additionally, the APIs require elevated privileges to disable and re- 100 // enable minidumps, which makes this untenable. For more information, see 101 // WerAddExcludedApplication and WerRemoveExcludedApplication (Vista and 102 // later). 103 // 104 // Windows also has modal pop-up message boxes. As this method is used by 105 // bugpoint, preventing these pop-ups is additionally important. 106 SetErrorMode(SEM_FAILCRITICALERRORS | 107 SEM_NOGPFAULTERRORBOX | 108 SEM_NOOPENFILEERRORBOX); 109 110 coreFilesPrevented = true; 111} 112 113/// Returns the environment variable \arg Name's value as a string encoded in 114/// UTF-8. \arg Name is assumed to be in UTF-8 encoding. 115Optional<std::string> Process::GetEnv(StringRef Name) { 116 // Convert the argument to UTF-16 to pass it to _wgetenv(). 117 SmallVector<wchar_t, 128> NameUTF16; 118 if (windows::UTF8ToUTF16(Name, NameUTF16)) 119 return None; 120 121 // Environment variable can be encoded in non-UTF8 encoding, and there's no 122 // way to know what the encoding is. The only reliable way to look up 123 // multibyte environment variable is to use GetEnvironmentVariableW(). 124 SmallVector<wchar_t, MAX_PATH> Buf; 125 size_t Size = MAX_PATH; 126 do { 127 Buf.reserve(Size); 128 SetLastError(NO_ERROR); 129 Size = 130 GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity()); 131 if (Size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) 132 return None; 133 134 // Try again with larger buffer. 135 } while (Size > Buf.capacity()); 136 Buf.set_size(Size); 137 138 // Convert the result from UTF-16 to UTF-8. 139 SmallVector<char, MAX_PATH> Res; 140 if (windows::UTF16ToUTF8(Buf.data(), Size, Res)) 141 return None; 142 return std::string(Res.data()); 143} 144 145/// Perform wildcard expansion of Arg, or just push it into Args if it doesn't 146/// have wildcards or doesn't match any files. 147static std::error_code WildcardExpand(StringRef Arg, 148 SmallVectorImpl<const char *> &Args, 149 StringSaver &Saver) { 150 std::error_code EC; 151 152 // Don't expand Arg if it does not contain any wildcard characters. This is 153 // the common case. Also don't wildcard expand /?. Always treat it as an 154 // option. 155 if (Arg.find_first_of("*?") == StringRef::npos || Arg == "/?" || 156 Arg == "-?") { 157 Args.push_back(Arg.data()); 158 return EC; 159 } 160 161 // Convert back to UTF-16 so we can call FindFirstFileW. 162 SmallVector<wchar_t, MAX_PATH> ArgW; 163 EC = windows::UTF8ToUTF16(Arg, ArgW); 164 if (EC) 165 return EC; 166 167 // Search for matching files. 168 // FIXME: This assumes the wildcard is only in the file name and not in the 169 // directory portion of the file path. For example, it doesn't handle 170 // "*\foo.c" nor "s?c\bar.cpp". 171 WIN32_FIND_DATAW FileData; 172 HANDLE FindHandle = FindFirstFileW(ArgW.data(), &FileData); 173 if (FindHandle == INVALID_HANDLE_VALUE) { 174 Args.push_back(Arg.data()); 175 return EC; 176 } 177 178 // Extract any directory part of the argument. 179 SmallString<MAX_PATH> Dir = Arg; 180 sys::path::remove_filename(Dir); 181 const int DirSize = Dir.size(); 182 183 do { 184 SmallString<MAX_PATH> FileName; 185 EC = windows::UTF16ToUTF8(FileData.cFileName, wcslen(FileData.cFileName), 186 FileName); 187 if (EC) 188 break; 189 190 // Append FileName to Dir, and remove it afterwards. 191 llvm::sys::path::append(Dir, FileName); 192 Args.push_back(Saver.save(StringRef(Dir)).data()); 193 Dir.resize(DirSize); 194 } while (FindNextFileW(FindHandle, &FileData)); 195 196 FindClose(FindHandle); 197 return EC; 198} 199 200static std::error_code GetExecutableName(SmallVectorImpl<char> &Filename) { 201 // The first argument may contain just the name of the executable (e.g., 202 // "clang") rather than the full path, so swap it with the full path. 203 wchar_t ModuleName[MAX_PATH]; 204 size_t Length = ::GetModuleFileNameW(NULL, ModuleName, MAX_PATH); 205 if (Length == 0 || Length == MAX_PATH) { 206 return mapWindowsError(GetLastError()); 207 } 208 209 // If the first argument is a shortened (8.3) name (which is possible even 210 // if we got the module name), the driver will have trouble distinguishing it 211 // (e.g., clang.exe v. clang++.exe), so expand it now. 212 Length = GetLongPathNameW(ModuleName, ModuleName, MAX_PATH); 213 if (Length == 0) 214 return mapWindowsError(GetLastError()); 215 if (Length > MAX_PATH) { 216 // We're not going to try to deal with paths longer than MAX_PATH, so we'll 217 // treat this as an error. GetLastError() returns ERROR_SUCCESS, which 218 // isn't useful, so we'll hardcode an appropriate error value. 219 return mapWindowsError(ERROR_INSUFFICIENT_BUFFER); 220 } 221 222 std::error_code EC = windows::UTF16ToUTF8(ModuleName, Length, Filename); 223 if (EC) 224 return EC; 225 226 StringRef Base = sys::path::filename(Filename.data()); 227 Filename.assign(Base.begin(), Base.end()); 228 return std::error_code(); 229} 230 231std::error_code 232windows::GetCommandLineArguments(SmallVectorImpl<const char *> &Args, 233 BumpPtrAllocator &Alloc) { 234 const wchar_t *CmdW = GetCommandLineW(); 235 assert(CmdW); 236 std::error_code EC; 237 SmallString<MAX_PATH> Cmd; 238 EC = windows::UTF16ToUTF8(CmdW, wcslen(CmdW), Cmd); 239 if (EC) 240 return EC; 241 242 SmallVector<const char *, 20> TmpArgs; 243 StringSaver Saver(Alloc); 244 cl::TokenizeWindowsCommandLine(Cmd, Saver, TmpArgs, /*MarkEOLs=*/false); 245 246 for (const char *Arg : TmpArgs) { 247 EC = WildcardExpand(Arg, Args, Saver); 248 if (EC) 249 return EC; 250 } 251 252 SmallVector<char, MAX_PATH> Arg0(Args[0], Args[0] + strlen(Args[0])); 253 SmallVector<char, MAX_PATH> Filename; 254 sys::path::remove_filename(Arg0); 255 EC = GetExecutableName(Filename); 256 if (EC) 257 return EC; 258 sys::path::append(Arg0, Filename); 259 Args[0] = Saver.save(Arg0).data(); 260 return std::error_code(); 261} 262 263std::error_code Process::FixupStandardFileDescriptors() { 264 return std::error_code(); 265} 266 267std::error_code Process::SafelyCloseFileDescriptor(int FD) { 268 if (::close(FD) < 0) 269 return std::error_code(errno, std::generic_category()); 270 return std::error_code(); 271} 272 273bool Process::StandardInIsUserInput() { 274 return FileDescriptorIsDisplayed(0); 275} 276 277bool Process::StandardOutIsDisplayed() { 278 return FileDescriptorIsDisplayed(1); 279} 280 281bool Process::StandardErrIsDisplayed() { 282 return FileDescriptorIsDisplayed(2); 283} 284 285bool Process::FileDescriptorIsDisplayed(int fd) { 286 DWORD Mode; // Unused 287 return (GetConsoleMode((HANDLE)_get_osfhandle(fd), &Mode) != 0); 288} 289 290unsigned Process::StandardOutColumns() { 291 unsigned Columns = 0; 292 CONSOLE_SCREEN_BUFFER_INFO csbi; 293 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) 294 Columns = csbi.dwSize.X; 295 return Columns; 296} 297 298unsigned Process::StandardErrColumns() { 299 unsigned Columns = 0; 300 CONSOLE_SCREEN_BUFFER_INFO csbi; 301 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi)) 302 Columns = csbi.dwSize.X; 303 return Columns; 304} 305 306// The terminal always has colors. 307bool Process::FileDescriptorHasColors(int fd) { 308 return FileDescriptorIsDisplayed(fd); 309} 310 311bool Process::StandardOutHasColors() { 312 return FileDescriptorHasColors(1); 313} 314 315bool Process::StandardErrHasColors() { 316 return FileDescriptorHasColors(2); 317} 318 319static bool UseANSI = false; 320void Process::UseANSIEscapeCodes(bool enable) { 321#if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) 322 if (enable) { 323 HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); 324 DWORD Mode; 325 GetConsoleMode(Console, &Mode); 326 Mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; 327 SetConsoleMode(Console, Mode); 328 } 329#endif 330 UseANSI = enable; 331} 332 333namespace { 334class DefaultColors 335{ 336 private: 337 WORD defaultColor; 338 public: 339 DefaultColors() 340 :defaultColor(GetCurrentColor()) {} 341 static unsigned GetCurrentColor() { 342 CONSOLE_SCREEN_BUFFER_INFO csbi; 343 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) 344 return csbi.wAttributes; 345 return 0; 346 } 347 WORD operator()() const { return defaultColor; } 348}; 349 350DefaultColors defaultColors; 351 352WORD fg_color(WORD color) { 353 return color & (FOREGROUND_BLUE | FOREGROUND_GREEN | 354 FOREGROUND_INTENSITY | FOREGROUND_RED); 355} 356 357WORD bg_color(WORD color) { 358 return color & (BACKGROUND_BLUE | BACKGROUND_GREEN | 359 BACKGROUND_INTENSITY | BACKGROUND_RED); 360} 361} 362 363bool Process::ColorNeedsFlush() { 364 return !UseANSI; 365} 366 367const char *Process::OutputBold(bool bg) { 368 if (UseANSI) return "\033[1m"; 369 370 WORD colors = DefaultColors::GetCurrentColor(); 371 if (bg) 372 colors |= BACKGROUND_INTENSITY; 373 else 374 colors |= FOREGROUND_INTENSITY; 375 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); 376 return 0; 377} 378 379const char *Process::OutputColor(char code, bool bold, bool bg) { 380 if (UseANSI) return colorcodes[bg?1:0][bold?1:0][code&7]; 381 382 WORD current = DefaultColors::GetCurrentColor(); 383 WORD colors; 384 if (bg) { 385 colors = ((code&1) ? BACKGROUND_RED : 0) | 386 ((code&2) ? BACKGROUND_GREEN : 0 ) | 387 ((code&4) ? BACKGROUND_BLUE : 0); 388 if (bold) 389 colors |= BACKGROUND_INTENSITY; 390 colors |= fg_color(current); 391 } else { 392 colors = ((code&1) ? FOREGROUND_RED : 0) | 393 ((code&2) ? FOREGROUND_GREEN : 0 ) | 394 ((code&4) ? FOREGROUND_BLUE : 0); 395 if (bold) 396 colors |= FOREGROUND_INTENSITY; 397 colors |= bg_color(current); 398 } 399 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); 400 return 0; 401} 402 403static WORD GetConsoleTextAttribute(HANDLE hConsoleOutput) { 404 CONSOLE_SCREEN_BUFFER_INFO info; 405 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info); 406 return info.wAttributes; 407} 408 409const char *Process::OutputReverse() { 410 if (UseANSI) return "\033[7m"; 411 412 const WORD attributes 413 = GetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE)); 414 415 const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN | 416 FOREGROUND_RED | FOREGROUND_INTENSITY; 417 const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN | 418 BACKGROUND_RED | BACKGROUND_INTENSITY; 419 const WORD color_mask = foreground_mask | background_mask; 420 421 WORD new_attributes = 422 ((attributes & FOREGROUND_BLUE )?BACKGROUND_BLUE :0) | 423 ((attributes & FOREGROUND_GREEN )?BACKGROUND_GREEN :0) | 424 ((attributes & FOREGROUND_RED )?BACKGROUND_RED :0) | 425 ((attributes & FOREGROUND_INTENSITY)?BACKGROUND_INTENSITY:0) | 426 ((attributes & BACKGROUND_BLUE )?FOREGROUND_BLUE :0) | 427 ((attributes & BACKGROUND_GREEN )?FOREGROUND_GREEN :0) | 428 ((attributes & BACKGROUND_RED )?FOREGROUND_RED :0) | 429 ((attributes & BACKGROUND_INTENSITY)?FOREGROUND_INTENSITY:0) | 430 0; 431 new_attributes = (attributes & ~color_mask) | (new_attributes & color_mask); 432 433 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), new_attributes); 434 return 0; 435} 436 437const char *Process::ResetColor() { 438 if (UseANSI) return "\033[0m"; 439 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors()); 440 return 0; 441} 442 443// Include GetLastError() in a fatal error message. 444static void ReportLastErrorFatal(const char *Msg) { 445 std::string ErrMsg; 446 MakeErrMsg(&ErrMsg, Msg); 447 report_fatal_error(ErrMsg); 448} 449 450unsigned Process::GetRandomNumber() { 451 HCRYPTPROV HCPC; 452 if (!::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL, 453 CRYPT_VERIFYCONTEXT)) 454 ReportLastErrorFatal("Could not acquire a cryptographic context"); 455 456 ScopedCryptContext CryptoProvider(HCPC); 457 unsigned Ret; 458 if (!::CryptGenRandom(CryptoProvider, sizeof(Ret), 459 reinterpret_cast<BYTE *>(&Ret))) 460 ReportLastErrorFatal("Could not generate a random number"); 461 return Ret; 462} 463 464typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); 465#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) 466 467llvm::VersionTuple llvm::GetWindowsOSVersion() { 468 HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll"); 469 if (hMod) { 470 auto getVer = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion"); 471 if (getVer) { 472 RTL_OSVERSIONINFOEXW info{}; 473 info.dwOSVersionInfoSize = sizeof(info); 474 if (getVer((PRTL_OSVERSIONINFOW)&info) == STATUS_SUCCESS) { 475 return llvm::VersionTuple(info.dwMajorVersion, info.dwMinorVersion, 0, 476 info.dwBuildNumber); 477 } 478 } 479 } 480 return llvm::VersionTuple(0, 0, 0, 0); 481} 482 483bool llvm::RunningWindows8OrGreater() { 484 // Windows 8 is version 6.2, service pack 0. 485 return GetWindowsOSVersion() >= llvm::VersionTuple(6, 2, 0, 0); 486} 487