在开发过程中经常遇到这种情况,程序在客户那里运行的时候会偶然的出现异常,而在开发环境里却很难重现问题导致排查问题非常困难,通过下面的方法可以通过dump文件将出现异常时的进程dump记下来,事后通过windbg等调试工具分析问题的详细过程。
首先在进程的入口处设置捕获未处理异常,在异常处理回调里记录内存dump,完成后退出进程,因为本进程记录dump会导致dump不准确,我们通过另外一个进程来记录dump。
获取到dump文件后通过windbg打开,kv显示调用栈,找到我们感兴趣的异常信息,这个函数的参数记录异常的详细信息,通过这个参数就能获取到异常的详细信息。
未处理异常回调:
long __stdcall unhandle_exception_filter( _EXCEPTION_POINTERS *msg)
{
WriteErrorLogA("unhandle error");
mstring path;
GetModuleFileNameA(NULL, path.alloc(MAX_PATH), MAX_PATH);
PathAppendA(path.alloc(MAX_PATH), "..//error_log");
path.setbuffer();
SHCreateDirectoryExA(NULL, path, NULL);
mstring file;
SYSTEMTIME time;
GetSystemTime(&time);
file.format(
"%hs\\%04d%02d%02d%02d%02d%02d_%08x.dmp",
path.c_str(),
time.wYear,
time.wMonth,
time.wDay,
time.wHour,
time.wMinute,
time.wSecond,
GetTickCount());
mstring tmp;
GetModuleFileNameA(NULL, tmp.alloc(MAX_PATH), MAX_PATH);
PathAppendA(tmp.alloc(MAX_PATH), "..\\memlog.exe");
tmp.setbuffer();
mstring mem;
mem.format("%hs %d \"%hs\"", tmp.c_str(), GetCurrentProcessId(), file.c_str());
//create_mem_log(GetCurrentProcessId(), file.c_str());
STARTUPINFOA si = { sizeof(si) };
PROCESS_INFORMATION pi;
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = TRUE;
BOOL ret = CreateProcessA(
NULL,
(char *)(mem.c_str()),
NULL,
NULL,
FALSE,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi);
if (!ret)
{
WriteErrorLogA("create mem process error\n");
}
else
{
WaitForSingleObject(pi.hProcess, 5000);
//Sleep(5000);
}
exit(-1);
return 0;
}
设置未处理异常回调:
int WINAPI WinMain(HINSTANCE module, HINSTANCE parent, char * cmd, int show)
{
SetLastError(0);
HANDLE mutex = CreateMutexA(NULL, NULL, "global/omserver/mutex");
if (ERROR_ALREADY_EXISTS == GetLastError())
{
MessageBoxA(0, "omserver已经启动", "error", 0);
return 0;
}
SetUnhandledExceptionFilter(unhandle_exception_filter);
}
独立进程记录异常信息:
void create_mem_log(int pid, const char *path)
{
HANDLE dump = NULL;
SYSTEMTIME time = {0};
HANDLE h = NULL;
do
{
dump = CreateFileA(
path,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (!dump || INVALID_HANDLE_VALUE == dump)
{
WriteErrorLogA("create dump file error\n");
break;
}
MINIDUMP_EXCEPTION_INFORMATION mini_dump_info;
mini_dump_info.ExceptionPointers = NULL;
mini_dump_info.ThreadId = GetCurrentThreadId();
mini_dump_info.ClientPointers = TRUE;
h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (!h || INVALID_HANDLE_VALUE == h)
{
WriteErrorLogA("open process error\n");
break;
}
if (!MiniDumpWriteDump(
h,
pid,
dump,
MiniDumpNormal,
NULL,
NULL,
NULL))
{
WriteErrorLogA("write dump file error, error = %d\n", GetLastError());
break;
}
} while (FALSE);
if (dump && INVALID_HANDLE_VALUE != dump)
{
CloseHandle(dump);
}
if (h && INVALID_HANDLE_VALUE != h)
{
CloseHandle(h);
}
return;
}