1. 程式人生 > >Unix/Linux core檔案配置和使用總結

Unix/Linux core檔案配置和使用總結

      雖然早已經接觸了core檔案,但是也是簡單的使用,最近也到了一些問題,自己Google了一些資料,在此記錄一下,當做一個筆記吧,順便給大家分享分享。

概述:core dump的概念

core dump is the recorded state of the working memory of a computer program at a specific time, generally when the program has terminated abnormally (crashed). In practice, other key pieces of program state are usually dumped at the same time, including the processor registers, which may include the program counter and stack pointer, memory management information, and other processor and operating system flags and information. The name comes from the once-standard memory technology core memory. Core dumps are often used to diagnose or debug errors in computer programs.

On many operating systems, a fatal error in a program automatically triggers a core dump, and by extension the phrase "to dump core" has come to mean, in many cases, any fatal error, regardless of whether a record of the program memory is created.


在linux平臺下,設定core dump檔案生成的方法:

1) 在終端中輸入ulimit -c 如果結果為0,說明當程式崩潰時,系統並不能生成core dump。


2) 使用ulimit -c unlimited命令,開啟core dump功能,並且不限制生成core dump檔案的大小。如果需要限制,加數字限制即可。ulimit - c 1024

3) 預設情況下,core dump生成的檔名為core,而且就在程式當前目錄下。新的core會覆蓋已存在的core。通過修改/proc/sys/kernel/core_uses_pid檔案,可以將程序的pid作為作為副檔名,生成的core檔案格式為core.xxx,其中xxx即為pid

4) 通過修改/proc/sys/kernel/core_pattern可以控制core檔案儲存位置和檔案格式。例如:將所有的core檔案生成到/corefile目錄下,檔名的格式為core-命令名-pid-時間戳. echo "/corefile/core-%e-%p-%t" > /proc/sys/kernel/core_pattern


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 檔案。

但是,我測試發現,除了上面12中訊號外,我遮蔽了PIPE訊號,程式也不會生成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 --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 )
[[email protected] core]$ gcc  -g  -o  m  main.c 

執行結果:
第一步:把 core 檔案大小設定為:無限制。 
[[email protected] core]$ ulimit -S -c unlimited
[[email protected] core]$ ulimit -c
unlimited

第二步:執行程式 m
[[email protected] core]# ./m 
pid = 16694
Segmentation fault (core dumped)

[[email protected] 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。

[[email protected] 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 failif the directory in which it is to be created is non-writable, or if a file with the same name exists and is notwritable 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).)


補充3:如何找到core檔案

一般情況下,core檔案會生成在你執行程式的地方。檔名是core.程序號
你也可以指定core檔名和生成目錄。在 /etc/sysctl.conf 檔案中指定。
1
# vi /etc/sysctl.conf
新增如下行:
kernel.core_uses_pid = 1
kernel.core_pattern = /tmp/core-%e-%s-%u-%g-%p-%t
fs.suid_dumpable = 2
kernel.core_uses_pid = 1 – 追加程序號到core檔名中
fs.suid_dumpable = 2 – 確保設定屬主的程序也可以生成core檔案
kernel.core_pattern = /tmp/core-%e-%s-%u-%g-%p-%t – 指定core檔案生成的位置和檔名規則。檔名規則可以使用的引數有:

%% – 符號%
%p – 程序號
%u – 程序使用者id
%g – 程序使用者組id
%s – 生成core檔案時收到的訊號
%t – 生成core檔案的 時間 (seconds since 0:00h, 1 Jan 1970)
%h – 主機名
%e – 程式檔名


執行如下命令,讓設定生效
#sysctl -p


除此之外,也可以通過如下方式指定core檔名和路徑
$echo /tmp/core-%e-%s-%u-%g-%p-%t > /proc/sys/kernel/core_pattern


如何使用core檔案
可以使用gdb命令檢視core檔案資訊
$ gdb -e /path/to/application -c /path/to/corefile



參考:

http://www.cppblog.com/kongque/archive/2011/03/07/141262.aspx

http://blog.chinaunix.net/u3/105349/showart.php?id=2121419