Lab: System calls

trace

根据文档的指引, 在 user/user.h, user/usys.pl, kernel/syscall.h 中添加对应的代码, 分别为:

user/user.h:

int trace(int);

user/usys.pl:

entry("trace");

kernel/syscall.h:

#define SYS_trace   22

而后在 kernel/sysproc.h 中添加 uint sys_trace(void) 的实现, 在实现过程中, 尽管参数被存在结构体 proc 的成员 a1 - a6 中, 然而在 kernel/syscall.c 中已经提供了 int argint(int n, int *ip) 以供使用, 故直接调用即可得到系统调用的参数.

得到参数后再解决如何记录待 “trace” 的调用的变量 mask 的问题, 该问题可以通过在 kernel/proc.h 中的结构体 proc 中添加成员变量 tracemask 中解决. 同时为了使得 fork()得到的子进程也具有同样的 tracemask, 在 kernel/proc.cfork() 函数中添加以下语句:

np->tracemask = p->tracemask;

解决上述问题后, sys_trace() 的实现便呼之欲出了, 直接获取参数后将其保存至结构体对应的成员变量即可:

uint64
sys_trace(void)
{
  struct proc *p = myproc();
  if (argint(0, &(p->tracemask)))
    return -1;

  return 0;
}

然后再实现最后的如何 trace 的问题, 根据文档, 在 kernel/syscall.c 中修改 syscall() 的实现, 在调用前将该系统调用对应的数字以及 tracemask 通过左移和按位与运算做判断, 如果是需要 trace 的系统调用则输出即可. 为了便捷地打印字符串, 可效仿 syscalls[] 数组创建一个类似的数组保存调用名.

修改后的 kernel/syscall.c 代码片段如下:

extern uint64 sys_trace(void);

static uint64 (*syscalls[])(void) = {
[SYS_fork]    sys_fork,
[SYS_exit]    sys_exit,
[SYS_wait]    sys_wait,
[SYS_pipe]    sys_pipe,
[SYS_read]    sys_read,
[SYS_kill]    sys_kill,
[SYS_exec]    sys_exec,
[SYS_fstat]   sys_fstat,
[SYS_chdir]   sys_chdir,
[SYS_dup]     sys_dup,
[SYS_getpid]  sys_getpid,
[SYS_sbrk]    sys_sbrk,
[SYS_sleep]   sys_sleep,
[SYS_uptime]  sys_uptime,
[SYS_open]    sys_open,
[SYS_write]   sys_write,
[SYS_mknod]   sys_mknod,
[SYS_unlink]  sys_unlink,
[SYS_link]    sys_link,
[SYS_mkdir]   sys_mkdir,
[SYS_close]   sys_close,
[SYS_trace]   sys_trace,
[SYS_sysinfo] sys_sysinfo
};

char *syscallsnames[] = {
  [0]           "",
  [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] "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, syscallsnames[num], p->trapframe->a0);
  } else {
    printf("%d %s: unknown sys call %d\\n",
            p->pid, p->name, num);
    p->trapframe->a0 = -1;
  }
}

sysinfo

首先按照与 trace 相同的步骤在对应的文件中添加代码: