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