免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5682 | 回复: 0
打印 上一主题 下一主题

FreeBSD7.0远程调试内核时,回溯汇编栈帧出现异常的一种规避方法 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-03-10 16:21 |只看该作者 |倒序浏览
双机远程串口调试FreeBSD7.0内核,建立调试连接之后,在vm_fault()函数处打断点,让目标机
继续运行并遇到vm_fault()断点时,若用backtrace命令查看调用栈,会在进入汇编语言栈帧之后
出现segmentation fault。

  1. #
  2. # kgdb -r /dev/cuad0 /sys/i386/compile/DEBUGKERNEL/kernel.debug
  3. [GDB will not be able to debug user-mode threads: /usr/lib/libthread_db.so: Undefined symbol "ps_pglobal_lookup"]
  4. GNU gdb 6.1.1 [FreeBSD]
  5. Copyright 2004 Free Software Foundation, Inc.
  6. GDB is free software, covered by the GNU General Public License, and you are
  7. welcome to change it and/or distribute copies of it under certain conditions.
  8. Type "show copying" to see the conditions.
  9. There is absolutely no warranty for GDB.  Type "show warranty" for details.
  10. This GDB was configured as "i386-marcel-freebsd".
  11. Switching to remote protocol
  12. kdb_enter (msg=0xc0aed472 "sysctl debug.kdb.enter") at ../../../kern/subr_kdb.c:310
  13. 310     }

  14. Unread portion of the kernel message buffer:
  15. KDB: enter: sysctl debug.kdb.enter

  16. #0  kdb_enter (msg=0xc0aed472 "sysctl debug.kdb.enter") at ../../../kern/subr_kdb.c:310
  17. 310     }
  18. (kgdb) b vm_fault
  19. Breakpoint 1 at 0xc097a066: file ../../../vm/vm_fault.c, line 222.
  20. (kgdb) c
  21. Continuing.
  22. [New Thread 100068]
  23. [Switching to Thread 100068]

  24. Breakpoint 1, vm_fault (map=0xc211cae0, vaddr=673189888, fault_type=3 '\003', fault_flags=1) at ../../../vm/vm_fault.c:222
  25. 222             PCPU_INC(cnt.v_vm_faults);
  26. (kgdb) bt
  27. #0  vm_fault (map=0xc211cae0, vaddr=673189888, fault_type=3 '\003', fault_flags=1) at ../../../vm/vm_fault.c:222
  28. #1  0xc097c12a in vm_fault_wire (map=0xc211cae0, start=673189888, end=673193984, user_wire=0, fictitious=0)
  29.     at ../../../vm/vm_fault.c:1025
  30. #2  0xc0981576 in vm_map_wire (map=0xc211cae0, start=673189888, end=673193984, flags=0) at ../../../vm/vm_map.c:2068
  31. #3  0xc097d1d5 in vslock (addr=0x28201040, len=4) at ../../../vm/vm_glue.c:226
  32. #4  0xc076877e in sysctl_wire_old_buffer (req=0xcd0c9ba4, len=4) at ../../../kern/kern_sysctl.c:1179
  33. #5  0xc0785c8f in kdb_sysctl_enter (oidp=0xc0b96460, arg1=0x0, arg2=0, req=0xcd0c9ba4) at ../../../kern/subr_kdb.c:157
  34. #6  0xc0768277 in sysctl_root (oidp=Variable "oidp" is not available.
  35. ) at ../../../kern/kern_sysctl.c:1306
  36. #7  0xc07683c4 in userland_sysctl (td=0xc251f210, name=0xcd0c9c14, namelen=3, old=0x28201040, oldlenp=0xbfbfe430, inkernel=0,
  37.     new=0x0, newlen=0, retval=0xcd0c9c10, flags=0) at ../../../kern/kern_sysctl.c:1401
  38. #8  0xc076915e in __sysctl (td=0xc251f210, uap=0xcd0c9cfc) at ../../../kern/kern_sysctl.c:1336
  39. #9  0xc0a5aa85 in syscall (frame=0xcd0c9d38) at ../../../i386/i386/trap.c:1035
  40. #10 0xc0a406b0 in Xint0x80_syscall () at ../../../i386/i386/exception.s:196
  41. Segmentation fault (core dumped)
  42. #
