6.s081(Fall 2022)Lab2: system calls

news2024/10/6 10:40:25

文章目录

  • 前言
  • 其他篇章
  • 参考链接
  • 0. 前置准备
  • 1. System call tracing (moderate)
    • 简单分析
    • Hint 1
    • Hint 2
    • Hint 3
    • Hint 4
    • Hint 5
    • 测试
  • 2. Sysinfo (moderate)

前言

好像没啥前言

其他篇章

环境搭建
Lab1:Utilities

参考链接

官网链接
xv6手册链接,这个挺重要的,建议做lab之前最好读一读。
xv6手册中文版,这是几位先辈们的辛勤奉献来的呀!再习惯英文文档阅读我还是更喜欢中文一点,开源无敌!
官方文档

0. 前置准备

很惭愧,以前github用得少,这一步折腾了老半天,我再说一遍我个人的开发流程——先在windows下git一个本地仓库,然后用VS编辑,写完后git push上去,在WSL的对应地方git pull下来,然后编译运行。

前面环境配置中我为了连接到我个人的远程仓库,是直接把原本的远程仓库删了的,然后lab1做完做到lab2发现这个lab整体不是循序渐进的,而是彼此分离的,每个实验需要选择相应的分支,因此就要重新弄一下:

 git remote add base  git://g.csail.mit.edu/xv6-labs-2022
 git fetch base
 git checkout syscall
 git push --set-upstream origin syscall

当然,别忘了加.gitignore
在这里插入图片描述

1. System call tracing (moderate)

简单分析

gdb教学我就不说了,看看这个task。
在这里插入图片描述
先简单研究一下我们需求的这个trace是干什么的吧,trace顾名思义,tracing,追踪、寻迹的意思,比如ray tracing,就是光线追踪,这个命令接受一个传参mask,内涵是一个掩码,每一位对应一个系统调用的一个序号,比如传入32,代表 32 1<<SYS_read,2147483647 代表追踪所有syscall,具体的这些值定义在了kernel/syscall.h里,我们待会也会写
在这里插入图片描述
初步了解之后,就写实现吧,这个task按照hint的步骤来很清晰:
在这里插入图片描述

Hint 1

Add $U/_trace to UPROGS in Makefile

首先添加makefile,司空见惯了。

Hint 2

Run make qemu and you will see that the compiler cannot compile user/trace.c, because the user-space stubs for the system call don’t exist yet: add a prototype for the system call to user/user.h, a stub to user/usys.pl, and a syscall number to kernel/syscall.h. The Makefile invokes the perl script user/usys.pl, which produces user/usys.S, the actual system call stubs, which use the RISC-V ecall instruction to transition to the kernel. Once you fix the compilation issues, run trace 32 grep hello README; it will fail because you haven’t implemented the system call in the kernel yet.

然后说这个时候make,会找不到trace,我们要在用户态user/user.h里加上trace的声明,根据原文 It should take one argument, an integer “mask”, whose bits specify which system calls to trace. 可知,这玩意应该接受一个int,然后返回也是一个int(返回值其实不影响来着):
在这里插入图片描述
然后我们在user/usys.pl下添加这么一行,这里的意思是声明了一个trace系统调用的入口,实际上这一段会为我们在usys.S中生成一段汇编代码。
在这里插入图片描述
然后在内核syscall.h中给它注册一个number
在这里插入图片描述

Hint 3

Add a sys_trace() function in kernel/sysproc.c that implements the new system call by remembering its argument in a new variable in the proc structure (see kernel/proc.h). The functions to retrieve system call arguments from user space are in kernel/syscall.c, and you can see examples of their use in kernel/sysproc.c.

然后模仿着添加原型?
在这里插入图片描述
这里简单解释一下后面这个syscalls数组,可能很多人没有看懂这,首先这是个static的不用说,然后这是个函数指针的数组(我一向很反感那些什么数组指针指针数组混着说的,直接说成装指针的数组不就一目了然了吗),函数返回值为uint64,参数为void,显然是为上面extern的那些函数准备的东西,这些都比较简单,后面的是个小feature了,它本身叫作指派初始化器(Designated Initializers),来自C99,意思就是给方括号里的那一位初始化为右边的值
在这里插入图片描述
但是可以看到,C99的指派初始化器的形式是[N] = expr的,中间需要一个等号连接,这里没有,它是来自GCC私货,原文出现在介绍指定初始化器的时候:An alternative syntax for this that has been obsolete since GCC 2.5 but GCC still accepts is to write ‘[index]’ before the element value, with no ‘=’. 意味着大家在自己使用时加个等号是更符合standard的写法。
在这里插入图片描述

