现在的位置: 首页 > 综合 > 正文

内核的动态调试

2013年10月03日 ⁄ 综合 ⁄ 共 7122字 ⁄ 字号 评论关闭

一。使用kdb调试内核

二。使用kgdb调试内核

三。使用uml调试内核

四。参考资料

一。使用kdb调试内核

kdb全称为Built-in Kernel Debugger,kdb的主要特点是调试器本身是内核的一部分,不需要另外的调试工具如gdb,就可以跟踪和调试内核。

kdb作为sgi的一个open source项目,大家可以访问http://oss.sgi.com/projects/kdb/了解更多信息。

1。kdb的获取

kdb可以从ftp://oss.sgi.com/www/projects/kdb/download/获得。一般kdb由两部分构成:平台相关部分和通用部分。kdb的命名规则是:kdb+版本号+内核版本号+支持平台或通用部分+更新子版本,bz2,选择kdb时需要考虑针对的内核版本、kdb版本和支持的平台,更新子版本一般越高越好。

以针对Linux内核版本2.6.22为例,目前我们需要下载的文件就是kdb-v4.4-2.6.22-i386-2.bz2和kdb-v4.4-2.6.22-common-4.bz2 。

2。kdb的安装

首先选择对应的内核版本,比如linux-2.6.22.tar.gz

tar vzxf linux-2.6.22.tar.gz

bunzip2 kdb-v4.4-2.6.22-i386-2.bz2

bunzip2 kdb-v4.4-2.6.22-common-4.bz2

然后为内核打补丁

cd linux-2.6.22

patch -p1 < ../kdb-v4.4-2.6.22-i386-2

patch -p1 < ../kdb-v4.4-2.6.22-common-4

接下来就是配置内核,主要是设置CONFIG_KDB,如下图所示:

保存配置文件后,就可以编译内核了。

make;make modules_install;make install

然后重启系统,选择刚编译的内核重新进入系统。 如果象下图一样在启动时看到kdb_cmd信息,就可以确认运行的内核是包含了kdb调试器的了。

3。kdb的使用

3.1激活kdb

可以通过cat /proc/sys/kernel/kdb查看kdb是否已经激活,通过echo 0 > /proc/sys/kernel/kdb关闭kdb。

3.2唤出kdb和返回操作系统

通过连按两下Break键唤出kdb命令调试模式,通过命令go回到操作系统。

3.3kdb命令介绍

3.4kdb使用实例

3.4.1查询函数或变量内存地址

查询函数netif_receive_skb的线性地址:

kdb> mds netif_receive_skb

0xc02db540 0001bd55

获得函数netif_receive_skb的线性地址为:0xc02db540

查询变量dev_base_head的线性地址:

kdb> mds dev_base_head

0xc0424a2c c7e6e830

获得变量dev_base_head的线性地址为:0xc0424a2c

3.4.2查询指定内存地址内容

kdb> md 0xc0424a2c

0xc0424a2c c7e6e830

3.4.3设置、清除、禁止和启用断点

设置断点

kdb> bp netif_receive_skb

清除断点

kdb> bc 0

禁止断点

kdb> bd 0

启用断点

kdb> be 0

3.4.4调用跟踪

kdb> bt

3.4.5修改内存数据

kdb> mm cf26ac0c 0x50

0xcf26ac0c 0x50

4。kdb的局限

kdb类似Windows平台上的softice,功能强大,但是基本是汇编级调试,对于一般使用者掌握比较困难,灵活性也比较欠缺。

二。使用kgdb调试内核

kgdb能很方便的在源码级对内核进行调试,使用的语法就是gdb的命令。缺点是kgdb只能进行远程调试,一般它需要一根串口线及两台机器来调试内核,这类似于微软的WinDbg,但目前也可以通过在同一台主机上用vmware软件运行两个操作系统的方式来进行调试。kgdb实质上是通过和gdb进行通讯来完成调试和跟踪的。

kgdb原本也是sgi的open source项目,原先的站点是在http://oss.sgi.com/projects/kgdb/,现在似乎已经独立出去,大家可以访问http://kgdb.linsyssoft.com/了解更多信息。

1。kgdb的获取

kgdb的free版本更新目前看似乎有点滞后(可能主要都发展收费的kgdb pro去了),现在支持Linux 2.6最后版本是2.6.15.5,可以从http://kgdb.linsyssoft.com/downloads/kgdb-2/linux-2.6.15.5-kgdb-2.4.tar.bz2下载获得。

2。kgdb的安装和准备

首先选择对应的内核版本,这里是2.6.15.5。

tar vzxf linux-2.6.15.5.tar.gz

tar vjxf linux-2.6.15.5-kgdb-2.4.tar.bz2

根据linux-2.6.15.5-kgdb-2.4里面README的描述,给内核打上如下补丁:

patch -p1 < ../linux-2.6.15.5-kgdb-2.4/core-lite.patch

patch -p1 < ../linux-2.6.15.5-kgdb-2.4/i386-lite.patch

patch -p1 < ../linux-2.6.15.5-kgdb-2.4/8250.patch

patch -p1 < ../linux-2.6.15.5-kgdb-2.4/eth.patch

patch -p1 < ../linux-2.6.15.5-kgdb-2.4/i386.patch

patch -p1 < ../linux-2.6.15.5-kgdb-2.4/core.patch

然后是配置内核,主要是选择CONFIG_KGDB、CONFIG_KGDB_CONSOLE和CONFIG_KGDB_8250,如下图所示:

这里要注意的是,kgdb可以通过串口和调试系统的gdb通讯,也可以通过以太网发送UDP包和调试系统的gdb通讯。

另外,和kgdb通讯的gdb也必须使用特殊修改过的gdb,在这里使用的是gdbmod-2.4,下载地址为http://kgdb.linsyssoft.com/downloads/gdbmod-2.4.bz2。

3。kgdb的使用

3.1使用步骤

被调试机以kgdb内核启动,内核启动参数要加上kgdbwait,这样被调试机会在启动开始停止,等待调试机和其通讯。

调试机以正常内核启动,使用gdbmod加载被调试机的内核,注意调试机应该是编译kgdb内核的开发机,在内核编译目录下运行

../gdbmod vmlinux

(gdb) tagert remort /dev/ttyS0

这样调试机器就开始和被调试机通讯了。在通讯顺利联系上时,调试机的gdb会打印信息:

breakpoint () at kernel/kgdb.c:1876

1876 atomic_set(&kgdb_setting_breakpoint, 0);

这样就可以开始正常的调试了,调试语法和gdb完全相同,若需要继续运行,可以如下操作:

(gdb) c

Continuing.

3.2 使用VMWare建立kgdb调试环境

其它的步骤和上面相同,只是设置VMWare虚拟机时需要注意以下事项。

3.2.1调试机端

设置服务器串口命名管道,如下图所示:

3.2.2被调试机端

设置客户端串口命名管道,如下图所示:

若需要验证串口是否联通,可以在被调试机端

cat /dev/ttyS0

在调试机端

echo test > /dev/ttyS0

如果被调试机端打印出了test ,则说明串口已经联通了。

3.3用kgdb进行调试

kgdb的调试语法和gdb完全相同,在这里就不举例子了。

4。kgdb的特点

kgdb的优点是调试语法和gdb完全相同,调试起来灵活简便,使用范围广泛,可以调试内核、模块以及设备驱动。问题是需要两个操作系统,需要配置串口或网络,操作起来相对比较麻烦。

三。使用uml调试内核

uml现在已经是Linux 2.6系列中内核发布的一部分,大家可以访问http://user-mode-linux.sourceforge.net/获得更多信息,另外还可以参考Documentation/uml/UserModeLinux-HOWTO.txt,不过此文件看起来已经太旧过时了。

