天天看點

crash核心調試準備事項之二三事

引言

解決Linux系統上疑難問題的常見方案之一是使用crash工具調試系統轉儲(coredump),

進入核心分析、排查。但是此方案時常不可行。這一點在核心較新的系統上尤甚。而捕捉

系統轉儲也有不少值得留意之處。我們一并讨論下使用crash工具調試系統轉儲的準備

事項及其背後的原因,以便更有效的使用此方案,減少無用功。

crash的黑魔法

crash工具對核心和gdb使用了很多黑魔法,而非其公開的API或者文檔化的

features。比如,crash并不是使用了libGDB架構,也不是如

ddd

等gdb前端那樣采用C/S架構。當然也

沒有使用在

Emacs

内嵌gdb支援時采用的

"通信協定" -- gdb的的annotate特性。

那麼,crash是怎麼使用gdb的呢?crash使用自帶而非系統安裝的gdb。對自帶的gdb,crash對

其打了更新檔。通過這種方式,crash把gdb收編了。兩者共存于同一程序,crash通過函數調用就

可以使用gdb。通過修改gdb指令執行完畢後傳回哪個函數,crash就接管了入口。不管指令來自

互動式界面還是批處理檔案,都是crash接到輸入,進而路由指令,而後由自身、shell或者gdb

三者之一來執行指令。

crash解析系統轉儲,對黑魔法的使用也不遑多讓。

憑借黑魔法,crash功能可觀,但是卻也時常因之無能為力。如何解決crash不能正常工作的

問題呢?答案是做好規劃和準備,簡化目标環境,降低複雜度,收集輔助資料,增加對目标環境的

認知。這也有助于我們了解crash的工作過程和驗證crash結果。

源碼和調試符号

調試需要調試符号和源碼,但是不同的發行版,對于調試符号和源碼的處理方式是不一樣的。

對于CentOS、Fedora之類RHEL-Like的發行版,其有專門的軟體源提供釋出軟體包各個

版本的調試符号和源碼。可以從軟體源手工下載下傳,也可以調整yum/dnf的配置,把有關

軟體源補充進來即可。比如,對于CentOS,其對應的軟體源在

debuginfo.centos.org

而debian及其衍生的發行版,比如Ubuntu,幾乎隻能找到部分最新版本軟體的調試符号,而且這些

調試符号對應的源碼也往往無法拿到。

是以,如果使用的是debian或者其衍生的發行版,應備份核心源碼等關鍵組建源碼,并準備好相應的

建構環境,以備不時之需。

為makedumpfile提供額外資訊

ECS之類的計算節點配備的記憶體越來越大,甚至記憶體大小都超出了其配備的磁盤空間。這種

情況下makedumpfile能夠通過過濾和壓縮産生較小系統轉儲,這個功能對存儲和傳遞

系統轉儲無疑提供了便利。

但是便利并非沒有成本。makedumpfile需要調試符号資訊,以分析和判斷哪些記憶體頁需要壓縮,

那些記憶體頁可以丢棄。就是說在做系統轉儲時,需要有核心調試符号。變通之處是在有核心

調試符号的系統中,makedumpfile工具可以生成vmcoreinfo檔案。這個檔案在做系統

轉儲時可以替代核心調試符号使用。但是這個變通之處并非處處可行。比如qemu

虛機的monitor指令,其子指令dump-guest-memory就沒有vmcoreinfo有關的選項。

但是,幾乎所有的發行版,其提供的核心都開啟了位址随機化(KASLR,

kernel address space layout randomization)。在沒有關閉kaslr的情況下,

vmcoreinfo提供了系統的運作時資訊,對于crash調試都是有益的。是以,在可能的情況下,

建議提供系統轉儲的同時,也提供vmcoreinfo檔案。

使用核心指令行參數nokaslr即可關閉核心位址随機化。

使用kdump捕捉系統轉儲

在主控端上我們可以把qemu程序視之為普通程序來做coredump;也可以使用qemu虛機的

monitor指令來儲存虛拟機記憶體的方式來制作虛拟機的系統轉儲。這兩種方案都有其應用

