前言:strace
常用來(lái)跟蹤進(jìn)程執(zhí)行時(shí)的系統(tǒng)調(diào)用的所接受的信號(hào)。在 linux 世界,進(jìn)程是不能直接訪問(wèn)硬件設(shè)備,當(dāng)進(jìn)程需要訪問(wèn)硬件 (比如讀取磁盤(pán)文件,接收網(wǎng)絡(luò)數(shù)據(jù)等等) 時(shí),必須由用戶態(tài)模式切換至內(nèi)核態(tài)模式,通過(guò)系統(tǒng)調(diào)用訪問(wèn)硬件設(shè)備。strace
可以跟蹤到一個(gè)進(jìn)程產(chǎn)生的系統(tǒng)調(diào)用,包括參數(shù),返回值,執(zhí)行消耗的時(shí)間,有其在調(diào)試的時(shí)候,strace
能幫助你追蹤到一個(gè)程序所執(zhí)行的系統(tǒng)調(diào)用。當(dāng)你想知道程序和操作系統(tǒng)是如何交互的時(shí)候,這是極其方便的,比如你想知道執(zhí)行了哪些系統(tǒng)調(diào)用,并且以何種順序執(zhí)行。
strace 詳解
格式:
strace [-dffhiqrtttTvxx] [-acolumn] [-eexpr] ... [-ofile] [-ppid] ... [-sstrsize] [-uusername] [-Evar=val] ... [-Evar]... [command [ arg ...] ]
strace -c [-eexpr] ... [-Ooverhead] [-Ssortby] [command [ arg...] ]
選項(xiàng):
```選項(xiàng)名 說(shuō)明 -f ,-F 告訴 strace 同時(shí)跟蹤 fork 和 vfork 出來(lái)的信號(hào) -o(字母)xxxx.txt 輸出到某個(gè)文檔 -e execve 只記錄 execve 這類系統(tǒng)調(diào)用。
案例:
首先使用 `vim` 編寫(xiě)一個(gè) C 語(yǔ)言的程序,代碼如下:
```\#filename test.c
\#include <stdio.h>
int main()
{
int a;
scanf(“%d”,&a);
printf(“%09d\n”,a);
return 0;
}
#gcc -o test test.c
,這樣會(huì)得到一個(gè)可執(zhí)行的文件。#./test
接著我們使用 strace:#strace ./test
輸出很多,我就不復(fù)制,我一看這個(gè)輸出的是我想到了黑客帝國(guó)這部電影,我第一次看的時(shí)候差不多就是這樣... 當(dāng)時(shí)覺(jué)得好炫酷,不過(guò)看見(jiàn)我自己電腦上的這一坨,你夠了,我不想看到你!
輸出的這一些內(nèi)容稱為 strace
的 trace
結(jié)構(gòu),從 trace
結(jié)構(gòu)可以看到,系統(tǒng)首先調(diào)用 execve
開(kāi)始一個(gè)新的進(jìn)程,接著進(jìn)行環(huán)境的初始化操作,最后停頓在 “read(0,” 上面,這就是執(zhí)行到了我們的 scanf
函數(shù),等待我們輸入數(shù)字,在輸入完 99 之后,在調(diào)用 write
函數(shù)將格式化后的數(shù)值 “000000099” 輸出到屏幕上,最后掉用 wxit_group
退出進(jìn)行,完成整個(gè)程序的執(zhí)行過(guò)程。
跟蹤信號(hào)傳遞
我們還是使用上面那個(gè)編譯好的 test 程序,來(lái)觀察進(jìn)程接收信號(hào)的情況。還是先:#strace ./test
,等到等待輸入的畫(huà)面的時(shí)候不要輸入任何東西,然后打開(kāi)另一個(gè)窗口,輸入如下命令:
\#killall test
這個(gè)時(shí)候我們就能看到我們的 test 程序退出了,最后的 trace 結(jié)果的最后兩行:
--- SIGTERM (Terminated) @ 0 (0) ---
+++ killed by SIGTERM +++
trace
中很清楚的告訴你 tes
t 進(jìn)程“+++ killed by SIGTERM +++”
,其中 SIGTERM
信號(hào)為程序結(jié)束信號(hào),與 SIGKILL
不同的是該信號(hào)可以被阻塞和處理。通常用來(lái)要求程序自己正常退出。shell
命令 kill
缺省產(chǎn)生 SIGTERM
。
系統(tǒng)調(diào)用統(tǒng)計(jì)
strace
不光能追蹤系統(tǒng)調(diào)用,通過(guò)使用 -c
選項(xiàng),它還能江金城所有的系統(tǒng)調(diào)用做一個(gè)統(tǒng)計(jì)分析給你,案例如下:
```#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` 選項(xiàng)的含義是統(tǒng)計(jì)每一系統(tǒng)調(diào)用的所執(zhí)行的時(shí)間,次數(shù)和出錯(cuò)的次數(shù)等。
**常用參數(shù)說(shuō)明**
除了 -c 參數(shù)之外,strace 還提供了其他有用的參數(shù)給我們,讓我們方便的得到自己想要的信息,介紹如下:
重定向輸出:
- 參數(shù) -o 用在將 strace 的結(jié)果輸出到文件中,如果不指定 -o 參數(shù)的話,默認(rèn)的輸出設(shè)備是 STDERR,也就是說(shuō)使用 “-o filename” 和 “2>filename” 的結(jié)果是一樣的。
以下這兩個(gè)命令都是講 strace 結(jié)果輸出到文件 test.txt 中
`\#strace -c -o test.txt ./test`
`#strace -c ./test 2>test.txt`
**對(duì)系統(tǒng)調(diào)用進(jìn)行計(jì)時(shí)**
strace 可以使用參數(shù) -T 將每個(gè)系統(tǒng)調(diào)用所花費(fèi)的事件打印出來(lái),每個(gè)掉用的時(shí)間花銷現(xiàn)在在調(diào)用行最右邊的尖括號(hào)里面。
```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) = ?
表示看不懂,不懂得東西,現(xiàn)在不要深究。
系統(tǒng)調(diào)用的時(shí)間
這是一個(gè)很有用的功能,strace 會(huì)將每次系統(tǒng)調(diào)用的發(fā)生時(shí)間記錄下來(lái),只要使用 -t/tt/ttt 三個(gè)參數(shù)就可以看到效果了,具體案例如下:
```參數(shù)名 輸出樣式 說(shuō)明 -t 10:50:10 exit_group(0) 輸出結(jié)果精確到秒 -tt 10:50:48.463555 exit_group(0) 輸出結(jié)果精確到微秒 -ttt 1438138307.923671 exit_group(0) 精確到微妙,而且時(shí)間表示為 unix 時(shí)間戳
**截?cái)噍敵?*
- `-s` 參數(shù)用于指定 `trsce` 結(jié)果的每一行輸出的字符串的長(zhǎng)度,下面看看 `test` 程序中 `-s` 參數(shù)對(duì)結(jié)果有什么影響,現(xiàn)指定 `-s` 為 10,然后在 `read` 的地方輸入一個(gè)超過(guò) 10 個(gè)字符的字符串:
```\#strace -s 10 ./test
read(0,123456789011
"1234567890"...,1024) = 13
部分輸出結(jié)果
分析:
\#strace -p pid // 跟蹤指定的進(jìn)程 PID