kgdb-调试内核和模块-靠谱

转载:kgdb-调试内核和模块-靠谱

首先两个非常有深度和帮助性的链接:
http://www.kgdb.info/category/kgdb/understand_kgdb/
http://kernel.org/pub/linux/kernel/people/jwessel/kdb/index.html
下面是步骤,罗嗦在最后,贴了不少源码:
内核版本2.6.32,gdb版本6.8(应该适合高版本),如何编译内核,网络上有很多,但关键的几个,不再叙述。
1.编译内核,添加内核启动参数 kgdboc=ttyS0,内核参数kgdbwait在内核启动过程中停止,但内核基本启动完毕,如果使用kgdbwait,则它一定放在kgdboc~~参数后面才起作用.
2.gdb vmlinux,进入输入命令 target remote /dev/pts/2,由于使用kvm,所以是虚拟串口文件
3.如果使用kgdbwait,此时kgdb应该链接上,如下所示:

  1. (gdb) target remote /dev/pts/5
  2. Remote debugging using /dev/pts/5
  3. kgdb_breakpoint () at kernel/kgdb.c:1721
  4. 1721                wmb(); /* Sync point after breakpoint */
  5. (gdb) bt
  6. #0  kgdb_breakpoint () at kernel/kgdb.c:1721
  7. #1  kgdb_initial_breakpoint () at kernel/kgdb.c:1631
  8. #2  kgdb_register_io_module (new_kgdb_io_ops=0xc08e5638) at kernel/kgdb.c:1673
  9. #3  0xc063557e in configure_kgdboc () at drivers/serial/kgdboc.c:67
  10. #4  0xc092209e in init_kgdboc () at drivers/serial/kgdboc.c:88
  11. #5  0xc0401033 in do_one_initcall (fn=0xc092208b <init_kgdboc>)
  12.     at init/main.c:721
  13. #6  0xc08fa375 in do_initcalls () at init/main.c:761
  14. #7  do_basic_setup () at init/main.c:783
  15. #8  kernel_init (unused=<value optimized out>) at init/main.c:879
  16. #9  0xc042e0c7 in kernel_thread_helper () at arch/x86/kernel/entry_32.S:990
  17. (gdb)

这是就进入调试模式了。


4.如果没有使用kgdbwait(一般不用,很麻烦),在虚拟机正常启动后,输入

  1. [root@localhost /]# echo g > /proc/sysrq-trigger
这时gdb链接上,如下所是:
  1. Program received signal SIGTRAP, Trace/breakpoint trap.
  2. [Switching to Thread 943]
  3. kgdb_breakpoint () at kernel/kgdb.c:1721
  4. 1721                wmb(); /* Sync point after breakpoint */
  5. (gdb) bt
  6. #0  kgdb_breakpoint () at kernel/kgdb.c:1721
  7. #1  sysrq_handle_gdb (key=<value optimized out>, tty=0x0) at kernel/kgdb.c:1581
  8. #2  0xc061eae6 in __handle_sysrq (key=103, tty=0x0, check_mask=0)
  9.     at drivers/char/sysrq.c:521
  10. #3  0xc061eb9c in write_sysrq_trigger (file=<value optimized out>,
  11.     buf=0xb77b0000 "g\n", count=2, ppos=0xdeeb4f98) at drivers/char/sysrq.c:599
  12. #4  0xc05452da in proc_reg_write (file=0xdf8a77c0, buf=0xb77b0000 "g\n",
  13.     count=2, ppos=0xdeeb4f98) at fs/proc/inode.c:207
  14. #5  0xc050af1c in vfs_write (file=0xdf8a77c0, buf=0xb77b0000 "g\n",
  15.     count=<value optimized out>, pos=0xdeeb4f98) at fs/read_write.c:347
  16. #6  0xc050b09d in sys_write (fd=1, buf=0xb77b0000 "g\n", count=2)
  17.     at fs/read_write.c:399
  18. #7  0xc042d595 in system_call () at arch/x86/kernel/entry_32.S:529
  19. #8  0xb77b0000 in ?? ()
  20. #9  0x00000002 in ?? ()
  21. #10 0xb77b0000 in ?? ()
  22. #11 0xbf9a7d70 in ?? ()
  23. #12 0x00000004 in ?? ()
  24. Backtrace stopped: previous frame inner to this frame (corrupt stack?)
  25. (gdb)
