内核调试 --环境搭建篇

Last updated on 8 months ago

在看ceph 源码的时候,一般都是搭建一个环境,然后gbd 到指定函数,边调试边分析,这样很方便,效率也高,前段时间 突然想到 ,系统调用能不能调试呢? 比如 调用个 write 函数,写数据到一个文件,这背后发生了什么?又比如 我们使用 socket 通信 ,然后收数据,这过程我们能不能用gdb 追踪呢? 带着这些问题,在网上摸索一大圈,于是记录下

准备工作 && 预备知识

操作系统也是个程序,同理也可以 gdb,但是内核编译后,在物理机跑有点麻烦,于是这里用 qemu 来模拟硬件,软件模拟硬件,方便调试。

[!NOTE] qemu
qmeu: 是一个托管的虚拟机镜像,它通过动态的二进制转换,模拟 CPU,并且提供一组设备模型,使它能够运行多种未修改的客户机 OS,可以通过与 KVM(kernel-based virtual machine 开源加速器)一起使用进而接近本地速度运行虚拟机(接近真实电脑的速度)

qmeu能跑内核,但也是裸跑内核,实际上 内核需要挂载到根⽂件系统,内核会将其挂载到根⽬录/下,然后运⾏根⽂件系统中init脚本执⾏⼀些启动任务,为了简便,直接 使用busybox 搭建一个轻量级的文件系统,busybox 功能强大,这里就先拿来使用,后面有时间再研究下

需要用的软件包

1
sudo apt install build-essential qemu  libncurses5-dev bison flex libssl-dev libelf-dev axel -y

编译工作

  • 下载内核 源码 && busbox 源码 (以下操作都在 /home 目录执行)

    1
    2
    wget https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.4.34.tar.xz
    wget https://busybox.net/downloads/busybox-1.31.1.tar.bz2
  • 编译linux 内核源码

1
2
3
cd linux-5.4.34
make defconfig #默认配置基于'x86_64_defconfig'
make menuconfig # 这里会弹出配置界面
1
2
3
4
5
6
7
8
9
10
#打开debug相关选项
Kernel hacking --->
Compile-time checks and compiler options --->
[*] Compile the kernel with debug info
[*] Provide GDB scripts for kernel debugging [*] Kernel debugging

#关闭KASLR,否则会导致打断点失败
Processor type and features ---->
[] Randomize the address of the kernel image (KASLR)

开始编译

1
make -j$(nproc)  #编译内核,需要几分钟的时间 ,$(nproc) 核心数

验证下是否能执行

1
2
3
4
5
6
7
8
9
10
#进入源码目录
hrp@ubuntu:~$ cd linux-5.4.34/

hrp@ubuntu:~/linux-5.4.34$ pwd
/home/hrp/linux-5.4.34

# 使用 qemu执行 此时会弹出个黑框(PS:我是 ubuntu )
hrp@ubuntu:~/linux-5.4.34$ qemu-system-x86_64 -kernel arch/x86/boot/bzImage
qemu-system-x86_64: warning: TCG doesn't support requested feature: CPUID.01H:ECX.vmx [bit 5]

  • 编译busybox
    1
    2
    3
    4
    5
    6
    cd busybox-1.31.1
    make menuconfig #进入配置项
    选择 编译成静态链接
    Settings --->
    [*] Build static binary (no shared libs)
    make -j$(nproc) && make install

