BOOL StackWalk( IN DWORD MachineType, IN HANDLE hProcess, IN HANDLE hThread, IN OUT LPSTACKFRAME StackFrame, IN OUT LPVOID Context, IN PREAD_PROCESS_MEMORY_ROUTINE ReadProcessMemoryRoutine, IN PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, IN PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, IN PTRANSLATE_ADDRESS_ROUTINE TranslateAddressRoutine);
この関数はNT4.0または95で使用可能。
引数の意味は以下の通り。
| MachineType | スタックトレースを生成したマシンの型を表すフラグ。定義済みの定数IMAGE_FILE_MACHINE_XXXを設定する。(XXXは、"I386"など) |
| hProcess | スタックトレースを生成したプロセスのハンドル。ReadProcessMemoryRoutineがNULLでないならばこの引数は無視される。 |
| hThread | スタックトレースを生成したスレッドのハンドル。ReadProcessMemoryRoutineがNULLでないならばこの引数は無視される。 |
| StackFrame | スタックフレーム。関数実行後、次のスタックフレームの情報が格納される。 |
| Context | スレッドコンテキスト。MachineTypeがIMAGE_FILE_MACHINE_I386でないときのみ必要。 |
| ReadProcessMemoryRoutine | メモリ読み込み用関数。NULLならば、hProcessで指定したプロセスに対してReadProcessMemory関数が使用される。 |
| FunctionTableAccessRoutine | ランタイム関数テーブルへアクセスするための関数。SymFunctionTableAccessを指定可能。 |
| GetModuleBaseRoutine | 与えられた仮想アドレスからモジュールベースアドレスを取得する関数。SymGetModuleBaseを指定可能。 |
| TranslateAddressRoutine | 16ビットアドレスの変換用関数。必要が無ければ、NULLを指定可能。 |
戻り値は、関数の実行に成功したか否かを表す真偽値である。
void TestStackWalk();
void Test1();
void Test2();
void Test3();
LONG CALLBACK SWFilter(EXCEPTION_POINTERS *ExInfo);
void TestStackWalk()
{
/* SWFilter()を例外フィルタとして設定しておく */
SetUnhandledExceptionFilter(SWFilter);
Test1();
}
void Test1()
{
Test2();
}
void Test2()
{
Test3();
}
void Test3()
{
/* 例外の発生するコード。SWFilter()関数が呼ばれる */
*(DWORD *)NULL = 0;
}
/* 例外発生時に関数の呼び出し履歴を表示する、例外フィルタ関数 */
LONG CALLBACK SWFilter(EXCEPTION_POINTERS *ExInfo)
{
STACKFRAME sf;
BOOL bResult;
PIMAGEHLP_SYMBOL pSym;
DWORD Disp;
printf("例外発生。\n");
/* シンボル情報格納用バッファの初期化 */
pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc(GMEM_FIXED, 10000);
pSym->SizeOfStruct = 10000;
pSym->MaxNameLength = 10000 - sizeof(IMAGEHLP_SYMBOL);
/* スタックフレームの初期化 */
ZeroMemory(&sf, sizeof(sf));
sf.AddrPC.Offset = ExInfo->ContextRecord->Eip;
sf.AddrStack.Offset = ExInfo->ContextRecord->Esp;
sf.AddrFrame.Offset = ExInfo->ContextRecord->Ebp;
sf.AddrPC.Mode = AddrModeFlat;
sf.AddrStack.Mode = AddrModeFlat;
sf.AddrFrame.Mode = AddrModeFlat;
/* シンボルハンドラの初期化 */
SymInitialize(GetCurrentProcess(), NULL, TRUE);
/* スタックフレームを順に表示していく */
for(;;) {
/* 次のスタックフレームの取得 */
bResult = StackWalk(
IMAGE_FILE_MACHINE_I386,
GetCurrentProcess(),
GetCurrentThread(),
&sf,
NULL,
NULL,
SymFunctionTableAccess,
SymGetModuleBase,
NULL);
/* 失敗ならば、ループを抜ける */
if(!bResult || sf.AddrFrame.Offset == 0) break;
/* プログラムカウンタから関数名を取得 */
bResult = SymGetSymFromAddr(GetCurrentProcess(), sf.AddrPC.Offset, &Disp, pSym);
/* 取得結果を表示 */
if(bResult) printf("0x%08x %s() + 0x%x\n", sf.AddrPC.Offset, pSym->Name, Disp);
else printf("%08x, ---", sf.AddrPC.Offset);
}
/* 後処理 */
SymCleanup(GetCurrentProcess());
GlobalFree(pSym);
return(EXCEPTION_EXECUTE_HANDLER);
}