윈도용 C++ 프로그램이 예외 때문에 종료될 때 미니덤프로 정보를 남기는 방법

예외 때문에 종료될 때 미니덤프로 정보를 기록하려면 예외를 __try/__except나 SetUnhandledExceptionFilter로 잡아 낸 후 MiniDumpWriteDump를 부르면 됩니다. 그런데 일부 예외는 무시되므로, _set_invalid_parameter_handler, _set_purecall_handler, 그리고 signal 등을 추가로 사용해서 잡아 내야 합니다.

미니덤프를 사용하려면 dbghelp.lib를 링크해야 하고, 소스 코드, 실행 파일, 그리고 .pdb 파일을 보관해야 합니다. 또 아래 그림처럼 /DEBUG 플래그를 켜서 .pdb 파일을 만들어야 합니다.

linker_debugging

소스 코드는 아래와 같습니다.

void write_minidump(PEXCEPTION_POINTERS exception_pointers, bool normal_dump)
{
	char dump_file_name[256];
	SYSTEMTIME systemtime;
	GetSystemTime(&systemtime);
	sprintf(dump_file_name, "%04d-%02d-%02d_%02d-%02d-%02d_%04x_%04x.dmp",
		systemtime.wYear, systemtime.wMonth, systemtime.wDay, systemtime.wHour, systemtime.wMinute, systemtime.wSecond,
		GetCurrentProcessId(), GetCurrentThreadId());
	HANDLE file_handle = CreateFileA(dump_file_name, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
	if (file_handle == INVALID_HANDLE_VALUE)
		return;

	MINIDUMP_EXCEPTION_INFORMATION minidump_exception_information;
	minidump_exception_information.ThreadId = GetCurrentThreadId();
	minidump_exception_information.ExceptionPointers = exception_pointers;
	minidump_exception_information.ClientPointers = FALSE;

	MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), file_handle, normal_dump ? MiniDumpNormal :
		static_cast<MINIDUMP_TYPE>(MiniDumpWithFullMemory | MiniDumpWithHandleData | MiniDumpWithProcessThreadData |
		MiniDumpWithFullMemoryInfo | MiniDumpWithThreadInfo), &minidump_exception_information, nullptr, nullptr);

	CloseHandle(file_handle);
}

LONG WINAPI handle_unhandled_exception(PEXCEPTION_POINTERS exception_pointers)
{
	write_minidump(exception_pointers, false);
	return EXCEPTION_EXECUTE_HANDLER;
}

void handle_invalid_parameter(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line,
	uintptr_t reserved)
{
	RaiseException(0, 0, 0, nullptr);
}

void handle_pure_call()
{
	RaiseException(0, 0, 0, nullptr);
}

void handle_signal(int signal)
{
	RaiseException(0, 0, 0, nullptr);
}

int _tmain(int argc, _TCHAR* argv[])
{
	if (!IsDebuggerPresent())
	{
		SetUnhandledExceptionFilter(handle_unhandled_exception);
		_set_invalid_parameter_handler(handle_invalid_parameter);
		_set_purecall_handler(handle_pure_call);
		signal(SIGABRT, handle_signal);
	}

	// ...

	return 0;
}

참고:

Advertisements

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중