http://www.devfront.com/?q=node/302

一种方便的Linux内核调试方法:VirtualBox + KGDB

基本想法是:配置GUEST OS的串口,使它定向到HOST OS的unix socket文件。然后使用socat把这个unix socket文件定向到UDP某个端口监听。gdb连接这个UDP端口,从而实现对guest OS kernel的调试。

说起来满复杂,做起来并不难。我的HOST OS是Ubuntu 7.04,gcc 3.4,binutils 2.17,基本步骤如下:

1. VirtualBox的准备工作

安装VirtualBox,安装GUEST OS,然后配置串口。假设GUEST OS是CentOS 5.0,名称是CentOS50_00,把它的/dev/ttyS0定向到host OS的/tmp/vboxpipe-CentOS50_00,只要在HOST OS运行如下命令就可以:

VBoxManage setextradata "CentOS50_00" "VBoxInternal/Devices/serial/0/Config/IRQ" 4
VBoxManage setextradata "CentOS50_00" "VBoxInternal/Devices/serial/0/Config/IOBase" 0x3f8
VBoxManage setextradata "CentOS50_00" "VBoxInternal/Devices/serial/0/LUN#0/Driver" Char
VBoxManage setextradata "CentOS50_00" "VBoxInternal/Devices/serial/0/LUN#0/AttachedDriver/Driver" NamedPipe
VBoxManage setextradata "CentOS50_00" "VBoxInternal/Devices/serial/0/LUN#0/AttachedDriver/Config/Location" "/tmp/vboxpipe-CentOS50_00"
VBoxManage setextradata "CentOS50_00" "VBoxInternal/Devices/serial/0/LUN#0/AttachedDriver/Config/IsServer"    1

2. 编译内核

http://www.kernel.org 上下载内核linux-2.6.15.5.tar.gz,从http://kgdb.linsyssoft.com/下载linux-2.6.15.5- kgdb-2.4.tar.bz2。把linux-2.6.15.5.tar.gz解压到/usr/src,解压后的目录应该是linux- 2.6.15.5,切换到这个目录,把linux-2.6.15.5-kgdb-2.4.tar.bz2解压到这个目录。结果如下:

[EMAIL PROTECTED]:/usr/src/linux-2.6.15.5# pwd
/usr/src/linux-2.6.15.5
[EMAIL PROTECTED]:/usr/src/linux-2.6.15.5# ls
arch     Documentation  ipc         linux-2.6.15.5-kgdb-2.4          Module.symvers  security
block    drivers        Kbuild      linux-2.6.15.5-kgdb-2.4.tar.bz2  net             sound
COPYING  fs             kernel      MAINTAINERS                      README          System.map
CREDITS  include        kgdbfs.txt  Makefile                         REPORTING-BUGS  usr
crypto   init           lib         mm                               scripts         vmlinux

2.1 给内核打补丁

阅读linux-2.6.15.5-kgdb-2.4目录下面的README,按照所说的文件列表的顺序给内核打补丁。我把需要的补丁文件存为 kgdbfs.txt(见上面的ls列表显示),内容如下:

[EMAIL PROTECTED]:/usr/src/linux-2.6.15.5# cat kgdbfs.txt 
core-lite.patch
core.patch
i386-lite.patch
i386.patch
8250.patch
eth.patch
cfi_annotations.patch
sysrq_bugfix.patch
module.patch
netpoll_pass_skb_to_rx_hook.patch

然后执行如下命令就可以打上补丁:

[EMAIL PROTECTED]:/usr/src/linux-2.6.15.5# for pp in $(cat kgdbfs.txt);do patch -p 1 < linux-2.6.15.5-kgdb-2.4/$pp;done

会有提示说文件不匹配,不过那是非x86平台用的,我们直接跳过去。

2.2 配置并编译内核

执行 make menuconfig 配置内核,注意在Kernel hacking选项把 KGDB 相关项勾上。我把串口芯片8250的驱动、ext2/ext3文件系统编译进了内核,这样省得加载驱动模块。

接下来是编译内核,make一下就可以。编译的结果会在arch/i386/boot/生成bzImage文件,把该文件拷贝到GUEST OS的/boot目录。

2.3 安装新内核模块

模块安装有一个小技巧,因为你并不想把模块安装到HOST OS吧。可指定模块安装的目标,比如

[EMAIL PROTECTED]:/usr/src/linux-2.6.15.5# make modules_install INSTALL_MOD_PATH=/tmp

然后把/tmp/lib目录下的内核模块目录拷贝到GUEST OS的/lib/modules下面。

2.4 准备init ramdisk

