Linux下coredump使用

Stella981
• 阅读 759

01 什么coredump

当程序运行的过程中异常终止或崩溃,操作系统会将程序当时的内存状态记录下来,保存在一个文件中(core文件),这种行为就叫做 Core Dump 或者叫做"核心转储",利用 coredump 可以帮助我们快速定位程序崩溃位置。
通常情况下,core文件会包含了程序运行时的内存,寄存器状态,堆栈指针,内存管理信息还有各种函数调用堆栈信息等,我们可以理解为是程序工作当前状态存储生成的一个文件,许多的程序出错的时候都会产生一个core文件,通过工具分析这个文件,我们可以定位到程序异常退出的时候对应的堆栈调用等信息,找出问题所在并进行及时解决。

02 开启和关闭coredump功能

已centos6.9为例说明。

02.01 查看coredump功能是否打开

ulimit -c  # 如果为 0 表示coredump开关处于关闭状态

02.02 打开coredump功能

# 指定coredump文件大小,即打开coredump功能
#ulimit -c 1024         # 1024个blocks,一般1block=512bytes
ulimit -c unlimited    # 取消大小限制,开发,试运行阶段可以使用次参数

02.03 检查coredump文件的选项参数

ulimit -a # 显示当前所有limit信息
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 15154
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) unlimited
real-time priority              (-r) 0
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 1024
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

02.04 ulimit 参数介绍

命令参数      描述                                          例子
-H 设置硬资源限制,一旦设置不能增加。                       ulimit –Hs 64;限制硬资源,线程栈大小为 64K。
-S 设置软资源限制,设置后可以增加,但是不能超过硬资源设置。 ulimit –Sn 32;限制软资源,32 个文件描述符。
-a 显示当前所有的 limit 信息                                ulimit –a;显示当前所有的 limit 信息
-c 最大的 core 文件的大小, 以 blocks 为单位                ulimit –c unlimited; 对生成的 core 文件的大小不进行限制
-d 进程最大的数据段的大小,以 Kbytes 为单位                 ulimit -d unlimited;对进程的数据段大小不进行限制
-f 进程可以创建文件的最大值,以 blocks 为单位               ulimit –f 2048;限制进程可以创建的最大文件大小为 2048 blocks
-l 最大可加锁内存大小,以 Kbytes 为单位                     ulimit –l 32;限制最大可加锁内存大小为 32 Kbytes
-m 最大内存大小,以 Kbytes 为单位                           ulimit –m unlimited;对最大内存不进行限制
-n 可以打开最大文件描述符的数量                             ulimit –n 128;限制最大可以使用 128 个文件描述符
-p 管道缓冲区的大小,以 Kbytes 为单位                       ulimit –p 512;限制管道缓冲区的大小为 512 Kbytes
-s 线程栈大小,以 Kbytes 为单位                             ulimit –s 512;限制线程栈的大小为 512 Kbytes
-t 最大的 CPU 占用时间,以秒为单位                          ulimit –t unlimited;对最大的 CPU 占用时间不进行限制
-u 用户最大可用的进程数                                     ulimit –u 64;限制用户最多可以使用 64 个进程
-v 进程最大可用的虚拟内存,以 Kbytes 为单位                 ulimit –v 200000;限制最大可用的虚拟内存为 200000 Kbytes

02.05 配置coredump永久生效

ulimit -c unlimited类型的ulimit -c仅仅是设置当前session中启动转储功能。
要永久生效,需要修改配置文件。

02.05.01 在配置文件中设置coredemp生效

可以在/etc/profile,~/.bash_profile, ~/.bashrc 中的某一个加入

ulimit -c unlimited

通过 source /etc/profile 类型的命令,使设置在当前session中生效。

02.05.02

修改/etc/security/limits.conf

#vim /etc/security/limits.conf
<domain>    <type>    <item>        <value>
 
*          soft       core         unlimited

03 coredump文件的存储位置和文件名

03.01 转储文件默认位置

coredump文件默认的存储位置与对应的可执行程序在同一目录下,文件名是core.pid,可以通过下面的命令看到core文件的存在位置:

cat /proc/sys/kernel/core_pattern # 缺省值是|/usr/libexec/abrt-hook-ccpp %s %c %p %u %g %t e

