반응형


예외 발생시 콜스택 출력과 미니덤프 생성하기  Visual C++/MFC 

2009/02/09 12:19

복사http://blog.naver.com/harkon/120063141029


디버깅 .NET 어플리케이션책에 포함된, BugSlayer 소스를 vs2005/8 로 재컴파일한것(멀티쓰레드 DLL)


사용법은
압축파일을 받아서, bugslayer 폴드에 압축을 푼다. (예, c:/myproj/bugslayer)
BugslayerUtil/BugslayerUtil.sln 프로젝트 파일을 열어서 release 모드로 컴파일
샘플 테스트 프로그램: bin/release/CrashTest.exe 

라이버러리에 필요한 헤더파일 라이버러리를 복사 (예, c:/myproj/include/bugslayer, c:/myproj/bin/relase)
copy_bugslayer.bat

echo copy bugslayer...
xcopy bugslayer\include\*.h ..\include\bugslayer  /D
xcopy bugslayer\bin\debug\CrashReport.* ..\bin\debug /D
xcopy bugslayer\bin\debug\dbghelp.dll ..\bin\debug /D
xcopy bugslayer\bin\Release\CrashReport.* ..\bin\release /D
xcopy bugslayer\bin\release\dbghelp.dll ..\bin\release /D
pause

적용할 프로젝트에 위 복사한 헤더파일 경로 지정, 라이버러리 경로 지정

c++ 옵션
/I c:/myproj/include/bugslayer

링커 옵션
/LIBPATH:c:/myproj/bin/release

콜스택을 출력할 다이얼로그 생성



WinMain 함수에 크래시 핸들러 설치


#define LOG printf
#define USE_CRASHHANDLER 1
#define TEST_CRASH 0 //테스트요: 강제 널포인트 참조 실행


#if USE_CRASHHANDLER
#include "BugslayerUtil.h"
#endif


HINSTANCE hInst; // 현재 인스턴스입니다.
TCHAR szTitle[MAX_LOADSTRING] = {"MyTest"}; // 제목 표시줄 텍스트입니다.



#if USE_CRASHHANDLER

#pragma comment (lib, "CrashReport.lib")

EXCEPTION_POINTERS *g_pExPtrs;

// 정보 대화 상자의 메시지 처리기입니다.
LRESULT CALLBACK OnCrash(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
LPCTSTR szStr = NULL;
HWND hList = 0;
switch (message)
{
case WM_INITDIALOG:
ShowCursor(TRUE);

LOG("************************************ Crash Occured! ************************************");

szStr = GetFaultReason ( g_pExPtrs ) ;
SetWindowText(GetDlgItem(hDlg, IDC_FAULTREASON), szStr) ;

LOG("FaultRegion: %s", convUni2Mbcs(szStr).c_str());

szStr = GetRegisterString ( g_pExPtrs ) ;
SetWindowText(GetDlgItem(hDlg, IDC_REGISTERS), szStr) ;

LOG("Register:\n%s", convUni2Mbcs(szStr).c_str());

hList = GetDlgItem(hDlg, IDC_CALLSTACK);
szStr = GetFirstStackTraceString ( GSTSO_MODULE     |
GSTSO_SYMBOL    |
GSTSO_SRCLINE    ,
g_pExPtrs        ) ;

while ( NULL != szStr )
{
SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)szStr);
LOG(convUni2Mbcs(szStr).c_str());
szStr = GetNextStackTraceString ( GSTSO_MODULE     |
GSTSO_SYMBOL   |
GSTSO_SRCLINE   ,
g_pExPtrs        ) ;
}

LOG("****************************************************************************************");

EnableWindow(GetDlgItem(hDlg, IDC_MINIDUMP), IsMiniDumpFunctionAvailable ());
return TRUE;

case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
else if (LOWORD(wParam) == IDC_MINIDUMP) 
{
TCHAR dumpFile[100], szTmp[100];
wsprintf(dumpFile, _T("%s.DMP"), szTitle); //APPTITLE _T(".DMP");
BSUMDRET eRet =
CreateCurrentProcessCrashDumpW ( MiniDumpWithHandleData ,
dumpFile,
GetCurrentThreadId ( ) ,
g_pExPtrs              ) ;

ASSERT( eDUMP_SUCCEEDED == eRet ) ;
if ( eDUMP_SUCCEEDED != eRet ) {
wsprintf(szTmp, _T ("MiniDump Save, Failed. Code : %d") , eRet ) ;
} else {
wsprintf(szTmp, _T ("MiniDump Save, Succeed. %s"), dumpFile ) ;
}

MessageBox(NULL, szTmp, _T("MiniDump"), MB_OK);
}
break;
}
return FALSE;
}


LONG __stdcall TheCrashHandlerFunction ( EXCEPTION_POINTERS * pExPtrs )
{
g_pExPtrs = pExPtrs ;

LONG lReturnVal = EXCEPTION_EXECUTE_HANDLER ;

INT_PTR iRet = DialogBox(NULL, (LPCTSTR)IDD_CRASH_DIALOG, NULL, (DLGPROC)OnCrash);

if ( IDOK == iRet )
{
lReturnVal = EXCEPTION_EXECUTE_HANDLER ;
}
else
{
lReturnVal = EXCEPTION_CONTINUE_SEARCH ;
}

g_pExPtrs = NULL;

return ( lReturnVal ) ;
}


void TestCrashAway()
{
char * p = NULL ;
*p = 'p' ;
}

#endif // USE_CRASHHANDLER


int WinMain(LPCTSTR szName, HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    #if USE_CRASHHANDLER
BOOL bRet = SetCrashHandlerFilter ( &TheCrashHandlerFunction ) ;
ASSERT ( TRUE == bRet ) ;

   #if TEST_CRASH
TestCrashAway();
   #endif
  
   #endif

   InitInstance(...)
   CreateWindow(...)
   while (GetMessage(...)) 
   {
    ...
   }

   return 0;
}

기타 

MiniDump 버튼을 누르면, *.DMP 파일이 생성되며, 더블 클릭하면, 비주얼 스튜디오 실행되면서, 클래쉬한 소스의 위치를 가르킨다. 컴파일할때 /Zi 옵션으로, *.pdb 디버깅 심볼파일 생성 필요.

프로세스가 응답없음 상태일때, userdump.exe 를 이용한 미니 덤프 생성하기

압축 파일에 포함된 dbghelp.dll 버전에 따라서, 콜스택을 출력할때, 심볼(함수이름)을 제대로 못읽는 경우가 발생할수 있다. 이 경우, ms 사이트에서 최신버전을 찾아서 설치해 볼것.

Bugslayer 와 비슷한 라이버러리 - 구글 breakpad


적용예

반응형

+ Recent posts