linux內核調試2

http://blog.chinaunix.net/uid-29401328-id-4932947.html


下面再來測試一次:

# insmod syst.ko
s_init success!
# ./test             // 卡死了,等10s會打印如下信息
asm_do_IRQ -> s3c2410_timer_irq : pid = 635 , task_name = test , pc = bf0d700c
asm_do_IRQ -> s3c2410_timer_irq : pid = 635 , task_name = test , pc =bf0d700c

我們一眼就看出來了,問題出現在test這個程序上,但具體出在哪不清楚,就要根據PC值去分析了,分析方法和之前博文講的一樣。
下面再嘮叨一遍:

1. bf0d700c所在的函數。
現在的系統僵死了,我們沒辦法繼續下去,只有重啓系統。這裏注意一個問題,重啓系統使用的內核要和僵死時使用的內核是同一個。
因爲如果內核變了,我們就很難還原僵死前的狀態了,新內核pc = bf0d700c可能代表不同的代碼。


用tftp啓動剛纔的內核,插入模塊sy.ko。
先去查看內核源碼下的 System.map 文件,看PC地址是否屬於其中,這裏不屬於(那裏面是內核函數,地址都是以C開頭

然後查看開發板的模塊地址:cat cat /proc/kallsyms >kall.txt  或者  cat /proc/kallsyms   | grep bf0d700c 管道過濾


打開kall.txt,在裏面查找PC值相近的地址(有可能直接查到,也有可能PC位於某段地址之間),這裏查到:

00000000 a system_dead.c        [sydead]
bf0d7000 t $a   [system_dead]
bf0d7000 t sysdead_test_open   [sydead]
bf0d7010 t sysdead_drv_exit     [sydead]

可知pc = bf0d700c位於sy_open函數中。接下來去分析這個函數

2. 分析發生錯誤的函數
因爲我們這裏的代碼很短,所以可以很快的定位出問題,但當代碼很長時,可能就需要看彙編了。這裏給出方法

反彙編sy_open函數位於的模塊sy.ko
arm-none-linux-gnueabi-objdump sy.ko -D >sy.dis

打開sy.dis:(貼出對我們有用的那段
00000000 :
   0:   e1a0c00d        mov     ip, sp
   4:   e92dd800        push    {fp, ip, lr, pc}
   8:   e24cb004        sub     fp, ip, #4      ; 0x4
   c:   eafffffe        b       c

到這裏就需要用匯編去分析了,我們這裏的錯誤比較明顯,就是一直跳轉到自己這個函數裏,調不出去了。

注:有可能兩次發生僵死時PC值不一樣,就算僵死在同一段代碼,PC值也可能不一樣。因爲果死循環是一段代碼,

那麼僵死時,程序可能正在執行這段代碼當中的任意一句。

2 OOPS

Oops 中包含的重要信息對於所有體系結構都是完全相同的 : 寄存器上下文和回溯線索 . 回溯線索顯示了導致錯誤發生的函數調用鏈 . 寄存器上下文信息可能同樣有用 , 儘管使用起來不那麼方便 . 如果你有函數的彙編代碼 , 這些寄存器數據可以幫助你重建引發問題的現場 . 在寄存器中一個本不應該出現的數值可能會在黑暗中給你帶來第一絲光明 .

[1] ksymoops

   提供編譯內核是產生的 System.map 和模塊信息 ( 如何你使用的是模塊 ) 把 OOPS 信息解碼 .

   $ ksymoops saved_oops.txt

[2] kallsysms

   開發版的 2.5 內核引入了 kallsysms 特性 , 它可以通過定義 CONFIG_KALLSYMS 配置選項啓用 . 該選項可以載入內核鏡像對應的內存地址的符號名稱 , 所以內核可以打印解碼好的跟蹤線索 . 相應地 , 解碼 oops 也不再需要 system.map 或者 ksysmoops 工具了 .

3 內核調試配置選

    這些選項都在內核配置編輯器的內核開發 (Kernel Hacking) 菜單中 , 他們都依賴於 CONFIG_DEBUG_KERNEL. 當你開發內核的時候 , 作爲一種練習 , 不妨都打開這些選項 .

[1] 調試原子操作

    把內核配置成一旦在原子操作過程中進程進入休眠或者做了一些可能引起休眠的操作 , 就打印警告信息並提供追蹤線索 .

    CONFIG_PREEMPT = y

    CONFIG_DEBUG_KERNEL = y

    CONFIG_KALLSYMS = y

    CONFIG_SPINLOCK_SLEEP = y

4 引發 bug 並打印信息

BUG() BUG_NO() 被調用時引發 oops, 導致棧的回溯和錯誤信息的打印

panic() 不但會打印錯誤信息 , 而且會掛起整個系統

dump_stack() 在終端上打印寄存器上下文和函數跟蹤線索 .

5 神奇的 SysRq

    神奇系統請求鍵是另外一根救命稻草 , 該功能可以通過定義 CONFIG_MAGIC_SYSRQ 配置選項開啓用 . 當該功能被啓用的時候 , 無論內核處於什麼狀態 , 你都可以通過特殊的組合鍵跟內核進行通信 .

6 內核調試器的傳奇

[1] gdb

    $ gdb vmlinux /proc/kcore

    > p global_variable

    > disassemble function

[2] kgdb

[3] kdb

http://blog.chinaunix.net/uid-26923078-id-3327126.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章