复制代码

kgdb至出异常时的调用栈为:

  1. Program received signal SIGSEGV, Segmentation fault.
  2. 0x2829ec87 in kvm_nlist () from /lib/libkvm.so.4
  3. (gdb) bt
  4. #0  0x2829ec87 in kvm_nlist () from /lib/libkvm.so.4
  5. #1  0x0804d548 in kgdb_lookup (sym=0x81e70a4 "calltrap") at kthr.c:62
  6. #2  0x0804e8a6 in kgdb_trgt_trapframe_prev_register (next_frame=0x285808ec, this_cache=0x28580d3c, regnum=8,
  7.     optimizedp=0xbfbfe184, lvalp=0xbfbfe170, addrp=0xbfbfe178, realnump=0xbfbfe174, valuep=0xbfbfe1b0) at trgt_i386.c:303
  8. #3  0x0811668e in frame_register_unwind (frame=0x28580d2c, regnum=8, optimizedp=0xbfbfe184, lvalp=0xbfbfe170, addrp=0xbfbfe178,
  9.     realnump=0xbfbfe174, bufferp=0xbfbfe1b0) at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/frame.c:547
  10. #4  0x08116a8b in frame_unwind_register (frame=0x28580d2c, regnum=8, buf=0xbfbfe1b0)
  11.     at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/frame.c:626
  12. #5  0x0817f40b in i386_unwind_pc (gdbarch=0x285a0008, next_frame=0x28580d2c)
  13.     at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/i386-tdep.c:754
  14. #6  0x081124b8 in gdbarch_unwind_pc (gdbarch=0x285a0008, next_frame=0x28580d2c)
  15.     at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/gdbarch.c:4595
  16. #7  0x0811627a in frame_pc_unwind (this_frame=0x28580d2c)
  17.     at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/frame.c:399
  18. #8  0x0811a1f1 in dummy_frame_sniffer (next_frame=0x28580d2c)
  19.     at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/dummy-frame.c:413
  20. #9  0x081195a6 in frame_unwind_find_by_frame (next_frame=0x28580d2c) at frame-unwind-kluge.c:90
  21. #10 0x08118d88 in get_frame_type (frame=0x28580da0) at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/frame.c:2127
  22. #11 0x0809e076 in print_frame_info (fi=0x28580da0, level=4, source=0, args=1)
  23.     at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/stack.c:427
  24. #12 0x0809f83b in backtrace_command_1 (count_exp=0x0, show_locals=0, from_tty=1)
  25.     at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/stack.c:1223
  26. #13 0x0809fa96 in backtrace_command (arg=0x0, from_tty=1)
  27.     at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/stack.c:1289
  28. #14 0x0817aa2b in do_cfunc (c=0x28567c10, args=0x0, from_tty=1)
  29.     at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/cli/cli-decode.c:57
  30. #15 0x0817d0a1 in cmd_func (cmd=0x28567c10, args=0x0, from_tty=1)
  31.     at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/cli/cli-decode.c:1541
  32. #16 0x0806cd8d in execute_command (p=0x28504082 "", from_tty=1)
  33.     at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/top.c:743
  34. #17 0x0806cf86 in command_loop () at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/top.c:822
  35. #18 0x0804cc2c in kgdb_interp_command_loop (data=0x0) at main.c:275
  36. #19 0x080f45b8 in current_interp_command_loop () at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/interps.c:277
  37. #20 0x080e913b in captured_command_loop (data=0x0) at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/main.c:97
  38. #21 0x0806c93c in do_catch_errors (uiout=0x28525800, data=0xbfbfe598)
  39.     at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/top.c:523
  40. #22 0x0806c6e0 in catcher (func=0x806c920 <do_catch_errors>, func_uiout=0x28525800, func_args=0xbfbfe598, func_val=0xbfbfe5a4,
  41.     func_caught=0xbfbfe5a0, errstring=0x8213b70 "", gdberrmsg=0x0, mask=6)
  42.     at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/top.c:430
  43. #23 0x0806c993 in catch_errors (func=0x80e9130 <captured_command_loop>, func_args=0x0, errstring=0x8213b70 "", mask=6)
  44.     at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/top.c:535
  45. #24 0x080e9f27 in captured_main (data=0xbfbfe864) at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/main.c:805
  46. #25 0x0806c93c in do_catch_errors (uiout=0x826d420, data=0xbfbfe7f8)
  47.     at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/top.c:523
  48. #26 0x0806c6e0 in catcher (func=0x806c920 <do_catch_errors>, func_uiout=0x826d420, func_args=0xbfbfe7f8, func_val=0xbfbfe804,
  49.     func_caught=0xbfbfe800, errstring=0x8213b70 "", gdberrmsg=0x0, mask=6)
  50.     at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/top.c:430
  51. #27 0x0806c993 in catch_errors (func=0x80e9180 <captured_main>, func_args=0xbfbfe864, errstring=0x8213b70 "", mask=6)
  52.     at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/top.c:535
  53. #28 0x080e9fa4 in gdb_main (args=0xbfbfe864) at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/main.c:814
  54. #29 0x0804d513 in main (argc=4, argv=0xbfbfed20) at main.c:495
