linux coredump 的设置与读取

nxdong October 26, 2022 [linux] #coredump

linux可以在程序崩溃的时候把当时的内存状态保存下来,便于之后的调试。

coredump 信号

linux会为程序设置一些默认的信号处理方法。

根据man signal.7 或者在线文档 可以查看哪些信号可以触发coredump操作。

SignalStandardActionComment
SIGABRTP1990CoreAbort signal from abort(3)
SIGALRMP1990TermTimer signal from alarm(2)
SIGBUSP2001CoreBus error (bad memory access)
SIGCHLDP1990IgnChild stopped or terminated
SIGCLD-IgnA synonym for SIGCHLD
SIGCONTP1990ContContinue if stopped
SIGEMT-TermEmulator trap
SIGFPEP1990CoreFloating-point exception
SIGHUPP1990TermHangup detected on controlling terminalor death of controlling process
SIGILLP1990CoreIllegal Instruction
SIGINFO--Asynonym for SIGPWR
SIGINTP1990TermInterrupt from keyboard
SIGIO-TermI/O now possible (4.2BSD)
SIGIOT-CoreIOT trap. A synonym for SIGABRT
SIGKILLP1990TermKill signal
SIGLOST-TermFile lock lost (unused)
SIGPIPEP1990TermBroken pipe: write to pipe with noreaders; see pipe(7)
SIGPOLLP2001TermPollable event (Sys V); synonym for SIGIO
SIGPROFP2001TermProfiling timer expired
SIGPWR-TermPower failure (System V)
SIGQUITP1990CoreQuit from keyboard
SIGSEGVP1990CoreInvalid memory reference
SIGSTKFLT-TermStack fault on coprocessor (unused)
SIGSTOPP1990StopStop process
SIGTSTPP1990StopStop typed at terminal
SIGSYSP2001CoreBad system call (SVr4); see also seccomp(2)
SIGTERMP1990TermTermination signal
SIGTRAPP2001CoreTrace/breakpoint trap
SIGTTINP1990StopTerminal input for background process
SIGTTOUP1990StopTerminal output for background process
SIGUNUSED-CoreSynonymous with SIGSYS
SIGURGP2001IgnUrgent condition on socket (4.2BSD)
SIGUSR1P1990TermUser-defined signal 1
SIGUSR2P1990TermUser-defined signal 2
SIGVTALRMP2001TermVirtual alarm clock (4.2BSD)
SIGXCPUP2001CoreCPU time limit exceeded (4.2BSD);see setrlimit(2)
SIGXFSZP2001CoreFile size limit exceeded (4.2BSD); see setrlimit(2)
SIGWINCH-IgnWindow resize signal (4.3BSD, Sun)

上个表中ActionCore 的信号,在默认情况下都会触发coredump操作。

开启coredump

查看coredump是否开启:

ulimit -c
# 在我现在的设置中,返回0,表示不会记录coredump文件。

开启不限制大小的coredump:

ulimit -c unlimited

这个设置只会影响当前的终端会话,重新连接就没了。

如果想持久化开启这个设置,需要额外的设置。

echo "ulimit -c unlimited" >> /etc/profile

设置生成coredump文件的名字

查看当前的coredump文件的名字:cat /proc/sys/kernel/core_pattern。 这里我的终端输出是core。 所以在我的实验中,程序异常后产生的coredump文件的名字是core

可以通过在命令行输入man core.5 或者 在线文档 查看一些可以设置的内容。

在其Naming of core dump files 一节中,有以下说明:

标识符说明
%%A single % character.
%cCore file size soft resource limit of crashing process(since Linux 2.6.24).
%dDump mode—same as value returned by prctl(2) PR_GET_DUMPABLE (since Linux 3.7).
%eThe process or thread's comm value, which typically is the same as the executable filename (without path prefix, and truncated to a maximum of 15 characters), but may have been modified to be something different; see the discussion of /proc/[pid]/comm and /proc/[pid]/task/[tid]/comm in proc(5).
%EPathname of executable, with slashes ('/') replaced by exclamation marks ('!') (since Linux 3.0).
%gNumeric real GID of dumped process.
%hHostname (same as nodename returned by uname(2)).
%iTID of thread that triggered core dump, as seen in the PID namespace in which the thread resides (since Linux 3.18).
%ITID of thread that triggered core dump, as seen in the initial PID namespace (since Linux 3.18).
%pPID of dumped process, as seen in the PID namespace in which the process resides.
%PPID of dumped process, as seen in the initial PID namespace (since Linux 3.12).
%sNumber of signal causing dump.
%tTime of dump, expressed as seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).
%uNumeric real UID of dumped process.

文件名也不能超过128字节。

如果我们想得到一个名字为core.进程号.信号.unix时间的coredump文件生成在/tmp/corefile/ (这个文件夹需要提前创建,如果只想在可执行程序所在目录生成,则不需要指定路径)文件夹内。 我们就需要执行echo /tmp/corefile/core.%p.%s.%t > /proc/sys/kernel/core_pattern (执行这个命令需要切到root命令行,sudo还不行)。

这样,发生coredump之后,我们就能得到一个类似/tmp/corefile/core.1803.8.1666772279 的文件(可以看出,这个程序是搞了错误的算术计算,触发了SIGFPE<8> 的信号)。

通过这个方式设置的coredump文件名字重启后会失效。 可以通过设置/etc/sysctl.conf 的方式来持久化设置这个信息。

