diff -U10 -rN -X excludelist strace-4.5.20-reformatted/Makefile.am strace-4.5.20-pathtrace/Makefile.am
--- strace-4.5.20-reformatted/Makefile.am	2010-04-07 05:17:50.000000000 -0500
+++ strace-4.5.20-pathtrace/Makefile.am	2011-02-14 13:44:44.000000000 -0600
@@ -8,22 +8,22 @@
 OS		= @opsys@
 # ARCH is `i386', `m68k', `sparc', etc.
 ARCH		= @arch@
 
 AM_CFLAGS = $(WARNFLAGS)
 INCLUDES = -I$(srcdir)/$(OS)/$(ARCH) -I$(srcdir)/$(OS)
 
 strace_SOURCES = strace.c syscall.c count.c util.c desc.c file.c ipc.c \
 		 io.c ioctl.c mem.c net.c process.c bjm.c quota.c \
 		 resource.c signal.c sock.c system.c term.c time.c \
-		 proc.c scsi.c stream.c
-noinst_HEADERS = defs.h
+		 proc.c scsi.c stream.c pathtrace.c fdmap.c
+noinst_HEADERS = defs.h fdmap.h
 
 EXTRA_DIST = $(man_MANS) errnoent.sh signalent.sh syscallent.sh ioctlsort.c \
 	     debian/changelog debian/control debian/copyright debian/rules \
 	     debian/compat debian/strace64.install debian/strace64.manpages \
 	     debian/strace.docs debian/strace.examples debian/strace.install \
 	     debian/strace.manpages debian/strace-udeb.install \
 	     strace.spec \
 	     strace-graph ChangeLog ChangeLog-CVS COPYRIGHT CREDITS PORTING \
 	     README-freebsd README-linux README-sunos4 README-svr4 \
 	     linux/ioctlsort.c linux/ioctlent.sh \
diff -U10 -rN -X excludelist strace-4.5.20-reformatted/defs.h strace-4.5.20-pathtrace/defs.h
--- strace-4.5.20-reformatted/defs.h	2010-04-07 05:19:26.000000000 -0500
+++ strace-4.5.20-pathtrace/defs.h	2011-02-14 11:29:06.000000000 -0600
@@ -655,10 +655,17 @@
 #endif
 
 extern int printllval(struct tcb *, const char *, int);
 #endif
 
 #ifdef IA64
 extern long ia32;
 #endif
 
 extern int not_failing_only;
