1. core檔案的簡單介紹
在一個程式崩潰時,它一般會在指定目錄下產生一個core檔案。core檔案僅僅是一個記憶體映象(同時加上調試資訊),主要是用來調試的。
2. 開啟或關閉core檔案的產生
用以下命令來阻止系統產生core檔案:ulimit -c 0,下面的命令可以檢查產生core檔案的選項是否開啟:ulimit -a該命令將顯示所有的使用者定製,其中選項-a代表“all”。也可以修改系統檔案來調整core選項在/etc/profile通常會有這樣一句話來禁止產生core檔案,通常這種設定是合理的:# No core files bydefaultulimit -S -c 0 > /dev/null 2>&1但是在開發過程中有時為了調試問題,還是需要在特定的使用者環境下開啟core檔案產生的設定在使用者的~/.bash_profile裡加上ulimit
-c unlimited來讓特定的使用者可以產生core檔案,如果ulimit -c 0則也是禁止產生core檔案,而ulimit -c 1024則限制產生的core檔案的大小不能超過1024kb
3. 設定Core Dump的核心轉儲檔案目錄和命名規則
/proc/sys/kernel/core_uses_pid可以控制產生的core檔案的檔案名稱中是否添加pid作為擴充,如果添加則檔案內容為1,否則為0。/proc/sys/kernel/core_pattern可以設定格式化的core檔案儲存位置或檔案名稱,比如原來檔案內容是core-%e可以這樣修改:echo "/corefile/core-%e-%p-%t" > core_pattern將會控制所產生的core檔案會存放到/corefile目錄下,產生的檔案名稱為core-命令名-pid-時間戳記,以下是參數列表:%p
- insert pid intofilename 添加pid%u -insert current uid into filename 添加當前uid%g - insert current gid into filename 添加當前gid%s - insert signal thatcaused the coredump into the filename 添加導致產生core的訊號%t - insertUNIX time that the coredump occurred into filename
添加core檔案產生時的unix時間%h - inserthostname where the coredump happened into filename 添加主機名稱%e - insert coredumpingexecutable name into filename 添加命令名
4. 使用core檔案
在core檔案所在目錄下鍵入:gdb -c core它會啟動GNU的調試器,來調試core檔案,並且會顯示產生此core檔案的程式名,中止此程式的訊號等等如果你已經知道是由什麼程式產生此core檔案的,比如MyServer崩潰了產生core.12345,那麼用此指令調試:gdb -c core MyServer以下怎麼辦就該去學習gdb的使用了
5. 一個小方法來測試產生core檔案
直接輸入指令:kill -sSIGSEGV $$
coredump簡介與coredump原因總結
之前寫了篇日誌《Linuxcore 檔案簡單介紹》,很多人會問coredump是什嗎?我們又能用coredump做什麼呢?準備寫一系列這種文章對coredump做一個詳細介紹
什麼是coredump?
通常情況下coredmp包含了程式運行時的記憶體,寄存器狀態,堆棧指標,記憶體管理資訊等。可以理解為把程式工作的目前狀態儲存成一個檔案。許多程式和作業系統出錯時會自動產生一個core檔案。
如何使用coredump?
coredump可以用在很多場合,使用Linux,或者solaris的人可能都有過這種經曆,系統在跑一些壓力測試或者系統負載一大的話,系統就hang住了或者乾脆system panic.這時唯一能協助你分析和解決問題的就是coredump了。
現在很多應該程式出錯時也會出現coredump.
分析coredump的工具
現在大部分類unix作業系統都提供了分析core檔案的工具,比如 GNU Binutils Binary FileDescriptor library (BFD), GNU Debugger (gdb),mdb等
coredump的檔案格式
類unix作業系統中使用efi格式儲存coredump檔案。
在solairs下
bash-3.2# file *unix.3 ELF 32-bit LSBexecutable 80386 Version 1, statically linked, not stripped, no debugginginformation availableunix.4 ELF 32-bit LSB executable 80386 Version 1,statically linked, not stripped, no debugging information available
造成程式coredump的原因很多,這雷根據以往的經驗總結一下:
1 記憶體訪問越界
a) 由於使用錯誤的下標,導致數組訪問越界。
b) 搜尋字串時,依靠字串結束符來判斷字串是否結束,但是字串沒有正常的使用結束符。
c) 使用strcpy, strcat, sprintf, strcmp,strcasecmp等字串操作函數,將目標字串讀/寫爆。應該使用strncpy,strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函數防止讀寫越界。
2 多線程程式使用了線程不安全的函數。
應該使用下面這些可重新進入的函數,尤其注意紅色標示出來的函數,它們很容易被用錯:
asctime_r(3c) gethostbyname_r(3n)getservbyname_r(3n) ctermid_r(3s) gethostent_r(3n) getservbyport_r(3n)ctime_r(3c) getlogin_r(3c) getservent_r(3n) fgetgrent_r(3c) getnetbyaddr_r(3n)getspent_r(3c) fgetpwent_r(3c) getnetbyname_r(3n) getspnam_r(3c)fgetspent_r(3c)
getnetent_r(3n) gmtime_r(3c) gamma_r(3m) getnetgrent_r(3n)lgamma_r(3m) getauclassent_r(3) getprotobyname_r(3n) localtime_r(3c)getauclassnam_r(3) etprotobynumber_r(3n) nis_sperror_r(3n) getauevent_r(3)getprotoent_r(3n) rand_r(3c) getauevnam_r(3) getpwent_r(3c)
readdir_r(3c)getauevnum_r(3) getpwnam_r(3c) strtok_r(3c) getgrent_r(3c) getpwuid_r(3c)tmpnam_r(3s) getgrgid_r(3c) getrpcbyname_r(3n) ttyname_r(3c) getgrnam_r(3c)getrpcbynumber_r(3n) gethostbyaddr_r(3n) getrpcent_r(3n)
3 多線程讀寫的資料未加鎖保護。
對於會被多個線程同時訪問的全域資料,應該注意加鎖保護,否則很容易造成core dump
4 非法指標
a) 使用null 指標
b) 隨意使用指標轉換。一個指向一段記憶體的指標,除非確定這段記憶體原先就分配為某種結構或類型,或者這種結構或類型的數組,否則不要將它轉換為這種結構或類型的指標,而應該將這段記憶體拷貝到一個這種結構或類型中,再訪問這個結構或類型。這是因為如果這段記憶體的開始地址不是按照這種結構或類型對齊的,那麼訪問它時就很容易因為bus error而core dump.
5 堆疊溢位
不要使用大的局部變數(因為局部變數都分配在棧上),這樣容易造成堆疊溢位,破壞系統的棧和堆結構,導致出現莫名其妙的錯誤。
Linux 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為好。
當我們的程式崩潰時,核心有可能把該程式當前記憶體映射到core檔案裡,方便程式員找到程式出現問題的地方。最常出現的,幾乎所有C程式員都出現過的錯誤就是“段錯誤”了。也是最難查出問題原因的一個錯誤。下面我們就針對“段錯誤”來分析core檔案的產生、以及我們如何利用core檔案找到出現崩潰的地方。
何謂core檔案
當一個程式崩潰時,在進程當前工作目錄的core檔案中複製了該進程的儲存映像。core檔案僅僅是一個記憶體映象(同時加上調試資訊),主要是用來調試的。
當程式接收到以下UNIX訊號會產生core檔案:
名字
說明
ANSI C POSIX.1
SVR4 4.3+BSD
預設動作
SIGABRT
異常終止(abort)
終止w/core
SIGBUS
硬體故障
終止w/core
SIGEMT
硬體故障
終止w/core
SIGFPE
算術異常
終止w/core
SIGILL
非法硬體指令
終止w/core
SIGIOT
硬體故障
終止w/core
SIGQUIT
終端退出符
終止w/core
SIGSEGV
無效儲存訪問
終止w/core
SIGSYS
無效系統調用
終止w/core
SIGTRAP
硬體故障
終止w/core
SIGXCPU
超過CPU限制(setrlimit)
終止w/core
SIGXFSZ
超過檔案長度限制(setrlimit)
終止w/core
在系統預設動作列,“終止w/core”表示在進程當前工作目錄的core檔案中複製了該進程的儲存映像(該檔案名稱為core,由此可以看出這種功能很久之前就是UNIX功能的一部分)。大多數UNIX偵錯工具都使用core檔案以檢查進程在終止時的狀態。
core檔案的產生不是POSIX.1所屬部分,而是很多UNIX版本的實現特徵。UNIX第6版沒有檢查條件(a)和(b),並且其原始碼中包含如下說明:“如果你正在找尋保護訊號,那麼當設定-使用者-ID命令執行時,將可能產生大量的這種訊號”。4.3 + BSD產生名為core.prog的檔案,其中prog是被執行的程式名的前1 6個字元。它對core檔案給予了某種標識,所以是一種改進特徵。
表中“硬體故障”對應於實現定義的硬體故障。這些名字中有很多取自UNIX早先在DP-11上的實現。請查看你所使用的系統的手冊,以確切地確定這些訊號對應於哪些錯誤類型。
下面比較詳細地說明這些訊號。
• SIGABRT 調用abort函數時產生此訊號。進程異常終止。
• SIGBUS 指示一個實現定義的硬體故障。
• SIGEMT 指示一個實現定義的硬體故障。
EMT這一名字來自PDP-11的emulator trap指令。
• SIGFPE 此訊號表示一個算術運算異常,例如除以0,浮點溢出等。
• SIGILL 此訊號指示進程已執行一條非法硬體指令。
4.3BSD由abort函數產生此訊號。SIGABRT現在被用於此。
• SIGIOT 這指示一個實現定義的硬體故障。
IOT這個名字來自於PDP-11對於輸入/輸出TRAP(input/outputTRAP)指令的縮寫。系統V的早期版本,由abort函數產生此訊號。SIGABRT現在被用於此。
• SIGQUIT 當使用者在終端上按退出鍵(一般採用Ctrl-/)時,產生此訊號,並送至前台進
程組中的所有進程。此訊號不僅終止前台進程組(如SIGINT所做的那樣),同時產生一個core檔案。
• SIGSEGV 指示進程進行了一次無效的儲存訪問。
名字SEGV表示“段違例(segmentation violation)”。
• SIGSYS 指示一個無效的系統調用。由於某種未知原因,進程執行了一條系統調用指令,
但其指示系統調用類型的參數卻是無效的。
• SIGTRAP 指示一個實現定義的硬體故障。
此訊號名來自於PDP-11的TRAP指令。
• SIGXCPU SVR4和4.3+BSD支援資源限制的概念。如果進程超過了其軟C P U時間限制,則產生此訊號。
• SIGXFSZ 如果進程超過了其軟檔案長度限制,則SVR4和4.3+BSD產生此訊號。
使用core檔案偵錯工具
看下面的例子:
/*core_dump_test.c*/
#include <stdio.h>
const char *str = "test";
void core_test(){
str[1] = 'T';
}
int main(){
core_test();
return 0;
}
編譯:
gcc –g core_dump_test.c -o core_dump_test
如果需要偵錯工具的話,使用gcc編譯時間加上-g選項,這樣調試core檔案的時候比較容易找到錯誤的地方。
執行:
./core_dump_test
段錯誤
運行core_dump_test程式出現了“段錯誤”,但沒有產生core檔案。這是因為系統預設core檔案的大小為0,所以沒有建立。可以用ulimit命令查看和修改core檔案的大小。
ulimit -c 0
ulimit -c 1000
ulimit -c 1000
-c 指定修改core檔案的大小,1000指定了core檔案大小。也可以對core檔案的大小不做限制,如:
ulimit -c unlimited
ulimit -c unlimited
如果想讓修改永久生效,則需要修改設定檔,如 .bash_profile、/etc/profile或/etc/security/limits.conf。
再次執行:
./core_dump_test
段錯誤 (coredumped)
ls core.*
core.6133
可以看到已經建立了一個core.6133的檔案.6133是core_dump_test程式啟動並執行進程ID。
調式core檔案
core檔案是個二進位檔案,需要用相應的工具來剖析器崩潰時的記憶體映像。
file core.6133
core.6133: ELF 32-bit LSB core file Intel80386, version 1 (SYSV), SVR4-style, from 'core_dump_test'
在Linux下可以用GDB來調試core檔案。
gdb core_dump_test core.6133
GNU gdb Red Hat Linux(5.3post-0.20021129.18rh)
Copyright 2003 Free Software Foundation,Inc.
GDB is free software, covered by the GNUGeneral Public License, and you are
welcome to change it and/or distributecopies of it under certain conditions.
Type "show copying" to see theconditions.
There is absolutely no warranty forGDB. Type "show warranty" fordetails.
This GDB was configured as"i386-redhat-linux-gnu"...
Core was generated by `./core_dump_test'.
Program terminated with signal 11,Segmentation fault.
Reading symbols from/lib/tls/libc.so.6...done.
Loaded symbols for /lib/tls/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0 0x080482fd in core_test () at core_dump_test.c:7
7 str[1] = 'T';
(gdb) where
#0 0x080482fd in core_test () at core_dump_test.c:7
#1 0x08048317 in main () at core_dump_test.c:12
#2 0x42015574in __libc_start_main () from /lib/tls/libc.so.6
GDB中鍵入where,就會看到程式崩潰時堆棧資訊(當前函數之前的所有已調用函數的列表(包括當前函數),gdb只顯示最近幾個),我們很容易找到我們的程式在最後崩潰的時候調用了core_dump_test.c 第7行的代碼,導致程式崩潰。注意:在編譯器的時候要加入選項-g。您也可以試試其他命令, 如 fram、list等。更詳細的用法,請查閱GDB文檔。
core檔案建立在什麼位置
在進程當前工作目錄的下建立。通常與程式在相同的路徑下。但如果程式中調用了chdir函數,則有可能改變了當前工作目錄。這時core檔案建立在chdir指定的路徑下。有好多程式崩潰了,我們卻找不到core檔案放在什麼位置。和chdir函數就有關係。當然程式崩潰了不一定都產生core檔案。
什麼時候不產生core檔案
在下列條件下不產生core檔案:
( a )進程是設定-使用者-ID,而且目前使用者並非程式檔案的所有者;
( b )進程是設定-組-ID,而且目前使用者並非該程式檔案的群組擁有者;
( c )使用者沒有寫當前工作目錄的許可權;
( d )檔案太大。core檔案的許可權(假定該檔案在此之前並不存在)通常是使用者讀/寫,組讀和其他讀。
利用GDB調試core檔案,當遇到程式崩潰時我們不再束手無策。