20135320赵瀚青LINUX第十八章读书笔记
概述:調試工作艱難是內核級開發區別于用戶級開發的一個顯著特點
18.1準備開始
內核調試往往是一個令人撓頭不已的漫長過程。幸運的是,在這些費勁的問題中也有不少比較簡單而且容易消滅的小bug,運氣好你可能面對的是些簡單的小bug。
開始做―些調查之前,不會清楚到底面對的是什么現在,需要的只是: 一個bug。聽起來很可笑,但確實需要一個確定的bug。如果錯誤總是能夠重現的話,那對我們會有很大的幫助(有一部分錯誤確實如此)。然而不幸的是,大部分bug通常都不是行為可靠而且定義明確的。 一個藏匿bug的內核版本。如果你知道這個bug最早出現在哪個內核版本中那就再理想不過了。 相關內核代碼的知識和運氣。調試內核其實是一個棘手的問題。不過對周圍的代碼理解得越多調試起來也就越輕松。18.2 內核中的bug
內核中的bug多種多樣,它們的產生可以有無數的原因,同時它們的表象也變化多端
- 明白無誤的錯誤代碼(比如,沒有把正確的值存放在恰當的位置)
- 同步時發生的錯誤(比如共享變量鎖定不當)
- 錯誤地管理硬件(比如,給錯誤的控制寄存器發送錯誤的指令)。
- 降低所有程序的運行性能到毀壞數據再到使得系統處于死鎖狀態,都可能是bug發作時的癥狀。
18.3通過打印來調試
printk():內核的格式化打印函數1. 健壯性
彈性極佳的函數:任何時候、任何地方都能調用它
可以在中斷上下文和進程上下文中被調用
可以在任何持有鎖時被調用
可以在多處理器上同時被調用
除非再啟動過程中的初期就要在終端上輸出
2. 日志等級
printk()和printf()在使用上最主要的區別就是前者可以指定一個日志級別。內核通過這個級別來判斷是否在終端上打印消息。
內核把級別比某個特定值低的所有消息顯示在終端上。
- 0 KERN_EMERG 最重要
- 7 KERN_DEBUG 最不重要
調試信息, 有兩種賦予記錄等級的方法:
- 保持終端的默認記錄等級不變,給所有調試信息KERN_CRIT或更低的等級。
- 給所有調試信息KERN_DEBUG等級,調整終端的默認記錄等級。
3. 記錄緩沖區
內核消息保存在一個LOG_BUF_LEN大小的環形隊列中,讀寫都是按照環形隊列方式操作的。
大小是可以在編譯時通過CONFIG_LOG_BUF_SHIFT進行調整。
在單處理器的系統上默認值是16kb,即內核在同一時間只能保存16kb的內核消息,再多的話新消息就會覆蓋老消息。
優點:
- 同步問題易解決
- 記錄維護容易
缺點: 可能會丟失消息
18.4、oops
1. 概述
oops是內核告知用戶有不幸發生的最常用的方式。
內核很難自我修復,也不能將自己殺死,只能發布oops,過程:- 向終端上輸出錯誤消息
- 輸出寄存器中保存的信息
輸出可供跟蹤的回溯線索
通常發送完oops之后,內核會處于一種不穩定狀態。
寄存器上下文信息也很有用,比如幫助沖進引發問題的現場
2. ksymoops
調用ksymoops命令:將回溯線索中的地址需要轉化成有意義的符號名稱
并且還必須提供編譯內核時產生的System.map。如果用的是模塊,還需要調用一些模塊信息:kysmoop saved_oops.txt
3. kallsyms
現在的版本中不需要使用kysmoops這個工具,因為可能會發生很多問題,新版本中引入了kallsyms,可以通過定義CONFIG_KALLSYMS配置選項啟用。
18.5 內核調試配置選項
在編譯的時候,為了方便調試和測試內核代碼,內核提供了許多配置選項。在內核配置編輯器的內核開發菜單。這些選項中,它們都依賴于CONFIG_DEBUG_KERNEL。當開發內核的時候,作為一種練習,不妨打開所有這些選項。
有些選項確實有用,這些選項確實能完成不少調試工作。
18.6 引發bug并打印信息
一些內核調用可以用來方便標記bug方便標記bug提供斷言并輸出信息。最常用的兩個是BUG()和些聲明BUG_ON()。當被調用的時候,它們會引發oops,導致棧的回溯和錯誤信息的打印。大部分體系結構把BUG()和BUG_ON()定義成某種會導致oops跟硬件的體系結構是相關的非法操作,這樣自然會產生需要的oops。可以把這些調用當做斷言使用,想要斷言某種情況不該發生。
18.7 神奇的系統請求鍵
神奇的系統請求鍵是另外一根救命稻草,該功能可以通過定義CONFIG_MAGIC_SYSRQ配置選項來啟用。
當該功能被啟用的時候,無論內核處于什么狀態,都可以通過特殊的組合鍵跟內核進行通信。這種功能可以讓你在面對一臺奄奄一息的系統時能完成一些有用的工作。除了配置選項以外,還要通過一個sysctl用來標記該特性的開或關。
需要啟用它時使用如下命令:echo 1> /proc/sys/kernel/sysrq
18.8 內核調試器的傳奇
很多內核開發者一直以來都希望能擁有一個用于內核的調試器.不幸的是,Linus不愿意在它的內核源代碼樹中加入一個調試器。他認為調試器會誤導開發者,從而致引入不良的修正,沒有人能對他的邏輯提出異議從真正理解代碼出發,確實更能保證修正的正確性。然而,許多內核開發者們還是希望有一個官方發布的、用于內核的調試器。因為這個要求看起來不會馬上被滿足,所以許多補丁應運而生了,它們為標準內核附加上了內核調試的支持,雖然這都是―些不被官方認可的附加補丁,但它們確實功能完善,十分強大。在我們深入這些解決方案之前,先看看標準的調試器gdb能夠給我們一些什么幫助是―個不錯的選擇。
18.9 探測系統
如果對內核調試有豐富的經驗的話,那么你會掌握一些訣竅來幫助你更進一步地探測系統從而找到想要的答案。內核調試很有挑戰性,即使是一點小的暗示或者技巧都能給你很大的幫助我們最好把它們聯系起來。
18.9.1 用UID作為選擇條件
假設為了加入一個激動人心的新特性,你重寫了fork()系統調用。除非第一次的嘗試就完美無缺,否則系統調試就是―場噩夢。如fork()系統調用不正常的話,壓根就不用指望整個系統還能正常工作。當然,和任何時候一樣,希望總是存在的,一般情況下,只要保留原有的算法而把你的新算法加入到其他位置上,基本就能保證安全:可以利用把用戶id作為選擇條件來實現這種功能,通過這種選擇條件,可以安排到底執行哪種算法。
18.9.2 使用條件變量
如果代碼與進程無關,或者希望有一個針對所有情況都能使用的機制來控制某個特性,可以使用條件變量。這比使用UID還來得簡單,只需要創建一個全局變量作為一個條件選擇開關。如果該變量為零,就使用一個分支上的代碼。如果它不為零,就選擇另外一個分支。可以通過某種接口提供對這個變量的操控,也可以直接通過調試器進行操控。
18.9.3 使用統計量
有些時候你需要掌握某個特定事件的發生規律。有些時候需要比較多個事件并從中得出規律。通過創建統計量并提供某種機制訪問其統計結果,很容易就能滿足這種需求。舉個例子,假設我們希望得到foo和bar的發生頻率,那么在某個文件中,當然最好是在定義該事件的那個文件里定義兩個全局變量。
18.9.4 重復頻率限制
18.10 用二分查找法找出引發罪惡的變更
18.11 使用Git進行二分搜索
Git源碼管理工具提供了一個有用的二分搜索機制。如果你使用Git來控制Linux源碼樹的副本,那么Git將自動運行二分搜索進程。此外,Git會在修訂版本中進行二分搜索,這樣可以找到具體哪次提交的代碼引發了bug。很多Git相關的任務比較繁雜,但使用Git進行二分搜索并不那么的困難。轉載于:https://www.cnblogs.com/5320zhq/p/5339113.html
總結
以上是生活随笔為你收集整理的20135320赵瀚青LINUX第十八章读书笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ExtJs之gridPanel的属性表格
- 下一篇: SQL Server 2008 R2 开