Core dump 分析

本文参考互联网文

Core,又称之为Core Dump文件,是Unix/Linux操作系统的一种机制,对于线上服务而言,Core令人闻之色变,因为出Core的过程意味着服务暂时不能正常响应,需要恢复,并且随着吐Core进程的内存空间越大,此过程可能持续很长一段时间(例如当进程占用60G+以上内存时,完整Core文件需要15分钟才能完全写到磁盘上),这期间产生的流量损失,不可估量。

凡事皆有两面性,OS在出Core的同时,虽然会终止掉当前进程,但是也会保留下第一手的现场数据,OS仿佛是一架被按下快门的相机,而照片就是产出的Core文件。

Core文件里面含有当进程被终止时内存、CPU寄存器等信息,可以供后续开发人员进行调试。

关于Core产生的原因很多,比如过去一些Unix的版本不支持现代Linux上这种GDB直接附着到进程上进行调试的机制,需要先向进程发送终止信号,然后用工具阅读core文件。在Linux上,我们就可以使用kill向一个指定的进程发送信号,

man 7 signal

以下信号将产生Core文件。

       Core   Default action is to terminate the process and dump core (see core(5)).

       First the signals described in the original POSIX.1-1990 standard.

       Signal     Value     Action   Comment

       ----------------------------------------------------------------------

       SIGQUIT       3       Core    Quit from keyboard

       SIGILL        4       Core    Illegal Instruction

       SIGABRT       6       Core    Abort signal from abort(3)

       SIGFPE        8       Core    Floating point exception

       SIGSEGV      11       Core    Invalid memory reference

       Next the signals not in the POSIX.1-1990 standard but described in SUSv2 and POSIX.1-2001.

       Signal       Value     Action   Comment

       --------------------------------------------------------------------

       SIGBUS      10,7,10     Core    Bus error (bad memory access)

       SIGSYS      12,-,12     Core    Bad argument to routine (SVr4)

       SIGTRAP        5        Core    Trace/breakpoint trap

       SIGXCPU     24,24,30    Core    CPU time limit exceeded (4.2BSD)

       SIGXFSZ     25,25,31    Core    File size limit exceeded (4.2BSD)

       Next various other signals.

       Signal       Value     Action   Comment

       --------------------------------------------------------------------

       SIGIOT         6        Core    IOT trap. A synonym for SIGABRT

或者使用gcore命令来使其主动出Core并退出。

[root@digoal sysctl]# gcore

usage:  gcore [-o filename] pid

如果从浅层次的原因上来讲,出Core意味着当前进程存在BUG,需要程序员修复。从深层次的原因上讲,是当前进程触犯了某些OS层级的保护机制,逼迫OS向当前进程发送诸如SIGSEGV(即signal 11)之类的信号, 例如访问空指针或数组越界出Core,实际上是触犯了OS的内存管理,访问了非当前进程的内存空间,OS需要通过出Core来进行警示,这就好像一个人身体内存在病毒,免疫系统就会通过发热来警示,并导致人体发烧是一个道理(有意思的是,并不是每次数组越界都会出Core,这和OS的内存管理中虚拟页面分配大小和边界有关,即使不出Core,也很有可能读到脏数据,引起后续程序行为紊乱,这是一种很难追查的BUG)。

说了这些,似乎感觉Core很强势,让人感觉缺乏控制力,其实不然。

控制Core产生的行为和方式,有两个途径:

1.修改/proc/sys/kernel/core_pattern文件(或者/etc/sysctl.conf),此文件用于控制Core文件产生的文件名,默认情况下,此文件内容只有一行内容:“core”,此文件支持定制,一般使用%配合不同的字符,这里罗列几种:

%p  出Core进程的PID

%u  出Core进程的UID

%s  造成Core的signal号

%t  出Core的时间,从1970-01-0100:00:00开始的秒数

%e  出Core进程对应的可执行文件名

