《Linux內核設計與實現》 第十八章學習筆記

調  試

1、準備開始

  • 一個bug
  • 一個藏匿bug的內核版本
  • 相關內核代碼的知識和運氣
  • 知道這個bug最先出如今哪一個內核版本中。

一、想要成功進行調試:linux

  • 讓這些錯誤重現
  • 抽象出問題
  • 從代碼中搜索

 

2、內核中的buggit

  從隱藏在源代碼中的錯誤到展示在目睹者面前的bug,每每是經歷一系列連鎖反應的事件纔可能觸發的。內核確實有一些獨特的問題須要考慮,像定時限制和競爭條件等,它們都是容許多個線程在內核中同時運行產生的結果。ide

 

3、經過打印來調試
  內核提供的打印函數printk()和C 庫提供的printf()函數功能幾乎相同。函數

一、健壯性oop

  • 健壯性是printk() 函數最容易讓人們接受的一個特質..能夠在中斷上下文和進程上下中被調用,能夠在任何持有鎖時被調用,能夠在多處理器上同時被調用,並且調用者連鎖都沒必要使用。
  • 解決的辦單是提供一個printk() 的變體函數一一early_printk(),這個函數在啓動過程的初期就具備在終端上打印的能力,它的功能與prink()徹底相同,區別僅僅在於名字和可以更早地工做,不過,因爲該函數在一些內核支持的硬件體系結構上沒法實現,因此這種辦法峽少可移植性。

二、日誌等級spa

  • printk()和printf()在使用上最主要的區別就是前者能夠指定一個日誌級別, 內核根據這個級別來判斷是否在終端上打印消息。內核把級別比某個特定值低的全部消息顯示在終端上。

三、記錄緩衝區線程

  • 內核消息都被保存在一個LOG_BUF_LEN 大小的環形隊列中。該緩衝區大小能夠在編譯時經過設置CONFIG_LOG_BUF_SHIFf 進行調整。在單處理器的系統上其默認值是16。若是消息隊列已經達到最大值,那麼若是再有printk()調用,新消息將覆蓋隊列中的老消息。這個記錄緩衝區之因此稱爲環形,是由於它的讀寫都是按照環形隊列方式進行操做的。
  • 環形緩衝區的惟一缺點一一可能會丟失消息

四、syslogd 和klogd調試

  • syslogd 守護進程把它接收到的全部消息添加進一個文件中,該文件默認是/var/log/messages.也能夠經過/etc/syslog.conf 配置文件從新指定。在啓動klogd 的時候,能夠經過指定-c 標誌來改變終端的記錄級。

 

4、oops日誌

  • oops 是內核告知用戶有不幸發生的最經常使用的方式。oops 的產生有不少可能緣由,其中包括內存訪問越界或者非法的指令等。

一、ksymoops
  若是使用的是模塊, 還須要一些模塊信息。ksymoops 一般會自行解析這些信息,調用後獲得解碼板的oops隊列

ksymoops saved_ oops. txt

二、kallsyms

  • 經過定義CONFIG_KALLS YMS 配置選項啓用。該選項存放着內核鏡像中相應函數地址的符號名稱,因此內核能夠打印解碼好的跟蹤線索

 

5、內核調試配置選項
  內核開發( Kernel hacking)菜單項中,它們都依賴於CONFIG_DEBUG_KERNEL。。其中最有用的一個是sleep-inside-spinlock-checking (自旋鎖內睡眠選項)。使用鎖時睡眠是引起死鎖的元兇。因此,包括正使用鎖的時候調用,正使用鎖的時候以阻塞方式請求分配內存和在引用單CPU 數據時睡眼在內,各類潛在的bug 都可以被探測到。

 

6、引起bug 並打印信息
  最經常使用的兩個是BUG() 和BUG_ON()。當披調用的時候,它們會引起oops ,致使栓的回溯和錯誤信息的打印能夠把這些調用當作斷言使用,想要斷言某種狀況不應發生:

if (bad_thing)
BUG();

  或者使用更好的形式:

BUG_ON (bad_thing);

  多數內核開發者相信BUG_ON()比BUG()更清晰、更可讀, 並且BUG_ON()會將其聲明做爲一個語句放入unlikely()中。

  能夠用panic()引起更嚴重的錯誤。調用panic()不但會打印錯誤消息,並且還會掛起整個系統。顯然,只應該在最糟糕的狀況下使用它

if (terrible_thing)
panic ( 」 terrible thing is %ld\n 」, terrible_thing);

 

7、內核調試器的傳奇
一、gdb

  • 可使用標準的GNU 調試器對正在運行的內核進行查看。針對內核啓動調試器的方站與針對進程的方棟大體相同:

gdb vml inux /proc/kcore

  【其中vmlinux 文件是未經壓縮的內核映像,不是壓縮過的zlmage 或bzlmage,它存放在源代碼樹的根目錄上。】

  • /proc/kcore 做爲一個參數選項,是做爲core 文件來用的,經過它可以訪問到內核駐留的高端內存。只有超級用戶才能讀取此文件的數據。可使用gdb 的全部命令來獲取信息。若是編譯內核的時候使用了-g 參數(在內核的Makefile 文件的CFLAGS 變量中加入-g),gdb 還能夠提供更多的信息。

二、kgdb

  • kgdb 是一個補丁,它可讓咱們在遠端主機上經過串口利用gdb 的全部功能對內核進行調試。這須要兩臺計算機:第一臺運行帶有kgdb補丁的內核,第二臺經過行線(不經過modem,直接鏈接兩臺機器的電纜)使用gdb對第一臺進行調試。

8、使用Git 進行二分搜索

一開始,你得告訴Git 你要進行二分搜索:

$ git bisect start

而後再爲Git 提供一個出現問題的最先內核版本:

$ git bisect bad <revision>

若是當前的內核版本就是引起bug的罪魁禍首,那麼就沒必要提供內核版本:

$ git bisect bad

而後,還得爲Git 提供一個最新的可正常運行的內核版本:

$ git bisect good v2.6.28

若是這個版本一切正常,能夠運行下面的命令:

$ git bisect good

若是這個版本運行有異常一一也就是說,若是證實這個給定的內核版本有bug,能夠運行:

$ git bisect bad

若是你已經知道引起bug 的源(好比, x86 機型的啓動代碼),你能夠指定git僅僅在與錯模相關的目錄列表中去二分搜索提交的補丁。

$ git bisect start - arch/x86
相關文章
相關標籤/搜索