John Bauman | 19bac1e | 2014-05-06 15:23:49 -0400 | [diff] [blame] | 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 |
|
| 14 | #include "Windows.h"
|
| 15 | #include <stdio.h>
|
| 16 | #include <vector>
|
| 17 | #include <algorithm>
|
| 18 |
|
| 19 | #ifdef __MINGW32__
|
| 20 | #include <imagehlp.h>
|
| 21 | #else
|
| 22 | #include <dbghelp.h>
|
| 23 | #endif
|
| 24 | #include <psapi.h>
|
| 25 |
|
| 26 | #ifdef _MSC_VER
|
| 27 | #pragma comment(lib, "psapi.lib")
|
| 28 | #pragma comment(lib, "dbghelp.lib")
|
| 29 | #elif __MINGW32__
|
| 30 | #if ((HAVE_LIBIMAGEHLP != 1) || (HAVE_LIBPSAPI != 1))
|
| 31 | #error "libimagehlp.a & libpsapi.a should be present"
|
| 32 | #endif
|
| 33 | // The version of g++ that comes with MinGW does *not* properly understand
|
| 34 | // the ll format specifier for printf. However, MinGW passes the format
|
| 35 | // specifiers on to the MSVCRT entirely, and the CRT understands the ll
|
| 36 | // specifier. So these warnings are spurious in this case. Since we compile
|
| 37 | // with -Wall, this will generate these warnings which should be ignored. So
|
| 38 | // we will turn off the warnings for this just file. However, MinGW also does
|
| 39 | // not support push and pop for diagnostics, so we have to manually turn it
|
| 40 | // back on at the end of the file.
|
| 41 | #pragma GCC diagnostic ignored "-Wformat"
|
| 42 | #pragma GCC diagnostic ignored "-Wformat-extra-args"
|
| 43 |
|
| 44 | #if !defined(__MINGW64_VERSION_MAJOR)
|
| 45 | // MinGW.org does not have updated support for the 64-bit versions of the
|
| 46 | // DebugHlp APIs. So we will have to load them manually. The structures and
|
| 47 | // method signatures were pulled from DbgHelp.h in the Windows Platform SDK,
|
| 48 | // and adjusted for brevity.
|
| 49 | typedef struct _IMAGEHLP_LINE64 {
|
| 50 | DWORD SizeOfStruct;
|
| 51 | PVOID Key;
|
| 52 | DWORD LineNumber;
|
| 53 | PCHAR FileName;
|
| 54 | DWORD64 Address;
|
| 55 | } IMAGEHLP_LINE64, *PIMAGEHLP_LINE64;
|
| 56 |
|
| 57 | typedef struct _IMAGEHLP_SYMBOL64 {
|
| 58 | DWORD SizeOfStruct;
|
| 59 | DWORD64 Address;
|
| 60 | DWORD Size;
|
| 61 | DWORD Flags;
|
| 62 | DWORD MaxNameLength;
|
| 63 | CHAR Name[1];
|
| 64 | } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64;
|
| 65 |
|
| 66 | typedef struct _tagADDRESS64 {
|
| 67 | DWORD64 Offset;
|
| 68 | WORD Segment;
|
| 69 | ADDRESS_MODE Mode;
|
| 70 | } ADDRESS64, *LPADDRESS64;
|
| 71 |
|
| 72 | typedef struct _KDHELP64 {
|
| 73 | DWORD64 Thread;
|
| 74 | DWORD ThCallbackStack;
|
| 75 | DWORD ThCallbackBStore;
|
| 76 | DWORD NextCallback;
|
| 77 | DWORD FramePointer;
|
| 78 | DWORD64 KiCallUserMode;
|
| 79 | DWORD64 KeUserCallbackDispatcher;
|
| 80 | DWORD64 SystemRangeStart;
|
| 81 | DWORD64 KiUserExceptionDispatcher;
|
| 82 | DWORD64 StackBase;
|
| 83 | DWORD64 StackLimit;
|
| 84 | DWORD64 Reserved[5];
|
| 85 | } KDHELP64, *PKDHELP64;
|
| 86 |
|
| 87 | typedef struct _tagSTACKFRAME64 {
|
| 88 | ADDRESS64 AddrPC;
|
| 89 | ADDRESS64 AddrReturn;
|
| 90 | ADDRESS64 AddrFrame;
|
| 91 | ADDRESS64 AddrStack;
|
| 92 | ADDRESS64 AddrBStore;
|
| 93 | PVOID FuncTableEntry;
|
| 94 | DWORD64 Params[4];
|
| 95 | BOOL Far;
|
| 96 | BOOL Virtual;
|
| 97 | DWORD64 Reserved[3];
|
| 98 | KDHELP64 KdHelp;
|
| 99 | } STACKFRAME64, *LPSTACKFRAME64;
|
| 100 |
|
| 101 | typedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess,
|
| 102 | DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize,
|
| 103 | LPDWORD lpNumberOfBytesRead);
|
| 104 |
|
| 105 | typedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( HANDLE ahProcess,
|
| 106 | DWORD64 AddrBase);
|
| 107 |
|
| 108 | typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess,
|
| 109 | DWORD64 Address);
|
| 110 |
|
| 111 | typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess,
|
| 112 | HANDLE hThread, LPADDRESS64 lpaddr);
|
| 113 |
|
| 114 | typedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64,
|
| 115 | PVOID, PREAD_PROCESS_MEMORY_ROUTINE64,
|
| 116 | PFUNCTION_TABLE_ACCESS_ROUTINE64,
|
| 117 | PGET_MODULE_BASE_ROUTINE64,
|
| 118 | PTRANSLATE_ADDRESS_ROUTINE64);
|
| 119 | static fpStackWalk64 StackWalk64;
|
| 120 |
|
| 121 | typedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64);
|
| 122 | static fpSymGetModuleBase64 SymGetModuleBase64;
|
| 123 |
|
| 124 | typedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64,
|
| 125 | PDWORD64, PIMAGEHLP_SYMBOL64);
|
| 126 | static fpSymGetSymFromAddr64 SymGetSymFromAddr64;
|
| 127 |
|
| 128 | typedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64,
|
| 129 | PDWORD, PIMAGEHLP_LINE64);
|
| 130 | static fpSymGetLineFromAddr64 SymGetLineFromAddr64;
|
| 131 |
|
| 132 | typedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64);
|
| 133 | static fpSymFunctionTableAccess64 SymFunctionTableAccess64;
|
| 134 |
|
| 135 | static bool load64BitDebugHelp(void) {
|
| 136 | HMODULE hLib = ::LoadLibrary("Dbghelp.dll");
|
| 137 | if (hLib) {
|
| 138 | StackWalk64 = (fpStackWalk64)
|
| 139 | ::GetProcAddress(hLib, "StackWalk64");
|
| 140 | SymGetModuleBase64 = (fpSymGetModuleBase64)
|
| 141 | ::GetProcAddress(hLib, "SymGetModuleBase64");
|
| 142 | SymGetSymFromAddr64 = (fpSymGetSymFromAddr64)
|
| 143 | ::GetProcAddress(hLib, "SymGetSymFromAddr64");
|
| 144 | SymGetLineFromAddr64 = (fpSymGetLineFromAddr64)
|
| 145 | ::GetProcAddress(hLib, "SymGetLineFromAddr64");
|
| 146 | SymFunctionTableAccess64 = (fpSymFunctionTableAccess64)
|
| 147 | ::GetProcAddress(hLib, "SymFunctionTableAccess64");
|
| 148 | }
|
| 149 | return StackWalk64 != NULL;
|
| 150 | }
|
| 151 | #endif // !defined(__MINGW64_VERSION_MAJOR)
|
| 152 | #endif // __MINGW32__
|
| 153 |
|
| 154 | // Forward declare.
|
| 155 | static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep);
|
| 156 | static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType);
|
| 157 |
|
| 158 | // InterruptFunction - The function to call if ctrl-c is pressed.
|
| 159 | static void (*InterruptFunction)() = 0;
|
| 160 |
|
| 161 | static std::vector<llvm::sys::Path> *FilesToRemove = NULL;
|
| 162 | static std::vector<std::pair<void(*)(void*), void*> > *CallBacksToRun = 0;
|
| 163 | static bool RegisteredUnhandledExceptionFilter = false;
|
| 164 | static bool CleanupExecuted = false;
|
| 165 | static bool ExitOnUnhandledExceptions = false;
|
| 166 | static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL;
|
| 167 |
|
| 168 | // Windows creates a new thread to execute the console handler when an event
|
| 169 | // (such as CTRL/C) occurs. This causes concurrency issues with the above
|
| 170 | // globals which this critical section addresses.
|
| 171 | static CRITICAL_SECTION CriticalSection;
|
| 172 |
|
| 173 | namespace llvm {
|
| 174 |
|
| 175 | //===----------------------------------------------------------------------===//
|
| 176 | //=== WARNING: Implementation here must contain only Win32 specific code
|
| 177 | //=== and must not be UNIX code
|
| 178 | //===----------------------------------------------------------------------===//
|
| 179 |
|
| 180 | #ifdef _MSC_VER
|
| 181 | /// CRTReportHook - Function called on a CRT debugging event.
|
| 182 | static int CRTReportHook(int ReportType, char *Message, int *Return) {
|
| 183 | // Don't cause a DebugBreak() on return.
|
| 184 | if (Return)
|
| 185 | *Return = 0;
|
| 186 |
|
| 187 | switch (ReportType) {
|
| 188 | default:
|
| 189 | case _CRT_ASSERT:
|
| 190 | fprintf(stderr, "CRT assert: %s\n", Message);
|
| 191 | // FIXME: Is there a way to just crash? Perhaps throw to the unhandled
|
| 192 | // exception code? Perhaps SetErrorMode() handles this.
|
| 193 | _exit(3);
|
| 194 | break;
|
| 195 | case _CRT_ERROR:
|
| 196 | fprintf(stderr, "CRT error: %s\n", Message);
|
| 197 | // FIXME: Is there a way to just crash? Perhaps throw to the unhandled
|
| 198 | // exception code? Perhaps SetErrorMode() handles this.
|
| 199 | _exit(3);
|
| 200 | break;
|
| 201 | case _CRT_WARN:
|
| 202 | fprintf(stderr, "CRT warn: %s\n", Message);
|
| 203 | break;
|
| 204 | }
|
| 205 |
|
| 206 | // Don't call _CrtDbgReport.
|
| 207 | return TRUE;
|
| 208 | }
|
| 209 | #endif
|
| 210 |
|
| 211 | static void RegisterHandler() {
|
| 212 | #if __MINGW32__ && !defined(__MINGW64_VERSION_MAJOR)
|
| 213 | // On MinGW.org, we need to load up the symbols explicitly, because the
|
| 214 | // Win32 framework they include does not have support for the 64-bit
|
| 215 | // versions of the APIs we need. If we cannot load up the APIs (which
|
| 216 | // would be unexpected as they should exist on every version of Windows
|
| 217 | // we support), we will bail out since there would be nothing to report.
|
| 218 | if (!load64BitDebugHelp()) {
|
| 219 | assert(false && "These APIs should always be available");
|
| 220 | return;
|
| 221 | }
|
| 222 | #endif
|
| 223 |
|
| 224 | if (RegisteredUnhandledExceptionFilter) {
|
| 225 | EnterCriticalSection(&CriticalSection);
|
| 226 | return;
|
| 227 | }
|
| 228 |
|
| 229 | // Now's the time to create the critical section. This is the first time
|
| 230 | // through here, and there's only one thread.
|
| 231 | InitializeCriticalSection(&CriticalSection);
|
| 232 |
|
| 233 | // Enter it immediately. Now if someone hits CTRL/C, the console handler
|
| 234 | // can't proceed until the globals are updated.
|
| 235 | EnterCriticalSection(&CriticalSection);
|
| 236 |
|
| 237 | RegisteredUnhandledExceptionFilter = true;
|
| 238 | OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter);
|
| 239 | SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE);
|
| 240 |
|
| 241 | // Environment variable to disable any kind of crash dialog.
|
| 242 | if (getenv("LLVM_DISABLE_CRT_DEBUG")) {
|
| 243 | #ifdef _MSC_VER
|
| 244 | _CrtSetReportHook(CRTReportHook);
|
| 245 | #endif
|
| 246 | SetErrorMode(SEM_FAILCRITICALERRORS |
|
| 247 | SEM_NOGPFAULTERRORBOX |
|
| 248 | SEM_NOOPENFILEERRORBOX);
|
| 249 | ExitOnUnhandledExceptions = true;
|
| 250 | }
|
| 251 |
|
| 252 | // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or
|
| 253 | // else multi-threading problems will ensue.
|
| 254 | }
|
| 255 |
|
| 256 | // RemoveFileOnSignal - The public API
|
| 257 | bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) {
|
| 258 | RegisterHandler();
|
| 259 |
|
| 260 | if (CleanupExecuted) {
|
| 261 | if (ErrMsg)
|
| 262 | *ErrMsg = "Process terminating -- cannot register for removal";
|
| 263 | return true;
|
| 264 | }
|
| 265 |
|
| 266 | if (FilesToRemove == NULL)
|
| 267 | FilesToRemove = new std::vector<sys::Path>;
|
| 268 |
|
| 269 | FilesToRemove->push_back(Filename);
|
| 270 |
|
| 271 | LeaveCriticalSection(&CriticalSection);
|
| 272 | return false;
|
| 273 | }
|
| 274 |
|
| 275 | // DontRemoveFileOnSignal - The public API
|
| 276 | void sys::DontRemoveFileOnSignal(const sys::Path &Filename) {
|
| 277 | if (FilesToRemove == NULL)
|
| 278 | return;
|
| 279 |
|
| 280 | RegisterHandler();
|
| 281 |
|
| 282 | FilesToRemove->push_back(Filename);
|
| 283 | std::vector<sys::Path>::reverse_iterator I =
|
| 284 | std::find(FilesToRemove->rbegin(), FilesToRemove->rend(), Filename);
|
| 285 | if (I != FilesToRemove->rend())
|
| 286 | FilesToRemove->erase(I.base()-1);
|
| 287 |
|
| 288 | LeaveCriticalSection(&CriticalSection);
|
| 289 | }
|
| 290 |
|
| 291 | /// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or
|
| 292 | /// SIGSEGV) is delivered to the process, print a stack trace and then exit.
|
| 293 | void sys::PrintStackTraceOnErrorSignal() {
|
| 294 | RegisterHandler();
|
| 295 | LeaveCriticalSection(&CriticalSection);
|
| 296 | }
|
| 297 |
|
| 298 |
|
| 299 | void sys::SetInterruptFunction(void (*IF)()) {
|
| 300 | RegisterHandler();
|
| 301 | InterruptFunction = IF;
|
| 302 | LeaveCriticalSection(&CriticalSection);
|
| 303 | }
|
| 304 |
|
| 305 |
|
| 306 | /// AddSignalHandler - Add a function to be called when a signal is delivered
|
| 307 | /// to the process. The handler can have a cookie passed to it to identify
|
| 308 | /// what instance of the handler it is.
|
| 309 | void sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) {
|
| 310 | if (CallBacksToRun == 0)
|
| 311 | CallBacksToRun = new std::vector<std::pair<void(*)(void*), void*> >();
|
| 312 | CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie));
|
| 313 | RegisterHandler();
|
| 314 | LeaveCriticalSection(&CriticalSection);
|
| 315 | }
|
| 316 | }
|
| 317 |
|
| 318 | static void Cleanup() {
|
| 319 | EnterCriticalSection(&CriticalSection);
|
| 320 |
|
| 321 | // Prevent other thread from registering new files and directories for
|
| 322 | // removal, should we be executing because of the console handler callback.
|
| 323 | CleanupExecuted = true;
|
| 324 |
|
| 325 | // FIXME: open files cannot be deleted.
|
| 326 |
|
| 327 | if (FilesToRemove != NULL)
|
| 328 | while (!FilesToRemove->empty()) {
|
| 329 | FilesToRemove->back().eraseFromDisk();
|
| 330 | FilesToRemove->pop_back();
|
| 331 | }
|
| 332 |
|
| 333 | if (CallBacksToRun)
|
| 334 | for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i)
|
| 335 | (*CallBacksToRun)[i].first((*CallBacksToRun)[i].second);
|
| 336 |
|
| 337 | LeaveCriticalSection(&CriticalSection);
|
| 338 | }
|
| 339 |
|
| 340 | void llvm::sys::RunInterruptHandlers() {
|
| 341 | Cleanup();
|
| 342 | }
|
| 343 |
|
| 344 | static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {
|
| 345 | Cleanup();
|
| 346 |
|
| 347 | // Initialize the STACKFRAME structure.
|
| 348 | STACKFRAME64 StackFrame;
|
| 349 | memset(&StackFrame, 0, sizeof(StackFrame));
|
| 350 |
|
| 351 | DWORD machineType;
|
| 352 | #if defined(_M_X64)
|
| 353 | machineType = IMAGE_FILE_MACHINE_AMD64;
|
| 354 | StackFrame.AddrPC.Offset = ep->ContextRecord->Rip;
|
| 355 | StackFrame.AddrPC.Mode = AddrModeFlat;
|
| 356 | StackFrame.AddrStack.Offset = ep->ContextRecord->Rsp;
|
| 357 | StackFrame.AddrStack.Mode = AddrModeFlat;
|
| 358 | StackFrame.AddrFrame.Offset = ep->ContextRecord->Rbp;
|
| 359 | StackFrame.AddrFrame.Mode = AddrModeFlat;
|
| 360 | #elif defined(_M_IX86)
|
| 361 | machineType = IMAGE_FILE_MACHINE_I386;
|
| 362 | StackFrame.AddrPC.Offset = ep->ContextRecord->Eip;
|
| 363 | StackFrame.AddrPC.Mode = AddrModeFlat;
|
| 364 | StackFrame.AddrStack.Offset = ep->ContextRecord->Esp;
|
| 365 | StackFrame.AddrStack.Mode = AddrModeFlat;
|
| 366 | StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp;
|
| 367 | StackFrame.AddrFrame.Mode = AddrModeFlat;
|
| 368 | #endif
|
| 369 |
|
| 370 | HANDLE hProcess = GetCurrentProcess();
|
| 371 | HANDLE hThread = GetCurrentThread();
|
| 372 |
|
| 373 | // Initialize the symbol handler.
|
| 374 | SymSetOptions(SYMOPT_DEFERRED_LOADS|SYMOPT_LOAD_LINES);
|
| 375 | SymInitialize(hProcess, NULL, TRUE);
|
| 376 |
|
| 377 | while (true) {
|
| 378 | if (!StackWalk64(machineType, hProcess, hThread, &StackFrame,
|
| 379 | ep->ContextRecord, NULL, SymFunctionTableAccess64,
|
| 380 | SymGetModuleBase64, NULL)) {
|
| 381 | break;
|
| 382 | }
|
| 383 |
|
| 384 | if (StackFrame.AddrFrame.Offset == 0)
|
| 385 | break;
|
| 386 |
|
| 387 | // Print the PC in hexadecimal.
|
| 388 | DWORD64 PC = StackFrame.AddrPC.Offset;
|
| 389 | #if defined(_M_X64)
|
| 390 | fprintf(stderr, "0x%016llX", PC);
|
| 391 | #elif defined(_M_IX86)
|
| 392 | fprintf(stderr, "0x%08lX", static_cast<DWORD>(PC));
|
| 393 | #endif
|
| 394 |
|
| 395 | // Print the parameters. Assume there are four.
|
| 396 | #if defined(_M_X64)
|
| 397 | fprintf(stderr, " (0x%016llX 0x%016llX 0x%016llX 0x%016llX)",
|
| 398 | StackFrame.Params[0],
|
| 399 | StackFrame.Params[1],
|
| 400 | StackFrame.Params[2],
|
| 401 | StackFrame.Params[3]);
|
| 402 | #elif defined(_M_IX86)
|
| 403 | fprintf(stderr, " (0x%08lX 0x%08lX 0x%08lX 0x%08lX)",
|
| 404 | static_cast<DWORD>(StackFrame.Params[0]),
|
| 405 | static_cast<DWORD>(StackFrame.Params[1]),
|
| 406 | static_cast<DWORD>(StackFrame.Params[2]),
|
| 407 | static_cast<DWORD>(StackFrame.Params[3]));
|
| 408 | #endif
|
| 409 | // Verify the PC belongs to a module in this process.
|
| 410 | if (!SymGetModuleBase64(hProcess, PC)) {
|
| 411 | fputs(" <unknown module>\n", stderr);
|
| 412 | continue;
|
| 413 | }
|
| 414 |
|
| 415 | // Print the symbol name.
|
| 416 | char buffer[512];
|
| 417 | IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer);
|
| 418 | memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64));
|
| 419 | symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
| 420 | symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64);
|
| 421 |
|
| 422 | DWORD64 dwDisp;
|
| 423 | if (!SymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) {
|
| 424 | fputc('\n', stderr);
|
| 425 | continue;
|
| 426 | }
|
| 427 |
|
| 428 | buffer[511] = 0;
|
| 429 | if (dwDisp > 0)
|
| 430 | fprintf(stderr, ", %s() + 0x%llX bytes(s)", symbol->Name, dwDisp);
|
| 431 | else
|
| 432 | fprintf(stderr, ", %s", symbol->Name);
|
| 433 |
|
| 434 | // Print the source file and line number information.
|
| 435 | IMAGEHLP_LINE64 line;
|
| 436 | DWORD dwLineDisp;
|
| 437 | memset(&line, 0, sizeof(line));
|
| 438 | line.SizeOfStruct = sizeof(line);
|
| 439 | if (SymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) {
|
| 440 | fprintf(stderr, ", %s, line %lu", line.FileName, line.LineNumber);
|
| 441 | if (dwLineDisp > 0)
|
| 442 | fprintf(stderr, " + 0x%lX byte(s)", dwLineDisp);
|
| 443 | }
|
| 444 |
|
| 445 | fputc('\n', stderr);
|
| 446 | }
|
| 447 |
|
| 448 | if (ExitOnUnhandledExceptions)
|
| 449 | _exit(-3);
|
| 450 |
|
| 451 | // Allow dialog box to pop up allowing choice to start debugger.
|
| 452 | if (OldFilter)
|
| 453 | return (*OldFilter)(ep);
|
| 454 | else
|
| 455 | return EXCEPTION_CONTINUE_SEARCH;
|
| 456 | }
|
| 457 |
|
| 458 | static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) {
|
| 459 | // We are running in our very own thread, courtesy of Windows.
|
| 460 | EnterCriticalSection(&CriticalSection);
|
| 461 | Cleanup();
|
| 462 |
|
| 463 | // If an interrupt function has been set, go and run one it; otherwise,
|
| 464 | // the process dies.
|
| 465 | void (*IF)() = InterruptFunction;
|
| 466 | InterruptFunction = 0; // Don't run it on another CTRL-C.
|
| 467 |
|
| 468 | if (IF) {
|
| 469 | // Note: if the interrupt function throws an exception, there is nothing
|
| 470 | // to catch it in this thread so it will kill the process.
|
| 471 | IF(); // Run it now.
|
| 472 | LeaveCriticalSection(&CriticalSection);
|
| 473 | return TRUE; // Don't kill the process.
|
| 474 | }
|
| 475 |
|
| 476 | // Allow normal processing to take place; i.e., the process dies.
|
| 477 | LeaveCriticalSection(&CriticalSection);
|
| 478 | return FALSE;
|
| 479 | }
|
| 480 |
|
| 481 | #if __MINGW32__
|
| 482 | // We turned these warnings off for this file so that MinGW-g++ doesn't
|
| 483 | // complain about the ll format specifiers used. Now we are turning the
|
| 484 | // warnings back on. If MinGW starts to support diagnostic stacks, we can
|
| 485 | // replace this with a pop.
|
| 486 | #pragma GCC diagnostic warning "-Wformat"
|
| 487 | #pragma GCC diagnostic warning "-Wformat-extra-args"
|
| 488 | #endif
|