构建调试Linux内核网络代码的环境MenuOS系统

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

构建调试Linux内核网络代码的环境MenuOS系统

3.验证我们的MenuOS是否能够正常工作。这里我们把hello/hi聊天程序从github上clone到本地来康康。

git clone https://github.com/mengning/linuxnet.git

构建调试Linux内核网络代码的环境MenuOS系统

构建调试Linux内核网络代码的环境MenuOS系统

构建调试Linux内核网络代码的环境MenuOS系统

通过图片我们可以看出TCP客户端和服务器正常工作。

4.然后重新打开一个终端进入gdb调试的过程,在qemu上启动gdb server。

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S

构建调试Linux内核网络代码的环境MenuOS系统

这个命令执行完了过后,就可以让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之间的连接。

构建调试Linux内核网络代码的环境MenuOS系统

6.在gdb界面中设置断点,这里断点的设置可以在target remote之前,也可以在之后。在设置好start_kernel处断点并且target remote之后可以继续运行,在运行到start_kernel的时候会停下来,等到gdb调试命令的输入,可以使用list来显示断点处的源代码。这里我们可以看到start_kernel在501行。

构建调试Linux内核网络代码的环境MenuOS系统

构建调试Linux内核网络代码的环境MenuOS系统

内核代码分析

我们把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就是进行了一系列的初始化工作。

相关推荐