LLVM  6.0.0svn
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 
51 // This function retrieves the page size using GetNativeSystemInfo() and is
52 // present solely so it can be called once to initialize the self_process member
53 // below.
54 static unsigned computePageSize() {
55  // GetNativeSystemInfo() provides the physical page size which may differ
56  // from GetSystemInfo() in 32-bit applications running under WOW64.
57  SYSTEM_INFO info;
58  GetNativeSystemInfo(&info);
59  // FIXME: FileOffset in MapViewOfFile() should be aligned to not dwPageSize,
60  // but dwAllocationGranularity.
61  return static_cast<unsigned>(info.dwPageSize);
62 }
63 
64 unsigned Process::getPageSize() {
65  static unsigned Ret = computePageSize();
66  return Ret;
67 }
68 
69 size_t
71 {
72  _HEAPINFO hinfo;
73  hinfo._pentry = NULL;
74 
75  size_t size = 0;
76 
77  while (_heapwalk(&hinfo) == _HEAPOK)
78  size += hinfo._size;
79 
80  return size;
81 }
82 
83 void Process::GetTimeUsage(TimePoint<> &elapsed, std::chrono::nanoseconds &user_time,
84  std::chrono::nanoseconds &sys_time) {
85  elapsed = std::chrono::system_clock::now();;
86 
87  FILETIME ProcCreate, ProcExit, KernelTime, UserTime;
88  if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime,
89  &UserTime) == 0)
90  return;
91 
92  user_time = toDuration(UserTime);
93  sys_time = toDuration(KernelTime);
94 }
95 
96 // Some LLVM programs such as bugpoint produce core files as a normal part of
97 // their operation. To prevent the disk from filling up, this configuration
98 // item does what's necessary to prevent their generation.
100  // Windows does have the concept of core files, called minidumps. However,
101  // disabling minidumps for a particular application extends past the lifetime
102  // of that application, which is the incorrect behavior for this API.
103  // Additionally, the APIs require elevated privileges to disable and re-
104  // enable minidumps, which makes this untenable. For more information, see
105  // WerAddExcludedApplication and WerRemoveExcludedApplication (Vista and
106  // later).
107  //
108  // Windows also has modal pop-up message boxes. As this method is used by
109  // bugpoint, preventing these pop-ups is additionally important.
110  SetErrorMode(SEM_FAILCRITICALERRORS |
111  SEM_NOGPFAULTERRORBOX |
112  SEM_NOOPENFILEERRORBOX);
113 
114  coreFilesPrevented = true;
115 }
116 
117 /// Returns the environment variable \arg Name's value as a string encoded in
118 /// UTF-8. \arg Name is assumed to be in UTF-8 encoding.
120  // Convert the argument to UTF-16 to pass it to _wgetenv().
121  SmallVector<wchar_t, 128> NameUTF16;
122  if (windows::UTF8ToUTF16(Name, NameUTF16))
123  return None;
124 
125  // Environment variable can be encoded in non-UTF8 encoding, and there's no
126  // way to know what the encoding is. The only reliable way to look up
127  // multibyte environment variable is to use GetEnvironmentVariableW().
129  size_t Size = MAX_PATH;
130  do {
131  Buf.reserve(Size);
132  SetLastError(NO_ERROR);
133  Size =
134  GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity());
135  if (Size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND)
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 }
void push_back(const T &Elt)
Definition: SmallVector.h:212
void remove_filename(SmallVectorImpl< char > &path, Style style=Style::native)
Remove the last component from path unless it is the root dir.
Definition: Path.cpp:483
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.
Definition: Error.cpp:103
Compute iterated dominance frontiers using a linear time algorithm.
Definition: AllocatorList.h:24
static const char * ResetColor()
Resets the terminals colors, or returns an escape sequence to do so.
LLVM_ATTRIBUTE_ALWAYS_INLINE size_type size() const
Definition: SmallVector.h:136
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:380
This file defines the MallocAllocator and BumpPtrAllocator interfaces.
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:464
static bool ColorNeedsFlush()
Whether changing colors requires the output to be flushed.
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:80
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&#39;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...
size_t capacity() const
Return the total number of elements in the currently allocated buffer.
Definition: SmallVector.h:140
static sys::TimePoint< std::chrono::seconds > now(bool Deterministic)
static bool coreFilesPrevented
Definition: Process.cpp:86
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:434
lazy value info
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()
Basic Register Allocator
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 &#39;vector&#39; (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:864
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:385
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 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 ...
amdgpu Simplify well known AMD library false Value Value * Arg
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:689
pointer data()
Return a pointer to the vector&#39;s buffer, even if empty().
Definition: SmallVector.h:143
std::chrono::microseconds toDuration(const struct timeval &TV)
Convert a struct timeval to a duration.
Definition: Unix.h:78
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.
constexpr char Size[]
Key for Kernel::Arg::Metadata::mSize.
static std::error_code SafelyCloseFileDescriptor(int FD)
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
static Optional< std::string > GetEnv(StringRef name)
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
void resize(size_type N)
Definition: SmallVector.h:355