KGDB && Build Ubuntu kernel

关于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

如下,记得要勾上Yield CPU on poll。

如果调试机也是虚拟机,类似添加串口设备,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