Exploring a limitation of the DTrace fbt provider (on x86)

December 8, 2010

The fine documentation for DTrace's kernel function tracer contains a little note that you might easily miss if, like me, you were just skimming:

For each instruction set, there are a small number of functions that do not call other functions and are highly optimized by the compiler (so-called leaf functions) that cannot be instrumented by FBT.

The first thing to know is that DTrace does not have any useful error messages when you run into this. Instead of a helpful note about, say, 'this function exists but cannot be traced', you get the generic report 'probe description fbt:<X>:entry does not match any probes'. If you know that the function exists, this is what you're running into.

(And speaking from personal experience, it is very puzzling and annoying if you've run into it and you didn't notice the note in the documentation. I spent rather a lot of time beating my head against this.)

The 'x86 Limitations' section of the fbt documentation has slightly more detail about what is going on; the real condition is that any function that doesn't create a stack frame can't be traced. 'Highly optimized' is a little bit of a misnomer, as I suspect that the real condition is closer to 'doesn't do very much'.

(In the case that I ran into yesterday, the function just did some very simple math with some global variables in order to return a boolean yes/no value.)

Why this limitation exists is that DTrace's fbt provider works by overwriting a bit of the function prequel so that it invokes DTrace hooks instead. Of course the DTrace hooks then have to do what the overwritten code would have done, and this only works if they know what that is and can easily duplicate it. On x86, the interception is done in part of the standard instruction sequence that sets up the function's stack frame; a function with no stack frame has no standard instruction sequence to set it up and thus no place for DTrace to safely overwrite.

Specifically, on 64-bit x86 DTrace overwrites pushq %rbp with int $0x3. You can actually see this in action with mdb -k if you want to by disassembling the first instruction of the function (with 'func/i') before and after you add a DTrace probe on the function. Note that fbt instruments both function entry and function returns no matter which you asked for.

This provides a convenient way to both check to see if a function exists and if it can be traced by fbt; start up mdb -k and disassemble the start of the function, looking for the pushq. If mdb can't find the function at all, there's a difference between the OpenSolaris code you're looking at and the Solaris that you're running.

(More details about this are in uts/intel/dtrace/fbt.c in the OpenSolaris code.)

PS: I'm aware that using 'mdb -k' instead of just having DTrace dump all fbt hooks is only convenient for a certain sort of person. I just happen to be that sort of person.

Written on 08 December 2010.
« More on https as a necessary mistake
A small request for C programmers: no static locals »

Page tools: View Source, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Wed Dec 8 00:58:17 2010
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.