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>
next in thread | raw e-mail | index | archive | help
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. */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200311120450.hAC4oQto026412>