gdb调试动态加载模块

origin: http://blog.csdn.net/su_ocean16/article/details/7843533
本文也即《Linux Device Drivers》,LDD3的第四章Debuging Techniques的读书笔记之六,但我们不限于此内容。这章看得比较慢,最近比较懒,而陷入了文档工作中,我决定这章节不会有之七,在之六打住。

   在用户程序中,有很多编译工具同提供的debug工具,用于设置断点或者单步跟踪,但是在kernel程序中是很困难的。LDD3介绍了gdb对于kernel模块的使用方式,但是需要kernel版本在2.6.7以上。我们需要两个文件vmlinux和/proc/kcore。我注意到moblin是没有看kcore的,而moblin的快速启动和效率是对linux的一个很大的优化,所以不知道以后是否还能通过这个方式。我在fc10进行实验,具体如下:

一、先获得vmlinux。

   这个不是/boot中任何相关的不bzImage或者zImage等经过压缩的文件,而且我们需要打开CONFIG_DEGBU_INFO的选项,因此我打算重新编译kernel来获取。根据我linux的当前版本,在网上下载kernel的source code文件kernel-2.6.27.5-117.fc10.src.rpm。下面的操作都在非root的普通用户下执行。

   1、rpm –ivh kernel-2.6.27.5-117.fc10.src.rpm,在~/rpmbuild/中或有SPECS/kernel.specs;

   2、进入~/rpmbuild/SPECS目录,执行rpmbuild –bp kernel.specs,在~/rpmbuild/BUILD/下有源代码

   3、进入~/rpmbuild/BUILD/kernel-2.6.27/linux-2.6.27.i386目录,需要根据我们的环境生成我们的.config文件,执行perl merge.pl config-i686 config-x86-generic > .config

   4、打开CONFIG_DEBUG_INFO的选项,执行make menuconfig,进入kernel hacking的选项,打开Kernel debugging,选择Compile the kernel with debug info,保存,查看vi .config,确认CONFIG_DEBUG_INFO的选项已经设置为y。

   5、如果我们直接编译,有一个bug,是Toshiba的api,需要打补丁,既然我的机器没有日立的API,可以在.config中将CONFIG_ACPI_TOSHIBA的选项直接关闭解决。我们只需要获得vmlinux,执行 make ARCH=x86 bzImage即可。这个过程花点时间,完成后在当前目录有一个文件vmlinux,这就是我们所需的。

二、进入kernel的gdb模式:

   执行gdb vmlinux /proc/kcore,在moblin中,不直接使用gdb vmlinux即可。我们加载scull模块后,在/sys/module/scull/sections中,使用ls -a的命令,有很多系统文件,用于显示scull模块的内存物理位置,其中需要注意的有.text。显示模块执行executable code的位置,.bss和.data显示模块变量的位置,如果编译时没有初始化位于.bss,如果编译时已经初始化则位于.data。  需查清各自物理内存的位置。cat .data .bss .text

   下面是处理的过程:

sudo gdb vmlinux /proc/kcore 
GNU gdb Fedora (6.8-29.fc10) 
Copyright (C) 2008 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later 

This is free software: you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law.  Type "show copying" 
and "show warranty" for details. 
This GDB was configured as "i386-redhat-linux-gnu"... 
Core was generated by `ro root=UUID=e57e257e-7340-411c-a6bb-6eb375f5aa8b rhgb quiet'. 
[New process 0] 
#0  0x00000000 in ?? () 

(gdb) add-symbol-file /home/wei/workspace/learning/kernel_module/scull_debug/scull.ko 0xf9df8000 -s .bss 0xf9dfaa00 -s .data 0xf9df9720 
add symbol table from file "/home/wei/workspace/learning/kernel_module/scull_debug/scull.ko" at 
    .text_addr = 0xf9df8000 
    .bss_addr = 0xf9dfaa00 
    .data_addr = 0xf9df9720 

(y or n) y 
Reading symbols from /workspace/wei/learning/kernel_module/scull_debug/scull.ko...done. 
(gdb) p mydev[0] 
$1 = {data = 0x0, quantum = 0, qset = 0, size = 0, access_key = 0, sem = { 
    lock = {raw_lock = {slock = 0}}, count = 1, wait_list = { 
      next = 0xf9dfaa3c, prev = 0xf9dfaa3c}}, cdev = {kobj = {name = 0x0, 
      entry = {next = 0xf9dfaa48, prev = 0xf9dfaa48}, parent = 0x0, 
      kset = 0x0, ktype = 0xc07d97c0, sd = 0x0, kref = {refcount = { 
          counter = 1}}, state_initialized = 1, state_in_sysfs = 0, 
      state_add_uevent_sent = 0, state_remove_uevent_sent = 0}, 
    owner = 0xf9df9880, ops = 0xf9df9740, list = {next = 0xf9dfaa70, 
      prev = 0xf9dfaa70}, dev = 260046848, count = 1}} 

(gdb) p mydev[0] //这里通过用户程序写入信息,在执行一次,发现结果相同,gdb给出的是上次结果的缓存 
$2 = {data = 0x0, quantum = 0, qset = 0, size = 0, access_key = 0, sem = { 
    lock = {raw_lock = {slock = 0}}, count = 1, wait_list = { 
      next = 0xf9dfaa3c, prev = 0xf9dfaa3c}}, cdev = {kobj = {name = 0x0, 
      entry = {next = 0xf9dfaa48, prev = 0xf9dfaa48}, parent = 0x0, 
      kset = 0x0, ktype = 0xc07d97c0, sd = 0x0, kref = {refcount = { 
          counter = 1}}, state_initialized = 1, state_in_sysfs = 0, 
      state_add_uevent_sent = 0, state_remove_uevent_sent = 0}, 
    owner = 0xf9df9880, ops = 0xf9df9740, list = {next = 0xf9dfaa70, 
      prev = 0xf9dfaa70}, dev = 260046848, count = 1}} 

(gdb) core-file /proc/kcore   //更新,flush cache,下次查询,将是实时内容 
Core was generated by `ro root=UUID=e57e257e-7340-411c-a6bb-6eb375f5aa8b rhgb quiet'. 
[New process 0] 
#0  0x00000000 in ?? () 
(gdb) p mydev[0] 
$3 = {data = 0xee327020, quantum = 1024, qset = 64, size = 1500, 
  access_key = 0, sem = {lock = {raw_lock = {slock = 2570}}, count = 1, 
    wait_list = {next = 0xf9dfaa3c, prev = 0xf9dfaa3c}}, cdev = {kobj = { 
      name = 0x0, entry = {next = 0xf9dfaa48, prev = 0xf9dfaa48}, 
      parent = 0x0, kset = 0x0, ktype = 0xc07d97c0, sd = 0x0, kref = { 
        refcount = {counter = 1}}, state_initialized = 1, state_in_sysfs = 0, 
      state_add_uevent_sent = 0, state_remove_uevent_sent = 0}, 
    owner = 0xf9df9880, ops = 0xf9df9740, list = {next = 0xf264df28, 
      prev = 0xf264df28}, dev = 260046848, count = 1}} 
(gdb)

   我们也可以通过print * (address)来查看某一个位置上的数据,例如上例子中,我们知道data的入口地址,我们就可以进一步查询相关内容,但是说实在的,我觉得这个还不很好用,俺们喜欢printk。


你可能感兴趣的:(iot_robot)