QEMU+gdb除錯Linux核心全過程
1、編譯原始碼(Linux kernel 4.6.2)
make menuconfig
執行make menuconfig
時報錯缺少庫檔案
需要安裝依賴庫
sudo apt-get install aptitude
sudo aptitude install libncurses5-dev
sudo apt-get install libssl-dev
首先編譯核心,編譯核心時注意要選兩個選項。(注意:除此之外kernel hacking
選項下其他的選項都不要選,否則會出現斷點無法攔截的情況。這個說法有待驗證)
kernel hacking –> kernel debugging –> compile the kernel with debug info
kernel hacking –> compile the kernel with frame pointers
make bzImage -j4
在編譯過程中會出現如下的warning,最好解決掉
解決方法:
進入make menuconfig的圖形介面,選擇kernel hacking,將frame size由1024改成2048即可。
這樣就生成了bzImage
和vmlinux
bzImage 位於Linux-4.6.2/arch/x86/boot/bzImage
vmlinux 位於linux-4.6.2/vmlinux
2、編譯QEMU(使用最新版2.12)
2.1 下載原始碼
https://download.qemu.org/
下載2.12.0
版本;
2.2 編譯前的工作
編譯之前需要安裝一些庫檔案,否則會卡在下面的頁面不動;
因此需要安裝SDL
圖形庫:(注意是2.0版本的SDL)
sudo apt-get install libsdl2-2.0
sudo apt-get install libsdl2-dev
執行下列程式碼:
./configure --enable-debug --target-list=x86_64-softmmu
執行上述命令,會出現不存在pixman錯誤;
執行如下命令解決:
sudo apt-get install libpixman-1-dev
緊接著,執行:
sudo make && make install
又會遇到如下問題:
缺少flex和bison
執行如下命令:
sudo apt-get install flex bison
再執行sudo make install
即可。
3、編譯gdb(更換新的gdb)
開始編譯:
./configure --prefix=~/gdb make make install
執行gdb需要進入
~/gdb/bin
目錄下,執行./gdb
;
4、busybox建立最小檔案系統
4.1 動態編譯的方法(不推薦)
4.2 另一種靜態庫編譯方法(推薦):
具體的流程如下:
4.2.1 安裝busybox(1.25.0版本)
編譯busybox原始碼
cd busybox-1.25.0 make defconfig make menuconfig
在menuconfig中修改配置,使用靜態編譯busybox,否則在程式執行期間需要對相應的庫進行動態載入,那麼在根檔案系統中則需要提供其所需的共享庫。
進入menuconfig圖形介面,選擇
-> Busybox Settings -> Build Options [*] Build BusyBox as a static binary (no shared libs)
make -j4
make 期間會遇到許多的warning,不用管它,對安裝影響不大。
sudo make install
此時可以在
busybox-1.25.0/
中看到生成的_install
目錄。通過下面的命令可以驗證busybox是否安裝正確:./busybox ls
生成initrd
首先將上一步生成的
_install
資料夾複製到其他位置cd .. mkdir ramdisk cd ramdisk cp -r ../busy-1.25.0/_install/* .
設定初始化程序init(建立一個軟連結,一定不能直接複製過去)
cd ramdisk ln -s bin/busybox init
設定開機啟動程式
首先,我們需要先設定一些程式執行所需要的資料夾
mkdir -pv {bin,sbin,etc,proc,sys,usr/{bin,sbin},dev}
init程式首先會訪問etc/inittab檔案,因此,我們需要編寫inittab,指定開機需要啟動的所有程式
cd etc vim inittab
inittab檔案的內容如下所示:
::sysinit:/etc/init.d/rcS ::askfirst:-/bin/sh ::restart:/sbin/init ::ctrlaltdel:/sbin/reboot ::shutdown:/bin/umount -a -r ::shutdown:/sbin/swapoff -a
賦予可執行許可權
chmod +x inittab
編寫系統初始化命令
從inittab檔案中可以看出,首先執行的是/etc/init.d/rcS指令碼,因此,我們生成初始化指令碼mkdir init.d cd init.d vim rcS
rcS檔案的內容如下所示:
#!/bin/sh mount proc mount -o remount,rw / mount -a clear echo "My Tiny Linux Start :D ......"
賦予可執行許可權
chmod +x rcS
在rcS指令碼中,mount -a 是自動掛載 /etc/fstab 裡面的東西,可以理解為掛在檔案系統,因此我們還需要編寫 fstab檔案來設定我們的檔案系統。
cd ramdisk/etc/ vim fstab
fstab檔案內容如下:
# /etc/fstab proc /proc proc defaults 0 0 sysfs /sys sysfs defaults 0 0 devtmpfs /dev devtmpfs defaults 0 0
至此,我們已經完成了RAM Disk中相關檔案的配置,可以壓縮生成檔案映象了。
cd ramdisk find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.img
最後生成的
initramfs.img
就是我們的根檔案系統。
4.2.2 測試根檔案系統
下面就可以測試根檔案系統了。
qemu-system-x86_64 -kernel /usr/src/Linux-4.6.2/arch/x86/boot/bzImage -initrd ../initramfs.img
這時qemu上會顯示出核心列印的各種資訊,最終顯示:
My Tiny Linux Start :D ......
Please press Enter to activate this console.
按Enter鍵後,就可以進入到檔案系統中,執行命令
ls /dev
如果能夠成功顯示目錄下所有檔案,則檔案系統掛載成功。
5. QEMU+GDB除錯核心
在之前的四個步驟中,已經準備好了全部的工具,下面就可以使用QEMU+GDB進行核心除錯了。
執行如下命令:
qemu-system-x86_64 -kernel /usr/src/linux-4.6.2/arch/x86/boot/bzImage -initrd ../initramfs.img -smp 2 -S -s
先使用命令啟動qemu。
qemu-system-x86_64的引數比較多,這裡簡單說下:
-kernel 是指定一個大核心檔案,當仁不讓的是bzImage。
-initrd 是指定一個 initrd.img檔案,這個檔案就是我們使用busybox生成的initramfs.img。
-smp 可以從名字猜想,它是給qemu指定幾個處理器,或者是幾個執行緒<嗯,大概意思就thread吧>。
-gdb則是啟動qemu的內嵌gdbserver,監聽的是本地tcp埠1234—如果這樣寫: -gdb tcp:192.168.1.100:1234 ,似乎也是沒問題的。
-S 就是掛起gdbserver,讓gdb remote connect it。
-s 預設使用1234埠進行遠端除錯,和-gdb tcp::1234類似。
-m 2048 指定記憶體大小為2048M
具體圖片如下:
執行上個命令之後,彈出下面這個頁面:
此時,開啟另一個terminal,執行如下命令:
gdb /usr/src/linux-4.6.2/vmlinux (修改成自己的vmlinux路徑)
target remote:1234 (預設埠是1234,進行遠端連線)
b start_kernel (設定斷點)
c (continue 執行到斷點處)
具體如下圖:
可以看到gdb執行start_kernel
斷點處停下來了,接下來就可以使用gdb的基本命令進行單步除錯了。
如果遇到b start_kernel
停不下來,可以使用下面的命令:
(普通的break斷點無法使得gdb在斷點處執行,這是可能是一個gdb的bug())
hb start_kernel //設定硬體斷點
如果需要檢視啟動過程中的資訊,則需要將qemu監視器中的內容重定向到terminal中。
使用如下命令 -nographic 配合-append”console=ttyS0”
最後總結
安裝QEMU+GDB可以說是坎坷不斷,耗費了好幾天才最後弄完。
期間遇到過許多錯誤,這在其他教程中是沒有出現的,所以只能自己一點一點的解決。
安裝過程中遇到的各種warning和error都不能放過,也許就是因為這些錯誤導致安裝失敗。即使看起來安裝成功,這些錯誤未解決仍然可能造成許多錯誤。
比如,編譯核心原始碼時,遇到需要的warning,當時我沒有留意,結果在執行QEMU時就失敗了。所以我只能一個一個解決每一個warning,直到完全成功。
另一方面,如果核心編譯時總是有錯誤,可以選擇更高版本的核心。有些低版本核心年久失修,而且需要使用特定版本的gcc編譯。而你的機器gcc版本過高會造成許多的warning或者error。