From 3c1940a260f93edd92c6f5c3b0c9868e0b77fa7e Mon Sep 17 00:00:00 2001 From: Wanne Date: Fri, 6 Apr 2012 08:39:16 +0000 Subject: [PATCH] - Improved gameloop unhandled exception handler to retrieve the line and source file (if PDB is available) and display in the fault screen instead of the location of the fault handler (by tazpn) git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@5166 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- .../ExceptionHandling.cpp | 227 +++++++++++++++++- Standard Gaming Platform/sgp.cpp | 20 +- 2 files changed, 237 insertions(+), 10 deletions(-) diff --git a/Standard Gaming Platform/ExceptionHandling.cpp b/Standard Gaming Platform/ExceptionHandling.cpp index b63e48bb..1a584bcb 100644 --- a/Standard Gaming Platform/ExceptionHandling.cpp +++ b/Standard Gaming Platform/ExceptionHandling.cpp @@ -1166,6 +1166,7 @@ static void ERLogStackWalk(HWFILE fdump, EXCEPTION_POINTERS* pExPtrs) #define TRAP_EDITED(f) f.Reserved[1] #define SAVE_TRAP(f) f.Reserved[2] + CONTEXT Context; DWORD dwDisplacement = 0; char *szSymName; IMAGEHLP_MODULE mi; @@ -1173,6 +1174,8 @@ static void ERLogStackWalk(HWFILE fdump, EXCEPTION_POINTERS* pExPtrs) DWORD i; HANDLE hProc = (HANDLE)GetCurrentProcess(); + memcpy( &Context, pExPtrs->ContextRecord, sizeof( CONTEXT ) ); + if (!ERLoadImageHlpDLL()) return; @@ -1187,22 +1190,22 @@ static void ERLogStackWalk(HWFILE fdump, EXCEPTION_POINTERS* pExPtrs) ZeroMemory( &stFrame, sizeof(stFrame) ); - stFrame.AddrPC.Offset = pExPtrs->ContextRecord->Eip ; + stFrame.AddrPC.Offset = Context.Eip ; stFrame.AddrPC.Mode = AddrModeFlat ; - stFrame.AddrStack.Offset = pExPtrs->ContextRecord->Esp ; + stFrame.AddrStack.Offset = Context.Esp ; stFrame.AddrStack.Mode = AddrModeFlat ; - stFrame.AddrFrame.Offset = pExPtrs->ContextRecord->Ebp ; + stFrame.AddrFrame.Offset = Context.Ebp ; stFrame.AddrFrame.Mode = AddrModeFlat ; ErrorLog(fdump, "FramePtr ReturnAd Param#1 Param#2 Param#3 Param#4 Function Name\r\n"); - for (i=0; i<100; i++) + for (i=0; i<15; i++) { if (!ERStackWalk( IMAGE_FILE_MACHINE_I386, hProc, GetCurrentThread(), &stFrame, - pExPtrs->ContextRecord, + &Context, NULL, ERSymFunctionTableAccess, ERSymGetModuleBase, @@ -1226,6 +1229,8 @@ static void ERLogStackWalk(HWFILE fdump, EXCEPTION_POINTERS* pExPtrs) stFrame.Params[3] ); + memset(&mi, 0, sizeof(mi)); + mi.SizeOfStruct = sizeof(mi); if (ERSymGetModuleInfo(hProc, stFrame.AddrPC.Offset, &mi )) { ErrorLog(fdump, "%s!", mi.ModuleName ); } @@ -1288,6 +1293,218 @@ static void ERLogStackWalk(HWFILE fdump, EXCEPTION_POINTERS* pExPtrs) } #endif //_IMAGEHLP_ +//************************************ +// Method: ERLogStackWalk +// FullName: ERLogStackWalk +// Access: public static +// Returns: LPCSTR (Free with LocalFree) +// Qualifier: +// Parameter: EXCEPTION_POINTERS * pExPtrs +//************************************ +LPCSTR ERStackWalk(EXCEPTION_POINTERS* pExPtrs) +{ +#if defined(_IMAGEHLP_) && defined(_X86_) + CONTEXT Context; + DWORD dwDisplacement = 0; + char *szSymName; + IMAGEHLP_MODULE mi; + STACKFRAME stFrame; + DWORD i; + HANDLE hProc = (HANDLE)GetCurrentProcess(); + + if (!ERLoadImageHlpDLL()) + return NULL; + + std::stringstream ss; + + HMODULE hModule = GetModuleHandle(NULL); + + memcpy( &Context, pExPtrs->ContextRecord, sizeof( CONTEXT ) ); + + ERSymInitialize(hProc, NULL, TRUE); + + memset(g_sym, 0, MAX_SYMNAME_SIZE + sizeof(IMAGEHLP_SYMBOL) ) ; + g_sym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); + g_sym->MaxNameLength = MAX_SYMNAME_SIZE; + + ZeroMemory( &stFrame, sizeof(stFrame) ); + + stFrame.AddrPC.Offset = Context.Eip ; + stFrame.AddrPC.Mode = AddrModeFlat ; + stFrame.AddrStack.Offset = Context.Esp ; + stFrame.AddrStack.Mode = AddrModeFlat ; + stFrame.AddrFrame.Offset = Context.Ebp ; + stFrame.AddrFrame.Mode = AddrModeFlat ; + + for (i=0; i<100; i++) + { + if (!ERStackWalk( IMAGE_FILE_MACHINE_I386, + hProc, + GetCurrentThread(), + &stFrame, + &Context, + NULL, + ERSymFunctionTableAccess, + ERSymGetModuleBase, + NULL)) + { + break; + } + + if (ERSymGetSymFromAddr(hProc, stFrame.AddrPC.Offset, &dwDisplacement, g_sym)) { + szSymName = g_sym->Name; + } + else { + szSymName = ""; + } + memset(&mi, 0, sizeof(mi)); + mi.SizeOfStruct = sizeof(mi); + if (ERSymGetModuleInfo(hProc, stFrame.AddrPC.Offset, &mi )) { + if (mi.BaseOfImage != (DWORD)hModule) + { + ss << mi.ModuleName << "!"; + } + } + ss << szSymName << " "; + + ER_IMAGEHLP_LINE64 lineInfo; + ZeroMemory( &lineInfo, sizeof(lineInfo) ); + lineInfo.SizeOfStruct = sizeof(lineInfo); + dwDisplacement = 0; + if ( ERSymGetLineFromAddr(hProc, stFrame.AddrPC.Offset, &dwDisplacement, &lineInfo) ) + { + LPSTR pFileName = strrchr(lineInfo.FileName, '\\'); + if (pFileName) ++pFileName; + if (!pFileName) pFileName = lineInfo.FileName; + + ss << " \t" << pFileName << ":" << lineInfo.LineNumber << " "; + } + ss << std::endl; + } + ss << std::endl; + + ERSymCleanup(hProc); + + std::string str = ss.str(); + LPSTR lpResult = (LPSTR)LocalAlloc(LPTR, str.length()+1); + strcpy(lpResult, str.c_str()); + return lpResult; +#else + return NULL; +#endif //_IMAGEHLP_ +} + + +//************************************ +// Method: ERGetFirstModuleException +// FullName: ERGetFirstModuleException +// Access: public +// Returns: BOOL +// Qualifier: +// Parameter: EXCEPTION_POINTERS * pExPtrs +// Parameter: HMODULE hModule +// Parameter: LPSTR funcName +// Parameter: INT funcNameLen +// Parameter: LPSTR sourceName +// Parameter: INT sourceNameLen +// Parameter: INT * lpLineNum +//************************************ +BOOL ERGetFirstModuleException( + EXCEPTION_POINTERS* pExPtrs + , HMODULE hModule + , LPSTR funcName, INT funcNameLen + , LPSTR sourceName, INT sourceNameLen + , INT *lpLineNum + ) +{ +#if defined(_IMAGEHLP_) && defined(_X86_) + CONTEXT Context; + DWORD dwDisplacement = 0; + char *szSymName; + IMAGEHLP_MODULE mi; + STACKFRAME stFrame; + DWORD i; + HANDLE hProc = (HANDLE)GetCurrentProcess(); + BOOL bFound = FALSE; + + if (!ERLoadImageHlpDLL()) + return FALSE; + + memcpy( &Context, pExPtrs->ContextRecord, sizeof( CONTEXT ) ); + + if (hModule == NULL) + hModule = GetModuleHandle(NULL); + + ERSymInitialize(hProc, NULL, TRUE); + + memset(g_sym, 0, MAX_SYMNAME_SIZE + sizeof(IMAGEHLP_SYMBOL) ) ; + g_sym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); + g_sym->MaxNameLength = MAX_SYMNAME_SIZE; + + ZeroMemory( &stFrame, sizeof(stFrame) ); + + stFrame.AddrPC.Offset = Context.Eip ; + stFrame.AddrPC.Mode = AddrModeFlat ; + stFrame.AddrStack.Offset = Context.Esp ; + stFrame.AddrStack.Mode = AddrModeFlat ; + stFrame.AddrFrame.Offset = Context.Ebp ; + stFrame.AddrFrame.Mode = AddrModeFlat ; + + for (i=0; i<15; i++) + { + if (!ERStackWalk( IMAGE_FILE_MACHINE_I386, + hProc, + GetCurrentThread(), + &stFrame, + &Context, + NULL, + ERSymFunctionTableAccess, + ERSymGetModuleBase, + NULL)) + { + break; + } + + if (ERSymGetSymFromAddr(hProc, stFrame.AddrPC.Offset, &dwDisplacement, g_sym)) { + szSymName = g_sym->Name; + } + else { + szSymName = ""; + } + memset(&mi, 0, sizeof(mi)); + mi.SizeOfStruct = sizeof(mi); + if (!ERSymGetModuleInfo(hProc, stFrame.AddrPC.Offset, &mi )) + continue; + + if (mi.BaseOfImage != (DWORD)hModule) + continue; + + ER_IMAGEHLP_LINE64 lineInfo; + ZeroMemory( &lineInfo, sizeof(lineInfo) ); + lineInfo.SizeOfStruct = sizeof(lineInfo); + dwDisplacement = 0; + if ( ERSymGetLineFromAddr(hProc, stFrame.AddrPC.Offset, &dwDisplacement, &lineInfo) ) + { + LPSTR pFileName = strrchr(lineInfo.FileName, '\\'); + if (pFileName) ++pFileName; + if (!pFileName) pFileName = lineInfo.FileName; + + if (funcName) lstrcpyn(funcName,szSymName, funcNameLen); + if (sourceName) lstrcpyn(sourceName,pFileName, sourceNameLen); + if (lpLineNum) *lpLineNum = lineInfo.LineNumber; + bFound = TRUE; + break; + } + } + + ERSymCleanup(hProc); + return bFound; +#else + return FALSE; +#endif //_IMAGEHLP_ +} + + void ERLogModules(HWFILE fdump) { #ifdef _USE_PSAPI_ diff --git a/Standard Gaming Platform/sgp.cpp b/Standard Gaming Platform/sgp.cpp index 82805ab5..11e36469 100644 --- a/Standard Gaming Platform/sgp.cpp +++ b/Standard Gaming Platform/sgp.cpp @@ -1862,15 +1862,25 @@ static void PopulateSectionFromCommandLine(vfs::PropertyContainer &oProps, vfs:: static LONG __stdcall SGPExceptionFilter(int exceptionCount, EXCEPTION_POINTERS* pExceptInfo) { #ifdef ENABLE_EXCEPTION_HANDLING - + extern BOOL ERGetFirstModuleException(EXCEPTION_POINTERS*, HMODULE, LPSTR, INT, LPSTR, INT, INT *); + extern STR GetExceptionString( DWORD uiExceptionCode ); + CHAR funcName[64], sourceName[MAX_PATH]; + INT lineNum = 0; if (exceptionCount >= 1) { - // the exception handler writer can fail with exceptions too - __try - { + bool showAssert = true; + __try{ + // the exception handler writer can fail with exceptions too RecordExceptionInfo(pExceptInfo); + + LPCSTR exceptMsg = GetExceptionString(pExceptInfo->ExceptionRecord->ExceptionCode); + if ( ERGetFirstModuleException(pExceptInfo, NULL, funcName, _countof(funcName), sourceName, _countof(sourceName), &lineNum ) ) + { + _FailMessage(exceptMsg, lineNum, funcName, sourceName); + showAssert = false; + } } __except (EXCEPTION_EXECUTE_HANDLER) {} - AssertMsg(FALSE, "Unhanded exception processing GameLoop unable to recover."); + if (showAssert) AssertMsg(FALSE, "Unhanded exception processing GameLoop unable to recover."); } #endif