然后叫我们仿照着kernel/sysproc.c里的其他函数给trace写一个定义进去:

uint64
sys_trace(void)
{
  
  return 0;
}

使用argint从寄存器取出用户传入的参数:

  int mask;
  argint(0, &mask); // 保存用户传入的参数

然后我们要把接到的这个mask保存到进程的元数据中,根据原文Add a sys_trace() function in kernel/sysproc.c that implements the new system call by remembering its argument in a new variable in the proc structure (see kernel/proc.h). T 我们在kernel/proc.h中可以找到一个结构体struct proc
在这里插入图片描述
很显然这个结构体记录着一些元数据,我们在这个基础上再添加一条承载mask的:

  int traceMask;               // 用于接收trace的mask

显然每一个进程都有一个独属于自己的proc对象,我们可以通过myproc()来获取这个对象的指针,就此我们可以完成我们的sys_trace定义:

uint64
sys_trace(void)
{
  argint(0, &myproc()->mask); // 尝试从用户空间读取参数
  return 0;
}

Hint 4

Modify fork() (see kernel/proc.c) to copy the trace mask from the parent to the child process.

我们知道fork出的子进程会复制父进程的内存空间,根据hint我们可以找到它的实现:
在这里插入图片描述
可以看到,这里明显是要做一个pnp的拷贝,p指向的是父进程的proc对象,np则应该是new proc的缩写了:
在这里插入图片描述
我们这个mask的修改不需要持有锁,因此只需要在alloc之后的合适时机将父进程的值赋出即可:
在这里插入图片描述
既然提到了alloc,这里刚好就可以想到一个问题——资源的分配与释放呢?我们知道C语言访问未初始化变量的行为是UB,那么我们默认状态下的mask进行初始化了吗?在上面那张图里我们可以清晰地看到(或者说猜到)内核依赖allocproc分配内存,依赖freeproc释放内存,因此我们可以直接F12进去看一看实现:
在这里插入图片描述
如图,我们可以很容易地为mask初始化以及释放时赋0值。

Hint 5

Modify the syscall() function in kernel/syscall.c to print the trace output. You will need to add an array of syscall names to index into.

然后我们为syscall这个总体的函数实现我们的功能,也就是前文中的那些打印:
在这里插入图片描述
我们分析一下需要做的事情:当我们进行了trace调用时,我们应当追踪mask标记的所有调用,并打印出4: syscall close -> 0这样的内容,不难看出,打印内容分为三部分:PID、系统调用的名称与系统调用的返回值,其中pid我们可以通过读取proc来获取,返回值实际在框架中都告诉你了:

    // and store its return value in p->trapframe->a0
    p->trapframe->a0 = syscalls[num]();

可以看到,系统调用的返回值被保存在了寄存器a0中,至于系统调用的名称呢?C语言中没有反射,我们就只好提前建立一张syscall的名称表,再根据mask去寻址:

// 系统调用的名称
static const char *syscallnames[] = {
[SYS_fork]    "fork",
[SYS_exit]    "exit",
[SYS_wait]    "wait",
[SYS_pipe]    "pipe",
[SYS_read]    "read",
[SYS_kill]    "kill",
[SYS_exec]    "exec",
[SYS_fstat]   "fstat",
[SYS_chdir]   "chdir",
[SYS_dup]     "dup",
[SYS_getpid]  "getpid",
[SYS_sbrk]    "sbrk",
[SYS_sleep]   "sleep",
[SYS_uptime]  "uptime",
[SYS_open]    "open",
[SYS_write]   "write",
[SYS_mknod]   "mknod",
[SYS_unlink]  "unlink",
[SYS_link]    "link",
[SYS_mkdir]   "mkdir",
[SYS_close]   "close",
[SYS_trace]   "trace",
};

搞清楚并完成了所有前置工作我们就可以开始写逻辑了,最后的syscall函数代码,很简单:

void
syscall(void)
{
  int num;
  struct proc *p = myproc();

  num = p->trapframe->a7;
  if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
    // Use num to lookup the system call function for num, call it,
    // and store its return value in p->trapframe->a0
    p->trapframe->a0 = syscalls[num]();
    if ((p->mask >> num) & 1) { // 判断系统调用是否被跟踪
      printf("%d: syscall %s -> %d\n",
              p->pid, syscallnames[num], p->trapframe->a0);
    }
  } else {
    printf("%d %s: unknown sys call %d\n",
            p->pid, p->name, num);
    p->trapframe->a0 = -1;
  }
}

