转载请注明出处:http://blog.chinaunix.net/u3/105349/showart.php?id=2121419
1. 什么是 core 文件
在一个进程异常终止时,在一定的条件下(下面将介绍),会在当前工作目录下生成一个core文件。
core文件是该进程(异常终止时)的内存映像(同时加上调试信息)。大多数调试程序都使用 core 文件以检查进程终止时的状态。
2. 产生 core 的条件
当进程接收到以下信号时,默认动作会产生core文件:
UNIX System signals
Name |
Description |
ISO C |
SUS |
FreeBSD5.2.1 |
Linux2.4.22 |
MacOSX10.3 |
Solaris9 |
默认动作 |
SIGABRT |
异常终止(abort) |
Y |
Y |
Y |
Y |
Y |
Y |
终止+core |
SIGBUS |
硬件故障 |
|
Y |
Y |
Y |
Y |
Y |
终止+core |
SIGEMT |
硬件故障 |
|
|
Y |
Y |
Y |
Y |
终止+core |
SIGFPE |
算术异常 |
Y |
Y |
Y |
Y |
Y |
Y |
终止+core |
SIGILL |
非法硬件指令 |
Y |
Y |
Y |
Y |
Y |
Y |
终止+core |
SIGIOT |
硬件故障 |
|
|
Y |
Y |
Y |
Y |
终止+core |
SIGQUIT |
终端退出符 |
|
Y |
Y |
Y |
Y |
Y |
终止+core |
SIGSEGV |
无效内存引用 |
Y |
Y |
Y |
Y |
Y |
Y |
终止+core |
SIGSYS |
无效系统调用 |
|
XSI |
Y |
Y |
Y |
Y |
终止+core |
SIGTRAP |
硬件故障 |
|
XSI |
Y |
Y |
Y |
Y |
终止+core |
SIGXCPU |
超过CPU限制(setrlimit) |
|
XSI |
Y |
Y |
Y |
Y |
终止+core |
SIGXFSZ |
超过文件长度限制(setrlimit) |
|
XSI |
Y |
Y |
Y |
Y |
终止+core |
说明:
1) 在不同的实现中,core 文件的名字可能不同。例如,在 FreeBSD5.2.1 中,core 文件名为 cmdname.core,其中, cmdname 是接收到信号的进程所执行的命令名。在 Mac OS X 10.3 中,core 文件名是 core.pid,其中,pid 是接收到信号的进程的ID。(这些系统允许经 sysctl 参数配置 core 文件名)
大多数实现在相应进程的当前工作目录中存放 core 文件;但 Max OS X 将所有 core 文件都放置在 /cores 目录中。
core 文件的权限(假定该文件在此之前并不存在)通常是用户 读/写,但 Mac OS X只设置为用户读。
2) 上表中“硬件故障”对应于实现定义的硬件故障。这些名字中有很多取自UNIX早先在DP-11 上的实现。
请查看你所使用的系统的手册,以确切地确定这些信号对应于哪些错误类型。
3)
SIGIOT 信号:
On FreeBSD 5.2.1, Linux 2.4.22, Mac OS X 10.3, and Solaris 9, SIGIOT is defined to be the same value as SIGABRT.
SIGEMT 信号:
Not all platforms support this signal. On Linux, for example, SIGEMT is supported only for selected architectures, such as SPARC, MIPS, and PA-RISC.
3. 阻止产生 core 文件的 6 种情况:
1) 进程是设置用户 ID 的,而且当前用户并非程序文件的所有者;
2) 进程是设置组 ID 的,而且当前用户并非该程序文件的组所有者;
3) 用户没有写当前工作目录的权限;
4) 该文件已存在,而且用户对该文件没有写权限;(上述 4 条超级用户除外)
5) 该文件太大(超过了 RLIMIT_CORE 限制,下面将介绍:查询、更改该值的方法)
特殊情况:
6)如果程序是通过 daemon 命令来启动的,需要编辑文件:/etc/init.d/functions,注释掉ulimit的设置或改变这行:
a) 在 Linux rh8 2.4.20-24.8 下为:
ulimit -S -c 0 >/dev/null 2>&1
b) 在 Linux 2.6.23.1-42.fc8 下为:
corelimit="ulimit -S -c ${DAEMON_COREFILE_LIMIT:-0}"
第五条也是控制 core 文件的产生与否的最方便的方法(通过执行命令 ulimit -c coresize )。
注意: 上述12种信号(有的系统可能没有这么多)的默认动作是: 终止+core。但是,如果将上述信号忽略,或者设置信号捕捉函数,则不产生core 文件。
4. 对 3 中条件 5 --RLIMIT_CORE 限制的说明
每一个进程都有一组资源限制值,其中的一些可以用 getrlimit 和 setrlimit 函数查询可更改。
1)
#include <sys/resource.h> int getrlimit(int resource, struct rlimit *rlptr); int setrlimit(int resource, const struct rlimit *rlptr); Both return: 0 if OK, nonzero on error |
其中,rlimit 结构如下:
struct rlimit { rlim_t rlim_cur; /* soft limit: current limit */ rlim_t rlim_max; /* hard limit: maximum value for rlim_cur */ }; |
在更改资源限制时,须遵循下列三条规则:
a)任何一个进程都可以将一个软限制值更改为 <= 其硬限制值。
b)任何一个进程都可降低其硬限制值,但它必须 >= 其软限制值。这种降低对普通用户而言是不可逆的。
c)只有超级用户进程可以提高硬限制值。
注意:
常量 RLIM_INFINITY 指定了一个无限量的限制。
(有关资源限制的更多信息,见 APUE2 学习笔记《getrlimit和setrlimit函数》)
2) 在所有资源限制值中,有个名称为:RLIMIT_CORE 的资源限制值,它指定了 core 文件的最大字节数,
若其值为0, 则阻止创建core文件。(这也是 3 中条件5的特殊情况)
5. ulimit 命令
1) ulimit -H -c :显示硬限制值。
ulimit -S -c :显示软限制值。(软限制值直接影响 core 文件的大小)
ulimit -c :显示软限制值。
如果上述前 2 个命令后面加上数值,则为设置相应的限制值。
如果:ulimit -c unlimited,则表示core文件的大小不受限制,与 RLIM_INFINITY 相应。
第三个命令有点不同:
ulimit -c 100 同时修改了:RLIMIT_CORE 的软限制值和硬限制值。
这里的 100 指的是 块(block) 的个数,实际的 RLIMIT_CORE 限制值是以字节为单位,
所以 core 文件的大小限制,以linux 为例,为 1024 * 100 = 102400 bytes。
(查看 block 大小的方法(以 sda 为例):/sbin/tune2fs -l /dev/sda1 )
2) Linux 系统默认的 RLIMIT_CORE 软、硬限制值分别是: 0 和 无限大。
所以,第一次的时候,由于硬限制值为无限大,普通用户可以使用命令: ulimit -c 100 设置RLIMIT_CORE 限制值。
这个时候,RLIMIT_CORE 的软、硬限制值都为 100 * 1024。
如果下次再执行 ulimit -c coresize, 则这里的 coresize 必须小于或等于 100.
6. 永久和临时设置 core 文件大小
1) Linux 下,默认是不会产生 core 文件的,执行 ulimit -c ,其结果为:0
查看文件 /etc/profile ,
# No core files by default ulimit -S -c 0 > /dev/null 2>&1 |
这里设定了 core 文件的大小为0 ,所以禁止产生 core 文件。
2) 永久设置 core 文件的大小。举例说明:
ulimit -S -c 100 > /dev/null 2>&1
这样,core 文件的大小限制为:100 *1024 bytes。
注意:这里仅仅是设定RLIMIT_CORE 的软限制值为100 * 1024, 其硬限制值仍旧为:无限大。
另外:配置文件 /etc/security/limits.conf 或 ~/.bash_profile 也可以设置core大小限制。(本文不考虑)
3) 临时设置 core 文件的大小:ulimit -c size。
该命令设置的大小只是影响:当前 shell 以及该shell中调用的进程,并由其子进程继承。
对其他 shell 没有任何影响。
7. 使用 core 文件的示例
示例代码: main.c
#include <stdio.h> #include <unistd.h> int main(int argc, char *argv[]) { char *str = NULL; printf("pid = %d\n", getpid()); sprintf(str, "123"); return 0; } |
编译保存为:m (注意:在编译程序的时候要加入选项 -g )
[liumin@bogon core]$ gcc -g -o m main.c
执行结果:
第一步:把 core 文件大小设置为:无限制。
[liumin@bogon core]$ ulimit -S -c unlimited
[liumin@bogon core]$ ulimit -c
unlimited
第二步:执行程序 m
[root@bogon core]# ./m
pid = 16694
Segmentation fault (core dumped)
[liumin@bogon core]$ ls -l
total 76
-rw------- 1 liumin liumin 143360 2009-12-13 23:29 core.16694
-rwxrwxr-x 1 liumin liumin 6178 2009-12-13 23:22 m
-rw-rw-r-- 1 liumin liumin 167 2009-12-13 23:22 main.c
第三步:使用 core 文件检查进程终止时的状态。
core 文件是个二进制文件,需要用相应的工具来分析程序崩溃时的内存映像。
我们可以使用 GDB。
[liumin@bogon core]$ gdb m core.16694
GNU gdb 6.6
Copyright (C) 2006 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 "i686-pc-linux-gnu"...
Using host libthread_db library "/lib/libthread_db.so.1".
warning: Can't read pathname for load map: Input/output error.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./m'.
Program terminated with signal 11, Segmentation fault.
#0 0x08048404 in main () at main.c:10
10 sprintf(str, "123");
(gdb) where
#0 0x08048404 in main () at main.c:10
(gdb) backtrace
#0 0x08048404 in main () at main.c:10
(gdb) bt
#0 0x08048404 in main () at main.c:10
GDB中键入where 或 backtrace 或 bt,就会看到程序崩溃时堆栈信息
(当前函数之前的所有已调用函数的列表(包括当前函数),gdb只显示最近几个),
我们很容易找到导致程序崩溃的代码的位置。
你也可以试试其他命令,如 frame、list等。更详细的用法,请查阅GDB文档。
8. 非 0 情况下,core 文件大小对 core 的影响
若ulimit -c size,设定 core 文件的大小限制。如果生成的信息超过此大小,将会被裁剪。
而且,裁剪之后 core 文件的大小,不是完全等于 size * block size 大小(在一定范围内,有时大,有时小)。
在网上看到一种说法:
如果 core 文件被裁剪,在调试此core文件的时候,gdb会提示错误。
但是:我用上面的示例代码,测试 core 文件裁剪后,gdb 调试并没有报错。
以上面的代码为例,测试过程如下:
0) 其 core 文件的完整大小为:143360 bytes
1) 执行:ulimit -c 1 (则实际限制为 1 * 1024 bytes)-->没有产生 core 文件
2) 执行: ulimit -c 2 (则实际限制为 2 * 1024 bytes)-->没有产生 core 文件
3) 执行: ulimit -c 3 (则实际限制为 3 * 1024 bytes)-->没有产生 core 文件
4) 执行: ulimit -c 4 (则实际限制为 4 * 1024 bytes = 4096)-->产生 core 文件
-rw------- 1 root root 972 2009-12-14 22:01 core.3066 (972 < 4096 bytes)
5) 执行: ulimit -c 5 (则实际限制为 5 * 1024 bytes = 5120)-->产生 core 文件
-rw------- 1 root root 8192 2009-12-14 22:03 core.3114 (8192 > 5120 bytes)
6) 设置 ulimit -c 6 (则实际限制为 6 * 1024 bytes = 6144)-->产生 core 文件
-rw------- 1 root root 8192 2009-12-14 22:03 core.3137 (8192 > 6144 bytes)
7) 设置 ulimit -c 7 (则实际限制为 7 * 1024 bytes = 7168)-->产生 core 文件
-rw------- 1 root root 8192 2009-12-14 22:03 core.3137 (8192 > 7168 bytes)
8) 设置 ulimit -c 8 (则实际限制为 8 * 1024 bytes = 8192)-->产生 core 文件
-rw------- 1 root root 8192 2009-12-14 22:03 core.3137 (8192 = 8192 bytes)
9) 设置 ulimit -c 9 (则实际限制为 9 * 1024 bytes = 9216)-->产生 core 文件
-rw------- 1 root root 12288 2009-12-14 22:09 core.3307 (12288 > 9216 bytes)
10) 设置 ulimit -c 10 (则实际限制为 10 * 1024 bytes = 10240)-->产生 core 文件
-rw------- 1 root root 12288 2009-12-14 22:10 core.3355 (12288 > 10240 bytes)
...... 后面没有继续测试。
猜测:莫非 core 文件的大小限制(非 0 时),对系统来说,只是个参考值?
为了生成能用于调试的 core 文件,系统会根据这个指定的值,选择一个合适的实际值?
---------------->
希望大家指正~~~谢谢!!!
9. 在程序中使用setrlimit函数设置core文件的大小限制。
#include <stdio.h> #include <stdlib.h> #include <sys/resource.h> /* 显示当前进程的 core 文件大小限制 */ int showcorelimit(void) { struct rlimit limit; if (getrlimit(RLIMIT_CORE, &limit) != 0) return -1; printf("softlimit = %lu, hardlimit= %lu\n", limit.rlim_cur, limit.rlim_max); return 0; } /* 设置 core 文件的大小限制 */ int setcorelimit(void) { struct rlimit limit; if (getrlimit(RLIMIT_CORE, &limit) != 0) return -1; /*系统定义的宏: #define RLIM_INFINITY (~0UL) */ /* 设置 softlimit = hardlimit,默认情况下,linux 的hardlimit=(~0UL)= 4294967295 字节 */ limit.rlim_cur = limit.rlim_max; return setrlimit(RLIMIT_CORE, &limit); } int main(int argc, char *argv[]) { int i =5; /* 设置之前显示一次 core 大小限制 */ showcorelimit(); /* 设置 core 文件的大小限制 */ setcorelimit(); /* 设置之后显示一次 core 大小限制 */ showcorelimit(); /* 产生 SIGFPE 信号*/ i /= 0; exit(0); } |
10.
补充1:
设置Core Dump的核心转储文件目录和命名规则
a) /proc/sys/kernel/core_uses_pid可以控制产生的core文件的文件名中是否添加pid作为扩展,如果添加则文件内容为1,否则为0
b) /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 添加命令名
补充2:
Linux Programmer’s Manual 中对阻止产生 core 文件的情景说明:
There are various circumstances in which a core dump file is not produced:
* The process does not have permission to write the core file. (By default the core file is called core, and is created in the current working directory. See below for details on naming.) Writing the core file will fail if the directory in which it is to be created is non-writable, or if a file with the same name exists and is not writable or is not a regular file (e.g., it is a directory or a symbolic link).
* A (writable, regular) file with the same name as would be used for the core dump already exists, but there is more than one hard link to that file.
* The file system where the core dump file would be created is full; or has run out of i-nodes; or is mounted read only; or the user has reached their quota for the file system.
* The directory in which the core dump file is to be created does not exist.
* RLIMIT_CORE or RLIMIT_FSIZE resource limits for a process are set to zero(see getrlimit(2)).
* The binary being executed by the process does not have read permission enabled.
* The process is executing a set-user-ID (set-group-ID) program that is owned by a user (group) other than the real user (group) ID of the process.
(However, see the description of the prctl(2) PR_SET_DUMPABLE operation, and the description of the /proc/sys/fs/suid_dumpable file in proc(5).)