生成core文件

一、简介

corefile是Linux下程序崩溃时生成的文件,可以用来分析程序崩溃的原因,因为它内部包含了程序崩溃时的堆栈信息。

方式一、临时设置

1 、如何生成 coredump 文件 ?

1)使用ulimit -c命令可查看core文件的生成开关。若结果为0,则表示关闭了此功能,不会生成core文件。

2)使用ulimit -c filesize命令,可以限制core文件的大小(filesize的单位为kbyte),如果生成的信息超过此大小,将会被裁剪,最终生成一个不完整的core文件。在调试此core文 件的时候,gdb会提示错误。。若ulimit -c unlimited,则表示core文件的大小不受限制。

2、设置 Core Dump 的核心转储文件目录和命名规则

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

proc/sys/kernel/core_pattern 可以设置格式化的 core 文件保存位置或文件名 ,比如原来文件内容是 core-%e

可以这样修改 :

echo "/corefile/core-%e-%p-%t" > core_pattern
  • 将会控制所产生的 core 文件会存放到 /corefile 目录下,产生的文件名为 core- 命令名 -pid- 时间戳

以下是参数列表 :

    %p - insert pid into filename 添加 pid
    %u - insert current uid into filename 添加当前 uid
    %g - insert current gid into filename 添加当前 gid
    %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 添加命令名

方法二、永久设置

1、如何生成core文件

在/etc/profile中最后添加ulimit -c unlimited

2、命名规则及保存路径设置

在/etc目录中的sysctl.conf文件中最后添加如下内容:

kernel.core_pattern=/corefile/core.%e.%p.%t(生成的core文件需要放置的路径及文件命名格式)

在添加完成后保存并退出,使用source ./sysctl.conf执行sysctl.conf文件,或者sysctl -p /etc/sysctl.conf使得设置立即生效

 

如果以上设置不成功看看如下:

默认情况下,程序崩溃是不会生成corefile了,因为被操作系统限制。可以通过命令: ulimit -c 来查看,如果值为0则表示被限制了。

打开的方式有多种,最简单的是: ulimit -c unlimited 其中unlimited表示corefile文件的大小无限制,默认为0,所以不能生成corefile文件,你也可以指定其他的值。

这种设置方式虽然简单,但它却只是跟shell相关的,也就是说,如果我们关闭了当前shell再打开一个,则刚才的设置就失效了,这是很不方便的。

另外一种方式时修改文件:/etc/security/limits.conf。将其中的这一行 #* soft core 0 取消注释并将最后的0修改为unlimited或者你希望的值。

这个修改重新登录的时候才会生效,当然也有使其立即生效的方法:将ulimit -c unlimited 放入/etc/profile中,然后执行source /etc/profile即可立即生效。

默认corefile是生成在程序的执行目录下或者程序启动调用了chdir之后的目录,那么我们可以通过设置生成corefile的格式来控制它,让其生成在固定的目录下。

在/proc/sys/kernel/core_pattern文件中的内容控制着它的格式。但是这里的设置在重启后会失效,如果想要长期生效,那么久需要修改文件:/etc/sysctl.conf,在其中添加一行:kernel.core_pattern=/home/robin/corefile/%e-%p,这个格式表示将corefile放在/home/robin/corefile目录下,每个corefile的格式为:程序名+进程id。当然修改文件/etc/sysctl.conf是不能立即生效的,如果想要立即生效:sysctl -p /etc/sysctl.conf,即可。

测试:

如何产生Core Dump

发生doredump一般都是在进程收到某个信号的时候,Linux上现在大概有60多个信号,可以使用 kill -l 命令全部列出来。

sagi@sagi-laptop:~$ kill -l
     1) SIGHUP   2) SIGINT   3) SIGQUIT  4) SIGILL   5) SIGTRAP
      6) SIGABRT     7) SIGBUS   8) SIGFPE   9) SIGKILL 10) SIGUSR1
      11) SIGSEGV   12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
      16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
      21) SIGTTIN   22) SIGTTOU 23) SIGURG  24) SIGXCPU 25) SIGXFSZ
      26) SIGVTALRM 27) SIGPROF 28) SIGWINCH    29) SIGIO   30) SIGPWR
      31) SIGSYS    34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
      38) SIGRTMIN+4    39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
      43) SIGRTMIN+9    44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
      48) SIGRTMIN+14   49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
      53) SIGRTMAX-11   54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
      58) SIGRTMAX-6    59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
      63) SIGRTMAX-1    64) SIGRTMAX

针对特定的信号,应用程序可以写对应的信号处理函数。如果不指定,则采取默认的处理方式, 默认处理是coredump的信号如下:

3)SIGQUIT   4)SIGILL    6)SIGABRT   8)SIGFPE    11)SIGSEGV    7)SIGBUS    31)SIGSYS
5)SIGTRAP   24)SIGXCPU  25)SIGXFSZ  29)SIGIOT

我们看到SIGSEGV在其中,一般数组越界或是访问空指针都会产生这个信号。另外虽然默认是这样的,但是你也可以写自己的信号处理函数改变默认行为,更多信号相关可以看参考链接33。

上述内容只是产生coredump的必要条件,而非充分条件。要产生core文件还依赖于程序运行的shell,可以通过ulimit -a命令查看,输出内容大致如下:

sagi@sagi-laptop:~$ ulimit -a
    core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 20
    file size               (blocks, -f) unlimited
    pending signals                 (-i) 16382
    max locked memory       (kbytes, -l) 64
    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) unlimited
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited

看到第一行了吧,core file size,这个值用来限制产生的core文件大小,超过这个值就不会保存了。我这里输出是0,也就是不会保存core文件,即使产生了,也保存不下来==! 要改变这个设置,可以使用ulimit -c unlimited。

OK, 现在万事具备,只缺一个能产生Core的程序了,介个对C程序员来说太容易了。

#include <stdio.h>;
#include <stdlib.h>;
 
    int crash()
    {
            char *xxx = "crash!!";
            xxx[1] = 'D'; // 写只读存储区!
            return 2;
    }
 
    int foo()
    {
            return crash();
    }
 
    int main()
    {
            return foo();
    }

上手调试

测试如下代码

1

2

3

4

5

6

7

8

9

10

11

12

#include <stdio.h>

 

int func(int *p)

{

        *p = 0;

}

 

int main()

{

        func(NULL);

        return 0;

}

 

生成可执行文件并运行

gcc -o main a.c

root@ubuntu:~# ./main
Segmentation fault (core dumped) 

<-----这里出现段错误并生成core文件了。

在/tmp目录下发现文件core-main-10815 

 

如何查看进程挂在哪里了?

我们可以用

gdb main /tmp/core-main-10815 

查看信息,发现能定位到函数了

Program terminated with signal 11, Segmentation fault.
#0  0x080483ba in func ()

 

如何定位到行?

在编译的时候开启-g调试开关就可以了

gcc -o main -g a.c

gdb main /tmp/core-main-10815 

最终看到的结果如下,好棒。

Program terminated with signal 11, Segmentation fault.
#0  0x080483ba in func (p=0x0) at a.c:5
5          *p = 0;

 

总结一下,需要定位进程挂在哪一行我们只需要4个操作,

ulimit -c unlimited

echo "/tmp/core-%e-%p" > /proc/sys/kernel/core_pattern

gcc -o main -g a.c

gdb main /tmp/core-main-10815 

就可以啦。

 

上边的程序编译的时候有一点需要注意,需要带上参数-g, 这样生成的可执行程序中会带上足够的调试信息。编译运行之后你就应该能看见期待已久的“Segment Fault(core dumped)”或是“段错误 (核心已转储)”之类的字眼了。看看当前目录下是不是有个core或是core.xxx的文件。祭出linux下经典的调试器GDB,首先带着core文件载入程序:gdb exefile core,这里需要注意的这个core文件必须是exefile产生的,否则符号表会对不上。载入之后大概是这个样子的:

sagi@sagi-laptop:~$ gdb coredump core
Core was generated by ./coredump'.
    Program terminated with signal 11, Segmentation fault.
#0  0x080483a7 in crash () at coredump.c:8
    8       xxx[1] = 'D';
(gdb)

我们看到已经能直接定位到出core的地方了,在第8行写了一个只读的内存区域导致触发Segment Fault信号。在载入core的时候有个小技巧,如果你事先不知道这个core文件是由哪个程序产生的,你可以先随便找个代替一下,比如/usr/bin/w就是不错的选择。比如我们采用这种方法载入上边产生的core,gdb会有类似的输出:

sagi@sagi-laptop:~$ gdb /usr/bin/w core
Core was generated by ./coredump'.
    Program terminated with signal 11, Segmentation fault.
#0  0x080483a7 in ?? ()
    (gdb)

可以看到GDB已经提示你了,这个core是由哪个程序产生的。

GDB 常用操作

上边的程序比较简单,不需要另外的操作就能直接找到问题所在。现实却不是这样的,常常需要进行单步跟踪,设置断点之类的操作才能顺利定位问题。下边列出了GDB一些常用的操作。

  • 启动程序:run

     

  • 设置断点:b 行号|函数名

     

  • 删除断点:delete 断点编号

     

  • 禁用断点:disable 断点编号

     

  • 启用断点:enable 断点编号

     

  • 单步跟踪:next 也可以简写 n

     

  • 单步跟踪:step 也可以简写 s

     

  • 打印变量:print 变量名字

     

  • 设置变量:set var=value

     

  • 查看变量类型:ptype var

     

  • 顺序执行到结束:cont

     

  • 顺序执行到某一行: util lineno

     

  • 打印堆栈信息:bt
  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值