测试

到这里就基本完成了,还是老规矩,我们make qemu编译,然后试一试文档中的几个命令:

trace 32 grep hello README

在这里插入图片描述

trace 2147483647 grep hello README

在这里插入图片描述

grep hello README

trace 2 usertests forkforkfork # 这一条输入之后貌似要等一会才会出一大坨

在这里插入图片描述


在这里插入图片描述

最后跑一下总体批分./grade-lab-syscall trace
在这里插入图片描述
成功通过!

2. Sysinfo (moderate)

然后让我们来完成一下task2,这个是也是添加一个系统调用,叫sysinfo
在这里插入图片描述
我们先搞清楚这个调用是干啥的,从介绍可以看到,这个sysinfo接收一个struct sysinfo的指针,我们就是要写这个指针指向的对象,怎么写呢?就是将空闲的字节数存到对象里的freemem字段,将state不为UNUSED的进程数量写到nproc字段。

有一个初步的印象后就可以去写实现了,整体思路和上文trace的步骤差不多:

首先是增加$U/_sysinfotest\到Makefile:
在这里插入图片描述
user/user.h里加声明:
在这里插入图片描述
syscall.h中:
在这里插入图片描述
syscall.c中(第三个是上面的那个名称表):
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第2集丨Vue 江湖 —— Vue中的一些必备概念

目录 一、Object.defineProperty()1.1 属性描述符1.2 共享属性1.2.1 configurable1.2.2 enumerable 1.3 数据描述符属性1.3.1 value1.3.2 writable 1.4 访问器描述符属性1.4.1 get1.4.2 set1.4.3 注意点 1.5 案例1.5.1 数据描述符1.5.2 访问器描述符 二、Vue 模板语法2.1 插值语…

作为面试官,有些事想吐槽一下

作者&#xff1a;拭心 前段时间组里有岗位招人&#xff0c;花了些时间面试&#xff0c;趁着周末把过程中的感悟和槽点总结成文和大家讲讲。 简历书写和自我介绍 1.今年的竞争很激烈&#xff1a;找工作的人数量比去年多、平均质量比去年高。裸辞的慎重&#xff0c;要做好和好学…

npm发布包

1.npm 登录 在控制台输入命令 npm login 按提示输入用户名&#xff0c;密码&#xff0c;邮箱后登录 如果出现如下提示 需要将淘宝镜像源切换为npm源&#xff0c;删除或注释以下内容就行 2.发布 进入准备发布的代码的根目录下&#xff0c;输入命令 npm publish 3.删除已发…

《TCP IP 网络编程》第十五章

第 15 章 套接字和标准I/O 15.1 标准 I/O 的优点 标准 I/O 函数的两个优点&#xff1a; 除了使用 read 和 write 函数收发数据外&#xff0c;还能使用标准 I/O 函数收发数据。下面是标准 I/O 函数的两个优点&#xff1a; 标准 I/O 函数具有良好的移植性标准 I/O 函数可以利用…

Python入门二

目录&#xff1a; python封装与property装饰器python继承与类型检查python多态与superpython 模块与包错误与异常Debug 调试与分析python类型注解python数据类dataclasspython内置装饰器python装饰器学生信息管理系统 1.python封装与property装饰器 封装的概念 封装&#x…

深度学习各层负责什么内容?

1、深度学习——神经网络简介 深度学习(Deep Learning)(也称为深度结构学习【Deep Structured Learning】、层次学习【Hierarchical Learning】或者是深度机器学习【Deep Machine Learning】)是一类算法集合&#xff0c;是机器学习的一个分支。 深度学习方法近年来&#xff0c…

Expectation (Easy Version) 2023“钉耙编程”中国大学生算法设计超级联赛(5)hdu7330

Problem - 7330 题目大意&#xff1a;有n次游戏&#xff0c;每次游戏有a/b的概率获胜&#xff0c;且相互独立&#xff0c;如果当前赢了cnt次游戏&#xff0c;那么这次游戏会赢得的分数&#xff0c;问最后得分的期望 1<n<1e6;1<m,a<b<998244353 思路&#xff…

windows10 设置代理

场景&#xff1a;同一个办公室&#xff0c;只有A的电脑有权限访问网站 http://10.129.129.129:5601&#xff0c; 那办公室其他B,C同学想访问 http://10.129.129.129:5601&#xff0c;需要怎么处理&#xff1f; A 同学电脑安装代理软件&#xff1a; 1. 下载wproxy IMFirewall, …

d3dx9_30.dll如何修复,分享几种一键修复方法

