您的位置:首页 > 运维架构 > Linux

linux用户程序调用栈打印backtrace

2015-10-14 22:36 369 查看
在调试程序的时候,有时候程序跑到一个分支不知道怎么调用到的/在走到不应该走的分支后希望把整个调用栈打印出现,在linux用户程序里面有一个glibc库函数backtrace可以打印出当前进程栈信息(如果希望进程退出的话可以用ASSERT(),在内核态中有对应的dump_stack()和BUG()/BUG_ON()):

int backtrace(void **buffer, int size);

该函数用于获取当前现场的调用堆栈。函数返回值是指针数组中指针的个数,buffer是用来存放指针的指针数组,size是数组的最大个数。

buffer中的指针实际上是从堆栈获取的函数的返回地址。

char **backtrace_symbols(void *const*buffer, int size);

backtrace_symbols将从backtrace函数获取的信息转化为一个字符串数组. 参数buffer应该是从backtrace函数获取的指针数组,size是该数组中的元素个数(backtrace的返回值)
函数返回值是一个指向字符串数组的指针,它的大小同buffer相同.每个字符串包含了一个相对于buffer中对应元素的可打印信息.它包括函数名,函数的偏移地址,和实际的返回地址。

现在,只有使用ELF二进制格式的程序才能获取函数名称和偏移地址.在其他系统,只有16进制的返回地址能被获取.另外,你可能需要传递相应的符号给链接器,以能支持函数名功能(比如,在使用GNU ld链接器的系统中,你需要传递(-rdynamic), -rdynamic可用来通知链接器将所有符号添加到动态符号表中,如果你的链接器支持-rdynamic的话,建议将其加上!)

该函数的返回值是通过malloc函数申请的空间,因此调用者必须使用free函数来释放指针.

注意:如果不能为字符串获取足够的空间函数的返回值将会为NULL;

backtrace还可以用来定位段错误。例如如果程序发生段错误系统都会发送SIGSEGV信号给程序,缺省处理是程序退出,可以在收到该信号的处理函数中增加通过backtrace把栈信息打印出来。

如下是一个打印的栈信息,包括函数名和对应的偏移地址

Obtained6stackframes.nm

./backstrace_debug(dump+0x45)[0x80487c9]

[0x468400]

./backstrace_debug(func_b+0x8)[0x804888c]

./backstrace_debug(func_a+0x8)[0x8048896]

./backstrace_debug(main+0x33)[0x80488cb]

/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0x129113]

接着可以用objdum反汇编出二进制文件,找到对应的位置。

objdump -d test > test.s

在test.s中搜索func_b然后加上偏移大概找到对应的出错语句。

我们也可以通过addr2line来查看

addr2line 0x804888c -e backstrace_debug -f

输出:

func_b

/home/astrol/c/backstrace_debug.c:57
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: