visual studio 怎么生成coredump文件_coredump详解
一,什么是coredump
? ? ? ? 我們經(jīng)常聽到大家說到程序core掉了,需要定位解決,這里說的大部分是指對應(yīng)程序由于各種異常或者bug導(dǎo)致在運行過程中異常退出或者中止,并且在滿足一定條件下(這里為什么說需要滿足一定的條件呢?下面會分析)會產(chǎn)生一個叫做core的文件。
? ? ? ? 通常情況下,core文件會包含了程序運行時的內(nèi)存,寄存器狀態(tài),堆棧指針,內(nèi)存管理信息還有各種函數(shù)調(diào)用堆棧信息等,我們可以理解為是程序工作當(dāng)前狀態(tài)存儲生成第一個文件,許多的程序出錯的時候都會產(chǎn)生一個core文件,通過工具分析這個文件,我們可以定位到程序異常退出的時候?qū)?yīng)的堆棧調(diào)用等信息,找出問題所在并進行及時解決。
二,coredump文件的存儲位置
? ?core文件默認的存儲位置與對應(yīng)的可執(zhí)行程序在同一目錄下,文件名是core,大家可以通過下面的命令看到core文件的存在位置:
? ?cat ?/proc/sys/kernel/core_pattern
? ?缺省值是core
注意:這里是指在進程當(dāng)前工作目錄的下創(chuàng)建。通常與程序在相同的路徑下。但如果程序中調(diào)用了chdir函數(shù),則有可能改變了當(dāng)前工作目錄。這時core文件創(chuàng)建在chdir指定的路徑下。有好多程序崩潰了,我們卻找不到core文件放在什么位置。和chdir函數(shù)就有關(guān)系。當(dāng)然程序崩潰了不一定都產(chǎn)生 core文件。
如下程序代碼:則會把生成的core文件存儲在/data/coredump/wd,而不是大家認為的跟可執(zhí)行文件在同一目錄。
通過下面的命令可以更改coredump文件的存儲位置,若你希望把core文件生成到/data/coredump/core目錄下:
? ?echo “/data/coredump/core”> /proc/sys/kernel/core_pattern
注意,這里當(dāng)前用戶必須具有對/proc/sys/kernel/core_pattern的寫權(quán)限。
缺省情況下,內(nèi)核在coredump時所產(chǎn)生的core文件放在與該程序相同的目錄中,并且文件名固定為core。很顯然,如果有多個程序產(chǎn)生core文件,或者同一個程序多次崩潰,就會重復(fù)覆蓋同一個core文件,因此我們有必要對不同程序生成的core文件進行分別命名。
我們通過修改kernel的參數(shù),可以指定內(nèi)核所生成的coredump文件的文件名。例如,使用下面的命令使kernel生成名字為core.filename.pid格式的core dump文件:
echo “/data/coredump/core.%e.%p” >/proc/sys/kernel/core_pattern
這樣配置后,產(chǎn)生的core文件中將帶有崩潰的程序名、以及它的進程ID。上面的%e和%p會被替換成程序文件名以及進程ID。
如果在上述文件名中包含目錄分隔符“/”,那么所生成的core文件將會被放到指定的目錄中。 需要說明的是,在內(nèi)核中還有一個與coredump相關(guān)的設(shè)置,就是/proc/sys/kernel/core_uses_pid。如果這個文件的內(nèi)容被配置成1,那么即使core_pattern中沒有設(shè)置%p,最后生成的core dump文件名仍會加上進程ID。
三,如何判斷一個文件是coredump文件?
在類unix系統(tǒng)下,coredump文件本身主要的格式也是ELF格式,因此,我們可以通過readelf命令進行判斷。
? ? ?可以看到ELF文件頭的Type字段的類型是:CORE (Core file)
? ? ?可以通過簡單的file命令進行快速判斷:? ? ?
四,產(chǎn)生coredum的一些條件總結(jié)
1, ?產(chǎn)生coredump的條件,首先需要確認當(dāng)前會話的ulimit –c,若為0,則不會產(chǎn)生對應(yīng)的coredump,需要進行修改和設(shè)置。
ulimit ?-c unlimited ?(可以產(chǎn)生coredump且不受大小限制)
若想甚至對應(yīng)的字符大小,則可以指定:
ulimit –c [size]
? ? ? ?可以看出,這里的size的單位是blocks,一般1block=512bytes
? ? ? ? 如:
? ? ? ? ulimit –c 4 ?(注意,這里的size如果太小,則可能不會產(chǎn)生對應(yīng)的core文件,筆者設(shè)置過ulimit –c 1的時候,系統(tǒng)并不生成core文件,并嘗試了1,2,3均無法產(chǎn)生core,至少需要4才生成core文件)
但當(dāng)前設(shè)置的ulimit只對當(dāng)前會話有效,若想系統(tǒng)均有效,則需要進行如下設(shè)置:
? ?在/etc/profile中加入以下一行,這將允許生成coredump文件
ulimit-c unlimited
? ?在rc.local中加入以下一行,這將使程序崩潰時生成的coredump文件位于/data/coredump/目錄下:
echo /data/coredump/core.%e.%p> /proc/sys/kernel/core_pattern?
注意rc.local在不同的環(huán)境,存儲的目錄可能不同,susu下可能在/etc/rc.d/rc.local
? ? ? 更多ulimit的命令使用,可以參考:http://baike.baidu.com/view/4832100.htm
? ? ? 這些需要有root權(quán)限, 在ubuntu下每次重新打開中斷都需要重新輸入上面的ulimit命令, 來設(shè)置core大小為無限.
2, 當(dāng)前用戶,即執(zhí)行對應(yīng)程序的用戶具有對寫入core目錄的寫權(quán)限以及有足夠的空間。
3, 幾種不會產(chǎn)生core文件的情況說明:
The core file will not be generated if
(a) ? ?the process was set-user-ID and the current user is not the owner of the program file, or
(b) ? ? the process was set-group-ID and the current user is not the group owner of the file,
(c) ? ? the user does not have permission to write in the current working directory,?
(d) ? ? the file already exists and the user does not have permission to write to it, or?
(e) ? ? the file is too big (recall the RLIMIT_CORE limit in Section 7.11). The permissions of the core file (assuming that the file doesn't already exist) are usually user-read and user-write, although Mac OS X sets only user-read.
五,coredump產(chǎn)生的幾種可能情況
造成程序coredump的原因有很多,這里總結(jié)一些比較常用的經(jīng)驗吧:
?1,內(nèi)存訪問越界
? a) 由于使用錯誤的下標,導(dǎo)致數(shù)組訪問越界。
? b) 搜索字符串時,依靠字符串結(jié)束符來判斷字符串是否結(jié)束,但是字符串沒有正常的使用結(jié)束符。
? c) 使用strcpy, strcat, sprintf, strcmp,strcasecmp等字符串操作函數(shù),將目標字符串讀/寫爆。應(yīng)該使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函數(shù)防止讀寫越界。
?2,多線程程序使用了線程不安全的函數(shù)。
應(yīng)該使用下面這些可重入的函數(shù),它們很容易被用錯:
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,多線程讀寫的數(shù)據(jù)未加鎖保護。
對于會被多個線程同時訪問的全局數(shù)據(jù),應(yīng)該注意加鎖保護,否則很容易造成coredump
?4,非法指針
? a) 使用空指針
? b) 隨意使用指針轉(zhuǎn)換。一個指向一段內(nèi)存的指針,除非確定這段內(nèi)存原先就分配為某種結(jié)構(gòu)或類型,或者這種結(jié)構(gòu)或類型的數(shù)組,否則不要將它轉(zhuǎn)換為這種結(jié)構(gòu)或類型的指針,而應(yīng)該將這段內(nèi)存拷貝到一個這種結(jié)構(gòu)或類型中,再訪問這個結(jié)構(gòu)或類型。這是因為如果這段內(nèi)存的開始地址不是按照這種結(jié)構(gòu)或類型對齊的,那么訪問它時就很容易因為bus error而core dump。
?5,堆棧溢出
不要使用大的局部變量(因為局部變量都分配在棧上),這樣容易造成堆棧溢出,破壞系統(tǒng)的棧和堆結(jié)構(gòu),導(dǎo)致出現(xiàn)莫名其妙的錯誤。 ?
六,利用gdb進行coredump的定位
? 其實分析coredump的工具有很多,現(xiàn)在大部分類unix系統(tǒng)都提供了分析coredump文件的工具,不過,我們經(jīng)常用到的工具是gdb。
? 這里我們以程序為例子來說明如何進行定位。
1, ?段錯誤 – segmentfault
? ?我們寫一段代碼往受到系統(tǒng)保護的地址寫內(nèi)容。
? ?按如下方式進行編譯和執(zhí)行,注意這里需要-g選項編譯。
可以看到,當(dāng)輸入12的時候,系統(tǒng)提示段錯誤并且core dumped
? ?我們進入對應(yīng)的core文件生成目錄,優(yōu)先確認是否core文件格式并啟用gdb進行調(diào)試。
從紅色方框截圖可以看到,程序中止是因為信號11,且從bt(backtrace)命令(或者where)可以看到函數(shù)的調(diào)用棧,即程序執(zhí)行到coremain.cpp的第5行,且里面調(diào)用scanf 函數(shù),而該函數(shù)其實內(nèi)部會調(diào)用_IO_vfscanf_internal()函數(shù)。
接下來我們繼續(xù)用gdb,進行調(diào)試對應(yīng)的程序。
記住幾個常用的gdb命令:
l(list) ,顯示源代碼,并且可以看到對應(yīng)的行號;
b(break)x, x是行號,表示在對應(yīng)的行號位置設(shè)置斷點;
p(print)x, x是變量名,表示打印變量x的值
r(run), 表示繼續(xù)執(zhí)行到斷點的位置
n(next),表示執(zhí)行下一步
c(continue),表示繼續(xù)執(zhí)行
q(quit),表示退出gdb
啟動gdb,注意該程序編譯需要-g選項進行。
注: ?SIGSEGV ? ? 11 ? ? ? Core ? ?Invalid memoryreference
七,附注:
1, ?gdb的查看源碼
顯示源代碼
GDB 可以打印出所調(diào)試程序的源代碼,當(dāng)然,在程序編譯時一定要加上-g的參數(shù),把源程序信息編譯到執(zhí)行文件中。不然就看不到源程序了。當(dāng)程序停下來以后,GDB會報告程序停在了那個文件的第幾行上。你可以用list命令來打印程序的源代碼。還是來看一看查看源代碼的GDB命令吧。
list
顯示程序第linenum行的周圍的源程序。
list
顯示函數(shù)名為function的函數(shù)的源程序。
list
顯示當(dāng)前行后面的源程序。
list -
顯示當(dāng)前行前面的源程序。
一般是打印當(dāng)前行的上5行和下5行,如果顯示函數(shù)是是上2行下8行,默認是10行,當(dāng)然,你也可以定制顯示的范圍,使用下面命令可以設(shè)置一次顯示源程序的行數(shù)。
setlistsize
設(shè)置一次顯示源代碼的行數(shù)。
showlistsize
查看當(dāng)前l(fā)istsize的設(shè)置。
list命令還有下面的用法:
list,
顯示從first行到last行之間的源代碼。
list ,
顯示從當(dāng)前行到last行之間的源代碼。
list +
往后顯示源代碼。
一般來說在list后面可以跟以下這些參數(shù):
? 行號。
? 當(dāng)前行號的正偏移量。
? 當(dāng)前行號的負偏移量。
?哪個文件的哪一行。
?函數(shù)名。
哪個文件中的哪個函數(shù)。
?程序運行時的語句在內(nèi)存中的地址。
2, ?一些常用signal的含義
SIGABRT:調(diào)用abort函數(shù)時產(chǎn)生此信號。進程異常終止。
SIGBUS:指示一個實現(xiàn)定義的硬件故障。
SIGEMT:指示一個實現(xiàn)定義的硬件故障。EMT這一名字來自PDP-11的emulator trap 指令。
SIGFPE:此信號表示一個算術(shù)運算異常,例如除以0,浮點溢出等。
SIGILL:此信號指示進程已執(zhí)行一條非法硬件指令。4.3BSD由abort函數(shù)產(chǎn)生此信號。SIGABRT現(xiàn)在被用于此。
SIGIOT:這指示一個實現(xiàn)定義的硬件故障。IOT這個名字來自于PDP-11對于輸入/輸出TRAP(input/outputTRAP)指令的縮寫。系統(tǒng)V的早期版本,由abort函數(shù)產(chǎn)生此信號。SIGABRT現(xiàn)在被用于此。
SIGQUIT:當(dāng)用戶在終端上按退出鍵(一般采用Ctrl-/)時,產(chǎn)生此信號,并送至前臺進
程組中的所有進程。此信號不僅終止前臺進程組(如SIGINT所做的那樣),同時產(chǎn)生一個core文件。
SIGSEGV:指示進程進行了一次無效的存儲訪問。名字SEGV表示“段違例(segmentationviolation)”。
SIGSYS:指示一個無效的系統(tǒng)調(diào)用。由于某種未知原因,進程執(zhí)行了一條系統(tǒng)調(diào)用指令,但其指示系統(tǒng)調(diào)用類型的參數(shù)卻是無效的。
SIGTRAP:指示一個實現(xiàn)定義的硬件故障。此信號名來自于PDP-11的TRAP指令。
SIGXCPUSVR4和4.3+BSD支持資源限制的概念。如果進程超過了其軟C P U時間限制,則產(chǎn)生此信號。
SIGXFSZ:如果進程超過了其軟文件長度限制,則SVR4和4.3+BSD產(chǎn)生此信號。
3, ?Core_pattern的格式
可以在core_pattern模板中使用變量還很多,見下面的列表:
%% 單個%字符
%p 所dump進程的進程ID
%u 所dump進程的實際用戶ID
%g 所dump進程的實際組ID
%s 導(dǎo)致本次core dump的信號
%t core dump的時間 (由1970年1月1日計起的秒數(shù))
%h 主機名
%e 程序文件名
總結(jié)
以上是生活随笔為你收集整理的visual studio 怎么生成coredump文件_coredump详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python从mysql导出大量数据_p
- 下一篇: options请求_前端数据请求的终极方