使用SetUnhandledExceptionFilter()为访问冲突异常创建minidump

时间:2011-01-31 09:58:58

标签: c++ winapi debugging windbg

每当从我的代码生成结构化异常时,我使用以下代码创建一个minidump文件:

void CreateMiniDump( EXCEPTION_POINTERS* pep ) 
{
  // Open the file 
typedef BOOL (*PDUMPFN)( 
  HANDLE hProcess, 
  DWORD ProcessId, 
  HANDLE hFile, 
  MINIDUMP_TYPE DumpType, 
  PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, 
  PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, 
  PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);


    HANDLE hFile = CreateFile( _T("C:/temp/MiniDump.dmp"), GENERIC_READ | GENERIC_WRITE, 
    0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); 

    HMODULE h = ::LoadLibrary(L"DbgHelp.dll");
    PDUMPFN pFn = (PDUMPFN)GetProcAddress(h, "MiniDumpWriteDump");

  if( ( hFile != NULL ) && ( hFile != INVALID_HANDLE_VALUE ) ) 
  {
    // Create the minidump 

    MINIDUMP_EXCEPTION_INFORMATION mdei; 

    mdei.ThreadId           = GetCurrentThreadId(); 
    mdei.ExceptionPointers  = pep; 
    mdei.ClientPointers     = TRUE; 

    MINIDUMP_TYPE mdt       = MiniDumpNormal; 

    BOOL rv = (*pFn)( GetCurrentProcess(), GetCurrentProcessId(), 
      hFile, mdt, (pep != 0) ? &mdei : 0, 0, 0 ); 



    // Close the file 

    CloseHandle( hFile ); 

  }

}

LONG WINAPI MyUnhandledExceptionFilter(
 struct _EXCEPTION_POINTERS *ExceptionInfo
)
 {
     CreateMiniDump(ExceptionInfo);
     return EXCEPTION_EXECUTE_HANDLER;
 }

我正在从我的应用程序的主入口点开始SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);(我不是为每个线程设置它)。在此之后测试此代码我执行以下操作以生成访问冲突:int* p = 0; *p = 0;转储文件确实已生成。然后我使用windbg并打开转储文件并使用.ecxr命令获取异常记录。但是,没有信息(即我没有得到调用堆栈)。此外,如果我使用!analyze -v命令,则可以显示发生崩溃的行。有人知道我错过了什么以及如何解决这个问题吗?

BTW,我正在使用VC7编译器和/ EHa(asynchronuos异常模型)标志。

2 个答案:

答案 0 :(得分:3)

你的代码创建minidump是好的,问题是验尸调试。调试器必须能够访问程序源代码,.pdb文件(应该是构建此程序可执行文件时创建的pdb文件)和OS调试符号。只有拥有所有这些信息,调试器才能在源代码和调用堆栈中显示异常位置。

使用Visual Studio调试器的事后调试过程在此处详细描述:http://www.codeproject.com/KB/debug/postmortemdebug_standalone1.aspx对于WinDbg,使用符号,源和图像文件路径为调试器提供相同的信息。

答案 1 :(得分:3)

  

但是,没有信息(即我没有收到调用堆栈)

.ecxr不应该打印一个callstack,它只是应该将上下文设置为存储的异常记录的上下文 - 你想要像k 10那样实际打印它。或者,因为您正在使用WinDBG,请打开callstack窗口。

(也许你已经这样做了;我不能从你的描述中确定.ecxr是如何失败的 - 它应该打印一些东西让你知道它是什么/不能做什么......)

要检查的另一件事是你实际上正在获取传入的异常指针 - 代码将生成一个没有它们的转储,但你会得到一个时髦的callstack。

你提到in a comment on Alex's answer有一些来自DLL的干扰覆盖你的过滤器与运行时库的...这是一个常见的问题。我使用the technique described by Oleg Starodumov祝你好运:

  

还有一种方法可行,而且比前两种方法更容易实现。在我们注册了自己的过滤器后,我们可以修补SetUnhandledExceptionFilter函数的开头,以便它不再能够注册过滤器。

他为此提供了一些方便的示例代码,这些代码多年来一直很好用。