Linux Kernel Hacking With KGDB in VMWARE
在VMWARE中使用KGDB进行源码级Linux内核调试
CopyRight By MikeFeng
[环境]
VMWARE 5.5
Windows XP SP2(可替换)
虚拟机Ubuntu 6.06 (被调试机)
虚拟机Kubuntu 6.10 (调试机,可替换为其他linux操作系统)
[工具] KGDB 2.4
[内核] 2.6.15.5 + KGDB 2.6.15.5补丁
[目的] 对Linux 2.6内核进行源码级调试,就像windbg一样。
1.准备工作
使用vmware安装Ubuntu6.06和KUbuntu6.10(可替换为其他linux操作系统)。
在kgdb官方网站下载linux-2.6.15.5.tar.bz2和linux-2.6.15.5-kgdb-2.4.tar.bz2,将这些source移至/usr/src并且解包。因为Ubuntu 6.06的内核是2.6.15的,因此内核编译成功性稍大一点,推荐在Ubuntu 6.06上进行编译。
linux-2.6.15.5-kgdb-2.4.tar.bz2中含有对linux-2.6.15.5的kgdb补丁,推荐按照以下顺序用patch命令打补丁(假设你装的是32位的ubuntu):
cd /usr/src/linux-2.6.15.5
patch –p1 < ../linux-2.6.15.5-kgdb-2.4.tar.bz2/core-lite.patch
patch –p1 < ../linux-2.6.15.5-kgdb-2.4.tar.bz2/core.patch
patch –p1 < ../linux-2.6.15.5-kgdb-2.4.tar.bz2/i386-lite.patch
patch –p1 < ../linux-2.6.15.5-kgdb-2.4.tar.bz2/ i386.patch
patch –p1 < ../linux-2.6.15.5-kgdb-2.4.tar.bz2/ 8250.patch
2.编译内核
Make menuconfig,按照KGDB官方网站上的说明文档配置必要的KGDB选项。注意将默认的串口1改为0。这个在make menuconfig的过程中不能更改,可以通过make oldconfig进行交互式配置更改,也可以在make menuconfig之后编辑kernel source目录下生成的.config文件,确保关于kgdb的配置如下(特别是最后一句)
CONFIG_KGDB_8250_NOMODULE=y
CONFIG_KGDB_8250=y
CONFIG_KGDB_SIMPLE_SERIAL=y
CONFIG_KGDB_BAUDRATE=115200
CONFIG_KGDB_PORT_NUM=0
然后就是编译了。编译能否成功除了看人品之外,还需要注意别用版本太高或者太低的gcc编译器。据说4.1版本的gcc加入了堆栈溢出保护的功能,如果碰到堆栈什么符号未定义之类的错误,那么先确认自己的gcc版本是不是太高了。使用debian特有的命令进行编译配置,大致流程如下。不推荐直接用make,配置起来麻烦。
make-kpkg clean
fakeroot make-kpkg --initrd --append-to-version=-custom kernel_image kernel_headers
在--append-to-version= 后面你可以写上任何字符串来区别内核版本, 但是必须以" - "符号开始而且后面不包括任何空格.
如果在编译过程中出现某些错误,那么请在make menuconfig中不要将相关功能选中,确保通过编译。每次编译都要花较长时间,大概在半小时到一小时左右。其中大部分时间都花在内核模块文件的生成上。
3.安装内核
编译完成之后,可以在/usr/src目录中发现多了两个.deb文件,安装可以用dpkg命令:
dpkg -i linux-image-2.6.15.5-kgdb_10.00.Custom_i386.deb
dpkg -i linux-headers-2.6.15.5-kgdb_10.00.Custom_i386.deb
安装会自动将生成的内核vmlinuz和initrd.img拷贝至/boot/目录中,并且更改grub设置。察看menu.lst(或者grub.conf)文件可以看到在启动项最后添加了两项。将其中一项按照kgdb的官方说明文档更改为如下所示:
title Ubuntu, kernel 2.6.15.5-kgdb
root (hd0,0)
kernel /boot/vmlinuz-2.6.15.5-kgdb root=/dev/sda1 ro kgdbwait kgdb8250=0, 115200
initrd /boot/initrd.img-2.6.15.5-kgdb
savedefault
boot
其中关于root的配置因人而异,可以不是sda1。
4.配置虚拟机
更改两台机器的vmware配置,分别加上一个串口。注意被调试机要选this end is the client, the other end is a virtual machine,而调试机要选this end is the server,the other end is a virtual machine。可以用在被调试机上打命令cat /dev/ttyS0,在调试机上打echo abc > /dev/ttyS0来测试设置是否生效。测试之间别忘了检查下网络是否能相互连通,本地vmware NAT/DHCP之类的服务有没有被禁用。通过测试之后就剩最后一步了。
5.联机调试
启动被调试机,根据提示按esc进行grub选择。选择刚才生成的新内核,等待Ok.booting the kernel的出现。
在调试机上进行如下设置,确保串口通信速率是115200,端口是0
stty ispeed 115200 ospped 115200 < /dev/ttyS0
确保调试机和被调试机的源码和System.map一致,然后将目录切换至源码目录,输入
gdb vmlinuz
(gdb) target remote /dev/ttyS0
等待断点。如果收到的是error,那么就是串口端口相关的配置没有设定好,或者是gdb版本太低。检查make menuconfig中的端口配置,检查grub中的设定,检查stty命令是否正确。如果收到的是类似于breakpoint () at gdbstub.c 1153之类的信息,那么恭喜你,你成功了。