diff --git a/Makefile b/Makefile index 59d261c..8bc60d9 100644 --- a/Makefile +++ b/Makefile @@ -194,6 +194,7 @@ UPROGS=\ $U/_primes\ $U/_find\ $U/_xargs\ + $U/_trace\ diff --git a/conf/lab.mk b/conf/lab.mk index 05e8b8d..278d1a8 100644 --- a/conf/lab.mk +++ b/conf/lab.mk @@ -1 +1 @@ -LAB=util +LAB=syscall diff --git a/grade-lab-syscall b/grade-lab-syscall new file mode 100644 index 0000000..b218cc0 --- /dev/null +++ b/grade-lab-syscall @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 + +import re +from gradelib import * + +r = Runner(save("xv6.out")) + +@test(5, "answers-syscall.txt") +def test_answers(): + # just a simple sanity check, will be graded manually + check_answers("answers-syscall.txt") + +@test(5, "trace 32 grep") +def test_trace_32_grep(): + r.run_qemu(shell_script([ + 'trace 32 grep hello README' + ])) + + sys_cnt = { + 'read' : 0 + } + + sys_cnt['read'] += 1 + s = r'^\d+: syscall read\(trace counts: ' + str(sys_cnt['read']) + r'\) -> 1023' + r.match(s) + + sys_cnt['read'] += 1 + s = r'^\d+: syscall read\(trace counts: ' + str(sys_cnt['read']) + r'\) -> 961' + r.match(s) + + sys_cnt['read'] += 1 + s = r'^\d+: syscall read\(trace counts: ' + str(sys_cnt['read']) + r'\) -> 321' + r.match(s) + + sys_cnt['read'] += 1 + s = r'^\d+: syscall read\(trace counts: ' + str(sys_cnt['read']) + r'\) -> 0' + r.match(s) + +@test(5, "trace all grep") +def test_trace_all_grep(): + r.run_qemu(shell_script([ + 'trace 2147483647 grep hello README' + ])) + + sys_cnt = { + 'read' : 0, + 'trace' : 0, + 'exec' : 0, + 'open' : 0, + 'close' : 0, + 'fork' : 0, + } + + sys_cnt['trace'] += 1 + s = r'^\d+: syscall trace\(trace counts: ' + str(sys_cnt['trace']) + r'\) -> 0' + r.match(s) + + sys_cnt['exec'] += 1 + s = r'^\d+: syscall exec\(trace counts: ' + str(sys_cnt['exec']) + r'\) -> 3' + r.match(s) + + sys_cnt['open'] += 1 + s = r'^\d+: syscall open\(trace counts: ' + str(sys_cnt['open']) + r'\) -> 3' + r.match(s) + + + sys_cnt['read'] += 1 + s = r'^\d+: syscall read\(trace counts: ' + str(sys_cnt['read']) + r'\) -> 1023' + r.match(s) + + sys_cnt['read'] += 1 + s = r'^\d+: syscall read\(trace counts: ' + str(sys_cnt['read']) + r'\) -> 961' + r.match(s) + + sys_cnt['read'] += 1 + s = r'^\d+: syscall read\(trace counts: ' + str(sys_cnt['read']) + r'\) -> 321' + r.match(s) + + sys_cnt['read'] += 1 + s = r'^\d+: syscall read\(trace counts: ' + str(sys_cnt['read']) + r'\) -> 0' + r.match(s) + + sys_cnt['close'] += 1 + s = r'^\d+: syscall close\(trace counts: ' + str(sys_cnt['close']) + r'\) -> 0' + r.match(s) + +@test(5, "trace nothing") +def test_trace_nothing(): + r.run_qemu(shell_script([ + 'grep hello README' + ])) + r.match(no=[".* syscall .*"]) + +@test(5, "trace children") +def test_trace_children(): + r.run_qemu(shell_script([ + 'trace 2 usertests forkforkfork' + ])) + + sys_cnt = { + 'read' : 0, + 'trace' : 0, + 'exec' : 0, + 'open' : 0, + 'close' : 0, + 'fork' : 0, + } + + sys_cnt['fork'] += 1 + s = r'3: syscall fork\(trace counts: ' + str(sys_cnt['fork']) + r'\) -> 4' + r.match(s) + + s = r'^5: syscall fork\(trace counts: \d+\) -> \d+' + r.match(s) + + s = r'^6: syscall fork\(trace counts: \d+\) -> \d+' + r.match(s) + + s = r'^\d+: syscall fork\(trace counts: \d+\) -> -1' + r.match(s) + + r.match('^ALL TESTS PASSED') + +@test(14, "sysinfotest") +def test_sysinfotest(): + r.run_qemu(shell_script([ + 'sysinfotest' + ])) + r.match('^sysinfotest: OK', no=[".* FAIL .*"]) + +@test(1, "time") +def test_time(): + check_time() + +run_tests() + diff --git a/grade-lab-util b/grade-lab-util deleted file mode 100755 index 9032ea6..0000000 --- a/grade-lab-util +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env python3 - -import re -from gradelib import * - -r = Runner(save("xv6.out")) - -@test(5, "sleep, no arguments") -def test_sleep_no_args(): - r.run_qemu(shell_script([ - 'sleep' - ])) - r.match(no=["exec .* failed", "$ sleep\n$"]) - -@test(5, "sleep, returns") -def test_sleep_no_args(): - r.run_qemu(shell_script([ - 'sleep', - 'echo OK' - ])) - r.match('^OK$', no=["exec .* failed", "$ sleep\n$"]) - -@test(10, "sleep, makes syscall") -def test_sleep(): - r.run_qemu(shell_script([ - 'sleep 10', - 'echo FAIL' - ]), stop_breakpoint('sys_sleep')) - r.match('\\$ sleep 10', no=['FAIL']) - -@test(20, "pingpong") -def test_pingpong(): - r.run_qemu(shell_script([ - 'pingpong', 'echo OK' - ])) - r.match('^\\d+: received ping$', '^\\d+: received pong$', '^OK$') - -@test(20, "primes") -def test_primes(): - r.run_qemu(shell_script([ - 'primes', 'echo OK' - ])) - args = ['prime %d' % i for i in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]] - args.append('^OK$') - r.match(*args) - -@test(10, "find, in current directory") -def test_find_curdir(): - fn = random_str() - r.run_qemu(shell_script([ - 'echo > %s' % fn, - 'find . %s' % fn - ])) - r.match('./%s' % fn) - -@test(10, "find, recursive") -def test_find_recursive(): - needle = random_str() - dirs = [random_str() for _ in range(3)] - r.run_qemu(shell_script([ - 'mkdir %s' % dirs[0], - 'echo > %s/%s' % (dirs[0], needle), - 'mkdir %s/%s' % (dirs[0], dirs[1]), - 'echo > %s/%s/%s' % (dirs[0], dirs[1], needle), - 'mkdir %s' % dirs[2], - 'echo > %s/%s' % (dirs[2], needle), - 'find . %s' % needle - ])) - r.match('./%s/%s' % (dirs[0], needle), - './%s/%s/%s' % (dirs[0], dirs[1], needle), - './%s/%s' % (dirs[2], needle)) - -@test(19, "xargs") -def test_xargs(): - r.run_qemu(shell_script([ - 'sh < xargstest.sh', - 'echo DONE', - ], 'DONE')) - matches = re.findall("hello", r.qemu.output) - assert_equal(len(matches), 3, "Number of appearances of 'hello'") - -@test(1, "time") -def test_time(): - check_time() - -run_tests() diff --git a/kernel/proc.c b/kernel/proc.c index 58a8a0b..a343244 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -310,6 +310,8 @@ fork(void) safestrcpy(np->name, p->name, sizeof(p->name)); + // 复制掩码 + np->tracemask = p->tracemask; pid = np->pid; release(&np->lock); diff --git a/kernel/proc.h b/kernel/proc.h index d021857..7eabad0 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -91,6 +91,7 @@ struct proc { int killed; // If non-zero, have been killed int xstate; // Exit status to be returned to parent's wait int pid; // Process ID + int tracemask; // Trace Mask // wait_lock must be held when using this: struct proc *parent; // Parent process diff --git a/kernel/syscall.c b/kernel/syscall.c index ed65409..3c81e5f 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -7,6 +7,11 @@ #include "syscall.h" #include "defs.h" +// 保留系统调用别名 +char* syscalls_name[24] = {"", "fork", "exit", "wait", "pipe", "read", "kill", "exec", + "fstat", "chdir", "dup", "getpid", "sbrk", "sleep", "uptime", + "open", "write", "mknod", "unlink", "link", "mkdir", "close", "trace"}; + // Fetch the uint64 at addr from the current process. int fetchaddr(uint64 addr, uint64 *ip) @@ -101,6 +106,7 @@ extern uint64 sys_unlink(void); extern uint64 sys_link(void); extern uint64 sys_mkdir(void); extern uint64 sys_close(void); +extern uint64 sys_trace(void); // An array mapping syscall numbers from syscall.h // to the function that handles the system call. @@ -126,6 +132,7 @@ static uint64 (*syscalls[])(void) = { [SYS_link] sys_link, [SYS_mkdir] sys_mkdir, [SYS_close] sys_close, +[SYS_trace] sys_trace, }; void @@ -139,6 +146,9 @@ syscall(void) // Use num to lookup the system call function for num, call it, // and store its return value in p->trapframe->a0 p->trapframe->a0 = syscalls[num](); + if (p->tracemask & (1 << num)) { + printf("%d: syscall %s -> %d\n",p->pid, syscalls_name[num], p->trapframe->a0); + } } else { printf("%d %s: unknown sys call %d\n", p->pid, p->name, num); diff --git a/kernel/syscall.h b/kernel/syscall.h index bc5f356..cc112b9 100644 --- a/kernel/syscall.h +++ b/kernel/syscall.h @@ -20,3 +20,4 @@ #define SYS_link 19 #define SYS_mkdir 20 #define SYS_close 21 +#define SYS_trace 22 diff --git a/kernel/sysproc.c b/kernel/sysproc.c index 3b4d5bd..46af86b 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -91,3 +91,13 @@ sys_uptime(void) release(&tickslock); return xticks; } + +uint64 +sys_trace(void) +{ + int n; + argint(0, &n); + if(n<0) return -1; + myproc()->tracemask = n; + return 0; +} diff --git a/user/trace.c b/user/trace.c new file mode 100644 index 0000000..386bfc1 --- /dev/null +++ b/user/trace.c @@ -0,0 +1,29 @@ +#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]; + + //保证trace的参数不少于三个,并且跟踪的系统调用号在0-99之间 + if(argc < 3 || (argv[1][0] < '0' || argv[1][0] > '9')){ + fprintf(2, "Usage: %s mask command\n", argv[0]); + exit(1); + } + //调用trace系统调用,传入待跟踪系统调用号 + 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); +} diff --git a/user/user.h b/user/user.h index 075769d..36603a0 100644 --- a/user/user.h +++ b/user/user.h @@ -23,6 +23,7 @@ int getpid(void); char *sbrk(int); int sleep(int); int uptime(void); +int trace(int); // ulib.c int stat(const char *, struct stat *); diff --git a/user/usys.pl b/user/usys.pl index 01e426e..9c97b05 100755 --- a/user/usys.pl +++ b/user/usys.pl @@ -36,3 +36,4 @@ entry("getpid"); entry("sbrk"); entry("sleep"); entry("uptime"); +entry("trace");