GDB除錯core檔案樣例(如何定位Segment fault)
core dump又叫核心轉儲, 當程式執行過程中發生異常, 程式異常退出時, 由作業系統把程式當前的記憶體狀況儲存在一個core檔案中, 叫core dump. (linux中如果記憶體越界會收到SIGSEGV訊號,然後就會core dump)
在程式執行的過程中,有的時候我們會遇到Segment fault(段錯誤)這樣的錯誤。這種看起來比較困難,因為沒有任何的棧、trace資訊輸出。該種類型的錯誤往往與指標操作相關。往往可以通過這樣的方式進行定位。
一 造成segment fault,產生core dump的可能原因
1.記憶體訪問越界
a) 由於使用錯誤的下標,導致陣列訪問越界
b) 搜尋字串時,依靠字串結束符來判斷字串是否結束,但是字串沒有正常的使用結束符
c) 使用strcpy, strcat, sprintf, strcmp, strcasecmp等字串操作函式,將目標字串讀/寫爆。應該使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函式防止讀寫越界。
2 多執行緒程式使用了執行緒不安全的函式。
3 多執行緒讀寫的資料未加鎖保護。對於會被多個執行緒同時訪問的全域性資料,應該注意加鎖保護,否則很容易造成core dump
4 非法指標
a) 使用空指標
b) 隨意使用指標轉換。一個指向一段記憶體的指標,除非確定這段記憶體原先就分配為某種結構或型別,或者這種結構或型別的陣列,否則不要將它轉換為這種結構或型別的指標,而應該將這段記憶體拷貝到一個這種結構或型別中,再訪問這個結構或型別。這是因為如果這段記憶體的開始地址不是按照這種結構或型別對齊的,那麼訪問它時就很容易因為bus error而core dump.
5 堆疊溢位.不要使用大的區域性變數(因為區域性變數都分配在棧上),這樣容易造成堆疊溢位,破壞系統的棧和堆結構,導致出現莫名其妙的錯誤。
二 配置作業系統使其產生core檔案
首先通過ulimit命令檢視一下系統是否配置支援了dump core的功能。通過ulimit -c或ulimit -a,可以檢視core file大小的配置情況,如果為0,則表示系統關閉了dump core。可以通過ulimit -c unlimited來開啟。若發生了段錯誤,但沒有core dump,是由於系統禁止core檔案的生成。
解決方法:$ulimit -c unlimited (只對當前shell程序有效)或在~/.bashrc
# ulimit -c
0
$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
三 用gdb檢視core檔案
發生core dump之後, 用gdb進行檢視core檔案的內容, 以定位檔案中引發core dump的行.
gdb [exec file] [core file]
如: gdb ./test test.core
四 樣例
1. 空指標
樣例:
#include <stdio.h>
int main(void)
{
printf("hello world! dump core for set value to NULL pointer/n");
*(char *)0 = 0;
return 0;
}
# gcc -g test.c -o test
# ./test
hello world! dump core for set value to NULL pointer
Segmentation fault
/× Get segmentation fault, but there is no core dump. The reason is that the system configure core file size to zero ×/
# ls
test test.c
/* Set core file size to unlimited */
# ulimit -c unlimited
# ./test
hello world! dump core for set value to NULL pointer
Segmentation fault (core dumped)
/* Get core dump after change core file size. */
# ls
core.5581 test test.c
/* gdb to debug core dump */
# gdb test core.5581GNU gdb Red Hat Linux (6.3.0.0-1.132.EL4rh)Copyright 2004 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you arewelcome to change it and/or distribute copies of it under certain conditions.Type "show copying" to see the conditions.There is absolutely no warranty for GDB. Type "show warranty" for details.This GDB was configured as "x86_64-redhat-linux-gnu"...Using host libthread_db library "/lib64/tls/libthread_db.so.1".
Core was generated by `./test'.Program terminated with signal 11, Segmentation fault.Reading symbols from /lib64/tls/libc.so.6...done.Loaded symbols for /lib64/tls/libc.so.6Reading symbols from /lib64/ld-linux-x86-64.so.2...done.Loaded symbols for /lib64/ld-linux-x86-64.so.2#0 0x000000000040048b in main () at test.c:6
warning: Source file is more recent than executable.
6 *(char *)0 = 0;(gdb) bt#0 0x000000000040048b in main () at test.c:6
2. 棧溢位。
有關棧溢位的程式,請參見:一個測試棧大小的小程式
# gcc -g test.c -o test -lpthread
# ls
test test.c
# ./test
...
Segmentation fault (core dumped)
# ls
core.5616 test test.c
# gdb test core.5616GNU gdb Red Hat Linux (6.3.0.0-1.132.EL4rh)Copyright 2004 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you arewelcome to change it and/or distribute copies of it under certain conditions.Type "show copying" to see the conditions.There is absolutely no warranty for GDB. Type "show warranty" for details.This GDB was configured as "x86_64-redhat-linux-gnu"...Using host libthread_db library "/lib64/tls/libthread_db.so.1".
Core was generated by `./test'.Program terminated with signal 11, Segmentation fault.Reading symbols from /lib64/tls/libpthread.so.0...done.Loaded symbols for /lib64/tls/libpthread.so.0Reading symbols from /lib64/tls/libc.so.6...done.Loaded symbols for /lib64/tls/libc.so.6Reading symbols from /lib64/ld-linux-x86-64.so.2...done.Loaded symbols for /lib64/ld-linux-x86-64.so.2#0 0x0000002a957c051e in vfprintf () from /lib64/tls/libc.so.6(gdb) list1314 buffer[0]=i;15 test(s);16 }1718 int main()19 {20 pthread_t p;2122 pthread_create(&p, NULL, &test, NULL);
對於棧溢位的segment fault沒有第一個定位方便,需要分析程式碼才能判斷出原因。