1. 程式人生 > >linux core dump 檔案 gdb分析【轉】

linux core dump 檔案 gdb分析【轉】

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 unlimited (一勞永逸)

# 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

使用gdb 除錯方法,首先要在gcc編譯時加入-g選項。

除錯core檔案,在Linux命令列下:gdb pname corefile。

例如,程式名為controller_tester,core檔案為core.3421,則為:gdb controller_tester core.3421。

這樣進入了gdb core除錯模式。

追蹤產生segmenttation fault的位置及程式碼函式呼叫情況:

gdb>bt

這樣,一般就可以看到出錯的程式碼是哪一句了,還可以打印出相應變數的數值,進行進一步分析。

gdb>print 變數名

之後,就全看各位自己的程式設計功力與經驗了,gdb已經做了很多了。

2. 對於結構複雜的程式,如涉及模板類及複雜的呼叫,gdb得出了出錯位置,似乎這還不夠,這時候要使用更為專業的工具——valgrind。

valgrind是一款專門用作記憶體除錯,記憶體洩露檢測的開源工具軟體,valgrind這個名字取自北歐神話英靈殿的入口,不過,不能不承認,它確實是Linux下做記憶體呼叫分析的神器。一般Linux系統上應該沒有自帶valgrind,需要自行進行下載安裝。

進入下載資料夾,分別執行(需要root許可權,且必須按預設路徑安裝,否則有載入錯誤):

./configure

make

make install

安裝成功後,使用類似如下命令啟動程式:

valgrind --tool=memcheck --leak-check=full --track-origins=yes --leak-resolution=high --show-reachable=yes --log-file=memchecklog ./controller_test

其中,–log-file=memchecklog指記錄日誌檔案,名字為memchecklog;–tool=memcheck和–leak-check=full用於記憶體檢測。

可以得到類似的記錄:

==23735== ==23735== Thread 1: ==23735== Invalid read of size 4 ==23735== at 0x804F327: ResourceHandler<HBMessage>::~ResourceHandler() (ResourceHandler.cpp:48) ==23735== by 0x804FDBE: ConnectionManager<HBMessage>::~ConnectionManager() (ConnectionManager.cpp:74) ==23735== by 0×8057288: MainThread::~MainThread() (MainThread.cpp:73) ==23735== by 0x8077B2F: main (Main.cpp:177) ==23735== Address 0×0 is not stack’d, malloc’d or (recently) free’d ==23735==

可以看到說明為無法訪問Address 0x0,明顯為一處錯誤。

這樣valgrind直接給出了出錯原因以及程式中所有的記憶體呼叫、釋放記錄,非常智慧,在得知錯誤原因的情況下,找出錯誤就效率高多了。

再說一句,valgrind同時給出了程式的Memory Leak情況的報告,給出了new-delete對應情況,所有洩漏點位置給出,這一點在其他工具很難做到,十分好用。