Signals.inc revision 226633
1218885Sdim//===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===//
2218885Sdim//
3218885Sdim//                     The LLVM Compiler Infrastructure
4218885Sdim//
5218885Sdim// This file is distributed under the University of Illinois Open Source
6218885Sdim// License. See LICENSE.TXT for details.
7218885Sdim//
8218885Sdim//===----------------------------------------------------------------------===//
9218885Sdim//
10218885Sdim// This file provides the Win32 specific implementation of the Signals class.
11218885Sdim//
12218885Sdim//===----------------------------------------------------------------------===//
13218885Sdim
14218885Sdim#include "Windows.h"
15218885Sdim#include <stdio.h>
16218885Sdim#include <vector>
17218885Sdim#include <algorithm>
18218885Sdim
19218885Sdim#ifdef __MINGW32__
20218885Sdim #include <imagehlp.h>
21218885Sdim#else
22218885Sdim #include <dbghelp.h>
23218885Sdim#endif
24218885Sdim#include <psapi.h>
25218885Sdim
26226633Sdim#ifdef _MSC_VER
27226633Sdim #pragma comment(lib, "psapi.lib")
28226633Sdim #pragma comment(lib, "dbghelp.lib")
29226633Sdim#elif __MINGW32__
30218885Sdim #if ((HAVE_LIBIMAGEHLP != 1) || (HAVE_LIBPSAPI != 1))
31218885Sdim  #error "libimagehlp.a & libpsapi.a should be present"
32218885Sdim #endif
33226633Sdim // The version of g++ that comes with MinGW does *not* properly understand
34226633Sdim // the ll format specifier for printf. However, MinGW passes the format
35226633Sdim // specifiers on to the MSVCRT entirely, and the CRT understands the ll
36226633Sdim // specifier. So these warnings are spurious in this case. Since we compile
37226633Sdim // with -Wall, this will generate these warnings which should be ignored. So
38226633Sdim // we will turn off the warnings for this just file. However, MinGW also does
39226633Sdim // not support push and pop for diagnostics, so we have to manually turn it
40226633Sdim // back on at the end of the file.
41226633Sdim #pragma GCC diagnostic ignored "-Wformat"
42226633Sdim #pragma GCC diagnostic ignored "-Wformat-extra-args"
43218885Sdim
44226633Sdim #if !defined(__MINGW64_VERSION_MAJOR)
45226633Sdim // MinGW.org does not have updated support for the 64-bit versions of the
46226633Sdim // DebugHlp APIs. So we will have to load them manually. The structures and
47226633Sdim // method signatures were pulled from DbgHelp.h in the Windows Platform SDK,
48226633Sdim // and adjusted for brevity.
49226633Sdim typedef struct _IMAGEHLP_LINE64 {
50226633Sdim   DWORD    SizeOfStruct;
51226633Sdim   PVOID    Key;
52226633Sdim   DWORD    LineNumber;
53226633Sdim   PCHAR    FileName;
54226633Sdim   DWORD64  Address;
55226633Sdim } IMAGEHLP_LINE64, *PIMAGEHLP_LINE64;
56226633Sdim
57226633Sdim typedef struct _IMAGEHLP_SYMBOL64 {
58226633Sdim   DWORD   SizeOfStruct;
59226633Sdim   DWORD64 Address;
60226633Sdim   DWORD   Size;
61226633Sdim   DWORD   Flags;
62226633Sdim   DWORD   MaxNameLength;
63226633Sdim   CHAR    Name[1];
64226633Sdim } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64;
65226633Sdim
66226633Sdim typedef struct _tagADDRESS64 {
67226633Sdim   DWORD64       Offset;
68226633Sdim   WORD          Segment;
69226633Sdim   ADDRESS_MODE  Mode;
70226633Sdim } ADDRESS64, *LPADDRESS64;
71226633Sdim
72226633Sdim typedef struct _KDHELP64 {
73226633Sdim   DWORD64   Thread;
74226633Sdim   DWORD   ThCallbackStack;
75226633Sdim   DWORD   ThCallbackBStore;
76226633Sdim   DWORD   NextCallback;
77226633Sdim   DWORD   FramePointer;
78226633Sdim   DWORD64   KiCallUserMode;
79226633Sdim   DWORD64   KeUserCallbackDispatcher;
80226633Sdim   DWORD64   SystemRangeStart;
81226633Sdim   DWORD64   KiUserExceptionDispatcher;
82226633Sdim   DWORD64   StackBase;
83226633Sdim   DWORD64   StackLimit;
84226633Sdim   DWORD64   Reserved[5];
85226633Sdim } KDHELP64, *PKDHELP64;
86226633Sdim
87226633Sdim typedef struct _tagSTACKFRAME64 {
88226633Sdim   ADDRESS64   AddrPC;
89226633Sdim   ADDRESS64   AddrReturn;
90226633Sdim   ADDRESS64   AddrFrame;
91226633Sdim   ADDRESS64   AddrStack;
92226633Sdim   ADDRESS64   AddrBStore;
93226633Sdim   PVOID       FuncTableEntry;
94226633Sdim   DWORD64     Params[4];
95226633Sdim   BOOL        Far;
96226633Sdim   BOOL        Virtual;
97226633Sdim   DWORD64     Reserved[3];
98226633Sdim   KDHELP64    KdHelp;
99226633Sdim } STACKFRAME64, *LPSTACKFRAME64;
100226633Sdim
101226633Sdimtypedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess,
102226633Sdim                      DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize,
103226633Sdim                      LPDWORD lpNumberOfBytesRead);
104226633Sdim
105226633Sdimtypedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( HANDLE ahProcess,
106226633Sdim                      DWORD64 AddrBase);
107226633Sdim
108226633Sdimtypedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess,
109226633Sdim                      DWORD64 Address);
110226633Sdim
111226633Sdimtypedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess,
112226633Sdim                      HANDLE hThread, LPADDRESS64 lpaddr);
113226633Sdim
114226633Sdimtypedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64,
115226633Sdim                      PVOID, PREAD_PROCESS_MEMORY_ROUTINE64,
116226633Sdim                      PFUNCTION_TABLE_ACCESS_ROUTINE64,
117226633Sdim                      PGET_MODULE_BASE_ROUTINE64,
118226633Sdim                      PTRANSLATE_ADDRESS_ROUTINE64);
119226633Sdimstatic fpStackWalk64 StackWalk64;
120226633Sdim
121226633Sdimtypedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64);
122226633Sdimstatic fpSymGetModuleBase64 SymGetModuleBase64;
123226633Sdim
124226633Sdimtypedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64,
125226633Sdim                      PDWORD64, PIMAGEHLP_SYMBOL64);
126226633Sdimstatic fpSymGetSymFromAddr64 SymGetSymFromAddr64;
127226633Sdim
128226633Sdimtypedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64,
129226633Sdim                      PDWORD, PIMAGEHLP_LINE64);
130226633Sdimstatic fpSymGetLineFromAddr64 SymGetLineFromAddr64;
131226633Sdim
132226633Sdimtypedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64);
133226633Sdimstatic fpSymFunctionTableAccess64 SymFunctionTableAccess64;
134226633Sdim
135226633Sdimstatic bool load64BitDebugHelp(void) {
136226633Sdim  HMODULE hLib = ::LoadLibrary("Dbghelp.dll");
137226633Sdim  if (hLib) {
138226633Sdim    StackWalk64 = (fpStackWalk64)
139226633Sdim                      ::GetProcAddress(hLib, "StackWalk64");
140226633Sdim    SymGetModuleBase64 = (fpSymGetModuleBase64)
141226633Sdim                      ::GetProcAddress(hLib, "SymGetModuleBase64");
142226633Sdim    SymGetSymFromAddr64 = (fpSymGetSymFromAddr64)
143226633Sdim                      ::GetProcAddress(hLib, "SymGetSymFromAddr64");
144226633Sdim    SymGetLineFromAddr64 = (fpSymGetLineFromAddr64)
145226633Sdim                      ::GetProcAddress(hLib, "SymGetLineFromAddr64");
146226633Sdim    SymFunctionTableAccess64 = (fpSymFunctionTableAccess64)
147226633Sdim                     ::GetProcAddress(hLib, "SymFunctionTableAccess64");
148226633Sdim  }
149226633Sdim  return StackWalk64 != NULL;
150226633Sdim}
151226633Sdim #endif // !defined(__MINGW64_VERSION_MAJOR)
152226633Sdim#endif // __MINGW32__
153226633Sdim
154218885Sdim// Forward declare.
155218885Sdimstatic LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep);
156218885Sdimstatic BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType);
157218885Sdim
158218885Sdim// InterruptFunction - The function to call if ctrl-c is pressed.
159218885Sdimstatic void (*InterruptFunction)() = 0;
160218885Sdim
161218885Sdimstatic std::vector<llvm::sys::Path> *FilesToRemove = NULL;
162218885Sdimstatic std::vector<std::pair<void(*)(void*), void*> > *CallBacksToRun = 0;
163218885Sdimstatic bool RegisteredUnhandledExceptionFilter = false;
164218885Sdimstatic bool CleanupExecuted = false;
165218885Sdimstatic bool ExitOnUnhandledExceptions = false;
166218885Sdimstatic PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL;
167218885Sdim
168218885Sdim// Windows creates a new thread to execute the console handler when an event
169218885Sdim// (such as CTRL/C) occurs.  This causes concurrency issues with the above
170218885Sdim// globals which this critical section addresses.
171218885Sdimstatic CRITICAL_SECTION CriticalSection;
172218885Sdim
173218885Sdimnamespace llvm {
174218885Sdim
175218885Sdim//===----------------------------------------------------------------------===//
176218885Sdim//=== WARNING: Implementation here must contain only Win32 specific code
177218885Sdim//===          and must not be UNIX code
178218885Sdim//===----------------------------------------------------------------------===//
179218885Sdim
180218885Sdim#ifdef _MSC_VER
181218885Sdim/// CRTReportHook - Function called on a CRT debugging event.
182218885Sdimstatic int CRTReportHook(int ReportType, char *Message, int *Return) {
183218885Sdim  // Don't cause a DebugBreak() on return.
184218885Sdim  if (Return)
185218885Sdim    *Return = 0;
186218885Sdim
187218885Sdim  switch (ReportType) {
188218885Sdim  default:
189218885Sdim  case _CRT_ASSERT:
190218885Sdim    fprintf(stderr, "CRT assert: %s\n", Message);
191218885Sdim    // FIXME: Is there a way to just crash? Perhaps throw to the unhandled
192218885Sdim    // exception code? Perhaps SetErrorMode() handles this.
193218885Sdim    _exit(3);
194218885Sdim    break;
195218885Sdim  case _CRT_ERROR:
196218885Sdim    fprintf(stderr, "CRT error: %s\n", Message);
197218885Sdim    // FIXME: Is there a way to just crash? Perhaps throw to the unhandled
198218885Sdim    // exception code? Perhaps SetErrorMode() handles this.
199218885Sdim    _exit(3);
200218885Sdim    break;
201218885Sdim  case _CRT_WARN:
202218885Sdim    fprintf(stderr, "CRT warn: %s\n", Message);
203218885Sdim    break;
204218885Sdim  }
205218885Sdim
206218885Sdim  // Don't call _CrtDbgReport.
207218885Sdim  return TRUE;
208218885Sdim}
209218885Sdim#endif
210218885Sdim
211218885Sdimstatic void RegisterHandler() {
212226633Sdim#if __MINGW32__ && !defined(__MINGW64_VERSION_MAJOR)
213226633Sdim  // On MinGW.org, we need to load up the symbols explicitly, because the
214226633Sdim  // Win32 framework they include does not have support for the 64-bit
215226633Sdim  // versions of the APIs we need.  If we cannot load up the APIs (which
216226633Sdim  // would be unexpected as they should exist on every version of Windows
217226633Sdim  // we support), we will bail out since there would be nothing to report.
218226633Sdim  if (!load64BitDebugHelp()) {
219226633Sdim    assert(false && "These APIs should always be available");
220226633Sdim    return;
221226633Sdim  }
222226633Sdim#endif
223226633Sdim
224218885Sdim  if (RegisteredUnhandledExceptionFilter) {
225218885Sdim    EnterCriticalSection(&CriticalSection);
226218885Sdim    return;
227218885Sdim  }
228218885Sdim
229218885Sdim  // Now's the time to create the critical section.  This is the first time
230218885Sdim  // through here, and there's only one thread.
231218885Sdim  InitializeCriticalSection(&CriticalSection);
232218885Sdim
233218885Sdim  // Enter it immediately.  Now if someone hits CTRL/C, the console handler
234218885Sdim  // can't proceed until the globals are updated.
235218885Sdim  EnterCriticalSection(&CriticalSection);
236218885Sdim
237218885Sdim  RegisteredUnhandledExceptionFilter = true;
238218885Sdim  OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter);
239218885Sdim  SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE);
240218885Sdim
241218885Sdim  // Environment variable to disable any kind of crash dialog.
242218885Sdim  if (getenv("LLVM_DISABLE_CRT_DEBUG")) {
243218885Sdim#ifdef _MSC_VER
244218885Sdim    _CrtSetReportHook(CRTReportHook);
245218885Sdim#endif
246218885Sdim    SetErrorMode(SEM_FAILCRITICALERRORS |
247218885Sdim                 SEM_NOGPFAULTERRORBOX |
248218885Sdim                 SEM_NOOPENFILEERRORBOX);
249218885Sdim    ExitOnUnhandledExceptions = true;
250218885Sdim  }
251218885Sdim
252218885Sdim  // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or
253218885Sdim  // else multi-threading problems will ensue.
254218885Sdim}
255218885Sdim
256218885Sdim// RemoveFileOnSignal - The public API
257218885Sdimbool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) {
258218885Sdim  RegisterHandler();
259218885Sdim
260218885Sdim  if (CleanupExecuted) {
261218885Sdim    if (ErrMsg)
262218885Sdim      *ErrMsg = "Process terminating -- cannot register for removal";
263218885Sdim    return true;
264218885Sdim  }
265218885Sdim
266218885Sdim  if (FilesToRemove == NULL)
267218885Sdim    FilesToRemove = new std::vector<sys::Path>;
268218885Sdim
269218885Sdim  FilesToRemove->push_back(Filename);
270218885Sdim
271218885Sdim  LeaveCriticalSection(&CriticalSection);
272218885Sdim  return false;
273218885Sdim}
274218885Sdim
275218885Sdim// DontRemoveFileOnSignal - The public API
276218885Sdimvoid sys::DontRemoveFileOnSignal(const sys::Path &Filename) {
277218885Sdim  if (FilesToRemove == NULL)
278218885Sdim    return;
279218885Sdim
280218885Sdim  RegisterHandler();
281218885Sdim
282218885Sdim  FilesToRemove->push_back(Filename);
283218885Sdim  std::vector<sys::Path>::reverse_iterator I =
284218885Sdim  std::find(FilesToRemove->rbegin(), FilesToRemove->rend(), Filename);
285218885Sdim  if (I != FilesToRemove->rend())
286218885Sdim    FilesToRemove->erase(I.base()-1);
287218885Sdim
288218885Sdim  LeaveCriticalSection(&CriticalSection);
289218885Sdim}
290218885Sdim
291218885Sdim/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or
292218885Sdim/// SIGSEGV) is delivered to the process, print a stack trace and then exit.
293218885Sdimvoid sys::PrintStackTraceOnErrorSignal() {
294218885Sdim  RegisterHandler();
295218885Sdim  LeaveCriticalSection(&CriticalSection);
296218885Sdim}
297218885Sdim
298218885Sdim
299218885Sdimvoid sys::SetInterruptFunction(void (*IF)()) {
300218885Sdim  RegisterHandler();
301218885Sdim  InterruptFunction = IF;
302218885Sdim  LeaveCriticalSection(&CriticalSection);
303218885Sdim}
304218885Sdim
305218885Sdim
306218885Sdim/// AddSignalHandler - Add a function to be called when a signal is delivered
307218885Sdim/// to the process.  The handler can have a cookie passed to it to identify
308218885Sdim/// what instance of the handler it is.
309218885Sdimvoid sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) {
310218885Sdim  if (CallBacksToRun == 0)
311218885Sdim    CallBacksToRun = new std::vector<std::pair<void(*)(void*), void*> >();
312218885Sdim  CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie));
313218885Sdim  RegisterHandler();
314218885Sdim  LeaveCriticalSection(&CriticalSection);
315218885Sdim}
316218885Sdim}
317218885Sdim
318218885Sdimstatic void Cleanup() {
319218885Sdim  EnterCriticalSection(&CriticalSection);
320218885Sdim
321218885Sdim  // Prevent other thread from registering new files and directories for
322218885Sdim  // removal, should we be executing because of the console handler callback.
323218885Sdim  CleanupExecuted = true;
324218885Sdim
325218885Sdim  // FIXME: open files cannot be deleted.
326218885Sdim
327218885Sdim  if (FilesToRemove != NULL)
328218885Sdim    while (!FilesToRemove->empty()) {
329218885Sdim      FilesToRemove->back().eraseFromDisk();
330218885Sdim      FilesToRemove->pop_back();
331218885Sdim    }
332218885Sdim
333218885Sdim  if (CallBacksToRun)
334218885Sdim    for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i)
335218885Sdim      (*CallBacksToRun)[i].first((*CallBacksToRun)[i].second);
336218885Sdim
337218885Sdim  LeaveCriticalSection(&CriticalSection);
338218885Sdim}
339218885Sdim
340218885Sdimvoid llvm::sys::RunInterruptHandlers() {
341218885Sdim  Cleanup();
342218885Sdim}
343218885Sdim
344218885Sdimstatic LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {
345218885Sdim  Cleanup();
346218885Sdim
347218885Sdim  // Initialize the STACKFRAME structure.
348226633Sdim  STACKFRAME64 StackFrame;
349218885Sdim  memset(&StackFrame, 0, sizeof(StackFrame));
350218885Sdim
351226633Sdim  DWORD machineType;
352226633Sdim#if defined(_M_X64)
353226633Sdim  machineType = IMAGE_FILE_MACHINE_AMD64;
354226633Sdim  StackFrame.AddrPC.Offset = ep->ContextRecord->Rip;
355226633Sdim  StackFrame.AddrPC.Mode = AddrModeFlat;
356226633Sdim  StackFrame.AddrStack.Offset = ep->ContextRecord->Rsp;
357226633Sdim  StackFrame.AddrStack.Mode = AddrModeFlat;
358226633Sdim  StackFrame.AddrFrame.Offset = ep->ContextRecord->Rbp;
359226633Sdim  StackFrame.AddrFrame.Mode = AddrModeFlat;
360226633Sdim#elif defined(_M_IX86)
361226633Sdim  machineType = IMAGE_FILE_MACHINE_I386;
362218885Sdim  StackFrame.AddrPC.Offset = ep->ContextRecord->Eip;
363218885Sdim  StackFrame.AddrPC.Mode = AddrModeFlat;
364218885Sdim  StackFrame.AddrStack.Offset = ep->ContextRecord->Esp;
365218885Sdim  StackFrame.AddrStack.Mode = AddrModeFlat;
366218885Sdim  StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp;
367218885Sdim  StackFrame.AddrFrame.Mode = AddrModeFlat;
368226633Sdim#endif
369218885Sdim
370218885Sdim  HANDLE hProcess = GetCurrentProcess();
371218885Sdim  HANDLE hThread = GetCurrentThread();
372218885Sdim
373218885Sdim  // Initialize the symbol handler.
374218885Sdim  SymSetOptions(SYMOPT_DEFERRED_LOADS|SYMOPT_LOAD_LINES);
375218885Sdim  SymInitialize(hProcess, NULL, TRUE);
376218885Sdim
377218885Sdim  while (true) {
378226633Sdim    if (!StackWalk64(machineType, hProcess, hThread, &StackFrame,
379226633Sdim                   ep->ContextRecord, NULL, SymFunctionTableAccess64,
380226633Sdim                   SymGetModuleBase64, NULL)) {
381218885Sdim      break;
382218885Sdim    }
383218885Sdim
384218885Sdim    if (StackFrame.AddrFrame.Offset == 0)
385218885Sdim      break;
386218885Sdim
387218885Sdim    // Print the PC in hexadecimal.
388226633Sdim    DWORD64 PC = StackFrame.AddrPC.Offset;
389226633Sdim#if defined(_M_X64)
390226633Sdim    fprintf(stderr, "0x%016llX", PC);
391226633Sdim#elif defined(_M_IX86)
392226633Sdim    fprintf(stderr, "0x%08lX", static_cast<DWORD>(PC));
393226633Sdim#endif
394218885Sdim
395218885Sdim    // Print the parameters.  Assume there are four.
396226633Sdim#if defined(_M_X64)
397226633Sdim    fprintf(stderr, " (0x%016llX 0x%016llX 0x%016llX 0x%016llX)",
398226633Sdim                StackFrame.Params[0],
399226633Sdim                StackFrame.Params[1],
400226633Sdim                StackFrame.Params[2],
401226633Sdim                StackFrame.Params[3]);
402226633Sdim#elif defined(_M_IX86)
403218885Sdim    fprintf(stderr, " (0x%08lX 0x%08lX 0x%08lX 0x%08lX)",
404226633Sdim                static_cast<DWORD>(StackFrame.Params[0]),
405226633Sdim                static_cast<DWORD>(StackFrame.Params[1]),
406226633Sdim                static_cast<DWORD>(StackFrame.Params[2]),
407226633Sdim                static_cast<DWORD>(StackFrame.Params[3]));
408226633Sdim#endif
409218885Sdim    // Verify the PC belongs to a module in this process.
410226633Sdim    if (!SymGetModuleBase64(hProcess, PC)) {
411218885Sdim      fputs(" <unknown module>\n", stderr);
412218885Sdim      continue;
413218885Sdim    }
414218885Sdim
415218885Sdim    // Print the symbol name.
416218885Sdim    char buffer[512];
417226633Sdim    IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer);
418226633Sdim    memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64));
419226633Sdim    symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
420226633Sdim    symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64);
421218885Sdim
422226633Sdim    DWORD64 dwDisp;
423226633Sdim    if (!SymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) {
424218885Sdim      fputc('\n', stderr);
425218885Sdim      continue;
426218885Sdim    }
427218885Sdim
428218885Sdim    buffer[511] = 0;
429218885Sdim    if (dwDisp > 0)
430226633Sdim      fprintf(stderr, ", %s() + 0x%llX bytes(s)", symbol->Name, dwDisp);
431218885Sdim    else
432218885Sdim      fprintf(stderr, ", %s", symbol->Name);
433218885Sdim
434218885Sdim    // Print the source file and line number information.
435226633Sdim    IMAGEHLP_LINE64 line;
436226633Sdim    DWORD dwLineDisp;
437218885Sdim    memset(&line, 0, sizeof(line));
438218885Sdim    line.SizeOfStruct = sizeof(line);
439226633Sdim    if (SymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) {
440218885Sdim      fprintf(stderr, ", %s, line %lu", line.FileName, line.LineNumber);
441226633Sdim      if (dwLineDisp > 0)
442226633Sdim        fprintf(stderr, " + 0x%lX byte(s)", dwLineDisp);
443218885Sdim    }
444218885Sdim
445218885Sdim    fputc('\n', stderr);
446218885Sdim  }
447218885Sdim
448218885Sdim  if (ExitOnUnhandledExceptions)
449218885Sdim    _exit(-3);
450218885Sdim
451218885Sdim  // Allow dialog box to pop up allowing choice to start debugger.
452218885Sdim  if (OldFilter)
453218885Sdim    return (*OldFilter)(ep);
454218885Sdim  else
455218885Sdim    return EXCEPTION_CONTINUE_SEARCH;
456218885Sdim}
457218885Sdim
458218885Sdimstatic BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) {
459218885Sdim  // We are running in our very own thread, courtesy of Windows.
460218885Sdim  EnterCriticalSection(&CriticalSection);
461218885Sdim  Cleanup();
462218885Sdim
463218885Sdim  // If an interrupt function has been set, go and run one it; otherwise,
464218885Sdim  // the process dies.
465218885Sdim  void (*IF)() = InterruptFunction;
466218885Sdim  InterruptFunction = 0;      // Don't run it on another CTRL-C.
467218885Sdim
468218885Sdim  if (IF) {
469218885Sdim    // Note: if the interrupt function throws an exception, there is nothing
470218885Sdim    // to catch it in this thread so it will kill the process.
471218885Sdim    IF();                     // Run it now.
472218885Sdim    LeaveCriticalSection(&CriticalSection);
473218885Sdim    return TRUE;              // Don't kill the process.
474218885Sdim  }
475218885Sdim
476218885Sdim  // Allow normal processing to take place; i.e., the process dies.
477218885Sdim  LeaveCriticalSection(&CriticalSection);
478218885Sdim  return FALSE;
479218885Sdim}
480226633Sdim
481226633Sdim#if __MINGW32__
482226633Sdim // We turned these warnings off for this file so that MinGW-g++ doesn't
483226633Sdim // complain about the ll format specifiers used.  Now we are turning the
484226633Sdim // warnings back on.  If MinGW starts to support diagnostic stacks, we can
485226633Sdim // replace this with a pop.
486226633Sdim #pragma GCC diagnostic warning "-Wformat"
487226633Sdim #pragma GCC diagnostic warning "-Wformat-extra-args"
488226633Sdim#endif
489