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