可gdb调试内核代码的MenuOS搭建
实验环境:Ubuntu18.04.1, qemu
1. 尝试升级当前系统内核
1.1 查看当前系统内核
当前内核为5.0.0-23-generic
$ uname -a
Linux ubuntu 5.0.0-23-generic #24~18.04.1-Ubuntu SMP Mon Jul 29 16:12:28 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
1.2 下载Linux内核源代码
# 创建目录,下载最新内核
~$ mkdir ~/LinuxKernel
~$ cd ~/LinuxKernel/
~/LinuxKernel$ wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.4.2.tar.xz
1.3 下载过程如下
linux-5.4.2.tar.xz 100%[============================================>] 104.37M 275KB/s 用时 3m 9s
2019-12-10 19:37:51 (566 KB/s) - 已保存 “linux-5.4.2.tar.xz” [109441848/109441848])
1.4 解压并编译内核
# 解压xz压缩文件
~/LinuxKernel$ xz -d linux-5.4.2.tar.xz
# 提取tar归档文件
~/LinuxKernel$ tar -xvf linux-5.4.2.tar
# 安装编译依赖
~/LinuxKernel$ sudo apt install build-essential flex bison libssl-dev libelf-dev libncurses-dev
# 编译内核
~/LinuxKernel$ cd linux-5.4.2/
~/LinuxKernel/linux-5.4.2$ make i386_defconfig # 按照默认值生成32位x86配置文件
~/LinuxKernel/linux-5.4.2$ make
编译完成
1.5 尝试升级当前系统内核
最后失败了,不想对系统内核尝试升级的/或者不是在虚拟机上进行的,这部分可以跳过。
1.5.1 系统快照
防止升级当前系统内核后无法启动,创建系统快照
1.5.2 升级内核
~/LinuxKernel/linux-5.4.2$ sudo make modules install
~/LinuxKernel/linux-5.4.2$ sudo make install
~/LinuxKernel/linux-5.4.2$ sudo update-grub
# 接着重启系统
~/LinuxKernel/linux-5.4.2$ reboot
重启后发现,系统起不来了,还好进行了快照备份。。。
快照恢复,算了不折腾当前系统内核了
2. QEMU虚拟机
2.1 下载安装QEMU
~/LinuxKernel$ sudo apt install qemu
# 使用qemu加载linux内核,参数kernel需要调整为对应版本号的镜像
~/LinuxKernel$ qemu-system-i386 -kernel linux-5.4.2/arch/x86/boot/bzImage
2.2 构造menuOS
~/LinuxKernel$ git clone https://github.com/mengning/menu.git
~/LinuxKernel/menu$ cd menu
~/LinuxKernel/menu$ sudo apt-get install libc6-dev-i386 # 32位编译所需要的库
~/LinuxKernel/menu$ nvim Makefile
有两处地方需要修改,第一个是修改为对应启动命令,第二个是修改内核版本号为之前编译的内核文件夹名
~/LinuxKernel/menu$ make rootfs
接着就会启动MenuOS,同时Linux目录下会生成一个rootfs.img
,下次启动就不用make
了
比如关了qemu后,下次可以在LinuxKernel
文件夹下直接通过qemu-system-i386 -kernel linux-5.4.2/arch/x86/boot/bzImage -initrd rootfs.img
来启动虚拟机
2.3 集成TCP服务端测试网络功能
在MenuOS中集成我们的TCP服务端程序
~/LinuxKernel$ git clone https://github.com/mengning/linuxnet.git
~/LinuxKernel$ cd linuxnet/lab2
~/LinuxKernel/linuxnet/lab2$ make
~/LinuxKernel/linuxnet/lab2$ cd ~/LinuxKernel/menu/
会发现menuos中多个一个replyhi的命令
此时只是集成了TCP服务端程序
检查lab3的Makefile,修改内核路径部分,并构建
~/LinuxKernel/linuxnet/lab3$ nvim Makefile
~/LinuxKernel/linuxnet/lab3$ make rootfs
运行服务并测试TCP功能
2.4 重新编译内核
为了能进行调试,对内核进行重新编译
~/LinuxKernel/menu$ make menuconfig
# kernel hacking—>Compile-time checks and compiler options—>
# [*] compile the kernel with debug info
依次进入kernel hacking
和Compile-time checks and compiler options
,选中compile the kernel with debug info
,然后save
save
的时候检查下是否有该信息,接着就可以Esc
退出了
~/LinuxKernel/menu$ make
make重新编译(时间较长)
2.5 启动带gdbserver的MenuOS
~/LinuxKernel$ qemu-system-i386 -kernel linux-5.4.2/arch/x86/boot/bzImage -initrd rootfs.img -append "root=/dev/sda init=/init nokaslr" -s -S
-S
freeze CPU at startup(usec
to start execution)-s
shorthand for-gdb tcp::1234
(可以使用-gbd tcp::xxxx
来更换端口)nokaslr
KASLR是kernel address space layout randomization的缩写
运行命令后,qemu虚拟机会等待gdb连接,所以是一个黑屏的界面
2.6 启动gdb连接gdbserver
2.6.1 新打开一个窗口
~/LinuxKernel$ gdb
(gdb) file ~/LinuxKernel/linux-5.4.2/vmlinux
(gdb) target remote:1234 # 设置gdbserver端口
(gdb) break start_kernel # 设置启动断点
(gdb) break sys_socketcall # 套接字调用断点
2.6.2 输入c
让系统继续启动
(gdb) c
(gdb) list # 停下来后通过list查看断点上下文命令
可以看到
gdb中继续输入c
,让系统继续启动,发现进入了socketcall
断点
在qemu中可以看到是在启动本地环回端口
接着c
继续,加上环回地址总共进入了三次socketcall
断点,在qemu上分别是lo,eth0,list all interfaes,然后进入了系统
2.6.3 使用tcp服务端和客户端通信
这里要重新集成测试用的TCP服务端和客户端
(gdb) replyhi
(gdb) hello
在这期间,可以看到多次进入socketcall
断点
到此通过gdb可以跟踪到内核代码,比如start_kernel
、sys_socketcall
等内核函数的MenuOS已搭建完成。
作者:SA19225176,万有引力丶