LLVM  8.0.1
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"
20 #include <malloc.h>
21 
22 // The Windows.h header must be after LLVM and standard headers.
23 #include "WindowsSupport.h"
24 
25 #include <direct.h>
26 #include <io.h>
27 #include <psapi.h>
28 #include <shellapi.h>
29 
30 #if !defined(__MINGW32__)
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 
45 using namespace llvm;
46 
47 // This function retrieves the page size using GetNativeSystemInfo() and is
48 // present solely so it can be called once to initialize the self_process member
49 // below.
50 static unsigned computePageSize() {
51  // GetNativeSystemInfo() provides the physical page size which may differ
52  // from GetSystemInfo() in 32-bit applications running under WOW64.
53  SYSTEM_INFO info;
54  GetNativeSystemInfo(&info);
55  // FIXME: FileOffset in MapViewOfFile() should be aligned to not dwPageSize,
56  // but dwAllocationGranularity.
57  return static_cast<unsigned>(info.dwPageSize);
58 }
59 
60 unsigned Process::getPageSize() {
61  static unsigned Ret = computePageSize();
62  return Ret;
63 }
64 
65 size_t
67 {
68  _HEAPINFO hinfo;
69  hinfo._pentry = NULL;
70 
71  size_t size = 0;
72 
73  while (_heapwalk(&hinfo) == _HEAPOK)
74  size += hinfo._size;
75 
76  return size;
77 }
78 
79 void Process::GetTimeUsage(TimePoint<> &elapsed, std::chrono::nanoseconds &user_time,
80  std::chrono::nanoseconds &sys_time) {
81  elapsed = std::chrono::system_clock::now();;
82 
83  FILETIME ProcCreate, ProcExit, KernelTime, UserTime;
84  if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime,
85  &UserTime) == 0)
86  return;
87 
88  user_time = toDuration(UserTime);
89  sys_time = toDuration(KernelTime);
90 }
91 
92 // Some LLVM programs such as bugpoint produce core files as a normal part of
93 // their operation. To prevent the disk from filling up, this configuration
94 // item does what's necessary to prevent their generation.
96  // Windows does have the concept of core files, called minidumps. However,
97  // disabling minidumps for a particular application extends past the lifetime
98  // of that application, which is the incorrect behavior for this API.
99  // Additionally, the APIs require elevated privileges to disable and re-
100  // enable minidumps, which makes this untenable. For more information, see
101  // WerAddExcludedApplication and WerRemoveExcludedApplication (Vista and
102  // later).
103  //
104  // Windows also has modal pop-up message boxes. As this method is used by
105  // bugpoint, preventing these pop-ups is additionally important.
106  SetErrorMode(SEM_FAILCRITICALERRORS |
107  SEM_NOGPFAULTERRORBOX |
108  SEM_NOOPENFILEERRORBOX);
109 
110  coreFilesPrevented = true;
111 }
112 
113 /// Returns the environment variable \arg Name's value as a string encoded in
114 /// UTF-8. \arg Name is assumed to be in UTF-8 encoding.
116  // Convert the argument to UTF-16 to pass it to _wgetenv().
117  SmallVector<wchar_t, 128> NameUTF16;
118  if (windows::UTF8ToUTF16(Name, NameUTF16))
119  return None;
120 
121  // Environment variable can be encoded in non-UTF8 encoding, and there's no
122  // way to know what the encoding is. The only reliable way to look up
123  // multibyte environment variable is to use GetEnvironmentVariableW().
125  size_t Size = MAX_PATH;
126  do {
127  Buf.reserve(Size);
128  SetLastError(NO_ERROR);
129  Size =
130  GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity());
131  if (Size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND)
132  return None;
133 
134  // Try again with larger buffer.
135  } while (Size > Buf.capacity());
136  Buf.set_size(Size);
137 
138  // Convert the result from UTF-16 to UTF-8.
140  if (windows::UTF16ToUTF8(Buf.data(), Size, Res))
141  return None;
142  return std::string(Res.data());
143 }
144 
145 /// Perform wildcard expansion of Arg, or just push it into Args if it doesn't
146 /// have wildcards or doesn't match any files.
147 static std::error_code WildcardExpand(StringRef Arg,
149  StringSaver &Saver) {
150  std::error_code EC;
151 
152  // Don't expand Arg if it does not contain any wildcard characters. This is
153  // the common case. Also don't wildcard expand /?. Always treat it as an
154  // option.
155  if (Arg.find_first_of("*?") == StringRef::npos || Arg == "/?" ||
156  Arg == "-?") {
157  Args.push_back(Arg.data());
158  return EC;
159  }
160 
161  // Convert back to UTF-16 so we can call FindFirstFileW.
163  EC = windows::UTF8ToUTF16(Arg, ArgW);
164  if (EC)
165  return EC;
166 
167  // Search for matching files.
168  // FIXME: This assumes the wildcard is only in the file name and not in the
169  // directory portion of the file path. For example, it doesn't handle
170  // "*\foo.c" nor "s?c\bar.cpp".
171  WIN32_FIND_DATAW FileData;
172  HANDLE FindHandle = FindFirstFileW(ArgW.data(), &FileData);
173  if (FindHandle == INVALID_HANDLE_VALUE) {
174  Args.push_back(Arg.data());
175  return EC;
176  }
177 
178  // Extract any directory part of the argument.
181  const int DirSize = Dir.size();
182 
183  do {
184  SmallString<MAX_PATH> FileName;
185  EC = windows::UTF16ToUTF8(FileData.cFileName, wcslen(FileData.cFileName),
186  FileName);
187  if (EC)
188  break;
189 
190  // Append FileName to Dir, and remove it afterwards.
191  llvm::sys::path::append(Dir, FileName);
192  Args.push_back(Saver.save(StringRef(Dir)).data());
193  Dir.resize(DirSize);
194  } while (FindNextFileW(FindHandle, &FileData));
195 
196  FindClose(FindHandle);
197  return EC;
198 }
199 
200 static std::error_code GetExecutableName(SmallVectorImpl<char> &Filename) {
201  // The first argument may contain just the name of the executable (e.g.,
202  // "clang") rather than the full path, so swap it with the full path.
203  wchar_t ModuleName[MAX_PATH];
204  size_t Length = ::GetModuleFileNameW(NULL, ModuleName, MAX_PATH);
205  if (Length == 0 || Length == MAX_PATH) {
206  return mapWindowsError(GetLastError());
207  }
208 
209  // If the first argument is a shortened (8.3) name (which is possible even
210  // if we got the module name), the driver will have trouble distinguishing it
211  // (e.g., clang.exe v. clang++.exe), so expand it now.
212  Length = GetLongPathNameW(ModuleName, ModuleName, MAX_PATH);
213  if (Length == 0)
214  return mapWindowsError(GetLastError());
215  if (Length > MAX_PATH) {
216  // We're not going to try to deal with paths longer than MAX_PATH, so we'll
217  // treat this as an error. GetLastError() returns ERROR_SUCCESS, which
218  // isn't useful, so we'll hardcode an appropriate error value.
219  return mapWindowsError(ERROR_INSUFFICIENT_BUFFER);
220  }
221 
222  std::error_code EC = windows::UTF16ToUTF8(ModuleName, Length, Filename);
223  if (EC)
224  return EC;
225 
226  StringRef Base = sys::path::filename(Filename.data());
227  Filename.assign(Base.begin(), Base.end());
228  return std::error_code();
229 }
230 
231 std::error_code
233  BumpPtrAllocator &Alloc) {
234  const wchar_t *CmdW = GetCommandLineW();
235  assert(CmdW);
236  std::error_code EC;
238  EC = windows::UTF16ToUTF8(CmdW, wcslen(CmdW), Cmd);
239  if (EC)
240  return EC;
241 
243  StringSaver Saver(Alloc);
244  cl::TokenizeWindowsCommandLine(Cmd, Saver, TmpArgs, /*MarkEOLs=*/false);
245 
246  for (const char *Arg : TmpArgs) {
247  EC = WildcardExpand(Arg, Args, Saver);
248  if (EC)
249  return EC;
250  }
251 
252  SmallVector<char, MAX_PATH> Arg0(Args[0], Args[0] + strlen(Args[0]));
255  EC = GetExecutableName(Filename);
256  if (EC)
257  return EC;
258  sys::path::append(Arg0, Filename);
259  Args[0] = Saver.save(Arg0).data();
260  return std::error_code();
261 }
262 
263 std::error_code Process::FixupStandardFileDescriptors() {
264  return std::error_code();
265 }
266 
267 std::error_code Process::SafelyCloseFileDescriptor(int FD) {
268  if (::close(FD) < 0)
269  return std::error_code(errno, std::generic_category());
270  return std::error_code();
271 }
272 
274  return FileDescriptorIsDisplayed(0);
275 }
276 
278  return FileDescriptorIsDisplayed(1);
279 }
280 
282  return FileDescriptorIsDisplayed(2);
283 }
284 
286  DWORD Mode; // Unused
287  return (GetConsoleMode((HANDLE)_get_osfhandle(fd), &Mode) != 0);
288 }
289 
290 unsigned Process::StandardOutColumns() {
291  unsigned Columns = 0;
292  CONSOLE_SCREEN_BUFFER_INFO csbi;
293  if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
294  Columns = csbi.dwSize.X;
295  return Columns;
296 }
297 
298 unsigned Process::StandardErrColumns() {
299  unsigned Columns = 0;
300  CONSOLE_SCREEN_BUFFER_INFO csbi;
301  if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi))
302  Columns = csbi.dwSize.X;
303  return Columns;
304 }
305 
306 // The terminal always has colors.
308  return FileDescriptorIsDisplayed(fd);
309 }
310 
312  return FileDescriptorHasColors(1);
313 }
314 
316  return FileDescriptorHasColors(2);
317 }
318 
319 static bool UseANSI = false;
320 void Process::UseANSIEscapeCodes(bool enable) {
321 #if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
322  if (enable) {
323  HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE);
324  DWORD Mode;
325  GetConsoleMode(Console, &Mode);
326  Mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
327  SetConsoleMode(Console, Mode);
328  }
329 #endif
330  UseANSI = enable;
331 }
332 
333 namespace {
334 class DefaultColors
335 {
336  private:
337  WORD defaultColor;
338  public:
339  DefaultColors()
340  :defaultColor(GetCurrentColor()) {}
341  static unsigned GetCurrentColor() {
342  CONSOLE_SCREEN_BUFFER_INFO csbi;
343  if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
344  return csbi.wAttributes;
345  return 0;
346  }
347  WORD operator()() const { return defaultColor; }
348 };
349 
350 DefaultColors defaultColors;
351 
352 WORD fg_color(WORD color) {
353  return color & (FOREGROUND_BLUE | FOREGROUND_GREEN |
354  FOREGROUND_INTENSITY | FOREGROUND_RED);
355 }
356 
357 WORD bg_color(WORD color) {
358  return color & (BACKGROUND_BLUE | BACKGROUND_GREEN |
359  BACKGROUND_INTENSITY | BACKGROUND_RED);
360 }
361 }
362 
364  return !UseANSI;
365 }
366 
367 const char *Process::OutputBold(bool bg) {
368  if (UseANSI) return "\033[1m";
369 
370  WORD colors = DefaultColors::GetCurrentColor();
371  if (bg)
372  colors |= BACKGROUND_INTENSITY;
373  else
374  colors |= FOREGROUND_INTENSITY;
375  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
376  return 0;
377 }
378 
379 const char *Process::OutputColor(char code, bool bold, bool bg) {
380  if (UseANSI) return colorcodes[bg?1:0][bold?1:0][code&7];
381 
382  WORD current = DefaultColors::GetCurrentColor();
383  WORD colors;
384  if (bg) {
385  colors = ((code&1) ? BACKGROUND_RED : 0) |
386  ((code&2) ? BACKGROUND_GREEN : 0 ) |
387  ((code&4) ? BACKGROUND_BLUE : 0);
388  if (bold)
389  colors |= BACKGROUND_INTENSITY;
390  colors |= fg_color(current);
391  } else {
392  colors = ((code&1) ? FOREGROUND_RED : 0) |
393  ((code&2) ? FOREGROUND_GREEN : 0 ) |
394  ((code&4) ? FOREGROUND_BLUE : 0);
395  if (bold)
396  colors |= FOREGROUND_INTENSITY;
397  colors |= bg_color(current);
398  }
399  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
400  return 0;
401 }
402 
403 static WORD GetConsoleTextAttribute(HANDLE hConsoleOutput) {
404  CONSOLE_SCREEN_BUFFER_INFO info;
405  GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
406  return info.wAttributes;
407 }
408 
409 const char *Process::OutputReverse() {
410  if (UseANSI) return "\033[7m";
411 
412  const WORD attributes
413  = GetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE));
414 
415  const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN |
416  FOREGROUND_RED | FOREGROUND_INTENSITY;
417  const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN |
418  BACKGROUND_RED | BACKGROUND_INTENSITY;
419  const WORD color_mask = foreground_mask | background_mask;
420 
421  WORD new_attributes =
422  ((attributes & FOREGROUND_BLUE )?BACKGROUND_BLUE :0) |
423  ((attributes & FOREGROUND_GREEN )?BACKGROUND_GREEN :0) |
424  ((attributes & FOREGROUND_RED )?BACKGROUND_RED :0) |
425  ((attributes & FOREGROUND_INTENSITY)?BACKGROUND_INTENSITY:0) |
426  ((attributes & BACKGROUND_BLUE )?FOREGROUND_BLUE :0) |
427  ((attributes & BACKGROUND_GREEN )?FOREGROUND_GREEN :0) |
428  ((attributes & BACKGROUND_RED )?FOREGROUND_RED :0) |
429  ((attributes & BACKGROUND_INTENSITY)?FOREGROUND_INTENSITY:0) |
430  0;
431  new_attributes = (attributes & ~color_mask) | (new_attributes & color_mask);
432 
433  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), new_attributes);
434  return 0;
435 }
436 
437 const char *Process::ResetColor() {
438  if (UseANSI) return "\033[0m";
439  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors());
440  return 0;
441 }
442 
443 // Include GetLastError() in a fatal error message.
444 static void ReportLastErrorFatal(const char *Msg) {
445  std::string ErrMsg;
446  MakeErrMsg(&ErrMsg, Msg);
447  report_fatal_error(ErrMsg);
448 }
449 
450 unsigned Process::GetRandomNumber() {
451  HCRYPTPROV HCPC;
452  if (!::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL,
453  CRYPT_VERIFYCONTEXT))
454  ReportLastErrorFatal("Could not acquire a cryptographic context");
455 
456  ScopedCryptContext CryptoProvider(HCPC);
457  unsigned Ret;
458  if (!::CryptGenRandom(CryptoProvider, sizeof(Ret),
459  reinterpret_cast<BYTE *>(&Ret)))
460  ReportLastErrorFatal("Could not generate a random number");
461  return Ret;
462 }
463 
464 typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
465 #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
466 
468  HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
469  if (hMod) {
470  auto getVer = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion");
471  if (getVer) {
472  RTL_OSVERSIONINFOEXW info{};
473  info.dwOSVersionInfoSize = sizeof(info);
474  if (getVer((PRTL_OSVERSIONINFOW)&info) == STATUS_SUCCESS) {
475  return llvm::VersionTuple(info.dwMajorVersion, info.dwMinorVersion, 0,
476  info.dwBuildNumber);
477  }
478  }
479  }
480  return llvm::VersionTuple(0, 0, 0, 0);
481 }
482 
484  // Windows 8 is version 6.2, service pack 0.
485  return GetWindowsOSVersion() >= llvm::VersionTuple(6, 2, 0, 0);
486 }
std::error_code GetCommandLineArguments(SmallVectorImpl< const char *> &Args, BumpPtrAllocator &Alloc)
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:499
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:140
This class represents lattice values for constants.
Definition: AllocatorList.h:24
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.
void push_back(const T &Elt)
Definition: SmallVector.h:218
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:376
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:128
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:480
amdgpu Simplify well known AMD library false Value Value const Twine & Name
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:81
void TokenizeWindowsCommandLine(StringRef Source, StringSaver &Saver, SmallVectorImpl< const char *> &NewArgv, bool MarkEOLs=false)
Tokenizes a Windows command line which may contain quotes and escaped quotes.
void assign(size_type NumElts, const T &Elt)
Definition: SmallVector.h:423
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
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...
Allocate memory in an ever growing pool, as if by bump-pointer.
Definition: Allocator.h:141
static sys::TimePoint< std::chrono::seconds > now(bool Deterministic)
static bool coreFilesPrevented
Definition: Process.cpp:88
std::error_code mapWindowsError(unsigned EV)
size_t capacity() const
Definition: SmallVector.h:54
lazy value info
bool RunningWindows8OrGreater()
Determines if the program is running on Windows 8 or newer.
size_t size() const
Definition: SmallVector.h:53
static size_t GetMallocUsage()
Return process memory usage.
static unsigned getPageSize()
llvm::VersionTuple GetWindowsOSVersion()
Returns the Windows version as Major.Minor.0.BuildNumber.
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...
auto size(R &&Range, typename std::enable_if< std::is_same< typename std::iterator_traits< decltype(Range.begin())>::iterator_category, std::random_access_iterator_tag >::value, void >::type *=nullptr) -> decltype(std::distance(Range.begin(), Range.end()))
Get the size of a range.
Definition: STLExtras.h:1167
This is a &#39;vector&#39; (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:847
static unsigned StandardErrColumns()
This function determines the number of columns in the window if standard error is connected to a "tty...
static bool StandardOutHasColors()
This function determines whether the terminal connected to standard output supports colors...
StringRef save(const char *S)
Definition: StringSaver.h:29
bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix)
iterator begin() const
Definition: StringRef.h:106
amdgpu Simplify well known AMD library false Value Value * Arg
static unsigned GetRandomNumber()
Get the result of a process wide random number generator.
Saves strings in the provided stable storage and returns a StringRef with a stable character pointer...
Definition: StringSaver.h:22
Represents a version number in the form major[.minor[.subminor[.build]]].
Definition: VersionTuple.h:27
pointer data()
Return a pointer to the vector&#39;s buffer, even if empty().
Definition: SmallVector.h:149
static const size_t npos
Definition: StringRef.h:51
StringRef filename(StringRef path, Style style=Style::native)
Get filename.
Definition: Path.cpp:590
std::chrono::microseconds toDuration(const struct timeval &TV)
Convert a struct timeval to a duration.
Definition: Unix.h:78
LLVM_NODISCARD size_t find_first_of(char C, size_t From=0) const
Find the first character in the string that is C, or npos if not found.
Definition: StringRef.h:395
Deduce function attributes
uint32_t Size
Definition: Profile.cpp:47
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.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
void set_size(size_t Size)
Set the array size to N, which the current array must have enough capacity for.
Definition: SmallVector.h:67
static std::error_code SafelyCloseFileDescriptor(int FD)
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
iterator end() const
Definition: StringRef.h:108
static Optional< std::string > GetEnv(StringRef name)
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
void resize(size_type N)
Definition: SmallVector.h:351