void Foo ( void )
{
__try
{
try
{
// Execute code to accomplish something.
}
__except ( EXCEPTION_EXECUTE_HANDLER )
{
// This will be executed if the code in the __try block
// causes an access violation or other hard crash.
// The code in here is also called the exception handler.
}
__finally
{
// This will be executed no matter if the function causes a
// crash or not. This is where mandatory cleanup code goes.
}
}
Figure 2 Using C++ Exception Handling
BOOL ReadFileHeader ( CFile * pFile , LPHEADERINFO pHeader )
{
BOOL bRet ;
try
{
pFile->Read ( pHeader , sizeof ( HEADERINFO ) ) ;
bRet = TRUE ;
}
catch ( CFileException cFE )
{
// If the header could not be read because the file was
// truncated, then handle it, otherwise continue the unwind.
if ( CFileException::endOfFile == cFE.m_cause )
{
bRet = FALSE ;
}
else
{
// throw just by itself throws the same exception as passed
// to this catch block.
throw ;
}
}
return ( bRet ) ;
}
/* John Robbins - Microsoft Systems Journal Bugslayer Column - August '98
CONDITIONAL COMPILATION :
WORK_AROUND_SRCLINE_BUG - Define this to work around the SymGetLineFromAddr
bug where PDB file lookups fail after the first lookup.
----------------------------------------------------------------------*/
#include "pch.h"
#include "BugslayerUtil.h"
#include "CrashHandler.h"
#include "Internal.h" // The project internal header file.
// File Scope Global Variables
static PFNCHFILTFN g_pfnCallBack = NULL; // The filter function.
// The original exception filter.
static LPTOP_LEVEL_EXCEPTION_FILTER g_pfnOrigFilt = NULL ;
// The array of modules to limit Crash Handler to.
static HMODULE * g_ahMod = NULL;
static UINT g_uiModCount = 0; // The size, in items, of g_ahMod.
// The static buffer returned by various functions. This avoids putting
// things on the stack.
#define BUFF_SIZE 1024
static TCHAR g_szBuff [ BUFF_SIZE ];
// The static symbol lookup buffer. This gets casted to make it work.
#define SYM_BUFF_SIZE 512
static BYTE g_stSymbol [ SYM_BUFF_SIZE ];
// The static source and line structure.
static IMAGEHLP_LINE g_stLine;
// The stack frame used in walking the stack.
static STACKFRAME g_stFrame;
// The pointer to the SymGetLineFromAddr function I GetProcAddress out
// of IMAGEHLP.DLL in case the user has an older version that does not
// support the new extensions.
static PFNSYMGETLINEFROMADDR g_pfnSymGetLineFromAddr = NULL;
// The flag that says if I have already done the GetProcAddress on
// g_pfnSymGetLineFromAddr.
static BOOL g_bLookedForSymFuncs = FALSE;
// The flag that indicates that the symbol engine as been initialized.
static BOOL g_bSymEngInit = FALSE;
// File Scope Function Declarations
// The exception handler.
LONG __stdcall CrashHandlerExceptionFilter(EXCEPTION_POINTERS *pExPtrs);
// Converts a simple exception to a string value.
LPCTSTR ConvertSimpleException(DWORD dwExcept);
// The internal function that does all the stack walking.
LPCTSTR __stdcall InternalGetStackTraceString(DWORD dwOpts,
EXCEPTION_POINTERS *pExPtrs);
// The internal SymGetLineFromAddr function.
BOOL InternalSymGetLineFromAddr(IN HANDLE hProcess, IN DWORD dwAddr, OUT PDWORD
pdwDisplacement,OUT PIMAGEHLP_LINE Line);
void InitSymEng ( void ); // Initializes the symbol engine if needed.
void CleanupSymEng ( void ); // Cleans up the symbol engine if needed.
//Destructor Class
// See the note in MemDumpValidator.cpp about automatic classes.
#pragma warning (disable : 4073)
#pragma init_seg(lib)
class CleanUpCrashHandler
{
public :
CleanUpCrashHandler(void){}
~CleanUpCrashHandler(void)
{
// Is there any outstanding memory allocations?
if ( NULL != g_ahMod ){
VERIFY (HeapFree(GetProcessHeap(), 0, g_ahMod));
g_ahMod = NULL;
}
if (NULL != g_pfnOrigFilt){
// Set the handler back to what it originally was.
SetUnhandledExceptionFilter (g_pfnOrigFilt);
}
}
};
static CleanUpCrashHandler g_cBeforeAndAfter; // The static class.
// Crash Handler Function Implementation
BOOL __stdcall SetCrashHandlerFilter(PFNCHFILTFN pFn)
{
// It's OK to have a NULL parameter because this will unhook the callback.
if (NULL == pFn){
if (NULL != g_pfnOrigFilt){
// Put the original one back.
SetUnhandledExceptionFilter (g_pfnOrigFilt);
g_pfnOrigFilt = NULL;
if (NULL != g_ahMod){
free (g_ahMod);
g_ahMod = NULL;
}
g_pfnCallBack = NULL;
}
}
else{
g_pfnCallBack = pFn;
// If this is the first time that CrashHandler has been called
// set the exception filter and save off the previous handler.
if (NULL == g_pfnOrigFilt){
g_pfnOrigFilt=SetUnhandledExceptionFilter(CrashHandlerExceptionFilter);
}
}
return (TRUE);
}
BOOL __stdcall AddCrashHandlerLimitModule(HMODULE hMod)
{
ASSERT (NULL != hMod); // Check the obvious cases.
if (NULL == hMod) return (FALSE);
// TODO: Check that hMod really is a PE module.
// Allocate a temporary version. This must be allocated into memory
// that is guaranteed to be around even if the process is toasting.
// This means the RTL heap is probably already gone so I do it out
// of the process heap.
HMODULE *phTemp = (HMODULE*)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS,
(sizeof(HMODULE)*(g_uiModCount+1)));
ASSERT (NULL != phTemp);
if (NULL == phTemp){
TRACE0 ("Serious trouble in the house! - malloc failed!!!\n");
return (FALSE);
}
if (NULL == g_ahMod){
g_ahMod = phTemp;
g_ahMod[ 0 ] = hMod;
g_uiModCount++;
}
else{
// Copy the old values.
CopyMemory(phTemp, g_ahMod, sizeof (HMODULE)* g_uiModCount);
g_ahMod = phTemp;
g_ahMod[ g_uiModCount ] = hMod;
g_uiModCount++;
}
return (TRUE) ;
}
UINT __stdcall GetLimitModuleCount(void)
{
return (g_uiModCount);
}
int __stdcall GetLimitModulesArray(HMODULE *pahMod, UINT uiSize)
{
int iRet;
__try
{
ASSERT (FALSE == IsBadWritePtr( pahMod, uiSize * sizeof(HMODULE)));
if (TRUE == IsBadWritePtr (pahMod, uiSize * sizeof(HMODULE)))
{
iRet = GLMA_BADPARAM;
__leave;
}
if ( uiSize < g_uiModCount )
{
iRet = GLMA_BUFFTOOSMALL;
__leave;
}
CopyMemory(pahMod, g_ahMod, sizeof(HMODULE) * g_uiModCount);
iRet = GLMA_SUCCESS;
}
__except ( EXCEPTION_EXECUTE_HANDLER )
{
iRet = GLMA_FAILURE;
}
return (iRet);
}
LONG __stdcall CrashHandlerExceptionFilter (EXCEPTION_POINTERS* pExPtrs)
{
LONG lRet = EXCEPTION_CONTINUE_SEARCH;
__try
{
if ( NULL != g_pfnCallBack )
{ // The symbol engine has to be initialized here so that
// I can look up the base module information for the
// crash address as well as just get the symbol engine ready.
InitSymEng();
// Check the g_ahMod list.
BOOL bCallIt = FALSE;
if (0 == g_uiModCount) bCallIt = TRUE ;
else
{
HINSTANCE hBaseAddr =(HINSTANCE)SymGetModuleBase(
GetCurrentProcess(),
(DWORD)pExPtrs->ExceptionRecord->ExceptionAddress);
if (NULL != hBaseAddr){
for (UINT i = 0 ; i < g_uiModCount ; i++){
if (hBaseAddr == g_ahMod[ i ]){
bCallIt = TRUE ;
break ;
}
}
}
}
if (TRUE == bCallIt){
// Check that the filter function still exists in memory
// before I call it. The user might have forgotten to
// unregister and the filter function is invalid
// because it got unloaded. Of course, if something loaded
// back into the same address, there is not much I can do.
if (FALSE == IsBadCodePtr((FARPROC)g_pfnCallBack)){
lRet = g_pfnCallBack ( pExPtrs ) ;
}
}
else{
// Call the previous filter but only after it checks
// out. I am just being a little paranoid.
if (FALSE == IsBadCodePtr((FARPROC)g_pfnOrigFilt)){
lRet = g_pfnOrigFilt(pExPtrs);
}
}
CleanupSymEng();
}
}
__except ( EXCEPTION_EXECUTE_HANDLER ){
lRet = EXCEPTION_CONTINUE_SEARCH;
}
return (lRet);
}
// EXCEPTION_POINTER Translation Functions Implementation
LPCTSTR __stdcall GetFaultReason (EXCEPTION_POINTERS *pExPtrs)
{
ASSERT ( FALSE == IsBadReadPtr( pExPtrs, sizeof(EXCEPTION_POINTERS)));
if ( TRUE == IsBadReadPtr( pExPtrs, sizeof(EXCEPTION_POINTERS))){
TRACE0 ( "Bad parameter to GetFaultReasonA\n" ) ;
return ( NULL ) ;
}
// The value that holds the return.
LPCTSTR szRet ;
__try
{
// Initialize the symbol engine in case it is not initialized.
InitSymEng ();
int iCurr = 0; // The current position in the buffer.
// A temp value holder to keep the stack usage to a minimum.
DWORD dwTemp ;
iCurr += BSUGetModuleBaseName(GetCurrentProcess(), NULL, g_szBuff,
BUFF_SIZE);
iCurr += wsprintf ( g_szBuff + iCurr , _T ( " caused a " ) ) ;
dwTemp = (DWORD)ConvertSimpleException(
pExPtrs->ExceptionRecord->ExceptionCode);
if (NULL != dwTemp)
{
iCurr += wsprintf(g_szBuff + iCurr, _T("%s"), dwTemp);
}
else
{
iCurr += (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_HMODULE,
GetModuleHandle(_T("NTDLL.DLL")),
pExPtrs->ExceptionRecord->ExceptionCode,
0,
g_szBuff + iCurr,
BUFF_SIZE, 0)
* sizeof(TCHAR));
}
ASSERT (iCurr < BUFF_SIZE);
iCurr += wsprintf ( g_szBuff + iCurr, _T(" in module "));
dwTemp = SymGetModuleBase(GetCurrentProcess(),
(DWORD)pExPtrs->ExceptionRecord->ExceptionAddress);
ASSERT (NULL != dwTemp);
if (NULL == dwTemp){
iCurr += wsprintf( g_szBuff + iCurr, _T("<UNKNOWN>"));
}
else{
iCurr += BSUGetModuleBaseName(GetCurrentProcess(),
(HINSTANCE)dwTemp,g_szBuff+iCurr, BUFF_SIZE-iCurr);
}
#ifdef _ALPHA_
iCurr += wsprintf(g_szBuff + iCurr, _T ( " at %08X" ),
pExPtrs->ExceptionRecord->ExceptionAddress);
#else
iCurr += wsprintf( g_szBuff + iCurr, _T(" at %04X:%08X"),
pExPtrs->ContextRecord->SegCs,
pExPtrs->ExceptionRecord->ExceptionAddress);
#endif
ASSERT (iCurr < BUFF_SIZE);
// Start looking up the exception address.
// lint -e545
PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)&g_stSymbol;
//lint +e545
FillMemory(pSym , NULL , SYM_BUFF_SIZE);
pSym->SizeOfStruct = sizeof (IMAGEHLP_SYMBOL);
pSym->MaxNameLength = SYM_BUFF_SIZE - sizeof (IMAGEHLP_SYMBOL);
DWORD dwDisp ;
if ( TRUE == SymGetSymFromAddr(GetCurrentProcess(),
(DWORD)pExPtrs->ExceptionRecord->ExceptionAddress,
&dwDisp, pSym)){
iCurr += wsprintf ( g_szBuff + iCurr, _T(", "));
// Copy no more than there is room for.
dwTemp = lstrlen(pSym->Name);
if ((int)dwTemp > (BUFF_SIZE - iCurr - 20))
{
lstrcpyn (g_szBuff + iCurr, pSym->Name, BUFF_SIZE-iCurr-1) ;
// Gotta leave now.
szRet = g_szBuff ;
__leave ;
}
else
{
if ( dwDisp > 0 )
{
iCurr += wsprintf(g_szBuff + iCurr, _T("%s()+%d byte(s)"),
pSym->Name, dwDisp);
}
else
{
iCurr += wsprintf(g_szBuff + iCurr, _T("%s "), pSym->Name);
}
}
}
else
{
// If the symbol was not found, the source and line will not
// be found either so leave now.
szRet = g_szBuff;
__leave;
}
ASSERT (iCurr < BUFF_SIZE);
// Do the source and line lookup.
ZeroMemory(&g_stLine, sizeof(IMAGEHLP_LINE));
g_stLine.SizeOfStruct = sizeof(IMAGEHLP_LINE);
if ( TRUE == InternalSymGetLineFromAddr(GetCurrentProcess(),
(DWORD)pExPtrs->ExceptionRecord->ExceptionAddress,
&dwDisp, &g_stLine))
{
iCurr += wsprintf (g_szBuff + iCurr, _T(", "));
// Copy no more than there is room for.
dwTemp = lstrlen ( g_stLine.FileName );
if ( (int)dwTemp > ( BUFF_SIZE - iCurr - 25 ) )
{
lstrcpyn(g_szBuff + iCurr,
g_stLine.FileName, BUFF_SIZE - iCurr - 1);
// Gotta leave now.
szRet = g_szBuff;
__leave;
}
else
{
if ( dwDisp > 0 )
{
iCurr += wsprintf(g_szBuff + iCurr,
_T("%s, line %d+%d byte(s)"), g_stLine.FileName,
g_stLine.LineNumber, dwDisp);
}
else
{
iCurr += wsprintf(g_szBuff + iCurr, _T("%s, line %d"),
g_stLine.FileName, g_stLine.LineNumber);
}
}
}
szRet = g_szBuff;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
ASSERT (FALSE);
szRet = NULL;
}
return (szRet);
}
BOOL __stdcall GetFaultReasonVB(EXCEPTION_POINTERS *pExPtrs, LPTSTR szBuff,
UINT uiSize)
{
ASSERT (FALSE == IsBadWritePtr(szBuff, uiSize));
if (TRUE == IsBadWritePtr(szBuff ,uiSize)) return (FALSE);
LPCTSTR szRet;
__try{
szRet = GetFaultReason(pExPtrs);
ASSERT (NULL != szRet);
if (NULL == szRet){
__leave;
}
lstrcpyn(szBuff, szRet, min((UINT)lstrlen(szRet) + 1, uiSize));
}
__except(EXCEPTION_EXECUTE_HANDLER){
szRet = NULL;
}
return (NULL != szRet);
}
LPCTSTR BUGSUTIL_DLLINTERFACE __stdcall GetFirstStackTraceString(
DWORD dwOpts, EXCEPTION_POINTERS *pExPtrs)
{
// All of the error checking is in InternalGetStackTraceString
// Initialize the STACKFRAME structure.
ZeroMemory (&g_stFrame , sizeof(STACKFRAME));
#ifdef _X86_
g_stFrame.AddrPC.Offset = pExPtrs->ContextRecord->Eip;
g_stFrame.AddrPC.Mode = AddrModeFlat;
g_stFrame.AddrStack.Offset = pExPtrs->ContextRecord->Esp;
g_stFrame.AddrStack.Mode = AddrModeFlat;
g_stFrame.AddrFrame.Offset = pExPtrs->ContextRecord->Ebp;
g_stFrame.AddrFrame.Mode = AddrModeFlat;
#else
g_stFrame.AddrPC.Offset = (DWORD)pExPtrs->ContextRecord->Fir;
g_stFrame.AddrPC.Mode = AddrModeFlat;
g_stFrame.AddrReturn.Offset = (DWORD)pExPtrs->ContextRecord->IntRa;
g_stFrame.AddrReturn.Mode = AddrModeFlat;
g_stFrame.AddrStack.Offset = (DWORD)pExPtrs->ContextRecord->IntSp;
g_stFrame.AddrStack.Mode = AddrModeFlat;
g_stFrame.AddrFrame.Offset = (DWORD)pExPtrs->ContextRecord->IntFp;
g_stFrame.AddrFrame.Mode = AddrModeFlat;
#endif
return (InternalGetStackTraceString(dwOpts ,pExPtrs));
}
LPCTSTR BUGSUTIL_DLLINTERFACE __stdcall GetNextStackTraceString(
DWORD dwOpts, EXCEPTION_POINTERS *pExPtrs)
{
// All error checking is in InternalGetStackTraceString. Assume that
// GetFirstStackTraceString has initialized the stack frame information.
return (InternalGetStackTraceString(dwOpts, pExPtrs));
}
// The internal function that does all the stack walking.
LPCTSTR __stdcall InternalGetStackTraceString(DWORD dwOpts,
EXCEPTION_POINTERS *pExPtrs)
{
ASSERT (FALSE == IsBadReadPtr(pExPtrs, sizeof(EXCEPTION_POINTERS)));
if (TRUE == IsBadReadPtr(pExPtrs, sizeof(EXCEPTION_POINTERS))){
TRACE0 ("GetStackTraceString - invalid pExPtrs!\n");
return (NULL);
}
LPCTSTR szRet; // The value that is returned.
// A temporary for all to use. This saves stack space.
DWORD dwTemp ;
__try
{
// Initialize the symbol engine in case it is not initialized.
InitSymEng();
#ifdef _ALPHA_
#define CH_MACHINE IMAGE_FILE_MACHINE_ALPHA
#else
#define CH_MACHINE IMAGE_FILE_MACHINE_I386
#endif
// Note: If the source and line functions are used, then
// StackWalk can access violate.
BOOL bSWRet = StackWalk(CH_MACHINE, GetCurrentProcess(),
GetCurrentThread(), &g_stFrame,
pExPtrs->ContextRecord, NULL,
SymFunctionTableAccess,SymGetModuleBase,NULL);
if ((FALSE == bSWRet)||(0 == g_stFrame.AddrFrame.Offset)){
szRet = NULL;
__leave;
}
int iCurr = 0;
// At a minimum, put the address in.
#ifdef _ALPHA_
iCurr += wsprintf(g_szBuff + iCurr, _T("0x%08X"),
g_stFrame.AddrPC.Offset);
#else
iCurr += wsprintf(g_szBuff + iCurr, _T("%04X:%08X"),
pExPtrs->ContextRecord->SegCs, g_stFrame.AddrPC.Offset);
#endif
// Do the parameters?
if (GSTSO_PARAMS == (dwOpts & GSTSO_PARAMS)){
iCurr += wsprintf(g_szBuff + iCurr,
_T(" (0x%08X 0x%08X 0x%08X 0x%08X)"),
g_stFrame.Params[0], g_stFrame.Params[1],
g_stFrame.Params[2], g_stFrame.Params[3]);
}
if (GSTSO_MODULE == (dwOpts & GSTSO_MODULE)){
iCurr += wsprintf(g_szBuff + iCurr, _T(" "));
dwTemp = SymGetModuleBase(GetCurrentProcess(),
g_stFrame.AddrPC.Offset);
ASSERT ( NULL != dwTemp );
if (NULL == dwTemp){
iCurr += wsprintf(g_szBuff + iCurr, _T("<UNKNOWN>"));
}
else{
iCurr += BSUGetModuleBaseName(GetCurrentProcess(),
(HINSTANCE)dwTemp, g_szBuff + iCurr,
BUFF_SIZE - iCurr);
}
}
ASSERT (iCurr < BUFF_SIZE);
DWORD dwDisp;
if (GSTSO_SYMBOL == (dwOpts & GSTSO_SYMBOL)){
// Start looking up the exception address.
//lint -e545
PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)&g_stSymbol;
//lint +e545
ZeroMemory(pSym , SYM_BUFF_SIZE);
pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
pSym->MaxNameLength = SYM_BUFF_SIZE - sizeof(IMAGEHLP_SYMBOL);
if ( TRUE == SymGetSymFromAddr(GetCurrentProcess(),
g_stFrame.AddrPC.Offset, &dwDisp, pSym)){
iCurr += wsprintf(g_szBuff + iCurr, _T(", "));
// Copy no more than there is room for.
dwTemp = lstrlen(pSym->Name);
if (dwTemp > (DWORD)(BUFF_SIZE - iCurr - 20)){
lstrcpyn (g_szBuff + iCurr, pSym->Name, BUFF_SIZE-iCurr-1);
szRet = g_szBuff;
__leave;
}
else{
if (dwDisp > 0){
iCurr += wsprintf(g_szBuff + iCurr,
_T("%s()+%d byte(s)"), pSym->Name, dwDisp);
}
else{
iCurr += wsprintf(g_szBuff+iCurr, _T("%s"),pSym->Name);
}
}
}
else{
// If the symbol was not found, the source and line will
// not be found either so leave now.
szRet = g_szBuff;
__leave;
}
}
if (GSTSO_SRCLINE == (dwOpts & GSTSO_SRCLINE)){
ZeroMemory(&g_stLine, sizeof(IMAGEHLP_LINE));
g_stLine.SizeOfStruct = sizeof(IMAGEHLP_LINE);
if (TRUE == InternalSymGetLineFromAddr(GetCurrentProcess(),
g_stFrame.AddrPC.Offset, &dwDisp, &g_stLine)){
iCurr += wsprintf(g_szBuff + iCurr, _T(", "));
// Copy no more than there is room for.
dwTemp = lstrlen(g_stLine.FileName);
if (dwTemp > (DWORD)(BUFF_SIZE - iCurr - 25)){
lstrcpyn(g_szBuff + iCurr, g_stLine.FileName,
BUFF_SIZE - iCurr - 1);
szRet = g_szBuff ;
__leave ;
}
else{
if (dwDisp > 0){
iCurr += wsprintf(g_szBuff + iCurr,
_T("%s, line %d+%d byte(s)"), g_stLine.FileName,
g_stLine.LineNumber, dwDisp);
}
else{
iCurr += wsprintf(g_szBuff + iCurr,
_T("%s, line %d"), g_stLine.FileName,
g_stLine.LineNumber);
}
}
}
}
szRet = g_szBuff ;
}
__except (EXCEPTION_EXECUTE_HANDLER){
ASSERT (FALSE);
szRet = NULL;
}
return (szRet);
}
BOOL __stdcall GetFirstStackTraceStringVB(DWORD dwOpts,
EXCEPTION_POINTERS *pExPtrs, LPTSTR szBuff, UINT uiSize)
{
ASSERT (FALSE == IsBadWritePtr(szBuff ,uiSize));
if (TRUE == IsBadWritePtr(szBuff , uiSize)){
return (FALSE);
}
LPCTSTR szRet;
__try{
szRet = GetFirstStackTraceString(dwOpts, pExPtrs);
if (NULL == szRet) __leave;
lstrcpyn(szBuff, szRet, min((UINT)lstrlen(szRet) + 1, uiSize));
}
__except ( EXCEPTION_EXECUTE_HANDLER ) szRet = NULL ;
return ( NULL != szRet ) ;
}
BOOL __stdcall GetNextStackTraceStringVB(DWORD dwOpts,
EXCEPTION_POINTERS *pExPtrs, LPTSTR szBuff, UINT uiSize)
{
ASSERT (FALSE == IsBadWritePtr(szBuff, uiSize));
if (TRUE == IsBadWritePtr(szBuff, uiSize)) return (FALSE);
LPCTSTR szRet;
__try{
szRet = GetNextStackTraceString(dwOpts, pExPtrs);
if (NULL == szRet) __leave;
lstrcpyn(szBuff, szRet, min((UINT)lstrlen(szRet) + 1, uiSize));
}
__except ( EXCEPTION_EXECUTE_HANDLER ) szRet = NULL;
return (NULL != szRet);
}
LPCTSTR __stdcall GetRegisterString(EXCEPTION_POINTERS *pExPtrs)
{
// Check the parameter.
ASSERT (FALSE == IsBadReadPtr(pExPtrs, sizeof(EXCEPTION_POINTERS)));
if (TRUE == IsBadReadPtr(pExPtrs, sizeof(EXCEPTION_POINTERS))){
TRACE0 ("GetRegisterString - invalid pExPtrs!\n");
return (NULL);
}
#ifdef _ALPHA_
// Do the ALPHA ones if needed.
ASSERT (FALSE);
#else
// 48 bytes to the stack. This could be a problem when the stack is blown.
wsprintf(g_szBuff, _T("EAX=%08X EBX=%08X ECX=%08X EDX=%08X ESI=%08X\n"\
"EDI=%08X EBP=%08X ESP=%08X EIP=%08X FLG=%08X\n"\
"CS=%04X DS=%04X SS=%04X ES=%04X FS=%04X GS=%04X"),
pExPtrs->ContextRecord->Eax, pExPtrs->ContextRecord->Ebx,
pExPtrs->ContextRecord->Ecx, pExPtrs->ContextRecord->Edx,
pExPtrs->ContextRecord->Esi, pExPtrs->ContextRecord->Edi,
pExPtrs->ContextRecord->Ebp, pExPtrs->ContextRecord->Esp,
pExPtrs->ContextRecord->Eip, pExPtrs->ContextRecord->EFlags,
pExPtrs->ContextRecord->SegCs, pExPtrs->ContextRecord->SegDs,
pExPtrs->ContextRecord->SegSs, pExPtrs->ContextRecord->SegEs,
pExPtrs->ContextRecord->SegFs, pExPtrs->ContextRecord->SegGs);
#endif
return (g_szBuff);
}
BOOL __stdcall GetRegisterStringVB(EXCEPTION_POINTERS *pExPtrs, LPTSTR szBuff,
UINT uiSize)
{
ASSERT (FALSE == IsBadWritePtr(szBuff, uiSize));
if (TRUE == IsBadWritePtr(szBuff, uiSize)) return (FALSE);
LPCTSTR szRet;
__try{
szRet = GetRegisterString(pExPtrs);
if (NULL == szRet) __leave;
lstrcpyn(szBuff, szRet, min((UINT)lstrlen(szRet) + 1, uiSize));
}
__except ( EXCEPTION_EXECUTE_HANDLER ) szRet = NULL;
return (NULL != szRet);
}
//lint -e527
LPCTSTR ConvertSimpleException(DWORD dwExcept)
{
switch (dwExcept){
case EXCEPTION_ACCESS_VIOLATION:
return (_T("EXCEPTION_ACCESS_VIOLATION")); break ;
case EXCEPTION_DATATYPE_MISALIGNMENT:
return (_T("EXCEPTION_DATATYPE_MISALIGNMENT")); break;
case EXCEPTION_BREAKPOINT:
return (_T("EXCEPTION_BREAKPOINT")); break;
case EXCEPTION_SINGLE_STEP:
return (_T("EXCEPTION_SINGLE_STEP")); break;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
return (_T("EXCEPTION_ARRAY_BOUNDS_EXCEEDED")); break;
case EXCEPTION_FLT_DENORMAL_OPERAND:
return (_T("EXCEPTION_FLT_DENORMAL_OPERAND")); break;
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
return (_T("EXCEPTION_FLT_DIVIDE_BY_ZERO")); break;
case EXCEPTION_FLT_INEXACT_RESULT:
return (_T("EXCEPTION_FLT_INEXACT_RESULT")); break;
case EXCEPTION_FLT_INVALID_OPERATION:
return (_T("EXCEPTION_FLT_INVALID_OPERATION")); break;
case EXCEPTION_FLT_OVERFLOW:
return (_T("EXCEPTION_FLT_OVERFLOW")); break;
case EXCEPTION_FLT_STACK_CHECK:
return (_T("EXCEPTION_FLT_STACK_CHECK")); break;
case EXCEPTION_FLT_UNDERFLOW:
return (_T("EXCEPTION_FLT_UNDERFLOW")); break;
case EXCEPTION_INT_DIVIDE_BY_ZERO:
return (_T("EXCEPTION_INT_DIVIDE_BY_ZERO")); break;
case EXCEPTION_INT_OVERFLOW:
return (_T("EXCEPTION_INT_OVERFLOW")); break;
case EXCEPTION_PRIV_INSTRUCTION:
return (_T("EXCEPTION_PRIV_INSTRUCTION")); break;
case EXCEPTION_IN_PAGE_ERROR:
return (_T("EXCEPTION_IN_PAGE_ERROR")); break;
case EXCEPTION_ILLEGAL_INSTRUCTION:
return (_T("EXCEPTION_ILLEGAL_INSTRUCTION")); break;
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
return (_T("EXCEPTION_NONCONTINUABLE_EXCEPTION")); break;
case EXCEPTION_STACK_OVERFLOW:
return (_T("EXCEPTION_STACK_OVERFLOW")); break;
case EXCEPTION_INVALID_DISPOSITION:
return (_T("EXCEPTION_INVALID_DISPOSITION")); break;
case EXCEPTION_GUARD_PAGE:
return (_T("EXCEPTION_GUARD_PAGE")); break ;
case EXCEPTION_INVALID_HANDLE:
return (_T("EXCEPTION_INVALID_HANDLE")); break;
default:
return (NULL); break;
}
}
//lint +e527
BOOL InternalSymGetLineFromAddr(IN HANDLE hProcess, IN DWORD dwAddr,
OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE Line)
{
// Have I already done the GetProcAddress?
if (FALSE == g_bLookedForSymFuncs){
g_bLookedForSymFuncs = TRUE;
g_pfnSymGetLineFromAddr = (PFNSYMGETLINEFROMADDR) GetProcAddress(
GetModuleHandle(_T("IMAGEHLP.DLL")), "SymGetLineFromAddr");
}
if ( NULL != g_pfnSymGetLineFromAddr ){
#ifdef WORK_AROUND_SRCLINE_BUG
// The problem is that the symbol engine only finds those source
// line addresses (after the first lookup) that fall exactly on
// a zero displacement. I will walk backwards 100 bytes to
// find the line and return the proper displacement.
DWORD dwTempDis = 0;
while (FALSE == g_pfnSymGetLineFromAddr(hProcess, dwAddr - dwTempDis,
pdwDisplacement, Line)){
dwTempDis += 1;
if (100 == dwTempDis) return (FALSE);
}
// It was found and the source line information is correct so
// change the displacement if it was looked up multiple times.
if (0 != dwTempDis) *pdwDisplacement = dwTempDis;
return (TRUE);
#else // WORK_AROUND_SRCLINE_BUG
return (g_pfnSymGetLineFromAddr(hProcess, dwAddr, pdwDisplacement,
Line));
#endif
}
return (FALSE);
}
// Initializes the symbol engine if needed.
void InitSymEng (void){
if (FALSE == g_bSymEngInit){
DWORD dwOpts = SymGetOptions(); // Set up the symbol engine.
// Always defer loading to make life faster.
SymSetOptions(dwOpts | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
// Initialize the symbol engine.
VERIFY (SymInitialize(GetCurrentProcess(), NULL, TRUE));
}
g_bSymEngInit = TRUE ;
}
// Cleans up the symbol engine if needed.
void CleanupSymEng(void){
if (TRUE == g_bSymEngInit) VERIFY (SymCleanup(GetCurrentProcess()));
g_bSymEngInit = FALSE ;
}
Options | Output |
0 | Just the stack address |
GSTSO_PARAMS | Include the possible params |
GSTSO_MODULE | Include the module name |
GSTSO_SYMBOL | Include the symbol name of the stack address |
GSTSO_SRCLINE | Include source and line info of the stack address |