zoukankan      html  css  js  c++  java
  • 构建调试Linux内核网络代码的环境MenuOS系统

             该实验是基于Ubuntu18.0.4和Linux5.0.1完成的  

          一、安装,编译Linux内核

            1.1下载内核源代码

    mkdir LinuxKernel  #创建LinuxKernel根目录
    cd ~/LinuxKernel/
    wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.0.1.tar.xz #下载Linux内核,这里用的是5.0.1版本
    xz -d linux-5.0.1.tar.xz #解压
    tar -xvf linux-5.0.1.tar
    cd linux-5.0.1

            1.2安装依赖包

    #如果已经安装过就忽略这一步
    sudo apt-get install build-essential sudo apt-get install libelf-dev sudo apt-get install libncurses-dev sudo apt-get install flex sudo apt-get install bison
    sudo apt-get install libssl-dev

           1.3配置编译需要的信息

    #进入解压出来的目录
    cd /linux-5.0.1/
    #使用现存内核的配置文件:(xxx处使用TAB补全)
    sudo cp /boot/config-xxx -r .config
    #应用现存配置文件
    sudo make oldconfig
    #仅安装已有module
    sudo make localmodconfig
    #配置其他编译选项
    sudo make menuconfig
    #这个地方可能会报错
    Your display is too small to run Menuconfig!
    It must be at least 19 lines by 80 columns.
    make[1]: *** [menuconfig] Error 1
    make: *** [menuconfig] Error 2
    这里需要点击Terminal->Preferences->Unnamed,然后将Initial terminal size,columns的数值增大,然后重新打开终端,执行命令

                                   

         接着会出现以下界面,依次选择 Kernel hacking ->Compile-time checks and compiler options ->[ ]Compile the kernel with debug info 

    然后按Y键,选择 Save ,选择Exit直到退出。

    1.4 编译

    sudo make
    #或者使用sudo make -j*,*位cpu核数

         然后就等待编译完成,时间取决于机器性能,一般需要20分钟到数小时

    1.5 升级内核

    #安装modules
    sudo make modules_install
    #安装
    sudo make install
    #重启虚拟机
    sudo shutdown -r now
    #查看内核版本
    uname -a

         可以看到内核已经更新为Linux 5.0.1

           二、制作根文件目录

    2.1 QEMU虚拟机加载内核

    cd ~/LinuxKernel/
    sudo apt install qemu#安装qemu命令
    qemu-system-x86_64 -kernel linux-5.0.1/arch/x86_64/boot/bzImage

    2.2 构造MenuOS

    #创建MenuOS根目录
    mkdir rootfs
    #下载MenuOS
    git clone https://github.com/mengning/menu.git

      这里如果git clone的速度太慢,可以修改/etc/hosts/内容,再刷新DNS

    nslookup github.global.ssl.fastly.net
    nslookup github.com
    #这里会返回两个IP地址
    sudo vim/etc/hosts
    #按i进入插入模式,然后将xxxx
    github.global.ssl.fastly.net xxxx github.com
    添加至最后一行,然后按ESC,输入:wq!保存退出
    sudo /etc/init.d/networking restart
    #刷新DNS

    2.3 安装libc6-dev-i386并初始化根目录

    cd menu
    sudo apt-get install libc6-dev-i386#在64位环境下编译32位
    #注意在初始化根目录之前要修改Makefile的内容,因为实验楼的系统是Linux 3.18.6,这里要改为5.0.1,修改之后如下
    #qemu-system-x86_64 -kernel ../linux-5.0.1/arch/x86_64/boot/bzImage -initrd ../rootfs.img
    #注意在Makefile修改命令时开头需加上TAB键,否则会报错
    make rootfs

    得到结果如下,输入help可以看到当前MenuOS中有help,version,quit,time,time-asm等命令

    接下来需要验证MenuOS的网络可以正常工作,可以通过在MenuOS上完成TCP客户端和服务器发送和接收hello/hi

    2.4 验证MenuOS的网络

    2.4.1 将TCP网络通信程序的服务端集成到MenuOS 系统中

    cd ~/LinuxKernel/ 
    git clone https://github.com/mengning/linuxnet.git
    cd linuxnet/lab2
    make
    cd ../../menu/#这里要修改Makefile文件
    make rootfs

    2.4.2 将TCP网络通信程序的客户端集成到MenuOS系统中

    cd ~/LinuxKernel/
    cd linuxnet/lab3
    make rootfs#Make rootfs之前要修改Makefile
    #未修改之前qemu -kernel ../../linux-3.18.6/arch/x86/boot/bzImage -initrd ../rootfs.img
    #修改之后 qemu-system-x86_64 -kernel ../../linux-5.0.1/arch/x86/boot/bzImage -initrd ../rootfs.img

    现在可以得到以下结果,输入replyhi,输入hello,收到了hi,证明MenuOS的网络可以正常工作

          三、gdb调试

    3.1 重启QEMU

    cd ~/LinuxKernel/menu
    #先修改Makefile,在qemu-system-x86_64 -kernel ../linux-5.0.1/arch/x86_64/boot/bzImage -initrd ../rootfs.img
    #末尾加上-append nokaslr -s -S
    make rootfs

    结果如下

    3.2 连接gdb server并调试

        重新打开一个终端

    gdb
    file ~/LinuxKernel/linux-5.0.1/vmlinux
    target remote:1234
    #设置断点对start_kernel进行跟踪
    break start_kernel
    c #继续运行
    list#查看上下文

         结果如下

           

          结果显示gdb可以追踪到start_kernel函数,断点在init/mian.c的538行

         继续在rest_init处设置断点

    break rest_init
    c

             

            断点在init/mian.c的398行

           我们来简要分析一下运行到start_kernel()的过程,start_kernel()实际上是内核的汇编代码和c代码的交接处。

           截取一段start_kernel()的源码

    asmlinkage __visible void __init start_kernel(void)
    {
        char *command_line;
        char *after_dashes;
    
        set_task_stack_end_magic(&init_task);
    ...
    ...

      /* Do the rest non-__init'ed, we're now alive */
        arch_call_rest_init();
    }

         当程序运行到start_kernel()时:

          (1)手工通过 set_task_stack_end_magic(&init_task)创建0号进程,init_task是0号进程上下文信息的描述符,是内核中所有进程、线程

    的task_struct雏形,在内核初始化过程中,通过静态定义构造出了一个task_struct接口,取名为init_task,init_idle()函数会把init_task加入到

    cpu的运行队列中去,在没有其他进程加入cpu队列的时候,init_task会一直运行,当其他进程加入进来的时候,init_task就会被设置成idle,

    并使用调度函数将切换到新加入进来的进程上。

        (2)将内存管理模块、中断、调度模块等模块初始化。

        (3)start_kernrl函数运行到rest_init(),开始初始化进程并创建1号和2号进程。

            我们接着看一下rest_init的部分源码

    noinline void __ref rest_init(void)
    {
        struct task_struct *tsk;
        int pid;
        rcu_scheduler_starting();
        /*
         * We need to spawn init first so that it obtains pid 1, however
         * the init task will end up wanting to create kthreads, which, if
         * we schedule it before we create kthreadd, will OOPS.
         */
        pid = kernel_thread(kernel_init, NULL, CLONE_FS);
        rcu_read_lock();
        tsk = find_task_by_pid_ns(pid, &init_pid_ns);
        set_cpus_allowed_ptr(tsk, cpumask_of(smp_processor_id()));
        rcu_read_unlock();
        numa_default_policy();
        pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
        rcu_read_lock();
        kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
        rcu_read_unlock();
        system_state = SYSTEM_SCHEDULING;
        complete(&kthreadd_done);
        schedule_preempt_disabled();
        /* Call into cpu_idle with preempt disabled */
        cpu_startup_entry(CPUHP_ONLINE);
    }
    pid = kernel_thread(kernel_init, NULL, CLONE_FS)创建了1号进程
    pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES)创建了2号进程
    cpu_startup_entry(CPUHP_ONLINE)进行cpu队列进程的切换,将0号进程设置idle
    这就是Linux下的三个特殊进程
    0号进程由系统自动创建, 运行在内核态
    1号进程由idle通过kernel_thread创建,在内核空间完成初始化后, 加载init程序, 并最终在用户空间
    2号进程由idle通过kernel_thread创建,并始终运行在内核空间, 负责所有内核线程的调度和管理

    参考资料
    https://blog.csdn.net/gatieme/article/details/51484562
    https://github.com/mengning/net/tree/master/lab3

  • 相关阅读:
    opencv和linux的关联
    附加数据库 对于server XXX失败
    android.app.Dialog(23)里window的那些事(坑)
    hdu 4722 Good Numbers(数位dp)
    Java程序猿必知的10个调试技巧
    iir调试记录
    在Scope利用Content sharing Widget来分享内容
    JavaEE 技术选型建议,server配置,部署策略
    x265探索与研究(四):怎样编码视频?
    计算git树上随意两点的近期切割点。
  • 原文地址:https://www.cnblogs.com/ustc-kunkun/p/12002488.html
Copyright © 2011-2022 走看看