复制代码


从现象上看,故障原因是启动kgdb的时候指定了-r /dev/cuad0参数,kgdb因此不会去打开kvm文件操作符,
参见/usr/src/gnu/usr.bin/gdb/kgdb/main.c的main()函数:

  1.         if (remote == NULL) {
  2.                 kvm = kvm_openfiles(kernel, vmcore, NULL,
  3.                     writecore ? O_RDWR : O_RDONLY, kvm_err);
  4.                 if (kvm == NULL)
  5.                         errx(1, kvm_err);
  6.                 atexit(kgdb_atexit);
  7.                 kgdb_thr_init();
  8.         }
复制代码


因此,以这种方式启动时,kvm指针为空。而在后面的栈帧回溯过程中,kgdb调用到了kgdb_lookup()函数,
参见/usr/src/gnu/usr.bin/gdb/kgdb/kthr.c:

  1. uintptr_t
  2. kgdb_lookup(const char *sym)
  3. {
  4.         struct nlist nl[2];

  5.         nl[0].n_name = (char *)(uintptr_t)sym;
  6.         nl[1].n_name = NULL;
  7.         if (kvm_nlist(kvm, nl) != 0) {
  8.                 warnx("kvm_nlist(%s): %s", sym, kvm_geterr(kvm));
  9.                 return (0);
  10.         }
  11.         return (nl[0].n_value);
  12. }
复制代码


由于kvm为空,导致在kvm_nlist()函数中出现segmentation fault。如果不想去深究gdb栈帧回溯算法的
问题,可以直接在kgdb_lookup()函数中加一个简单的保护来规避这个问题:

  1. uintptr_t
  2. kgdb_lookup(const char *sym)
  3. {
  4.         struct nlist nl[2];

  5.         if (kvm == 0)
  6.                 return (0);

  7.         nl[0].n_name = (char *)(uintptr_t)sym;
  8.         nl[1].n_name = NULL;
  9.         if (kvm_nlist(kvm, nl) != 0) {
  10.                 warnx("kvm_nlist(%s): %s", sym, kvm_geterr(kvm));
  11.                 return (0);
  12.         }
  13.         return (nl[0].n_value);
  14. }
复制代码


