BACKTRACE(3) Linux Programmer's Manual BACKTRACE(3)

名前

backtrace, backtrace_symbols, backtrace_symbols_fd - アプリケーション自身でのデバッグのサポート

書式

#include <execinfo.h>

int backtrace(void **buffer, int size);

char **backtrace_symbols(void *const *buffer, int size);

void backtrace_symbols_fd(void *const *buffer, int size, int fd);

説明

backtrace() は、呼び出したプログラムのバックトレースを buffer が指す配列に入れて返す。バックトレースは、プログラムで 現在動作中の関数呼び出しの並びである。 buffer が指す配列の個々の要素は void * 型で、 対応するスタックフレームからのリターンアドレスである。 size 引数は buffer に格納できるアドレスの最大個数を指定する。 バックトレースが size より大きい場合、 size 個の直近の関数呼び出しに対応するアドレスが返される。 完全なバックトレースを取得するためには、確実に buffersize が十分大きくなるようにすること。

backtrace() によって buffer にアドレスの集合が得られたら、 backtrace_symbols() によって、アドレス集合を、そのアドレスをシンボルで表した文字列の配列 に翻訳できる。 size 引数は buffer に格納されたアドレスの数を指定する。 個々のアドレスのシンボル表現は、関数名 (特定できた場合)、 関数へのオフセット (16進表記)、実際のリターンアドレス (16進表記) から構成される。 backtrace_symbols() の実行結果としては、 文字列ポインターの配列のアドレスが返される。 この配列は backtrace_symbols() によって malloc(3) され、呼び出し側で free しなければならない (ポインターの配列が指す個々の文字列は free する必要はないし、 free すべきでもない)。

backtrace_symbols_fd() は、 backtrace_symbols() と同じ引数 buffersize をとるが、呼び出し側に文字列の配列を返す代わりに、 文字列をファイルディスクリプター fd に 1 行に 1 エントリーの形で書き込む。 backtrace_symbols_fd() は malloc(3) を呼び出さない。 そのため、これに続く関数が失敗する可能性がある状況でも利用できるが、「注意」も参照のこと。

返り値

backtrace() は buffer に格納したアドレスの個数を返す。その個数は size より大きくなることはない。 返り値が size より小さい場合、バックトレース全体が格納されている。返り値が size と等しい場合、バックトレースは切り詰められているかもしれない。 切り詰められた場合、最も古いスタックフレームのアドレスは 返されないことになる。

backtrace_symbols() は、成功すると、この呼び出しで malloc(3) された配列へのポインターを返す。 エラーの場合、 NULL を返す。

バージョン

backtrace(), backtrace_symbols(), backtrace_symbols_fd() はバージョン 2.1 以降の glibc で提供されている。

属性

この節で使用されている用語の説明については、 attributes(7) を参照。

インターフェース 属性
backtrace(), backtrace_symbols(), backtrace_symbols_fd() Thread safety MT-Safe

準拠

これらの関数は GNU による拡張である。

注意

これらの関数は、関数のリターンアドレスがスタック上でどのように格納されるか に関してある仮定を置いている。 以下の点に注意。

シンボル名は特別なリンカーオプションを使用しないと利用できない場合がある。 GNU リンカーを使用するシステムでは、 -rdynamic リンカーオプションを使う必要がある。 "static" な関数のシンボル名は公開されず、 バックトレースでは利用できない点に注意すること。

以下のプログラムは、 backtrace() と backtrace_symbols() の使用例を示したものである。 以下に示すシェルのセッションは、 このプログラムを動かした際の実行例である。


$ cc -rdynamic prog.c -o prog
$ ./prog 3
backtrace() returned 8 addresses
./prog(myfunc3+0x5c) [0x80487f0]
./prog [0x8048871]
./prog(myfunc+0x21) [0x8048894]
./prog(myfunc+0x1a) [0x804888d]
./prog(myfunc+0x1a) [0x804888d]
./prog(main+0x65) [0x80488fb]
/lib/libc.so.6(__libc_start_main+0xdc) [0xb7e38f9c]
./prog [0x8048711]

プログラムのソース

#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BT_BUF_SIZE 100
void
myfunc3(void)
{
    int nptrs;
    void *buffer[BT_BUF_SIZE];
    char **strings;
    nptrs = backtrace(buffer, BT_BUF_SIZE);
    printf("backtrace() returned %d addresses\n", nptrs);
    /* backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO) を
       呼び出しても、以下と同様の出力が得られる。 */
    strings = backtrace_symbols(buffer, nptrs);
    if (strings == NULL) {
        perror("backtrace_symbols");
        exit(EXIT_FAILURE);
    }
    for (int j = 0; j < nptrs; j++)
        printf("%s\n", strings[j]);
    free(strings);
}
static void   /* "static" はシンボルを公開しないことを意味する */
myfunc2(void)
{
    myfunc3();
}
void
myfunc(int ncalls)
{
    if (ncalls > 1)
        myfunc(ncalls - 1);
    else
        myfunc2();
}
int
main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "%s num-calls\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    myfunc(atoi(argv[1]));
    exit(EXIT_SUCCESS);
}

関連項目

addr2line(1), gcc(1), gdb(1), ld(1), dlopen(3), malloc(3)

この文書について

この man ページは Linux man-pages プロジェクトのリリース 5.10 の一部である。プロジェクトの説明とバグ報告に関する情報は https://www.kernel.org/doc/man-pages/ に書かれている。

2020-11-01 GNU