#include "Windows.h"
#include <stdio.h>
#include <vector>
#include <algorithm>
#ifdef __MINGW32__
#include <imagehlp.h>
#else
#include <dbghelp.h>
#endif
#include <psapi.h>
#ifdef __MINGW32__
#if ((HAVE_LIBIMAGEHLP != 1) || (HAVE_LIBPSAPI != 1))
#error "libimagehlp.a & libpsapi.a should be present"
#endif
#else
#pragma comment(lib, "psapi.lib")
#pragma comment(lib, "dbghelp.lib")
#endif
static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep);
static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType);
static void (*InterruptFunction)() = 0;
static std::vector<llvm::sys::Path> *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;
static CRITICAL_SECTION CriticalSection;
namespace llvm {
#ifdef _MSC_VER
static int CRTReportHook(int ReportType, char *Message, int *Return) {
if (Return)
*Return = 0;
switch (ReportType) {
default:
case _CRT_ASSERT:
fprintf(stderr, "CRT assert: %s\n", Message);
_exit(3);
break;
case _CRT_ERROR:
fprintf(stderr, "CRT error: %s\n", Message);
_exit(3);
break;
case _CRT_WARN:
fprintf(stderr, "CRT warn: %s\n", Message);
break;
}
return TRUE;
}
#endif
static void RegisterHandler() {
if (RegisteredUnhandledExceptionFilter) {
EnterCriticalSection(&CriticalSection);
return;
}
InitializeCriticalSection(&CriticalSection);
EnterCriticalSection(&CriticalSection);
RegisteredUnhandledExceptionFilter = true;
OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter);
SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE);
if (getenv("LLVM_DISABLE_CRT_DEBUG")) {
#ifdef _MSC_VER
_CrtSetReportHook(CRTReportHook);
#endif
SetErrorMode(SEM_FAILCRITICALERRORS |
SEM_NOGPFAULTERRORBOX |
SEM_NOOPENFILEERRORBOX);
ExitOnUnhandledExceptions = true;
}
}
bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) {
RegisterHandler();
if (CleanupExecuted) {
if (ErrMsg)
*ErrMsg = "Process terminating -- cannot register for removal";
return true;
}
if (FilesToRemove == NULL)
FilesToRemove = new std::vector<sys::Path>;
FilesToRemove->push_back(Filename);
LeaveCriticalSection(&CriticalSection);
return false;
}
void sys::DontRemoveFileOnSignal(const sys::Path &Filename) {
if (FilesToRemove == NULL)
return;
RegisterHandler();
FilesToRemove->push_back(Filename);
std::vector<sys::Path>::reverse_iterator I =
std::find(FilesToRemove->rbegin(), FilesToRemove->rend(), Filename);
if (I != FilesToRemove->rend())
FilesToRemove->erase(I.base()-1);
LeaveCriticalSection(&CriticalSection);
}
void sys::PrintStackTraceOnErrorSignal() {
RegisterHandler();
LeaveCriticalSection(&CriticalSection);
}
void sys::SetInterruptFunction(void (*IF)()) {
RegisterHandler();
InterruptFunction = IF;
LeaveCriticalSection(&CriticalSection);
}
void 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() {
EnterCriticalSection(&CriticalSection);
CleanupExecuted = true;
if (FilesToRemove != NULL)
while (!FilesToRemove->empty()) {
FilesToRemove->back().eraseFromDisk();
FilesToRemove->pop_back();
}
if (CallBacksToRun)
for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i)
(*CallBacksToRun)[i].first((*CallBacksToRun)[i].second);
LeaveCriticalSection(&CriticalSection);
}
void llvm::sys::RunInterruptHandlers() {
Cleanup();
}
static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {
Cleanup();
#ifdef _WIN64
#else
STACKFRAME StackFrame;
memset(&StackFrame, 0, sizeof(StackFrame));
StackFrame.AddrPC.Offset = ep->ContextRecord->Eip;
StackFrame.AddrPC.Mode = AddrModeFlat;
StackFrame.AddrStack.Offset = ep->ContextRecord->Esp;
StackFrame.AddrStack.Mode = AddrModeFlat;
StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp;
StackFrame.AddrFrame.Mode = AddrModeFlat;
HANDLE hProcess = GetCurrentProcess();
HANDLE hThread = GetCurrentThread();
SymSetOptions(SYMOPT_DEFERRED_LOADS|SYMOPT_LOAD_LINES);
SymInitialize(hProcess, NULL, TRUE);
while (true) {
if (!StackWalk(IMAGE_FILE_MACHINE_I386, hProcess, hThread, &StackFrame,
ep->ContextRecord, NULL, SymFunctionTableAccess,
SymGetModuleBase, NULL)) {
break;
}
if (StackFrame.AddrFrame.Offset == 0)
break;
DWORD PC = StackFrame.AddrPC.Offset;
fprintf(stderr, "%08lX", PC);
fprintf(stderr, " (0x%08lX 0x%08lX 0x%08lX 0x%08lX)",
StackFrame.Params[0],
StackFrame.Params[1], StackFrame.Params[2], StackFrame.Params[3]);
if (!SymGetModuleBase(hProcess, PC)) {
fputs(" <unknown module>\n", stderr);
continue;
}
char buffer[512];
IMAGEHLP_SYMBOL *symbol = reinterpret_cast<IMAGEHLP_SYMBOL *>(buffer);
memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL));
symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL);
DWORD dwDisp;
if (!SymGetSymFromAddr(hProcess, PC, &dwDisp, symbol)) {
fputc('\n', stderr);
continue;
}
buffer[511] = 0;
if (dwDisp > 0)
fprintf(stderr, ", %s()+%04lu bytes(s)", symbol->Name, dwDisp);
else
fprintf(stderr, ", %s", symbol->Name);
IMAGEHLP_LINE line;
memset(&line, 0, sizeof(line));
line.SizeOfStruct = sizeof(line);
if (SymGetLineFromAddr(hProcess, PC, &dwDisp, &line)) {
fprintf(stderr, ", %s, line %lu", line.FileName, line.LineNumber);
if (dwDisp > 0)
fprintf(stderr, "+%04lu byte(s)", dwDisp);
}
fputc('\n', stderr);
}
#endif
if (ExitOnUnhandledExceptions)
_exit(-3);
if (OldFilter)
return (*OldFilter)(ep);
else
return EXCEPTION_CONTINUE_SEARCH;
}
static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) {
EnterCriticalSection(&CriticalSection);
Cleanup();
void (*IF)() = InterruptFunction;
InterruptFunction = 0;
if (IF) {
IF(); LeaveCriticalSection(&CriticalSection);
return TRUE; }
LeaveCriticalSection(&CriticalSection);
return FALSE;
}