ubuntu core 文件產生

關於內核轉儲的設置方法linux

 

1. 內核轉儲做用shell

 

(1) 內核轉儲的最大好處是可以保存問題發生時的狀態。ubuntu

(2) 只要有可執行文件和內核轉儲,就能夠知道進程當時的狀態。服務器

(3) 只要獲取內核轉儲,那麼即便沒有復現環境,也能調試。函數

 

2. 啓用內核轉儲測試

1.1 查看內核轉儲是否有效spa

在終端中輸入如下命令,查看內核轉儲是否有效。命令行

#ulimit -c調試

0code

-c 表示內核轉儲文件的大小限制,如今顯示爲零,表示不能用。

能夠改成1G

#ulimit -c 1073741824

也能夠改成無限制

#ulimit -c unlimited

 

2.2 測試一個例子

例子的源代碼:

#include <stdio.h>

int main(void)

{

int *a = NULL;

*a = 0x1;

return 0;

}

 

把以上源代碼,寫成一個a.c文件後,編譯a.c文件產生一個a.out的可執行文件:

#gcc -g a.c -o a.out

修改a.out文件的權限後,執行它:

#./a.out

就會顯示:

Segmentation fault(core dump)

這表示在當前目錄下, 已經生成了a.out對應的內核轉儲文件。

注意:後面帶有(core dump), 才說明轉儲文件成功生成了。

#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調試內核轉儲文件,應該使用如下方式啓動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號信號。用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            }

這裏默認都是當前目錄,也能夠給core 和a.out 指定路徑

到這裏測試完成!

 

2.3 永久生效的辦法

上面所述的方法,只是在當前shell中生效,重啓以後,就再也不有效了。永久生效的辦法是:

#vi /etc/profile 而後,在profile中添加:

ulimit -c 1073741824

 (可是,若將產生的轉儲文件大小大於該數字時,將不會產生轉儲文件)

或者

ulimit -c unlimited

 

這樣重啓機器後生效了。 或者, 使用source命令使之立刻生效。

#source /etc/profile

 

3. 指定內核轉儲的文件名和目錄

缺省狀況下,內核在coredump時所產生的core文件放在與該程序相同的目錄中,而且文件名固定爲core。很顯然,若是有多個程序產生core文件,或者同一個程序屢次崩潰,就會重複覆蓋同一個core文件。

咱們能夠經過修改kernel的參數,指定內核轉儲所生成的core文件的路徑和文件名。

能夠經過在/etc/sysctl.conf文件中,對sysctl變量kernel.core_pattern的設置。

#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。若是這個文件的內容被配置成1,即便core_pattern中沒有設置%p,最後生成的core dump文件名仍會加上進程ID。

這裏%e, %p分別表示:

%c 轉儲文件的大小上限

%e 所dump的文件名

%g 所dump的進程的實際組ID

%h 主機名

%p 所dump的進程PID

%s 致使本次coredump的信號

%t 轉儲時刻(由1970年1月1日起計的秒數)

%u 所dump進程的實際用戶ID

可使用如下命令,使修改結果立刻生效。

#sysctl –p /etc/sysctl.conf

 

請在/var目錄下先創建core文件夾,而後執行a.out程序,就會在/var/core/下產生以指定格式命名的內核轉儲文件。查看轉儲文件的狀況:

#ls /var/core

core_a.out_2834

 

4. 手動強制某個進程產生core dump的方法(嘗試)

當某些程序發生crash時,對應進程會產生coredump文件。經過這個coredump文件,開發人員能夠找到bug的緣由。可是coredump的產生,大都是由於程序crash了。

而有些bug是不會致使程序crash的,好比死鎖,這時程序已經不正常了,但是卻沒有coredump產生。若是環境又不容許gdb調試,難道咱們就一籌莫展了嗎?

針對以上這種狀況,通常狀況下,對於這樣的進程能夠利用 watchdog監控它們,當發現這些進程很長時間沒有更新其heartbeat時,能夠給這些進程發送能夠致使其產生coredump的信號。根據 linux的信號默認的處理行爲,SIGQUIT,SIGABRT, SIGFPE和SIGSEGV均可以讓該進程產生coredump文件。這樣咱們能夠經過coredump來得知死鎖是否發生。 固然, 若是進程添加了這些信號的處理函數,那麼就不會產生coredump了。不過,對於SIGQUIT, SIGABRT, SIGFPE, SIGSEGV,有誰會爲它們加上信號處理函數呢。

 

還有一種狀況,進程並無死鎖或者block在某個位置, 可是咱們須要在某個指定位置進行調試,獲取某些變量或者其它信息。可是,有多是客戶環境或者生產環境,不容許咱們進行長時間的檢測。那麼,咱們就須要通 過coredump來得到進程在運行到該點時的快照。 這個時候,能夠利用gdb來手工產生coredump。在attach上這個進程時,在指定位置打上斷點,當斷點觸發時,使用gdb的命令gcore,可 以當即產生一個coredump。 這樣,咱們就拿到了這個位置的進程快照。

 

1.尋找您要發送信號的進程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號是3207

2.使用kill(1)去發送信號。

 

# /bin/kill -s QUIT 3207

 

發送其餘的信號也很類似, 只要在命令行中替換QUIT 爲ABRT,TERM 或 KILL 就好了

 

重要提示: 在系統上隨意殺死進程是一個壞主意,特別是init(8),它的PID是1,它很是特殊。 能夠運行 /bin/kill -s KILL 1 命令來讓系統迅速關機。  當您按下 Return (回車)鍵以前,必定要 詳細檢查您運行 kill(1) 時所指定的參數。

 

5 使用core dump進行調試

在Linux下遇到「段錯誤」(segmentation fault),若是段錯誤發生在服務器端,而服務器端要繼續工做,不容許調試,這時「內核轉儲(core dump)」就派上了用場,能夠把生成的內核轉儲複製到本地進行調試。

    首先,按照上面的永久生效方法,在服務器上進行相應設置。 而後程序在崩潰時,就會在程序所在目錄(或本身指定的目錄)生成一個core文件,把這個core文件拷到本地(最好與該進程對應的可執行文件放到同一個目錄,若否則,在gdb時指出路徑也能夠)。

 

具體方法以下:

方法一:

輸入命令 #gdb <程序可執行文件> <coredump轉儲文件>

例如:

# gdb /usr/local/bin/qemu-system-x86_64  /var/core/core-3207-qemu-system-x86

而後,在(gdb)提示符後輸入 l,  會顯示main主函數

 

 

方法二:

(1) 在終端輸入命令# gdb [-c] <coredump文件>,

例如: gdb -c /var/core/core-3207-qemu-system-x86

(2)而後,在(gdb)提示符後輸入file <可執行程序>

例如:(gdb) file  /usr/local/bin/qemu-system-x86_64

(3) 這時就能夠用backtrace/thread等命令查看當時的錯誤了,就像程序在本地執行到崩潰點同樣

或者用where回車, 也能夠顯示程序在哪一行當掉的

 

5. 啓用整個系統的內核轉儲

(未完待續......)

 

(4.1) 編輯/etc/profile, 開啓登陸到系統的全部用戶的內核轉儲功能

首先,看看用的是個什麼機器:

# uname –a

Linux ubuntu240 2.6.32-21-server #32-Ubuntu SMP Fri Apr 16 09:17:34 UTC 2010 x86_64 GNU/Linux

其次,再查看一些默認參數,若core file size是0,即便程序出錯時,也不會產生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

 

查看棧信息

 

      當程序被停住了,你須要作的第一件事就是查看程序是在哪裏停住的。當你的程序調用了一個函數,函數的地址,函數參數,函數內的局部變量都會被壓入「棧」(Stack)中。你能夠用GDB命令來查看當前的棧中的信息。

下面是一些查看函數調用棧信息的GDB命令:

backtrace
bt

打印當前的函數調用棧的全部信息。如:

(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

從上能夠看出函數的調用棧信息:__libc_start_main --> main() --> func()

backtrace
bt

n是一個正整數,表示只打印棧頂上n層的棧信息。

backtrace <-n>
bt <-n>

-n表一個負整數,表示只打印棧底下n層的棧信息。

若是你要查看某一層的信息,你須要在切換當前的棧,通常來講,程序中止時,最頂層的棧就是當前棧,若是你要查看棧下面層的詳細信息,首先要作的是切換當前棧。

frame
f

n是一個從0開始的整數,是棧中的層編號。好比:frame 0,表示棧頂,frame 1,表示棧的第二層。

up

表示向棧的上面移動n層,能夠不打n,表示向上移動一層。

down

表示向棧的下面移動n層,能夠不打n,表示向下移動一層。

上面的命令,都會打印出移動到的棧層的信息。若是你不想讓其打出信息。你可使用這三個命令:

select-frame 對應於 frame 命令。
up-silently 對應於 up 命令。
down-silently 對應於 down 命令。

查看當前棧層的信息,你能夠用如下GDB命令:

frame 或 f

會打印出這些信息:棧的層編號,當前的函數名,函數參數值,函數所在文件及行號,函數執行到的語句。

info frame
info f

      這個命令會打印出更爲詳細的當前棧層的信息,只不過,大多數都是運行時的內內地址。好比:函數地址,調用函數的地址,被調用函數的地址,目前的函數是由什麼樣的程序語言寫成的、函數參數地址及值、局部變量的地址等等。如:

(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打印出當前函數的參數名及其值。info locals打印出當前函數中全部局部變量及其值。info catch打印出當前的函數中的異常處理信息。

相關文章
相關標籤/搜索