制作文件系统

  • 创建一个镜像(相当于创建一个盘)

    1
    dd if=/dev/zero of=./busybox.img bs=1M count=300
  • 格式盘,这里试用 ext3

    1
    mkfs.ext3 busybox.img
  • 要往镜像里面添加文件,为了方便,直接将镜像挂载到 /mnt 下

    1
    2
    3
    4
    sudo mkdir /mnt/disk
    sudo mount -o loop busybox.img /mnt/disk
    #将文件系统必要的文件 拷贝到挂载目录
    sudo cp -rf busybox源码目录/_install/* /mnt/disk
  • 创建必要的文件目录

    1
    2
    cd /mnt/disk/
    sudo mkdir dev sys proc etc lib mnt
  • 创建设备点

    1
    2
    3
    4
    5
    cd dev/
    mknod console c 5 1
    mknod null c 1 3
    mknod tty2 c 4 2

  • busybox默认的设置文件,内核启动后会执行 rcS 脚本,这个脚本我们可以挂载目录,和配置网络

    1
    2
    3
    4
    5

    sudo cp -a /dir/to/busybox-1.17.0/examples/bootfloppy/etc/* /mnt/disk/etc

    sudo vi /mnt/disk/etc/init.d/rcS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#! /bin/sh
MAC=08:90:90:59:62:21
IP=192.168.100.2
Mask=255.255.255.0
Gateway=192.168.100.1
/sbin/ifconfig lo 127.0.0.1
ifconfig eth0 down
ifconfig eth0 hw ether $MAC
ifconfig eth0 $IP netmask $Mask up
route add default gw $Gateway
/bin/mount -a
/bin/mount -t sysfs sysfs /sys
/bin/mount -t tmpfs tmpfs /dev
/sbin/mdev -s
mount -o remount,rw,noatime -n /dev/root /
  • 修改fstab 文件

    1
    2
    3
    4
    5
    6
    7
    $ vim etc/fstab
    proc /proc proc defaults 0 0
    tmpfs /tmp tmpfs defaults 0 0
    sysfs /sys sysfs defaults 0 0
    tmpfs /dev tmpfs defaults 0 0
    var /dev tmpfs defaults 0 0

  • 接触挂载

    1
    sudo umount /mnt/disk
  • 启动内核 ,进入 bash交互

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31


    qemu-system-x86_64 -m 512 -kernel /home/hrp/linux-5.4.34/arch/x86_64/boot/bzImage -append "root=/dev/sda rw console=ttyS0 " -nographic -boot c -hda /home/hrp/busybox.img -k en-us -net nic -net tap,ifname=tap0,script=no


    #-----------


    WARNING: Image format was not specified for '/home/hrp/busybox.img' and probing guessed raw.
    Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
    Specify the 'raw' format explicitly to remove the restrictions.
    qemu-system-x86_64: warning: TCG doesn't support requested feature: CPUID.01H:ECX.vmx [bit 5]
    [ 0.000000] Linux version 5.4.34 (hrp@ubuntu) (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)) #3 SMP Fri Jan 26 22:22:23 PST 2024
    [ 0.000000] Command line: root=/dev/sda rw console=ttyS0
    [ 0.000000] x86/fpu: x87 FPU will use FXSAVE
    [ 0.000000] BIOS-provided physical RAM map:
    [ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
    [ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
    [ 0.000000] BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved
    ....
    mount: mounting tmpfs on /tmp failed: No such file or directory
    mount: mounting sysfs on /sys failed: Device or resource busy
    [ 2.702166] EXT4-fs (sda): re-mounted. Opts: (null)
    [ 2.702386] ext3 filesystem being remounted at / supports timestamps until 2038 (0x7fffffff)
    [ 2.703963] rcS (94) used greatest stack depth: 13424 bytes left

    Processing /etc/profile... Done

    / #


调试

  • 参数加入 -S -s ,默认端口 1234
1
2
3
4
5
6
7
8
 qemu-system-x86_64 -m 512 -kernel /home/hrp/linux-5.4.34/arch/x86_64/boot/bzImage -append "root=/dev/sda rw console=ttyS0 " -nographic   -boot c -hda /home/hrp/busybox.img -k en-us  -net nic -net tap,ifname=tap0,script=no -S -s

WARNING: Image format was not specified for '/home/hrp/busybox.img' and probing guessed raw.
Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
Specify the 'raw' format explicitly to remove the restrictions.
qemu-system-x86_64: warning: TCG doesn't support requested feature: CPUID.01H:ECX.vmx [bit 5]

## 等待调试
  • 新建窗口 开始gdb
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    root@ubuntu:/mnt/disk# gdb /home/hrp/linux-5.4.34/vmlinux
    GNU gdb (Ubuntu 8.1.1-0ubuntu1) 8.1.1
    Copyright (C) 2018 Free Software Foundation, Inc.
    ....
    line to your configuration file "/root/.gdbinit".
    For more information about this security protection see the
    "Auto-loading safe path" section in the GDB manual. E.g., run from the shell:
    info "(gdb)Auto-loading safe path"
    (gdb)
    (gdb) target remote:1234
    Remote debugging using :1234
    0x000000000000fff0 in entry_stack_storage ()
    (gdb) c #键入c ,内核开始执行
    Continuing.


1
2
3
4
5
6
7
8
9
10
11
12
qemu 相关参数
-kernel ./bzImage:指定启用的内核镜像;

-initrd ./rootfs.img:指定启动的内存文件系统;

-append "nokaslr console=ttyS0":附加参数,其中 参数必须添加进来,防止内核起始地址随机化,这样会导致 gdb 断点不能命中;参数说明可以参见这里。nokaslr

-s:监听在 gdb 1234 端口;

-S:表示启动后就挂起,等待 gdb 连接;

-nographic:不启动图形界面,调试信息输出到终端与参数 组合使用;console=ttyS0