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

2018-02-24 15:49 更新

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

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

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

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

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

跟蹤信息常用來支持發(fā)給應(yīng)用程序開發(fā)者的故障報告, 但是對內(nèi)核程序員也是很有價值的. 我們已經(jīng)看到驅(qū)動代碼運(yùn)行如何響應(yīng)系統(tǒng)調(diào)用; strace 允許我們檢查每個調(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) = ?

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

作為另一個例子, 讓我們讀取 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ù)總量等同于前個例子寫入的. 注意在這個例子里讀取是如何組織的, 同前面跟蹤的相反. wc 為快速讀被優(yōu)化過, 因此繞過了標(biāo)準(zhǔn)庫, 試圖一個系統(tǒng)調(diào)用讀取更多數(shù)據(jù). 你可從跟蹤的讀的行里看到 wc 是如何試圖一次讀取 16 KB.

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

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

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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號