本来你还需要制作init ramdisk,以创建控制台设备,进行内核启动前的用户空间初始化。如果需要那么做,可以从usr目录(相对于内核编译目录)寻求帮助。我是直接用 GUEST OS原内核的init ramdisk。

2.5 修改GUEST OS的启动配置文件

修改GUEST OS的/boot/grub/menu.lst文件,新加上

title Kernel Debug (2.6.15.5-kgdb)
        root (hd0,0)
        kernel /boot/vmlinuz-2.6.15.5-kgdb ro root=/dev/hda1 kgdbwait
        initrd /boot/initrd-2.6.18-8.el5.img

3. 调试内核

确保GUEST OS存在新编译的内核,内核相关的模块,grub.conf已设置妥当。重启GUEST OS,选择启动新内核,如没问题就可看到如下提示:

Uncompressing Linux... Ok, booting the kernel.

这时候在HOST OS开启一个终端窗口,重定向GUEST OS的串口:

[EMAIL PROTECTED]:/tmp# socat udp4-listen:6443 /tmp/vboxpipe-CentOS50_00

再开启另一个终端窗口,调试内核:

[EMAIL PROTECTED]:/usr/src/linux-2.6.15.5# gdb ./vmlinux 
GNU gdb 6.6-debian
Copyright (C) 2006 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 "i486-linux-gnu"...
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
(gdb) target remote udp:localhost:6443
warning: The remote protocol may be unreliable over UDP.
Some events may be lost, rendering further debugging impossible.
Remote debugging using udp:localhost:6443
warning: shared library handler failed to enable breakpoint
breakpoint () at kernel/kgdb.c:1876
1876            atomic_set(&kgdb_setting_breakpoint, 0);
(gdb) l
1871
1872            atomic_set(&kgdb_setting_breakpoint, 1);
1873            wmb();
1874            BREAKPOINT();
1875            wmb();
1876            atomic_set(&kgdb_setting_breakpoint, 0);
1877    }
1878
1879    EXPORT_SYMBOL(breakpoint);
1880
(gdb)

输入gdb命令 c 就会完成内核的启动过程,Ctrl-C中断内核,回到gdb控制。

如果我的文章有疏漏,建议参考 KGDB快速开始 (http://kgdb.linsyssoft.com/downloads/kgdb-2/kgdbquickstart-2.4.pdf)。

相关连接:

KGDB官方网站 http://kgdb.linsyssoft.com/
VirtualBox官方网站 http://www.virtualbox.org/

Comments

cpio ramdisk的制作办法

参考如下命令

1. 解压ramdisk

[EMAIL PROTECTED]:/tmp# mkdir initfs
[EMAIL PROTECTED]:/tmp# cd initfs
[EMAIL PROTECTED]:/tmp/initfs# scp itvb00:/boot/initrd-2.6.18-8.el5.img ./
[EMAIL PROTECTED]'s password:
initrd-2.6.18-8.el5.img 100% 1365KB 1.3MB/s 00:00
[EMAIL PROTECTED]:/tmp/initfs# ls
initrd-2.6.18-8.el5.img
[EMAIL PROTECTED]:/tmp/initfs# mv initrd-2.6.18-8.el5.img initrd.gz
[EMAIL PROTECTED]:/tmp/initfs# gzip -d initrd.gz
[EMAIL PROTECTED]:/tmp/initfs# ls
initrd
[EMAIL PROTECTED]:/tmp/initfs# cpio -idv < initrd
...
[EMAIL PROTECTED]:/tmp/initfs# ls
bin dev etc init initrd lib proc sbin sys sysroot

主机itvb00是我的GUEST OS。这时候就可以根据需要修改ramdisk了。

2. 生成ramdisk

[EMAIL PROTECTED]:/tmp/initfs# rm initrd
[EMAIL PROTECTED]:/tmp/initfs# find . -print | cpio -ov > /tmp/initrd-new.cpio
[EMAIL PROTECTED]:/tmp/initfs# gzip /tmp/initrd-new.cpio

内核编译技巧

安装编译工具

# yum groupinstall 'Development Tools'
# yum install qt-devel

或者

# aptitude install build-essential libqt3-mt-dev qt3-dev-tools

查看硬件信息:lshw,lspci,注意使用update-pciids先更新一下。查看cpu信息 cat /proc/cpuinfo。
制作initrd文件系统:在编译目录运行 # mkinitrd -o /boot/initrd-2.6.22.img
使用 blkid 识别磁盘UUID。

参考
http://www.enterprisenetworkingplanet.com/netos/article.php/10951_3690371_1
http://www.bitbenderforums.com/vb22/showthread.php?t=58650




Reply via email to