uml是以虚拟机的方式运行的应用层程序,而且一般需要在X-Window环境中运行。由于是应用层程序,就可以很方便地使用gdb来进行调试和跟踪,不像kgdb需要两个操作系统才可以进行调试内核。

1。uml环境的获得

uml的获得比较简单,因为已经被包含到Linux 2.6版本中了,只需要按照如下操作,就可以获得支持uml的内核:

首先在解开的linux-2.6.22目录下配置编译参数,主要是需要选择虚拟块设备、字符设备以及虚拟网络和调试信息的配置。

make menuconfig ARCH=um

如下图所示:

选择虚拟块设备

选择字符设备

选择虚拟网络设备

然后是在kernel hacking中选择调试信息

最后编译系统

make ARCH=um

得到的最终文件是根目录下的文件linux。

完成uml环境还需要安装一些工具,主要是uml_utilities,如uml_switch、uml_mconsole等工具。具体可以从http://user-mode-linux.sourceforge.net/old/dl-sf.html获得。

2。uml的使用

uml的使用和上面两种调试方法不同,由于uml是使用虚拟机的方式运行的应用层程序,所以不但需要有自己的文件系统,另外还需要一些工具软件支持和宿主机的网络通讯。

2.1uml的文件系统

uml的文件系统可以从网络获得,也可以自己制作。参看http://user-mode-linux.sourceforge.net/old/dl-sf.html,可以获得一些文件系统,这里简单介绍自己制作文件系统。

首先制作空的文件系统并格式化,例如要制作一个128M的文件系统。

dd if=/dev/zero of=root_fs count=256k

mkfs.ext3 root_fs

然后将文件系统挂接到本地。

mkdir loop

mount root_fs loop -o loop

最后有选择地将最小化的文件拷贝到挂接目录下,例如一个busybox系统目录,然后umount脱离挂接目录,这样就可以获得一个自己的最小化文件系统了,如果还需要其它文件,可以按照同样形式拷贝到root_fs中。

2.2启动uml虚拟机

启动uml非常简单,如果文件系统命名为root_fs且和运行目录在同一目录下,只要直接运行./linux就可以了。如果文件系统不叫root_fs或不在运行目录下,可以如下运行uml。

./linux ubd0=/path/fsname

当然,还可以挂接多个文件系统,如

./linux ubd0=file1 ubd1=file2

下面是uml运行的图例:

2.3和宿主机进行网络通讯

uml虚拟机可以和宿主机以及网络上的其它主机通讯,但需要宿主机支持uml选用的网络方式,并使用uml_utilities中的uml_switch设置arp_proxy,当然这些都是由程序设定,不需要完全手工执行的,在这里只介绍tuntap方式的网络通讯,其余可以参考http://user-mode-linux.sourceforge.net/old/networking.html。

2.3.1确认宿主机支持tuntap

即确认宿主机支持Universal TUN/TAP device driver support 网络驱动。

2.3.2运行uml_switch

编译安装uml_utilities,运行uml_switch

2.3.3按照以下命令运行uml

./linux ubd0=/path/fsname eth0=tuntap,,,172.31.111.111 eth1=daemon

再这里eth0是可以和宿主机通讯的虚拟网卡,eth1是可以和宿主机上其它uml虚拟机通讯的虚拟网卡。网络地址172.31.111.111是给宿主机的tap0设备设置的ip,然后在uml虚拟机里面设置ip

ifconfig eth0 172.31.1.11

这样就可以和宿主机网络上的其它主机通讯了。

2.4使用uml进行调试

现在终于进入到正题了,利用uml进行内核调试。Linux 2.6中的uml调试和2.4以前的有一些不同,linux命令行中的debug命令已经无效,可以参考http://user-mode-linux.sourceforge.net/hacking.html。下面介绍主要步骤。

