一般保護違反で死んでしまった時、WindowsNT/2000ならワトソン博士のログが出るのでいいんですが、Windows95/98系だとあまり詳しい情報が出てくれないのでデバッグ作業が手こずってしまいます。そこで、__try / __except を使って一般保護違反を横取りし、独自にログを出しましょう。
また、内部的なエラーチェック時にもスタックトレースを出力するととても便利です。
以下、参考ソースコードです。(そのままでは使えません)
int WINAPI WinMain( ... ) {
#ifndef _DEBUG
PEXCEPTION_POINTERS pInfo;
__try {
#endif
...
... WinMainの処理 ...
...
#ifndef _DEBUG
}
__except( pInfo = GetExceptionInformation(), TRUE ) {
StartDump( "Exception" );
DumpContext( pInfo->ContextRecord );
EndDump();
MessageBox( NULL, "××ソフトのプロセスで保護違反が発生しました。××ソフトは異常終了します。\n\n"
"××ソフトの異常終了についての詳細情報は、dump.txtファイルに出力されています。"
"そのファイル内容を作者に連絡ください。"
, NULL, MB_OK | MB_ICONHAND | MB_SYSTEMMODAL );
return TRUE;
}
#endif
}
////////////////////////////////////////////////////////
static HANDLE hfileDump;
void DumpOut( char* psz ) {
DWORD cbWritten;
WriteFile( hfileDump, psz, strlen(psz), &cbWritten, NULL );
}
void StartDump( char* pszTitle ) {
hfileDump = CreateFile( "dump.txt", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE
, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL );
SetFilePointer( hfileDump, 0, NULL, FILE_END );
SYSTEMTIME st;
GetLocalTime( &st );
char sz[256];
wsprintf( sz, "********** %02u/%02u/%02u %02u:%02u:%02u.%03u ××ソフト V1.00 "
, st.wYear % 100, st.wMonth, st.wDay
, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds );
DumpOut( sz );
DumpOut( pszTitle );
DumpOut( "\r\n" );
}
void EndDump() {
DumpOut( "\r\n\r\n" );
CloseHandle( hfileDump );
}
void DumpContext( CONTEXT* pcont ) {
char sz[256];
wsprintf( sz, "eax=%08X ebx=%08X ecx=%08X edx=%08X esi=%08X edi=%08X ebp=%08X esp=%08X eip=%08X\r\n"
, pcont->Eax, pcont->Ebx, pcont->Ecx, pcont->Edx, pcont->Esi, pcont->Edi, pcont->Ebp, pcont->Esp, pcont->Eip );
DumpOut( sz );
DumpOut( "Stack Dump\r\n" );
int i;
DWORD* esp = (DWORD*)pcont->Esp;
for( i = 0; i < 8; i++ ) {
if( IsBadReadPtr( esp, 8 * 4 ) ) {
break;
}
wsprintf( sz, "%08X %08X %08X %08X %08X %08X %08X %08X\r\n"
, esp[0], esp[1], esp[2], esp[3], esp[4], esp[5], esp[6], esp[7] );
DumpOut( sz );
esp += 8;
}
DumpOut( "FramePtr ReturnAd Param#1 Param#2 Param#3 Param#4 Param#5 Param#6 Param#7 Param#8 Param#9 Param#10 MachineCode\r\n" );
i = 0;
DWORD* ebp = (DWORD*)pcont->Ebp;
while( i < 80 && !IsBadReadPtr( ebp, 4 * (10 + 1 + 1) ) ) {
wsprintf( sz, "%08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X "
, ebp[0], ebp[1], ebp[2], ebp[3], ebp[4], ebp[5], ebp[6], ebp[7], ebp[8], ebp[9], ebp[10], ebp[11], ebp[12] );
DumpOut( sz );
BYTE* pbCode = (BYTE*)(ebp[1]);
if( !IsBadReadPtr( pbCode, 8 ) ) {
wsprintf( sz, "%02X %02X %02X %02X %02X %02X %02X %02X"
, pbCode[0], pbCode[1], pbCode[2], pbCode[3], pbCode[4], pbCode[5], pbCode[6], pbCode[7] );
DumpOut( sz );
}
DumpOut( "\r\n" );
i ++;
ebp = (DWORD*)*ebp;
}
DumpOut( "\r\n" );
}
もちろん、レジスターやスタックトレース、さらには逆アセンブルリストを理解できることが前提ですが…。あ、そうそう、ここで出てくるマシンコードのアドレスは、.mapファイル上では0x00401000引いた値が該当するようです。
『戻る』