c++ - 非表示 - シンボル情報がありません




プログラムがクラッシュしたときにスタックトレースを自動的に生成する方法 (19)

私はLinux上でGCCコンパイラを使って作業しています。 私のC ++プログラムがクラッシュすると、自動的にスタックトレースが生成されます。

私のプログラムは多くの異なるユーザーによって実行されており、Linux、Windows、およびMacintoshでも動作します(すべてのバージョンはgccを使用してコンパイルされています)。

私は自分のプログラムがクラッシュしたときにスタックトレースを生成できるようにしたいが、次回にユーザがそれを実行するときにスタックトレースを私に送信して問題を追跡できるかどうか尋ねる。 私は情報を私に送信することはできますが、トレース文字列の生成方法はわかりません。 何か案は?


Linux

スタックトレースを出力するためにexecinfo.hのbacktrace()関数を使用してますが、セグメンテーション違反が発生したときに正常終了することは既に提案されいますが 、結果のバックトレースが実際の場所を指していることを確認するためには、 (少なくともいくつかのアーキテクチャでは、x86とARM)。

シグナルハンドラに入ったときのスタックフレームチェーンの最初の2つのエントリには、シグナルハンドラ内のリターンアドレスとlibc内のsigaction()の1つが含まれています。 シグナルの前に呼び出された最後の関数のスタックフレーム(フォルトの位置)が失われます。

コード

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#ifndef __USE_GNU
#define __USE_GNU
#endif

#include <execinfo.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ucontext.h>
#include <unistd.h>

/* This structure mirrors the one found in /usr/include/asm/ucontext.h */
typedef struct _sig_ucontext {
 unsigned long     uc_flags;
 struct ucontext   *uc_link;
 stack_t           uc_stack;
 struct sigcontext uc_mcontext;
 sigset_t          uc_sigmask;
} sig_ucontext_t;

void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext)
{
 void *             array[50];
 void *             caller_address;
 char **            messages;
 int                size, i;
 sig_ucontext_t *   uc;

 uc = (sig_ucontext_t *)ucontext;

 /* Get the address at the time the signal was raised */
#if defined(__i386__) // gcc specific
 caller_address = (void *) uc->uc_mcontext.eip; // EIP: x86 specific
#elif defined(__x86_64__) // gcc specific
 caller_address = (void *) uc->uc_mcontext.rip; // RIP: x86_64 specific
#else
#error Unsupported architecture. // TODO: Add support for other arch.
#endif

 fprintf(stderr, "signal %d (%s), address is %p from %p\n", 
  sig_num, strsignal(sig_num), info->si_addr, 
  (void *)caller_address);

 size = backtrace(array, 50);

 /* overwrite sigaction with caller's address */
 array[1] = caller_address;

 messages = backtrace_symbols(array, size);

 /* skip first stack frame (points here) */
 for (i = 1; i < size && messages != NULL; ++i)
 {
  fprintf(stderr, "[bt]: (%d) %s\n", i, messages[i]);
 }

 free(messages);

 exit(EXIT_FAILURE);
}

int crash()
{
 char * p = NULL;
 *p = 0;
 return 0;
}

int foo4()
{
 crash();
 return 0;
}

int foo3()
{
 foo4();
 return 0;
}

int foo2()
{
 foo3();
 return 0;
}

int foo1()
{
 foo2();
 return 0;
}

int main(int argc, char ** argv)
{
 struct sigaction sigact;

 sigact.sa_sigaction = crit_err_hdlr;
 sigact.sa_flags = SA_RESTART | SA_SIGINFO;

 if (sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL) != 0)
 {
  fprintf(stderr, "error setting signal handler for %d (%s)\n",
    SIGSEGV, strsignal(SIGSEGV));

  exit(EXIT_FAILURE);
 }

 foo1();

 exit(EXIT_SUCCESS);
}

出力

signal 11 (Segmentation fault), address is (nil) from 0x8c50
[bt]: (1) ./test(crash+0x24) [0x8c50]
[bt]: (2) ./test(foo4+0x10) [0x8c70]
[bt]: (3) ./test(foo3+0x10) [0x8c8c]
[bt]: (4) ./test(foo2+0x10) [0x8ca8]
[bt]: (5) ./test(foo1+0x10) [0x8cc4]
[bt]: (6) ./test(main+0x74) [0x8d44]
[bt]: (7) /lib/libc.so.6(__libc_start_main+0xa8) [0x40032e44]

