私は Linux で GCC コンパイラを使って作業しています。C++ プログラムがクラッシュしたときに、スタックトレースを自動的に生成したいと思います。
私のプログラムは多くの異なるユーザーによって実行されており、Linux、Windows、Macintosh でも実行されます (すべてのバージョンは を使用してコンパイルされていますgcc
)。
プログラムがクラッシュしたときにスタック トレースを生成し、次回ユーザーがプログラムを実行したときに、問題を追跡できるようにスタック トレースを送信してもよいかどうかをユーザーに確認できるようにしたいと考えています。情報を送信することはできますが、トレース文字列を生成する方法がわかりません。何かアイデアはありますか?
ベストアンサー1
LinuxおよびMac OS Xでは、gccまたはglibcを使用するコンパイラを使用している場合、セグメンテーション違反が発生したときにスタックトレースを出力して正常に終了するためにbacktrace()関数を使用できますexecinfo.h
。ドキュメントはlibcマニュアル内。
SIGSEGV
以下は、ハンドラをインストールし、セグメント エラーが発生したときにスタック トレースを出力するサンプル プログラムですstderr
。baz()
この関数は、ハンドラをトリガーするセグメント エラーを引き起こします。
#include <stdio.h>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
void handler(int sig) {
void *array[10];
size_t size;
// get void*'s for all entries on the stack
size = backtrace(array, 10);
// print out all the frames to stderr
fprintf(stderr, "Error: signal %d:\n", sig);
backtrace_symbols_fd(array, size, STDERR_FILENO);
exit(1);
}
void baz() {
int *foo = (int*)-1; // make a bad pointer
printf("%d\n", *foo); // causes segfault
}
void bar() { baz(); }
void foo() { bar(); }
int main(int argc, char **argv) {
signal(SIGSEGV, handler); // install our handler
foo(); // this will call foo, bar, and baz. baz segfaults.
}
コンパイルすると-g -rdynamic
出力にシンボル情報が得られ、glibc はこれを使用して適切なスタックトレースを作成できます。
$ gcc -g -rdynamic ./test.c -o test
これを実行すると、次の出力が得られます。
$ ./test
Error: signal 11:
./test(handler+0x19)[0x400911]
/lib64/tls/libc.so.6[0x3a9b92e380]
./test(baz+0x14)[0x400962]
./test(bar+0xe)[0x400983]
./test(foo+0xe)[0x400993]
./test(main+0x28)[0x4009bd]
/lib64/tls/libc.so.6(__libc_start_main+0xdb)[0x3a9b91c4bb]
./test[0x40086a]
これは、スタック内の各フレームの取得元のロード モジュール、オフセット、および関数を示しています。ここでは、、、、およびmain
に加えて、スタックの一番上にあるシグナル ハンドラーと、その前の libc 関数を確認できます。main
foo
bar
baz