DinkSmallwoodHD/source/StackWalker/StackUtils.cpp
seth d4f66a5d2e Initial commit of Dink Smallwood HD source. See the "Programmer readme.txt" for information on how to set it up.
git-svn-id: svn://rtsoft.com/rtsvn/projects/RTDink@1469 353e56fe-9613-0410-8469-b96ad8e6f29c
2017-09-12 04:57:47 +00:00

122 lines
No EOL
3.6 KiB
C++

#include "StackUtils.h"
#include <tchar.h>
#include <stdio.h>
// For more info about "PreventSetUnhandledExceptionFilter" see:
// "SetUnhandledExceptionFilter" and VC8
// http://blog.kalmbachnet.de/?postid=75
// and
// Unhandled exceptions in VC8 and above… for x86 and x64
// http://blog.kalmbach-software.de/2008/04/02/unhandled-exceptions-in-vc8-and-above-for-x86-and-x64/
// Even better: http://blog.kalmbach-software.de/2013/05/23/improvedpreventsetunhandledexceptionfilter/
class StackWalkerToConsole : public StackWalker
{
protected:
virtual void OnOutput(LPCSTR szText)
{
LogMsg(szText);
}
};
#if defined _M_X64 || defined _M_IX86
static BOOL PreventSetUnhandledExceptionFilter()
{
HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll"));
if (hKernel32 == NULL) return FALSE;
void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter");
if (pOrgEntry == NULL) return FALSE;
#ifdef _M_IX86
// Code for x86:
// 33 C0 xor eax,eax
// C2 04 00 ret 4
unsigned char szExecute[] = { 0x33, 0xC0, 0xC2, 0x04, 0x00 };
#elif _M_X64
// 33 C0 xor eax,eax
// C3 ret
unsigned char szExecute[] = { 0x33, 0xC0, 0xC3 };
#else
#error "The following code only works for x86 and x64!"
#endif
DWORD dwOldProtect = 0;
BOOL bProt = VirtualProtect(pOrgEntry, sizeof(szExecute),
PAGE_EXECUTE_READWRITE, &dwOldProtect);
SIZE_T bytesWritten = 0;
BOOL bRet = WriteProcessMemory(GetCurrentProcess(),
pOrgEntry, szExecute, sizeof(szExecute), &bytesWritten);
if ((bProt != FALSE) && (dwOldProtect != PAGE_EXECUTE_READWRITE))
{
DWORD dwBuf;
VirtualProtect(pOrgEntry, sizeof(szExecute), dwOldProtect, &dwBuf);
}
return bRet;
}
#else
#pragma message("This code works only for x86 and x64!")
#endif
static BOOL s_bUnhandledExeptionFilterSet = FALSE;
static LONG __stdcall CrashHandlerExceptionFilter(EXCEPTION_POINTERS* pExPtrs)
{
#ifdef _M_IX86
if (pExPtrs->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW)
{
static char MyStack[1024 * 128]; // be sure that we have enought space...
// it assumes that DS and SS are the same!!! (this is the case for Win32)
// change the stack only if the selectors are the same (this is the case for Win32)
//__asm push offset MyStack[1024*128];
//__asm pop esp;
__asm mov eax, offset MyStack[1024 * 128];
__asm mov esp, eax;
}
#endif
LogMsg("DINK CRASHED! STACK TRACE BELOW");
LogMsg("---------------------------------------------------------");
StackWalkerToConsole sw; // output to console
sw.ShowCallstack(GetCurrentThread(), pExPtrs->ContextRecord);
LogMsg("---------------------------------------------------------");
TCHAR lString[500];
_stprintf_s(lString,
_T("Dink crashed! Info on where it crashed was written to %slog.txt. If you're a tester, give Seth that file so he can fix it!"),
GetBaseAppPath().c_str()
);
FatalAppExit(-1, lString);
return EXCEPTION_CONTINUE_SEARCH;
}
void InitUnhandledExceptionFilter()
{
/*
TCHAR szModName[_MAX_PATH];
if (GetModuleFileName(NULL, szModName, sizeof(szModName) / sizeof(TCHAR)) != 0)
{
_tcscpy_s(s_szExceptionLogFileName, szModName);
_tcscat_s(s_szExceptionLogFileName, _T(".exp.log"));
}
*/
if (s_bUnhandledExeptionFilterSet == FALSE)
{
// set global exception handler (for handling all unhandled exceptions)
SetUnhandledExceptionFilter(CrashHandlerExceptionFilter);
#if defined _M_X64 || defined _M_IX86
PreventSetUnhandledExceptionFilter();
#endif
s_bUnhandledExeptionFilterSet = TRUE;
}
}