所有的规则请参考man 5 core或/usr/share/doc/kernel-doc-2.6.32/Documentation/sysctl/kernel.txt

           %%  a single % character

           %c  core file size soft resource limit of crashing process (since Linux 2.6.24)

           %d  dump mode—same as value returned by prctl(2) PR_GET_DUMPABLE (since Linux 3.7)

           %e  executable filename (without path prefix)

           %E  pathname of executable, with slashes ('/') replaced by exclamation marks ('!') (since Linux 3.0).

           %g  (numeric) real GID of dumped process

           %h  hostname (same as nodename returned by uname(2))

           %p  PID of dumped process, as seen in the PID namespace in which the process resides

           %P  PID of dumped process, as seen in the initial PID namespace (since Linux 3.12)

           %s  number of signal causing dump

           %t  time of dump, expressed as seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC)

           %u  (numeric) real UID of dumped process

==============================================================

core_pattern:

core_pattern is used to specify a core dumpfile pattern name.

. max length 128 characters; default value is "core"

. core_pattern is used as a pattern template for the output filename;

  certain string patterns (beginning with '%') are substituted with

  their actual values.

. backward compatibility with core_uses_pid:

        If core_pattern does not include "%p" (default does not)

        and core_uses_pid is set, then .PID will be appended to

        the filename.

. corename format specifiers:

        %<NUL>  '%' is dropped

        %%      output one '%'

        %p      pid

        %u      uid

        %g      gid

        %s      signal number

        %t      UNIX time of dump

        %h      hostname

        %e      executable filename (may be shortened)

        %E      executable path

        %<OTHER> both are dropped

. If the first character of the pattern is a '|', the kernel will treat

  the rest of the pattern as a command to run.  The core dump will be

  written to the standard input of that program instead of to a file.

例子:

[root@digoal ~]# sysctl -a|grep core

kernel.core_uses_pid = 1

kernel.core_pattern = |/usr/libexec/abrt-hook-ccpp %s %c %p %u %g %t e

kernel.core_pipe_limit = 4

[root@digoal ~]# /usr/libexec/abrt-hook-ccpp --help

Usage: /usr/libexec/abrt-hook-ccpp SIGNO CORE_SIZE_LIMIT PID UID GID TIME BINARY_NAME [HOSTNAME]

2.ulimit -c 命令,此命令可以显示当前OS对于Core文件大小的限制,如果为0,则表示不允许产生Core文件。

如果想进行修改,可以使用:

ulimit -c n

其中n为数字,表示允许Core文件体积的最大值,单位为Kb,如果想设为无限大,可以执行:

ulimit -c unlimited

产生了Core文件之后,就是如何查看Core文件,并确定问题所在,进行修复。为此,我们不妨先来看看Core文件的格式,多了解一些Core文件。

首先可以明确一点,Core文件的格式ELF格式,这一点可以通过使用readelf -h命令来证实,如下图:

 

从读出来的ELF头信息可以看到,此文件类型为Core文件,那么readelf是如何得知的呢?可以从下面的数据结构中窥得一二:

 

其中当值为4的时候,表示当前文件为Core文件。如此,整个过程就很清楚了。

了解了这些之后,我们来看看如何阅读Core文件,并从中追查BUG。在Linux下,一般读取Core的命令为:

gdb exec_file core_file

使用GDB,先从可执行文件中读取符号表信息,然后读取Core文件。

如果不与可执行文件搅合在一起可以吗?答案是不行,因为Core文件中没有符号表信息,无法进行调试,可以使用如下命令来验证:

objdump -x core_file | tail

我们看到如下两行信息:

SYMBOL TABLE:

no symbols

表明当前的ELF格式文件中没有符号表信息。

为了解释如何看Core中信息,我们来举一个简单的例子:

#include "stdio.h"

int main(){

int stack_of[100000000];

int b=1;

int* a;

*a=b;

}

这段程序使用gcc -g a.c -o a进行编译,运行后直接会Core掉,使用gdb a core_file查看栈信息,可见其Core在了这行代码:

int stack_of[100000000];

