程序异常时通过dump文件记录下异常的详细信息

时间:2022-09-01 21:39:23

在开发过程中经常遇到这种情况,程序在客户那里运行的时候会偶然的出现异常,而在开发环境里却很难重现问题导致排查问题非常困难,通过下面的方法可以通过dump文件将出现异常时的进程dump记下来,事后通过windbg等调试工具分析问题的详细过程。


首先在进程的入口处设置捕获未处理异常,在异常处理回调里记录内存dump,完成后退出进程,因为本进程记录dump会导致dump不准确,我们通过另外一个进程来记录dump。


获取到dump文件后通过windbg打开,kv显示调用栈,找到我们感兴趣的异常信息,这个函数的参数记录异常的详细信息,通过这个参数就能获取到异常的详细信息。

程序异常时通过dump文件记录下异常的详细信息


程序异常时通过dump文件记录下异常的详细信息


未处理异常回调:

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; 
}