核心傾印與事後除錯(core dump)
有時候程式當掉時你並沒有在看——它在凌晨三點死在某台伺服器上,或者它每一千次才壞一次、你根本來不及當場抓到。要是能有一張死亡那一刻的快照就太好了:每一個變數、呼叫堆疊、暫存器裡的值,全部凍結在它們當時的樣子。核心傾印正是那張快照。當程式嚴重當掉時,作業系統可以把它記憶體的內容與 CPU 狀態寫進一個叫做核心(或「核心傾印」)的檔案,把這具屍體保存下來供你日後檢驗。
具體來說,當一個行程撞上致命錯誤——區段錯誤、abort、非法指令——核心(kernel)在設定允許的情況下,可能把這個行程的定址空間與暫存器狀態傾印成一個檔案(常命名為「core」或「core.PID」)。之後你做事後除錯:把那個核心檔連同原本的可執行檔一起載入除錯器——在 gdb 裡是「gdb ./program core」——除錯器就把現場重建得彷彿當機剛剛發生。你無法往前走(程式已死、已凍結),但其餘所有唯讀的事你都能做:用「bt」看通向當機的呼叫堆疊追蹤、用「print」檢查變數、檢視記憶體、走過各堆疊框找出那個壞值。這是一場驗屍:對死亡那一刻有完整資訊,但無法讓病人繼續。
為何重要:核心傾印把無法當場觀看、偶發、或生產環境的當機,變成可調查的證據——你不需要當場重現臭蟲,只要有屍體和帶著除錯資訊建構出來的對應執行檔。誠實的提醒:傾印常常預設是關閉的、並受一個資源限制所封頂(在 Linux 上「ulimit -c unlimited」開啟它們),所以除非你事先打開,否則可能什麼也拿不到;一個搭配到錯誤或最佳化過的執行檔的核心檔會給出誤導或無符號的結果;核心檔可能很大(它是整個記憶體映像)、也可能含有敏感資料,所以要小心處理。
$ ulimit -c unlimited 接著執行程式直到它發生區段錯誤,產生一個名為 core 的檔案。然後 $ gdb ./program core 在裡面, bt 顯示死亡那一刻的呼叫堆疊、 print 揭露那些變數——而這一切都不必再重現一次當機。
一個核心檔加上執行檔,讓你能驗屍一場你從未親眼看到發生的當機。
核心傾印常常預設是關閉的(大小限制為零),也可能被作業系統重新導向,所以除非你事先啟用,否則一場當機可能完全不留下核心檔。核心檔只有搭配產生它的那個確切執行檔才有意義,最好是用 -g 建構出來的。