1 Linux篇(调试linux)

  1. 内核各个版本: https://www.kernel.org/pub/linux/kernel/

  2. 最新主线版本: https://kernel.org/

2 initrd制作

此处我用的6.6.109版本.

1
dracut -q --force -i ./package /my --add "busybox kernel-modules-extra kernel-modules rootfs-block" /tmp/bar.img 6.6.109

initrd/initramfs 本质上是一个压缩的rootfs镜像(通常是cpio格式),QEMU启动时用 -initrd 传给内核,内核会把它解压到内存里(ramfs/tmpfs),并把它临时挂载为根文件系统 /.

当内核完成自身初始化后,它必须进入用户态,去运行第一个用户进程(PID 1)。这个进程就从根文件系统里找。查找顺序大概是.

  • 如果内核启动参数里写了 rdinit=,它会在 initrd 文件系统里找这个路径

  • 如果没指定 rdinit=,内核默认会尝试这些路径:

    1
    2
    3
    4
    /init
    /sbin/init
    /etc/init
    /bin/init

    一旦找到就执行,成为 PID 1.

3 调试方法

首先编译下载完毕的内核, 根据需要进行裁剪.

具体镜像的编译方式: https://gitee.com/jvle/works/blob/master/study/kernel/kernel_configs.md#%E8%B0%83%E8%AF%95%E5%86%85%E6%A0%B8%E4%BD%BF%E7%94%A8busybox%E5%88%B6%E4%BD%9Crootfs

这里添加一下调试内核模块的方法.

3.1 调试内核模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 这里举个例子
obj-m := helloworld.o

KDIR := ../../linux-6.6.109
PWD := $(shell pwd)
INSTALL := /mnt/rootfs

all:
$(MAKE) -C $(KDIR) M=$(PWD) modules

install:
$(MAKE) -C $(KDIR) M=$(pwd) INSTALL_MOD_PATH=$(INSTALL) modules_install

clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean

其中先build将模块信息编译完成,之后 install 到指定的镜像根目录,后面将 ko 模块拷贝到镜像中任意位置处即可调试内核模块.

3.2 x86

client.

1
2
3
4
5
6
# 这里可以不用initrd选项,使用默认的.
# 调试的时候务必加上 nokaslr 不然会无法成功 gdb
qemu-system-x86_64 -kernel ./linux-6.6.109/arch/x86/boot/bzImage \
-initrd ./bar.img \
-append "rdinit=my/init_sh_echo console=ttyS0 no5lvl nokaslr" \
-m 2048 -serial stdio -s -S

remote.

1
2
gdb ./vmlinux
target remote :1234

或者在当前目录下写个 .gdbinit

1
2
file ./vmlinux
target remote :1234