如何在崩溃的时候得到完整的栈信息

shuice 2009-07-11 10:59:01
加精
我用StackWalk函数在程序崩溃的时候得到栈信息,在debug版本下面还好,release版本下面只能得到一部分,请问怎么解决呢
debug版本看起来像这个样子
-MyExe.exe 0x0400015 + 0x0C
-MFC80d.dll 0x0700152 + 0x120
而release版本没有MFC80.dll这一行

另外kernel32.dll里面的函数调用也没有得到,我看迅雷,qq都能得到kernel32.dll里面的栈
谢谢
...全文
2734 42 打赏 收藏 转发到动态 举报
写回复
用AI写文章
42 条回复
切换为时间正序
请发表友善的回复…
发表回复
sjdev 2010-03-01
  • 打赏
  • 举报
回复
大家在比着贴代码啊,设置顶级异常过滤,然后转储不就完事了吗?
ecswm 2010-03-01
  • 打赏
  • 举报
回复
mark下,多长才够长??
qrlvls 2010-03-01
  • 打赏
  • 举报
回复
你的release没有生成相应的pdb文件吧,在工程项目中打开这一项应该就好了
zottff 2010-02-23
  • 打赏
  • 举报
回复
关注 学习 收藏...........
哈利路亚1874 2010-02-23
  • 打赏
  • 举报
回复
这个还是顶一下先,收藏
周江涛 2010-02-05
  • 打赏
  • 举报
回复
http://topic.csdn.net/t/20060120/09/4526635.html
周江涛 2010-02-05
  • 打赏
  • 举报
回复
好贴啊,mark 一下
周成风 2009-07-28
  • 打赏
  • 举报
回复
1、内存管理是和异常是没有什么关系,但new一个对象在后面再delete,中间异常了就delete不了了,一般都采用类似智能指针的办法防止内存泄漏,但指针智能就是利用了C++对象的析构机制。

2、__try __except 是针对当前域的,而SetUnhandledExceptionFilter是针对所有未处理的异常,其实并不冲突,不在__try块中的代码发生异常也可以被SetUnhandledExceptionFilter捕获。至于您所说的有情况无法捕获,的确存在。。我也不知道具体原因。

3、如果不是为了设置顶层的异常处理,类似SetUnhandledExceptionFilter函数做的工作。在C++中完全可以利用try..catch..代替__try __except 。
rendao0563 2009-07-28
  • 打赏
  • 举报
回复
[Quote=引用 27 楼 alicehyxx 的回复:]
引用 24 楼 rendao0563 的回复:
这都属于小技巧。

这样的确可以解决编译的问题,但我提出两点:
1、既然可能发生异常,而new了一个对象,很可能导致内存泄漏。

2、__try  __except 捕获的异常只是当前线程的,在__try块中创建线程并触发异常,是捕获不到的。
 
函数SetUnhandledExceptionFilter设置的异常处理函数,可以捕获由设置线程创建的所有线程的异常。
如下代码异常未捕获。

[/Quote]

1. 内存管理应该是用户自己管理的。程序退出了。内存就不存在泄漏。内存管理和异常处理应该没什么关系的。

2. __try __except 捕获的异常是针对当前作用域。跟线程没关系。新启的线程没加__try。

3. 可以用SetUnhandledExceptionFilter。现在开发基本上都是模块化,不是很提倡跨线程处理别人的异常。另:使用的时候感觉这个不是很稳定。90%以上情况都正常。极少数情况无法捕获。这让人很尴尬。因为不是必现,具体原因没排查出来。如果有知道原因的,麻烦告诉我一下。
stivenjia 2009-07-28
  • 打赏
  • 举报
回复

#if !defined(__JADE_EXCEPTION_H_)
#define __JADE_EXCEPTION_H_