重新编译kgdb(如果之前没有在本地编译过gdb代码/usr/src/gnu/usr.bin中的gdb代码,则需要在
/usr/src/gnu/usr.bin/gdb目录下make,并根据错误提示到上一级目录中对应的库目录下make。)
这样修改之后,虽然在原故障位置之后的栈帧信息多少有些莫名其妙,但kgdb不会再因segmentation fault
而退出了,我们可以继续跟踪感兴趣的内核代码:

  1. #
  2. # /usr/src/gnu/usr.bin/gdb/kgdb/kgdb -r /dev/cuad0 /sys/i386/compile/DEBUGKERNEL/kernel.debug
  3. [GDB will not be able to debug user-mode threads: /usr/lib/libthread_db.so: Undefined symbol "ps_pglobal_lookup"]
  4. GNU gdb 6.1.1 [FreeBSD]
  5. Copyright 2004 Free Software Foundation, Inc.
  6. GDB is free software, covered by the GNU General Public License, and you are
  7. welcome to change it and/or distribute copies of it under certain conditions.
  8. Type "show copying" to see the conditions.
  9. There is absolutely no warranty for GDB.  Type "show warranty" for details.
  10. This GDB was configured as "i386-marcel-freebsd".
  11. Switching to remote protocol
  12. vm_fault (map=0xc211cae0, vaddr=673189888, fault_type=3 '\003', fault_flags=1) at ../../../vm/vm_fault.c:222
  13. 222             PCPU_INC(cnt.v_vm_faults);

  14. Unread portion of the kernel message buffer:
  15. KDB: enter: sysctl debug.kdb.enter

  16. #0  vm_fault (map=0xc211cae0, vaddr=673189888, fault_type=3 '\003', fault_flags=1) at ../../../vm/vm_fault.c:222
  17. 222             PCPU_INC(cnt.v_vm_faults);
  18. (kgdb) bt
  19. #0  vm_fault (map=0xc211cae0, vaddr=673189888, fault_type=3 '\003', fault_flags=1) at ../../../vm/vm_fault.c:222
  20. #1  0xc097c12a in vm_fault_wire (map=0xc211cae0, start=673189888, end=673193984, user_wire=0, fictitious=0)
  21.     at ../../../vm/vm_fault.c:1025
  22. #2  0xc0981576 in vm_map_wire (map=0xc211cae0, start=673189888, end=673193984, flags=0) at ../../../vm/vm_map.c:2068
  23. #3  0xc097d1d5 in vslock (addr=0x28201040, len=4) at ../../../vm/vm_glue.c:226
  24. #4  0xc076877e in sysctl_wire_old_buffer (req=0xcd0c9ba4, len=4) at ../../../kern/kern_sysctl.c:1179
  25. #5  0xc0785c8f in kdb_sysctl_enter (oidp=0xc0b96460, arg1=0x0, arg2=0, req=0xcd0c9ba4) at ../../../kern/subr_kdb.c:157
  26. #6  0xc0768277 in sysctl_root (oidp=Variable "oidp" is not available.
  27. ) at ../../../kern/kern_sysctl.c:1306
  28. #7  0xc07683c4 in userland_sysctl (td=0xc251f210, name=0xcd0c9c14, namelen=3, old=0x28201040, oldlenp=0xbfbfe430, inkernel=0,
  29.     new=0x0, newlen=0, retval=0xcd0c9c10, flags=0) at ../../../kern/kern_sysctl.c:1401
  30. #8  0xc076915e in __sysctl (td=0xc251f210, uap=0xcd0c9cfc) at ../../../kern/kern_sysctl.c:1336
  31. #9  0xc0a5aa85 in syscall (frame=0xcd0c9d38) at ../../../i386/i386/trap.c:1035
  32. #10 0xc0a406b0 in Xint0x80_syscall () at ../../../i386/i386/exception.s:196
  33. #11 0x2815566f in ?? ()
  34. Previous frame inner to this frame (corrupt stack?)
  35. (kgdb)
复制代码

[ 本帖最后由 雨丝风片 于 2008-3-10 16:44 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP