1. 概述
C程序崩溃之后会自动转存储,利用这个信息可以快速定位出错的地方。
但要正确地使用这个功能,需要注意如下几点:
- 代码在编译的时候,添加调试选项-g
- 设置转存储的大小(有些系统缺省为0)
- 结合gdb和coredump文件定位异常点
2. 示例1
示例代码:
#include <stdio.h>
int core_dump() {
int i;
for (i = 5; i >= 0; i--) {
printf("(%d, %d)\n", i, 100 / i);
}
return 0;
}
int main() {
core_dump();
return 0;
}
以上代码存在除0异常,编译运行:
gcc main.c
./a.out
运行结果:
(5, 20)
(4, 25)
(3, 33)
(2, 50)
(1, 100)
[1] 9662 floating point exception (core dumped) ./a.out
为了更清楚地找到代码出错的地方,可以使用gdb来分析coredump文件:
~/examples/cpp/core_dump % gdb ./a.out core
GNU gdb (GDB) 7.7
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
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 "i686-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...done.
[New LWP 9662]
warning: Could not load shared library symbols for linux-gate.so.1.
Do you need "set solib-search-path" or "set sysroot"?
Core was generated by `./a.out'.
Program terminated with signal SIGFPE, Arithmetic exception.
#0 0x08048415 in core_dump ()
(gdb) where
#0 0x08048415 in core_dump ()
#1 0x0804844b in main ()
(gdb) q
可以看到上面并没有给出具体的代码&行号,因为需要添加-g编译选项。为此重新编译、运行,此时的coredumnp文件就提供了全面的信息:
~/examples/cpp/core_dump % gdb ./a.out core
GNU gdb (GDB) 7.7
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
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 "i686-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...done.
[New LWP 9758]
warning: Could not load shared library symbols for linux-gate.so.1.
Do you need "set solib-search-path" or "set sysroot"?
Core was generated by `./a.out'.
Program terminated with signal SIGFPE, Arithmetic exception.
#0 0x08048415 in core_dump () at main.c:7
7 printf("(%d, %d)\n", i, 100 / i);
(gdb) where
#0 0x08048415 in core_dump () at main.c:7
#1 0x0804844b in main () at main.c:14
(gdb)
3. 示例2:ulimit设置转存储大小
下面这个例子是在一台新安装Ubuntu 12后第一次运用内存转存储的功能,期间遇到转存储后无法找到core文件。此时,就需要用ulimit命令设置转存储的大小。
代码如下:
#include <stdio.h> //fopen etc
#include <string.h> //strlen
int main()
{
const char* s = "hello";
FILE* fp = NULL;
fp = fopen("./hello_c.txt", "rb");
fwrite(s, 1, strlen(s), fp);
fclose(fp);
return 0;
}
编译、运行:
flying-bird@flying-bird:~/examples/cpp/echo$ gcc -g ./hello.c
flying-bird@flying-bird:~/examples/cpp/echo$ ./a.out
段错误 (核心已转储)
flying-bird@flying-bird:~/examples/cpp/echo$ ll
总用量 24
drwxrwxr-x 2 flying-bird flying-bird 4096 5月 10 15:19 ./
drwxrwxr-x 3 flying-bird flying-bird 4096 5月 10 15:19 ../
-rwxrwxr-x 1 flying-bird flying-bird 9464 5月 10 15:19 a.out*
-rw-rw-r-- 1 flying-bird flying-bird 211 5月 10 15:17 hello.c
flying-bird@flying-bird:~/examples/cpp/echo$
虽然提示已经转存储了,但仍然找不到core文件。为此查询core大小,并修改:
flying-bird@flying-bird:~/examples/cpp/echo$ ulimit -c
0
flying-bird@flying-bird:~/examples/cpp/echo$ ulimit -c unlimited
flying-bird@flying-bird:~/examples/cpp/echo$ ./a.out
段错误 (核心已转储)
flying-bird@flying-bird:~/examples/cpp/echo$ ll
总用量 352
drwxrwxr-x 2 flying-bird flying-bird 4096 5月 10 15:21 ./
drwxrwxr-x 3 flying-bird flying-bird 4096 5月 10 15:19 ../
-rwxrwxr-x 1 flying-bird flying-bird 9464 5月 10 15:19 a.out*
-rw------- 1 flying-bird flying-bird 335872 5月 10 15:21 core
-rw-rw-r-- 1 flying-bird flying-bird 211 5月 10 15:17 hello.c
flying-bird@flying-bird:~/examples/cpp/echo$
此时,生成了core文件,然后就可以用于定位问题了:
flying-bird@flying-bird:~/examples/cpp/echo$ gdb ./a.out core
GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
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 "i686-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/flying-bird/examples/cpp/echo/a.out...done.
[New LWP 4108]
warning: Can't read pathname for load map: 输入/输出错误.
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
#0 0xb761e775 in fwrite () from /lib/i386-linux-gnu/libc.so.6
(gdb) where
#0 0xb761e775 in fwrite () from /lib/i386-linux-gnu/libc.so.6
#1 0x080484ca in main () at ./hello.c:8
(gdb) q
flying-bird@flying-bird:~/examples/cpp/echo$
4. 补充
- 并不是所有的异常都会生成coredump文件,具体请参考《Unix环境高级编程(2nd)》第十章 信号。
- 有时候需要在代码中动态执行ulimit的功能,为此需要调用getrlimit()和setrlimit()函数。具体请参考《Advanced Linux Programming》8.5节。