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