5.使用kgdb本来是想调内核模块,内核只是想看看里面的模样,但这时是没法调试模块的,只能使用gdb的add-symbol-file命令加载符号,进入调试状态:
  1. (gdb) l sys_init_module
  2. 2562        }
  3. 2563       
  4. 2564        /* This is where the real work happens */
  5. 2565        SYSCALL_DEFINE3(init_module, void __user *, umod,
  6. 2566                        unsigned long, len, const char __user *, uargs)
  7. 2567        {
  8. 2568                struct module *mod;
  9. 2569                int ret = 0;
  10. 2570       
  11. 2571                /* Must have permission */
  12. (gdb) l
  13. 2572                if (!capable(CAP_SYS_MODULE) || modules_disabled)
  14. 2573                        return -EPERM;
  15. 2574       
  16. 2575                /* Only one module load at a time, please */
  17. 2576                if (mutex_lock_interruptible(&module_mutex) != 0)
  18. 2577                        return -EINTR;
  19. 2578       
  20. 2579                /* Do all the hard work */
  21. 2580                mod = load_module(umod, len, uargs);
  22. 2581                if (IS_ERR(mod)) {
  23. (gdb)
  24. 2582                        mutex_unlock(&module_mutex);
  25. 2583                        return PTR_ERR(mod);
  26. 2584                }
  27. 2585       
  28. 2586                /* Drop lock so they can recurse */
  29. 2587                mutex_unlock(&module_mutex);
  30. 2588       
  31. 2589                blocking_notifier_call_chain(&module_notify_list,
  32. 2590                                MODULE_STATE_COMING, mod);
  33. 2591       
  34. (gdb)
  35. 2592                do_mod_ctors(mod);
  36. 2593                /* Start the module */
  37. 2594                if (mod->init != NULL)
  38. (gdb) b 2580
  39. Breakpoint 4 at 0xc049fd9c: file kernel/module.c, line 2580.
  40. (gdb) c
继续,在虚拟机中加载内核   insmod my_dir.ko,然后gdb中显示如下:
  1. Breakpoint 4, sys_init_module (umod=0x9002018, len=99891, uargs=0x9002008 "")
  2.     at kernel/module.c:2580
  3. 2580                mod = load_module(umod, len, uargs);
  4. (gdb) p *mod
  5. Cannot access memory at address 0x0
  6. (gdb) n
  7. 2581                if (IS_ERR(mod)) {
  8. (gdb) p *mod
  9. Cannot access memory at address 0x0
  10. (gdb) n
  11. 2580                mod = load_module(umod, len, uargs);
  12. (gdb) p *mod
  13. $5 = {state = MODULE_STATE_COMING, list = {next = 0xc08cfce4,
  14.     prev = 0xc08cfce4}, name = "my_dir", '\0' <repeats 53 times>, mkobj = {
  15.     kobj = {name = 0xdef4cd20 "my_dir", entry = {next = 0xdf859800,
  16.         prev = 0xdf8b0a04}, parent = 0xdf85980c, kset = 0xdf859800,
  17.       ktype = 0xc08cf480, sd = 0xdef4d8fc, kref = {refcount = {counter = 3}},
  18.       state_initialized = 1, state_in_sysfs = 1, state_add_uevent_sent = 1,
  19.       state_remove_uevent_sent = 0, uevent_suppress = 0}, mod = 0xe0b8a160,
  20.     drivers_dir = 0x0, mp = 0x0}, modinfo_attrs = 0xdeeb1080, version = 0x0,
  21.   srcversion = 0xdf801200 "A8DC41FB925141E6B17A45D", holders_dir = 0xdf371a80,
  22.   syms = 0x0, crcs = 0x0, num_syms = 0, kp = 0x0, num_kp = 0,
  23.   num_gpl_syms = 0, gpl_syms = 0x0, gpl_crcs = 0x0, unused_syms = 0x0,
  24.   unused_crcs = 0x0, num_unused_syms = 0, num_unused_gpl_syms = 0,
  25.   unused_gpl_syms = 0x0, unused_gpl_crcs = 0x0, gpl_future_syms = 0x0,
  26.   gpl_future_crcs = 0x0, num_gpl_future_syms = 0, num_exentries = 0,
  27.   extable = 0x0, init = 0xe0b8d000, module_init = 0xe0b8d000,
  28.   module_core = 0xe0b8a000, init_size = 1291, core_size = 830,
  29.   init_text_size = 295, core_text_size = 173, arch = {<No data fields>},
  30.   taints = 0, num_bugs = 0, bug_list = {next = 0xc08dd054, prev = 0xc08dd054},
  31.   bug_table = 0x0, symtab = 0xe0b8d128, core_symtab = 0xe0b8a2c0,
  32.   num_symtab = 44, core_num_syms = 5, strtab = 0xe0b8d3e8 "",
  33.   core_strtab = 0xe0b8a310 "", sect_attrs = 0xdee0a000,
  34.   notes_attrs = 0xdfa4f340, percpu = 0x0, args = 0xdef4cd80 "",
  35.   tracepoints = 0x0, num_tracepoints = 0, trace_bprintk_fmt_start = 0x0,
  36.   num_trace_bprintk_fmt = 0, trace_events = 0x0, num_trace_events = 0,
  37.   modules_which_use_me = {next = 0xe0b8a2a4, prev = 0xe0b8a2a4},
  38.   waiter = 0xdf8e4170, exit = 0xe0b8a0a8, refptr = 0xc0977220 "", ctors = 0x0,
  39.   num_ctors = 0}
  40. (gdb)
谁能给我解释一下mod一会没了,一回又有了,如果一直没有,那你到load_module函数里面去搞。
  1. (gdb) p *(mod->sect_attrs->attrs+1)
  2. $6 = {mattr = {attr = {name = 0xdeeab460 ".text", owner = 0x0, mode = 292},
  3.     show = 0xc049d3e0 <module_sect_show>, store = 0, setup = 0, test = 0,
  4.     free = 0}, name = 0xdeeab460 ".text", address = 3770195968}
  5. (gdb) p *(mod->sect_attrs->attrs+2)
  6. $7 = {mattr = {attr = {name = 0xdeeab4e0 ".exit.text", owner = 0x0,
  7.       mode = 292}, show = 0xc049d3e0 <module_sect_show>, store = 0, setup = 0,
  8.     test = 0, free = 0}, name = 0xdeeab4e0 ".exit.text", address = 3770196136}
  9. (gdb) p *(mod->sect_attrs->attrs+3)
  10. $8 = {mattr = {attr = {name = 0xdeeab5a0 ".init.text", owner = 0x0,
  11.       mode = 292}, show = 0xc049d3e0 <module_sect_show>, store = 0, setup = 0,
  12.     test = 0, free = 0}, name = 0xdeeab5a0 ".init.text", address = 3770208256}
  13. (gdb) add-symbol-file /home/sword/se/my_proc/my_dir.o 3770195968 -s .exit.text 3770196136 -s .init.text 3770208256
  14. add symbol table from file "/home/sword/se/my_proc/my_dir.o" at
  15.         .text_addr = 0xe0b8a000
  16.         .exit.text_addr = 0xe0b8a0a8
  17.         .init.text_addr = 0xe0b8d000
  18. (y or n) y
  19. Reading symbols from /home/sword/se/my_proc/my_dir.o...done.
  20. (gdb) b my_init
  21. Breakpoint 5 at 0xe0b8d00e: file /home/sword/se/my_proc/my_dir.c, line 84.
  22. (gdb) c
  23. Continuing.

  24. Breakpoint 5, kmem_cache_alloc_notrace () at include/linux/slab_def.h:120
  25. 120                return kmem_cache_alloc(cachep, flags);
  26. (gdb) bt
  27. #0  kmem_cache_alloc_notrace () at include/linux/slab_def.h:120
  28. #1  kmalloc () at include/linux/slab_def.h:155
  29. #2  my_init () at /home/sword/se/my_proc/my_dir.c:84
  30. #3  0xc0401033 in do_one_initcall (fn=0xe0b8d000 <my_init>) at init/main.c:721
  31. #4  0xc049fe01 in sys_init_module (umod=0x9002018, len=99891,
  32.     uargs=0x9002008 "") at kernel/module.c:2595
  33. #5  0xc042d595 in system_call () at arch/x86/kernel/entry_32.S:529
  34. #6  0x00018633 in ?? ()
  35. #7  0x09002008 in ?? ()
  36. #8  0x00000000 in ?? ()
  37. (gdb)
结束,建议先看开始的链接,我也并不清楚sysrq之类的,但我估计是调用了一个中断触发指令,然后让系统陷入异常处理函数,让kgdb接管系统。这里在网上找了资料,什么gdbmod,还有gdb-light之类的,都没弄通(后者gdb7.0没编译过去,自己的f10太老了吧,不想折腾),参考一下add-symbol-file命令,如下:
  1. (gdb) help add-symbol-file
  2. Load symbols from FILE, assuming FILE has been dynamically loaded.
  3. Usage: add-symbol-file FILE ADDR [-s <SECT> <SECT_ADDR> -s <SECT> <SECT_ADDR> ...]
  4. ADDR is the starting address of the file's text.
  5. The optional arguments are section-name section-address pairs and
  6. should be specified if the data and bss segments are not contiguous
  7. with the text.  SECT is a section name to be loaded at SECT_ADDR.
  8. (gdb)
给定elf文件,还有text段的起始地址即可,自己一开始也就直接使用
add-symbol-file /home/sword/se/my_proc/my_dir.o 0xXXXXXXXX
但是没法调试my_init,也就是模块初始化函数,这里自己写的内核测试函数,都是在my_init里面跑一下,返回-1就散了,省等程序错了没法卸载模块,还要折腾重启。所以就像上面所说的添加了.init.text和.exit.text两个段。可以调试自己模块初始化函数,如果你的模块中有全局变量之类的,还得添加别的data段之类的,可以像上面写的试试
(gdb) p *(mod->sect_attrs->attrs+n)
n的最大值可以达16,你可以使用objdump命令来看看它的段表。
这里您要是调的话不免看一下您的源码,mod结构的sect_attrs变量比一定都有的,有时需要配置一下内核编译选项才行。
最后一句话 insmod_module和add-symbol-table都是解析elf头。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值