Core Dump Usage - 内核转存储使用

AI 摘要: 本文介绍了应用程序在收到某些信号时会导致进程终止并生成核心转储文件(Coredump)的概念。核心转储文件是进程终止时内存的快照,可以被调试工具用于分析进程终止原因。文章还提到了一些导致生成Coredump的信号和处理脚本编译的示例。此外,文章还介绍了使用Coredump进行内存泄露和异常终止问题分析的场景。

1. 概述

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

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

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

1.1. 导致生成 Coredump 的信号

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
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可见),可以通过下述参数修改:

1
2
3
4
5
6
7
8
9
%%  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,配置内容:

1
2
3
4
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。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[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 文件命名格式

1
2
// 基于常规名(按执行文件、进程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 命名配置

1
2
3
4
// 以管道符号开头
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 文件导致)