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