中断、异常和系统调用(2-1,2-2,2-3)

2-1 课堂练习2.1:外部中断

本实训分析 Linux 0.11 对外部中断的响应和处理过程。在每条指令执行的末尾,如果没有关中断,CPU 会检查是否收到了外部中断信号,如果有信号,则 CPU 就切换到核心态去执行对应的中断处理程序,在处理完毕后,会执行 iret 这个中断返回指令,回到原状态(一般是用户态),继续执行原程序。

第1关时钟中断的发生

任务描述

 本关任务:通过实际操作回答在输出第一行 0/1 字符的过程中(如下图所示),共发生了几次时钟中断?

相关知识

为了完成本关任务,你需要掌握: 1.设置版本 1 内核为分析对象; 2.开始用 gdb 调试内核; 3.跟踪分析时钟中断。

设置版本1内核为分析对象

首先解压版本1内核源码。使用cp命令将/data/workspace/myshixun/exp1中的1.tgz复制到~/os/目录下;

切换到~/os/linux-0.11-lab目录下,将1.tgz解压到当前目录下;

然后调整cur的指向。先使用rm -rf curcur删除,再使用ln命令创建符号链接。

现在可以编译和测试版本 1 内核。首先进入1/linux目录下编译内核;

确认内核映像文件Image已经生成;

然后回到目录~/os/linux-0.11-lab,并使用./run启动虚拟机检测内核是否正常;

如果正常虚拟机在加载完毕之后将会出现如下画面。

第2关第一次时钟中断

 任务描述

分析版本1内核,找到第一次时钟中断的恢复点地址。

相关知识

为了完成本关任务,你需要掌握: 1.用 gdb 调试内核; 2.跟踪分析时钟中断; 3.中断/异常的恢复点分析。

准备阶段

本关卡的分析对象是版本1内核,可以基于前一关卡环境进行后续实验,如果重置实验环境则需要重新将版本1内核设置为分析对象,详见第一关的相关知识。

使用 gdb 调试内核

启动两个终端,在一个终端里切换到目录~/os/linux-0.11-lab,然后运行脚本 rungdb,以启动 bochs 虚拟机并等待 gdb 连接;

在另一个终端里切换到目录~/os/linux-0.11-lab,然后执行脚本./mygdb,以启动 gdb 并读入符号信息,跟踪到 main 函数入口。

跟踪分析时钟中断

在函数 do_timer(由时钟中断的处理函数 timer_interrupt 调用)处设置断点; 跟踪到该断点第 1 次出现;

中断/异常的恢复点分析

当一个中断/异常被 gdb 捕获时,通常正在运行中断处理程序,这时可以继续跟踪,直至回到恢复点指令。以时钟中断为例,为了从函数 do_timer 跟踪到恢复点,可以如下操作:

由上图可见时钟中断处理程序的入口是 timer_interrupt 函数。 跟踪到当前函数(do_timer)执行完毕返回到 timer_interrupt 函数;

跟踪到 timer_interrupt 函数(用汇编语言写的)末尾的 iret 指令;

通过单步执行命令 si 来执行该 iret 指令,返回到恢复点;

再通过反汇编命令:disas ,分析恢复点指令的地址。

关闭 gdb 调试: 在评测通关之后为了保证环境的正常,不影响下一关的操作,需要先输入 kill 指令关闭虚拟机,然后输入 quit 退出 gdb 调试。

答案

第3关第六次时钟中断

 任务描述

本关任务:通过相关知识以及实验回答:版本 1 内核的第 6 次时钟中断发生时,断点和恢复点(指令地址)分别是多少?此时 bochs 虚拟机输出的 0/1 字符串是什么?(忽略空格)

相关知识

为了完成本关任务,你需要掌握: 1.使用 gdb 调试内核; 2.跟踪分析时钟中断。

准备阶段

本关卡基于前面关卡环境进行后续实验,如果重置实验环境请从第一关重新开始。

使用 gdb 调试内核

启动两个终端,在一个终端里切换到目录~/os/linux-0.11-lab,然后运行脚本 rungdb,以启动 bochs 虚拟机并等待 gdb 连接;

在另一个终端里切换到目录~/os/linux-0.11-lab,然后执行脚本./mygdb,以启动 gdb 并读入符号信息,跟踪到 main 函数入口。

