secondid 2019-12-09
构建调试Linux内核网络代码的环境MenuOS系统
如何构建一个可以调试Linux内核网络代码的环境MenuOS呢?
在Ubuntu下构建一个MenuOS
首先,我们要下载Linux内核的源代码。网址是:http://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.0.1.tar.xz
然后用命令进行解压。
xz -d linux-5.0.1.tar.xz tara -xvf linux-5.0.1.tar cd linux-5.0.1
接下来安装内核编译工具.
sudo apt install build-essential flex bison libeel-dev libelf-dev libncurses-dev
配置编译内核
make defconfig #按照默认值生成
接下来通过QEMU虚拟机加载内核
sudo apt install qemu qemu-system-i386 -kernel linux-5.0.1/arch/x86/boot/bzImage #make i386_defconfig qemu-system-x86_64 -kernel linux-5.0.1/arch/x86_64/boot/bzImage
构造MenuOS
git clone https://github.com/mengning/menu.git cd menu sudo apt-get install libc6-dev-i386 make rootfs cd .. qemu-system-i386 -kernel linux-5.0.1/arch/x86/boot/bzImage -initrd rootfs.img #makei386_defconfig qemu-system-x86_64 -kernel linux-5.0.1/arch/x86_64/boot/bzImage -initrd
如果是在自己的Ubuntu下构造MenuOS大概就是以上过程了,在这里为了简化实验过程。我选择了在实验楼环境下进行操作,因为这个环境下的Linux内核文件都已经下载配置完成了,所以就方便的多。实验楼的环境Linux的版本是3.18.6
在实验楼构建MenuOS
1.首先打开一个终端,进入LinuxKernel文件夹。
cd LinuxKernel
2.接下来就构造一个MenuOS
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img
3.验证我们的MenuOS是否能够正常工作。这里我们把hello/hi聊天程序从github上clone到本地来康康。
git clone https://github.com/mengning/linuxnet.git
通过图片我们可以看出TCP客户端和服务器正常工作。
4.然后重新打开一个终端进入gdb调试的过程,在qemu上启动gdb server。
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
这个命令执行完了过后,就可以让CPU停止在启动的那一刻,此时qemu在等待gdb的连接。
其中-S的意思是让系统启动的时候冻结CPU,按c键就可以继续执行。
-s的意思是打开远程调试端口,这里默认用的1234端口。
5.这个时候再重新打开一个终端进入gdb调试阶段,这里注意,这个冻结的CPU千万别关了,不然待会儿的1234端口连接不上的。在这个gdb中运行下面的命令:
file linux-3.18.6/vmlinux target remote:1234
其中file linux-3.18.6/vmlinux是用来记载Linux中的符号表,target remote:1234则可以建立gdb和gdbserver之间的连接。
6.在gdb界面中设置断点,这里断点的设置可以在target remote之前,也可以在之后。在设置好start_kernel处断点并且target remote之后可以继续运行,在运行到start_kernel的时候会停下来,等到gdb调试命令的输入,可以使用list来显示断点处的源代码。这里我们可以看到start_kernel在501行。
内核代码分析
我们把start_kernel的代码拿出来看看
asmlinkage __visible void __init start_kernel(void) { char *command_line; char *after_dashes; ? /* * Need to run as early as possible, to initialize the * lockdep hash: */ lockdep_init(); set_task_stack_end_magic(&init_task); smp_setup_processor_id(); debug_objects_early_init(); ? /* * Set up the the initial canary ASAP: */ boot_init_stack_canary(); ? cgroup_init_early();
内核的初始化程序在start_kernel这个函数中,通过阅读start_kernel代码,可以大致了解到内核在初始化的时候,大概的过程:首先通过lockdep_init()初始化内核依赖关系表,检查互斥机制的死锁问题。然后调用init_task,手工创建一个0号进程。通过smp_setup_processor_id()来获取CPU的硬件ID。boot_init_stack_canary()为栈增加保护机制,预防一些缓冲区溢出之类的攻击。总而言之,start_kernel就是进行了一系列的初始化工作。