linux kdb 内核调试器
許多讀者可能奇怪為什么內(nèi)核沒有建立更多高級(jí)的調(diào)試特性在里面.答案, 非常簡(jiǎn)單, 是 Linus 不相信交互式的調(diào)試器. 他擔(dān)心它們會(huì)導(dǎo)致不好的修改, 這些修改給問題打了補(bǔ)丁 而不是找到問題的真正原因. 因此, 沒有內(nèi)嵌的調(diào)試器.
其他內(nèi)核開發(fā)者, 但是, 見到了交互式調(diào)試工具的一個(gè)臨時(shí)使用. 一個(gè)這樣的工具是 kdb 內(nèi)嵌式內(nèi)核調(diào)試器, 作為來自 oss.sgi.com 的一個(gè)非官方補(bǔ)丁. 要使用 kdb, 你必須獲 得這個(gè)補(bǔ)丁(確認(rèn)獲得一個(gè)匹配你的內(nèi)核版本的版本), 應(yīng)用它, 重建并重安裝內(nèi)核. 注意, 直到本書編寫時(shí), kdb 只在 IA-32(x86)系統(tǒng)中運(yùn)行(盡管一個(gè)給 IA-64 的版本在主線內(nèi)核 版本存在了一陣子, 在被去除之前.)
一旦你運(yùn)行一個(gè)使能了 kdb 的內(nèi)核, 有幾個(gè)方法進(jìn)入調(diào)試器. 在控制臺(tái)上按下 Pause(或 者 Break) 鍵啟動(dòng)調(diào)試器. kdb 在一個(gè)內(nèi)核 oops 發(fā)生時(shí)或者命中一個(gè)斷點(diǎn)時(shí)也啟動(dòng), 在 任何一種情況下, 你看到象這樣的一個(gè)消息:
Entering kdb (0xc0347b80) on processor 0 due to Keyboard Entry [0]kdb>
注意, 在 kdb 運(yùn)行時(shí)內(nèi)核停止任何東西. 在你調(diào)用 kdb 的系統(tǒng)中不應(yīng)當(dāng)運(yùn)行其他東西; 特別, 你不應(yīng)當(dāng)打開網(wǎng)絡(luò) -- 除非, 當(dāng)然, 你在調(diào)試一個(gè)網(wǎng)絡(luò)驅(qū)動(dòng). 一般地以單用戶模式 啟動(dòng)系統(tǒng)是一個(gè)好主意, 如果你將使用 kdb.
作為一個(gè)例子, 考慮一個(gè)快速 scull 調(diào)試會(huì)話. 假設(shè)驅(qū)動(dòng)已經(jīng)加載, 我們可以這樣告訴 kdb 在 sucll_read 中設(shè)置一個(gè)斷點(diǎn):
[0]kdb> bp scull_read
Instruction(i) BP #0 at 0xcd087c5dc (scull_read) is enabled globally adjust 1
[0]kdb> go
bp 命令告訴 kdb 在下一次內(nèi)核進(jìn)入 scull_read 時(shí)停止. 你接著鍵入 go 來繼續(xù)執(zhí)行. 在將一些東西放入一個(gè) scull 設(shè)備后, 我們可以試著通過在另一個(gè)終端的外殼下運(yùn)行 cat 命令來讀取它, 產(chǎn)生下面:
Instruction(i) breakpoint #0 at 0xd087c5dc (adjusted) 0xd087c5dc scull_read: int3
Entering kdb (current=0xcf09f890, pid 1575) on processor 0 due to
Breakpoint @ 0xd087c5dc [0]kdb>
我們現(xiàn)在位于 scull_read 的開始. 為看到我們?nèi)魏蔚侥抢锏? 我們可以獲得一個(gè)堆棧回 溯:
[0]kdb> bt
ESP EIP
Function (args)
0xcdbddf74
0xd087c5dc [scull]scull_read 0xcdbddf78 0xc0150718 vfs_read+0xb8 0xcdbddfa4
0xc01509c2 sys_read+0x42 0xcdbddfc4 0xc0103fcf syscall_call+0x7 [0]kdb>
kdb 試圖打印出調(diào)用回溯中每個(gè)函數(shù)的參數(shù). 然而, 它被編譯器的優(yōu)化技巧搞糊涂了. 因 此, 它無法打印 scull_read 的參數(shù).
到時(shí)候查看一些數(shù)據(jù)了. mds 命令操作數(shù)據(jù); 我們可以查詢 schull_devices 指針的值, 使用這樣一個(gè)命令:
[0]kdb> mds scull_devices 1 0xd0880de8 cf36ac00
....
這里我們要求一個(gè)(4 字節(jié))字, 起始于
scull_devices 的位置; 答案告訴我們的設(shè)備數(shù)組 在地址
0xd0880de8; 第一個(gè)設(shè)備結(jié)構(gòu)自己在 0xcf36ac00. 為查看那個(gè)設(shè)備結(jié)構(gòu), 我們需 要使用這個(gè)地址:
[0]kdb>
mds cf36ac00 0xcf36ac00 ce137dbc .... 0xcf36ac04 00000fa0 .... 0xcf36ac08
000003e8 ....
0xcf36ac0c 0000009b .... 0xcf36ac10 00000000 ....
0xcf36ac14 00000001 ....
0xcf36ac18 00000000 ....
0xcf36ac1c 00000001 ....
這里的 8 行對(duì)應(yīng)于 scull_dev 結(jié)構(gòu)的開始部分.
因此, 我們看到第一個(gè)設(shè)備的內(nèi)存位于 0xce137dbc, quantum 是 4000 (16 進(jìn)制 fa0), 量子集大小是 1000 (16 進(jìn)制
3e8 ), 當(dāng) 前有 155( 16 進(jìn)制 9b) 字節(jié)存于設(shè)備中.
kdb 也可以改變數(shù)據(jù). 假想我們要截短一些數(shù)據(jù)從設(shè)備中: [0]kdb> mm cf26ac0c 0x50
0xcf26ac0c = 0x50
在設(shè)備上一個(gè)后續(xù)的 cat 會(huì)返回比之前少的數(shù)據(jù).
kdb
有不少其他功能, 包括單步(指令, 不是 C 源碼的一行), 在數(shù)據(jù)存取上設(shè)置斷點(diǎn), 反匯編代碼, 步入鏈表, 存取寄存器數(shù)據(jù), 還有更多. 在你應(yīng)用了
kdb 補(bǔ)丁后, 一個(gè)完 整的手冊(cè)頁(yè)集能夠在你的源碼樹的 documentation/kdb 下發(fā)現(xiàn).
總結(jié)
以上是生活随笔為你收集整理的linux kdb 内核调试器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 源码方式安装 lrzsz 库
- 下一篇: Python标准库存储对象(pickle