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 <stdio.h>

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

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章