能否实现获取指定进程的调用堆栈信息?
我们知道调用backtrace()可以获取当前进程的调用堆栈信息,那如果想要获取另外一个进程(我们当然知道这个进程的pid)的调用堆栈信息,是否有办法呢?
在stackoverflow上,就有人提出了这个问题,有网友给出的答案是向该进程发出一个信号,然后由该进程在信号处理函数里获取自身的调用堆栈,然后再发回来…。先不管这种方法行或不行,但至少不适合一般情况,因为它需要在指定进程里进行信号处理。
想想gdb工具,gdb几乎可以attach到任何进程上,在无需其它进程做任何额外工作的情况下,获取它的当前调用堆栈信息,所以说,回到题目问题,能够实现获取指定进程的调用堆栈信息,而恰好就有这么一个特定的工具pstack:
[root@localhost ~]# pstack 4468 Thread 2 (Thread 0x4166f940 (LWP 4469)): #0 0x00007fbcaf6e6b99 in pthread_cond_wait@@GLIBC_2.3.2 () #1 0x00007fbcb071e9fb in ?? () from /proc/4468/exe #2 0x00007fbcaf6e24a7 in start_thread () from /lib64/libpthread.so.0 #3 0x00007fbcaf9cac2d in clone () from /lib64/libc.so.6 Thread 1 (Thread 0x7fbcb06f46e0 (LWP 4468)): #0 0x00007fbcaf9cb018 in epoll_wait () from /lib64/libc.so.6 #1 0x00007fbcb072800c in ?? () from /proc/4468/exe #2 0x00007fbcb0726fec in ?? () from /proc/4468/exe #3 0x00007fbcb071d319 in main () from /proc/4468/exe [root@localhost ~]#
从上实例可以看到,pstack可以获取指定进程(通过进程id)的所有线程调用堆栈信息,怎么做到的呢?其实pstack就是一个利用gdb实现的shell脚本:
[root@localhost ~]# ls -l `which pstack` lrwxrwxrwx 1 root root 6 Jul 14 2010 /usr/bin/pstack -> gstack [root@localhost ~]# file /usr/bin/gstack /usr/bin/gstack: Bourne shell script text executable [root@localhost ~]# cat !$ cat /usr/bin/gstack #!/bin/sh if test $# -ne 1; then echo "Usage: `basename $0 .sh` <process-id>" 1>&2 exit 1 fi if test ! -r /proc/$1; then echo "Process $1 not found." 1>&2 exit 1 fi # GDB doesn't allow "thread apply all bt" when the process isn't # threaded; need to peek at the process to determine if that or the # simpler "bt" should be used. backtrace="bt" if test -d /proc/$1/task ; then # Newer kernel; has a task/ directory. if test `/bin/ls /proc/$1/task | /usr/bin/wc -l` -gt 1 2>/dev/null ; then backtrace="thread apply all bt" fi elif test -f /proc/$1/maps ; then # Older kernel; go by it loading libpthread. if /bin/grep -e libpthread /proc/$1/maps > /dev/null 2>&1 ; then backtrace="thread apply all bt" fi fi GDB=${GDB:-/usr/bin/gdb} if $GDB -nx --quiet --batch --readnever > /dev/null 2>&1; then readnever=--readnever else readnever= fi # Run GDB, strip out unwanted noise. $GDB --quiet $readnever -nx /proc/$1/exe $1 <<EOF 2>&1 | $backtrace EOF /bin/sed -n \ -e 's/^(gdb) //' \ -e '/^#/p' \ -e '/^Thread/p' [root@localhost ~]#
转载请保留地址:http://lenky.info/archives/2012/06/30/1765 或 http://lenky.info/?p=1765
备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。
法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以或书面等方式告知,本站将及时删除相关内容或链接。
凯哥的博客写的很用心啊,格式清晰、写东西娓娓道来,学习!
这里面的的最后用的是GDB的bt命令查看进程的堆栈,这个实现还可以深入研究下。