用 kGDB 調試 Linux 內核
by Pingbo Wen of TinyLab.org
2013/08/11
簡介
這個文檔記錄了用kGDB調試Linux內核的全過程,都是在前人工作基礎上的一些總結。以下操作都是基于特定板子來進行,但是大部分都能應用于其他平臺。
要使用KGDB來調試內核,首先需要修改config配置文件,打開相應的配置,配置內核啟動參數,甚至修改串口驅動添加poll支持,然后才能通過串口遠程調試內核。
配置內核
基本配置
在內核配置文件:.config中,需要打開如下選項
CONFIG_KGDB | 加入KGDB支持 |
CONFIG_KGDB_SERIAL_CONSOLE | 使KGDB通過串口與主機通信(打開這個選項,默認會打開CONFIG_CONSOLE_POLL和CONFIG_MAGIC_SYSRQ) |
CONFIG_KGDB_KDB | 加入KDB支持 |
CONFIG_DEBUG_KERNEL | 包含驅動調試信息 |
CONFIG_DEBUG_INFO | 使內核包含基本調試信息 |
CONFIG_DEBUG_RODATA=n | 關閉這個,能在只讀區域設置斷點 |
可選選項
CONFIG_PANIC_TIMEOUT=5 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1 CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=1 CONFIG_S3C2410_WATCHDOG_ATBOOT=0 CONFIG_FRAME_POINTER -- 使KDB能夠打印更多的棧信息 CONFIG_KALLSYMS -- 加入符號信息 CONFIG_KDB_KEYBOARD -- 如果是通過目標版的鍵盤與KDB通信,需要把這個打開,且鍵盤不能是USB接口 CONFIG_KGDB_TESTS
啟動參數
打開相應的選項后,需要配置kernel啟動參數,使KGDB和內核能夠找到正確的通信接口。如果是使用串口,則需要配置如下選項:
console=ttySAC3,115200 kgdboc=ttySAC3,115200
如果需要調試內核的啟動過程,則需要在kgdboc后面加入kgdbwait。
在其他板子上,若使用以太網口來和KGDB進行通信,則要把kgdboc換成kgdboe(kgdb
over ethernet))。
配置完后,就可以正常編譯,然后把內核下載到目標板上面。
串口驅動修改
如果在內核啟動的過程中出現如下錯誤提示:
kgdb: Unregistered I/O driver, debugger disabled.
則需要根據這一部分,修改串口驅動程序,若能正常進入kgdb,則忽略該節,直接進入下一節使用KGDB。
在drivers/tty/serial/kgdboc.c中的configure_kgdboc函數,會通過tty_find_polling_driver(cptr,
&tty_line)來找尋內核啟動參數中指定的串口驅動。然后通過kgdboc_get_char()和kgdboc_put_char()來和主機串口正常通信。
可以看到在config配置文件的CONFIG_CONSOLE_POLL就是使能串口與kgdboc的接口。如果 tty_find_polling_driver沒有找到對應的串口通信接口,則會調用kernel/debug/debug_core.c中的 kgdb_unregister_io_module進行錯誤處理。
有的板子的串口驅動并沒有加入對kgdboc通信的支持,例如Samsung的串口驅動需要在drivers/tty/serial/samsung.c中手動添加。
添加與kgdboc通信的接口,只需添加一個發送函數和接收函數,然后在驅動操作結構體中加入對應的函數就可以了。具體的PATCH如下:
drivers/tty/serial/samsung.c | 22 ++++++++++++++++++++++ 1 files changed, 22 insertions(+), 0 deletions(-) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index ff6a4f8..5ceb7d7 100755 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -893,7 +893,29 @@ static struct console s3c24xx_serial_console; #define S3C24XX_SERIAL_CONSOLE NULL #endif +#ifdef CONFIG_CONSOLE_POLL +static void s3c24xx_serial_poll_put_char(struct uart_port *port, unsigned char c) +{ + while (!(rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE)) + ; + + wr_regl(port, S3C2410_UTXH, c); +} + +static int s3c24xx_serial_poll_get_char(struct uart_port *port) +{ + while (!(rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_RXDR)) + ; + + return rd_regl(port, S3C2410_URXH); +} +#endif + static struct uart_ops s3c24xx_serial_ops = { +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = s3c24xx_serial_poll_get_char, + .poll_put_char = s3c24xx_serial_poll_put_char, +#endif .pm = s3c24xx_serial_pm, .tx_empty = s3c24xx_serial_tx_empty, .get_mctrl = s3c24xx_serial_get_mctrl, -- 1.7.5.4
加入這個patch,重新編譯內核,之后就能正常進入kgdb
gdb遠程調試
如果在內核啟動參數中加入了kgdbwait,則內核會在完成基本的初始化之后,停留在kgdb的調試陷阱中,等待主機的gdb的遠程連接。
由于大部分的板子只有一個調試串口,所以你需要把之前與串口通信的minicom退出來,然后在內核源碼的目錄下,執行以下命令:
$ arm-linux-gnueabi-gcc vmlinux (gdb) target remote /dev/ttyUSB0 (gdb) set detach-on-fork on (gdb) b panic() (gdb) c
當然,你也可以agent-proxy來復用一個串口,通過虛擬出兩個TCP端口。這時候,gdb就需要用target
remote命令連接kgdb,例如:
(gdb) target remote localhost:5551
agent-proxy可以通過這里獲取:git://git.kernel.org/pub/scm/utils/kernel/kgdb/agent-proxy.git,具體用法,請看該repo下的README。
在用gdb來調試內核的時候,由于內核在初始化的時候,會創建很多子線程。而默認gdb會接管所有的線程,如果你從一個線程切換到另外一個線程,gdb會馬上把原先的線程暫停。但是這樣很容易導致kernel死掉,所以需要設置一下gdb。
一般用gdb進行多線程調試,需要注意兩個參數:follow-fork-mode和detach-on-fork。
-
detach-on-fork參數,指示GDB在fork之后是否斷開(detach)某個進程的調試,或者都交由GDB控制:
set detach-on-fork [on|off]
- on: 斷開調試follow-fork-mode指定的進程。
- off: gdb將控制父進程和子進程。
-
follow-fork-mode指定的進程將被調試,另一個進程置于暫停(suspended)狀態。follow-fork-mode的用法為:
set follow-fork-mode [parent|child]
- parent: fork之后繼續調試父進程,子進程不受影響。
- child: fork之后調試子進程,父進程不受影響。
REFERENCE
- gdb user
mannual: http://sourceware.org/gdb/current/onlinedocs/gdb/ - gdb
internal: http://www.sourceware.org/gdb/onlinedocs/gdbint.html - kgdb/kdb official
website: https://kgdb.wiki.kernel.org/ - kernel debug
usage: http://www.kernel.org/doc/htmldocs/kgdb.html - kdb in elinux.org: http://elinux.org/KDB
- multi-threads debug in
gdb: http://www.ibm.com/developerworks/cn/linux/l-cn-gdbmp/ - KGDB.info: http://www.kgdb.info/