您的位置首页>企业动态>

你知道Linux Core Dump是什么?

导读 大家好,我是极客范的本期栏目编辑小友,现在为大家讲解你知道Linux Core Dump是什么?问题。当程序在运行过程中异常终止或崩溃时,操作

大家好,我是极客范的本期栏目编辑小友,现在为大家讲解你知道Linux Core Dump是什么?问题。

当程序在运行过程中异常终止或崩溃时,操作系统会记录程序当时的内存状态,并保存在文件中。这种行为被称为核心转储(有些中文翻译成“核心转储”)。我们可以把核心转储想象成一个“内存快照”,但实际上除了内存信息之外,一些关键的程序运行状态也是同时转储的,比如寄存器信息(包括程序指针、堆栈指针等)。),内存管理信息,其他处理器和操作系统状态和信息。Core dump对于程序员诊断和调试程序非常有帮助,因为很难重现一些程序错误,比如指针异常,而core dump文件可以重现程序出错时的情况。

核心转储名词解释

在半导体被用作计算机存储材料之前,计算机存储器使用磁芯存储器,核心转储中的核心遵循核心存储器的核心表达。图为一个单位的磁芯存储器,来自维基百科。

在《APUE》一书中,作者写了这样一句话:

因为该文件名为docore,所以它显示了这个特性成为Unix系统的一部分有多长时间了。

在这里,核心是早期计算机核心内存中的表达,我们也可以看到Unix系统的Core Dump机制的悠久历史。

转储是指将一个存储介质中的部分内容复制到另一个存储介质,或者打印、显示或其他输出设备。转储的输出是格式化的,一些工具可以用来解析它。

在现代操作系统中,当程序异常终止或崩溃时,使用Core Dump将进程内存的内容复制到磁盘文件中存储,方便程序员调试。

核心转储是如何生成的?

它说程序在运行过程中异常终止或崩溃时会发生核心转储,但没有说程序会异常终止或崩溃的具体情况。例如,当我们用kill -9命令杀死一个进程时,会发生核心转储吗?实验证明不能,那么会发生什么呢?

Linux中的信号是一种异步事件处理机制,每个信号都有其默认操作。你可以在这里查看Linux系统提供的信号和默认处理。默认动作主要包括忽略信号(Ingore)、停止进程(stop)、终止进程(Terminate)、终止并生成核心转储(core)等。如果我们的信号都采用默认操作,那么下面的信号就会被列出来,当它们发生时会产生核心转储:

signalactioncommentsgquitcorexit from keyboadsignillcore非法指令sigabrtcorexabort from aborttsigsegvcoreffective memory references igtrappcoretrace/断点陷阱

当然,并不限于上述信号。这就是为什么我们用Ctrl z挂起一个进程或者Ctrl C结束一个进程而不产生核心转储的原因,因为前者会向进程发送SIGTSTP信号,而这个信号的默认操作是停止进程。后者会向进程发送SIGINT信号,这个信号的默认操作是终止进程。上面提到的kill -9命令会发出SIGKILL命令,默认情况下会终止进程。并且如果我们使用Ctrl \终止一个进程,我们会向该进程发送一个SIGQUIT信号,默认情况下会生成一个核心转储。还有其他会产生核心转储的场景,比如:程序调用abort()函数、内存访问错误、非法指令等等。

这里有两个例子来说明:

比较终端下的Ctrl C和Ctrl \ C:

郭海林@国浩海林3360 ~ $ sleep10 #使用sleep命令休眠10 s^C #使用Ctrl C终止此程序,它不会产生核心dump国海林@国浩海林3360 ~ $ sleep10 \退出(

core dumped) #使用 Ctrl+\ 退出程序, 会产生 core dumpguohailin@guohailin:~$ ls #多出下面一个 core 文件-rw-------  1 guohailin guohailin 335872 10月 22 11:31 sleep.core.21990

小程序产生 core dump

#include int main(){ int *null_ptr = NULL; *null_ptr = 10; //对空指针指向的内存区域写,会发生段错误 return 0;}

#编译执行guohailin@guohailin:~$ ./a.outSegmentaTIon fault (core dumped)guohailin@guohailin:~$ ls #多出下面一个 core 文件-rw------- 1 guohailin guohailin 200704 10月 22 11:35 a.out.core.22070

Linux 下打开 Core Dump

我使用的 Linux 发行版是 Ubuntu 13.04,设置生成 core dump 文件的方法如下:

打开 core dump 功能

在终端中输入命令 ulimit -c ,输出的结果为 0,说明默认是关闭 core dump 的,即当程序异常终止时,也不会生成 core dump 文件。

我们可以使用命令 ulimit -c unlimited 来开启 core dump 功能,并且不限制 core dump 文件的大小; 如果需要限制文件的大小,将 unlimited 改成你想生成 core 文件最大的大小,注意单位为 blocks(KB)。

用上面命令只会对当前的终端环境有效,如果想需要永久生效,可以修改文件 /etc/security/limits.conf文件,关于此文件的设置参看 这里 。增加一行:

# /etc/security/limits.conf##Each line describes a limit for a user in the form:## * soft core unlimited

修改 core 文件保存的路径

默认生成的 core 文件保存在可执行文件所在的目录下,文件名就为 core。

通过修改 /proc/sys/kernel/core_uses_pid 文件可以让生成 core 文件名是否自动加上 pid 号。例如 echo 1 > /proc/sys/kernel/core_uses_pid ,生成的 core 文件名将会变成 core.pid,其中 pid 表示该进程的 PID。

还可以通过修改 /proc/sys/kernel/core_pattern 来控制生成 core 文件保存的位置以及文件名格式。例如可以用 echo"/tmp/corefile-%e-%p-%t"> /proc/sys/kernel/core_pattern 设置生成的 core 文件保存在 “/tmp/corefile” 目录下,文件名格式为 “core-命令名-pid-时间戳”。这里 有更多详细的说明!

使用 gdb 调试 Core 文件

产生了 core 文件,我们该如何使用该 Core 文件进行调试呢?Linux 中可以使用 GDB 来调试 core 文件,步骤如下:

首先,使用 gcc 编译源文件,加上 -g 以增加调试信息;

按照上面打开 core dump 以使程序异常终止时能生成 core 文件;

运行程序,当core dump 之后,使用命令 gdb program core 来查看 core 文件,其中 program 为可执行程序名,core 为生成的 core 文件名。

下面用一个简单的例子来说明:

#include int func(int *p){ int y = *p; return y;}int main(){ int *p = NULL; return func(p);}

编译加上调试信息, 运行之后core dump, 使用 gdb 查看 core 文件.

guohailin@guohailin:~$ gcc core_demo.c -o core_demo -gguohailin@guohailin:~$ ./core_demo SegmentaTIon fault (core dumped)guohailin@guohailin:~$ gdb core_demo core_demo.core.24816...Core was generated by './core_demo'.Program terminated with signal 11, Segmentation fault.#0 0x080483cd in func (p=0x0) at core_demo.c:55 int y = *p;(gdb) where#0 0x080483cd in func (p=0x0) at core_demo.c:5#1 0x080483ef in main () at core_demo.c:12(gdb) info frameStack level 0, frame at 0xffd590a4: eip = 0x80483cd in func (core_demo.c:5); saved eip 0x80483ef called by frame at 0xffd590c0 source language c. Arglist at 0xffd5909c, args: p=0x0 Locals at 0xffd5909c, Previous frame's sp is 0xffd590a4 Saved registers: ebp at 0xffd5909c, eip at 0xffd590a0(gdb)

从上面可以看出,我们可以还原 core_demo 执行时的场景,并使用 where 可以查看当前程序调用函数栈帧, 还可以使用 gdb 中的命令查看寄存器,变量等信息.

 

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。