【Linux进阶】core dump文件的形成和设置
时间:2015-09-11 12:09:11 作者:vaster 标签: core dump Linux 分类: Linux
Core,又称之为Core Dump文件,是Unix/Linux操作系统的一种机制,对于线上服务而言,Core令人闻之色变,因为出Core的过程意味着服务暂时不能正常响应, 需要恢复,并且随着吐Core进程的内存空间越大,此过程可能持续很长一段时间(例如当进程占用60G+以上内存时,完整Core文件需要15分钟才能完 全写到磁盘上)
OS在出Core的同时,虽然会终止掉当前进程,但是也会保留下第一手的现场数据,OS仿佛是一架被按下快门的相机,而照片就是产出的Core文件。里面含有当进程被终止时内存、CPU寄存器等信息,可以供后续开发人员进行调试。
关于Core产生的原因很多,比如过去一些Unix的版本不支持现代Linux上这种GDB直接附着到进程上进行调试的机制,需要先向进程发送终止信号,然后用工具阅读core文件。在Linux上,我们就可以使用kill向一个指定的进程发送信号或者使用gcore命令来使其主动出Core并退 出。如果从浅层次的原因上来讲,出Core意味着当前进程存在BUG,需要程序员修复。从深层次的原因上讲,是当前进程触犯了某些OS层级的保护机制,逼迫OS向当前进程发送诸如SIGSEGV(即signal 11)之类的信号, 例如访问空指针或数组越界出Core,实际上是触犯了OS的内存管理,访问了非当前进程的内存空间,OS需要通过出Core来进行警示,这就好像一个人身 体内存在病毒,免疫系统就会通过发热来警示,并导致人体发烧是一个道理(有意思的是,并不是每次数组越界都会出Core,这和OS的内存管理中虚拟页面分 配大小和边界有关,即使不出Core,也很有可能读到脏数据,引起后续程序行为紊乱,这是一种很难追查的BUG)。
core文件的生成
ulimit -c
此命令可以显示当前OS对于Core文件大小的限制,如果为0,则表示不允许产生Core文件。
ulimit -c n
其中n为数字,表示允许Core文件体积的最大值,单位为Kb
ulimit -c unlimited
设置core文件为无限大
core文件名格式
/proc/sys/kernel/core_pattern文件,此文件用于控制Core文件产生的文件名,此文件支持定制,一般使用%配合不同的字符,这里罗列几种:
%p 出Core进程的PID
%u 出Core进程的UID
%g 出core进程的GID
%s 造成Core的signal号
%t 出Core的时间,从1970-01-0100:00:00开始的秒数
%e 出Core进程对应的可执行文件名
%h 出主机名
core文件的生成目录
临时修改
echo "/data/corefile/core-%e-%p-%t" > /proc/sys/kernel/core_pattern
sysctl -w kernel.core_pattern=/data/corefile/core-%e-%p-%t
永久修改
在/etc/sysctl.conf文件中添加
kernel.core_pattern = /data/corefile/core-%e-%p-%t
将所产生的core文件存放到/data/corefile目录,文件名为core-命令-pid-时间戳
配置ulimit永久生效
# cat /etc/security/limits.conf
* soft core unlimited
# ulimit -c unlimited
C文件
# cat a.c
#include "stdio.h"
#include "stdlib.h"
int main(){
int* stack_of = malloc(sizeof(int)*100000000);
int b;
int* a;
*a=b;
}
编译
普通编译
gcc -g a.c -o a
优化编译
gcc -O3 -g a.c -o a
-O3参数,可以对程序进行优化,一个负面效应是优化过程中会舍弃部分局部变量,导致调试时出现困难。
执行
# ./a
Segmentation fault
调试C程序
调试c程序和core dump文件,最常用的工作就是gdb了
安装GDB命令
# yum whatprovides */gdb
gdb-7.2-83.el6.x86_64 : A GNU source-level debugger for C, C++, Java and other languages
Repo : base
Matched from:
Filename : /usr/share/gdb/python/gdb
Filename : /usr/share/gdb
Filename : /usr/bin/gdb
# yum install gdb-7.2-83.el6.x86_64
gdb工具的使用
调试程序
# gdb a <---------- 启动GDB
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-83.el6)
Copyright (C) 2010 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 /home/vaster/a...done.
(gdb) l <-------------------- l命令相当于list,从第一行开始例出原码。
1 #include "stdio.h"
2 #include "stdlib.h"
3 int main(){
4 int* stack_of = malloc(sizeof(int)*100000000);
5 int b;
6 int* a;
7 *a=b;
8 }
(gdb) break 6 <-------------------- 设置断点,在源程序第6行处
Breakpoint 1 at 0x4004da: file a.c, line 6.
(gdb) info break <-------------------- 查看断点信息。
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004004da in main at a.c:6
(gdb) r <--------------------- 运行程序,run命令简写
Starting program: /home/vaster/a
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x7ffff7ffa000
Breakpoint 1, main () at a.c:7 <---------- 在断点处停住
7 *a=b;
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.132.el6_5.4.x86_64
(gdb) n <--------------------- 单条语句执行,next命令简写
Program received signal SIGSEGV, Segmentation fault.
0x00000000004004e1 in main () at a.c:7
7 *a=b;
(gdb) c <--------------------- 继续运行程序,continue命令简写
Continuing.
Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
(gdb) bt <--------------------- 查看函数堆栈。
No stack.
(gdb) q <--------------------- 退出gdb。