coredump 断点_coredump调试的使用
一,什么是coredump
跑程序的時(shí)候經(jīng)常碰到SIGNAL 或者 call trace的問題,需要定位解決,這里說的大部分是指對(duì)應(yīng)程序由于各種異常或者bug導(dǎo)致在運(yùn)行過程中異常退出或者中止,并且在滿足一定條件下(這里為什么說需要滿足一定的條件呢?下面會(huì)分析)會(huì)產(chǎn)生一個(gè)叫做core的文件。
通常情況下,core文件會(huì)包含了程序運(yùn)行時(shí)的內(nèi)存,寄存器狀態(tài),堆棧指針,內(nèi)存管理信息還有各種函數(shù)調(diào)用堆棧信息等,我們可以理解為是程序工作當(dāng)前狀態(tài) 存儲(chǔ)生成第一個(gè)文件,許多的程序出錯(cuò)的時(shí)候都會(huì)產(chǎn)生一個(gè)core文件,通過工具分析這個(gè)文件,我們可以定位到程序異常退出的時(shí)候?qū)?yīng)的堆棧調(diào)用等信息,找 出問題所在并進(jìn)行及時(shí)解決。
二,coredump文件的存儲(chǔ)位置
core文件默認(rèn)的存儲(chǔ)位置與對(duì)應(yīng)的可執(zhí)行程序在同一目錄下,文件名是core,大家可以通過下面的命令看到core文件的存在位置:
cat? /proc/sys/kernel/core_pattern
缺省值是core
注意:這里是指在進(jìn)程當(dāng)前工作目錄的下創(chuàng)建。
通常與程序在相同的路徑下。但如果程序中調(diào)用了chdir函數(shù),則有可能改變了當(dāng)前工作目錄。這時(shí)core文件創(chuàng)建在chdir指定的路徑下。有好多程序
崩潰了,我們卻找不到core文件放在什么位置。和chdir函數(shù)就有關(guān)系。當(dāng)然程序崩潰了不一定都產(chǎn)生 core文件。
如下程序代碼:則會(huì)把生成的core文件存儲(chǔ)在/data/coredump/wd,而不是大家認(rèn)為的跟可執(zhí)行文件在同一目錄。
通過下面的命令可以更改coredump文件的存儲(chǔ)位置,若你希望把core文件生成到/data/coredump/core目錄下:
echo “/data/coredump/core”> /proc/sys/kernel/core_pattern
注意,這里當(dāng)前用戶必須具有對(duì)/proc/sys/kernel/core_pattern的寫權(quán)限。
缺省情況下,內(nèi)核在coredump時(shí)所產(chǎn)生的core文件放在與該程序相同的目錄中,并且文件名固定為core。很顯然,如果有多個(gè)程序產(chǎn)生core文件,或者同一個(gè)程序多次崩潰,就會(huì)重復(fù)覆蓋同一個(gè)core文件,因此我們有必要對(duì)不同程序生成的core文件進(jìn)行分別命名。
我們通過修改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文件中將帶有崩潰的程序名、以及它的進(jìn)程ID。上面的%e和%p會(huì)被替換成程序文件名以及進(jìn)程ID。
如果在上述文件名中包含目錄分隔符“/”,那么所生成的core文件將會(huì)被放到指定的目錄中。
需要說明的是,在內(nèi)核中還有一個(gè)與coredump相關(guān)的設(shè)置,就是/proc/sys/kernel/core_uses_pid。如果這個(gè)文件的內(nèi)容
被配置成1,那么即使core_pattern中沒有設(shè)置%p,最后生成的core dump文件名仍會(huì)加上進(jìn)程ID。
三,如何判斷一個(gè)文件是coredump文件?
在類unix系統(tǒng)下,coredump文件本身主要的格式也是ELF格式,因此,我們可以通過readelf命令進(jìn)行判斷。
可以看到ELF文件頭的Type字段的類型是:CORE (Core file)
可以通過簡單的file命令進(jìn)行快速判斷:
四,產(chǎn)生coredum的一些條件總結(jié)
1,? 產(chǎn)生coredump的條件,首先需要確認(rèn)當(dāng)前會(huì)話的ulimit –c,若為0,則不會(huì)產(chǎn)生對(duì)應(yīng)的coredump,需要進(jìn)行修改和設(shè)置。
ulimit? -c?unlimited? (可以產(chǎn)生coredump且不受大小限制)
若想甚至對(duì)應(yīng)的字符大小,則可以指定:
ulimit –c [size]
可以看出,這里的size的單位是blocks,一般1block=512bytes
如:
ulimit –c 4? (注意,這里的size如果太小,則可能不會(huì)產(chǎn)生對(duì)應(yīng)的core文件,筆者設(shè)置過ulimit –c 1的時(shí)候,系統(tǒng)并不生成core文件,并嘗試了1,2,3均無法產(chǎn)生core,至少需要4才生成core文件)
但當(dāng)前設(shè)置的ulimit只對(duì)當(dāng)前會(huì)話有效,若想系統(tǒng)均有效,則需要進(jìn)行如下設(shè)置:
?? 在/etc/profile中加入以下一行,這將允許生成coredump文件
ulimit-c unlimited
?? 在rc.local中加入以下一行,這將使程序崩潰時(shí)生成的coredump文件位于/data/coredump/目錄下:
echo /data/coredump/core.%e.%p> /proc/sys/kernel/core_pattern
注意rc.local在不同的環(huán)境,存儲(chǔ)的目錄可能不同,susu下可能在/etc/rc.d/rc.local
這些需要有root權(quán)限, 在ubuntu下每次重新打開中斷都需要重新輸入上面的ulimit命令, 來設(shè)置core大小為無限.
2, 當(dāng)前用戶,即執(zhí)行對(duì)應(yīng)程序的用戶具有對(duì)寫入core目錄的寫權(quán)限以及有足夠的空間。
3, 幾種不會(huì)產(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)驗(yàn)吧:
1,內(nèi)存訪問越界
a) 由于使用錯(cuò)誤的下標(biāo),導(dǎo)致數(shù)組訪問越界。
b) 搜索字符串時(shí),依靠字符串結(jié)束符來判斷字符串是否結(jié)束,但是字符串沒有正常的使用結(jié)束符。
c) 使用strcpy, strcat, sprintf,
strcmp,strcasecmp等字符串操作函數(shù),將目標(biāo)字符串讀/寫爆。應(yīng)該使用strncpy, strlcpy, strncat,
strlcat, snprintf, strncmp, strncasecmp等函數(shù)防止讀寫越界。
2,多線程程序使用了線程不安全的函數(shù)。
應(yīng)該使用下面這些可重入的函數(shù),它們很容易被用錯(cuò):
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ù)未加鎖保護(hù)。
對(duì)于會(huì)被多個(gè)線程同時(shí)訪問的全局?jǐn)?shù)據(jù),應(yīng)該注意加鎖保護(hù),否則很容易造成coredump
4,非法指針
a) 使用空指針
b) 隨意使用指針轉(zhuǎn)換。一個(gè)指向一段內(nèi)存的指針,除非確定這段內(nèi)存原先就分配為某種結(jié)構(gòu)或類型,或者這種結(jié)構(gòu)或類型的數(shù)組,否則不要將它轉(zhuǎn)換為這種結(jié)構(gòu)或類型的指針,而應(yīng)該將這段內(nèi)存拷貝到一個(gè)這種結(jié)構(gòu)或類型中,再訪問這個(gè)結(jié)構(gòu)或類型。這是因?yàn)槿绻@段內(nèi)存的開始地址不是按照這種結(jié)構(gòu)或類型對(duì)齊的,那么訪問它時(shí)就很容易因?yàn)閎us error而core dump。
5,堆棧溢出
不要使用大的局部變量(因?yàn)榫植孔兞慷挤峙湓跅I?,這樣容易造成堆棧溢出,破壞系統(tǒng)的棧和堆結(jié)構(gòu),導(dǎo)致出現(xiàn)莫名其妙的錯(cuò)誤。
六,利用gdb進(jìn)行coredump的定位
其實(shí)分析coredump的工具有很多,現(xiàn)在大部分類unix系統(tǒng)都提供了分析coredump文件的工具,不過,我們經(jīng)常用到的工具是gdb。
這里我們以程序?yàn)槔觼碚f明如何進(jìn)行定位。
1,? 段錯(cuò)誤 – segmentfault
?? 我們寫一段代碼往受到系統(tǒng)保護(hù)的地址寫內(nèi)容。
?? 按如下方式進(jìn)行編譯和執(zhí)行,注意這里需要-g選項(xiàng)編譯。
可以看到,當(dāng)輸入12的時(shí)候,系統(tǒng)提示段錯(cuò)誤并且core dumped
?? 我們進(jìn)入對(duì)應(yīng)的core文件生成目錄,優(yōu)先確認(rèn)是否core文件格式并啟用gdb進(jìn)行調(diào)試。
從紅色方框截圖可以看到,程序中止是因?yàn)樾盘?hào)11,且從bt(backtrace)命令(或者where)可以看到函數(shù)的調(diào)用棧,即程序執(zhí)行到
coremain.cpp的第5行,且里面調(diào)用scanf 函數(shù),而該函數(shù)其實(shí)內(nèi)部會(huì)調(diào)用_IO_vfscanf_internal()函數(shù)。
接下來我們繼續(xù)用gdb,進(jìn)行調(diào)試對(duì)應(yīng)的程序。
記住幾個(gè)常用的gdb命令:
l(list) ,顯示源代碼,并且可以看到對(duì)應(yīng)的行號(hào);
b(break)x, x是行號(hào),表示在對(duì)應(yīng)的行號(hào)位置設(shè)置斷點(diǎn);
p(print)x, x是變量名,表示打印變量x的值
r(run), 表示繼續(xù)執(zhí)行到斷點(diǎn)的位置
n(next),表示執(zhí)行下一步
c(continue),表示繼續(xù)執(zhí)行
q(quit),表示退出gdb
啟動(dòng)gdb,注意該程序編譯需要-g選項(xiàng)進(jìn)行。
注:? SIGSEGV?????11?????? Core??? Invalid memoryreference
七,附注:
1,? gdb的查看源碼
顯示源代碼
GDB
可以打印出所調(diào)試程序的源代碼,當(dāng)然,在程序編譯時(shí)一定要加上-g的參數(shù),把源程序信息編譯到執(zhí)行文件中。不然就看不到源程序了。當(dāng)程序停下來以
后,GDB會(huì)報(bào)告程序停在了那個(gè)文件的第幾行上。你可以用list命令來打印程序的源代碼。還是來看一看查看源代碼的GDB命令吧。
list
顯示程序第linenum行的周圍的源程序。
list
顯示函數(shù)名為function的函數(shù)的源程序。
list
顯示當(dāng)前行后面的源程序。
list -
顯示當(dāng)前行前面的源程序。
一般是打印當(dāng)前行的上5行和下5行,如果顯示函數(shù)是是上2行下8行,默認(rèn)是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ù):
?? 行號(hào)。
?? 當(dāng)前行號(hào)的正偏移量。
?? 當(dāng)前行號(hào)的負(fù)偏移量。
? 哪個(gè)文件的哪一行。
? 函數(shù)名。
哪個(gè)文件中的哪個(gè)函數(shù)。
? 程序運(yùn)行時(shí)的語句在內(nèi)存中的地址。
2,? 一些常用signal的含義
SIGABRT:調(diào)用abort函數(shù)時(shí)產(chǎn)生此信號(hào)。進(jìn)程異常終止。
SIGBUS:指示一個(gè)實(shí)現(xiàn)定義的硬件故障。
SIGEMT:指示一個(gè)實(shí)現(xiàn)定義的硬件故障。EMT這一名字來自PDP-11的emulator trap 指令。
SIGFPE:此信號(hào)表示一個(gè)算術(shù)運(yùn)算異常,例如除以0,浮點(diǎn)溢出等。
SIGILL:此信號(hào)指示進(jìn)程已執(zhí)行一條非法硬件指令。4.3BSD由abort函數(shù)產(chǎn)生此信號(hào)。SIGABRT現(xiàn)在被用于此。
SIGIOT:這指示一個(gè)實(shí)現(xiàn)定義的硬件故障。IOT這個(gè)名字來自于PDP-11對(duì)于輸入/輸出TRAP(input/outputTRAP)指令的縮寫。系統(tǒng)V的早期版本,由abort函數(shù)產(chǎn)生此信號(hào)。SIGABRT現(xiàn)在被用于此。
SIGQUIT:當(dāng)用戶在終端上按退出鍵(一般采用Ctrl-/)時(shí),產(chǎn)生此信號(hào),并送至前臺(tái)進(jìn)
程組中的所有進(jìn)程。此信號(hào)不僅終止前臺(tái)進(jìn)程組(如SIGINT所做的那樣),同時(shí)產(chǎn)生一個(gè)core文件。
SIGSEGV:指示進(jìn)程進(jìn)行了一次無效的存儲(chǔ)訪問。名字SEGV表示“段違例(segmentationviolation)”。
SIGSYS:指示一個(gè)無效的系統(tǒng)調(diào)用。由于某種未知原因,進(jìn)程執(zhí)行了一條系統(tǒng)調(diào)用指令,但其指示系統(tǒng)調(diào)用類型的參數(shù)卻是無效的。
SIGTRAP:指示一個(gè)實(shí)現(xiàn)定義的硬件故障。此信號(hào)名來自于PDP-11的TRAP指令。
SIGXCPUSVR4和4.3+BSD支持資源限制的概念。如果進(jìn)程超過了其軟C P U時(shí)間限制,則產(chǎn)生此信號(hào)。
SIGXFSZ:如果進(jìn)程超過了其軟文件長度限制,則SVR4和4.3+BSD產(chǎn)生此信號(hào)。
名字
說明
ANSI C? POSIX.1
SVR4? 4.3+BSD
缺省動(dòng)作
SIGABRT
異常終止(abort)
.?????? .
.????? .
終止w/core
SIGBUS
硬件故障
.
.????? .
終止w/core
SIGEMT
硬件故障
.????? .
終止w/core
SIGFPE
算術(shù)異常
.?????? .
.????? .
終止w/core
SIGILL
非法硬件指令
.?????? .
.????? .
終止w/core
SIGIOT
硬件故障
.????? .
終止w/core
SIGQUIT
終端退出符
.
.????? .
終止w/core
SIGSEGV
無效存儲(chǔ)訪問
.?????? .
.????? .
終止w/core
SIGSYS
無效系統(tǒng)調(diào)用
.????? .
終止w/core
SIGTRAP
硬件故障
.????? .
終止w/core
SIGXCPU
超過CPU限制(setrlimit)
.????? .
終止w/core
SIGXFSZ
超過文件長度限制(setrlimit)
.????? .
終止w/core
3,? Core_pattern的格式
可以在core_pattern模板中使用變量還很多,見下面的列表:
%% 單個(gè)%字符
%p 所dump進(jìn)程的進(jìn)程ID
%u 所dump進(jìn)程的實(shí)際用戶ID
%g 所dump進(jìn)程的實(shí)際組ID
%s 導(dǎo)致本次core dump的信號(hào)
%t core dump的時(shí)間 (由1970年1月1日計(jì)起的秒數(shù))
%h 主機(jī)名
%e 程序文件名
總結(jié):
coredump文件的生成方法以及使用方法:
(realtek平臺(tái)為例)
1.用menuconfig打開linux coredump的支持
CONFIG_ELF_CORE = y
2.在/etc/profile中加上如下語句ulimit -c unlimited
firsttime=`test -e /var/coredump; echo $?`
if [ "$firsttime" = "1" ]; then
mkdir /var/coredump
echo /var/coredump/core.%e.%p >/proc/sys/kernel/core_pattern
fi
3. ?確保SIGSEGV信號(hào)的操作沒有被改變,如果改變了,可能不會(huì)產(chǎn)生coredump文件
不能有 這種設(shè)置 SIGNAL(SIGSEGV, bad_signal);
4.??? 在編譯的時(shí)候必須要加上 "-g" 選項(xiàng)
5.執(zhí)行程序:在異常退出時(shí),會(huì)顯示如下信息,注意括號(hào)里的內(nèi)容Segmentation fault (core dumped)
core文件放在/var/coredump目錄下
6.?? 在板子里沒有g(shù)db tool 的時(shí)候,用tftp將coredump文件拷到崩潰程序的文件夾里面
#tftp -p -l core.pppd.1172 192.168.1.62
#cp core.pppd.1172 to xxx/pppd/
7.用gdb分析:(1) 進(jìn)入coredump文件所在的文件夾
#cd xxx/pppd
(2) ? gdb coredump
/toolchain/msdk-4.4.7-mips-EB-3.10-0.9.33-m32t-131227b/bin/mips-linux-gdb ./pppd --core=./core.pppd.1172
(3) ? 導(dǎo)入程序文件的一些公共庫,比如我現(xiàn)在用到一些public libs, 出錯(cuò)的位置也有可能在這些libs上,所以需要導(dǎo)進(jìn)去
(gdb)set sysroot /home/xxx/realtek/rtl8198c/romfs/
(4) bt跟蹤
(gdb)bt
總結(jié)
以上是生活随笔為你收集整理的coredump 断点_coredump调试的使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ckeditor5加字数_CKEdito
- 下一篇: python socket发送组播数据_