프로그래밍을 하다 보면 여러 에러가 나타납니다.
문법을 틀리거나 잘못된 인자를 사용하는 등의 컴파일 에러, 링크 단계에서 나타나는 링크 에러, 프로그램 실행중 나타나는 런타임 에러가 있을 수 있습니다.
컴파일, 링크에러의 경우 보통 개발도구에서 에러 메시지를 표시하기 때문에 프로그래머가 확인하기 용이하지만(그렇다고 바로 고칠수 있는건 아니지만)
런타임 에러같은 경우는 프로그래머 의도와 다른 값으로, 프로그램 실행 중에 발생하므로, 프로그래머가 확인하기 어렵습니다.
예를들어 아래와 같은 코드입니다.
// 0 나누기
int iX = 0, iY = 3;
int iZ = iY / iX;
CString sDiv;
sDiv.Format( _T( "%d" ), iZ );
// 오버플로우
int iA = 0, iB[3] = { 1, 2, 3 };
memcpy( &iA, iB, sizeof( iB ) );
CString sOver;
sOver.Format( _T( "%d" ), iA );
// Null 포인트
int *iP = NULL;
CString sNull;
sNull.Format( _T( "%d" ), *iP );
위 코드들은 컴파일은 되지만 실행할 때 에러가 발생됩니다. 이 에러들은 SetUnhandledExceptionFilter을 이용하여 CALLBACK 함수를 등록한 뒤 Dump파일을 생성함으로써 확인할 수 있습니다.
LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(
LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
);
MSDN에 아래와 같이 설명되어있습니다.
After calling this function, if an exception occurs in a process that is not being debugged, and the exception makes it to the unhandled exception filter, that filter will call the exception filter function specified by the lpTopLevelExceptionFilter parameter.
디버깅 상태가 아닐때 사용할 수 있다고 하네요.
자, 이제 만들어 보겠습니다. 프로젝트 생성 후 아래와 같이 헤더파일과 라이브러리를 사용합니다.
#include <DbgHelp.h>
#pragma comment ( lib, "DbgHelp" )
그 다음 콜백 함수를 아래와 같이 사용합니다.
// 선언
static LONG CALLBACK TopLevelExceptionFilterCallBack( EXCEPTION_POINTERS* exceptionInfo );
// 정의
LONG CALLBACK TopLevelExceptionFilterCallBack( EXCEPTION_POINTERS * exceptionInfo )
{
MINIDUMP_EXCEPTION_INFORMATION dmpInfo = { 0 };
dmpInfo.ThreadId = ::GetCurrentThreadId(); // Threae ID
dmpInfo.ExceptionPointers = exceptionInfo; // Exception Info
dmpInfo.ClientPointers = FALSE;
HANDLE hFile = CreateFile( _T("Test.dmp"), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
// 덤프 생성
BOOL bWrite = ::MiniDumpWriteDump( ::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, &dmpInfo, NULL, NULL );
return 0L;
}
위에서 알려드렸던, 에러 발생용 코드를 만드신 뒤, 프로그램을 실행시켜 에러를 발생시킵니다.
그러면 프로그램이 종료되면서 덤프파일이 생성됩니다.
Test.dmp 파일을 더블 클릭하시거나, 개발툴에 맞춰서 실행 시키면 아래와 같은 화면이 나옵니다.
저는 Visual Studio 2015에서 개발했습니다.
요약 메시지가 가운데 나옵니다. 자세히 보시려면 우측에 네이티브 전용으로 디버그를 클릭합니다.
그러면 아래와 같이 메시지가 나오면서 화면이 전환 됩니다.
해당 상태에서, 호출 스택과 조사식도 사용할 수 있습니다.
※ 주의사항 ※
1. 덤프 파일 위치는 .exe와 .pdb 과 같은 위치에 있어야합니다.
2. 동일한 코드여도 .exe와 .pdb 파일 시간이 달라지면 기존 덤프 파일은 사용할 수 없습니다.(그래서 배포를 하면 .exe와 .pdb 파일을 백업해야합니다.)
3. Release 모드에서 조사식을 사용할 수 없는 경우가 있는데, 이럴 경우 프로젝트 속성 -> C/C++ -> 최적화 -> 최적화 사용안함 설정을 하셔야합니다.