久しぶりにWin32API関連の覚書です。
Cで呼び出し履歴(コールスタック)の取得サンプルを漁ると、こんなのをよく見かけました。
※これ以降のコードは超概略記述なので、このままコピペしても動作しません。
IMAGEHLP_LINE64 line = { sizeof(IMAGEHLP_LINE64) };
SymFromAddr(hProcess, address, &disp, symbol);
SymGetLineFromAddr64(hProcess, symbol->Address, &dispLine, &line64);
printf("filename=%s, line=%d\n", line64.FileName, line64.LineNumber);
最初、コピペで実行してみたのですが、どうも呼び出し元の行の位置がずれているのです。例えば、
void GetCallStack()
{
IMAGEHLP_LINE64 line = { sizeof(IMAGEHLP_LINE64) };
SymFromAddr(hProcess, address, &disp, symbol);
SymGetLineFromAddr64(hProcess, symbol->Address, &dispLine, &line64);
printf("filename=%s, line=%d\n", line64.FileName, line64.LineNumber);
}
int main()
{
Statement1;
Statement2;
Statement3;
GetCallStack();
}
と組んでみたときに、呼び出し元は15行目なので「line=15」と出力してほしいのですが、「line=11」と出力されます。
結論は、SymFromAddr()で取得したDisplacement(変位)をSymGetLineFromAddr64()のアドレスに加えないといけないのです。
SymFromAddr(hProcess, address, &disp, symbol); SymGetLineFromAddr64(hProcess, symbol->Address + disp, &dispLine, &line64);
あと、Release版のときは、コンパイルオプションに「/Od」(最適化を無効にする)を指定しないとDebug版と同様な綺麗な呼び出し履歴が取得できないので注意です。