APUE小結之 Unix/Linux core文件

轉載請註明出處: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).)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章