簡介
當(dāng)程序運行的過程中異常終止或崩潰,操作系統(tǒng)會將程序當(dāng)時的內(nèi)存狀態(tài)記錄下來,保存在一個文件中,這種行為就叫做 Core Dump(中文有的翻譯成“核心轉(zhuǎn)儲”)。
我們可以認(rèn)為 core dump 是“內(nèi)存快照”,但實際上,除了內(nèi)存信息之外,還有些關(guān)鍵的程序運行狀態(tài)也會同時 dump 下來,例如寄存器信息(包括程序指針、棧指針等)、內(nèi)存管理信息、其他處理器和操作系統(tǒng)狀態(tài)和信息。
core dump 對于編程人員診斷和調(diào)試程序是非常有幫助的,因為對于有些程序錯誤是很難重現(xiàn)的,例如指針異常,而 core dump 文件可以再現(xiàn)程序出錯時的情景。
核心轉(zhuǎn)儲如何產(chǎn)生
上面說當(dāng)程序運行過程中異常終止或崩潰時會發(fā)生 core dump,但還沒說到什么具體的情景程序會發(fā)生異常終止或崩潰。
例如我們使用 kill -9 命令殺死一個進(jìn)程會發(fā)生 core dump 嗎?實驗證明是不能的,那么什么情況會產(chǎn)生呢?
Linux 中信號是一種異步事件處理的機制,每種信號都有其對應(yīng)的默認(rèn)操作,你可以在 signal(7) 查看 Linux 系統(tǒng)提供的信號以及默認(rèn)處理。
默認(rèn)操作主要包括:終止進(jìn)程(Term)、忽略該信號(Ing)、終止進(jìn)程并發(fā)生核心轉(zhuǎn)儲(Core)、暫停進(jìn)程(Stop)、繼續(xù)運行被暫停的進(jìn)程(Cont)。
如果我們信號均是采用默認(rèn)操作,那么,以下列出的幾種信號,它們在發(fā)生時會產(chǎn)生 core dump:
Signal | Action | Comment | 說明 |
---|---|---|---|
SIGABRT | Core | Abort signal from abort | 來自abort的終止信號 |
SIGBUS | Core | Bus error (bad memory access) | 總線錯誤(內(nèi)存訪問錯誤) |
SIGFPE | Core | Floating-point exception | 浮點異常 |
SIGILL | Core | Illegal Instruction | 非法指令 |
SIGIOT | Core | IOT trap. A synonym for SIGABRT | 物聯(lián)網(wǎng)陷阱。SIGABRT 的同義詞 |
SIGQUIT | Core | Quit from keyboard | 從鍵盤退出 |
SIGSEGV | Core | Invalid memory reference | 無效的內(nèi)存引用 |
SIGSYS | Core | Bad system call (SVr4) | 錯誤的系統(tǒng)調(diào)用 |
SIGTRAP | Core | Trace/breakpoint trap | 跟蹤/斷點陷阱 |
SIGUNUSED | Core | Synonymous with SIGSYS | SIGSYS 的同義詞 |
SIGXCPU | Core | CPU time limit exceeded (4.2BSD) | 超出 CPU 時間限制 |
SIGXFSZ | Core | File size limit exceeded (4.2BSD) | 超出文件大小限制 |
這就是為什么我們使用 Ctrl+z 來掛起一個進(jìn)程或者 Ctrl+C 結(jié)束一個進(jìn)程均不會產(chǎn)生 core dump。
因為前者會向進(jìn)程發(fā)出 SIGTSTP 信號,該信號的默認(rèn)操作為暫停進(jìn)程(Stop Process);后者會向進(jìn)程發(fā)出SIGINT 信號,該信號默認(rèn)操作為終止進(jìn)程(Terminate Process)。
同樣,上面提到的 kill -9 命令會發(fā)出 SIGKILL 命令,該命令默認(rèn)為終止進(jìn)程。而如果我們使用 Ctrl+\\ 來終止一個進(jìn)程,會向進(jìn)程發(fā)出 SIGQUIT 信號,默認(rèn)是會產(chǎn)生 core dump 的。
還有其它情景會產(chǎn)生 core dump, 如:程序調(diào)用 abort() 函數(shù)、訪存錯誤、非法指令等等。
不會生成core dump文件的情況
- 進(jìn)程沒有寫入核心文件的權(quán)限。(默認(rèn)情況下,核心文件稱為 core 或 core.pid,其中 pid 是轉(zhuǎn)儲核心的進(jìn)程的 ID,并在當(dāng)前工作目錄中創(chuàng)建。有關(guān)命名的詳細(xì)信息,請參見下文。)如果出現(xiàn)以下情況,則寫入核心文件失敗:要創(chuàng)建的目錄不可寫,或者如果存在同名文件且不可寫或不是常規(guī)文件(例如,它是目錄或符號鏈接)。
- 一個(可寫的、常規(guī)的)文件與用于核心轉(zhuǎn)儲的同名文件已經(jīng)存在,但有多個硬鏈接到該文件。
- 將創(chuàng)建核心轉(zhuǎn)儲文件的文件系統(tǒng)已滿;或已用完 inode;或以只讀方式安裝;或者用戶已達(dá)到文件系統(tǒng)的配額。
- 要創(chuàng)建核心轉(zhuǎn)儲文件的目錄不存在。
- 進(jìn)程的 RLIMIT_CORE(核心文件大小)或 RLIMIT_FSIZE(文件大小)資源限制設(shè)置為零;請參閱 getrlimit(2) 和 shell 的 ulimit 命令的文檔(csh(1) 中的限制)。
- 進(jìn)程正在執(zhí)行的二進(jìn)制文件沒有啟用讀取權(quán)限。(這是一種安全措施,可確保內(nèi)容不可讀的可執(zhí)行文件不會產(chǎn)生可能可讀的核心轉(zhuǎn)儲,其中包含可執(zhí)行文件的映像。)
- 進(jìn)程正在執(zhí)行一個set-user-ID(set-group-ID)程序,該程序被除進(jìn)程的真實用戶(組)ID之外的用戶(組)擁有,或者進(jìn)程正在執(zhí)行具有文件能力(capabilities)的程序(請參閱 capabilities(7))。(但是,請參閱 prctl(2) PR_SET_DUMPABLE 操作的說明,以及 proc(5) 中 /proc/sys/fs/suid_dumpable 文件的說明)
- /proc/sys/kernel/core_pattern 為空且 /proc/sys/kernel/core_uses_pid 包含值 0。請注意,如果 /proc/sys/kernel/core_pattern 為空且 /proc/ sys/kernel/core_uses_pid 包含值 1,核心轉(zhuǎn)儲文件將具有 .pid 形式的名稱,除非使用 ls(1) -a 選項,否則此類文件將被隱藏。
- (自 Linux 3.7 起)內(nèi)核配置時沒有配置 CONFIG_COREDUMP 選項。
此外,如果使用了 madvise(2) MADV_DONTDUMP 標(biāo)志,則核心轉(zhuǎn)儲可能會排除進(jìn)程的部分地址空間。
啟用內(nèi)核轉(zhuǎn)儲
使用ulimit命令可以查看當(dāng)前的內(nèi)核轉(zhuǎn)儲功能是否生效。-c表示內(nèi)核轉(zhuǎn)儲文件的大小限制,0表示內(nèi)核轉(zhuǎn)儲無效。
root@firefly:~# ulimit -c
0
使用以下命令即可開啟內(nèi)核轉(zhuǎn)儲功能,unlimited表示不限制core文件的大小。
root@firefly:~# ulimit -c unlimited
root@firefly:~# ulimit -c
unlimited
在服務(wù)器上交叉編譯一個測試程序,確認(rèn)內(nèi)核轉(zhuǎn)儲是否生效。
#include
int main(void)
{
int *a=NULL;
*a=0x1;
return 0;
}
aarch64-linux-gnu-gcc -g test.c -o test
將生成的可執(zhí)行程序拷貝到開發(fā)板上。
root@firefly:~/code# ./test
Segmentation fault (core dumped)
root@firefly:~/code# ls
core test
root@firefly:~/code# file core
core: ELF 64-bit LSB core file, ARM aarch64, version 1 (SYSV), SVR4-style, from './test', real uid: 0, effective uid: 0, real gid: 0, effective gid: 0, execfn: './test', platform: 'aarch64'
將core文件拷貝到服務(wù)器上,可以使用以下命令解core文件
? mnt sudo aarch64-linux-gnu-gdb test core
.....
GNU gdb (Linaro_GDB-2017.05) 7.12.1.20170417-git
......
warning: Could not load shared library symbols for 2 libraries, e.g. /lib/aarch64-linux-gnu/libc.so.6.
Use the "info sharedlibrary" command to see the complete listing.
Do you need "set solib-search-path" or "set sysroot"?
Core was generated by `./test'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00000055815836f4 in main () at test.c:6
6 *a=0x1;
(gdb) l 6
1 #include h>
2
3 int main(void)
4 {
5 int *a=NULL;
6 *a=0x1;
7 return 0;
8 }
(gdb)
可以看到,在GDB啟動后,已經(jīng)打印出test.c的第6行收到了SIGSEGV信號,產(chǎn)生了段錯誤。使用list命令可以查看附近的源代碼。
在專用目錄生成內(nèi)核轉(zhuǎn)儲
core文件默認(rèn)會在當(dāng)前目錄生成,大多數(shù)時候,我們希望固定core文件的生成位置。
內(nèi)核轉(zhuǎn)儲保存位置可以通過sysctl變量kernel.core_pattern設(shè)置。例如,在/etc/sysctl.conf中做如下設(shè)置。
root@firefly:~# vim /etc/sysctl.conf
#在末尾追加以下兩行
kernel.core_pattern = /root/core/%t-%e-%p-%c.core
kernel.core_uses_pid = 0
#使配置生效
root@firefly:~# sysctl -p
kernel.core_pattern = /root/core/%t-%e-%p-%c.core
kernel.core_uses_pid = 0
在該狀態(tài)下執(zhí)行test測試程序,就會在/root/core/下生成內(nèi)核轉(zhuǎn)儲文件。
root@firefly:~/mnt# ./test
Segmentation fault (core dumped)
root@firefly:~/mnt# ls /root/core/
1664718591-test-2699-18446744073709551615.core
kernel.core_pattern 中可以設(shè)置的格式符如下
格式符 | 說明 |
---|---|
%% | % 字符本身 |
%p | 被轉(zhuǎn)儲進(jìn)程的進(jìn)程 ID(PID) |
%u | 被轉(zhuǎn)儲進(jìn)程的真實用戶 ID(real UID) |
%g | 被轉(zhuǎn)儲進(jìn)程的真實組 ID(real GID) |
%s | 引發(fā)轉(zhuǎn)儲的信號編號 |
%t | 轉(zhuǎn)儲時刻(從 1970/1/1 0:00 開始的秒數(shù)) |
%h | 主機名(同 uname(2) 返回的 nodename) |
%e | 可執(zhí)行文件名 |
%c | 轉(zhuǎn)儲文件的大小上限(內(nèi)核版本 2.6.24 后可用) |
壓縮轉(zhuǎn)儲文件
kernel.core_pattern也支持管道,可以在kernel.core_pattern 后加入管道符自動壓縮內(nèi)核轉(zhuǎn)儲文件。
vim /etc/sysctl.conf
kernel.core_pattern = |/usr/local/sbin/core_helper %t %e %p %c
kernel.core_uses_pid = 0
sysctl -p
core_helper內(nèi)容如下
#!/bin/sh
exec gzip -> /root/core/$1-$2-$3-$4.core.gz
加上可執(zhí)行權(quán)限
chmod 777 /usr/local/sbin/core_helper
這樣,發(fā)生內(nèi)核轉(zhuǎn)儲時,就會在/root/core下生成壓縮的轉(zhuǎn)儲文件。
root@firefly:~/mnt# ./test
Segmentation fault (core dumped)
root@firefly:~/mnt# ls /root/core/
1664720072-test-2723-18446744073709551615.core.gz
root@firefly:~/mnt#
啟用整個系統(tǒng)的內(nèi)核轉(zhuǎn)儲功能
在終端通過命令行只是臨時修改,重啟后無效 ,要想永久修改有三種方式:
- 在/etc/rc.local 中增加一行 ulimit -c unlimited
- 在/etc/security/limits.conf最后增加如下兩行記錄:
@root soft core unlimited
@root hard core unlimited
利用內(nèi)核轉(zhuǎn)儲掩碼排除共享內(nèi)存
大型應(yīng)用程序,通常會跑多個進(jìn)程。如果所有進(jìn)程的共享內(nèi)存全部轉(zhuǎn)存儲的話,會對磁盤造成壓力,轉(zhuǎn)儲過程也會加重系統(tǒng)的負(fù)擔(dān),甚至?xí)捎谵D(zhuǎn)儲時間過長導(dǎo)致服務(wù)停止時間過長。
由于共享內(nèi)存的進(jìn)程中,共享內(nèi)存的內(nèi)容是相同的,所以可以只在某個進(jìn)程中轉(zhuǎn)儲共享內(nèi)存,無需全部轉(zhuǎn)儲。
bit 0 轉(zhuǎn)儲匿名私有映射。
bit 1 轉(zhuǎn)儲匿名共享映射。
bit 2 轉(zhuǎn)儲文件支持的私有映射。
bit 3 轉(zhuǎn)儲文件支持的共享映射。
bit 4(自 Linux 2.6.24 起)轉(zhuǎn)儲 ELF 標(biāo)頭。
bit 5(自 Linux 2.6.28 起)轉(zhuǎn)儲私有大頁面。
bit 6 (自 Linux 2.6.28) 轉(zhuǎn)儲共享大頁面。
bit 7(自 Linux 4.4 起)轉(zhuǎn)儲私有 DAX 頁面。
bit 8(自 Linux 4.4 起)轉(zhuǎn)儲共享 DAX 頁面。
通過coredump_filter的內(nèi)容可以查看設(shè)置情況
cat /proc//coredump_filter
如果要跳過所有共享內(nèi)存區(qū)域,應(yīng)將掩碼值設(shè)置為1.
-
內(nèi)存
+關(guān)注
關(guān)注
8文章
3111瀏覽量
75017 -
操作系統(tǒng)
+關(guān)注
關(guān)注
37文章
7101瀏覽量
125021 -
程序
+關(guān)注
關(guān)注
117文章
3824瀏覽量
82490
發(fā)布評論請先 登錄
崩潰轉(zhuǎn)儲
怎么在B2902A上通過SCPI設(shè)置自動觸發(fā)和屏幕轉(zhuǎn)儲
怎么從Virtex 6的FPGA中取出BRAM轉(zhuǎn)儲
如何轉(zhuǎn)儲程序4bit程序
MPLABX有字節(jié)字節(jié)的HEX轉(zhuǎn)儲選項嗎?
位文件轉(zhuǎn)儲后合成設(shè)計更改
轉(zhuǎn)儲用于VHDL代碼的saif文件
在FPGA上生成位文件和轉(zhuǎn)儲時無法看到輸出是為什么?
有什么方法可以追溯地將加密標(biāo)志應(yīng)用于現(xiàn)有加密設(shè)備上的核心轉(zhuǎn)儲分區(qū)?
如何轉(zhuǎn)儲QN9021的bin數(shù)據(jù)?
紫金橋?qū)崟r數(shù)據(jù)庫_實時數(shù)據(jù)轉(zhuǎn)儲功能深度剖析

Ubuntu 16.04系統(tǒng)中調(diào)試Apollo項目核心轉(zhuǎn)儲文件的方法
linux內(nèi)核參數(shù)設(shè)置_linux內(nèi)核的功能有哪些

評論