在linux中,Core是內存的意思。當程序運行過程中檢測到異常程序異常退出時, 系統把程序當前的內存狀況存儲在一個core文件中, 叫core dumped,也就信息轉儲;操作系統檢測到當前進程異常時將通過信號的方式通知目標進程相應的錯誤信息,常見的信號有SIGSEGV、SIGBUS等,默認情況下進程接收到相應的信號都有相應的處理機制。
本教程操作環境:linux7.3系統、Dell G3電腦。
在Linux下開發中,我們經常聽到程序員說我的程序core掉了,通常出現這類的問題是低級bug中的內存訪問越界、使用空指針、堆棧溢出等情況。使程序運行過程中異常退出或者終止,滿足這些條件就會產生core的文件。
為什么會發生Coredump
Core就是內存的意思,這個詞源自很早以前制造內存的材料,一直延用到現在,當程序運行過程中檢測到異常程序異常退出時, 系統把程序當前的內存狀況存儲在一個core文件中, 叫core dumped,也就信息轉儲,操作系統檢測到當前進程異常時將通過信號的方式通知目標進程相應的錯誤信息,常見的信號有SIGSEGV,SIGBUS等,默認情況下進程接收到相應的信號都有相應的處理機制。
以Linux為例,Action則對應信號的處理方式,紅色框標注為常見信號
在此之前最好先了解下進程的內存布局, Unix與Linux系統的進程空間布局會稍微有點不同,內核空間會比Linux小,特別是內核與用戶進程采用分離的地址空間模式,這里以Linux為例:
coredump文件的存儲位置
我們知道在Linux系統中,如果進程崩潰了,系統內核會捕獲到進程崩潰信息,然后將進程的coredump ?信息寫入到文件中,這個文件名默認是core ? 。存儲位置與對應的可執行程序在同一目錄下,文件名是core,大家可以通過下面的命令看到core文件的存在位置:

Core_pattern的格式:
%p ? 轉儲過程的PID
%u ?(數字)轉儲進程的實際UID
%G ?(數字)轉儲過程的實際GID
%s ?引起轉儲的信號數
%t ? 轉儲時間,表示為自1970年1月1日00:00:00 +0000(UTC)以來的秒數
%H ?主機名(與uname(2)返回的節點名相同)
%e ?可執行文件名(無路徑前綴)
%E ?可執行文件的路徑名,用斜杠(’/’)替換為感嘆號(’!’)。
%C ?崩潰過程的核心文件大小軟資源限制(自Linux 2.6.24開始)
下面的程序可用于演示/ proc / sys / kernel / core_pattern文件中管道語法的用法。
#include?<sys> #include?<fcntl.h> #include?<limits.h> #include?<stdio.h> #include?<stdlib.h> #include?<unistd.h> #define?BUF_SIZE?1024 int?main(int?argc,?char?*argv[]) { ????int?tot,?j; ????ssize_t?nread; ????char?buf[BUF_SIZE]; ????FILE?*fp; ????char?cwd[PATH_MAX]; ???/*?屬性的當前工作目錄崩潰的過程*/ ????snprintf(cwd,?PATH_MAX,?"/proc/%s/cwd",?argv[1]); ????chdir(cwd); ???/*?將輸出寫到該目錄下的文件"core.info"?*/ ????fp?=?fopen("core.info",?"w+"); if?(fp?==?NULL) { exit(EXIT_FAILURE); } ???fprintf(fp,?"argc=%dn",?argc); ????for?(j?=?0;?j?n",?j,?argv[j]); } ???/*?計算標準輸入(核心轉儲)中的字節數*/ ????tot?=?0; ????while?((nread?=?read(STDIN_FILENO,?buf,?BUF_SIZE))?>?0) { ????????tot?+=?nread; } ????fprintf(fp,?"Total?bytes?in?core?dump:?%dn",?tot); ???return?0; }</unistd.h></stdlib.h></stdio.h></limits.h></fcntl.h></sys>
注意一下: ?這里是指在進程當前工作目錄的下創建。通常與程序在相同的路徑下。但如果程序中調用了chdir函數,則有可能改變了當前工作目錄。這時core文件創建在chdir指定的路徑下。有好多程序崩潰了,我們卻找不到core文件放在什么位置。和chdir函數就有關系。當然程序崩潰了不一定都產生 ?core文件。
下面通過的命令可以更改coredump文件的存儲位置,如下:
echo?“|$PWD/core_pattern_pipe_test?%p?UID=%u?GID=%g?sig=%s”?>? /proc/sys/kernel/core_pattern
cat /proc/sys/kernel/core_pattern 查看路徑已經變為如下:

下面帶大家配置永久的core。只要出現內存訪問越界、使用空指針、堆棧溢出等情況,都可以在這個目錄下查看。
配置 core
1、首先在根目錄下建立一個儲存coredump文件的文件夾,命令如下:
mkdir?/corefile
2、設置產生coredump文件的大小,命令如下:
ulimit?-c?unlimited
3、 執行以下兩條命令:
echo?“1”?>?/proc/sys/kernel/core_uses_pid???????//將1寫入到該文件里 echo?“/corefile/core-%e-%p-%t”?>?/proc/sys/kernel/core_pattern
將coredump產生的格式制定好寫入core_pattern文件,這樣當coredump產生時會直接以這種格式存入到根目錄下的文件夾corefile中。
4、修改配置文件/etc/profile
vim?/etc/profile
添加 ulimit -S -c unlimited > /dev/null 2>&1
執行命令生效該文件

5、 在配置文件/etc/rc.local中最后面添加信息(機器重啟時會自動加載該命令):添加命令:
rm?-rf?/corefile/*
機器重啟時清空該文件夾,由于產生的coredump文件很大,若不清空的話時間長了會將硬盤占滿;
再執行以下兩條命令:
echo?“1”?>?/proc/sys/kernel/core_uses_pid echo?“/corefile/core-%e-%p-%t”?>?/proc/sys/kernel/core_pattern
測試
下面寫個例子測試一下是否配置好了corefile文件
#include
編譯運行,注意這里需要-g選項編譯。

進入前面創建的corefile文件夾:

出現core文件表示完成coredump配置。可以用通過readelf命令進行判斷是否是core文件:
運行gdb閱讀core文件,命令為“gdb 程序 對應coredump文件”,這時就進入gdb的提示符“(gdb)”。
從紅色方框截圖可以看到,程序中止是因為信號11。
下面可以通過bt(backtrace)命令(或者where)可以看到函數的調用棧情況:

即程序執行到test.cpp的第6行是出現段錯誤。原因是指向了空指針。
總結
造成程序coredump的原因有很多,這里總結一下,主要是內存訪問越界、使用線程不安全的函數、使用空指針、堆棧溢出等等。
這里要說一下,gdb調試coredump,大部分時候還是只能從core文件找出core的直觀原因,但是更根本的原因一般還是需要結合代碼一起分析當時進程的運行上下文場景,才能推測出程序代碼問題所在。
相關推薦:《Linux視頻教程》