diff options
Diffstat (limited to 'contrib/llvm/lib/Support/Windows/Signals.inc')
-rw-r--r-- | contrib/llvm/lib/Support/Windows/Signals.inc | 285 |
1 files changed, 171 insertions, 114 deletions
diff --git a/contrib/llvm/lib/Support/Windows/Signals.inc b/contrib/llvm/lib/Support/Windows/Signals.inc index 35ba6f8..6006499 100644 --- a/contrib/llvm/lib/Support/Windows/Signals.inc +++ b/contrib/llvm/lib/Support/Windows/Signals.inc @@ -10,12 +10,15 @@ // This file provides the Win32 specific implementation of the Signals class. // //===----------------------------------------------------------------------===// - #include "llvm/Support/FileSystem.h" #include <algorithm> +#include <signal.h> #include <stdio.h> #include <vector> +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + // The Windows.h header must be after LLVM and standard headers. #include "WindowsSupport.h" @@ -165,13 +168,97 @@ static std::vector<std::string> *FilesToRemove = NULL; static std::vector<std::pair<void(*)(void*), void*> > *CallBacksToRun = 0; static bool RegisteredUnhandledExceptionFilter = false; static bool CleanupExecuted = false; -static bool ExitOnUnhandledExceptions = false; static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; // Windows creates a new thread to execute the console handler when an event // (such as CTRL/C) occurs. This causes concurrency issues with the above // globals which this critical section addresses. static CRITICAL_SECTION CriticalSection; +static bool CriticalSectionInitialized = false; + +static void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess, + HANDLE hThread, STACKFRAME64 &StackFrame, + CONTEXT *Context) { + DWORD machineType; +#if defined(_M_X64) + machineType = IMAGE_FILE_MACHINE_AMD64; +#else + machineType = IMAGE_FILE_MACHINE_I386; +#endif + + // Initialize the symbol handler. + SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); + SymInitialize(hProcess, NULL, TRUE); + + while (true) { + if (!StackWalk64(machineType, hProcess, hThread, &StackFrame, Context, NULL, + SymFunctionTableAccess64, SymGetModuleBase64, NULL)) { + break; + } + + if (StackFrame.AddrFrame.Offset == 0) + break; + + using namespace llvm; + // Print the PC in hexadecimal. + DWORD64 PC = StackFrame.AddrPC.Offset; +#if defined(_M_X64) + OS << format("0x%016llX", PC); +#elif defined(_M_IX86) + OS << format("0x%08lX", static_cast<DWORD>(PC)); +#endif + +// Print the parameters. Assume there are four. +#if defined(_M_X64) + OS << format(" (0x%016llX 0x%016llX 0x%016llX 0x%016llX)", + StackFrame.Params[0], StackFrame.Params[1], StackFrame.Params[2], + StackFrame.Params[3]); +#elif defined(_M_IX86) + OS << format(" (0x%08lX 0x%08lX 0x%08lX 0x%08lX)", + static_cast<DWORD>(StackFrame.Params[0]), + static_cast<DWORD>(StackFrame.Params[1]), + static_cast<DWORD>(StackFrame.Params[2]), + static_cast<DWORD>(StackFrame.Params[3])); +#endif + // Verify the PC belongs to a module in this process. + if (!SymGetModuleBase64(hProcess, PC)) { + OS << " <unknown module>\n"; + continue; + } + + // Print the symbol name. + char buffer[512]; + IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer); + memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64)); + symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64); + + DWORD64 dwDisp; + if (!SymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) { + OS << '\n'; + continue; + } + + buffer[511] = 0; + if (dwDisp > 0) + OS << format(", %s() + 0x%llX bytes(s)", (const char*)symbol->Name, + dwDisp); + else + OS << format(", %s", (const char*)symbol->Name); + + // Print the source file and line number information. + IMAGEHLP_LINE64 line = {}; + DWORD dwLineDisp; + line.SizeOfStruct = sizeof(line); + if (SymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) { + OS << format(", %s, line %lu", line.FileName, line.LineNumber); + if (dwLineDisp > 0) + OS << format(" + 0x%lX byte(s)", dwLineDisp); + } + + OS << '\n'; + } +} namespace llvm { @@ -184,7 +271,8 @@ namespace llvm { /// AvoidMessageBoxHook - Emulates hitting "retry" from an "abort, retry, /// ignore" CRT debug report dialog. "retry" raises an exception which /// ultimately triggers our stack dumper. -static int AvoidMessageBoxHook(int ReportType, char *Message, int *Return) { +static LLVM_ATTRIBUTE_UNUSED int +AvoidMessageBoxHook(int ReportType, char *Message, int *Return) { // Set *Return to the retry code for the return value of _CrtDbgReport: // http://msdn.microsoft.com/en-us/library/8hyw4sy7(v=vs.71).aspx // This may also trigger just-in-time debugging via DebugBreak(). @@ -196,6 +284,22 @@ static int AvoidMessageBoxHook(int ReportType, char *Message, int *Return) { #endif +extern "C" void HandleAbort(int Sig) { + if (Sig == SIGABRT) { + LLVM_BUILTIN_TRAP; + } +} + +static void InitializeThreading() { + if (CriticalSectionInitialized) + return; + + // Now's the time to create the critical section. This is the first time + // through here, and there's only one thread. + InitializeCriticalSection(&CriticalSection); + CriticalSectionInitialized = true; +} + static void RegisterHandler() { #if __MINGW32__ && !defined(__MINGW64_VERSION_MAJOR) // On MinGW.org, we need to load up the symbols explicitly, because the @@ -214,9 +318,7 @@ static void RegisterHandler() { return; } - // Now's the time to create the critical section. This is the first time - // through here, and there's only one thread. - InitializeCriticalSection(&CriticalSection); + InitializeThreading(); // Enter it immediately. Now if someone hits CTRL/C, the console handler // can't proceed until the globals are updated. @@ -226,17 +328,6 @@ static void RegisterHandler() { OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); - // Environment variable to disable any kind of crash dialog. - if (getenv("LLVM_DISABLE_CRASH_REPORT")) { -#ifdef _MSC_VER - _CrtSetReportHook(AvoidMessageBoxHook); -#endif - SetErrorMode(SEM_FAILCRITICALERRORS | - SEM_NOGPFAULTERRORBOX | - SEM_NOOPENFILEERRORBOX); - ExitOnUnhandledExceptions = true; - } - // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or // else multi-threading problems will ensue. } @@ -267,7 +358,6 @@ void sys::DontRemoveFileOnSignal(StringRef Filename) { RegisterHandler(); - FilesToRemove->push_back(Filename); std::vector<std::string>::reverse_iterator I = std::find(FilesToRemove->rbegin(), FilesToRemove->rend(), Filename); if (I != FilesToRemove->rend()) @@ -276,19 +366,63 @@ void sys::DontRemoveFileOnSignal(StringRef Filename) { LeaveCriticalSection(&CriticalSection); } +void sys::DisableSystemDialogsOnCrash() { + // Crash to stack trace handler on abort. + signal(SIGABRT, HandleAbort); + + // The following functions are not reliably accessible on MinGW. +#ifdef _MSC_VER + // We're already handling writing a "something went wrong" message. + _set_abort_behavior(0, _WRITE_ABORT_MSG); + // Disable Dr. Watson. + _set_abort_behavior(0, _CALL_REPORTFAULT); + _CrtSetReportHook(AvoidMessageBoxHook); +#endif + + // Disable standard error dialog box. + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | + SEM_NOOPENFILEERRORBOX); + _set_error_mode(_OUT_TO_STDERR); +} + /// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or /// SIGSEGV) is delivered to the process, print a stack trace and then exit. -void sys::PrintStackTraceOnErrorSignal() { +void sys::PrintStackTraceOnErrorSignal(bool DisableCrashReporting) { + DisableSystemDialogsOnCrash(); RegisterHandler(); LeaveCriticalSection(&CriticalSection); } +} + +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +// Provide a prototype for RtlCaptureContext, mingw32 from mingw.org is +// missing it but mingw-w64 has it. +extern "C" VOID WINAPI RtlCaptureContext(PCONTEXT ContextRecord); +#endif -void llvm::sys::PrintStackTrace(FILE *) { - // FIXME: Implement. +void llvm::sys::PrintStackTrace(raw_ostream &OS) { + + STACKFRAME64 StackFrame = {}; + CONTEXT Context = {}; + ::RtlCaptureContext(&Context); +#if defined(_M_X64) + StackFrame.AddrPC.Offset = Context.Rip; + StackFrame.AddrStack.Offset = Context.Rsp; + StackFrame.AddrFrame.Offset = Context.Rbp; +#else + StackFrame.AddrPC.Offset = Context.Eip; + StackFrame.AddrStack.Offset = Context.Esp; + StackFrame.AddrFrame.Offset = Context.Ebp; +#endif + StackFrame.AddrPC.Mode = AddrModeFlat; + StackFrame.AddrStack.Mode = AddrModeFlat; + StackFrame.AddrFrame.Mode = AddrModeFlat; + PrintStackTraceForThread(OS, GetCurrentProcess(), GetCurrentThread(), + StackFrame, &Context); } -void sys::SetInterruptFunction(void (*IF)()) { +void llvm::sys::SetInterruptFunction(void (*IF)()) { RegisterHandler(); InterruptFunction = IF; LeaveCriticalSection(&CriticalSection); @@ -298,16 +432,18 @@ void sys::SetInterruptFunction(void (*IF)()) { /// AddSignalHandler - Add a function to be called when a signal is delivered /// to the process. The handler can have a cookie passed to it to identify /// what instance of the handler it is. -void sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { +void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { if (CallBacksToRun == 0) CallBacksToRun = new std::vector<std::pair<void(*)(void*), void*> >(); CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie)); RegisterHandler(); LeaveCriticalSection(&CriticalSection); } -} static void Cleanup() { + if (CleanupExecuted) + return; + EnterCriticalSection(&CriticalSection); // Prevent other thread from registering new files and directories for @@ -323,13 +459,18 @@ static void Cleanup() { } if (CallBacksToRun) - for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i) - (*CallBacksToRun)[i].first((*CallBacksToRun)[i].second); + for (auto &I : *CallBacksToRun) + I.first(I.second); LeaveCriticalSection(&CriticalSection); } void llvm::sys::RunInterruptHandlers() { + // The interrupt handler may be called from an interrupt, but it may also be + // called manually (such as the case of report_fatal_error with no registered + // error handler). We must ensure that the critical section is properly + // initialized. + InitializeThreading(); Cleanup(); } @@ -337,12 +478,9 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { Cleanup(); // Initialize the STACKFRAME structure. - STACKFRAME64 StackFrame; - memset(&StackFrame, 0, sizeof(StackFrame)); + STACKFRAME64 StackFrame = {}; - DWORD machineType; #if defined(_M_X64) - machineType = IMAGE_FILE_MACHINE_AMD64; StackFrame.AddrPC.Offset = ep->ContextRecord->Rip; StackFrame.AddrPC.Mode = AddrModeFlat; StackFrame.AddrStack.Offset = ep->ContextRecord->Rsp; @@ -350,7 +488,6 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { StackFrame.AddrFrame.Offset = ep->ContextRecord->Rbp; StackFrame.AddrFrame.Mode = AddrModeFlat; #elif defined(_M_IX86) - machineType = IMAGE_FILE_MACHINE_I386; StackFrame.AddrPC.Offset = ep->ContextRecord->Eip; StackFrame.AddrPC.Mode = AddrModeFlat; StackFrame.AddrStack.Offset = ep->ContextRecord->Esp; @@ -361,90 +498,10 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { HANDLE hProcess = GetCurrentProcess(); HANDLE hThread = GetCurrentThread(); + PrintStackTraceForThread(llvm::errs(), hProcess, hThread, StackFrame, + ep->ContextRecord); - // Initialize the symbol handler. - SymSetOptions(SYMOPT_DEFERRED_LOADS|SYMOPT_LOAD_LINES); - SymInitialize(hProcess, NULL, TRUE); - - while (true) { - if (!StackWalk64(machineType, hProcess, hThread, &StackFrame, - ep->ContextRecord, NULL, SymFunctionTableAccess64, - SymGetModuleBase64, NULL)) { - break; - } - - if (StackFrame.AddrFrame.Offset == 0) - break; - - // Print the PC in hexadecimal. - DWORD64 PC = StackFrame.AddrPC.Offset; -#if defined(_M_X64) - fprintf(stderr, "0x%016llX", PC); -#elif defined(_M_IX86) - fprintf(stderr, "0x%08lX", static_cast<DWORD>(PC)); -#endif - - // Print the parameters. Assume there are four. -#if defined(_M_X64) - fprintf(stderr, " (0x%016llX 0x%016llX 0x%016llX 0x%016llX)", - StackFrame.Params[0], - StackFrame.Params[1], - StackFrame.Params[2], - StackFrame.Params[3]); -#elif defined(_M_IX86) - fprintf(stderr, " (0x%08lX 0x%08lX 0x%08lX 0x%08lX)", - static_cast<DWORD>(StackFrame.Params[0]), - static_cast<DWORD>(StackFrame.Params[1]), - static_cast<DWORD>(StackFrame.Params[2]), - static_cast<DWORD>(StackFrame.Params[3])); -#endif - // Verify the PC belongs to a module in this process. - if (!SymGetModuleBase64(hProcess, PC)) { - fputs(" <unknown module>\n", stderr); - continue; - } - - // Print the symbol name. - char buffer[512]; - IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer); - memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64)); - symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); - symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64); - - DWORD64 dwDisp; - if (!SymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) { - fputc('\n', stderr); - continue; - } - - buffer[511] = 0; - if (dwDisp > 0) - fprintf(stderr, ", %s() + 0x%llX bytes(s)", symbol->Name, dwDisp); - else - fprintf(stderr, ", %s", symbol->Name); - - // Print the source file and line number information. - IMAGEHLP_LINE64 line; - DWORD dwLineDisp; - memset(&line, 0, sizeof(line)); - line.SizeOfStruct = sizeof(line); - if (SymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) { - fprintf(stderr, ", %s, line %lu", line.FileName, line.LineNumber); - if (dwLineDisp > 0) - fprintf(stderr, " + 0x%lX byte(s)", dwLineDisp); - } - - fputc('\n', stderr); - } - - if (ExitOnUnhandledExceptions) - _exit(ep->ExceptionRecord->ExceptionCode); - - // Allow dialog box to pop up allowing choice to start debugger. - if (OldFilter) - return (*OldFilter)(ep); - else - return EXCEPTION_CONTINUE_SEARCH; + _exit(ep->ExceptionRecord->ExceptionCode); } static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { |