Date: Tue, 11 Nov 2003 20:50:26 -0800 (PST) From: Dan Nelson <dnelson@allantgroup.com> To: freebsd-bugs@FreeBSD.org Subject: Re: bin/52190: [Patch] decode more syscalls in truss Message-ID: <200311120450.hAC4oQto026412@freefall.freebsd.org>
index | next in thread | raw e-mail
The following reply was made to PR bin/52190; it has been noted by GNATS.
From: Dan Nelson <dnelson@allantgroup.com>
To: FreeBSD-gnats-submit@FreeBSD.org
Cc:
Subject: Re: bin/52190: [Patch] decode more syscalls in truss
Date: Tue, 11 Nov 2003 22:44:25 -0600
Another update. Also decode struct sigaction, getitimer(),
setitimer(), and pipe().
Index: syscall.h
===================================================================
RCS file: /home/ncvs/src/usr.bin/truss/syscall.h,v
retrieving revision 1.11
diff -u -p -r1.11 syscall.h
--- syscall.h 9 Nov 2003 03:48:13 -0000 1.11
+++ syscall.h 12 Nov 2003 00:05:15 -0000
@@ -9,9 +9,18 @@
* write() arguments as such, even though they may *not* be
* printable data.
* Ptr -- pointer to some specific structure. Just print as hex for now.
- * Quad -- a double-word value. e.g., lseek(int, offset_t, int)
* Stat -- a pointer to a stat buffer. Currently unused.
* Ioctl -- an ioctl command. Woefully limited.
+ * Quad -- a double-word value. e.g., lseek(int, offset_t, int)
+ * Signal -- a signal number. Prints the signal name (SIGxxx)
+ * Sockaddr -- a pointer to a struct sockaddr. Prints symbolic AF, and IP:Port
+ * StringArray -- a pointer to an array of string pointers.
+ * Timespec -- a pointer to a struct timespec. Prints both elements.
+ * Timeval -- a pointer to a struct timeval. Prints both elements.
+ * Itimerval -- a pointer to a struct itimerval. Prints all elements.
+ * Pollfd -- a pointer to an array of struct pollfd. Prints .fd and .events.
+ * Fd_set -- a pointer to an array of fd_set. Prints the fds that are set.
+ * Sigaction -- a pointer to a struct sigaction. Prints all elements.
*
* In addition, the pointer types (String, Ptr) may have OUT masked in --
* this means that the data is set on *return* from the system call -- or
@@ -22,7 +31,8 @@
*/
enum Argtype { None = 1, Hex, Octal, Int, String, Ptr, Stat, Ioctl, Quad,
- Signal, Sockaddr, StringArray };
+ Signal, Sockaddr, StringArray, Timespec, Timeval, Itimerval, Pollfd,
+ Fd_set, Sigaction, PipeArg };
#define ARG_MASK 0xff
#define OUT 0x100
Index: syscalls.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/truss/syscalls.c,v
retrieving revision 1.32
diff -u -p -r1.32 syscalls.c
--- syscalls.c 9 Nov 2003 03:48:13 -0000 1.32
+++ syscalls.c 12 Nov 2003 04:33:56 -0000
@@ -48,6 +48,7 @@ static const char rcsid[] =
#include <ctype.h>
#include <err.h>
+#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -110,7 +111,7 @@ struct syscall syscalls[] = {
{ "exit", 0, 1, { { Hex, 0 }}},
{ "access", 1, 2, { { String | IN, 0 }, { Int, 1 }}},
{ "sigaction", 1, 3,
- { { Signal, 0 }, { Ptr | IN, 1 }, { Ptr | OUT, 2 }}},
+ { { Signal, 0 }, { Sigaction | IN, 1 }, { Sigaction | OUT, 2 }}},
{ "accept", 1, 3,
{ { Hex, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
{ "bind", 1, 3,
@@ -135,9 +136,29 @@ struct syscall syscalls[] = {
{ "kldnext", 0, 1, { { Int, 0 }}},
{ "kldstat", 0, 2, { { Int, 0 }, { Ptr, 1 }}},
{ "kldfirstmod", 0, 1, { { Int, 0 }}},
+ { "nanosleep", 0, 1, { { Timespec, 0 }}},
+ { "select", 1, 5, { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 }, { Timeval, 4 }}},
+ { "poll", 1, 3, { { Pollfd, 0 }, { Int, 1 }, { Int, 2 }}},
+ { "gettimeofday", 1, 2, { { Timeval | OUT, 0 }, { Ptr, 1 }}},
+ { "clock_gettime", 1, 2, { { Int, 0 }, { Timeval | OUT, 1 }}},
+ { "recvfrom", 1, 6, { { Int, 0 }, { Ptr | OUT, 1 }, { Int, 2 }, { Int, 3 }, { Sockaddr | OUT, 4}, {Ptr | OUT, 5}}},
+ { "getitimer", 1, 2, { { Int, 0 }, { Itimerval | OUT, 2 }}},
+ { "setitimer", 1, 3, { { Int, 0 }, { Itimerval, 1} , { Itimerval | OUT, 2 }}},
{ 0, 0, 0, { { 0, 0 }}},
};
+const char* const pollflags[] = {
+ "IN", "PRI", "OUT", "ERR", /* 0x000n */
+ "HUP", "NVAL", "RDNORM", "RDBAND", /* 0x00n0 */
+ "WRBAND", "INIGNEOF", NULL /* 0x0n00 */
+};
+
+const char* const saflags[] = {
+ "SA_ONSTACK", "SA_RESTART", "SA_RESETHAND", "SA_NOCLDSTOP", /* 0x000n */
+ "SA_NODEFER", "SA_NOCLDWAIT", "SA_SIGINFO", "*ERROR*", /* 0x00n0 */
+ "SA_USERTRAMP", NULL /* 0x0n00 */
+};
+
/*
* If/when the list gets big, it might be desirable to do it
* as a hash table or binary search.
@@ -163,21 +184,8 @@ get_syscall(const char *name) {
static int
get_struct(int procfd, void *offset, void *buf, int len) {
- char *pos;
- FILE *p;
- int c, fd;
-
- if ((fd = dup(procfd)) == -1)
- err(1, "dup");
- if ((p = fdopen(fd, "r")) == NULL)
- err(1, "fdopen");
- fseeko(p, (uintptr_t)offset, SEEK_SET);
- for (pos = (char *)buf; len--; pos++) {
- if ((c = fgetc(p)) == EOF)
- return -1;
- *pos = c;
- }
- fclose(p);
+ if (pread(procfd, buf, len, (uintptr_t)offset) != len)
+ return -1;
return 0;
}
@@ -329,6 +337,141 @@ print_arg(int fd, struct syscall_args *s
asprintf(&tmp, "0x%lx", args[sc->offset]);
}
break;
+ case Timespec:
+ {
+ struct timespec ts;
+ if (get_struct(fd, (void *)args[sc->offset], &ts, sizeof(struct timespec)) != -1)
+ asprintf(&tmp, "{%d %d}", ts.tv_sec, ts.tv_nsec);
+ else
+ asprintf(&tmp, "0x%lx", args[sc->offset]);
+ }
+ break;
+ case Timeval:
+ {
+ struct timeval tv;
+ if (get_struct(fd, (void *)args[sc->offset], &tv, sizeof(struct timeval)) != -1)
+ asprintf(&tmp, "{%d %d}", tv.tv_sec, tv.tv_usec);
+ else
+ asprintf(&tmp, "0x%lx", args[sc->offset]);
+ }
+ break;
+ case Itimerval:
+ {
+ struct itimerval itv;
+ if (get_struct(fd, (void *)args[sc->offset], &itv, sizeof(struct itimerval)) != -1)
+ asprintf(&tmp, "{%d %d, %d %d}",
+ itv.it_interval.tv_sec, itv.it_interval.tv_usec,
+ itv.it_value.tv_sec, itv.it_value.tv_usec);
+ else
+ asprintf(&tmp, "0x%lx", args[sc->offset]);
+ }
+ break;
+ case Pollfd:
+ {
+ /*
+ * XXX: A Pollfd argument expects the /next/ syscall argument to be
+ * the number of fds in the array. This matches the poll syscall.
+ */
+ struct pollfd *pfd;
+ int numfds = args[sc->offset+1];
+ int bytes = sizeof(struct pollfd) * numfds;
+ pfd = malloc(bytes);
+ if (!pfd)
+ err(1, "Cannot malloc %d bytes for pollfd array", bytes);
+ if (get_struct(fd, (void *)args[sc->offset], pfd, bytes) != -1)
+ {
+ int i;
+ int used = 0;
+ int tmpsize = 1024;
+ char *tmp2;
+
+ /*
+ Pollfd's output can vary wildly in size, so just allocate a 1k
+ buffer and double its size whenever it gets close to filling up.
+ */
+ tmp = malloc(tmpsize);
+ if (!tmp)
+ err(1, "Cannot alloc %d bytes for poll output", tmpsize);
+
+ used += sprintf(tmp + used, "{");
+ for (i = 0; i < numfds; i++)
+ {
+ used += sprintf(tmp + used, "%s%d", i>0 ? " " : "", pfd[i].fd);
+ if (pfd[i].events)
+ {
+ int j;
+ for (j = 0; pollflags[j]; j++)
+ if (pfd[i].events & 1<<j)
+ used += sprintf(tmp + used, "|%s", pollflags[j]);
+ }
+
+ if (used + 100 > tmpsize)
+ {
+ tmpsize = tmpsize * 2;
+ tmp = realloc(tmp, tmpsize);
+ if (!tmp)
+ err(1, "Cannot realloc %d bytes for poll output", tmpsize);
+ }
+ }
+ used += sprintf(tmp + used, "}");
+ }
+ else
+ asprintf(&tmp, "0x%lx", args[sc->offset]);
+ free(pfd);
+ }
+ break;
+ case Fd_set:
+ {
+ /*
+ * XXX: A Fd_set argument expects the /first/ syscall argument to be
+ * the number of fds in the array. This matches the select syscall.
+ */
+ fd_set *fds;
+ int numfds = args[0];
+ int bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
+ fds = malloc(bytes);
+ if (!fds)
+ err(1, "Cannot malloc %d bytes for fd_set array", bytes);
+ if (get_struct(fd, (void *)args[sc->offset], fds, bytes) != -1)
+ {
+ char *tmp2;
+ int tmpsize = 1024;
+ int used = 0;
+ int i;
+
+ /*
+ * The number of set bits can vary wildly in size, so just allocate
+ * a 1k buffer and double its size whenever it gets close to
+ * filling up.
+ */
+
+ tmp = malloc(tmpsize);
+ if (!tmp)
+ err(1, "Cannot alloc %d bytes for fd_set output", tmpsize);
+
+ used += sprintf(tmp + used, "{");
+ for (i = 0; i < numfds; i++)
+ {
+ if (FD_ISSET(i, fds))
+ used += sprintf(tmp + used, "%d ", i);
+
+ if (used + 100 > tmpsize)
+ {
+ tmpsize = tmpsize * 2;
+ tmp = realloc(tmp, tmpsize);
+ if (!tmp)
+ err(1, "Cannot realloc %d bytes for fd_set output", tmpsize);
+ }
+ }
+ if (tmp[used-1] == ' ')
+ used--;
+ used += sprintf(tmp + used, "}");
+ }
+ else
+ asprintf(&tmp, "0x%lx", args[sc->offset]);
+ free(fds);
+ }
+ break;
case Signal:
{
long sig;
@@ -402,6 +545,30 @@ print_arg(int fd, struct syscall_args *s
p += sprintf(p, " %#02x,", *q);
}
}
+ }
+ break;
+ case Sigaction:
+ {
+ struct sigaction sa;
+ if (get_struct(fd, (void *)args[sc->offset], &sa, sizeof(struct sigaction)) != -1)
+ {
+ int used = 0;
+ tmp = malloc(1024);
+ used += sprintf(tmp + used, "{ 0x%lx ", sa.sa_handler);
+ if (sa.sa_flags)
+ {
+ int j;
+ for (j = 0; saflags[j]; j++)
+ if (sa.sa_flags & 1<<j)
+ used += sprintf(tmp + used, "%s|", saflags[j]);
+ used--;
+ } else
+ used += sprintf(tmp + used, "0");
+ used += sprintf(tmp + used, " ss_t");
+ used += sprintf(tmp + used, " }");
+ } else
+ asprintf(&tmp, "0x%lx", args[sc->offset]);
+
}
break;
}
Index: i386-fbsd.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/truss/i386-fbsd.c,v
retrieving revision 1.20
diff -u -p -r1.20 i386-fbsd.c
--- i386-fbsd.c 9 Nov 2003 03:48:13 -0000 1.20
+++ i386-fbsd.c 12 Nov 2003 04:22:24 -0000
@@ -329,6 +329,19 @@ i386_syscall_exit(struct trussinfo *trus
}
/*
+ * The pipe syscall returns its fds in two registers and has assembly glue
+ * to provide the libc API, so it cannot be handled like regular syscalls.
+ * The nargs check is so we don't have to do yet another strcmp on every
+ * syscall.
+ */
+ if (!errorp && fsc.nargs == 0 && strcmp(fsc.name, "pipe") == 0) {
+ fsc.nargs = 1;
+ fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*));
+ asprintf(&fsc.s_args[0], "[%d,%d]", retval, regs.r_edx);
+ retval = 0;
+ }
+
+ /*
* It would probably be a good idea to merge the error handling,
* but that complicates things considerably.
*/
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200311120450.hAC4oQto026412>
