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 にアドレスの集合が得られたら、 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_symbols() は、成功すると、この呼び出しで malloc(3) された配列へのポインタを返す。 エラーの場合、 NULL を返す。
シンボル名は特別なリンカ・オプションを使用しないと利用できない場合がある。 GNU リンカを使用するシステムでは、 -rdynamic リンカ・オプションを使う必要がある。 "static" な関数のシンボル名は公開されず、 バックトレースでは利用できない点に注意すること。
$ 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);
}