在 MacOS 上直接編譯 Linux Kernel 在我看來並不是一個很好的選擇:
- 我不喜歡 MacOS 的第三方包管理工具
brew - 我不希望在沒有隔離的情況下安裝一堆我不瞭解的工具
或者説,在 Ubuntu 上調試 Linux Kernel 才是一個更誘人的選擇:
apt生態很好- 基於 Ubuntu gcc 工具鏈編譯 Linux Kernel 社區討論更多,支持更完善
於是問題就變成了從哪找一台 Ubuntu ?
- 在雲服務商那裏以白嫖價格搞來的機器太小,大機器又覺得不值當
- 又不想白白浪費 Mac M1 Pro 的性能
OrbStack 是一個非常好的選擇。
OrbStack is the fast, light, and easy way to run Docker containers and Linux. Develop at lightspeed with our Docker Desktop alternative.
OrbStack 是專用於 Mac 上的環境隔離工具:
- 可以無縫銜接
docker命令,也可以直接創建linux虛擬機 - 其開銷非常小,目前個人版是免費的
- 還有許多其他極其實用的功能,比如可以直接以
ssh的形式進入虛擬機,帶來類似遠程開發的體驗,也方便 VSCode 這類工具連接環境
下面是本文的脈絡:
- 初始化 Ubuntu 開發環境
- 編譯 Linux Kernel
- 基於 busybox 製作 root fs
- 啓動 QEMU
- gdb 連接
- VS Code 連接
初始化 Ubuntu 開發環境
首先在我們的 Mac OS 上基於 OrbStack 創建 Linux 虛擬機。
✗ orb version
Version: 1.10.3 (1100300)
Commit: 2b5dd5f580d80a3d2494b7b40dde2ef46813cfc5 (v1.10.3)
✗ orb create ubuntu:24.04 ubuntu-24-debug
創建地飛快。
進入虛擬機: ssh ubuntu-24-debug@orb 。接下來我們所有的命令都是在虛擬機中操作的。
# 先看看我們的版本
uname -a
Linux ubuntu-24-debug 6.13.7-orbstack-00283-g9d1400e7e9c6 #104 SMP Mon Mar 17 06:15:48 UTC 2025 aarch64 aarch64 aarch64 GNU/Linux
# 創建我們的 WorkDir ,下載 Linux Kernel
mkdir -p ~/debug-linux-kernel-on-qemu/kernel_dev
cd ~/debug-linux-kernel-on-qemu/kernel_dev
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
# 我們選擇和 Ubuntu 一致的 6.13 版本
cd linux
git checkout v6.13
上面下載 linux kernel 基本是最慢的一步了。如果你的網速實在不給力,可以只下載特定的 tag 並且制定下 max-depth 。
接下來開始安裝需要用到的工具:
sudo apt update
sudo apt install -y build-essential flex bison libssl-dev libelf-dev libncurses-dev \
qemu-system-aarch64 gdb dwarves busybox-static e2fsprogs bc
這些工具的作用分別是:
build-essential: 包含編譯 C/C++ 程序所需的基礎工具集,如gcc,g++,make等,是編譯內核的前提。flex,bison: 分別是詞法分析器和語法分析器的生成器,內核的構建過程依賴它們來處理 Kconfig 文件和代碼中的某些部分。libssl-dev: 提供 OpenSSL 庫的開發文件(頭文件和庫),內核編譯時需要用到其中的加密和證書相關功能。libelf-dev: 提供操作 ELF (Executable and Linkable Format) 文件的庫和頭文件,內核編譯和後續生成調試信息時需要。libncurses-dev: 提供ncurses庫的開發文件,用於支持基於文本的圖形界面,比如make menuconfig。bc: 一個基礎的命令行計算器,內核構建腳本中有時會用到它進行計算。qemu-system-aarch64: QEMU 模擬器,專門用於模擬 ARM64 (aarch64) 架構的完整系統。我們將用它來運行我們編譯的內核。gdb: 大名鼎鼎的 GNU 調試器(GNU Debugger),是我們用來調試內核的主要工具。dwarves: 包含pahole等工具,用於讀取和分析 DWARF 調試信息。內核編譯時可能需要pahole來生成 BTF (BPF Type Format) 信息,這對於 eBPF 開發和一些現代調試技術很有幫助。busybox-static: 一個包含了許多標準 Unix 工具(如ls,cat,mount,sh等)的單個可執行文件。這裏的static版本表示它是靜態鏈接的,不依賴外部共享庫,非常適合用來構建一個最小化的根文件系統(root filesystem)。e2fsprogs: 包含用於創建、檢查和維護 ext2/ext3/ext4 文件系統的工具集,比如我們後面會用到的mkfs.ext4。
編譯 Linux Kernel
編譯 Linux Kernel 過程也較為簡單,唯一麻煩的就是配置。
cd ~/debug-linux-kernel-on-qemu/kernel_dev/linux
make ARCH=arm64 defconfig
make ARCH=arm64 menuconfig
這裏的 menuconfig 會讓 console 變成可交互界面:
- 使用方向鍵進行移動
- 使用回車鍵進入子菜單,空格鍵選中/取消選中
- 這個
make ARCH=arm64 menuconfig的核心目的是幫你修改內核配置文件.config
為了方便後續調試,我們需要調整以下幾個配置選項(如果找不到具體選項,可以在 menuconfig 界面中按 / 鍵,然後輸入配置項名稱,如 CONFIG_DEBUG_INFO 來搜索):
-
啓用調試信息:
- 進入
Kernel hacking--->Compile-time checks and compiler options---> - 確保
Compile the kernel with debug info選項被選中(顯示為[*])。如果未選中(顯示為[ ]),按空格鍵切換。這將啓用CONFIG_DEBUG_INFO=y,讓編譯器在編譯內核時加入 DWARF 調試符號。 - 在同一菜單下,確保
Provide GDB scripts for kernel debugging選項也被選中([*])。這將啓用CONFIG_GDB_SCRIPTS=y,會生成一些輔助 GDB 調試的腳本。
- 進入
-
禁用 KASLR (可選但強烈推薦):
- 返回到
Kernel hacking菜單 ---> (可能需要先退回主菜單再進入)Processor type and features---> - 找到
Randomize the address of the kernel image (KASLR)選項,按空格鍵取消選中(確保顯示為[ ])。這將設置CONFIG_RANDOMIZE_BASE=n,禁用內核地址空間佈局隨機化(Kernel Address Space Layout Randomization, KASLR)。禁用 KASLR 後,內核每次加載到內存的基地址都是固定的,這極大地簡化了在 GDB 中設置早期斷點和理解內存地址的過程。
- 返回到
-
確保 Virtio 控制枱支持:
- 進入
Device Drivers--->Character devices--->Virtual terminal---> - 確保
Virtio console support被選中(顯示為<*>表示編譯進內核,或<M>表示編譯為模塊)。通常defconfig會默認選中。這是為了讓內核能夠通過 QEMU 的virtio串口設備 (ttyAMA0) 輸出信息。
- 進入
完成以上修改後,使用方向鍵移動光標到屏幕底部的 < Save >,按回車鍵確認保存配置(默認會保存到 .config 文件),然後反覆選擇 < Exit > 退出 menuconfig。
操作後記得檢查 .config 文件中是否符合你的預期:比如看看 CONFIG_DEBUG_INFO=y、 CONFIG_GDB_SCRIPTS=y 和 CONFIG_RANDOMIZE_BASE=n 是否存在且設置正確。
開始編譯:
make ARCH=arm64 -j8
這裏的 -j8 表示使用 8 個線程並行編譯,你可以根據自己機器的 CPU 核心數調整。速度非常快,我這裏大概花了 10 分鐘。並且在編譯時一個 WARNING 都沒有遇到,寫過大型 C/C++ 項目的朋友知道這其實並不容易辦到。
編譯後我們會得到多個文件,對我們調試最重要的主要是兩個:
vmlinux: 位於內核源碼根目錄下。這是一個未經壓縮、包含完整符號表和調試信息的 ELF 格式的內核可執行文件。gdb需要加載這個文件來識別函數名、變量名、源代碼行號等信息,是調試時必不可少的文件。arch/arm64/boot/Image: 這是一個經過壓縮、去除了大部分調試信息、並且符合 ARM64 架構引導規範的內核鏡像文件。QEMU(或真實的引導加載程序)實際加載並運行的是這個文件。它比vmlinux小得多,適合啓動。
基於 busybox 製作 root fs
這一步是為 QEMU 虛擬機創建一個最小化的根文件系統 (root filesystem),讓內核啓動後能找到基本的運行環境和 shell。這是我踩坑最久的一步。
1. 創建臨時目錄和基本結構
首先,我們需要一個臨時目錄來構建文件系統的內容,並在其中創建標準 Linux 目錄結構。
# 回到主工作目錄
cd ~/debug-linux-kernel-on-qemu
# 創建並進入 rootfs 構建目錄
mkdir rootfs
cd rootfs
# 創建 Linux 基本目錄結構
mkdir -p bin sbin etc proc sys dev lib usr/bin usr/sbin
這些目錄是 Linux 系統運行所必需的,例如 bin 和 sbin 用於存放可執行命令,etc 用於存放配置文件,proc 和 sys 用於內核與用户空間交互,dev 用於存放設備文件。
2. 引入 BusyBox
busybox 將為我們的最小系統提供核心的用户態工具。
# 確認 busybox 是靜態鏈接的(輸出應包含 "statically linked")
file /usr/bin/busybox
# /usr/bin/busybox: ELF 64-bit LSB executable, ARM aarch64, version 1 (GNU/Linux), statically linked, ... stripped
# 複製 busybox 到我們的 bin 目錄
cp /usr/bin/busybox ./bin/busybox
# 使用 busybox --install 命令創建常用命令的符號鏈接
# -s 表示創建符號鏈接 (symbolic link)
./bin/busybox --install -s ./bin
執行 busybox --install -s ./bin 後,./bin 目錄下會多出很多指向 busybox 的符號鏈接,例如 ls, sh, mount, echo 等。當內核啓動後執行 /bin/sh 時,實際上是執行了 busybox,busybox 會根據被調用時的名稱 (sh) 來模擬對應命令的行為。
3. 修正 BusyBox 鏈接路徑 (重要)
默認的 busybox --install 創建的符號鏈接可能包含了絕對路徑(如 ash -> /path/to/rootfs/bin/busybox)。當這個 rootfs 目錄被製作成鏡像並掛載到 QEMU 虛擬機內部時,這個絕對路徑就不再有效了。我們需要的是相對鏈接(如 ash -> busybox)。
下面的腳本用於修正這個問題:
# 創建修正腳本
cat <<EOF > ../fix_busybox_path.sh
#!/bin/bash
# 進入我們 rootfs 的 bin 目錄
cd ~/debug-linux-kernel-on-qemu/rootfs/bin || exit 1
echo "Fixing busybox symlinks in $(pwd)"
# 遍歷 bin 目錄下的所有文件/鏈接
for link in *; do
# 只處理符號鏈接
if [ -L "\$link" ]; then
target=$(readlink "\$link")
# 如果鏈接的目標是 busybox (可能是絕對路徑或相對路徑)
if [[ "\$target" == *"busybox"* ]]; then
# 如果鏈接名不是 busybox 本身
if [ "\$link" != "busybox" ]; then
echo "Relinking \$link -> busybox"
# 刪除舊鏈接
rm -f "\$link"
# 創建指向 busybox 的相對鏈接
ln -sv busybox "\$link"
fi
fi
fi
done
echo "Symlink fixing complete."
EOF
# 給腳本執行權限並運行
chmod +x ../fix_busybox_path.sh
bash ../fix_busybox_path.sh
# 回到 rootfs 目錄
cd ~/debug-linux-kernel-on-qemu/rootfs
這個腳本會遍歷 bin 目錄下的所有符號鏈接,如果它們指向 busybox,就刪除舊鏈接,然後創建一個新的、名為原鏈接名、指向 busybox 的相對符號鏈接。
4. 創建初始化腳本 init.d/rcS
內核啓動後,會執行 init 進程(我們後面在 QEMU 參數中指定為 /bin/init,它會鏈接到 busybox)。busybox init 會尋找並執行 /etc/init.d/rcS 腳本來做一些系統初始化的工作。
# 創建 init.d 目錄
mkdir -p etc/init.d
# 創建 rcS 文件
cat <<EOF > etc/init.d/rcS
#!/bin/sh
# 掛載必要的偽文件系統
echo "Mounting /proc, /sys, /dev..."
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs none /dev
# 打印一些啓動信息
echo "============================="
echo " Minimal BusyBox RootFS Booted"
echo " Running rcS..."
echo " Remounting rootfs rw..."
echo "============================="
# 重新掛載根文件系統為可讀寫模式
# (雖然 QEMU append 參數裏也加了 rw,但這裏再確認一下)
mount -o remount,rw /
# 啓動一個交互式 Shell
echo "Starting shell..."
exec /bin/sh
EOF
# 給 rcS 腳本添加執行權限
chmod +x etc/init.d/rcS
這個腳本主要做了幾件事:
- 掛載
/proc(進程信息)、/sys(系統和設備信息)、/dev(設備節點) 這三個重要的虛擬文件系統。 - 重新掛載根文件系統為可讀寫模式 (
rw),允許我們在 shell 中進行修改。 - 最後通過
exec /bin/sh啓動一個 shell,提供用户交互界面。
5. 創建 ext4 文件系統鏡像並填充內容
現在 rootfs 目錄裏已經有了最小系統所需的內容,我們需要把它打包成一個 QEMU 可以使用的磁盤鏡像文件。
# 回到主工作目錄
cd ~/debug-linux-kernel-on-qemu
# 使用 dd 創建一個 512MB 大小的空文件作為鏡像文件
# bs=1M 表示塊大小為 1MB, count=512 表示 512 個塊
echo "Creating rootfs.img (512MB)..."
dd if=/dev/zero of=rootfs.img bs=1M count=512
# 在該鏡像文件上創建 ext4 文件系統
echo "Formatting rootfs.img with ext4..."
mkfs.ext4 rootfs.img
# 創建臨時掛載點
echo "Mounting rootfs.img..."
sudo mkdir -p /mnt/rootfs_mount
# 使用 loop device 將鏡像文件掛載到掛載點
# 這樣就可以像操作普通目錄一樣操作鏡像文件內部了
sudo mount -o loop rootfs.img /mnt/rootfs_mount
# 將我們準備好的 rootfs 目錄內容複製到掛載的鏡像中
# -a 參數表示歸檔模式,保留文件屬性、鏈接等
echo "Copying files to rootfs.img..."
sudo cp -a rootfs/* /mnt/rootfs_mount/
# 確保所有數據都寫入磁盤(鏡像文件)
echo "Syncing..."
sync
# 卸載鏡像文件
echo "Unmounting rootfs.img..."
sudo umount /mnt/rootfs_mount
# 刪除臨時掛載點
sudo rmdir /mnt/rootfs_mount
# 刪除臨時的 rootfs 構建目錄,因為內容已經拷到鏡像裏了
echo "Cleaning up temporary rootfs directory..."
rm -rf rootfs
echo "rootfs.img created successfully."
至此,我們已經有了一個包含最小 BusyBox 環境的 rootfs.img 文件,可以被 QEMU 用作虛擬硬盤了。
啓動 QEMU
你可以直接啓動 QEMU 來運行內核和我們製作的根文件系統:
qemu-system-aarch64 \
-machine virt \
-cpu cortex-a57 \
-m 1G \
-nographic \
-kernel kernel_dev/linux/arch/arm64/boot/Image \
-drive file=rootfs.img,format=raw,if=virtio,id=hd0 \
-append "root=/dev/vda console=ttyAMA0 rw init=/bin/init"
執行後,你應該能看到內核啓動日誌滾動輸出,最後停在 busybox 提供的 shell 提示符下,表示系統已成功啓動:
...
[ 0.695675] EXT4-fs (vda): recovery complete
[ 0.696629] EXT4-fs (vda): mounted filesystem cc0fd9b9-0e58-4fd7-8015-b411d90464b3 r/w with ordered data mode. Quota mode: none.
[ 0.697215] VFS: Mounted root (ext4 filesystem) on device 254:0.
[ 0.699176] devtmpfs: mounted
[ 0.742512] Freeing unused kernel memory: 10560K
[ 0.743359] Run /bin/init as init process
mount: mounting none on /dev failed: Device or resource busy
=============================
Minimal BusyBox RootFS Booted
Running rcS...
Remounting rootfs rw...
=============================
[ 0.865086] EXT4-fs (vda): re-mounted cc0fd9b9-0e58-4fd7-8015-b411d90464b3 r/w. Quota mode: none.
Starting shell...
BusyBox v1.36.1 (Ubuntu 1:1.36.1-6ubuntu3.1) built-in shell (ash)
Enter 'help' for a list of built-in commands.
/bin/sh: can't access tty; job control turned off
~ # ls
bin lib sys
dev lost+found usr
etc proc
fix_busybox_path.sh sbin
~ #
當然,為了配合後續步驟的 gdb 調試,我們需要以添加 -s 和 -S 選項的模式啓動 QEMU:
qemu-system-aarch64 \
-machine virt \
-cpu cortex-a57 \
-m 1G \
-nographic \
-kernel kernel_dev/linux/arch/arm64/boot/Image \
-drive file=rootfs.img,format=raw,if=virtio,id=hd0 \
-append "root=/dev/vda console=ttyAMA0 rw init=/bin/init" \
-s \
-S
這裏的啓動參數解釋如下:
qemu-system-aarch64: 指定使用 QEMU 來模擬aarch64(ARM64) 架構的系統。-machine virt: 指定模擬的機器類型為virt。這是一種為 KVM 和 QEMU 設計的通用虛擬平台,兼容性好,支持virtio等半虛擬化設備。-cpu cortex-a57: 指定模擬的 CPU 型號為 ARMCortex-A57。選擇具體的 CPU 型號有助於模擬更真實的硬件行為。-m 1G: 分配給虛擬機的內存大小為 1GB。-nographic: 禁止 QEMU 創建圖形界面窗口。內核和系統的所有控制枱輸出將直接顯示在當前運行 QEMU 命令的終端上。-kernel kernel_dev/linux/arch/arm64/boot/Image: 指定要加載並執行的 Linux 內核鏡像文件。注意這裏使用的是壓縮過的Image文件,而不是vmlinux。-
-drive file=rootfs.img,format=raw,if=virtio,id=hd0: 定義一個虛擬硬盤。file=rootfs.img: 硬盤內容來自我們之前創建的rootfs.img文件。format=raw: 鏡像文件的格式是原始(raw)格式,即沒有額外的元數據或壓縮。if=virtio: 指定硬盤接口類型為virtio-blk。virtio是一種半虛擬化接口標準,性能通常優於完全模擬的 IDE 或 SCSI 接口。內核需要啓用對應的virtio驅動(我們編譯時已確認)。id=hd0: 為這個虛擬硬盤分配一個內部 IDhd0。
-
-append "...": 向 Linux 內核傳遞命令行參數,這些參數會影響內核的啓動行為。root=/dev/vda: 告訴內核根文件系統位於哪個設備上。對於virtio-blk接口,設備名通常是/dev/vda,/dev/vdb等。console=ttyAMA0: 指定內核使用哪個設備作為主控制枱進行輸入輸出。ttyAMA0是virt機器模型上 PL011 UART 串口設備的標準名稱。這確保了內核的printk信息能夠通過 QEMU 重定向到我們的宿主機終端。rw: 指示內核以可讀寫(read-write)模式掛載根文件系統。init=/bin/init: 指定內核啓動後要執行的第一個用户空間程序(PID 1)。在我們的 BusyBox 系統中,/bin/init是指向busybox的符號鏈接,busybox會執行初始化流程,包括運行/etc/init.d/rcS腳本。
-s: 這是-gdb tcp::1234的簡寫。它使 QEMU 在啓動時監聽本地 TCP 端口 1234,作為一個 GDB 服務器 (gdbserver),等待 GDB 客户端連接。-S: 指示 QEMU 在啓動後立即暫停 CPU 的執行。直到有 GDB 客户端連接上來,併發送continue(或c) 命令後,CPU 才會開始執行第一條指令(即內核的入口點)。這對於在內核非常早期的代碼路徑上設置斷點至關重要。
執行這條帶 -s -S 的命令後,QEMU 不會輸出任何東西,它在後台運行並等待 GDB 連接到 1234 端口。
gdb 連接
現在 QEMU 已經在後台運行,並且因為 -S 參數暫停了 CPU,等待在 1234 端口。我們需要打開 另一個 終端窗口(同樣 ssh 進入 Ubuntu 虛擬機),然後啓動 GDB 並連接上去。
# 切換到工作目錄
cd ~/debug-linux-kernel-on-qemu
# 啓動 GDB,加載帶有調試信息的 vmlinux 文件
# 注意:加載的是 vmlinux,而不是 QEMU 運行的 Image 文件
gdb kernel_dev/linux/vmlinux
進入 GDB 交互環境後,執行以下命令:
# 連接到 QEMU 啓動的 gdbserver (默認監聽 localhost:1234)
(gdb) target remote :1234
Remote debugging using :1234
0x0000000040000000 in ?? ()
連接成功後,GDB 會顯示當前暫停的位置(通常是內核的入口點 _stext)。現在 CPU 仍然是暫停的,你可以開始設置斷點。例如,我們可以在 read 和 write 系統調用的 ARM64 實現入口處設置斷點:
# 設置斷點在 read 系統調用函數
(gdb) b __arm64_sys_read
Breakpoint 1 at 0xffff80008030c244: file fs/read_write.c, line 717.
# 設置斷點在 write 系統調用函數
(gdb) b __arm64_sys_write
Breakpoint 2 at 0xffff80008030c374: file fs/read_write.c, line 742.
設置好斷點後,輸入 c (continue) 命令讓內核繼續執行:
(gdb) c
Continuing.
現在,切換回運行 QEMU 的那個終端窗口,你會看到內核的啓動日誌開始滾動輸出。當內核執行到 read 或 write 系統調用時(例如,shell 嘗試讀取用户輸入或打印輸出時),執行流會在 GDB 中暫停,並顯示命中斷點的信息。屆時你就可以使用 GDB 的各種命令(如 n (next), s (step), p (print), bt (backtrace) 等)來檢查代碼和狀態了。
VS Code 連接
雖然 GDB 命令行很強大,但對於習慣了圖形化界面的開發者來説,VS Code 提供了更友好的調試體驗。我們可以配置 VS Code 連接到 QEMU 的 GDB 服務器。
首先,確保你的 VS Code 已經通過 Remote - SSH 擴展連接到了 OrbStack 中的 Ubuntu 虛擬機,並且打開了 ~/debug-linux-kernel-on-qemu 這個工作目錄。同時,你需要安裝 Microsoft 的 C/C++ 擴展 (ms-vscode.cpptools)。
然後,在工作目錄中創建 .vscode/launch.json 文件(如果不存在的話),並填入以下配置:
{
"version": "0.2.0",
"configurations": [
{
"name": "Kernel Debug",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/kernel_dev/linux/vmlinux",
"miDebuggerServerAddress": "localhost:1234",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"logging": {
"engineLogging": true
},
"MIMode": "gdb",
"setupCommands": []
}
]
}
這個配置的關鍵點解釋如下:
"name": 在 VS Code 調試側邊欄顯示的配置名稱。"type": "cppdbg": 表明使用 C/C++ 擴展提供的調試器。"request": "launch": 通常用於啓動程序,但當"miDebuggerServerAddress"被指定時,它實際上會執行 "attach" 操作,連接到一個已存在的 GDB 服務器。"program": "${workspaceFolder}/kernel_dev/linux/vmlinux": 告訴 VS Code 調試器加載哪個可執行文件來獲取符號和源碼信息。${workspaceFolder}是 VS Code 中打開的根目錄,即~/debug-linux-kernel-on-qemu。我們加載的是包含調試信息的vmlinux。"miDebuggerServerAddress": "localhost:1234": 這是核心配置,指示調試器連接到運行在localhost(對於 VS Code 遠程會話來説就是 Ubuntu 虛擬機內部) 的 1234 端口上的 GDB 服務器(由 QEMU-s提供)。"stopAtEntry": false": 我們不希望 VS Code 在連接後自動停在某個入口點,因為內核的“入口”由 QEMU 的-S控制,並且我們希望手動控制何時繼續執行。"cwd": "${workspaceFolder}": 設置調試會話的工作目錄。"MIMode": "gdb": 確認底層使用的調試器是 GDB,並使用其機器接口 (Machine Interface, MI)。"setupCommands": 可以在這裏預設一些 GDB 命令,在連接成功後自動執行,比如設置初始斷點。
使用方法:
- 確保 QEMU 已經以
-s -S參數啓動並在等待連接。 - 在 VS Code 中,切換到 "Run and Debug" 視圖 (通常是側邊欄的播放按鈕圖標)。
- 從頂部的下拉菜單中選擇 "Kernel Debug (Attach to QEMU)" 配置。
- 點擊綠色的播放按鈕 "Start Debugging" (F5)。
VS Code 幾乎可以隨時打下斷點,十分方便。
如果你想調試一些系統調用,可以在 Ubuntu 裏用 .c 編譯好程序,將其包裹在 root fs 裏,這樣你就可以在虛擬機中調試了。