天天看點

段錯誤調試神器 - Core Dump詳解

一、前言:

有的程式可以通過編譯, 但在運作時會出現Segment fault(段錯誤). 這通常都是指針錯誤引起的. 但這不像編譯錯誤一樣會提示到檔案某一行, 而是沒有任何資訊, 使得我們的調試變得困難起來. 

gdb: 有一種辦法是, 我們用gdb的step, 一步一步尋找. 這放在短小的代碼中是可行的, 但要讓你step一個上萬行的代碼, 我想你會從此厭惡程式員這個名字, 而把他叫做調試員. 我們還有更好的辦法, 這就是core file. 

ulimit: 如果想讓系統在信号中斷造成的錯誤時産生core檔案, 我們需要在shell中按如下設定: #設定core大小為無限 ulimit -c unlimited #設定檔案大小為無限 ulimit unlimited 這些需要有root權限, 在ubuntu下每次重新打開中斷都需要重新輸入上面的第一條指令, 來設定core大小為無限. 

用gdb檢視core檔案: 下面我們可以在發生運作時信号引起的錯誤時發生core dump了. 發生core dump之後, 用gdb進行檢視core檔案的内容, 以定位檔案中引發core dump的行. gdb [exec file] [core file] 如: gdb ./test test.core 在進入gdb後, 用bt指令檢視backtrace以檢查發生程式運作到哪裡, 來定位core dump的檔案->行. 

1. 什麼是Core: 

Sam之前一直以為Core Dump中Core是 Linux Kernel的意思. 今天才發現在這裡,Core是另一種意思: 

在使用半導體作為記憶體的材料前,人類是利用線圈當作記憶體的材料(發明者為王安),線圈就叫作 core ,用線圈做的記憶體就叫作 core memory。如今 ,半導體工業澎勃發展,已經沒有人用 core memory 了,不過,在許多情況下, 人們還是把記憶體叫作 core 。 

2. 什麼是Core Dump: 

我們在開發(或使用)一個程式時,最怕的就是程式莫明其妙地當掉。雖然系統沒事,但我們下次仍可能遇到相同的問題。于是這時作業系統就會把程式當掉 時的記憶體内容 dump 出來(現在通常是寫在一個叫 core 的 file 裡面),讓 我們或是 debugger 做為參考。這個動作就叫作 core dump。 

3. Core Dump時會生成何種檔案: 

Core Dump時,會生成諸如 core.程序号 的檔案。 

4. 為何有時程式Down了,卻沒生成 Core檔案。 

Linux下,有一些設定,标明了resources available to the shell and to processes。 可以使用#ulimit -a 來看這些設定。 (ulimit是bash built-in Command) 

-a All current limits are reported 

-c The maximum size of core files created 

-d The maximum size of a process鈥檚 data segment 

-e The maximum scheduling priority ("nice") 

-f The maximum size of files written by the shell and its children 

-i The maximum number of pending signals 

-l The maximum size that m ay be locked into memory 

-m The maximum resident set size (has no effect on Linux) 

-n The maximum number of open file descriptors (most systems do not allow this value to be set) 

-p The pipe size in 512-byte blocks (this may not be set) 

-q The maximum number of bytes in POSIX message queues 

-r The maximum real-time scheduling priority 

-s The maximum stack size 

-t The maximum amount of cpu time in seconds 

-u The maximum number of processes available to a single user 

-v The maximum amount of virtual memory available to the shell 

-x The maximum number of file locks 

從這裡可以看出,如果 -c是顯示:core file size (blocks, -c) 如果這個值為0,則無法生成core檔案。是以可以使用: 

#ulimit -c 1024 或者 #ulimit -c unlimited 來使能 core檔案。 

如果程式出錯時生成Core 檔案,則會顯示Segmentation fault (core dumped) 。 

5. Core Dump的核心轉儲檔案目錄和命名規則: 

/proc/sys/kernel /core_uses_pid可以控制産生的core檔案的檔案名中是否添加pid作為擴充,如果添加則檔案内容為1,否則為0 

6. 如何使用Core檔案: 

在Linux下,使用: 

#gdb -c core.pid program_name 

就可以進入gdb模式。 

輸入where,就可以指出是在哪一行被Down掉,哪個function内,由誰調用等等。 

(gdb) where 

或者輸入 bt。 

(gdb) bt 

7. 如何讓一個正常的程式down: 

#kill -s SIGSEGV pid 

8. 察看Core檔案輸出在何處: 

存放Coredump的目錄即程序的目前目錄,一般就是當初發出指令啟動該程序時所在的目錄。但如果是通過腳本啟動,則腳本可能會修改目前目錄,這時程序真正的目前目錄就會與當初執行腳本所在目錄不同。這時可以檢視”/proc/<程序pid>/cwd“符号連結的目标來确定程序真正的目前目錄位址。通過系統服務啟動的程序也可通過這一方法檢視。 

9. 嵌入式裝置下如何使用Core dump: 

linux coredump配置與調試 

Linux 

二、Core Dump 配置與調試 

1.core檔案的生成開關和大小限制 

--------------------------------- 

1)使用ulimit -c 指令可檢視core檔案的生成開關。若結果為0,則表示關閉了此功能,不會生成core檔案。 

2)使用ulimit -c filesize指令,可以限制core檔案的大小(filesize的機關為kbyte)。若ulimit -c unlimited,則表示core檔案的大小不受限制。如果生成的資訊超過此大小,将會被裁剪,最終生成一個不完整的core檔案。在調試此core檔案的時候,gdb會提示錯誤。 

2.core檔案的名稱和生成路徑 

---------------------------- 

若系統生成的core檔案不帶其它任何擴充名稱,則全部命名為core。新的core檔案生成将覆寫原來的core檔案 。 

1)/proc/sys /kernel/core_uses_pid可以控制core檔案的檔案名中是否添加pid作為擴充。檔案内容為1,表示添加pid作為擴充名,生成的 core檔案格式為core.xxxx;為0則表示生成的core檔案同一命名為core。 

可通過以下指令修改此檔案: 

echo"1" >/proc/sys/kernel/core_uses_pid 

2)proc/sys/kernel/core_pattern可以控制core檔案儲存位置和檔案名格式。 

echo"/corefile/core-%e-%p-%t" >core_pattern,可以将core檔案統一生成到/corefile目錄下,産生的檔案名為core-指令名-pid-時間戳 

以下是參數清單: 

%p - insert pid into filename 添加pid 

%u - insert current uid into filename 添加目前uid 

%g - insert current gid into filename 添加目前gid 

%s - insert signal that caused the coredump into the filename 添加導緻産生core的信号 

%t - insert UNIX time that the coredump occurred into filename 添加core檔案生成時的unix時間 

%h - insert hostname where the coredump happened into filename 添加主機名 

%e - insert coredumping executable name into filename 添加指令名 

3.用gdb檢視core檔案: 

下面我們可以在發生運作時信号引起的錯誤時發生core dump了. 

發生 core dump之後,用gdb進行檢視core檔案的内容,以定位檔案中引發core dump的行. 

gdb [exec file] [core file] 

如:gdb ./test test.core 

在進入gdb後,用 bt指令檢視backtrace以檢查發生程式運作到哪裡,來定位core dump的檔案->行. 

4.開發闆上使用core檔案調試 

----------------------------- 

如果開發闆的作業系統也是linux,core調試方法依然适用。如果開發闆上不支援gdb,可将開發闆的環境(頭檔案、庫)、可執行檔案和core檔案拷貝到PC的linux下,運作相關指令即可。 

注意:待調試的可執行檔案,在編譯的時候需要加-g,core檔案才能正常顯示出錯資訊! 

注意的問題: 

在Linux下要保證程式崩潰時生成 Coredump要注意這些問題: 

  一、要保證存放Coredump的目錄存在且程序對該目錄有寫權限。存放Coredump 的目錄即程序的目前目錄,一般就是當初發出指令啟動該程序時所在的目錄。但如果是通過腳本啟動,則腳本可能會修改目前目錄,這時程序真正的目前目錄就會與當初執行腳本所在目錄不同。這時可以檢視”/proc/程序pid>/cwd“符号連結的目标來确定程序真正的目前目錄位址。通過系統服務啟動的程序也可通過這一方法檢視。 

  二、若程式調用了seteuid()/setegid()改變了程序的有效使用者或組,則在預設情況下系統不會為這些程序生成Coredump。很多服務程式都會調用seteuid(),如MySQL,不論你用什麼使用者運作 mysqld_safe啟動MySQL,mysqld進行的有效使用者始終是msyql使用者。如果你當初是以使用者A運作了某個程式,但在ps裡看到的 

這個程式的使用者卻是B的話,那麼這些程序就是調用了seteuid了。為了能夠讓這些程序生成core dump,需要将/proc/sys/fs/suid_dumpable 檔案的内容改為1(一般預設是0)。 

  三、這個一般都知道,就是要設定足夠大的Core檔案大小限制了。程式崩潰時生成的 Core檔案大小即為程式運作時占用的記憶體大小。但程式崩潰時的行為不可按平常時的行為來估計,比如緩沖區溢出等錯誤可能導緻堆棧被破壞,是以經常會出現某個變量的值被修改成亂七八糟的,然後程式用這個大小去申請記憶體就可能導緻程式比平常時多占用很多記憶體。是以無論程式正常運作時占用的記憶體多麼少,要保證生成Core檔案還是将大小限制設為unlimited為好。 

ulimit -- 使用者資源限制指令 

1、說明 :ulimit用于shell啟動程序所占用的資源. 

2、類别 :shell内建指令 

3、文法格式 :ulimit [-acdfHlmnpsStvw] [size] 

4、參數介紹 : 

-H 設定硬體資源限制. 

-S 設定軟體資源限制. 

-a 顯示目前所有的資源限制. 

-c size:設定core檔案的最大值.機關:blocks 

-d size:設定資料段的最大值.機關:kbytes 

-f size:設定建立檔案的最大值.機關:blocks 

-l size:設定在記憶體中鎖定程序的最大值.機關:kbytes 

-m size:設定可以使用的常駐記憶體的最大值.機關:kbytes 

-n size:設定核心可以同時打開的檔案描述符的最大值.機關:n 

-p size:設定管道緩沖區的最大值.機關:kbytes 

-s size:設定堆棧的最大值.機關:kbytes 

-t size:設定CPU使用時間的最大上限.機關:seconds 

-v size:設定虛拟記憶體的最大值.機關:kbytes 5,簡單執行個體: 

5、舉例 

在Linux下寫程式的時候,如果程式比較大,經常會遇到“段錯誤”(segmentationfault)這樣的問題,這主要就是由于Linux系統初始的堆棧大小(stack size)太小的緣故,一般為10M。我一般把stacksize設定成256M,這樣就沒有段錯誤了!指令為:ulimit -s 262140 

如果要系統自動記住這個配置,就編輯/etc/profile檔案,在 “ulimit -S -c 0 > /dev/null 2>&1”行下,添加“ulimit -s 262140”,儲存重新開機系統就可以了! 

1] 在RH8的環境檔案/etc/profile中,我們可以看到系統是如何配置ulimit的: 

#grep ulimit /etc/profile 

ulimit -S -c 0 > /dev/null 2>&1 

這條語句設定了對軟體資源和對core檔案大小的設定 

2] 如果我們想要對由shell建立的檔案大小作些限制,如: 

#ll h 

-rw-r--r-- 1 lee lee 150062 7月 22 02:39 h 

#ulimit -f 100 #設定建立檔案的最大塊(一塊=512位元組) 

#cat h>newh 

File size limit exceeded 

#ll newh 

-rw-r--r-- 1 lee lee 51200 11月 8 11:47 newh 

檔案h的大小是150062位元組,而我們設定的建立檔案的大小是512位元組x100塊=51200位元組,當然系統就會根據你的設定生成了51200位元組的newh檔案. 

3] 可以像執行個體1]一樣,把你要設定的ulimit放在/etc/profile這個環境檔案中. 

用途:設定或報告使用者資源極限。 

文法:ulimit [ -H ] [ -S ] [ -a ] [ -c ] [ -d ] [ -f ] [ -m ] [ -n ] [ -s ] [ -t ] [ Limit ] 

描述:ulimit 指令設定或報告使用者程序資源極限,如 /etc/security/limits 檔案所定義。檔案包含以下預設值極限: 

fsize = 2097151 

core = 2097151 

cpu = -1 

data = 262144 

rss = 65536 

stack = 65536 

nofiles = 2000 

當新使用者添加到系統中時,這些值被作為預設值使用。當向系統中添加使用者時,以上值通過 mkuser 指令設定,或通過 chuser 指令更改。 

極限分為軟性或硬性。通過 ulimit 指令,使用者可将軟極限更改到硬極限的最大設定值。要更改資源硬極限,必須擁有 root 使用者權限。 

很多系統不包括以上一種或數種極限。 特定資源的極限在指定 Limit 參數時設定。Limit 參數的值可以是每個資源中指定單元中的數字,或者為值 unlimited。要将特定的 ulimit 設定為 unlimited,可使用詞 unlimited。 

注:在 /etc/security/limits 檔案中設定預設極限就是設定了系統寬度極限, 而不僅僅是建立使用者時使用者所需的極限。 

省略 Limit 參數時,将會列印出目前資源極限。除非使用者指定 -H 标志,否則列印出軟極限。當使用者指定一個以上資源時,極限名稱和單元在值之前列印。如果未給予選項,則假定帶有了 -f 标志。 

由于 ulimit 指令影響目前 shell 環境,是以它将作為 shell 正常内置指令提供。如果在獨立的指令執行環境中調用該指令,則不影響調用者環境的檔案大小極限。以下示例中正是這種情況: 

nohup ulimit -f 10000 

env ulimit 10000 

一旦通過程序減少了硬極限,若無 root 特權則無法增加,即使傳回到原值也不可能。 

關于使用者和系統資源極限的更多資訊,請參見 AIX 5L Version 5.3 Technical Reference: BaseOperating System and Extensions Volume 1 中的 getrlimit、setrlimit 或vlimit 子例程。 

标志 

-a 列出所有目前資源極限。 

-c 以 512 位元組塊為機關,指定核心轉儲的大小。 

-d 以 K 位元組為機關指定資料區域的大小。 

-f 使用 Limit 參數時設定檔案大小極限(以塊計),或者在未指定參數時報告檔案大小極限。預設值為 -f 标志。 

-H 指定設定某個給定資源的硬極限。如果使用者擁有 root 使用者權限,可以增大硬極限。任何使用者均可減少硬極限。 

-m 以 K 位元組為機關指定實體存儲器的大小。 

-n 指定一個程序可以擁有的檔案描述符的數量的極限。 

-s 以 K 位元組為機關指定堆棧的大小。 

-S 指定為給定的資源設定軟極限。軟極限可增大到硬極限的值。如果 -H 和 -S 标志均未指定,極限适用于以上二者。 

-t 指定每個程序所使用的秒數 。 

退出狀态 

傳回以下退出值: 

0 成功完成。