class CExceptionByJade
{
public:
/*****************************************************************************\
函数名称:CExceptionByJade
函数功能:异常类型对象构造函数
参数:
input:
DWORD dwCode 异常信息代号
std::string szFun 异常函数名称
LPEXCEPTION_POINTERS lpException 异常信息结构
返回值:

异常类型:

\*****************************************************************************/
CExceptionByJade(DWORD dwCode,std::string szFun,LPEXCEPTION_POINTERS lpException);
/*****************************************************************************\
函数名称:CExceptionByJade
函数功能:异常类型对象构造函数
参数:
input:
DWORD dwCode 异常信息代号
std::string szFun 异常函数名称
CComBSTR cError 错误信息描述串
返回值:

异常类型:

\*****************************************************************************/
CExceptionByJade(DWORD dwCode,std::string szFun,CComBSTR cError);
/*****************************************************************************\
函数名称:CExceptionByJade
函数功能:异常类型对象构造函数
参数:
input:
std::string szFun 异常函数名称
返回值:

异常类型:

\*****************************************************************************/
CExceptionByJade(std::string szFun);
CExceptionByJade(DWORD dwCode,std::string szFun);
CExceptionByJade(void);
~CExceptionByJade(void);
public:
/*****************************************************************************\
函数名称:DumpFile
函数功能:将异常环境最小调试信息记录文件
参数:
input:
LPCTSTR lpFile 生成的文件完全路径
BOOL bExcept 环境调试信息是否包含异常信息结构
DWORD dwOption Dump选项该参数保留
返回值:
0 —— 正常值
非0 —— 错误代号
\*****************************************************************************/
DWORD DumpFile(LPCTSTR lpFile,BOOL bExcept,DWORD dwOption = 0);
/*****************************************************************************\
函数名称:FormatMsg
函数功能:查询错误代号在该系统下的信息描述
参数:
input:
USHORT usPrimaryLang 主要语言类型代号
USHORT usSubLange 语言种类描述
output:
std::wstring &szMsg 错误代号在该系统下的字符描述
返回值:
0 —— 正常值
非0 —— 错误代号
\*****************************************************************************/
DWORD FormatMsg(std::wstring &szMsg,USHORT usPrimaryLang,USHORT usSubLang);
/*****************************************************************************\
函数名称:ErrorCode
函数功能:得到错误代号
参数:
input:

output:

返回值:
错误代号
\*****************************************************************************/
DWORD ErrorCode(void);
/*****************************************************************************\
函数名称:GetRecord
函数功能:得到异常记录
参数:
input:
EXCEPTION_RECORD *lpRecord 异常记录指针
DWORD dwLen lpRecord长度
output:

返回值:
0 —— 正常值
非0 —— 错误代号
\*****************************************************************************/
DWORD GetRecord(EXCEPTION_RECORD *lpRecord,DWORD dwLen);
/*****************************************************************************\
函数名称:GetFunName
函数功能:异常函数描述
参数:
input:

output:
std::string &szFun 异常函数描述符
返回值:

\*****************************************************************************/
void GetFunName(std::string &szFun);
/*****************************************************************************\
函数名称:Install
函数功能:C++异常处理转换为SEH
参数:
input:

output:

返回值:

异常类型:

\*****************************************************************************/
void Install(void) throw();
protected:
inline static void TranslatorSEH(UINT unCode,LPEXCEPTION_POINTERS lptgInfo);
private:
EXCEPTION_POINTERS m_tgException;
DWORD m_dwCode;
CComBSTR m_cError;
std::string m_szFun;
};

inline void CExceptionByJade::GetFunName(std::string &szFun)
{
szFun = m_szFun;
}

inline DWORD CExceptionByJade::ErrorCode(void)
{
return m_dwCode;
}

inline void CExceptionByJade::Install(void) throw()
{
_set_se_translator(TranslatorSEH);
}

inline void CExceptionByJade::TranslatorSEH(UINT unCode,LPEXCEPTION_POINTERS lptgInfo)
{
throw CExceptionByJade(unCode,"TranslatorSEH",lptgInfo);
}

