簡介
當程序運行的過程中異常終止或崩潰,操作系統會將程序當時的內存狀態記錄下來,保存在一個文件中,這種行為就叫做 Core Dump(中文有的翻譯成“核心轉儲”)。
我們可以認為 core dump 是“內存快照”,但實際上,除了內存信息之外,還有些關鍵的程序運行狀態也會同時 dump 下來,例如寄存器信息(包括程序指針、棧指針等)、內存管理信息、其他處理器和操作系統狀態和信息。
core dump 對于編程人員診斷和調試程序是非常有幫助的,因為對于有些程序錯誤是很難重現的,例如指針異常,而 core dump 文件可以再現程序出錯時的情景。
核心轉儲如何產生
上面說當程序運行過程中異常終止或崩潰時會發生 core dump,但還沒說到什么具體的情景程序會發生異常終止或崩潰。
例如我們使用 kill -9 命令殺死一個進程會發生 core dump 嗎?實驗證明是不能的,那么什么情況會產生呢?
Linux 中信號是一種異步事件處理的機制,每種信號都有其對應的默認操作,你可以在 signal(7) 查看 Linux 系統提供的信號以及默認處理。
默認操作主要包括:終止進程(Term)、忽略該信號(Ing)、終止進程并發生核心轉儲(Core)、暫停進程(Stop)、繼續運行被暫停的進程(Cont)。
如果我們信號均是采用默認操作,那么,以下列出的幾種信號,它們在發生時會產生 core dump:
Signal | Action | Comment | 說明 |
---|---|---|---|
SIGABRT | Core | Abort signal from abort | 來自abort的終止信號 |
SIGBUS | Core | Bus error (bad memory access) | 總線錯誤(內存訪問錯誤) |
SIGFPE | Core | Floating-point exception | 浮點異常 |
SIGILL | Core | Illegal Instruction | 非法指令 |
SIGIOT | Core | IOT trap. A synonym for SIGABRT | 物聯網陷阱。SIGABRT 的同義詞 |
SIGQUIT | Core | Quit from keyboard | 從鍵盤退出 |
SIGSEGV | Core | Invalid memory reference | 無效的內存引用 |
SIGSYS | Core | Bad system call (SVr4) | 錯誤的系統調用 |
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 來掛起一個進程或者 Ctrl+C 結束一個進程均不會產生 core dump。
因為前者會向進程發出 SIGTSTP 信號,該信號的默認操作為暫停進程(Stop Process);后者會向進程發出SIGINT 信號,該信號默認操作為終止進程(Terminate Process)。
同樣,上面提到的 kill -9 命令會發出 SIGKILL 命令,該命令默認為終止進程。而如果我們使用 Ctrl+ 來終止一個進程,會向進程發出 SIGQUIT 信號,默認是會產生 core dump 的。
還有其它情景會產生 core dump, 如:程序調用 abort() 函數、訪存錯誤、非法指令等等。
不會生成core dump文件的情況
進程沒有寫入核心文件的權限。(默認情況下,核心文件稱為 core 或 core.pid,其中 pid 是轉儲核心的進程的 ID,并在當前工作目錄中創建。有關命名的詳細信息,請參見下文。)如果出現以下情況,則寫入核心文件失敗:要創建的目錄不可寫,或者如果存在同名文件且不可寫或不是常規文件(例如,它是目錄或符號鏈接)。
一個(可寫的、常規的)文件與用于核心轉儲的同名文件已經存在,但有多個硬鏈接到該文件。
將創建核心轉儲文件的文件系統已滿;或已用完 inode;或以只讀方式安裝;或者用戶已達到文件系統的配額。
要創建核心轉儲文件的目錄不存在。
進程的 RLIMIT_CORE(核心文件大小)或 RLIMIT_FSIZE(文件大小)資源限制設置為零;請參閱 getrlimit(2) 和 shell 的 ulimit 命令的文檔(csh(1) 中的限制)。
進程正在執行的二進制文件沒有啟用讀取權限。(這是一種安全措施,可確保內容不可讀的可執行文件不會產生可能可讀的核心轉儲,其中包含可執行文件的映像。)
進程正在執行一個set-user-ID(set-group-ID)程序,該程序被除進程的真實用戶(組)ID之外的用戶(組)擁有,或者進程正在執行具有文件能力(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,核心轉儲文件將具有 .pid 形式的名稱,除非使用 ls(1) -a 選項,否則此類文件將被隱藏。
(自 Linux 3.7 起)內核配置時沒有配置 CONFIG_COREDUMP 選項。
此外,如果使用了 madvise(2) MADV_DONTDUMP 標志,則核心轉儲可能會排除進程的部分地址空間。
啟用內核轉儲
使用ulimit命令可以查看當前的內核轉儲功能是否生效。-c表示內核轉儲文件的大小限制,0表示內核轉儲無效。
root@firefly:~#ulimit-c 0
使用以下命令即可開啟內核轉儲功能,unlimited表示不限制core文件的大小。
root@firefly:~#ulimit-cunlimited root@firefly:~#ulimit-c unlimited
在服務器上交叉編譯一個測試程序,確認內核轉儲是否生效。
#includeintmain(void) { int*a=NULL; *a=0x1; return0; }
aarch64-linux-gnu-gcc-gtest.c-otest
將生成的可執行程序拷貝到開發板上。
root@firefly:~/code#./test Segmentationfault(coredumped) root@firefly:~/code#ls coretest root@firefly:~/code#filecore core:ELF64-bitLSBcorefile,ARMaarch64,version1(SYSV),SVR4-style,from'./test',realuid:0,effectiveuid:0,realgid:0,effectivegid:0,execfn:'./test',platform:'aarch64'
將core文件拷貝到服務器上,可以使用以下命令解core文件
?mntsudoaarch64-linux-gnu-gdbtestcore ..... GNUgdb(Linaro_GDB-2017.05)7.12.1.20170417-git ...... warning:Couldnotloadsharedlibrarysymbolsfor2libraries,e.g./lib/aarch64-linux-gnu/libc.so.6. Usethe"infosharedlibrary"commandtoseethecompletelisting. Doyouneed"setsolib-search-path"or"setsysroot"? Corewasgeneratedby`./test'. ProgramterminatedwithsignalSIGSEGV,Segmentationfault. #00x00000055815836f4inmain()attest.c:6 6*a=0x1; (gdb)l6 1#include2 3intmain(void) 4{ 5int*a=NULL; 6*a=0x1; 7return0; 8} (gdb)
可以看到,在GDB啟動后,已經打印出test.c的第6行收到了SIGSEGV信號,產生了段錯誤。使用list命令可以查看附近的源代碼。
在專用目錄生成內核轉儲
core文件默認會在當前目錄生成,大多數時候,我們希望固定core文件的生成位置。
內核轉儲保存位置可以通過sysctl變量kernel.core_pattern設置。例如,在/etc/sysctl.conf中做如下設置。
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
在該狀態下執行test測試程序,就會在/root/core/下生成內核轉儲文件。
root@firefly:~/mnt#./test Segmentationfault(coredumped) root@firefly:~/mnt#ls/root/core/ 1664718591-test-2699-18446744073709551615.core
kernel.core_pattern 中可以設置的格式符如下
格式符 | 說明 |
---|---|
%% | % 字符本身 |
%p | 被轉儲進程的進程 ID(PID) |
%u | 被轉儲進程的真實用戶 ID(real UID) |
%g | 被轉儲進程的真實組 ID(real GID) |
%s | 引發轉儲的信號編號 |
%t | 轉儲時刻(從 1970/1/1 0:00 開始的秒數) |
%h | 主機名(同 uname(2) 返回的 nodename) |
%e | 可執行文件名 |
%c | 轉儲文件的大小上限(內核版本 2.6.24 后可用) |
壓縮轉儲文件
kernel.core_pattern也支持管道,可以在kernel.core_pattern 后加入管道符自動壓縮內核轉儲文件。
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內容如下
#!/bin/sh execgzip->/root/core/$1-$2-$3-$4.core.gz
加上可執行權限
chmod777/usr/local/sbin/core_helper
這樣,發生內核轉儲時,就會在/root/core下生成壓縮的轉儲文件。
root@firefly:~/mnt#./test Segmentationfault(coredumped) root@firefly:~/mnt#ls/root/core/ 1664720072-test-2723-18446744073709551615.core.gz root@firefly:~/mnt#
啟用整個系統的內核轉儲功能
在終端通過命令行只是臨時修改,重啟后無效 ,要想永久修改有三種方式:
在/etc/rc.local 中增加一行 ulimit -c unlimited
在/etc/security/limits.conf最后增加如下兩行記錄:
@rootsoftcoreunlimited @roothardcoreunlimited
利用內核轉儲掩碼排除共享內存
大型應用程序,通常會跑多個進程。如果所有進程的共享內存全部轉存儲的話,會對磁盤造成壓力,轉儲過程也會加重系統的負擔,甚至會由于轉儲時間過長導致服務停止時間過長。
由于共享內存的進程中,共享內存的內容是相同的,所以可以只在某個進程中轉儲共享內存,無需全部轉儲。
bit 0轉儲匿名私有映射。 bit 1 轉儲匿名共享映射。 bit 2 轉儲文件支持的私有映射。 bit 3 轉儲文件支持的共享映射。 bit 4(自 Linux 2.6.24 起)轉儲 ELF 標頭。 bit 5(自 Linux 2.6.28 起)轉儲私有大頁面。 bit 6 (自 Linux 2.6.28)轉儲共享大頁面。 bit 7(自 Linux 4.4 起)轉儲私有 DAX 頁面。 bit 8(自 Linux 4.4 起)轉儲共享 DAX 頁面。
通過coredump_filter的內容可以查看設置情況
cat/proc//coredump_filter
如果要跳過所有共享內存區域,應將掩碼值設置為1.
審核編輯:湯梓紅
-
寄存器
+關注
關注
31文章
5363瀏覽量
121155 -
內核
+關注
關注
3文章
1382瀏覽量
40421 -
Linux
+關注
關注
87文章
11345瀏覽量
210385
原文標題:內核轉儲的設置
文章出處:【微信號:嵌入式與Linux那些事,微信公眾號:嵌入式與Linux那些事】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論