/etc/sysctl.conf文件的末尾添加如下内容:

kernel.core_pattern=/tmp/corefile/core.%p.%s.%t

并保存退出,执行sysctl -p命令使其生效。

通过cat /proc/sys/kernel/core_pattern 验证设置是否生效。 每个进程也可以通过setrlimitRLIMIT_CORE配置进程级别的core大小。

测试coredump的程序代码

注意,为了方便调试,我们的coredump文件名称中去掉了路径的指定,coredump文件会生成在可执行文件所在的文件夹。 相应的命令:echo core.%p.%s.%t > /proc/sys/kernel/core_pattern

文件coredump_test.c内容如下:

#include <stdio.h>
#include <stdlib.h>

void test_divide_zero()
{
    // 除零会触发SIGFPE 信号
    // 根据man手册,这个信号也会触发Coredump
    int a = 1;
    int b = 0;
    int c = a / b;
}

void test_big_memory()
{
    // 触发异常时,有大量的堆空间。
    int mem_size = 1024 * 1024 * 512; // 512MB
    void *bigmem = malloc(mem_size);
    int a = 1;
    int b = 0;
    int c = a / b;
    free(bigmem);
}

int main(int argc, char const *argv[])
{
    int method_flag = 0;
    if (argc == 2)
    {
        method_flag = atoi(argv[1]);
    }
    else
    {
        printf("Args Help:\n");
        printf("0: divide zero \n");
        printf("1: big heap mem \n");
        exit(0);
    }

    switch (method_flag)
    {
    case 0:
        test_divide_zero();
        break;
    case 1:
        test_big_memory();
        break;

    default:
        printf("Invalid args!\n");
        break;
    }

    return 0;
}

编译:gcc coredump_test.c

运行生成coredump文件:

# 运行分支1
$ ./a.out 0
[1]    5747 floating point exception (core dumped)  ./a.out 0
#生成了coredump文件
$ file core.5747.8.1666782546
core.5747.8.1666782546: ELF 64-bit LSB core file, x86-64, version 1 (SYSV), SVR4-style, from './a.out 0', real uid: 1000, effective uid: 1000, real gid: 1000, effective gid: 1000, execfn: './a.out', platform: 'x86_64'

# 运行分支2
./a.out 1
[1]    5769 floating point exception (core dumped)  ./a.out 1
$ file core.5769.8.1666782549
core.5769.8.1666782549: ELF 64-bit LSB core file, x86-64, version 1 (SYSV), SVR4-style, from './a.out 1', real uid: 1000, effective uid: 1000, real gid: 1000, effective gid: 1000, execfn: './a.out', platform: 'x86_64'

# 查看文件大小
$ ll
-rw-r--r-- 1 sss sss  13K Oct 26 19:12 README.md
-rwxr-xr-x 1 sss sss  16K Oct 26 18:49 a.out
-rw------- 1 sss sss 292K Oct 26 19:09 core.5747.8.1666782546
-rw------- 1 sss sss 513M Oct 26 19:09 core.5769.8.1666782549
-rw-r--r-- 1 sss sss  979 Oct 26 18:49 coredump_test.c

可见,core文件会把程序当前的内存空间也dump出来。

这可能会导致产生巨大的coredump文件。 所以可以对coredump的内容进行一些过滤。

使用coredump文件

coredump文件可以使用gdb加载。

$ gdb ./a.out core.5747.8.1666782546
xxxxx
--Type <RET> for more, q to quit, c to continue without paging--
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...
(No debugging symbols found in ./a.out)
[New LWP 5747]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `./a.out 0'.
Program terminated with signal SIGFPE, Arithmetic exception.
#0  0x000000000040117c in test_divide_zero ()
(gdb) bt
#0  0x000000000040117c in test_divide_zero ()
#1  0x000000000040124a in main ()

过滤dump内容

如上所见,coredump默认情况下会dump内存空间,这可能导致生成巨大的core文件。

所以需要对coredump的内容进行过滤。

这一部分内容可以参考man core.5 或者网页手册coreControlling which mappings are written to the core dump 一节。

设置位说明
bit 0Dump anonymous private mappings.
bit 1Dump anonymous shared mappings.
bit 2Dump file-backed private mappings.
bit 3Dump file-backed shared mappings.
bit 4(since Linux 2.6.24) Dump ELF headers.
bit 5(since Linux 2.6.28) Dump private huge pages.
bit 6(since Linux 2.6.28) Dump shared huge pages.
bit 7(since Linux 4.4) Dump private DAX pages.
bit 8(since Linux 4.4) Dump shared DAX pages.

默认情况下,开启: 0 1 4 5。

这也可以通过命令cat /proc/self/coredump_filter查看。 我这里显示的结果是00000033, 这个值是十六进制显示的,其二进制为110011,从后往前,刚好是0145位置1。

同理,我们可以通过向这个文件写值的方式改变当前程序的过滤设置。

echo 0x7 > /proc/self/coredump_filter

参考

man signal.7

man core.5

linux信号以及core-dump文件 - 知乎 (zhihu.com)

coredump文件生成,以及GDB工具使用_ITPUB博客

coredump文件 - 海林的菜园子 - 博客园 (cnblogs.com)

coredump文件过大_如何调试没有core文件的coredump_weixin_39652658的博客-CSDN博客

Linux下可执行程序调试信息的分离及release程序的调试 - 走看看 (zoukankan.com)