Mac OS X の C++ アプリで現在のスタックを保存してから印刷する方法を考え出そうとしています。問題は実際にはコンパイル オプションであると思われますが、よくわかりません。
Darwin/Leopard のバックトレース コードを試してみましたが、dladdr が呼び出され、dladdr を呼び出す自分のコードと同じ問題が発生します。
元の投稿: 現在、次のコードでスタックをキャプチャしています:
int BackTrace(Addr *buffer, int max_frames)
{
void **frame = (void **)__builtin_frame_address(0);
void **bp = ( void **)(*frame);
void *ip = frame[1];
int i;
for ( i = 0; bp && ip && i < max_frames; i++ )
{
*(buffer++) = ip;
ip = bp[1];
bp = (void**)(bp[0]);
}
return i;
}
これはうまくいくようです。次に、次のように dladdr を使用して、見ているスタックを印刷します。
Dl_info dli;
if (dladdr(Ip, &dli))
{
ptrdiff_t offset;
int c = 0;
if (dli.dli_fname && dli.dli_fbase)
{
offset = (ptrdiff_t)Ip - (ptrdiff_t)dli.dli_fbase;
c = snprintf(buf, buflen, "%s+0x%x", dli.dli_fname, offset );
}
if (dli.dli_sname && dli.dli_saddr)
{
offset = (ptrdiff_t)Ip - (ptrdiff_t)dli.dli_saddr;
c += snprintf(buf+c, buflen-c, "(%s+0x%x)", dli.dli_sname, offset );
}
if (c > 0)
snprintf(buf+c, buflen-c, " [%p]", Ip);
これはほとんど機能しますが、出力例は次のとおりです。
/Users/matthew/Library/Frameworks/Lgi.framework/Versions/A/Lgi+0x2473d(LgiStackTrace+0x5d) [0x102c73d]
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x2a006(tart+0x28e72) [0x2b006]
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x2f438(tart+0x2e2a4) [0x30438]
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x35e9c(tart+0x34d08) [0x36e9c]
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x1296(tart+0x102) [0x2296]
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x11bd(tart+0x29) [0x21bd]
共有オブジェクトのメソッド名は正しく取得されていますが、メインアプリのメソッド名は取得されていません。それらは単に「tart」(または「start」から最初の文字を引いたもの)にマップされます。
理想的には、その時点で行番号とメソッド名が必要です。しかし、初心者向けの正しい関数/メソッド名に落ち着きます。Linux では、独自の命令セットを持つプライベート ELF ブロック用に独自のパーサーを作成する必要があると聞いています。怖いですね。
とにかく、誰かがこのコードを整理して、メソッド名を正しく取得できますか?