Don’t underestimate the value of
printf. The way
printf is implemented in Pintos, you can call it from practically anywhere in the kernel, whether it’s in a kernel thread or an interrupt handler, almost regardless of what locks are held.
printf is useful for more than just examining data. It can also help figure out when and where something goes wrong, even when the kernel crashes or panics without a useful error message. The strategy is to sprinkle calls to
printf with different strings (e.g.:
...) throughout the pieces of code you suspect are failing. If you don’t even see
<1> printed, then something bad happened before that point, if you see
<1> but not
<2>, then something bad happened between those two points, and so on. Based on what you learn, you can then insert more
printf calls in the new, smaller region of code you suspect. Eventually you can narrow the problem down to a single statement. See section Triple Faults, for a related technique.