使用QEMU虛擬機調試Linux內核

    作爲一名初級的嵌入式底層開發人員,若想要深入學習Linux內核,需要謹慎地選擇開發環境和開發工具。與應用層開發不同的是,Linux內核的學習和開發調試通常是比較困難的,原因之一在於可用的Linux內核調試工具比較少。很久以前筆者注意到安卓工程中使用到了QEMU虛擬機模擬了安卓硬件設備,可以完整地運行安卓系統(從物理按鍵和顯示、觸摸屏,到Linux內核,直至Framework層)。還有QEMU支持與GDB建立連接,可以通過常用的調試手段加深對Linux內核的理解。當然,現在關於QEMU虛擬機運行、調試Linux內核的文章也很多,筆者在這裏簡要地增加一例,忝列門牆,不勝惶悚。

    筆者使用的操作系統爲ubuntu 16.04,系統官方提供的QEMU版本相對較低,於是使用以下配置參數來編譯qemu的3.1.0版本。如果執行configure的過程中出錯,請使用apt安裝出錯信息指出缺少的庫;當configure成功返回後,即可執行make && make install完成qemu的編譯和安裝:

#!/bin/bash

./configure '--target-list=aarch64-softmmu,aarch64-linux-user,arm-softmmu,arm-linux-user' \
    '--cc=/usr/bin/gcc-5' '--cxx=/usr/bin/g++-5' '--extra-cflags=-O2' '--extra-cxxflags=-O2' \
    --disable-strip --disable-sdl --enable-gnutls --enable-virtfs --enable-curl --enable-fdt \
    --enable-tools --enable-linux-aio --enable-cap-ng --enable-attr --enable-spice \
    --enable-libiscsi --enable-libnfs --enable-libusb --enable-usb-redir --enable-libssh2 \
    --enable-lzo --enable-snappy --enable-seccomp --enable-coroutine-pool --enable-glusterfs \
    --enable-libxml2 --enable-replication --prefix=/opt/qemu3 # --enable-bzip2 --enable-vde --enable-rbd

    接下來需要編譯Linux內核。下載最新版本的Linux內核源碼,筆者通過該URL下載了v5.2.4版本的Linux內核源碼:http://mirrors.ustc.edu.cn/kernel.org/linux/kernel/v5.x/linux-5.2.4.tar.xz 。下載後解壓Linux內核源碼,並修改arch/arm/configs/vexpress_defconfig,在CONFIG_DEVTMPFS=y下面加入一行配置:CONFIG_DEVTMPFS_MOUNT=y。之後,依次執行:

    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- vexpress_defconfig
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j8 zImage dtbs

    這樣就能夠編譯得到QEMU虛擬機需要的兩個文件,路徑分別爲:

  Kernel: arch/arm/boot/Image is ready
  OBJCOPY arch/arm/boot/zImage
  Kernel: arch/arm/boot/zImage is ready
  DTC     arch/arm/boot/dts/vexpress-v2p-ca5s.dtb
  DTC     arch/arm/boot/dts/vexpress-v2p-ca9.dtb
  DTC     arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dtb
  DTC     arch/arm/boot/dts/vexpress-v2p-ca15_a7.dtb

    運行Linux內核依賴一個完整的根文件系統,筆者已提供了一個使用buildroot生成的根文件系統rootfs.ext2.xz(實際上,下面運行QEMU的簡單腳本也源自於buildroot),可以在筆者的資源下載區找到。下載後解壓得到rootfs.ext2,可以將rootfs.ext2重命名爲rootfs.ext4。隨後,將zImage/vexpress-v2p-ca9.dtb/rootfs.ext2放置於同一目錄下,使用下面的腳本運行qemu虛擬機:

yejq@ubuntu:~/program/arm-qemu$ cat run-vm.sh 
#!/bin/bash

export PATH="/opt/qemu3/bin:$PATH"

exec qemu-system-arm -M vexpress-a9 -smp 1 -m 256 -kernel zImage \
	-dtb vexpress-v2p-ca9.dtb -drive 'file=rootfs.ext4,if=sd,format=raw' \
	-append 'console=ttyAMA0,115200 root=/dev/mmcblk0' -serial stdio \
	-net 'nic,model=lan9118' -net user -gdb 'tcp::2019'

yejq@ubuntu:~/program/arm-qemu$ ./run-vm.sh
audio: Could not init `oss' audio driver
VNC server running on 127.0.0.1:5900
Booting Linux on physical CPU 0x0
Linux version 5.2.4+ (yejq@ubuntu) (gcc version 6.4.1 20180425 [linaro-6.4-2018.05 revision 7b15d0869c096fe39603ad63dc19ab7cf035eb70] (Linaro GCC 6.4-2018.05)) #1 SMP Sat Aug 3 23:17:25 CST 2019
CPU: ARMv7 Processor [410fc090] revision 0 (ARMv7), cr=10c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
OF: fdt: Machine model: V2P-CA9
Memory policy: Data cache writeback
Reserved memory: created DMA memory pool at 0x4c000000, size 8 MiB
OF: reserved mem: initialized node vram@4c000000, compatible id shared-dma-pool
cma: Reserved 16 MiB at 0x6f000000
CPU: All CPU(s) started in SVC mode.
percpu: Embedded 20 pages/cpu s49484 r8192 d24244 u81920
Built 1 zonelists, mobility grouping on.  Total pages: 65024
Kernel command line: console=ttyAMA0,115200 root=/dev/mmcblk0

    內核加載完成後,會提示豋錄,用戶名爲root,密碼爲123456:

Starting logging: OK
Initializing random number generator... done.
Starting network: OK
Starting telnetd: OK

Welcome to Buildroot
buildroot login: root
Password: 
# ls
# uname -a
Linux buildroot 5.2.4+ #1 SMP Sat Aug 3 23:17:25 CST 2019 armv7l GNU/Linux
# 

    最後,使用gdb調試器與QEMU建立連接,這樣就可以像調試普通應用一樣調試Linux內核了:

yejq@ubuntu:~/program/linux-5.2.4$ arm-linux-gnueabihf-gdb ./vmlinux
GNU gdb (Linaro_GDB-2018.05) 8.1.0.20180611-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-unknown-linux-gnu --target=arm-linux-gnueabihf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./vmlinux...done.
(gdb) target remote localhost:2019
Remote debugging using localhost:2019
cpu_v7_do_idle () at arch/arm/mm/proc-v7.S:78
78		ret	lr
(gdb) bt
#0  cpu_v7_do_idle () at arch/arm/mm/proc-v7.S:78
#1  0x80108fb0 in arch_cpu_idle () at arch/arm/kernel/process.c:71
#2  0x8014e6d8 in cpuidle_idle_call () at kernel/sched/idle.c:154
#3  do_idle () at kernel/sched/idle.c:263
#4  0x8014ea38 in cpu_startup_entry (state=CPUHP_ONLINE) at kernel/sched/idle.c:354
#5  0x8072fc70 in rest_init () at init/main.c:451
#6  0x80a00a24 in arch_call_rest_init () at init/main.c:548
#7  0x80a00ea0 in start_kernel () at init/main.c:761
#8  0x00000000 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章