構造化例外処理 ~ 例外情報の取得

例外 (SEH) が発生した際、例外フィルタにて GetExceptionInformation を用いて、その例外の情報を取得することが可能です。 GetExceptionInformation は例外フィルタでしか参照することはできません。

LPEXCEPTION_POINTERS GetExceptionInformation(void);

GetExceptionInformation は EXCEPTION_POINTERS へのポインタを返します。

EXCEPTION_POINTERS の定義は次です。

typedef struct _EXCEPTION_POINTERS {
	PEXCEPTION_RECORD ExceptionRecord;
	PCONTEXT ContextRecord;
} EXCEPTION_POINTERS,  *PEXCEPTION_POINTERS;

すなわち、EXCEPTION_RECORD へのポインタと CONTEXT へのポインタを保持します。

EXCEPTION_RECORD の定義は次です。

typedef struct _EXCEPTION_RECORD {
	DWORD ExceptionCode;
	DWORD ExceptionFlags;  
	struct _EXCEPTION_RECORD *ExceptionRecord;  
	PVOID ExceptionAddress;  
	DWORD NumberParameters;  
	ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD,  *PEXCEPTION_RECORD;

CONTEXT の定義はターゲットの環境によって変わります。基本的にレジスタの情報などを持ちます。 WinNT.h ヘッダを参照してください。

また、例外コードのみであれば GetExceptionCode を使って参照可能です。 これは例外フィルタ及び例外ハンドラ内で呼ぶことができます。

DWORD GetExceptionCode(void);

動作実験

では実際に動かして使ってみましょう。

下のコードでは __try ブロックにてわざと AV (Access Violation) を発生させています。 そして、MyFilter という名前の例外フィルタにて GetExceptionInformation を渡し、MyFilter では例外の情報を少しかいつまんでダンプしています。 例外ハンドラでは GetExceptionCode を用いて、確かに例外コードが取得できることを確認しています。


#include <windows.h>
#include <stdio.h>

INT MyFilter( PEXCEPTION_POINTERS pep ) {
     
     PEXCEPTION_RECORD per = pep->ExceptionRecord;
     PCONTEXT pctx = pep->ContextRecord;

     printf( "-- Exception Record --\n" );
     printf( "Exception Code: %08X\n", per->ExceptionCode );
     printf( "Exception Address: %08X\n", per->ExceptionAddress );

     printf( "-- Context --\n" );
     printf( "EIP %08X\tEBP %08X\n", pctx->Eip, pctx->Ebp );
     printf( "EAX %08X\tEBX %08X\tECX %08X\n", pctx->Eax, pctx->Ebx, pctx->Ecx );
               
     return EXCEPTION_EXECUTE_HANDLER;
}

int main(int argc, char* argv[]) {

     __try {

          strcat( NULL, NULL );

     }
     __except ( MyFilter( GetExceptionInformation() ) ) {

          printf("__except\n");
          printf( "Exception Code: %X\n", GetExceptionCode() );

     }

     return 0;
}

この実行結果は以下のようになりました。

> seh2.exe
-- Exception Record --
Exception Code: C0000005
Exception Address: 004012B0
-- Context --
EIP 004012B0    EBP 0012FF40
EAX 0012FF30    EBX 7FFDF000    ECX 00000000
__except
Exception Code: C0000005

C0000005 は AV の例外コードです。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Web/DB プログラミング徹底解説