什麼是Core Dump?

何謂 core?
       在使用半導體作爲內存的材料前,人類是利用線圈當作內存的材料(發明 者爲王安),線圈就叫作 core ,用線圈做的內存就叫作 core memory。如今 ,半導體工業澎勃發展,已經沒有人用 core memory 了,不過,在許多情況下, 人們還是把記憶體叫作 core 。
        何謂 core dump?
        我們在開發(或使用)一個程序時,最怕的就是程序莫明其妙地當掉。雖然系 統沒事,但我們下次仍可能遇到相同的問題。於是這時操作系統就會把程序當掉 時的內存內容 dump 出來(現在通常是寫在一個叫 core 的 file 裏面),讓 我們或是 debugger 做爲參考。這個動作就叫作 core dump。
       爲何會發生 core dump?
       前面說過,在程序當掉時出錯。在 C/C++語言中,最常發生錯誤的地方就是指 針有問題。您可以利用 core 文件和 debugger 把錯誤找出來(要怎麼在 debugger 中使用 core 文件?man 一下 gdb 吧!)。
       如何用gdb調用core?

當c編寫的程序出現core是,可以用gdb programname core,查看core。如果找不到core文件,可以用一下命令查看和修改。

ulimit -a  //查看core文件的大小

ulimit -c  //修改core文件的大小

如果gdb -c core 時遇到一下情況:

#0 0x08048373 in ?? ()

#1 0xbfffd8f8 in ?? ()

#2 0x0804839e in ?? ()

#3 0xb74cc6b3 in ?? ()

#4 0x00000000 in ?? ()

請用以下方法解決:gdb ./a.out core 然後bt就可以了。

除了bt以外還有如下命令:where, frame, up, down, print可以使用。


什麼是Core Dump?

Core的意思是內存, Dump的意思是扔出來, 堆出來.

開發和使用Unix程序時, 有時程序莫名其妙的down了, 卻沒有任何的提示(有時候會提示core dumped). 這時候可以查看一下有沒有形如core.進程號的文件生成, 這個文件便是操作系統把程序down掉時的內存內容扔出來生成的, 它可以做爲調試程序的參考.

core dump又叫核心轉儲, 當程序運行過程中發生異常, 程序異常退出時, 由操作系統把程序當前的內存狀況存儲在一個core文件中, 叫core dump.

如何使用core文件?

gdb -c core文件路徑 [應用程序的路徑]

進去後輸入where回車, 就可以顯示程序在哪一行當掉的, 在哪個函數中.

爲什麼沒有core文件生成呢?

有時候程序down了, 但是core文件卻沒有生成. core文件的生成跟你當前系統的環境設置有關係, 可以用下面的語句設置一下, 然後再運行程序便成生成core文件.

ulimit -c unlimited

core文件生成的位置一般於運行程序的路徑相同, 文件名一般爲core.進程號

4. 用gdb查看core文件:

下面我們可以在發生運行時信號引起的錯誤時發生core dump了.

發生core dump之後, 用gdb進行查看core文件的內容, 以定位文件中引發core dump的行.

gdb [exec file] [core file]

如:

gdb ./test test.core

在進入gdb後, 用bt命令查看backtrace以檢查發生程序運行到哪裏, 來定位core dump的文件->行.


Core Dump 配置與調試
1.core文件的生成開關和大小限制
---------------------------------
1)使用ulimit
-c命令可查看core文件的生成開關。若結果爲0,則表示關閉了此功能,不會生成core文件。
2)
使用ulimit
-cfilesize命令,可以限制core文件的大小(filesize的單位爲kbyte)。若ulimit
-cunlimited,則表示core文件的大小不受限制。如果生成的信息超過此大小,將會被裁剪,最終生成一個不完整的core文件。在調試此
core文件的時候,gdb會提示錯誤。
2.core文件的名稱和生成路徑
----------------------------
若系統生成的core文件不帶其它任何擴展名稱,則全部命名爲core。新的core文件生成將覆蓋原來的core文件。
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)proc/sys/kernel/core_pattern可以控制core文件保存位置和文件名格式。
可通過以下命令修改此文件:
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
添加命令名
3.用gdb查看core文件:
下面我們可以在發生運行時信號引起的錯誤時發生core
dump了.
發生core
dump之後,
用gdb進行查看core文件的內容,
以定位文件中引發core
dump的行.
gdb [exec
file] [core file]
如:
gdb
./test test.core
在進入gdb後,
用bt命令查看backtrace以檢查發生程序運行到哪裏,
來定位core dump的文件->行.
4.開發板上使用core文件調試
-----------------------------
如果開發板的操作系統也是linux,core調試方法依然適用。如果開發板上不支持gdb,可將開發板的環境(頭文件、庫)、可執行文件和core文件拷貝到PC的linux下,運行相關命令即可。
注意:待調試的可執行文件,在編譯的時候需要加-g,core文件才能正常顯示出錯信息!
注意的問題:
在Linux下要保證程序崩潰時生成Coredump要注意這些問題:
  一、要保證存放Coredump的目錄存在且進程對該目
錄有寫權限。存放Coredump的目錄即進程的當前目錄,一般就是當初發出命令啓動該進程時所在的目錄。但如果是通過腳本啓動,則腳本可能會修改當前目
錄,這時進程真正的當前目錄就會與當初執行腳本所在目錄不同。這時可以查看”/proc/進程pid>/cwd“符號鏈接的目標來確定進程
真正的當前目錄地址。通過系統服務啓動的進程也可通過這一方法查看。
  二、若程序調用了seteuid()/setegid()改變
了進程的有效用戶或組,則在默認情況下系統不會爲這些進程生成Coredump。很多服務程序都會調用seteuid(),如MySQL,不論你用什麼用
戶運行mysqld_safe啓動MySQL,mysqld進行的有效用戶始終是msyql用戶。如果你當初是以用戶A運行了某個程序,但在ps裏看到的
這個程序的用戶卻是B的話,那麼這些進程就是調用了seteuid了。爲了能夠讓這些進程生成core
dump,需要將/proc/sys/fs
/suid_dumpable文件的內容改爲1(一般默認是0)。
  三、這個一般都知道,就是要設置足夠大的Core文件大小限制
了。程序崩潰時生成的Core文件大小即爲程序運行時佔用的內存大小。但程序崩潰時的行爲不可按平常時的行爲來估計,比如緩衝區溢出等錯誤可能導致堆棧被
破壞,因此經常會出現某個變量的值被修改成亂七八糟的,然後程序用這個大小去申請內存就可能導致程序比平常時多佔用很多內存。因此無論程序正常運行時佔用
的內存多麼少,要保證生成Core文件還是將大小限制設爲unlimited爲好。


Linux系統中在應用程序運行過程中經常會遇到程序突然崩潰,提示:Segmentation fault,這是因爲應用程序收到了SIGSEGV信號。這個信號提示當進程發生了無效的存儲訪問,當接收到這個信號時,缺省動作是:終止w/core。 終止w/core的含義是:在進程當前目錄生成core文件,並將進程的內存映象複製到core文件中,core文件的默認名稱就是“core”(這是Unix類系統的一個由來已久的功能)。
    事實上,並不是只有SIGSEGV信號產生coredump,還有下面一些信號也產生coredump:SIGABRT(異常終止)、SIGBUS(硬件故障)、SIGEMT(硬件故障)、SIGFPE(算術異常)、SIGILL(非法硬件指令)、SIGIOT(硬件故障),SIGQUIT,SIGSYS(無效系統調用),SIGTRAP(硬件故障)等。
    在程序的開發調試階段(尤其是大型軟件開發),發生程序異常崩潰時常規的調試方法常常是無比的痛苦:無窮的log中也不見得有什麼有意義的信息。好在GDB提供和利用core文件進行調試的途徑,大大方便了這類問題的調試。

    下面我們通過一個簡單的例子來看看怎麼通過GDB來調試一個違規訪問內存導致的程序崩潰。這裏我們順便講講動態庫的調試。

/******** mylib.h **********/
#ifndef __MY_LIB_H__
#define __MY_LIB_H__

int add(int x, int y);

#endif // __MY_LIB_H__
/******** end **********/



/******** mylib.c **********/
#include <stdlib.h>
#include "mylib.h"

int add(int x, int y)
{
    char* pc = NULL;
    *pc = 10;

    return x + y;
}
/******** end **********/

/******** main.c **********/

#include <stdio.h>
#include <stdlib.h>

#include "mylib.h"

int main (void)
{
    int ret = -1;
    int a = 10, b = 20;
    ret = add(a, b);

    printf("The result is: %d\n", ret);

    return 0;
}
/******** end **********/

#####################################
# File Name: Makefile
#
#####################################

CC = gcc
LD = gcc

all:
        $(CC) mylib.c -g -I. -fPIC -shared -o libmylib.so
        $(CC) main.c -g -I. -L. -lmylib -o test

clean:
        rm *.so test
#############   END   ###############

    首先將上面的代碼分別存儲到相應的目錄,名稱爲:mylib.h、mylib.c、main.c、Makefile。

1)編譯測試代碼。注)編譯時的 -g 選項是必須的。
[xxx@yyy]$ make
gcc mylib.c -g -I. -fPIC -shared -o libmylib.so
gcc main.c -g -I. -L. -lmylib -o t

通過ls命令我們可以看到生成了測試程序test.
[xxx@yyy]$ ls
libmylib.so main.c Makefile mylib.c mylib.h test

2)執行測試程序
[xxx@yyy]$ ./test
./test: error while loading shared libraries: libmylib.so: cannot open shared object file: No such file or directory

這個錯誤表明程序在運行階段不能找到相應的動態庫文件,此時需要通過環境變量 LD_LIBRARY_PATH 來指定運行期動態庫的搜索目錄,我們的動態庫就在當前目錄,如下:

[xxx@yyy]$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.

3)再次執行測試程序
[leo@localhost debug]$ ./test
Segmentation fault
[leo@localhost debug]$ ls
libmylib.so main.c Makefile mylib.c mylib.h test

4)設置core文件大小
Segmentation fault如期而至,但是卻沒有我們更想見到的core文件!
原來系統在默認情況下core文件的大小設置爲0,換句話講也就是不產生core文件。我們可以通過 ulimit 命令來修改core文件的大小,unlimited表示不限制core文件的大小,如下(設置core文件的大小需要root權限):
[root@yyy]# ulimit -c unlimited
[root@yyy]# ./test
Segmentation fault (core dumped)
[root@yyy]# ls
core.2890 libmylib.so main.c Makefile mylib.c mylib.h test

5)設置core文件的格式,輸出路徑
通過下面命令我們還可以指定core文件的命名格式,路徑等(需要root權限):
[root@yyy]# echo "core_%e_%s" >/proc/sys/kernel/core_pattern
[root@yyy]# ./test
Segmentation fault (core dumped)
[root@yyy]# ls
core.2890 core_test_11.2898 libmylib.so main.c Makefile mylib.c mylib.h test

6)調試
[root@yyy]# gdb test core.2890
GNU gdb Red Hat Linux (6.5-8.fc6rh)
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 "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".

Core was generated by `./test'.
Program terminated with signal 11, Segmentation fault.
Error while mapping shared library sections:
libmylib.so: Success.
Reading symbols from /home/xxx/tst/libmylib.so...done.
Loaded symbols for libmylib.so
Reading symbols from /lib/i686/libc.so.6...done.
Loaded symbols for /lib/i686/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0 0x00a8969c in ?? ()
(gdb)

鍵入GDB命令 where
(gdb) where
#0 0x001ec44c in ?? ()
#1 0x00000000 in ?? ()

?? ()並不是我們想看到的,之所以這樣,是因爲GDB不能正確加載我們編寫的動態庫libmylib.so,我們需要在這裏設置GDB的動態庫搜索路徑,如下:

(gdb) set solib-search-path .
Reading symbols from /home/xxx/test/tst/libmylib.so...done.
Loaded symbols for /home/xxx/test/tst/libmylib.so
Reading symbols from /lib/i686/libc.so.6...done.
Loaded symbols for /lib/i686/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2

可以看到GDB已經加載了libmylib.so,再次鍵入where命令:
(gdb) where
#0 0x001ec44c in add (x=10, y=20) at mylib.c:8
#1 0x0804847c in main () at main.c:12
(gdb)

這次我們期待的結果出現了,GDB清楚的列出了錯誤出現的位置:mylib.c的第8行,好了,到那裏去改code吧!

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