mirror of
https://github.com/JochenKalmbach/StackWalker
synced 2026-06-08 11:24:59 +00:00
223 lines
5.6 KiB
C++
223 lines
5.6 KiB
C++
/**********************************************************************
|
|
*
|
|
* main.cpp
|
|
*
|
|
*
|
|
* History:
|
|
* 2008-11-27 v1 - Header added
|
|
* Samples for Exception-Crashes added...
|
|
* 2009-11-01 v2 - Moved to stackwalker.codeplex.com
|
|
*
|
|
**********************************************************************/
|
|
|
|
#include "stackwalker.h"
|
|
#include <tchar.h>
|
|
#include <stdio.h>
|
|
|
|
//#define EXCEPTION_TESTS
|
|
|
|
// secure-CRT_functions are only available starting with VC8
|
|
#if _MSC_VER < 1400
|
|
#define _tcscpy_s _tcscpy
|
|
#define _tcscat_s _tcscat
|
|
#define _stprintf_s _stprintf
|
|
#define strcpy_s(a, b, c) strcpy(a, c)
|
|
#endif
|
|
|
|
|
|
// Specialized stackwalker-output classes
|
|
// Console (printf):
|
|
class StackWalkerToConsole : public StackWalker
|
|
{
|
|
protected:
|
|
virtual void OnOutput(LPCSTR szText)
|
|
{
|
|
printf("%s", szText);
|
|
}
|
|
};
|
|
|
|
void Func5()
|
|
{
|
|
StackWalkerToConsole sw;
|
|
sw.ShowCallstack();
|
|
}
|
|
void Func4()
|
|
{
|
|
Func5();
|
|
}
|
|
void Func3()
|
|
{
|
|
Func4();
|
|
}
|
|
void Func2()
|
|
{
|
|
Func3();
|
|
}
|
|
void Func1()
|
|
{
|
|
Func2();
|
|
}
|
|
|
|
void StackWalkTest()
|
|
{
|
|
Func1();
|
|
}
|
|
|
|
#ifdef EXCEPTION_TESTS
|
|
|
|
// 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/
|
|
|
|
#if defined _M_X64 || defined _M_IX86
|
|
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI
|
|
MyDummySetUnhandledExceptionFilter(
|
|
LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
|
|
{
|
|
return NULL;
|
|
}
|
|
#else
|
|
#pragma message("This code works only for x86 and x64!")
|
|
#endif
|
|
|
|
BOOL PreventSetUnhandledExceptionFilter()
|
|
{
|
|
HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll"));
|
|
if (hKernel32 == NULL) return FALSE;
|
|
void *pOrgEntry = GetProcAddress(hKernel32,
|
|
"SetUnhandledExceptionFilter");
|
|
if(pOrgEntry == NULL) return FALSE;
|
|
|
|
DWORD dwOldProtect = 0;
|
|
SIZE_T jmpSize = 5;
|
|
#ifdef _M_X64
|
|
jmpSize = 13;
|
|
#endif
|
|
BOOL bProt = VirtualProtect(pOrgEntry, jmpSize,
|
|
PAGE_EXECUTE_READWRITE, &dwOldProtect);
|
|
BYTE newJump[20];
|
|
void *pNewFunc = &MyDummySetUnhandledExceptionFilter;
|
|
#ifdef _M_IX86
|
|
DWORD dwOrgEntryAddr = (DWORD) pOrgEntry;
|
|
dwOrgEntryAddr += jmpSize; // add 5 for 5 op-codes for jmp rel32
|
|
DWORD dwNewEntryAddr = (DWORD) pNewFunc;
|
|
DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;
|
|
// JMP rel32: Jump near, relative, displacement relative to next instruction.
|
|
newJump[0] = 0xE9; // JMP rel32
|
|
memcpy(&newJump[1], &dwRelativeAddr, sizeof(pNewFunc));
|
|
#elif _M_X64
|
|
newJump[0] = 0x49; // MOV R15, ...
|
|
newJump[1] = 0xBF; // ...
|
|
memcpy(&newJump[2], &pNewFunc, sizeof (pNewFunc));
|
|
//pCur += sizeof (ULONG_PTR);
|
|
newJump[10] = 0x41; // JMP R15, ...
|
|
newJump[11] = 0xFF; // ...
|
|
newJump[12] = 0xE7; // ...
|
|
#endif
|
|
SIZE_T bytesWritten;
|
|
BOOL bRet = WriteProcessMemory(GetCurrentProcess(),
|
|
pOrgEntry, newJump, jmpSize, &bytesWritten);
|
|
|
|
if (bProt != FALSE)
|
|
{
|
|
DWORD dwBuf;
|
|
VirtualProtect(pOrgEntry, jmpSize, dwOldProtect, &dwBuf);
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
static TCHAR s_szExceptionLogFileName[_MAX_PATH] = _T("\\exceptions.log"); // default
|
|
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
|
|
|
|
StackWalkerToConsole sw; // output to console
|
|
sw.ShowCallstack(GetCurrentThread(), pExPtrs->ContextRecord);
|
|
TCHAR lString[500];
|
|
_stprintf_s(lString,
|
|
_T("*** Unhandled Exception!\n")
|
|
_T(" ExpCode: 0x%8.8X\n")
|
|
_T(" ExpFlags: %d\n")
|
|
_T(" ExpAddress: 0x%8.8X\n")
|
|
_T(" Please report!"),
|
|
pExPtrs->ExceptionRecord->ExceptionCode,
|
|
pExPtrs->ExceptionRecord->ExceptionFlags,
|
|
pExPtrs->ExceptionRecord->ExceptionAddress);
|
|
FatalAppExit(-1, lString);
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
|
|
static 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);
|
|
PreventSetUnhandledExceptionFilter();
|
|
s_bUnhandledExeptionFilterSet = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
/*void ExpTest5() { char *p = NULL; p[0] = 0; }
|
|
void ExpTest4() { ExpTest5(); }
|
|
void ExpTest3() { ExpTest4(); }
|
|
void ExpTest2() { ExpTest3(); }
|
|
void ExpTest1() { ExpTest2(); }
|
|
void TestExceptionWalking()
|
|
{
|
|
__try
|
|
{
|
|
ExpTest1();
|
|
}
|
|
__except (ExpFilter(GetExceptionInformation(), GetExceptionCode()))
|
|
{
|
|
}
|
|
}*/
|
|
|
|
int f(int i)
|
|
{
|
|
if (i<0) return i;
|
|
return f(i+1);
|
|
}
|
|
|
|
#endif
|
|
|
|
int _tmain(int argc, _TCHAR* argv[])
|
|
{
|
|
// Shows the StackWalker-Feature:
|
|
StackWalkTest();
|
|
|
|
#ifdef EXCEPTION_TESTS
|
|
// Exception-Tests:
|
|
InitUnhandledExceptionFilter();
|
|
//f(0); // endlress recursion
|
|
char *szTemp = (char*)1;
|
|
strcpy_s(szTemp, 1000, "A");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|