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;
}
編譯、運作:
[email protected]:~/examples/cpp/echo$ gcc -g ./hello.c
[email protected]:~/examples/cpp/echo$ ./a.out
段錯誤 (核心已轉儲)
[email protected]:~/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
[email protected]:~/examples/cpp/echo$
雖然提示已經轉存儲了,但仍然找不到core檔案。為此查詢core大小,并修改:
[email protected]:~/examples/cpp/echo$ ulimit -c
0
[email protected]:~/examples/cpp/echo$ ulimit -c unlimited
[email protected]:~/examples/cpp/echo$ ./a.out
段錯誤 (核心已轉儲)
[email protected]:~/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
[email protected]:~/examples/cpp/echo$
此時,生成了core檔案,然後就可以用于定位問題了:
[email protected]:~/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
[email protected]:~/examples/cpp/echo$
4. 補充
- 并不是所有的異常都會生成coredump檔案,具體請參考《Unix環境進階程式設計(2nd)》第十章 信号。
- 有時候需要在代碼中動态執行ulimit的功能,為此需要調用getrlimit()和setrlimit()函數。具體請參考《Advanced Linux Programming》8.5節。