diff --git a/.gitignore b/.gitignore
index 9f17271..7828bad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,8 @@
 .libs
 .*.swp
 
+.dir-locals.el
+
 ChangeLog
 
 Makefile
diff --git a/Makefile.am b/Makefile.am
index fd2a6c3..aa036ff 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -16,7 +16,7 @@ AM_CPPFLAGS = -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 block.c
+                proc.c scsi.c stream.c block.c pathtrace.c
 noinst_HEADERS = defs.h
 
 EXTRA_DIST = $(man_MANS) errnoent.sh signalent.sh syscallent.sh ioctlsort.c \
diff --git a/defs.h b/defs.h
index bccffbc..a980c53 100644
--- a/defs.h
+++ b/defs.h
@@ -398,6 +398,7 @@ struct tcb {
 #define TCB_SIGTRAPPED	00200	/* Process wanted to block SIGTRAP */
 #define TCB_FOLLOWFORK	00400	/* Process should have forks followed */
 #define TCB_REPRINT	01000	/* We should reprint this syscall on exit */
+#define TCB_FILTERED	02000	/* This system call has been filtered out */
 #ifdef LINUX
 /* x86 does not need TCB_WAITEXECVE.
  * It can detect execve's SIGTRAP by looking at eax/rax.
@@ -407,7 +408,7 @@ struct tcb {
   || defined(POWERPC) || defined(IA64) || defined(HPPA) \
   || defined(SH) || defined(SH64) || defined(S390) || defined(S390X) \
   || defined(ARM) || defined(MIPS) || defined(BFIN) || defined(TILE)
-#  define TCB_WAITEXECVE 02000	/* ignore SIGTRAP after exceve */
+#  define TCB_WAITEXECVE 04000	/* ignore SIGTRAP after exceve */
 # endif
 # define TCB_CLONE_THREAD  010000 /* CLONE_THREAD set in creating syscall */
 # define TCB_GROUP_EXITING 020000 /* TCB_EXITING was exit_group, not _exit */
@@ -449,6 +450,7 @@ struct tcb {
 #define syserror(tcp)	((tcp)->u_error != 0)
 #define verbose(tcp)	(qual_flags[(tcp)->scno] & QUAL_VERBOSE)
 #define abbrev(tcp)	(qual_flags[(tcp)->scno] & QUAL_ABBREV)
+#define filtered(tcp)   ((tcp)->flags & TCB_FILTERED)
 
 struct xlat {
 	int val;
@@ -702,3 +704,11 @@ extern long ia32;
 #endif
 
 extern int not_failing_only;
+extern int show_fd_path;
+extern int tracing_paths;
+
+extern void pathtrace_select(char *path);
+extern int  pathtrace_match(struct tcb *tcp);
+extern void printfd(struct tcb* tcp, long fd);
+
+
diff --git a/desc.c b/desc.c
index 2b9f30a..ebbcf57 100644
--- a/desc.c
+++ b/desc.c
@@ -309,7 +309,8 @@ int
 sys_fcntl(struct tcb *tcp)
 {
 	if (entering(tcp)) {
-		tprintf("%ld, ", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
 		printxval(fcntlcmds, tcp->u_arg[1], "F_???");
 		switch (tcp->u_arg[1]) {
 		case F_SETFD:
@@ -422,7 +423,8 @@ int
 sys_flock(struct tcb *tcp)
 {
 	if (entering(tcp)) {
-		tprintf("%ld, ", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
 		printflags(flockcmds, tcp->u_arg[1], "LOCK_???");
 	}
 	return 0;
@@ -433,7 +435,7 @@ int
 sys_close(struct tcb *tcp)
 {
 	if (entering(tcp)) {
-		tprintf("%ld", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
 	}
 	return 0;
 }
@@ -442,7 +444,7 @@ int
 sys_dup(struct tcb *tcp)
 {
 	if (entering(tcp)) {
-		tprintf("%ld", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
 	}
 	return 0;
 }
@@ -451,7 +453,9 @@ static int
 do_dup2(struct tcb *tcp, int flags_arg)
 {
 	if (entering(tcp)) {
-		tprintf("%ld, %ld", tcp->u_arg[0], tcp->u_arg[1]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
+		printfd(tcp,tcp->u_arg[1]);
 		if (flags_arg >= 0) {
 			tprintf(", ");
 			printflags(open_mode_flags, tcp->u_arg[flags_arg], "O_???");
diff --git a/file.c b/file.c
index afdbf32..d22fd6e 100644
--- a/file.c
+++ b/file.c
@@ -543,7 +543,8 @@ sys_lseek(struct tcb *tcp)
 	int _whence;
 
 	if (entering(tcp)) {
-		tprintf("%ld, ", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
 		offset = tcp->ext_arg[1];
 		_whence = tcp->u_arg[2];
 		if (_whence == SEEK_SET)
@@ -562,7 +563,8 @@ sys_lseek(struct tcb *tcp)
 	int _whence;
 
 	if (entering(tcp)) {
-		tprintf("%ld, ", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
 		offset = tcp->u_arg[1];
 		_whence = tcp->u_arg[2];
 		if (_whence == SEEK_SET)
@@ -586,14 +588,16 @@ sys_llseek(struct tcb *tcp)
 		 * rather than one 64-bit argument for which LONG_LONG works
 		 * appropriate for the native byte order.
 		 */
-		if (tcp->u_arg[4] == SEEK_SET)
-			tprintf("%ld, %llu, ", tcp->u_arg[0],
-				(((long long int) tcp->u_arg[1]) << 32
-				 | (unsigned long long) (unsigned) tcp->u_arg[2]));
-		else
-			tprintf("%ld, %lld, ", tcp->u_arg[0],
-				(((long long int) tcp->u_arg[1]) << 32
-				 | (unsigned long long) (unsigned) tcp->u_arg[2]));
+		if (tcp->u_arg[4] == SEEK_SET) {
+			printfd(tcp,tcp->u_arg[0]);
+			tprintf(", %llu, ", (((long long int) tcp->u_arg[1]) << 32
+					     | (unsigned long long) (unsigned) tcp->u_arg[2]));
+		}
+		else {
+			printfd(tcp,tcp->u_arg[0]);
+			tprintf(", %lld, ", (((long long int) tcp->u_arg[1]) << 32
+					     | (unsigned long long) (unsigned) tcp->u_arg[2]));
+		}
 	}
 	else {
 		long long int off;
@@ -611,7 +615,8 @@ sys_readahead(struct tcb *tcp)
 {
 	if (entering(tcp)) {
 		int argn;
-		tprintf("%ld, ", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
 		argn = printllval(tcp, "%lld", 1);
 		tprintf(", %ld", tcp->u_arg[argn]);
 	}
@@ -625,7 +630,8 @@ sys_lseek64(struct tcb *tcp)
 {
 	if (entering(tcp)) {
 		int argn;
-		tprintf("%ld, ", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
 		if (tcp->u_arg[3] == SEEK_SET)
 			argn = printllval(tcp, "%llu, ", 1);
 		else
@@ -1366,9 +1372,10 @@ sys_oldstat(struct tcb *tcp)
 int
 sys_fstat(struct tcb *tcp)
 {
-	if (entering(tcp))
-		tprintf("%ld, ", tcp->u_arg[0]);
-	else {
+	if (entering(tcp)) {
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
+	} else {
 		printstat(tcp, tcp->u_arg[1]);
 	}
 	return 0;
@@ -1379,9 +1386,10 @@ int
 sys_fstat64(struct tcb *tcp)
 {
 #ifdef HAVE_STAT64
-	if (entering(tcp))
-		tprintf("%ld, ", tcp->u_arg[0]);
-	else {
+	if (entering(tcp)) {
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
+	} else {
 		printstat64(tcp, tcp->u_arg[1]);
 	}
 	return 0;
@@ -1394,9 +1402,10 @@ sys_fstat64(struct tcb *tcp)
 int
 sys_oldfstat(struct tcb *tcp)
 {
-	if (entering(tcp))
-		tprintf("%ld, ", tcp->u_arg[0]);
-	else {
+	if (entering(tcp)) {
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
+	} else {
 		printoldstat(tcp, tcp->u_arg[1]);
 	}
 	return 0;
@@ -1940,7 +1949,7 @@ int
 sys_fchdir(struct tcb *tcp)
 {
 	if (entering(tcp)) {
-		tprintf("%ld", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
 	}
 	return 0;
 }
@@ -1959,7 +1968,7 @@ int
 sys_fchroot(struct tcb *tcp)
 {
 	if (entering(tcp)) {
-		tprintf("%ld", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
 	}
 	return 0;
 }
@@ -1986,7 +1995,8 @@ sys_linkat(struct tcb *tcp)
 		tprintf(", ");
 		print_dirfd(tcp->u_arg[2]);
 		printpath(tcp, tcp->u_arg[3]);
-		tprintf(", %ld", tcp->u_arg[4]);
+		tprintf(", ");
+		printfd(tcp,tcp->u_arg[4]);
 	}
 	return 0;
 }
@@ -2137,7 +2147,7 @@ int
 sys_fchown(struct tcb *tcp)
 {
 	if (entering(tcp)) {
-		tprintf("%ld", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
 		printuid(", ", tcp->u_arg[1]);
 		printuid(", ", tcp->u_arg[2]);
 	}
@@ -2174,7 +2184,8 @@ int
 sys_fchmod(struct tcb *tcp)
 {
 	if (entering(tcp)) {
-		tprintf("%ld, %#lo", tcp->u_arg[0], tcp->u_arg[1]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", %#lo", tcp->u_arg[1]);
 	}
 	return 0;
 }
@@ -2337,7 +2348,7 @@ int
 sys_fsync(struct tcb *tcp)
 {
 	if (entering(tcp)) {
-		tprintf("%ld", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
 	}
 	return 0;
 }
@@ -2974,7 +2985,8 @@ sys_fallocate(struct tcb *tcp)
 {
 	if (entering(tcp)) {
 		int argn;
-		tprintf("%ld, ", tcp->u_arg[0]);	/* fd */
+		printfd(tcp,tcp->u_arg[0]);		/* fd */
+		tprintf(", ");
 		tprintf("%#lo, ", tcp->u_arg[1]);	/* mode */
 		argn = printllval(tcp, "%llu, ", 2);	/* offset */
 		printllval(tcp, "%llu", argn);		/* len */
diff --git a/io.c b/io.c
index 3d2970c..a0191cf 100644
--- a/io.c
+++ b/io.c
@@ -51,7 +51,8 @@ sys_read(tcp)
 struct tcb *tcp;
 {
 	if (entering(tcp)) {
-		tprintf("%ld, ", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
 	} else {
 		if (syserror(tcp))
 			tprintf("%#lx", tcp->u_arg[1]);
@@ -67,7 +68,8 @@ sys_write(tcp)
 struct tcb *tcp;
 {
 	if (entering(tcp)) {
-		tprintf("%ld, ", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
 		printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
 		tprintf(", %lu", tcp->u_arg[2]);
 	}
@@ -151,7 +153,8 @@ sys_readv(tcp)
 struct tcb *tcp;
 {
 	if (entering(tcp)) {
-		tprintf("%ld, ", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
 	} else {
 		if (syserror(tcp)) {
 			tprintf("%#lx, %lu",
@@ -169,7 +172,8 @@ sys_writev(tcp)
 struct tcb *tcp;
 {
 	if (entering(tcp)) {
-		tprintf("%ld, ", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
 		tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
 		tprintf(", %lu", tcp->u_arg[2]);
 	}
@@ -184,7 +188,8 @@ sys_pread(tcp)
 struct tcb *tcp;
 {
 	if (entering(tcp)) {
-		tprintf("%ld, ", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
 	} else {
 		if (syserror(tcp))
 			tprintf("%#lx", tcp->u_arg[1]);
@@ -206,7 +211,8 @@ sys_pwrite(tcp)
 struct tcb *tcp;
 {
 	if (entering(tcp)) {
-		tprintf("%ld, ", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
 		printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
 #if UNIXWARE
 		/* off_t is signed int */
@@ -229,9 +235,10 @@ sys_sendfile(tcp)
 struct tcb *tcp;
 {
 	if (entering(tcp)) {
-		tprintf("%ld, %ld, %llu, %lu", tcp->u_arg[0], tcp->u_arg[1],
-			LONG_LONG(tcp->u_arg[2], tcp->u_arg[3]),
-			tcp->u_arg[4]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
+		printfd(tcp,tcp->u_arg[1]);
+		tprintf(", %llu, %lu", LONG_LONG(tcp->u_arg[2], tcp->u_arg[3]),	tcp->u_arg[4]);
 	} else {
 		off_t offset;
 
@@ -280,7 +287,8 @@ sys_pread(tcp)
 struct tcb *tcp;
 {
 	if (entering(tcp)) {
-		tprintf("%ld, ", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
 	} else {
 		if (syserror(tcp))
 			tprintf("%#lx", tcp->u_arg[1]);
@@ -297,7 +305,8 @@ sys_pwrite(tcp)
 struct tcb *tcp;
 {
 	if (entering(tcp)) {
-		tprintf("%ld, ", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
 		printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
 		tprintf(", %lu, ", tcp->u_arg[2]);
 		printllval(tcp, "%llu", PREAD_OFFSET_ARG);
@@ -312,7 +321,10 @@ struct tcb *tcp;
 	if (entering(tcp)) {
 		off_t offset;
 
-		tprintf("%ld, %ld, ", tcp->u_arg[0], tcp->u_arg[1]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
+		printfd(tcp,tcp->u_arg[1]);
+		tprintf(", ");
 		if (!tcp->u_arg[2])
 			tprintf("NULL");
 		else if (umove(tcp, tcp->u_arg[2], &offset) < 0)
@@ -331,7 +343,10 @@ struct tcb *tcp;
 	if (entering(tcp)) {
 		loff_t offset;
 
-		tprintf("%ld, %ld, ", tcp->u_arg[0], tcp->u_arg[1]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
+		printfd(tcp,tcp->u_arg[1]);
+		tprintf(", ");
 		if (!tcp->u_arg[2])
 			tprintf("NULL");
 		else if (umove(tcp, tcp->u_arg[2], &offset) < 0)
@@ -351,7 +366,8 @@ sys_pread64(tcp)
 struct tcb *tcp;
 {
 	if (entering(tcp)) {
-		tprintf("%ld, ", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
 	} else {
 		if (syserror(tcp))
 			tprintf("%#lx", tcp->u_arg[1]);
@@ -368,7 +384,8 @@ sys_pwrite64(tcp)
 struct tcb *tcp;
 {
 	if (entering(tcp)) {
-		tprintf("%ld, ", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
 		printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
 		tprintf(", %lu, ", tcp->u_arg[2]);
 		printllval(tcp, "%#llx", 3);
@@ -384,7 +401,8 @@ struct tcb *tcp;
 	const struct ioctlent *iop;
 
 	if (entering(tcp)) {
-		tprintf("%ld, ", tcp->u_arg[0]);
+		printfd(tcp,tcp->u_arg[0]);
+		tprintf(", ");
 		iop = ioctl_lookup(tcp->u_arg[1]);
 		if (iop) {
 			tprintf("%s", iop->symbol);
diff --git a/mem.c b/mem.c
index ec5707a..8b196f9 100644
--- a/mem.c
+++ b/mem.c
@@ -262,9 +262,10 @@ long long offset;
 		printflags(mmap_flags, u_arg[3], "MAP_???");
 #endif
 		/* fd (is always int, not long) */
-		tprintf(", %d, ", (int)u_arg[4]);
+		tprintf(", ");
+		printfd(tcp,(int)u_arg[4]);
 		/* offset */
-		tprintf("%#llx", offset);
+		tprintf(", %#llx", offset);
 	}
 	return RVAL_HEX;
 }
diff --git a/pathtrace.c b/pathtrace.c
new file mode 100644
index 0000000..cac4a80
--- /dev/null
+++ b/pathtrace.c
@@ -0,0 +1,238 @@
+/*
+ * 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 <ctype.h>
+#include "defs.h"
+#include "syscall.h"
+
+#define NumElem(a)  ((sizeof (a))/((sizeof (a)[0])))
+
+#define MAXSELECTED  256  // max number of "selected" paths
+static char *selected[MAXSELECTED];   // paths selected for tracing
+
+// get path associated with pid,fd tuple
+static char *getpath(pid_t pid, int fd)
+{
+  static char path[1024];
+  char linkpath[64];
+  ssize_t n;
+
+  snprintf(linkpath, sizeof linkpath, "/proc/%d/fd/%d", pid, fd);
+  n = readlink(linkpath, path, (sizeof path) - 0);
+  if (n<=0)
+    return NULL;
+  path[n] = '\0';
+  return path;
+}
+
+
+// return true if specified path matches one that we're tracing
+static int 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
+static int fdmatch(pid_t pid, int fd)
+{
+  char *path =getpath(pid,fd);
+  if (!path)
+    return 0;
+  return pathmatch(pid,path);
+}
+
+
+// add a path to the set we're tracing.  Secifying NULL will delete
+// all paths.
+void pathtrace_select(char *path)
+{
+  int i;
+
+  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,"Max trace paths exceeded, only using first %d\n",NumElem(selected));
+}
+
+
+// return true if syscall accesses a selected path (or if no paths
+// have been specified for tracing).
+int pathtrace_match(struct tcb *tcp)
+{
+  char path[1024];
+  const struct sysent *s;
+
+  if (selected[0] == NULL)
+    return 1;
+
+  s = &sysent[tcp->scno];
+
+  if (!(s->sys_flags & (TRACE_FILE | TRACE_DESC)))
+    return 0;
+
+  // check for special cases where we need to do something other than
+  // test arg[0]
+
+#ifdef LINUX
+  if (s->sys_func == sys_dup3 ||
+      s->sys_func == sys_sendfile ||
+      s->sys_func == sys_sendfile64 ||
+      !strcmp(s->sys_name,"tee"))
+    {
+      // fd,fd
+      return fdmatch(tcp->pid,tcp->u_arg[0]) || fdmatch(tcp->pid,tcp->u_arg[1]);
+    }
+
+  if (s->sys_func == sys_inotify_add_watch ||
+      s->sys_func == sys_faccessat ||
+      s->sys_func == sys_fchmodat ||
+      s->sys_func == sys_futimesat ||
+      s->sys_func == sys_mkdirat ||
+      s->sys_func == sys_unlinkat ||
+      s->sys_func == sys_newfstatat ||
+      s->sys_func == sys_mknodat ||
+      s->sys_func == sys_openat ||
+      s->sys_func == sys_readlinkat ||
+      s->sys_func == sys_utimensat ||
+      s->sys_func == sys_fchownat ||
+      s->sys_func == sys_pipe2)
+    {
+      // fd,path
+
+      return fdmatch(tcp->pid,tcp->u_arg[0]) ||
+             (umovestr(tcp,tcp->u_arg[1],sizeof path,path), pathmatch(tcp->pid,path));
+    }
+
+  if (s->sys_func == sys_link ||
+      s->sys_func == sys_pivotroot ||
+      s->sys_func == sys_rename ||
+      s->sys_func == sys_symlink ||
+      s->sys_func == sys_mount)
+    {
+      // path,path
+      return (umovestr(tcp,tcp->u_arg[0],sizeof path,path), pathmatch(tcp->pid,path)) ||
+             (umovestr(tcp,tcp->u_arg[1],sizeof path,path), pathmatch(tcp->pid,path));
+    }
+
+  if (s->sys_func == sys_renameat ||
+      s->sys_func == sys_linkat)
+    {
+      // fd,path,fd,path
+      return fdmatch(tcp->pid,tcp->u_arg[0]) ||
+             fdmatch(tcp->pid,tcp->u_arg[2]) ||
+             (umovestr(tcp,tcp->u_arg[1],sizeof path,path), pathmatch(tcp->pid,path)) ||
+             (umovestr(tcp,tcp->u_arg[3],sizeof path,path), pathmatch(tcp->pid,path));
+    }
+
+  if (s->sys_func == sys_old_mmap)
+    {
+      // x,x,x,x,fd
+      return fdmatch(tcp->pid,tcp->u_arg[4]);
+    }
+
+  if (s->sys_func == sys_symlinkat)
+    {
+      // path,fd,path
+      return fdmatch(tcp->pid,tcp->u_arg[1]) ||
+             (umovestr(tcp,tcp->u_arg[0],sizeof path,path), pathmatch(tcp->pid,path)) ||
+             (umovestr(tcp,tcp->u_arg[2],sizeof path,path), pathmatch(tcp->pid,path));
+    }
+
+
+  if (s->sys_func == sys_poll ||
+      s->sys_func == printargs ||
+      s->sys_func == sys_ppoll  ||
+      s->sys_func == sys_select ||
+      s->sys_func == sys_oldselect  ||
+      s->sys_func == sys_pselect6  ||
+      s->sys_func == sys_pipe  ||
+      s->sys_func == sys_pipe2  ||
+      s->sys_func == sys_eventfd2  ||
+      s->sys_func == sys_eventfd  ||
+      s->sys_func == sys_inotify_init1  ||
+      s->sys_func == sys_timerfd_create)
+    {
+      // these either return fd's or they do other things we donn't
+      // yet handle
+      return 0;
+    }
+#else
+#  warning "path tracing only using arg[0]"
+#endif
+
+
+  if (s->sys_flags & TRACE_FILE)
+    {
+      umovestr(tcp,tcp->u_arg[0],sizeof path,path);
+      return pathmatch(tcp->pid,path);
+    }
+
+  if (s->sys_flags & TRACE_DESC)
+    {
+      return fdmatch(tcp->pid,tcp->u_arg[0]);
+    }
+
+  return 0;
+}
+
+// return a "formatted string" for a file descriptor (including the
+// associated path if known)
+
+void printfd(struct tcb* tcp, long fd)
+{
+  char *p;
+  if (show_fd_path && (p=getpath(tcp->pid, fd)))
+    tprintf("%ld<%s>", fd, p);
+  else
+    tprintf("%ld", fd);
+}
+
+
diff --git a/strace.1 b/strace.1
index ec03e9a..e01f3a4 100644
--- a/strace.1
+++ b/strace.1
@@ -43,7 +43,7 @@ strace \- trace system calls and signals
 .SH SYNOPSIS
 .B strace
 [
-.B \-CdDffhiqrtttTvxx
+.B \-CdDffhiqrtttTvxxy
 ]
 [
 .BI \-a column
@@ -60,6 +60,10 @@ strace \- trace system calls and signals
 ]
 \&...
 [
+.BI \-P path
+]
+\&...
+[
 .BI \-s strsize
 ]
 [
@@ -358,6 +362,9 @@ Print all non-ASCII strings in hexadecimal string format.
 .B \-xx
 Print all strings in hexadecimal string format.
 .TP
+.B \-y
+Print paths associated with file descriptor arguments.
+.TP
 .BI "\-a " column
 Align return values in a specific column (default column 40).
 .TP
@@ -549,6 +556,13 @@ options can be used to attach to up to 32 processes in addition to
 .B \-p
 option is given).
 .TP
+.BI "\-P " path
+Trace only system calls accessing
+.I path.
+Multiple
+.B \-P
+options can be used to specify up to 256 paths.
+.TP
 .BI "\-s " strsize
 Specify the maximum string size to print (the default is 32).  Note
 that filenames are not considered strings and are always printed in
diff --git a/strace.c b/strace.c
index 6b0ebac..d11d327 100644
--- a/strace.c
+++ b/strace.c
@@ -104,6 +104,12 @@ static bool daemonized_tracer = 0;
 /* Sometimes we want to print only succeeding syscalls. */
 int not_failing_only = 0;
 
+/* Show path associated with fd arguments */
+int show_fd_path;
+
+/* are we filtering traces based on paths? */
+int tracing_paths = 0;
+
 static int exit_code = 0;
 static int strace_child = 0;
 
@@ -169,9 +175,9 @@ FILE *ofp;
 int exitval;
 {
 	fprintf(ofp, "\
-usage: strace [-CdDffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]\n\
+usage: strace [-CdDffhiqrtttTvVxxy] [-a column] [-e expr] ... [-o file]\n\
               [-p pid] ... [-s strsize] [-u username] [-E var=val] ...\n\
-              [command [arg ...]]\n\
+              [-P path] [command [arg ...]]\n\
    or: strace -c [-D] [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...\n\
               [command [arg ...]]\n\
 -c -- count time, calls, and errors for each syscall and report summary\n\
@@ -184,6 +190,7 @@ usage: strace [-CdDffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]\n\
 -T -- print time spent in each syscall, -V -- print version\n\
 -v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
 -x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
+-y -- print paths associated with file descriptor arguments\n\
 -a column -- alignment COLUMN for printing syscall results (default %d)\n\
 -e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
    options: trace, abbrev, verbose, raw, signal, read, or write\n\
@@ -196,6 +203,7 @@ usage: strace [-CdDffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]\n\
 -u username -- run command as username handling setuid and/or setgid\n\
 -E var=val -- put var=val in the environment for command\n\
 -E var -- remove var from the environment for command\n\
+-P path -- trace accesses to path\n\
 " /* this is broken, so don't document it
 -z -- print only succeeding syscalls\n\
   */
@@ -781,11 +789,11 @@ main(int argc, char *argv[])
 	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) {
@@ -839,6 +847,9 @@ main(int argc, char *argv[])
 		case 'x':
 			xflag++;
 			break;
+		case 'y':
+			show_fd_path = 1;
+			break;
 		case 'v':
 			qualify("abbrev=none");
 			break;
@@ -875,6 +886,10 @@ main(int argc, char *argv[])
 			tcp->flags |= TCB_ATTACHED;
 			pflag_seen++;
 			break;
+		case 'P':
+			tracing_paths = 1;
+			pathtrace_select(optarg);
+			break;
 		case 's':
 			max_strlen = atoi(optarg);
 			if (max_strlen < 0) {
@@ -1245,7 +1260,7 @@ proc_open(struct tcb *tcp, int attaching)
 #else /* FREEBSD */
 	/* just unset the PF_LINGER flag for the Run-on-Last-Close. */
 	if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
-	        perror("PIOCGFL");
+		perror("PIOCGFL");
 		return -1;
 	}
 	arg &= ~PF_LINGER;
@@ -1363,7 +1378,7 @@ proc_open(struct tcb *tcp, int attaching)
 			   it did the kill -STOP */
 			if (tcp->status.PR_WHY == PR_SIGNALLED &&
 			    tcp->status.PR_WHAT == SIGSTOP)
-			        kill(tcp->pid, SIGCONT);
+				kill(tcp->pid, SIGCONT);
 #endif
 		}
 #ifndef FREEBSD
@@ -1507,8 +1522,8 @@ struct tcb *tcp;
 		tcp->pfd = -1;
 #ifdef FREEBSD
 		if (tcp->pfd_reg != -1) {
-		        close(tcp->pfd_reg);
-		        tcp->pfd_reg = -1;
+			close(tcp->pfd_reg);
+			tcp->pfd_reg = -1;
 		}
 		if (tcp->pfd_status != -1) {
 			close(tcp->pfd_status);
@@ -2095,7 +2110,7 @@ trace()
 		default:
 #ifdef HAVE_POLLABLE_PROCFS
 #ifdef POLL_HACK
-		        /* On some systems (e.g. UnixWare) we get too much ugly
+			/* On some systems (e.g. UnixWare) we get too much ugly
 			   "unfinished..." stuff when multiple proceses are in
 			   syscalls.  Here's a nasty hack */
 
@@ -2239,7 +2254,7 @@ trace()
 #endif /* !FREEBSD */
 		case PR_SYSENTRY:
 #ifdef POLL_HACK
-		        in_syscall = tcp;
+			in_syscall = tcp;
 #endif
 		case PR_SYSEXIT:
 			if (trace_syscall(tcp) < 0) {
diff --git a/syscall.c b/syscall.c
index dc82b2a..38f0a26 100644
--- a/syscall.c
+++ b/syscall.c
@@ -1785,12 +1785,12 @@ get_error(struct tcb *tcp)
 #ifdef FREEBSD
 		if (regs.r_eflags & PSL_C) {
 			tcp->u_rval = -1;
-		        u_error = regs.r_eax;
+			u_error = regs.r_eax;
 		} else {
 			tcp->u_rval = regs.r_eax;
 			tcp->u_lrval =
 			  ((unsigned long long) regs.r_edx << 32) +  regs.r_eax;
-		        u_error = 0;
+			u_error = 0;
 		}
 #endif /* FREEBSD */
 	tcp->u_error = u_error;
@@ -2421,8 +2421,7 @@ trace_syscall_exiting(struct tcb *tcp)
 	if (res == 1)
 		internal_syscall(tcp);
 
-	if (res == 1 && tcp->scno >= 0 && tcp->scno < nsyscalls &&
-	    !(qual_flags[tcp->scno] & QUAL_TRACE)) {
+	if (res==1 && filtered(tcp)) {
 		tcp->flags &= ~TCB_INSYSCALL;
 		return 0;
 	}
@@ -2687,11 +2686,16 @@ trace_syscall_entering(struct tcb *tcp)
 	}
 
 	internal_syscall(tcp);
-	if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
+
+	if ((tracing_paths && !pathtrace_match(tcp)) ||
+	    (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE))) {
+		tcp->flags |= TCB_FILTERED;
 		tcp->flags |= TCB_INSYSCALL;
 		return 0;
 	}
 
+	tcp->flags &= ~TCB_FILTERED;
+
 	if (cflag == CFLAG_ONLY_STATS) {
 		tcp->flags |= TCB_INSYSCALL;
 		gettimeofday(&tcp->etime, NULL);
