2011-08-04 6 views
10

私の(C++)プログラムの実行のある時点でバックトレースを取得しようとしています。スタックトレースと名前空間での機能

私はバックトレースとbacktrace_symbolsを使用しています。この行に沿ったもの:

std::string stacktrace(unsigned int frames_to_skip) 
{ 
    std::string str; 

    void* stack_addrs[50]; 
    int trace_size = backtrace(stack_addrs, 50); 
    char** stack_strings = backtrace_symbols(stack_addrs, trace_size); 

    str += "[bt] backtrace:\n"; 
    // skip frames_to_skip stack frames 
    for(int i = frames_to_skip; i < trace_size; ++i) 
    { 
     char tmp[4096]; 
     sprintf(tmp, "[bt] #%d %s\n", i-frames_to_skip, stack_strings[i]); 
     str += tmp; 
    } 

    free(stack_strings); 

    return str; 
} 

機能はありますが、一部の機能名がありません。例:私は(他の修正なし)無名の名前空間内の関数9を入れてみました
...彼らはすべての名前空間に座って、それからdisapears:

[bt] #0 /path/to/executable() [0x43e1b5] 
[bt] #1 /path/to/executable() [0x43e0cd] 
[bt] #2 /path/to/executable() [0x43df51] 
[bt] #3 /path/to/executable() [0x43dd44] 
[bt] #4 /path/to/executable() [0x43db50] 
[bt] #5 /path/to/executable() [0x43d847] 
[bt] #6 /path/to/executable() [0x43d216] 
[bt] #7 /path/to/executable() [0x43c1e1] 
[bt] #8 /path/to/executable() [0x43b293] 
[bt] #9 /path/to/executable(_Z29SomeRN5other8symbolE+0x2c) [0x43a6ca] 
[bt] #10 /path/to/executable(_Z11SomeIN5_8symbolEPFvRS1_EEvRKT_RKT0_+0x77) [0x441716] 
... 

機能0〜8つの共通点を持っていますバックトレース...次のようになります。それを修正する方法はあり

[bt] #0 /path/to/executable() [0x43e1b5] 
[bt] #1 /path/to/executable() [0x43e0cd] 
[bt] #2 /path/to/executable() [0x43df51] 
[bt] #3 /path/to/executable() [0x43dd44] 
[bt] #4 /path/to/executable() [0x43db50] 
[bt] #5 /path/to/executable() [0x43d847] 
[bt] #6 /path/to/executable() [0x43d216] 
[bt] #7 /path/to/executable() [0x43c1e1] 
[bt] #8 /path/to/executable() [0x43b293] 
[bt] #9 /path/to/executable() [0x43a6ca] 
[bt] #10 /path/to/executable(_Z11SomeIN5_8symbolEPFvRS1_EEvRKT_RKT0_+0x77) [0x441716] 
... 

PS:++グラムのバージョン: G ++(GCC)4.6.0 20110530(Red Hatの4.6.0-9)コードモンキーの発言の後にバックトレースの最大の深さを固定

編集
EDIT2
EDIT3コードは-O0 -g3してコンパイルし、使用している機能かもしれ-rdynamic

答えて

6

あなたの問題とリンクされている機能の完全なコードを追加しました。 max_depthbacktrace(..)は16に設定されています。それは低すぎるかもしれません。とにかく...

C++ stack traces with GCCのこのブログ記事は、スタックトレースの実行方法について説明しています。要するに、

#include <execinfo.h> 
void print_trace(FILE *out, const char *file, int line) 
{ 
    const size_t max_depth = 100; 
    size_t stack_depth; 
    void *stack_addrs[max_depth]; 
    char **stack_strings; 

    stack_depth = backtrace(stack_addrs, max_depth); 
    stack_strings = backtrace_symbols(stack_addrs, stack_depth); 

    fprintf(out, "Call stack from %s:%d:\n", file, line); 

    for (size_t i = 1; i < stack_depth; i++) { 
     fprintf(out, " %s\n", stack_strings[i]); 
    } 
    free(stack_strings); // malloc()ed by backtrace_symbols 
    fflush(out); 
} 

GCCはまたC++名(デ)マングラーへのアクセスを提供します。そこメモリの所有権について学ぶためにいくつかの かなり毛深い詳細は、スタックトレース出力を のインターフェースは、文字列解析のビットを必要とするが、それは は、これに上記内側のループを交換するに沸く:

#include <cxxabi.h> 
... 
for (size_t i = 1; i < stack.depth; i++) { 
    size_t sz = 200; // just a guess, template names will go much wider 
    char *function = static_cast(malloc(sz)); 
    char *begin = 0, *end = 0; 
    // find the parentheses and address offset surrounding the mangled name 
    for (char *j = stack.strings[i]; *j; ++j) { 
     if (*j == '(') { 
      begin = j; 
     } 
     else if (*j == '+') { 
      end = j; 
     } 
    } 
    if (begin && end) { 
     *begin++ = ''; 
     *end = ''; 
     // found our mangled name, now in [begin, end) 

     int status; 
     char *ret = abi::__cxa_demangle(begin, function, &sz, &status); 
     if (ret) { 
      // return value may be a realloc() of the input 
      function = ret; 
     } 
     else { 
      // demangling failed, just pretend it's a C function with no args 
      std::strncpy(function, begin, sz); 
      std::strncat(function, "()", sz); 
      function[sz-1] = ''; 
     } 
     fprintf(out, " %s:%s\n", stack.strings[i], function); 
    } 
    else 
    { 
     // didn't find the mangled name, just print the whole line 
     fprintf(out, " %s\n", stack.strings[i]); 
    } 
    free(function); 
} 

そのサイトに関する詳細情報があります(私は逐語的にコピーしたくありませんでした)が、このコードを見れば、上記のサイトは正しい軌道に乗ります。

+0

こんにちは、お返事ありがとうございます。あなたは最大深さについて正しいですが、バックトレースの最後は欠落していましたが、それらの欠落した呼び出しは私が使用しているテストフレームワークからのものであったため、問題はありません。それでも問題は残っており、私はブログ記事と同じことを言っています。ただし、テストフレームワークは名前空間に関数を持ち、stacktraceに表示されています。私の関数はそうではありません...私は再びテストを行いました(名前空間に関数を入れました)バックトレースではもはや表示されません... – foke

1

backtraceリストマシンコードにcall命令ではなく、ソースレベルの関数呼び出しに対応する通話フレーム、。

相違点は、インライン化では、最適化コンパイラでソースコードのすべての論理関数呼び出しにcall命令を使用しないことがしばしばあります。

+0

その場合、btには全く表示されませんでしたが、ここでは最適化はありません。 -g3'また、バックトレースを構築する関数を壊して、シンボルなしのアドレスに行った場合、逆アセンブル表示(私はeclipseを使用しています)で、 'call'命令の直後に終了します正しく表示されます(別名、ジャンプする関数/メソッドの名前が表示されます)。 – foke