• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1//===- Win32/Signals.cpp - Win32 Signals 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 Signals class.
11//
12//===----------------------------------------------------------------------===//
13#include "llvm/Support/FileSystem.h"
14#include "llvm/Support/Path.h"
15#include "llvm/Support/Process.h"
16#include "llvm/Support/WindowsError.h"
17#include <algorithm>
18#include <io.h>
19#include <signal.h>
20#include <stdio.h>
21
22#include "llvm/Support/Format.h"
23#include "llvm/Support/raw_ostream.h"
24
25// The Windows.h header must be after LLVM and standard headers.
26#include "WindowsSupport.h"
27
28#ifdef __MINGW32__
29 #include <imagehlp.h>
30#else
31 #include <crtdbg.h>
32 #include <dbghelp.h>
33#endif
34#include <psapi.h>
35
36#ifdef _MSC_VER
37 #pragma comment(lib, "psapi.lib")
38#elif __MINGW32__
39 #if (HAVE_LIBPSAPI != 1)
40  #error "libpsapi.a should be present"
41 #endif
42 // The version of g++ that comes with MinGW does *not* properly understand
43 // the ll format specifier for printf. However, MinGW passes the format
44 // specifiers on to the MSVCRT entirely, and the CRT understands the ll
45 // specifier. So these warnings are spurious in this case. Since we compile
46 // with -Wall, this will generate these warnings which should be ignored. So
47 // we will turn off the warnings for this just file. However, MinGW also does
48 // not support push and pop for diagnostics, so we have to manually turn it
49 // back on at the end of the file.
50 #pragma GCC diagnostic ignored "-Wformat"
51 #pragma GCC diagnostic ignored "-Wformat-extra-args"
52
53 #if !defined(__MINGW64_VERSION_MAJOR)
54 // MinGW.org does not have updated support for the 64-bit versions of the
55 // DebugHlp APIs. So we will have to load them manually. The structures and
56 // method signatures were pulled from DbgHelp.h in the Windows Platform SDK,
57 // and adjusted for brevity.
58 typedef struct _IMAGEHLP_LINE64 {
59   DWORD    SizeOfStruct;
60   PVOID    Key;
61   DWORD    LineNumber;
62   PCHAR    FileName;
63   DWORD64  Address;
64 } IMAGEHLP_LINE64, *PIMAGEHLP_LINE64;
65
66 typedef struct _IMAGEHLP_SYMBOL64 {
67   DWORD   SizeOfStruct;
68   DWORD64 Address;
69   DWORD   Size;
70   DWORD   Flags;
71   DWORD   MaxNameLength;
72   CHAR    Name[1];
73 } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64;
74
75 typedef struct _tagADDRESS64 {
76   DWORD64       Offset;
77   WORD          Segment;
78   ADDRESS_MODE  Mode;
79 } ADDRESS64, *LPADDRESS64;
80
81 typedef struct _KDHELP64 {
82   DWORD64   Thread;
83   DWORD   ThCallbackStack;
84   DWORD   ThCallbackBStore;
85   DWORD   NextCallback;
86   DWORD   FramePointer;
87   DWORD64   KiCallUserMode;
88   DWORD64   KeUserCallbackDispatcher;
89   DWORD64   SystemRangeStart;
90   DWORD64   KiUserExceptionDispatcher;
91   DWORD64   StackBase;
92   DWORD64   StackLimit;
93   DWORD64   Reserved[5];
94 } KDHELP64, *PKDHELP64;
95
96 typedef struct _tagSTACKFRAME64 {
97   ADDRESS64   AddrPC;
98   ADDRESS64   AddrReturn;
99   ADDRESS64   AddrFrame;
100   ADDRESS64   AddrStack;
101   ADDRESS64   AddrBStore;
102   PVOID       FuncTableEntry;
103   DWORD64     Params[4];
104   BOOL        Far;
105   BOOL        Virtual;
106   DWORD64     Reserved[3];
107   KDHELP64    KdHelp;
108 } STACKFRAME64, *LPSTACKFRAME64;
109 #endif // !defined(__MINGW64_VERSION_MAJOR)
110#endif // __MINGW32__
111
112typedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess,
113                      DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize,
114                      LPDWORD lpNumberOfBytesRead);
115
116typedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( HANDLE ahProcess,
117                      DWORD64 AddrBase);
118
119typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess,
120                      DWORD64 Address);
121
122typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess,
123                      HANDLE hThread, LPADDRESS64 lpaddr);
124
125typedef BOOL(WINAPI *fpMiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,
126                                          PMINIDUMP_EXCEPTION_INFORMATION,
127                                          PMINIDUMP_USER_STREAM_INFORMATION,
128                                          PMINIDUMP_CALLBACK_INFORMATION);
129static fpMiniDumpWriteDump fMiniDumpWriteDump;
130
131typedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64,
132                      PVOID, PREAD_PROCESS_MEMORY_ROUTINE64,
133                      PFUNCTION_TABLE_ACCESS_ROUTINE64,
134                      PGET_MODULE_BASE_ROUTINE64,
135                      PTRANSLATE_ADDRESS_ROUTINE64);
136static fpStackWalk64 fStackWalk64;
137
138typedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64);
139static fpSymGetModuleBase64 fSymGetModuleBase64;
140
141typedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64,
142                      PDWORD64, PIMAGEHLP_SYMBOL64);
143static fpSymGetSymFromAddr64 fSymGetSymFromAddr64;
144
145typedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64,
146                      PDWORD, PIMAGEHLP_LINE64);
147static fpSymGetLineFromAddr64 fSymGetLineFromAddr64;
148
149typedef BOOL(WINAPI *fpSymGetModuleInfo64)(HANDLE hProcess, DWORD64 dwAddr,
150                                           PIMAGEHLP_MODULE64 ModuleInfo);
151static fpSymGetModuleInfo64 fSymGetModuleInfo64;
152
153typedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64);
154static fpSymFunctionTableAccess64 fSymFunctionTableAccess64;
155
156typedef DWORD (WINAPI *fpSymSetOptions)(DWORD);
157static fpSymSetOptions fSymSetOptions;
158
159typedef BOOL (WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL);
160static fpSymInitialize fSymInitialize;
161
162typedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID);
163static fpEnumerateLoadedModules fEnumerateLoadedModules;
164
165static bool load64BitDebugHelp(void) {
166  HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll");
167  if (hLib) {
168    fMiniDumpWriteDump = (fpMiniDumpWriteDump)
169                      ::GetProcAddress(hLib, "MiniDumpWriteDump");
170    fStackWalk64 = (fpStackWalk64)
171                      ::GetProcAddress(hLib, "StackWalk64");
172    fSymGetModuleBase64 = (fpSymGetModuleBase64)
173                      ::GetProcAddress(hLib, "SymGetModuleBase64");
174    fSymGetSymFromAddr64 = (fpSymGetSymFromAddr64)
175                      ::GetProcAddress(hLib, "SymGetSymFromAddr64");
176    fSymGetLineFromAddr64 = (fpSymGetLineFromAddr64)
177                      ::GetProcAddress(hLib, "SymGetLineFromAddr64");
178    fSymGetModuleInfo64 = (fpSymGetModuleInfo64)
179                      ::GetProcAddress(hLib, "SymGetModuleInfo64");
180    fSymFunctionTableAccess64 = (fpSymFunctionTableAccess64)
181                     ::GetProcAddress(hLib, "SymFunctionTableAccess64");
182    fSymSetOptions = (fpSymSetOptions)::GetProcAddress(hLib, "SymSetOptions");
183    fSymInitialize = (fpSymInitialize)::GetProcAddress(hLib, "SymInitialize");
184    fEnumerateLoadedModules = (fpEnumerateLoadedModules)
185      ::GetProcAddress(hLib, "EnumerateLoadedModules64");
186  }
187  return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump;
188}
189
190using namespace llvm;
191
192// Forward declare.
193static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep);
194static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType);
195
196// InterruptFunction - The function to call if ctrl-c is pressed.
197static void (*InterruptFunction)() = 0;
198
199static std::vector<std::string> *FilesToRemove = NULL;
200static bool RegisteredUnhandledExceptionFilter = false;
201static bool CleanupExecuted = false;
202static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL;
203
204// Windows creates a new thread to execute the console handler when an event
205// (such as CTRL/C) occurs.  This causes concurrency issues with the above
206// globals which this critical section addresses.
207static CRITICAL_SECTION CriticalSection;
208static bool CriticalSectionInitialized = false;
209
210static StringRef Argv0;
211
212enum {
213#if defined(_M_X64)
214  NativeMachineType = IMAGE_FILE_MACHINE_AMD64
215#else
216  NativeMachineType = IMAGE_FILE_MACHINE_I386
217#endif
218};
219
220static bool printStackTraceWithLLVMSymbolizer(llvm::raw_ostream &OS,
221                                              HANDLE hProcess, HANDLE hThread,
222                                              STACKFRAME64 &StackFrameOrig,
223                                              CONTEXT *ContextOrig) {
224  // StackWalk64 modifies the incoming stack frame and context, so copy them.
225  STACKFRAME64 StackFrame = StackFrameOrig;
226
227  // Copy the register context so that we don't modify it while we unwind. We
228  // could use InitializeContext + CopyContext, but that's only required to get
229  // at AVX registers, which typically aren't needed by StackWalk64. Reduce the
230  // flag set to indicate that there's less data.
231  CONTEXT Context = *ContextOrig;
232  Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
233
234  static void *StackTrace[256];
235  size_t Depth = 0;
236  while (fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame,
237                      &Context, 0, fSymFunctionTableAccess64,
238                      fSymGetModuleBase64, 0)) {
239    if (StackFrame.AddrFrame.Offset == 0)
240      break;
241    StackTrace[Depth++] = (void *)(uintptr_t)StackFrame.AddrPC.Offset;
242    if (Depth >= array_lengthof(StackTrace))
243      break;
244  }
245
246  return printSymbolizedStackTrace(Argv0, &StackTrace[0], Depth, OS);
247}
248
249namespace {
250struct FindModuleData {
251  void **StackTrace;
252  int Depth;
253  const char **Modules;
254  intptr_t *Offsets;
255  StringSaver *StrPool;
256};
257}
258
259static BOOL CALLBACK findModuleCallback(PCSTR ModuleName,
260                                        DWORD64 ModuleBase, ULONG ModuleSize,
261                                        void *VoidData) {
262  FindModuleData *Data = (FindModuleData*)VoidData;
263  intptr_t Beg = ModuleBase;
264  intptr_t End = Beg + ModuleSize;
265  for (int I = 0; I < Data->Depth; I++) {
266    if (Data->Modules[I])
267      continue;
268    intptr_t Addr = (intptr_t)Data->StackTrace[I];
269    if (Beg <= Addr && Addr < End) {
270      Data->Modules[I] = Data->StrPool->save(ModuleName).data();
271      Data->Offsets[I] = Addr - Beg;
272    }
273  }
274  return TRUE;
275}
276
277static bool findModulesAndOffsets(void **StackTrace, int Depth,
278                                  const char **Modules, intptr_t *Offsets,
279                                  const char *MainExecutableName,
280                                  StringSaver &StrPool) {
281  if (!fEnumerateLoadedModules)
282    return false;
283  FindModuleData Data;
284  Data.StackTrace = StackTrace;
285  Data.Depth = Depth;
286  Data.Modules = Modules;
287  Data.Offsets = Offsets;
288  Data.StrPool = &StrPool;
289  fEnumerateLoadedModules(GetCurrentProcess(), findModuleCallback, &Data);
290  return true;
291}
292
293static void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess,
294                                     HANDLE hThread, STACKFRAME64 &StackFrame,
295                                     CONTEXT *Context) {
296#if ENABLE_BACKTRACES
297  // Initialize the symbol handler.
298  fSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
299  fSymInitialize(hProcess, NULL, TRUE);
300
301  // Try llvm-symbolizer first. llvm-symbolizer knows how to deal with both PDBs
302  // and DWARF, so it should do a good job regardless of what debug info or
303  // linker is in use.
304  if (printStackTraceWithLLVMSymbolizer(OS, hProcess, hThread, StackFrame,
305                                        Context)) {
306    return;
307  }
308
309  while (true) {
310    if (!fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame,
311                      Context, 0, fSymFunctionTableAccess64,
312                      fSymGetModuleBase64, 0)) {
313      break;
314    }
315
316    if (StackFrame.AddrFrame.Offset == 0)
317      break;
318
319    using namespace llvm;
320    // Print the PC in hexadecimal.
321    DWORD64 PC = StackFrame.AddrPC.Offset;
322#if defined(_M_X64)
323    OS << format("0x%016llX", PC);
324#elif defined(_M_IX86)
325    OS << format("0x%08lX", static_cast<DWORD>(PC));
326#endif
327
328// Print the parameters.  Assume there are four.
329#if defined(_M_X64)
330    OS << format(" (0x%016llX 0x%016llX 0x%016llX 0x%016llX)",
331            StackFrame.Params[0], StackFrame.Params[1], StackFrame.Params[2],
332            StackFrame.Params[3]);
333#elif defined(_M_IX86)
334    OS << format(" (0x%08lX 0x%08lX 0x%08lX 0x%08lX)",
335            static_cast<DWORD>(StackFrame.Params[0]),
336            static_cast<DWORD>(StackFrame.Params[1]),
337            static_cast<DWORD>(StackFrame.Params[2]),
338            static_cast<DWORD>(StackFrame.Params[3]));
339#endif
340    // Verify the PC belongs to a module in this process.
341    if (!fSymGetModuleBase64(hProcess, PC)) {
342      OS << " <unknown module>\n";
343      continue;
344    }
345
346    // Print the symbol name.
347    char buffer[512];
348    IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer);
349    memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64));
350    symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
351    symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64);
352
353    DWORD64 dwDisp;
354    if (!fSymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) {
355      OS << '\n';
356      continue;
357    }
358
359    buffer[511] = 0;
360    if (dwDisp > 0)
361      OS << format(", %s() + 0x%llX bytes(s)", (const char*)symbol->Name,
362                   dwDisp);
363    else
364      OS << format(", %s", (const char*)symbol->Name);
365
366    // Print the source file and line number information.
367    IMAGEHLP_LINE64 line = {};
368    DWORD dwLineDisp;
369    line.SizeOfStruct = sizeof(line);
370    if (fSymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) {
371      OS << format(", %s, line %lu", line.FileName, line.LineNumber);
372      if (dwLineDisp > 0)
373        OS << format(" + 0x%lX byte(s)", dwLineDisp);
374    }
375
376    OS << '\n';
377  }
378#endif
379}
380
381namespace llvm {
382
383//===----------------------------------------------------------------------===//
384//=== WARNING: Implementation here must contain only Win32 specific code
385//===          and must not be UNIX code
386//===----------------------------------------------------------------------===//
387
388#ifdef _MSC_VER
389/// AvoidMessageBoxHook - Emulates hitting "retry" from an "abort, retry,
390/// ignore" CRT debug report dialog.  "retry" raises an exception which
391/// ultimately triggers our stack dumper.
392static LLVM_ATTRIBUTE_UNUSED int
393AvoidMessageBoxHook(int ReportType, char *Message, int *Return) {
394  // Set *Return to the retry code for the return value of _CrtDbgReport:
395  // http://msdn.microsoft.com/en-us/library/8hyw4sy7(v=vs.71).aspx
396  // This may also trigger just-in-time debugging via DebugBreak().
397  if (Return)
398    *Return = 1;
399  // Don't call _CrtDbgReport.
400  return TRUE;
401}
402
403#endif
404
405extern "C" void HandleAbort(int Sig) {
406  if (Sig == SIGABRT) {
407    LLVM_BUILTIN_TRAP;
408  }
409}
410
411static void InitializeThreading() {
412  if (CriticalSectionInitialized)
413    return;
414
415  // Now's the time to create the critical section. This is the first time
416  // through here, and there's only one thread.
417  InitializeCriticalSection(&CriticalSection);
418  CriticalSectionInitialized = true;
419}
420
421static void RegisterHandler() {
422  // If we cannot load up the APIs (which would be unexpected as they should
423  // exist on every version of Windows we support), we will bail out since
424  // there would be nothing to report.
425  if (!load64BitDebugHelp()) {
426    assert(false && "These APIs should always be available");
427    return;
428  }
429
430  if (RegisteredUnhandledExceptionFilter) {
431    EnterCriticalSection(&CriticalSection);
432    return;
433  }
434
435  InitializeThreading();
436
437  // Enter it immediately.  Now if someone hits CTRL/C, the console handler
438  // can't proceed until the globals are updated.
439  EnterCriticalSection(&CriticalSection);
440
441  RegisteredUnhandledExceptionFilter = true;
442  OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter);
443  SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE);
444
445  // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or
446  // else multi-threading problems will ensue.
447}
448
449// RemoveFileOnSignal - The public API
450bool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) {
451  RegisterHandler();
452
453  if (CleanupExecuted) {
454    if (ErrMsg)
455      *ErrMsg = "Process terminating -- cannot register for removal";
456    return true;
457  }
458
459  if (FilesToRemove == NULL)
460    FilesToRemove = new std::vector<std::string>;
461
462  FilesToRemove->push_back(Filename);
463
464  LeaveCriticalSection(&CriticalSection);
465  return false;
466}
467
468// DontRemoveFileOnSignal - The public API
469void sys::DontRemoveFileOnSignal(StringRef Filename) {
470  if (FilesToRemove == NULL)
471    return;
472
473  RegisterHandler();
474
475  std::vector<std::string>::reverse_iterator I =
476      find(reverse(*FilesToRemove), Filename);
477  if (I != FilesToRemove->rend())
478    FilesToRemove->erase(I.base()-1);
479
480  LeaveCriticalSection(&CriticalSection);
481}
482
483void sys::DisableSystemDialogsOnCrash() {
484  // Crash to stack trace handler on abort.
485  signal(SIGABRT, HandleAbort);
486
487  // The following functions are not reliably accessible on MinGW.
488#ifdef _MSC_VER
489  // We're already handling writing a "something went wrong" message.
490  _set_abort_behavior(0, _WRITE_ABORT_MSG);
491  // Disable Dr. Watson.
492  _set_abort_behavior(0, _CALL_REPORTFAULT);
493  _CrtSetReportHook(AvoidMessageBoxHook);
494#endif
495
496  // Disable standard error dialog box.
497  SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
498               SEM_NOOPENFILEERRORBOX);
499  _set_error_mode(_OUT_TO_STDERR);
500}
501
502/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or
503/// SIGSEGV) is delivered to the process, print a stack trace and then exit.
504void sys::PrintStackTraceOnErrorSignal(StringRef Argv0,
505                                       bool DisableCrashReporting) {
506  ::Argv0 = Argv0;
507
508  if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT"))
509    Process::PreventCoreFiles();
510
511  DisableSystemDialogsOnCrash();
512  RegisterHandler();
513  LeaveCriticalSection(&CriticalSection);
514}
515}
516
517#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
518// Provide a prototype for RtlCaptureContext, mingw32 from mingw.org is
519// missing it but mingw-w64 has it.
520extern "C" VOID WINAPI RtlCaptureContext(PCONTEXT ContextRecord);
521#endif
522
523void llvm::sys::PrintStackTrace(raw_ostream &OS) {
524  STACKFRAME64 StackFrame = {};
525  CONTEXT Context = {};
526  ::RtlCaptureContext(&Context);
527#if defined(_M_X64)
528  StackFrame.AddrPC.Offset = Context.Rip;
529  StackFrame.AddrStack.Offset = Context.Rsp;
530  StackFrame.AddrFrame.Offset = Context.Rbp;
531#else
532  StackFrame.AddrPC.Offset = Context.Eip;
533  StackFrame.AddrStack.Offset = Context.Esp;
534  StackFrame.AddrFrame.Offset = Context.Ebp;
535#endif
536  StackFrame.AddrPC.Mode = AddrModeFlat;
537  StackFrame.AddrStack.Mode = AddrModeFlat;
538  StackFrame.AddrFrame.Mode = AddrModeFlat;
539  PrintStackTraceForThread(OS, GetCurrentProcess(), GetCurrentThread(),
540                           StackFrame, &Context);
541}
542
543
544void llvm::sys::SetInterruptFunction(void (*IF)()) {
545  RegisterHandler();
546  InterruptFunction = IF;
547  LeaveCriticalSection(&CriticalSection);
548}
549
550
551/// AddSignalHandler - Add a function to be called when a signal is delivered
552/// to the process.  The handler can have a cookie passed to it to identify
553/// what instance of the handler it is.
554void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) {
555  CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie));
556  RegisterHandler();
557  LeaveCriticalSection(&CriticalSection);
558}
559
560static void Cleanup() {
561  if (CleanupExecuted)
562    return;
563
564  EnterCriticalSection(&CriticalSection);
565
566  // Prevent other thread from registering new files and directories for
567  // removal, should we be executing because of the console handler callback.
568  CleanupExecuted = true;
569
570  // FIXME: open files cannot be deleted.
571  if (FilesToRemove != NULL)
572    while (!FilesToRemove->empty()) {
573      llvm::sys::fs::remove(FilesToRemove->back());
574      FilesToRemove->pop_back();
575    }
576  llvm::sys::RunSignalHandlers();
577  LeaveCriticalSection(&CriticalSection);
578}
579
580void llvm::sys::RunInterruptHandlers() {
581  // The interrupt handler may be called from an interrupt, but it may also be
582  // called manually (such as the case of report_fatal_error with no registered
583  // error handler). We must ensure that the critical section is properly
584  // initialized.
585  InitializeThreading();
586  Cleanup();
587}
588
589/// \brief Find the Windows Registry Key for a given location.
590///
591/// \returns a valid HKEY if the location exists, else NULL.
592static HKEY FindWERKey(const llvm::Twine &RegistryLocation) {
593  HKEY Key;
594  if (ERROR_SUCCESS != ::RegOpenKeyExA(HKEY_LOCAL_MACHINE,
595                                       RegistryLocation.str().c_str(), 0,
596                                       KEY_QUERY_VALUE | KEY_READ, &Key))
597    return NULL;
598
599  return Key;
600}
601
602/// \brief Populate ResultDirectory with the value for "DumpFolder" for a given
603/// Windows Registry key.
604///
605/// \returns true if a valid value for DumpFolder exists, false otherwise.
606static bool GetDumpFolder(HKEY Key,
607                          llvm::SmallVectorImpl<char> &ResultDirectory) {
608  using llvm::sys::windows::UTF16ToUTF8;
609
610  if (!Key)
611    return false;
612
613  DWORD BufferLengthBytes = 0;
614
615  if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ,
616                                      NULL, NULL, &BufferLengthBytes))
617    return false;
618
619  SmallVector<wchar_t, MAX_PATH> Buffer(BufferLengthBytes);
620
621  if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ,
622                                      NULL, Buffer.data(), &BufferLengthBytes))
623    return false;
624
625  DWORD ExpandBufferSize = ::ExpandEnvironmentStringsW(Buffer.data(), NULL, 0);
626
627  if (!ExpandBufferSize)
628    return false;
629
630  SmallVector<wchar_t, MAX_PATH> ExpandBuffer(ExpandBufferSize);
631
632  if (ExpandBufferSize != ::ExpandEnvironmentStringsW(Buffer.data(),
633                                                      ExpandBuffer.data(),
634                                                      ExpandBufferSize))
635    return false;
636
637  if (UTF16ToUTF8(ExpandBuffer.data(), ExpandBufferSize - 1, ResultDirectory))
638    return false;
639
640  return true;
641}
642
643/// \brief Populate ResultType with a valid MINIDUMP_TYPE based on the value of
644/// "DumpType" for a given Windows Registry key.
645///
646/// According to
647/// https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181(v=vs.85).aspx
648/// valid values for DumpType are:
649///   * 0: Custom dump
650///   * 1: Mini dump
651///   * 2: Full dump
652/// If "Custom dump" is specified then the "CustomDumpFlags" field is read
653/// containing a bitwise combination of MINIDUMP_TYPE values.
654///
655/// \returns true if a valid value for ResultType can be set, false otherwise.
656static bool GetDumpType(HKEY Key, MINIDUMP_TYPE &ResultType) {
657  if (!Key)
658    return false;
659
660  DWORD DumpType;
661  DWORD TypeSize = sizeof(DumpType);
662  if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"DumpType", RRF_RT_REG_DWORD,
663                                      NULL, &DumpType,
664                                      &TypeSize))
665    return false;
666
667  switch (DumpType) {
668  case 0: {
669    DWORD Flags = 0;
670    if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"CustomDumpFlags",
671                                        RRF_RT_REG_DWORD, NULL, &Flags,
672                                        &TypeSize))
673      return false;
674
675    ResultType = static_cast<MINIDUMP_TYPE>(Flags);
676    break;
677  }
678  case 1:
679    ResultType = MiniDumpNormal;
680    break;
681  case 2:
682    ResultType = MiniDumpWithFullMemory;
683    break;
684  default:
685    return false;
686  }
687  return true;
688}
689
690/// \brief Write a Windows dump file containing process information that can be
691/// used for post-mortem debugging.
692///
693/// \returns zero error code if a mini dump created, actual error code
694/// otherwise.
695static std::error_code WINAPI
696WriteWindowsDumpFile(PMINIDUMP_EXCEPTION_INFORMATION ExceptionInfo) {
697  using namespace llvm;
698  using namespace llvm::sys;
699
700  std::string MainExecutableName = fs::getMainExecutable(nullptr, nullptr);
701  StringRef ProgramName;
702
703  if (MainExecutableName.empty()) {
704    // If we can't get the executable filename,
705    // things are in worse shape than we realize
706    // and we should just bail out.
707    return mapWindowsError(::GetLastError());
708  }
709
710  ProgramName = path::filename(MainExecutableName.c_str());
711
712  // The Windows Registry location as specified at
713  // https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx
714  // "Collecting User-Mode Dumps" that may optionally be set to collect crash
715  // dumps in a specified location.
716  StringRef LocalDumpsRegistryLocation =
717      "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps";
718
719  // The key pointing to the Registry location that may contain global crash
720  // dump settings.  This will be NULL if the location can not be found.
721  ScopedRegHandle DefaultLocalDumpsKey(FindWERKey(LocalDumpsRegistryLocation));
722
723  // The key pointing to the Registry location that may contain
724  // application-specific crash dump settings.  This will be NULL if the
725  // location can not be found.
726  ScopedRegHandle AppSpecificKey(
727      FindWERKey(Twine(LocalDumpsRegistryLocation) + "\\" + ProgramName));
728
729  // Look to see if a dump type is specified in the registry; first with the
730  // app-specific key and failing that with the global key.  If none are found
731  // default to a normal dump (GetDumpType will return false either if the key
732  // is NULL or if there is no valid DumpType value at its location).
733  MINIDUMP_TYPE DumpType;
734  if (!GetDumpType(AppSpecificKey, DumpType))
735    if (!GetDumpType(DefaultLocalDumpsKey, DumpType))
736      DumpType = MiniDumpNormal;
737
738  // Look to see if a dump location is specified in the registry; first with the
739  // app-specific key and failing that with the global key.  If none are found
740  // we'll just create the dump file in the default temporary file location
741  // (GetDumpFolder will return false either if the key is NULL or if there is
742  // no valid DumpFolder value at its location).
743  bool ExplicitDumpDirectorySet = true;
744  SmallString<MAX_PATH> DumpDirectory;
745  if (!GetDumpFolder(AppSpecificKey, DumpDirectory))
746    if (!GetDumpFolder(DefaultLocalDumpsKey, DumpDirectory))
747      ExplicitDumpDirectorySet = false;
748
749  int FD;
750  SmallString<MAX_PATH> DumpPath;
751
752  if (ExplicitDumpDirectorySet) {
753    if (std::error_code EC = fs::create_directories(DumpDirectory))
754      return EC;
755    if (std::error_code EC = fs::createUniqueFile(
756            Twine(DumpDirectory) + "\\" + ProgramName + ".%%%%%%.dmp", FD,
757            DumpPath))
758      return EC;
759  } else if (std::error_code EC =
760                 fs::createTemporaryFile(ProgramName, "dmp", FD, DumpPath))
761    return EC;
762
763  // Our support functions return a file descriptor but Windows wants a handle.
764  ScopedCommonHandle FileHandle(reinterpret_cast<HANDLE>(_get_osfhandle(FD)));
765
766  if (!fMiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(),
767                          FileHandle, DumpType, ExceptionInfo, NULL, NULL))
768    return mapWindowsError(::GetLastError());
769
770  llvm::errs() << "Wrote crash dump file \"" << DumpPath << "\"\n";
771  return std::error_code();
772}
773
774static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {
775  Cleanup();
776
777  // We'll automatically write a Minidump file here to help diagnose
778  // the nasty sorts of crashes that aren't 100% reproducible from a set of
779  // inputs (or in the event that the user is unable or unwilling to provide a
780  // reproducible case).
781  if (!llvm::Process::AreCoreFilesPrevented()) {
782    MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo;
783    ExceptionInfo.ThreadId = ::GetCurrentThreadId();
784    ExceptionInfo.ExceptionPointers = ep;
785    ExceptionInfo.ClientPointers = FALSE;
786
787    if (std::error_code EC = WriteWindowsDumpFile(&ExceptionInfo))
788      llvm::errs() << "Could not write crash dump file: " << EC.message()
789                   << "\n";
790  }
791
792  // Initialize the STACKFRAME structure.
793  STACKFRAME64 StackFrame = {};
794
795#if defined(_M_X64)
796  StackFrame.AddrPC.Offset = ep->ContextRecord->Rip;
797  StackFrame.AddrPC.Mode = AddrModeFlat;
798  StackFrame.AddrStack.Offset = ep->ContextRecord->Rsp;
799  StackFrame.AddrStack.Mode = AddrModeFlat;
800  StackFrame.AddrFrame.Offset = ep->ContextRecord->Rbp;
801  StackFrame.AddrFrame.Mode = AddrModeFlat;
802#elif defined(_M_IX86)
803  StackFrame.AddrPC.Offset = ep->ContextRecord->Eip;
804  StackFrame.AddrPC.Mode = AddrModeFlat;
805  StackFrame.AddrStack.Offset = ep->ContextRecord->Esp;
806  StackFrame.AddrStack.Mode = AddrModeFlat;
807  StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp;
808  StackFrame.AddrFrame.Mode = AddrModeFlat;
809#endif
810
811  HANDLE hProcess = GetCurrentProcess();
812  HANDLE hThread = GetCurrentThread();
813  PrintStackTraceForThread(llvm::errs(), hProcess, hThread, StackFrame,
814                           ep->ContextRecord);
815
816  _exit(ep->ExceptionRecord->ExceptionCode);
817}
818
819static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) {
820  // We are running in our very own thread, courtesy of Windows.
821  EnterCriticalSection(&CriticalSection);
822  Cleanup();
823
824  // If an interrupt function has been set, go and run one it; otherwise,
825  // the process dies.
826  void (*IF)() = InterruptFunction;
827  InterruptFunction = 0;      // Don't run it on another CTRL-C.
828
829  if (IF) {
830    // Note: if the interrupt function throws an exception, there is nothing
831    // to catch it in this thread so it will kill the process.
832    IF();                     // Run it now.
833    LeaveCriticalSection(&CriticalSection);
834    return TRUE;              // Don't kill the process.
835  }
836
837  // Allow normal processing to take place; i.e., the process dies.
838  LeaveCriticalSection(&CriticalSection);
839  return FALSE;
840}
841
842#if __MINGW32__
843 // We turned these warnings off for this file so that MinGW-g++ doesn't
844 // complain about the ll format specifiers used.  Now we are turning the
845 // warnings back on.  If MinGW starts to support diagnostic stacks, we can
846 // replace this with a pop.
847 #pragma GCC diagnostic warning "-Wformat"
848 #pragma GCC diagnostic warning "-Wformat-extra-args"
849#endif
850