From:http://blog.csdn.net/mr_chenping/article/details/13767609
在Linux下程序不寻常退出时,内核会在当前工作目录下生成一个core文件(是一个内存映像,同时加上调试信息)。使用gdb来查看core文件,可以指示出导致程序出错的代码所在文件和行数。
注:
1. 当然首先编译时要带上gdb信息
1. core文件的生成开关和大小限制
1.1使用ulimit -c命令可查看core文件的生成开关。
若结果为0,则表示关闭了此功能,不会生成core文件。
1.2 使用ulimit -c filesize命令,可以限制core文件的大小(filesize的单位为kbyte)。
如果生成的信息超过此大小,将会被裁剪,最终生成一个不完整的core文件或者根本就不生成。如果生成被裁减的core文件,调试此core文件的时候,gdb也会提示错误。
用以下命令来表示core文件的大小不受限制。
ulimit -c unlimited
用以下命令来阻止系统生成core文件:
ulimit -c 0
下面的命令可以检查生成core文件的选项是否打开:
ulimit -a
该命令将显示所有的用户定制,其中选项-a代表“all”。
-
$ 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
注:
a) ulimit命令设置后只对一个终端有效,所以另起终端后需要重新设置。
b) 要在整个系统中生效,可以通过如下方法(当然此方法未必管用和linux版本相关):
b.1) 编辑/root/.bash_profile文件,在其中加入:ulimit -S -c unlimited (需要注意的是:不是每个版本的系统都有这个文件(Suse下面就没有),可以手工创建)
b.2) 重启系统或者执行:soruce /root/.bash_profile
c) 关于 ulimit 命令的用法见:
2. core文件的名称和生成路径
core文件生成路径:
输入可执行文件运行命令的同一路径下。若系统生成的core文件不带其它任何扩展名称,则全部命名为core。新的core文件生成将覆盖原来的core文件。
2.1. /proc/sys/kernel/core_uses_pid可以控制core文件的文件名中是否添加pid作为扩展。
文件内容为1,表示添加pid作为扩展名,生成的core文件格式为core.xxxx;为0则表示生成的core文件同一命名为core。
可通过以下命令修改此文件:
-
echo "1" > /proc/sys/kernel/core_uses_pid
2.2 . /proc/sys/kernel/core_pattern或者/etc/sysctl.conf文件,可以控制core文件保存位置和文件名格式。到底哪一个,和系统版本相关,需要实际测试.
2.2.1 修改/proc/sys/kernel/core_pattern, 可通过以下命令修改此文件:
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 添加命令名
注:
a) 目录proc文件系统是一个伪文件系统,以文件系统的方式为访问系统内核数据的操作提供接口。/proc目录的内容为系统启动时自动生成的,某写文件可改,某写
文件不可改。比如可以通过修改proc的文件微调内核参数。使用vi可能无法成功编辑proc/sys/kernel/core_pattern,只能使用echo命令修改或者命令sysctl修改。sysctl命令如下:
-
sysctl -w "kernel.core_pattern=$core_dir/core_%e_%t" >/dev/null
-
sysctl -w "kernel.core_uses_pid=0" >/dev/null
b) 即使使用echo命令修改成功,也可能无法成功产生core文件,如所用的centor5.4 装于虚拟机中。proc/sys/kernel/core_pattern内容为:
-
/usr/libexec/abrt-hook-ccpp %s %c %p %u %g %t e
按照上述方式修改(echo "/corefile/core-%e-%p-%t" > core_pattern),core文件甚至都不再产生.
2.2.2 修改/etc/sysctl.conf ( )
添加需要保存的路径 "kernel.core_pattern =
/tmp/corefile/core.%e.%t",需要注意的是该路径必须应用有写的权限,不然core文件是不会生成的。再执行命令"sysctl
-p"即可生效。关于core_users_pid默认在sysctl文件里面已经存在,不需要更改,pid还是很重要的信息。
注:
a) 需要注意的是,如果 /tmp/corefile目录原先不存在,那么生成的 core dump 文件就无处存放,所以要先确定设置的目录是事先存在的。
3. core文件产生促发条件
当程序接收到以下信号时会产生 core 文件:
-
SIGABRT :异常终止(abort)时发出的信号
-
说明:
-
调用abort函数时产生此信号。进程异常终止。
-
-
SIGBUS :硬件发生故障时发出的信号
-
说明:
-
指示一个实现定义的硬件故障。
-
-
SIGFPE :算术异常时发出的信号
-
说明:
-
此信号表示一个算术运算异常,例如除以0,浮点溢出等。
-
-
SIGILL :遇到非法硬件指令时发出的信号
-
说明:
-
此信号指示进程已执行一条非法硬件指令。4.3BSD由abort函数产生此信号。现在 abort() 函数用来生成 SIGABRT 信号。
-
-
SIGIOT :硬件故障时发出的信号
-
说明:
-
IOT这个名字来自于PDP-11对于 输入/输出 TRAP(input/output TRAP)指令的缩写。系统V的早期版本,由abort函数产生此信号。SIGABRT现在被用于此。
-
-
SIGQUIT :终端退出时发出的信号
-
说明:
-
当用户在终端上按退出键(一般采用Ctrl-\)时,产生此信号,并送至前台进程组中的所有进程。此信号不仅终止前台进程组(如SIGINT所做的那样),同时产生一个core文件。
-
-
SIGSEGV :无效存储访问发出的信号
-
说明:
-
进程进行了一次无效的存储访问。字SEGV表示“段违例(segmentation violation)”。
-
-
SIGSYS :无效的系统调用时发出的信号
-
说明:
-
进行了一个无效的系统调用。由于某种未知原因,进程执行了一条系统调用指令,但其指示系统调用类型的参数却是无效的。
-
-
SIGTRAP :硬件故障时发出的信号
-
说明:
-
此信号名来自于 PDP-11 的TRAP指令。
-
-
SIGXCPU :超过CPU限制(setrlimit)时发出的信号
-
说明:
-
SVR4 和 4.3+BSD 支持资源限制的概念。如果进程超过了其软 CPU 时间限制,则产生此信号。XCPU 是 "exceeded CPU time“ 的缩写。
-
-
SIGXFSZ :超过文件长度限制(setrlimit)时发出的信号
-
说明:
-
如果进程超过了其软文件长度限制时发出此信号。
4. core文件调试
4.1 调试命令(http://blog.csdn.net/shaovey/article/details/2744487)
core文件需要使用gdb来查看。
-
gdb ./a.out
-
core-file core.xxxx
使用bt命令即可看到程序出错的地方。
以下两种命令方式具有相同的效果,但是在有些环境下不生效,所以推荐使用上面的命令。
-
1)gdb -core=core.xxxx
-
file ./a.out
-
bt
-
2)gdb -c core.xxxx
-
file ./a.out
-
bt
4.2 例子
写个简单的程序,看看core文件是不是会被产生。(http://blogger.org.cn/blog/more.asp?name=yach&id=22810)
-
#include
-
static void sub(void);
-
int main(void)
-
{
-
sub();
-
return 0;
-
}
-
-
static void sub(void)
-
{
-
int *p = NULL;
-
-
printf("%d", *p);
-
}
-
$ gcc -Wall -g foo.c
-
$ ./a.out
-
Segmentation fault
-
-
$ ls -l core.*
-
ls: core.*: No such file or directory
没有找到core文件,我们改改ulimit的设置,让它产生。1024是随便取的,要是core文件大于1024个块,就产生不出来了。
-
$ ulimit -c 1024
-
-
$ ulimit -a
-
core file size (blocks, -c) 1024
-
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
-
-
$ ./a.out
-
Segmentation fault (core dumped)
-
$ ls -l core.*
-
-rw------- 1 uniware uniware 53248 Jun 30 17:10 core.9128
注意看上述的输出信息,多了个(core dumped)。确实产生了一个core文件,9128是该进程的PID。我们用GDB来看看这个core。
-
$ gdb --core=core.9128
-
GNU gdb Asianux (6.0post-0.20040223.17.1AX)
-
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 "i386-asianux-linux-gnu".
-
Core was generated by `./a.out'.
-
Program terminated with signal 11, Segmentation fault.
-
#0 0x08048373 in ?? ()
-
(gdb) bt
-
#0 0x08048373 in ?? ()
-
#1 0xbfffd8f8 in ?? ()
-
#2 0x0804839e in ?? ()
-
#3 0xb74cc6b3 in ?? ()
-
#4 0x00000000 in ?? ()
此时用bt看不到backtrace,也就是调用堆栈,原来GDB还不知道符号信息在哪里。我们告诉它一下:
-
(gdb) file ./a.out
-
Reading symbols from ./a.out...done.
-
Using host libthread_db library "/lib/tls/libthread_db.so.1".
-
(gdb) bt
-
#0 0x08048373 in sub () at foo.c:17
-
#1 0x08048359 in main () at foo.c:8
此时backtrace出来了。
-
(gdb) l
-
8 sub();
-
9 return 0;
-
10 }
-
11
-
12 static void sub(void)
-
13 {
-
14 int *p = NULL;
-
15
-
16 /* derefernce a null pointer, expect core dump. */
-
17 printf("%d", *p);
-
(gdb)
4.3 开发板上使用core文件调试(http://blog.csdn.net/shaovey/article/details/2744487)
如果开发板的操作系统也是linux,core调试方法依然适用。如果开发板上不支持gdb,可将开发板的环境(依赖库)、可执行文件和core文件拷贝到PC的linux下。
在PC上调试开发板上产生的core文件,需要使用交叉编译器自带的gdb,并且需要在gdb中指定solib-absolute-prefix和
solib-search-path两个变量以保证gdb能够找到可执行程序的依赖库路径。有一种建立配置文件的方法,不需要每次启动gdb都配置以上变
量,即:在待运行gdb的路径下建立.gdbinit。
配置文件内容:
-
set solib-absolute-prefix YOUR_CROSS_COMPILE_PATH
-
set solib-search-path YOUR_CROSS_COMPILE_PATH
-
set solib-search-path YOUR_DEVELOPER_TOOLS_LIB_PATH
-
handle SIG32 nostop noprint pass
注意:待调试的可执行文件,在编译的时候需要加-g,core文件才能正常显示出错信息!有时候core信息很大,超出了开发板的空间限制,生成的core信息会残缺不全而无法使用,可以通过挂载到PC的方式来规避这一点。
5. 附录:
5.1 ulimit命令
1、说明:
ulimit用于shell启动进程所占用的资源.
2、类别:
shell内建命令
3、语法格式:
-
ulimit [-acdfHlmnpsStvw] [size]
4、参数介绍:
-H 设置硬件资源限制.
-S 设置软件资源限制.
-a 显示当前所有的资源限制.
-c size:设置core文件的最大值.单位:blocks
-d size:设置数据段的最大值.单位:kbytes
-f size:设置创建文件的最大值.单位:blocks
-l size:设置在内存中锁定进程的最大值.单位:kbytes
-m size:设置可以使用的常驻内存的最大值.单位:kbytes
-n size:设置内核可以同时打开的文件描述符的最大值.单位:n
-p size:设置管道缓冲区的最大值.单位:kbytes
-s size:设置堆栈的最大值.单位:kbytes
-t size:设置CPU使用时间的最大上限.单位:seconds
-v size:设置虚拟内存的最大值.单位:kbytes 5,简单实例:
5、举例
在Linux下写程序的时候,如果程序比较大,经常会遇到“段错误”(segmentationfault)这样的问题,这主要就是由于Linux系
统初始的堆栈大小(stack size)太小的缘故,一般为10M。我一般把stacksize设置成256M,这样就没有段错误了!命令为:
ulimit -s 262140
如果要系统自动记住这个配置,就编辑/etc/profile文件,在 “ulimit -S -c 0 > /dev/null 2>&1”行下,添加“ulimit -s 262140”,保存重启系统就可以了!
1] 在RH8的环境文件/etc/profile中,我们可以看到系统是如何配置ulimit的:
-
#grep ulimit /etc/profile
-
ulimit -S -c 0 > /dev/null 2>&1
这条语句设置了对软件资源和对core文件大小的设置
2]如果我们想要对由shell创建的文件大小作些限制,如:
-
#ll h
-
-rw-r--r-- 1 lee lee 150062 7月 22 02:39 h
-
#ulimit -f 100 #设置创建文件的最大块(一块=512字节)
-
#cat h>newh
-
File size limit exceeded
-
#ll newh
-
-rw-r--r-- 1 lee lee 51200 11月 8 11:47 newh
文件h的大小是150062字节,而我们设定的创建文件的大小是512字节x100块=51200字节. 当然系统就会根据你的设置生成了51200字节的newh文件.
3]可以像实例1]一样,把你要设置的ulimit放在/etc/profile这个环境文件中.
用途
设置或报告用户资源极限。
语法
-
ulimit [ -H ] [ -S ] [ -a ] [ -c ] [ -d ] [ -f ] [ -m ] [ -n ] [ -s ] [ -t ] [ Limit ]
描述
ulimit 命令设置或报告用户进程资源极限,如 /etc/security/limits 文件所定义。文件包含以下缺省值极限:
-
fsize = 2097151
-
core = 2097151
-
cpu = -1
-
data = 262144
-
rss = 65536
-
stack = 65536
-
nofiles = 2000
当新用户添加到系统中时,这些值被作为缺省值使用。当向系统中添加用户时,以上值通过 mkuser 命令设置,或通过 chuser
命令更改。极限分为软性或硬性。通过 ulimit 命令,用户可将软极限更改到硬极限的最大设置值。要更改资源硬极限,必须拥有 root 用户权限。
很多系统不包括以上一种或数种极限。 特定资源的极限在指定 Limit 参数时设定。Limit
参数的值可以是每个资源中指定单元中的数字,或者为值 unlimited。要将特定的 ulimit 设置为 unlimited,可使用词
unlimited。
注:在 /etc/security/limits 文件中设置缺省极限就是设置了系统宽度极限, 而不仅仅是创建用户时用户所需的极限。
省略 Limit 参数时,将会打印出当前资源极限。除非用户指定 -H 标志,否则打印出软极限。当用户指定一个以上资源时,极限名称和单元在值之前打印。如果未给予选项,则假定带有了 -f 标志。
由于 ulimit 命令影响当前 shell 环境,所以它将作为 shell 常规内置命令提供。如果在独立的命令执行环境中调用该命令,则不影响调用者环境的文件大小极限。以下示例中正是这种情况:
-
nohup ulimit -f 10000
-
env ulimit 10000
一旦通过进程减少了硬极限,若无 root 特权则无法增加,即使返回到原值也不可能。
关于用户和系统资源极限的更多信息,请参见 AIX 5L Version 5.3 Technical Reference:
BaseOperating System and Extensions Volume 1 中的 getrlimit、setrlimit
或 vlimit 子例程。
标志
-a 列出所有当前资源极限。
-c 以 512 字节块为单位,指定核心转储的大小。
-d 以 K 字节为单位指定数据区域的大小。
-f 使用 Limit 参数时设定文件大小极限(以块计),或者在未指定参数时报告文件大小极限。缺省值为 -f 标志。
-H 指定设置某个给定资源的硬极限。如果用户拥有 root 用户权限,可以增大硬极限。任何用户均可减少硬极限。
-m 以 K 字节为单位指定物理存储器的大小。
-n 指定一个进程可以拥有的文件描述符的数量的极限。
-s 以 K 字节为单位指定堆栈的大小。
-S 指定为给定的资源设置软极限。软极限可增大到硬极限的值。如果 -H 和 -S 标志均未指定,极限适用于以上二者。
-t 指定每个进程所使用的秒数。
退出状态
返回以下退出值:
0 成功完成。
>0 拒绝对更高的极限的请求,或发生错误。
示例
要将文件大小极限设置为 51,200 字节,输入:
ulimit -f 100
源地址:http://blog.csdn.net/arau_sh/article/details/8182744