利用虚拟机调试内核模块
本文描述了在虚拟机中,利用KGDB双机联调NBD驱动的准备过程以及使用频率较高的调试命令。以此为例,介绍调试Linux内核以及内核模块的一种较常用的方法。
在进行内核调试时,系统已经不会响应用户态程序,所以需要使用两台计算机利用串行端口或网络进行双机联调,本文介绍的是利用串行端口进行联调。
下面详细介绍调试的准备工作和调试过程:
1 准备工作
- 新建虚拟机,并安装linux系统。本教程使用的是SUSE Linux Enterprise 11。
- 从kernel.org取得最新内核,截止到2011-02-11,最新的内核版本号是2.6.37。
下面列出的,是编译nbd-server程序时必须的库文件包。如果要调试其他驱动,则根据需要酌情下载和安装:
- gettext,本文使用的版本是0.18.1.1。
- libxml,本文使用的版本是2.7.8。
- zlib,本文使用的版本是1.2.5。
- Glib,本文使用的版本是2.26.1。
- NBD,本文使用的版本是2.9.20。
2 开启linux的内核调试功能
2.1 更新内核,打开KGDB
将得到的linux源代码解压缩到linux的/usr/src路径下,并在同目录下建立连接linux,连接到代码路径下:
localhost:/usr/src # ln -s linux-2.6.37 linux
将/boot下的config文件拷贝到/usr/src/linux下,并改名为.config。 在linux源码路径下面运行make menuconfig命令,开始配置内核编译选项:
localhost:/usr/src/linux # make menuconfig
在弹出的配置换面中,确保以下编译选项是开启的:
CONFIG_FRAME_POINTER=y CONFIG_KGDB=y CONFIG_KGDB_SERIAL_CONSOLE=y
编译并更新内核:
localhost:/usr/src/linux # make && make modules_install && make install
内核编译并更新完成后,即可重新启动计算机,并在启动菜单中选择从新的内核启动。
4 配置串口
在hypervisor manager里配置两台虚拟机的串口。
5 安装必要的库
按照这个顺序安装必要的库文件: gettextl -> libxml-> zlib -> glib 注:以上是编译nbd-server程序时必须的库文件包。如果要调试其他驱动,则根据需要酌情安装。
6 开启内核调试
6.1 开启服务端(调试目标)
利用串口发送和接受串口消息:
localhost:/ # echo ttyS0 > /sys/module/kgdboc/parameters/kgdboc
引发内核调试断点:
localhost:/ # echo g > /proc/sysrq-trigger
在服务端运行上面两个命令,就使系统进入调试状态。此时服务端已经停止用户态响应。
6.2 开启客户端(调试机)
在命令行中,将当前目录设置到linux的源码目录下:
localhost:/ # cd usr/src/linux
启动gdb调试程序:
localhost:/usr/src/linux # gdb ./vmlinux
等待gdb启动完成后,设置gdb连接服务端:
(gdb) set remotebaud 115200 (gdb) target remote /dev/ttyS0
等待gdb输出以下消息,说明调试环境建立成功:
kgdb_breakpoint () at kernel/debug/debug_core.c:960 960 wmb();
7 开始调试
7.1 加载NBD的符号文件
恢复运行服务端:
(gdb) c
在服务端上取得NBD模块的加载地址:
localhost:/ # cat /proc/modules
此时服务端会输入类似如下的信息:
nbd 12427 1 - Live 0xd8831000 xt_tcpudp 2632 3 - Live 0xd8b50000 xt_pkttype 796 3 - Live 0xd8b17000
由上得出nbd的加载地址是0xd8831000。 继续引发服务端的内核调试断点:
localhost:/ # echo g > /proc/sysrq-trigger
在客户端上加载nbd的符号文件:
(gdb) add-symbol-file drivers/block/nbd.ko >0xd8831000
gdb输出如下信息,选择y,并回车:
add symbol table from file "drivers/block/nbd.ko" at .text_addr = 0xd8831000 (y or n) y
接下来就可以使用标准的gdb命令来远程调试了。