基于VSCode的Linux内核调试环境搭建以及start_kernel跟踪分析

本文详细介绍了如何在Ubuntu环境下编译Linux内核,包括安装必要的开发工具,下载和配置内核源码,关闭KASLR,以及使用QEMU测试内核。接着,文章讲解了制作内存根文件系统的过程,涉及BusyBox的配置与安装,并创建了简单的init脚本。最后,文章提到了如何利用VSCode进行内核调试,通过设置断点跟踪了从start_kernel到kernel_init的流程,以及内核线程的创建过程。
摘要由CSDN通过智能技术生成

  1. 安装开发工具

    sudo apt install build-essential
    sudo apt install qemu # install QEMU
    sudo apt install libncurses5-dev bison flex libssl-dev libelf-dev
    #编译内核所需的依赖---一些基础库
    
  2. 下载内核源码

    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
  3. 配置内核选项

    make defconfig # Default configuration is based on 'x86_64_defconfig'
    make menuconfig
    # 打开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)
    
  4. 编译和运行内核

    make -j$(nproc) # nproc gives the number of CPU cores/threads available
    # 测试一下内核能不能正常加载运行,因为没有文件系统最终会kernel panic
    qemu-system-x86_64 -kernel arch/x86/boot/bzImage
    
  5. 制作内存根文件系统

    首先从https://www.busybox.net下载 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
    记得要编译成静态链接,不用动态链接库。
    Settings  --->
        [*] Build static binary (no shared libs)
    然后编译安装,默认会安装到源码目录下的 _install 目录中。
    make -j$(nproc) && make install
    
    然后制作内存根文件系统镜像,大致过程如下:
    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脚本文件放在根文件系统跟目录下(rootfs/init),添加如下内容到init文件。
    #!/bin/sh
    mount -t proc none /proc
    mount -t sysfs none /sys
    echo "Wellcome MengningOS!"
    echo "--------------------"
    cd home
    /bin/sh
    给init脚本添加可执行权限
    chmod +x init
    
    
    打包成内存根文件系统镜像
    find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz 
    测试挂载根文件系统,看内核启动完成后是否执行init脚本
    qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz
    //本文由于将rootfs放在了linux文件夹下,命令如下:
    //qemu-system-x86_64 -kernel ./arch/x86/boot/bzImage -initrd rootfs.cpio.gz
    
    
  6. 图片结果显示

  7. 配置VScode

    1、在命令行输入python ./scripts/gen_compile_commands.py
    2、新建.vscode文件夹,将提供的配置文件放入文件夹内
  8. 跟踪分析

    执行
    qemu-system-x86_64 -kernel ./arch/x86/boot/bzImage -initrd rootfs.cpio.gz -S -s
    设置断点start_kernel,在vscode中按F5进行调试

     可以看出,vscode停在了start_kernel处。

    点击单点跳过,这里我们看到了0号进程init_task被设置整个系统的第一个进程(0进程是手工创建的,其他进程都是0号进程创建的)在内核引导时,init_task会被创建并启动,它是所有其他进程的起点。

    继续跳过,start_kernel会继续执行一些初始化操作,包括初始化各种重要的数据结构、驱动程序、中断处理程序等。在这个阶段,内核会建立好一些必要的核心数据结构,如物理内存管理器、虚拟内存管理器,以及进程调度器等。
    最后来到start_kernel的结尾arch_call_reset_init(),这个点开这个函数的定义是执行了reset_init()函数,因此我们再设置一个函数断点"reset_init",继续点击单点跳过发现就进入了reset_init函数内部。这个函数是由0号进程执行的。

     继续执行,这时候遇到了kernel_init,即1号进程,它是所有用户进程的祖先,由kernel_thread函数创建,kernel_thread函数创建一个新的内核线程(实际linux不支持线程所以是一个内核进程),该线程的入口地址是kernel_init()函数。

    设置kernel_thread,继续执行,进入kernel_thread函数的定义。

     发现kernel_thread函数是通过_do_fork函数来创建进程的。设置_do_fork断点,进入_do_fork函数定义。

     _do_fork函数主要完成了调用copy_process()复制父进程、调用wake_up_new_task将子进程加入就绪队列等待调度执行等。

     

    另一个进程则由kthreadd创建。 一共涉及到3个内核进程/线程。操作系统用数字来表示/记录一个进程/线程,此数字就被称为这个进程的进程号。这个号码是从0开始分配的。进程0:也就是那个死循环,也叫idle进程(空闲进程)。进程1:也就是kernel_init函数,这个进程被称为init进程。进程2:也就是kthreadd函数,这个进程是linux内核的守护进程。这个进程是用来保证linux内核自己本身能正常工作的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值