一般要捕获异常只需要两个函数:SetUnhandledExceptionFilter截获异常;MiniDumpWriteDump写dump文件。但是由于CRT函数可能会在内部调用SetUnhandledExceptionFilter(NULL),解除我们程序设置的异常处理,这导致我们的程序无法完整捕获崩溃。另外,还有一部分非异常的CRT错误,不属于SEH异常捕获的范畴,需要通过_set_invalid_parameter_handler、_set_purecall_handler拦截,否则会弹出很丑陋的Runtime Error提示框。为保证所有异常都能由我们捕获,需要把SetUnhandledExceptionFilter函数Hook掉,不让“其他人”去设置自己的Exception处理,有Exception我们自己搞定;还有,对CRT错误做拦截,避免弹出错误窗口:_set_invalid_parameter_handler、_set_purecall_handler。
     chromium的breakpad当前只是使用了上边提到的_set_invalid_parameter_handler、_set_purecall_handler函数,并没有屏蔽“其他人”的SetUnhandledExceptionFilter行为,可能导致了部分Crash无法捕获,为什么不这么做呢?有待考察。(stackoverflow也有人提到这个问题:http://stackoverflow.com/questions/11350801/why-does-google-breakpad-not-handle-all-crashes-how-can-i-debug-these-cases)。
     进程内捕获dump示例代码
.h
 namespace CatchDumpFile
{ void simple_log(const std::wstring& log_msg); class CDumpCatch
{
public:
CDumpCatch();
~CDumpCatch();
private: static LPTOP_LEVEL_EXCEPTION_FILTER WINAPI TempSetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter);
static BOOL ReleaseDumpFile(const std::wstring& strPath, EXCEPTION_POINTERS *pException);
static LONG WINAPI UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS *pException);
static void MyPureCallHandler(void);
static void MyInvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved); BOOL AddExceptionHandle();
BOOL RemoveExceptionHandle();
BOOL PreventSetUnhandledExceptionFilter();
void SetInvalidHandle();
void UnSetInvalidHandle();
private:
LPTOP_LEVEL_EXCEPTION_FILTER m_preFilter;
_invalid_parameter_handler m_preIph;
_purecall_handler m_prePch;
};
};

