内核模块的调试方法

内核可加载模块的调试具有其特殊性。由于内核模块中各段的地址是在模块加载进内核的时候才最终确定的,所以 develop 机的 gdb 无法得到各种符号地址信息。所以,使用 kgdb 调试模块所需要解决的一个问题是,需要通过某种方法获得可加载模块的最终加载地址信息,并把这些信息加入到 gdb 环境中。
I 、在 Linux 2.4 内核中的内核模块调试方法
Linux2.4.x 内核中,可以使用 insmod -m 命令输出模块的加载信息,例如:
 

[root@lisl tmp]# insmod -m hello.ko >modaddr
 
查看模块加载信息文件 modaddr 如下:
 

.this           00000060 c88d8000 2**2
.text           00000035 c88d8060 2**2
.rodata         00000069 c88d80a0 2**5
……
.data           00000000 c88d833c 2**2
.bss            00000000 c88d833c 2**2
……
 
在这些信息中,我们关心的只有 4 个段的地址 :.text .rodata .data .bss 。在 development 机上将以上地址信息加入到 gdb , 这样就可以进行模块功能的测试了。
 

(gdb) Add-symbol-file hello.o 0xc88d8060 -s .data 0xc88d80a0 -s
.rodata 0xc88d80a0 -s .bss 0x c88d833c
 
这种方法也存在一定的不足,它不能调试模块初始化的代码,因为此时模块初始化代码已经执行过了。而如果不执行模块的加载又无法获得模块插入地址,更不可能在模块初始化之前设置断点了。对于这种调试要求可以采用以下替代方法。
target 机上用上述方法得到模块加载的地址信息,然后再用 rmmod 卸载模块。在 development 机上将得到的模块地址信息导入到 gdb 环境中,在内核代码的调用初始化代码之前设置断点。这样,在 target 机上再次插入模块时,代码将在执行模块初始化之前停下来,这样就可以使用 gdb 命令调试模块初始化代码了。
另外一种调试模块初始化函数的方法是:当插入内核模块时,内核模块机制将调用函数 sys_init_module(kernel/modle.c) 执行对内核模块的初始化,该函数将调用所插入模块的初始化函数。程序代码片断如下:
 

…… ……
   if (mod->init != NULL)
      ret = mod->init();
…… ……
 
在该语句上设置断点,也能在执行模块初始化之前停下来。
II 、在 Linux 2.6.x 内核中的内核模块调试方法
Linux 2.6之后的内核中,由于module-init-tools工具的更改,insmod命令不再支持-m 参数,只有采取其他的方法来获取模块加载到内核的地址。通过分析 ELF 文件格式,我们知道程序中各段的意义如下:
.text (代码段):用来存放可执行文件的操作指令,也就是说是它是可执行程序在内存种的镜像。
.data (数据段):数据段用来存放可执行文件中已初始化全局变量,也就是存放程序静态分配的变量和全局变量
.bss BSS 段): BSS 段包含了程序中未初始化全局变量,在内存中 bss 段全部置零。
.rodata (只读段):该段保存着只读数据,在进程映象中构造不可写的段。
通过在模块初始化函数中放置一下代码,我们可以很容易地获得模块加载到内存中的地址。
 

……
int bss_var;
static int hello_init(void)
{
printk(KERN_ALERT "Text location .text(Code Segment):%p/n",hello_init);

static int data_var=0;
printk(KERN_ALERT "Data Location .data(Data Segment):%p/n",&data_var);

printk(KERN_ALERT "BSS Location: .bss(BSS Segment):%p/n",&bss_var);
……
}
Module_init(hello_init);
 
这里,通过在模块的初始化函数中添加一段简单的程序,使模块在加载时打印出在内核中的加载地址。 .rodata 段的地址可以通过执行命令readelf -e hello.ko 取得 .rodata 在文件中的偏移量并加上段的 align 值得出。
为了使读者能够更好地进行模块的调试, kgdb项目还发布了一些脚本程序能够自动探测模块的插入并自动更新gdb 中模块的符号信息。这些脚本程序的工作原理与前面解释的工作过程相似,更多的信息请阅读参考资料 [4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值