標籤:

Linux Core Dump

Linux Core Dump

當程序運行的過程中異常終止或崩潰,操作系統會將程序當時的內存狀態記錄下來,保存在一個文件中,這種行為就叫做Core Dump(中文有的翻譯成「核心轉儲」)。我們可以認為 core dump 是「內存快照」,但實際上,除了內存信息之外,還有些關鍵的程序運行狀態也會同時 dump 下來,例如寄存器信息(包括程序指針、棧指針等)、內存管理信息、其他處理器和操作系統狀態和信息。core dump 對於編程人員診斷和調試程序是非常有幫助的,因為對於有些程序錯誤是很難重現的,例如指針異常,而 core dump 文件可以再現程序出錯時的情景。

Core Dump 名詞解釋

在半導體作為電腦內存材料之前,電腦內存使用的是 磁芯內存(Magnetic Core Memory),Core Dump 中的 Core 沿用了磁芯內存的 Core 表達。圖為磁芯內存的一個單元,來自 Wikipedia.

在 APUE 一書中作者有句話這樣寫的:

Because the file is named core, it shows how long this feature has been part of the Unix System.

這裡的 core 就是沿用的是早期電腦磁芯內存中的表達,也能看出 Unix 系統 Core Dump 機制的悠久歷史。

Dump 指的是拷貝一種存儲介質中的部分內容到另一個存儲介質,或者將內容列印、顯示或者其它輸出設備。dump 出來的內容是格式化的,可以使用一些工具來解析它。

現代操作系統中,用 Core Dump 表示當程序異常終止或崩潰時,將進程此時的內存中的內容拷貝到磁碟文件中存儲,以方便編程人員調試。

Core Dump 如何產生

上面說當程序運行過程中異常終止或崩潰時會發生 core dump,但還沒說到什麼具體的情景程序會發生異常終止或崩潰,例如我們使用 kill -9 命令殺死一個進程會發生 core dump 嗎?實驗證明是不能的,那麼什麼情況會產生呢?

Linux 中信號是一種非同步事件處理的機制,每種信號對應有其默認的操作,你可以在 這裡 查看 Linux 系統提供的信號以及默認處理。默認操作主要包括忽略該信號(Ingore)、暫停進程(Stop)、終止進程(Terminate)、終止並發生core dump(core)等。如果我們信號均是採用默認操作,那麼,以下列出幾種信號,它們在發生時會產生 core dump:

SignalActionCommentSIGQUITCoreQuit from keyboardSIGILLCoreIllegal InstructionSIGABRTCoreAbort signal from abortSIGSEGVCoreInvalid memory referenceSIGTRAPCoreTrace/breakpoint trap

當然不僅限於上面的幾種信號。這就是為什麼我們使用 Ctrl+z 來掛起一個進程或者 Ctrl+C 結束一個進程均不會產生 core dump,因為前者會向進程發出 SIGTSTP 信號,該信號的默認操作為暫停進程(Stop Process);後者會向進程發出SIGINT 信號,該信號默認操作為終止進程(Terminate Process)。

同樣上面提到的 kill -9 命令會發出 SIGKILL 命令,該命令默認為終止進程。而如果我們使用 Ctrl+ 來終止一個進程,會向進程發出 SIGQUIT 信號,默認是會產生 core dump 的。還有其它情景會產生 core dump, 如:程序調用 abort() 函數、訪存錯誤、非法指令等等。

下面舉兩個例子來說明:

  • 終端下比較 Ctrl+C 和 Ctrl+:

guohailin@guohailin:~$ sleep 10 #使用sleep命令休眠 10 s

^C #使用 Ctrl+C 終止該程序,不會產生 core dump

guohailin@guohailin:~$ sleep 10

^Quit (core dumped) #使用 Ctrl+ 退出程序, 會產生 core dump

guohailin@guohailin:~$ ls #多出下面一個 core 文件

-rw-------  1 guohailin guohailin 335872 10月 22 11:31 sleep.core.21990

  • 小程序產生 core dump

#include

int main()

{

int *null_ptr = NULL;

*null_ptr = 10; //對空指針指向的內存區域寫,會發生段錯誤

return 0;

}

#編譯執行

guohailin@guohailin:~$ ./a.out

Segmentation fault (core dumped)

guohailin@guohailin:~$ ls #多出下面一個 core 文件

-rw------- 1 guohailin guohailin 200704 10月 22 11:35 a.out.core.22070

Linux 下打開 Core Dump

我使用的 Linux 發行版是 Ubuntu 13.04,設置生成 core dump 文件的方法如下:

  • 打開 core dump 功能

    • 在終端中輸入命令 ulimit -c ,輸出的結果為 0,說明默認是關閉 core dump 的,即當程序異常終止時,也不會生成 core dump 文件。

    • 我們可以使用命令 ulimit -c unlimited 來開啟 core dump 功能,並且不限制 core dump 文件的大小; 如果需要限制文件的大小,將 unlimited 改成你想生成 core 文件最大的大小,注意單位為 blocks(KB)。

    • 用上面命令只會對當前的終端環境有效,如果想需要永久生效,可以修改文件 /etc/security/limits.conf文件,關於此文件的設置參看 這裡 。增加一行:

# /etc/security/limits.conf

#

#Each line describes a limit for a user in the form:

#

#<domain> <type> <item> <value>

* soft core unlimited

  • 修改 core 文件保存的路徑

    • 默認生成的 core 文件保存在可執行文件所在的目錄下,文件名就為 core。

    • 通過修改 /proc/sys/kernel/core_uses_pid 文件可以讓生成 core 文件名是否自動加上 pid 號。

      例如 echo 1 > /proc/sys/kernel/core_uses_pid ,生成的 core 文件名將會變成 core.pid,其中 pid 表示該進程的 PID。

    • 還可以通過修改 /proc/sys/kernel/core_pattern 來控制生成 core 文件保存的位置以及文件名格式。

      例如可以用 echo "/tmp/corefile-%e-%p-%t" > /proc/sys/kernel/core_pattern 設置生成的 core 文件保存在 「/tmp/corefile」 目錄下,文件名格式為 「core-命令名-pid-時間戳」。這裡 有更多詳細的說明!

使用 gdb 調試 Core 文件

產生了 core 文件,我們該如何使用該 Core 文件進行調試呢?Linux 中可以使用 GDB 來調試 core 文件,步驟如下:

  • 首先,使用 gcc 編譯源文件,加上 -g 以增加調試信息;

  • 按照上面打開 core dump 以使程序異常終止時能生成 core 文件;

  • 運行程序,當core dump 之後,使用命令 gdb program core 來查看 core 文件,其中 program 為可執行程序名,core 為生成的 core 文件名。

下面用一個簡單的例子來說明:

#include

int func(int *p)

{

int y = *p;

return y;

}

int main()

{

int *p = NULL;

return func(p);

}

編譯加上調試信息, 運行之後core dump, 使用 gdb 查看 core 文件.

guohailin@guohailin:~$ gcc core_demo.c -o core_demo -g

guohailin@guohailin:~$ ./core_demo

Segmentation fault (core dumped)

guohailin@guohailin:~$ gdb core_demo core_demo.core.24816

...

Core was generated by ./core_demo.

Program terminated with signal 11, Segmentation fault.

#0 0x080483cd in func (p=0x0) at core_demo.c:5

5 int y = *p;

(gdb) where

#0 0x080483cd in func (p=0x0) at core_demo.c:5

#1 0x080483ef in main () at core_demo.c:12

(gdb) info frame

Stack level 0, frame at 0xffd590a4:

eip = 0x80483cd in func (core_demo.c:5); saved eip 0x80483ef

called by frame at 0xffd590c0

source language c.

Arglist at 0xffd5909c, args: p=0x0

Locals at 0xffd5909c, Previous frames sp is 0xffd590a4

Saved registers:

ebp at 0xffd5909c, eip at 0xffd590a0

(gdb)

從上面可以看出,我們可以還原 core_demo 執行時的場景,並使用 where 可以查看當前程序調用函數棧幀, 還可以使用 gdb 中的命令查看寄存器,變數等信息.

來源:hazir

鏈接:Linux Core Dump - hazir - 博客園


推薦閱讀:

有什麼理由選擇收費的RHEL而不用免費的Centos?
怎麼才能可以有點玩轉 Linux 的感覺?為什麼覺得自己搞了半年的時間,還是擺脫不了被玩的感覺?
Linux文件亂碼
微軟為什麼用帶 BOM 的 UTF-8,造成和多數系統的不兼容?
ATM 系統為什麼使用 Windows 而不使用 Linux?

TAG:Linux |