在qemu環境中用gdb調試Linux內核


簡介

對用戶態進程,利用gdb調試代碼是很方便的手段。而對於內核態的問題,可以利用crash等工具基於coredump文件進行調試。其實我們也可以利用一些手段對Linux內核代碼進行gdb調試,qemu就是一種。qemu是一款完全軟件模擬(Binary translation)的虛擬化軟件,在虛擬化的實現中性能相對較差。但利用它來在測試環境中gdb調試Linux內核代碼,是熟悉Linux內核代碼的一個好方法。本文旨在介紹怎么利用qemu搭建Linux的gdb調試環境。其中主要包括了如何編譯Linux內核,如何利用gdb遠程連接qemu啟動的gdbserver,進而進一步進行內核代碼調試。

 

環境

  • Linux Distribution: Ubuntu 14.04.5 TLS
  • 調試內核版本:3.18.6 (本文將內核編譯成x86 32位架構來做演示)

 

編譯內核

下載3.18.6版本內核源代碼。

# wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.18.6.tar.xz
# xz –d linux-3.18.6.tar.xz
# tar –xvf linux-3.18.6.tar
# cd linux-3.18.6

 編譯選項 

不同的架構有不同的默認文件,比如x86平台,可以在arch/x86/configs找到相關文件:i386_defconfig。通過執行make i386_defconfig 即可基於這個文件生成.config文件,在此基礎上可以再運行make menuconfig 來進行個別的調整。更多的細節請參考:Documentation\kbuild\kconfig.txt。 總之,無論怎么配置,最終都是為了生成.config文件。這些宏最終將影響Makefile中參與編譯的文件。

 

代碼的編譯選項配置很多,這里主要做如下兩處配置:

  • 讓系統內核在32位架構中運行 //只是為了演示,非必須
  • 開啟"Compile the kernel with debug info"選項 //如果要讓內核可調試,這個選項必選
# make i386_defconfig //32位架構
# make menuconfig // 調整編譯選項

注意:默認make menuconfig會報錯如下,因為最小系統不支持圖形顯示。

# make menuconfig
HOSTCC scripts/kconfig/mconf.o
In file included from scripts/kconfig/mconf.c:23:0:
scripts/kconfig/lxdialog/dialog.h:38:20: fatal error: curses.h: No such file or directory
#include CURSES_LOC
^
compilation terminated.

解決方法:

# apt-get install libncurses5-dev -y

 在內核編譯選項中,開啟如下"Compile the kernel with debug info"

Kernel hacking --->
    Compile-time checks and compiler options --->
        [ ] Compile the kernel with debug info

示意圖如下,利用鍵盤選中debug選項,然后敲"Y"勾選:

 

在menuconfig中選完編譯選項,結果會寫入到.config文件中。可以看到.config文件的CONFIG_DEBUG_INFO被設置成Y。

編譯

編譯選項選完后,利用make編譯,編譯需要較長時間。

# make -j2

編譯完成之后,會有一些新的文件產生,如:

  • linux-3.18.6/arch/x86/boot/bzImage // 相當於/boot目錄下vmlinuz,是一個壓縮的,可以bootable的Linux kernel文件
  • linux-3.18.6/vmlinux // 一個非壓縮的,不可以bootable的Linux kernel文件。是用來生成bzImage/vmlinuz的中間步驟。

 

qemu

安裝qemu

# apt-get update
# apt-get install qemu
# 因為用的32位平台環境,所以用下面的qemu
# ln -s /usr/bin/qemu-system-i386 /usr/bin/qemu

qemu主要選項解釋:

  • -kernel bzImage: Use bzImage as kernel image. The kernel can be either a Linux kernel or in multiboot format. // 指定可以bootable的內核壓縮文件
  • -initrd file: use 'file' as initial ram disk // 指定initramdisk
  • -append cmdline: use 'cmdline' as kernel command line // 指定kernel cmdline
  • -S: Do not start CPU at startup (you must type 'c' in the monitor). // 用於調試代碼
  • -s: Shorthand for -gdb tcp::1234, i.e. open a gdbserver on TCP port 1234. // 開啟一個gdbserver, 可以通過TCP端口1234連接
  • -nographic: Normally, QEMU uses SDL to display the VGA output. With this option, you can totally disable graphical output so that QEMU is a simple command line application. The emulated serial port is redirected on the console and muxed with the monitor (unless redirected elsewhere explicitly). // 默認qemu使用圖形方式,該現象可以啟用非圖形方式

 

利用gdb調試

利用qemu啟動編譯好的內核,如下:

# qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -s -S -append "console=ttyS0" -nographic

在本機另一個terminal利用gdb連接本地的gdbserver 1234端口

# gdb
# (gdb) file linux-3.18.6/vmlinux //load Linux符號表
Reading symbols from linux-3.18.6/vmlinux...done.
# (gdb) target remote:1234 //遠程連接監聽在TCP 1234的gdb server
(gdb) break start_kernel //在start_kernel函數設置斷點
Breakpoint 1 at 0xc1a2f7c5: file init/main.c, line 501.
(gdb) c //continue,繼續執行代碼

 

在繼續執行后,最終qemu的輸出如下,在qemu虛擬機里運行的Linux系統能成功啟動,並且最終以Kernel panic宣告結束。看到call trace打出來的是在initrd_load的時候出錯,原因很簡單,因為啟動系統的時候只指定了bzImage,沒有指定initrd文件,系統無法mount上initrd (init ram disk) 及其initramfs文件系統。

 

到此為止,gdb調試Linux內核代碼的基本環境已經搭建完成,可以利用斷點來調試啟動啟動中的細節。后面將介紹如何構建initramfs文件系統,能讓qemu運行的Linux系統更像“完整的系統”。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM