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