場景和便利之處。比如因為程序pid耗盡導緻無法登陸或者業務程序無法啟動的場景。但

這兩種方案,即要在主控端上有相應的權限,還缺少對虛拟機内部的知識,可用的

機制也不夠靈活。

接下來我們讨論一個有競争力的系統轉儲方案:基于kexec技術的Kdump。

kexec: 運作時啟動新核心

kexec能夠在運作時啟動新核心。即在目前運作的Linux系統上,kexec能夠讓我們加載和

啟用一個新的核心,代替老的核心來運作。這就帶來了一種新的、生成系統轉儲的方案。

在Linux系統上,加載一個新的核心但不啟動之。這時系統上就有了兩個核心。一個是目前

在運作的核心,我們稱之為生産核心;一個是剛剛加載但是沒有運作的核心,我們稱之為

捕獲核心。然後把系統配置為生産核心panic時啟動捕獲核心。正如其名字所示的,捕獲核心

負責為生産核心捕捉系統轉儲。

kdump怎麼使用kexec?

預留記憶體

kdump要為捕獲核心預留記憶體,這需要配置crashkernel核心指令行參數。RHEL-Like發行版

預設配置了這個參數,但是debian及其衍生版則未必。

持久化的配置核心指令行參數,需要調整GRUB的設定并重新整理之,而後重新開機生效。是以,在

debian及其衍生版上部署kdump,如果新配置或者調整了核心指令行參數,需要重新開機系統。

提供守護程序

捕獲核心依賴守護程序實作系統轉儲功能,這個守護程序需要kdump部署。這樣捕獲核心啟動

後運作此守護程序即可。

那麼,kdump是怎麼通知捕獲核心運作哪個守護程序的呢?答案是kdump提供了第二個守護程序。

這個守護程序運作在生産核心場景下,其職能就是實作某種機制用以告知捕獲核心哪一個守護程序

是捕獲程序(這裡用程序不甚恰當,捕獲程序不會在生産核心下運作)。這第二個守護程序

也負責處理核心有更新時的場景。

就是說,kdump提供了兩個守護程序。一個運作在生産核心下,功能是告知捕獲核心誰是捕獲

程序;一個運作在捕獲核心下,負責系統轉儲。

題外話,RHEL-Like發行版和debian及其衍生版實作上述功能采用了差異頗大的技術棧。

kdump的靈活性

可以充分借用makedumpfile的功能

捕獲程序是單獨的守護程序,使用的工具是makedumpfile。因之可以靈活的按需配置。比如說

把系統轉儲直接通過網絡投遞出去、過濾掉更多無用的記憶體頁等等。更多細節請參考

makedumpfile的文檔。

調配觸發配置,擴大使用場景

生産核心panic時kdump才會生成系統轉儲。是以,可以按需調整系統,讓其在特定條件下

panic,這樣我們就能得到系統轉儲。

這裡讨論兩種情況。

調整核心參數

核心有參數控制某些情況出現時核心是否panic。比如vm.panic_on_oom參數。将之設定

為1則oom時會觸發panic。其他類似的參數還有kernel.hung_task_panic、

kernel.panic_on_rcu_stall等。

靈活使用魔術鍵

使用

魔術鍵

可以手工觸發或者在腳本中觸發核心panic。了解這一點,則可以在生産核心場景下部署腳本,檢測

到問題複現則觸發核心panic。

如何部署kdump?

根據上面的讨論,部署需要:

  1. 部署軟體包:
    • RHEL-Like的發行版部署kexec-tools。除非必要,否則不必讓kexec負責重新開機功能。
    • debian及其衍生版需要部署kexec-tools和kdump-tools
  2. 檢查grub配置,核實為捕獲核心預留了記憶體
  3. 如果調整了核心指令行參數,則重新開機系統
  4. 驗證守護程序運作了
  5. (可選)通過魔術鍵測試kdump工作。

小結

crash調試系統轉儲,源碼、調試符号和轉儲内容,三者缺一不可。提前做好規劃和準備,使用crash

解決疑難問題,會更加便利和有效。

參考

RHEL debian

Ubuntu

RHEL-Like的發行版使用

dracut apt aptitude rpm yum/dnf