Linux-lab3: 基于Qemu/Busybox的内核跟踪调试

Linux内核的核心目录

init : 其中的main.c中的start_kernel函数是内核的起点

kernel : 主内核代码 (内核的内核)

mm : memory management

fs : file system,实现了文件系统

ipc : inter-process communication,进程通信

net : 实现网络,如TCP/IP协议栈

drivers: 设备驱动程序

lib : 库文件,因为内核无法使用C标准库函数

include :建立内核代码时所需的公共的头文件,它们是各种体系结构(例如:ARM/x86)共用的

调试过程

下载linux内核源代码并解压:

sudo apt install axel
axel -n 20 https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.4.34.tar.xz
xz -d linux-5.4.34.tar.xz
tar -xvf linux-5.4.34.tar
cd linux-5.4.34

下载编译工具:

sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev         # 编译器大礼包
make defconfig     # 进行默认设置。每个新的内核版本都会带来一串新的选项,我们不需要在每次内核发布时升级我们的defconfig。[r1]
make -j$(nproc)    # 编译内核,时间较久
sudo apt install qemu    # install QEMU
qemu-system-x86_64 -kernel arch/x86/boot/bzImage # 使用qemu运行内核程序
sudo apt install libncurses5-dev bison flex libssl-dev libelf-dev # 这里相比上一个实验多了一个工具

在linux-5.4.34文件夹下:

make menuconfig

在UI中设置debug选项并关闭KASLR (kernel address space layout randomize,为提高内核安全性将kernel随机的加载到不同的物理地址运行。但是这一特性将导致实验中打断点失败)

UI使用技巧:按space选中[*]或取消选择

Kernel hacking  --->                  # debug选项
    Compile-time checks and compiler options  --->
        [*] Compile the kernel with debug info
        [*]   Provide GDB scripts for kernel debugging
    [*] Kernel debugging
Processor type and features ---->     # KASLR选项
    [] Randomize the address of the kernel image (KASLR)

 返回cmd输入以下命令:

make -j$(nproc)
qemu-system-x86_64 -kernel arch/x86/boot/bzImage # 测试内核能不能正常加载运行

内核运行结果如下,由于没有文件系统,导致kernel panic。

 以下我们借助Busybox制作一个简易根文件系统,它能提供基本的用户态可执行程序。下载安装:

axel -n 20 https://busybox.net/downloads/busybox-1.31.1.tar.bz2
tar -jxvf busybox-1.31.1.tar.bz2
cd busybox-1.31.1
make menuconfig                    # 设置BusyBox
make -j$(nproc) && make install    # 编译BusyBox

编译过程:

 编译成功的提示:

 将相关文件复制到文件夹rootfs中:

mkdir rootfs
cd rootfs
cp ../busybox-1.31.1/_install/* ./ -rf
mkdir dev proc sys home    # 建立多个文件夹
sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} dev/

然后新建一个init脚本文件,内容如下:

#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
echo "Wellcome MengningOS!"
echo "--------------------"
cd home
/bin/sh

然后给该脚本文件加可执行权限:

chmod +x init

打包成内存根文件系统镜像;

测试挂载根文件系统,可以发现启动完成后执行了init脚本。

使用以下命令打开或关闭虚拟机:

qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz -S -s        # 新窗口启动虚拟机
qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz -S -s -nographic -append "console=ttyS0" # 使用纯命令行下启动虚拟机
killall qemu-system-x86_64  # 强行关闭虚拟机

在linux内核文件夹下启动一个新的终端,加载内核符号表,这样就能在命令行中调试内核代码了。

 也可以在VSCode中进行断点调试,但需要额外配置调试环境。

 

Linux内耗启动分析(main.c)

 1、内核起点start_kernel();

通过init_task()创建0号进程,它同样也是idle进程(用于维持内核态的无限循环),它能将该函数及其之前的一系列指令都划归到0号进程的进程环境中。

 2、内核初始化init_task();

lockdep_init()             // 内核依赖关系表和哈希表
boot_init_stack_canary():  // 栈保护,防止缓冲区攻击
tick_init():               // 启动时钟
boot_cpu_init():           // 激活CPU
setup_arch():              // 设置不同CPU的参数
trap_init():               // 硬件中断门
mm_init():                 // 内存分配
sched_init():              // 任务调度
init_IRQ():                // 中断向量
set_intr_gate;             // 中断门
set_system_trap_gate;      // 系统调用

3、rest_init()函数创建了kernel_init()和kthreadd两个线程,后者负责对其他内核线程管理调度。

 4、当根文件系统就绪后,kernel_init()函数通过do_execve系统调用执行/sbin/init文件,此时OS进入用户态。

 

参考资料

跟踪分析Linux内核启动过程

跟踪分析Linux内核的启动过程

孟宁 / linuxkernel

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值