6

gdb のように、より多くの情報を含むコール スタックを出力したいと思います。

これは私がこれまでに持っているものです。

void to_print_callstack()
{
    void *buffer[100];
    int n = backtrace(buffer,10);
    char **str = backtrace_symbols(buffer, n);

    for (int i = 0; i < n; i++)
    {
        printf("%d:  %s\n", i, str[i]);
    }
}

実行すると、以下のようなものが得られます。

0:  ./test-prog() [0x4466bf]
1:  ./test-prog() [0x445e1d]
2:  ./test-prog() [0x443fd5]
3:  ./test-prog() [0x439a99]
4:  ./test-prog() [0x43302f]
5:  ./test-prog() [0x4322c9]
6:  ./test-prog() [0x4320cd]
7:  ./test-prog() [0x43e76b]
8:  /lib/libc.so.6(__libc_start_main+0xfd) [0x7fc4de7d8c4d]
9:  ./test-prog() [0x431569]

読みにくいです。関数名を使用すると、はるかに優れたものになります。ヒントをありがとう。

4

1 に答える 1

8

免責事項: 以下は主に GCC を使用する Linux または libstdc++ を使用する Clang の場合です。他のシステムでは別の方法が必要になる場合があります。

最も重要なことは-rdynamic、リンク時にコマンド ラインに追加することです。これがすべてのシステムで必要かどうかはわかりませんが、私にとっては、実際にこれらすべてのアドレスがシンボルに変わりました。

ある程度の情報が得られたので、おそらくシンボルをデマングルしたいと思うでしょう。任意のシンボルをデマングルするスタンドアロン関数から始めます。

// you most likely need these headers (plus stuff for std::cout, ...)
#include <cxxabi.h>
#include <execinfo.h>

std::string demangle( const char* const symbol )
{
    const std::unique_ptr< char, decltype( &std::free ) > demangled(
      abi::__cxa_demangle( symbol, 0, 0, 0 ), &std::free );
    if( demangled ) {
        return demangled.get();
    }
    else {
        return symbol;
    }
}

そして今、本物のために。からの出力の形式が指定されているかどうかはわかりませんbacktrace_symbolsが、次のようにするとうまくいきます。

void backtrace()
{
  // TODO: replace hardcoded limit?                                                      
  void* addresses[ 256 ];
  const int n = ::backtrace( addresses, std::extent< decltype( addresses ) >::value );
  const std::unique_ptr< char*, decltype( &std::free ) > symbols(
    ::backtrace_symbols( addresses, n ), &std::free );
  for( int i = 0; i < n; ++i ) {
    // we parse the symbols retrieved from backtrace_symbols() to                                                                                                                
    // extract the "real" symbols that represent the mangled names.                                                                                                              
    char* const symbol = symbols.get()[ i ];
    char* end = symbol;
    while( *end ) {
      ++end;
    }
    // scanning is done backwards, since the module name
    // might contain both '+' or '(' characters.
    while( end != symbol && *end != '+' ) {
      --end;
    }
    char* begin = end;
    while( begin != symbol && *begin != '(' ) {
      --begin;
    }

    if( begin != symbol ) {
      std::cout << std::string( symbol, ++begin - symbol );
      *end++ = '\0';
      std::cout << demangle( begin ) << '+' << end;
    }
    else {
      std::cout << symbol;
    }
    std::cout << std::endl;
  }
}

(私は を使用していないため、コードを少し調整するstd::cout必要がありました。そのため、いくつかの小さな癖がある可能性があります。コードが機能するかどうかを確認し、そうでない場合は、修正のサポートが必要な場合はお知らせください)。

于 2013-10-04T20:41:19.550 に答える