ubuntu core 文件产生
關(guān)于內(nèi)核轉(zhuǎn)儲(chǔ)的設(shè)置方法
?
1. 內(nèi)核轉(zhuǎn)儲(chǔ)作用
?
(1) 內(nèi)核轉(zhuǎn)儲(chǔ)的最大好處是能夠保存問題發(fā)生時(shí)的狀態(tài)。
(2) 只要有可執(zhí)行文件和內(nèi)核轉(zhuǎn)儲(chǔ),就可以知道進(jìn)程當(dāng)時(shí)的狀態(tài)。
(3) 只要獲取內(nèi)核轉(zhuǎn)儲(chǔ),那么即使沒有復(fù)現(xiàn)環(huán)境,也能調(diào)試。
?
2. 啟用內(nèi)核轉(zhuǎn)儲(chǔ)
1.1 查看內(nèi)核轉(zhuǎn)儲(chǔ)是否有效
在終端中輸入以下命令,查看內(nèi)核轉(zhuǎn)儲(chǔ)是否有效。
#ulimit -c
0
-c 表示內(nèi)核轉(zhuǎn)儲(chǔ)文件的大小限制,現(xiàn)在顯示為零,表示不能用。
可以改為1G
#ulimit -c 1073741824
也可以改為無限制
#ulimit -c unlimited
?
2.2 測(cè)試一個(gè)例子
例子的源代碼:
#include <stdio.h>
int main(void)
{
int *a = NULL;
*a = 0x1;
return 0;
}
?
把以上源代碼,寫成一個(gè)a.c文件后,編譯a.c文件產(chǎn)生一個(gè)a.out的可執(zhí)行文件:
#gcc -g a.c -o a.out
修改a.out文件的權(quán)限后,執(zhí)行它:
#./a.out
就會(huì)顯示:
Segmentation fault(core dump)
這表示在當(dāng)前目錄下, 已經(jīng)生成了a.out對(duì)應(yīng)的內(nèi)核轉(zhuǎn)儲(chǔ)文件。
注意:后面帶有(core dump), 才說明轉(zhuǎn)儲(chǔ)文件成功生成了。
#file core*
core:ELF 64-bit LSB core file x86-64, version 1(SYSV), SVR4-style, from './a.out'
coreDump: UTF-8 Unicode C program text
?
要用GDB調(diào)試內(nèi)核轉(zhuǎn)儲(chǔ)文件,應(yīng)該使用以下方式啟動(dòng)GDB:
#gdb -c ./*.core ./a.out
GNU gdb (GDB) 7.1-Ubuntu
...
Core was generated by './a.out'.
Program terminated with signal 11, Segmentation fault.
#0 0x00000000004004dc in main() at a.c:6
6 *a =0x1;
a.c的第6行收到了11號(hào)信號(hào)。用GDB的list命令可以查看附近的源代碼。
(gdb) l 5
1 ?????????? #include <stdio.h>
2???????????
3 ?????????? int main(void)
4 ?????????? {
5 ????????????????? int *a = NULL;
6 ????????????????? *a = 0x1;
7 ????????????????? return 0;
8 ?????????? }
這里默認(rèn)都是當(dāng)前目錄,也可以給core 和a.out 指定路徑
到這里測(cè)試完成!
?
2.3 永久生效的辦法
上面所述的方法,只是在當(dāng)前shell中生效,重啟之后,就不再有效了。永久生效的辦法是:
#vi /etc/profile 然后,在profile中添加:
ulimit -c 1073741824
?(但是,若將產(chǎn)生的轉(zhuǎn)儲(chǔ)文件大小大于該數(shù)字時(shí),將不會(huì)產(chǎn)生轉(zhuǎn)儲(chǔ)文件)
或者
ulimit -c unlimited
?
這樣重啟機(jī)器后生效了。 或者, 使用source命令使之馬上生效。
#source /etc/profile
?
3. 指定內(nèi)核轉(zhuǎn)儲(chǔ)的文件名和目錄
缺省情況下,內(nèi)核在coredump時(shí)所產(chǎn)生的core文件放在與該程序相同的目錄中,并且文件名固定為core。很顯然,如果有多個(gè)程序產(chǎn)生core文件,或者同一個(gè)程序多次崩潰,就會(huì)重復(fù)覆蓋同一個(gè)core文件。
我們可以通過修改kernel的參數(shù),指定內(nèi)核轉(zhuǎn)儲(chǔ)所生成的core文件的路徑和文件名。
可以通過在/etc/sysctl.conf文件中,對(duì)sysctl變量kernel.core_pattern的設(shè)置。
#vi /etc/sysctl.conf 然后,在sysctl.conf文件中添加下面兩句話:
kernel.core_pattern = /var/core/core_%e_%p
kernel.core_uses_pid = 0
保存后退出。
需要說明的是,?/proc/sys/kernel/core_uses_pid。如果這個(gè)文件的內(nèi)容被配置成1,即使core_pattern中沒有設(shè)置%p,最后生成的core dump文件名仍會(huì)加上進(jìn)程ID。
這里%e, %p分別表示:
%c 轉(zhuǎn)儲(chǔ)文件的大小上限
%e 所dump的文件名
%g 所dump的進(jìn)程的實(shí)際組ID
%h 主機(jī)名
%p 所dump的進(jìn)程PID
%s 導(dǎo)致本次coredump的信號(hào)
%t 轉(zhuǎn)儲(chǔ)時(shí)刻(由1970年1月1日起計(jì)的秒數(shù))
%u 所dump進(jìn)程的實(shí)際用戶ID
可以使用以下命令,使修改結(jié)果馬上生效。
#sysctl –p /etc/sysctl.conf
?
請(qǐng)?jiān)?var目錄下先建立core文件夾,然后執(zhí)行a.out程序,就會(huì)在/var/core/下產(chǎn)生以指定格式命名的內(nèi)核轉(zhuǎn)儲(chǔ)文件。查看轉(zhuǎn)儲(chǔ)文件的情況:
#ls /var/core
core_a.out_2834
?
4. 手動(dòng)強(qiáng)制某個(gè)進(jìn)程產(chǎn)生core dump的方法(嘗試)
當(dāng)某些程序發(fā)生crash時(shí),對(duì)應(yīng)進(jìn)程會(huì)產(chǎn)生coredump文件。通過這個(gè)coredump文件,開發(fā)人員可以找到bug的原因。但是coredump的產(chǎn)生,大都是因?yàn)槌绦騝rash了。
而有些bug是不會(huì)導(dǎo)致程序crash的,比如死鎖,這時(shí)程序已經(jīng)不正常了,可是卻沒有coredump產(chǎn)生。如果環(huán)境又不允許gdb調(diào)試,難道我們就束手無策了嗎?
針對(duì)以上這種情況,一般情況下,對(duì)于這樣的進(jìn)程可以利用 watchdog監(jiān)控它們,當(dāng)發(fā)現(xiàn)這些進(jìn)程很長時(shí)間沒有更新其heartbeat時(shí),可以給這些進(jìn)程發(fā)送可以導(dǎo)致其產(chǎn)生coredump的信號(hào)。根據(jù) linux的信號(hào)默認(rèn)的處理行為,SIGQUIT,SIGABRT, SIGFPE和SIGSEGV都可以讓該進(jìn)程產(chǎn)生coredump文件。這樣我們可以通過coredump來得知死鎖是否發(fā)生。 當(dāng)然, 如果進(jìn)程添加了這些信號(hào)的處理函數(shù),那么就不會(huì)產(chǎn)生coredump了。不過,對(duì)于SIGQUIT, SIGABRT, SIGFPE, SIGSEGV,有誰會(huì)為它們加上信號(hào)處理函數(shù)呢。
?
還有一種情況,進(jìn)程并沒有死鎖或者block在某個(gè)位置, 但是我們需要在某個(gè)指定位置進(jìn)行調(diào)試,獲取某些變量或者其它信息。但是,有可能是客戶環(huán)境或者生產(chǎn)環(huán)境,不允許我們進(jìn)行長時(shí)間的檢測(cè)。那么,我們就需要通 過coredump來獲得進(jìn)程在運(yùn)行到該點(diǎn)時(shí)的快照。 這個(gè)時(shí)候,可以利用gdb來手工產(chǎn)生coredump。在attach上這個(gè)進(jìn)程時(shí),在指定位置打上斷點(diǎn),當(dāng)斷點(diǎn)觸發(fā)時(shí),使用gdb的命令gcore,可 以立即產(chǎn)生一個(gè)coredump。 這樣,我們就拿到了這個(gè)位置的進(jìn)程快照。
?
1.尋找您要發(fā)送信號(hào)的進(jìn)程ID,
?
# ps -ef? | grep qemu
root????? 3207? 3206 44 10:32 pts/1??? 00:00:18 /usr/local/bin/qemu-system-x86
得出 qemu-system-x86的 PID號(hào)是3207
2.使用kill(1)去發(fā)送信號(hào)。
?
# /bin/kill -s QUIT 3207
?
發(fā)送其他的信號(hào)也很相似, 只要在命令行中替換QUIT 為ABRT,TERM 或 KILL 就行了
?
重要提示:?在系統(tǒng)上隨意殺死進(jìn)程是一個(gè)壞主意,特別是init(8),它的PID是1,它非常特殊。 可以運(yùn)行 /bin/kill -s KILL 1 命令來讓系統(tǒng)迅速關(guān)機(jī)。? 當(dāng)您按下?Return?(回車)鍵之前,一定要?詳細(xì)檢查您運(yùn)行?kill(1)?時(shí)所指定的參數(shù)。
?
5 使用core dump進(jìn)行調(diào)試
在Linux下遇到“段錯(cuò)誤”(segmentation fault),如果段錯(cuò)誤發(fā)生在服務(wù)器端,而服務(wù)器端要繼續(xù)工作,不允許調(diào)試,這時(shí)“內(nèi)核轉(zhuǎn)儲(chǔ)(core dump)”就派上了用場,可以把生成的內(nèi)核轉(zhuǎn)儲(chǔ)復(fù)制到本地進(jìn)行調(diào)試。
??? 首先,按照上面的永久生效方法,在服務(wù)器上進(jìn)行相應(yīng)設(shè)置。 然后程序在崩潰時(shí),就會(huì)在程序所在目錄(或自己指定的目錄)生成一個(gè)core文件,把這個(gè)core文件拷到本地(最好與該進(jìn)程對(duì)應(yīng)的可執(zhí)行文件放到同一個(gè)目錄,若不然,在gdb時(shí)指出路徑也可以)。
?
具體方法如下:
方法一:
輸入命令 #gdb <程序可執(zhí)行文件> <coredump轉(zhuǎn)儲(chǔ)文件>
例如:
# gdb /usr/local/bin/qemu-system-x86_64? /var/core/core-3207-qemu-system-x86
然后,在(gdb)提示符后輸入 l,? 會(huì)顯示main主函數(shù)
?
?
方法二:
(1) 在終端輸入命令# gdb [-c] <coredump文件>,
例如: gdb -c /var/core/core-3207-qemu-system-x86
(2)然后,在(gdb)提示符后輸入file <可執(zhí)行程序>
例如:(gdb) file? /usr/local/bin/qemu-system-x86_64
(3) 這時(shí)就可以用backtrace/thread等命令查看當(dāng)時(shí)的錯(cuò)誤了,就像程序在本地執(zhí)行到崩潰點(diǎn)一樣
或者用where回車, 也可以顯示程序在哪一行當(dāng)?shù)舻?/span>
?
5. 啟用整個(gè)系統(tǒng)的內(nèi)核轉(zhuǎn)儲(chǔ)
(未完待續(xù)......)
?
(4.1) 編輯/etc/profile, 開啟登錄到系統(tǒng)的所有用戶的內(nèi)核轉(zhuǎn)儲(chǔ)功能
首先,看看用的是個(gè)什么機(jī)器:
# uname –a
Linux ubuntu240 2.6.32-21-server #32-Ubuntu SMP Fri Apr 16 09:17:34 UTC 2010 x86_64 GNU/Linux
其次,再查看一些默認(rèn)參數(shù),若core file size是0,即使程序出錯(cuò)時(shí),也不會(huì)產(chǎn)生core文件。
# ulimit -a
core file size????????????? (blocks, -c) unlimited
data seg size????????????? (kbytes, -d) unlimited
scheduling priority?????????????? (-e) 20
file size????????????????? (blocks, -f) unlimited
pending signals????????????????? (-i) 16382
max locked memory??????? (kbytes, -l) 64
max memory size?? ??????(kbytes, -m) unlimited
open files????????????????????? (-n) 1024
pipe size????????????? (512 bytes, -p) 8
POSIX message queues???? (bytes, -q) 819200
real-time priority??????????????? (-r) 0
stack size??????????????? (kbytes, -s) 8192
cpu time?????? ?????????(seconds, -t) unlimited
max user processes????????????? (-u) unlimited
virtual memory?????????? (kbytes, -v) unlimited
file locks????????????????????? (-x) unlimited
?
查看棧信息
?
????? 當(dāng)程序被停住了,你需要做的第一件事就是查看程序是在哪里停住的。當(dāng)你的程序調(diào)用了一個(gè)函數(shù),函數(shù)的地址,函數(shù)參數(shù),函數(shù)內(nèi)的局部變量都會(huì)被壓入“棧”(Stack)中。你可以用GDB命令來查看當(dāng)前的棧中的信息。
下面是一些查看函數(shù)調(diào)用棧信息的GDB命令:
backtrace
bt
打印當(dāng)前的函數(shù)調(diào)用棧的所有信息。如:
(gdb) bt
#0 func (n=250) at tst.c:6
#1 0x08048524 in main (argc=1, argv=0xbffff674) at tst.c:30
#2 0x400409ed in __libc_start_main () from /lib/libc.so.6
從上可以看出函數(shù)的調(diào)用棧信息:__libc_start_main --> main() --> func()
backtrace
bt
n是一個(gè)正整數(shù),表示只打印棧頂上n層的棧信息。
backtrace <-n>
bt <-n>
-n表一個(gè)負(fù)整數(shù),表示只打印棧底下n層的棧信息。
如果你要查看某一層的信息,你需要在切換當(dāng)前的棧,一般來說,程序停止時(shí),最頂層的棧就是當(dāng)前棧,如果你要查看棧下面層的詳細(xì)信息,首先要做的是切換當(dāng)前棧。
frame
f
n是一個(gè)從0開始的整數(shù),是棧中的層編號(hào)。比如:frame 0,表示棧頂,frame 1,表示棧的第二層。
up
表示向棧的上面移動(dòng)n層,可以不打n,表示向上移動(dòng)一層。
down
表示向棧的下面移動(dòng)n層,可以不打n,表示向下移動(dòng)一層。
上面的命令,都會(huì)打印出移動(dòng)到的棧層的信息。如果你不想讓其打出信息。你可以使用這三個(gè)命令:
select-frame 對(duì)應(yīng)于 frame 命令。
up-silently 對(duì)應(yīng)于 up 命令。
down-silently 對(duì)應(yīng)于 down 命令。
查看當(dāng)前棧層的信息,你可以用以下GDB命令:
frame 或 f
會(huì)打印出這些信息:棧的層編號(hào),當(dāng)前的函數(shù)名,函數(shù)參數(shù)值,函數(shù)所在文件及行號(hào),函數(shù)執(zhí)行到的語句。
info frame
info f
????? 這個(gè)命令會(huì)打印出更為詳細(xì)的當(dāng)前棧層的信息,只不過,大多數(shù)都是運(yùn)行時(shí)的內(nèi)內(nèi)地址。比如:函數(shù)地址,調(diào)用函數(shù)的地址,被調(diào)用函數(shù)的地址,目前的函數(shù)是由什么樣的程序語言寫成的、函數(shù)參數(shù)地址及值、局部變量的地址等等。如:
(gdb) info f
Stack level 0, frame at 0xbffff5d4:
eip = 0x804845d in func (tst.c:6); saved eip 0x8048524
called by frame at 0xbffff60c
source language c.
Arglist at 0xbffff5d4, args: n=250
Locals at 0xbffff5d4, Previous frame's sp is 0x0
Saved registers:
ebp at 0xbffff5d4, eip at 0xbffff5d8
info args
打印出當(dāng)前函數(shù)的參數(shù)名及其值。
info locals
打印出當(dāng)前函數(shù)中所有局部變量及其值。
info catch
打印出當(dāng)前的函數(shù)中的異常處理信息。
http://my.oschina.net/u/219482/blog/313598
總結(jié)
以上是生活随笔為你收集整理的ubuntu core 文件产生的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【解决方案】Ehome协议视频融合平台E
- 下一篇: ubuntu18.04安装pycharm