Mathias,

You've on the right track, but you've got a number of basic things wrong. Here's an improved version of your script ...

syscall::recvfrom:entry
/pid != $pid && (execname == $$1 || ($$1 == "" && execname != "dtrace"))/
{
       self->in = 1;

       printf("%Y: ", walltimestamp);

       self->arg0 = arg0; /* int s */
       self->arg1 = arg1; /* void *buf */
       self->arg2 = arg2; /* size_t len */
       self->arg3 = arg3; /* int flags */
       self->arg4 = arg4; /* struct sockaddr *from */
       self->arg5 = arg5; /* socklen_t *fromlen */

       printf("%s(PID:%d) called %s", execname, pid, probefunc);
       printf("(s=%d, buf=\"%S\", len=%d)\n",
           arg0, stringof(copyin(arg1, arg2)), arg2);
}

syscall::recvfrom:return
/self->in/
{
       printf("%Y: ", walltimestamp);

       printf("%s(PID:%d) returned %s", execname, pid, probefunc);
       printf("(s=%d, buf=\"%S\", len=%d) => %d (errno=%d)\n",
           self->arg0,
           stringof(copyin(self->arg1, self->arg2)),
           self->arg2,
           arg0,
           errno);

       self->len = *(socklen_t *) copyin((uintptr_t)self->arg5,
           sizeof(socklen_t));
       self->socks = (struct sockaddr *) copyin((uintptr_t)self->arg4,
           self->len);

       self->hport = (uint_t)(self->socks->sa_data[0]);
       self->lport = (uint_t)(self->socks->sa_data[1]);
       self->hport <<= 8;
       self->port = self->hport + self->lport;
       printf("Port number: %d\n", self->port);

       printf("IP address: %d.%d.%d.%d\n",
           self->socks->sa_data[2],
           self->socks->sa_data[3],
           self->socks->sa_data[4],
           self->socks->sa_data[5]);
       printf("======\n");

       self->in = 0;
}

Your code wasn't thread safe because you were using global variables (I've added more self-> prefixes), and you weren't matching entry and return probes (I've added the customary "self->in" gate which also saves you from a return probe firing first and simplifies the return probe predicate).

It may be possible to improve your entry probe predicate, but not knowing how you intend to use the script, I thought I'd leave that well alone.

I'm not claiming that this is the definitive implementation, and there may be other bugs which others can spot, but the above is a more correct version of what I think you intended.

Your main bug, was to forget that fromlen is a pointer, which means you also need to copyin() the fromlen value before you can use it.

Hope this helps,
Phil


Mathias Koerber wrote:
I am new to Dtrace, so bear with me...

I am trying to debug a problem where outgoing (reply) UDP packets are
apparently lost from a server, though I have good reason to believe that
the daemon actually sends them, but they may get routed on the wrong
interface, or lost elsewhere.

To verify this, but in order to avoid the high impact truss may have,
I am trying to write a Dtrace script that logs all network
activity. Note that this is for SOlaris 10, so I have no ip provider or
such available.


However, after many iterations I am not getting past some errors which
are leaving me baffled:

Here is the script I tried:

BEGIN
{
        printf("tracing starts at %d=%Y\n", timestamp,walltimestamp);
}

END
{
        printf("tracing ends at %d\n", timestamp);
}

syscall::recvfrom:entry
/pid != $pid && (execname == $$1 || ($$1 == "" && execname != "dtrace"))/
{
printf("%Y: ", walltimestamp);

self->desc     = (int )   arg0; /* file descriptor passed to write() */
self->bufp     = (uintptr_t) arg1; /* buffer pointer passed to write() */
self->size     = (size_t) arg2; /* size, in bytes passed to write() */
self->flags    = (int)    arg3; /* flags */
self->from     = (struct sockaddr *) arg4;
self->fromlen  = (socklen_t *)       arg5;

printf("%s(PID:%d) called %s(rc=%d) (socket=%d,\nbuf=\"%S\"\n size=%d) => 
err=%d\n", execname, pid, probefunc, arg0,
        self->desc,
        stringof(copyin(self->bufp, self->size)),
        self->size,
        errno);
}



syscall::recvfrom:return
/pid != $pid && (execname == $$1 || ($$1 == "" && execname != "dtrace"))/
{
printf("%Y: ", walltimestamp);

printf("%s(PID:%d) returned %s(rc=%d) (socket=%d,\nbuf=\"%S\"\n size=%d) => err=%d\n", execname, pid, probefunc, arg0, self->desc,
        stringof(copyin(self->bufp, (ssize_t)arg0)),
        self->size,
        errno);

     ** Note, since the size of the buffer is returned in
        the returncode, I am using arg0 here to copy that data into the
        kernel.

printf("self->from = 0x%x\n", (long) self->from);
printf("self->fromlen = 0x%x\n", (long) self->fromlen);

socks = (struct sockaddr *) copyin( (uintptr_t)self->from, *((socklen_t *)self->fromlen) );

     ** similarly, the fromlen parameter points to the size of the
        address-structure returned... So is the above correct?

hport = (uint_t)(socks->sa_data[0]);
lport = (uint_t)(socks->sa_data[1]);
hport <<= 8;
port = hport + lport;
printf("Port number: %d\n", port);
printf("IP address: %d.%d.%d.%d\n", socks->sa_data[2],
socks->sa_data[3],
socks->sa_data[4],
socks->sa_data[5]);
printf("======\n");

self->desc    = 0;
self->bufp    = 0;
self->size    = 0;
self->flags   = 0;
self->from    = 0;
self->fromlen = 0;
self->sock    = 0;
}



However, calling this to trace the process 'v' I get:

# dtrace  -q -s v.d v
tracing starts at 488313267882683=2009 Nov 15 23:32:43
2009 Nov 15 23:32:45: v(PID:657) called recvfrom(rc=12) (socket=12,
buf="\0"
 size=4000) => err=0
dtrace: error on enabled probe ID 4 (ID 43897: syscall::recvfrom:return): 
invalid address (0xfffffd7ffdf18c8c) in action #12 at DIF offset 8
2009 Nov 15 23:32:45: v(PID:657) called recvfrom(rc=12) (socket=12,
buf="\004\227\001\0"
 size=4000) => err=0
dtrace: error on enabled probe ID 4 (ID 43897: syscall::recvfrom:return): out 
of scratch space in action #7 at DIF offset 40
^C
tracing ends at 488317440553167

Why am I getting out of scratch-space?

And where does the invalid address come from? I am specifically not
trying to access the data in the user-process but using copyin to copy
it for dtrace access, but why am I getting this problem ?

Any help is appreciated.

I had a look at the Dtrace tools like dtruss etc, but there doesn't seem
to be one that monitors a processes detailed network traffic. If there
is I would appreciate a pointer

Thanks
M

_______________________________________________
dtrace-discuss mailing list
dtrace-discuss@opensolaris.org

_______________________________________________
dtrace-discuss mailing list
dtrace-discuss@opensolaris.org

Reply via email to