c++ - C/C++中如何更 pretty-print 调用栈?

标签 c++ c callstack

我想像在 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]

很难读。有了函数名,会好很多。 非常感谢您的提示。

最佳答案

免责声明:以下内容主要针对使用 GCC 或 Clang 和 libstdc++ 的 Linux,在其他系统上您可能需要不同的方法。

最重要的是链接时在命令行中加入-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,所以那里可能有一些小怪癖 - 检查代码是否适合你,如果不适合你你需要帮助修复它,让我知道)。

关于c++ - C/C++中如何更 pretty-print 调用栈?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19190273/

相关文章:

c++ - 在不使用 reverse 的情况下反转 C++ 中的字符串

c++ - SQL 语句的解析树 - 精确针对 "SELECT"语句

c++: 没有重载函数 "regex_search"的实例与参数列表匹配

c - 在 c 中使用数组分配 LIFO 内存的目的是什么?

R:了解省略号 (...) 如何在嵌套函数中工作,以及 iit 如何不工作

python - 从 SWIG 包装的 C++ 函数中获取当前的 Python 调用堆栈

c++ - 在for循环中生成随机 float

c - 如何以优化方式加载更大的文本文件到缓冲区--c程序

c - 逐行读取文件并在c中进行比较

c - 菜单选项导致程序失败。 (C)