.cc

 namespace CatchDumpFile
{
void simple_log(const std::wstring& log_msg)
{
std::wstring strLogWnd = L"cswuyg_simple_debug_log";
HWND hSend = ::FindWindow(NULL, strLogWnd.c_str());
COPYDATASTRUCT copydate;
copydate.cbData = (DWORD)(log_msg.length() + ) * sizeof(wchar_t);
copydate.lpData = (PVOID)log_msg.c_str();
::SendMessage(hSend, WM_COPYDATA, , (LPARAM)&copydate);
} void CDumpCatch::MyPureCallHandler(void)
{
//simple_log(L"MyPureCallHandler");
throw std::invalid_argument("");
} void CDumpCatch::MyInvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved)
{
//simple_log(L"MyPureCallHandler");
//The parameters all have the value NULL unless a debug version of the CRT library is used.
throw std::invalid_argument("");
} void CDumpCatch::SetInvalidHandle()
{
#if _MSC_VER >= 1400 // MSVC 2005/8
m_preIph = _set_invalid_parameter_handler(MyInvalidParameterHandler);
#endif // _MSC_VER >= 1400
m_prePch = _set_purecall_handler(MyPureCallHandler); //At application, this call can stop show the error message box.
}
void CDumpCatch::UnSetInvalidHandle()
{
#if _MSC_VER >= 1400 // MSVC 2005/8
_set_invalid_parameter_handler(m_preIph);
#endif // _MSC_VER >= 1400
_set_purecall_handler(m_prePch); //At application this can stop show the error message box.
} LPTOP_LEVEL_EXCEPTION_FILTER WINAPI CDumpCatch::TempSetUnhandledExceptionFilter( LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter )
{
return NULL;
} BOOL CDumpCatch::AddExceptionHandle()
{
m_preFilter = ::SetUnhandledExceptionFilter(UnhandledExceptionFilterEx);
PreventSetUnhandledExceptionFilter();
return TRUE;
} BOOL CDumpCatch::RemoveExceptionHandle()
{
if(m_preFilter != NULL)
{
::SetUnhandledExceptionFilter(m_preFilter);
m_preFilter = NULL;
}
return TRUE;
} CDumpCatch::CDumpCatch()
{
SetInvalidHandle();
AddExceptionHandle();
} CDumpCatch::~CDumpCatch()
{
UnSetInvalidHandle();
RemoveExceptionHandle();
} BOOL CDumpCatch::ReleaseDumpFile(const std::wstring& strPath, EXCEPTION_POINTERS *pException)
{
HANDLE hDumpFile = ::CreateFile(strPath.c_str(), GENERIC_WRITE, , NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hDumpFile == INVALID_HANDLE_VALUE)
{
return FALSE;
}
MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
dumpInfo.ExceptionPointers = pException;
dumpInfo.ThreadId = ::GetCurrentThreadId();
dumpInfo.ClientPointers = TRUE;
// ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);
BOOL bRet = ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hDumpFile, MiniDumpWithFullMemory, &dumpInfo, NULL, NULL);
::CloseHandle(hDumpFile);
return bRet;
} LONG WINAPI CDumpCatch::UnhandledExceptionFilterEx( struct _EXCEPTION_POINTERS *pException )
{
//simple_log(L"UnhandledExceptionFilterEx");
wchar_t szPath[MAX_PATH] = { };
::GetModuleFileName(NULL, szPath, MAX_PATH);
::PathRemoveFileSpec(szPath);
std::wstring strPath = szPath;
strPath += L"\\CrashDumpFile.dmp";
BOOL bRelease = ReleaseDumpFile(strPath.c_str(), pException);
//::FatalAppExit(0, L"Error");
if (bRelease)
{
return EXCEPTION_EXECUTE_HANDLER;
}
return EXCEPTION_CONTINUE_SEARCH;
} BOOL CDumpCatch::PreventSetUnhandledExceptionFilter()
{
HMODULE hKernel32 = LoadLibrary(L"kernel32.dll");
if (hKernel32 == NULL)
{
return FALSE;
}
void *pOrgEntry = ::GetProcAddress(hKernel32, "SetUnhandledExceptionFilter");
if(pOrgEntry == NULL)
{
return FALSE;
} unsigned char newJump[];
DWORD dwOrgEntryAddr = (DWORD)pOrgEntry;
dwOrgEntryAddr += ; //jump instruction has 5 byte space. void *pNewFunc = &TempSetUnhandledExceptionFilter;
DWORD dwNewEntryAddr = (DWORD)pNewFunc;
DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr; newJump[] = 0xE9; //jump
memcpy(&newJump[], &dwRelativeAddr, sizeof(DWORD));
SIZE_T bytesWritten;
DWORD dwOldFlag, dwTempFlag;
::VirtualProtect(pOrgEntry, , PAGE_READWRITE, &dwOldFlag);
BOOL bRet = ::WriteProcessMemory(::GetCurrentProcess(), pOrgEntry, newJump, , &bytesWritten);
::VirtualProtect(pOrgEntry, , dwOldFlag, &dwTempFlag);
return bRet;
} }
   能引发pure function called 错误的代码
