strace
前言:strace常用来跟踪进程执行时的系统调用的所接受的信号.在linux世界,进程是不能直接访问硬件设备,当进程需要访问硬件(比如读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核态模式,通过系统调用访问硬件设备.strace可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间,有其在调试的时候,strace能帮助你追踪到一个程序所执行的系统调用.当你想知道程序和操作系统是如何交互的时候,这是极其方便的,比如你想知道执行了哪些系统调用,并且以何种顺序执行.
strace详解
格式:
strace [ -dffhiqrtttTvxx ] [ -acolumn ] [ -eexpr ] ... [ -ofile ] [-ppid ] ... [ -sstrsize ] [ -uusername ] [ -Evar=val ] ... [ -Evar ]... [ command [ arg ... ] ]
strace -c [ -eexpr ] ... [ -Ooverhead ] [ -Ssortby ] [ command [ arg... ] ]
选项:
选项名 |
说明 |
-f ,-F |
告诉strace同时跟踪fork和vfork出来的信号 |
-o(字母)xxxx.txt |
输出到某个文档 |
-e execve |
只记录execve这类系统调用. |
案例:
首先使用vim编写一个C语言的程序,代码如下:
#filename test.c
#include
int main()
{
int a;
scanf(“%d”,&a);
printf(“%09d\n”,a);
return 0;
}
然后使用命令:#gcc -o test test.c,这样会得到一个可执行的文件.
我们执行这个可执行文件(先不使用strace):#./test
执行期间这个程序会要求我们输入一个整数,我们输入99,会得到以下结果:000000099
接着我们使用strace:#strace ./test
输出很多,我就不复制,我一看这个输出的是我想到了黑客帝国这部电影,我第一次看的时候差不多就是这样...当时觉得好炫酷,不过看见我自己电脑上的这一坨,你够了,我不想看到你!
输出的这一些内容称为strace的trace结构,从trace结构可以看到,系统首先调用execve开始一个新的进程,接着进行环境的初始化操作,最后停顿在”read(0,”上面,这就是执行到了我们的scanf函数,等待我们输入数字,在输入完99之后,在调用write函数将格式化后的数值”000000099”输出到屏幕上,最后掉用wxit_group退出进行,完成整个程序的执行过程.
跟踪信号传递.
我们还是使用上面那个编译好的test程序,来观察进程接收信号的情况.还是先:#strace ./test,等到等待输入的画面的时候不要输入任何东西,然后打开另一个窗口,输入如下命令:
#killall test
这个时候我们就能看到我们的test程序退出了,最后的trace结果的最后两行:
--- SIGTERM (Terminated) @ 0 (0) ---
+++ killed by SIGTERM +++
trace中很清楚的告诉你test进程”+++ killed by SIGTERM +++”,其中SIGTERM信号为程序结束信号,与SIGKILL不同的是该信号可以被阻塞和处理.通常用来要求程序自己正常退出.shell命令kill缺省产生SIGTERM.
系统调用统计
strace不光能追踪系统调用,通过使用-c选项,它还能江金城所有的系统调用做一个统计分析给你,案例如下:
#strace -c ./test(需要按下Ctrl+C)
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
-nan 0.000000 0 2 read
-nan 0.000000 0 1 write
-nan 0.000000 0 2 open
-nan 0.000000 0 2 close
-nan 0.000000 0 4 fstat
-nan 0.000000 0 10 mmap
-nan 0.000000 0 3 mprotect
-nan 0.000000 0 1 munmap
-nan 0.000000 0 1 brk
-nan 0.000000 0 1 1 access
-nan 0.000000 0 1 execve
-nan 0.000000 0 1 arch_prctl
------ ----------- ----------- --------- --------- ----------------
100.00 0.000000 29 1 total
-c选项的含义是统计每一系统调用的所执行的时间,次数和出错的次数等.
常用参数说明
除了-c参数之外,strace还提供了其他有用的参数给我们,让我们方便的得到自己想要的信息,介绍如下:
重定向输出:
参数-o用在将strace的结果输出到文件中,如果不指定-o参数的话,默认的输出设备是STDERR,也就是说使用”-o filename”和”2>filename”的结果是一样的.
以下这两个命令都是讲strace结果输出到文件test.txt中
#strace -c -o test.txt ./test
#strace -c ./test 2>test.txt
对系统调用进行计时
strace可以使用参数-T将每个系统调用所花费的事件打印出来,每个掉用的时间花销现在在调用行最右边的尖括号里面.
read(0, 1
"1\n", 1024) = 2 <7.195016>
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 <0.000010>
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1431bd1000 <0.000014>
write(1, "000000001\n", 10000000001
) = 10 <0.000011>
exit_group(0) = ?
表示看不懂,不懂得东西,现在不要深究.
系统调用的时间
这是一个很有用的功能,strace会将每次系统调用的发生时间记录下来,只要使用-t/tt/ttt三个参数就可以看到效果了,具体案例如下:
参数名 |
输出样式 |
说明 |
-t |
10:50:10 exit_group(0) |
输出结果精确到秒 |
-tt
|
10:50:48.463555 exit_group(0) |
输出结果精确到微秒 |
-ttt |
1438138307.923671 exit_group(0) |
精确到微妙,而且时间表示为unix时间戳 |
截断输出
-s参数用于指定trsce结果的每一行输出的字符串的长度,下面看看test程序中-s参数对结果有什么影响,现指定-s为10,然后在read的地方输入一个超过10个字符的字符串:
#strace -s 10 ./test
read(0, 123456789011
"1234567890"..., 1024) = 13
部分输出结果
分析:我们一共输入了12个字符,而我们看到的结果只有10个
trace一个现有的进程
strace不光能自己初始化一个进程进行trace,还能追踪现有的进程,参数-p就是去的这个用法,用法简单,具体如下:
#strace -p pid //跟踪指定的进程PID