Signals.inc revision 353358
1218885Sdim//===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===//
2218885Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6218885Sdim//
7218885Sdim//===----------------------------------------------------------------------===//
8218885Sdim//
9218885Sdim// This file provides the Win32 specific implementation of the Signals class.
10218885Sdim//
11218885Sdim//===----------------------------------------------------------------------===//
12341825Sdim#include "llvm/Support/ConvertUTF.h"
13261991Sdim#include "llvm/Support/FileSystem.h"
14309124Sdim#include "llvm/Support/Path.h"
15309124Sdim#include "llvm/Support/Process.h"
16309124Sdim#include "llvm/Support/WindowsError.h"
17249423Sdim#include <algorithm>
18309124Sdim#include <io.h>
19288943Sdim#include <signal.h>
20218885Sdim#include <stdio.h>
21218885Sdim
22288943Sdim#include "llvm/Support/Format.h"
23288943Sdim#include "llvm/Support/raw_ostream.h"
24288943Sdim
25276479Sdim// The Windows.h header must be after LLVM and standard headers.
26276479Sdim#include "WindowsSupport.h"
27276479Sdim
28218885Sdim#ifdef __MINGW32__
29218885Sdim #include <imagehlp.h>
30218885Sdim#else
31314564Sdim #include <crtdbg.h>
32218885Sdim #include <dbghelp.h>
33218885Sdim#endif
34218885Sdim#include <psapi.h>
35218885Sdim
36226633Sdim#ifdef _MSC_VER
37226633Sdim #pragma comment(lib, "psapi.lib")
38226633Sdim#elif __MINGW32__
39226633Sdim // The version of g++ that comes with MinGW does *not* properly understand
40226633Sdim // the ll format specifier for printf. However, MinGW passes the format
41226633Sdim // specifiers on to the MSVCRT entirely, and the CRT understands the ll
42226633Sdim // specifier. So these warnings are spurious in this case. Since we compile
43226633Sdim // with -Wall, this will generate these warnings which should be ignored. So
44226633Sdim // we will turn off the warnings for this just file. However, MinGW also does
45226633Sdim // not support push and pop for diagnostics, so we have to manually turn it
46226633Sdim // back on at the end of the file.
47226633Sdim #pragma GCC diagnostic ignored "-Wformat"
48226633Sdim #pragma GCC diagnostic ignored "-Wformat-extra-args"
49218885Sdim
50226633Sdim #if !defined(__MINGW64_VERSION_MAJOR)
51226633Sdim // MinGW.org does not have updated support for the 64-bit versions of the
52226633Sdim // DebugHlp APIs. So we will have to load them manually. The structures and
53226633Sdim // method signatures were pulled from DbgHelp.h in the Windows Platform SDK,
54226633Sdim // and adjusted for brevity.
55226633Sdim typedef struct _IMAGEHLP_LINE64 {
56226633Sdim   DWORD    SizeOfStruct;
57226633Sdim   PVOID    Key;
58226633Sdim   DWORD    LineNumber;
59226633Sdim   PCHAR    FileName;
60226633Sdim   DWORD64  Address;
61226633Sdim } IMAGEHLP_LINE64, *PIMAGEHLP_LINE64;
62226633Sdim
63226633Sdim typedef struct _IMAGEHLP_SYMBOL64 {
64226633Sdim   DWORD   SizeOfStruct;
65226633Sdim   DWORD64 Address;
66226633Sdim   DWORD   Size;
67226633Sdim   DWORD   Flags;
68226633Sdim   DWORD   MaxNameLength;
69226633Sdim   CHAR    Name[1];
70226633Sdim } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64;
71226633Sdim
72226633Sdim typedef struct _tagADDRESS64 {
73226633Sdim   DWORD64       Offset;
74226633Sdim   WORD          Segment;
75226633Sdim   ADDRESS_MODE  Mode;
76226633Sdim } ADDRESS64, *LPADDRESS64;
77226633Sdim
78226633Sdim typedef struct _KDHELP64 {
79226633Sdim   DWORD64   Thread;
80226633Sdim   DWORD   ThCallbackStack;
81226633Sdim   DWORD   ThCallbackBStore;
82226633Sdim   DWORD   NextCallback;
83226633Sdim   DWORD   FramePointer;
84226633Sdim   DWORD64   KiCallUserMode;
85226633Sdim   DWORD64   KeUserCallbackDispatcher;
86226633Sdim   DWORD64   SystemRangeStart;
87226633Sdim   DWORD64   KiUserExceptionDispatcher;
88226633Sdim   DWORD64   StackBase;
89226633Sdim   DWORD64   StackLimit;
90226633Sdim   DWORD64   Reserved[5];
91226633Sdim } KDHELP64, *PKDHELP64;
92226633Sdim
93226633Sdim typedef struct _tagSTACKFRAME64 {
94226633Sdim   ADDRESS64   AddrPC;
95226633Sdim   ADDRESS64   AddrReturn;
96226633Sdim   ADDRESS64   AddrFrame;
97226633Sdim   ADDRESS64   AddrStack;
98226633Sdim   ADDRESS64   AddrBStore;
99226633Sdim   PVOID       FuncTableEntry;
100226633Sdim   DWORD64     Params[4];
101226633Sdim   BOOL        Far;
102226633Sdim   BOOL        Virtual;
103226633Sdim   DWORD64     Reserved[3];
104226633Sdim   KDHELP64    KdHelp;
105226633Sdim } STACKFRAME64, *LPSTACKFRAME64;
106288943Sdim #endif // !defined(__MINGW64_VERSION_MAJOR)
107288943Sdim#endif // __MINGW32__
108226633Sdim
109226633Sdimtypedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess,
110226633Sdim                      DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize,
111226633Sdim                      LPDWORD lpNumberOfBytesRead);
112226633Sdim
113226633Sdimtypedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( HANDLE ahProcess,
114226633Sdim                      DWORD64 AddrBase);
115226633Sdim
116226633Sdimtypedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess,
117226633Sdim                      DWORD64 Address);
118226633Sdim
119226633Sdimtypedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess,
120226633Sdim                      HANDLE hThread, LPADDRESS64 lpaddr);
121226633Sdim
122309124Sdimtypedef BOOL(WINAPI *fpMiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,
123309124Sdim                                          PMINIDUMP_EXCEPTION_INFORMATION,
124309124Sdim                                          PMINIDUMP_USER_STREAM_INFORMATION,
125309124Sdim                                          PMINIDUMP_CALLBACK_INFORMATION);
126309124Sdimstatic fpMiniDumpWriteDump fMiniDumpWriteDump;
127309124Sdim
128226633Sdimtypedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64,
129226633Sdim                      PVOID, PREAD_PROCESS_MEMORY_ROUTINE64,
130226633Sdim                      PFUNCTION_TABLE_ACCESS_ROUTINE64,
131226633Sdim                      PGET_MODULE_BASE_ROUTINE64,
132226633Sdim                      PTRANSLATE_ADDRESS_ROUTINE64);
133288943Sdimstatic fpStackWalk64 fStackWalk64;
134226633Sdim
135226633Sdimtypedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64);
136288943Sdimstatic fpSymGetModuleBase64 fSymGetModuleBase64;
137226633Sdim
138226633Sdimtypedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64,
139226633Sdim                      PDWORD64, PIMAGEHLP_SYMBOL64);
140288943Sdimstatic fpSymGetSymFromAddr64 fSymGetSymFromAddr64;
141226633Sdim
142226633Sdimtypedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64,
143226633Sdim                      PDWORD, PIMAGEHLP_LINE64);
144288943Sdimstatic fpSymGetLineFromAddr64 fSymGetLineFromAddr64;
145226633Sdim
146296417Sdimtypedef BOOL(WINAPI *fpSymGetModuleInfo64)(HANDLE hProcess, DWORD64 dwAddr,
147296417Sdim                                           PIMAGEHLP_MODULE64 ModuleInfo);
148296417Sdimstatic fpSymGetModuleInfo64 fSymGetModuleInfo64;
149296417Sdim
150226633Sdimtypedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64);
151288943Sdimstatic fpSymFunctionTableAccess64 fSymFunctionTableAccess64;
152226633Sdim
153288943Sdimtypedef DWORD (WINAPI *fpSymSetOptions)(DWORD);
154288943Sdimstatic fpSymSetOptions fSymSetOptions;
155288943Sdim
156288943Sdimtypedef BOOL (WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL);
157288943Sdimstatic fpSymInitialize fSymInitialize;
158288943Sdim
159296417Sdimtypedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID);
160296417Sdimstatic fpEnumerateLoadedModules fEnumerateLoadedModules;
161296417Sdim
162226633Sdimstatic bool load64BitDebugHelp(void) {
163261991Sdim  HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll");
164226633Sdim  if (hLib) {
165309124Sdim    fMiniDumpWriteDump = (fpMiniDumpWriteDump)
166309124Sdim                      ::GetProcAddress(hLib, "MiniDumpWriteDump");
167288943Sdim    fStackWalk64 = (fpStackWalk64)
168226633Sdim                      ::GetProcAddress(hLib, "StackWalk64");
169288943Sdim    fSymGetModuleBase64 = (fpSymGetModuleBase64)
170226633Sdim                      ::GetProcAddress(hLib, "SymGetModuleBase64");
171288943Sdim    fSymGetSymFromAddr64 = (fpSymGetSymFromAddr64)
172226633Sdim                      ::GetProcAddress(hLib, "SymGetSymFromAddr64");
173288943Sdim    fSymGetLineFromAddr64 = (fpSymGetLineFromAddr64)
174226633Sdim                      ::GetProcAddress(hLib, "SymGetLineFromAddr64");
175296417Sdim    fSymGetModuleInfo64 = (fpSymGetModuleInfo64)
176296417Sdim                      ::GetProcAddress(hLib, "SymGetModuleInfo64");
177288943Sdim    fSymFunctionTableAccess64 = (fpSymFunctionTableAccess64)
178226633Sdim                     ::GetProcAddress(hLib, "SymFunctionTableAccess64");
179288943Sdim    fSymSetOptions = (fpSymSetOptions)::GetProcAddress(hLib, "SymSetOptions");
180288943Sdim    fSymInitialize = (fpSymInitialize)::GetProcAddress(hLib, "SymInitialize");
181296417Sdim    fEnumerateLoadedModules = (fpEnumerateLoadedModules)
182296417Sdim      ::GetProcAddress(hLib, "EnumerateLoadedModules64");
183226633Sdim  }
184309124Sdim  return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump;
185226633Sdim}
186226633Sdim
187296417Sdimusing namespace llvm;
188296417Sdim
189218885Sdim// Forward declare.
190218885Sdimstatic LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep);
191218885Sdimstatic BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType);
192218885Sdim
193341825Sdim// The function to call if ctrl-c is pressed.
194218885Sdimstatic void (*InterruptFunction)() = 0;
195218885Sdim
196261991Sdimstatic std::vector<std::string> *FilesToRemove = NULL;
197218885Sdimstatic bool RegisteredUnhandledExceptionFilter = false;
198218885Sdimstatic bool CleanupExecuted = false;
199218885Sdimstatic PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL;
200218885Sdim
201218885Sdim// Windows creates a new thread to execute the console handler when an event
202218885Sdim// (such as CTRL/C) occurs.  This causes concurrency issues with the above
203218885Sdim// globals which this critical section addresses.
204218885Sdimstatic CRITICAL_SECTION CriticalSection;
205288943Sdimstatic bool CriticalSectionInitialized = false;
206218885Sdim
207309124Sdimstatic StringRef Argv0;
208309124Sdim
209296417Sdimenum {
210288943Sdim#if defined(_M_X64)
211296417Sdim  NativeMachineType = IMAGE_FILE_MACHINE_AMD64
212327952Sdim#elif defined(_M_ARM64)
213327952Sdim  NativeMachineType = IMAGE_FILE_MACHINE_ARM64
214327952Sdim#elif defined(_M_IX86)
215327952Sdim  NativeMachineType = IMAGE_FILE_MACHINE_I386
216327952Sdim#elif defined(_M_ARM)
217327952Sdim  NativeMachineType = IMAGE_FILE_MACHINE_ARMNT
218288943Sdim#else
219327952Sdim  NativeMachineType = IMAGE_FILE_MACHINE_UNKNOWN
220288943Sdim#endif
221296417Sdim};
222288943Sdim
223296417Sdimstatic bool printStackTraceWithLLVMSymbolizer(llvm::raw_ostream &OS,
224296417Sdim                                              HANDLE hProcess, HANDLE hThread,
225296417Sdim                                              STACKFRAME64 &StackFrameOrig,
226296417Sdim                                              CONTEXT *ContextOrig) {
227296417Sdim  // StackWalk64 modifies the incoming stack frame and context, so copy them.
228296417Sdim  STACKFRAME64 StackFrame = StackFrameOrig;
229296417Sdim
230296417Sdim  // Copy the register context so that we don't modify it while we unwind. We
231296417Sdim  // could use InitializeContext + CopyContext, but that's only required to get
232296417Sdim  // at AVX registers, which typically aren't needed by StackWalk64. Reduce the
233296417Sdim  // flag set to indicate that there's less data.
234296417Sdim  CONTEXT Context = *ContextOrig;
235296417Sdim  Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
236296417Sdim
237296417Sdim  static void *StackTrace[256];
238296417Sdim  size_t Depth = 0;
239296417Sdim  while (fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame,
240296417Sdim                      &Context, 0, fSymFunctionTableAccess64,
241296417Sdim                      fSymGetModuleBase64, 0)) {
242296417Sdim    if (StackFrame.AddrFrame.Offset == 0)
243296417Sdim      break;
244296417Sdim    StackTrace[Depth++] = (void *)(uintptr_t)StackFrame.AddrPC.Offset;
245296417Sdim    if (Depth >= array_lengthof(StackTrace))
246296417Sdim      break;
247296417Sdim  }
248296417Sdim
249309124Sdim  return printSymbolizedStackTrace(Argv0, &StackTrace[0], Depth, OS);
250296417Sdim}
251296417Sdim
252296417Sdimnamespace {
253296417Sdimstruct FindModuleData {
254296417Sdim  void **StackTrace;
255296417Sdim  int Depth;
256296417Sdim  const char **Modules;
257296417Sdim  intptr_t *Offsets;
258296417Sdim  StringSaver *StrPool;
259296417Sdim};
260296417Sdim}
261296417Sdim
262309124Sdimstatic BOOL CALLBACK findModuleCallback(PCSTR ModuleName,
263296417Sdim                                        DWORD64 ModuleBase, ULONG ModuleSize,
264296417Sdim                                        void *VoidData) {
265296417Sdim  FindModuleData *Data = (FindModuleData*)VoidData;
266296417Sdim  intptr_t Beg = ModuleBase;
267296417Sdim  intptr_t End = Beg + ModuleSize;
268296417Sdim  for (int I = 0; I < Data->Depth; I++) {
269296417Sdim    if (Data->Modules[I])
270296417Sdim      continue;
271296417Sdim    intptr_t Addr = (intptr_t)Data->StackTrace[I];
272296417Sdim    if (Beg <= Addr && Addr < End) {
273314564Sdim      Data->Modules[I] = Data->StrPool->save(ModuleName).data();
274296417Sdim      Data->Offsets[I] = Addr - Beg;
275296417Sdim    }
276296417Sdim  }
277296417Sdim  return TRUE;
278296417Sdim}
279296417Sdim
280296417Sdimstatic bool findModulesAndOffsets(void **StackTrace, int Depth,
281296417Sdim                                  const char **Modules, intptr_t *Offsets,
282296417Sdim                                  const char *MainExecutableName,
283296417Sdim                                  StringSaver &StrPool) {
284296417Sdim  if (!fEnumerateLoadedModules)
285296417Sdim    return false;
286296417Sdim  FindModuleData Data;
287296417Sdim  Data.StackTrace = StackTrace;
288296417Sdim  Data.Depth = Depth;
289296417Sdim  Data.Modules = Modules;
290296417Sdim  Data.Offsets = Offsets;
291296417Sdim  Data.StrPool = &StrPool;
292296417Sdim  fEnumerateLoadedModules(GetCurrentProcess(), findModuleCallback, &Data);
293296417Sdim  return true;
294296417Sdim}
295296417Sdim
296296417Sdimstatic void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess,
297296417Sdim                                     HANDLE hThread, STACKFRAME64 &StackFrame,
298296417Sdim                                     CONTEXT *Context) {
299288943Sdim  // Initialize the symbol handler.
300288943Sdim  fSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
301288943Sdim  fSymInitialize(hProcess, NULL, TRUE);
302288943Sdim
303296417Sdim  // Try llvm-symbolizer first. llvm-symbolizer knows how to deal with both PDBs
304296417Sdim  // and DWARF, so it should do a good job regardless of what debug info or
305296417Sdim  // linker is in use.
306296417Sdim  if (printStackTraceWithLLVMSymbolizer(OS, hProcess, hThread, StackFrame,
307296417Sdim                                        Context)) {
308296417Sdim    return;
309296417Sdim  }
310296417Sdim
311288943Sdim  while (true) {
312296417Sdim    if (!fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame,
313296417Sdim                      Context, 0, fSymFunctionTableAccess64,
314296417Sdim                      fSymGetModuleBase64, 0)) {
315288943Sdim      break;
316288943Sdim    }
317288943Sdim
318288943Sdim    if (StackFrame.AddrFrame.Offset == 0)
319288943Sdim      break;
320288943Sdim
321288943Sdim    using namespace llvm;
322288943Sdim    // Print the PC in hexadecimal.
323288943Sdim    DWORD64 PC = StackFrame.AddrPC.Offset;
324327952Sdim#if defined(_M_X64) || defined(_M_ARM64)
325288943Sdim    OS << format("0x%016llX", PC);
326327952Sdim#elif defined(_M_IX86) || defined(_M_ARM)
327288943Sdim    OS << format("0x%08lX", static_cast<DWORD>(PC));
328288943Sdim#endif
329288943Sdim
330288943Sdim// Print the parameters.  Assume there are four.
331327952Sdim#if defined(_M_X64) || defined(_M_ARM64)
332288943Sdim    OS << format(" (0x%016llX 0x%016llX 0x%016llX 0x%016llX)",
333288943Sdim            StackFrame.Params[0], StackFrame.Params[1], StackFrame.Params[2],
334288943Sdim            StackFrame.Params[3]);
335327952Sdim#elif defined(_M_IX86) || defined(_M_ARM)
336288943Sdim    OS << format(" (0x%08lX 0x%08lX 0x%08lX 0x%08lX)",
337288943Sdim            static_cast<DWORD>(StackFrame.Params[0]),
338288943Sdim            static_cast<DWORD>(StackFrame.Params[1]),
339288943Sdim            static_cast<DWORD>(StackFrame.Params[2]),
340288943Sdim            static_cast<DWORD>(StackFrame.Params[3]));
341288943Sdim#endif
342288943Sdim    // Verify the PC belongs to a module in this process.
343288943Sdim    if (!fSymGetModuleBase64(hProcess, PC)) {
344288943Sdim      OS << " <unknown module>\n";
345288943Sdim      continue;
346288943Sdim    }
347288943Sdim
348288943Sdim    // Print the symbol name.
349288943Sdim    char buffer[512];
350288943Sdim    IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer);
351288943Sdim    memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64));
352288943Sdim    symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
353288943Sdim    symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64);
354288943Sdim
355288943Sdim    DWORD64 dwDisp;
356288943Sdim    if (!fSymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) {
357288943Sdim      OS << '\n';
358288943Sdim      continue;
359288943Sdim    }
360288943Sdim
361288943Sdim    buffer[511] = 0;
362288943Sdim    if (dwDisp > 0)
363288943Sdim      OS << format(", %s() + 0x%llX bytes(s)", (const char*)symbol->Name,
364288943Sdim                   dwDisp);
365288943Sdim    else
366288943Sdim      OS << format(", %s", (const char*)symbol->Name);
367288943Sdim
368288943Sdim    // Print the source file and line number information.
369288943Sdim    IMAGEHLP_LINE64 line = {};
370288943Sdim    DWORD dwLineDisp;
371288943Sdim    line.SizeOfStruct = sizeof(line);
372288943Sdim    if (fSymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) {
373288943Sdim      OS << format(", %s, line %lu", line.FileName, line.LineNumber);
374288943Sdim      if (dwLineDisp > 0)
375288943Sdim        OS << format(" + 0x%lX byte(s)", dwLineDisp);
376288943Sdim    }
377288943Sdim
378288943Sdim    OS << '\n';
379288943Sdim  }
380288943Sdim}
381288943Sdim
382218885Sdimnamespace llvm {
383218885Sdim
384218885Sdim//===----------------------------------------------------------------------===//
385218885Sdim//=== WARNING: Implementation here must contain only Win32 specific code
386218885Sdim//===          and must not be UNIX code
387218885Sdim//===----------------------------------------------------------------------===//
388218885Sdim
389218885Sdim#ifdef _MSC_VER
390341825Sdim/// Emulates hitting "retry" from an "abort, retry, ignore" CRT debug report
391341825Sdim/// dialog. "retry" raises an exception which ultimately triggers our stack
392341825Sdim/// dumper.
393288943Sdimstatic LLVM_ATTRIBUTE_UNUSED int
394288943SdimAvoidMessageBoxHook(int ReportType, char *Message, int *Return) {
395251662Sdim  // Set *Return to the retry code for the return value of _CrtDbgReport:
396251662Sdim  // http://msdn.microsoft.com/en-us/library/8hyw4sy7(v=vs.71).aspx
397251662Sdim  // This may also trigger just-in-time debugging via DebugBreak().
398251662Sdim  if (Return)
399251662Sdim    *Return = 1;
400251662Sdim  // Don't call _CrtDbgReport.
401251662Sdim  return TRUE;
402251662Sdim}
403251662Sdim
404218885Sdim#endif
405218885Sdim
406288943Sdimextern "C" void HandleAbort(int Sig) {
407288943Sdim  if (Sig == SIGABRT) {
408288943Sdim    LLVM_BUILTIN_TRAP;
409288943Sdim  }
410288943Sdim}
411288943Sdim
412288943Sdimstatic void InitializeThreading() {
413288943Sdim  if (CriticalSectionInitialized)
414288943Sdim    return;
415288943Sdim
416288943Sdim  // Now's the time to create the critical section. This is the first time
417288943Sdim  // through here, and there's only one thread.
418288943Sdim  InitializeCriticalSection(&CriticalSection);
419288943Sdim  CriticalSectionInitialized = true;
420288943Sdim}
421288943Sdim
422218885Sdimstatic void RegisterHandler() {
423288943Sdim  // If we cannot load up the APIs (which would be unexpected as they should
424288943Sdim  // exist on every version of Windows we support), we will bail out since
425288943Sdim  // there would be nothing to report.
426226633Sdim  if (!load64BitDebugHelp()) {
427226633Sdim    assert(false && "These APIs should always be available");
428226633Sdim    return;
429226633Sdim  }
430226633Sdim
431218885Sdim  if (RegisteredUnhandledExceptionFilter) {
432218885Sdim    EnterCriticalSection(&CriticalSection);
433218885Sdim    return;
434218885Sdim  }
435218885Sdim
436288943Sdim  InitializeThreading();
437218885Sdim
438218885Sdim  // Enter it immediately.  Now if someone hits CTRL/C, the console handler
439218885Sdim  // can't proceed until the globals are updated.
440218885Sdim  EnterCriticalSection(&CriticalSection);
441218885Sdim
442218885Sdim  RegisteredUnhandledExceptionFilter = true;
443218885Sdim  OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter);
444218885Sdim  SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE);
445218885Sdim
446218885Sdim  // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or
447218885Sdim  // else multi-threading problems will ensue.
448218885Sdim}
449218885Sdim
450341825Sdim// The public API
451261991Sdimbool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) {
452218885Sdim  RegisterHandler();
453218885Sdim
454218885Sdim  if (CleanupExecuted) {
455218885Sdim    if (ErrMsg)
456218885Sdim      *ErrMsg = "Process terminating -- cannot register for removal";
457218885Sdim    return true;
458218885Sdim  }
459218885Sdim
460218885Sdim  if (FilesToRemove == NULL)
461261991Sdim    FilesToRemove = new std::vector<std::string>;
462218885Sdim
463218885Sdim  FilesToRemove->push_back(Filename);
464218885Sdim
465218885Sdim  LeaveCriticalSection(&CriticalSection);
466218885Sdim  return false;
467218885Sdim}
468218885Sdim
469341825Sdim// The public API
470261991Sdimvoid sys::DontRemoveFileOnSignal(StringRef Filename) {
471218885Sdim  if (FilesToRemove == NULL)
472218885Sdim    return;
473218885Sdim
474218885Sdim  RegisterHandler();
475218885Sdim
476261991Sdim  std::vector<std::string>::reverse_iterator I =
477314564Sdim      find(reverse(*FilesToRemove), Filename);
478218885Sdim  if (I != FilesToRemove->rend())
479218885Sdim    FilesToRemove->erase(I.base()-1);
480218885Sdim
481218885Sdim  LeaveCriticalSection(&CriticalSection);
482218885Sdim}
483218885Sdim
484288943Sdimvoid sys::DisableSystemDialogsOnCrash() {
485288943Sdim  // Crash to stack trace handler on abort.
486288943Sdim  signal(SIGABRT, HandleAbort);
487288943Sdim
488288943Sdim  // The following functions are not reliably accessible on MinGW.
489288943Sdim#ifdef _MSC_VER
490288943Sdim  // We're already handling writing a "something went wrong" message.
491288943Sdim  _set_abort_behavior(0, _WRITE_ABORT_MSG);
492288943Sdim  // Disable Dr. Watson.
493288943Sdim  _set_abort_behavior(0, _CALL_REPORTFAULT);
494288943Sdim  _CrtSetReportHook(AvoidMessageBoxHook);
495288943Sdim#endif
496288943Sdim
497288943Sdim  // Disable standard error dialog box.
498288943Sdim  SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
499288943Sdim               SEM_NOOPENFILEERRORBOX);
500288943Sdim  _set_error_mode(_OUT_TO_STDERR);
501288943Sdim}
502288943Sdim
503341825Sdim/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
504341825Sdim/// process, print a stack trace and then exit.
505309124Sdimvoid sys::PrintStackTraceOnErrorSignal(StringRef Argv0,
506309124Sdim                                       bool DisableCrashReporting) {
507309124Sdim  ::Argv0 = Argv0;
508309124Sdim
509309124Sdim  if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT"))
510309124Sdim    Process::PreventCoreFiles();
511309124Sdim
512288943Sdim  DisableSystemDialogsOnCrash();
513218885Sdim  RegisterHandler();
514218885Sdim  LeaveCriticalSection(&CriticalSection);
515218885Sdim}
516288943Sdim}
517218885Sdim
518288943Sdim#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
519288943Sdim// Provide a prototype for RtlCaptureContext, mingw32 from mingw.org is
520288943Sdim// missing it but mingw-w64 has it.
521288943Sdimextern "C" VOID WINAPI RtlCaptureContext(PCONTEXT ContextRecord);
522288943Sdim#endif
523288943Sdim
524288943Sdimvoid llvm::sys::PrintStackTrace(raw_ostream &OS) {
525288943Sdim  STACKFRAME64 StackFrame = {};
526288943Sdim  CONTEXT Context = {};
527288943Sdim  ::RtlCaptureContext(&Context);
528288943Sdim#if defined(_M_X64)
529288943Sdim  StackFrame.AddrPC.Offset = Context.Rip;
530288943Sdim  StackFrame.AddrStack.Offset = Context.Rsp;
531288943Sdim  StackFrame.AddrFrame.Offset = Context.Rbp;
532327952Sdim#elif defined(_M_IX86)
533288943Sdim  StackFrame.AddrPC.Offset = Context.Eip;
534288943Sdim  StackFrame.AddrStack.Offset = Context.Esp;
535288943Sdim  StackFrame.AddrFrame.Offset = Context.Ebp;
536341825Sdim#elif defined(_M_ARM64)
537327952Sdim  StackFrame.AddrPC.Offset = Context.Pc;
538327952Sdim  StackFrame.AddrStack.Offset = Context.Sp;
539327952Sdim  StackFrame.AddrFrame.Offset = Context.Fp;
540341825Sdim#elif defined(_M_ARM)
541341825Sdim  StackFrame.AddrPC.Offset = Context.Pc;
542341825Sdim  StackFrame.AddrStack.Offset = Context.Sp;
543341825Sdim  StackFrame.AddrFrame.Offset = Context.R11;
544288943Sdim#endif
545288943Sdim  StackFrame.AddrPC.Mode = AddrModeFlat;
546288943Sdim  StackFrame.AddrStack.Mode = AddrModeFlat;
547288943Sdim  StackFrame.AddrFrame.Mode = AddrModeFlat;
548288943Sdim  PrintStackTraceForThread(OS, GetCurrentProcess(), GetCurrentThread(),
549288943Sdim                           StackFrame, &Context);
550249423Sdim}
551218885Sdim
552249423Sdim
553288943Sdimvoid llvm::sys::SetInterruptFunction(void (*IF)()) {
554218885Sdim  RegisterHandler();
555218885Sdim  InterruptFunction = IF;
556218885Sdim  LeaveCriticalSection(&CriticalSection);
557218885Sdim}
558218885Sdim
559353358Sdimvoid llvm::sys::SetInfoSignalFunction(void (*Handler)()) {
560353358Sdim  // Unimplemented.
561353358Sdim}
562218885Sdim
563353358Sdim
564341825Sdim/// Add a function to be called when a signal is delivered to the process. The
565341825Sdim/// handler can have a cookie passed to it to identify what instance of the
566341825Sdim/// handler it is.
567341825Sdimvoid llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr,
568341825Sdim                                 void *Cookie) {
569341825Sdim  insertSignalHandler(FnPtr, Cookie);
570218885Sdim  RegisterHandler();
571218885Sdim  LeaveCriticalSection(&CriticalSection);
572218885Sdim}
573218885Sdim
574218885Sdimstatic void Cleanup() {
575288943Sdim  if (CleanupExecuted)
576288943Sdim    return;
577288943Sdim
578218885Sdim  EnterCriticalSection(&CriticalSection);
579218885Sdim
580218885Sdim  // Prevent other thread from registering new files and directories for
581218885Sdim  // removal, should we be executing because of the console handler callback.
582218885Sdim  CleanupExecuted = true;
583218885Sdim
584218885Sdim  // FIXME: open files cannot be deleted.
585218885Sdim  if (FilesToRemove != NULL)
586218885Sdim    while (!FilesToRemove->empty()) {
587276479Sdim      llvm::sys::fs::remove(FilesToRemove->back());
588218885Sdim      FilesToRemove->pop_back();
589218885Sdim    }
590296417Sdim  llvm::sys::RunSignalHandlers();
591218885Sdim  LeaveCriticalSection(&CriticalSection);
592218885Sdim}
593218885Sdim
594218885Sdimvoid llvm::sys::RunInterruptHandlers() {
595288943Sdim  // The interrupt handler may be called from an interrupt, but it may also be
596288943Sdim  // called manually (such as the case of report_fatal_error with no registered
597288943Sdim  // error handler). We must ensure that the critical section is properly
598288943Sdim  // initialized.
599288943Sdim  InitializeThreading();
600218885Sdim  Cleanup();
601218885Sdim}
602218885Sdim
603341825Sdim/// Find the Windows Registry Key for a given location.
604309124Sdim///
605309124Sdim/// \returns a valid HKEY if the location exists, else NULL.
606309124Sdimstatic HKEY FindWERKey(const llvm::Twine &RegistryLocation) {
607309124Sdim  HKEY Key;
608309124Sdim  if (ERROR_SUCCESS != ::RegOpenKeyExA(HKEY_LOCAL_MACHINE,
609309124Sdim                                       RegistryLocation.str().c_str(), 0,
610309124Sdim                                       KEY_QUERY_VALUE | KEY_READ, &Key))
611309124Sdim    return NULL;
612309124Sdim
613309124Sdim  return Key;
614309124Sdim}
615309124Sdim
616341825Sdim/// Populate ResultDirectory with the value for "DumpFolder" for a given
617309124Sdim/// Windows Registry key.
618309124Sdim///
619309124Sdim/// \returns true if a valid value for DumpFolder exists, false otherwise.
620309124Sdimstatic bool GetDumpFolder(HKEY Key,
621309124Sdim                          llvm::SmallVectorImpl<char> &ResultDirectory) {
622309124Sdim  using llvm::sys::windows::UTF16ToUTF8;
623309124Sdim
624309124Sdim  if (!Key)
625309124Sdim    return false;
626309124Sdim
627309124Sdim  DWORD BufferLengthBytes = 0;
628309124Sdim
629309124Sdim  if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ,
630309124Sdim                                      NULL, NULL, &BufferLengthBytes))
631309124Sdim    return false;
632309124Sdim
633309124Sdim  SmallVector<wchar_t, MAX_PATH> Buffer(BufferLengthBytes);
634309124Sdim
635309124Sdim  if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ,
636309124Sdim                                      NULL, Buffer.data(), &BufferLengthBytes))
637309124Sdim    return false;
638309124Sdim
639309124Sdim  DWORD ExpandBufferSize = ::ExpandEnvironmentStringsW(Buffer.data(), NULL, 0);
640309124Sdim
641309124Sdim  if (!ExpandBufferSize)
642309124Sdim    return false;
643309124Sdim
644309124Sdim  SmallVector<wchar_t, MAX_PATH> ExpandBuffer(ExpandBufferSize);
645309124Sdim
646309124Sdim  if (ExpandBufferSize != ::ExpandEnvironmentStringsW(Buffer.data(),
647309124Sdim                                                      ExpandBuffer.data(),
648309124Sdim                                                      ExpandBufferSize))
649309124Sdim    return false;
650309124Sdim
651309124Sdim  if (UTF16ToUTF8(ExpandBuffer.data(), ExpandBufferSize - 1, ResultDirectory))
652309124Sdim    return false;
653309124Sdim
654309124Sdim  return true;
655309124Sdim}
656309124Sdim
657341825Sdim/// Populate ResultType with a valid MINIDUMP_TYPE based on the value of
658309124Sdim/// "DumpType" for a given Windows Registry key.
659309124Sdim///
660309124Sdim/// According to
661309124Sdim/// https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181(v=vs.85).aspx
662309124Sdim/// valid values for DumpType are:
663309124Sdim///   * 0: Custom dump
664309124Sdim///   * 1: Mini dump
665309124Sdim///   * 2: Full dump
666309124Sdim/// If "Custom dump" is specified then the "CustomDumpFlags" field is read
667309124Sdim/// containing a bitwise combination of MINIDUMP_TYPE values.
668309124Sdim///
669309124Sdim/// \returns true if a valid value for ResultType can be set, false otherwise.
670309124Sdimstatic bool GetDumpType(HKEY Key, MINIDUMP_TYPE &ResultType) {
671309124Sdim  if (!Key)
672309124Sdim    return false;
673309124Sdim
674309124Sdim  DWORD DumpType;
675309124Sdim  DWORD TypeSize = sizeof(DumpType);
676309124Sdim  if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"DumpType", RRF_RT_REG_DWORD,
677309124Sdim                                      NULL, &DumpType,
678309124Sdim                                      &TypeSize))
679309124Sdim    return false;
680309124Sdim
681309124Sdim  switch (DumpType) {
682309124Sdim  case 0: {
683309124Sdim    DWORD Flags = 0;
684309124Sdim    if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"CustomDumpFlags",
685309124Sdim                                        RRF_RT_REG_DWORD, NULL, &Flags,
686309124Sdim                                        &TypeSize))
687309124Sdim      return false;
688309124Sdim
689309124Sdim    ResultType = static_cast<MINIDUMP_TYPE>(Flags);
690309124Sdim    break;
691309124Sdim  }
692309124Sdim  case 1:
693309124Sdim    ResultType = MiniDumpNormal;
694309124Sdim    break;
695309124Sdim  case 2:
696309124Sdim    ResultType = MiniDumpWithFullMemory;
697309124Sdim    break;
698309124Sdim  default:
699309124Sdim    return false;
700309124Sdim  }
701309124Sdim  return true;
702309124Sdim}
703309124Sdim
704341825Sdim/// Write a Windows dump file containing process information that can be
705309124Sdim/// used for post-mortem debugging.
706309124Sdim///
707309124Sdim/// \returns zero error code if a mini dump created, actual error code
708309124Sdim/// otherwise.
709309124Sdimstatic std::error_code WINAPI
710309124SdimWriteWindowsDumpFile(PMINIDUMP_EXCEPTION_INFORMATION ExceptionInfo) {
711309124Sdim  using namespace llvm;
712309124Sdim  using namespace llvm::sys;
713309124Sdim
714309124Sdim  std::string MainExecutableName = fs::getMainExecutable(nullptr, nullptr);
715309124Sdim  StringRef ProgramName;
716309124Sdim
717309124Sdim  if (MainExecutableName.empty()) {
718309124Sdim    // If we can't get the executable filename,
719309124Sdim    // things are in worse shape than we realize
720309124Sdim    // and we should just bail out.
721309124Sdim    return mapWindowsError(::GetLastError());
722309124Sdim  }
723309124Sdim
724309124Sdim  ProgramName = path::filename(MainExecutableName.c_str());
725309124Sdim
726309124Sdim  // The Windows Registry location as specified at
727309124Sdim  // https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx
728309124Sdim  // "Collecting User-Mode Dumps" that may optionally be set to collect crash
729309124Sdim  // dumps in a specified location.
730309124Sdim  StringRef LocalDumpsRegistryLocation =
731309124Sdim      "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps";
732309124Sdim
733309124Sdim  // The key pointing to the Registry location that may contain global crash
734309124Sdim  // dump settings.  This will be NULL if the location can not be found.
735309124Sdim  ScopedRegHandle DefaultLocalDumpsKey(FindWERKey(LocalDumpsRegistryLocation));
736309124Sdim
737309124Sdim  // The key pointing to the Registry location that may contain
738309124Sdim  // application-specific crash dump settings.  This will be NULL if the
739309124Sdim  // location can not be found.
740309124Sdim  ScopedRegHandle AppSpecificKey(
741309124Sdim      FindWERKey(Twine(LocalDumpsRegistryLocation) + "\\" + ProgramName));
742309124Sdim
743309124Sdim  // Look to see if a dump type is specified in the registry; first with the
744309124Sdim  // app-specific key and failing that with the global key.  If none are found
745309124Sdim  // default to a normal dump (GetDumpType will return false either if the key
746309124Sdim  // is NULL or if there is no valid DumpType value at its location).
747309124Sdim  MINIDUMP_TYPE DumpType;
748309124Sdim  if (!GetDumpType(AppSpecificKey, DumpType))
749309124Sdim    if (!GetDumpType(DefaultLocalDumpsKey, DumpType))
750309124Sdim      DumpType = MiniDumpNormal;
751309124Sdim
752309124Sdim  // Look to see if a dump location is specified in the registry; first with the
753309124Sdim  // app-specific key and failing that with the global key.  If none are found
754309124Sdim  // we'll just create the dump file in the default temporary file location
755309124Sdim  // (GetDumpFolder will return false either if the key is NULL or if there is
756309124Sdim  // no valid DumpFolder value at its location).
757309124Sdim  bool ExplicitDumpDirectorySet = true;
758309124Sdim  SmallString<MAX_PATH> DumpDirectory;
759309124Sdim  if (!GetDumpFolder(AppSpecificKey, DumpDirectory))
760309124Sdim    if (!GetDumpFolder(DefaultLocalDumpsKey, DumpDirectory))
761309124Sdim      ExplicitDumpDirectorySet = false;
762309124Sdim
763309124Sdim  int FD;
764309124Sdim  SmallString<MAX_PATH> DumpPath;
765309124Sdim
766309124Sdim  if (ExplicitDumpDirectorySet) {
767309124Sdim    if (std::error_code EC = fs::create_directories(DumpDirectory))
768309124Sdim      return EC;
769309124Sdim    if (std::error_code EC = fs::createUniqueFile(
770309124Sdim            Twine(DumpDirectory) + "\\" + ProgramName + ".%%%%%%.dmp", FD,
771309124Sdim            DumpPath))
772309124Sdim      return EC;
773309124Sdim  } else if (std::error_code EC =
774309124Sdim                 fs::createTemporaryFile(ProgramName, "dmp", FD, DumpPath))
775309124Sdim    return EC;
776309124Sdim
777309124Sdim  // Our support functions return a file descriptor but Windows wants a handle.
778309124Sdim  ScopedCommonHandle FileHandle(reinterpret_cast<HANDLE>(_get_osfhandle(FD)));
779309124Sdim
780309124Sdim  if (!fMiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(),
781309124Sdim                          FileHandle, DumpType, ExceptionInfo, NULL, NULL))
782309124Sdim    return mapWindowsError(::GetLastError());
783309124Sdim
784309124Sdim  llvm::errs() << "Wrote crash dump file \"" << DumpPath << "\"\n";
785309124Sdim  return std::error_code();
786309124Sdim}
787309124Sdim
788218885Sdimstatic LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {
789218885Sdim  Cleanup();
790218885Sdim
791309124Sdim  // We'll automatically write a Minidump file here to help diagnose
792309124Sdim  // the nasty sorts of crashes that aren't 100% reproducible from a set of
793309124Sdim  // inputs (or in the event that the user is unable or unwilling to provide a
794309124Sdim  // reproducible case).
795321369Sdim  if (!llvm::sys::Process::AreCoreFilesPrevented()) {
796309124Sdim    MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo;
797309124Sdim    ExceptionInfo.ThreadId = ::GetCurrentThreadId();
798309124Sdim    ExceptionInfo.ExceptionPointers = ep;
799309124Sdim    ExceptionInfo.ClientPointers = FALSE;
800309124Sdim
801309124Sdim    if (std::error_code EC = WriteWindowsDumpFile(&ExceptionInfo))
802309124Sdim      llvm::errs() << "Could not write crash dump file: " << EC.message()
803309124Sdim                   << "\n";
804309124Sdim  }
805309124Sdim
806218885Sdim  // Initialize the STACKFRAME structure.
807288943Sdim  STACKFRAME64 StackFrame = {};
808218885Sdim
809226633Sdim#if defined(_M_X64)
810226633Sdim  StackFrame.AddrPC.Offset = ep->ContextRecord->Rip;
811226633Sdim  StackFrame.AddrPC.Mode = AddrModeFlat;
812226633Sdim  StackFrame.AddrStack.Offset = ep->ContextRecord->Rsp;
813226633Sdim  StackFrame.AddrStack.Mode = AddrModeFlat;
814226633Sdim  StackFrame.AddrFrame.Offset = ep->ContextRecord->Rbp;
815226633Sdim  StackFrame.AddrFrame.Mode = AddrModeFlat;
816226633Sdim#elif defined(_M_IX86)
817218885Sdim  StackFrame.AddrPC.Offset = ep->ContextRecord->Eip;
818218885Sdim  StackFrame.AddrPC.Mode = AddrModeFlat;
819218885Sdim  StackFrame.AddrStack.Offset = ep->ContextRecord->Esp;
820218885Sdim  StackFrame.AddrStack.Mode = AddrModeFlat;
821218885Sdim  StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp;
822218885Sdim  StackFrame.AddrFrame.Mode = AddrModeFlat;
823327952Sdim#elif defined(_M_ARM64) || defined(_M_ARM)
824327952Sdim  StackFrame.AddrPC.Offset = ep->ContextRecord->Pc;
825327952Sdim  StackFrame.AddrPC.Mode = AddrModeFlat;
826327952Sdim  StackFrame.AddrStack.Offset = ep->ContextRecord->Sp;
827327952Sdim  StackFrame.AddrStack.Mode = AddrModeFlat;
828341825Sdim#if defined(_M_ARM64)
829327952Sdim  StackFrame.AddrFrame.Offset = ep->ContextRecord->Fp;
830341825Sdim#else
831341825Sdim  StackFrame.AddrFrame.Offset = ep->ContextRecord->R11;
832341825Sdim#endif
833327952Sdim  StackFrame.AddrFrame.Mode = AddrModeFlat;
834226633Sdim#endif
835218885Sdim
836218885Sdim  HANDLE hProcess = GetCurrentProcess();
837218885Sdim  HANDLE hThread = GetCurrentThread();
838288943Sdim  PrintStackTraceForThread(llvm::errs(), hProcess, hThread, StackFrame,
839288943Sdim                           ep->ContextRecord);
840218885Sdim
841288943Sdim  _exit(ep->ExceptionRecord->ExceptionCode);
842218885Sdim}
843218885Sdim
844218885Sdimstatic BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) {
845218885Sdim  // We are running in our very own thread, courtesy of Windows.
846218885Sdim  EnterCriticalSection(&CriticalSection);
847218885Sdim  Cleanup();
848218885Sdim
849218885Sdim  // If an interrupt function has been set, go and run one it; otherwise,
850218885Sdim  // the process dies.
851218885Sdim  void (*IF)() = InterruptFunction;
852218885Sdim  InterruptFunction = 0;      // Don't run it on another CTRL-C.
853218885Sdim
854218885Sdim  if (IF) {
855218885Sdim    // Note: if the interrupt function throws an exception, there is nothing
856218885Sdim    // to catch it in this thread so it will kill the process.
857218885Sdim    IF();                     // Run it now.
858218885Sdim    LeaveCriticalSection(&CriticalSection);
859218885Sdim    return TRUE;              // Don't kill the process.
860218885Sdim  }
861218885Sdim
862218885Sdim  // Allow normal processing to take place; i.e., the process dies.
863218885Sdim  LeaveCriticalSection(&CriticalSection);
864218885Sdim  return FALSE;
865218885Sdim}
866226633Sdim
867226633Sdim#if __MINGW32__
868226633Sdim // We turned these warnings off for this file so that MinGW-g++ doesn't
869226633Sdim // complain about the ll format specifiers used.  Now we are turning the
870226633Sdim // warnings back on.  If MinGW starts to support diagnostic stacks, we can
871226633Sdim // replace this with a pop.
872226633Sdim #pragma GCC diagnostic warning "-Wformat"
873226633Sdim #pragma GCC diagnostic warning "-Wformat-extra-args"
874226633Sdim#endif
875