原因很明显,直接在栈上申请如此大的数组,导致栈空间溢出,触犯了OS对于栈空间大小的限制,所以出Core(这里是否出Core还和OS对栈空间的大小配置有关,一般为8M)。但是这里要明确一点,真正出Core的代码不是分配栈空间的int stack_of[100000000], 而是后面这句int b=1, 为何?出Core的一种原因是因为对内存的非法访问,在上面的代码中分配数组stack_of时并未访问它,但是在其后声明变量并赋值,就相当于进行了越界访问,继而出Core。为了解释得更详细些,让我们使用gdb来看一下出Core的地方,使用命令gdb a core_file可见:

 

可知程序出现了段错误"Segmentation fault", 代码是int b=1这句。我们来查看一下当前的栈信息:

 

其中可见指令指针rip指向地址为0x400473, 我们来看下当前的指令是什么:

 

这条movl指令要把立即数1送到0xffffffffe8287bfc(%rbp)这个地址去,其中rbp存储的是帧指针,而0xffffffffe8287bfc很明显是一个负数,结果计算为-400000004。这就可以解释了:其中我们申请的int stack_of[100000000]占用400000000字节,b是int类型,占用4个字节,且栈空间是由高地址向低地址延伸,那么b的栈地址就是0xffffffffe8287bfc(%rbp),也就是$rbp-400000004。当我们尝试访问此地址时:

 

可以看到无法访问此内存地址,这是因为它已经超过了OS允许的范围。

下面我们把程序进行改进:

#include "stdio.h"

int main(){

int* stack_of = malloc(sizeof(int)*100000000);

int b=1;

int* a;

*a=b;

}

使用gcc -O3 -g a.c -o a进行编译,运行后会再次Core掉,使用gdb查看栈信息,请见下图:

 

可见BUG出在第7行,也就是*a=b这句,这时我们尝试打印b的值,却发现符号表中找不到b的信息。为何?原因在于gcc使用了-O3参数,此参数可以对程序进行优化,一个负面效应是优化过程中会舍弃部分局部变量,导致调试时出现困难。在我们的代码中,b声明时即赋值,随后用于为*a赋值。优化后,此变量不再需要,直接为*a赋值为1即可,如果汇编级代码上讲,此优化可以减少一条MOV语句,节省一个寄存器。

此时我们的调试信息已经出现了一些扭曲,为此我们重新编译源程序,去掉-O3参数(这就解释了为何一些大型软件都会有debug版本存在,因为debug是未经优化的版本,包含了完整的符号表信息,易于调试),并重新运行,得到新的core并查看,如下图:

 

这次就比较明显了,b中的值没有问题,有问题的是a,其指向的地址是非法区域,也就是a没有分配内存导致的Core。当然,本例中的问题其实非常明显,几乎一眼就能看出来,但不妨碍它成为一个例子,用来解释在看Core过程中,需要注意的一些问题。

其他例子

5.使用gdb调试core文件。    运行命令:$gdb ./a.out ./core.7369,可看到如下打印:

[michael@localhost core_dump]$ gdb ./a.out ./core.7369 

GNU gdb (GDB) Fedora (7.2-52.fc14)

Copyright (C) 2010 Free Software Foundation, Inc.

License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software: you are free to change and redistribute it.

There is NO WARRANTY, to the extent permitted by law.  Type "show copying"

and "show warranty" for details.

This GDB was configured as "i686-redhat-linux-gnu".

For bug reporting instructions, please see:

<http://www.gnu.org/software/gdb/bugs/>...

Reading symbols from /home/michael/core_dump/a.out...done.

[New Thread 7369]

Missing separate debuginfo for 

Try: yum --disablerepo='*' --enablerepo='*-debuginfo' install /usr/lib/debug/.build-id/c4/1c574f31a203492b9389c783adad6ff1989915

Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.

Loaded symbols for /lib/libc.so.6

Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.

Loaded symbols for /lib/ld-linux.so.2

