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