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