注意:这里是指在进程当前工作目录的下创建。通常与程序在相同的路径下。但如果程序中调用了chdir函数,则有可能改变了当前工作目录。这时core文件创建在chdir指定的路径下。有好多程序崩溃了,我们却找不到core文件放在什么位置。和chdir函数就有关系。当然程序崩溃了不一定都产生 core文件。

echo "/data/coredump/core" > /proc/sys/kernel/core_pattern # 把core文件生成到/data/coredump/core目录下

03.02 coredump文件的命名

缺省情况下,内核在coredump时所产生的coredump文件放在与该程序相同的目录中,并且文件名固定为core。

A. coredump文件名带pid
/proc/sys/kernel/core_uses_pid可以控制core文件的文件名中是否添加pid作为扩展。文件内容为1,表示添加pid作为扩展名,生成的core文件格式为core.xxxx;为0则表示生成的core文件同一命名为core。可通过以下命令修改此文件:

echo "1" > /proc/sys/kernel/core_uses_pid

B. coredump文件名格式
proc/sys/kernel/core_pattern可以控制core文件保存位置和文件名格式,可通过以下命令修改此文件:

echo "/corefile/core-%e-%p-%t" > core_pattern # 可以将core文件统一生成到/corefile目录下,产生的文件名为core-命令名-pid-时间戳

C. coredump 文件名参数说明

%% - 单个%字符
%p - 添加pid
%u - 添加当前uid
%g - 添加当前gid
%s - 添加导致产生core的信号
%t - 添加core文件生成时的unix时间
%h - 添加主机名
%e - 添加程序文件名 

04 造成程序core的原因

造成程序coredump的原因有很多,这里总结一些比较常用的经验吧:

04.01 内存访问越界

A. 由于使用错误的下标,导致数组访问越界。
B. 搜索字符串时,依靠字符串结束符来判断字符串是否结束,但是字符串没有正常的使用结束符。
C. 使用strcpy, strcat, sprintf, strcmp, strcasecmp等字符串操作函数,将目标字符串读/写爆。应该使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函数防止读写越界。

04.02 多线程程序使用了线程不安全的函数

应该使用下面这些可重入的函数,它们很容易被用错

asctime_r(3c) 、gethostbyname_r(3n) 、getservbyname_r(3n)、ctermid_r(3s) 、gethostent_r(3n) 、getservbyport_r(3n)、 ctime_r(3c) 、getlogin_r(3c)、getservent_r(3n) 、fgetgrent_r(3c) 、getnetbyaddr_r(3n) 、getspent_r、(3c)fgetpwent_r、(3c) getnetbyname_r(3n)、 getspnam_r(3c)、 fgetspent_r(3c)、getnetent_r(3n) 、gmtime_r(3c)、 gamma_r(3m) 、getnetgrent_r(3n) 、lgamma_r(3m) 、getauclassent_r(3)、getprotobyname_r(3n) 、localtime_r(3c) 、getauclassnam_r(3) 、etprotobynumber_r(3n)、nis_sperror_r(3n) 、getauevent_r(3) 、getprotoent_r(3n) 、rand_r(3c) 、getauevnam_r(3)、getpwent_r(3c) 、readdir_r(3c) 、getauevnum_r(3) 、getpwnam_r(3c) 、strtok_r(3c)、 getgrent_r(3c)、getpwuid_r(3c) 、tmpnam_r(3s) 、getgrgid_r(3c) 、getrpcbyname_r(3n)、 ttyname_r(3c)、getgrnam_r(3c) 、getrpcbynumber_r(3n) 、gethostbyaddr_r(3n) 、getrpcent_r(3n)

04.03 多线程读写的数据未加锁保护

对于会被多个线程同时访问的全局数据,应该注意加锁保护,否则很容易造成coredump。

04.04 非法指针

A. 使用空指针
B. 随意使用指针转换。一个指向一段内存的指针,除非确定这段内存原先就分配为某种结构或类型,或者这种结构或类型的数组,否则不要将它转换为这种结构或类型的指针,而应该将这段内存拷贝到一个这种结构或类型中,再访问这个结构或类型。这是因为如果这段内存的开始地址不是按照这种结构或类型对齐的,那么访问它时就很容易因为bus error而core dump。

04.05 堆栈溢出:

不要使用大的局部变量(因为局部变量都分配在栈上),这样容易造成堆栈溢出,破坏系统的栈和堆结构,导致出现莫名其妙的错误。