シグナルハンドラでbacktrace()関数を呼び出す危険性はまだありますので、見逃してはいけませんが、私がここで説明した機能は、クラッシュのデバッグに非常に役立ちます。

私が提供した例は、Linux for x86で開発/テストされていることに注意することが重要です。 私はまた、 uc_mcontext.arm_pc代わりにuc_mcontext.eipを使用してARM上でこれを実装しました。

ここでは、この実装の詳細を学んだ記事へのリンクがあります: http://www.linuxjournal.com/article/6391 : http://www.linuxjournal.com/article/6391


"man backserace"よりも簡単ですが、glibcでlibSegFault.soとして配布されている、少し文書化されたライブラリ(GNU特有)があります。これは、プログラムcatchsegv(see "man catchsegv")をサポートするためにUlrich Drepperによって書かれたものです。

これは3つの可能性を与える。 "program -o hai"を実行する代わりに:

  1. catchsegv内で実行する:

    $ catchsegv program -o hai
    
  2. 実行時にlibSegFaultとリンクする:

    $ LD_PRELOAD=/lib/libSegFault.so program -o hai
    
  3. コンパイル時にlibSegFaultとリンクする:

    $ gcc -g1 -lSegFault -o program program.cc
    $ program -o hai
    

3つすべてのケースで、最適化(gcc -O0または-O1)とデバッグシンボル(gcc -g)を減らして、より明確なバックトレースを得ることができます。 さもなければ、あなたはメモリアドレスの束で終わるかもしれません。

また、次のようなものを使ってスタックトレースのシグナルを捕まえることもできます:

$ export SEGFAULT_SIGNALS="all"       # "all" signals
$ export SEGFAULT_SIGNALS="bus abrt"  # SIGBUS and SIGABRT

出力は次のようになります(下部のバックトレースに注目してください)。

*** Segmentation fault Register dump:

 EAX: 0000000c   EBX: 00000080   ECX:
00000000   EDX: 0000000c  ESI:
bfdbf080   EDI: 080497e0   EBP:
bfdbee38   ESP: bfdbee20

 EIP: 0805640f   EFLAGS: 00010282

 CS: 0073   DS: 007b   ES: 007b   FS:
0000   GS: 0033   SS: 007b

 Trap: 0000000e   Error: 00000004  
OldMask: 00000000  ESP/signal:
bfdbee20   CR2: 00000024

 FPUCW: ffff037f   FPUSW: ffff0000  
TAG: ffffffff  IPOFF: 00000000  
CSSEL: 0000   DATAOFF: 00000000  
DATASEL: 0000

 ST(0) 0000 0000000000000000   ST(1)
0000 0000000000000000  ST(2) 0000
0000000000000000   ST(3) 0000
0000000000000000  ST(4) 0000
0000000000000000   ST(5) 0000
0000000000000000  ST(6) 0000
0000000000000000   ST(7) 0000
0000000000000000

Backtrace:
/lib/libSegFault.so[0xb7f9e100]
??:0(??)[0xb7fa3400]
/usr/include/c++/4.3/bits/stl_queue.h:226(_ZNSt5queueISsSt5dequeISsSaISsEEE4pushERKSs)[0x805647a]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/player.cpp:73(_ZN6Player5inputESs)[0x805377c]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/socket.cpp:159(_ZN6Socket4ReadEv)[0x8050698]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/socket.cpp:413(_ZN12ServerSocket4ReadEv)[0x80507ad]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/socket.cpp:300(_ZN12ServerSocket4pollEv)[0x8050b44]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/main.cpp:34(main)[0x8049a72]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe5)[0xb7d1b775]
/build/buildd/glibc-2.9/csu/../sysdeps/i386/elf/start.S:122(_start)[0x8049801]

もしあなたが細部の詳細を知りたければ、残念なことにソースとして最適です: http://sourceware.org/git/?p=glibc.git;a=blob;f=debug/segfault.c ://sourceware.org/git/?p=glibc.git;a=blob;f=debug/segfault.cとその親ディレクトリを参照してhttp://sourceware.org/git/?p=glibc.git;a=blob;f=debug/segfault.c http://sourceware.org/git/?p=glibc.git;a=tree;f=debug


GNU libc backtrace()関数の使い方を記述した正しい答えが与えられていて、シグナルハンドラからのバックトレースが実際の障害の位置を指すようにする方法を記述した私自身の答えを提供しました2 、バックトレースから出力されたC ++シンボルをdemanglingすることについては言及していません。

C ++プログラムからバックトレースを取得する場合、出力は、シンボルをデマングルするために、またはabi::__cxa_demangle 1を直接使用して、 c++filt 1を通して実行できます。

  • 1 Linux&OS X c++filt__cxa_demangleはGCC固有のものです
  • 2 Linux

次のC ++ Linuxの例では、私の他の答えと同じシグナルハンドラを使用し、シンボルをデマングルするためにc++filtどのように使用できるかを示しています。

コード

class foo
{
public:
    foo() { foo1(); }

private:
    void foo1() { foo2(); }
    void foo2() { foo3(); }
    void foo3() { foo4(); }
    void foo4() { crash(); }
    void crash() { char * p = NULL; *p = 0; }
};

int main(int argc, char ** argv)
{
    // Setup signal handler for SIGSEGV
    ...

    foo * f = new foo();
    return 0;
}

出力./test ):

signal 11 (Segmentation fault), address is (nil) from 0x8048e07
[bt]: (1) ./test(crash__3foo+0x13) [0x8048e07]
[bt]: (2) ./test(foo4__3foo+0x12) [0x8048dee]
[bt]: (3) ./test(foo3__3foo+0x12) [0x8048dd6]
[bt]: (4) ./test(foo2__3foo+0x12) [0x8048dbe]
[bt]: (5) ./test(foo1__3foo+0x12) [0x8048da6]
[bt]: (6) ./test(__3foo+0x12) [0x8048d8e]
[bt]: (7) ./test(main+0xe0) [0x8048d18]
[bt]: (8) ./test(__libc_start_main+0x95) [0x42017589]
[bt]: (9) ./test(__register_frame_info+0x3d) [0x8048981]

デミングル出力./test 2>&1 | c++filt ):

signal 11 (Segmentation fault), address is (nil) from 0x8048e07
[bt]: (1) ./test(foo::crash(void)+0x13) [0x8048e07]
[bt]: (2) ./test(foo::foo4(void)+0x12) [0x8048dee]
[bt]: (3) ./test(foo::foo3(void)+0x12) [0x8048dd6]
[bt]: (4) ./test(foo::foo2(void)+0x12) [0x8048dbe]
[bt]: (5) ./test(foo::foo1(void)+0x12) [0x8048da6]
[bt]: (6) ./test(foo::foo(void)+0x12) [0x8048d8e]
[bt]: (7) ./test(main+0xe0) [0x8048d18]
[bt]: (8) ./test(__libc_start_main+0x95) [0x42017589]
[bt]: (9) ./test(__register_frame_info+0x3d) [0x8048981]

以下は、私の元の答えからシグナルハンドラを構築し、上記の例のシグナルハンドラを置き換えて、 abi::__cxa_demangleを使ってシンボルをデマングルする方法を示します。 このシグナルハンドラは、上記の例と同じ出力を生成します。

コード

void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext)
{
    sig_ucontext_t * uc = (sig_ucontext_t *)ucontext;

    void * caller_address = (void *) uc->uc_mcontext.eip; // x86 specific

    std::cerr << "signal " << sig_num 
              << " (" << strsignal(sig_num) << "), address is " 
              << info->si_addr << " from " << caller_address 
              << std::endl << std::endl;

    void * array[50];
    int size = backtrace(array, 50);

    array[1] = caller_address;

    char ** messages = backtrace_symbols(array, size);    

    // skip first stack frame (points here)
    for (int i = 1; i < size && messages != NULL; ++i)
    {
        char *mangled_name = 0, *offset_begin = 0, *offset_end = 0;

        // find parantheses and +address offset surrounding mangled name
        for (char *p = messages[i]; *p; ++p)
        {
            if (*p == '(') 
            {
                mangled_name = p; 
            }
            else if (*p == '+') 
            {
                offset_begin = p;
            }
            else if (*p == ')')
            {
                offset_end = p;
                break;
            }
        }

        // if the line could be processed, attempt to demangle the symbol
        if (mangled_name && offset_begin && offset_end && 
            mangled_name < offset_begin)
        {
            *mangled_name++ = '\0';
            *offset_begin++ = '\0';
            *offset_end++ = '\0';

            int status;
            char * real_name = abi::__cxa_demangle(mangled_name, 0, 0, &status);

            // if demangling is successful, output the demangled function name
            if (status == 0)
            {    
                std::cerr << "[bt]: (" << i << ") " << messages[i] << " : " 
                          << real_name << "+" << offset_begin << offset_end 
                          << std::endl;

            }
            // otherwise, output the mangled function name
            else
            {
                std::cerr << "[bt]: (" << i << ") " << messages[i] << " : " 
                          << mangled_name << "+" << offset_begin << offset_end 
                          << std::endl;
            }
            free(real_name);
        }
        // otherwise, print the whole line
        else
        {
            std::cerr << "[bt]: (" << i << ") " << messages[i] << std::endl;
        }
    }
    std::cerr << std::endl;

    free(messages);

    exit(EXIT_FAILURE);
}

Linuxの場合、gccを使用している場合はMac OS X、glibcを使用するコンパイラを使用する場合は、 execinfo.h backtrace()関数を使用してスタックトレースをexecinfo.hし、セグメント化エラーが発生したときに正常に終了できます。 マニュアルはlibcマニュアルにあります

ここでは、 SIGSEGVハンドラをインストールし、segfaults時にスタックトレースをstderrするプログラム例を示します。 ここでbaz()関数を呼び出すと、ハンドラをトリガするsegfaultが発生します。

#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コンパイルすると、シンボル情報が出力されます-g -rdynamicはこれを使って素敵なスタックトレースを作成できます:

$ 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]

これは、スタック内の各フレームが発生したロードモジュール、オフセット、および関数を示しています。 ここでは、 mainfoobar 、およびbazに加えて、スタックの上にシグナルハンドラがあり、 main前にlibc関数があります。


backtrace()関数やマクロを使ってソースを変更したり、ハックしたりするのは忘れてください。

適切に機能する解決策として、私はアドバイスをします:

  1. デバッグシンボルをバイナリに埋め込むために、プログラムを "-g"フラグでコンパイルします(これはあなたのパフォーマンスには影響しません)。
  2. Linuxでは次のコマンドを実行します: "ulimit -c unlimited" - システムが大きなクラッシュダンプを作成できるようにします。
  3. プログラムがクラッシュしたとき、作業ディレクトリにファイル "core"が表示されます。
  4. バックトレースをstdoutに出力するには、次のコマンドを実行します。gdb -batch -ex "backtrace" ./your_program_exe ./core

これは、プログラムの適切な読み取り可能なバックトレースを人間が読める形式で出力します(ソースファイル名と行番号で)。 プロセスがコアダンプを作成したかどうかを確認し、開発者に電子メールでバックトレースを送信するか、またはこれをいくつかのログシステムに記録する短いスクリプトを用意して、システムを自動化することができます。


libcのいくつかのバージョンには、スタックトレースを扱う関数が含まれています。 それらを使用することができます:

http://www.gnu.org/software/libc/manual/html_node/Backtraces.html

私はスタックトレースを得るために長い時間前にlibunwindを使用したことを覚えていますが、あなたのプラットフォームではサポートされていないかもしれません。


ACEスタックトレース機能(ADAPTIVE通信環境)を参照してください。 これは、すべての主要なプラットフォーム(とそれ以上)をカバーするためにすでに書かれています。 ライブラリはBSD形式でライセンスされているので、ACEを使用したくない場合でもコードをコピー/ペーストすることができます。


Google Breakpad 、クロスプラットフォームのクラッシュダンプジェネレータとダンプを処理するツールを検討する価値があります。


ulimit -c <value>は、コアファイルサイズの制限をunixに設定します。 デフォルトでは、コアファイルのサイズ制限は0ですulimit -aを使用してulimit値を確認できます。

