內核調試之 Kdump 的原理及配置
生產內核(production kernel):產品或者線上服務器當前運行的內核。
捕獲內核(capture kernel):系統崩潰時,使用 kexec 啓動的內核,該內核用於捕獲生產內核當前內存中的運行狀態和數據信息。
Kdump 是系統崩潰的時候,用來轉儲運行內存的一個工具。系統一旦崩潰,生產內核就沒法正常工作,這時 Kdump 啓動捕獲內核,將此時內存中的所有運行狀態和數據信息收集到一個 dump core 文件中,以便之後分析崩潰原因。一旦內存信息收集完成,系統將自動重啓。
Kdump 的核心實現基於 Kexec(Kernel execution),kexec 類似於 Linux 的 exec 系統調用。
Kexec 可以快速啓動一個新的內核(捕獲內核),它會跳過 BIOS 或者 Bootloader 等引導程序的初始化階段,這個特性可以讓系統崩潰時快速切換到捕獲內核,這樣生產內核的內存就得到保留,Kdump 的工作流程如下圖所示:
捕獲內核啓動後,會像一般內核一樣,去運行爲它創建的 ramdisk 上的 init 程序。而各種轉儲機制都可以事先在 init 中實現。
爲了在生產內核崩潰時能順利啓動捕獲內核,捕獲內核以及它的 ramdisk 是事先放到生產內核的內存中的(保留內存)。
生產內核的內存是通過 / proc/vmcore 這個文件交給捕獲內核的,爲了生成它,用戶工具在生產內核中分析出內存的使用和分佈等情況,然後把這些信息綜合起來生成一個 ELF 頭文件保存起來。捕獲內核被引導時會被同時傳遞這個 ELF 文件頭的地址,通過分析它,捕獲內核就可以生成出 / proc/vmcore。有了 / proc/vmcore 這個文件,捕獲內核的 ramdisk 中的腳本就可以通過通常的文件讀寫和網絡來實現各種策略了。
Crash 是一個用於分析內核轉儲文件的工具,和 Kdump 配套使用。Kdump 會在內存中保留一塊區域,這個區域用於存放捕獲內核,生產內核運行過程中崩潰時,Kdump 通過 Kexec 機制自動啓動捕獲內核,對生產內核的完整信息(CPU 寄存器、棧幀數據等)進行保存,生產內核重啓後,使用 Crash 工具來分析這個轉儲的文件。
使用對象:Linux 物理機或者虛擬機;
使用場景:主要用於分析 Linux 系統崩潰問題;注意,在系統無法熱啓動的情況下,Kdump 是不適用的,如硬件的異常導致 CPU 宕機,也就是隻能通過重新關閉開啓電源才能啓動的情況。
本實驗所使用的環境爲 VirtualBox+Ubuntu18.04。
Ubuntu 配置的內核已經使能 Kdump 的支持,僅需要安裝 linux-crashdump 包即可,運行命令如下:
sudo apt install linux-crashdump
該軟件包含 crash,kdump-tools,grub 等相關依賴,安裝中選擇默認啓動,如下圖所示。
安裝過程中會修改 kernel cmdline 已預留 kdump 轉儲轉儲內核內存空間,可以通過修改 / etc/default/grub.d/kdump-tools.cfg 文件修改保留內存的大小,默認爲 192M,如下圖所示:
配置完成後更新 grub(sudo update-grub),重啓操作系統(reboot)。
使用 kdump-config show 命令查看 kdump 相關配置,如下圖所示。
使用如下命令簡單快速測試:
echo c > /proc/sysrq-trigger
如果 Kdump 配置正確,上述命令會讓系統快速重啓並且啓動捕獲內核進行轉儲,轉儲完成後會自動切換爲生產內核,在進入生產內核的操作系統後,查看 / var/crash 目錄中是否有根據年月日時分命名的文件夾,如下所示。
進入時間對應的目錄,目錄包含 dmesg 文件和 dump 文件,文件後綴爲內核崩潰的時間,其中 dmesg 是生產內核發生崩潰時生成的內核日誌信息,dump 時捕獲內核轉儲的文件,如下圖所示。
打開 Crash 工具進行分析,Crash 工具的使用方式如下:
crash [dump] [vmlinux]
Crash 需要指定兩個文件:
dump:轉儲的內核文件,通常在 / var/crash 目錄下;
vmlinux:帶調試內核符號信息的內核映像。
注意,Ubuntu 系統默認不包含 vmlinux 文件,筆者已經對 Ubuntu 系統的內核進行更換,更換過程中生成帶調試符號的 vmlinux 文件,具體步驟可以關注《話說 Linux》訂閱號,查看文章《Linux 內核更換》。
crash 啓動 dump 文件界面如下。
9.1 help 命令
help 命令用於在線查看 crash 命令的幫助,在 crash 命令行中輸入 help 命令可以查看 crash 支持的所有子命令。
help 命令不僅可以查看 crash 支持的命令,還可以查看某個子命令的幫助說明,如查看 bt 命令的幫助說明。
9.2 bt 命令
bt 命令查看一個進程的內核棧的函數調用關係,包括所有異常棧的信息,常用參數如下。
-
-f:顯示每一棧幀裏的數據。
-
-l:顯示文件名和行號。
-
-t:顯示棧中所有的文本符號。
-
pid:顯示指定 pid 的進程的內核棧的函數調用信息。
上圖可以看到,bt 命令將系統崩潰瞬間正在運行的進程內核棧信息全部顯示出來。當前進程的 id 是 4265,task_struct 數據結構的地址是 0xffff8d026b198000,當前進程運行在 CPU1 上,當前進程的運行命令是 bash。後面的棧幀列出了該進程在內核態的調用關係,執行順序是自下而上。
9.3 mod 命令
mod 命令不僅可以用來顯示當前系統加載的內核模塊信息,還可以用來加載某個內核模塊的符號信息和調試信息等,常用參數如下。
-
-s:加載某個內核模塊的符號信息。
-
-S:從某個指定目錄加載所有內核模塊的符號信息,默認目錄是 / lib/modules/ 目錄查找並加載內核模塊的符號信息。
-
-d:刪除某個內核模塊的符號信息。
9.4 dis 命令
dis 命令用來輸出反彙編結果,常用參數如下。
-
-l:顯示反彙編和對應源代碼的行號。
-
-r:(反向)顯示從例程開始到指定地址(包括指定地址)的所有指令。
-
-s:顯示對應的源代碼。
如輸出 sysrq_handle_crash() 接口的反彙編結果。
以下是查看 sysrq_handle_crash() 接口源碼的信息。
9.5 rd 命令
rd 命令用來讀取內存地址中的值,常用參數如下。
-
-a:顯示 ASCII。
-
-d:顯示十進制。
-
-p:讀取物理地址。
-
-s:顯示符號。
-
-32:顯示 32 位寬的值。
-
-64:顯示 64 位寬的值。
以下命令用於讀 0xffff8d026b198000 內存中的值,並連續輸出 16 個內存地址中的值。
9.6 struct 命令
struct 命令用於顯示內核中數據結構的定義或者具體的值,常用的參數如下。
-
struct_name:數據結構的名稱。
-
.member:數據結構的某個成員。
-
-o:顯示成員在數據結構中的偏移量。
以下命令用於顯示 task_struct 數據結構的定義。
以下命令用於顯示 task_struct 數據結構中每個成員的偏移量。
此外,struct 命令後面還可以指定一個地址,用來按照數據結構的格式顯示每個成員的值,例如已知 task_struct 數據結構的地址爲 0xffff8d026b198000,因此可以通過 struct 命令查看該數據結構中每個成員的值。
9.7 irq 命令
irq 命令用於顯示中斷的相關信息,常用參數如下。
-
index:顯示某個指定 IRQ 的信息。
-
-a:顯示中斷的親和性。
-
-b:顯示中斷的下半部信息。
-
-s:顯示系統中斷信息。
9.8 task 命令
task 命令用於顯示進程的 task_struct 數據結構和 thread_info 數據結構的內容。以下命令用於顯示 task_struct 數據結構信息,其中 - x 表示以十六進制顯示。
9.9 vm 命令
vm 命令用於顯示進程地址空間的相關信息,常用參數如下。
-
-p:顯示虛擬地址和物理地址。
-
-m:顯示 mm_struct 數據結構。
-
-v:顯示進程中所有 vma(vm_area_struct)數據結構的值。
-
-R:搜索特定字符串或者數值。
以下命令用於顯示當前進程的虛擬地址空間信息。
9.10 kmem 命令
kmem 命令用來顯示系統內存信息,常用參數如下。
-
-g:顯示 page 數據結構裏 flagsde 標誌位。
-
-i:顯示系統內存使用情況。
-
-p:顯示每個頁面的使用情況。
-
-s:顯示 slab 使用情況。
-
-v:顯示 vmalloc 使用情況。
-
-z:顯示沒個 zone 使用情況。
-
-V:顯示系統 vm_stat 情況。
9.11 sym 命令
sym 命令用於解析內核符號信息,常用選項如下所示。
-
-l:顯示所有符號信息。
-
-m:顯示某個內核模塊的所有符號信息。
-
-q:查詢符號信息。
以下代碼用於查看 oops 模塊的所有符號信息。
9.12 list 命令
list 命令用來遍歷鏈表,並且可以輸出鏈表成員的值,常用的參數如下。
-
-h:指定鏈表頭的地址。
-
-s:用來輸出鏈表成員的值。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/BCgcbzIjOtTgcdpNEYrm_A