在程序崩溃前纪录callback信息

首先在程序进入点前加上如下代码:
#include <DbgHelp.h>

#include <vector>
#include <string>
#pragma comment( lib,"dbghelp.lib" )
using namespace std;


const int MAX_ADDRESS_LENGTH = 32;
const int MAX_NAME_LENGTH    = 1024;


struct CrashInfo
{
	CHAR ErrorCode[MAX_ADDRESS_LENGTH];
	CHAR Address[MAX_ADDRESS_LENGTH];
	CHAR Flags[MAX_ADDRESS_LENGTH];
};


struct CallStackInfo
{
	CHAR ModuleName[MAX_NAME_LENGTH];
	CHAR MethodName[MAX_NAME_LENGTH];
	CHAR FileName[MAX_NAME_LENGTH];
	CHAR LineNumber[MAX_NAME_LENGTH];
};
void SaftStrCpy( char* szDast,size_t nMaxDestSize,const char* szSrc )
{
	if ( nMaxDestSize <= 0 )
	{
		return;
	}


	if ( strlen( szSrc ) < nMaxDestSize )
	{
		strcpy( szDast,szSrc );
	}
	else
	{
		strncpy( szDast,szSrc,nMaxDestSize );
		szDast[nMaxDestSize-1] = '\0';
	}
}
CrashInfo GetCrashInfo( const EXCEPTION_RECORD* pRecord )
{
	CrashInfo crashInfo;
	SaftStrCpy( crashInfo.Address,MAX_ADDRESS_LENGTH,"N/A" );
	SaftStrCpy( crashInfo.ErrorCode,MAX_ADDRESS_LENGTH,"N/A" );
	SaftStrCpy( crashInfo.Flags,MAX_ADDRESS_LENGTH,"N/A" );


	sprintf( crashInfo.Address, "%08X", pRecord->ExceptionAddress);  
	sprintf( crashInfo.ErrorCode, "%08X", pRecord->ExceptionCode);  
	sprintf( crashInfo.Flags, "%08X", pRecord->ExceptionFlags);  
	return crashInfo;  
}
// 得到CallStack信息  
//  
vector<CallStackInfo> GetCallStack(const CONTEXT *pContext)  
{  
	HANDLE hProcess = GetCurrentProcess();  


	SymInitialize(hProcess, NULL, TRUE);  


	vector<CallStackInfo> arrCallStackInfo;  


	CONTEXT c = *pContext;  


	STACKFRAME64 sf;  
	memset(&sf, 0, sizeof(STACKFRAME64));  
	DWORD dwImageType = IMAGE_FILE_MACHINE_I386;  


	// 不同的CPU类型,具体信息可查询MSDN  
	//  
#ifdef _M_IX86  
	sf.AddrPC.Offset = c.Eip;  
	sf.AddrPC.Mode = AddrModeFlat;  
	sf.AddrStack.Offset = c.Esp;  
	sf.AddrStack.Mode = AddrModeFlat;  
	sf.AddrFrame.Offset = c.Ebp;  
	sf.AddrFrame.Mode = AddrModeFlat;  
#elif _M_X64  
	dwImageType = IMAGE_FILE_MACHINE_AMD64;  
	sf.AddrPC.Offset = c.Rip;  
	sf.AddrPC.Mode = AddrModeFlat;  
	sf.AddrFrame.Offset = c.Rsp;  
	sf.AddrFrame.Mode = AddrModeFlat;  
	sf.AddrStack.Offset = c.Rsp;  
	sf.AddrStack.Mode = AddrModeFlat;  
#elif _M_IA64  
	dwImageType = IMAGE_FILE_MACHINE_IA64;  
	sf.AddrPC.Offset = c.StIIP;  
	sf.AddrPC.Mode = AddrModeFlat;  
	sf.AddrFrame.Offset = c.IntSp;  
	sf.AddrFrame.Mode = AddrModeFlat;  
	sf.AddrBStore.Offset = c.RsBSP;  
	sf.AddrBStore.Mode = AddrModeFlat;  
	sf.AddrStack.Offset = c.IntSp;  
	sf.AddrStack.Mode = AddrModeFlat;  
#else  
#error "Platform not supported!"  
#endif  


	HANDLE hThread = GetCurrentThread();  


	while (true)  
	{  
		// 该函数是实现这个功能的最重要的一个函数  
		// 函数的用法以及参数和返回值的具体解释可以查询MSDN  
		//  
		if (!StackWalk64(dwImageType, hProcess, hThread, &sf, &c, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))  
		{  
			break;  
		}  


		if (sf.AddrFrame.Offset == 0)  
		{  
			break;  
		}  


		CallStackInfo callstackinfo;  
		SaftStrCpy(callstackinfo.MethodName, MAX_NAME_LENGTH, "N/A");  
		SaftStrCpy(callstackinfo.FileName, MAX_NAME_LENGTH, "N/A");  
		SaftStrCpy(callstackinfo.ModuleName, MAX_NAME_LENGTH, "N/A");  
		SaftStrCpy(callstackinfo.LineNumber, MAX_NAME_LENGTH, "N/A");  


		BYTE symbolBuffer[sizeof(IMAGEHLP_SYMBOL64) + MAX_NAME_LENGTH];  
		IMAGEHLP_SYMBOL64 *pSymbol = (IMAGEHLP_SYMBOL64*)symbolBuffer;  
		memset(pSymbol, 0, sizeof(IMAGEHLP_SYMBOL64) + MAX_NAME_LENGTH);  


		pSymbol->SizeOfStruct = sizeof(symbolBuffer);  
		pSymbol->MaxNameLength = MAX_NAME_LENGTH;  


		DWORD symDisplacement = 0;  


		// 得到函数名  
		//  
		if (SymGetSymFromAddr64(hProcess, sf.AddrPC.Offset, NULL, pSymbol))  
		{  
			SaftStrCpy(callstackinfo.MethodName, MAX_NAME_LENGTH, pSymbol->Name);  
		}  


		IMAGEHLP_LINE64 lineInfo;  
		memset(&lineInfo, 0, sizeof(IMAGEHLP_LINE64));  


		lineInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64);  


		DWORD dwLineDisplacement;  


		// 得到文件名和所在的代码行  
		//  
		if (SymGetLineFromAddr64(hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &lineInfo))  
		{  
			SaftStrCpy(callstackinfo.FileName, MAX_NAME_LENGTH, lineInfo.FileName);  
			sprintf(callstackinfo.LineNumber, "%d", lineInfo.LineNumber);  
		}  


		IMAGEHLP_MODULE64 moduleInfo;  
		memset(&moduleInfo, 0, sizeof(IMAGEHLP_MODULE64));  


		moduleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);  


		// 得到模块名  
		//  
		if (SymGetModuleInfo64(hProcess, sf.AddrPC.Offset, &moduleInfo))  
		{  
			SaftStrCpy(callstackinfo.ModuleName, MAX_NAME_LENGTH, moduleInfo.ModuleName);  
		}  


		arrCallStackInfo.push_back(callstackinfo);  
	}  


	SymCleanup(hProcess);  


	return arrCallStackInfo;  
}
// 处理Unhandled Exception的回调函数  
//  
LONG ApplicationCrashHandler(EXCEPTION_POINTERS *pException)  
{     
	// 确保有足够的栈空间  
	//  
#ifdef _M_IX86  
	if (pException->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW)  
	{  
		static char TempStack[1024 * 128];  
		__asm mov eax,offset TempStack[1024 * 128];  
		__asm mov esp,eax;  
	}  
#endif    


	CrashInfo crashinfo = GetCrashInfo(pException->ExceptionRecord);  


	// 输出Crash信息  
	// 
	CFile file( "a.txt",CFile::modeReadWrite|CFile::modeCreate );


	CString strFormat;
	strFormat.Format( "ErrorCode: %s\r\nAddress: %s\r\nFlags: %s\r\n",crashinfo.ErrorCode,crashinfo.Address,crashinfo.Flags );
// 	strFormat.Format( "ErrorCode: %s",crashinfo.ErrorCode );
// 	strFormat.Format( "\r\n");
	file.Write( strFormat.GetBuffer( 0 ),strFormat.GetLength() );


	vector<CallStackInfo> arrCallStackInfo = GetCallStack(pException->ContextRecord);  


	// 输出CallStack  
	//  
	file.Write( _T("调用堆栈:\r\n"),sizeof( "调用堆栈:\r\n" )  );
	for (vector<CallStackInfo>::iterator i = arrCallStackInfo.begin(); i != arrCallStackInfo.end(); ++i)  
	{  
		CallStackInfo callstackinfo = (*i);  


		strFormat.Format( "%s() : [%s] (File: %s @Line %s)\r\n",callstackinfo.MethodName,callstackinfo.ModuleName, callstackinfo.FileName,callstackinfo.LineNumber );
		file.Write( strFormat.GetBuffer( 0 ),strFormat.GetLength() );
	}  


	// 这里弹出一个错误对话框并退出程序  
	//  
	FatalAppExit(-1,  "程序出现了异常,请重新启动程序..." );  


	return EXCEPTION_EXECUTE_HANDLER;  
}
然后再真正执行的地方使用如下函数即可:

SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)ApplicationCrashHandler); 

这样,程序在core掉的时候会把core的那个点的堆栈信息打印出来.存到a.txt文件下.

你可能感兴趣的:(在程序崩溃前纪录callback信息)