また、gdbの中からプログラムを実行すると、プログラムは "セグメンテーション違反"( SIGSEGV 、割り当てられていないメモリにアクセスしたとき)に停止するか、ブレークポイントを設定することができます。

dddとnemiverはgdbのフロントエンドであり、初心者の方にとっては非常に簡単です。


あなたはオペレーティングシステムを指定していないので、これは答えにくいです。 gnu libcに基づくシステムを使用している場合は、libc関数backtrace()を使用することができます。

GCCには、あなたを助けることができる2つの組み込み関数がありますが、それらはあなたのアーキテクチャで完全に実装されているかもしれませんし、 __builtin_frame_address__builtin_return_addressです。 どちらも直近の整数レベルが必要です(即値では変数ではありません)。 指定されたレベルの__builtin_frame_addressがゼロでない場合、同じレベルの戻りアドレスを取得することは安全です。


上記の回答に加えて、ここでDebian Linux OSでコアダンプを生成させる方法

  1. ユーザーのホームフォルダに "coredumps"フォルダを作成する
  2. /etc/security/limits.confに移動します。 ''の行の下に "soft core unlimited"と入力し、ルートのコアダンプを有効にしている場合は "root soft core unlimited"と入力し、コアダンプのスペースを無制限にします。
  3. 注: "* soft core unlimited"はルートをカバーしていないため、ルートはそれ自身の行で指定する必要があります。
  4. これらの値を確認するには、ログアウトして再度ログインし、 "ulimit -a"と入力します。「コアファイルサイズ」は無制限に設定する必要があります。
  5. 。ulimitがそこに設定されていないことを確認するには、.bashrcファイル(ユーザーとrootが該当する場合)を調べます。それ以外の場合、上記の値は起動時に上書きされます。
  6. /etc/sysctl.confを開きます。一番下に「kernel.core_pattern = /home//coredumps/%e_%t.dump」と入力します。(%eはプロセス名、%tはシステム時刻になります)
  7. exitとタイプして "sysctl -p"と入力して、新しい設定を読み込みます。/ proc / sys / kernel / core_patternを確認し、あなたが入力したものと一致することを確認してください。
  8. コアダンプは、コマンドライン( "&")でプロセスを実行し、kill -11で強制終了することでテストできます。コアダンプが成功した場合、セグメンテーションフォルトの表示後に "(コアダンプされた)"が表示されます。

町の新しい王が到着しましたhttps://github.com/bombela/backward-cpp

1ヘッダをコードに配置し、1ライブラリをインストールします。

個人的に私はこの関数を使って呼びます

#include "backward.hpp"
void stacker() {

using namespace backward;
StackTrace st;


st.load_here(99); //Limit the number of trace depth to 99
st.skip_n_firsts(3);//This will skip some backward internal function from the trace

Printer p;
p.snippet = true;
p.object = true;
p.color = true;
p.address = true;
p.print(st, stderr);
}

私は@ tgamblinの解決策が完全ではないことを発見しました。 それは、で処理することはできません。 私は、デフォルトではシグナルハンドラは同じスタックで呼び出され、SIGSEGVは2回スローされるからだと思います。 あなたを保護するには、シグナルハンドラのために独立したスタックを登録する必要があります。

これは以下のコードで確認できます。 デフォルトでは、ハンドラは失敗します。 定義されたマクロSTACK_OVERFLOWでは問題ありません。

#include <iostream>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include <cassert>

using namespace std;

//#define STACK_OVERFLOW

#ifdef STACK_OVERFLOW
static char stack_body[64*1024];
static stack_t sigseg_stack;
#endif

static struct sigaction sigseg_handler;

void handler(int sig) {
  cerr << "sig seg fault handler" << endl;
  const int asize = 10;
  void *array[asize];
  size_t size;

  // get void*'s for all entries on the stack
  size = backtrace(array, asize);

  // print out all the frames to stderr
  cerr << "stack trace: " << endl;
  backtrace_symbols_fd(array, size, STDERR_FILENO);
  cerr << "resend SIGSEGV to get core dump" << endl;
  signal(sig, SIG_DFL);
  kill(getpid(), sig);
}

void foo() {
  foo();
}

