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 ()