鍍金池/ 教程/ Linux/ shell 學(xué)習(xí)五十四天----進(jìn)程系統(tǒng)調(diào)用的追蹤 strace
shell 學(xué)習(xí)四十一天----列出文件 ls 和 od 命令
shell 學(xué)習(xí)小結(jié)
shell 學(xué)習(xí)第二十八天----case 語(yǔ)句
shell 學(xué)習(xí)四十四天----尋找文件
shell 學(xué)習(xí)三十五天----波浪號(hào)展開(kāi)與通配符
shell 學(xué)習(xí)三十八天----執(zhí)行順序和 eval
shell 學(xué)習(xí)四十八天----文件校驗(yàn)和匹配
shell 學(xué)習(xí)四十天----awk 的驚人表現(xiàn)
shell 學(xué)習(xí)第十一天----sed 正則的精確控制
shell 學(xué)習(xí)第十七天----awk 命令
shell 學(xué)習(xí)三十九天----內(nèi)建命令
shell 學(xué)習(xí)四十五天----xargs
shell 學(xué)習(xí)三十七天----引用
shell 學(xué)習(xí)第十六天----join 練習(xí)
shell 學(xué)習(xí)第二十四天----提取開(kāi)頭或結(jié)尾數(shù)行
shell 學(xué)習(xí)第九天----分組
shell 學(xué)習(xí)第五天----基本的 I/O 重定向
shell 學(xué)習(xí)第十五天----使用 cut 選定字段
shell 學(xué)習(xí)四十六天----文件系統(tǒng)的空間信息 df 和 du 命令
shell 學(xué)習(xí)第八天----擴(kuò)展正則表達(dá)式 (ERE)
shell 學(xué)習(xí)第十九天----文本塊排序
shell 學(xué)習(xí)第二十一天----重新格式化段落
shell 學(xué)習(xí)三十六天----命令替換
shell 學(xué)習(xí)第二十天----sort 的其他內(nèi)容以及 uniq 命令
shell 學(xué)習(xí)四十二天----使用 touch 更新文件時(shí)間
shell 學(xué)習(xí)五十一天----top 命令查看進(jìn)程列表
shell 學(xué)習(xí)第一天
shell 學(xué)習(xí)五十四天----進(jìn)程系統(tǒng)調(diào)用的追蹤 strace
shell 學(xué)習(xí)五十天----查看進(jìn)程 ps 命令
shell 學(xué)習(xí)第二十七天----退出狀態(tài)和 if 語(yǔ)句
shell 學(xué)習(xí)第二十三天----打印
shell 學(xué)習(xí)三十三天----關(guān)于重定向
shell 學(xué)習(xí)四十九天----進(jìn)程建立
shell 學(xué)習(xí)第三十天----break,continue,shift,getopts
shell 學(xué)習(xí)五十五天----進(jìn)程記賬
shell 學(xué)習(xí)總結(jié)一
shell 學(xué)習(xí)第二十六天----變量與算數(shù)
shell 學(xué)習(xí)第二十二天----計(jì)算行數(shù), 字?jǐn)?shù)以及字符數(shù)
shell 學(xué)習(xí)五十八天----/proc 文件系統(tǒng)
shell 學(xué)習(xí)第二十五天----神器的管道符
shell 學(xué)習(xí)第三十二天----read 讀取一行
sheel 學(xué)習(xí)第三天
shell 學(xué)習(xí)----小結(jié)
shell 學(xué)習(xí)第十八天----文本排序
shell 學(xué)習(xí)第三十一天----函數(shù)問(wèn)題
shell 學(xué)習(xí)第十天----sed 查找與替換
shell 學(xué)習(xí)四十三天----臨時(shí)性文件的建立與使用
shell 學(xué)習(xí)四十七天----文件比較 cmp,diff,patch
shell 學(xué)習(xí)三十四天----printf 詳解
shell 學(xué)習(xí)五十七天 ----linux 任務(wù)管理,針對(duì)上一講的總結(jié)和擴(kuò)展
shell 學(xué)習(xí)第六天----小結(jié)
shell 學(xué)習(xí)第十三天----sed 案例分析
shell 學(xué)習(xí)第七天----基礎(chǔ)正則表達(dá)式 (BRE)
shell 學(xué)習(xí)第十二天----行與字符串
shell 學(xué)習(xí)小結(jié)四
shell 學(xué)習(xí)第二十九天----循環(huán)
shell 學(xué)習(xí)五十二天----刪除進(jìn)程 kill 命令
shell 學(xué)習(xí)五十六天----延遲進(jìn)程調(diào)度
shell 學(xué)習(xí)第四天----華麗的 printf 輸出
shell 學(xué)習(xí)第十五天----join 連接字段
shell 學(xué)習(xí)完結(jié)篇----希望你能看到
shell 學(xué)習(xí)第二天
shell 學(xué)習(xí)五十三天----捕獲信號(hào) trap

shell 學(xué)習(xí)五十四天----進(jìn)程系統(tǒng)調(diào)用的追蹤 strace

strace

前言: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í)行的文件。
  • 我們執(zhí)行這個(gè)可執(zhí)行文件 (先不使用 strace):#./test
  • 執(zhí)行期間這個(gè)程序會(huì)要求我們輸入一個(gè)整數(shù),我們輸入 99,會(huì)得到以下結(jié)果:000000099

接著我們使用 strace:#strace ./test

輸出很多,我就不復(fù)制,我一看這個(gè)輸出的是我想到了黑客帝國(guó)這部電影,我第一次看的時(shí)候差不多就是這樣... 當(dāng)時(shí)覺(jué)得好炫酷,不過(guò)看見(jiàn)我自己電腦上的這一坨,你夠了,我不想看到你!

輸出的這一些內(nèi)容稱為 stracetrace 結(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 中很清楚的告訴你 test 進(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é)果

分析:

  • 我們一共輸入了 12 個(gè)字符,而我們看到的結(jié)果只有 10 個(gè)
  • trace 一個(gè)現(xiàn)有的進(jìn)程
  • strace 不光能自己初始化一個(gè)進(jìn)程進(jìn)行 trace,還能追蹤現(xiàn)有的進(jìn)程,參數(shù) -p 就是去的這個(gè)用法,用法簡(jiǎn)單,具體如下: \#strace -p pid // 跟蹤指定的進(jìn)程 PID