int main(int argc, char **argv) {
#ifdef STACK_OVERFLOW
  sigseg_stack.ss_sp = stack_body;
  sigseg_stack.ss_flags = SS_ONSTACK;
  sigseg_stack.ss_size = sizeof(stack_body);
  assert(!sigaltstack(&sigseg_stack, nullptr));
  sigseg_handler.sa_flags = SA_ONSTACK;
#else
  sigseg_handler.sa_flags = SA_RESTART;  
#endif
  sigseg_handler.sa_handler = &handler;
  assert(!sigaction(SIGSEGV, &sigseg_handler, nullptr));
  cout << "sig action set" << endl;
  foo();
  return 0;
} 

私はLinux版で助けることができます:関数backtrace、backtrace_symbols、backtrace_symbols_fdを使うことができます。 対応するマニュアルページを参照してください。


私はこの問題をしばらく見ていました。

GoogleのパフォーマンスツールのREADMEには深く掘り下げられています

http://code.google.com/p/google-perftools/source/browse/trunk/README

libunwindについて語る

libunwind

この図書館の意見を聞くのが大好きです。

-rdynamicの問題は、バイナリのサイズをある程度大きくすることができるということです


見る:

男3バックトレース

そして:

#include <exeinfo.h>
int backtrace(void **buffer, int size);

これらはGNU拡張です。


Windowsのみのソリューションとして、Windows WERを使用して、スタックトレースと同等のものを(多くの情報をWER)得ることができます。わずかなレジストリエントリで、ユーザモードのダンプ収集するように設定できます。

Windows Server 2008およびWindows Vista Service Pack 1(SP1)から、ユーザーモードアプリケーションがクラッシュした後に完全なユーザーモードダンプが収集され、ローカルに格納されるようにWindowsエラー報告(WER)を構成できます。 [...]

この機能はデフォルトでは有効になっていません。この機能を有効にするには、管理者権限が必要です。機能を有効にして構成するには、HKEY_LOCAL_MACHINE¥SOFTWARE¥Microsoft¥Windows¥Windowsのエラー報告¥LocalDumpsキーの下にある次のレジストリ値を使用します。

必要な権限を持つインストーラからレジストリエントリを設定できます。

ユーザーモードダンプを作成すると、クライアント上でスタックトレースを生成する場合に比べて、次のような利点があります。

  • すでにシステムに実装されています。上で概説したようにWERを使用するか、ダンプする情報の量を細かく制御する必要がある場合は、MiniDumpWriteDump自分で呼び出してください。(別のプロセスから呼び出してください)
  • スタックトレースよりも完全な方法。とりわけ、ローカル変数、関数引数、他のスレッドのスタック、ロードされたモジュールなどを含むことができます。データ量(および結果としてサイズ)は高度にカスタマイズ可能です。
  • デバッグシンボルを出荷する必要はありません。これにより、デプロイメントのサイズが大幅に減少するだけでなく、アプリケーションのリバースエンジニアリングが難しくなります。
  • 大部分はコンパイラに依存しません。WERを使用してもコードは必要ありません。いずれにしても、シンボルデータベース(PDB)を取得する方法は、オフライン分析に非常に役立ちます。私はGCCがPDBを生成できると信じています。あるいは、シンボルデータベースをPDB形式に変換するツールがあります。

そのWERは、アプリケーションのクラッシュ(つまり、処理されない例外のためにプロセスを終了させるシステム)によってのみ引き起こされることに注意してください。MiniDumpWriteDumpいつでも呼び出すことができます。これは、クラッシュ以外の問題を診断するために現在の状態をダンプする必要がある場合に役立ちます。

ミニダンプの適用性を評価したい場合は必須の読み:


プログラムがクラッシュした場合、クラッシュダンプ情報を生成するのはオペレーティングシステム自体です。あなたが* nix OSを使用しているならば、単にulimitコマンドの 'coredump'オプションをチェックしてください。


ulimit -c unlimited

アプリケーションがクラッシュした後にコアダンプを作成できるようにするシステム変数です。 この場合、無制限の金額です。 非常に同じディレクトリにあるcoreというファイルを探します。 デバッグ情報を有効にしてコードをコンパイルしてください!

敬具





assert