1.coredump介紹及產生原因
什麼是coredump:
程序由於各種異常或者bug導致在運行過程中異常退出或者中止, 此時系統會生成core文件, 其中包含程序運行時的內存,寄存器狀態,堆棧指針,內存管理信息還有各種函數調用堆棧信息等.程序coredump原因:
<1>.內存訪問越界
<2>.多線程程序使用了線程不安全的函數
<3>.多線程讀寫的數據未加鎖保護
<4>.非法指針
<5>.堆棧溢出
2.GDB調試coredump步驟
- 設置coreDump文件大小, 默認是0:
首先在當前會話執行命令:ulimit –c,若爲0,則不會產生對應的coredump,需要進行修改和設置:
ulimit -c 1024(字節)
ulimit -c unlimited (可以產生coredump且不受大小限制) - 程序gcc/g++編譯時加 “-g”參數.
- 經過上述兩步, 再運行程序coredump後, 會在當前目錄生成core.xxx文件.
- 開始調試, 執行命令:gdb [可執行文件] [core.xxx文件]
- 輸入命令: bt或back trace, 查看調用堆棧(會顯示每個調用幀及幀號)
- 輸入命令: f或frame [num], 查看對應堆棧幀
- 輸入命令: args:查看函數參數; locals:查看本地變量
3.GDB斷點調試命令
- gdb [可執行文件] : 開始調試
- run: 重新運行程序
- break/b [fileName] : [lineNum]/[funcName] :設置斷點
- continue/c: 運行至斷點處, 相當於VS中的F5
- next: 過程調試, 相當於VS中的F10
- step: 單步調試, 相當於VS中的F11
- print [variableName]: 查看變量值
- list/l : 顯示當前代碼段
- info break/b: 查看所有斷點
- delete/d [breakNum]: 刪除對應斷點
- clear: 刪除所有斷點
4. GDB調試守護進程
使用GDB調試某個進程,如果該進程fork了子進程,GDB會繼續調試該進程,子進程會不受干擾地運行下去。如果你事先在子進程代碼裏設定了斷點,子進程會收到SIGTRAP信號並終止。那麼該如何調試子進程呢?
上網查了下, 一共有3種方法, 這裏採用attach的方法:
其它方法詳見鏈接
- ps -ef :查看所需調試的子進程號, pidNum
- 運行gdb, 並執行命令:(gdb)attach [pidNum]
附加到該子進程後,一個新的問題是:子進程一直在運行,attach上去後都不知道運行到哪裏了.
一個辦法是,在要調試的子進程初始代碼中,比如main函數開始處,加入一段特殊代碼,使子進程在某個條件成立時便循環睡眠等待,attach到進程後在該代碼段後設上斷點,再把成立的條件取消,使代碼可以繼續執行下去。:
至於這段代碼所採用的條件,看你的偏好了。比如我們可以檢查一個指定的環境變量的值,或者檢查一個特定的文件存不存在。以文件爲例,其形式可以如下:#include <unistd.h>//linux下 access()函數頭文件 void debug_wait(char* fileName) { while(1) { if (!access(fileName, 0))//access檢查文件,存在返回0 睡眠一段時間; else break; } }
當attach到進程後,在該段代碼之後設上斷點,再把該文件刪除就OK了。當然你也可以採用其他的條件或形式,只要這個條件可以設置/檢測即可。
Attach進程方法還是很方便的,它能夠應付各種各樣複雜的進程系統,比如孫子/曾孫進程,比如守護進程(daemon process),唯一需要的就是加入一小段代碼。接下來就可以繼續打斷點調試了
info threads:當前運行線程, 可以使用thread [num] 切換線程
set scheduler-locking off|on, on 可以保證斷點只讓當前線程命中, 默認是off(所有線程都可命中斷點)