d3dx9_30.dll是DirectX 的一个动态链接库文件&#xff0c;它包含了一些用于图形和游戏的函数和资源。在了解d3dx9_30.dll的解决方法和丢失原因之前&#xff0c;我们先来了解一下DirectX。DirectX是一套由微软开发的多媒体和游戏编程接口&#xff08;API&#xff09;集合。它提供…

0802|IO进程线程 day5 进程概念

一、进程的基础 1.1 什么是进程 1&#xff09;进程是程序的一次执行过程 程序&#xff1a;是静态的&#xff0c;它是存储在外存上的可执行二进制文件&#xff1b;进程&#xff1a;动态的概念&#xff0c;它是程序的一次执行过程&#xff0c;包括了进程的创建&#xff0c;调度、…

c语言——计算两个正整数的最大公倍数

//计算两个正整数的最大公倍数 //例如40和60的最大公约数为20. //计算两个正整数的最大公倍数 //例如40和60的最大公约数为20. #include<stdio.h> int main() {int a,b,temp,i;printf("Input a & b:");scanf("%d%d",&a,&b);if(a<b){…

Cat.1如何成为物联网业务加速器?

随着Cat.1芯片及模组在功耗和成本上的不断优化&#xff0c;在窄带物联网领域&#xff0c;越来越多的终端客户把Cat.1当做与NB-IoT相比较的第二选择。越来越多的表计、烟感、市政等行业终端将Cat.1模组应用于非集中化部署的上报类终端业务中&#xff0c;Cat.1这只“网红猫”仍保…

UIKit相关

CALayer和UIView 区别 UIView继承自UIResponder&#xff0c;主要负责事件传递、事件响应&#xff0c;属于基于UIKit框架 CALayer继承自NSObject&#xff0c;负责图像渲染&#xff0c;动画和视图的显示&#xff0c;属于QuartzCore框架 而且这两大内容都符合单一职责原则&#…

【开发心得】黑客是如何攻击你的web应用的?

本文记录一次黑客利用sql注入漏洞攻击应用系统的全过程。 由于涉及到隐私&#xff0c;所以就不能上图了&#xff0c;尽量把过程描述的详细一下&#xff0c;希望能够给开发人员提个醒&#xff0c;有些漏洞&#xff0c;其实修补很简单。好在现在有了chatGPT&#xff0c;把你的代…

调度:setTimeout 和 setInterval

有时一个函数并不需要立刻执行&#xff0c;而是等待特定一段时间之后再执行。这就是所谓的“计划调用&#xff08;scheduling a call&#xff09; setTimeout() 是延时器&#xff0c;setInterval() 是定时器 setTimeout 允许我们将函数推迟到一段时间间隔之后再执行。setInte…

mongodb docker 及常用命令

MongoDB属于非关系型数据库&#xff0c;它是由C编写的分布式文档数据库。内部使用类似于Json的bson二进制格式。 中文手册 https://www.w3cschool.cn/mongodb/ 安装 https://www.mongodb.com/try/download/community 二进制安装可见另一篇&#xff1a; centos7 mongodb 4.0.28…

el-tooltip设置文字溢出时展示否则不展示

改写el-tooltip使其支持文字溢出时展示否则不展示&#xff0c;而不是需要使用js设置单独控制 新建 src/utils/rewriteElTooltip.js &#xff08;一模一样 cv就行&#xff09; export default function rewriteElTooltip(el) {el.props {...el.props,overflow: Boolea…

docker: Error response from daemon: No command specified.

执行 docker run -it -d -v /home/dell/workspace/workspace/test_192.168.1.202_pipeline:/home/workspace1 --name test_192.168.1.202_pipeline_10 qnx:7.1报错 问题定位&#xff1a;export导入的镜像需要带上command&#xff0c;以下命令查看command信息 docker ps --no…

计算机二级Python基本操作题-序号44

1. # 使用turtle库的turtle.fd()函数和turtle.seth()函数绘制一个边长为100的三角形 import turtle for i in range(3): #绘制三条边turtle.seth(i * 120) #底边行进角度为0&#xff1b;右斜边行进角度为120(按逆时针);左斜边行进角度为240(按逆时针)turtle.fd(100) #边长为100…

甜椒叶病害数据集

1.数据集分为训练集和测试集 2.训练集如下所示 第一个文件夹是细菌斑叶&#xff08;449张&#xff09; 第二个是健康叶子&#xff08;4014张&#xff09; 测试集 细菌斑叶 11张 健康叶子10张 import numpy as np import os import matplotlib.pyplot as plt import cv2impor…