点击量:1788
上一篇文章匆忙地记录了一次分析core文件报错的过程,今天则花点时间来认真总结下Linux下core文件的开启,生成,调试,以及堆栈定位。
一、什么是core文件?
进程在运行时可能会因为各种各样的原因(后面会细说)崩溃,而在崩溃前的一瞬间操作系统会像拍照片一样生成一个core文件,这个文件记录了程序运行时的状态,主要包括内存信息,堆栈指针,寄存器状态等,生成core文件的这一过程俗称为coredump。开发人员可以通过对core文件的分析来排查,定位问题,找到程序崩溃的原因。
二、core文件设置
a).如何开启
1 |
ulimit -c |
这条命令输出的是允许生产core文件的最大size,如果是0则表示你没有开启coredump,如果是unlimited则表示不限制大小。所以如果要开启coredump,只需要输入:
1 |
ulimit -c unlimited |
其中,unlimited可以换成具体的数字,比如1024(单位是KB)。
b).文件名及目录
默认设置下,
1.core文件是这么命名的:core.xxxx,xxxx表示进程号pid
2.core文件的目录和进程的运行目录一致
如果要修改默认设置的话,可以编辑文件/proc/sys/kernel/core_pattern,该文件的缺省值是core。可以像这样修改路径及文件名:echo ‘/var/log/%e.core.%p’ > /proc/sys/kernel/core_pattern,其中:
%% 单个%字符
%p 所dump进程的进程ID
%u 所dump进程的实际用户ID
%g 所dump进程的实际组ID
%s 导致本次core dump的信号
%t core dump的时间 (由1970年1月1日计起的秒数)
%h 主机名
%e 程序文件名
而/proc/sys/kernel/core_uses_pid则用来配置是否使用进程号作为core文件的扩展名(0或者1)。
c).怎么判断文件是不是core文件?
core文件是一种ELF文件(文件中除了包含机器码以外还存储了一些额外信息,比如符号表,加载地址等),可以通过以下命令来查看该文件的头文件信息(-h),可以看到type字段的值是CORE。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
[xxxx@VM_72_32_tlinux ~/fanyy]$ readelf -h core.20096 ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: CORE (Core file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x0 Start of program headers: 64 (bytes into file) Start of section headers: 0 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 17 Size of section headers: 0 (bytes) Number of section headers: 0 Section header string table index: 0 |
d).为什么没有生成core文件?
总的来说有这几个原因:
1.输出目录没有写入的权限
2.文件太大或者磁盘空间不足
三、有哪些原因会导致coredump?
1.内存访问越界,也就是说你访问了没有分配给你的内存,常见的有数组越界
2.指针使用不当,比如使用了空指针,或者指针转换错误
3.栈溢出,常见的像网络读包时缓冲区溢出
4.多线程读写数据未加锁保护
5.多线程程序使用了线程不安全的函数
四、如何生成一个core文件?
按照之前提到的coredump的原因分析,可以很容易的写出如下C代码以生成core文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <stdio.h> void test1(){ char *p = "this is a string"; *p = 0; } void test2(){ int *p = NULL; *p = 3; } void main(){ test2(); return; } |
编译:
1 |
gcc -g test.c -o test |
运行:
1 2 |
[xxxx@VM_72_32_tlinux ~/fanyy]$ ./test Segmentation fault (core dumped) |
结果出现了段错误,于是core dump了。
五、如何用GDB调试?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
[xxxx@VM_72_32_tlinux ~/fanyy]$ gdb /home/xxxx/fanyy/test core.25724 GNU gdb (GDB) Red Hat Enterprise Linux (7.2-50.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/xxxx/fanyy/test...done. [New Thread 25724] Missing separate debuginfo for Try: yum --disablerepo='*' --enablerepo='*-debuginfo' install /usr/lib/debug/.build-id/f5/b0ec68ff2f7b63983e1362ba6ccf5bb65a371d Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done. Loaded symbols for /lib64/libc.so.6 Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done. Loaded symbols for /lib64/ld-linux-x86-64.so.2 Core was generated by `./test'. Program terminated with signal 11, Segmentation fault. #0 0x0000000000400499 in test2 () at test.c:10 10 *p = 3; Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.149.tl1.5.x86_64 (gdb) where #0 0x0000000000400499 in test2 () at test.c:10 #1 0x00000000004004af in main () at test.c:14 (gdb) bt #0 0x0000000000400499 in test2 () at test.c:10 #1 0x00000000004004af in main () at test.c:14 |
这里要注意两点:
1.进入gdb之后,输入bt或者where来定位堆栈
2.gdb第二个参数一定要指定当时出core的那个可执行文件,否则会导致缺少符号表而无法调试出堆栈,就像下面这样:
1 2 3 4 |
#0 0x0000000000400499 in ?? () #1 0x00007fff84155c80 in ?? () #2 0x00000000004004af in ?? () #3 0x0000000000000000 in ?? () |