跟踪分析时钟中断

开始用 gdb 调试内核,跟踪到 main 函数入口。方法与第 1 关的步骤(2)一样。 (点击右下角上一关可以直接查看上一关内容,不会对关卡造成影响,但是不要点击评测,会改变环境)

捕获第 6 次时钟中断的发生

方法与第 2 关的步骤(3)类似,跟踪到断点 do_timer 第 6 次出现时即可,此时 jiffies 的值也是 6 。

中断/异常的恢复点分析

当一个中断/异常被 gdb 捕获时,通常正在运行中断处理程序,这时可以继续跟踪,直至回到恢复点指令。以时钟中断为例,为了从函数 do_timer 跟踪到恢复点,可以类似如下操作:

由上图可见时钟中断处理程序的入口是 timer_interrupt 函数。 跟踪到当前函数(do_timer)执行完毕返回到 timer_interrupt 函数;

跟踪到 timer_interrupt 函数(用汇编语言写的)末尾的 iret 指令;

使用调试命令 si 来执行该 iret 指令,返回到恢复点;

然后通过反汇编命令:disas ,来分析恢复点指令的地址。

断点指令和恢复点指令的分析

对于外部中断而言,恢复点指令是断点指令的后一条。需要说明的是,loop 指令的功能是先将 ecx 寄存器减一,然后检查其值,如果其值非 0 ,则继续循环,否则中止循环,执行下一条指令。以如下指令为例:

其功能是:在地址 0x7977 处循环,每次 ecx 寄存器都减一,直到其值为 0 。因此,loop 指令的上一条有可能是它自己。 在 gdb 中查看寄存器值的命令是 info reg:

断点指令和恢复点指令的分析

对于外部中断而言,恢复点指令是断点指令的后一条。需要说明的是,loop 指令的功能是先将 ecx 寄存器减一,然后检查其值,如果其值非 0 ,则继续循环,否则中止循环,执行下一条指令。以如下指令为例:

其功能是:在地址 0x7977 处循环,每次 ecx 寄存器都减一,直到其值为 0 。因此,loop 指令的上一条有可能是它自己。 在 gdb 中查看寄存器值的命令是 info reg:

答案

 

2-2 课后作业2.1:外部中断

第1关修改版本 1 内核源码,使得每次时钟中断发生时,都在屏幕上输出字符 ‘t’

任务描述

本关任务:修改版本 0 内核,使得每发生 100 次时钟中断,就在屏幕上输出一个字符‘t’和当时的进程号,如“t(0)”表示0号进程运行时发生了时钟中断。

相关知识

为了完成本关任务,你需要掌握: 1.内核态下的字符输出; 2.判断已经发生了多少次时钟中断。

内核态下的字符输出

在版本 0 内核里,可以使用函数printk来输出字符,其用法类似于printf注: 在版本 0 内核中,没有实现用int 0x81指令输出字符这个功能。

printk用法示例:

  1. printk("trying to free inode with count=%d\n",inode->i_count);
判断已经发生了多少次时钟中断

已经发生的时钟中断的次数记录在全局变量 jiffies 中,每发生一次时钟中断,该变量的值就增加 1 。

编程要求

根据相关知识,以及上课内容,对版本 0 内核进行修改,使得每发生 100 次时钟中断,就在屏幕上输出一个字符‘t’和当时的进程号。

,

使用VScode打开1/linux文件夹,获取版本1内核源代码 

在timer_interrupt函数开头添加输出字符t的汇编代码:

movb $116, %al
int $0x81

回到命令行中重新编译1/linux,再启动./rungdb和./mygdb虚拟机即可过关

第2关修改版本 0 内核

任务描述

本关任务:修改版本 0 内核,使得每发生 100 次时钟中断,就在屏幕上输出一个字符‘t’和当时的进程号,如“t(0)”表示0号进程运行时发生了时钟中断。

相关知识

为了完成本关任务,你需要掌握: 1.内核态下的字符输出; 2.判断已经发生了多少次时钟中断。

内核态下的字符输出

在版本 0 内核里,可以使用函数printk来输出字符,其用法类似于printf注: 在版本 0 内核中,没有实现用int 0x81指令输出字符这个功能。

printk用法示例:

  1. printk("trying to free inode with count=%d\n",inode->i_count);
