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

内核模块的调试方法

2018年04月17日 ⁄ 综合 ⁄ 共 1938字 ⁄ 字号 评论关闭
内核可加载模块的调试具有其特殊性。由于内核模块中各段的地址是在模块加载进内核的时候才最终确定的,所以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(数据段):数据段用来存放可执行文件中已初始化全局变量,也就是存放程序静态分配的变量和全局变量
.bssBSS段):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]
【上篇】
【下篇】

抱歉!评论已关闭.