bin/52190: [Patch] decode more syscalls in truss

Dan Nelson dnelson at allantgroup.com
Tue Nov 11 20:50:28 PST 2003


The following reply was made to PR bin/52190; it has been noted by GNATS.

From: Dan Nelson <dnelson at allantgroup.com>
To: FreeBSD-gnats-submit at 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.
     */
 
 


More information about the freebsd-bugs mailing list