D377 - A syscall gadget is not a function

decided - 2026-08-29

D376 ended on ptr_syscall: klogsrv renders its message with vsnprintf and then calls a raw syscall gadget. Watching that call needed a stub unlike every other one here.

Every other diagnostic reports arguments, and that is not enough

The handoff reporters shift the guest's arguments along and print three of them, which is right for a function. A syscall gadget is not a function. The number it is being asked to perform arrives in rax, and the fourth argument arrives in r10 rather than rcx, because that is what the syscall instruction uses. No argument-shaped report can see either.

So a gadget stub saves rax, the six argument registers and r10 into its own buffer and prints all eight. Between them they say which convention the caller used, which is the whole question. One buffer per stub, so two guest threads calling two gadgets cannot overwrite each other's report.

The measurement moved the thing it was measuring, twice

First, by renumbering. Markers were numbered by how many markers had been issued, so pointing one global at a stub renumbered every marker after it - and the guest computes with those values (D368). Numbered by the global's own position now, so watching one changes nothing about the others.

Second, and this is the finding. With ptr_syscall holding an unmapped marker, the run reaches it and stops there, reproducibly. With it holding a stub - an address that is real and executable - the run fails earlier, inside vsnprintf.

So the guest tests ptr_syscall before using it, and takes a different path when it is set. That is worth more than the register dump would have been: it says a stub answering zero is not enough. A gadget that exists must work, because a program that finds one there proceeds as though syscalls are available.

What that means for the next unit

The syscall boundary has to be implemented rather than stubbed. That is bounded work and nothing about it is a mystery: the numbers are in sys/sys/syscall.h in the checkout the ABI constants already come from, the convention is FreeBSD's, and the implementations the numbers map onto are written already - read, write, open, close, getpid and the rest have been here for a while under their names.

What is not free is that a syscall dispatcher is orbistoun being the kernel, and every number it does not know has to fail the way the kernel would rather than the way a stub does.