33

この質問は以前に尋ねられ、Windows 固有の回答がありましたが、満足のいく gcc の回答はありませんでした。未処理の例外がスローされたときにset_terminate()( の代わりに) 呼び出される関数を設定するために使用できます。terminate()バックトレース ライブラリを使用して、プログラム内の特定のポイントからスタック トレースを生成する方法を知っています。ただし、terminate-replacement が呼び出された時点でスタックが巻き戻されているため、これは役に立ちません。

それでも、単にプログラムを許可するabort()と、例外がスローされた時点からの完全なスタック情報を含むコア ダンプが生成されます。情報はそこにありますが、たとえば、コアファイルを調べるのではなく、ログに記録できるようにプログラムで取得する方法はありますか?

4

3 に答える 3

32

編集された回答:

std::set_terminateを使用できます

#include <cstdlib>
#include <iostream>
#include <stdexcept>

#include <execinfo.h>

void
handler()
{
    void *trace_elems[20];
    int trace_elem_count(backtrace( trace_elems, 20 ));
    char **stack_syms(backtrace_symbols( trace_elems, trace_elem_count ));
    for ( int i = 0 ; i < trace_elem_count ; ++i )
    {
        std::cout << stack_syms[i] << "\n";
    }
    free( stack_syms );

    exit(1);
}   

int foo()
{
    throw std::runtime_error( "hello" );
}   

void bar()
{
    foo();
}

void baz()
{
    bar();
}

int
main()
{
    std::set_terminate( handler );
    baz();
}

この出力を与える:

samm@macmini ~> ./a.out 
./a.out [0x10000d20]
/usr/lib/libstdc++.so.6 [0xf9bb8c8]
/usr/lib/libstdc++.so.6 [0xf9bb90c]
/usr/lib/libstdc++.so.6 [0xf9bbaa0]
./a.out [0x10000c18]
./a.out [0x10000c70]
./a.out [0x10000ca0]
./a.out [0x10000cdc]
/lib/libc.so.6 [0xfe4dd80]
/lib/libc.so.6 [0xfe4dfc0]
samjmill@bgqfen4 ~> 

バイナリにデバッグシンボルがあると仮定すると、addr2lineを使用して、よりきれいなスタックトレースを事後的に構築できます。

samm@macmini ~> addr2line 0x10000c18
/home/samm/foo.cc:23
samm@macmini ~> 

元の答えは以下です


私は過去にboost::error_infobacktraceを使用してこれを行い、 fromを使用してスタックトレースをexecinfo.hスローされた例外に挿入しました。

typedef boost::error_info<struct tag_stack_str,std::string> stack_info;

次に、例外をキャッチするときに、次のことができます。

} catch ( const std::exception& e ) {                                                                                                            
    if ( std::string const *stack boost::get_error_info<stack_error_info>(e) ) {                    
        std::cout << stack << std::endl;
    }
}
于 2010-07-28T19:02:58.043 に答える
4

しかし、単にプログラムにabort()を許可すると、例外がスローされた時点からの完全なスタック情報を含むコアダンプが生成されます。したがって、情報はそこにありますが、コアファイルを調べるのではなく、たとえばログに記録できるように、プログラムで取得する方法はありますか?

私の経験があなたのニーズに合うとは思えませんが、とにかくここに行きます。

abort()libcの前に独自のオブジェクトファイルを追加するか、LD_PRELOADを使用して、オーバーロードしていました。私自身のバージョンではabort()、プロセスにアタッチし(まあ、私は確かに私のPIDを知っています)、スタックトレースをファイルにダンプするようにデバッガーを起動していました(コマンドはコマンドラインを介してデバッガーに渡されました)。デバッガーが終了したら、たとえばでプロセスを終了します_exit(100)

これは、GDBを使用するLinuxでのことです。Solarisでは、私は日常的に同様のトリックを採用していますが、正常なデバッガーが利用できないため、pstackツールを使用していますsystem("pstack <PID>")

于 2010-07-28T21:31:07.840 に答える