lab3:基于VS Code的Linux内核调试环境搭建及start_kernel跟踪分析

前言:ubuntu 22.04 许多bug.

环境:ubuntu 18.04 

1.安装开发工具

sudo apt install build-essential

sudo apt 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

make menuconfig

进入界面后

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)

qemu-system-x86_64 -kernel arch/x86/boot/bzImage

编译成功后测试一下内核能不能正常加载运行,因为没有文件系统最终会kernel panic

5.制作内存跟文件系统 

电脑加电启动首先由bootloader加载内核,内核紧接着需要挂载内存根文件系统,其中包含必要的设备驱动和工具,bootloader加载根文件系统到内存中,内核会将其挂载到根目录/下,然后运行根文件系统中init脚本执行一些启动任务,最后才挂载真正的磁盘根文件系统。

我们这里为了简化实验环境,仅制作内存根文件系统。这里借助BusyBox 构建极简内存根文件系统,提供基本的用户态可执行程序。

axel -n 20 https://busybox.net/downloads/busybox-1.36.0.tar.bz2

tar -jxvf busybox-1.36.0.tar.bz2

cd busybox-1.36.0

 老版本busybox-1.31.1可能会出现错误,这里直接安装最新版本的busybox。

make menuconfig

Settings  --->     [*] Build static binary (no shared libs)

编译成静态链接,不用动态链接库

 然后编译安装,默认会安装到源码目录下的 _install 目录中。

make -j$(nproc) && make install

制作内存根文件系统镜像:

cd ~

mkdir rootfs

cd rootfs

cp ~/busybox-1.36.0/_install/* ./ -rf

mkdir dev proc sys home

sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} dev/

完成之后,将init脚本文件放在根文件系统跟目录下;init内容如下:

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

对脚本进行添加可执行权限: 

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 

结果如下:

 gdb调试:

6.配置VScode调试linux内核

安装GNU Global

sudo apt install global

安装C++相关插件以及GDB DeBug

 

 由于 Linux 内核高度定制化,所以没有办法直接通过配置 includePath 等让 Intellisense 正常提示,这里借助一个 Python 脚本来生成 compile_commands.json 文件帮助 Intellisense 正常提示(包括头文件和宏定义等)。在Linux源代码目录下直接运行如下命令就可以生成 compile_commands.json 了。

python ./scripts/gen_compile_commands.py

在linux-5.4.34文件夹中新建一个.vscode文件夹,将配置文件放入:

其中tasks.json文件中的路径要对应自己的文件配置路径 

settings.json中的disable的d要改成小写: 

vscode的调试环境就配置好了。

7.跟踪linux内核启动过程

Linux内核的起点是start_kernel函数,在start_kernel处打断点;启动调试:

通过单步跳过并跟踪分析, set_task_stack_end_magic将0号进程init_task被设为整个系统的初始进程,在此之后的所有进程都会由0号进程创建,继续单步调试发现会进行各种初始化的操作,包括初始化各种重要的数据结构、驱动程序、中断处理程序等。在这个阶段,内核会建立好一些必要的核心数据结构,如物理内存管理器、虚拟内存管理器,以及进程调度器等。最后到函数的的末尾,由arch_call_rest_init()函数调用rest_init()函数。

 再在rest_init处打断点:

进入函数之后看到了kernel_init,即1号进程,它是所有用户进程的祖先,由kernel_thread函数创建,kernel_thread函数创建一个新的内核线程(实际linux不支持线程所以是一个内核进程)。

 进入kernel_thread函数查看:

 该函数通过_do_fork函数创建进程。所以可以看到1号进程和2号进程最终都是通过_do_fork创建的,用户态通过系统调用fork创建一个进程最终也是通过_do_fork来完成的。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值