実行中でのコールスタックの取得と表示

 メモ用。デバッグ等で有用なコールスタックはgdbなどの各種デバッガで取得できるけれど、実行中にアプリケーション内で取得したい場合がある。
 それはglibcが使えるならbacktrace()、backtrace_symbols()で実現できる。
 例えば下記のコード:

#include <stdio.h>
#include <execinfo.h>

void hoge1(void)
{
        size_t i;
        void *trace[128];
        char **ss_trace;
        size_t size = backtrace(trace, sizeof(trace) / sizeof(trace[0]));
        ss_trace = backtrace_symbols(trace, size);
        if (ss_trace == NULL) {
                /*Failure*/
                return;
        }

        /*例えば表示*/
        for (i = 0; i < size; i++) {
                printf("%s\n", ss_trace[i]);
        }
        free(ss_trace);
}

void hoge2(void)
{
        hoge1();
}

void hoge3(void)
{
        hoge2();
}

int main(void)
{
        hoge3();
        return 0;
}

 これをgccなら「-rdynamic」のオプションをつけてビルド(必要なら「-g」オプションも)。そして実行すると、例えばmacなら以下の様なバックトレース出力が得られる。

0   a.out                               0x0000000100b4cd9b hoge1 + 43
1   a.out                               0x0000000100b4ce39 hoge2 + 9
2   a.out                               0x0000000100b4ce49 hoge3 + 9
3   a.out                               0x0000000100b4ce5d main + 13
4   libdyld.dylib                       0x00007fff8ff3d7e1 start + 0

 コード内でのファイル名と行数情報を得たい場合、GNU binutilsを使えるならaddr2lineを使用。実行ファイルがa.outで、上記のhoge2の記述箇所を知りたいなら、例えば以下のコマンドを実行すると取得できる。

addr2line -f -e a.out 0x100b4cd39