カーネル内であれば、show_stack()を呼び出すことで走行時のスタックトレースを簡単に得ることが出来ますが、アプリケーションプログラムでもexecinfoを使うと同様のことが出来ます。
具体的には、
- backtrace()関数でスタック情報を取得します。
スタック情報はvoidのポインタへの配列として用意します。この配列の大きさが、取得できるスタックの深さ(ネスト)の最大値を規定することになります。backtrace()関数の戻り値が実際に取得したスタックの深さになります。void *trace[100];
nr = backtrace(trace, 100); - backtrace_symbol()関数で、取得したスタック情報をシンボル化します。
char **ents;
ents = backtrace_symbols(trace, nr); - 取得したスタック情報を表示
for(i=0; i<nr; i++) {
printf("#%d : [%s]\n", i, ents[i]);
} - 後始末(シンボル配列の開放)
backtrace_symbols()関数はchar *の配列を返却しますが、この配列はbacktrace_symbols()関数が内部的にmalloc(3)で確保したものなので、最後にfreeしてあげる必要があります。
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#define MAXFRAME 64
void show_stack(void)
{
int i, nr;
void *trace[MAXFRAME];
char **ents;
nr = backtrace(trace, MAXFRAME);
if (nr>=MAXFRAME) {
printf("Stack too deep, some entries are stripped off\n");
}
ents = backtrace_symbols(trace, nr);
if (ents == NULL) {
perror("backtrace_symbols");
exit(1);
}
for(i=0; i<nr; i++) {
printf("#%d : [%s]\n", i, ents[i]);
}
free(ents);
}
void b(void)
{
show_stack();
}
void a(void)
{
b();
}
main()
{
a();
}
実行例です。正しくスタック情報が取れていることが判ります。
# cc execinfo.c -o execinfo
# ./execinfo
#0 : [./execinfo(show_stack+0x1f) [0x8048743]]
#1 : [./execinfo(b+0xb) [0x80487dd]]
#2 : [./execinfo(a+0xb) [0x80487ea]]
#3 : [./execinfo(main+0x16) [0x8048802]]
#4 : [/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe0) [0xb7e6b450]]
#5 : [./execinfo [0x80486c1]]
なお、エクスポートしていないシンボルは当然ながら表示されないので、確実に表示したい場合には ld に -rdynamic オプションを付与しなければなりません。
0 件のコメント:
コメントを投稿