web-dev-qa-db-ja.com

プログラム内からgdbを呼び出してスタックトレースを出力する最良の方法は?

次のような関数を使用します。

#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

void print_trace() {
    char pid_buf[30];
    sprintf(pid_buf, "--pid=%d", getpid());
    char name_buf[512];
    name_buf[readlink("/proc/self/exe", name_buf, 511)]=0;
    int child_pid = fork();
    if (!child_pid) {           
        dup2(2,1); // redirect output to stderr
        fprintf(stdout,"stack trace for %s pid=%s\n",name_buf,pid_buf);
        execlp("gdb", "gdb", "--batch", "-n", "-ex", "thread", "-ex", "bt", name_buf, pid_buf, NULL);
        abort(); /* If gdb failed to start */
    } else {
        waitpid(child_pid,NULL,0);
    }
}

出力にprint_traceの詳細が表示されます。

他の方法はありますか?

57
Vi.

Linuxを使用している場合、標準Cライブラリには、backtraceという関数が含まれています。これは、フレームの戻りアドレスを配列に設定し、backtrace_symbolsという別の関数は、backtraceからアドレスを取得し、対応する関数を検索します名前。これらは GNU C Libraryマニュアル に文書化されています。

これらは引数値、ソース行などを表示せず、呼び出しスレッドにのみ適用されます。ただし、GDBをそのように実行するよりもはるかに高速(そしておそらくそれほど安定的ではない)でなければならないので、彼らは自分たちの場所を持っています。

8
Jim Blandy

nobar 投稿済み 素晴らしい回答 要するに;

したがって、gdbスタックトレースにあり、アプリケーションを終了しないすべての機能を備えたスタックトレースを出力するスタンドアロン関数が必要です。答えは、非対話モードでのgdbの起動を自動化して、必要なタスクのみを実行することです。

これは、fork()を使用してgdbを子プロセスで実行し、アプリケーションがスクリプトの完了を待機している間にスタックトレースを表示するようにスクリプトを作成することによって行われます。これは、コアダンプを使用せずに、アプリケーションを中断せずに実行できます。

これがあなたが探しているものだと思います、@ Vi

6
karlphillip

abort()は単純ではありませんか?

こうすることで、フィールドで発生した場合、顧客はコアファイルを送信できます(myアプリケーションに十分に関与してデバッグを強制する多くのユーザーを知りません)。

1
Motti