linux之strace命令跟踪进程的系统调用

1 系统调用

操作系统的进程空间分为用户空间和内核空间,操作系统内核直接运行在硬件上,提供设备管理、内存管理、任务调度等功能,我们用户空间不能直接调用,所以就有了系统调用(运行在用户空间的程序向操作系统内核请求需要更高权限运行的服务),系统调用提供用户程序与操作系统之间的接口。用户空间通过API请求内核空间的服务来完成其功能——内核提供给用户空间的这些API, 就是系统调用。Linux内核目前有300多个系统调用,详细的列表可以通过syscalls手册页查看。这些系统调用主要分为几类:

文件和设备访问类 比如open/close/read/write/chmod等
进程管理类 fork/clone/execve/exit/getpid等
信号类 signal/sigaction/kill 等
内存管理 brk/mmap/mlock等
进程间通信IPC shmget/semget * 信号量,共享内存,消息队列等
网络通信 socket/connect/sendto/sendmsg 等
其他

 

 

2 strace命令

strace:这个命令我们可以用来跟踪用户空间的系统调用,比如我们执行了一个可执行文件或者命令,我们只能看到结果,如果我们要知道这个进程系统调用,
我们可以使用这个命令,但是这个命令参数很多,我们一般只要记住下面几个参数就行
参数意义如下

-c

统计和报告每个系统调用所执行的时间、调用次数和出错次数等

-f

跟踪当前进程及其通过fork系统调用所创建的子进程

-tt

在每行输出前添加绝对时间戳信息,精确到微秒级

-o file

strace输出信息写入文件file中

-p pid

指定待跟踪的进程号(pid)

 

 

 

 

3 strace命令的基本使用

1) 通过进程id来跟踪该进程的系统调用

找到进行id

ps -A | grep ****
strace -p pid -tt  -o log.txt

 比如我们在终端进行进行ping baidu.com操作,看下系统调用情况

PING baidu.com (123.125.114.144) 56(84) bytes of data.
64 bytes from 123.125.114.144: icmp_seq=1 ttl=51 time=3.13 ms
64 bytes from 123.125.114.144: icmp_seq=2 ttl=51 time=3.24 ms
64 bytes from 123.125.114.144: icmp_seq=3 ttl=51 time=3.05 ms
64 bytes from 123.125.114.144: icmp_seq=4 ttl=51 time=3.12 ms
64 bytes from 123.125.114.144: icmp_seq=5 ttl=51 time=3.04 ms

然后我们找到ping的进程ID

ps -A | grep ping
18111 pts/1    00:00:00 ping

我们再用strace命令跟踪进程id按系统调用

strace -tt -p 18111 -o 2.txt
Process 18111 attached

 然后我们用tail命令进行查看2.txt文件尾巴信息

tail -F 2.txt
20:41:07.655393 socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP) = 5
20:41:07.656491 connect(5, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("10.3.3.3")}, 16)
 = 0
