2008-09-05
Something to remember when using DTrace on userland programs
As mentioned before, Solaris's DTrace
is fundamentally a kernel debugger; in order to extract information
from userland programs, you need to copy it to kernel space (generally
using DTrace's copyin()
function) before you can start printing it or
otherwise use it.
The most important thing to remember about this is that you wind up
dealing with two sorts of pointers: userland pointers, which is what
are in all of those data structures you copy in from your program, and
kernel pointers, which is what copyin()
and friends return. Let's call
the former 'locations' and the latter 'pointers'.
Keeping them straight is vital, because you have to do different things
in order to use them; you dereference pointers but give locations to
copyin()
, which returns a pointer that you have to dereference in
order to get the actual userland data. Fortunately they have different
types; locations are type uintptr_t
, while pointers are, well,
pointers.
Thus the incantation to get an object of primitive type TYPE (like an
integer, a long, or a pointer) from a user level pointer LOC is:
uintptr_t LOC; TYPE var; var = * ((TYPE *) copyin(LOC, sizeof(TYPE)));
(Unfortunately DTrace doesn't have #define
, or you could make this
a macro.)
If this seems confusing, well, it is.
The DTrace language is very C-like and it lets you define structures
just like C, enough so that you can generally just copy the structure
definitions from your C header files into your DTrace program. However,
watch out; all of the pointers in your program's structures are userland
pointers, ie locations, not kernel pointers (real pointers). You will
avoid a lot of confusion if you take all of those structure definitions
and change the type of every pointer field to be uintptr_t
, so
that you will get a compile time error if you ever attempt to directly
dereference one (instead of tediously doing it via copyin()
).
(The DTrace language helps you out by not having a #include
, so
you have to copy the structure definitions to start with.)
As a suggestion: if you do this, leave yourself a comment about what
type the pointers actually point to, so you can remember what you get
when you dereference them via copyin()
(and how much data you need to
tell copyin()
to copy).