linux下的coredump

来源:互联网 发布:劲舞团解压数据错误 编辑:程序博客网 时间:2024/04/30 02:33

基本概念

coredump:当程序运行的过程中异常终止或崩溃,操作系统会将程序当时的内存状态记录下来,保存在一个文件中,这种行为就叫做Core Dump(中文有的翻译成“核心转储”)。我们可以认为 core dump 是“内存快照”,但实际上,除了内存信息之外,还有些关键的程序运行状态也会同时 dump 下来,例如寄存器信息(包括程序指针、栈指针等)、内存管理信息、其他处理器和操作系统状态和信息。core dump 对于编程人员诊断和调试程序是非常有帮助的,因为对于有些程序错误是很难重现的,例如指针异常,而 core dump 文件可以再现程序出错时的情景。
上面说当程序运行过程中异常终止或崩溃时会发生 core dump,但还没说到什么具体的情景程序会发生异常终止或崩溃,例如我们使用 kill -9 命令杀死一个进程会发生 core dump 吗?实验证明是不能的,那么什么情况会产生呢?

  • core的产生

Linux 中信号是一种异步事件处理的机制,每种信号对应有其默认的操作,你可以在 这里 查看 Linux 系统提供的信号以及默认处理。默认操作主要包括忽略该信号(Ingore)、暂停进程(Stop)、终止进程(Terminate)、终止并发生core dump(core)等。如果我们信号均是采用默认操作,那么,以下列出几种信号,它们在发生时会产生 core dump:

Signal Action Comment SIGQUIT Core Quit from keyboard SIGILL Core Illegal Instruction SIGABRT Core Abort signal from abort SIGSEGV Core Invalid memory reference SIGTRAP Core Trace/breakpoint trap

当然不仅限于上面的几种信号。这就是为什么我们使用 Ctrl+z 来挂起一个进程或者 Ctrl+C 结束一个进程均不会产生 core dump,因为前者会向进程发出 SIGTSTP 信号,该信号的默认操作为暂停进程(Stop Process);后者会向进程发出SIGINT 信号,该信号默认操作为终止进程(Terminate Process)。同样上面提到的 kill -9 命令会发出 SIGKILL 命令,该命令默认为终止进程。而如果我们使用 Ctrl+\ 来终止一个进程,会向进程发出 SIGQUIT 信号,默认是会产生 core dump 的。还有其它情景会产生 core dump, 如:程序调用 abort() 函数、访存错误、非法指令等等。

终端下比较 Ctrl+CCtrl+\

[niuxiaoke@niuxiaoke]# sleep 10^C       //使用Ctrl+C终止该程序,不会产生core dump[niuxiaoke@niuxiaoke]# sleep 10^\Quit (core dumped) //使用Ctrl+\终止程序,会产生core dump文件。[niuxiaoke@niuxiaoke]# ll  core.3681  //多了一个core文件-rw-------. 1 niuxiaoke niuxiaoke 159744 Dec 25 19:17 core.3681

小程序产生 core dump

#include<stdio.h>int mai(){  int *ptr = null;  ptr = 10;  return 0;}
#编译执行niuxiaoke@niuxiaoke:~$ ./a.outSegmentation fault (core dumped)niuxiaoke@niuxiaoke:~$ ls      //多出下面一个 core 文件-rw-------  1 guohailin guohailin 200704 1022 11:35 a.out.core.22070    

开启coredump

