4.4. 使用觀察來(lái)調(diào)試

2018-02-24 15:49 更新

4.4.?使用觀察來(lái)調(diào)試

有時(shí)小問(wèn)題可以通過(guò)觀察用戶空間的應(yīng)用程序的行為來(lái)追蹤. 監(jiān)視程序也有助于建立對(duì)驅(qū)動(dòng)正確工作的信心. 例如, 我們能夠?qū)?scull 感到有信心, 在看了它的讀實(shí)現(xiàn)如何響應(yīng)不同數(shù)量數(shù)據(jù)的讀請(qǐng)求之后.

有幾個(gè)方法來(lái)監(jiān)視用戶空間程序運(yùn)行. 你可以運(yùn)行一個(gè)調(diào)試器來(lái)單步過(guò)它的函數(shù), 增加打印語(yǔ)句, 或者在 strace 下運(yùn)行程序. 這里, 我們將討論最后一個(gè)技術(shù), 當(dāng)真正目的是檢查內(nèi)核代碼時(shí)它是最有趣的.

strace 命令時(shí)一個(gè)有力工具, 顯示所有的用戶空間程序發(fā)出的系統(tǒng)調(diào)用. 它不僅顯示調(diào)用, 還以符號(hào)形式顯示調(diào)用的參數(shù)和返回值. 當(dāng)一個(gè)系統(tǒng)調(diào)用失敗, 錯(cuò)誤的符號(hào)值(例如, ENOMEM)和對(duì)應(yīng)的字串(Out of memory) 都顯示. strace 有很多命令行選項(xiàng); 其中最有用的是 -t 來(lái)顯示每個(gè)調(diào)用執(zhí)行的時(shí)間, -T 來(lái)顯示調(diào)用中花費(fèi)的時(shí)間, -e 來(lái)限制被跟蹤調(diào)用的類型, 以及-o 來(lái)重定向輸出到一個(gè)文件. 缺省地, strace 打印調(diào)用信息到 stderr.

strace 從內(nèi)核自身獲取信息. 這意味著可以跟蹤一個(gè)程序, 不管它是否帶有調(diào)試支持編譯(對(duì) gcc 是 -g 選項(xiàng))以及不管它是否 strip 過(guò). 你也可以連接追蹤到一個(gè)運(yùn)行中的進(jìn)程, 類似于一個(gè)調(diào)試器的方式連接到一個(gè)運(yùn)行中的進(jìn)程并控制它.

跟蹤信息常用來(lái)支持發(fā)給應(yīng)用程序開發(fā)者的故障報(bào)告, 但是對(duì)內(nèi)核程序員也是很有價(jià)值的. 我們已經(jīng)看到驅(qū)動(dòng)代碼運(yùn)行如何響應(yīng)系統(tǒng)調(diào)用; strace 允許我們檢查每個(gè)調(diào)用的輸入和輸出數(shù)據(jù)的一致性.

例如, 下面的屏幕輸出顯示(大部分)運(yùn)行命令 strace ls /dev > /dev/scull0 的最后的行:


open("/dev", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY) = 3
fstat64(3, {st_mode=S_IFDIR|0755, st_size=24576, ...}) = 0

fcntl64(3, F_SETFD, FD_CLOEXEC)  = 0  
getdents64(3, /* 141 entries */, 4096)  = 4088  
[...]  
getdents64(3, /* 0 entries */, 4096)  = 0  
close(3)  = 0  
[...]  

fstat64(1, {st_mode=S_IFCHR|0664, st_rdev=makedev(254, 0), ...}) = 0
write(1, "MAKEDEV\nadmmidi0\nadmmidi1\nadmmid"..., 4096) = 4000
write(1, "b\nptywc\nptywd\nptywe\nptywf\nptyx0\n"..., 96) = 96
write(1, "b\nptyxc\nptyxd\nptyxe\nptyxf\nptyy0\n"..., 4096) = 3904
write(1, "s17\nvcs18\nvcs19\nvcs2\nvcs20\nvcs21"..., 192) = 192
write(1, "\nvcs47\nvcs48\nvcs49\nvcs5\nvcs50\nvc"..., 673) = 673
close(1) = 0
exit_group(0) = ?

從第一個(gè) write 調(diào)用看, 明顯地, 在 ls 結(jié)束查看目標(biāo)目錄后, 它試圖寫 4KB. 奇怪地(對(duì)ls), 只有 4000 字節(jié)寫入, 并且操作被重復(fù). 但是, 我們知道 scull 中的寫實(shí)現(xiàn)一次寫一個(gè)單個(gè)量子, 因此我們本來(lái)就期望部分寫. 幾步之后, 所有東西清空, 程序成功退出.

作為另一個(gè)例子, 讓我們讀取 scull 設(shè)備(使用 wc 命令):


[...]
open("/dev/scull0", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFCHR|0664, st_rdev=makedev(254, 0), ...}) = 0
read(3, "MAKEDEV\nadmmidi0\nadmmidi1\nadmmid"..., 16384) = 4000
read(3, "b\nptywc\nptywd\nptywe\nptywf\nptyx0\n"..., 16384) = 4000
read(3, "s17\nvcs18\nvcs19\nvcs2\nvcs20\nvcs21"..., 16384) = 865
read(3, "", 16384) = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
write(1, "8865 /dev/scull0\n", 17) = 17
close(3) = 0
exit_group(0) = ?

如同期望的, read 一次只能獲取 4000 字節(jié), 但是數(shù)據(jù)總量等同于前個(gè)例子寫入的. 注意在這個(gè)例子里讀取是如何組織的, 同前面跟蹤的相反. wc 為快速讀被優(yōu)化過(guò), 因此繞過(guò)了標(biāo)準(zhǔn)庫(kù), 試圖一個(gè)系統(tǒng)調(diào)用讀取更多數(shù)據(jù). 你可從跟蹤的讀的行里看到 wc 是如何試圖一次讀取 16 KB.

Linux 專家能夠從 strace 的輸出中發(fā)現(xiàn)更多有用信息. 如果你不想看到所有的符號(hào), 你可使用 efile 標(biāo)志來(lái)限制你自己僅查看文件方法是如何工作的.

就個(gè)人而言, 我們發(fā)現(xiàn) strace 對(duì)于查明系統(tǒng)調(diào)用的運(yùn)行時(shí)錯(cuò)誤是非常有用. 常常是應(yīng)用程序或演示程序中的 perror 調(diào)用不足夠詳細(xì), 并且能夠確切說(shuō)出哪個(gè)系統(tǒng)調(diào)用的哪個(gè)參數(shù)觸發(fā)了錯(cuò)誤是非常有幫助的.

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)