当我们想知道某个进程为什么突然卡了,或者是某个工具到底是如何实现的时候。strace就派上了用场。它能将程序的调用信息打印出来。
strace原理:
它的实现基础是ptrace系统调用。ptrace系统调用提供了一种方法来跟踪和控制进程的执行,它可以读取和修改进程地址空间中的内容,包括寄存器的值。ptrace主要用于实现断点调试和跟踪系统调用。
ptrace系统调用
1 |
#include <sys/ptrace.h> |
2 |
int ptrace( int request, int pid, int addr, int data);
|
Ptrace 提供了一种父进程可以控制子进程运行,并可以检查和改变它的核心image。它主要用于实现断点调试。
一个被跟踪的进程运行中,在执行系统调用之前,内核会先检查当前进程是否处于被“跟踪”(traced)的状态。如果是的话,内核暂停当前进程并将控制权交给跟踪进程,使跟踪进程得以察看或者修改被跟踪进程的寄存器。
在一个进程被跟踪之后,跟踪者进程会在某种意义上充当被跟踪进程的父进程(如使用ps命令就可以看到他们的父子关系),而子进程真正的父进程被保存在其task_struct结构的real_parent成员中。
当子进程产生系统调用时,就会被暂停,父进程会在每次调用wait()时得到子进程停止运行的通知,这时父进程就可以检测和修改子进程了,随后父进程可以让子进程继续运行。当父进程不想跟踪了,可以通过设置PTRACE_KILL标记来终止子进程的运行。也可以通过设置PTRACE_DETACH标记让子进程解除被跟踪,继续正常运行。
函数参数:
- request:用于选择一个操作。
- pid:目标进程即被跟踪进程的pid。
- addr用于修改和拷贝被跟踪进程的进程地址空间的数据。
- data功能同addr。
父进程跟踪一个进程的方式有两种:
- 调用fork(),然后子进程打上PTRACE_TRACEME标记,并执行exec。
- 父进程可以给自己打上PTRACE_ATTACH标记来跟踪一个已有进程。
所以我们看strace有两种用法,一个是strace直接加要运行的程序,一个是用-p指定一个正在运行的进程。
一个进程被跟踪后,他只要接收到一个信号(即使这个信号被设置为忽略)就会停止运行(SIGKILL除外),然后父进程会在每次调用wait()时得到子进程停止运行的通知,这时父进程就可以检测和修改子进程了,随后父进程可以让子进程继续运行。
当父进程不想跟踪了,可以通过设置PTRACE_KILL标记来终止子进程的运行。也可以通过设置PTRACE_DETACH标记让子进程解除被跟踪,继续正常运行。
strace用法:
最简单的用法其实就是trace后面直接跟着要执行的命令。比如:
就能追踪到它的系统调用。
1 |
execve( "/bin/ls" , [ "ls" , "-l" ], [ ]) = 0
|
3 |
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fee98686000 |
4 |
access( "/etc/ld.so.preload" , R_OK) = -1 ENOENT (No such file or directory)
|
5 |
open( "/etc/ld.so.cache" , O_RDONLY) = 3
|
命令参数:
- -p pid :绑定到一个由pid对应的正在运行的进程。此参数常用来调试后台进程。
- -e 函数名:只追踪定义函数名。
- -f :除了跟踪当前进程外,还跟踪其子进程。
- -o file :将输出信息写到文件file中,而不是显示到标准错误输出(stderr)。
在linux中,很多性能查看命令都是通过读取/proc中的文件实现的。所以我们如果想学习它们的实现,就可以使用strace追踪,用-e筛选出open函数,就知道它读取了什么文件。比如mount命令。
02 |
open ( "/etc/ld.so.cache" , O_RDONLY) = 3
|
03 |
open ( "/lib64/libblkid.so.1" , O_RDONLY) = 3
|
04 |
open ( "/lib64/libuuid.so.1" , O_RDONLY) = 3
|
05 |
open ( "/lib64/libselinux.so.1" , O_RDONLY) = 3
|
06 |
open ( "/lib64/libsepol.so.1" , O_RDONLY) = 3
|
07 |
open ( "/lib64/libc.so.6" , O_RDONLY) = 3
|
08 |
open ( "/lib64/libdl.so.2" , O_RDONLY) = 3
|
09 |
open ( "/proc/filesystems" , O_RDONLY) = 3
|
10 |
open ( "/usr/lib/locale/locale-archive" , O_RDONLY) = 3
|
11 |
open ( "/dev/null" , O_RDWR) = 3
|
12 |
<span style= "color: #ff0000;" ><strong> open ( "/etc/mtab" , O_RDONLY) = 3
|
参考资料:
http://blog.csdn.net/sealyao/article/details/6710772
转载请注明:旅途@KryptosX » 系统调用追踪工具strace