class IPureCall
{
public:
virtual ~IPureCall(){};
IPureCall()
{
//indirect call the virtual function, the compiler would not treat as "static binding", it is "dynamic binding".
//At this time, the CPureCall class hasn't been constructed, the virtual table didn't has the pure_call function's point, so it cause "pure virtual function called exception".
call_by_constructor();
};
virtual void pure_call() = ;
void call_by_constructor()
{
pure_call();
}
}; class CPureCall : public IPureCall
{
public:
CPureCall()
{
}
void pure_call()
{
}
};
  pure virtual function called在之前的文章里介绍过(http://www.cnblogs.com/cswuyg/archive/2012/08/22/2650610.html)。
  
  进程外捕获崩溃的做法是使用进程间通信(IPC,内存映射文件或者管道都行),把EXCEPTION_POINTERS指针数据等信息通知捕获进程,让捕获进程去写dump(windows下捕获dump之Google breakpad_client的理解)。进程外捕获dump是比较推荐的做法,chromium的breakpad文档解释说,“一般认为在崩溃进程内部写minidump是不安全的:关键的进程数据结构可能会被破坏掉,或者异常处理程序获取到的堆栈可能是被覆盖了的”(原文:http://code.google.com/p/google-breakpad/wiki/GettingStartedWithBreakpad)。
 
     可复用源码分享:https://github.com/cswuyg/simple_win/tree/master/dump_catch/dump_catch
 
     多模块dump处理相关补充
1、如果CRT是/MD,那么CRT错误捕获EXE、DLL共用;dump捕获多EXE、DLL共用,只需要在EXE里加上处理就ok;
2、如果CRT是/MT,那么CRT错误捕获各PE文件独立,EXE、DLL必须有自己的处理;dump捕获多EXE、DLL共用。
这方面的知识MSDN也稍有提及:
http://technet.microsoft.com/zh-cn/library/t296ys27(v=vs.71)
http://msdn.microsoft.com/en-us/library/windows/desktop/ms680634(v=vs.85).aspx
 
 
不错的编程资料:
 
不错的抓dump工具介绍:
 
breakpad相关代码:
 

windows下捕获dump的更多相关文章

  1. windows下捕获dump之守护进程

    一两个月前为产品写了一个独立的exe,由于产品使用的捕获dump是一个现成的进程外exe,如果以资源的方式集成它容易出现安全警告,由于时间关系没有寻求新的解决方法,还是遵循旧方案,不捕获dump. 最 ...

  2. windows下捕获dump之Google breakpad_client的理解

    breakpad是Google开源的一套跨平台工具,用于dump的处理.很全的一套东西,我这里只简单涉及breakpad客户端,不涉及纯文本符号生成,不涉及dump解析. 一.使用 最简单的是使用进程 ...

  3. windows下捕获dump之Google breakpad_client

    breakpad是Google开源的一套跨平台工具,用于dump的处理.很全的一套东西,我这里只简单涉及breakpad客户端,不涉及纯文本符号生成,不涉及dump解析. 一.使用 最简单的是使用进程 ...

  4. Windows下获取Dump文件以及进程下各线程调用栈的方法总结(转)

    1. Dump文件的用途 Dump文件, 主要用于诊断一个进程的运行状态,尤其是碰到崩溃(Crash)或者挂起(hang)不响应时,需要分析它的工作状态.  除了平时常见的attach到这个进程, 分 ...

  5. windows下捕获本地回环网络中的报文RawCap

    一.下载地址: 官网地址:https://www.netresec.com/?page=RawCap 百度云:链接:https://pan.baidu.com/s/1mWCOTRF5XicuJitBA ...

  6. Google Breakpad 在 windows下捕获程序崩溃报告

    http://blog.csdn.net/goforwardtostep/article/details/56304285

  7. Windows下 dmp文件的产生

    一.windows下的崩溃捕获windows程序当遇到异常,没有try-catch或者try-catch也无法捕获到的异常时,程序就会自动退出.windows系统默认是不产生程序dmp文件的.dump ...

  8. 原创 C++应用程序在Windows下的编译、链接:第三部分 静态链接(二)

    3.5.2动态链接库的创建 3.5.2.1动态链接库的创建流程 动态链接库的创建流程如下图所示: 在系统设计阶段,主要的设计内容包括:类结构的设计以及功能类之间的关系,动态链接库的接口.在动态链接库中 ...

  9. 记一次windows下物理迁移数据库的过程

    背景:      最近因为一次设备故障,导致一台运行windows环境下的机器无法启动,里面有一个正在使用的财务数据库,该数据库也只是每月使用一次,需要把物理数据迁移出来,于是拔出了故障机器的硬盘,通 ...

随机推荐

  1. jQuery细节总结

    1.mouseover和mouseenter 区别 mouseenter指鼠标进入元素时触发,鼠标在元素子元素上不触发. mouseover指鼠标进入元素时触发,在元素进入子元素会触发. 在此引用一个 ...

  2. Gradient Boosted Regression Trees 2

    Gradient Boosted Regression Trees 2   Regularization GBRT provide three knobs to control overfitting ...

  3. js简介、基本语法、类型转换、变量、运算符、分支语句、循环语句、函数、函数调用

    javascript是个脚本语言,需要有宿主文件,他的宿主文件是html文件. 三个常用对话框 alert("")警告对话框,弹出一个警告对话框 <script> al ...

  4. SQL 调优专题总结

    oracle 的优化器: oracle 有两种优化器:基于规则的优化器(rbo/rule based optimizer)和基于代价的优化器(cbo/cost based optimizer). 有时 ...

  5. Traffic Sign Recognition with Multi-Scale Convolutional Networks

    总结一下文中几点值得学习的地方: 1,卷积神经网络的结构图:Multi-Scale Features.   因为它提取的特征的分层的,对吧,虽然最后 一层可以提供全局信息,但是呢,前面的几层可以提供更 ...

  6. Linux系统负载排查

    参考  http://www.ruanyifeng.com/blog/2011/07/linux_load_average_explained.html 在Linux系统中,我们一般使用uptime命 ...

  7. Erlang安装笔记

    今天,为了安装RabbitMQ,需要安装Erlang,中间遇到了一些坑,记录下来. 1. 下载Erlang安装包 http://www.erlang.org/downloads http://erla ...

  8. go框架

    beego 的 http server… Author 逆雪寒 2015.12.02 原文地址 https://github.com/nixuehan/beego_you_know/blob/mast ...

  9. JDK中的Timer和TimerTask详解(zhuan)

    http://www.cnblogs.com/lingiu/p/3782813.html ************************************************** 目录结构 ...

  10. Ajax 完整教程 (转)

    http://www.cnblogs.com/Garden-blog/archive/2011/03/11/1981778.html