coredump是在程序崩潰後,由linux系統自動收集程序的內存信息並保存到文件的一種機制。如下面所示的提示。
造成這個錯誤的原因有很多,在這邊 博文 有細說。
本文主要講coredump的使用
1.打開coredump
默認情況下,coredump是沒有開啓的,通過命令ulimt -a查看
圖中,core file size爲0,
ulimit -c unlimited
上面的命令表示在程序異常時產生core dump文件,並且不對core dump文件的大小進行限制。
這個命令是當前shell有效的,可以修改.bashrc文件,將命令加入。這樣打開shell就可以自動生效了。
2.設置core文件名命名規則
以上的設置完成後,還需要設置coredump的文件命名規則。
默認情況下,coredump在當前目錄下生成一個叫core的文件。如果有多個程序都發生錯誤,這個core文件是不會覆蓋的。(巨坑!),依然保持最舊的那個。爲了解決這個問題,需要設置coredump的文件命名規則。
echo 'core.%e.%p' > /proc/sys/kernel/core_pattern
這樣配置後,產生的core文件中將帶有崩潰的程序名、以及它的進程ID。上面的%e和%p會被替換成程序文件名以及進程ID。
可以在core_pattern模板中使用變量還很多,見下面的列表:
%% 單個%字符
%p 所dump進程的進程ID
%u 所dump進程的實際用戶ID
%g 所dump進程的實際組ID
%s 導致本次core dump的信號
%t core dump的時間 (由1970年1月1日計起的秒數)
%h 主機名
%e 程序文件名
如果在上述文件名中包含目錄分隔符”/“,那麼所生成的core文件將會被放到指定的目錄中。
需要說明的是,在內核中還有一個與coredump相關的設置,就是/proc/sys/kernel/core_uses_pid。如果這個文件的內容被配置成1,那麼即使core_pattern中沒有設置%p,最後生成的core dump文件名仍會加上進程ID。
對所生成的core dump進程分析,需要使用調試工具,例如GDB等。
3、調試coredump文件
調試方式爲: gdb program coredump文件
例如我的可執行文件爲test, 生成的coredump文件爲core.3533,則命令如下:
gdb test core.3533
顯示如下圖所示:
嗯,有的人運氣好,直接就顯示源代碼了,如果你像我一樣,接着用下面的命令
backtrace
打印堆棧信息。
我們看到最接近崩潰的地方在第8行。也就是你熟悉的代碼的那一行。
然後調用命令
frame 8
直接找到源代碼的位置:
調試第二例
在調試一個“進程的demo“的時候,出現了錯誤,如下
diffork: cxa_atexit.c:100: __new_exitfn: Assertion `l != NULL' failed.
parent gloVar =9,var=32769
diffork: cxa_atexit.c:100: __new_exitfn: Assertion `l != NULL' failed.
已放棄 (核心已轉儲)
這種有錯誤提示的,直接搜一下提示。我就是直接搜提示找到原因的。不過我想看看coredump收集了啥,所以又去看了看coredump。
gdb ./diffork ./core.diffork.102448 執行gdb程序
輸出如下,gdb有提示哪裏出錯了,但是因爲raise.c這個系統源碼文件找不到,所以就顯示不出來。只知道在54行。
Program terminated with signal SIGABRT, Aborted.
#0 0x00007fc48c95c428 in __GI_raise (sig=sig@entry=6)
at ../sysdeps/unix/sysv/linux/raise.c:54
54 ../sysdeps/unix/sysv/linux/raise.c: 沒有那個文件或目錄.
打印堆棧,錯誤提示和終端輸出的是一樣的。後來google了下那個錯誤提示,是因爲我vfork的進程沒有正常的exec或exit。改正後,錯誤就沒有了。
(gdb) backtrace
#0 0x00007fc48c95c428 in __GI_raise (sig=sig@entry=6)
at ../sysdeps/unix/sysv/linux/raise.c:54
#1 0x00007fc48c95e02a in __GI_abort () at abort.c:89
#2 0x00007fc48c954bd7 in __assert_fail_base (fmt=<optimized out>,
assertion=assertion@entry=0x7fc48cab3c58 "l != NULL",
file=file@entry=0x7fc48cab3c4b "cxa_atexit.c", line=line@entry=100,
function=function@entry=0x7fc48cab7348 <__PRETTY_FUNCTION__.7638> "__new_exitfn") at assert.c:92
#3 0x00007fc48c954c82 in __GI___assert_fail (
assertion=0x7fc48cab3c58 "l != NULL", file=0x7fc48cab3c4b "cxa_atexit.c",
line=100,
function=0x7fc48cab7348 <__PRETTY_FUNCTION__.7638> "__new_exitfn")
at assert.c:101
#4 0x00007fc48c961228 in __new_exitfn (
listp=listp@entry=0x7fc48cceb5f8 <__exit_funcs>) at cxa_atexit.c:100
#5 0x00007fc48c961299 in __internal_atexit (
listp=0x7fc48cceb5f8 <__exit_funcs>, d=0x0, arg=0x0, func=0x1b)
at cxa_atexit.c:35
#6 __GI___cxa_atexit (func=0x1b, arg=arg@entry=0x0, d=d@entry=0x0)
at cxa_atexit.c:58
#7 0x00007fc48c947793 in __libc_start_main (main=0x400636 <main>, argc=1,
argv=0x7fff101df7c8, init=0x400750 <__libc_csu_init>,
fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fff101df7b8)
---Type <return> to continue, or q <return> to quit---
at ../csu/libc-start.c:221
#8 0x0000000000400569 in _start ()