首先按照上面介绍的顺序运行uml。

接着获取uml进程的pid,可以有两个方法获得:运行ps查看最小的linux pid;或则ls /用户目录/.uml -al,查看最近生成目录里的pid文件内容。这两个方法可以相互验证。

例如,本实例中使用方法一,获得的最小pid是17460:

[root@FG4DEV linux-2.6.22]# ps ax|grep ./linux-2.6.22/linux

1242 pts/13 S+ 0:00 grep ./linux-2.6.22/linux

17460 pts/16 S+ 0:00 ./linux-2.6.22/linux eth0=tuntap,,,172.31.111.111 eth1-daemon

17465 pts/16 S+ 0:00 ./linux-2.6.22/linux eth0=tuntap,,,172.31.111.111 eth1-daemon

17466 pts/16 S+ 0:00 ./linux-2.6.22/linux eth0=tuntap,,,172.31.111.111 eth1-daemon

17467 pts/16 S+ 0:00 ./linux-2.6.22/linux eth0=tuntap,,,172.31.111.111 eth1-daemon

17473 pts/18 Ss+ 0:00 ./linux-2.6.22/linux eth0=tuntap,,,172.31.111.111 eth1-daemon

17505 pts/21 Ss+ 0:00 ./linux-2.6.22/linux eth0=tuntap,,,172.31.111.111 eth1-daemon

17509 pts/22 Ss+ 0:00 ./linux-2.6.22/linux eth0=tuntap,,,172.31.111.111 eth1-daemon

使用方法二,获得的pid也是17460

[root@FG4DEV linux-2.6.22]# ls /root/.uml/ -al

drwxr-xr-x 7 root root 4096 08-08 10:30 .

drwxr-x--- 27 root root 4096 08-08 10:14 ..

drwxr-xr-x 2 root root 4096 08-08 09:29 3dRcIw

drwxr-xr-x 2 root root 4096 08-08 09:26 6GT1oZ

drwxr-xr-x 2 root root 4096 08-07 15:33 lk9LuY

drwxr-xr-x 2 root root 4096 08-08 09:03 oQCINR

drwxr-xr-x 2 root root 4096 08-08 10:30 yMk81E

[root@FG4DEV linux-2.6.22]# cat /root/.uml/yMk81E/pid 17460

所以可以判定,此时uml的初始进程号就是17460。

到这个时候,就在uml编译目录下运行gdb程序了。

gdb linux 17460

这样gdb已经和uml的内核attach了,可以设置断点进行调试了。

例如此时设置了两个断点

(gdb) b netif_receive_skb

Breakpoint 1 at 0x81d13c9: file net/core/dev.c, line 1835.

(gdb) b dev_queue_xmit

Breakpoint 2 at 0x81d0e29: file net/core/dev.c, line 1482.

(gdb) c

Continuing.

然后我们在uml里ping外面主机,gdb立刻将系统断住,接下来就可以用gdb的语法进行调试了,例如bt

2.5在uml启动时debug内核

可以如下操作,在uml编译目录下,

gdb linux

(gdb) set args "ubd0=/path/fsname eth0=tuntap,,,172.31.111.111 eth1=daemon"

(gdb) b start_kernel

(gdb) r

这样在系统运行到start_kernel时就可以被断住。

3。uml的局限

uml对于非设备相关的内核部分调试是一个很好的选择,调试语法也完全是gdb的命令,但由于是虚拟机形式运行的应用层程序,所以对涉及真实设备以及平台相关部分的调试是无能为力的,同时uml还需要宿主机必须安装上XWindow系统。

四。参考资料

http://oss.sgi.com/projects/kdb/

http://kgdb.linsyssoft.com/

http://user-mode-linux.sourceforge.net/

http://mail.xfocus.net/articles/200509/820.html

http://www.gentoo.org/doc/zh_tw/uml.xml

 

抱歉!评论已关闭.