第二周实验1 :trace
trace函数: 参数为一个整数mask。他的bit为1的位置决定了需要trace的syscall函数,比如trace 32, 32 = 100000, 1所在的位置是第5位(从0开始,右往左),查看syscall.h文件,编号为5的函数是sys_read(). 因此trace 32 xxx。 会打印xxx命令中涉及read函数的信息
过程:
-
Add $U/_trace to UPROGS in Makefile -
在user/user.h中添加 trace的声明 int trace(int);
-
在user/usys.pl添加, usys.pl会生成汇编usys.S,而这个usys.S会使用ecall 进入内核 entry("trace");
-
在kernel/syscall.h中为trace添加一个号码 #define SYS_trace 22
-
在 kernel/sysproc.c 添加并实现 sys_trace(), 需要使用一个结构体proc (见 kernel/proc.h)。从用户空间获取system calls参数的方法在kernel/syscall.c, 可以在kernel/sysproc.c找到它们的使用实例。
uint64 sys_trace(void) {
int mask;
argint(0, &mask);
struct proc* proc = myproc();
proc->tracemask = mask;
return 0;
}
- 修改 fork() 将proc中新的变量也复制到child里面
np->tracemask = p->tracemask;
- 修改kernel/syscall.c中的 syscall() ,添加一个保存了函数名的结构体,print语句
static char* syscallsname[] = {
[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",
[SYS_sysinfo] "sys_sysinfo",
};
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->tracemask & (1<<num)){
printf("%d: syscall %s -> %d\n",p->pid,syscallsname[num],p->trapframe->a0);
}
} else {
printf("%d %s: unknown sys call %d\n",
p->pid, p->name, num);
p->trapframe->a0 = -1;
}
}
部分源码说明:
- kernel/proc.h: 定义了一个结构体proc(还有其他结构体),用以保存进程的状态信息. 如给定p为该进程的proc结构体指针。则:
- p->pagetable可得到该进程的虚拟页表。
- p->kstack可得到两个栈,每个进程均有用户栈和内核栈,用户模式下使用用户栈,仅当进程通过system call 或 interrupt进入内核时才能使用内核栈
- p->state可获取进程的状态
实验二 sysinfo
前面流程和trace一致,修改Makefile,在user/user.h,user/usys.pl,kernel/syscall.h添加信息。 sysinfo记录的是 可用进程数 和 空闲内存, 这两个属性封装在一个结构体(见kernel/sysinfo.h)
int freemem_size() {
struct run *r;
int num = 0;
r = kmem.freelist;
while(r) {
num++;
r = r->next;
}
return num * PGSIZE;
}
// for sys_info
int freemem_size(void);
int proc_num(void);
- 需要在内核中将这些信息返回到用户态,参考sys_fstat() (kernel/sysfile.c) and filestat() (kernel/file.c)中的copyout用法, 在sys_proc.c中添加:
uint64 sys_sysinfo(void) {
struct sysinfo sys_info;
sys_info.freemem = freemem_size();
sys_info.nproc = proc_num();
struct proc *p = myproc();
uint64 addr;
if(argaddr(0, &addr) < 0)
return -1;
if(copyout(p->pagetable, addr, (char *)&sys_info, sizeof(sys_info)) < 0)
return -1;
return 0;
}
|