1.system call tracing(moderate)

要求:创建一个系统调用来实现跟踪特性,它采用一个参数来指定跟踪哪一个系统调用,例如:跟踪fork系统调用,程序调用trace(1<<SYS_fork),其中SYS_fork是kernel/syscall.h中的系统调用号。如果在掩码中设置了系统调用的编号,则必须修改须

xv6的内核,以便在每个系统调用即将返回时输出一行。这一行应包括进程id、系统调用的名称和返回值。不需要打印系统调用参数。用于跟踪的系统调用应能够跟踪调用它的进程以及随后的子进程,但不能影响其它的进程。

 

要实现的效果:

trace 32 grep hello README,表示执行grep hello README时,read系统调用发生时,跟踪并打印要求的东西。

$ trace 32 grep hello README
3: syscall read -> 1023
3: syscall read -> 966
3: syscall read -> 70
3: syscall read -> 0

这里32表示的是1<<SYS_read的结果。

 

提示:

  • 在makefile中添加$U/_trace
  • 这个时候直接运行make qemu会发现无法编译user/trace.c,trace这个系统调用还没有实现,即在用户态下的存根还不存在。要在user/user.h中将系统调用声明出来(即int trace(int)),在user/usys.pl中添加存根(entry("trace")),在 kernel/syscall.h中添加系统调用号。

    这里Makefile 调用 perl 脚本 user/usys.pl,它生成 user/usys.S,即实际的系统调用存根,它使用 RISC-V 中的ecall回调指令转换到内核。

    在完成了上面的操作之后就算是修复了编译问题了,这时可以成功的make qemu了。一旦修复了编译问题,就运行trace 32 grep hello README; 它将失败,因为您还没有在内核中实现系统调用。
  • 在 kernel/sysproc.c 中添加 sys _ trace ()函数,该函数通过在 proc 结构中的新变量中记住参数来实现新的系统调用(参见 kernel/proc.h)。从用户空间检索系统调用参数的函数在 kernel/syscall.c 中,您可以在 kernel/sysproc.c 中看到它们的使用示例。(没看太明白,但是可以以照猫画虎的做)
  • 修改 fork ()(参见 kernel/proc.c) ,将跟踪掩码从父进程复制到子进程。
  • 修改 kernel/syscall.c 中的 syscall ()函数以打印跟踪输出。您需要添加要索引到的系统调用名称数组。

可以知道的信息:

在根据提示完成相关的文件配置之后,可以知道目前需要在kernel/sysproc.c中来完成sys_trace()这个函数。

 

根据提示三以及参考sysproc.c中的其它函数,先大致做一个测试:

uint64
sys_trace(void)
{
printf("sys_trace:hi\n");
return 0;
}

当运行trace 32 grep hello README的时候可以看到输出就是我们在sys_trace中所打印的东西,就也意味着这里要实现trace系统调用被调用时要输出的东西。

 

再根据提示三中的从用户空间检索系统调用参数的函数在 kernel/syscall.c 中,转到syscall.c中最下面可以看到syscall函数.在这个函数中首先定义了一个整型的num来记录一个参数,当if判断不成功的时候它会打印“pid(进程号) name(所传入的调用名字):unknown sys call”这样的信息,那么大致可以知道当if判断成功的时候,应该就是对要执行的系统调用做处理,由于每次调用成功会去找到syscalls[num],那么可以推测是根据num来判断是哪一个系统调用,因此不妨再写一个存放系统调用名字的数组来打印一下试试



这时make qemu试一下,可以发现随着xv6的启动,调用的系统调用被打印出来,如下图所示:



 

这个时候就可以明确syscall是调用系统函数的一个入口,sys_trace是处理trace系统调用的地方,有了这两个函数就应该可以实现这个实验所要实现的效果。

 

在实现sys_trace函数的时候发现在其它的函数中都有这么一段代码:

int n;
if(argint(0, &n) < 0)
return -1;

那么继续照猫画虎,把这一段搬到sys_trace中用输出调试一下,即printf("sys_trace:hi,n is %d\n",n);,可以发现这段代码是把用户态得到的掩码传给n,比如trace 32 grep hello README得到的n就是32,这个n用于决定要追踪的函数,那么现在的问题就是:如何让syscall也可以获得这个值,毕竟在syscall中需要这个掩码来打印对应得系统调用。

 

这个时候再返回到提示三中,有这样一句话:在 kernel/sysproc.c 中添加 sys _ trace ()函数,该函数通过在 proc 结构体中的新变量中记住参数来实现新的系统调用(参见 kernel/proc.h),按照这个提示,我们应该在proc中添加变量来实现两个函数共用这一掩码值,而proc结构体所存得是每一个进程的状态信息。

 

到了这里,基本功能都能实现了,但是我们发现提示4:“修改 fork ()(参见 kernel/proc.c) ,将跟踪掩码从父进程复制到子进程”好像一直没有用到,于是去查看proc.c中的fork,发现在这里面有两个结构体np和p,我们需要将父进程p的相关信息复制给np,于是添加一行:np->trace_mask=p->trace_mask;

 

实现:

对syscall的修改

static char* syscall_names[]={
"fork","exit","wait","pipe","read","kill","exec","fstat","chdir",
"dup","getpid","sbrk","sleep","uptime","open","write","mknod",
"unlink","link","mkdir","close","trace"
}; void
syscall(void)
{
int num;
struct proc *p = myproc(); num = p->trapframe->a7;
if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
p->trapframe->a0 = syscalls[num]();//返回值放在a0这个寄存器中
int mask=p->trace_mask;
if((mask>>num)&1){
printf("%d: syscall %s -> %d\n",p->pid,syscall_names[num-1],p->trapframe->a0);
}
} else {
printf("%d %s: unknown sys call %d\n",
p->pid, p->name, num);
p->trapframe->a0 = -1;
}
}

对sys_trace的修改:

uint64
sys_trace(void)
{
int mask;//n是从用户态传进来的掩码,比如追踪的是fork传进来的就是32
if(argint(0, &mask) < 0)
return -1;
//printf("sys_trace:hi,n is %d\n",mask); struct proc *p = myproc();
p->trace_mask=mask;//把掩码放到进程信息中 return 0;
}

补充:

在测试grep hello README的时候发现输出和预期的不太一样,在这里输出了上一次所跟踪的信息,后来发现在proc.c中根据注释发现有一个freeproc函数用于释放进程信息,我们需要在里面添加一行p->proc_mask=0

2.sysinfo(moderate)

要求:写一个sysinfo这个system call,需要获取当前空闲的内存大小填入struct sysinfo.freemem中,获取当前所有不是UNUSED的进程数量填入struct sysinfo.nproc中

 

提示:

  • 在makefile中添加$U/_sysinfotest
  • 运行 make qemu; user/sysinfotest.c 将无法编译。添加系统调用 sysinfo,步骤与前面的任务相同。要在 user/user.h 中声明 sysinfo ()的原型,需要预先声明 struct sysinfo 的存在:
struct sysinfo;
int sysinfo(struct sysinfo *);
  • Sysinfo 需要将一个 struct sysinfo 复制回用户空间; 请参阅 sys _ fstat ()(kernel/sysfile.c)和 filestat ()(kernel/file.c)以获得如何使用 copy out ()实现这一点的示例。
  • 要收集空闲内存量,请向 kernel/kalloc.c 添加一个函数
  • 要收集进程数,请向 kernel/proc.c 添加一个函数
  • 在sysproc.c中完成系统调用函数的编写,在syscall中记得对syscalls修改并extern
  • 和前面一样先要在user/user.h中声明system callint sysinfo(struct sysinfo *)以及struct sysinfo,在user/usys.pl中注册entry,在kernel/syscall.h中注册一个syscall number,在kernel/sysproc.c中对uint64 sys_sysinfo(void)进行实现,注意要在sysproc.c中添加头文件sysinfo.h

实现:

sysproc.c中实现系统调用

uint64
sys_sysinfo(void)
{
struct sysinfo info;
uint64 addr;
struct proc *p=myproc(); info.freemem=acquire_freemem();
info.nproc=acquire_nproc(); if(argaddr(0, &addr) < 0)//入参放到addr里
return -1; if(copyout(p->pagetable, addr, (char *)&info, sizeof(info)) < 0)//函数运算后的info结果放到addr里
return -1; return 0;
}

kalloc.c中实现获取空闲内存

uint64 acquire_freemem()
{
struct run *r; uint64 cnt=0; acquire(&kmem.lock);
r = kmem.freelist;
while(r)
{
r=r->next;
cnt++;//链表的长度就是页表的个数
}
release(&kmem.lock); return cnt*PGSIZE;//页表的个数乘以页表的大小就是整个系统空闲内存的大小
}

proc.c中实现获取使用进程数

uint64 acquire_nproc()
{
struct proc *p;
int cnt=0; for(p = proc; p < &proc[NPROC]; p++) {
acquire(&p->lock);
if(p->state != UNUSED) {
cnt++;
}
release(&p->lock);
}
return cnt;
}

3测试结果

mit6.s081 lab2: system calls的更多相关文章

  1. MIT 6.828 JOS学习笔记18. Lab 3.2 Part B: Page Faults, Breakpoints Exceptions, and System Calls

    现在你的操作系统内核已经具备一定的异常处理能力了,在这部分实验中,我们将会进一步完善它,使它能够处理不同类型的中断/异常. Handling Page Fault 缺页中断是一个非常重要的中断,因为我 ...

  2. Hooking Android System Calls for Pleasure and Benefit

    The Android kernel is a powerful ally to the reverse engineer. While regular Android apps are hopele ...

  3. MIT6.S081/6.828 实验1:Lab Unix Utilities

    Mit6.828/6.S081 fall 2019的Lab1是Unix utilities,主要内容为利用xv6的系统调用实现sleep.pingpong.primes.find和xargs等工具.本 ...

  4. MIT-6.828-JOS-lab5:File system, Spawn and Shell

    Lab 5: File system, Spawn and Shell tags: mit-6.828 os 概述 本lab将实现JOS的文件系统,只要包括如下四部分: 引入一个文件系统进程(FS进程 ...

  5. MIT6.828 Lab2 内存管理

    Lab2 0. 任务介绍 你将编写一个内存管理代码.主要分为两大部分.分别对物理内存和虚拟内存的管理. 对于物理内存,每次分配内存分配器会为你分配4096bytes.也称为一个页(在大部分操作系统中一 ...

  6. 【MIT6.S081/6.828】手把手教你搭建开发环境

    目录 1. 简介 2. 安装ubuntu20.04 3. 更换源 3.1 更换/etc/apt/sources.list文件里的源 3.2 备份源列表 3.3 打开sources.list文件修改 3 ...

  7. Linux Kernel sys_call_table、Kernel Symbols Export Table Generation Principle、Difference Between System Calls Entrance In 32bit、64bit Linux

    目录 . sys_call_table:系统调用表 . 内核符号导出表:Kernel-Symbol-Table . Linux 32bit.64bit环境下系统调用入口的异同 . Linux 32bi ...

  8. Linux Kernel sys_call_table、Kernel Symbols Export Table Generation Principle、Difference Between System Calls Entrance In 32bit、64bit Linux【转】

    转自:http://www.cnblogs.com/LittleHann/p/4127096.html 目录 1. sys_call_table:系统调用表 2. 内核符号导出表:Kernel-Sym ...

  9. Linux System Calls Hooking Method Summary

    http://www.cnblogs.com/LittleHann/p/3854977.html http://www.cnblogs.com/cozy/articles/3175615.html h ...

  10. MIT6.828 JOS系统 lab2

    MIT6.828 LAB2:http://pdos.csail.mit.edu/6.828/2014/labs/lab2/ LAB2里面主要讲的是系统的分页过程,还有就是简单的虚拟地址到物理地址的过程 ...

随机推荐

  1. 题解 CF916C

    题目大意: 要求构造一张图,并让该图满足以下条件: 有 \(n\) 个点,\(m\) 条边. 每条边的边权范围是 \([1,10^9]\). 图中从 \(1\) 到 \(n\) 的最短路径长度是个质数 ...

  2. uni-app框架开发app发布流程

    uni-app框架开发app发布流程 1.首先公司申请软著 步骤:申请软著详细流程 - 阿长*长 - 博客园 (cnblogs.com) 一.安卓端 1,点击发行>原生-app云打包 正式包和自 ...

  3. Linux删除‘-’开头的文件

    版权声明:原创作品,谢绝转载!否则将追究法律责任. ----- 作者:kirin 先看两个特殊文件(以--开头) [root@kirin ~]# ll total 0 -rw-r--r-- 1 roo ...

  4. 记一次逆向分析解密还原Class文件

    前言 前阵子我的一位朋友发来一份代码让我帮忙看看.具体就是所有的jsp文件内容和大小都一样,漏洞挖掘无从下手.经过分析发现所有的Class都使用了自定义的加密工具加密,经过逆向分析,顺利解密,因而有了 ...

  5. 【matlab混沌理论】1.5.洛伦兹模型的分析

    洛伦兹方程用于生成y变量的图.这是对三种y初始条件敏感依赖的一个例子. 1.洛伦兹吸引子的y敏感依赖的着色图 input: % 洛伦兹方程用于生成y变量的图.x和z的初始条件保持不变,但y的初始条件在 ...

  6. 单元测试平台搭建:sonarQube+sonarScanner+Jenkins+jacoco

    单元测试平台搭建及结果分析 一.方案 需求目标:提高单元测试覆盖率和规范代码编写规范 选用工具:Sonarqube.sonarqube Scanner.Jenkins.jacoco 方案: 工程中引入 ...

  7. pytorch学习笔记——训练时显存逐渐增加,几个epoch后out-of-memory

    问题起因:笔者想把别人的torch的代码复制到笔者的代码框架下,从而引起的显存爆炸问题 该bug在困扰了笔者三天的情况下,和学长一同解决了该bug,故在此记录这次艰辛的debug之路. 尝试思路1:检 ...

  8. 组合式api的使用方式

    方式一:通过setup选项 <script> export default { setup(){ // 提供数据 // 提供函数 // 提供计算属性等等..... } } </scr ...

  9. 2023-12-23:用go语言,一支n个士兵的军队正在趁夜色逃亡,途中遇到一条湍急的大河 敌军在T的时长后到达河面,没到过对岸的士兵都会被消灭 现在军队只找到了1只小船,这船最多能同时坐上2个士兵。

    2023-12-23:用go语言,一支n个士兵的军队正在趁夜色逃亡,途中遇到一条湍急的大河 敌军在T的时长后到达河面,没到过对岸的士兵都会被消灭 现在军队只找到了1只小船,这船最多能同时坐上2个士兵. ...

  10. 开源数据血缘和元数据管理框架DataHub的血缘摄取 V0.12.1版本

    DataHUb的安装很简单:你有绿色上网就soeasy 前置条件,你已经运行好DataHub整个Docker-Compse服务 打开地址:http://host:9002/ 输入账号DataHub 密 ...