xv6, line by line
lab 1
Lab 11 trace: logging system calls

Lab 1 · reveal · 17 steps · 6 commits

trace: logging system calls: the reference solution

You add a new system call, trace(mask), and a command, trace MASK command args.... While a process’s mask has bit i set, the kernel prints one line each time system call number i returns: 3: syscall read -> 1023. Children made by fork inherit the mask, and exec keeps it, so trace 32 grep hello README shows every read that grep makes.

The feature is small (about fifty lines of kernel code, half of them a table of names), but building it walks you through every layer a system call crosses, from the three-instruction user stub to the trapframe and back. You will see every place a new system call must be registered and why each one exists, where per-process state lives and what fork copies under which lock, and why the only place that can print the return value is right after the call in syscall. On three harts, you will also see that printk’s lock keeps trace lines whole with respect to each other, but not with respect to a user program’s output.

Each step shows one change on the branch ext/01-trace, the code around it, and the state of the machine when that code runs.

The route
  1. 1A number both sides agree on kernel/syscall.h
  2. 2The stub that makes the trap user/usys.pl
  3. 3usertrap hands the call to syscall() kernel/trap.c
  4. 4Without a table entry, 23 is unknown kernel/syscall.c
  5. 5The mask is private to the process kernel/proc.h
  6. 6sys_trace swaps the mask kernel/sysproc.c
  7. 7argint reads the saved a0 kernel/syscall.c
  8. 8Registering the handler kernel/syscall.c
  9. 9freeproc clears the mask kernel/proc.c
  10. 10kfork copies the mask while it holds the child's lock kernel/proc.c
  11. 11A names table indexed like the handler table kernel/syscall.c
  12. 12Print after the call, when the result is known kernel/syscall.c
  13. 13Inside printk, pr.lock keeps the line whole kernel/printk.c
  14. 14The value reaches user space in a0 kernel/trampoline.S
  15. 15The child returns from fork without syscall() kernel/proc.c
  16. 16The trace command is set-mask-then-exec user/trace.c
  17. 17The test checks what a program can see user/tracetest.c

Keys: ← → step · Home start