接下来一步一步的讲解如何使用以上这些函数来获取程序的堆栈
一、第一版代码如下
#define MAX_FRAMES 100
void GetStackTrace (std::string* stack)
{
void* addresses[MAX_FRAMES];
int size = backtrace (addresses, MAX_FRAMES);
std::unique_ptr<char*, void(*)(void*)> symbols {
backtrace_symbols (addresses, size),
std::free
};
for (int i = 0; i < size; ++i) {
stack->append (symbols.get()[i]);
stack->append ("n");
}
}
void TestFunc (std::string& stack, int value)
{
while (--value);
GetStackTrace (&stack);
}
int main(int argc, char* argv[])
{
std::string stack;
TestFunc (stack, 5);
std::cout << stack << std::endl;
return 0;
}
编译成可执行文件StackTrace后执行输出如下结果:
./StackTrace(_Z13GetStackTracePSs+0x27) [0x4035d5]
./StackTrace(_Z8TestFuncRSsi+0x2a) [0x4036e6]
./StackTrace(main+0x2d) [0x403715]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5) [0x7f7302027de5]
./StackTrace() [0x403139]
从输出的结果中可以得知程序的调用过程,但是看起来比较难以理解。让我们来稍微改动一下GetStackTrace函数。
二、进阶版代码,在第一点中的代码基础上改动
void DemangleSymbol (std::string* symbol)
{
size_t size = 0;
int status = -4;
char temp[256] = {' '};
//first, try to demangle a c++ name
if (1 == sscanf (symbol->c_str (), "%*[^(]%*[^_]%[^)+]", temp)) {
std::unique_ptr<char, void(*)(void*)> demangled {
abi::__cxa_demangle (temp, NULL, &size, &status),
std::free
};
if (demangled.get ()) {
symbol->clear ();
symbol->append (demangled.get ());
return;
}
}
//if that didn't work, try to get a regular c symbol
if (1 == sscanf(symbol->c_str (), "%255s", temp)) {
symbol->clear ();
symbol->append (temp);
}
}
void GetStackTrace (std::string* stack)
{
void* addresses[MAX_FRAMES];
int size = backtrace (addresses, MAX_FRAMES);
std::unique_ptr<char*, void(*)(void*)> symbols {
backtrace_symbols (addresses, size),
std::free
};
for (int i = 0; i < size; ++i) {
std::string demangled (symbols.get()[i]);
DemangleSymbol (&demangled);
stack->append (demangled);
stack->append ("n");
}
}
该版本通过__cxa_demangle来将backtrace_symbols返回的字符串逐个解析成可以方便看懂的字符串,由于__cxa_demangle只能解析_Z13GetStackTracePSs这样的字符串,所以使用sscanf来简单的截取backtrace_symbols函数返回的数据,当然,现在已不这么提倡使用sscanf函数了。编译成可执行文件StackTrace后执行输出如下结果:
GetStackTrace(std::string*)
TestFunc(std::string&, int)
./StackTrace(main+0x2d)
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5)
./StackTrace()
从输出的结果中可以得知程序的调用过程,但是少了一些其他的信息,让我们来改动一下DemangleSymbol函数








