Core Dump Usage - 内核转存储使用

1. 概述

应用程序在收到某些信号(man coreman 7 signal查看)的导致进程终止并生成核心转储文件(Coredump),即包含进程映像的磁盘文件终止时的内存(内存快照)。

这个内存映像快照可以被debugger(GDB)调试工具用于分析进程终止原因,内存映像文件大小可以通过RLIMIT_CORE进行设置;

比如常见的Ctrl+\即(kill -QUIT PID) 或 kill -ABRT PID都会导致CoreDump,相关参考man core

1.1. 导致生成Coredump的信号

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

// SIGFPE信号异常
[root@gearbest-web01-test_10 coredump-test]# sleep 100&
[4] 9040
[root@gearbest-web01-test_10 coredump-test]# kill -8 9040
[4]+  浮点数例外         (core dumped) sleep 100

// SIGILL信号异常
[root@gearbest-web01-test_10 coredump-test]# jobs
[3]+  Running                 sleep 100 &
[root@gearbest-web01-test_10 coredump-test]# kill -4 %3
[3]+  非法指令            (core dumped) sleep 100

1.2. 导致无法启用core dump机制

  • 进程没有写核心文件或目录权限(默认核心文件称为core,并在当前工作目录中创建)
  • 存在相同的文件,但不可写,或者磁盘、inode、只读问题导致无法正常生成core dump
  • 进程的RLIMIT_CORE或者RLIMIT_FSIZE设置为0,见下文(getrlimitulimit)

1.3. 命名 - /proc/sys/kernel/core_pattern

导出的core dump文件名称默认为core(cat /proc/sys/kernel/core_pattern可见),可以通过下述参数修改:

%%  a single % character
%p  PID of dumped process
%u  (numeric) real UID of dumped process
%g  (numeric) real GID of dumped process
%s  number of signal causing dump
%t  time of dump, expressed as seconds since the Epoch (00:00h, 1 Jan 1970, UTC)
%h  hostname (same as nodename returned by uname(2))
%e  executable filename (without path prefix)
%c  core file size soft resource limit of crashing process (since Linux 2.6.24)

ps: linux2.4还可以通过/proc/sys/kernel/core_uses_pid启用修改,默认生产类似core.PID的转存储文件;

1.4. 管道转发core dump文件

从linux2.6.19,若/proc/sys/kernel/core_pattern首个字符是管道符号|,则后续基于程序处理,而非写到磁盘;

1.5. 控制哪些内存映射内容导出到core dump文件

基于特定的pid文件,/proc/PID/coredump_filter,配置内容:

bit 0  Dump anonymous private mappings.
bit 1  Dump anonymous shared mappings.
bit 2  Dump file-backed private mappings.
bit 3  Dump file-backed shared mappings.

coredump_filter的默认值为0x3,这反映了传统的Linux行为,这意味着只转储匿名内存段。

2. 开启CoreDump相关配置

2.1. 检测资源限制问题

ulimit -c,0 表示不產生core dump,所以要先執行ulimit -c unlimited允許產生 core dump。

[root@gearbest-web01-test_10 coredump-test]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 31404
..

// 单次生效
ulimit -c unlimited

2.2. 指定core dump文件命名格式

// 基于常规名(按执行文件、进程ID、收到的信号、导出时间生成coredump)
echo "core.%e.%p.%s.%t" > /proc/sys/kernel/core_pattern

2.3. 可以基于gdb调试和查看生成的coredump文件

#include <stdio.h>
int main() {
    int *ptr = NULL; // NULL pointer.
    *ptr = 100;
    printf("%s", "SW-VERSION=0.1");
    return 0;
}
// 编译
gcc abc.c
// 运行
[root@gearbest-web01-test_10 coredump-test]# ./a.out
段错误 (core dumped)
[New Thread 9285]
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
#0  0x0000000000400506 in ?? ()
"/root/coredump-test/core.a.out.9285.1569493778" is a core file.
Please specify an executable to debug.
...

3. 基于管道转到特定进程处理coredump内容(可忽略)

该处理流程是通过管道转发到特定程序处理后的结果,而非原本的coredump信息,这点需要处理,如果想重现所有内存信息,还是建议存储所有的coredump内存信息内容

3.1. coredump命名配置

// 以管道符号开头
echo '|$PWD/core_pattern_pipe_test %p UID=%u GID=%g sig=%s' > /proc/sys/kernel/core_pattern
// 我这边通过$PWD无法有效生成,可以通过绝对路径指定
echo '|/root/coredump-test/core_pattern_pipe_test %p UID=%u GID=%g sig=%s' > /proc/sys/kernel/core_pattern

3.2. 处理脚本编译

/* core_pattern_pipe_test.c */
#define _GNU_SOURCE
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define BUF_SIZE 1024

int main(int argc, char *argv[]) {
    int tot, j;
    ssize_t nread;
    char buf[BUF_SIZE];
    FILE *fp;
    char cwd[PATH_MAX];

    /* Change our current working directory to that of the
       crashing process */
    snprintf(cwd, PATH_MAX, "/proc/%s/cwd", argv[1]);
    chdir(cwd);

    /* Write output to file "core.info" in that directory */
    fp = fopen("core.info", "w+");
    if (fp == NULL)
        exit(EXIT_FAILURE);

    /* Display command-line arguments given to core_pattern
       pipe program */
    fprintf(fp, "argc=%d\n", argc);
    for (j = 0; j < argc; j++)
        fprintf(fp, "argc[%d]=<%s>\n", j, argv[j]);

    /* Count bytes in standard input (the core dump) */
    tot = 0;
    while ((nread = read(STDIN_FILENO, buf, BUF_SIZE)) > 0)
        tot += nread;
    fprintf(fp, "Total bytes in core dump: %d\n", tot);

    exit(EXIT_SUCCESS);
}

// 编译
cc -o core_pattern_pipe_test core_pattern_pipe_test.c

// 通过Ctrl+\信号退出,产生coredump
[root@gearbest-web01-test_10 coredump-test]# sleep 10
^\退出 (core dumped)

// 查看core.info文件(通过我们的c程序处理脚本生成)
[root@gearbest-web01-test_10 coredump-test]# cat core.info
argc=5
argc[0]=</root/coredump-test/core_pattern_pipe_test>
argc[1]=<1631>
argc[2]=<UID=0>
argc[3]=<GID=0>
argc[4]=<sig=3>
Total bytes in core dump: 319488

4. 应用场景

在执行应用进程,尤其是常驻服务,可能存在内存泄露的引用OOM,但无法知道具体是由于什么问题引起,包括应用内存使用情况,可以考虑采用CoreDump分析问题;

另外一些应用导致异常终止,比较段错误、越界、浮点异常等,若应用没有对应的处理,也会导致问题很难复现,此时可以通过记录coredump来复现故障前的内存快照来进行分析(之前就发现PHP的OOM问题,是由于读取大量Excel文件导致)