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 void AllocateAndPush(const SmallVectorImpl<char> &S, 143 SmallVectorImpl<const char *> &Vector, 144 SpecificBumpPtrAllocator<char> &Allocator) { 145 char *Buffer = Allocator.Allocate(S.size() + 1); 146 ::memcpy(Buffer, S.data(), S.size()); 147 Buffer[S.size()] = '\0'; 148 Vector.push_back(Buffer); 149} 150 151/// Convert Arg from UTF-16 to UTF-8 and push it onto Args. 152static std::error_code 153ConvertAndPushArg(const wchar_t *Arg, SmallVectorImpl<const char *> &Args, 154 SpecificBumpPtrAllocator<char> &Allocator) { 155 SmallVector<char, MAX_PATH> ArgString; 156 if (std::error_code ec = windows::UTF16ToUTF8(Arg, wcslen(Arg), ArgString)) 157 return ec; 158 AllocateAndPush(ArgString, Args, Allocator); 159 return std::error_code(); 160} 161 162/// \brief Perform wildcard expansion of Arg, or just push it into Args if it 163/// doesn't have wildcards or doesn't match any files. 164static std::error_code 165WildcardExpand(const wchar_t *Arg, SmallVectorImpl<const char *> &Args, 166 SpecificBumpPtrAllocator<char> &Allocator) { 167 if (!wcspbrk(Arg, L"*?")) { 168 // Arg does not contain any wildcard characters. This is the common case. 169 return ConvertAndPushArg(Arg, Args, Allocator); 170 } 171 172 if (wcscmp(Arg, L"/?") == 0 || wcscmp(Arg, L"-?") == 0) { 173 // Don't wildcard expand /?. Always treat it as an option. 174 return ConvertAndPushArg(Arg, Args, Allocator); 175 } 176 177 // Extract any directory part of the argument. 178 SmallVector<char, MAX_PATH> Dir; 179 if (std::error_code ec = windows::UTF16ToUTF8(Arg, wcslen(Arg), Dir)) 180 return ec; 181 sys::path::remove_filename(Dir); 182 const int DirSize = Dir.size(); 183 184 // Search for matching files. 185 // FIXME: This assumes the wildcard is only in the file name and not in the 186 // directory portion of the file path. For example, it doesn't handle 187 // "*\foo.c" nor "s?c\bar.cpp". 188 WIN32_FIND_DATAW FileData; 189 HANDLE FindHandle = FindFirstFileW(Arg, &FileData); 190 if (FindHandle == INVALID_HANDLE_VALUE) { 191 return ConvertAndPushArg(Arg, Args, Allocator); 192 } 193 194 std::error_code ec; 195 do { 196 SmallVector<char, MAX_PATH> FileName; 197 ec = windows::UTF16ToUTF8(FileData.cFileName, wcslen(FileData.cFileName), 198 FileName); 199 if (ec) 200 break; 201 202 // Append FileName to Dir, and remove it afterwards. 203 llvm::sys::path::append(Dir, StringRef(FileName.data(), FileName.size())); 204 AllocateAndPush(Dir, Args, Allocator); 205 Dir.resize(DirSize); 206 } while (FindNextFileW(FindHandle, &FileData)); 207 208 FindClose(FindHandle); 209 return ec; 210} 211 212static std::error_code 213ExpandShortFileName(const wchar_t *Arg, SmallVectorImpl<const char *> &Args, 214 SpecificBumpPtrAllocator<char> &Allocator) { 215 SmallVector<wchar_t, MAX_PATH> LongPath; 216 DWORD Length = GetLongPathNameW(Arg, LongPath.data(), LongPath.capacity()); 217 if (Length == 0) 218 return mapWindowsError(GetLastError()); 219 if (Length > LongPath.capacity()) { 220 // We're not going to try to deal with paths longer than MAX_PATH, so we'll 221 // treat this as an error. GetLastError() returns ERROR_SUCCESS, which 222 // isn't useful, so we'll hardcode an appropriate error value. 223 return mapWindowsError(ERROR_INSUFFICIENT_BUFFER); 224 } 225 LongPath.set_size(Length); 226 return ConvertAndPushArg(LongPath.data(), Args, Allocator); 227} 228 229std::error_code 230Process::GetArgumentVector(SmallVectorImpl<const char *> &Args, 231 ArrayRef<const char *>, 232 SpecificBumpPtrAllocator<char> &ArgAllocator) { 233 int ArgCount; 234 wchar_t **UnicodeCommandLine = 235 CommandLineToArgvW(GetCommandLineW(), &ArgCount); 236 if (!UnicodeCommandLine) 237 return mapWindowsError(::GetLastError()); 238 239 Args.reserve(ArgCount); 240 std::error_code ec; 241 242 // The first argument may contain just the name of the executable (e.g., 243 // "clang") rather than the full path, so swap it with the full path. 244 wchar_t ModuleName[MAX_PATH]; 245 int Length = ::GetModuleFileNameW(NULL, ModuleName, MAX_PATH); 246 if (0 < Length && Length < MAX_PATH) 247 UnicodeCommandLine[0] = ModuleName; 248 249 // If the first argument is a shortened (8.3) name (which is possible even 250 // if we got the module name), the driver will have trouble distinguishing it 251 // (e.g., clang.exe v. clang++.exe), so expand it now. 252 ec = ExpandShortFileName(UnicodeCommandLine[0], Args, ArgAllocator); 253 254 for (int i = 1; i < ArgCount && !ec; ++i) { 255 ec = WildcardExpand(UnicodeCommandLine[i], Args, ArgAllocator); 256 if (ec) 257 break; 258 } 259 260 LocalFree(UnicodeCommandLine); 261 return ec; 262} 263 264std::error_code Process::FixupStandardFileDescriptors() { 265 return std::error_code(); 266} 267 268std::error_code Process::SafelyCloseFileDescriptor(int FD) { 269 if (::close(FD) < 0) 270 return std::error_code(errno, std::generic_category()); 271 return std::error_code(); 272} 273 274bool Process::StandardInIsUserInput() { 275 return FileDescriptorIsDisplayed(0); 276} 277 278bool Process::StandardOutIsDisplayed() { 279 return FileDescriptorIsDisplayed(1); 280} 281 282bool Process::StandardErrIsDisplayed() { 283 return FileDescriptorIsDisplayed(2); 284} 285 286bool Process::FileDescriptorIsDisplayed(int fd) { 287 DWORD Mode; // Unused 288 return (GetConsoleMode((HANDLE)_get_osfhandle(fd), &Mode) != 0); 289} 290 291unsigned Process::StandardOutColumns() { 292 unsigned Columns = 0; 293 CONSOLE_SCREEN_BUFFER_INFO csbi; 294 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) 295 Columns = csbi.dwSize.X; 296 return Columns; 297} 298 299unsigned Process::StandardErrColumns() { 300 unsigned Columns = 0; 301 CONSOLE_SCREEN_BUFFER_INFO csbi; 302 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi)) 303 Columns = csbi.dwSize.X; 304 return Columns; 305} 306 307// The terminal always has colors. 308bool Process::FileDescriptorHasColors(int fd) { 309 return FileDescriptorIsDisplayed(fd); 310} 311 312bool Process::StandardOutHasColors() { 313 return FileDescriptorHasColors(1); 314} 315 316bool Process::StandardErrHasColors() { 317 return FileDescriptorHasColors(2); 318} 319 320static bool UseANSI = false; 321void Process::UseANSIEscapeCodes(bool enable) { 322 UseANSI = enable; 323} 324 325namespace { 326class DefaultColors 327{ 328 private: 329 WORD defaultColor; 330 public: 331 DefaultColors() 332 :defaultColor(GetCurrentColor()) {} 333 static unsigned GetCurrentColor() { 334 CONSOLE_SCREEN_BUFFER_INFO csbi; 335 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) 336 return csbi.wAttributes; 337 return 0; 338 } 339 WORD operator()() const { return defaultColor; } 340}; 341 342DefaultColors defaultColors; 343 344WORD fg_color(WORD color) { 345 return color & (FOREGROUND_BLUE | FOREGROUND_GREEN | 346 FOREGROUND_INTENSITY | FOREGROUND_RED); 347} 348 349WORD bg_color(WORD color) { 350 return color & (BACKGROUND_BLUE | BACKGROUND_GREEN | 351 BACKGROUND_INTENSITY | BACKGROUND_RED); 352} 353} 354 355bool Process::ColorNeedsFlush() { 356 return !UseANSI; 357} 358 359const char *Process::OutputBold(bool bg) { 360 if (UseANSI) return "\033[1m"; 361 362 WORD colors = DefaultColors::GetCurrentColor(); 363 if (bg) 364 colors |= BACKGROUND_INTENSITY; 365 else 366 colors |= FOREGROUND_INTENSITY; 367 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); 368 return 0; 369} 370 371const char *Process::OutputColor(char code, bool bold, bool bg) { 372 if (UseANSI) return colorcodes[bg?1:0][bold?1:0][code&7]; 373 374 WORD current = DefaultColors::GetCurrentColor(); 375 WORD colors; 376 if (bg) { 377 colors = ((code&1) ? BACKGROUND_RED : 0) | 378 ((code&2) ? BACKGROUND_GREEN : 0 ) | 379 ((code&4) ? BACKGROUND_BLUE : 0); 380 if (bold) 381 colors |= BACKGROUND_INTENSITY; 382 colors |= fg_color(current); 383 } else { 384 colors = ((code&1) ? FOREGROUND_RED : 0) | 385 ((code&2) ? FOREGROUND_GREEN : 0 ) | 386 ((code&4) ? FOREGROUND_BLUE : 0); 387 if (bold) 388 colors |= FOREGROUND_INTENSITY; 389 colors |= bg_color(current); 390 } 391 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); 392 return 0; 393} 394 395static WORD GetConsoleTextAttribute(HANDLE hConsoleOutput) { 396 CONSOLE_SCREEN_BUFFER_INFO info; 397 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info); 398 return info.wAttributes; 399} 400 401const char *Process::OutputReverse() { 402 if (UseANSI) return "\033[7m"; 403 404 const WORD attributes 405 = GetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE)); 406 407 const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN | 408 FOREGROUND_RED | FOREGROUND_INTENSITY; 409 const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN | 410 BACKGROUND_RED | BACKGROUND_INTENSITY; 411 const WORD color_mask = foreground_mask | background_mask; 412 413 WORD new_attributes = 414 ((attributes & FOREGROUND_BLUE )?BACKGROUND_BLUE :0) | 415 ((attributes & FOREGROUND_GREEN )?BACKGROUND_GREEN :0) | 416 ((attributes & FOREGROUND_RED )?BACKGROUND_RED :0) | 417 ((attributes & FOREGROUND_INTENSITY)?BACKGROUND_INTENSITY:0) | 418 ((attributes & BACKGROUND_BLUE )?FOREGROUND_BLUE :0) | 419 ((attributes & BACKGROUND_GREEN )?FOREGROUND_GREEN :0) | 420 ((attributes & BACKGROUND_RED )?FOREGROUND_RED :0) | 421 ((attributes & BACKGROUND_INTENSITY)?FOREGROUND_INTENSITY:0) | 422 0; 423 new_attributes = (attributes & ~color_mask) | (new_attributes & color_mask); 424 425 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), new_attributes); 426 return 0; 427} 428 429const char *Process::ResetColor() { 430 if (UseANSI) return "\033[0m"; 431 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors()); 432 return 0; 433} 434 435// Include GetLastError() in a fatal error message. 436static void ReportLastErrorFatal(const char *Msg) { 437 std::string ErrMsg; 438 MakeErrMsg(&ErrMsg, Msg); 439 report_fatal_error(ErrMsg); 440} 441 442unsigned Process::GetRandomNumber() { 443 HCRYPTPROV HCPC; 444 if (!::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL, 445 CRYPT_VERIFYCONTEXT)) 446 ReportLastErrorFatal("Could not acquire a cryptographic context"); 447 448 ScopedCryptContext CryptoProvider(HCPC); 449 unsigned Ret; 450 if (!::CryptGenRandom(CryptoProvider, sizeof(Ret), 451 reinterpret_cast<BYTE *>(&Ret))) 452 ReportLastErrorFatal("Could not generate a random number"); 453 return Ret; 454} 455