segmentation fault core dump

  • 在代码量较多时,调试比较困难。常用方法是在源码中插入大量的printf语句。但是当发生segmentation fault时,定位就比较复杂了。

core dump又叫核心转储, 当程序运行过程中发生异常, 程序异常退出时, 由操作系统把程序当前的内存状况存储在一个core文件中, 叫core dump. (linux中如果内存越界会收到SIGSEGV信号,然后就会core dump)

 

在程序运行的过程中,有的时候我们会遇到Segment fault(段错误)这样的错误。这种看起来比较困难,因为没有任何的栈、trace信息输出。该种类型的错误往往与指针操作相关。往往可以通过这样的方式进行定位。

 

 造成segment fault,产生core dump的可能原因

 

1.内存访问越界

 

a) 由于使用错误的下标,导致数组访问越界

 

b) 搜索字符串时,依靠字符串结束符来判断字符串是否结束,但是字符串没有正常的使用结束符

 

c) 使用strcpy, strcat, sprintf, strcmp, strcasecmp等字符串操作函数,将目标字符串读/写爆。应该使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函数防止读写越界。

 

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

 

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

 

4 非法指针

 

a) 使用空指针

 

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

 

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

 

二 配置操作系统使其产生core文件

 

首 先通过ulimit命令查看一下系统是否配置支持了dump core的功能。通过ulimit -c或ulimit -a,可以查看core file大小的配置情况,如果为0,则表示系统关闭了dump core。可以通过ulimit -c unlimited来打开。若发生了段错误,但没有core dump,是由于系统禁止core文件的生成。

 

解决方法:

$ulimit -c unlimited  (只对当前shell进程有效)

或在~/.bashrc 的最后加入: ulimit -c unlimited (一劳永逸)

 

# ulimit -c

 

0

 

 

$ ulimit -a

core file size (blocks, -c) 0

 

data seg size (kbytes, -d) unlimited

 

file size (blocks, -f) unlimited

 

三 用gdb查看core文件

 

发生core dump之后, 用gdb进行查看core文件的内容, 以定位文件中引发core dump的行.

 

gdb [exec file] [core file]

 

如: gdb ./test test.core

 

四 样例

 

1. 空指针

 

样例:

 

#include

 

int main(void)

 

{

 

printf("hello world! dump core for set value to NULL pointer\n");

 

*(char *)0 = 0;

 

return 0;

 

}

 

# gcc -g test.c -o test

 

# ./test

 

hello world! dump core for set value to NULL pointer

 

Segmentation fault

 

/× Get segmentation fault, but there is no core dump. The reason is that the system configure core file size to zero ×/

 

# ls

 

test test.c

 

/* Set core file size to unlimited */

 

# ulimit -c unlimited

 

# ./test

 

hello world! dump core for set value to NULL pointer

 

Segmentation fault (core dumped)

 

/* Get core dump after change core file size. */

 

# ls

 

core.5581 test test.c

 

/* gdb to debug core dump */

 

# gdb test core.5581

GNU gdb Red Hat Linux (6.3.0.0-1.132.EL4rh)

Copyright 2004 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB. Type "show warranty" for details.

This GDB was configured as "x86_64-redhat-linux-gnu"...Using host libthread_db library "/lib64/tls/libthread_db.so.1".

 

Core was generated by `./test'.

Program terminated with signal 11, Segmentation fault.

Reading symbols from /lib64/tls/libc.so.6...done.

Loaded symbols for /lib64/tls/libc.so.6

Reading symbols from /lib64/ld-linux-x86-64.so.2...done.

Loaded symbols for /lib64/ld-linux-x86-64.so.2

#0 0x000000000040048b in main () at test.c:6

 

warning: Source file is more recent than executable.

 

6 *(char *)0 = 0;

(gdb) bt

#0 0x000000000040048b in main () at test.c:6

 

2. 栈溢出。

 

有关栈溢出的程序,请参见:一个测试栈大小的小程序

 

http://blog.163.com/huang_bp/blog/static/12311983720099150746901/edit/

 

 

# gcc -g test.c -o test -lpthread

 

# ls

 

test test.c

 

# ./test

 

...

 

Segmentation fault (core dumped)

 

# ls

 

core.5616 test test.c

 

# gdb test core.5616

GNU gdb Red Hat Linux (6.3.0.0-1.132.EL4rh)

Copyright 2004 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB. Type "show warranty" for details.

This GDB was configured as "x86_64-redhat-linux-gnu"...Using host libthread_db library "/lib64/tls/libthread_db.so.1".

 

Core was generated by `./test'.

Program terminated with signal 11, Segmentation fault.

Reading symbols from /lib64/tls/libpthread.so.0...done.

Loaded symbols for /lib64/tls/libpthread.so.0

Reading symbols from /lib64/tls/libc.so.6...done.

Loaded symbols for /lib64/tls/libc.so.6

Reading symbols from /lib64/ld-linux-x86-64.so.2...done.

Loaded symbols for /lib64/ld-linux-x86-64.so.2

#0 0x0000002a957c051e in vfprintf () from /lib64/tls/libc.so.6

(gdb) list

13

14 buffer[0]=i;

15 test(s);

16 }

17

18 int main()

19 {

20 pthread_t p;

21

22 pthread_create(&p, NULL, &test, NULL);

 

对于栈溢出的segment fault没有第一个定位方便,需要分析代码才能判断出原因。 

在嵌入式的开发和测试中,有时候一些问题只能在特定的环境下才能重现,重现的时机和条件都难以把握,可能很多次的测试才能偶尔的重现一次问题,这给我们的调试和修改都带来很多不便之处

还有一种难以跟踪调试的情形,在大型的软件项目中,要从数万行甚至更多的代码中准确的找到问题所在,靠设断点和单步跟踪的方法是很麻烦很需要时间的.

这些问题可以通过Core Dump的方式,或者说事后调试(postmortem debug)技术,来协助分析.主要方法是在程序崩溃的时候,将程序的内存映象加上调试信息保存到一个文件中,这后通过分析这个所谓的Core文件来找到程序崩溃的原因.Core Dump的名称来源于以前工业界的叫法---当内存还是线圈的时候,它被叫做Core,我们可以利用GDB来分析core文件来查找出错的原因.

1. core文件的简单介绍
在一个程序崩溃时,它一般会在指定目录下生成一个core文件。core文件仅仅是一个内存映象(同时加上调试信息),主要是用来调试的。

2. 开启或关闭core文件的生成
用以下命令来阻止系统生成core文件:
ulimit -c 0
下面的命令可以检查生成core文件的选项是否打开:
ulimit -a
该命令将显示所有的用户定制,其中选项-a代表“all”。
也可以修改系统文件来调整core选项
在/etc/profile通常会有这样一句话来禁止产生core文件,通常这种设置是合理的:
# No core files by default
ulimit -S -c 0 > /dev/null 2>&1
但是在开发过程中有时为了调试问题,还是需要在特定的用户环境下打开core文件产生的设置
在用户的~/.bash_profile里加上ulimit -c unlimited来让特定的用户可以产生core文件
如果ulimit -c 0 则也是禁止产生core文件,而ulimit -c 1024则限制产生的core文件的大小不能超过1024kb


3. 设置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" > /proc/sys/kernel/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 添加命令名


4. 使用core文件
在core文件所在目录下键入:
gdb -c core
它会启动GNU的调试器,来调试core文件,并且会显示生成此core文件的程序名,中止此程序的信号等等
如果你已经知道是由什么程序生成此core文件的,比如MyServer崩溃了生成core.12345,那么用此指令调试:
gdb -c core MyServer
以下怎么办就该去学习gdb的使用了


5. 一个小方法来测试产生core文件
直接输入指令:
kill -s SIGSEGV $$

【详细说明】
当程序因为未知原因down掉后,可以使用core dump把内存dump出来,用来调试时使用。 

看一下core dump是否开启
#ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
max locked memory (kbytes, -l) 4
max memory size (kbytes, -m) unlimited
open files (-n) 2048
pipe size (512 bytes, -p) 8
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 7168
virtual memory (kbytes, -v) unlimited
看到core file size是0,说明core dump没开启,使用ulimit -c unlimited来开启core dump,当然unlimited也可以换成具体的文件大小(单位是kb),只是unlimited最省事儿
设置core dump文件名及其位置
/proc/sys/kernel/core_uses_pid 这个文件内容为0的话,所有core dump文件名都是core,没有扩展名;内容为1的话,文件名编程core.pid,即加上进程号作为扩展名。
还可以通过修改/proc/sys/kernel/core_pattern来指定core dump文件位置和文件名,此文件内容改为/tmp/coredumpfile/core-%e-%p-%t,表示所有的core dump都放在/tmp/coredumpfile目录下,文件名为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 添加命令名
查看core dump
gdb --core=core.12345(core dump文件名) 或 gdb exe名 core名
bt 查看程序运行到哪儿,backtrace
file exe名 找exe位置
l 列出代码
where 显示在哪儿down掉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值