+
+extern int   show_fd_path;
+extern char *formatfd(struct tcb *tcp, long fd);
+extern int   pathtrace_match(struct tcb *tcp);
+extern void  pathtrace_update_fdmap(struct tcb *tcp);
+extern void  pathtrace_select(char *pathlist);
+extern void  pathtrace_preload(struct tcb *tcp);
diff -U10 -rN -X excludelist strace-4.5.20-reformatted/desc.c strace-4.5.20-pathtrace/desc.c
--- strace-4.5.20-reformatted/desc.c	2011-02-14 13:51:52.000000000 -0600
+++ strace-4.5.20-pathtrace/desc.c	2011-02-11 16:47:14.000000000 -0600
@@ -318,21 +318,21 @@
   else
     tprintf("}");
 }
 #endif
 
 int
 sys_fcntl(struct tcb *tcp)
 {
   if (entering(tcp))
     {
-      tprintf("%ld, ", tcp->u_arg[0]);
+      tprintf("%s, ", formatfd(tcp,tcp->u_arg[0]));
       printxval(fcntlcmds, tcp->u_arg[1], "F_???");
       switch (tcp->u_arg[1])
         {
         case F_SETFD:
           tprintf(", ");
           printflags(fdflags, tcp->u_arg[2], "FD_???");
           break;
         case F_SETOWN:
         case F_DUPFD:
 #ifdef F_DUPFD_CLOEXEC
@@ -440,53 +440,53 @@
   return 0;
 }
 
 #ifdef LOCK_SH
 
 int
 sys_flock(struct tcb *tcp)
 {
   if (entering(tcp))
     {
-      tprintf("%ld, ", tcp->u_arg[0]);
+      tprintf("%s, ", formatfd(tcp,tcp->u_arg[0]));
       printflags(flockcmds, tcp->u_arg[1], "LOCK_???");
     }
   return 0;
 }
 #endif /* LOCK_SH */
 
 int
 sys_close(struct tcb *tcp)
 {
   if (entering(tcp))
     {
-      tprintf("%ld", tcp->u_arg[0]);
+      tprintf("%s", formatfd(tcp,tcp->u_arg[0]));
     }
   return 0;
 }
 
 int
 sys_dup(struct tcb *tcp)
 {
   if (entering(tcp))
     {
-      tprintf("%ld", tcp->u_arg[0]);
+      tprintf("%s", formatfd(tcp,tcp->u_arg[0]));
     }
   return 0;
 }
 
 static int
 do_dup2(struct tcb *tcp, int flags_arg)
 {
   if (entering(tcp))
     {
-      tprintf("%ld, %ld", tcp->u_arg[0], tcp->u_arg[1]);
+      tprintf("%s, %s", formatfd(tcp,tcp->u_arg[0]), formatfd(tcp,tcp->u_arg[1]));
       if (flags_arg >= 0)
         {
           tprintf(", ");
           printflags(open_mode_flags, tcp->u_arg[flags_arg], "O_???");
         }
     }
   return 0;
 }
 
 int
diff -U10 -rN -X excludelist strace-4.5.20-reformatted/fdmap.c strace-4.5.20-pathtrace/fdmap.c
--- strace-4.5.20-reformatted/fdmap.c	1969-12-31 18:00:00.000000000 -0600
+++ strace-4.5.20-pathtrace/fdmap.c	2011-02-14 11:13:42.000000000 -0600
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2011, Comtrol Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+// A set of fuctions used to maintain fd->path mappings for a set of
+// PIDs.  In a high-level language, we'd just use a dictionary
+// (associative array), but this is C, so we roll our own.  Also
+// implement a mechanism to check whether or not a descriptor is
+// associated with a path that is in a set of "selected" paths.
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+
+#if 0
+# define debug printf
+#else
+# define debug(...) /* noop */
+#endif
+
+#define MAXSELECTED  256  // max number of "selected" paths
+#define MAXPATHS     256  // max descriptor number 
+#define MAXPIDS       16  // max number of PIDs
+
+static char *selected[MAXSELECTED];   // paths selected for tracing
+
+typedef struct  // fd->path mapping for one or more pids
+{
+  int refcount;
+  char *paths[MAXPATHS];
+}fdmap_t;
+
+typedef struct  // per-pid structure
+{
+  pid_t pid;
+  fdmap_t *map;
+} pmap_t;
+
+
+pmap_t pmap[MAXPIDS];  // for now a, hard limit on #of pids
+
+#define NumElem(a) ((sizeof (a))/(sizeof ((a)[0])))
+
+// find pmap pointer for specified pid, and optionally allocate one if
+// it doesn't already exist.
+#define PMAP_NOALLOC 0
+#define PMAP_ALLOC   1
+static pmap_t *get_pmap(pid_t pid, int alloc)
+{
+  int i;
+
+  for (i=0; i<NumElem(pmap); ++i)
+    if (pmap[i].pid == pid)
+      return &pmap[i];
+
+  if (!alloc)
+    return NULL;
+
+  for (i=0; i<NumElem(pmap); ++i)
+    if (pmap[i].pid == 0)
+      {
+        pmap[i].pid = pid;
+        return &pmap[i];
+      }
+  
+  return NULL;
+}
+
+// display the fd->path mappings for all pids
+void fdmap_display(void)
+{
+  int i,fd;
+  printf("fdmap:\n");
+  for (i=0; i<NumElem(pmap); ++i)
+    if (pmap[i].pid)
+      {
+        printf("  [%5d] <%p,%d>\n",pmap[i].pid,pmap[i].map, pmap[i].map ? pmap[i].map->refcount : 0);
+        if (pmap[i].map == NULL)
+          continue;
+          
+        for (fd=0; fd<NumElem(pmap[i].map->paths); ++fd)
+          if (pmap[i].map->paths[fd])
+            printf("    %2d: '%s'\n",fd,pmap[i].map->paths[fd]);
+      }
+  fflush(stdout);
+}
+
+// add a path for specified pid,fd
+void fdmap_add(pid_t pid, int fd, char *path)
+{
+  pmap_t *p;
+
+  debug("fdmap_add(pid=%d,fd=%d,path='%s')\n",pid,fd,path);
+
+  p = get_pmap(pid,PMAP_ALLOC);
+  if (!p)
+    {
+      fprintf(stderr,"fdmap: max number of pids exceeded\n");
+      return;
+    }
+
+  if (!p->map)
+    {
+      // no map yet for this pid, so allocate one
+      p->map = calloc(1, sizeof (fdmap_t));
+      if (!p->map)
+        {
+          fprintf(stderr,"fdmap: calloc() failed\n");
+          return;
+        }
+      p->map->refcount = 1;
+    }
+
+  if (fd >= NumElem(p->map->paths))
+    {
+      fprintf(stderr,"fdmap: max num fds exceeded\n");
+      return;
+    }
+
+  p->map->paths[fd] = strdup(path);
+}
+
+// delete the path associated with pid,fd
+void fdmap_del(pid_t pid, int fd)
+{
+  pmap_t *p;
+
+  debug("fdmap_del(pid=%d,fd=%d)\n",pid,fd);
+
+  p = get_pmap(pid,PMAP_NOALLOC);
+
+  if (!p || !p->map)
+    return;
+
+  if (fd >= NumElem(p->map->paths))
+    return;
+
+  if (p->map->paths[fd])
+    free(p->map->paths[fd]);
+
+  p->map->paths[fd] = NULL;
+}
+
+// return path associated with pid,fd. NULL if unkown
+char *fdmap_get(pid_t pid, int fd)
+{
+  pmap_t *p;
+
+  p = get_pmap(pid,PMAP_NOALLOC);
+
+  if (!p || !p->map)
+    return NULL;
+
+  if (fd >= NumElem(p->map->paths))
+    return NULL;
+
+  return p->map->paths[fd];
+}
+
+// delete the fd/path map for a pid
+void fdmap_pdel(pid_t pid)
+{
+  pmap_t *p;
+  int fd;
+
+  debug("fdmap_pdel(pid=%d)\n",pid);
+
+  p = get_pmap(pid,PMAP_NOALLOC);
+
+  if (!p)
+    return;
+
+  p->pid = 0;
+
+  if (!p->map)
+    return;
+
+  --p->map->refcount;
+
+  if (p->map->refcount == 0)
+    {
+      for (fd=0; fd<NumElem(p->map->paths); ++fd)
+        if (p->map->paths[fd])
+          free(p->map->paths[fd]);
+      free(p->map);
+    }
+
+  p->map = NULL;
+}
+
+// copy fd/path mapping from opid to npid
+void fdmap_copy(pid_t npid, pid_t opid)
+{
+  pmap_t *op;
+  int fd;
+
+  debug("fdmap_copy(npid=%d, opid=%d)\n",npid,opid);
+
+  op = get_pmap(opid,PMAP_NOALLOC);
+
+  if (!op || !op->map)
+    return;
+
+  for (fd=0; fd<NumElem(op->map->paths); ++fd)
+    if (op->map->paths[fd])
+      fdmap_add(npid,fd,op->map->paths[fd]);
+}
+
+// make npid and npid share opid's mapping 
+void fdmap_share(pid_t npid, pid_t opid)
+{
+  pmap_t *op,*np;
+
+  debug("fdmap_share(npid=%d, opid=%d)\n",npid,opid);
+  
+  op = get_pmap(opid,PMAP_NOALLOC);
+
+  if (!op)
+    return;
+
+  fdmap_pdel(npid);
+  np = get_pmap(npid,PMAP_ALLOC);
+
+  if (!np)
+    return;
+
+  if (op->map)
+    {
+      // share map from old pid
+      np->map = op->map;
+      ++np->map->refcount;
+    }
+  else
+    {
+      // old pid didn't have a map yet, so create one and share it.
+      np->map = op->map = calloc(1, sizeof (fdmap_t));
+      if (!op->map)
+        {
+          fprintf(stderr,"fdmap: calloc() failed\n");
+          return;
+        }
+      op->map->refcount = 2;
+    }
+  
+}
+
+// add a path to the set we're tracing.  Secifying NULL will delete
+// all paths.
+void fdmap_select(char *path)
+{
+  int i;
+
+  debug("fdmap_select(%s)\n", path);
+
+  if (path==NULL)
+    {
+      for (i=0; i<NumElem(selected); ++i)
+        if (selected[i])
+          {
+            free(selected[i]);
+            selected[i] = NULL;
+          }
+      return;
+    }
+
+  for (i=0; i<NumElem(selected); ++i)
+    if (!selected[i])
+      {
+        selected[i] = strdup(path);
+        return;
+      }
+  
+  fprintf(stderr,"fdmap: max paths exceeded, only using first %d\n",NumElem(selected));
+}
+
+// return true if specified path matches one that we're tracing
+int fdmap_pathmatch(pid_t pid, char *path)
+{
+  int i;
+  for (i=0; i<NumElem(selected); ++i)
+    {
+      if (selected[i] == NULL)
+        return 0;
+      if (!strcmp(path,selected[i]))
+        return 1;
+    }
+  return 0;
+}
+
+// return true if spedified fd maps to a path we're tracing
+int fdmap_fdmatch(pid_t pid, int fd)
+{
+  char *path =fdmap_get(pid,fd);
+  if (!path)
+    return 0;
+  return fdmap_pathmatch(pid,path);
+}
+
+// clear all pid,fd,path mappings, and delete all path selections
+void fdmap_done(void)
+{
+  int i;
+  debug("fdmap_done()\n");
+  for (i=0; i<NumElem(pmap); ++i)
+    if (pmap[i].pid)
+      fdmap_pdel(pmap[i].pid);
+  fdmap_select(NULL);
+}
diff -U10 -rN -X excludelist strace-4.5.20-reformatted/fdmap.h strace-4.5.20-pathtrace/fdmap.h
--- strace-4.5.20-reformatted/fdmap.h	1969-12-31 18:00:00.000000000 -0600
+++ strace-4.5.20-pathtrace/fdmap.h	2011-02-11 14:05:27.000000000 -0600
@@ -0,0 +1,12 @@
+#include <sys/types.h>
+extern void  fdmap_add(pid_t pid, int fd, char *path);
+extern void  fdmap_del(pid_t pid, int fd);
+extern char *fdmap_get(pid_t pid, int fd);
+extern void  fdmap_copy(pid_t npid, pid_t opid);
+extern void  fdmap_share(pid_t npid, pid_t opid);
+extern void  fdmap_pdel(pid_t pid);
+extern void  fdmap_display(void);
+extern void  fdmap_select(char *path);
+extern  int  fdmap_fdmatch(pid_t, int fd);
+extern  int  fdmap_pathmatch(pid_t, char *path);
+extern void  fdmap_done(void);
diff -U10 -rN -X excludelist strace-4.5.20-reformatted/io.c strace-4.5.20-pathtrace/io.c
--- strace-4.5.20-reformatted/io.c	2011-02-14 13:51:52.000000000 -0600
+++ strace-4.5.20-pathtrace/io.c	2011-02-11 16:40:28.000000000 -0600
@@ -45,40 +45,40 @@
 #define sys_pread64	sys_pread
 #define sys_pwrite64	sys_pwrite
 #endif
 
 int
 sys_read(tcp)
 struct tcb *tcp;
 {
   if (entering(tcp))
     {
-      tprintf("%ld, ", tcp->u_arg[0]);
+      tprintf("%s, ", formatfd(tcp,tcp->u_arg[0]));
     }
   else
     {
       if (syserror(tcp))
         tprintf("%#lx", tcp->u_arg[1]);
       else
         printstr(tcp, tcp->u_arg[1], tcp->u_rval);
       tprintf(", %lu", tcp->u_arg[2]);
     }
   return 0;
 }
 
 int
 sys_write(tcp)
 struct tcb *tcp;
 {
   if (entering(tcp))
     {
-      tprintf("%ld, ", tcp->u_arg[0]);
+      tprintf("%s, ", formatfd(tcp,tcp->u_arg[0]));
       printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
       tprintf(", %lu", tcp->u_arg[2]);
     }
   return 0;
 }
 
 #if HAVE_SYS_UIO_H
 void
 tprint_iov(tcp, len, addr)
 struct tcb * tcp;
@@ -166,21 +166,21 @@
 #undef iov_iov_base
 #undef iov_iov_len
 }
 
 int
 sys_readv(tcp)
 struct tcb *tcp;
 {
   if (entering(tcp))
     {
-      tprintf("%ld, ", tcp->u_arg[0]);
+      tprintf("%s, ", formatfd(tcp,tcp->u_arg[0]));
     }
   else
     {
       if (syserror(tcp))
         {
           tprintf("%#lx, %lu",
                   tcp->u_arg[1], tcp->u_arg[2]);
           return 0;
         }
       tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
@@ -188,37 +188,37 @@
     }
   return 0;
 }
 
 int
 sys_writev(tcp)
 struct tcb *tcp;
 {
   if (entering(tcp))
     {
-      tprintf("%ld, ", tcp->u_arg[0]);
+      tprintf("%s, ", formatfd(tcp,tcp->u_arg[0]));
       tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
       tprintf(", %lu", tcp->u_arg[2]);
     }
   return 0;
 }
 #endif
 
 #if defined(SVR4)
 
 int
 sys_pread(tcp)
 struct tcb *tcp;
 {
   if (entering(tcp))
     {
-      tprintf("%ld, ", tcp->u_arg[0]);
+      tprintf("%s, ", formatfd(tcp,tcp->u_arg[0]));
     }
   else
     {
       if (syserror(tcp))
         tprintf("%#lx", tcp->u_arg[1]);
       else
         printstr(tcp, tcp->u_arg[1], tcp->u_rval);
 #if UNIXWARE
       /* off_t is signed int */
       tprintf(", %lu, %ld", tcp->u_arg[2], tcp->u_arg[3]);
@@ -229,21 +229,21 @@
     }
   return 0;
 }
 
 int
 sys_pwrite(tcp)
 struct tcb *tcp;
 {
   if (entering(tcp))
     {
-      tprintf("%ld, ", tcp->u_arg[0]);
+      tprintf("%s, ", formatfd(tcp,tcp->u_arg[0]));
       printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
 #if UNIXWARE
       /* off_t is signed int */
       tprintf(", %lu, %ld", tcp->u_arg[2], tcp->u_arg[3]);
 #else
       tprintf(", %lu, %llu", tcp->u_arg[2],
               LONG_LONG(tcp->u_arg[3], tcp->u_arg[4]));
 #endif
     }
   return 0;
@@ -253,21 +253,21 @@
 #ifdef FREEBSD
 #include <sys/types.h>
 #include <sys/socket.h>
 
 int
 sys_sendfile(tcp)
 struct tcb *tcp;
 {
   if (entering(tcp))
     {
-      tprintf("%ld, %ld, %llu, %lu", tcp->u_arg[0], tcp->u_arg[1],
+      tprintf("%s, %s, %llu, %lu", formatfd(tcp,tcp->u_arg[0]), formatfd(tcp,tcp->u_arg[1]),
               LONG_LONG(tcp->u_arg[2], tcp->u_arg[3]),
               tcp->u_arg[4]);
     }
   else
     {
       off_t offset;
 
       if (!tcp->u_arg[5])
         tprintf(", NULL");
       else
@@ -309,135 +309,135 @@
 #else
 #define PREAD_OFFSET_ARG 3
 #endif
 
 int
 sys_pread(tcp)
 struct tcb *tcp;
 {
   if (entering(tcp))
     {
-      tprintf("%ld, ", tcp->u_arg[0]);
+      tprintf("%s, ", formatfd(tcp,tcp->u_arg[0]));
     }
   else
     {
       if (syserror(tcp))
         tprintf("%#lx", tcp->u_arg[1]);
       else
         printstr(tcp, tcp->u_arg[1], tcp->u_rval);
       tprintf(", %lu, ", tcp->u_arg[2]);
       printllval(tcp, "%llu", PREAD_OFFSET_ARG);
     }
   return 0;
 }
 
 int
 sys_pwrite(tcp)
 struct tcb *tcp;
 {
   if (entering(tcp))
     {
-      tprintf("%ld, ", tcp->u_arg[0]);
+      tprintf("%s, ", formatfd(tcp,tcp->u_arg[0]));
       printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
       tprintf(", %lu, ", tcp->u_arg[2]);
       printllval(tcp, "%llu", PREAD_OFFSET_ARG);
     }
   return 0;
 }
 
 int
 sys_sendfile(tcp)
 struct tcb *tcp;
 {
   if (entering(tcp))
     {
       off_t offset;
 
-      tprintf("%ld, %ld, ", tcp->u_arg[0], tcp->u_arg[1]);
+      tprintf("%s, %s, ", formatfd(tcp,tcp->u_arg[0]), formatfd(tcp,tcp->u_arg[1]));
       if (!tcp->u_arg[2])
         tprintf("NULL");
       else if (umove(tcp, tcp->u_arg[2], &offset) < 0)
         tprintf("%#lx", tcp->u_arg[2]);
       else
         tprintf("[%lu]", offset);
       tprintf(", %lu", tcp->u_arg[3]);
     }
   return 0;
 }
 
 int
 sys_sendfile64(tcp)
 struct tcb *tcp;
 {
   if (entering(tcp))
     {
       loff_t offset;
 
-      tprintf("%ld, %ld, ", tcp->u_arg[0], tcp->u_arg[1]);
+      tprintf("%s, %s, ", formatfd(tcp,tcp->u_arg[0]), formatfd(tcp,tcp->u_arg[1]));
       if (!tcp->u_arg[2])
         tprintf("NULL");
       else if (umove(tcp, tcp->u_arg[2], &offset) < 0)
         tprintf("%#lx", tcp->u_arg[2]);
       else
         tprintf("[%llu]", (unsigned long long int) offset);
       tprintf(", %lu", tcp->u_arg[3]);
     }
   return 0;
 }
 
 #endif /* LINUX */
 
 #if _LFS64_LARGEFILE || HAVE_LONG_LONG_OFF_T
 int
 sys_pread64(tcp)
 struct tcb *tcp;
 {
   if (entering(tcp))
     {
-      tprintf("%ld, ", tcp->u_arg[0]);
+      tprintf("%s, ", formatfd(tcp,tcp->u_arg[0]));
     }
   else
     {
       if (syserror(tcp))
         tprintf("%#lx", tcp->u_arg[1]);
       else
         printstr(tcp, tcp->u_arg[1], tcp->u_rval);
       tprintf(", %lu, ", tcp->u_arg[2]);
       printllval(tcp, "%#llx", 3);
     }
   return 0;
 }
 
 int
 sys_pwrite64(tcp)
 struct tcb *tcp;
 {
   if (entering(tcp))
     {
-      tprintf("%ld, ", tcp->u_arg[0]);
+      tprintf("%s, ", formatfd(tcp,tcp->u_arg[0]));
       printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
       tprintf(", %lu, ", tcp->u_arg[2]);
       printllval(tcp, "%#llx", 3);
     }
   return 0;
 }
 #endif
 
 int
 sys_ioctl(tcp)
 struct tcb *tcp;
 {
   const struct ioctlent *iop;
 
   if (entering(tcp))
     {
-      tprintf("%ld, ", tcp->u_arg[0]);
+      tprintf("%s, ", formatfd(tcp,tcp->u_arg[0]));
       iop = ioctl_lookup(tcp->u_arg[1]);
       if (iop)
         {
           tprintf("%s", iop->symbol);
           while ((iop = ioctl_next_match(iop)))
             tprintf(" or %s", iop->symbol);
         }
       else
         tprintf("%#lx", tcp->u_arg[1]);
       ioctl_decode(tcp, tcp->u_arg[1], tcp->u_arg[2]);
diff -U10 -rN -X excludelist strace-4.5.20-reformatted/pathtrace.c strace-4.5.20-pathtrace/pathtrace.c
--- strace-4.5.20-reformatted/pathtrace.c	1969-12-31 18:00:00.000000000 -0600
+++ strace-4.5.20-pathtrace/pathtrace.c	2011-02-14 11:21:11.000000000 -0600
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2011, Comtrol Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <dirent.h>
+#include <ctype.h>
+#include "defs.h"
+#include "syscall.h"
+#include "fdmap.h"
+
+//TBD handle clone/fork for other OSes
+#include <linux/sched.h>
+
+typedef char path_t[1024];
+path_t path;
+
+
+int pathtrace_active;  // true if paths have been specified
+
+// update fd/path mapping based on results of syscall
+
+void pathtrace_update_fdmap(struct tcb *tcp)
+{
+  const struct sysent *s = &sysent[tcp->scno];
+  int  pid = tcp->pid;
+
+  if (!exiting(tcp))
+    return;
+
+  if ((s->sys_func == sys_open || s->sys_func == sys_creat) && (tcp->u_rval >= 0))
+    {
+      umovestr(tcp,tcp->u_arg[0],sizeof path,path);
+      fdmap_add(pid, tcp->u_rval, path);
+    }
+  else if (s->sys_func == sys_close)
+    {
+      fdmap_del(pid, tcp->u_arg[0]);
+    }
+  else if ((s->sys_func == sys_dup || s->sys_func == sys_dup2) && tcp->u_rval >= 0)
+    {
+      fdmap_add(pid,tcp->u_rval,fdmap_get(pid,tcp->u_arg[0]));
+    }
+  else if (s->sys_func == sys_clone)
+    {
+      if (tcp->u_arg[0] & CLONE_FILES)
+        fdmap_share(tcp->u_rval, pid);
+      else
+        fdmap_copy(tcp->u_rval, pid);
+    }
+  else
+    return;
+
+  if (0)
+    fdmap_display();
+}
+
+
+// return true if syscall accesses a selected path (or if no paths
+// have been specified for tracing).
+//
+// [We'll assume that TRACE_DESCRIPTOR means arg[0] is fd, and
+// TRACE_FILE means arg[0] is path.  That's not 100% accurate, but
+// it's close enough to be useful for now.]
+
+int pathtrace_match(struct tcb *tcp)
+{
+  int flags;
+
+  if (!pathtrace_active)
+    return 1;
+
+  flags = sysent[tcp->scno].sys_flags;
+  if (flags & TRACE_FILE)
+    {
+      umovestr(tcp,tcp->u_arg[0],sizeof path,path);
+      return fdmap_pathmatch(tcp->pid,path);
+    }
+  else if (flags & TRACE_DESC)
+    return fdmap_fdmatch(tcp->pid,tcp->u_arg[0]);
+  else
+    return 0;
+} 
+
+// pathlist is a colon-separated list of paths that we want to trace.
+
+void pathtrace_select(char *pathlist)
+{
+  char *path;
+
+  while (1)
+    {
+      path = strtok(pathlist,":");
+      if (!path)
+        break;
+      fdmap_select(path);
+      pathlist=NULL;
+    }
+
+  pathtrace_active = 1;
+}
+
+// load file descriptor table for an already-running process.  only
+// tested on Linux.
+
+extern void  pathtrace_preload(struct tcb *tcp)
+{
+  char procpath[128];
+  DIR *dir;
+
+  snprintf(procpath, sizeof procpath, "/proc/%d/fd", tcp->pid);
+
+  dir = opendir(procpath);
+  if (dir != NULL)
+    {
+      struct dirent *de;
+      while ((de = readdir(dir)) != NULL)
+        {
+          size_t s;
+          if (!isdigit(de->d_name[0]))
+            continue;
+          snprintf(procpath, sizeof procpath, "/proc/%d/fd/%s", tcp->pid, de->d_name);
+          s = readlink(procpath, path, (sizeof path) - 1);
+          if (s>0)
+            {
+              path[s] = '\0';
+              fdmap_add(tcp->pid,atoi(de->d_name),path);
+            }
+        }
+    }
+}
+
+
+// return a "formatted string" for a file descriptor (including the
+// associated path if known)
+
+char *formatfd(struct tcb* tcp, long fd)
+{
+  char *p;
+  // "paths" is storage for return values. we rotate through them so
+  // you can use multiple calls to this function in a printf arg list.
+  // Yea, Ugly.
+  #define NUMPATHS 4                  // must be power of 2
+  static path_t paths[NUMPATHS];
+  static int i;
+  i += 1;
+  i &= NUMPATHS-1;
+  if (show_fd_path && (p=fdmap_get(tcp->pid, fd)))
+    snprintf(paths[i], sizeof paths[i], "%ld<%s>", fd, p);
+  else
+    snprintf(paths[i], sizeof paths[i], "%ld", fd);
+  return paths[i];
+}
+
+
diff -U10 -rN -X excludelist strace-4.5.20-reformatted/strace.c strace-4.5.20-pathtrace/strace.c
--- strace-4.5.20-reformatted/strace.c	2011-02-14 13:51:53.000000000 -0600
+++ strace-4.5.20-pathtrace/strace.c	2011-02-14 11:19:56.000000000 -0600
@@ -96,20 +96,23 @@
  * This allows for more transparent interaction in cases
  * when process and its parent are communicating via signals,
  * wait() etc. Without -D, strace process gets lodged in between,
  * disrupting parent<->child link.
  */
 static bool daemonized_tracer = 0;
 
 /* Sometimes we want to print only succeeding syscalls. */
 int not_failing_only = 0;
 
+/* Should we attempt to show pathnames associated with fd args? */
+int show_fd_path = 0;
+
 static int exit_code = 0;
 static int strace_child = 0;
 
 static char *username = NULL;
 uid_t run_uid;
 gid_t run_gid;
 
 int acolumn = DEFAULT_ACOLUMN;
 int max_strlen = DEFAULT_STRLEN;
 static char *outfname = NULL;
@@ -476,20 +479,21 @@
                   droptcb(tcp);
                   continue;
                 }
               if (!qflag)
                 {
                   fprintf(stderr, ntid > 1
                           ? "Process %u attached with %u threads - interrupt to quit\n"
                           : "Process %u attached - interrupt to quit\n",
                           tcbtab[tcbi]->pid, ntid);
                 }
+              pathtrace_preload(tcp);
               continue;
             } /* if (opendir worked) */
         } /* if (-f) */
 # endif
       if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0)
         {
           perror("attach: ptrace(PTRACE_ATTACH, ...)");
           droptcb(tcp);
           continue;
         }
@@ -507,20 +511,22 @@
            * Also makes grandparent's wait() unblock.
            */
           kill(getppid(), SIGKILL);
         }
 
 #endif /* !USE_PROCFS */
       if (!qflag)
         fprintf(stderr,
                 "Process %u attached - interrupt to quit\n",
                 tcp->pid);
+
+      pathtrace_preload(tcp);
     }
 
   if (interactive)
     sigprocmask(SIG_SETMASK, &empty_set, NULL);
 }
 
 static void
 startup_child (char **argv)
 {
   struct stat statbuf;
@@ -754,25 +760,25 @@
 
   outf = stderr;
   interactive = 1;
   set_sortby(DEFAULT_SORTBY);
   set_personality(DEFAULT_PERSONALITY);
   qualify("trace=all");
   qualify("abbrev=all");
   qualify("verbose=all");
   qualify("signal=all");
   while ((c = getopt(argc, argv,
-                     "+cCdfFhiqrtTvVxz"
+                     "+cCdfFhiqrtTvVxyz"
 #ifndef USE_PROCFS
                      "D"
 #endif
-                     "a:e:o:O:p:s:S:u:E:")) != EOF)
+                     "a:e:o:O:p:s:S:u:E:P:")) != EOF)
     {
       switch (c)
         {
         case 'c':
           if (cflag == CFLAG_BOTH)
             {
               fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
                       progname);
               exit(1);
             }
@@ -817,20 +823,23 @@
           break;
         case 't':
           tflag++;
           break;
         case 'T':
           dtime++;
           break;
         case 'x':
           xflag++;
           break;
+        case 'y':
+          show_fd_path = 1;
+          break;
         case 'v':
           qualify("abbrev=none");
           break;
         case 'V':
           printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
           exit(0);
           break;
         case 'z':
           not_failing_only = 1;
           break;
@@ -855,20 +864,23 @@
             }
           if (pid == getpid())
             {
               fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
               break;
             }
           tcp = alloc_tcb(pid, 0);
           tcp->flags |= TCB_ATTACHED;
           pflag_seen++;
           break;
