系统实验 (基于 xv6)
系统调用 (System Call) 是操作系统向用户程序暴露其核心功能的接口,用户程序只能通过系统调用 (以操作系用所允许的方式) 来向操作系统请求服务。 在本实验中,我们需要为 xv6 添加一个新的系统调用,以此来熟悉操作系统中系统调用的实现及其处理流程。
在进行本次实验之前,请先参考实验页面配置 xv6 的实验环境,并阅读 xv6 book 的 Chapter 2.2~2.3、以及 Chapter 4.1~4.4。
运行如下命令下载实验框架代码,并切换到 分支:
在本次实验中,我们需要为 xv6 实现一个新的系统调用 (Easy System Call Trace),该系统调用将激活对其调用者的 tracing,并打印追踪到的系统调用信息:
- 参数 指定要追踪的系统调用名称,如果有多个,使用 分隔 (例如 );如果该参数为 (即空指针),则默认追踪所有系统调用;
- 参数 指定是否追踪子进程产生的系统调用, 为追踪子进程, 为不追踪子进程;
- 调用成功时返回 ,失败时返回 。
基于上述系统调用,框架代码里提供了一个名为 的命令行工具,可在激活 tracing 的情况下执行给定的应用程序 (源代码见 )。该工具的使用方式为:
其中, 指定要追踪的单个系统调用名称 ,如不指定则默认追踪所有系统调用; 指定是否追踪子进程的系统调用,如果不指定,则默认不追踪子进程; 为要追踪的可执行程序。例如:
在 正确实现的情况下,在 xv6 的 Shell 中执行 时应能观察到如下的输出 (追踪到的每个系统调用都会打印系统调用 ID、相关参数、以及系统调用返回值):
当激活 tracing 后,对于进程随后产生的每一个系统调用,需要按如下格式进行打印 (注意不要缺少或增加空格):
其中, 为进程 ID, 为系统调用名称,、 等为系统调用的参数值, 为系统调用的返回值。
xv6 系统调用涉及的参数类型一共有五种 (空、整数、地址、字符串、文件描述符),不同参数类型分别按如下方式打印:
- 空参数:不打印,例如
- 整数参数:直接打印,例如
- 地址参数:按十六进制打印地址,例如
- 字符串参数:打印字符串,并添加引号,例如
- 中定义了打印参数的最大长度 ,如果字符串长度超过 ,则只打印字符串的前 个字符,并添加省略号
- 例如,对于 , 当 时打印 ;当 时打印
- 文件描述符参数:直接按整型打印文件描述符,例如
一些特殊的情况:
- 对于 系统调用,由于在执行该系统调用之后进程终止、且没有返回值,此时请使用半角问号 来代替返回值;
- 如果输入参数指定了不存在的系统调用,直接忽略即可。例如执行 不会打印任何信息。
在本实验中,对于追踪到的系统调用信息,只需要在 xv6 内核中直接用 进行打印即可,但需要考虑在哪个位置打印更合适。
你可以采用不同的实现方式来完成本实验,但对 xv6 代码的修改应局限于以下文件:
在 xv6 中,当用户程序执行一个系统调用时,会首先执行该系统调用在用户空间的 stub (位于 ,该文件由 生成),通过汇编代码实现系统调用的参数传递,并最终执行 指令来陷入内核。 这一步骤将依次经过 uservec () 和 usertrap (),并最终通过 syscall () 来跳转到处理所指定系统调用的具体函数。
为了实现 ,你可以首先考虑跑通上面的系统调用处理流程。例如:
- 如何在 中添加合适的内容来生成 的 stub;
- 如何为 分配一个新的系统调用 ID;
- 如何在内核中获取系统调用参数,并跳转到特定的函数来处理系统调用。
在此基础上,可以再考虑 system call traing 具体功能逻辑的实现。例如:
- 如何在内核中维护特定的数据结构来记录必要信息;
- 如何确定在哪个位置打印系统调用信息更合适。
你可以使用如下测试用例先在本地进行测试 ( 取决于系统的运行情况,但其他内容应该相同):
1) 追踪 产生的所有系统调用:
2) 追踪 使用 系统调用的情况:
3) 追踪 使用 系统调用的情况,并追踪子进程 (fork() 的返回值是子进程的 pid,因此可能会不同):
4) 追踪 使用 系统调用的情况,并追踪子进程:
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/te-jc/40423.html