近期受邀發表了一場與「kernel debug」有關的演講,進行時間大約是70分鐘,在此提供簡報電子檔[加入 kernel 除蟲大隊]供有興趣的朋友下載。本次演講的目的是對 kernel debug 主題做「開場」,再加上時間有限,因此並沒有對 kernel debug 的技術做太深入的討論,反而是透過整理的方式,對幾個常見的 kernel debug 工具與方法做總覽。
演講最後展示了使用 gdb+qemu 來進行 kernel source-level debug 的方法。「加入 kernel 除蟲大隊」需要具備什麼樣的基本技能呢?
首先,主要的工具「GNU Debugger」當然是必學的主題,不過因為這次的主題是 kernel debug,因此只約略介紹 user-space 下幾個重要的除錯觀念:
Breakpoint, single step, inspect variables
如何設定中斷點,進行單步執行,並在程式 run-time 時期檢視變數內容。
Segmentation fault
程式被訊號(signal)被中止時,怎麼找到不正常終止的程式碼。一個典型的 segmentation fault 是發生在程式存取非法的記憶體位置時。
Core dump
程式不正常中止時,會產生 core dump 檔案。透過 core dump 檔與原始的 ELF image 來比對出程式發生不正常中斷的行號。
Multi-threaded, client-server, GUI
多執行緒的除錯、client-server 架構與 GUI 系統的除錯也是重要的除錯技能。以多執行緒為例,我們可以透過「attach」的方式讓 gdb attach 到執行中的子程序進行除錯;又以 GUI 系統為例,我們有時會想要追踪一個由 kernel 發出到 UI 端的事件(event),或是追踪 IPC 的訊息內容。針對這部份來說,有時透過除錯來觀察「系統行為」會比程式邏輯的除錯來得重要,當然除錯上也會稍微複雜一些。
針對 kernel debug 的部份來說,初學者應該以「建立正確使用除錯工具的觀念」與「建立合適的除錯環境」為主軸。另外,對於 oops(kernel panic)訊息的分析,則是核心除錯的重頭大戲,只是這裡所涉及的背景知識會多一些,在投影片裡列出 oops 訊息分析所應了解的幾個主題。不過,不管是 user-space 除錯,或是 kernel-space 除錯,仍必須建立基本的系統程式觀念,像是:
* symbol table
* process virtual address space
* kernel virtual address space
* system call
* exceptions
* stack, heap
本次演講,也介紹了一些關於核心除錯的重要觀念,幾個未列在投影片的部份,在這裡做個簡單整理。
開機是一個循序式過程
Kernel 的開機過程,是一個傳統的「循序式(sequence)」執行過程,如同我們展示以 gdb + qemu 進行除錯一樣,可以檢視並了解 kernel 的開機流程,以及開機失敗時的程式碼位置。
開機完成後是狀態切換
當 kernel 開機完成後,便會啟動一個外部程式,稱為 init process,從這個時間開始,user-space 程式便得以執行。Kernel 此時並不是一個循序式執行(sequential function calls)的狀態。
當不同的 process 執行時,因為呼叫的 system call 不同,因此 kernel 的狀態也不同。再舉一例,以驅動程式來說,在開機過程中,kernel module 只做載入的動作;但是,驅動程式所實作的 system call,如:read、write、ioctl,則是必須透過 user program 執行 system call 才會被叫用。以後面的例子來說,這就不會只是一個單的 kernel debug,或者說「並不是只對 kernel 做除錯」。
Remote Debug
以 remote debug 的方式進行除錯,remote 端(target 端)所載入的 kernel 是編譯完成後,放置於 arch/arm/boot(以 ARM 為例)目錄下的 kernel image,這是 target 端所使用的 kernel image(run-time)。
Local 端(除錯本機端)也要載入 kernel image,此時載入 kernel image 的目的是為了讀取 symbol table 以及其它 ELF 節區資訊,這裡所載入的 kernel image 為 ‘vmlinux’,即編譯完成後放置於 kernel 根目錄下的原始 ELF image file。由此可知,本機端的 ELF image 必須包含完整的除錯資訊,讓 kernel image 包含除錯資訊的做法是在編譯核心時,將幾個除錯選項打開,這部份在簡報中有做說明。
最後,大家可以參考 jserv 兄過去所發表過有關gdb的演講簡報 [「快快樂樂學 GNU Debugger (gdb) Part I + II」簡報上線]。
Jollen's Blog 使用 Github issues 與讀者交流討論。請點擊上方的文章專屬 issue,或 open a new issue
您可透過電子郵件 jollen@jollen.org,或是 Linkedin 與我連絡。更歡迎使用微信,請搜尋 WeChat ID:jollentw