当前位置: 技术问答>linux和unix
Linux下多线程程序崩溃时如何提取出所有线程的函数调用栈
来源: 互联网 发布时间:2017-01-24
本文导语: 尝试过三种方法都不凑效 1.libc 中的backtrace函数 2.内联汇编,提取出ebp寄存器的值再回溯出函数调用栈(会有兼容性问题,x86下试过可以,一移植到其他平台就用不了,本人菜鸟,汇编不熟) 3.gcc 内建的两个函数 B...
尝试过三种方法都不凑效
1.libc 中的backtrace函数
2.内联汇编,提取出ebp寄存器的值再回溯出函数调用栈(会有兼容性问题,x86下试过可以,一移植到其他平台就用不了,本人菜鸟,汇编不熟)
3.gcc 内建的两个函数
Built-in Function: void * __builtin_return_address (unsigned int level)
Built-in Function: void * __builtin_frame_address (unsigned int level)
这些都是只能提取出当前线程的调用栈信息
望各位大虾赐教,感激不尽
ps: 是通过signal监听异常信号,要在回调函数中把堆栈信息提取出来
目前我只能发100分的贴
1.libc 中的backtrace函数
2.内联汇编,提取出ebp寄存器的值再回溯出函数调用栈(会有兼容性问题,x86下试过可以,一移植到其他平台就用不了,本人菜鸟,汇编不熟)
3.gcc 内建的两个函数
Built-in Function: void * __builtin_return_address (unsigned int level)
Built-in Function: void * __builtin_frame_address (unsigned int level)
这些都是只能提取出当前线程的调用栈信息
望各位大虾赐教,感激不尽
ps: 是通过signal监听异常信号,要在回调函数中把堆栈信息提取出来
目前我只能发100分的贴
|
A backtrace is the series of currently active function calls for the program.
-----------------------------------------------------------------------------
以上是man手册里的一句话,我的理解是:
1)如果用backtrace函数记录堆栈信息,应当在每个需要记录堆栈信息的函数体内运行这个函数(这时堆栈正常);
2)当异常发生时,比如楼主说的Test2()函数内除零,只有在Test2函数上下文环境没有被破坏时,
backtrace才能正常运行,如果在信号处理函数里运行backtrace时,之前的上下文可能已经不存在了;
因为信号处理函数注册后,在内核发出异常信号后被程序捕捉执行,这时信号处理函数内的backtrace读取的是这个时刻的上下文环境;
3)信号处理函数是进程中所有线程共享的,任何一个线程改变了信号处理函数,都影响其它线程;
与硬件故障或计时器超时相关信号被发送到引起该事件的线程中去;
其它信号则被发送到任意一个线程,在Linux中,就是当前进程的第一个线程;
我是菜鸟,一点拙见,欢迎批评指正;
-----------------------------------------------------------------------------
以上是man手册里的一句话,我的理解是:
1)如果用backtrace函数记录堆栈信息,应当在每个需要记录堆栈信息的函数体内运行这个函数(这时堆栈正常);
2)当异常发生时,比如楼主说的Test2()函数内除零,只有在Test2函数上下文环境没有被破坏时,
backtrace才能正常运行,如果在信号处理函数里运行backtrace时,之前的上下文可能已经不存在了;
因为信号处理函数注册后,在内核发出异常信号后被程序捕捉执行,这时信号处理函数内的backtrace读取的是这个时刻的上下文环境;
3)信号处理函数是进程中所有线程共享的,任何一个线程改变了信号处理函数,都影响其它线程;
与硬件故障或计时器超时相关信号被发送到引起该事件的线程中去;
其它信号则被发送到任意一个线程,在Linux中,就是当前进程的第一个线程;
我是菜鸟,一点拙见,欢迎批评指正;
|
两个问题:
1、你确定捕捉信号的那个位置是在创建线程之前还是之后?
2、你可以考虑把所有线程记录下来,用pthread_kill给所有线程发送一个消息(比如USR1)。在USR1中独立用backtrace打印调用栈。
1、你确定捕捉信号的那个位置是在创建线程之前还是之后?
2、你可以考虑把所有线程记录下来,用pthread_kill给所有线程发送一个消息(比如USR1)。在USR1中独立用backtrace打印调用栈。
|
我觉得可能是线程处理信号的问题。
linux的线程是轻量级进程,线程有自己的信号处理表,继承于父进程。而内核发送信号的单位是进程级别的,不向所有的线程发信号。
参考一下这个文章:
http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/
linux的线程是轻量级进程,线程有自己的信号处理表,继承于父进程。而内核发送信号的单位是进程级别的,不向所有的线程发信号。
参考一下这个文章:
http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/
|
2,3确实有它行不通的理由,对于2相当于反汇编bin抓call跟进去找返回地址的处理,确实有兼容性问题,我搞类似的有遇到过这种情况,我搞不懂的是为什么1不可以,把处理代码贴下看看?思路还是拿ebp吧,这个ebp不知道你是让内核去搞的还是你自己
|
gdb下用thread apply all bt这个命令不行么?
|
看下下面的页面,或许有帮助
http://www.2cto.com/kf/201107/97270.html
http://www.2cto.com/kf/201107/97270.html
|
突然想到一个,你用gdb调试,用backtrace命令看看。就算不能查看所有线程的栈,但是对程序崩溃的原因调查应该有所帮助吧!
|
atexit + backtrace试试。