Linux 內核(如下簡稱內核)是一個不與特定進程相關的功能集合,內核的代碼很難輕易的在調試器中執行和跟蹤。開發者認爲,內核若是發生了錯誤,就不該該繼續運行。所以內核發生錯誤時,它的行爲一般被設定爲系統崩潰,機器重啓。基於動態存儲器的電氣特性,機器重啓後,上次錯誤發生時的現場會遭到破壞,這使得查找內核的錯誤變得異常困難。架構
內核社區和一些商業公司爲此開發了不少種調試技術和工具,但願可讓內核的調試變得簡單。其中一種是單步跟蹤調試方法,即便用代碼調試器,一步步的跟蹤執行的代碼,經過查看變量和寄存器的值來分析錯誤發生的緣由。這一類的調試器有 gdb,kdb, kgdb。另外一種方法是在系統崩潰時,將內存保存起來,供過後進行分析。多數狀況下,單步調式跟蹤能夠知足需求,可是單步跟蹤調試也有缺點。如遇到以下幾種狀況時:app
- 錯誤發生在客戶的機器上。
- 錯誤發生在很關鍵的生產機器上。
- 錯誤很難重現。
單步調試跟蹤方法將無能爲力。對於這幾種狀況,在內核發生錯誤並崩潰的時候,將內存轉儲起來供過後分析就顯得尤其重要。本文接下來將介紹內核的內存轉儲機制以及如何對其進行分析。函數
回頁首工具
因爲 Linux 的開放性的緣故,在 Linux 下有好幾種內存轉儲機制。下面將對它們分別作簡要的介紹。網站
LKCD(Linux Kernel Crash Dump) 是 Linux 下第一個內核崩潰內存轉儲項目,它最初由 SGI 的工程師開發和維護。它提供了一種可靠的方法來發現、保存和檢查系統的崩潰。LKCD 做爲 Linux 內核的一個補丁,它一直以來都沒有被接收進入內核的主線。目前該項目已經徹底中止開發。
Diskdump 是另一個內核崩潰內存轉儲的內核補丁,它由塔高 (Takao Indoh) 在 2004 年開發出來。與 LKCD 相比,Diskdump 更加簡單。當系統崩潰時,Diskdump 對系統有徹底的控制。爲避免混亂,它首先關閉全部的中斷;在 SMP 系統上,它還會把其餘的 CPU 停掉。而後它校驗它本身的代碼,若是代碼與初始化時不同。它會認爲它已經被破壞,並拒絕繼續運行。而後 Diskdump 選擇一個位置來存放內存轉儲。Diskdump 做爲一個內核的補丁,也沒有被接收進入內核的主線。在衆多的發行版中,它也只獲得了 RedHat 的支持。
RedHat 在它的 Linux 高級服務器 2.1 的版本中,提供了它本身的第一個內核崩潰內存轉儲機制:Netdump。 與 LKCD 和 Diskdump 將內存轉儲保存在本地磁盤不一樣,當系統崩潰時,Netdump 將內存轉儲文件經過網絡保存到遠程機器中。RedHat 認爲採用網絡方式比採用磁盤保的方式要簡單,由於當系統崩潰時,能夠在沒有中斷的狀況下使用網卡的論詢模式來進行網絡數據傳送。同時,網絡方式對內存轉儲文件提供了更好的管理支持。與 Diskdump 同樣,Netdump 沒有被接收進入內核的主線,目前也只有 RedHat 的發行版對 Netdump 提供支持。
Kdump 是一種基於 kexec 的內存轉儲工具,目前它已經被內核主線接收,成爲了內核的一部分,它也由此得到了絕大多數 Linux 發行版的支持。與傳統的內存轉儲機制不一樣不一樣,基於 Kdump 的系統工做的時候須要兩個內核,一個稱爲系統內核,即系統正常工做時運行的內核;另一個稱爲捕獲內核,即正常內核崩潰時,用來進行內存轉儲的內核。 在本文稍後的內容中,將會介紹如何設置 kump。
MKdump(mini kernel dump) 是 NTT 數據和 VA Linux 開發另外一個內核內存轉儲工具,它與 Kdump 相似,都是基於 kexec,都須要使用兩個內核來工做。其中一個是系統內核;另一個是 mini 內核,用來進行內存轉儲。與 Kdump 相比,它有如下特色:
- 將內存保存到磁盤。
- 能夠將內存轉儲鏡像轉換到 lcrash 支持格式。
- 經過 kexec 啓動時,mini 內核覆蓋第一個內核。
與具備衆多的內存轉儲機制同樣,Linux 下也有衆多的內存轉儲分析工具,下面將會逐一作簡單介紹。
Lcrash 是隨 LKCD 一塊兒發佈的一個內內存儲分析工具。隨着 LKCD 開發的中止,lcrash 的開發也同時中止了。目前它的代碼已經被合併進入 Crash 工具中。
Alicia (Advanced Linux Crash-dump Interactive Analyzer,高級 Linux 崩潰內存轉儲交互分析器 ) 是一個創建在 lcrash 和 Crash 工具之上的一個內存轉儲分析工具。它使用 Perl 語言封裝了 Lcrash 和 Crash 的底層命令,向用戶提供了一個更加友好的交互方式和界面。Alicia 目前的開發也已經停滯。
Crash 是由 Dave Anderson 開發和維護的一個內存轉儲分析工具,目前它的最新版本是 5.0.0。 在沒有統一標準的內存轉儲文件的格式的狀況下,Crash 工具支持衆多的內存轉儲文件格式,包括:
- Live linux 系統
- kdump 產生的正常的和壓縮的內存轉儲文件
- 由 makedumpfile 命令生成的壓縮的內存轉儲文件
- 由 Netdump 生成的內存轉儲文件
- 由 Diskdump 生成的內存轉儲文件
- 由 Kdump 生成的 Xen 的內存轉儲文件
- IBM 的 390/390x 的內存轉儲文件
- LKCD 生成的內存轉儲文件
- Mcore 生成的內存轉儲文件
經過前面的學習,你如今可能已經躍躍欲試了。本文接下來的部分,將以 kdump 爲例子,向你們演示如何設置系統、如何產生內存轉儲文件以及如何對內存轉儲文件進行分析。
如前面所述,支持 kdump 的系統使用兩個內核進行工做。目前一些發行版,如 RedHat 和 SUSE 的 Linux 都已經編譯並設置好這兩個內核。若是你使用其餘發行版的 Linux 或者想本身編譯內核支持 kdump,那麼能夠根據以下介紹進行。
- 使用 root 用戶登陸系統。
- 使用 wget 從 Internet 上下載 kexec。
wget http://www.kernel.org/pub/linux/kernel/people/horms/kexec-tools/\ kexec-tools.tar.gz
- 解壓並安裝 kexec 到系統中。
# tar xvpzf kexec-tools.tar.gz # cd kexec-tools-VERSION # ./configure # make && make install
- 在 "Processor type and features."選項中啓用"kexec system call"。
CONFIG_KEXEC=y
- 在"Filesystem" -> "Pseudo filesystems." 中啓用"sysfs file system support"。
CONFIG_SYSFS=y
- 在"Kernel hacking."中啓用"Compile the kernel with debug info"。
CONFIG_DEBUG_INFO=Y
- 在"Processor type and features"中啓用"kernel crash dumps"。
CONFIG_CRASH_DUMP=y
- 在"Filesystems" -> "Pseudo filesystems"中啓用"/proc/vmcore support"。
CONFIG_PROC_VMCORE=y
Linux 內核支持多種 CPU 架構,這裏只介紹捕捉內核在 i386 下的配置
- 在"Processor type and features"中啓用高端內存支持。
CONFIG_HIGHMEM64G=y
- 在"Processor type and features"中關閉多處理器支持。
CONFIG_SMP=n
- 在"Processor type and features"中啓用"Build a relocatable kernel"。
CONFIG_RELOCATABLE=y
- 在"Processor type and features"->"Physical address where the kernel is loaded"中,爲內核設置一個加載起始地址。在大多數的機器上,16M 是一個合適的值。
CONFIG_PHYSICAL_START=0x1000000
- 編譯系統內核和捕捉內核。
- 將從新編譯好的內核添加到啓動引導中,注意不要將捕捉內核添加到啓動引導菜單中。
- 給系統內核添加啓動參數"crashkernel=Y@X",這裏,Y 是爲 dump 捕捉內核保留的內存,X 是保留部份內存的開始位置。在 i386 的機器上,設置"crashkernel=64M@16M"。
- 重啓機器,在啓動菜單中選擇新添加的啓動項,啓動新的系統內核。
在系統內核引導完成後,須要將捕捉內核加載到內存中。使用 kexec 工具將捕捉內核加載到內存:
# kexec -p <dump-capture-kernel-bzImage> \ --initrd=<initrd-for-dump-capture-kernel> \ --append="root=<root-dev> <arch-specific-options>" |
在捕捉內核被加載進入內存後,若是系統崩潰開關被觸發,則系統會自動切換進入捕捉內核。觸發系統崩潰的開關有 panic(),die(),die_nmi() 內核函數和 sysrq 觸發事件,可使用其中任意的一個來觸發內核崩潰。不過,在讓內核崩潰以前,咱們還須要作一些安裝設置。
Crash 目前的最新的版本是 5.0.0, 你能夠從它的官方網站下載最新的版本。下載完成後對其進行解壓安裝。
# tar -zvxf crash-5.0.0.tar.gz # cd crash-5.0.0 # ./configure # make &&make install |
如今已經設置好 Kdump 和 crash,如今可使用前面介紹的系統崩潰開關中的任意一個來引起系統崩潰來生成一個內存轉儲文件,並可使用 crash 對其進行分析。
首先,觸發系統崩潰,這裏使用 sysrq 觸發事件。
# echo c > /proc/sysrq-trigger |
緊接着,系統會自動啓動捕捉內核。待徹底啓動進入捕捉內核後,經過如下命令保存內存轉儲文件。
# cp /proc/vmcore mydumpfile |
將在當前目錄生成一個 mydumpfile 文件。
如今有了一個內存轉儲文件,接下來使用 crash 對其進行分析
# crash vmlinux mydumpfile |
這裏 vmlinux 是帶調試信息的內核。若是一切正常,將會進入到 crash 中,如圖 1 所示。
圖 1. crash 命令提示符
在該提示符下,能夠執行 crash 的內部命令。經過 crash 的內部命令,能夠查看寄存器的值、函數的調用堆棧等信息。在圖 2 中,顯示了執行 bt
命令後獲得的函數調用的堆棧信息。
圖 2. 函數調用堆棧信息
crash 使用 gdb 做爲它的內部引擎,crash 中的不少命令和語法都與 gdb 相同。若是你曾經使用過 gdb,就會發現 crash 並非很陌生。若是想得到 crash 更多的命令和相關命令的詳細說明,可使用 crash 的內部命令 help
來獲取。
本文介紹了 Linux 下的各類內存轉儲機制,以及如何 crash 工具開對內存轉儲文件進行分析。內核雖然複雜,但經過結合使用內核的內存轉儲文件和 crash 分析工具,能夠輕鬆的找到內核問題的所在。經過對這篇文章的學習,相信你也能夠像一個專業的內核開發者那樣去追蹤和修復內核的錯誤了。