void ffl_dump_report::generate_exception( ffl_text_file * file, ffl_dump_param_t * param ) { if( file != NULL && param != NULL ) { PEXCEPTION_RECORD exception_record = param->exception_ptr->ExceptionRecord; ffl_dump_print( file, FFL_T( "Exception code : %08X %s\r\n" ), exception_record->ExceptionCode, ffl_get_exception_string( exception_record->ExceptionCode ) ); ffl_tchar_t faulting_module[MAX_PATH] = { 0, }; DWORD section = 0; DWORD offset = 0; get_logical_address( exception_record->ExceptionAddress, faulting_module, FFL_COUNTOF(faulting_module), §ion, &offset ); ffl_dump_print( file, FFL_T( "Fault address :%08X %02X:%08X %s\r\n" ), exception_record->ExceptionAddress, section, offset, faulting_module ); PCONTEXT context = param->exception_ptr->ContextRecord; // Show the registers #ifdef _M_IX86 // Intel Only! ffl_dump_print( file, FFL_T( "\r\nRegisters:\r\n" ) ); ffl_dump_print( file, FFL_T( "EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n" ), context->Eax, context->Ebx, context->Ecx, context->Edx, context->Esi, context->Edi ); ffl_dump_print( file, FFL_T( "CS:EIP:%04X:%08X\r\n" ), context->SegCs, context->Eip ); ffl_dump_print( file, FFL_T( "SS:ESP:%04X:%08X EBP:%08X\r\n" ), context->SegSs, context->Esp, context->Ebp ); ffl_dump_print( file, FFL_T( "DS:%04X ES:%04X FS:%04X GS:%04X\r\n" ), context->SegDs, context->SegEs, context->SegFs, context->SegGs ); ffl_dump_print( file, FFL_T( "Flags:%08X\r\n" ), context->EFlags ); #endif //_M_IX86 static const ffl_tchar_t dll_name[] = FFL_T( "imagehlp.dll" ); HMODULE imagehlp = ::LoadLibrary( dll_name ); if( imagehlp != NULL ) { if( inti_imagehlp_func( imagehlp ) == true ) { imagehlp_stack_walk( file, context, param->dump_thread ); sym_cleanup_( ::GetCurrentProcess() ); } ::FreeLibrary( imagehlp ); imagehlp = NULL; } else { #ifdef _M_IX86 // Intel Only! // Walk the stack using x86 specific code intel_stack_walk( file, context ); #endif } ffl_dump_print( file, FFL_T( "\r\n" ) ); } return; }
void ffl_dump_report::imagehlp_stack_walk( ffl_text_file * file, PCONTEXT context, HANDLE dump_thread ) { ffl_dump_print( file, FFL_T( "\r\nCall stack:\r\n" ) ); ffl_dump_print( file, FFL_T( "Address Frame\r\n" ) ); STACKFRAME stack_frame; ::memset( &stack_frame, 0, sizeof( stack_frame ) ); stack_frame.AddrPC.Offset = context->Eip; stack_frame.AddrPC.Mode = AddrModeFlat; stack_frame.AddrStack.Offset = context->Esp; stack_frame.AddrStack.Mode = AddrModeFlat; stack_frame.AddrFrame.Offset = context->Ebp; stack_frame.AddrFrame.Mode = AddrModeFlat; #pragma warning( push ) #pragma warning( disable : 4127 ) // 조건식이 상수입니다. while( true ) #pragma warning( pop ) { if( stack_walk_( IMAGE_FILE_MACHINE_I386, ::GetCurrentProcess(), dump_thread, &stack_frame, context, 0, sym_function_table_access_, sym_get_module_base_, 0 ) == FALSE ) { break; } if( 0 == stack_frame.AddrFrame.Offset ) { break; } ffl_dump_print( file, FFL_T( "%08X %08X " ), stack_frame.AddrPC.Offset, stack_frame.AddrFrame.Offset ); BYTE symbol_buffer[ sizeof( IMAGEHLP_SYMBOL ) + 512 ] = { 0, }; PIMAGEHLP_SYMBOL symbol = reinterpret_cast< PIMAGEHLP_SYMBOL >( symbol_buffer ); symbol->SizeOfStruct = sizeof( symbol_buffer ); symbol->MaxNameLength = 512; DWORD sym_displacement = 0; if( sym_get_sym_from_addr_( ::GetCurrentProcess(), stack_frame.AddrPC.Offset, &sym_displacement, symbol ) == TRUE ) { ffl_dump_print( file, FFL_T( "%hs+%X\r\n" ), symbol->Name, sym_displacement ); } else { ffl_tchar_t module[MAX_PATH] = { 0, }; DWORD section = 0, offset = 0; get_logical_address( reinterpret_cast< void * >( stack_frame.AddrPC.Offset ), module, FFL_COUNTOF( module ), §ion, &offset ); ffl_dump_print( file, FFL_T( "%04X:%08X %s\r\n" ), section, offset, module ); } } }
void stack_walk(CString& strStack, PCONTEXT p_context) { CONTEXT * pContext = p_context; HANDLE hCurrentProcess = ::GetCurrentProcess(); HANDLE hCurrentThread = ::GetCurrentThread(); STACKFRAME64 sStackFrame; memset(&sStackFrame,0,sizeof(STACKFRAME64)); sStackFrame.AddrPC.Offset = pContext->Eip; sStackFrame.AddrPC.Mode = AddrModeFlat; sStackFrame.AddrStack.Offset= pContext->Esp; sStackFrame.AddrStack.Mode = AddrModeFlat; sStackFrame.AddrFrame.Offset= pContext->Ebp; sStackFrame.AddrFrame.Mode = AddrModeFlat; USES_CONVERSION; //TCHAR atszCallbackBuffer[1024]; //DWORD dwLen = 0; SymInitialize(GetCurrentProcess(),NULL,TRUE); while(StackWalk64(IMAGE_FILE_MACHINE_I386,hCurrentProcess,hCurrentThread,&sStackFrame,pContext,0,0,0,0)) { if( sStackFrame.AddrFrame.Offset == 0 ) { break; } strStack.Format(L"%s[%08X]", strStack,sStackFrame.AddrPC.Offset); BYTE sym_buffer[sizeof(IMAGEHLP_SYMBOL) + 512]; PIMAGEHLP_SYMBOL p_symbol = (PIMAGEHLP_SYMBOL)sym_buffer; p_symbol->SizeOfStruct = sizeof(sym_buffer); p_symbol->MaxNameLength = 512; // Displacement of the input address, relative to the start of the symbol DWORD sym_displacement = 0; if (!SymGetSymFromAddr(::GetCurrentProcess(), sStackFrame.AddrPC.Offset, &sym_displacement, p_symbol)) { p_symbol->Name[0] = 0; } TCHAR sz_module[MAX_PATH] = {0}; UINT_PTR section = 0, offset = 0; get_logical_address((PVOID)(UINT_PTR)sStackFrame.AddrPC.Offset, sz_module, sizeof(sz_module)); strStack.Format(L"%s\t%s\t%s\r\n",strStack,A2T(p_symbol->Name),sz_module); } SymCleanup(GetCurrentProcess()); }
void ffl_dump_report::intel_stack_walk( ffl_text_file * file, PCONTEXT context ) { ffl_dump_print( file, FFL_T( "\r\nCall stack:\r\n" ) ); ffl_dump_print( file, FFL_T( "Address Frame Logical addr Module\r\n" ) ); DWORD pc = context->Eip; PDWORD frame = NULL, prev_frame = NULL; frame = reinterpret_cast< PDWORD >( context->Ebp ); do { ffl_tchar_t module[MAX_PATH] = { 0, }; DWORD section = 0, offset = 0; get_logical_address( reinterpret_cast< void *>( pc ), module, FFL_COUNTOF( module ), §ion, &offset ); ffl_dump_print( file, FFL_T( "%08X %08X %04X:%08X %s\r\n" ), pc, frame, section, offset, module ); pc = frame[1]; prev_frame = frame; frame = reinterpret_cast< PDWORD >( frame[0] ); if( reinterpret_cast< DWORD >( frame ) & 3 ) { break; } if( frame <= prev_frame ) { break; } if( ::IsBadWritePtr( frame, sizeof( void * )*2 ) ) { break; } #pragma warning( push ) #pragma warning( disable : 4127 ) // 조건식이 상수입니다. } while( true ); #pragma warning( pop ) }
////////////////////////////////////////////////////////////////////////// //截获异常信息,并生成自定义的异常报告和弹出窗口 ////////////////////////////////////////////////////////////////////////// LONG WINAPI CustomExceptionFun(struct _EXCEPTION_POINTERS* ExceptionInfo) { SetUnhandledExceptionFilter(NULL); CString logPath,folderPath,errDetail; CString tips; CString strDes,strStack; CTime timer; CStdioFile stFile; TCHAR sz_module[MAX_PATH] = {0}; UINT_PTR section = 0, offset = 0; strDes.Format(L"%s\r\n%s",L"我们很抱歉地通知您,程序遇到错误,不得不终止。",L"以下是该错误的详细信息:"); //werDlg.SetDes(strDes); TCHAR szFileName[MAX_PATH]; ::GetModuleFileName(NULL, szFileName, MAX_PATH); *(_tcsrchr(szFileName, _T('\\')) + 1) = 0; timer = CTime::GetCurrentTime(); folderPath.Format(L"%slog\\",szFileName); logPath.Format(L"%slog\\dump_%d_%d_%d_%d.txt", szFileName, timer.GetYear(), timer.GetMonth(), timer.GetDay(), timer.GetHour()); tips.Format(L"%s\r\n%s",L"以上错误信息保存在:",logPath); g_strErrLogPath = logPath; //生成错误地址 get_logical_address(ExceptionInfo->ExceptionRecord->ExceptionAddress, sz_module, sizeof(sz_module)); //生成堆栈信息 stack_walk(strStack,ExceptionInfo->ContextRecord); //生成寄存器信息 #ifdef _M_IX86 // Intel Only! CString strReg; strReg = L"\nRegisters:\r\n"; strReg.Format(L"%sEAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n", strReg,ExceptionInfo->ContextRecord->Eax, ExceptionInfo->ContextRecord->Ebx, ExceptionInfo->ContextRecord->Ecx, ExceptionInfo->ContextRecord->Edx, ExceptionInfo->ContextRecord->Esi, ExceptionInfo->ContextRecord->Edi ); strReg.Format(L"%sCS:EIP: %04X:%08X\r\n",strReg, ExceptionInfo->ContextRecord->SegCs, ExceptionInfo->ContextRecord->Eip); strReg.Format(L"%sSS:ESP: %04X:%08X \r\nEBP:%08X\r\n",strReg, ExceptionInfo->ContextRecord->SegSs, ExceptionInfo->ContextRecord->Esp, ExceptionInfo->ContextRecord->Ebp ); strReg.Format(L"%sDS:%04X ES:%04X FS:%04X GS:%04X\r\n", strReg,ExceptionInfo->ContextRecord->SegDs, ExceptionInfo->ContextRecord->SegEs, ExceptionInfo->ContextRecord->SegFs, ExceptionInfo->ContextRecord->SegGs ); strReg.Format(L"%sFlags:%08X\r\n",strReg, ExceptionInfo->ContextRecord->EFlags); #endif //_M_IX86 //生成错误详细信息 errDetail.Format(L"Error Code:%x\r\n%s\r\nAddress:%x\r\n%s\r\n\r\n%s\r\n%s", ExceptionInfo->ExceptionRecord->ExceptionCode, get_exception_string(ExceptionInfo->ExceptionRecord->ExceptionCode), ExceptionInfo->ExceptionRecord->ExceptionAddress, sz_module, strReg, strStack); g_strErrDetail = errDetail; //写日志 CFileFind fileFinder; if (!fileFinder.FindFile(folderPath)) { if (::CreateDirectory(folderPath,NULL) < 0) return EXCEPTION_EXECUTE_HANDLER; } if (stFile.Open(logPath,CFile::modeCreate | CFile::modeNoTruncate | CFile::modeReadWrite | CFile::typeBinary)) { stFile.SeekToEnd(); stFile.Write("\377\376", 2); stFile.WriteString(errDetail); stFile.Close(); } //werDlg.DoModal(); CreateWerWindow(logPath,errDetail); return EXCEPTION_EXECUTE_HANDLER; }