第五周 扒开系统调用的三层皮(下)

  • 给MenuOS增加time和time-asm命令

更新menu代码到最新版

在main函数中增加MenuConfig

增加对应的Time函数和TimeAsm函数

make rootfs

  • 使用gdb跟踪系统调用内核函数sys_time

一直按n单步执行会进入schedule函数

sys_time返回后进入汇编代码处理gdb无法继续跟踪

执行int 0x80之后执行system_call对应的代码

  • 系统调用在内核代码中的处理过程

1.系统调用在内核代码中的工作机制和初始化

2.系统调用机制的初始化

3.中断上下文的切换和进程上下文的切换

  • 实验:使用gdb跟踪分析一个系统调用内核函数

1.运行MenuOS系统

在实验楼的虚拟机环境里,打击打开shell,使用命令

cd LinuxKernel/

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

即可启动这个用于实验的Linux系统MenuOS,实际上就是一个在Linux内核的基础上,再运行一个简单菜单命令行程序。我们可在MenuOS>的提示符下输入help,看到其全部支持的命令.

2.调试运行

1)使用带参数命令启动MenuOS

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)

-s shorthand for -gdb tcp::1234 若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项

也就是在启动MenuOS系统的时候,添加了-S和-s这两个参数,这样可以使得系统在刚刚启动的时候,暂停执行。以便等待我们调试器跟踪执行。

2)启动gdb,设置断点,运行

在shell窗口上,右键单击,选择水平分割,在分割出的新的窗口中,输入gdb,在出现gdb提示符后,加载符号文件

(gdb)file linux-3.18.6/vmlinux

建立和被调试程序的连接

(gdb)target remote:1234

在start_kernel函数入口处设置断点

(gdb)break start_kernel

继续输入c,使得系统运行到start_kernel处停住

(gdb)c

在gdb下,使用list,列出断点附近的源代码,使用n,单步执行等命令,从而可以详细的跟踪到Linux系统启动的过程。

gdb调试常用参数

  • r(run)            :    开始运行程序;
  • c(continue)  :    继续运行一直到断点停止
  • b(break)       :   设置程序断点;
  • p(print)         :    打印出变量值;如 p var,会把var变量的值输出
  • s(step)         :    单步跟踪,会进入函数内部
  • n(next)         :    单步跟踪,不进入函数
  • finish           :     跳出函数调试,并打印返回时的信息
  • u(until)        :     跳出循环体
  • q(quit)         :     退出gdb
  • l(list)            :     显示当前行后面的源程序
  • bt (backtrace)   :     查看堆栈信息
  • info              :      查看各类gdb信息以及环境信息,比如:info break 可以查看断点信息
  • clear            :       清除全部已定义的断点
  • delete         :       删除指点的断点号,后面接断点号

3. 总结

start_kernel()是内核的汇编与C语言的交接点,在该函数以前,内核的代码都是用汇编写的,完成一些最基本的初始化与环境设置工作。start_kernel就像是c代码中的main函数。不管你关注Linux的内核模块,总是离不开start_kernel函数的,因为大部分模块的初始化工作都是在start_kernel中完成的。在start_kernel()中Linux将完成整个系统的内核初始化,因此start_kernel函数也比较复杂,好在我们只需要关注自己感兴趣的部分即可。内核初始化的最后一步就是启动init进程这个所有进程的祖先。

在start_kernel的最后,是调用rest_init函数,在rest_init函数,内核将使用下面的代码产生第一个真正的进程,即pid=1的1号进程,而init_task是静态制造出来的,pid=0,我们可以在start_kernel函数的开始处,看到其被初始化的代码 。

它试图将从最早的汇编代码一直到start_kernel的执行都纳入到init_task进程上下文中,在其初始化工作完成后,就会成为系统的idle进程。事实上在更早前的sched_init函数中,通过init_idle(current, smp_processor_id())函数的调用就已经把init_task初始化成了一个idle task,init_idle函数的第一个参数current就是&init_task,在init_idle中将会把init_task加入到cpu的运行队列中,这样当运行队列中没有别的就绪进程时,init_task(也就是idle task)将会被调用,它的核心是一个while(1)循环,在循环中它将会调用schedule函数以便在运行队列中有新进程加入时切换到该新进程上。

  • 流程图

  • 实验总结

系统通过 int 0x80从用户态进入内核态,在这个过程中系统先保存了中断环境,然后执行系统调用函数。system_call() 函数通过系统调用号查找系统调用表 sys_cal_table 来查找到具体的系统调用服务进程。在执行完系统调用后在执行 iret 之前,内核做了一系列检查,用于检查是否有新的中断产生。如果没有新的中断,则通过已保存的系统中断环境返回用户态。这样就完成了一个系统调用过程。