inline DWORD CExceptionByJade::GetRecord(EXCEPTION_RECORD *lpRecord,DWORD dwLen)
{
if(IsBadWritePtr(lpRecord,sizeof(EXCEPTION_POINTERS)))
return -1;
if(IsBadReadPtr(lpRecord,sizeof(EXCEPTION_POINTERS)))
return -1;
memcpy(lpRecord,&m_tgException.ExceptionRecord,sizeof(EXCEPTION_POINTERS));
return 0;
}

#endif /*__JADE_EXCEPTION_H_H*/
stivenjia 2009-07-28
  • 打赏
  • 举报
回复


/*-------------------------------------------------------------------------------\
宏功能:
依据版本进行头文件的选择
\-------------------------------------------------------------------------------*/
#if (_WIN32_WINNT>=0x0501)
#include <DbgHelp.h>
#else
#include "DbgHelp.h"
#endif

#include "ExceptionByJade.h"
#pragma comment(lib,"DbgHelp")


CExceptionByJade::CExceptionByJade(DWORD dwCode,std::string szFun,LPEXCEPTION_POINTERS lpException)
:m_dwCode(dwCode),m_szFun(szFun)
{
memcpy(&m_tgException,lpException,sizeof(EXCEPTION_POINTERS));
}

CExceptionByJade::CExceptionByJade(DWORD dwCode,std::string szFun,CComBSTR cError)
:m_dwCode(dwCode),m_szFun(szFun)
{
m_cError = cError;
ZeroMemory(&m_tgException,sizeof(EXCEPTION_POINTERS));
}

CExceptionByJade::CExceptionByJade(std::string szFun) : m_szFun(szFun)
{
ZeroMemory(&m_tgException,sizeof(EXCEPTION_POINTERS));
}

CExceptionByJade::CExceptionByJade(DWORD dwCode,std::string szFun)
: m_szFun(szFun),m_dwCode(dwCode)
{
ZeroMemory(&m_tgException,sizeof(EXCEPTION_POINTERS));
}

CExceptionByJade::CExceptionByJade(void) : m_dwCode(0)
{
ZeroMemory(&m_tgException,sizeof(EXCEPTION_POINTERS));
}

CExceptionByJade::~CExceptionByJade(void)
{
ZeroMemory(&m_tgException,sizeof(EXCEPTION_POINTERS));
}


DWORD CExceptionByJade::DumpFile(LPCTSTR lpFile,BOOL bExcept,DWORD dwOption)
{
HANDLE hThis = GetCurrentProcess();
DWORD dwId = GetCurrentProcessId();
MINIDUMP_EXCEPTION_INFORMATION tgExcpetion = { 0 };
HANDLE hFile = CreateFile(lpFile,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL
,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);

if(hFile == INVALID_HANDLE_VALUE)
return GetLastError();
tgExcpetion.ClientPointers = TRUE;
tgExcpetion.ThreadId = GetCurrentThreadId();
memcpy(&tgExcpetion.ExceptionPointers,&m_tgException,sizeof(EXCEPTION_POINTERS));
switch(dwOption)
{
case 0:
if(bExcept)
MiniDumpWriteDump(hThis,dwId,hFile,MiniDumpNormal,&tgExcpetion,NULL,NULL);
else
MiniDumpWriteDump(hThis,dwId,hFile,MiniDumpNormal,NULL,NULL,NULL);
break;
}
return 0;
}

DWORD CExceptionByJade::FormatMsg(std::wstring &szMsg,USHORT usPrimaryLang,USHORT usSubLang)
{
LPVOID lpMsgBuf = NULL;
DWORD dwLang = MAKELANGID(usPrimaryLang,usSubLang) , dwRetVal = 0;
dwRetVal = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
NULL,m_dwCode,dwLang,(LPTSTR) &lpMsgBuf,0,NULL);
if(!dwRetVal) return GetLastError();
szMsg = (WCHAR*)lpMsgBuf;
LocalFree(lpMsgBuf);
return 0;
}
周成风 2009-07-28
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 rendao0563 的回复:]
这都属于小技巧。

