每当从我的代码生成结构化异常时,我使用以下代码创建一个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
命令,则可以显示发生崩溃的行。有人知道我错过了什么以及如何解决这个问题吗?
答案 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
函数的开头,以便它不再能够注册过滤器。
他为此提供了一些方便的示例代码,这些代码多年来一直很好用。