您的位置:首页 > 其它

Vs中使用dump文件调试程序崩溃

2013-04-08 09:13 471 查看
Vs中使用dump文件调试程序崩溃



1. Dump文件的生成

在vs中要生成dump文件需要加入一些代码,这些代码在debug或release代码下均有效果。

首先定义异常类:

class CSE_Exception {

public:

CSE_Exception() : m_nSENumber(0) {}



unsigned int m_nSENumber;

EXCEPTION_RECORD m_SERecord;

CONTEXT m_SEContext;



// set SE handler, for CSE_Exception. 应该为每个线程调用

static void InitSEException();

static long _DbgDumpError(struct _EXCEPTION_POINTERS *excpInfo, LPCTSTR szPrex);

static void _DumpSystemInfo(LPTSTR szDump, int nSize);

static void _DumpCallStack();

private:

static void trans_func( unsigned int uSENum, _EXCEPTION_POINTERS* pExp );

};



其实现为:

#include "DbgHelp.h"

typedef BOOL (WINAPI* MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,

CONST
PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,

CONST
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,

CONST
PMINIDUMP_CALLBACK_INFORMATION CallbackParam);



long CSE_Exception::_DbgDumpError(struct _EXCEPTION_POINTERS *excpInfo, LPCTSTR szPrex )

{



LONG retval = EXCEPTION_CONTINUE_SEARCH;



HMODULE hDll = ::LoadLibrary(_T("DBGHELP.DLL"));

LPCTSTR szResult = NULL;

MINIDUMPWRITEDUMP pDump = NULL;



if (hDll)

pDump = (MINIDUMPWRITEDUMP)::GetProcAddress(hDll,"MiniDumpWriteDump");



if (pDump)

{

TCHAR szDumpPath [_MAX_PATH] = {0};

TCHAR szDumpFile [_MAX_PATH] = {0};

GetModuleFileName(NULL, szDumpPath, _MAX_PATH);

_tcsrchr(szDumpPath, _T('\\'))[1] = 0;

_tcscat(szDumpPath, _T("..\\logs\"));



time_t timeCurrent = time(0);

struct tm* tmc = localtime(&timeCurrent);

if ( tmc )

_stprintf(szDumpFile, _T("%s%d_%d_%d_%d_%d.dmp"), szPrex, tmc->tm_mon+1, tmc->tm_mday, tmc->tm_hour, tmc->tm_min, tmc->tm_sec);

else

_tcscpy(szDumpFile, _T("error.dmp"));

_tcscat(szDumpPath, szDumpFile);



// create the file

HANDLE hFile = ::CreateFile( szDumpPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,

FILE_ATTRIBUTE_NORMAL, NULL );



if (hFile!=INVALID_HANDLE_VALUE)

{

if (excpInfo == NULL) //如果没有传入异常, 比如是在程序里面调用的, 生成一个异常

{

// Generate exception to get proper context in dump



DWORD dwSize = 0;

char *sz = "_EXCEPTION_POINTERS is null";

::WriteFile(hFile, sz, strlen(sz), &dwSize, NULL);

}

else

{

MINIDUMP_EXCEPTION_INFORMATION eInfo;

eInfo.ThreadId = GetCurrentThreadId(); //把需要的信息添进去

eInfo.ExceptionPointers = excpInfo;

eInfo.ClientPointers = FALSE;



// Dump的类型是小型的, 节省空间. 可以参考MSDN生成更详细的Dump.

pDump(

GetCurrentProcess(),

GetCurrentProcessId(),

hFile,

MiniDumpNormal,

excpInfo ? &eInfo : NULL,

NULL,

NULL);

}

::CloseHandle(hFile);



}

}

if( hDll )

::FreeLibrary(hDll);



return retval;

}





void CSE_Exception::InitSEException()

{

_set_se_translator( CSE_Exception::trans_func );

}



void CSE_Exception::_DumpCallStack()

{

__try

{

__try

{

RaiseException(1, 0, 0, NULL);

}

__finally

{

}

}

__except(_DbgDumpError(GetExceptionInformation(), _T("T")),

EXCEPTION_CONTINUE_EXECUTION)

{

}

}



void CSE_Exception::trans_func( unsigned int uSENum, _EXCEPTION_POINTERS* pExp )

{

#define SE_BUF_SIZE 250

TCHAR pszBuf[SE_BUF_SIZE+2];



_DbgDumpError(pExp, _T("e"));

switch(uSENum)

{

case EXCEPTION_ACCESS_VIOLATION:

_sntprintf(pszBuf, SE_BUF_SIZE, _T("Access Violation: IP: 0x%08X %s Address: 0x%08X"),

pExp->ExceptionRecord->ExceptionAddress, pExp->ExceptionRecord->ExceptionInformation[0]?_T("Write"):_T("Read"), pExp->ExceptionRecord->ExceptionInformation[1]);

break;

case EXCEPTION_INT_DIVIDE_BY_ZERO:

_sntprintf(pszBuf, SE_BUF_SIZE, _T("INT_DIVIDE_BY_ZERO"));

break;

case EXCEPTION_FLT_DIVIDE_BY_ZERO:

_sntprintf(pszBuf, SE_BUF_SIZE, _T("FLT_DIVIDE_BY_ZERO"));

break;

case EXCEPTION_ILLEGAL_INSTRUCTION:

_sntprintf(pszBuf, SE_BUF_SIZE, _T("ILLEGAL_INSTRUCTION"));

break;

case EXCEPTION_PRIV_INSTRUCTION:

_sntprintf(pszBuf, SE_BUF_SIZE, _T("EXCEPTION_PRIV_INSTRUCTION"));

break;

case EXCEPTION_STACK_OVERFLOW:

_sntprintf(pszBuf, SE_BUF_SIZE, _T("EXCEPTION_STACK_OVERFLOW"));

break;

default:

_sntprintf(pszBuf, SE_BUF_SIZE, _T("Unknown SE_exception: %08X"), uSENum);

break;

}



CSE_Exception e(pszBuf);

e.m_nSENumber = uSENum;

e.m_SERecord = *(pExp->ExceptionRecord);

e.m_SEContext = *(pExp->ContextRecord);



throw e;

}



然后在程序的InitInstance中加入代码如下:

LONG WINAPI DbgUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)

{

CSE_Exception::_DbgDumpError(pExceptionInfo, _T("E"));

return EXCEPTION_CONTINUE_SEARCH; // 程序停止运行

}

BOOL CDCPWorkerApp::InitInstance()

{

//EHA

CSE_Exception::InitSEException();

//捕获未处理的异常

SetUnhandledExceptionFilter(DbgUnhandledExceptionFilter);

}



这样就可以了。



还有在 编译的时候,还要把.pdb文件放好,放在运行的目录下,则要一致对应。



2. 使用dump文件进行调试

首先用vs2008将它打开,点调试。

下面就下载符号表才行。

点 工具à调试à符号

再点增加, 在符号文件.pdb路径下加入:: http://msdl.microsoft.com/download/symbols

在下面的文本框中加入一个本地存放pdb解析文件的路径如:c:\Symbols



上面的下载过程很慢,如果下载完成,则会断下,这时,在 调试中打开调用栈,打开线程,

一个一个线程进行分析,看程序是core在哪个线程中的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: