1. 程式人生 > >使用Qemu+gdb來除錯核心

使用Qemu+gdb來除錯核心

昨天聽別人講使用Qemu和gdb來實現原始碼級核心除錯,今天試了一下,果然非常方便,現簡單的記錄一下。

Qemu是一個開源的虛擬機器軟體,能夠提供全系統的模擬,可以執行在多個平臺上,並模擬多個別的平臺。Qemu虛擬機器是採用動態翻譯來實現CPU的模擬的,對硬體的依賴程度低,通過它提供的眾多引數,你能夠對虛擬的機器進行定製以滿足你的需求。

要想對核心進行除錯,那自然需要重新編譯核心了,編譯核心的具體方法這裡就不羅嗦了,需要注意的是在配置核心時,要將“kernel hacking"中的“compile the kernel with debug info"選上,否則沒有除錯資訊,gdb也難為無米之炊。

編譯好核心之後,我們還需要製作一個rootfs作為Qemu虛擬機器的硬碟,這個步驟可以通過Qemu來完成,大致的步驟如下:

1. 建立一個虛擬的硬碟

# qemu-img create foobar.img 8G  # 建立一個8G的虛擬硬碟

2. 在虛擬的硬碟上安裝一個Linux系統

# qemu -hda foobar.img -cdrom xxx.iso -boot d -m 512 -enable-audio -localtime 

# xxx.iso為某linux的發行版本的iso,該命令就是要從iso啟動,並將系統安裝到foobar.img中

當然,其實也可以將init ram disk作為Qemu的rootfs,但這時需要對initrd進行修改,如果你對initrd不熟悉的話,最好還是花點時間,做個rootfs,這個可以省去一些麻煩。

Qemu虛擬機器只是提供了一個虛擬的機器,使得程式執行在虛擬機器中如同執行真實的物理機器上一樣,除此以外,Qemu還必須能夠對虛擬機器進行完全的控制,但Qemu和gdb又是怎麼扯上關係的呢?這是因為Qemu中內建了gdbserver,這使得Qemu能夠和遠端的gdb進行通訊,通過遠端的gdb來控制Qemu虛擬機器的執行,從而達到除錯的目的。具體的操作如下:

1. 切換到剛剛編譯的核心的路徑,然後啟動Qemu

# qemu -kernel arch/x86/boot/bzImage -initrd /boot/initrd.img-2.6.31-22-generic -gdb tcp::1234 -S

# -kernel 用來指定核心,注arch/x86/bzImage是不帶除錯資訊的核心,vmlinux是帶有除錯資訊的核心

# -initrd 用來指定核心啟動時使用的ram disk,

# -gdb tcp::1234表示啟動gdbserver,並在tcp的1234埠監聽,-S表示在開始的時候凍結CPU直到遠端的gdb輸入相應的控制命令

2. 啟動gdb,並和Qemu進行聯絡,然後你就可以像除錯應用程式那些除錯核心了

# gdb

(gdb) file vmlinux

(gdb) target remote :1234

(gdb) b start_kernel

(gdb) c

呵呵,是不是很簡單,下面再簡單的介紹一下gdb常用的一些除錯命令: help:即時幫助,當你不太記得或不太熟悉某些命令時,一個help就可以搞定 edit:在gdb中使用$EDITOR對某個檔案進行編輯,在開始之前可以將$EDITOR設定為自己喜歡的編輯器 list:列出被除錯程式當前上下文的源程式 make:相當於在shell中執行make,對工程進行編譯,編譯完成後使用run即可重新開始除錯 run:簡寫為r,開始執行被除錯的程式 break:簡寫為b,設定一個斷點,該斷點可以為某個檔案的某行,也可是某個函式名,還可以是某個地址, 此外通過if引數還可以設定條件斷點 backtrace:輸出呼叫堆疊 info:檢視當前gdb的各種資訊,如斷點資訊,呼叫堆疊等 step:簡寫為s,單步執行,每次執行一行源程式,會跟蹤進入函式 next:簡寫為n,單步執行,每次執行一行源程式,不跟蹤進入函式
stepi:簡寫為si,單步執行,每次執行一個指令,會跟蹤進入函式 nexti:簡寫為ni,單步執行,每次執行一個指令,不跟蹤進入函式 finish:執行直到從當前函式返回 until:簡寫為u,執行直到所在的迴圈結束 continue:簡寫為c,繼續執行直到下一個斷點或程式結束或gdb收到訊號 print:簡寫p,用來輸出某個變數的值,只輸出一次,輸出結構時可以設定“set print pretty on“,這樣觀察更方便  display:觀察某個變數,每次執行時都顯示相應的變數

x:檢視記憶體,通過相應的引數來執行記憶體的地址和要顯示多少資料