linux core 调试实例

文中提到:[indent]大多数UNIX调试程序都使用core文件以检查进程终止时的状态。[/indent]如书上表10-1所示,当进程接收到例如SIGABRT(异常终止)、SIGBUS(硬件故障)、SIGSEGV(无效内存引用)等信号的时候会产生相应的core文件,该core文件复制了进程的存储镜像。在运行程序的时候,我们会经常遇到Segmentation fault,也就是段错误,表示该进程进行了一次无效的内存访问。对于此类情况,我们很难发现问题具体是出现在程序的哪一行,如果是一小段程序,我们可以直接用gdb一步一步跟踪调试,但是如果程序规模很大,这样做显然就不实现了。回过头来,我们发现对于此类错误,程序会接收到SIGSEGV(无效内存引用)信号,而该信号在终止程序的同时,会在当前目录产生一个相应的core文件。因此,我们可以让gdb根据该core文件分析中断的位置,也就是出现该错误的位置。首先,我们应该现查看当前系统是否开启了core文件支持(以GNU/Linux为例):[list=1]
[]~ $ ulimit -c
[
]0
[]~ $ ulimit -c unlimited
[
]~ $ ulimit -c
[]unlimited
[
] 默认情况下,core dump生成的文件名为core,而且就在程序当前目录下。新的core会覆盖已存在的core。通过修改/proc/sys/kernel/core_uses_pid文件,可以将进程的pid作为作为扩展名,生成的core文件格式为core.xxx,其中xxx即为pid 方法:sudo echo “1” > /proc/sys/kernel/core_uses_pid 通过修改/proc/sys/kernel/core_pattern可以控制core文件保存位置和文件格式。例如:将所有的core文件生成到/corefile目录下,文件名的格式为core-命令名-pid-时间戳. 方法:sudo echo “/corefile/core-%e-%p-%t” > /proc/sys/kernel/core_pattern
[/list]
0表示未开启,大于0的表示默认core文件的大小,如果超过此大小,则截断,这会造成core文件的信息不完整,因此我们这里将其设置为unlimited,也就是无限大。接下来,我们写一段C代码来测试:[list=1]
[]#include <stdio.h>
[
]
[]char str;
[
]
[
]void core_test()
[]{
[
] printf(“%c\n”,str);
[
]}
[]
[
]int main(int argc, char argv[])
[
]{
[] core_test();
[
] return 0;
[]}
[/list]
然后,依次进行编译(无警告无错误),运行(段错误),并结合产生的core文件调试:[list=1]
[
]~ $ gcc -o test test.c -g
[]~ $ ./test
[
]Segmentation fault (core dumped)
[]~ $ file core
[
]core: ELF 32-bit LSB core file Intel 80386, version 1 (SYSV), SVR4-style, from ‘./test’
[]~ $ gdb test core
[
]GNU gdb (Gentoo 7.3.1 p1) 7.3.1
[]Copyright (C) 2011 Free Software Foundation, Inc.
[
]…
[]Core was generated by `./test’.
[
]Program terminated with signal 11, Segmentation fault.
[]#0 0x08048574 in core_test () at test.c:7
[
]7 printf(“%c\n”,str);
* where
[
]#0 0x08048574 in core_test () at test.c:7
[]#1 0x0804859d in main (argc=1, argv=0xbfed0214) at test.c:12
* quit
[/list]
很明显,问题是出在这里:[list=1]
[
]#0 0x08048574 in core_test () at test.c:7
[*]7 printf(“%c\n”,*str);
[/list]
字符指针str未经初始化就试图(解除引用)访问它所指向的内存空间,导致出现无效的内存访问。其中where命令用来查看当前调用栈信息。