可以使用命令ulimit开启,也可以在程序中通过setrlimit系统调用开启。

  • 打开coredump功能
    ·在终端中输入 ulimit -c ,输出结果为0,说明默认是关闭的core dump,也就是当程序异常终止时,也不会生成core dump文件。
    ·我们可以使用命令 ulimit -c unlimited来开启core dump功能,并且不限制core dump文件的大小,(这里改为了无穷大,也可以设置为你需要的大小,单位是blocks(KB))。
    ·上面的命令只对当前的终端环境有效,如果想永久生效,可以修改文件/etc/security/limits.conf文件。
    ·修改 core 文件保存的路径
    默认生成的 core 文件保存在可执行文件所在的目录下,文件名就为 core。
    通过修改 /proc/sys/kernel/core_uses_pid 文件可以让生成 core 文件名是否自动加上 pid 号。
    例如 echo 1 > /proc/sys/kernel/core_uses_pid ,生成的 core 文件名将会变成 core.pid,其中 pid 表示该进程的 PID。
    还可以通过修改 /proc/sys/kernel/core_pattern 来控制生成 core 文件保存的位置以及文件名格式。

    使用gdb调试core文件

  • 首先,使用 gcc 编译源文件,加上 -g 以增加调试信息;

  • 按照上面打开 core dump 以使程序异常终止时能生成 core 文件;

  • 运行程序,当core dump 之后,使用命令 gdb program core 来查看 core 文件,其中 program 为可执行程序名,core 为生成的 core 文件名。

    下面用一个简单的例子来说明:

#include<stdio.h>int func(int *p){    int y = p;       return y;}int main(){  int *ptr = null;  return func(ptr);}

编译加上调试信息, 运行之后core dump, 使用 gdb 查看 core 文件.

niuxiaoke@niuxiaoke:~$ gcc core_demo.c -o core_demo -gniuxiaoke@niuxiaoke:~$ ./core_demo Segmentation fault (core dumped)niuxiaoke@niuxiaoke:~$ gdb core_demo core_demo.core.24816Core was generated by './core_demo'.Program terminated with signal 11, Segmentation fault.#0  0x080483cd in func (p=0x0) at core_demo.c:55       int y = *p;(gdb)  where#0  0x080483cd in func (p=0x0) at core_demo.c:5#1  0x080483ef in main () at core_demo.c:12(gdb) info frameStack level 0, frame at 0xffd590a4: eip = 0x80483cd in func (core_demo.c:5); saved eip 0x80483ef called by frame at 0xffd590c0 source language c. Arglist at 0xffd5909c, args: p=0x0 Locals at 0xffd5909c, Previous frame's sp is 0xffd590a4 Saved registers:  ebp at 0xffd5909c, eip at 0xffd590a0(gdb) 

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

  • 如何判断一个文件时core dump 文件
    答:在类unix系统下,coredump文件本身主要的格式也是ELF格式,因此,我们可以通过readelf命令进行判断
[root@localhost Signal]# readelf core.4466 -hELF Header:  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00   Class:                             ELF32  Data:                              2's complement, little endian  Version:                           1 (current)  OS/ABI:                            UNIX - System V  ABI Version:                       0> Type:                              CORE (Core file)  Machine:                           Intel 80386  Version:                           0x1  Entry point address:               0x0  Start of program headers:          52 (bytes into file)  Start of section headers:          0 (bytes into file)  Flags:                             0x0  Size of this header:               52 (bytes)  Size of program headers:           32 (bytes)  Number of program headers:         14  Size of section headers:           0 (bytes)  Number of section headers:         0  Section header string table index: 0
[root@localhost Signal]# file core.4466core.4466: ELF 32-bit LSB core file Intel 80386, version 1 (SYSV), SVR4-style, from './test'

附一些gdb常用调试命令:

1,l(list) ,显示源代码,并且可以看到对应的行号;
b(break)x, x是行号,表示在对应的行号位置设置断点;
p(print)x, x是变量名,表示打印变量x的值
r(run), 表示继续执行到断点的位置
n(next),表示执行下一步
c(continue),表示继续执行
q(quit),表示退出gdb

启动gdb,注意该程序编译需要-g选项进行。

