須要的是準備是: - 一個bug - 一個藏匿bug的內核版本 - 相關內核代碼的知識和運氣linux
重點: 想要成功的進行調試,就取決因而否能讓這些錯誤重現。如若不能,消滅bug就只能經過抽象出問題,再從代碼中尋找蛛絲馬跡來進行了。算法
bug出現時可能的症狀:sass
內核bug發做時可能的症狀:app
概述:編輯器
內核中的bug表現得不像用戶級程序中那麼清晰——由於內核、用戶以及硬件之間的交互會很微妙ide
健壯性是printk()函數最容易讓人們接受的一個特質,在任什麼時候候,任何地方都能調用它。函數
printk()函數變體——early-printk()函數,區別僅在於能夠更早(甚至在啓動初期,終端尚未初始化以前)地工做oop
優點:性能
缺點:可能會丟失信息。學習
這是兩個用戶空間的守護進程,klogd從記錄緩衝區中獲取內核消息,再經過syslogd守護進程將他們保存在系統日誌文件中。 - klogd
- 既能夠從/proc/kmsg文件中,也能夠經過syslog()系統調用讀取這些消息。 - 默認是/proc方式。 - 兩種狀況klogd都會阻塞,知道有新的內核消息可供讀出,喚醒以後默認處理是將消息傳給syslogd。 - 能夠經過-c標誌來改變終端的記錄等級
過程包括:
關於oops發生的時機:
1.發生在中斷上下文:內核沒法繼續,會陷入混亂,致使系統死機
2.發生在idle進程或init進程(0號進程和1號進程),同上
3.發生在其餘進程運行時,內核會殺死該進程並嘗試着繼續執行
oops發生的可能緣由:
內存訪問越界
非法的指令
……
oops中包含的重要信息:寄存器上下文和回溯線索回溯線索:顯示了致使錯誤發生的函數調用鏈。
寄存器上下文信息也頗有用,好比幫助衝進引起問題的現場
• 將回溯線索中的地址轉換成有意義的符號名稱:
• ksymoops saved_oops.txt
• 經過定義CONFIG_KALLSYMS配置選項啓用,該選項中存放內核鏡像中相應函數地址的符號名稱,內核能夠打印解碼好的跟蹤線索
位於內核配置編輯器的內核開發菜單項中,都依賴於CONFIGDEBUGKERNEL。
slab layer debugging slab層調試選項 high-memory debugging 高端內存調試選項 I/O mapping debugging I/O映射調試選項 spin-lock debugging 自旋鎖調試選項 stack-overflow debugging 棧溢出檢查選項 sleep-inside-spinlock checking 自旋鎖內睡眠選項 ……
例如;正在使用一個自旋鎖或禁止搶佔的代碼。 使用鎖時睡眠是引起死鎖的元兇。
利用BUG()以及BUG_ON()(由於大多數體系結構都把這兩個函數定義成某種非法操做,能夠觸發oops)
調用panic()函數會在打印錯誤信息的同時掛起系統
調用dump_stack(),只在終端上打印寄存器上下文及函數的跟蹤線索
除了配置選項之外,還要經過一個sysctl用來標記該特性的開或關,啓動命令以下:
echo 1 > /proc/sys/kernel/sysrq
Sysrq的幾個命令:
SysRq-s:將「髒」緩衝區跟硬盤交換分區同步 SysRq-u:卸載全部的文件系統 SysRq-b:重啓設備
gdb vmlinux(未經壓縮的內核映像)-
可使用gdb的全部命令來獲取信息。例如:
打印一個變量的值: p global_variable 反彙編一個函數: disassemble function -g參數還能夠提供更多的信息。
侷限性:
沒有辦法修改內核數據
不能單步執行內核代碼
- 讀取和修改變量值 - 設置斷點 - 設置關注變量 - 單步執行
這種方式比使用UID更簡單,只須要建立一個全局變量做爲一個條件選擇開關:
若是該變量爲0,就使用某一個分支上的代碼; 不然,選擇另一個分支。
定義全局變量
在/proc目錄中建立一個文件 or新建一個系統調用 or經過調試器直接訪問(最直接)
(1)重複頻率限制 (2)發生次數限制
本章主要講內核的調試,調試過程就是一種尋求實現與目標誤差的行爲,經過學習各類調試技巧,,發現困難重重,但相信有一天努力會有成果的。
《linux內核設計與實現》原書第三版