網路上許多 kgdb 的教學都是拿編好的 kernel image 搭配 busybox 來載入 qemu 開機,但這次學校作業內容包含執行 Firefox,所以需要跑在一個較完整的作業系統上。
這篇文章是這幾天摸索的心得,其實還沒包含如何去玩 kernel debugging ,因為我還不會XD。 文章分成三個部份:1. 設定與安裝 Debian 於 QEMU 虛擬機器、2. 編譯 Linux 支援 kgdb 的核心以及 initrd、3. 使用 gdb/kgdb 做核心除錯。
首先,要在安裝一份運行再 qemu 上的 Debian 系統,第一步是用 qemu-img 產生一份硬碟 image:
這樣會產生一個容量為 5Gb 的硬碟檔案,映像檔的格式為 qcow2,會隨著硬碟的使用長大映像檔的大小。另外,qemu-img 也提供了硬碟 snapshot 的功能,而且是直接存在 image 內:
產生好硬碟檔之後,讓 qemu 從抓好的 Debian 安裝光碟開機:
qemu 的參數長得白癡中帶點很可愛,-boot 控制開機裝置,不知道為什麼要接的是類似 Windows 裝置命名習慣(C代表硬碟開機、D代表光碟、A/B代表軟碟),-cdrom/-hda 用來指定光碟/硬碟印象擋,十分直覺。執行指令後變可以按照正常程序安裝 Debian 系統,qemu 會自動模擬一個 DHCP 伺服器來餵網路到 VM 內部。安裝完畢之後便可以開機:
看到 Debian 系統正確開機,第一步驟便完成了。另外列幾個我常用 qemu 參數。
詳細如何編譯核心不在本文的範疇內,不過如果使用 Debian patch 好的 kernel source 以及 .config大概很難失敗。
我用 aptitude 安裝了 linux-source-2.6.32 以及 linux-header-2.6.32 用來編譯,只遇到了三個小問題,一個是 kernel 的 bug,一個是很小的 include 問題,最後一個我忘了XDDDD。寫筆記果然對我很重要orz
最後一步驟會把 modules 安裝到 /lib/modules/ 下面,不喜歡的話可能要設定一下 make / mkinitramfs 的參數。做到這裡,你會產生三個接下來會用到的檔案:initrd-2.6.32、vmlinux、arch/i386/boot/bzImage。
最後一個步驟,我們要跳過 grub ,直接用 qemu 內建*的 boot loader (?) 從參數指定 kernel image 來開機,並傳入 kgdb 的參數:
執行之後 qemu 會顯示 “QEMU waiting for connection on: tcp:0.0.0.0:4321,server” 並 hang 住,接著執行 gdb vmlinux,並輸入 target remote localhost:4321 便會繼續開機,並在預設的 breakpoint 停下:
接著你就可以使用 l 來看 kernel source code、用 n 來 step through code、用 b 設定 breakpoints。例如:設定 b printk,就可以看到每一次執行 continue 變會多印出一行 kernel message ~
(updates)
不知道是設計使然還是我設定錯誤,與一般 process 不同,我不能在 gdb 中按 C-c 來把 kernel 的執行中斷。因此,如果沒有在一開始預設 break point 設定其他 break point 便讓執行 continue 的話,便無法再次成功中斷 kernel。找到的解決方法是在需要 debug 的區域自行加上 ”break point”。(比較正確的說法好像是:在程式碼中加入 debug stub,讓執行到該位置時開始 debug 程序。對於 kgdb / gdb 的運作模式並不是狠清楚,無法詳細描述)
只要在想要 debug 區段的開頭加上:
便會在執行到該區段時 issue 一個 debug/breakpoint interrupt,中斷 kernel 的執行。接著就可以在 gdb 中 step through code,或是動態的加入新的 breakpoints。