trace

该系统调用程序,可以跟踪其他的系统调用命令,该系统调用的形参为一个整数掩码。其具体实参为1 << sys_call所得到的整数值,sys_call是一个系统调用指令在内核中定义的系统调用编号。返回值包含进程id,系统调用sys_call的名称和返回值。并且trace指令可以跟踪当前进程和它派生的所有子进程。

即具体用法为

trace [sys_call_mask] [call] [call_params]

call: 可以为一个unix命令 如grep

sys_call_mask: 为系统调用指令,可以传入2147483647,可以跟踪运行call指令期间的所有系统调用指令

call_params:即call命令需要的合法参数格式

trace.c



可以看到,在该自定义函数中调用了trace的sys_call,如果成功那么将进行切割,nargv为sys_call_mask后的具体指令,然后利用exec系统调用进行执行

添加原型、存根、系统调用编号

提示中说到需要在usys.h添加系统调用的原型



可以看到原本xv6中系统调用指令的原型

trace指令通过接受整型mask返回一个字符串

char* trace(int);

第二步在usys.pl中添加存根,Makefile将调用该perl脚本,生成实际的系统调用存根usys.S

entry("trace");

第三步在syscall.h中添加系统调用编号

#define SYS_trace 22

内核中的实现

上述步骤只实现了trace指令的声明,还需要在内核中进行实现。

第一步需要在proc.h中的proc结构体内定义一个新的变量,用来记录我们给定的mask值,然后和之后的每个系统调用的mask值进行比较,如果相等则打印输出



第二步就是实现sys_trace函数,该函数主要功能就是对proc结构体中的trace_mask值进行赋值操作,需要使用argint函数,当进行系统调用时,会向a0寄存器中写入当前系统调用指令的mask即系统调用指令所需要的参数会存放到a0和a1中,利用argint函数可以从a0寄存器中获取,然后将其转换为整数。

在执行某个系统调用指令时,a0和a1用来接受参数,当函数返回时a0会存放返回值

//sys_trace()
uint64
sys_trace(void)
{
//get the param of the sys_call
if(argint(0,&(myproc()->trace_mask))<0)
{
return -1;
}
return 0;
}

打印子进程

由于要求打印父进程会派生出的所有子进程,所以需要将父进程的trace_mask传入到子进程里面,可以在fork()函数中实现,fork函数中会创建两个proc的结构体一个代表子进程np,一个代表当前进程p

np->trace_mask = p->trace_mask;

打印输出

调用trace指令后,我们需要对满足输入mask的系统调用进行输出

p->trapframe->a7表示当前系统调用的号码。我们可以通过比较(1<<(p->trapframe->a7))和存放在proc中的之前a0寄存器中的值来进行判断

if((1<<num) & p->trace_mask)
{
printf("%d: syscall %s -> %d\n", p->pid,syscalls_name[num],p->trapframe->a0);
}

输出格式按照样例格式,syscalls_name[]为新建的数组,用来存储每个系统调用的名称。

sysinfo

该系统调用主要作用是收集正在运行的系统信息,形参为定义在kernal/sysinfo.h文件下的sysinfo结构体指针,在内核态填写这个结构体,然后返回到用户空间

获取空闲内存空间

根据提示,在kalloc.c中添加函数,kalloc.c中有两个结构体,分别表示当前内存空间和空闲的内存空间

struct run {
struct run *next;
}; struct {
struct spinlock lock;
struct run *freelist;
} kmem;

所以我们获得空间内存空间大小就是获得freelist这个链表的长度,直接遍历计数即可

void
getfree(uint64 *res)
{
*res = 0;
struct run *cur = kmem.freelist;
//lock
acquire(&kmem.lock);
while(cur)
{
//Base: PGSIZE
*res += PGSIZE;
cur = cur->next;
}
release(&kmem.lock);
}

获取当前的进程数量

proc.c中定义了一个存储所有进程结构体的数组,我们只需要统计其中state!=UNUSED的进程即可

void
getprocnum(uint64* num)
{
*num = 0;
struct proc* p;
for(p = proc; p < &proc[NPROC]; p++)
{
acquire(&pid_lock);
if(p->state != UNUSED) (*num)++;
release(&pid_lock);
}
}

通过系统调用复制到用户空间

编写sys_sysinfo系统调用指令,提示中也说到使用copyout()指令,首先我们需要定义一个sysinfo的结构体,然后通过上述两个函数对两个值进行赋值操作。

然后我们需要得到用户空间下的地址,可以利用argaddr函数从a0寄存器中获取然后赋值给我们的变量。当得到用户空间的地址后,利用copyout函数进行从内核到用户空间的复制操作。p->pagetable所代表的就是当前进程的页表,然后addr就是该页表下的地址。

uint64
sys_sysinfo(void)
{
//the struct of sysinfo
struct sysinfo info;
getfree(&info.freemem);
getprocnum(&info.nproc);
struct proc* p = myproc();
//the kernal memory addr use argaddr
uint64 addr;
if(argaddr(0,&addr) < 0)
{
return -1;
}
if(copyout(p->pagetable, addr, (char*)&info, sizeof(info)) < 0)
{
return -1;
}
return 0;
}

注意

  1. 由于在sysproc.c中使用了struct sysinfo,所以需要在头文件添加sysinfo.h
  2. 需要在defs.h中对我们定义在kalloc.c和proc.c的两个函数进行声明

    defs.h定义了整个操作系统中会用到的结构体,枚举类型和函数

声明一个系统调用

定义一个系统调用

Lab2:System Call的更多相关文章

  1. MIT6.828 JOS系统 lab2

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

  2. MIT 操作系统实验 MIT JOS lab2

    MIT JOS lab2 首先把内存分布理清楚,由/boot/main.c可知这里把kernel的img的ELF header读入到物理地址0x10000处 这里能够回想JOS lab1的一个小问.当 ...

  3. 《ucore lab2》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 练习1:实现 first-fit 连续物理内存分配算法 题目 在实现first fit 内存分配算法的回收函数时,要考虑地址连续的空闲块之间的合 ...

  4. CMU15-455 Lab2 - task4 Concurrency Index -并发B+树索引算法的实现

    最近在做 CMU-15-445 Database System,lab2 是需要完成一个支持并发操作的B+树,最后一部分的 Task4 是完成并发的索引这里对这部分加锁的思路和完成做一个总结,关于 B ...

  5. MIT6.828 Lab2 内存管理

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

  6. ChCore Lab2 内存管理 实验笔记

    本文为上海交大 ipads 研究所陈海波老师等人所著的<现代操作系统:原理与实现>的课程实验(LAB)的学习笔记的第二篇.所有章节的笔记可在此处查看:chcore | 康宇PL's Blo ...

  7. .Net多线程编程—System.Threading.Tasks.Parallel

    System.Threading.Tasks.Parallel类提供了Parallel.Invoke,Parallel.For,Parallel.ForEach这三个静态方法. 1 Parallel. ...

  8. .Net Core MVC 网站开发(Ninesky) 2.2、栏目管理功能-System区域添加

    在asp或asp.net中为了方便网站的结构清晰,通常把具有类似功能的页面放到一个文件夹中,用户管理功能都放在Admin文件夹下,用户功能都放在Member文件夹下,在MVC中,通常使用区域(Area ...

  9. .Net Core上用于代替System.Drawing的类库

    目前.Net Core上没有System.Drawing这个类库,想要在.Net Core上处理图片得另辟蹊径. 微软给出了将来取代System.Drawing的方案,偏向于使用一个单独的服务端进行各 ...

  10. System.Guid ToString五中格式

    参考:https://msdn.microsoft.com/en-us/library/97af8hh4.aspx 测试代码: using System; using System.Collectio ...

随机推荐

  1. Js中的逻辑运算符

    Js中的逻辑运算符 JavaScript中有三个逻辑运算符,&&与.||或.!非,虽然他们被称为逻辑运算符,但这些运算符却可以被应用于任意类型的值而不仅仅是布尔值,他们的结果也同样可以 ...

  2. win32 - 检查权限

    检查当前句柄是否有指定的权限. #include <iostream> #include <windows.h> #include <tchar.h> //#pra ...

  3. 链表--insert

    分别是使用了二级指针和一级指针的两种方法,最后会按插入的顺序依次打印1,2,3,4 主要区别在于,使用二级指针,可以在main函数里直接用一个空的Node指针,而一级指针是在main函数里面先添加了一 ...

  4. 7z命令

    文件解压缩命令 语法格式:7z 参数 文件名 常用参数 a 向压缩包中添加文件 t 测试压缩包的完整性 d 从压缩包中删除文件 u 更新压缩包中的文件 e 从压缩包中提取文件 x 解压文件时保留绝对路 ...

  5. Centos下配置python环境

    https://blog.csdn.net/longzhoufeng/article/details/109879818

  6. 【Azure Developer】使用REST API获取Activity Logs、传入Data Lake的数据格式问题

    问题一:.  如何在用REST API获取活动日志时,控制输出的项? [答]参考REST API对于获取活动日志的说明接口,在参数是$filter和$select中可以分别控制过滤条件和输出项 GET ...

  7. 如何当个优秀的文档工程师?从 TC China 看技术文档工程师的自我修养

    本文系 NebulaGraph Community Academic 技术文档工程师 Abby 的参会观感,讲述了她在中国技术传播大会分享的收获以及感悟. 据说,技术内容领域.传播领域的专家和决策者们 ...

  8. C++ //常用拷贝和替换算法 //copy //replace 将指定区间范围内的旧元素修改为新元素 //replace_if(满足条件的元素,替换指定的元素) //swap 互换两个容器的元素

    //常用拷贝和替换算法 //copy //replace 将指定区间范围内的旧元素修改为新元素 //replace_if(满足条件的元素,替换指定的元素) //swap 互换两个容器的元素 #incl ...

  9. spirmmvc框架整合手抄版示例,供基础搭建代码对照

    注明所有文档和图片完整对照,辟免笔记出错,不能复习   package com.ithm.config; import com.alibaba.druid.pool.DruidDataSource; ...

  10. springboot发送邮件的几种方式

    准备工作(以QQ邮箱为例) SMTP 协议全称为 Simple Mail Transfer Protocol,译作简单邮件传输协议,它定义了邮件客户端软件与 SMTP 服务器之间,以及 SMTP 服务 ...