[/Quote]

这样的确可以解决编译的问题,但我提出两点:
1、既然可能发生异常,而new了一个对象,很可能导致内存泄漏。

2、__try __except 捕获的异常只是当前线程的,在__try块中创建线程并触发异常,是捕获不到的。

函数SetUnhandledExceptionFilter设置的异常处理函数,可以捕获由设置线程创建的所有线程的异常。
如下代码异常未捕获。


#include <Windows.h>
#include "Dumper.h"
#include <iostream>
using namespace std;

DWORD WINAPI ThreadProc(
LPVOID lpParameter
)
{
cout << "Thread Start" << endl;

char *p = NULL;
*p = 1;

cout << "Thread Stop" << endl;
return 0;
}

class A
{
public:
int m_nStep;
int* m_pTest;

public:
A(void) : m_nStep(0),m_pTest(NULL)
{
m_pTest = new int;
};

~A(void)
{
if(m_pTest != NULL)
{
delete m_pTest;
m_pTest = NULL;
}
};

static A* Create()
{
return new A;
}

void Test(void)
{
cout << "A::Test" << endl;
}
};

int main()
{


#ifndef _DEBUG
__try
{
#endif
A *value = A::Create();
value->Test();

//char *p = NULL;
//*p = 1;

DWORD dwThreadID;
::CreateThread(NULL,0,ThreadProc,NULL,0,&dwThreadID);

EXCEPTION_INT_DIVIDE_BY_ZERO

#ifndef _DEBUG
}
__except(CDumper::OnError(GetExceptionInformation()))
{
cout << "OnError" << endl;
}
#endif

system("pause");

return 0;
}


zzmoutmans 2009-07-28
  • 打赏
  • 举报
回复
回帖是一种美德!
zhuweiping2003 2009-07-28
  • 打赏
  • 举报
回复
呵呵 学习一下
icesnowjank 2009-07-28
  • 打赏
  • 举报
回复
这个多半是你自己程序的问题~~ 不应该来怀疑 mfc.dll~~
kongxiangxiang 2009-07-28
  • 打赏
  • 举报
回复
我也有这个问题啊,学习到了,谢谢了
caitian6 2009-07-27
  • 打赏
  • 举报
回复
rendao0563 2009-07-27
  • 打赏
  • 举报
回复
这都属于小技巧。



#include "stdafx.h"
#include "Dumper.h"

class A
{
public:
int m_nStep;
int* m_pTest;

public:
A(void) : m_nStep(0),m_pTest(NULL)
{
m_pTest = new int;
};

~A(void)
{
if(m_pTest != NULL)
{
delete m_pTest;
m_pTest = NULL;
}
};

static A* Create()
{
return new A;
}


void Test(void)
{

}
};

int main()
{


#ifndef _DEBUG
__try
{
#endif
char *p = NULL;

*p = 1;
A *value = A::Create();
value->Test();

#ifndef _DEBUG
}
__except(CDumper::OnError(GetExceptionInformation()))
{

}
#endif

return 0;
}

周成风 2009-07-27
  • 打赏
  • 举报
回复
利用
__try
{
}
__except()
{
}

处理异常,在_try 块中不能存在C++对象。。

#include "stdafx.h"
#include "Dumper.h"

class A
{
int m_nStep;
int* m_pTest;

public:
A(void) : m_nStep(0),m_pTest(NULL)
{
m_pTest = new int;
};

~A(void)
{
if(m_pTest != NULL)
{
delete m_pTest;
m_pTest = NULL;
}
};
};

int main()
{
#ifndef _DEBUG
__try
{
#endif
char *p = NULL;

*p = 1;

A value;

#ifndef _DEBUG
}
__except(CDumper::OnError(GetExceptionInformation()))
{

}
#endif

return 0;
}


