关于KGDB:GDB是GUN的调试器,用来调试普通程序。KGDB是用来调试操作系统内核的。当我还在念小学的时候,Linus严辞拒绝KGDB进入主线内核的,理由是:真正懂内核的人不需要工具来调试,人脑就能调代码[1]。可是到了2.6.26时代,却已经欣然接受KGDB,很想知道是谁说服了那个顽固的天才。
下面开始在Ubuntu 10.04下快乐的使用KGDB。
为什么是Ubuntu 10.04?我用过的发行版不多,也就Ubuntu、Archlinux、Redhat、Centos、Fedora、LFS。Ubuntu并不是最好用的,很多地方都不符合我的习惯,但是,因为手边正好有一张Ubuntu的推广光盘,这张质量上乘的推广光盘使我把附近能用的机器都装上了Ubuntu。光盘安装的便利性是各种硬盘安装、网络安装、U盘安装等繁琐手段无法比拟的。于是乎,我被Ubuntu俘虏了。
真要我说Ubuntu最吸引我的地方,大概就是它那个默认的红色配色了,看着很舒服。字体也刚刚好。
Ubuntu 不太适合搞KGDB,因为在Ubuntu上换内核特别麻烦。注意,是特别麻烦。
10.04的内核默认已经打开了KGDB选项,但是因为发行版不提供原始的vmlinux文件,因此需要重做一个(反正已经重编了内核,顺手就换下内核,好处是可以完美match 符号表,自己动手编的vmlinux文件和官方的核不能100%契合)。
官方的wiki上提供了两种编译内核的方式,一种是编Ubuntu kernel,一种是编主线kernel。
图省事我编的是Ubuntu kernel。
首先拿到内核源码,推荐使用git方式。
Git路径如下:
quantal |
git://kernel.ubuntu.com/ubuntu/ubuntu-quantal.git |
precise |
git://kernel.ubuntu.com/ubuntu/ubuntu-precise.git |
oneiric |
git://kernel.ubuntu.com/ubuntu/ubuntu-oneiric.git |
natty |
git://kernel.ubuntu.com/ubuntu/ubuntu-natty.git |
lucid |
git://kernel.ubuntu.com/ubuntu/ubuntu-lucid.git |
hardy |
git://kernel.ubuntu.com/ubuntu/ubuntu-hardy.git |
10.04 是lucid,所以执行
$git clone git://kernel.ubuntu.com/ubuntu/ubuntu-lucid.git
然后切换至对应的tag上。查看版本
$uname -a
Linux hacklu-desktop 2.6.32-21-generic #32-Ubuntu SMP
所以对应的tag是Ubuntu-2.6.32-21.32。
$git checkout -b my_kernel Ubuntu-2.6.32-21.32
编译选项最好在发行版的基础上修改
$cp /boot/config-2.6.32-21-generic .config
$make oldconfig
在这基础上修改自定义的配置(调试内核,需要把CONFIG_DEBUG_RODATA关闭,代码段的只读属性不去掉,KGDB无法下断点。因为断点是通过把欲断处指令改成INT3来实现)
$make menuconfig
$make-kpkg clean # only needed if you want to do a "clean" build
$cp Ubuntu-kernel-src/debian/control-scripts/{postinst,postrm,preinst,prerm} ~/kernel-package/pkg/image/
$ cp Ubuntu-kernel-src /debian/control-scripts/headers-postinst ~/kernel-package/pkg/headers/
$CONCURRENCY_LEVEL=2 fakeroot make-kpkg --initrd --append-to-version=-hacklu.v1 --overlay-dir=~/kernel-package/ kernel_image kernel_headers
解释下, CONCURRENCY_LEVEL=2 相当于平时的make -j2 编译速度加快。
fakeroot 是make-kpkg以为你是root
--append-to-version=-hacklu.v1 后面的字符串会自动加在编译好的内核版本后面
--overlay-dir=~/kernel-package/ make-kpkg 命令需要这个选项指定定制脚本路径,如果没有这一项,编译出来的内核缺少initramfs。
Kernel_image 表示编译image.deb
Kernel_header表示编译header.deb
命令执行完毕会在当前目录的上一级生成两个deb包,分别安装即可
$sudo dpkg -i *.deb
Image.deb会根据控制脚本自动生成initramfs,并更新grub,重启即可切换至新编出的内核。
此刻KGDB 和vmlinux都已经准备好了。如果有串口线则可调试实体机器,不然就放在vmware中调试。
Vmware中安装好一台ubuntu10.04的系统做被调试机,然后add device—》serial port—》named pipe
如果调试机也是虚拟机,类似添加串口设备,server和client互换。
如果调试机是局域网内一台物理机器,则可以利用命名管道转网络工具[2]把虚拟机中的被调试机器的串口转发到局域网中去。
在被调试机器上执行如下指令
$sudo -s
#echo ttyS0 > /sys/module/kgdboc/parameters/kgdboc #指定通信串口号
#echo g > /proc/sysrq-trigger #挂起被调试机器,产生kgdb_breakpoint中断。此时调试端gdb可以连入
在调试机器上执行如下
$gdb vmlinux
$target remote /dev/ttyS0
之后就可以开心的使用GDB调试内核了。
Ps:最好使用Ubuntu自带的gdb来调试,10.04的内核跟7.2以上的GDB不合拍。
[1] Linus say: Without a debugger, you basically have to go the next step: understand what the program does. Not just that particular line. https://lkml.org/lkml/2000/9/6/65
[2] Named Pipe TCP Proxy Utility http://shvechkov.tripod.com/nptp.html