使用kgdb調(diào)試linux內(nèi)核及內(nèi)核模塊
1. 幾種內(nèi)核調(diào)試工具比較
kdb:只能在匯編代碼級(jí)進(jìn)行調(diào)試;
優(yōu)點(diǎn)是不需要兩臺(tái)機(jī)器進(jìn)行調(diào)試。
gdb:在調(diào)試模塊時(shí)缺少一些至關(guān)重要的功能,它可用來(lái)查看內(nèi)核的運(yùn)行情況,包括反匯編內(nèi)核函數(shù)。
kgdb:能很方便的在源碼級(jí)對(duì)內(nèi)核進(jìn)行調(diào)試,缺點(diǎn)是kgdb只能進(jìn)行遠(yuǎn)程調(diào)試,它需要一根串口線及兩臺(tái)機(jī)器來(lái)調(diào)試內(nèi)核(也可以是在同一臺(tái)主機(jī)上用vmware軟件運(yùn)行兩個(gè)操作系統(tǒng)來(lái)調(diào)試)
使用kdb和gdb調(diào)試內(nèi)核的方法相對(duì)比較簡(jiǎn)單,這里只描述如何使用kgdb來(lái)調(diào)試內(nèi)核。
2.軟硬件準(zhǔn)備
環(huán)境:
一臺(tái)開(kāi)發(fā)機(jī)developer(192.168.16.5 com1),一臺(tái)測(cè)試機(jī)target(192.168.16.30 com2),都預(yù)裝redhat 9;一根串口線
下載以下軟件包:
linux內(nèi)核2.4.23 linux-2.4.23.tar.bz2
kgdb內(nèi)核補(bǔ)丁1.9版 linux-2.4.23-kgdb-1.9.patch
可調(diào)試內(nèi)核模塊的gdb gdbmod-1.9.bz2
3.ok,開(kāi)始
3.1 測(cè)試串口線
物理連接好串口線后,使用一下命令進(jìn)行測(cè)試,stty可以對(duì)串口參數(shù)進(jìn)行設(shè)置
在developer上執(zhí)行:
stty ispeed 115200 ospeed 115200 -F /dev/ttyS0
echo hello > /dev/ttyS0
在target上執(zhí)行:
stty ispeed 115200 ospeed 115200 -F /dev/ttyS1
cat /dev/ttyS1
串口線沒(méi)問(wèn)題的話在target的屏幕上顯示hello
3.2 安裝與配置
3.2.1 安裝
下載linux-2.4.23.tar.bz2,linux-2.4.23-kgdb-1.9.patch,gdbmod-1.9.bz2到developer的/home/liangjian目錄
*在developer機(jī)器上
#cd /home/liangjian
#bunzip2 linux-2.4.23.tar.bz2
#tar -xvf linux-2.4.23.tar
#bunzip2 gdbmod-1.9.bz2
#cp gdbmod-1.9 /usr/local/bin
#cd linux-2.4.23
#patch -p1 < ../linux-2.4.23-kgdb-1.9.patch
#make menuconfig
在Kernel hacking配置項(xiàng)中將以下三項(xiàng)編譯進(jìn)內(nèi)核
KGDB: Remote (serial) kernel debugging with gdb
KGDB: Thread analysis
KGDB: Console messages through gdb
注意在編譯內(nèi)核的時(shí)候需要加上-g選項(xiàng)
#make dep;make bzImage
使用scp進(jìn)行將相關(guān)文件拷貝到target上(當(dāng)然也可以使用其它的網(wǎng)絡(luò)工具)
#scp arch/i386/boot/bzImage root@192.168.16.30:/boot/vmlinuz-2.4.23-kgdb
#scp System.map root@192.168.16.30:/boot/System.map-2.4.23-kgdb
#scp arch/i386/kernel/gdbstart root@192.168.16.30:/sbin
gdbstart為kgdb提供的一個(gè)工具,用于激活內(nèi)核鉤子,使內(nèi)核處于調(diào)試狀態(tài)
{{分頁(yè)}}
3.2.2 配置
*在developer機(jī)器上
在內(nèi)核源碼目錄下編輯一文件.gdbinit(該文件用以對(duì)gdb進(jìn)行初始化),內(nèi)容如下:
#vi .gdbinit
define rmt
set remotebaud 115200
target remote /dev/ttyS0
end
#
以上在.gdbinit中定義了一個(gè)宏rmt,該宏主要是設(shè)置使用的串口號(hào)和速率
*在target機(jī)器上
編輯/etc/grub.conf文件,加入以下行:
#vi /etc/grub.conf
title Red Hat Linux (2.4.23-kgdb)
root (hd0,0)
kernel /boot/vmlinuz-2.4.23-kgdb ro root=/dev/hda1
#
在root目錄下建立一個(gè)腳本文件debugkernel,內(nèi)容如下:
#vi debug
#!/bin/bash
gdbstart -s 115200 -t /dev/ttyS1 <<EOF
EOF
#chmod +x debugkernel
這個(gè)腳本主要是調(diào)用gdbstart程序設(shè)置target機(jī)上使用的串口及其速率,并使內(nèi)核處于調(diào)試狀態(tài)
3.3 開(kāi)始調(diào)試
target上的內(nèi)核或內(nèi)核模塊處于調(diào)試狀態(tài)時(shí),可以查看其變量、設(shè)置斷點(diǎn)、查看堆棧等,并且是源碼級(jí)的調(diào)試,和用gdb調(diào)試用戶程序一樣
3.3.1 內(nèi)核啟動(dòng)后調(diào)試
*在target機(jī)器上
重啟系統(tǒng),選擇以 2.4.23-kgdb內(nèi)核啟動(dòng),啟動(dòng)完成后運(yùn)行debugkenel,
這時(shí)內(nèi)核將停止運(yùn)行,在控制臺(tái)屏幕上顯示信息,并等待來(lái)自developer的
串口連接
#./debug
About to activate GDB stub in the kernel on /dev/ttyS1
Waiting for connection from remote gdb...
*在developer機(jī)器上
#cd /home/liangjian/linux-2.4.23
# gdb vmlinux
GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
執(zhí)行rmt宏
(gdb) rmt
breakpoint () at kgdbstub.c:1005
1005 atomic_set(&kgdb_setting_breakpoint, 0);
這時(shí)target上的內(nèi)核處于調(diào)試狀態(tài),可以查看其變量、設(shè)置斷點(diǎn)、查看堆棧等,和用gdb調(diào)試用戶程序一樣
查看堆棧
(gdb) bt
#0 breakpoint () at kgdbstub.c:1005
#1 0xc0387f48 in init_task_union ()
#2 0xc01bc867 in gdb_interrupt (irq=3, dev_id=0x0, regs=0xc0387f98) at
gdbserial.c:158
#3 0xc010937b in handle_IRQ_event (irq=3, regs=0xc0387f98, action=0xce5a9860)
at irq.c:452
#4 0xc0109597 in do_IRQ (regs=
{ebx = -1072671776, ecx = -1, edx = -1070047232, esi = -1070047232, edi
= -1070047232, ebp = -1070039092, eax = 0, xds
= -1070071784, xes = -1070071784, orig_eax = -253, eip = -1072671729, xcs =
16, eflags = 582, esp = -1070039072, xss = -1072671582}) at irq.c:639
#5 0xc010c0e8 in call_do_IRQ ()
查看jiffies變量的值
(gdb) p jiffies
$1 = 76153
如果想讓target上的內(nèi)核繼續(xù)運(yùn)行,執(zhí)行continue命令
(gdb) continue
Continuing.
3.3.2 內(nèi)核在引導(dǎo)時(shí)調(diào)試
kgdb可以在內(nèi)核引導(dǎo)時(shí)就對(duì)其進(jìn)行調(diào)試,但并不是所有引導(dǎo)過(guò)程都是可調(diào)試的,如在kgdb 1.9版中,它在init/main.c的start_kernel()函數(shù)中插入以下代碼:
start_kernel()
{
......
smp_init();
#ifdef CONFIG_KGDB
if (gdb_enter) {
gdb_hook(); /* right at boot time */
}
#endif
......
}
所以在smp_init()之前的初始化引導(dǎo)過(guò)程是不能調(diào)試的。
{{分頁(yè)}}
另外要想讓target的內(nèi)核在引導(dǎo)時(shí)就處于調(diào)試狀態(tài),需要修改其/etc/grub.conf文件為如下形式:
title Red Hat Linux (2.4.23-kgdb)
root (hd0,0)
kernel /boot/vmlinuz-2.4.23-kgdb ro root=/dev/hda1 gdb gdbttyS=1 gdbbaud=115200
*在target機(jī)器上
引導(dǎo)2.4.23-kgdb內(nèi)核,內(nèi)核將在短暫的運(yùn)行后暫停并進(jìn)入調(diào)試狀態(tài),打印如下信息:
Waiting for connection from remote gdb...
*在developer機(jī)器上
#cd /home/liangjian/linux-2.4.23
# gdb vmlinux
GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
執(zhí)行rmt宏
(gdb) rmt
breakpoint () at kgdbstub.c:1005
1005 atomic_set(&kgdb_setting_breakpoint, 0);
查看當(dāng)前堆棧
(gdb) bt
#0 breakpoint () at kgdbstub.c:1005
#1 0xc0387fe0 in init_task_union ()
#2 0xc01bc984 in gdb_hook () at gdbserial.c:250
#3 0xc0388898 in start_kernel () at init/main.c:443
在do_basic_setup函數(shù)處設(shè)置斷點(diǎn),并讓內(nèi)核恢復(fù)運(yùn)行
(gdb) b do_basic_setup
Breakpoint 1 at 0xc0388913: file current.h, line 9.
(gdb) continue
Continuing.
[New Thread 1]
[Switching to Thread 1]
Breakpoint 1, do_basic_setup () at current.h:9
9 __asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL));
內(nèi)核在do_basic_setup斷點(diǎn)處停止運(yùn)行后查看當(dāng)前堆棧
(gdb) bt
#0 do_basic_setup () at current.h:9
(gdb)
3.3.3 內(nèi)核模塊調(diào)試調(diào)試
要想調(diào)試內(nèi)核模塊,需要相應(yīng)的gdb支持,kgdb的主頁(yè)上提供了一個(gè)工具gdbmod,它修正了gdb 6.0在解析模塊地址時(shí)的錯(cuò)誤,可以用來(lái)正確的調(diào)試內(nèi)核模塊
*在developer機(jī)器上
寫了個(gè)測(cè)試用的內(nèi)核模塊orig,如下:
void xcspy_func()
{
printk("<1>xcspy_funcn");
printk("<1>aaaaaaaaaaan");
}
int xcspy_init()
{
printk("<1>xcspy_init_modulen");
return 0;
}
void xcspy_exit()
{
printk("<1>xcspy_cleanup_modulen");
}
module_init(xcspy_init);
module_exit(xcspy_exit);
{{分頁(yè)}}
編譯該模塊:
#cd /home/liangjian/lkm
#gcc -D__KERNEL__ -DMODULE -I/home/liangjian/linux-2.4.23/include -O -Wall -g -c -o orig.o orig.c
#scp orig.o root@192.168.16.30:/root
開(kāi)始調(diào)試:
# gdbmod vmlinux
GNU gdb 6.0
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...
設(shè)置符號(hào)文件的搜索路徑
(gdb) set solib-search-path /home/liangjian/lkm
執(zhí)行rmt宏
(gdb) rmt
breakpoint () at kgdbstub.c:1005
1005 atomic_set(&kgdb_setting_breakpoint, 0);
設(shè)置斷點(diǎn)使得可以調(diào)試內(nèi)核模塊的init函數(shù),查內(nèi)核源碼可知,內(nèi)核是通過(guò)module.c文件的第566行(sys_init_module函數(shù)中)mod->init來(lái)調(diào)用模塊的init函數(shù)的
(gdb) b module.c:566
Breakpoint 1 at 0xc011cd83: file module.c, line 566.
(gdb) c
Continuing.
[New Thread 1352]
[Switching to Thread 1352]
這時(shí)在target機(jī)器上執(zhí)行insmod orig.o,developer則相應(yīng)的在斷點(diǎn)處被暫停,如下
Breakpoint 1, sys_init_module (name_user=0xc03401bc "