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