0

I'm tracking some libc functions with dtrace. I want to make a predicate that only executes the action when the function returns to an adress into a specific module given in the parameters.

copyin(uregs[R_ESP],1) on the return probe should give the return adress i think, i'm not entirely sure of it so it would be nice if someone can confirm.

But then i need a way to resolve that adress to a module, is this possible and how?

Vision
  • 57
  • 5

1 Answers1

1

There is a ucaller variable which will give you the saved program counter as a uint64_t and umod() will translate it into the corresponding module name, e.g.

# dtrace -n 'pid$target:::entry {@[umod(ucaller)]=count()}' -p `pgrep -n xscreensaver`
dtrace: description 'pid$target:::entry ' matched 14278 probes
^C

  xscreensaver                                                     16
  libXt.so.4                                                       73
  libX11.so.4                                                      92
  libxcb.so.1                                                     141
  libc.so.1                                                       144
^C# 

However, umod() is an action (as opposed to a subroutine); it cannot be assigned to an lvalue and therefore cannot be used in an expression (because the translation is deferred until the address is received by the dtrace(1) user-land program).

Fortunately, there's nothing stopping you from finding the address range occupied by libc in your process and comparing it with ucaller. Here's an example on Solaris (where a hardware-specific libc is mounted at boot time):

# mount | fgrep libc
/lib/libc.so.1 on /usr/lib/libc/libc_hwcap1.so.1 read/write/setuid/devices/rstchown/dev=30d0002 on Sat Jul 13 20:27:32 2013
# pmap `pgrep -n gedit` | fgrep libc_hwcap1.so.1
FEE10000    1356K r-x--  /usr/lib/libc/libc_hwcap1.so.1
FEF73000      44K rwx--  /usr/lib/libc/libc_hwcap1.so.1
FEF7E000       4K rwx--  /usr/lib/libc/libc_hwcap1.so.1
#

I'll assume that the text section is the one with only read & execute permissions, but note that in some circumstances the text section will be writeable.

# cat Vision.d 
/*
 * self->current is a boolean indicating whether or not execution is currently
 * within the target range.
 *
 * self->next is a boolean indicating whether or not execution is about to
 * return to the target range.
 */
BEGIN
{
    self->current = 1;
}

pid$target:::entry
{   
    self->current = (uregs[R_PC] >= $1 && uregs[R_PC] < $2);
}

syscall:::return
/pid==$target/
{
    self->next = self->current;
    self->current = 0;
}

pid$target:::return
{
    self->next = (ucaller >= $1 && ucaller < $2);
}

pid$target:::return,syscall:::return
/pid==$target && self->next && !self->current/
{
    printf("Returning to target from %s:%s:%s:%s...\n",
        probeprov, probemod, probefunc, probename);
    ustack();
    printf("\n");
}

pid$target:::return,syscall:::return
/pid==$target/
{
    self->current = self->next;
} 
# dtrace -qs Vision.d 0xFEE10000 0xFEF73000 -p `pgrep -n gedit`

This produces results like

Returning to target from pid2095:libcairo.so.2.10800.10:cairo_bo_event_compare:return...

              libcairo.so.2.10800.10`cairo_bo_event_compare+0x158
              libc.so.1`qsort+0x51c
              libcairo.so.2.10800.10`_cairo_bo_event_queue_init+0x122
              libcairo.so.2.10800.10`_cairo_bentley_ottmann_tessellate_bo_edges+0x2d
              libcairo.so.2.10800.10`_cairo_bentley_ottmann_tessellate_polygon+0
              .
              .
              .

Returning to target from syscall::pollsys:return...

              libc.so.1`__pollsys+0x15
              libc.so.1`poll+0x81
              libxcb.so.1`_xcb_conn_wait+0xb5
              libxcb.so.1`_xcb_out_send+0x3b
              libxcb.so.1`xcb_writev+0x65
              libX11.so.4`_XSend+0x17c
              libX11.so.4`_XFlush+0x30
              libX11.so.4`XFlush+0x37
Robert Harris
  • 1,522
  • 9
  • 11