判断已经发生了多少次时钟中断

已经发生的时钟中断的次数记录在全局变量 jiffies 中,每发生一次时钟中断,该变量的值就增加 1 。

编程要求

根据相关知识,以及上课内容,对版本 0 内核进行修改,使得每发生 100 次时钟中断,就在屏幕上输出一个字符‘t’和当时的进程号。

,

通过vscode找到do_timer

 在函数中添加

if(jiffies%100==0)
prink("t(%d),sys_getpid());

2-3 课堂练习2.2:中断/异常的处理过程


第1关除零异常分析

任务描述

分析版本 1.1 内核,回答下列问题: 1.在函数 main 的语句jiffies = jiffies/0;所对应的汇编指令片段中,有一个 idiv 指令,此指令的地址是多少? 2.在该 idiv 指令执行之前,当前指令位置(CS:EIP)和栈位置(SS:ESP)分别是多少? 3.使用 si 命令执行了该指令后,新指令位置和栈位置分别是多少?此时栈中保存的恢复点位置和用户栈位置分别是多少?

相关知识

为了完成本关任务,你需要掌握: 1.如何设置某版本的内核为分析对象; 2.如何开始用 gdb 调试内核; 3.查看 C 语句编译之后对应的汇编指令片段; 4.分析响应中断/异常时,CPU 做了哪些工作; 5.查看当前寄存器的状态; 6.查看当前栈顶的状态。

实验准备

本关卡使用版本 1.1 内核作为分析对象,内核文件存放在/data/workspace/myshixun/exp1文件夹中,可以将其解压到linux-0.11-lab下使用。

如何设置某版本的内核为分析对象

下面以版本1内核为例进行讲解。

首先解压版本1内核源码。使用cp命令将/data/workspace/myshixun/exp1中的1.1.tgz复制到~/os/目录下;

切换到~/os/linux-0.11-lab目录下,将1.1.tgz解压到当前目录下;

然后调整cur的指向。先使用rm -rf curcur删除,再使用ln命令创建符号链接。

如何开始用 gdb 调试内核

先关闭bochs虚拟机,然后打开两个终端,其中一个终端在linux-0.11-lab目录下运行rungdb脚本,以启动 bochs 虚拟机并等待 gdb 连接;

在另一个终端里切换到目录~/os/linux-0.11-lab/,然后启动脚本./mygdb,这个命令会启动 gdb 并读入内核符号信息,同时会通过执行0.gdb中的调试命令来连接到 bochs 虚拟机,并进而跟踪到 main 函数入口。

查看 C 语句编译之后对应的汇编指令片段

如果要查看某条 C 语句编译之后对应的汇编指令片段,可以在该 C 语句处设置断点,并跟踪到该断点,然后反汇编,所看到的当前指令之后的一段汇编指令就对应于该 C 语句。

例如,jiffies = jiffies/0;是文件 main.c 的第 147 行,可以如下方式查看:

上面显示的汇编指令中,有一行前面有箭头标识,此即为当前指令,即马上将要执行的指令。

分析响应中断/异常时,CPU 做了哪些工作
  • 切换到核心栈,并在其中保存中断现场。

  • 转到中断处理程序去运行,并切换到核心态。

如下图所示:

上图显示了栈中中断现场的结构,(OLD SS:OLD ESP) 描述了用户栈顶的位置,(OLD CS:OLD EIP) 描述了恢复点的位置。

如何查看当前寄存器的状态

使用 gdb 调试命令 info registers 即可,如下所示:

也可以单独查看某一个寄存器:

如何查看当前栈顶的状态

可以使用命令 x 来查看:

上面显示了栈顶的 5 个长字,是某异常发生时的中断现场,其中存储的用户栈顶的位置是 0x17:0x2573c ,存储的恢复点的位置是 0xf:0x7967 。需要注意的是,x86 中栈是从高地址向低地址方向增长的,这里的栈顶位置是 0x1fa0c 。

编程要求

根据相关知识,回答问题:(将答案填写在/data/workspace/myshixun/第一关.txt中) 1.在函数 main 的语句jiffies = jiffies/0;所对应的汇编指令片段中,有一个 idiv 指令,此指令的地址是多少? 2.在该 idiv 指令执行之前,当前指令位置(CS:EIP)和栈位置(SS:ESP)分别是多少? 3.使用 si 命令执行了该指令后,新指令位置和栈位置分别是多少?此时栈中保存的恢复点位置和用户栈位置分别是多少?

答案

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/258796.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

推荐5款让人安心的软件,大胆分享给别人吧

​ 今天我要分享五款神器软件,它们都是各领域的佼佼者,能让你的生活和工作更好。请大家放心地用它们,也告诉别人它们的好处。请看下面的介绍吧。 1.文件加密——Cryptomator ​ Cryptomator是一款文件加密软件,可以让用户对文件…

中伟视界:皮带跑偏、异物检测AI算法除了矿山行业应用,还能在钢铁、火电、港口等行业中使用吗?

随着工业化的发展,皮带输送机已经成为各行业中不可或缺的重要设备,但是在使用过程中,由于各种原因,皮带常常出现跑偏问题,给生产运营带来了诸多困扰。不仅仅是矿山行业,钢铁、火电、港口等行业也都面临着皮…

Web前端 ---- 【Vue】Vuex的使用(辅助函数、模块化开发)

目录 前言 Vuex是什么 Vuex的配置 安装vuex 配置vuex文件 Vuex核心对象 actions mutations getters state Vuex在vue中的使用 辅助函数 Vuex模块化开发 前言 本文介绍一种新的用于组件传值的插件 —— vuex Vuex是什么 Vuex 是一个专为 Vue.js 应用程序开发的状态…

SQL Server——权限管理

一。SQL Server的安全机制 SQL Server 的安全性是建立在认证和访问许可两种安全机制之上的。其中.认证用来确定登录Sal Server 的用户的登录账户和密码是否正确.以此来验证其是否具有连接SQL Server 的权限;访问许可用来授予用户或组能够在数据库中执行哪…

C语言精选——选择题Day39

第一题 1. 有下面的定义,则 sizeof(s) 为多少? char *s "\ta\017bc"; A:9 B:5 C:6 D:7 答案及解析 C 本题涉及到了转义字符 \t 是水平制表符,算一个字节 \017 是表示八进制数&#…

整合消息队列RabbitMQ

为什么使用消息队列MQ? 因为使用消息队列有多个好处:可以实现系统服务的解耦、异步和削峰: 异步通信:消息队列提供了一种异步通信的方式,发送方可以将消息发送到队列中,然后继续执行其他任务,…

《Linux源码趣读》| 好书推荐

目录 一. 🦁 前言二. 🦁 像小说一样趣读 Linux 源码三. 🦁 学习路线 一. 🦁 前言 最近、道然科技给狮子送了两本书:一本是付东来的《labuladong的算法笔记》、一本是闪客著的《Linux源码趣读》,《labulado…

基于AIS数据的船舶密度计算与规律研究

参考文献:[1]陈晓. 基于AIS数据的船舶密度计算与规律研究[D].大连海事大学,2021.DOI:10.26989/d.cnki.gdlhu.2020.001129. 谢谢姐姐的文章! 网格化AIS数据 网格化 AIS 数据是处理和分析船舶轨迹数据的一种有效方法,特别是当涉及到密度计算和…

unity3d摄像机和观察对象坐标轴修正

让摄像机与观察对象在场景层级并列,以世界坐标看齐 ,在local模式,只调整模型或者摄像机方向

案例063:基于微信小程序的传染病防控宣传系统

文末获取源码 开发语言:Java 框架:springboot JDK版本:JDK1.8 数据库:mysql 5.7 开发软件:eclipse/myeclipse/idea Maven包:Maven3.5.4 小程序框架:uniapp 小程序开发软件:HBuilder …

多线程并发Ping脚本

1. 前言 最近需要ping地址,还是挺多的,就使用python搞一个ping脚本,记录一下,以免丢失了。 2. 脚本介绍 首先检查是否存在True.txt或False.txt文件,并在用户确认后进行删除,然后从IP.txt的文件中读取IP地…

docker的资源控制

docker容器的资源控制 Docker通过Cgroup 来控制容器使用的资源配额,包括CPU、内存、磁盘三大方面,基本覆盖了常见的资源配额和使用量控制。Cgroup 是ControlGroups的缩写,是Linux 内核提供的一种可以限制、记录、隔离进程组所使用的物理资源(…