使用 GDB + Qemu 调试 Linux 内核
-
2 mins read
使用 GDB + Qemu 调试 Linux 内核
Linux 内核编译
使用 master
分支
$ git clone https://github.com/torvalds/linux.git
$ cd linux
$ make mrproper # 清理旧配置和编译生成的文件
$ make x86_64_defconfig # 生成默认配置
$ make nconfig # 开启 debug 选项
# Kernel hacking --> Compile-time checks and compile options --> Debug information --> Generate DWARF Version 5 Debuginfo
$ make -j$(nproc) # 编译
# 内核文件
$ ls -hl vmlinxu
$ ls -hl ./arch/x86_64/boot/bzImage # 压缩后的内核文件
文件系统制作
使用 busybox
$ git clone git://busybox.net/busybox.git
# or
# git clone https://github.com/mirror/busybox.git # github 镜像
$ cd busybox
$ make menuconfig # 选择静态编译
# Settings # 按Enter 进入
# --> Build Options
# [*] Build static binary (no shared libs) # 按 Y 选择
$ make -j$(nproc)
$ make install
# 创建系统目录
$ cd _install
$ mkdir proc
$ mkdir sys
$ touch init
$ vim init # 输入初始化程序
$ chmod +x init # 添加可执行权限
$ find . | cpio -o --format=newc > ./rootfs.img # 生成 rootfs 文件
init
程序
#!/bin/sh
echo "{==DBG==} INIT SCRIPT"
mkdir /tmp
mount -t proc none /proc
mount -t sysfs none /sys
mount -t debugfs none /sys/kernel/debug
mount -t tmpfs none /tmp
mdev -s
echo -e "{==DBG==} Boot took $(cut -d' ' -f1 /proc/uptime) seconds"
# normal user
setsid /bin/cttyhack setuidgid 1000 /bin/sh
Qemu 启动内核
$ qemu-system-x86_64 -kernel ./bzImage -initrd ./rootfs.img -append "nokaslr console=ttyS0" -s -S -nographic
-kernel ./bzImage
: 指定启用的内核镜像;-initrd ./rootfs.img
:指定启动的内存文件系统;-append "nokaslr console=ttyS0"
: 附加参数,其中 nokaslr 参数必须添加进来,防止内核起始地址随机化,这样会导致 gdb 断点不能命中;参数说明可以参见这里。-s
:监听在 gdb 1234 端口;-S
:表示启动后就挂起,等待 gdb 连接;-nographic
:不启动图形界面,调试信息输出到终端与参数 console=ttyS0 组合使用;
GDB 调试
$ gdb
(gdb) file vmlinux
(gdb) target remote :1234
(gdb) break start_kernel
(gdb) c # 启动时会停止在 start_kernel 函数上
(gdb) add-auto-load-safe-path /opt/os/linux/
(gdb) source vmlinux-gdb.py # 使用 vmlinux-gdb 提供的命令