Linux 內核的測試和調試(6)
寫好代碼後,編譯它。把 make 過程產生的輸出保存到文檔中,查看新代碼有沒有警告信息。找到所有的警告信息,處理掉。當你的代碼編譯過程沒有任何不正常的輸出,安裝這個內核,然後啟動測試。如果啟動正常,查看 dmesg 裡面有沒於錯誤,與老內核生成的 dmesg 日誌做個比較。運行一些壓力測試,請參考我們以前講過的測試內容。如果這個補丁用於修復某個 bug,請確保真的已經修復了。如果真的修復了,請確保能通過系統測試。找出打你補丁的模塊下面的回歸測試工具,運行一下。如果補丁涉及到其他架構,你需要交叉編譯然後測試一下。請通過下面的目錄查找測試工具:
- linux_git/Documentation
- linux_git/tools/testing
- 交叉編譯參考:在 x86_64 架構上交叉編譯 Linux 內核:初學者教程
如果你對你的補丁測試結果感到很滿意,你就可以提交補丁了。請確保提交 commit 的信息要描述得非常清楚。要讓內核維護者和其他開發者看懂補丁所修改的內容,這一點非常重要。生成補丁後,執行 scripts/checkpatch.pl 腳本,找到 checkpatch 是產生的錯誤或警告(如果有的話),修復它們。重新生成補丁,直到補丁通過這個腳本的測試。重新測試這個補丁。將本補丁用於其他的內核源碼上,保證不會有衝突產生。
現在你做好提交補丁的準備了。先運行 scriptst/get_maintainer.pl 來確認你應該把補丁發給哪個內核維護者。注意不要以附件形式發送補丁,而是以純文本形式粘貼在郵件裡面。確保你的郵件客戶端可以發送純文本信息,你可以試試給自己發送一份補丁郵件來測試你的郵件客戶端的功能。收到自己的郵件後,運行 checkpatch 命令並給自己的內核源碼打上你的補丁。如果這兩部都能通過,你就可以給 Linux 郵箱列表發送補丁了。使用 git send-email 命令是提交補丁最安全的方式,可以避免你的郵箱的兼容性問題。你的 .gitconfig 文件裡面需要配置好有效的 smtp 伺服器,詳細操作參考 git 的幫助文檔。
更多提交補丁的規矩,請參考下面的資料:
- linux_git/Documentation/applying-patches.txt
- linux_git/Documentation/SubmitChecklist
- linux_git/Documentation/SubmittingDrivers
- linux_git/Documentation/SubmittingPatches
- linuxgit/Documentation/stablekernel_rules.txt
- linuxgit/Documentation/stableapi_nonsense.txt
下面是一些內核測試教程的資料:
- USB Testing on Linux
- Linux Kernel Tester's Guide Chapter2
- Linux Kernel Tester's Guide
- Testing resources at eLinux.org
- eLinux Debugging Portal
內核測試套件和項目
除我們討論過的測試資源之外,這裡還有很多測試項目值得介紹,包括開源的和廠家自己提供的。這些項目每一個都是針對特定領域的,比如嵌入式或者企業自己使用。我們簡單過一下。
Linux 測試項目(LTP)測試套件是一系列工具的集合,用於測試內核的可靠性、健壯性和穩定性。你可以為這個項目添加自己的測試代碼,並且 LTP 項目歡迎你貢獻自己的代碼。runltp 腳本默認情況下會測試下面的子系統:
- 文件系統壓力測試
- 磁碟 IO 測試
- 內存管理壓力測試
- IPC(進程間通信)測試
- 調度器測試
- 命令的功能性驗證測試
- 系統調用功能驗證測試
LTP-DDT 是一個基於 LTP 的測試應用(LCTT:就是 LTP 的閹割版么),專註於測試嵌入式設備驅動。
Linux Driver Verification 這個項目的目標是提高 Linux 設備驅動的質量,它為設備驅動驗證開發了集成環境平台,並且利用與時俱進的研究來增強驗證工具的質量。
一致性測試
如果你有將某個 Unix 平台下的應用一直到另一個平台的經驗,你就能理解 Linux Standard Base (LSB) 和 LSB 一致性測試套件的重要性了。LSB 是 Linux Foundation 工作組創建的用於降低支持不同 Linux 平台所需要的開銷,方法就是通過降低不同 Linux 發行版之間的差別,保證應用在不同發行版之間的可移植性。前事不忘後事之師,Unix 世界的分歧在 Linux 世界一定要避免。這就是為什麼你可以把一個 rpm 包轉化成 deb 包後還能安裝並正常運行的秘密。
靜態分析工具
靜態分析之所以會被稱為「靜態分析」,是因為這些工具只分析代碼,並不執行它們。分析 Linux 內核代碼的靜態分析工具有很多,Sparse 是 Linus Torvalds 寫的專門用於檢查內核靜態類型的工具。它是一個語義檢查器,會為 C 語言的語義建立語義檢析樹,執行惰性類型評估。內核編譯系統支持 sparse,並且為編譯內核的命令提供開啟 sparse 的選項。
為內核所有需要重新編譯的 C 文件執行 sparse 語義檢查:
make C=1 allmodconfig
為內核所有 C 文件(即使不需要重新編譯)執行 sparse 語義檢查:
make C=2 allmodconfig
Sparse 的資源:
Smatch 分析程序代碼的邏輯錯誤。它可以檢測到諸如「為一個沒鎖上的 spinlock 執行解鎖」的邏輯錯誤。內核源碼支持 smatch:
在 Linux 內核中運行 smatch:
make CHECK="~/path/to/smatch/smatch -p=kernel" C=1 bzImage modules | tee warns.txt
請參考下面的資料來獲取和編譯 smatch。需要注意的是 smatch 是個正在發展的項目,架構會不斷變化。
那麼我們該怎麼處理 Sparse 和 Smatch 所發現的語義和邏輯上的錯誤呢?一些錯誤可以被分離為日常問題或模塊問題,可以輕易被解決。但是有些語義錯誤涉及到全局,因為剪切粘貼了一些代碼。在一些環境中,當一些介面函數被廢棄不再使用,或者僅僅做了寫微小的修改,你就需要大規模更新源碼。這時候你需要 Coccinelle 來幫忙。,Coccinelle 使用 SmPL 語言(語義包語言)來為 C 代碼提供匹配和轉換代碼的功能。Coccinelle 的從一開始就作為 Linux 的附屬產品持續發展的。
舉個例子:foo(int) 函數突然變成 foo(int, char *) 函數,多出了一個輸入參數(可以把第二個參數置為 null)。所有調用 foo() 函數的代碼都需要更新了,這可能是個悲摧的體力活。但是使用 Coccinelle 的話,這項工作瞬間變得輕鬆,腳本會幫你找到調用 foo(parameter1) 的代碼,然後替換成 foo(parameter1, NULL)。做完這些後,所有調用這個函數的代碼都可以運行一遍,驗證下第二個參數為 NULL 是否能正常工作。關於 Coccinelle 的更多信息,以及在不同項目中(當然,也包括 Linux 內核這個項目)的使用方法,請參考項目主頁:Cocinelle。
參考文獻
本文涵蓋了很多方面,這裡列出一些參考文檔供讀者做進一步研究。
- KernelHacking
- kernel Documentation
- Linux Device Drivers, Third Edition
- Dynamic Event Tracing in Linux Kernel
- Kernel Testing: Tool and Techniques
鳴謝
感謝來自 Oracle 的 Khalid Aziz,審查校對並提供許多非常有價值的建議。感謝來自三星的 Mauro Chehab 和 Guy Martin,他們給了我多次反饋。感謝來自 Linux Foundation 的 Grey Kroah-Hartman 對本文的審閱。感謝來自三星的 Ibrahim Haddad,沒有他的支持和鼓勵,我可能還不會坐下來寫出這篇文章。
作者:Shuah Khan
Shuah Khan 是三星公司開源組的高級 Linux 內核開發工程師。 她為 Linux 內核中的 IOMMU、DMA、電源管理、PCIe 貢獻代碼,同時維護內核,為內核提供補丁包。Shuah 有多年 Unix 內核開發經驗。她也為 OpenHPI 和 LLDP 項目作貢獻。
via: http://www.linuxjournal.com/content/linux-kernel-testing-and-debugging?page=0,5
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive