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
  個の直近の関数呼び出しに対応するアドレスが返される。
  完全なバックトレースを取得するためには、確実に
  
buffer と 
size
  が十分大きくなるようにすること。
backtrace() によって 
buffer
  にアドレスの集合が得られたら、
  
backtrace_symbols()
  によって、アドレス集合を、そのアドレスをシンボルで表した文字列の配列
  に翻訳できる。 
size
  引き数は 
buffer
  に格納されたアドレスの数を指定する。
  個々のアドレスのシンボル表現は、関数名
  (特定できた場合)、
  関数へのオフセット
  (16進表記)、実際のリターンアドレス
  (16進表記)
  から構成される。
  
backtrace_symbols()
  の実行結果としては、
  文字列ポインタの配列のアドレスが返される。
  この配列は 
backtrace_symbols()
  によって 
malloc(3)
  され、呼び出し側で free
  しなければならない
  (ポインタの配列が指す個々の文字列は
  free する必要はないし、
  free すべきでもない)。
backtrace_symbols_fd() は、 
backtrace_symbols()
  と同じ引き数 
buffer と
  
size
  をとるが、呼び出し側に文字列の配列を返す代わりに、
  文字列をファイルディスクリプタ
  
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 で提供されている。
これらの関数は GNU
  による拡張である。
これらの関数は、関数のリターンアドレスがスタック上でどのように格納されるか
  に関してある仮定を置いている。
  以下の点に注意。
  - *
 
  - (gcc(1) の 0
      以外の最適化レベルで暗黙のうちに行われる)
      フレームポインタの省略を行うと、これらの前提が崩れる可能性がある。
 
  - *
 
  - インライン関数はスタックフレームを持たない。
 
  - *
 
  - 末尾呼び出しの最適化
      (tail-call optimization) を行うと、
      あるスタックフレームが別のスタックフレームを置き換える可能性がある。
 
シンボル名は特別なリンカ・オプションを使用しないと利用できない場合がある。
  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>
void
myfunc3(void)
{
    int j, nptrs;
#define SIZE 100
    void *buffer[100];
    char **strings;
    nptrs = backtrace(buffer, 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 (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);
}
関連項目¶
gcc(1), 
ld(1), 
dlopen(3), 
malloc(3)
この文書について¶
この man ページは Linux 
man-pages
  プロジェクトのリリース
  3.65 の一部
  である。プロジェクトの説明とバグ報告に関する情報は
  
http://www.kernel.org/doc/man-pages/
  に書かれている。