利用虚拟机调试内核模块

举报
皮皮 发表于 2018/07/16 16:26:15 2018/07/16
【摘要】 利用虚拟机调试内核模块本文描述了在虚拟机中,利用KGDB双机联调NBD驱动的准备过程以及使用频率较高的调试命令。以此为例,介绍调试Linux内核以及内核模块的一种较常用的方法。在进行内核调试时,系统已经不会响应用户态程序,所以需要使用两台计算机利用串行端口或网络进行双机联调,本文介绍的是利用串行端口进行联调。下面详细介绍调试的准备工作和调试过程:1 准备工作新建虚拟机,并安装linux系统。...

利用虚拟机调试内核模块

本文描述了在虚拟机中,利用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=yCONFIG_KGDB=yCONFIG_KGDB_SERIAL_CONSOLE=y123

编译并更新内核:

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(); /* Sync point after breakpoint */

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

7.2 调试NBD模块简单示例

在nbd.c代码的237行下断点:

(gdb) b nbd.c:237

gdb输出如下信息说明断点设置成功:

(gdb) Breakpoint 1 at 0xd88316b1: file drivers/block/nbd.c, line 237

恢复运行服务端:

(gdb)c

在服务端上做一些nbd的操作,系统会在刚才的断点上中断:

Breakpoint 1, nbd_send_req (lo=0xd5634000, req=0xd4ea02d8) 
at drivers/block/nbd.c:237 
237 unsigned long size = blk_rq_bytes(req);

单步执行:(n:单步跳过。s:单步进入)

(gdb) n

gdb输出:

239 request.magic = htonl(NBD_REQUEST_MAGIC);

查看此时237行size变量的值:

(gdb) p size

gdb输出:

$1 = 1024

修改变量size的值:

(gdb) set size=1025

查看此时237行size变量的值:

(gdb) p size

gdb输出:

$1 = 1025

在nbd.c代码的239行下条件断点(条件是237行的size为1024):

(gdb) b nbd.c:239 if size==1024

恢复运行服务端:

(gdb) c

当size的值为1024的时候,系统中断,gdb输出如下信息:

Breakpoint 2, nbd_send_req (lo=0xd5634000, req=0xd4ea02d8) 
at drivers/block/nbd.c:239 
239 request.magic = htonl(NBD_REQUEST_MAGIC);

此时查看size的值,为1024:

(gdb) p size 
$3 = 1024

查看调用堆栈:

(gdb) bt 
#0 nbd_send_req (lo=0xd5634000, req=0xd4ea02d8) at drivers/block/nbd.c:239 
#1 0xd8832210 in nbd_handle_req (lo=0xd5634000, req=0xd4ea02d8) 
at drivers/block/nbd.c:478 
#2 0xd8832452 in nbd_thread (data=0xd5634000) at drivers/block/nbd.c:523 
#3 0xc025b8f4 in kthread (_create=) 
at kernel/kthread.c:95 
#4 0xc0203336 in ?? () at arch/x86/kernel/entry_32.S:1009 
#5 0x00000000 in ?? ()

查看断点附近的代码:

(gdb) l 
234 { 
235 int result, flags; 
236 struct nbd_request request; 
237 unsigned long size = blk_rq_bytes(req); 
238 
239 request.magic = htonl(NBD_REQUEST_MAGIC); 
240 request.type = htonl(nbd_cmd(req)); 
241 request.from = cpu_to_be64((u64)blk_rq_pos(req) << 9); 
242 request.len = htonl(size); 
243 memcpy(request.handle, &req, sizeof(req)); 

8 结束调试

首先删除所有的断点:

(gdb) delete 
Delete all breakpoints? (y or n) y

恢复服务端运行:

(gdb) c 
Continuing.

按下ctrl+c:

Give up (and stop debugging it)? (y or n) y

输入结束命令:

(gdb) quit 
localhost:/usr/src/linux #


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。