RSSArchive About LinkedIn flickr Links to previous projects

[bizkit|張至] good coders code, great steal.

*
Tag
17
Nov
#geek   #linux   #kernel   #gdb   #qemu  

Linux Kernel Development / Debugging (1) - 第一次玩 qemu/kgdb 就上手

網路上許多 kgdb 的教學都是拿編好的 kernel image 搭配 busybox 來載入 qemu 開機,但這次學校作業內容包含執行 Firefox,所以需要跑在一個較完整的作業系統上。

這篇文章是這幾天摸索的心得,其實還沒包含如何去玩 kernel debugging ,因為我還不會XD。 文章分成三個部份:1. 設定與安裝 Debian 於 QEMU 虛擬機器、2. 編譯 Linux 支援 kgdb 的核心以及 initrd、3. 使用 gdb/kgdb 做核心除錯。

Setup QEMU VM


首先,要在安裝一份運行再 qemu 上的 Debian 系統,第一步是用 qemu-img 產生一份硬碟 image:

  • qemu-img create -f qcow2 image.qcow2 5G

這樣會產生一個容量為 5Gb 的硬碟檔案,映像檔的格式為 qcow2,會隨著硬碟的使用長大映像檔的大小。另外,qemu-img 也提供了硬碟 snapshot 的功能,而且是直接存在 image 內:

  • qemu-img snapshot -c snapshot_name image.qcow2 //新增一個snapshot
  • qemu-img snapshot -l image.qcow2  //列出所有snapshots
  • qemu-img snapshot -a snapshot_name image.qcow2  //使用某個snapshot

產生好硬碟檔之後,讓 qemu 從抓好的 Debian 安裝光碟開機:

  • qemu -boot d -cdrom debian.iso -hda image.qcow2

qemu 的參數長得白癡中帶點很可愛,-boot 控制開機裝置,不知道為什麼要接的是類似 Windows 裝置命名習慣(C代表硬碟開機、D代表光碟、A/B代表軟碟),-cdrom/-hda 用來指定光碟/硬碟印象擋,十分直覺。執行指令後變可以按照正常程序安裝 Debian 系統,qemu 會自動模擬一個 DHCP 伺服器來餵網路到 VM 內部。安裝完畢之後便可以開機:

  • qemu -boot c -hda image.qcow2 

看到 Debian 系統正確開機,第一步驟便完成了。另外列幾個我常用 qemu 參數。

  • -k en-us // keyboard layut 遠端操作遇到問題的時候可以加上試試
  • -m size // 指定 vm 的記憶體大小
  • -redir tcp:2222::22 // 將 host 的 2222 port 重導至 VM 的 22 port
  • // 如此便能使用習慣的 terminal 遠端 ssh/scp 到 VM 內部

Compiling Kernel


詳細如何編譯核心不在本文的範疇內,不過如果使用 Debian patch 好的 kernel source 以及 .config大概很難失敗。

我用 aptitude 安裝了 linux-source-2.6.32 以及 linux-header-2.6.32 用來編譯,只遇到了三個小問題,一個是 kernel 的 bug,一個是很小的 include 問題,最後一個我忘了XDDDD。寫筆記果然對我很重要orz

  1. 從 linux-headers-2.6.32/ 將 .config 複製到 linux-source-2.6.32,並加入 “CONFIG_DEBUG_INFO=y” “CONFIG_KGDB=y” “CONFIG_KGDB_SERIAL_CONSOLE=y” 三行設定。
  2. Apply 這個 patch 不然之後連 kgdb 的時候會出現 “ trace API error 0x2.” 錯誤。
  3. 執行 make 產生 kernel image
  4. 執行 make modules ; sudo make modules_install ; mkinitramfs -o initrd-2.6.32 2.6.32 產生 initrd。

最後一步驟會把 modules 安裝到 /lib/modules/ 下面,不喜歡的話可能要設定一下 make / mkinitramfs 的參數。做到這裡,你會產生三個接下來會用到的檔案:initrd-2.6.32、vmlinux、arch/i386/boot/bzImage。

Kernel Debugging with KGDB


最後一個步驟,我們要跳過 grub ,直接用 qemu 內建*的 boot loader (?) 從參數指定 kernel image 來開機,並傳入 kgdb 的參數:

  • qemu -initrd initrd-2.6.32 -kernel bzImage -append “root=/dev/sda kgdboc=ttyS0 kgdbwait” -hda hd.image -serial “tcp::4321,server”

執行之後 qemu 會顯示 “QEMU waiting for connection on: tcp:0.0.0.0:4321,server” 並 hang 住,接著執行 gdb vmlinux,並輸入 target remote localhost:4321 便會繼續開機,並在預設的 breakpoint 停下:

Picture 6

接著你就可以使用 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 區段的開頭加上:

  • asm( ” int $3”);

便會在執行到該區段時 issue 一個 debug/breakpoint interrupt,中斷 kernel 的執行。接著就可以在 gdb 中 step through code,或是動態的加入新的 breakpoints。

Reference


Comments
blog comments powered by Disqus
Page 1 of 1