coredump

linux/Ubuntu下生成core dump文件调试方法


开启core dump

dbtu@dbtu:~$ 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) 384811
max locked memory       (kbytes, -l) 65536
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 384811
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

core file size这一项为0,说明不生成core dump文件。

# 限制产生的 core 文件的大小不能超过 1024kb
$ ulimit -c 1024
# 取消转储文件大小限制
$ ulimit -c unlimited

但是,这样设置会有一个问题,就是这个命令只在当前打开的shell中生效,关闭后就失效了。想要每次打开shell都会生效,需要将命令写入~/.bashrc或者/etc/profile:

$ echo 'ulimit -c unlimited' >> ~/.bashrc
$ echo "ulimit -c 1024" >> /etc/profile

core dump文件保存的路径

/proc/sys/kernel/core_uses_pid 可以控制产生的 core 文件的文件名中是否添加 pid 作为扩展 ,如果添加则文件内容为 1 ,否则为 0 。

proc/sys/kernel/core_pattern 可以设置格式化的 core 文件保存位置或文件名,比如原来文件内容是 core-%e,可以修改为 /tmp/corefile-%e-%p-%t,即文件名格式“corefile-文件名-pid-时间戳”,保存到/tmp/文件夹中。也可以不写文件夹,则直接保存到崩溃程序的同文件夹中。

还可以使用sysctl命令来设置保存路径:

$ sudo sysctl -w kernel.core_pattern=core.%p.%s.%c.%d.%P.%E

每个%开头的符号含义请参考命令man 5 core : core(5) — Linux manual page

   Naming of core dump files
       By  default,  a  core dump file is named core, but the /proc/sys/kernel/core_pattern file (since Linux
       2.6 and 2.4.21) can be set to define a template that is used to name core dump  files.   The  template
       can contain % specifiers which are substituted by the following values when a core file is created:

           %%  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))
           %i  TID of thread that triggered core dump, as seen in the  PID  namespace  in  which  the  thread
               resides (since Linux 3.18)
           %I  TID  of  thread  that  triggered  core dump, as seen in the initial PID namespace (since Linux
               3.18)
           %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

       A single % at the end of the template is dropped from the core filename, as is the combination of a  %
       followed  by any character other than those listed above.  All other characters in the template become
       a literal part of the core filename.  The template may include '/' characters, which  are  interpreted
       as  delimiters  for directory names.  The maximum size of the resulting core filename is 128 bytes (64
       bytes in kernels before 2.6.19).  The default value in this file is "core".  For backward  compatibil‐
       ity,  if  /proc/sys/kernel/core_pattern  does  not  include %p and /proc/sys/kernel/core_uses_pid (see
       below) is nonzero, then .PID will be appended to the core filename.

       Paths are interpreted according to the settings that are active for the crashing process.  That  means
       the crashing process's mount namespace (see mount_namespaces(7)), its current working directory (found
       via getcwd(2)), and its root directory (see chroot(2)).

       Since version 2.4, Linux has also provided a more primitive method of controlling the name of the core
       dump  file.  If the /proc/sys/kernel/core_uses_pid file contains the value 0, then a core dump file is
       simply named core.  If this file contains a nonzero value,  then  the  core  dump  file  includes  the
       process ID in a name of the form core.PID.

       Since Linux 3.6, if /proc/sys/fs/suid_dumpable is set to 2 ("suidsafe"), the pattern must be either an
       absolute pathname (starting with a leading '/' character) or a pipe, as defined below.

测试程序

#include <iostream>

int main() {
  int *p = nullptr;
  *p = 0;
  return 0;
}
# 使用 -g 参数编译添加调试信息
$ g++ -g test.cpp -o testcore
# 运行调试程序
$ ./testcore
Segmentation fault (core dumped)
# 使用ls等命令找到coredump转储的文件,然后用gdb打开
$ gdb ./testcore core.testcore.1663553436.2705214 
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2
Copyright (C) 2020 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 "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./testcore...

warning: exec file is newer than core file.
[New LWP 2705214]
Core was generated by `./testcore'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00005562d441b17d in main () at test.cpp:5
5               *p = 0;
(gdb) where
#0  0x00005562d441b17d in main () at test.cpp:5
(gdb) info frame
Stack level 0, frame at 0x7ffd6863cc60:
 rip = 0x5562d441b17d in main (test.cpp:5); saved rip = 0x7f0da5bb4083
 source language c++.
 Arglist at 0x7ffd6863cc48, args: 
 Locals at 0x7ffd6863cc48, Previous frame's sp is 0x7ffd6863cc60
 Saved registers:
  rbp at 0x7ffd6863cc50, rip at 0x7ffd6863cc58
(gdb) 

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

参考资料