1、System call tracing
实现一个追踪系统调用的函数,系统中已经提供了一个用户层面的trace程序(user/trace.c),我们要做的就是创建一个新的系统调用来控制跟踪。
trace命令的用法:trace + mask(一个整数,表示需要跟踪的命令) + 待调用的命令
trace.c的代码如下:(主要功能是将命令行中的参数argv复制到nargv
中,除了argv
中的前2个参数)
#include "kernel/param.h"
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int
main(int argc, char *argv[])
{
int i;
char *nargv[MAXARG];
if(argc < 3 || (argv[1][0] < '0' || argv[1][0] > '9')){
fprintf(2, "Usage: %s mask command\n", argv[0]);
exit(1);
}
if (trace(atoi(argv[1])) < 0) {
fprintf(2, "%s: trace failed\n", argv[0]);
exit(1);
}
for(i = 2; i < argc && i < MAXARG; i++){
nargv[i-2] = argv[i];
}
exec(nargv[0], nargv);
exit(0);
}
我们需要在proc结构体中添加一个参数mask来存储trace后跟的第一个参数(表示跟踪命令的整数掩码)。
struct proc {
// ...
int mask; // mask for trace system call
};
在kernel/sysproc.c中添加sys_trace函数,从用户栈中取出mask,并保存到当前进程的proc结构体中。
uint64
sys_trace(void)
{
int mask;
if(argint(0, &mask) < 0)
return -1;
myproc()->mask = mask;
return 0;
}
由于我们要跟踪的是各个系统调用,因此我们需要在syscall函数(kernel/syscall.c)中添加处理逻辑。
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]();
// 当前系统调用需要被跟踪,打印相关信息
if((p->mask & (1 << num)) != 0){
printf("%d: syscall %s -> %d\n",
p->pid, syscall_nums[num - 1], p->trapframe->a0);
}
} else {
printf("%d %s: unknown sys call %d\n",
p->pid, p->name, num);
p->trapframe->a0 = -1;
}
}
还有最后一步,添加系统调用编号。
static uint64 (*syscalls[])(void) = {
// ..
[SYS_trace] sys_trace,
};
static char *syscall_nums[] = {
//..
"trace",
};
2、Sysinfo
添加一个系统调用sysinfo,它收集有关正在运行的系统的信息。
系统已经给出sysinfo将要用到的sysinfo结构体定义:
struct sysinfo {
uint64 freemem; // amount of free memory (bytes)
uint64 nproc; // number of process
};
在kalloc.c(kernel/kalloc.c)中添加获取空闲存储的函数:
// 遍历空闲链表
uint64
kcountfree(void)
{
uint64 count = 0;
struct run *p = kmem.freelist;
acquire(&kmem.lock);
while(p){
count += PGSIZE;
p = p -> next;
}
release(&kmem.lock);
return count;
}
在kernel/proc.c中添加一个函数获取当前系统中状态不是UNUSED的进程数:
// 遍历proc数组以获得状态不为UNUSED的进程数
uint64
countnproc(void)
{
int n = 0;
struct proc *p;
for(p = proc; p < &proc[NPROC]; p++){
if(p->state == UNUSED)
continue;
++n;
}
return n;
}
在kernel/sysproc.c中添加一个函数调用kcountfree()和countnproc获取数据写入结构体并调用copyout函数(kernel/vm.c)传递到用户空间:
uint64
sys_sysinfo(void)
{
struct proc *p = myproc();
uint64 info;
if(argaddr(0, &info) < 0)
return -1;
uint64 count[2];
count[0] = kcountfree();
count[1] = countnproc();
if(copyout(p->pagetable, info, (char *)&count, sizeof(count)) < 0)
return -1;
return 0;
}
还有一些步骤跟上一题一样,这里便不赘述。