From dan@dan.emsphone.com  Tue May 13 11:34:54 2003
Return-Path: <dan@dan.emsphone.com>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id D5B0937B401
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 13 May 2003 11:34:54 -0700 (PDT)
Received: from dan.emsphone.com (dan.emsphone.com [199.67.51.101])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 4409F43F75
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 13 May 2003 11:34:54 -0700 (PDT)
	(envelope-from dan@dan.emsphone.com)
Received: (from dan@localhost)
	by dan.emsphone.com (8.12.9/8.12.9) id h4DIYreY097942;
	Tue, 13 May 2003 13:34:53 -0500 (CDT)
	(envelope-from dan)
Message-Id: <200305131834.h4DIYreY097942@dan.emsphone.com>
Date: Tue, 13 May 2003 13:34:53 -0500 (CDT)
From: Dan Nelson <dnelson@allantgroup.com>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: [Patch] decode more syscalls in truss
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         52190
>Category:       bin
>Synopsis:       [Patch] decode more syscalls in truss
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    pav
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Tue May 13 11:40:05 PDT 2003
>Closed-Date:    Mon May 15 21:19:12 GMT 2006
>Last-Modified:  Mon May 15 21:19:12 GMT 2006
>Originator:     Dan Nelson
>Release:        FreeBSD 5.1-BETA i386
>Organization:
The Allant Group
>Environment:
System: FreeBSD dan.emsphone.com 5.1-BETA FreeBSD 5.1-BETA #269: Tue May 13 09:30:33 CDT 2003 zsh@dan.emsphone.com:/usr/src/sys/i386/compile/DANSMP i386


	
>Description:
	
>How-To-Repeat:
	
>Fix:

This adds the ability to decode struct timespec and timeval, and adds a
bunch of syscalls that use them.  As a bonus, describe recvfrom to its
sockaddr can be printed.

Index: syscall.h
===================================================================
RCS file: /home/ncvs/src/usr.bin/truss/syscall.h,v
retrieving revision 1.10
diff -u -p -r1.10 syscall.h
--- syscall.h	4 Aug 2002 02:24:21 -0000	1.10
+++ syscall.h	13 May 2003 17:24:08 -0000
@@ -9,9 +9,14 @@
  *	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.
  *
  * 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 +27,7 @@
  */
 
 enum Argtype { None = 1, Hex, Octal, Int, String, Ptr, Stat, Ioctl, Quad,
-	Signal, Sockaddr, StringArray };
+	Signal, Sockaddr, StringArray, Timespec, Timeval };
 
 #define ARG_MASK	0xff
 #define OUT	0x100
Index: syscalls.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/truss/syscalls.c,v
retrieving revision 1.28
diff -u -p -r1.28 syscalls.c
--- syscalls.c	15 Apr 2003 06:12:12 -0000	1.28
+++ syscalls.c	13 May 2003 16:18:16 -0000
@@ -131,6 +131,12 @@ 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 }, { Ptr, 1 }, { Ptr, 2 }, { Ptr, 3 }, { Timeval, 4 }}},
+	{ "poll", 1, 3, { { Ptr, 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}}},
 	{ 0, 0, 0, { { 0, 0 }}},
 };
 