Core was generated by `./a.out'.

Program terminated with signal 11, Segmentation fault.

#0  0x080483b8 in do_it () at ./test.c:10

10        *p = 'a'; //真正产生段错误的在这里,试图更改地址1的值,此时内核会终止该进程,并且把core文件dump出来

Missing separate debuginfos, use: debuginfo-install glibc-2.13-2.i686

(gdb) 

    运行命令:where,即可看到出现段错误的行数了,如下打印:

(gdb) where

#0  0x080483b8 in do_it () at ./test.c:10

#1  0x0804839f in main () at ./test.c:4

(gdb) 

    在第10行,很容易吧。

[参考]

http://my.oschina.net/michaelyuanyuan/blog/68618

http://blog.csdn.net/_xiao/article/details/22389997

http://blog.csdn.net/_xiao/article/details/23177577

http://www.cnblogs.com/kernel-style/archive/2012/12/26/2833485.html

http://www.bo56.com/%E6%80%8E%E6%A0%B7%E7%94%A8core%E6%96%87%E4%BB%B6%E8%B0%83%E8%AF%95%E4%BD%A0%E7%9A%84linux%E7%A8%8B%E5%BA%8F/

http://baidutech.blog.51cto.com/4114344/904419

man 5 core

man 7 signal

ulimit -a

readelf

gdb

objdump 

/usr/share/doc/kernel-doc-2.6.32/Documentation/sysctl/kernel.txt

==============================================================

core_pattern:

core_pattern is used to specify a core dumpfile pattern name.

. max length 128 characters; default value is "core"

. core_pattern is used as a pattern template for the output filename;

  certain string patterns (beginning with '%') are substituted with

  their actual values.

. backward compatibility with core_uses_pid:

        If core_pattern does not include "%p" (default does not)

        and core_uses_pid is set, then .PID will be appended to

        the filename.

. corename format specifiers:

        %<NUL>  '%' is dropped

        %%      output one '%'

        %p      pid

        %u      uid

        %g      gid

        %s      signal number

        %t      UNIX time of dump

        %h      hostname

        %e      executable filename (may be shortened)

        %E      executable path

        %<OTHER> both are dropped

. If the first character of the pattern is a '|', the kernel will treat

  the rest of the pattern as a command to run.  The core dump will be

  written to the standard input of that program instead of to a file.

==============================================================

core_pipe_limit:

This sysctl is only applicable when core_pattern is configured to pipe core

files to user space helper a (when the first character of core_pattern is a '|',

see above).  When collecting cores via a pipe to an application, it is

occasionally usefull for the collecting application to gather data about the

crashing process from its /proc/pid directory.  In order to do this safely, the

kernel must wait for the collecting process to exit, so as not to remove the

crashing processes proc files prematurely.  This in turn creates the possibility

that a misbehaving userspace collecting process can block the reaping of a

crashed process simply by never exiting.  This sysctl defends against that.  It

defines how many concurrent crashing processes may be piped to user space

applications in parallel.  If this value is exceeded, then those crashing

processes above that value are noted via the kernel log and their cores are

skipped.  0 is a special value, indicating that unlimited processes may be

captured in parallel, but that no waiting will take place (i.e. the collecting

process is not guaranteed access to /proc/<crahing pid>/).  This value defaults

to 0.

==============================================================

core_uses_pid:

The default coredump filename is "core".  By setting

core_uses_pid to 1, the coredump filename becomes core.PID.

If core_pattern does not include "%p" (default does not)

and core_uses_pid is set, then .PID will be appended to

the filename.

时间: 2024-08-04 00:15:00

Core dump 分析的相关文章

gcc的 “-fpack-struct” 编译选项导致程序core dump的分析

感谢网友[nanxiao]的投稿 最近team引入gcov来做代码分析.编译好的程序在Solaris上运行的好好的,结果在Linux上一运行就会产生core dump文件.这篇文章就介绍整个分析过程. 首先用gdb分析core文件,显示是strlen调用出了问题: (gdb) #0 0x00000034e433386f in __strlen_sse42 () from /lib64/libc.so.6 #1 0x000000000053c57a in __gcov_init () #2 0x0

ubuntu-c++有获取core dump文件名的的api吗

问题描述 c++有获取core dump文件名的的api吗 kernel.core_pattern定义了core dump文件格式,如果我想自己生成core文件,又不想解析kernel.core_pattern这个字符串,C++有现成的API用来获取core文件名吗? 解决方案 C++ 没有这样的功能,因为 C++ 使用在什么系统.什么环境都不清楚. 这个只能从具体系统提供的功能来分析. 解决方案二: http://blog.csdn.net/xie1xiao1jun/article/detai

Ora-00494 / Aiowait timeout cause instance crashed.(SYSTEM DUMP分析案例)

报错如下: Wed Oct 21 03:06:22 2015 Thread 1 advanced to log sequence 254206 (LGWR switch)   Current log# 9 seq# 254206 mem# 0: /boss_sysdata/oradata/dtvboss/redo09.log Wed Oct 21 03:17:10 2015 WARNING: aiowait timed out 1 times Wed Oct 21 03:22:11 2015 E

linux中core dump开启使用教程

一.什么是coredump 我们经常听到大家说到程序core掉了,需要定位解决,这里说的大部分是指对应程序由于各种异常或者bug导致在运行过程中异常退出或者中止,并且在满足一定条件下(这里为什么说需要满足一定的条件呢?下面会分析)会产生一个叫做core的文件. 通常情况下,core文件会包含了程序运行时的内存,寄存器状态,堆栈指针,内存管理信息还有各种函数调用堆栈信息等,我们可以理解为是程序工作当前状态存储生成第一个文件,许多的程序出错的时候都会产生一个core文件,通过工具分析这个文件,我们可

gcc编译选项 -fpack-struct 致程序 core dump 原因及解决

最近team引入gcov来做代码分析.编译好的程序在Solaris上运行的好好的,结果在Linux上一运行就会产生core dump文件.这篇文章就介绍整个分析过程. 首先用gdb分析core文件,显示是strlen调用出了问题: (gdb) bt #0  0x00000034e433386f in __strlen_sse42 () from /lib64/libc.so.6 #1  0x000000000053c57a in __gcov_init () #2  0x000000000053

jstack和线程dump分析

jstack和线程dump分析 jstack定义: jstack是java虚拟机自带的一种堆栈跟踪工具. 基本介绍: jstack用于生成java虚拟机当前时刻的线程快照.线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁.死循环.请求外部资源导致的长时间等待等. 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源. 命令格式: jstack

core dump磁盘报警问题排查过程

磁盘报警.分区磁盘容量已经占用超过80%.同一批上线的几台机器都没报警.而且离报警阀值还差很远. 大概的排查步骤如下: 首先,查找导致磁盘报警的大文件 $ find /home/ -type f -size +100M /home/demo/web/demo/api/core.7982 /home/demo/web/demo/api/core.10035 ..................... 此处省略N多行 ..................... 看来是core dump文件过多导致的

php ssh2 so core-Linux下,PHP加载ssh2.so时,报core dump

问题描述 Linux下,PHP加载ssh2.so时,报core dump 在php下扩展安装ssh2已经两天了.一直以为是php没有找到ssh2路径的问题.后来-w了一下,结果报错说找不到libssh2.so,然后我就把libssh2的lib目录添加到LD_LIBRARY_PATH中了. 结果运行php -i时就给直接core掉了.于是我怀疑是不是libssh2的问题. 但是网上只有libssh2这一个版本啊. 我的linux信息: CST 2014 x86_64 GNU/Linux CentO

应用-程序崩溃后,dump分析不到具体原因?

问题描述 程序崩溃后,dump分析不到具体原因? 程序崩溃了,也用windbg抓取了dump文件,但是使用windbg分析后发现找不到问题点. 我用的是c#编写的程序,source code和pdb文件不知道如何挂在windbg上去.请大侠帮忙看下. FAULTING_IP: System_Windows_Forms_ni+3329bb 000007fe`e83829bb 498b03 mov rax,qword ptr [r11] EXCEPTION_RECORD: fffffffffffff