我用StackWalk函数在程序崩溃的时候得到栈信息,在debug版本下面还好,release版本下面只能得到一部分,请问怎么解决呢
debug版本看起来像这个样子
-MyExe.exe    0x0400015 + 0x0C
-MFC80d.dll   0x0700152 + 0x120
而release版本没有MFC80.dll这一行另外kernel32.dll里面的函数调用也没有得到,我看迅雷,qq都能得到kernel32.dll里面的栈
谢谢

解决方案 »

  1.   

    你需要用工具抓full dump
    adplus之类的工具都可以
      

  2.   

    mini dump肯定不行,只有部分错误信息
      

  3.   

    我想在Release版本中也实现这个功能,QQ,迅雷都实现了呵呵
      

  4.   

    类似下面的东东
    迅雷5 5.7.2.371
    ———————————–
    Type: EXCEPTION_UNCATCH_THROW
    Address: 0×7C812A5B
    Error: [3536][asyn_io_manager] unknownCall stack:
    0×7C800000[12A5B] kernel32.dll: RaiseException[+52](-536838143,1,1,21036956)
    0×21350000[10FA0] download_interface.dll: debug_p2p_pipe_simulate_remote_choke_local[+45D0](11364736,1429560,1243148,11364736)
    0×7C800000[B683] kernel32.dll: GetModuleFileNameA[+1B4](0,0,0,0) 
      

  5.   

    可能是编译Realse版本的时候添加的Debug Info,在VC里有设置的
      

  6.   

    利用MS的dbghelp.dll提供的DbgHelpCreateUserDump来生成dump文件就可以了
      

  7.   

    顶楼上的,一般都是用的dbghelp.dll
      

  8.   

    很简单的,用WINDBG分析,只要是全DUMP,就好分析
      

  9.   

    MFC80d.dll这是调试版调用的MFC库。
    Release版是不调用这个的,当然你看不到这个了
      

  10.   

    http://www.codeproject.com/KB/threads/StackWalker.aspx 看这个例子
      

  11.   

    1. 生成map
    2.用dump抓 crash文件核对map  去查代码
      

  12.   

    看了楼主的帖子,我研究了一下这方面的东西。。
    在blog上整理了网上的几篇文章。blog.csdn.net/alicehyxx
      

  13.   

    别的不说了,贴代码。觉得好用就加分。
    dumper.h#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);    static int OnError(LPEXCEPTION_POINTERS pException);
        static std::string FormateDateTime(time_t t);
        static const char* GetRootPath(void);
        static void Test(void);
    };#endif //__DUMPER_H__
    dumper.cpp#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 dump
            if (!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;
    }const char* CDumper::GetRootPath(void)
    {
        static char szPath[MAX_PATH];
        static bool 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
        {
    #endif
    char *p = NULL; *p = 1;#ifndef _DEBUG
        }
        __except(CDumper::OnError(GetExceptionInformation()))
        {    }
    #endif}
    main.cpp
    #include "stdafx.h"#include "Dumper.h"int main() 
    {
    #ifndef _DEBUG
        __try
        {
    #endif
    char *p = NULL; *p = 1;#ifndef _DEBUG
        }
        __except(CDumper::OnError(GetExceptionInformation()))
        {    }
    #endif    return 0; 
    } 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不加分实在说不过去。大家说呢。
      

  14.   

    利用
    __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模式下编译将报错。。
      

  15.   

    这都属于小技巧。#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; 
    }
      

  16.   


    这样的确可以解决编译的问题,但我提出两点:
    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; 
    }
      

  17.   

    /*-------------------------------------------------------------------------------\
    宏功能:
    依据版本进行头文件的选择
    \-------------------------------------------------------------------------------*/
    #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;
    }
      

  18.   


    #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*/
      

  19.   


    1. 内存管理应该是用户自己管理的。程序退出了。内存就不存在泄漏。内存管理和异常处理应该没什么关系的。2. __try  __except 捕获的异常是针对当前作用域。跟线程没关系。新启的线程没加__try。3. 可以用SetUnhandledExceptionFilter。现在开发基本上都是模块化,不是很提倡跨线程处理别人的异常。另:使用的时候感觉这个不是很稳定。90%以上情况都正常。极少数情况无法捕获。这让人很尴尬。因为不是必现,具体原因没排查出来。如果有知道原因的,麻烦告诉我一下。
      

  20.   

    1、内存管理是和异常是没有什么关系,但new一个对象在后面再delete,中间异常了就delete不了了,一般都采用类似智能指针的办法防止内存泄漏,但指针智能就是利用了C++对象的析构机制。2、__try  __except 是针对当前域的,而SetUnhandledExceptionFilter是针对所有未处理的异常,其实并不冲突,不在__try块中的代码发生异常也可以被SetUnhandledExceptionFilter捕获。至于您所说的有情况无法捕获,的确存在。。我也不知道具体原因。3、如果不是为了设置顶层的异常处理,类似SetUnhandledExceptionFilter函数做的工作。在C++中完全可以利用try..catch..代替__try  __except 。
      

  21.   

    这个多半是你自己程序的问题~~ 不应该来怀疑 mfc.dll~~
      

  22.   

    http://topic.csdn.net/t/20060120/09/4526635.html
      

  23.   

    你的release没有生成相应的pdb文件吧,在工程项目中打开这一项应该就好了