+        case 'P':
+          pathtrace_select(optarg);
+          break;
         case 's':
           max_strlen = atoi(optarg);
           if (max_strlen < 0)
             {
               fprintf(stderr,
                       "%s: invalid -s argument: %s\n",
                       progname, optarg);
               exit(1);
             }
           break;
diff -U10 -rN -X excludelist strace-4.5.20-reformatted/syscall.c strace-4.5.20-pathtrace/syscall.c
--- strace-4.5.20-reformatted/syscall.c	2011-02-14 13:51:53.000000000 -0600
+++ strace-4.5.20-pathtrace/syscall.c	2011-02-14 09:45:47.000000000 -0600
@@ -2591,20 +2591,21 @@
   return 1;
 }
 
 static int
 trace_syscall_exiting(struct tcb *tcp)
 {
   int sys_res;
   struct timeval tv;
   int res, scno_good;
   long u_error;
+  int pathmatch;
 
   /* Measure the exit time as early as possible to avoid errors. */
   if (dtime || cflag)
     gettimeofday(&tv, NULL);
 
   /* BTW, why we don't just memorize syscall no. on entry
    * in tcp->something?
    */
   scno_good = res = get_scno(tcp);
   if (res == 0)
@@ -2620,20 +2621,30 @@
   if (res == 1)
     internal_syscall(tcp);
 
   if (res == 1 && tcp->scno >= 0 && tcp->scno < nsyscalls &&
       !(qual_flags[tcp->scno] & QUAL_TRACE))
     {
       tcp->flags &= ~TCB_INSYSCALL;
       return 0;
     }
 
+  pathmatch = pathtrace_match(tcp);
+
+  pathtrace_update_fdmap(tcp);
+
+  if (!pathmatch)
+    {
+      tcp->flags &= ~TCB_INSYSCALL;
+      return 0;
+    }
+
   if (tcp->flags & TCB_REPRINT)
     {
       printleader(tcp);
       tprintf("<... ");
       if (scno_good != 1)
         tprintf("????");
       else if (tcp->scno >= nsyscalls || tcp->scno < 0)
         tprintf("syscall_%lu", tcp->scno);
       else
         tprintf("%s", sysent[tcp->scno].sys_name);
@@ -2899,20 +2910,26 @@
 #endif
     }
 
   internal_syscall(tcp);
   if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE))
     {
       tcp->flags |= TCB_INSYSCALL;
       return 0;
     }
 
+  if (!pathtrace_match(tcp))
+    {
+      tcp->flags |= TCB_INSYSCALL;
+      return 0;
+    }
+
   if (cflag == CFLAG_ONLY_STATS)
     {
       tcp->flags |= TCB_INSYSCALL;
       gettimeofday(&tcp->etime, NULL);
       return 0;
     }
 
   printleader(tcp);
   tcp->flags &= ~TCB_REPRINT;
   tcp_last = tcp;
