使用方法:pstack pid, 就是说要先把程序跑起来,查见进程号,再使用pstack pid
在ubunbu系统上,使用sudo apt-get install pstack可以直接安装pstack,注意这里
安装上的是二进制的程序。之前对这样安装上的pstack作了测试,无法显示函数的调用
关系。根据man pstack的说明,现在的pstack只支持32bit ELF binaries网上的一些文章指出,pstack只是一个脚本程序,在相关网站上下载了pstack.sh脚本
测试。使用时总是提示出错,但是表现看不出来错误,全部删去,就留下前几行,还是
显示有错,新建一个脚本文件,照抄那几行过来(这时两个文件看起来一样),但是用
diff ***.sh ***.sh测试一下,竟然不一样。用ghex查看二进制的文件,看出是字符行
尾的时候的编码不一样。想到下载的脚本可以是在windows下的脚本,下载安装 dos2unix
编码转换工具,然后dos2unix pstack.sh, 工具可以使用。pstack.sh脚本简单分析:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53/* pstack.sh */
#! /bin/sh
# 输入参数以及pid是否存在的判断
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.
# 先设置参数bt, 要是多线程的情况,那么设置为:thread apply all bt
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}
# echo $GDB -> /usr/bin/gdb
# -nx: Do not execute commands from any `.gdbinit' initialization files. Normal
ly, the commands in these files are executed after all the command options
and argu‐ments have been processed.
# --quiet: Do not print the introductory and copyright messages. These message
s are also suppressed in batch mode
# --batch: ...
# --readnever: ...
if $GDB -nx --quiet --batch --readnever > /dev/null 2>&1; then
readnever=--readnever
else
readnever=
fi
# 单步运行/usr/bin/gdb -nx --quiet --batch --readnever时,--readnever会出错
# Run GDB, strip out unwanted noise.
# 原来用/proc/$1/exe找到pid对应的命令行,但是发现下面命令中的是/proc/$1/exe
# 改成下面的'echo /proc/$1/exe'就可以了
$GDB --quiet $readnever -nx 'echo /proc/$1/exe' $1 <<EOF 2>&1 |
$backtrace
EOF
这里,运行pstack [pid]一次会显示当时的函数调用,不能显示指定位置的堆栈情况。
可以先运行gdb –quiet -nx /proc/command/exe command, 待gdb起来后,在想要的地
方设立断点,程序停住之后,使用bt,显示出当时的堆栈函数调用情况
整理显示输出格式
/bin/sed -n
-e ‘s/^(gdb) //‘
-e ‘/^#/p’
-e ‘/^Thread/p’
附:测试程序和堆栈情况(单线程和多线程)
单线程:
1 | #include <stdio.h> |
测试输出:
1 | 29788 pts/5 00:00:34 test2 |
注:使用pc上已经在运行的应用程序调试时,无法显示具体的函数名和相关参数,原因是pc
上的应用程序没有加入调试信息
多线程:
1 | # include<stdio.h> |
测试输出:
1 | *** 30280 22661 30280 99 3 21:51 pts/5 00:00:12 ./multi_threads |
注:按照下面gdb multi-thread debug方法,在pc上无法显示有关多线程的信息(被调试进
程使用pc已经在运行的应用程序进程)
gdb多线程debug:
https://sourceware.org/gdb/onlinedocs/gdb/Threads.html#Threads