05 用GDB调试coredump文件

注意:调试coredump文件最好是debug。因为有符号文件,方便问题定位。

05.01 一个产生coredump的c文件

testdump.c

void test_core_dump() {
    const char* str = "test_core_dump";
    char* p = (char*)str;
    p[0] = '0'; // 段错误程序终止,生成core文件
}

int main(int argc, char* argv[]) {
 
    test_core_dump();
    
    return 0;
}

编译

gcc -o testdump testdump.c

运行

 ./testdump 
段错误 (core dumped)
ls core*
core.18293

05.02 判断是否为core文件

在类unix系统下,coredump文件本身主要的格式也是ELF格式,可以通过简单的file命令进行快速判断。

file core.18293 
core.18293: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from './testdump', real uid: 500, effective uid: 500, real gid: 500, effective gid: 500, execfn: './testdump', platform: 'x86_64'

05.01 gdb调试方法01

A. 启动gdb,进入core文件,命令格式:gdb ["exec file params"] [core file],用法示例:

gdb ./testdump core.18293
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-92.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/soft/test/testdump...(no debugging symbols found)...done.
[New Thread 18293]
Reading symbols from /lib64/libc.so.6...Reading symbols from /usr/lib/debug/lib64/libc-2.12.so.debug...done.
done.
Loaded symbols for /lib64/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...Reading symbols from /usr/lib/debug/lib64/ld-2.12.so.debug...done.
done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
Core was generated by `./testdump'.
Program terminated with signal 11, Segmentation fault.
#0  0x000000000040048c in test_core_dump ()

B. 进入gdb后,查找段错误位置:where 或者 bt,用法示例:

(gdb) where
#0  0x000000000040048c in test_core_dump ()
#1  0x00000000004004aa in main ()
(gdb) bt
#0  0x000000000040048c in test_core_dump ()
#1  0x00000000004004aa in main ()

05.02 gdb调试方法02

A. 启动gdb,进入core文件,命令格式:
gdb -c [core file] //或 gdb --core=[core file]
B. 在进入gdb后,指定core文件对应的符号表,命令格式:
(gdb) file [exec file]
C. 查找段错误位置:where或者bt。用法示例:
bt

05.03 带符号的coredump文件调试效果

编译时,带-g参数,即debug版本产生coredump文件

$ gcc -g -o testdumpg testdump.c
$ ./testdumpg
段错误 (core dumped)
$ gdb "./testdumpg" core.18
core.18293  core.18473  
$ gdb "./testdumpg" core.18473 
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-92.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/soft/test/testdumpg...done.
[New Thread 18473]
Reading symbols from /lib64/libc.so.6...Reading symbols from /usr/lib/debug/lib64/libc-2.12.so.debug...done.
done.
Loaded symbols for /lib64/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...Reading symbols from /usr/lib/debug/lib64/ld-2.12.so.debug...done.
done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
Core was generated by `./testdumpg'.
Program terminated with signal 11, Segmentation fault.
#0  0x000000000040048c in test_core_dump () at testdump.c:5
5        p[0] = '0'; // 段错误程序终止,生成core文件
(gdb) where
#0  0x000000000040048c in test_core_dump () at testdump.c:5
#1  0x00000000004004aa in main (argc=1, argv=0x7ffff6b3ff08) at testdump.c:10
(gdb) q

05.04 不带符号的coredump文件调试效果

$ gcc -o testdump testdump.c
$ ./testdump
段错误 (core dumped)
$ gdb "./testdump" core.18506 
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-92.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/soft/test/testdump...(no debugging symbols found)...done.
[New Thread 18506]
Reading symbols from /lib64/libc.so.6...Reading symbols from /usr/lib/debug/lib64/libc-2.12.so.debug...done.
done.
Loaded symbols for /lib64/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...Reading symbols from /usr/lib/debug/lib64/ld-2.12.so.debug...done.
done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
Core was generated by `./testdump'.
Program terminated with signal 11, Segmentation fault.
#0  0x000000000040048c in test_core_dump ()
(gdb) where
#0  0x000000000040048c in test_core_dump ()
#1  0x00000000004004aa in main ()
(gdb) bt
#0  0x000000000040048c in test_core_dump ()
#1  0x00000000004004aa in main ()
(gdb) q
点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
4个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这