如何打印调用堆栈在C / C ++更漂亮? [英] How to print call stack in C/C++ more beautifully?
问题描述
我想用gdb中的更多信息打印调用堆栈。
I would like to print call stack with more information like in 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]);
}
}
运行时, / p>
When it runs, I get something as below.
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]
很难阅读。使用函数名称,会更好。
非常感谢提示。
It is hard to read. With function names, it would be much better. Thanks a lot for the tip.
推荐答案
免责声明:以下主要针对Linux使用GCC或Clang与libstdc ++ ,您可能需要在其他系统上使用不同的方法。
Disclaimer: The following is mostly for Linux using GCC or Clang with libstdc++, you might need different ways on other systems.
最重要的是将 -rdynamic
添加到命令线连接。我不知道这是否在所有系统上都是必需的,但对我来说,这实际上把所有这些地址变成符号。
The most important thing is to add -rdynamic
to the command line when linking. I don't know if this is required on all systems, but for me, this actually turned all those addresses into symbols.
现在你得到一些信息,你可能想要解开符号。你可以用一个独立的函数来解开任何符号:
Now that you get some information, you probably want to demangle the symbols. You start with a stand-alone function to demangle any symbol:
// 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
的输出格式,但以下对我来说效果很好:
And now for the real thing. I don't know if the format of the output from backtrace_symbols
is specified, but the following works quite well for me:
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;
}
}
'm不使用 std :: cout
,所以可能有一些小怪物 - 检查代码,如果它适用于你,如果没有,你需要帮助修复它,让我知道)。
(I had to adapt my code slightly since I'm not using std::cout
, so there might be some little quirks there - check the code if it works for you and if not and you need help fixing it, let me know).
这篇关于如何打印调用堆栈在C / C ++更漂亮?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!