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 <malloc.h> 16 17// The Windows.h header must be after LLVM and standard headers. 18#include "WindowsSupport.h" 19 20#include <direct.h> 21#include <io.h> 22#include <psapi.h> 23#include <shellapi.h> 24 25#ifdef __MINGW32__ 26 #if (HAVE_LIBPSAPI != 1) 27 #error "libpsapi.a should be present" 28 #endif 29 #if (HAVE_LIBSHELL32 != 1) 30 #error "libshell32.a should be present" 31 #endif 32#else 33 #pragma comment(lib, "psapi.lib") 34 #pragma comment(lib, "shell32.lib") 35#endif 36 37//===----------------------------------------------------------------------===// 38//=== WARNING: Implementation here must contain only Win32 specific code 39//=== and must not be UNIX code 40//===----------------------------------------------------------------------===// 41 42#ifdef __MINGW32__ 43// This ban should be lifted when MinGW 1.0+ has defined this value. 44# define _HEAPOK (-2) 45#endif 46 47using namespace llvm; 48using namespace sys; 49 50 51process::id_type self_process::get_id() { 52 return GetCurrentProcessId(); 53} 54 55static TimeValue getTimeValueFromFILETIME(FILETIME Time) { 56 ULARGE_INTEGER TimeInteger; 57 TimeInteger.LowPart = Time.dwLowDateTime; 58 TimeInteger.HighPart = Time.dwHighDateTime; 59 60 // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond) 61 return TimeValue( 62 static_cast<TimeValue::SecondsType>(TimeInteger.QuadPart / 10000000), 63 static_cast<TimeValue::NanoSecondsType>( 64 (TimeInteger.QuadPart % 10000000) * 100)); 65} 66 67TimeValue self_process::get_user_time() const { 68 FILETIME ProcCreate, ProcExit, KernelTime, UserTime; 69 if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime, 70 &UserTime) == 0) 71 return TimeValue(); 72 73 return getTimeValueFromFILETIME(UserTime); 74} 75 76TimeValue self_process::get_system_time() const { 77 FILETIME ProcCreate, ProcExit, KernelTime, UserTime; 78 if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime, 79 &UserTime) == 0) 80 return TimeValue(); 81 82 return getTimeValueFromFILETIME(KernelTime); 83} 84 85// This function retrieves the page size using GetSystemInfo and is present 86// solely so it can be called once to initialize the self_process member below. 87static unsigned getPageSize() { 88 // NOTE: A 32-bit application running under WOW64 is supposed to use 89 // GetNativeSystemInfo. However, this interface is not present prior 90 // to Windows XP so to use it requires dynamic linking. It is not clear 91 // how this affects the reported page size, if at all. One could argue 92 // that LLVM ought to run as 64-bits on a 64-bit system, anyway. 93 SYSTEM_INFO info; 94 GetSystemInfo(&info); 95 // FIXME: FileOffset in MapViewOfFile() should be aligned to not dwPageSize, 96 // but dwAllocationGranularity. 97 return static_cast<unsigned>(info.dwPageSize); 98} 99 100// This constructor guaranteed to be run exactly once on a single thread, and 101// sets up various process invariants that can be queried cheaply from then on. 102self_process::self_process() : PageSize(getPageSize()) { 103} 104 105 106size_t 107Process::GetMallocUsage() 108{ 109 _HEAPINFO hinfo; 110 hinfo._pentry = NULL; 111 112 size_t size = 0; 113 114 while (_heapwalk(&hinfo) == _HEAPOK) 115 size += hinfo._size; 116 117 return size; 118} 119 120void Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time, 121 TimeValue &sys_time) { 122 elapsed = TimeValue::now(); 123 124 FILETIME ProcCreate, ProcExit, KernelTime, UserTime; 125 if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime, 126 &UserTime) == 0) 127 return; 128 129 user_time = getTimeValueFromFILETIME(UserTime); 130 sys_time = getTimeValueFromFILETIME(KernelTime); 131} 132 133// Some LLVM programs such as bugpoint produce core files as a normal part of 134// their operation. To prevent the disk from filling up, this configuration 135// item does what's necessary to prevent their generation. 136void Process::PreventCoreFiles() { 137 // Windows does have the concept of core files, called minidumps. However, 138 // disabling minidumps for a particular application extends past the lifetime 139 // of that application, which is the incorrect behavior for this API. 140 // Additionally, the APIs require elevated privileges to disable and re- 141 // enable minidumps, which makes this untenable. For more information, see 142 // WerAddExcludedApplication and WerRemoveExcludedApplication (Vista and 143 // later). 144 // 145 // Windows also has modal pop-up message boxes. As this method is used by 146 // bugpoint, preventing these pop-ups is additionally important. 147 SetErrorMode(SEM_FAILCRITICALERRORS | 148 SEM_NOGPFAULTERRORBOX | 149 SEM_NOOPENFILEERRORBOX); 150} 151 152/// Returns the environment variable \arg Name's value as a string encoded in 153/// UTF-8. \arg Name is assumed to be in UTF-8 encoding. 154Optional<std::string> Process::GetEnv(StringRef Name) { 155 // Convert the argument to UTF-16 to pass it to _wgetenv(). 156 SmallVector<wchar_t, 128> NameUTF16; 157 if (windows::UTF8ToUTF16(Name, NameUTF16)) 158 return None; 159 160 // Environment variable can be encoded in non-UTF8 encoding, and there's no 161 // way to know what the encoding is. The only reliable way to look up 162 // multibyte environment variable is to use GetEnvironmentVariableW(). 163 SmallVector<wchar_t, MAX_PATH> Buf; 164 size_t Size = MAX_PATH; 165 do { 166 Buf.reserve(Size); 167 Size = 168 GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity()); 169 if (Size == 0) 170 return None; 171 172 // Try again with larger buffer. 173 } while (Size > Buf.capacity()); 174 Buf.set_size(Size); 175 176 // Convert the result from UTF-16 to UTF-8. 177 SmallVector<char, MAX_PATH> Res; 178 if (windows::UTF16ToUTF8(Buf.data(), Size, Res)) 179 return None; 180 return std::string(Res.data()); 181} 182 183error_code 184Process::GetArgumentVector(SmallVectorImpl<const char *> &Args, 185 ArrayRef<const char *>, 186 SpecificBumpPtrAllocator<char> &ArgAllocator) { 187 int NewArgCount; 188 error_code ec; 189 190 wchar_t **UnicodeCommandLine = CommandLineToArgvW(GetCommandLineW(), 191 &NewArgCount); 192 if (!UnicodeCommandLine) 193 return windows_error(::GetLastError()); 194 195 Args.reserve(NewArgCount); 196 197 for (int i = 0; i < NewArgCount; ++i) { 198 SmallVector<char, MAX_PATH> NewArgString; 199 ec = windows::UTF16ToUTF8(UnicodeCommandLine[i], 200 wcslen(UnicodeCommandLine[i]), 201 NewArgString); 202 if (ec) 203 break; 204 205 char *Buffer = ArgAllocator.Allocate(NewArgString.size() + 1); 206 ::memcpy(Buffer, NewArgString.data(), NewArgString.size() + 1); 207 Args.push_back(Buffer); 208 } 209 LocalFree(UnicodeCommandLine); 210 if (ec) 211 return ec; 212 213 return error_code::success(); 214} 215 216bool Process::StandardInIsUserInput() { 217 return FileDescriptorIsDisplayed(0); 218} 219 220bool Process::StandardOutIsDisplayed() { 221 return FileDescriptorIsDisplayed(1); 222} 223 224bool Process::StandardErrIsDisplayed() { 225 return FileDescriptorIsDisplayed(2); 226} 227 228bool Process::FileDescriptorIsDisplayed(int fd) { 229 DWORD Mode; // Unused 230 return (GetConsoleMode((HANDLE)_get_osfhandle(fd), &Mode) != 0); 231} 232 233unsigned Process::StandardOutColumns() { 234 unsigned Columns = 0; 235 CONSOLE_SCREEN_BUFFER_INFO csbi; 236 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) 237 Columns = csbi.dwSize.X; 238 return Columns; 239} 240 241unsigned Process::StandardErrColumns() { 242 unsigned Columns = 0; 243 CONSOLE_SCREEN_BUFFER_INFO csbi; 244 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi)) 245 Columns = csbi.dwSize.X; 246 return Columns; 247} 248 249// The terminal always has colors. 250bool Process::FileDescriptorHasColors(int fd) { 251 return FileDescriptorIsDisplayed(fd); 252} 253 254bool Process::StandardOutHasColors() { 255 return FileDescriptorHasColors(1); 256} 257 258bool Process::StandardErrHasColors() { 259 return FileDescriptorHasColors(2); 260} 261 262static bool UseANSI = false; 263void Process::UseANSIEscapeCodes(bool enable) { 264 UseANSI = enable; 265} 266 267namespace { 268class DefaultColors 269{ 270 private: 271 WORD defaultColor; 272 public: 273 DefaultColors() 274 :defaultColor(GetCurrentColor()) {} 275 static unsigned GetCurrentColor() { 276 CONSOLE_SCREEN_BUFFER_INFO csbi; 277 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) 278 return csbi.wAttributes; 279 return 0; 280 } 281 WORD operator()() const { return defaultColor; } 282}; 283 284DefaultColors defaultColors; 285} 286 287bool Process::ColorNeedsFlush() { 288 return !UseANSI; 289} 290 291const char *Process::OutputBold(bool bg) { 292 if (UseANSI) return "\033[1m"; 293 294 WORD colors = DefaultColors::GetCurrentColor(); 295 if (bg) 296 colors |= BACKGROUND_INTENSITY; 297 else 298 colors |= FOREGROUND_INTENSITY; 299 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); 300 return 0; 301} 302 303const char *Process::OutputColor(char code, bool bold, bool bg) { 304 if (UseANSI) return colorcodes[bg?1:0][bold?1:0][code&7]; 305 306 WORD colors; 307 if (bg) { 308 colors = ((code&1) ? BACKGROUND_RED : 0) | 309 ((code&2) ? BACKGROUND_GREEN : 0 ) | 310 ((code&4) ? BACKGROUND_BLUE : 0); 311 if (bold) 312 colors |= BACKGROUND_INTENSITY; 313 } else { 314 colors = ((code&1) ? FOREGROUND_RED : 0) | 315 ((code&2) ? FOREGROUND_GREEN : 0 ) | 316 ((code&4) ? FOREGROUND_BLUE : 0); 317 if (bold) 318 colors |= FOREGROUND_INTENSITY; 319 } 320 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); 321 return 0; 322} 323 324static WORD GetConsoleTextAttribute(HANDLE hConsoleOutput) { 325 CONSOLE_SCREEN_BUFFER_INFO info; 326 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info); 327 return info.wAttributes; 328} 329 330const char *Process::OutputReverse() { 331 if (UseANSI) return "\033[7m"; 332 333 const WORD attributes 334 = GetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE)); 335 336 const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN | 337 FOREGROUND_RED | FOREGROUND_INTENSITY; 338 const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN | 339 BACKGROUND_RED | BACKGROUND_INTENSITY; 340 const WORD color_mask = foreground_mask | background_mask; 341 342 WORD new_attributes = 343 ((attributes & FOREGROUND_BLUE )?BACKGROUND_BLUE :0) | 344 ((attributes & FOREGROUND_GREEN )?BACKGROUND_GREEN :0) | 345 ((attributes & FOREGROUND_RED )?BACKGROUND_RED :0) | 346 ((attributes & FOREGROUND_INTENSITY)?BACKGROUND_INTENSITY:0) | 347 ((attributes & BACKGROUND_BLUE )?FOREGROUND_BLUE :0) | 348 ((attributes & BACKGROUND_GREEN )?FOREGROUND_GREEN :0) | 349 ((attributes & BACKGROUND_RED )?FOREGROUND_RED :0) | 350 ((attributes & BACKGROUND_INTENSITY)?FOREGROUND_INTENSITY:0) | 351 0; 352 new_attributes = (attributes & ~color_mask) | (new_attributes & color_mask); 353 354 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), new_attributes); 355 return 0; 356} 357 358const char *Process::ResetColor() { 359 if (UseANSI) return "\033[0m"; 360 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors()); 361 return 0; 362} 363 364unsigned Process::GetRandomNumber() { 365 HCRYPTPROV HCPC; 366 if (!::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL, 367 CRYPT_VERIFYCONTEXT)) 368 assert(false && "Could not acquire a cryptographic context"); 369 370 ScopedCryptContext CryptoProvider(HCPC); 371 unsigned Ret; 372 if (!::CryptGenRandom(CryptoProvider, sizeof(Ret), 373 reinterpret_cast<BYTE *>(&Ret))) 374 assert(false && "Could not generate a random number"); 375 return Ret; 376} 377