时间: 2024-10-05 18:04:57

第五周 扒开系统调用的三层皮(下)的相关文章

linux内核分析 第五周 扒开系统调用的三层皮(下)

rm menu -rf 强制删除原menu文件 git clone http://github.com/mengning/menu.git 从github中克隆 cd menu 在test.c中增加上周编写的两个函数:Getpid()和GetpidAsm(),修改test.c中的main函数,添加两行代码MenuConfig make rootfs这一步之后会打开menu,输入help后可以看到当前的系统调用: 分别执行刚加进去的两个系统调用: 插入断点进行调试: 从system_call开始到

20135201李辰希 《Linux内核分析》第五周 扒开系统调用的“三层皮”(下)

李辰希  原创作品转载请注明出处 <Linux内核分析> MOOC课程http://mooc.study.163.com/course/USTC-100002900 一.给MenusOS增加time和time-asm命令 1.操作步骤 进入实验楼 首先,强制删除当前的menu 克隆一个新的menu 进入menu之后,输入make rootfs,就可以自动编译 输入help,可以发现系统支持更多的命令: help version quit time time-asm 那么,time和time-a

Linux内核及分析 第五周 扒开系统调用的三层皮(下)

实验内容: 1.执行rm menu -rf命令,强制删除原有的menu 2.使用git命令 git clone https://github.com/mengning/menu.git 克隆新的menu 3.在test.c中,在main函数中增加两个MenuConfig 4.增加对应的GetPid函数和GetPidAsm函数 5.通过脚本 make rootfs,编译并运行Menu 6.设置断点使用gdb跟增系统调用内核函数sys_time 系统调用是一种中断: 1. 保存现场 在系统调用时,我

实验五:扒开系统调用的三层皮(下)

实验五:扒开系统调用的三层皮(下) 王朝宪20135114 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.给MenuOS增加time和time-asm命令 1. 通过内核的方式(跟踪调试系统调用)来理解并使用系统调用. rm menu -rf //强制删除当前menu git clone http://github.com/mengning/menu.git //重新克隆新版本的m

《Linux内核分析》 第五节 扒开系统调用的三层皮(下)

摘要:范闻泽 原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 1.实验环境是使用本课程配置的实验楼虚拟机环境,打开命令行客户端,cd LinuxKernel目录,使用命令rm -rf menu 删除原来的代码,使用git clone https://github.com/mengning/menu.git获取menu的最新代码,然后cd menu进入menu子文件夹,使用vi test.c

第四周—扒开系统调用的“三层皮”

[洪韶武 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ]  第四周 扒开系统调用的“三层皮” 一.本周学习内容总结   1.系统调用的“三层皮” xyz函数—API systemcall—中断向量 sysxyz—中断服务程序 2.系统调用的意义及API与系统调用的关系 (1)系统调用的意义: 把用户从底层的硬件编程中解放出来 极大提高了系统安全性 使用户程序具有可移植性 (2)API

20135327郭皓--Linux内核分析第四周 扒开系统调用的三层皮(上)

Linux内核分析第四周 扒开系统调用的三层皮(上) 郭皓 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 一.用户态.内核态和中断 用户态:当进程在执行用户自己的代码时,则称其处于用户态,即此时处理器在特权级最低的(3级)用户代码中运行. 内核态:当一个进程执行系统调用而陷入内核代码中执行时,我们就称进程处于内核态,此时处理器处于特权级最高的(0级)内核代码中执行. PS:CPU指令

《Linux内核分析》第四周 扒开系统调用的“三层皮”

[刘蔚然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] WEEK FOUR(3.14——3.20)扒开系统调用的“三层皮” SECTION 1 用户态.内核态和中断处理过程 1.用户态.内核态区别 在高级别的状态下,代码可以执行特权指令,访问任意的物理地址: 在相应的低级别执行状态下,代码的掌控范围会受到限制. 为什么会有这种级别划分? 没有访问权限划分容易使得系统混乱(毕竟普通程序

《Linux内核分析》第四周笔记 扒开系统调用的三层皮(上)

扒开系统调用的三层皮(上) 一.用户态.内核态和中断 库函数将系统调用封装起来. 1.什么是用户态和内核态 一般现代CPU都有几种不同的指令执行级别. 在高执行级别下,代码可以执行特权指令,访问任意的物理地址,这种CPU执行级别就对应着内核态. 而在相应的低级别执行状态下(用户态),代码的掌控范围会受到限制.只能在对应级别允许的范围内活动.系统容易崩溃. 在intel X86CPU有四种不同的执行级别0,1,2,3,linux只使用了0级和3级分别来表示内核态和用户态. 2.在linux内核代码