GDB调试技巧:gdb at pid无法调试的问题

作者:gfree.wind@gmail.com
博客:blog.focus-linux.net   linuxfocus.blog.chinaunix.net
 
 
本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以*拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
======================================================================================================
今天这个主题有点意思,各位同学听我慢慢道来。

当我们使用GDB调试一个daemon的时候,一般有两种方式:
1. 直接在shell命令行键入gdb attach pid (要调试daemon的进程ID)。一般情况下,我都习惯于缩写gdb at pid;
2. 在shell中键入gdb,进入gdb,然后attach pid(同样是要调试daemon的进程ID)。我不常用这种方式,因为这种方式需要2个步骤——尽管键入的字母是一样的。

下面来说说今天遇到的问题。公司的一个实习生来问我问题。他目前正在做一个工作,大致的功能是得到某个daemon的某一时刻的调用栈——就像gdb一样。但是他发现当daemon处于系统调用状态时,从EBP得到的返回地址不正确。然后我让他直接使用gdb查看是否可以看到完整的调用栈,如果GDB可以,那么就没有问题,可以去看GDB如何实现的。如果不能,再想为什么。——这里先插一句,当时我去查看了他的EBP的值,根据其值获得的返回地址确实不正确。今晚查了查,知道在某些函数调用时,为了速度,EBP有可能并没有被压栈。但是这个不是今天的主题,让我们再转回来。他很快的试了试,告诉我gdb虽然可以使用bt(backtrace)得到函数栈,但是显示出来的结果却不正确。

怎么回事呢?不可能啊。我在他那写了一个很简单的测试程序:
  1. #include <stdlib.h>
  2. #include <stdio.h>

  3. static void test(void)
  4. {
  5.     pause();
  6. }


  7. int main(void)
  8. {
  9.     test();

  10.     return 0;
  11. }
编译并运行:
  1. [xxx@xxx-vm-fc13 test]$ gcc -g test.c
  2. [xxx@xxx-vm-fc13 test]$ ./a.out
然后使用另外一个终端进行调试:
  1. [xxx@xxx-vm-fc13 test]$ ps auwx|grep a.out
  2. xxx 2412 0.0 0.0 1816 288 pts/4 S+ 11:19 0:00 ./a.out
  3. xxx 2415 0.0 0.0 4308 732 pts/5 S+ 11:20 0:00 grep a.out
  4. [xxx@xxx-vm-fc13 test]$ gdb at 2412
  5. GNU gdb (GDB) Fedora (7.1-18.fc13)
  6. Copyright (C) 2010 Free Software Foundation, Inc.
  7. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
  8. This is free software: you are free to change and redistribute it.
  9. There is NO WARRANTY, to the extent permitted by law. Type "show copying"
  10. and "show warranty" for details.
  11. This GDB was configured as "i686-redhat-linux-gnu".
  12. For bug reporting instructions, please see:
  13. <http://www.gnu.org/software/gdb/bugs/>...
  14. Reading symbols from /usr/bin/at...(no debugging symbols found)...done.
  15. Attaching to program: /usr/bin/at, process 2412
  16. Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
  17. Loaded symbols for /lib/ld-linux.so.2
  18. 0x009f4424 in __kernel_vsyscall ()
  19. Missing separate debuginfos, use: debuginfo-install at-3.1.12-5.fc13.i686
  20. (gdb) bt
  21. #0 0x009f4424 in __kernel_vsyscall ()
  22. #1 0x0065dac6 in ?? ()
  23. #2 0x080483dc in ?? ()
  24. #3 0x005d6cc6 in ?? ()
  25. #4 0x08048331 in ?? ()
  26. (gdb)
看到这个结果,我还真有些意外。我使用gdb也有些年头了,从来都是这样调试daemon的啊。怎么会这样呢啊?看这个输出,很像没有调试信息啊。可是前面的编译有-g选项啊。

使用第二种方法试试?
  1. [xxx@xxx-vm-fc13 test]$ gdb
  2. GNU gdb (GDB) Fedora (7.1-18.fc13)
  3. Copyright (C) 2010 Free Software Foundation, Inc.
  4. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
  5. This is free software: you are free to change and redistribute it.
  6. There is NO WARRANTY, to the extent permitted by law. Type "show copying"
  7. and "show warranty" for details.
  8. This GDB was configured as "i686-redhat-linux-gnu".
  9. For bug reporting instructions, please see:
  10. <http://www.gnu.org/software/gdb/bugs/>.
  11. (gdb) at 2412
  12. Attaching to process 2412
  13. Reading symbols from /home/fgao/works/test/a.out...done.
  14. Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
  15. Loaded symbols for /lib/libc.so.6
  16. Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
  17. Loaded symbols for /lib/ld-linux.so.2
  18. 0x009f4424 in __kernel_vsyscall ()
  19. Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.i686
  20. (gdb) bt
  21. #0 0x009f4424 in __kernel_vsyscall ()
  22. #1 0x0065dac6 in __pause_nocancel () from /lib/libc.so.6
  23. #2 0x080483cf in test () at test.c:6
  24. #3 0x080483dc in main () at test.c:12
  25. (gdb)
啊,这种方式就没有问题啊。怎么回事呢?难道是因为这两种方式的attach还有区别不成?于是我又查了gdb的说明,应该没有区别啊。

想了半天,又试了几次第一种方式,还是没有结果。当我感觉我以前的GDB的世界观都要崩溃的时候,对自己的GDB技能产生了极度的不自信的时候,再次退出gdb的时候,我发现了原因。该原因差点没把我郁闷死。。。

大家想一下哦。。。

  1. (gdb) q
  2. A debugging session is active.
  3. Inferior 1 [process 2412] will be detached.
  4. Quit anyway? (y or n) y
  5. Detaching from program: /usr/bin/at, process 2412
注意看这里的红色代码。进程号没有错,但是program却是/usr/bin/at。My god!原来我使用第一种方式的时候,一直在尝试调试at——这个linux命令。怪不得没有调试信息呢!在我以前的GDB应用中,因为系统中没有at这个命令,所以gdb at pid就等于gdb attach pid,是可以缩写的。但是在当前这个环境中,很并不幸的存在着at这个命令。结果GDB没有尝试去attach,而是直接去调试at命令。

不过这里,我觉得GDB可以做得更友好一些。虽然在这个情况下,GDB去调试at没有问题,但是后面的PID已经被我的测试程序占用了,它应该报个错误或者警告吧。

最后总结一下,GDB的缩写是好,但是小心过分的缩写会与已有命令冲突哦~~总之,缩写需谨慎。
上一篇:MySQL内核月报 2015.03-MySQL · 捉虫动态· pid file丢失问题分析


下一篇:C#调用Python