Friday, 8 April 2011

Either I am insane or dtrace is... dtrace_probe_error()

Inside the driver, when an address/fault occurs, a function called
dtrace_probe_error() is invoked. This recursively calls dtrace_probe()
to raise a probe against the ERROR probe. Nice.

Heres the function prototype for:

void dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, int fault, int fltoffs, uintptr_t illval)

This function, which is (perversely) written in assembler in FreeBSD and Solaris,
calls dtrace_probe(). An additional arg is passed back to dtrace_probe --
the internal id of the ERROR probe (dtrace_probeid_error).

All good so far.

But - and its late here, maybe I am too tired - the number of arguments are
*wrong*. The last parameter passed to dtrace_probe() is the "illval" argument
which is the address of a faulting instruction.

Consider this D script:

x = (int *)NULL;
y = *x;

We should get an error from Dtrace telling us we tried to access address
0x0000. But in Linux, we get some other random value. This is because
we cannot pass in the illval address - we ran out of arguments (arg0..arg4).

*Yet* FreeBSD/Solaris pass in the extra arg anyway - one arg too many.

I need to read this more to understand what is going on.

Heres the solaris code:

pushq %rbp
movq %rsp, %rbp
subq $0x8, %rsp
movq %r9, (%rsp) # <=== what is this?!
movq %r8, %r9
movq %rcx, %r8
movq %rdx, %rcx
movq %rsi, %rdx
movq %rdi, %rsi
movl dtrace_probeid_error(%rip), %edi
call dtrace_probe
addq $0x8, %rsp

Post created by CRiSP v10.0.3b-b5955

1 comment:

  1. Hi Paul
    Some Apple code here for comparison...