DWORD handleException(DEBUG_EVENT& oDebugEvent, cThreadContext& oThreadContext, cProcessInformation& oProcessInformation) { if ( !handleExceptionAccessViolation(oDebugEvent, oThreadContext, oProcessInformation) && !handleExceptionCxx(oDebugEvent, oThreadContext, oProcessInformation) && !handleExceptionInPageError(oDebugEvent, oThreadContext, oProcessInformation) && !handleExceptionThreadName(oDebugEvent, oThreadContext, oProcessInformation) ) { // Convert exception information array into a string: std::basic_string<TCHAR> sExceptionInformation; TCHAR sExceptionInformationBuffer[21]; // "18446744073709551615\0" in case of unsigned __int64 for (size_t iIndex = 0; iIndex < oDebugEvent.u.Exception.ExceptionRecord.NumberParameters; iIndex++) { if (iIndex) sExceptionInformation += _T(", "); _stprintf_s(sExceptionInformationBuffer, sizeof(sExceptionInformationBuffer) / sizeof(TCHAR), _T("%Iu"), oDebugEvent.u.Exception.ExceptionRecord.ExceptionInformation[iIndex]); sExceptionInformation += sExceptionInformationBuffer; } PTSTR sExceptionName = getExceptionName(oDebugEvent.u.Exception.ExceptionRecord.ExceptionCode); PTSTR siChance = oDebugEvent.u.Exception.dwFirstChance ? _T("1") : _T("2"); PTSTR sbContinuable = oDebugEvent.u.Exception.ExceptionRecord.ExceptionFlags == 0 ? _T("true") : _T("false"); if (sExceptionName) { _tprintf(_T("{\"sEventName\": \"%s\", \"iProcessId\": %u, \"iThreadId\": %u, \"sThreadISA\": \"%s\", \"iChance\": %s, \"bContinuable\": %s, \"iCodeAddress\": %Iu, \"aiExceptionInformation\": [%s]};\r\n"), sExceptionName, oDebugEvent.dwProcessId, oDebugEvent.dwThreadId, oThreadContext.bThreadIs64Bit ? _T("x64") : _T("x86"), siChance, sbContinuable, oDebugEvent.u.Exception.ExceptionRecord.ExceptionAddress, sExceptionInformation.c_str()); } else { _tprintf(_T("{\"sEventName\": \"exception\", \"iProcessId\": %u, \"iThreadId\": %u, \"sThreadISA\": \"%s\", \"iChance\": %s, \"bContinuable\": %s, \"iCodeAddress\": %Iu, \"iExceptionCode\": %u, \"aiExceptionInformation\": [%s]};\r\n"), oDebugEvent.dwProcessId, oDebugEvent.dwThreadId, oThreadContext.bThreadIs64Bit ? _T("x64") : _T("x86"), siChance, sbContinuable, oDebugEvent.u.Exception.ExceptionRecord.ExceptionAddress, oDebugEvent.u.Exception.ExceptionRecord.ExceptionCode, sExceptionInformation.c_str()); } } return oDebugEvent.u.Exception.dwFirstChance ? DBG_EXCEPTION_NOT_HANDLED : NULL; }
LONG CALLBACK ExceptionHandler(LPEXCEPTION_POINTERS e) { // generate crash report SymInitialize(GetCurrentProcess(), 0, TRUE); std::stringstream ss; ss << "== application crashed\n"; ss << stdext::format("app name: %s\n", g_app.getName()); ss << stdext::format("app version: %s\n", g_app.getVersion()); ss << stdext::format("build compiler: %s\n", BUILD_COMPILER); ss << stdext::format("build date: %s\n", __DATE__); ss << stdext::format("build type: %s\n", BUILD_TYPE); ss << stdext::format("build revision: %s (%s)\n", BUILD_REVISION, BUILD_COMMIT); ss << stdext::format("crash date: %s\n", stdext::date_time_string()); ss << stdext::format("exception: %s (0x%08lx)\n", getExceptionName(e->ExceptionRecord->ExceptionCode), e->ExceptionRecord->ExceptionCode); ss << stdext::format("exception address: 0x%08lx\n", (size_t)e->ExceptionRecord->ExceptionAddress); ss << stdext::format(" backtrace:\n"); Stacktrace(e, ss); ss << "\n"; SymCleanup(GetCurrentProcess()); // print in stdout g_logger.info(ss.str()); // write stacktrace to crashreport.log char dir[MAX_PATH]; GetCurrentDirectory(sizeof(dir) - 1, dir); std::string fileName = stdext::format("%s\\crashreport.log", dir); std::ofstream fout(fileName.c_str(), std::ios::out | std::ios::app); if(fout.is_open() && fout.good()) { fout << ss.str(); fout.close(); g_logger.info(stdext::format("Crash report saved to file %s", fileName)); } else g_logger.error("Failed to save crash report!"); // inform the user std::string msg = stdext::format( "The application has crashed.\n\n" "A crash report has been written to:\n" "%s", fileName.c_str()); MessageBox(NULL, msg.c_str(), "Application crashed", 0); // this seems to silently close the application //return EXCEPTION_EXECUTE_HANDLER; // this triggers the microsoft "application has crashed" error dialog return EXCEPTION_CONTINUE_SEARCH; }
const NAString StmtDDLDropExceptionTable::displayLabel1() const { return NAString ("Exception table name: ") + getExceptionName(); }
LONG __stdcall DCUnhandledExceptionFilter( LPEXCEPTION_POINTERS e ) { Lock l(cs); if(recursion++ > 30) exit(-1); #ifndef _DEBUG #if _MSC_VER == 1200 __pfnDliFailureHook = FailHook; #elif _MSC_VER == 1300 || _MSC_VER == 1310 || _MSC_VER == 1400 || _MSC_VER == 1500 || _MSC_VER == 1600 __pfnDliFailureHook2 = FailHook; #else #error Unknown Compiler version #endif // The release version loads the dll and pdb:s here... EXTENDEDTRACEINITIALIZE( Util::getPath(Util::PATH_RESOURCES).c_str() ); #endif if(firstException) { File::deleteFile(Util::getPath(Util::PATH_RESOURCES) + "exceptioninfo.txt"); firstException = false; } if(File::getSize(Util::getPath(Util::PATH_RESOURCES) + "AirDC.pdb") == -1) { // No debug symbols, we're not interested... ::MessageBox(WinUtil::mainWnd, _T("AirDC++ has crashed and you don't have AirDC.pdb file installed. Hence, I can't find out why it crashed, so don't report this as a bug unless you find a solution..."), _T("AirDC++ has crashed"), MB_OK); #ifndef _DEBUG exit(1); #else return EXCEPTION_CONTINUE_SEARCH; #endif } File f(Util::getPath(Util::PATH_RESOURCES) + "exceptioninfo.txt", File::WRITE, File::OPEN | File::CREATE); f.setEndPos(0); DWORD exceptionCode = e->ExceptionRecord->ExceptionCode ; string archStr = "x32"; #ifdef _WIN64 archStr = "x64"; #endif sprintf(buf, "Code: %x ( %s )\r\nVersion: %s %s\r\n", exceptionCode, getExceptionName(exceptionCode).c_str(), VERSIONSTRING, archStr); f.write(buf, strlen(buf)); #if defined(SVNVERSION) sprintf(buf, "SVN: %s\r\n", SVNVERSION); f.write(buf, strlen(buf)); #endif OSVERSIONINFOEX ver; WinUtil::getVersionInfo(ver); sprintf(buf, "Major: %d\r\nMinor: %d\r\nBuild: %d\r\nSP: %d\r\nType: %d\r\n", (DWORD)ver.dwMajorVersion, (DWORD)ver.dwMinorVersion, (DWORD)ver.dwBuildNumber, (DWORD)ver.wServicePackMajor, (DWORD)ver.wProductType); f.write(buf, strlen(buf)); time_t now; time(&now); strftime(buf, DEBUG_BUFSIZE, "Time: %Y-%m-%d %H:%M:%S\r\n", localtime(&now)); f.write(buf, strlen(buf)); f.write(LIT("TTH: ")); f.write(tth, strlen(tth)); f.write(LIT("\r\n")); f.write(LIT("\r\n")); STACKTRACE(f, e->ContextRecord); f.write(LIT("\r\n")); f.close(); if ((!SETTING(SOUND_EXC).empty()) && (!BOOLSETTING(SOUNDS_DISABLED))) PlaySound(Text::toT(SETTING(SOUND_EXC)).c_str(), NULL, SND_FILENAME | SND_ASYNC); NOTIFYICONDATA m_nid; m_nid.cbSize = sizeof(NOTIFYICONDATA); m_nid.hWnd = MainFrame::getMainFrame()->m_hWnd; m_nid.uID = 0; m_nid.uFlags = NIF_INFO; m_nid.uTimeout = 5000; m_nid.dwInfoFlags = NIIF_WARNING; _tcscpy(m_nid.szInfo, _T("exceptioninfo.txt was generated")); _tcscpy(m_nid.szInfoTitle, _T("AirDC++ has crashed")); Shell_NotifyIcon(NIM_MODIFY, &m_nid); if(MessageBox(WinUtil::mainWnd, _T("AirDC++ just encountered a fatal bug and should have written an exceptioninfo.txt the same directory as the executable. You can upload this file at http://www.airdcpp.net to help us find out what happened. Go there now?"), _T("AirDC++ Has Crashed"), MB_YESNO | MB_ICONERROR) == IDYES) { WinUtil::openLink(_T("http://crash.airdcpp.net")); } #ifndef _DEBUG EXTENDEDTRACEUNINITIALIZE(); exit(-1); #else return EXCEPTION_CONTINUE_SEARCH; #endif }
LONG __stdcall DCUnhandledExceptionFilter( LPEXCEPTION_POINTERS e ) { #ifdef __DEBUG MessageBox(NULL, _T("If you would like to debug DCUnhandledExceptionFilter - attach to this process now"), _T(APPNAME), MB_OK); #endif Lock l(cs); if(recursion++ > 30) exit(-1); #ifndef _DEBUG #if _MSC_VER == 1200 __pfnDliFailureHook = FailHook; #elif _MSC_VER == 1300 || _MSC_VER == 1310 || _MSC_VER == 1400 __pfnDliFailureHook2 = FailHook; #else #error Unknown Compiler version #endif // The release version loads the dll and pdb:s here... InitSymInfo(Text::toT(Util::getDataPath()).c_str()); #endif TCHAR pdbPath[MAX_PATH]; GetModuleFileName(NULL, pdbPath, sizeof(pdbPath)); TCHAR* dotPtr = _tcschr(pdbPath, '.'); if (dotPtr != NULL) { _tcscpy(dotPtr, _T(".pdb")); } if (GetFileAttributes(pdbPath) == INVALID_FILE_ATTRIBUTES) { // No debug symbols, we're not interested... ::MessageBox(WinUtil::mainWnd, _T(APPNAME) _T(" has crashed and you don't have .PDB file installed. Hence, I can't find out why it crashed, so don't report this as a bug unless you find a solution..."), _T(APPNAME) _T(" has crashed"), MB_OK); #ifndef _DEBUG exit(1); #else return EXCEPTION_CONTINUE_SEARCH; #endif } File f(Util::getConfigPath() + "exceptioninfo.txt", File::WRITE, File::OPEN | File::CREATE); f.setEndPos(0); char buf[DEBUG_BUFSIZE]; sprintf(buf, "Code: %x (%s)\r\n" "Version: %d (%s)\r\n", e->ExceptionRecord->ExceptionCode, getExceptionName(e->ExceptionRecord->ExceptionCode), BUILDID, Util::getCompileDate().c_str()); tstring exceptioninfo = Text::toT(buf); f.write(buf, strlen(buf)); OSVERSIONINFOEX ver; WinUtil::getVersionInfo(ver); const char *productType; if (ver.wProductType == VER_NT_DOMAIN_CONTROLLER) { productType = "domain controller"; } else if (ver.wProductType == VER_NT_SERVER) { productType = "server"; } else if (ver.wProductType == VER_NT_WORKSTATION) { productType = "workstation"; } else { productType = "unknown product type"; } sprintf(buf, "OS Version: %d.%d build %d service pack %d %s\r\n", (DWORD)ver.dwMajorVersion, (DWORD)ver.dwMinorVersion, (DWORD)ver.dwBuildNumber, (DWORD)ver.wServicePackMajor, productType); exceptioninfo += Text::toT(buf); f.write(buf, strlen(buf)); time_t now; time(&now); strftime(buf, DEBUG_BUFSIZE, "Time: %Y-%m-%d %H:%M:%S\r\n", localtime(&now)); exceptioninfo += Text::toT(buf); f.write(buf, strlen(buf)); #if 0 WinUtil::exceptioninfo += LIT(_T("TTH: ")); WinUtil::exceptioninfo += Text::toT(tth); WinUtil::exceptioninfo += LIT(_T("\r\n\r\n")); #endif f.write(LIT("\r\n")); exceptioninfo += _T("\r\n"); // !SMT! sprintf(buf, "exception code %08X at eip=%08X, nested: %08X\r\n" "eax=%08X ebx=%08X ecx=%08X edx=%08X\r\n" "esi=%08X edi=%08X ebp=%08X esp=%08X\r\n", e->ExceptionRecord->ExceptionCode, e->ExceptionRecord->ExceptionAddress, e->ExceptionRecord->ExceptionRecord, e->ContextRecord->Eax, e->ContextRecord->Ebx, e->ContextRecord->Ecx, e->ContextRecord->Edx, e->ContextRecord->Esi, e->ContextRecord->Edi, e->ContextRecord->Ebp, e->ContextRecord->Esp); exceptioninfo += Text::toT(buf); f.write(buf, strlen(buf)); const tstring trace = StackTrace(GetCurrentThread(), e->ContextRecord); f.write(LIT("\r\n")); f.write(Text::fromT(trace)); f.close(); #if 0 memcpy(&CurrExceptionRecord, e->ExceptionRecord, sizeof(EXCEPTION_RECORD)); memcpy(&CurrContext, e->ContextRecord, sizeof(CONTEXT)); #endif exceptioninfo += _T("\r\n"); exceptioninfo += trace; Sounds::PlaySound(SettingsManager::SOUND_EXC); if (WinUtil::mainWnd != NULL) { NOTIFYICONDATA m_nid = {0}; m_nid.cbSize = sizeof(NOTIFYICONDATA); m_nid.hWnd = WinUtil::mainWnd; m_nid.uID = 0; m_nid.uFlags = NIF_INFO; m_nid.uTimeout = 5000; m_nid.dwInfoFlags = NIIF_WARNING; _tcsncpy(m_nid.szInfo, _T("exceptioninfo.txt was generated"), 255); _tcsncpy(m_nid.szInfoTitle, _T(APPNAME) _T(" has crashed"), 63); Shell_NotifyIcon(NIM_MODIFY, &m_nid); } CExceptionDlg dlg(exceptioninfo); int iLastExceptionDlgResult = dlg.DoModal(WinUtil::mainWnd); if (iLastExceptionDlgResult == IDCANCEL) { ExitProcess(1); } #ifndef _DEBUG UninitSymInfo(); return EXCEPTION_CONTINUE_EXECUTION; #else return EXCEPTION_CONTINUE_SEARCH; #endif }