Release模式下编译将报错。。
xwsn007 2009-07-27
  • 打赏
  • 举报
回复
[Quote=引用 22 楼 rendao0563 的回复:]
别的不说了,贴代码。觉得好用就加分。


dumper.h
C/C++ code
#ifndef __DUMPER_H__#define __DUMPER_H__

#include<time.h>
#include<string>
#include<windows.h>
#include<dbghelp.h>#pragma comment(lib,"dbghelp.lib")class CDumper
{public:
CDumper(void);~CDumper(void);staticint OnError(LPEXCEPTION_POINTERS pException);static std::string FormateDateTime(time_t t);staticconstchar* GetRootPath(void);staticvoid Test(void);
};#endif//__DUMPER_H__

dumper.cpp
C/C++ code
#include"stdafx.h"
#include"dumper.h"

CDumper::CDumper(void)
{
}

CDumper::~CDumper(void)
{
}int CDumper::OnError(LPEXCEPTION_POINTERS pException)
{
LONG ret= EXCEPTION_CONTINUE_SEARCH;
std::string strTime= CDumper::FormateDateTime(time(NULL));
std::string strRootPath= CDumper::GetRootPath();
std::string strFileName= strRootPath+"\\crash"+ strTime+".dmp";
HANDLE hFile= ::CreateFile( strFileName.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL, NULL );if (hFile!=INVALID_HANDLE_VALUE)
{
MINIDUMP_EXCEPTION_INFORMATION ExInfo= {0};

ExInfo.ThreadId= ::GetCurrentThreadId();
ExInfo.ExceptionPointers= pException;
ExInfo.ClientPointers= NULL;// write the dumpif (!MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal,&ExInfo, NULL, NULL) )
{//MessageBox(NULL, "write dumpfile error.", "Error", MB_ICONQUESTION|MB_OK); ::CloseHandle(hFile);return EXCEPTION_EXECUTE_HANDLER;
}
::CloseHandle(hFile);
}return EXCEPTION_EXECUTE_HANDLER;
}

std::string CDumper::FormateDateTime(time_t t)
{char szData[128]= {0};
tm* ptm= localtime(&t);
sprintf(szData,"%d-%.2d-%.2d %.2d-%.2d-%.2d", ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec);return szData;
}constchar* CDumper::GetRootPath(void)
{staticchar szPath[MAX_PATH];staticbool bFirstTime=true;if(bFirstTime)
{
bFirstTime=false;
GetModuleFileName(NULL, szPath,sizeof(szPath));char*p= strrchr(szPath,'\\');*p='\0';
}return szPath;
}void CDumper::Test(void)
{
#ifndef _DEBUG
__try
{#endifchar*p= NULL;*p=1;

#ifndef _DEBUG
}
__except(CDumper::OnError(GetExceptionInformation()))
{

}#endif

}

main.cpp
C/C++ code

#include"stdafx.h"

#include"Dumper.h"int main()
{
#ifndef _DEBUG
__try
{#endifchar*p= NULL;*p=1;

#ifndef _DEBUG
}
__except(CDumper::OnError(GetExceptionInformation()))
{

}#endifreturn0;
}

1. 程序崩溃的话会在exe当前目录生成类似crash2009-07-24 17-16-45.dmp的文件

2. 双击文件会用VS打开。直接F5 定位到崩溃的位置。

3. 注意exe目录需要放好对应的pdb文件。否则可能无法定位。也就是说你发布一个程序以后你要保存对应的pdb文件和对应的源码。

4. vs2005以上版本默认是不打开。在C/C++ -> Code Generation -> Enable C++ Exceptions -> set Yes With SEH Exceptions (/EHa)

5. 那个sethandle啥啥啥的有问题。不是每次都能输出的。相对而言这个比那个药稳定一些。

6. LZ不加分实在说不过去。大家说呢。



[/Quote]

顶!
加载更多回复(22)

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