linux内核调试环境搭建-4 调试模块初始化函数

打开一终端执行:

qemu -m 512 -kernel bzImage -append "root=/dev/sda kgdboc=ttyS0,115200 kgdbwait" -boot c -hda busybox.img -k en-us -net nic -net tap,ifname=tap0,script=no -serial tcp::4321,server

显示等待调试端链接:

QEMU waiting for connection on: tcp:0.0.0.0:4321,server

 再打开一终端

$cd linux-2.6.35.9

$gdb vmlinux

调试客户端:

(gdb) target remote localhost:4321

Remote debugging using localhost:4321

kgdb_breakpoint (new_dbg_io_ops=0xc07c27e0)

at kernel/debug/debug_core.c:967

warning: Source file is more recent than executable.

967            wmb(); /* Sync point after breakpoint */

 

开启运行:

(gdb) c

Continuing.

一直到虚拟机启动。

让虚拟机进入调试模式:

#echo g > /proc/sysrq-trigger

 

在调试端下断点:

(gdb)b sys_init_module

(这个函数名在源文件中找不到,是由宏定义SYSCALL_DEFINE3展开的)

 

让虚拟机开启运行:

(gdb) c

Continuing.

在虚拟机中加载模块:

#insmod globalmem.ko

此时调试端中断在函数sys_init_module中:

Breakpoint 1, sys_init_module (umod=0xb777c008, len=134933, uargs=0x81c4348 "")

    at kernel/module.c:2618

2618         if (!capable(CAP_SYS_MODULE) || modules_disabled)

 

下断:

(gdb) b add_sect_attrs

Breakpoint 2 at 0xc017251d: file kernel/module.c, line 1160.

执行:

(gdb) c

Continuing.

Breakpoint 2, add_sect_attrs (mod=0xe0a356c0, nsect=34, secstrings=0xe0a2b621 "",

    sechdrs=0xe0a2b754) at kernel/module.c:1160

1160         for (i = 0; i < nsect; i++)

 

where显示调用栈:

(gdb) where

#0  add_sect_attrs (mod=0xe0a356c0, nsect=34, secstrings=0xe0a2b621 "", sechdrs=0xe0a2b754)

    at kernel/module.c:1160

#1  0xc0174029 in load_module (umod=<value optimized out>, len=<value optimized out>,

    uargs=<value optimized out>) at kernel/module.c:2552

#2  0xc01742e2 in sys_init_module (umod=0xb78b6008, len=134933, uargs=0x81c4348 "")

    at kernel/module.c:2622

 

下断第1192行:

(gdb) b 1192

Breakpoint 4 at 0xc01725db: file kernel/module.c, line 1192.

 

c开启运行:

(gdb) c

Continuing.

Breakpoint 4, add_sect_attrs (mod=<value optimized out>, nsect=<value optimized out>,

    secstrings=<value optimized out>, sechdrs=0xe0a2b754) at kernel/module.c:1192

1192                   *(gattr++) = &(sattr++)->mattr.attr;

 

此时打印  sattr ->name

(gdb) p sattr ->name

$4 = 0xdf412b60 ".note.gnu.build-id"

 

按若干次c之后:

(gdb) p sattr ->name

$2 = 0xdf8b25e8 ".text"

(gdb) p /x sattr ->address

$4 = 0xe0a35000

 

(gdb) p sattr ->name

$8 = 0xdf8b2600 ".data"

(gdb) p /x sattr ->address

$10 = 0xe0a356b8

 

gdb中增加调试信息:

add-symbol-file /home/gudujian/06/globalmemDriver/globalmem.ko 0xe0a35000 -s .data 0xe0a356b8


此时就可以对globalmem.ko模块中的符号,正常下断点:

(这里仅仅使用模块的两个节.data.text如果再使用其它节那么比较麻烦,如果有脚本可以做上面的事情就很好了)。

(gdb) b globalmem_init

Breakpoint 5 at 0xe0a35448: file /home/gudujian/06/globalmemDriver/globalmem.c, line 195.

 

c让程序开始运行:

(gdb) c

Continuing.

Breakpoint 5, globalmem_init () at /home/gudujian/06/globalmemDriver/globalmem.c:195

195           dev_t devno = MKDEV(globalmem_major, 0);

 

此时程序中断在新加载模块的module_init函数中:globalmem_init

此时因为编译这个内核模块时带有调试信息  EXTRA_CFLAGS=-g -O0

所以可以正常调试linux模块。





小技巧:
)当不知道一个指针指向具体哪个函数的时候可以用打印的方式;
比如: ret = info->fbops->fb_check_var(var, info);
可以打印: printk("info->fbops->fb_check_var is %x\n",info->fbops->fb_check_var);
得到这个函数指针的地址之后一切就好办了,可以用 cat /proc/kallsyms,或者用
map文件。或者用addr2line工具得到对应的具体哪个函数。






你可能感兴趣的:(linux内核调试环境搭建-4 调试模块初始化函数)