2, 一些常用signal的含义
SIGABRT:调用abort函数时产生此信号。进程异常终止。
SIGBUS:指示一个实现定义的硬件故障。
SIGEMT:指示一个实现定义的硬件故障。EMT这一名字来自PDP-11的emulator trap 指令。
SIGFPE:此信号表示一个算术运算异常,例如除以0,浮点溢出等。
SIGILL:此信号指示进程已执行一条非法硬件指令。4.3BSD由abort函数产生此信号。SIGABRT现在被用于此。
SIGIOT:这指示一个实现定义的硬件故障。IOT这个名字来自于PDP-11对于输入/输出TRAP(input/outputTRAP)指令的缩写。系统V的早期版本,由abort函数产生此信号。SIGABRT现在被用于此。
SIGQUIT:当用户在终端上按退出键(一般采用Ctrl-/)时,产生此信号,并送至前台进
程组中的所有进程。此信号不仅终止前台进程组(如SIGINT所做的那样),同时产生一个core文件。
SIGSEGV:指示进程进行了一次无效的存储访问。名字SEGV表示“段违例(segmentationviolation)”。
SIGSYS:指示一个无效的系统调用。由于某种未知原因,进程执行了一条系统调用指令,但其指示系统调用类型的参数却是无效的。
SIGTRAP:指示一个实现定义的硬件故障。此信号名来自于PDP-11的TRAP指令。
SIGXCPUSVR4和4.3+BSD支持资源限制的概念。如果进程超过了其软C P U时间限制,则产生此信号。
SIGXFSZ:如果进程超过了其软文件长度限制,则SVR4和4.3+BSD产生此信号。

3, Core_pattern的格式 可以在core_pattern模板中使用变量还很多,见下面的列表:
%% 单个%字符
%p 所dump进程的进程ID
%u 所dump进程的实际用户ID
%g 所dump进程的实际组ID
%s 导致本次core dump的信号
%tcore dump的时间 (由1970年1月1日计起的秒数)
%h 主机名 %e 程序文件名

  • 产生core dump的一些条件
    1,内存访问越界
    a) 由于使用错误的下标,导致数组访问越界。
    b) 搜索字符串时,依靠字符串结束符来判断字符串是否结束,但是字符串没有正常的使用结束符。
    c) 使用strcpy, strcat, sprintf, strcmp,strcasecmp等字符串操作函数,将目标字符串读/写爆。应该使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函数防止读写越界。
    2,多线程程序使用了线程不安全的函数。
    3,多线程读写的数据未加锁保护。
    对于会被多个线程同时访问的全局数据,应该注意加锁保护,否则很容易造成coredump
    4,非法指针
    a) 使用空指针
    b) 随意使用指针转换。一个指向一段内存的指针,除非确定这段内存原先就分配为某种结构或类型,或者这种结构或类型的数组,否则不要将它转换为这种结构或类型的指针,而应该将这段内存拷贝到一个这种结构或类型中,再访问这个结构或类型。这是因为如果这段内存的开始地址不是按照这种结构或类型对齐的,那么访问它时就很容易因为bus error而core dump。
    5,堆栈溢出
    不要使用大的局部变量(因为局部变量都分配在栈上),这样容易造成堆栈溢出,破坏系统的栈和堆结构,导致出现莫名其妙的错误。

参考:
http://www.cnblogs.com/hazir/p/linxu_core_dump.htm
http://www.cnblogs.com/niocai/archive/2012/04/01/2428128.html
http://baidutech.blog.51cto.com/4114344/904419/

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 宽怒 宽恕 宽恕的意思 宽恕的拼音 宽恕拼音 不可宽恕 宽恕女主角 宽恕的例子 宽恕连续剧 宽恕的故事 宽恕是什么意思 宽恕电视连续剧 电视连续剧宽恕 关于宽恕的名言 宽恕别人就是善待自己 宽恕的反义词是什么 不可宽恕者的面具 不可宽恕者的护肩 我也一个都不宽恕 冰之公主殿下的宽恕 宽慰 宽慰的意思 宽敞反义词 宽敞拼音 宽敞的拼音 宽敞 宽敞近义词 宽敞的意思 宽敞读音 宽敞的读音 宽敞的什么 宽敞的反义词 宽敞的近义词 宽敞的意思是什么 梦见宽敞明亮的大房子 宽敞的近义词和反义词 宽敞的近义词是什么 宽敞的拼音是什么 梦见很宽敞的漂亮的大房子 宽敞的反义词是什么 宽松