什么是coredump?
Coredump叫做核心转储,它是进程运行时在突然崩溃的那一刻的一个内存快照。操作系统在程序发生异常而异常在进程内部又没有被捕获的情况下,会把进程此刻内存、寄存器状态、运行堆栈等信息转储保存在一个文件里。
该文件也是二进制文件,可以使用gdb、elfdump、objdump或者windows下的windebug、solaris下的mdb进行打开分析里面的具体内容。
ulimit -c 可以设置core文件的大小,如果这个值为0.则不会产生core文件,这个值太小,则core文件也不会产生,因为core文件一般都比较大。
使用ulimit -c unlimited来设置无限大,则任意情况下都会产生core文件。
ulimit -a可以查看当前core文件限制。
1、设置core文件的名称和文件路径
默认生成路径:输入可执行文件运行命令的同一路径下
默认生成名字:默认命名为core。新的core文件会覆盖旧的core文件
a.设置pid作为文件扩展名
1:添加pid作为扩展名,生成的core文件名称为core.pid
0:不添加pid作为扩展名,生成的core文件名称为core
修改 /proc/sys/kernel/core_uses_pid 文件内容为: 1
修改文件命令: echo "1" > /proc/sys/kernel/core_uses_pid
或者
sysctl -w kernel.core_uses_pid=1 kernel.core_uses_pid = 1
2、控制core文件保存位置和文件名格式
修改文件命令: echo "/corefile/core-%e-%p-%t" > /proc/sys/kernel/core_pattern
或者:
sysctl -w kernel.core_pattern=/corefile/core-%e-%p-%t kernel.core_pattern = /corefile/core-%e-%p-%t
可以将core文件统一生成到/corefile目录下,产生的文件名为core-命令名-pid-时间戳
以下是参数列表:
%p - insert pid into filename 添加pid(进程id)
%u - insert current uid into filename 添加当前uid(用户id)
%g - insert current gid into filename 添加当前gid(用户组id)
%s - insert signal that caused the coredump into the filename 添加导致产生core的信号
%t - insert UNIX time that the coredump occurred into filename 添加core文件生成时的unix时间
%h - insert hostname where the coredump happened into filename 添加主机名
%e - insert coredumping executable name into filename 添加导致产生core的命令名
gdb 调试coredump的简单示例
#include "stdio.h" #include "stdlib.h" void dumpCrash() { char *ptr = "test"; free(ptr); } int main() { dumpCrash(); return 0; }
如上代码,pStr指针指向的是字符串常量,字符串常量是保存在常量区的,free释放常量区的内存肯定会导致coredump。
gcc -o dump test.c
运行test产生core文件,接下来利用gdb来调试coredump。
1、查看coredump时的堆栈。查看堆栈使用bt或者where命令
2、未gcc -g的话,没有调试信息的情况下,打开coredump堆栈,并不会直接显示core的代码行。
此时,frame addr(帧数)或者简写如下,f 4 跳转到core堆栈的第1帧。因为第0帧,1帧,2帧,3帧都是libc的代码,已经不是我们自己代码了。disassemble打开该帧函数的反汇编代码。
如下箭头(红标)位置表示coredump时该函数调用所在的位置
[root@tlinux /]# gdb dump(文件名) core.89056
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-110.el7
Copyright (C) 2013 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-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>;...
Reading symbols from /dump...(no debugging symbols found)...done.
[New LWP 89056]
Core was generated by `./dump'.
Program terminated with signal 6, Aborted.
#0 0x00007f2c4e1a8277 in raise () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.17-222.el7.x86_64 libgcc-4.8.5-36.el7.x86_64
(gdb) bt
#0 0x00007f2c4e1a8277 in raise () from /lib64/libc.so.6
#1 0x00007f2c4e1a9968 in abort () from /lib64/libc.so.6
#2 0x00007f2c4e1ead37 in __libc_message () from /lib64/libc.so.6
#3 0x00007f2c4e1f3499 in _int_free () from /lib64/libc.so.6
#4 0x0000000000400539 in dumpCrash ()
#5 0x0000000000400549 in main ()
(gdb) f 4
#4 0x0000000000400539 in dumpCrash ()
(gdb) disassemble
Dump of assembler code for function dumpCrash:
0x000000000040051d <+0>: push %rbp
0x000000000040051e <+1>: mov %rsp,%rbp
0x0000000000400521 <+4>: sub $0x10,%rsp
0x0000000000400525 <+8>: movq $0x4005e0,-0x8(%rbp)
0x000000000040052d <+16>: mov -0x8(%rbp),%rax
0x0000000000400531 <+20>: mov %rax,%rdi
0x0000000000400534 <+23>: callq 0x400400 <free@plt>
=> 0x0000000000400539 <+28>: leaveq
0x000000000040053a <+29>: retq
End of assembler dump.
(gdb)
不过上面的free使用去掉名词修饰效果和之前还是一样的。但是我们可以推测到这里是在调用free函数。
如此,我们就能知道我们coredump的位置,从而进一步能推断出coredump的原因。
当然,现实环境中,coredump的场景肯定远比这个复杂,都是逻辑都是一样的,我们需要先找到coredump的位置,再结合代码以及core文件推测coredump的原因。