Chinaunix首页 | 论坛 | 博客
  • 博客访问: 149770
  • 博文数量: 24
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 225
  • 用 户 组: 普通用户
  • 注册时间: 2014-08-09 13:04
个人简介

人若是没有理想,那跟咸鱼有什么区别!

文章分类

全部博文(24)

文章存档

2018年(1)

2017年(2)

2016年(8)

2015年(11)

2014年(2)

我的朋友

分类: LINUX

2016-03-13 22:32:11

一.搭建Linux内核编译、阅读环境。
    1.下载内核源码:
    wget 
    xz -d linux-3.18.28.tar.xz
    tar-xvf linux-3.18.28.tar
    cd linux-3.18.28
    make i386_defconfig
    make  menuconfig  -> kernel hacking—>[*] compile the kernel with debug info  //这样会在内核调试阶段加入debug信息。
    make # 一般要编译很长时间,少则20分钟多则数小时
    有的系统可能出现:curses.h: No such file or directory  这个错误,这个是因为本机开启menuconfig界面时,需要creses字符库的支持,所以只需要在本机上安装库就可以了,我使用的是Ubuntu10.04,安装命令为:apt-get install libncurses5-dev

    2.制作文件系统
    # 制作根文件系统
    
mkdir rootfs
    
git clone  
    cd menu
    gcc -o init linktable.c menu.c test.c -m32 -static –lpthread
    cd ../rootfs
    cp ../menu/init ./
    find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img

    3.运行内核
        qemu -kernel linux-3.18.28/arch/x86/boot/bzImage -initrd rootfs.img
    这时可以看到运行起来的menuos界面,并且通过 help命令可以查看支持的其他命令。



    4.使用vim搭建代码阅读环境,这个可以参考其他文档资料,我使用的是ctag+vim,参考来源为:http://blog.chinaunix.net/uid-22891435-id-380187.html

   二.使用gdb跟踪内核代码
    1.内核启动时的参数:
    qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S # 关于-s和-S选项的说明:
    # -S freeze CPU at startup (use ’c’ to start execution)冻结cpu
    # -s shorthand for -gdb tcp::1234 若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项
    2.gdb启动参数:
    gdb
    (gdb)file linux-3.18.6/vmlinux # 在gdb界面中targe remote之前加载符号表
    (gdb)target remote:1234 # 建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行
    (gdb)break start_kernel # 断点的设置可以在target remote之前,也可以在之后
运行起来的效果图就如上面,区别在于,我们可以通过gdb添加断点来调试内核,跟踪内核的启动流程。
    a.我们添加第一个断点:
    在gdb中输入如下:break start_kernel        #break也可以使用单个字符 b 来代替
    然后 输入  continue        #continue 可以使用 单个字符 c 来代替
    进入如下打印片段,这是qemu已经进入了内核启动的开始阶段。

点击(此处)折叠或打开

  1. Breakpoint 1, start_kernel () at init/main.c:501
  2. 501    {
  3. (gdb)
    我们可以进入init/main.c 501行,可以看到很多初始化函数,下面只列举几个函数:
    

点击(此处)折叠或打开

  1. void set_task_stack_end_magic(struct task_struct *tsk)    //这个表示对任务列表进行初始化
  2.  {
  3.          unsigned long *stackend;
  4.  
  5.          stackend = end_of_stack(tsk);
  6.          *stackend = STACK_END_MAGIC; /* for overflow detection */
  7.  }
    在main.c中的调用为:

点击(此处)折叠或打开

  1. set_task_stack_end_magic(&init_task);   //对task进行初始化

点击(此处)折叠或打开

  1. void __init trap_init(void);    //完成硬件中断初始化
  2. mm_init();    //内存管理初始化
  3.  /*
     * Set up the scheduler prior starting any interrupts (such as the
     * timer interrupt). Full topology setup happens at smp_init()
     * time - but meanwhile we still have a functioning scheduler.
     */
      sched_init();    //如上所述,完成进程调度管理的初始化
  4. init_IRQ();    //初始化中断处理
  5. /*
    1. 从rest_init开始,Linux开始产生进程,因为init_task是静态制造出来的,pid=0,它试图将从最早的汇编代码一直到start_kernel的执行都纳入到init_task进程上下文中。在rest_init函数中,内核将通过下面的代码产生第一个真正的进程(pid=1):
    2. */
  6. rest_init();    
    rest_init();函数结束后,整个内核就开始了。


作者程大鹏, 转载请注明出处    http://blog.chinaunix.net/blog/post.html
Linux内核分析》MOOC课程 ”



阅读(2301) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~