20:41:07.656600 poll([{fd=5, events=POLLOUT}], 1, 0) = 1 ([{fd=5, revents=POLLOUT}])
20:41:07.656689 sendto(5, "O\306\1\0\0\1\0\0\0\0\0\0\003144\003114\003125\003123\7in-"..., 46, MSG_NOSI
GNAL, NULL, 0) = 46
20:41:07.656788 poll([{fd=5, events=POLLIN}], 1, 5000) = 1 ([{fd=5, revents=POLLIN}])
20:41:07.659021 ioctl(5, FIONREAD, [46]) = 0
20:41:07.659112 recvfrom(5, "O\306\201\203\0\1\0\0\0\0\0\0\003144\003114\003125\003123\7in-"..., 1024,
0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("10.3.3.3")}, [16]) = 46
20:41:07.659205 close(4)                = 0
20:41:07.659300 close(5)                = 0
20:41:07.659394 write(1, "64 bytes from 123.125.114.144: i"..., 63) = 63
20:41:07.659482 sendmsg(3, {msg_name(16)={sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("123
.125.114.144")}, msg_iov(1)=[{"\10\0\7EF\277\0U\343f\366\\\0\0\0\0\7\20\n\0\0\0\0\0\20\21\22\23\24\25\2
6\27"..., 64}], msg_controllen=0, msg_flags=0}, MSG_CONFIRM) = 64
20:41:07.659606 recvmsg(3, {msg_name(16)={sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("113
.232.78.137")}, msg_iov(1)=[{"E\0\0\221H@\0\0002\1?uq\350N\211jx\325\315\3\1\376\35\0\0\0\0E\0\0u"...,
192}], msg_controllen=32, {cmsg_len=32, cmsg_level=SOL_SOCKET, cmsg_type=0x1d /* SCM_??? */, ...}, msg_
flags=0}, 0) = 145
20:41:07.659700 recvmsg(3, 0x7ffef98cf7e0, MSG_DONTWAIT) = -1 EAGAIN (Resource temporarily unavailable)
20:41:07.659781 recvmsg(3, {msg_name(16)={sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("123
.125.114.144")}, msg_iov(1)=[{"E\0\0T\307X\0\0003\1\221\375{}r\220jx\325\315\0\0\17EF\277\0U\343f\366\\
"..., 192}], msg_controllen=32, {cmsg_len=32, cmsg_level=SOL_SOCKET, cmsg_type=0x1d /* SCM_??? */, ...}
, msg_flags=0}, 0) = 84
20:41:07.662715 open("/etc/hosts", O_RDONLY|O_CLOEXEC) = 4
20:41:07.662812 fstat(4, {st_mode=S_IFREG|0755, st_size=186, ...}) = 0
20:41:07.662895 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fd953f530
00
20:41:07.662979 read(4, "127.0.0.1   localhost localhost."..., 4096) = 186
20:41:07.663068 read(4, "", 4096)       = 0
20:41:07.663146 close(4)                = 0
20:41:07.663222 munmap(0x7fd953f53000, 4096) = 0
20:41:07.663321 socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP) = 4
20:41:07.663402 connect(4, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("202.106.0.20")},
 16) = 0
20:41:07.663488 poll([{fd=4, events=POLLOUT}], 1, 0) = 1 ([{fd=4, revents=POLLOUT}])
20:41:07.663572 sendto(4, "\2371\1\0\0\1\0\0\0\0\0\0\003144\003114\003125\003123\7in-"..., 46, MSG_NOSI
GNAL, NULL, 0) = 46
20:41:07.663669 poll([{fd=4, events=POLLIN}], 1, 5000

 然后我们在终端ctrl+C操作
我们可以看到2.txt尾巴信息为

) = ? ERESTART_RESTARTBLOCK (Interrupted by signal)
20:41:44.411910 --- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL, si_value={int=2633635416, ptr=0x7fdb9cf
a1658}} ---
20:41:44.411969 write(1, "64 bytes from 123.125.114.144: i"..., 63) = 63
20:41:44.412025 write(1, "\n", 1)       = 1
20:41:44.412072 write(1, "--- baidu.com ping statistics --"..., 34) = 34
20:41:44.412118 write(1, "99 packets transmitted, 99 recei"..., 67) = 67
20:41:44.412167 write(1, "rtt min/avg/max/mdev = 2.977/3.1"..., 50) = 50
20:41:44.412236 exit_group(0)           = ?
20:41:44.412387 +++ exited with 0 +++

可以看到,这个收到了信号,然后退出了

 

 

2)通过将要执行的文件来跟踪系统调用 

strace -tt -f  file 

我们先写个简单退出的C程序

#include 

int main()
{
    exit(1);
    return 0;
}

 然后我们编译下这个文件

gcc -g 1.c -o 1

然后我们直接用strace命令来执行这个1

strace -tt -o log.txt -f ./1

然后我们看下log.txt

cat log.txt

3329  20:47:01.496844 execve("./1", ["./1"], [/* 16 vars */]) = 0
3329  20:47:01.497046 uname({sys="Linux", node="ubuntu", ...}) = 0
3329  20:47:01.497273 brk(0)            = 0x86a1000
3329  20:47:01.497316 open("/etc/ld.so.preload", O_RDONLY) = -1 ENOENT (No such file or directory)
3329  20:47:01.497391 open("/etc/ld.so.cache", O_RDONLY) = 3
3329  20:47:01.497427 fstat64(3, {st_mode=S_IFREG|0644, st_size=44545, ...}) = 0
3329  20:47:01.497507 old_mmap(NULL, 44545, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb777e000
3329  20:47:01.497558 close(3)          = 0
3329  20:47:01.497596 open("/lib/tls/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
3329  20:47:01.497633 open("/lib/i686/mmx/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
3329  20:47:01.497668 stat64("/lib/i686/mmx", 0xbff8ddf0) = -1 ENOENT (No such file or directory)
3329  20:47:01.497701 open("/lib/i686/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
3329  20:47:01.497734 stat64("

 

 

 

 

4 总结

如果进行或者执行的脚本会莫名奇怪死了或者有其他异常,或者我们想看下进行的系统调用无论是正在执行的或者将要执行的都可以用strace命令。

strace -tt -o log.txt -f  file 
strace -p pid -tt -o log.txt

 

 

你可能感兴趣的:(Linux/Unix积累)