一文教你如何使用GDB+Qemu調(diào)試Linux內(nèi)核
概述
在某些情況下,我們需要對(duì)于內(nèi)核中的流程進(jìn)行分析,雖然通過 BPF 的技術(shù)可以對(duì)于函數(shù)傳入的參數(shù)和返回結(jié)果進(jìn)行展示,但是在流程的調(diào)試上還是不如直接 GDB 單步調(diào)試來的直接。本文采用的編譯方式如下,在一臺(tái) 16 核 CentOS 7.7 的機(jī)器上進(jìn)行內(nèi)核源碼相關(guān)的編譯(主要是考慮編譯效率),調(diào)試則是基于 VirtualBox 的 Ubuntu 20.04 系統(tǒng)中,采用 Qemu + GDB 進(jìn)行單步調(diào)試,網(wǎng)上查看了很多文章,在最終進(jìn)行單步跟蹤的時(shí)候,始終不能夠在斷點(diǎn)處停止,進(jìn)行過多次嘗試和查詢文檔,最終發(fā)現(xiàn)需要在內(nèi)核啟動(dòng)參數(shù)上添加 ,本文是對(duì)整個(gè)搭建過程的總結(jié)。nokaslr

2. Linux 內(nèi)核編譯和文件系統(tǒng)制作
2.1 Linux 內(nèi)核編譯
編譯內(nèi)核和制作文件系統(tǒng)在 CentOS 7.7 的機(jī)器上。源碼從國(guó)內(nèi)清華的源下載:http://ftp.sjtu.edu.cn/sites/ftp.kernel.org/pub/linux/kernel/, 此處選擇 linux-4.19.172.tar.gz 版本。詳細(xì)編譯步驟如下:
在內(nèi)核編譯選項(xiàng)中,開啟如下
內(nèi)核黑客攻擊 — > 編譯時(shí)檢查和編譯器選項(xiàng) — > [ ] 使用調(diào)試信息編譯內(nèi)核

以上配置完成后會(huì)在當(dāng)前目錄生成 ?文件,我們可以使用 ?進(jìn)行驗(yàn)證:.configgrep
接著我們進(jìn)行內(nèi)核編譯:
不同發(fā)行版本下的內(nèi)核的詳細(xì)編譯文檔可以參考這里。
【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個(gè)人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。?!前100名進(jìn)群領(lǐng)取,額外贈(zèng)送一份價(jià)值699的內(nèi)核資料包(含視頻教程、電子書、實(shí)戰(zhàn)項(xiàng)目及代碼)?
?

其中上述的 ?文件內(nèi)容如下,打印啟動(dòng)日志和系統(tǒng)的整個(gè)啟動(dòng)過程花費(fèi)的時(shí)間:init
到此為止我們已經(jīng)編譯了好了 Linux 內(nèi)核(vmlinux 和 bzImage)和啟動(dòng)的內(nèi)存文件系統(tǒng)(rootfs.img)。
2.3 錯(cuò)誤排查
在編譯過程中出現(xiàn)以下報(bào)錯(cuò):
出錯(cuò)的原因是因?yàn)槲覀儾捎渺o態(tài)編譯依賴的底層庫(kù)沒有安裝,如果不清楚這些庫(kù)有哪些 rpm 安裝包提供,則可以通過 ?命令查看,然后安裝相關(guān)依賴包重新編譯即可。yum provides ?
3. Qemu 啟動(dòng)內(nèi)核
在上述步驟準(zhǔn)備好以后,我們需要在調(diào)試的 Ubuntu 20.04 的系統(tǒng)中安裝 Qemu 工具,其中調(diào)測(cè)的 Ubuntu 系統(tǒng)使用 VirtualBox 安裝。
把上述編譯好的 vmlinux、bzImage、rootfs.img 和編譯的源碼拷貝到我們當(dāng)前 Unbuntu 機(jī)器中。
拷貝 Linux 編譯的源碼主要是在 gdb 的調(diào)試過程中查看源碼,其中 vmlinux 和 linux 源碼處于相同的目錄,本例中 vmlinux 位于 linux-4.19.172 源目錄中。
使用上述命令啟動(dòng)調(diào)試,啟動(dòng)后會(huì)停止在界面處,并等待遠(yuǎn)程 gdb 進(jìn)行調(diào)試,在使用 GDB 調(diào)試之前,可以先使用以下命令進(jìn)程測(cè)試內(nèi)核啟動(dòng)是否正常。
其中命令行中各參數(shù)如下:
-kernel ./bzImage:指定啟用的內(nèi)核鏡像;
-initrd ./rootfs.img:指定啟動(dòng)的內(nèi)存文件系統(tǒng);
-Append "nokaslr console=ttyS0":附加參數(shù),其中 參數(shù)必須添加進(jìn)來,防止內(nèi)核起始地址隨機(jī)化,這樣會(huì)導(dǎo)致 gdb 斷點(diǎn)不能命中;參數(shù)說明可以參見這里。nokaslr
-s:監(jiān)聽在 gdb 1234 端口;
-S:表示啟動(dòng)后就掛起,等待 gdb 連接;
-nographic:不啟動(dòng)圖形界面,調(diào)試信息輸出到終端與參數(shù) ?組合使用;console=ttyS0

4. GDB 調(diào)試
在使用 命令啟動(dòng)內(nèi)核以后,進(jìn)入到我們從編譯機(jī)器上拷貝過來的 Linux 內(nèi)核源代碼目錄中,在另外一個(gè)終端我們來啟動(dòng) gdb 命令:qemu-system-x86_64
整體運(yùn)行界面如下:

5. Eclipse 圖像化調(diào)試
我們可以通過 eclipse-cdt 進(jìn)行可視化項(xiàng)目調(diào)試。
"File" -> "New" -> "Project" ,然后選擇 "Makefile Project with Existing Code" 選項(xiàng),后續(xù)按照向?qū)?dǎo)入代碼。

在 "Run" -> "Debug Configurations" 選項(xiàng)中,創(chuàng)建一個(gè) "C/C++ Attach to Application" 的調(diào)試選項(xiàng)。
Project:選擇我們剛才創(chuàng)建的項(xiàng)目名字;
C/C++ Application:選擇編譯 Linux 內(nèi)核帶符號(hào)信息表的 vmlinux;
啟動(dòng)前構(gòu)建:選擇 "禁用自動(dòng)構(gòu)建";
Debugger:選擇 gdbserver,具體設(shè)置如下圖;
在 Debugger 中的 Connection 信息中選擇 "TCP",并填寫端口為 "1234";
啟動(dòng) Debug 調(diào)試,即可看到與 gdb 類似的窗口。

啟動(dòng) "Debug" 調(diào)試以后的窗口如下,在 Debug 窗口欄中,設(shè)置與 gdb 調(diào)試相同的步驟即可。

