• 关于内核转储(core dump)的设置方法


    原作者:http://blog.csdn.net/wj_j2ee/article/details/7161586

    1. 内核转储作用

     

    (1) 内核转储的最大好处是能够保存问题发生时的状态。

    (2) 只要有可执行文件和内核转储,就可以知道进程当时的状态。

    (3) 只要获取内核转储,那么即使没有复现环境,也能调试。

     

    2. 启用内核转储

    1.1 查看内核转储是否有效

    在终端中输入以下命令,查看内核转储是否有效。

    #ulimit -c

    0

    -c 表示内核转储文件的大小限制,现在显示为零,表示不能用。

    可以改为1G

    #ulimit -c 1073741824

    也可以改为无限制

    #ulimit -c unlimited

     

    2.2 测试一个例子

    例子的源代码:

    #include <stdio.h>

    int main(void)

    {

    int *a = NULL;

    *a = 0x1;

    return 0;

    }

     

    把以上源代码,写成一个a.c文件后,编译a.c文件产生一个a.out的可执行文件:

    #gcc -g a.c -o a.out

    修改a.out文件的权限后,执行它:

    #./a.out

    就会显示:

    Segmentation fault(core dump)

    这表示在当前目录下, 已经生成了a.out对应的内核转储文件。

    注意:后面带有(core dump), 才说明转储文件成功生成了。

    #file core*

    core:ELF 64-bit LSB core file x86-64, version 1(SYSV), SVR4-style, from './a.out'

    coreDump: UTF-8 Unicode C program text

     

    要用GDB调试内核转储文件,应该使用以下方式启动GDB:

    #gdb -c ./*.core ./a.out

    GNU gdb (GDB) 7.1-Ubuntu

    ...

    Core was generated by './a.out'.

    Program terminated with signal 11, Segmentation fault.

    #0 0x00000000004004dc in main() at a.c:6

    6 *a =0x1;

    a.c的第6行收到了11号信号。用GDB的list命令可以查看附近的源代码。

    (gdb) l 5

    1            #include <stdio.h>

    2           

    3            int main(void)

    4            {

    5                   int *a = NULL;

    6                   *a = 0x1;

    7                   return 0;

    8            }

    这里默认都是当前目录,也可以给core 和a.out 指定路径

    到这里测试完成!

     

    2.3 永久生效的办法

    上面所述的方法,只是在当前shell中生效,重启之后,就不再有效了。永久生效的办法是:

    #vi /etc/profile 然后,在profile中添加:

    ulimit -c 1073741824

     (但是,若将产生的转储文件大小大于该数字时,将不会产生转储文件)

    或者

    ulimit -c unlimited

     

    这样重启机器后生效了。 或者, 使用source命令使之马上生效。

    #source /etc/profile

     

    3. 指定内核转储的文件名和目录

    缺省情况下,内核在coredump时所产生的core文件放在与该程序相同的目录中,并且文件名固定为core。很显然,如果有多个程序产生core文件,或者同一个程序多次崩溃,就会重复覆盖同一个core文件。

    我们可以通过修改kernel的参数,指定内核转储所生成的core文件的路径和文件名。

    可以通过在/etc/sysctl.conf文件中,对sysctl变量kernel.core_pattern的设置。

    #vi /etc/sysctl.conf 然后,在sysctl.conf文件中添加下面两句话:

    kernel.core_pattern = /var/core/core_%e_%p

    kernel.core_uses_pid = 0

    保存后退出。

    需要说明的是, /proc/sys/kernel/core_uses_pid。如果这个文件的内容被配置成1,即使core_pattern中没有设置%p,最后生成的core dump文件名仍会加上进程ID。

    这里%e, %p分别表示:

    %c 转储文件的大小上限

    %e 所dump的文件名

    %g 所dump的进程的实际组ID

    %h 主机名

    %p 所dump的进程PID

    %s 导致本次coredump的信号

    %t 转储时刻(由1970年1月1日起计的秒数)

    %u 所dump进程的实际用户ID

    可以使用以下命令,使修改结果马上生效。

    #sysctl –p /etc/sysctl.conf

     

    请在/var目录下先建立core文件夹,然后执行a.out程序,就会在/var/core/下产生以指定格式命名的内核转储文件。查看转储文件的情况:

    #ls /var/core

    core_a.out_2834

     

    4. 手动强制某个进程产生core dump的方法(尝试)

    当某些程序发生crash时,对应进程会产生coredump文件。通过这个coredump文件,开发人员可以找到bug的原因。但是coredump的产生,大都是因为程序crash了。

    而有些bug是不会导致程序crash的,比如死锁,这时程序已经不正常了,可是却没有coredump产生。如果环境又不允许gdb调试,难道我们就束手无策了吗?

    针对以上这种情况,一般情况下,对于这样的进程可以利用watchdog监控它们,当发现这些进程很长时间没有更新其heartbeat时,可以给这些进程发送可以导致其产生coredump的信号。根据linux的信号默认的处理行为,SIGQUIT,SIGABRT, SIGFPE和SIGSEGV都可以让该进程产生coredump文件。这样我们可以通过coredump来得知死锁是否发生。 当然, 如果进程添加了这些信号的处理函数,那么就不会产生coredump了。不过,对于SIGQUIT, SIGABRT, SIGFPE, SIGSEGV,有谁会为它们加上信号处理函数呢。

     

    还有一种情况,进程并没有死锁或者block在某个位置,但是我们需要在某个指定位置进行调试,获取某些变量或者其它信息。但是,有可能是客户环境或者生产环境,不允许我们进行长时间的检测。那么,我们就需要通过coredump来获得进程在运行到该点时的快照。 这个时候,可以利用gdb来手工产生coredump。在attach上这个进程时,在指定位置打上断点,当断点触发时,使用gdb的命令gcore,可以立即产生一个coredump。 这样,我们就拿到了这个位置的进程快照。

     

    1.寻找您要发送信号的进程ID,

     

    # ps -ef  | grep qemu

    root      3207  3206 44 10:32 pts/1    00:00:18 /usr/local/bin/qemu-system-x86

    得出 qemu-system-x86的 PID号是3207

    2.使用kill(1)去发送信号。

     

    # /bin/kill -s QUIT 3207

     

    发送其他的信号也很相似, 只要在命令行中替换QUIT 为ABRT,TERM 或 KILL 就行了

     

    重要提示: 在系统上随意杀死进程是一个坏主意,特别是init(8),它的PID是1,它非常特殊。 可以运行 /bin/kill -s KILL 1 命令来让系统迅速关机。  当您按下 Return (回车)键之前, 一定要 详细检查您运行 kill(1) 时所指定的参数。

     

    5 使用core dump进行调试

    在Linux下遇到“段错误”(segmentation fault),如果段错误发生在服务器端,而服务器端要继续工作,不允许调试,这时“内核转储(core dump)”就派上了用场,可以把生成的内核转储复制到本地进行调试。

        首先,按照上面的永久生效方法,在服务器上进行相应设置。 然后程序在崩溃时,就会在程序所在目录(或自己指定的目录)生成一个core文件,把这个core文件拷到本地(最好与该进程对应的可执行文件放到同一个目录,若不然,在gdb时指出路径也可以)。

     

    具体方法如下:

    方法一:

    输入命令 #gdb <程序可执行文件> <coredump转储文件>

    例如:

    # gdb /usr/local/bin/qemu-system-x86_64  /var/core/core-3207-qemu-system-x86

    然后,在(gdb)提示符后输入 l,  会显示main主函数

     

     

    方法二:

    (1) 在终端输入命令# gdb [-c] <coredump文件>,

    例如: gdb -c /var/core/core-3207-qemu-system-x86

    (2)然后,在(gdb)提示符后输入file <可执行程序>

    例如:(gdb) file  /usr/local/bin/qemu-system-x86_64

    (3) 这时就可以用backtrace/thread等命令查看当时的错误了,就像程序在本地执行到崩溃点一样

    或者用where回车, 也可以显示程序在哪一行当掉的

     

    5. 启用整个系统的内核转储

    (未完待续......)

     

    (4.1) 编辑/etc/profile, 开启登录到系统的所有用户的内核转储功能

    首先,看看用的是个什么机器:

    # uname –a

    Linux ubuntu240 2.6.32-21-server #32-Ubuntu SMP Fri Apr 16 09:17:34 UTC 2010 x86_64 GNU/Linux

    其次,再查看一些默认参数,若core file size是0,即使程序出错时,也不会产生core文件。

    # ulimit -a

    core file size              (blocks, -c) unlimited

    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


    6.使用内核转储掩码来排除要转储的内存块

    你可能会因为不希望设置ulimit 的时候太僵硬导致空间不够没有得到完整的转储,所以设置ulimit 为"unlimited" (不限制)。但是如果执行一个占用内存很恐怖的程序,当这个程序内核转储的时候也就会生成体积很恐怖的转储文件。

    为了避免这种情况,可以指定内核转储掩码来排除要转储的内存段。

    掩码请查看/usr/src/linux/Documentation/sysctl/kernel.txt 中的3.4 小节,没有内核源码可以到这里的网络版,这里摘录出来如下:

    The following 7 memory types are supported:
      - (bit 0) anonymous private memory(匿名私有内存段)
      - (bit 1) anonymous shared memory(匿名共享内存段)
      - (bit 2) file-backed private memory(file-backed 私有内存段)
      - (bit 3) file-backed shared memory(file-bakced 共享内存段)
      - (bit 4) ELF header pages in file-backed private memory areas (it is
                effective only if the bit 2 is cleared)(ELF 文件映射,只有在bit 2 复位的时候才起作用)
      - (bit 5) hugetlb private memory(大页面私有内存)
      - (bit 6) hugetlb shared memory(大页面共享内存)

    设置方法很简单:找到程序的PID,然后修改/proc/PID/coredump_filter 的值。

    如果你要设置某些还没有运行的进程的内核转储掩码,请修改/proc/self/coredump_filter 的值。

    PS

    a. 默认的coredump_filter 的值一般是0x23,至于代表什么,请换成二进制00100011,从右向左看,bit 0、bit 1、bit 5 被置位,也就是说会转储所有的匿名内存段和大页面私有内存段。

    b. 共享内存段都是一样的,可以不必转储。

    7. 在系统中全局设置转储功能

    全局设置没有什么好说的,把你的配置写入/etc/profile.d/ 目录下任意一个新建的文件当中,别忘了设置属组和所有者为root:root,权限为751。

    根据上面说的,写入的要有一条ulimit 指令,可能还有一条sysctl 指令,最后可能还有一条cat 指令。

    更多的设置请查看上面提到的kernel.txtproc.txt,例如你想把SUID 程序也转储,你需要

    sysctl -w 'fs.suid_dumpable=1'
  • 相关阅读:
    linux时间同步,ntpd、ntpdate
    重启HPE管理芯片ILO5的5种方法(Reset ilo)
    Linux内核SPI支持概述
    linux 查看CPU详情命令
    高可用
    NFS的介绍
    SELINUX
    error: undefined reference to 'android::hardware::details::return_status::~return_status()'
    errors collectiions
    大型分布式架构设计与实现-第三章互联网安全架构
  • 原文地址:https://www.cnblogs.com/zlcxbb/p/6431191.html
Copyright © 2020-2023  润新知