- A+
所属分类:linux技术
Part One: System call tracing
任务:修改Xv6内核的代码来打印出每个系统调用以及返回值
根据提示,应该在syscall.c中修改syscall()。
首先在syscall.c中增加对应系统调用名称的数组:
static char *syscalls_name[] = { [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", };
接着在syscall()中添加打印命令:
void syscall(void) { int num; struct proc *curproc = myproc(); num = curproc->tf->eax; if(num > 0 && num < NELEM(syscalls) && syscalls[num]) { curproc->tf->eax = syscalls[num](); cprintf("%s -> %dn", syscalls_name[num], curproc->tf->eax); } else { cprintf("%d %s: unknown sys call %dn", curproc->pid, curproc->name, num); curproc->tf->eax = -1; } }
最终执行结果如下:
xv6... cpu0: starting 0 sb: size 1000 nblocks 941 ninodes 200 nlog 30 logstart 2 inodestart 32 bmap start 58 exec -> 0 open -> 0 dup -> 1 dup -> 2 iwrite -> 1 nwrite -> 1 iwrite -> 1 twrite -> 1 :write -> 1 write -> 1 swrite -> 1 twrite -> 1 awrite -> 1 rwrite -> 1 twrite -> 1 iwrite -> 1 nwrite -> 1 gwrite -> 1 write -> 1 swrite -> 1 hwrite -> 1 write -> 1 fork -> 2 exec -> 0 open -> 3 close -> 0 $write -> 1 write -> 1
注:shell的输出和系统调用的调用路径混在了一起,原因是shell是通过系统调用write来打印输出的
Part Two: Date System Call
任务: 在Xv6中新增一个系统调用date。使用定义于lapic.c中的函数cmostime(),以系统调用uptime为例,观察如何添加一个系统调用。并且在用户层添加一个调用系统调用date的程序。
- 首先使用grep - n uptime *.[chS]命令在源码中查找uptime相关的代码,接下来逐个查看搜索到的位置,模仿写出date系统调用所需要的代码
❯ grep -n uptime *.[chS] syscall.c:105:extern int sys_uptime(void); syscall.c:121:[SYS_uptime] sys_uptime, syscall.h:15:#define SYS_uptime 14 sysproc.c:83:sys_uptime(void) user.h:25:int uptime(void); usys.S:31:SYSCALL(uptime)
- 在syscall.c的对应位置添加代码后如下:
extern int sys_chdir(void); extern int sys_close(void); extern int sys_dup(void); extern int sys_exec(void); extern int sys_exit(void); extern int sys_fork(void); extern int sys_fstat(void); extern int sys_getpid(void); extern int sys_kill(void); extern int sys_link(void); extern int sys_mkdir(void); extern int sys_mknod(void); extern int sys_open(void); extern int sys_pipe(void); extern int sys_read(void); extern int sys_sbrk(void); extern int sys_sleep(void); extern int sys_unlink(void); extern int sys_wait(void); extern int sys_write(void); extern int sys_uptime(void); extern int sys_date(void); // 新添加 static int (*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_date] sys_date, // 新添加 };
- 在syscall.h中添加代码:
#define SYS_date 22
- 在user.h中添加代码:
int date(struct rtcdate*);
- 在usys.S中添加代码:
SYSCALL(date)
- 在sysproc.c中添加代码:
int sys_date(void) { struct rtcdate* r = 0; if (argptr(0, (char**)&r, sizeof(*r) < 0)) { return -1; } cmostime(r); return 0; }
- 以上在操作系统中添加了一个系统调用,下面编写一个执行该系统调用的命令,编写date.c,代码如下:
#include "types.h" #include "user.h" #include "date.h" int main(int argc, char *argv[]) { struct rtcdate r; if (date(&r)) { printf(2, "date failedn"); exit(); } printf(1, "%d-%d-%d %d:%d:%dn", r.year, r.month, r.day, r.hour, r.minute, r.second); exit(); }
- 在Makefile中的UPROG中添加
_date
在完成以上步骤后,成功添加了系统调用date以及调用它的命令date,测试结果如下:
xv6... cpu0: starting 0 sb: size 1000 nblocks 941 ninodes 200 nlog 30 logstart 2 inodestart 32 bmap start 58 init: starting sh $ date 2022-11-10 18:19:21 $