在开发过程中经常遇到这种情况,程序在客户那里运行的时候会偶然的出现异常,而在开发环境里却很难重现问题导致排查问题非常困难,通过下面的方法可以通过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; }