免责声明:以下主要适用于使用 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
,所以那里可能有一些小怪癖 - 检查代码是否适合你,如果不适合,你需要帮助修复它,让我知道)。