@@ -333,6 +339,24 @@ print_arg(int fd, struct syscall_args *s
       }
     }
     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 Signal:
     {
       long sig;
>Release-Note:
>Audit-Trail:

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, 3 Jun 2003 17:54:06 -0500

 Updated patch that decodes struct pollfd and fd_set, fixes a memory
 leak in get_struct(), and avoids a unnecessary abort when a NULL
 sockaddr is passed to recvfrom().
 
 Index: syscall.h
 ===================================================================
 RCS file: /home/ncvs/src/usr.bin/truss/syscall.h,v
 retrieving revision 1.10
 diff -p -u -r1.10 syscall.h
 --- syscall.h	4 Aug 2002 02:24:21 -0000	1.10
 +++ syscall.h	2 Jun 2003 19:15:54 -0000
 @@ -9,9 +9,16 @@
   *	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.
 + * 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.
   *
   * 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 +29,7 @@
   */
  
  enum Argtype { None = 1, Hex, Octal, Int, String, Ptr, Stat, Ioctl, Quad,
 -	Signal, Sockaddr, StringArray };
 +	Signal, Sockaddr, StringArray, Timespec, Timeval, Pollfd, Fd_set };
  
  #define ARG_MASK	0xff
  #define OUT	0x100
 Index: syscalls.c
 ===================================================================
 RCS file: /home/ncvs/src/usr.bin/truss/syscalls.c,v
 retrieving revision 1.28
 diff -p -u -r1.28 syscalls.c
 --- syscalls.c	15 Apr 2003 06:12:12 -0000	1.28
 +++ syscalls.c	3 Jun 2003 22:45:57 -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>
 @@ -131,9 +132,21 @@ 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}}},
  	{ 0, 0, 0, { { 0, 0 }}},
  };
  
 +const char* const pollflags[] = {
 +    "IN", "PRI", "OUT", "ERR",              /* 0x000n */
 +    "HUP", "NVAL", "RDNORM", "RDBAND",      /* 0x00n0 */
 +    "WRBAND", "INIGNEOF", NULL              /* 0x0n00 */
 +};
 +
  /*
   * If/when the list gets big, it might be desirable to do it
   * as a hash table or binary search.
 @@ -159,21 +172,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)
 +	if (pread(procfd, buf, len, (uintptr_t)offset) != len)
  			return -1;
 -		*pos = c;
 -	}
 -	fclose(p);
  	return 0;
  }
  
 @@ -333,6 +333,127 @@ print_arg(int fd, struct syscall_args *s
        }
      }
      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 Pollfd:
 +    {
 +      /* XXX: A Pollfd argument expects the /next/ syscall argument to be
 +         the number of fds in the array, which is what poll() does.
 +      */
 +      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 realloc %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, which is what select() does.
 +      */
 +      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;
 +
 +        /*
 +           FD_set'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 realloc %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;
 @@ -360,6 +481,12 @@ print_arg(int fd, struct syscall_args *s
        char *p;
        u_char *q;
        int i;
 +
 +      if (args[sc->offset] == NULL)
 +      {
 +        asprintf(&tmp, "0x0");
 +        break;
 +      }
  
        /* yuck: get ss_len */
        if (get_struct(fd, (void *)args[sc->offset], (void *)&ss,

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.
     */
 
 
Responsible-Changed-From-To: freebsd-bugs->dwmalone 
Responsible-Changed-By: dwmalone 
Responsible-Changed-When: Thu Jan 8 01:43:07 PST 2004 
Responsible-Changed-Why:  
I'll try to have a look at this, unless someone beats me to it. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=52190 

From: Dan Nelson <dnelson@allantgroup.com>
To: FreeBSD-gnats-submit@FreeBSD.org
Cc:  
Subject: Re: bin/52190: [Patch] decode more syscalls in truss
Date: Wed, 2 Mar 2005 20:13:39 -0600

 Another update.  
 
 - Add decoding of kse_release, kevent, sigprocmask,
   unmount, socket, getrusage, rename, __getcwd, shutdown, getrlimit,
   setrlimit, utimes, lutimes.  
 
 - Decode more arguments of open, mprot, *stat, and fcntl.  
 
 - Convert all constant-macro and bitfield decoding to lookup tables;
   much cleaner than previous code.
 
 - Print escaped string contents of read and write syscalls (amount
   selectable by new -s option).
 
 - Print the timestamp of process exit and signal reception when -d or 
   -D are in use
 
 Index: extern.h
 ===================================================================
 RCS file: /home/ncvs/src/usr.bin/truss/extern.h,v
 retrieving revision 1.9
 diff -u -p -r1.9 extern.h
 --- extern.h	17 Jul 2004 19:19:36 -0000	1.9
 +++ extern.h	25 Jan 2005 18:19:06 -0000
 @@ -60,3 +60,4 @@ extern long sparc64_syscall_exit(struct 
  #endif
  
  extern int Procfd;
 +extern int max_string;
 Index: i386-fbsd.c
 ===================================================================
 RCS file: /home/ncvs/src/usr.bin/truss/i386-fbsd.c,v
 retrieving revision 1.23
 diff -u -p -r1.23 i386-fbsd.c
 --- i386-fbsd.c	8 Aug 2004 23:29:36 -0000	1.23
 +++ i386-fbsd.c	6 Jan 2005 18:11:42 -0000
 @@ -180,7 +180,8 @@ i386_syscall_entry(struct trussinfo *tru
    if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1)
      return;
  
 -  sc = get_syscall(fsc.name);
 +  if (fsc.name)
 +  	sc = get_syscall(fsc.name);
    if (sc) {
      fsc.nargs = sc->nargs;
    } else {
 @@ -316,7 +317,7 @@ i386_syscall_exit(struct trussinfo *trus
        char *temp;
        if (sc->args[i].type & OUT) {
  	/*
 -	 * If an error occurred, than don't bothe getting the data;
 +	 * If an error occurred, then don't bother getting the data;
  	 * it may not be valid.
  	 */
  	if (errorp)
 @@ -329,6 +330,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 && fsc.name && strcmp(fsc.name, "pipe") == 0) {
 +      fsc.nargs = 1;
 +      fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*));
 +      asprintf(&fsc.s_args[0], "[%d,%d]", (int)retval, regs.r_edx);
 +      retval = 0;
 +  }
 +
 +  /*
     * It would probably be a good idea to merge the error handling,
     * but that complicates things considerably.
     */
 Index: main.c
 ===================================================================
 RCS file: /home/ncvs/src/usr.bin/truss/main.c,v
 retrieving revision 1.38
 diff -u -p -r1.38 main.c
 --- main.c	17 Jul 2004 19:19:36 -0000	1.38
 +++ main.c	25 Jan 2005 18:20:22 -0000
 @@ -66,6 +66,8 @@ __FBSDID("$FreeBSD: src/usr.bin/truss/ma
  
  int Procfd;
  
 +int max_string = 40;
 +
  static __inline void
  usage(void)
  {
 @@ -176,7 +178,7 @@ main(int ac, char **av) {
    bzero(trussinfo, sizeof(struct trussinfo));
    trussinfo->outfile = stderr;
  
 -  while ((c = getopt(ac, av, "p:o:faedDS")) != -1) {
 +  while ((c = getopt(ac, av, "p:o:faedDSs:")) != -1) {
      switch (c) {
      case 'p':	/* specified pid */
        trussinfo->pid = atoi(optarg);
 @@ -202,6 +204,9 @@ main(int ac, char **av) {
      case 'S':	/* Don't trace signals */ 
        trussinfo->flags |= NOSIGS;
        break;
 +    case 's':	/* maximum number of chars to print from strings */
 +      max_string = atoi(optarg);
 +      break;
      default:
        usage();
      }
 @@ -266,6 +271,7 @@ START_TRACE:
      if (ioctl(Procfd, PIOCWAIT, &pfs) == -1)
        warn("PIOCWAIT top of loop");
      else {
 +      struct timespec timediff;
        switch(i = pfs.why) {
        case S_SCE:
  	funcs->enter_syscall(trussinfo, pfs.val);
 @@ -305,12 +311,36 @@ START_TRACE:
  	break;
        case S_SIG:
  	signame = strsig(pfs.val);
 +	if (trussinfo->flags & FOLLOWFORKS)
 +	  fprintf(trussinfo->outfile, "%5d: ", trussinfo->pid);
 +	if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
 +	  timespecsubt(&trussinfo->after, &trussinfo->start_time, &timediff);
 +	  fprintf(trussinfo->outfile, "%ld.%09ld ",
 +	    (long)timediff.tv_sec, timediff.tv_nsec);
 +	}
 +	if (trussinfo->flags & RELATIVETIMESTAMPS) {
 +	  timespecsubt(&trussinfo->after, &trussinfo->before, &timediff);
 +	  fprintf(trussinfo->outfile, "%ld.%09ld ",
 +	    (long)timediff.tv_sec, timediff.tv_nsec);
 +	}
  	fprintf(trussinfo->outfile, "SIGNAL %lu (%s)\n", pfs.val,
  	    signame == NULL ? "?" : signame);
  	free(signame);
  	sigexit = pfs.val;
  	break;
        case S_EXIT:
 +	if (trussinfo->flags & FOLLOWFORKS)
 +	  fprintf(trussinfo->outfile, "%5d: ", trussinfo->pid);
 +	if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
 +	  timespecsubt(&trussinfo->after, &trussinfo->start_time, &timediff);
 +	  fprintf(trussinfo->outfile, "%ld.%09ld ",
 +	    (long)timediff.tv_sec, timediff.tv_nsec);
 +	}
 +	if (trussinfo->flags & RELATIVETIMESTAMPS) {
 +	  timespecsubt(&trussinfo->after, &trussinfo->before, &timediff);
 +	  fprintf(trussinfo->outfile, "%ld.%09ld ",
 +	    (long)timediff.tv_sec, timediff.tv_nsec);
 +	}
  	fprintf (trussinfo->outfile, "process exit, rval = %lu\n", pfs.val);
  	break;
        case S_EXEC:
 Index: syscall.h
 ===================================================================
 RCS file: /home/ncvs/src/usr.bin/truss/syscall.h,v
 retrieving revision 1.15
 diff -u -p -r1.15 syscall.h
 --- syscall.h	17 Jul 2004 19:48:49 -0000	1.15
 +++ syscall.h	3 Feb 2005 23:45:24 -0000
 @@ -9,7 +9,7 @@
   *	write() arguments as such, even though they may *not* be
   *	printable data.
   * Ptr -- pointer to some specific structure.  Just print as hex for now.
 - * Stat -- a pointer to a stat buffer.  Currently unused.
 + * Stat -- a pointer to a stat buffer.  Prints a couple fields.
   * 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)
 @@ -17,10 +17,15 @@
   * 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.
 + * Timeval2 -- a pointer to two struct timevals.  Prints both elements of both.
   * 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.
 + * Umtx -- a pointer to a struct umtx.  Prints the value of owner.
 + * Sigset -- a pointer to a sigset_t.  Prints the signals that are set.
 + * Sigprocmask -- the first argument to sigprocmask().  Prints the name.
 + * Kevent -- a pointer to an array of struct kevents.  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
 @@ -32,7 +37,9 @@
  
  enum Argtype { None = 1, Hex, Octal, Int, String, Ptr, Stat, Ioctl, Quad,
  	Signal, Sockaddr, StringArray, Timespec, Timeval, Itimerval, Pollfd, 
 -	Fd_set, Sigaction, Fcntl, Mprot, Mmapflags, Whence, Readlinkres };
 +	Fd_set, Sigaction, Fcntl, Mprot, Mmapflags, Whence, Readlinkres, 
 +	Umtx, Sigset, Sigprocmask, Kevent, Sockdomain, Socktype, Open, 
 +	Fcntlflag, Rusage, BinString, Shutdown, Resource, Rlimit, Timeval2 };
  
  #define ARG_MASK	0xff
  #define OUT	0x100
 Index: syscalls.c
 ===================================================================
 RCS file: /home/ncvs/src/usr.bin/truss/syscalls.c,v
 retrieving revision 1.44
 diff -u -p -r1.44 syscalls.c
 --- syscalls.c	8 Aug 2004 23:29:36 -0000	1.44
 +++ syscalls.c	3 Feb 2005 23:46:07 -0000
 @@ -46,6 +46,13 @@ static const char rcsid[] =
  #include <sys/un.h>
  #include <netinet/in.h>
  #include <arpa/inet.h>
 +#include <sys/ioccom.h>
 +#include <machine/atomic.h>
 +#include <errno.h>
 +#include <sys/umtx.h>
 +#include <sys/event.h>
 +#include <sys/stat.h>
 +#include <sys/resource.h>
  
  #include <ctype.h>
  #include <err.h>
 @@ -58,6 +65,7 @@ static const char rcsid[] =
  #include <string.h>
  #include <time.h>
  #include <unistd.h>
 +#include <vis.h>
  
  #include "truss.h"
  #include "extern.h"
 @@ -69,7 +77,7 @@ static const char rcsid[] =
  
  struct syscall syscalls[] = {
  	{ "fcntl", 1, 3,
 -	  { { Int, 0 } , { Fcntl, 1 }, { Hex, 2 }}},
 +	  { { Int, 0 } , { Fcntl, 1 }, { Fcntlflag | OUT, 2 }}},
  	{ "readlink", 1, 3,
  	  { { String, 0 } , { Readlinkres | OUT, 1 }, { Int, 2 }}},
  	{ "lseek", 2, 3,
 @@ -81,7 +89,7 @@ struct syscall syscalls[] = {
  	{ "mprotect", 1, 3,
  	  { { Ptr, 0 }, {Int, 1}, {Mprot, 2}}},
  	{ "open", 1, 3,
 -	  { { String | IN, 0} , { Hex, 1}, {Octal, 2}}},
 +	  { { String | IN, 0} , { Open, 1}, { Octal, 2}}},
  	{ "linux_open", 1, 3,
  	  { { String, 0 }, { Hex, 1}, { Octal, 2 }}},
  	{ "close", 1, 1,
 @@ -103,17 +111,19 @@ struct syscall syscalls[] = {
  	{ "umount", 0, 2,
  	  { { String, 0 }, { Int, 2 }}},
  	{ "fstat", 1, 2,
 -	  { { Int, 0},  {Ptr | OUT , 1 }}},
 +	  { { Int, 0}, { Stat | OUT , 1 }}},
  	{ "stat", 1, 2,
 -	  { { String | IN, 0 }, { Ptr | OUT, 1 }}},
 +	  { { String | IN, 0 }, { Stat | OUT, 1 }}},
  	{ "lstat", 1, 2,
 -	  { { String | IN, 0 }, { Ptr | OUT, 1 }}},
 +	  { { String | IN, 0 }, { Stat | OUT, 1 }}},
  	{ "linux_newstat", 1, 2,
  	  { { String | IN, 0 }, { Ptr | OUT, 1 }}},
  	{ "linux_newfstat", 1, 2,
  	  { { Int, 0 }, { Ptr | OUT, 1 }}},
  	{ "write", 1, 3,
 -	  { { Int, 0 }, { Ptr | IN, 1 }, { Int, 2 }}},
 +	  { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }}},
 +	{ "read", 1, 3,
 +	  { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }}},
  	{ "ioctl", 1, 3,
  	  { { Int, 0 }, { Ioctl, 1 }, { Hex, 2 }}},
  	{ "break", 1, 1, { { Hex, 0 }}},
 @@ -122,19 +132,19 @@ struct syscall syscalls[] = {
  	{ "sigaction", 1, 3,
  	  { { Signal, 0 }, { Sigaction | IN, 1 }, { Sigaction | OUT, 2 }}},
  	{ "accept", 1, 3,
 -	  { { Hex, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
 +	  { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
  	{ "bind", 1, 3,
 -	  { { Hex, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
 +	  { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
  	{ "connect", 1, 3,
 -	  { { Hex, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
 +	  { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
  	{ "getpeername", 1, 3,
 -	  { { Hex, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
 +	  { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
  	{ "getsockname", 1, 3,
 -	  { { Hex, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
 +	  { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
  	{ "recvfrom", 1, 6,
 -	  { { Hex, 0 }, { Ptr | IN, 1 }, { Int, 3 }, { Hex, 3 }, { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } },
 +	  { { Int, 0 }, { Ptr | IN, 1 }, { Int, 3 }, { Hex, 3 }, { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } },
  	{ "sendto", 1, 6,
 -	  { { Hex, 0 }, { Ptr | IN, 1 }, { Int, 3 }, { Hex, 3 }, { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } },
 +	  { { Int, 0 }, { Ptr | IN, 1 }, { Int, 3 }, { Hex, 3 }, { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } },
  	{ "execve", 1, 3,
  	  { { String | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } },
  	{ "linux_execve", 1, 3,
 @@ -149,13 +159,184 @@ struct syscall syscalls[] = {
  	{ "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}}},
 +	{ "clock_gettime", 1, 2, { { Int, 0 }, { Timespec | 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 }}},
 +	{ "kse_release", 0, 1, { { Timespec, 0 }}},
 +	{ "kevent", 0, 6, { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 }, { Int, 4 }, { Timespec, 5 }}},
 +	{ "_umtx_lock", 0, 1, { { Umtx, 0 }}},
 +	{ "_umtx_unlock", 0, 1, { { Umtx, 0 }}},
 +	{ "sigprocmask", 0, 3, { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 }}},
 +	{ "unmount", 1, 2, { { String, 0 }, { Int, 1 }}},
 +	{ "socket", 1, 3, { { Sockdomain, 0}, { Socktype, 1}, {Int, 2 }}},
 +	{ "getrusage", 1, 2, { { Int, 0 }, { Rusage | OUT, 1 }}},
 +	{ "rename", 1, 2, { { String, 0 }, { String, 0 }}},
 +	{ "__getcwd", 1, 2, { { String | OUT, 0}, { Int, 1 }}},
 +	{ "shutdown", 1, 2, { { Int, 0}, { Shutdown, 1}}},
 +	{ "getrlimit", 1, 2, { { Resource, 0}, {Rlimit | OUT, 1}}},
 +	{ "setrlimit", 1, 2, { { Resource, 0}, {Rlimit | IN, 1}}},
 +	{ "utimes", 1, 2, { { String , 0}, { Timeval2, 1 }}},
 +	{ "lutimes", 1, 2, { { String , 0}, { Timeval2, 1 }}},
  	{ 0, 0, 0, { { 0, 0 }}},
  };
  
 +/* Xlat idea from strace */
 +struct xlat {
 +	int val;
 +	char *str;
 +};
 +
 +#define X(a) { a, #a },
 +#define XEND { 0, NULL }
 +
 +static struct xlat kevent_filters[] = {
 +	X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE)
 +	X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER)
 +	X(EVFILT_NETDEV) X(EVFILT_FS) X(EVFILT_READ) XEND
 +};
 +
 +static struct xlat kevent_flags[] = {
 +	X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT)
 +	X(EV_CLEAR) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND
 +};
 +
 +struct xlat poll_flags[] = { 
 +	X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
 +	X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
 +	X(POLLWRBAND) X(POLLINIGNEOF) XEND
 +};
 +
 +static struct xlat mmap_flags[] = {
 +	X(MAP_SHARED) X(MAP_PRIVATE) X(MAP_FIXED) X(MAP_RENAME)
 +	X(MAP_NORESERVE) X(MAP_RESERVED0080) X(MAP_RESERVED0100)
 +	X(MAP_HASSEMAPHORE) X(MAP_STACK) X(MAP_NOSYNC) X(MAP_ANON)
 +	X(MAP_NOCORE) XEND
 +};
 +
 +static struct xlat mprot_flags[] = {
 +	X(PROT_NONE) X(PROT_READ) X(PROT_WRITE) X(PROT_EXEC) XEND
 +};
 +
 +static struct xlat whence_arg[] = {
 +	X(SEEK_SET) X(SEEK_CUR) X(SEEK_END) XEND
 +};
 +
 +static struct xlat sigaction_flags[] = { 
 +	X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
 +	X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
 +};
 +
 +static struct xlat fcntl_arg[] = {
 +	X(F_DUPFD) X(F_GETFD) X(F_SETFD) X(F_GETFL) X(F_SETFL)
 +	X(F_GETOWN) X(F_SETOWN) X(F_GETLK) X(F_SETLK) X(F_SETLKW) XEND
 +};
 +
 +static struct xlat fcntlfd_arg[] = {
 +	X(FD_CLOEXEC) XEND
 +};
 +
 +static struct xlat fcntlfl_arg[] = {
 +	X(O_APPEND) X(O_ASYNC) X(O_FSYNC) X(O_NONBLOCK) X(O_NOFOLLOW)
 +	X(O_DIRECT) XEND
 +};
 +
 +static struct xlat sockdomain_arg[] = {
 +	X(PF_UNSPEC) X(PF_LOCAL) X(PF_UNIX) X(PF_INET) X(PF_IMPLINK)
 +	X(PF_PUP) X(PF_CHAOS) X(PF_NETBIOS) X(PF_ISO) X(PF_OSI)
 +	X(PF_ECMA) X(PF_DATAKIT) X(PF_CCITT) X(PF_SNA) X(PF_DECnet)
 +	X(PF_DLI) X(PF_LAT) X(PF_HYLINK) X(PF_APPLETALK) X(PF_ROUTE)
 +	X(PF_LINK) X(PF_XTP) X(PF_COIP) X(PF_CNT) X(PF_SIP) X(PF_IPX)
 +	X(PF_RTIP) X(PF_PIP) X(PF_ISDN) X(PF_KEY) X(PF_INET6)
 +	X(PF_NATM) X(PF_ATM) X(PF_NETGRAPH) X(PF_SLOW) X(PF_SCLUSTER)
 +	X(PF_ARP) X(PF_BLUETOOTH) XEND
 +};
 +
 +static struct xlat socktype_arg[] = {
 +	X(SOCK_STREAM) X(SOCK_DGRAM) X(SOCK_RAW) X(SOCK_RDM)
 +	X(SOCK_SEQPACKET) XEND
 +};
 +
 +static struct xlat open_flags[] = {
 +	X(O_RDONLY) X(O_WRONLY) X(O_RDWR) X(O_ACCMODE) X(O_NONBLOCK)
 +	X(O_APPEND) X(O_SHLOCK) X(O_EXLOCK) X(O_ASYNC) X(O_FSYNC)
 +	X(O_NOFOLLOW) X(O_CREAT) X(O_TRUNC) X(O_EXCL) X(O_NOCTTY)
 +	X(O_DIRECT) XEND
 +};
 +
 +static struct xlat shutdown_arg[] = {
 +	X(SHUT_RD) X(SHUT_WR) X(SHUT_RDWR) XEND
 +};
 +
 +static struct xlat resource_arg[] = {
 +	X(RLIMIT_CPU) X(RLIMIT_FSIZE) X(RLIMIT_DATA) X(RLIMIT_STACK)
 +	X(RLIMIT_CORE) X(RLIMIT_RSS) X(RLIMIT_MEMLOCK) X(RLIMIT_NPROC)
 +	X(RLIMIT_NOFILE) X(RLIMIT_SBSIZE) X(RLIMIT_VMEM) XEND
 +};
 +
 +#undef X
 +#undef XEND
 +
 +/* Searches an xlat array for a value, and returns it if found.  Otherwise
 +   return a string representation. */
 +char *lookup(struct xlat *xlat, int val, int base)
 +{
 +	static char tmp[16];
 +	for (; xlat->str != NULL; xlat++)
 +		if (xlat->val == val)
 +			return xlat->str;
 +	switch (base) {
 +		case 8:
 +			sprintf(tmp, "0%o", val);
 +			break;
 +		case 16: 
 +			sprintf(tmp, "0x%x", val);
 +			break;
 +		case 10:
 +			sprintf(tmp, "%u", val);
 +			break;
 +		default:
 +			errx(1,"Unknown lookup base");
 +			break;
 +	}		
 +	return tmp;
 +}
 +
 +char *xlookup(struct xlat *xlat, int val)
 +{
 +	return lookup(xlat, val, 16);
 +}
 +
 +/* Searches an xlat array containing bitfield values.  Remaining bits
 +   set after removing the known ones are printed at the end:
 +   POLLIN|0x400 */
 +char *xlookup_bits(struct xlat *xlat, int val)
 +{
 +	static char str[512];
 +	int len = 0;
 +	int rem = val;
 +
 +	for (; xlat->str != NULL; xlat++)
 +	{
 +		if ((xlat->val & rem) == xlat->val)
 +		{
 +			/* don't print the "all-bits-zero" string unless all
 +			   bits are really zero */
 +			if (xlat->val == 0 && val != 0)
 +				continue;
 +			len += sprintf(str + len, "%s|", xlat->str);
 +			rem &= ~(xlat->val);
 +		}
 +	}
 +	/* if we have leftover bits or didn't match anything */
 +	if (rem || len == 0)
 +		len += sprintf(str + len, "0x%x", rem);
 +	if (len && str[len - 1] == '|')
 +		len--;
 +	str[len] = 0;
 +	return str;
 +}
 +
  /*
   * If/when the list gets big, it might be desirable to do it
   * as a hash table or binary search.
 @@ -206,7 +387,7 @@ get_string(int procfd, void *offset, int
  		err(1, "dup");
  	if ((p = fdopen(fd, "r")) == NULL)
  		err(1, "fdopen");
 -	buf = malloc( size = (max ? max : 64 ) );
 +	buf = malloc( size = (max ? max+1 : 64 ) );
  	len = 0;
  	buf[0] = 0;
  	if (fseeko(p, (uintptr_t)offset, SEEK_SET) == 0) {
 @@ -250,19 +431,6 @@ make_quad(unsigned long p1, unsigned lon
  }
  
  /*
 - * Remove a trailing '|' in a string, useful for fixup after decoding
 - * a "flags" argument.
 - */
 -
 -void
 -remove_trailing_or(char *str)
 -{
 -
 -	if (str != NULL && (str = rindex(str, '|')) != NULL && str[1] == '\0')
 -		*str = '\0';
 -}
 -
 -/*
   * print_arg
   * Converts a syscall argument into a string.  Said string is
   * allocated via malloc(), so needs to be free()'d.  The file
 @@ -293,6 +461,43 @@ print_arg(int fd, struct syscall_args *s
        free(tmp2);
      }
    break;
 +  case BinString:
 +    {
 +      /* Binary block of data that might have printable characters. 
 +         XXX If type|OUT, assume that the length is the syscall's
 +         return value.  Otherwise, assume that the length of the block
 +         is in the next syscall argument. */
 +      char tmp2[max_string+1], *tmp3;
 +      int len;
 +      int truncated = 0;
 +      
 +      if (sc->type & OUT)
 +        len = retval;
 +      else
 +        len = args[sc->offset + 1];
 +      
 +      /* Don't print more than max_string characters, to avoid word
 +         wrap.  If we have to truncate put some ... after the string.
 +         */
 +      if (len > max_string) {
 +        len = max_string;
 +        truncated = 1;
 +      }
 +      if (len && get_struct(fd, (void*)args[sc->offset], &tmp2, len) != -1)
 +      {
 +        tmp3 = malloc(len * 4 + 1);
 +        while (len) {
 +          if (strvisx(tmp3, tmp2, len, VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
 +            break;
 +          len--;
 +          truncated = 1;
 +        };
 +        asprintf(&tmp, "\"%s\"%s", tmp3, truncated?"...":"");
 +        free(tmp3);
 +      } else
 +      	asprintf(&tmp, "0x%lx", args[sc->offset]);
 +    }
 +  break;
    case StringArray:
      {
        int num, size, i;
 @@ -358,6 +563,21 @@ print_arg(int fd, struct syscall_args *s
        if (temp)
  	tmp = strdup(temp);
        else
 +      {
 +        unsigned long arg = args[sc->offset];
 +	asprintf(&tmp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu}", arg,
 +		arg&IOC_OUT?"R":"", arg&IOC_IN?"W":"",
 +		IOCGROUP(arg), isprint(IOCGROUP(arg))?(char)IOCGROUP(arg):'?', 
 +		arg & 0xFF, IOCPARM_LEN(arg));
 +      }
 +    }
 +    break;
 +  case Umtx:
 +    {
 +      struct umtx umtx;
 +      if (get_struct(fd, (void *)args[sc->offset], &umtx, sizeof(umtx)) != -1)
 +	asprintf(&tmp, "{0x%lx}", (long)umtx.u_owner);
 +      else
  	asprintf(&tmp, "0x%lx", args[sc->offset]);
      }
      break;
 @@ -365,7 +585,7 @@ print_arg(int fd, struct syscall_args *s
      {
        struct timespec ts;
        if (get_struct(fd, (void *)args[sc->offset], &ts, sizeof(ts)) != -1)
 -	asprintf(&tmp, "{%jd %jd}", (intmax_t)ts.tv_sec, (intmax_t)ts.tv_nsec);
 +	asprintf(&tmp, "{%ld.%09ld}", (long)ts.tv_sec, ts.tv_nsec);
        else
  	asprintf(&tmp, "0x%lx", args[sc->offset]);
      }
 @@ -374,7 +594,18 @@ print_arg(int fd, struct syscall_args *s
      {
        struct timeval tv;
        if (get_struct(fd, (void *)args[sc->offset], &tv, sizeof(tv)) != -1)
 -	asprintf(&tmp, "{%jd %jd}", (intmax_t)tv.tv_sec, (intmax_t)tv.tv_usec);
 +	asprintf(&tmp, "{%ld.%06ld}", (long)tv.tv_sec, tv.tv_usec);
 +      else
 +	asprintf(&tmp, "0x%lx", args[sc->offset]);
 +    }
 +    break;
 +  case Timeval2:
 +    {
 +      struct timeval tv[2];
 +      if (get_struct(fd, (void *)args[sc->offset], &tv, sizeof(tv)) != -1)
 +	asprintf(&tmp, "{%ld.%06ld, %ld.%06ld}", 
 +	  (long)tv[0].tv_sec, tv[0].tv_usec,
 +	  (long)tv[1].tv_sec, tv[1].tv_usec);
        else
  	asprintf(&tmp, "0x%lx", args[sc->offset]);
      }
 @@ -383,11 +614,11 @@ print_arg(int fd, struct syscall_args *s
      {
        struct itimerval itv;
        if (get_struct(fd, (void *)args[sc->offset], &itv, sizeof(itv)) != -1)
 -	asprintf(&tmp, "{%jd %jd, %jd %jd}", 
 -	    (intmax_t)itv.it_interval.tv_sec,
 -	    (intmax_t)itv.it_interval.tv_usec,
 -	    (intmax_t)itv.it_value.tv_sec,
 -	    (intmax_t)itv.it_value.tv_usec);
 +	asprintf(&tmp, "{%ld.%06ld, %ld.%06ld}", 
 +	    (long)itv.it_interval.tv_sec,
 +	    itv.it_interval.tv_usec,
 +	    (long)itv.it_value.tv_sec,
 +	    itv.it_value.tv_usec);
        else
  	asprintf(&tmp, "0x%lx", args[sc->offset]);
      }
 @@ -415,24 +646,12 @@ print_arg(int fd, struct syscall_args *s
  
  	tmp[used++] = '{';
  	for (i = 0; i < numfds; i++) {
 -#define POLLKNOWN_EVENTS \
 -	(POLLIN | POLLPRI | POLLOUT | POLLERR | POLLHUP | POLLNVAL | \
 -	 POLLRDNORM |POLLRDBAND | POLLWRBAND | POLLINIGNEOF) 
  
 -	  u += snprintf(tmp + used, per_fd,
 -	    "%s%d 0x%hx%s%s%s%s%s%s%s%s%s ",
 +	  u = snprintf(tmp + used, per_fd,
 +	    "%s%d/%s",
  	    i > 0 ? " " : "",
  	    pfd[i].fd,
 -	    pfd[i].events & ~POLLKNOWN_EVENTS,
 -	    pfd[i].events & POLLIN ? "" : "|IN",
 -	    pfd[i].events & POLLPRI ? "" : "|PRI",
 -	    pfd[i].events & POLLOUT ? "" : "|OUT",
 -	    pfd[i].events & POLLERR ? "" : "|ERR",
 -	    pfd[i].events & POLLHUP ? "" : "|HUP",
 -	    pfd[i].events & POLLNVAL ? "" : "|NVAL",
 -	    pfd[i].events & POLLRDNORM ? "" : "|RDNORM",
 -	    pfd[i].events & POLLRDBAND ? "" : "|RDBAND",
 -	    pfd[i].events & POLLWRBAND ? "" : "|WRBAND");
 +	    xlookup_bits(poll_flags, pfd[i].events));
  	  if (u > 0)
  	    used += u < per_fd ? u : per_fd;
  	}
 @@ -490,63 +709,95 @@ print_arg(int fd, struct syscall_args *s
          asprintf(&tmp, "%ld", sig);
      }
      break;
 -  case Fcntl:
 +  case Sigset:
 +    {
 +      long sig;
 +      sigset_t ss;
 +      int i, used;
 +
 +      sig = args[sc->offset];
 +      if (get_struct(fd, (void *)args[sc->offset], (void *)&ss,
 +          sizeof(ss)) == -1)
 +      {
 +	asprintf(&tmp, "0x%lx", args[sc->offset]);
 +	break;
 +      }
 +      tmp = malloc(sys_nsig * 8); /* 7 bytes avg per signal name */
 +      used = 0;
 +      for (i = 1; i < sys_nsig; i++)
 +      {
 +      	if (sigismember(&ss, i))
 +      	{
 +      	  used += sprintf(tmp + used, "%s|", strsig(i));
 +      	}
 +      }
 +      if(used)
 +	      tmp[used-1] = 0;
 +	  else
 +	      strcpy(tmp, "0x0");
 +    }
 +    break;
 +  case Sigprocmask:
      {
  	switch (args[sc->offset]) {
  #define S(a)	case a: tmp = strdup(#a); break;
 -	S(F_DUPFD);
 -	S(F_GETFD);
 -	S(F_SETFD);
 -	S(F_GETFL);
 -	S(F_SETFL);
 -	S(F_GETOWN);
 -	S(F_SETOWN);
 -	S(F_GETLK);
 -	S(F_SETLK);
 -	S(F_SETLKW);
 +	S(SIG_BLOCK);
 +	S(SIG_UNBLOCK);
 +	S(SIG_SETMASK);
  #undef S
  	}
  	if (tmp == NULL)
      		asprintf(&tmp, "0x%lx", args[sc->offset]);
      }
      break;
 -
 -  case Mprot:
 +    
 +  case Fcntl:
 +    tmp = strdup(xlookup(fcntl_arg, args[sc->offset]));
 +    break;
 +  case Fcntlflag:
      {
 -
 -#define S(a)	((args[sc->offset] & a) ? #a "|" : "")
 -	    asprintf(&tmp, "(0x%lx)%s%s%s%s", args[sc->offset],
 -		S(PROT_NONE), S(PROT_READ), S(PROT_WRITE), S(PROT_EXEC));
 -#undef S
 -	    remove_trailing_or(tmp);
 -
 +      /* XXX output depends on the value of the previous argument */
 +      switch (args[sc->offset-1]) {
 +        case F_SETFD:
 +          tmp = strdup(xlookup_bits(fcntlfd_arg, args[sc->offset]));
 +          break;
 +        case F_SETFL:
 +          tmp = strdup(xlookup_bits(fcntlfl_arg, args[sc->offset]));
 +          break;
 +        case F_GETFD:
 +        case F_GETFL:
 +        case F_GETOWN:
 +          tmp = strdup("");
 +          break;
 +        default:
 +          asprintf(&tmp, "0x%lx", args[sc->offset]);
 +          break;
 +      }
      }
      break;
 -
 +  case Open:
 +    tmp = strdup(xlookup_bits(open_flags, args[sc->offset]));
 +    break;
 +  case Mprot:
 +    tmp = strdup(xlookup_bits(mprot_flags, args[sc->offset]));
 +    break;
    case Mmapflags:
 -    {
 -#define S(a)	((args[sc->offset] & a) ? #a "|" : "")
 -	    asprintf(&tmp, "(0x%lx)%s%s%s%s%s%s%s%s", args[sc->offset],
 -		S(MAP_ANON), S(MAP_FIXED), S(MAP_HASSEMAPHORE),
 -		S(MAP_NOCORE), S(MAP_NOSYNC), S(MAP_PRIVATE),
 -		S(MAP_SHARED), S(MAP_STACK));
 -#undef S
 -
 -	    remove_trailing_or(tmp);
 -    }
 +    tmp = strdup(xlookup_bits(mmap_flags, args[sc->offset]));
      break;
 -
    case Whence:
 -    {
 -	switch (args[sc->offset]) {
 -#define S(a)	case a: tmp = strdup(#a); break;
 -	S(SEEK_SET);
 -	S(SEEK_CUR);
 -	S(SEEK_END);
 -#undef S
 -	default: asprintf(&tmp, "0x%lx", args[sc->offset]); break;
 -	}
 -    }
 +    tmp = strdup(xlookup(whence_arg, args[sc->offset]));
 +    break;
 +  case Sockdomain:
 +    tmp = strdup(xlookup(sockdomain_arg, args[sc->offset]));
 +    break;
 +  case Socktype:
 +    tmp = strdup(xlookup(socktype_arg, args[sc->offset]));
 +    break;
 +  case Shutdown:
 +    tmp = strdup(xlookup(shutdown_arg, args[sc->offset]));
 +    break;
 +  case Resource:
 +    tmp = strdup(xlookup(resource_arg, args[sc->offset]));
      break;
    case Sockaddr:
      {
 @@ -614,10 +865,6 @@ print_arg(int fd, struct syscall_args *s
        struct sigaction sa;
        char *hand;
        const char *h;
 -#define SA_KNOWN_FLAGS \
 -	(SA_ONSTACK | SA_RESTART | SA_RESETHAND | SA_NOCLDSTOP | SA_NODEFER | \
 -	 SA_NOCLDWAIT | SA_SIGINFO)
 -
  
        if (get_struct(fd, (void *)args[sc->offset], &sa, sizeof(sa)) != -1) {
  
 @@ -628,35 +875,108 @@ print_arg(int fd, struct syscall_args *s
  	  h = "SIG_IGN";
  	else
  	  h = hand;
 -	asprintf(&tmp, "{ %s 0x%x%s%s%s%s%s%s%s ss_t }",
 +
 +	asprintf(&tmp, "{ %s %s ss_t }",
  	    h,
 -	    sa.sa_flags & ~SA_KNOWN_FLAGS,
 -	    sa.sa_flags & SA_ONSTACK ? "" : "|ONSTACK",
 -	    sa.sa_flags & SA_RESTART ? "" : "|RESTART",
 -	    sa.sa_flags & SA_RESETHAND ? "" : "|RESETHAND",
 -	    sa.sa_flags & SA_NOCLDSTOP ? "" : "|NOCLDSTOP",
 -	    sa.sa_flags & SA_NODEFER ? "" : "|NODEFER",
 -	    sa.sa_flags & SA_NOCLDWAIT ? "" : "|NOCLDWAIT",
 -	    sa.sa_flags & SA_SIGINFO ? "" : "|SIGINFO");
 +	    xlookup_bits(sigaction_flags, sa.sa_flags));
  	free(hand);
        } else
  	asprintf(&tmp, "0x%lx", args[sc->offset]);
        
      }
      break;
 +  case Kevent:
 +    {
 +      /*
 +       * XXX XXX: the size of the array is determined by either the
 +       * next syscall argument, or by the syscall returnvalue,
 +       * depending on which argument number we are.  This matches the
 +       * kevent syscall, but luckily that's the only syscall that uses
 +       * them.
 +       */
 +      struct kevent *ke;
 +      int numevents = -1;
 +      int bytes = 0;
 +      int i, tmpsize, u, used;
 +      const int per_ke = 100;
 +
 +      if (sc->offset == 1)
 +      	numevents = args[sc->offset+1];
 +      else if (sc->offset == 3 && retval != -1)
 +        numevents = retval;
 +      
 +      if (numevents >= 0)
 +      	bytes = sizeof(struct kevent) * numevents;
 +      if ((ke = malloc(bytes)) == NULL)
 +        err(1, "Cannot malloc %d bytes for kevent array", bytes);
 +      if (numevents >= 0 && get_struct(fd, (void *)args[sc->offset], ke, bytes) != -1) {
 +	used = 0;
 +	tmpsize = 1 + per_ke * numevents + 2;
 +	if ((tmp = malloc(tmpsize)) == NULL)
 +	  err(1, "Cannot alloc %d bytes for kevent output", tmpsize);
 +
 +	tmp[used++] = '{';
 +	for (i = 0; i < numevents; i++) {
 +	  u = snprintf(tmp + used, per_ke,
 +	    "%s%d,%s,%s,%d,%p,%p",
 +	    i > 0 ? " " : "",
 +	    ke[i].ident,
 +	    xlookup(kevent_filters, ke[i].filter),
 +	    xlookup_bits(kevent_flags, ke[i].flags),
 +	    ke[i].fflags,
 +	    (void *)ke[i].data,
 +	    (void *)ke[i].udata);
 +	  if (u > 0)
 +	    used += u < per_ke ? u : per_ke;
 +	}
 +	tmp[used++] = '}';
 +	tmp[used++] = '\0';
 +      } else
 +	asprintf(&tmp, "0x%lx", args[sc->offset]);
 +      free(ke);
 +    }
 +    break;
 +  case Stat:
 +    {
 +      struct stat st;
 +      if (get_struct(fd, (void *)args[sc->offset], &st, sizeof(st)) != -1) {
 +	char mode[12];
 +	strmode(st.st_mode, mode);
 +	asprintf(&tmp, "{mode=%s,inode=%jd,size=%jd,blksize=%ld}", 
 +	  mode,
 +	  (intmax_t)st.st_ino,(intmax_t)st.st_size,(long)st.st_blksize);
 +      } else
 +	asprintf(&tmp, "0x%lx", args[sc->offset]);
 +    }
 +    break;
 +  case Rusage:
 +    {
 +      struct rusage ru;
 +      if (get_struct(fd, (void *)args[sc->offset], &ru, sizeof(ru)) != -1)
 +	asprintf(&tmp, "{u=%ld.%06ld,s=%ld.%06ld,in=%ld,out=%ld}", 
 +	  (long)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
 +	  (long)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
 +	  ru.ru_inblock, ru.ru_oublock);
 +      else
 +	asprintf(&tmp, "0x%lx", args[sc->offset]);
 +    }
 +    break;
 +  case Rlimit:
 +    {
 +      struct rlimit rl;
 +      if (get_struct(fd, (void *)args[sc->offset], &rl, sizeof(rl)) != -1)
 +	asprintf(&tmp, "{cur=%ju,max=%ju}", 
 +	  rl.rlim_cur, rl.rlim_max);
 +      else
 +	asprintf(&tmp, "0x%lx", args[sc->offset]);
 +    }
 +    break;
 +    default:
 +     errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
    }
    return tmp;
  }
  
 -#define timespecsubt(tvp, uvp, vvp)					\
 -	do {								\
 -		(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;		\
 -		(vvp)->tv_nsec = (tvp)->tv_nsec - (uvp)->tv_nsec;	\
 -		if ((vvp)->tv_nsec < 0) {				\
 -			(vvp)->tv_sec--;				\
 -			(vvp)->tv_nsec += 1000000000;			\
 -		}							\
 -	} while (0)
  
  /*
   * print_syscall
 Index: truss.1
 ===================================================================
 RCS file: /home/ncvs/src/usr.bin/truss/truss.1,v
 retrieving revision 1.15
 diff -u -p -r1.15 truss.1
 --- truss.1	26 Nov 2002 17:33:36 -0000	1.15
 +++ truss.1	25 Jan 2005 19:14:25 -0000
 @@ -10,10 +10,12 @@
  .Nm
  .Op Fl faedDS
  .Op Fl o Ar file
 +.Op Fl s Ar strsize
  .Fl p Ar pid
  .Nm
  .Op Fl faedDS
  .Op Fl o Ar file
 +.Op Fl s Ar strsize
  command
  .Op args
  .Sh DESCRIPTION
 @@ -58,6 +60,10 @@ instead of standard error.
  Follow the process specified by
  .Ar pid
  instead of a new command.
 +.It Fl s Ar strsize
 +When printing string values, truncate to
 +.Ar strsize
 +characters.
  .It Ar command Op args
  Execute
  .Ar command
 Index: truss.h
 ===================================================================
 RCS file: /home/ncvs/src/usr.bin/truss/truss.h,v
 retrieving revision 1.5
 diff -u -p -r1.5 truss.h
 --- truss.h	5 Aug 2002 12:22:55 -0000	1.5
 +++ truss.h	25 Jan 2005 18:18:57 -0000
 @@ -43,3 +43,13 @@ struct trussinfo
  	struct timespec before;
  	struct timespec after;
  };
 +
 +#define timespecsubt(tvp, uvp, vvp)					\
 +	do {								\
 +		(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;		\
 +		(vvp)->tv_nsec = (tvp)->tv_nsec - (uvp)->tv_nsec;	\
 +		if ((vvp)->tv_nsec < 0) {				\
 +			(vvp)->tv_sec--;				\
 +			(vvp)->tv_nsec += 1000000000;			\
 +		}							\
 +	} while (0)
 
 
 -- 
 	Dan Nelson
 	dnelson@allantgroup.com
State-Changed-From-To: open->closed 
State-Changed-By: pav 
State-Changed-When: Mon May 15 21:18:47 UTC 2006 
State-Changed-Why:  
Latest version of the patch (received off-gnats) was committed to HEAD. 


Responsible-Changed-From-To: dwmalone->pav 
Responsible-Changed-By: pav 
Responsible-Changed-When: Mon May 15 21:18:47 UTC 2006 
Responsible-Changed-Why:  
Take possible followups. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=52190 
>Unformatted:
