Add FreeBSD support
diff --git a/CREDITS b/CREDITS
index 4ff1bc8..ed03b50 100644
--- a/CREDITS
+++ b/CREDITS
@@ -39,3 +39,4 @@
 	Florian Lohoff <flo@rfc822.org>
 	D.J. Barrow <djbarrow@de.ibm.com>
 	Topi Miettinen <Topi.Miettinen@nic.fi>
+	Gaël Roualland <gael.roualland@dial.oleane.com>
diff --git a/ChangeLog b/ChangeLog
index 12050bd..7f6d438 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2000-09-01  Wichert Akkerman <wakkerma@debian.org>
+
+  *  lots of files: merge patch from Gaël Roualland to add
+     support for FreeBSD.
+
 2000-08-09  Wichert Akkerman <wakkerma@debian.org>
 
   * file.c: update to reflect that st_ino suddenly became a long long
diff --git a/Makefile.in b/Makefile.in
index 8b070f9..ca72d1d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -20,7 +20,7 @@
 LDFLAGS = @LDFLAGS@
 WARNFLAGS = @WARNFLAGS@
 
-# OS is one of `linux', `sunos4', or `svr4'.
+# OS is one of `linux', `sunos4', `svr4', or `freebsd'.
 OS = @opsys@
 # ARCH is one of `i386', `m68k', `sparc', `arm', `mips' or `ia64'.
 ARCH = @arch@
@@ -47,7 +47,7 @@
 
 INCLUDES = -I. -I$(OS)/$(ARCH) -I$(srcdir)/$(OS)/$(ARCH) -I$(OS) -I$(srcdir)/$(OS)
 SUBDIRS = $(OSARCH)
-ALL_SUBDIRS = test linux linux/alpha linux/powerpc sunos4 svr4
+ALL_SUBDIRS = test linux linux/alpha linux/powerpc sunos4 svr4 freebsd/i386
 OBJ = strace.o version.o syscall.o util.o \
 	desc.o file.o ipc.o io.o ioctl.o mem.o net.o process.o bjm.o \
 	resource.o signal.o sock.o system.o term.o time.o proc.o stream.o
diff --git a/acconfig.h b/acconfig.h
index 2a711d9..b86ddfa 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -9,6 +9,9 @@
    or a derivative like Solaris 2.x or Irix 5.x.  */
 #undef SVR4
 
+/* Define if this is running the FreeBSD operating system.  */
+#undef FREEBSD
+
 /* Define for UnixWare systems. */
 #undef UNIXWARE
 
diff --git a/configure.in b/configure.in
index c59e583..9f74a54 100644
--- a/configure.in
+++ b/configure.in
@@ -22,6 +22,9 @@
 irix[56]*)
 	opsys=svr4
 	;;
+freebsd*)
+	opsys=freebsd
+	;;
 *)
 	AC_MSG_ERROR(this operating system is not yet supported by strace)
 	;;
@@ -30,7 +33,7 @@
 
 # Autoheader trick.  Heh, heh.
 opsys_list='
-@@@syms="$syms LINUX SUNOS4 SVR4"@@@
+@@@syms="$syms LINUX SUNOS4 SVR4 FREEBSD"@@@
 '
 
 AC_MSG_CHECKING(for supported architecture)
@@ -148,7 +151,7 @@
 AC_CHECK_LIB(nsl, main)
 fi
 AC_CHECK_FUNCS(sigaction strerror strsignal pread sys_siglist _sys_siglist getdents mctl putpmsg prctl sendmsg inet_ntop)
-AC_CHECK_HEADERS(sys/reg.h sys/filio.h sys/acl.h sys/asynch.h sys/door.h sys/stream.h sys/tiuser.h sys/sysconfig.h asm/sigcontext.h ioctls.h sys/ioctl.h sys/ptrace.h termio.h linux/ptrace.h asm/reg.h linux/icmp.h linux/in6.h sys/uio.h linux/netlink.h linux/if_packet.h sys/poll.h)
+AC_CHECK_HEADERS(sys/reg.h sys/filio.h sys/acl.h sys/asynch.h sys/door.h sys/stream.h sys/tiuser.h sys/sysconfig.h asm/sigcontext.h ioctls.h sys/ioctl.h sys/ptrace.h termio.h linux/ptrace.h asm/reg.h linux/icmp.h linux/in6.h sys/uio.h linux/netlink.h linux/if_packet.h sys/poll.h sys/vfs.h)
 AC_DECL_SYS_ERRLIST
 AC_DECL_SYS_SIGLIST
 AC_DECL__SYS_SIGLIST
diff --git a/defs.h b/defs.h
index 906d62e..4dbed04 100644
--- a/defs.h
+++ b/defs.h
@@ -84,12 +84,30 @@
 #  endif
 #endif 
 
-#ifdef SVR4
+#if defined(SVR4) || defined(FREEBSD)
+#define USE_PROCFS
+#else
+#undef USE_PROCFS
+#endif
+
+#ifdef FREEBSD
+#ifndef I386
+#error "FreeBSD support is only for i386 arch right now."
+#endif
+#include <machine/psl.h>
+#include <machine/reg.h>
+#include <sys/syscall.h>
+#endif
+
+#ifdef USE_PROCFS
 #include <sys/procfs.h>
 #ifdef HAVE_MP_PROCFS
 #include <sys/uio.h>
 #endif
-#else /* !SVR4 */
+#ifdef FREEBSD
+#include <sys/pioctl.h>
+#endif /* FREEBSD */
+#else /* !USE_PROCFS */
 #if defined(LINUXSPARC) && defined(__GLIBC__)
 #include <sys/ptrace.h>
 #else
@@ -184,6 +202,22 @@
 #define PR_FLAGS	pr_flags
 #endif
 #endif
+#ifdef FREEBSD
+#define IOCTL		ioctl
+#define IOCTL_STATUS(t)	ioctl (t->pfd, PIOCSTATUS, &t->status)
+#define IOCTL_WSTOP(t)	ioctl (t->pfd, PIOCWAIT, &t->status)
+#define PIOCRUN         PIOCCONT
+#define PIOCWSTOP       PIOCWAIT
+#define PR_WHY		why
+#define PR_WHAT		val
+#define PR_FLAGS	flags
+/* from /usr/src/sys/miscfs/procfs/procfs_vnops.c,
+   status.state = 0 for running, 1 for stopped */
+#define PR_SYSENTRY     S_SCE
+#define PR_SYSEXIT      S_SCX
+#define PR_SIGNALLED    S_SIG
+#define PR_FAULTED      S_CORE
+#endif
 
 /* Trace Control Block */
 struct tcb {
@@ -219,6 +253,11 @@
 	prstatus_t status;	/* procfs status structure */
 #endif
 #endif
+#ifdef FREEBSD
+	struct procfs_status status;
+	int pfd_reg;
+	int pfd_status;
+#endif
 };
 
 /* TCB flags */
@@ -269,8 +308,10 @@
 #define RVAL_HEX	001	/* hex format */
 #define RVAL_OCTAL	002	/* octal format */
 #define RVAL_UDECIMAL	003	/* unsigned decimal format */
-#define RVAL_LDECIMAL	004	/* long long format */
-				/* Maybe add long long hex, octal, unsigned */
+#define RVAL_LDECIMAL	004	/* long decimal format */
+#define RVAL_LHEX	005	/* long hex format */
+#define RVAL_LOCTAL	006	/* long octal format */
+#define RVAL_LUDECIMAL	007	/* long unsigned decimal format */
 #define RVAL_MASK	007	/* mask for these values */
 
 #define RVAL_STR	010	/* Print `auxstr' field after return val */
@@ -315,6 +356,7 @@
 extern void set_overhead P((int));
 extern void qualify P((char *));
 extern void newoutf P((struct tcb *));
+extern int get_scno P((struct tcb *));
 extern int trace_syscall P((struct tcb *));
 extern void printxval P((struct xlat *, int, char *));
 extern int printargs P((struct tcb *));
@@ -375,7 +417,7 @@
 #if !(defined(LINUX) && !defined(SPARC))
 extern long getrval2 P((struct tcb *));
 #endif
-#ifdef SVR4
+#ifdef USE_PROCFS
 extern int proc_open P((struct tcb *tcp, int attaching));
 #endif
 
diff --git a/file.c b/file.c
index a53d229..a74beda 100644
--- a/file.c
+++ b/file.c
@@ -120,7 +120,15 @@
 #  include <sys/cred.h>
 #endif /* SVR4 */
 
+#ifdef HAVE_SYS_VFS_H
 #include <sys/vfs.h>
+#endif
+
+#ifdef FREEBSD
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#endif
 
 #ifdef MAJOR_IN_SYSMACROS
 #include <sys/sysmacros.h>
@@ -222,6 +230,12 @@
 #endif
 #ifdef FNOCTTY
 	{ FNOCTTY,	"FNOCTTY"	},
+#endif	
+#ifdef O_SHLOCK
+	{ O_SHLOCK,	"O_SHLOCK"	},
+#endif
+#ifdef O_EXLOCK
+	{ O_EXLOCK,	"O_EXLOCK"	},
 #endif
 	{ 0,		NULL		},
 };
@@ -339,14 +353,33 @@
 sys_lseek(tcp)
 struct tcb *tcp;
 {
+	off_t offset;
+	int _whence;
+
 	if (entering(tcp)) {
 		tprintf("%ld, ", tcp->u_arg[0]);
-		if (tcp->u_arg[2] == SEEK_SET)
-			tprintf("%lu, ", tcp->u_arg[1]);
+#ifndef FREEBSD
+		offset = tcp->u_arg[1];
+		_whence = tcp->u_arg[2];
+		if (_whence == SEEK_SET)
+			tprintf("%lu, ", offset);
 		else
-			tprintf("%ld, ", tcp->u_arg[1]);
-		printxval(whence, tcp->u_arg[2], "SEEK_???");
-	}
+			tprintf("%ld, ", offset);		
+#else /* FREEBSD */
+		offset = ((off_t) tcp->u_arg[1] << 32) +  tcp->u_arg[2];
+		_whence = tcp->u_arg[4];
+		if (_whence == SEEK_SET)
+			tprintf("%llu, ", offset);
+		else
+			tprintf("%lld, ", offset);		
+#endif		
+		printxval(whence, _whence, "SEEK_???");
+	} 
+#ifdef FREEBSD
+	else
+		if (!syserror(tcp))
+			return RVAL_LUDECIMAL;
+#endif /* FREEBSD */
 	return RVAL_UDECIMAL;
 }
 
@@ -383,7 +416,11 @@
 {
 	if (entering(tcp)) {
 		printpath(tcp, tcp->u_arg[0]);
+#ifndef FREEBSD
 		tprintf(", %lu", tcp->u_arg[1]);
+#else
+		tprintf(", %llu", ((off_t) tcp->u_arg[1] << 32) + tcp->u_arg[2]);
+#endif		
 	}
 	return 0;
 }
@@ -393,7 +430,12 @@
 struct tcb *tcp;
 {
 	if (entering(tcp)) {
+#ifndef FREEBSD
 		tprintf("%ld, %lu", tcp->u_arg[0], tcp->u_arg[1]);
+#else
+		tprintf("%ld, %llu", tcp->u_arg[0],
+			((off_t) tcp->u_arg[1] << 32) + tcp->u_arg[2]);
+#endif		
 	}
 	return 0;
 }
@@ -534,6 +576,50 @@
 }
 #endif /* LINUXSPARC */
 
+#ifdef FREEBSD
+static struct xlat fileflags[] = {
+	{ UF_NODUMP,	"UF_NODUMP"	},
+	{ UF_IMMUTABLE,	"UF_IMMUTABLE"	},
+	{ UF_APPEND,	"UF_APPEND"	},
+	{ UF_OPAQUE,	"UF_OPAQUE"	},
+	{ UF_NOUNLINK,	"UF_NOUNLINK"	},
+	{ SF_ARCHIVED,	"SF_ARCHIVED"	},
+	{ SF_IMMUTABLE,	"SF_IMMUTABLE"	},
+	{ SF_APPEND,	"SF_APPEND"	},
+	{ SF_NOUNLINK,	"SF_NOUNLINK"	},
+	{ 0,		NULL		},
+};
+
+int
+sys_chflags(tcp)
+struct tcb *tcp;
+{
+	if (entering(tcp)) {
+		printpath(tcp, tcp->u_arg[0]);
+		tprintf(", ");
+		if (tcp->u_arg[1])
+			printflags(fileflags, tcp->u_arg[1]);
+		else
+			tprintf("0");
+	}
+	return 0;
+}
+
+int
+sys_fchflags(tcp)
+struct tcb *tcp;
+{
+	if (entering(tcp)) {
+		tprintf("%ld, ", tcp->u_arg[0]);
+		if (tcp->u_arg[1])
+			printflags(fileflags, tcp->u_arg[1]);
+		else
+			tprintf("0");
+	}
+	return 0;
+}
+#endif
+
 static void
 realprintstat(tcp, statbuf)
 struct tcb *tcp;
@@ -577,7 +663,17 @@
     if (!abbrev(tcp)) {
 	    tprintf("st_atime=%s, ", sprinttime(statbuf->st_atime));
 	    tprintf("st_mtime=%s, ", sprinttime(statbuf->st_mtime));
+#ifndef FREEBSD
 	    tprintf("st_ctime=%s}", sprinttime(statbuf->st_ctime));
+#else /* FREEBSD */
+	    tprintf("st_ctime=%s, ", sprinttime(statbuf->st_ctime));
+	    tprintf("st_flags=");
+	    if (statbuf->st_flags) {
+		    printflags(fileflags, statbuf->st_flags);
+	    } else
+		    tprintf("0");
+	    tprintf(", st_gen=%u}", statbuf->st_gen);
+#endif /* FREEBSD */
     }
     else
 	    tprintf("...}");
@@ -1581,6 +1677,21 @@
 
 #endif /* linux */
 
+#ifdef FREEBSD
+struct xlat direnttypes[] = {
+	{ DT_FIFO,	"DT_FIFO" 	},
+	{ DT_CHR,	"DT_CHR" 	},
+	{ DT_DIR,	"DT_DIR" 	},
+	{ DT_BLK,	"DT_BLK" 	},
+	{ DT_REG,	"DT_REG" 	},
+	{ DT_LNK,	"DT_LNK" 	},
+	{ DT_SOCK,	"DT_SOCK" 	},
+	{ DT_WHT,	"DT_WHT" 	},
+	{ 0,		NULL		},
+};
+
+#endif
+
 int
 sys_getdents(tcp)
 struct tcb *tcp;
@@ -1635,6 +1746,15 @@
 				d->d_namlen, d->d_namlen, d->d_name);
 		}
 #endif /* SUNOS4 */
+#ifdef FREEBSD
+		if (!abbrev(tcp)) {
+			tprintf("%s{d_fileno=%u, d_reclen=%u, d_type=",
+				i ? " " : "", d->d_fileno, d->d_reclen);
+			printxval(direnttypes, d->d_type, "DT_???");
+			tprintf(", d_namlen=%u, d_name=\"%.*s\"}",
+				d->d_namlen, d->d_namlen, d->d_name);
+		}
+#endif /* FREEBSD */		
 		if (!d->d_reclen) {
 			tprintf("/* d_reclen == 0, problem here */");
 			break;
@@ -1651,8 +1771,62 @@
 	return 0;
 }
 
-#ifdef linux
+#ifdef FREEBSD
+int
+sys_getdirentries(tcp)
+struct tcb * tcp;
+{
+	int i, len, dents = 0;
+	long basep;
+	char *buf;
 
+	if (entering(tcp)) {
+		tprintf("%lu, ", tcp->u_arg[0]);
+		return 0;
+	}
+	if (syserror(tcp) || !verbose(tcp)) {
+		tprintf("%#lx, %lu, %#lx", tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3]);
+		return 0;
+	}
+	len = tcp->u_rval;
+	if ((buf = malloc(len)) == NULL) {
+		tprintf("out of memory\n");
+		return 0;
+	}
+	if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) {
+		tprintf("{...}, %lu, %#lx", tcp->u_arg[2], tcp->u_arg[3]);
+		free(buf);
+		return 0;
+	}
+	if (!abbrev(tcp))
+		tprintf("{");
+	for (i = 0; i < len;) {
+		struct kernel_dirent *d = (struct kernel_dirent *) &buf[i];
+		if (!abbrev(tcp)) {
+			tprintf("%s{d_fileno=%u, d_reclen=%u, d_type=",
+				i ? " " : "", d->d_fileno, d->d_reclen);
+			printxval(direnttypes, d->d_type, "DT_???");
+			tprintf(", d_namlen=%u, d_name=\"%.*s\"}",
+				d->d_namlen, d->d_namlen, d->d_name);
+		}
+		i += d->d_reclen;
+		dents++;
+	}
+	if (!abbrev(tcp))
+		tprintf("}");
+	else
+		tprintf("/* %u entries */", dents);
+	free(buf);
+	tprintf(", %lu", tcp->u_arg[2]);
+	if (umove(tcp, tcp->u_arg[3], &basep) < 0)
+		tprintf(", %#lx", tcp->u_arg[3]);
+	else
+		tprintf(", [%lu]", basep);
+	return 0;
+}
+#endif
+
+#ifdef linux
 int
 sys_getcwd(tcp)
 struct tcb *tcp;
@@ -1668,6 +1842,22 @@
 }
 #endif /* linux */
 
+#ifdef FREEBSD
+int
+sys___getcwd(tcp)
+struct tcb *tcp;
+{
+    if (exiting(tcp)) {
+	if (syserror(tcp))
+	    tprintf("%#lx", tcp->u_arg[0]);
+	else
+	    printpathn(tcp, tcp->u_arg[0], tcp->u_arg[1]);
+	tprintf(", %lu", tcp->u_arg[1]);
+    }
+    return 0;
+}
+#endif
+
 #ifdef HAVE_SYS_ASYNCH_H
 
 int
diff --git a/freebsd/.cvsignore b/freebsd/.cvsignore
new file mode 100644
index 0000000..f3c7a7c
--- /dev/null
+++ b/freebsd/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/freebsd/ioctlent.sh b/freebsd/ioctlent.sh
new file mode 100644
index 0000000..7d8a21c
--- /dev/null
+++ b/freebsd/ioctlent.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+# initialy from $FreeBSD: src/usr.bin/kdump/mkioctls,v 1.18 2000/08/02 07:37:44 ru Exp $
+# changed by Gaël Roualland.
+
+# Validate arg count.
+if [ $# -ne 1 ]
+then
+        echo "usage: $0 include-directory" >&2
+        exit 1
+fi
+
+# build a list of files with ioctls
+ioctl_includes=`
+	cd $1
+	find * -name '*.h' -follow |
+		egrep -v '^(netns)/' |
+		xargs egrep -l \
+'^#[ 	]*define[ 	]+[A-Za-z_][A-Za-z0-9_]*[ 	]+_IO[^a-z0-9_]'`
+
+# Generate the output file.
+echo '/* This file is automatically generated by ioctlent.sh */'
+echo
+echo '/* XXX obnoxious prerequisites. */'
+echo '#define COMPAT_43'
+echo
+echo '#include <sys/types.h>'
+echo '#include <sys/param.h>'
+echo '#include <sys/devicestat.h>'
+echo '#include <sys/disklabel.h>'
+echo '#include <sys/socket.h>'
+echo '#include <sys/time.h>'
+echo '#include <sys/tty.h>'
+echo '#include <net/ethernet.h>'
+echo '#include <net/if.h>'
+echo '#include <net/if_var.h>'
+echo '#include <net/route.h>'
+echo '#include <netatm/atm.h>'
+echo '#include <netatm/atm_if.h>'
+echo '#include <netatm/atm_sap.h>'
+echo '#include <netatm/atm_sys.h>'
+echo '#include <netinet/in.h>'
+echo '#include <netinet/ip_compat.h>'
+echo '#include <netinet/ip_fil.h>'
+echo '#include <netinet/ip_auth.h>'
+echo '#include <netinet/ip_nat.h>'
+echo '#include <netinet/ip_frag.h>'
+echo '#include <netinet/ip_state.h>'
+echo '#include <netinet/ip_mroute.h>'
+echo '#include <netinet6/in6_var.h>'
+echo '#include <netinet6/nd6.h>'
+echo '#include <netinet6/ip6_mroute.h>'
+echo '#include <cam/cam.h>'
+echo '#include <stdio.h>'
+echo
+echo "$ioctl_includes" | sed -e 's/^/#include </' -e s'/$/>/'
+echo
+echo 'struct ioctlent ioctlent [] ='
+echo '{'
+(cd $1 && for i in $ioctl_includes ; do echo "#include <$i>" | gcc -I$1 -E -dM - | egrep '^#[ 	]*define[ 	]+[A-Za-z_][A-Za-z0-9_]*[ 	]+_IO[^a-z0-9_]' | sed -n -e 's|^#[ 	]*define[ 	]*\([A-Za-z_][A-Za-z0-9_]*\).*|	{ "'$i'", "\1", \1 },|p' ; done )
+
+echo '};'
diff --git a/freebsd/syscalls.cat b/freebsd/syscalls.cat
new file mode 100644
index 0000000..0dde7b6
--- /dev/null
+++ b/freebsd/syscalls.cat
@@ -0,0 +1,177 @@
+#
+# Copyright (c) 2000, Gaël Roualland <gael.roualland@iname.com>
+# 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.
+#
+#      $Id$
+#
+# Syscalls categories
+# syntax: syscall catmask
+#
+# mostly built from other archs/os syscallent.h
+
+# file calls
+access	TF
+acct	TF
+acl	TF
+chdir	TF
+chmod	TF
+chown	TF
+chroot	TF
+creat	TF
+close 	TF
+chflags	TF
+fstat64	TF
+fstat	TF
+fchdir	TF
+fchflags	TF
+lchown	TF
+link	TF
+lstat	TF
+lstat64	TF
+lxstat	TF
+mkdir	TF
+mknod	TF
+mount	TF
+oldlstat	TF
+oldstat	TF
+oldumount	TF
+open	TF
+outime	TF
+pathconf	TF
+pread	TF
+pwrite	TF
+readlink	TF
+rename	TF
+rmdir	TF
+sendfile	TF
+stat	TF
+stat64	TF
+statfs	TF
+statvfs	TF
+swapon	TF
+symlink	TF
+truncate	TF
+umount	TF
+unlink	TF
+unmount	TF
+uselib	TF
+utime	TF
+utimes	TF
+xmknod	TF
+xstat	TF
+
+# file/process calls
+exec	TF|TP
+execv	TF|TP
+execve	TF|TP
+
+# IPC calls
+msgctl	TI
+msgget	TI
+msgrcv	TI
+msgsnd	TI
+msgsys	TI
+semctl	TI
+semget	TI
+semop	TI
+semsys	TI
+shmat	TI
+shmctl	TI
+shmdt	TI
+shmget	TI
+shmsys	TI
+
+# network calls
+accept	TN
+bind	TN
+connect	TN
+getmsg	TN
+getpeername	TN
+getpmsg	TN
+getsockname	TN
+getsockopt	TN
+listen	TN
+poll	TN
+putmsg	TN
+putpmsg	TN
+recv	TN
+recvfrom	TN
+recvmsg	TN
+send	TN
+sendmsg	TN
+sendto	TN
+setsockopt	TN
+shutdown	TN
+socket	TN
+socketpair	TN
+
+# process calls
+_exit	TP
+clone	TP
+fork	TP
+fork1	TP
+owait	TP
+owait3	TP
+vfork	TP
+wait	TP
+wait4	TP
+waitid	TP
+waitpid	TP
+waitsys	TP
+
+# signal calls
+kill	TS
+killpg	TS
+ksigqueue	TS
+pause	TS
+rt_sigaction	TS
+rt_sigpending	TS
+rt_sigprocmask	TS
+rt_sigqueueinfo	TS
+rt_sigreturn	TS
+rt_sigsuspend	TS
+rt_sigtimedwait	TS
+sigaction	TS
+sigaltstack	TS
+sigblock	TS
+sigcleanup	TS
+sigfillset	TS
+siggetmask	TS
+sighold	TS
+sigignore	TS
+signal	TS
+sigpause	TS
+sigpending	TS
+sigpoll	TS
+sigprocmask	TS
+sigrelse	TS
+sigreturn	TS
+sigsendset	TS
+sigset	TS
+sigsetmask	TS
+sigstack	TS
+sigsuspend	TS
+sigtimedwait	TS
+sigvec	TS
diff --git a/freebsd/syscalls.pl b/freebsd/syscalls.pl
new file mode 100644
index 0000000..0b072a9
--- /dev/null
+++ b/freebsd/syscalls.pl
@@ -0,0 +1,151 @@
+#!/usr/bin/perl -w
+#
+# Copyright (c) 2000, Gaël Roualland <gael.roualland@iname.com>
+# 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.
+#
+#      $Id$
+#/
+
+# Buils syscall.h and syscallent.h from:
+# - syscalls.cat containing lines of format: syscall catmask
+# - syscalls.print containing lines of format: syscall [printfunction]
+#   if no printfunction is provided, sys_<call> is used.
+# - syscalls.master in the FreeBSD kernel source tree (/usr/src/sys/kern)
+
+use strict;
+use POSIX;
+
+use vars qw(%sysprint %syscat);
+
+sub usage() {
+    print STDERR 
+	"usage: $0 syscalls.master [<syscalls.print>] [<syscalls.cat>]\n";
+    exit 1;
+}
+
+sub readprint ($) {
+    my($fprint) = @_;
+    
+    open (PRINT, "< $fprint") || die "can't open $fprint: $!";
+    while(<PRINT>) {
+	chomp;
+	s/^\s*//;
+	s/\s+$//;
+	s/#.*$//;
+	my($sys, $func) = split(/\s+/);
+	if (defined($sys)) {
+	    if (defined($func)) {
+		$sysprint{$sys} = $func;
+	    } else {
+		$sysprint{$sys} = "sys_$sys";
+	    }
+	}
+    }
+    close(PRINT);
+}
+
+sub readcat ($) {
+    my($fcat) = @_;
+    
+    open (CAT, "< $fcat") || die "can't open $fcat: $!";
+    while(<CAT>) {
+	chomp;
+	s/^\s*//;
+	s/\s+$//;
+	s/#.*$//;
+	my($sys, $cat) = split(/\s+/);
+	$syscat{$sys} = $cat if (defined($sys) && defined($cat));
+    }
+    close(CAT);
+}
+
+
+usage if (!defined($ARGV[0]) || defined($ARGV[3]));
+
+%sysprint = ();
+readprint $ARGV[1] if defined $ARGV[1];
+
+%syscat = ();
+readcat $ARGV[2] if defined $ARGV[2];
+
+open(MASTER, "< $ARGV[0]") || die "can't open $ARGV[0]: $!";
+
+open(SYSCALL, "> syscall.h") || die "can't create syscall.h: $!";
+
+print SYSCALL "/*\n * Automatically generated by $0 on " . ctime(time()) . " */\n\n";
+print "/*\n * Automatically generated by $0 on " . ctime(time()) . " */\n\n";
+
+my $sysnum = 0;
+
+while (<MASTER>) {
+    chomp;
+    # join broken lines
+    while (/\\$/) {
+	my $line;
+	s/\\$//;
+	$line = <MASTER>;
+	chomp($line);
+	$_ = "$_$line";
+    }
+
+    if (/^(\d+)\s+\w+\s+\w+\s+\{\s*([^}]+)\s*\}([^}]*)$/) {
+	my($proto, $ext, $name, $nargs, @args, $pfunc, $cat);
+	
+	$proto = $2;
+	$ext = $3;
+	
+	if ($1 > $sysnum) { # syscall gap
+	    while($sysnum < $1) {
+		print "  { -1,\t0,\tprintargs,\t\"SYS_$sysnum\"\t}, /* $sysnum */\n";
+		$sysnum++;
+	    }
+	} elsif ($1 < $sysnum) {
+	    warn "error in master file: syscall $1 found, expecting $sysnum.";
+	}
+	
+	if ($proto =~ /^[^\s]+\s+([^\s]+)\s*\(([^)]*)\);/) {
+	    my @args = split(/,/, $2);
+	    $nargs = @args;
+	    $name = $1;
+	    $name = $1 if ($ext =~ /^\s*([^\s]+)\s+[^\s]+\s+[^\s]+$/);
+	    if (defined($sysprint{$name})) {
+		$pfunc = $sysprint{$name};
+		print SYSCALL "int $pfunc();\n";
+	    } else {
+		$pfunc = "sys_$name";
+		print SYSCALL "#define $pfunc printargs\n";
+	    }
+	    if (defined($syscat{$name})) {
+		$cat = $syscat{$name};
+	    } else {
+		$cat = "0";
+	    }
+	    print "  { $nargs,\t$cat,\t$pfunc,\t\"$name\"\t}, /* $sysnum */\n";
+	    $sysnum++;
+	} else {
+	    warn "bad syscall specification for $sysnum: $proto";
+	}
+    }
+}
diff --git a/freebsd/syscalls.print b/freebsd/syscalls.print
new file mode 100644
index 0000000..bc59a6f
--- /dev/null
+++ b/freebsd/syscalls.print
@@ -0,0 +1,192 @@
+#
+# Copyright (c) 2000, Gaël Roualland <gael.roualland@iname.com>
+# 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.
+#
+#      $Id$
+#
+# Printable syscalls
+# syntax: syscall [printfunc]
+#
+# mostly built from sys_* functions in source code
+
+__getcwd
+__sysctl
+accept
+access
+adjtime
+alarm
+bind
+brk
+capget
+capset
+chdir
+chflags
+chmod
+chown
+chroot
+close
+connect
+creat
+dup
+dup2
+errlist
+execv
+execve
+exit
+fchdir
+fchflags
+fchmod
+fchown
+fchroot
+fcntl
+flock
+fork
+fpathconf
+fstat
+fstatfs
+fsync
+ftruncate
+getdents
+getdirentries
+getdomainname
+getdtablesize
+getgid
+getgroups
+gethostid
+gethostname
+getitimer
+getpagesize
+getpeername
+getpgid
+getpgrp
+getpid
+getpriority
+getrlimit
+getrusage
+getsid
+getsockname
+getsockopt
+gettimeofday
+getuid
+indir
+ioctl
+kill
+killpg
+link
+listen
+lseek
+lstat
+mincore
+mkdir
+mkfifo
+mknod
+mmap
+mprotect
+msgctl
+msgget
+msgrcv
+msgsnd
+msync
+munmap
+nerr
+nice
+open
+pathconf
+pipe
+poll
+pread
+ptrace
+pwrite
+quotactl
+read
+readlink
+readv
+recv
+recvfrom
+recvmsg
+rename
+rmdir
+sbrk
+select
+semctl
+semget
+semop
+send
+sendfile
+sendmsg
+sendto
+setdomainname
+setgroups
+sethostname
+setitimer
+setpgid
+setpgrp
+setpriority
+setregid
+setresgid
+setresuid
+setreuid
+setrlimit
+setsid
+setsockopt
+settimeofday
+shmat
+shmctl
+shmdt
+shmget
+shutdown
+sigaction
+sigaltstack
+sigblock
+sigcleanup
+signal
+sigpause
+sigpending
+sigprocmask
+sigsetmask
+sigstack
+sigsuspend
+sigvec
+socket
+socketpair
+stat
+statfs
+stime
+symlink
+sysctl
+time
+times
+truncate
+umask
+uname
+unlink
+utime
+utimes
+vfork
+wait
+wait4
+waitpid
+write
+writev
diff --git a/io.c b/io.c
index 45c3413..a819c11 100644
--- a/io.c
+++ b/io.c
@@ -63,13 +63,47 @@
 	return 0;
 }
 
+void
+tprint_iov(tcp, len, addr)
+struct tcb * tcp;
+int len;
+char * addr;
+{
+	struct iovec *iov;
+	int i;
+
+
+	if (!len) {
+		tprintf("[]");
+		return;
+	}
+	  
+	if ((iov = (struct iovec *) malloc(len * sizeof *iov)) == NULL) {
+		fprintf(stderr, "No memory");
+		return;
+	}
+	if (umoven(tcp, (int) addr,
+		   len * sizeof *iov, (char *) iov) < 0) {
+		tprintf("%#lx", tcp->u_arg[1]);
+	} else {
+		tprintf("[");
+		for (i = 0; i < len; i++) {
+			if (i)
+				tprintf(", ");
+			tprintf("{");
+			printstr(tcp, (long) iov[i].iov_base,
+				iov[i].iov_len);
+			tprintf(", %lu}", (unsigned long)iov[i].iov_len);
+		}
+		tprintf("]");
+	}
+	free((char *) iov);
+}
+
 int
 sys_readv(tcp)
 struct tcb *tcp;
 {
-	struct iovec *iov;
-	int i, len;
-
 	if (entering(tcp)) {
 		tprintf("%ld, ", tcp->u_arg[0]);
 	} else {
@@ -78,27 +112,7 @@
 					tcp->u_arg[1], tcp->u_arg[2]);
 			return 0;
 		}
-		len = tcp->u_arg[2];
-		if ((iov = (struct iovec *) malloc(len * sizeof *iov)) == NULL) {
-			fprintf(stderr, "No memory");
-			return 0;
-		}
-		if (umoven(tcp, tcp->u_arg[1],
-				len * sizeof *iov, (char *) iov) < 0) {
-			tprintf("%#lx", tcp->u_arg[1]);
-		} else {
-			tprintf("[");
-			for (i = 0; i < len; i++) {
-				if (i)
-					tprintf(", ");
-				tprintf("{");
-				printstr(tcp, (long) iov[i].iov_base,
-					iov[i].iov_len);
-				tprintf(", %lu}", (unsigned long)iov[i].iov_len);
-			}
-			tprintf("]");
-		}
-		free((char *) iov);
+		tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
 		tprintf(", %lu", tcp->u_arg[2]);
 	}
 	return 0;
@@ -108,39 +122,15 @@
 sys_writev(tcp)
 struct tcb *tcp;
 {
-	struct iovec *iov;
-	int i, len;
-
 	if (entering(tcp)) {
 		tprintf("%ld, ", tcp->u_arg[0]);
-		len = tcp->u_arg[2];
-		iov = (struct iovec *) malloc(len * sizeof *iov);
-		if (iov == NULL) {
-			fprintf(stderr, "No memory");
-			return 0;
-		}
-		if (umoven(tcp, tcp->u_arg[1],
-				len * sizeof *iov, (char *) iov) < 0) {
-			tprintf("%#lx", tcp->u_arg[1]);
-		} else {
-			tprintf("[");
-			for (i = 0; i < len; i++) {
-				if (i)
-					tprintf(", ");
-				tprintf("{");
-				printstr(tcp, (long) iov[i].iov_base,
-					iov[i].iov_len);
-				tprintf(", %lu}", (unsigned long)iov[i].iov_len);
-			}
-			tprintf("]");
-		}
-		free((char *) iov);
+		tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
 		tprintf(", %lu", tcp->u_arg[2]);
 	}
 	return 0;
 }
 
-#ifdef SVR4
+#if defined(SVR4) || defined(FREEBSD)
 
 int
 sys_pread(tcp)
@@ -157,9 +147,14 @@
 		/* off_t is signed int */
 		tprintf(", %lu, %ld", tcp->u_arg[2], tcp->u_arg[3]);
 #else
+#ifndef FREEBSD
 		tprintf(", %lu, %llu", tcp->u_arg[2],
 				(((unsigned long long) tcp->u_arg[4]) << 32
 				 | tcp->u_arg[3]));
+#else
+		tprintf(", %lu, %llu", tcp->u_arg[2], 
+				(((off_t) tcp->u_arg[3]) << 32) +  tcp->u_arg[4]);
+#endif
 #endif
 	}
 	return 0;
@@ -176,14 +171,61 @@
 		/* off_t is signed int */
 		tprintf(", %lu, %ld", tcp->u_arg[2], tcp->u_arg[3]);
 #else
+#ifndef FREEBSD
 		tprintf(", %lu, %llu", tcp->u_arg[2],
 				(((unsigned long long) tcp->u_arg[4]) << 32
 				 | tcp->u_arg[3]));
+#else
+		tprintf(", %lu, %llu", tcp->u_arg[2],
+				(((off_t) tcp->u_arg[3]) << 32) + tcp->u_arg[4]);
+#endif
 #endif
 	}
 	return 0;
 }
-#endif /* SVR4 */
+#endif /* SVR4 || FREEBSD */
+
+#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],
+			(((unsigned long long) tcp->u_arg[3]) << 32 |
+			 tcp->u_arg[2]), tcp->u_arg[4]);
+	} else {
+		off_t offset;
+
+		if (!tcp->u_arg[5])
+			tprintf(", NULL");
+		else {
+			struct sf_hdtr hdtr;
+
+			if (umove(tcp, tcp->u_arg[5], &hdtr) < 0)
+				tprintf(", %#lx", tcp->u_arg[5]);
+			else {
+				tprintf(", { ");
+				tprint_iov(tcp, hdtr.hdr_cnt, hdtr.headers);
+				tprintf(", %u, ", hdtr.hdr_cnt);
+				tprint_iov(tcp, hdtr.trl_cnt, hdtr.trailers);
+				tprintf(", %u }", hdtr.hdr_cnt);
+			}
+		}
+		if (!tcp->u_arg[6])
+			tprintf(", NULL");
+		else if (umove(tcp, tcp->u_arg[6], &offset) < 0)
+			tprintf(", %#lx", tcp->u_arg[6]);
+		else
+			tprintf(", [%llu]", offset);
+		tprintf(", %lu", tcp->u_arg[7]);
+	}
+	return 0;
+}
+#endif /* FREEBSD */
 
 #ifdef LINUX
 int
diff --git a/ioctl.c b/ioctl.c
index f4bb784..ed2a32b 100644
--- a/ioctl.c
+++ b/ioctl.c
@@ -105,15 +105,22 @@
 #ifdef LINUX
 	case 0x89:
 #else /* !LINUX */
-	case 'r': case 's': case 'i': case 'p':
+	case 'r': case 's': case 'i':
+#ifndef FREEBSD		
+	case 'p':
+#endif		
 #endif /* !LINUX */
 		return sock_ioctl(tcp, code, arg);
-#ifdef SVR4
+#ifdef USE_PROCFS
 #ifndef HAVE_MP_PROCFS
+#ifndef FREEBSD
 	case 'q':
+#else
+	case 'p':
+#endif		
 		return proc_ioctl(tcp, code, arg);
 #endif
-#endif /* SVR4 */
+#endif /* USE_PROCFS */
 #ifdef HAVE_SYS_STREAM_H
 	case 'S':
 		return stream_ioctl(tcp, code, arg);
diff --git a/ipc.c b/ipc.c
index e4dacab..06688f0 100644
--- a/ipc.c
+++ b/ipc.c
@@ -32,7 +32,7 @@
 
 #include "defs.h"
 
-#if defined(LINUX) || defined(SUNOS4)
+#if defined(LINUX) || defined(SUNOS4) || defined(FREEBSD)
 
 #include <sys/ipc.h>
 #include <sys/sem.h>
@@ -98,8 +98,12 @@
 	{ SHM_STAT,	"SHM_STAT"	},
 	{ SHM_INFO,	"SHM_INFO"	},
 #endif /* LINUX */
+#ifdef SHM_LOCK	
 	{ SHM_LOCK,	"SHM_LOCK"	},
+#endif
+#ifdef SHM_UNLOCK	
 	{ SHM_UNLOCK,	"SHM_UNLOCK"	},
+#endif	
 	{ 0,		NULL		},
 };
 
@@ -352,4 +356,4 @@
 	return 0;
 }
 
-#endif /* defined(LINUX) || defined(SUNOS4) */
+#endif /* defined(LINUX) || defined(SUNOS4) || defined(FREEBSD) */
diff --git a/mem.c b/mem.c
index 73a72fc..0d72870 100644
--- a/mem.c
+++ b/mem.c
@@ -134,6 +134,22 @@
 #ifdef MAP_LOCKED
 	{ MAP_LOCKED,"MAP_LOCKED"},
 #endif
+	/* FreeBSD ones */
+#ifdef MAP_ANON
+	{ MAP_ANON,		"MAP_ANON"	},
+#endif
+#ifdef MAP_HASSEMAPHORE
+	{ MAP_HASSEMAPHORE,	"MAP_HASSEMAPHORE"	},
+#endif
+#ifdef MAP_STACK
+	{ MAP_STACK,		"MAP_STACK"	},
+#endif
+#ifdef MAP_NOSYNC
+	{ MAP_NOSYNC,		"MAP_NOSYNC"	},
+#endif
+#ifdef MAP_NOCORE
+	{ MAP_NOCORE,		"MAP_NOCORE"	},
+#endif
 	{ 0,		NULL		},
 };
 
@@ -155,8 +171,12 @@
 		printflags(mmap_prot, u_arg[2]);
 		tprintf(", ");
 		/* flags */
+#ifdef MAP_TYPE
 		printxval(mmap_flags, u_arg[3] & MAP_TYPE, "MAP_???");
 		addflags(mmap_flags, u_arg[3] & ~MAP_TYPE);
+#else
+		printflags(mmap_flags, u_arg[3]);
+#endif
 		/* fd */
 		tprintf(", %ld, ", u_arg[4]);
 		/* offset */
diff --git a/net.c b/net.c
index db88c6d..da061c8 100644
--- a/net.c
+++ b/net.c
@@ -36,6 +36,9 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <netinet/in.h>
+#ifdef FREEBSD
+#include <netinet/tcp.h>
+#endif
 #include <arpa/inet.h>
 #if defined(LINUX)
 #include <asm/types.h>
diff --git a/proc.c b/proc.c
index d4969a6..854657d 100644
--- a/proc.c
+++ b/proc.c
@@ -186,3 +186,88 @@
 #endif /* HAVE_MP_PROCFS */
 #endif /* SVR4 */
 
+#ifdef FREEBSD
+#include <sys/pioctl.h>
+
+static struct xlat proc_status_why[] = {
+	{ S_EXEC,	"S_EXEC"	},
+	{ S_SIG,	"S_SIG"		},
+	{ S_SCE,	"S_SCE"		},
+	{ S_SCX,	"S_SCX"		},
+	{ S_CORE,	"S_CORE"	},
+	{ S_EXIT,	"S_EXIT"	},
+	{ 0,		NULL		}
+};
+
+static struct xlat proc_status_flags[] = {
+	{ PF_LINGER,	"PF_LINGER"	},
+	{ PF_ISUGID,	"PF_ISUGID"	},
+	{ 0,		NULL		}
+};
+
+int
+proc_ioctl(tcp, code, arg)
+struct tcb *tcp;
+int code, arg;
+{
+	int val;
+	struct procfs_status status;
+
+	if (entering(tcp))
+		return 0;
+
+	switch (code) {
+	case PIOCSTATUS:
+	case PIOCWAIT:
+		if (arg == 0)
+			tprintf(", NULL");
+		else if (syserror(tcp))
+			tprintf(", %x", arg);
+		else if (umove(tcp, arg, &status) < 0)
+			tprintf(", {...}");
+		else {
+			tprintf(", {state=%d, flags=", status.state);
+			if (!printflags(proc_status_flags, status.flags))
+				tprintf("0");
+			tprintf(", events=");
+			printflags(proc_status_why, status.events);
+			tprintf(", why=");
+			printxval(proc_status_why, status.why, "S_???");
+			tprintf(", val=%lu}", status.val);
+		}
+		return 1;
+	case PIOCBIS:
+		if (arg) {
+			tprintf(", ");
+			printflags(proc_status_why, arg);
+		} else
+			tprintf(", 0");
+		return 1;
+		return 1;
+	case PIOCSFL:
+		if (arg) {
+			tprintf(", ");
+			printflags(proc_status_flags, arg);
+		} else
+			tprintf(", 0");
+		return 1;
+	case PIOCGFL:
+	        if (syserror(tcp))
+			tprintf(", %#x", arg);
+		else if (umove(tcp, arg, &val) < 0)
+			tprintf(", {...}");
+		else {
+			tprintf(", [");
+			if (val)
+				printflags(proc_status_flags, val);
+			else
+				tprintf("0");
+			tprintf("]");
+		}
+		return 1;
+	default:
+		/* ad naseum */
+		return 0;
+	}
+}
+#endif
diff --git a/process.c b/process.c
index b409fa1..dda3b9e 100644
--- a/process.c
+++ b/process.c
@@ -49,6 +49,10 @@
 #include <machine/reg.h>
 #endif /* SUNOS4 */
 
+#ifdef FREEBSD
+#include <sys/ptrace.h>
+#endif
+
 #ifdef HAVE_SYS_REG_H
 # include <sys/reg.h>
 #ifndef PTRACE_PEEKUSR
@@ -333,7 +337,7 @@
 	return 0;
 }
 
-#ifdef SVR4
+#ifdef USE_PROCFS
 
 int
 sys_fork(tcp)
@@ -372,12 +376,13 @@
 			fprintf(stderr, "sys_fork: tcb table full\n");
 			return 0;
 		}
-		proc_open(tcpchild, 1);
+		if (proc_open(tcpchild, 1) < 0)
+		  	droptcb(tcpchild);
 	}
 	return 0;
 }
 
-#else /* !SVR4 */
+#else /* !USE_PROCFS */
 
 #ifdef LINUX
 
@@ -673,9 +678,9 @@
 	return 0;
 }
 
-#endif /* !SVR4 */
+#endif /* !USE_PROCFS */
 
-#if defined(SUNOS4) || defined(LINUX)
+#if defined(SUNOS4) || defined(LINUX) || defined(FREEBSD)
 
 int
 sys_vfork(tcp)
@@ -686,7 +691,7 @@
 	return 0;
 }
 
-#endif /* SUNOS4 || LINUX */
+#endif /* SUNOS4 || LINUX || FREEBSD */
 
 #ifndef LINUX
 
@@ -832,7 +837,7 @@
 	return 0;
 }
 
-#ifdef LINUX
+#if defined(LINUX) || defined(FREEBSD)
 int
 sys_setresuid(tcp)
      struct tcb *tcp;
@@ -858,7 +863,7 @@
 	return 0;
 }
 
-#endif /* LINUX */
+#endif /* LINUX || FREEBSD */
 
 int
 sys_setgroups(tcp)
@@ -1280,6 +1285,25 @@
 
 #endif /* SVR4 */
 
+#ifdef FREEBSD
+int
+sys_wait(tcp)
+struct tcb *tcp;
+{
+	int status;
+	
+	if (exiting(tcp)) {
+		if (!syserror(tcp)) {
+			if (umove(tcp, tcp->u_arg[0], &status) < 0)
+				tprintf("%#lx", tcp->u_arg[0]);
+			else
+				printstatus(status);
+		}
+	}
+	return 0;
+}
+#endif
+
 int
 sys_waitpid(tcp)
 struct tcb *tcp;
@@ -1608,6 +1632,7 @@
 #ifndef SVR4
 
 static struct xlat ptrace_cmds[] = {
+#ifndef FREEBSD	
 	{ PTRACE_TRACEME,	"PTRACE_TRACEME"	},
 	{ PTRACE_PEEKTEXT,	"PTRACE_PEEKTEXT",	},
 	{ PTRACE_PEEKDATA,	"PTRACE_PEEKDATA",	},
@@ -1653,9 +1678,29 @@
 #endif /* !I386 */
 	{ PTRACE_GETUCODE,	"PTRACE_GETUCODE"	},
 #endif /* SUNOS4 */
+#else /* FREEBSD */
+	{ PT_TRACE_ME,		"PT_TRACE_ME"		},
+	{ PT_READ_I,		"PT_READ_I"		},
+	{ PT_READ_D,		"PT_READ_D"		},
+	{ PT_WRITE_I,		"PT_WRITE_I"		},
+	{ PT_WRITE_D,		"PT_WRITE_D"		},
+	{ PT_READ_U,		"PT_WRITE_U"		},
+	{ PT_CONTINUE,		"PT_CONTINUE"		},
+	{ PT_KILL,		"PT_KILL"		},
+	{ PT_STEP,		"PT_STEP"		},
+	{ PT_ATTACH,		"PT_ATTACH"		},
+	{ PT_DETACH,		"PT_DETACH"		},
+	{ PT_GETREGS,		"PT_GETREGS"		},
+	{ PT_SETREGS,		"PT_SETREGS"		},
+	{ PT_GETFPREGS,		"PT_GETFPREGS"		},
+	{ PT_SETFPREGS,		"PT_SETFPREGS"		},
+	{ PT_GETDBREGS,		"PT_GETDBREGS"		},
+	{ PT_SETDBREGS,		"PT_SETDBREGS"		},
+#endif /* FREEBSD */
 	{ 0,			NULL			},
 };
 
+#ifndef FREEBSD
 #ifndef SUNOS4_KERNEL_ARCH_KLUDGE
 static
 #endif /* !SUNOS4_KERNEL_ARCH_KLUDGE */
@@ -2038,6 +2083,7 @@
 	{ sizeof(struct user),	"sizeof(struct user)"			},
 	{ 0,			NULL					},
 };
+#endif
 
 int
 sys_ptrace(tcp)
@@ -2049,10 +2095,15 @@
 
 	cmd = xlookup(ptrace_cmds, tcp->u_arg[0]);
 	if (!cmd)
+#ifndef FREEBSD
 		cmd = "PTRACE_???";
+#else
+		cmd = "PT_???";
+#endif		
 	if (entering(tcp)) {
 		tprintf("%s, %lu, ", cmd, tcp->u_arg[1]);
 		addr = tcp->u_arg[2];
+#ifndef FREEBSD
 		if (tcp->u_arg[0] == PTRACE_PEEKUSER
 			|| tcp->u_arg[0] == PTRACE_POKEUSER) {
 			for (x = struct_user_offsets; x->str; x++) {
@@ -2069,6 +2120,7 @@
 				tprintf("%s, ", x->str);
 		}
 		else
+#endif
 			tprintf("%#lx, ", tcp->u_arg[2]);
 #ifdef LINUX
 		switch (tcp->u_arg[0]) {
@@ -2113,6 +2165,10 @@
 		}
 	}
 #endif /* SUNOS4 */
+#ifdef FREEBSD
+		tprintf("%lu", tcp->u_arg[3]);
+	}
+#endif /* FREEBSD */
 	return 0;
 }
 
diff --git a/resource.c b/resource.c
index 74222f4..be776ce 100644
--- a/resource.c
+++ b/resource.c
@@ -41,7 +41,7 @@
 #ifdef SUNOS4
 #include <ufs/quota.h>
 #endif /* SUNOS4 */
-#ifdef SVR4
+#if defined(SVR4) || defined(FREEBSD)
 #include <sys/times.h>
 #include <sys/time.h>
 #endif
@@ -439,14 +439,23 @@
 
 #endif /* Linux */
 
-#ifdef SUNOS4
+#if defined(SUNOS4) || defined(FREEBSD)
+
+#ifdef FREEBSD
+#include <ufs/ufs/quota.h>
+#endif
 
 static struct xlat quotacmds[] = {
 	{ Q_QUOTAON,	"Q_QUOTAON"	},
 	{ Q_QUOTAOFF,	"Q_QUOTAOFF"	},
 	{ Q_GETQUOTA,	"Q_GETQUOTA"	},
 	{ Q_SETQUOTA,	"Q_SETQUOTA"	},
+#ifdef Q_SETQLIM
 	{ Q_SETQLIM,	"Q_SETQLIM"	},
+#endif
+#ifdef Q_SETUSE
+	{ Q_SETUSE,	"Q_SETUSE"	},
+#endif
 	{ Q_SYNC,	"Q_SYNC"	},
 	{ 0,		NULL		},
 };
@@ -457,12 +466,19 @@
 {
 	/* fourth arg (addr) not interpreted here */
 	if (entering(tcp)) {
+#ifdef SUNOS4
 		printxval(quotacmds, tcp->u_arg[0], "Q_???");
 		tprintf(", ");
 		printstr(tcp, tcp->u_arg[1], -1);
+#endif
+#ifdef FREEBSD
+		printpath(tcp, tcp->u_arg[0]);
+		tprintf(", ");
+		printxval(quotacmds, tcp->u_arg[1], "Q_???");
+#endif		
 		tprintf(", %lu, %#lx", tcp->u_arg[2], tcp->u_arg[3]);
 	}
 	return 0;
 }
 
-#endif /* SUNOS4 */
+#endif /* SUNOS4 || FREEBSD */
diff --git a/signal.c b/signal.c
index 90ac5fe..1b807d8 100644
--- a/signal.c
+++ b/signal.c
@@ -146,7 +146,7 @@
 char **signalent;
 int nsignals;
 
-#ifdef SUNOS4
+#if defined(SUNOS4) || defined(FREEBSD)
 
 static struct xlat sigvec_flags[] = {
 	{ SV_ONSTACK,	"SV_ONSTACK"	},
@@ -156,7 +156,7 @@
 	{ 0,		NULL		},
 };
 
-#endif /* SUNOS4 */
+#endif /* SUNOS4 || FREEBSD */
 
 #ifdef HAVE_SIGACTION
 
@@ -429,7 +429,7 @@
 #endif /* !SVR4 */
 }
 
-#if defined(SUNOS4)
+#if defined(SUNOS4) || defined(FREEBSD)
 
 int
 sys_sigvec(tcp)
@@ -534,7 +534,7 @@
 	return 0;
 }
 
-#endif /* SUNOS4 */
+#endif /* SUNOS4 || FREEBSD */
 
 #ifndef SVR4
 
@@ -546,12 +546,14 @@
 		sigset_t sigm;
 		long_to_sigset(tcp->u_arg[0], &sigm);
 		printsigmask(&sigm, 0);
+#ifndef USE_PROCFS
 		if ((tcp->u_arg[0] & sigmask(SIGTRAP))) {
 			/* Mark attempt to block SIGTRAP */
 			tcp->flags |= TCB_SIGTRAPPED;
 			/* Send unblockable signal */
 			kill(tcp->pid, SIGSTOP);
 		}
+#endif /* !USE_PROCFS */		
 	}
 	else if (!syserror(tcp)) {
 		sigset_t sigm;
@@ -622,21 +624,21 @@
 			tprintf("{SIG_DFL}");
 			break;
 		case (long) SIG_IGN:
-#ifndef SVR4
+#ifndef USE_PROCFS
 			if (tcp->u_arg[0] == SIGTRAP) {
 				tcp->flags |= TCB_SIGTRAPPED;
 				kill(tcp->pid, SIGSTOP);
 			}
-#endif /* !SVR4 */
+#endif /* !USE_PROCFS */
 			tprintf("{SIG_IGN}");
 			break;
 		default:
-#ifndef SVR4
+#ifndef USE_PROCFS
 			if (tcp->u_arg[0] == SIGTRAP) {
 				tcp->flags |= TCB_SIGTRAPPED;
 				kill(tcp->pid, SIGSTOP);
 			}
-#endif /* !SVR4 */
+#endif /* !USE_PROCFS */
 			tprintf("{%#lx, ", (long) sa.SA_HANDLER);
 #ifndef LINUX
 			printsigmask (&sa.sa_mask, 0);
@@ -674,21 +676,21 @@
 			tprintf("SIG_DFL");
 			break;
 		case (int) SIG_IGN:
-#ifndef SVR4
+#ifndef USE_PROCFS
 			if (tcp->u_arg[0] == SIGTRAP) {
 				tcp->flags |= TCB_SIGTRAPPED;
 				kill(tcp->pid, SIGSTOP);
 			}
-#endif /* !SVR4 */
+#endif /* !USE_PROCFS */
 			tprintf("SIG_IGN");
 			break;
 		default:
-#ifndef SVR4
+#ifndef USE_PROCFS
 			if (tcp->u_arg[0] == SIGTRAP) {
 				tcp->flags |= TCB_SIGTRAPPED;
 				kill(tcp->pid, SIGSTOP);
 			}
-#endif /* !SVR4 */
+#endif /* !USE_PROCFS */
 			tprintf("%#lx", tcp->u_arg[1]);
 		}
 		return 0;
@@ -960,7 +962,7 @@
 
 #endif /* LINUX */
 
-#ifdef SVR4
+#if defined(SVR4) || defined(FREEBSD)
 
 int
 sys_sigsuspend(tcp)
@@ -976,6 +978,7 @@
 	}
 	return 0;
 }
+#ifndef FREEBSD
 static struct xlat ucontext_flags[] = {
 	{ UC_SIGMASK,	"UC_SIGMASK"	},
 	{ UC_STACK,	"UC_STACK"	},
@@ -988,10 +991,10 @@
 #endif
 	{ 0,		NULL		},
 };
+#endif /* !FREEBSD */
+#endif /* SVR4 || FREEBSD */
 
-#endif
-
-#if defined SVR4 || defined LINUX
+#if defined SVR4 || defined LINUX || defined FREEBSD
 #if defined LINUX && !defined SS_ONSTACK
 #define SS_ONSTACK      1
 #define SS_DISABLE      2
@@ -1004,6 +1007,9 @@
 } stack_t;
 #endif
 #endif
+#ifdef FREEBSD
+#define stack_t struct sigaltstack
+#endif
 
 static struct xlat sigaltstack_flags[] = {
 	{ SS_ONSTACK,	"SS_ONSTACK"	},
@@ -1082,7 +1088,7 @@
 
 #endif /* SVR4 */
 
-#ifdef LINUX
+#if defined(LINUX) || defined(FREEBSD)
 
 static int
 print_stack_t(tcp, addr)
diff --git a/strace.c b/strace.c
index f96eaa0..3e4b4a6 100644
--- a/strace.c
+++ b/strace.c
@@ -44,9 +44,12 @@
 #include <grp.h>
 #include <string.h>
 
+#ifdef USE_PROCFS
+#include <poll.h>
+#endif
+
 #ifdef SVR4
 #include <sys/stropts.h>
-#include <poll.h>
 #ifdef HAVE_MP_PROCFS
 #include <sys/uio.h>
 #endif
@@ -87,7 +90,7 @@
 #endif /* !__STDC__ */
 #endif /* !HAVE_SIG_ATOMIC_T */
 
-#ifdef SVR4
+#ifdef USE_PROCFS
 
 static struct tcb *pfd2tcb P((int pfd));
 static void reaper P((int sig));
@@ -115,7 +118,7 @@
 #else
 #define POLLWANT	POLLPRI
 #endif
-#endif /* SVR4 */
+#endif /* USE_PROCFS */
 
 static void
 usage(ofp, exitval)
@@ -334,19 +337,19 @@
 		tcp->outf = outf;
 		if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
 			continue;
-#ifdef SVR4
+#ifdef USE_PROCFS
 		if (proc_open(tcp, 1) < 0) {
 			fprintf(stderr, "trouble opening proc file\n");
 			droptcb(tcp);
 			continue;
 		}
-#else /* !SVR4 */
+#else /* !USE_PROCFS */
 		if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
 			perror("attach: ptrace(PTRACE_ATTACH, ...)");
 			droptcb(tcp);
 			continue;
 		}
-#endif /* !SVR4 */
+#endif /* !USE_PROCFS */
 		if (!qflag)
 			fprintf(stderr,
 				"Process %u attached - interrupt to quit\n",
@@ -408,8 +411,8 @@
 			exit(1);
 			break;
 		case 0: {
-#ifdef SVR4
-			if (outf != stderr) close (fileno (outf));
+#ifdef USE_PROCFS
+		        if (outf != stderr) close (fileno (outf));
 #ifdef MIPS
 			/* Kludge for SGI, see proc_open for details. */
 			sa.sa_handler = foobar;
@@ -417,8 +420,12 @@
 			sigemptyset(&sa.sa_mask);
 			sigaction(SIGINT, &sa, NULL);
 #endif /* MIPS */
+#ifndef FREEBSD
 			pause();
-#else /* !SVR4 */
+#else /* FREEBSD */
+			kill(getpid(), SIGSTOP); /* stop HERE */
+#endif /* FREEBSD */			
+#else /* !USE_PROCFS */
 			if (outf!=stderr)	
 				close(fileno (outf));
 
@@ -459,7 +466,7 @@
 			}
 			else
 				setreuid(run_uid, run_uid);
-#endif /* !SVR4 */
+#endif /* !USE_PROCFS */
 
 			execv(pathname, &argv[optind]);
 			perror("strace: exec");
@@ -472,16 +479,16 @@
 				cleanup();
 				exit(1);
 			}
-#ifdef SVR4
+#ifdef USE_PROCFS
 			if (proc_open(tcp, 0) < 0) {
 				fprintf(stderr, "trouble opening proc file\n");
 				cleanup();
 				exit(1);
 			}
-#endif /* SVR4 */
-#ifndef SVR4
+#endif /* USE_PROCFS */
+#ifndef USE_PROCFS
 			fake_execve(tcp, pathname, &argv[optind], environ);
-#endif
+#endif /* !USE_PROCFS */
 			break;
 		}
 	}
@@ -512,10 +519,10 @@
 	sigaction(SIGQUIT, &sa, NULL);
 	sigaction(SIGPIPE, &sa, NULL);
 	sigaction(SIGTERM, &sa, NULL);
-#ifdef SVR4
+#ifdef USE_PROCFS
 	sa.sa_handler = reaper;
 	sigaction(SIGCHLD, &sa, NULL);
-#endif /* SVR4 */
+#endif /* USE_PROCFS */
 
 	if (trace() < 0)
 		exit(1);
@@ -572,7 +579,7 @@
 	return NULL;
 }
 
-#ifdef SVR4
+#ifdef USE_PROCFS
 int
 proc_open(tcp, attaching)
 struct tcb *tcp;
@@ -580,9 +587,11 @@
 {
 	char proc[32];
 	long arg;
+#ifdef SVR4
 	sysset_t sc_enter, sc_exit;
 	sigset_t signals;
 	fltset_t faults;
+#endif
 #ifndef HAVE_POLLABLE_PROCFS
 	static int last_pfd;
 #endif
@@ -630,8 +639,13 @@
 	}
 #else
 	/* Open the process pseudo-file in /proc. */
+#ifndef FREEBSD
 	sprintf(proc, "/proc/%d", tcp->pid);
 	if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
+#else /* FREEBSD */
+	sprintf(proc, "/proc/%d/mem", tcp->pid);
+	if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
+#endif /* FREEBSD */
 		perror("strace: open(\"/proc/...\", ...)");
 		return -1;
 	}
@@ -644,6 +658,21 @@
 		return -1;
 	}
 #endif
+#ifdef FREEBSD
+	sprintf(proc, "/proc/%d/regs", tcp->pid);
+	if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
+		perror("strace: open(\"/proc/.../regs\", ...)");
+		return -1;
+	}
+	if (cflag) {
+		sprintf(proc, "/proc/%d/status", tcp->pid);
+		if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
+			perror("strace: open(\"/proc/.../status\", ...)");
+			return -1;
+		}
+	} else
+		tcp->pfd_status = -1;
+#endif /* FREEBSD */
 	rebuild_pollv();
 	if (!attaching) {
 		/*
@@ -655,15 +684,21 @@
 				perror("strace: PIOCSTATUS");
 				return -1;
 			}
+#ifndef FREEBSD			
 			if (tcp->status.PR_FLAGS & PR_ASLEEP)
-				break;
+#else
+			if (tcp->status.state == 1)
+#endif
+			    break;
 		}
 	}
+#ifndef FREEBSD
 	/* Stop the process so that we own the stop. */
 	if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
 		perror("strace: PIOCSTOP");
 		return -1;
 	}
+#endif	
 #ifdef PIOCSET
 	/* Set Run-on-Last-Close. */
 	arg = PR_RLC;
@@ -678,6 +713,7 @@
 		return -1;
 	}
 #else  /* !PIOCSET */
+#ifndef FREEBSD	
 	if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
 		perror("PIOCSRLC");
 		return -1;
@@ -686,7 +722,20 @@
 		perror("PIOC{S,R}FORK");
 		return -1;
 	}
+#else /* FREEBSD */
+	/* just unset the PF_LINGER flag for the Run-on-Last-Close. */
+	if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
+	        perror("PIOCGFL");
+	        return -1;
+	}
+	arg &= ~PF_LINGER;
+	if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
+	        perror("PIOCSFL");
+	        return -1;
+	}
+#endif /* FREEBSD */
 #endif /* !PIOCSET */
+#ifndef FREEBSD
 	/* Enable all syscall entries. */
 	prfillset(&sc_enter);
 	if (IOCTL(tcp->pfd, PIOCSENTRY, &sc_enter) < 0) {
@@ -711,6 +760,14 @@
 		perror("PIOCSFAULT");
 		return -1;
 	}
+#else /* FREEBSD */
+	/* set events flags. */
+	arg = S_SIG | S_SCE | S_SCX ;
+	if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
+		perror("PIOCBIS");
+		return -1;
+	}
+#endif /* FREEBSD */
 	if (!attaching) {
 #ifdef MIPS
 		/*
@@ -719,13 +776,19 @@
 		 */
 		kill(tcp->pid, SIGINT);
 #else /* !MIPS */
+#ifdef PRSABORT	
 		/* The child is in a pause(), abort it. */
 		arg = PRSABORT;
 		if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
 			perror("PIOCRUN");
 			return -1;
 		}
-#endif /* !MIPS */
+#endif		
+#endif /* !MIPS*/
+#ifdef FREEBSD
+		/* wake up the child if it received the SIGSTOP */
+		kill(tcp->pid, SIGCONT);
+#endif		
 		for (;;) {
 			/* Wait for the child to do something. */
 			if (IOCTL_WSTOP (tcp) < 0) {
@@ -733,22 +796,40 @@
 				return -1;
 			}
 			if (tcp->status.PR_WHY == PR_SYSENTRY) {
-#ifdef HAVE_PR_SYSCALL
-				int scno = tcp->status.pr_syscall;
-#else /* !HAVE_PR_SYSCALL */
-				int scno = tcp->status.PR_WHAT;
-#endif /* !HAVE_PR_SYSCALL */
-				if (scno == SYS_execve)
+				tcp->flags &= ~TCB_INSYSCALL;
+				get_scno(tcp);
+				if (tcp->scno == SYS_execve)
 					break;
 			}
 			/* Set it running: maybe execve will be next. */
+#ifndef FREEBSD
 			arg = 0;
 			if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
+#else /* FREEBSD */
+			if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
+#endif /* FREEBSD */			  
 				perror("PIOCRUN");
 				return -1;
 			}
+#ifdef FREEBSD
+			/* handle the case where we "opened" the child before
+			   it did the kill -STOP */
+			if (tcp->status.PR_WHY == PR_SIGNALLED &&
+			    tcp->status.PR_WHAT == SIGSTOP)
+			        kill(tcp->pid, SIGCONT);
+#endif			
 		}
+#ifndef FREEBSD
 	}
+#else /* FREEBSD */
+	} else {
+	       /* little hack to show the current syscall */
+	       IOCTL_STATUS(tcp);
+	       tcp->flags &= ~TCB_INSYSCALL;
+	       tcp->status.why = PR_SYSENTRY;
+	       trace_syscall(tcp);
+	}
+#endif /* FREEBSD */
 #ifndef HAVE_POLLABLE_PROCFS
 	if (proc_poll_pipe[0] != -1)
 		proc_poller(tcp->pfd);
@@ -762,7 +843,7 @@
 	return 0;
 }
 
-#endif /* SVR4 */
+#endif /* USE_PROCFS */
 
 static struct tcb *
 pid2tcb(pid)
@@ -780,7 +861,7 @@
 	return NULL;
 }
 
-#ifdef SVR4
+#ifdef USE_PROCFS
 
 static struct tcb *
 pfd2tcb(pfd)
@@ -798,7 +879,7 @@
 	return NULL;
 }
 
-#endif /* SVR4 */
+#endif /* USE_PROCFS */
 
 void
 droptcb(tcp)
@@ -812,7 +893,17 @@
 	if (tcp->pfd != -1) {
 		close(tcp->pfd);
 		tcp->pfd = -1;
-#ifdef SVR4
+#ifdef FREEBSD
+		if (tcp->pfd_reg != -1) {
+		        close(tcp->pfd_reg);
+		        tcp->pfd_reg = -1;
+		}
+		if (tcp->pfd_status != -1) {
+			close(tcp->pfd_status);
+			tcp->pfd_status = -1;
+		}
+#endif /* !FREEBSD */		
+#ifdef USE_PROCFS
 		rebuild_pollv();
 #endif
 	}
@@ -827,7 +918,7 @@
 	tcp->outf = 0;
 }
 
-#ifndef SVR4
+#ifndef USE_PROCFS
 
 static int
 resume(tcp)
@@ -852,7 +943,7 @@
 	return 0;
 }
 
-#endif /* !SVR4 */
+#endif /* !USE_PROCFS */
 
 /* detach traced process; continue with sig */
 
@@ -934,10 +1025,10 @@
 		perror("detach: ptrace(PTRACE_DETACH, ...)");
 #endif /* SUNOS4 */
 
-#ifndef SVR4
+#ifndef USE_PROCFS
 	if (waiting_parent(tcp))
 		error = resume(tcp->parent);
-#endif /* !SVR4 */
+#endif /* !USE_PROCFS */
 
 	if (!qflag)
 		fprintf(stderr, "Process %u detached\n", tcp->pid);
@@ -946,7 +1037,7 @@
 	return error;
 }
 
-#ifdef SVR4
+#ifdef USE_PROCFS
 
 static void
 reaper(sig)
@@ -966,7 +1057,7 @@
 	}
 }
 
-#endif /* SVR4 */
+#endif /* USE_PROCFS */
 
 static void
 cleanup()
@@ -1054,7 +1145,7 @@
 
 #endif /* HAVE_STRSIGNAL */
 
-#ifdef SVR4
+#ifdef USE_PROCFS
 
 static void
 rebuild_pollv()
@@ -1141,6 +1232,9 @@
 	int i;
 	int n;
 	struct rlimit rl;
+#ifdef FREEBSD
+	struct procfs_status pfs;
+#endif /* FREEBSD */
 
 	switch (fork()) {
 	case -1:
@@ -1180,7 +1274,11 @@
 	pollinfo.fd = pfd;
 	pollinfo.pid = getpid();
 	for (;;) {
-		if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
+#ifndef FREEBSD
+	        if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
+#else /* FREEBSD */
+	        if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
+#endif /* FREEBSD */
 		{
 			switch (errno) {
 			case EINTR:
@@ -1331,7 +1429,17 @@
 	FOUND:
 		/* Get the status of the process. */
 		if (!interrupted) {
+#ifndef FREEBSD
 			ioctl_result = IOCTL_WSTOP (tcp);
+#else /* FREEBSD */
+			/* Thanks to some scheduling mystery, the first poller
+			   sometimes waits for the already processed end of fork
+			   event. Doing a non blocking poll here solves the problem. */
+			if (proc_poll_pipe[0] != -1)
+				ioctl_result = IOCTL_STATUS (tcp);
+			else
+			  	ioctl_result = IOCTL_WSTOP (tcp);
+#endif /* FREEBSD */			  
 			ioctl_errno = errno;
 #ifndef HAVE_POLLABLE_PROCFS
 			if (proc_poll_pipe[0] != -1) {
@@ -1354,6 +1462,9 @@
 			case EINTR:
 			case EBADF:
 				continue;
+#ifdef FREEBSD
+			case ENOTTY:
+#endif			  
 			case ENOENT:
 				droptcb(tcp);
 				continue;
@@ -1371,15 +1482,27 @@
 
 		if (cflag) {
 			struct timeval stime;
+#ifdef FREEBSD
+			char buf[1024];
+			int len;
 
+			if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
+				buf[len] = '\0';
+				sscanf(buf,
+				       "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
+				       &stime.tv_sec, &stime.tv_usec);
+			} else
+				stime.tv_sec = stime.tv_usec = 0;
+#else /* !FREEBSD */			
 			stime.tv_sec = tcp->status.pr_stime.tv_sec;
 			stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
+#endif /* !FREEBSD */
 			tv_sub(&tcp->dtime, &stime, &tcp->stime);
 			tcp->stime = stime;
 		}
-
 		what = tcp->status.PR_WHAT;
 		switch (tcp->status.PR_WHY) {
+#ifndef FREEBSD
 		case PR_REQUESTED:
 			if (tcp->status.PR_FLAGS & PR_ASLEEP) {
 				tcp->status.PR_WHY = PR_SYSENTRY;
@@ -1389,6 +1512,7 @@
 				}
 			}
 			break;
+#endif /* !FREEBSD */
 		case PR_SYSENTRY:
 #ifdef POLL_HACK
 		        in_syscall = tcp;
@@ -1414,13 +1538,21 @@
 				printtrailer(tcp);
 			}
 			break;
+#ifdef FREEBSD
+		case 0: /* handle case we polled for nothing */
+		  	continue;
+#endif			
 		default:
 			fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
 			exit(1);
 			break;
 		}
 		arg = 0;
+#ifndef FREEBSD		
 		if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
+#else		  
+		if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
+#endif		  
 			perror("PIOCRUN");
 			exit(1);
 		}
@@ -1428,7 +1560,7 @@
 	return 0;
 }
 
-#else /* !SVR4 */
+#else /* !USE_PROCFS */
 
 static int
 trace()
@@ -1667,7 +1799,7 @@
 	return 0;
 }
 
-#endif /* !SVR4 */
+#endif /* !USE_PROCFS */
 
 static int curcol;
 
diff --git a/stream.c b/stream.c
index 0cc14a0..4abf861 100644
--- a/stream.c
+++ b/stream.c
@@ -30,7 +30,7 @@
 
 #include "defs.h"
 
-#if defined(HAVE_SYS_STREAM_H) || defined(linux)
+#if defined(HAVE_SYS_STREAM_H) || defined(linux) || defined(FREEBSD)
 
 #if defined(linux)
 #ifdef HAVE_SYS_POLL_H
@@ -48,11 +48,15 @@
 
 #else /* linux */
 
+#ifndef FREEBSD
 #include <stropts.h>
 #include <poll.h>
 #include <sys/conf.h>
 #include <sys/stream.h>
 #include <sys/tihdr.h>
+#else /* FREEBSD */
+#include <poll.h>
+#endif /* FREEBSD */
 
 #endif /* linux */
 
@@ -62,6 +66,7 @@
 #include <sys/timod.h>
 #endif /* HAVE_SYS_TIUSER_H */
 
+#ifndef FREEBSD
 static struct xlat msgflags[] = {
 	{ RS_HIPRI,	"RS_HIPRI"	},
 	{ 0,		NULL		},
@@ -252,6 +257,7 @@
 }
 
 #endif /* HAVE_PUTPMSG */
+#endif /* !FREEBSD */
 
 
 #ifdef HAVE_SYS_POLL_H
@@ -349,7 +355,7 @@
 }
 #endif
 
-#ifndef linux
+#if !defined(linux) && !defined(FREEBSD)
 
 static struct xlat stream_flush_options[] = {
 	{ FLUSHR,	"FLUSHR"	},
@@ -824,7 +830,7 @@
 	}
 }
 
-#endif /* linux */
+#endif /* !linux && !FREEBSD */ 
 
-#endif /* LINUXSPARC && linux */
+#endif /* HAVE_SYS_STREAM_H || linux || FREEBSD */
 
diff --git a/syscall.c b/syscall.c
index 9642446..e59b16f 100644
--- a/syscall.c
+++ b/syscall.c
@@ -410,7 +410,23 @@
 	}
 }
 
+#ifndef FREEBSD
 enum subcall_style { shift_style, deref_style, mask_style, door_style };
+#else /* FREEBSD */
+enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
+
+struct subcall {
+  int call;
+  int nsubcalls;
+  int subcalls[5];
+};
+
+const struct subcall subcalls_table[] = {
+  { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
+  { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
+  { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
+};
+#endif /* FREEBSD */
 
 #if !(defined(LINUX) && ( defined(ALPHA) || defined(IA64) || defined(MIPS) ))
 
@@ -464,6 +480,11 @@
 enum subcall_style style;
 {
 	int i, addr, mask, arg;
+
+#ifndef FREEBSD
+	if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
+		return;
+#endif	
 	switch (style) {
 	case shift_style:
 		if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
@@ -513,6 +534,18 @@
 		else
 			tcp->u_nargs--;
 		break;
+#ifdef FREEBSD
+	case table_style:
+		for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
+			if (subcalls_table[i].call == tcp->scno) break;
+		if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
+		    tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
+			tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
+			for (i = 0; i < tcp->u_nargs; i++)
+				tcp->u_arg[i] = tcp->u_arg[i + 1];
+		}
+		break;
+#endif /* FREEBSD */
 	}
 }
 #endif
@@ -602,13 +635,18 @@
 	static long pc;
 #endif 
 #endif /* LINUX */
+#ifdef FREEBSD
+	struct reg regs;
+#endif /* FREEBSD */	
 
 int
 get_scno(tcp)
 struct tcb *tcp;
 {
 	long scno = 0;
+#ifndef USE_PROCFS
 	int pid = tcp->pid;
+#endif /* !PROCFS */	
 
 #ifdef LINUX
 #if defined(S390)
@@ -774,13 +812,29 @@
 	if (upeek(pid, uoff(u_arg[7]), &scno) < 0)
 		return -1;
 #endif
-#ifdef SVR4
+#ifdef USE_PROCFS
 #ifdef HAVE_PR_SYSCALL
 	scno = tcp->status.pr_syscall;
 #else /* !HAVE_PR_SYSCALL */
+#ifndef FREEBSD
 	scno = tcp->status.PR_WHAT;
+#else /* FREEBSD */
+	if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
+	        perror("pread");
+                return -1;
+        }
+	switch (regs.r_eax) {
+	case SYS_syscall:
+	case SYS___syscall:
+    	        pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
+	        break;
+	default:
+	        scno = regs.r_eax;
+	        break;
+	}
+#endif /* FREEBSD */
 #endif /* !HAVE_PR_SYSCALL */
-#endif
+#endif /* USE_PROCFS */
 	if (!(tcp->flags & TCB_INSYSCALL))
 		tcp->scno = scno;
 	return 1;
@@ -791,9 +845,11 @@
 syscall_fixup(tcp)
 struct tcb *tcp;
 {
+#ifndef USE_PROCFS
 	int pid = tcp->pid;
+#else /* USE_PROCFS */	
+	int scno = tcp->scno;
 
-#ifdef SVR4
 	if (!(tcp->flags & TCB_INSYSCALL)) {
 		if (tcp->status.PR_WHY != PR_SYSENTRY) {
 			if (
@@ -819,7 +875,7 @@
 			tcp->flags &= ~TCB_INSYSCALL;
 		}
 	}
-#endif /* SVR4 */
+#endif /* USE_PROCFS */
 #ifdef SUNOS4
 	if (!(tcp->flags & TCB_INSYSCALL)) {
 		if (scno == 0) {
@@ -1054,6 +1110,17 @@
 		}
 #endif /* MIPS */
 #endif /* SVR4 */
+#ifdef FREEBSD
+		if (regs.r_eflags & PSL_C) {
+ 		        tcp->u_rval = -1;
+		        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;
+		}
+#endif /* FREEBSD */	
 	tcp->u_error = u_error;
 	return 1;
 }
@@ -1061,12 +1128,17 @@
 int syscall_enter(tcp)
 struct tcb *tcp;
 {
+#ifndef USE_PROCFS
 	int pid = tcp->pid;
+#endif /* !USE_PROCFS */	
 #ifdef LINUX
 #if defined(S390)
 	{
 		int i;
-		tcp->u_nargs = sysent[tcp->scno].nargs;
+		if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
+			tcp->u_nargs = sysent[tcp->scno].nargs;
+		else 
+     	        	tcp->u_nargs = MAX_ARGS;
 		for (i = 0; i < tcp->u_nargs; i++) {
 			if (upeek(pid,i==0 ? PT_ORIGGPR2:PT_GPR2+(i<<2), &tcp->u_arg[i]) < 0)
 				return -1;
@@ -1075,7 +1147,10 @@
 #elif defined (ALPHA)
 	{
 		int i;
-		tcp->u_nargs = sysent[tcp->scno].nargs;
+		if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
+			tcp->u_nargs = sysent[tcp->scno].nargs;
+		else 
+     	        	tcp->u_nargs = MAX_ARGS;
 		for (i = 0; i < tcp->u_nargs; i++) {
 			/* WTA: if scno is out-of-bounds this will bomb. Add range-check
 			 * for scno somewhere above here!
@@ -1095,7 +1170,10 @@
 
 		bsp = ia64_rse_skip_regs(bsp, -(cfm & 0x7f));
 
-		tcp->u_nargs = sysent[tcp->scno].nargs;
+		if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
+			tcp->u_nargs = sysent[tcp->scno].nargs;
+		else 
+     	        	tcp->u_nargs = MAX_ARGS;
 		for (i = 0; i < tcp->u_nargs; ++i) {
 			if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(bsp, i), sizeof(long),
 				   (char *) &tcp->u_arg[i])
@@ -1108,7 +1186,10 @@
 	  	long sp;
 	  	int i, nargs;
 
-		nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
+		if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
+			nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
+		else 
+     	        	nargs = tcp->u_nargs = MAX_ARGS;
 		if(nargs > 4) {
 		  	if(upeek(pid, REG_SP, &sp) < 0)
 			  	return -1;
@@ -1128,7 +1209,10 @@
 #elif defined (POWERPC)
 	{
 		int i;
-		tcp->u_nargs = sysent[tcp->scno].nargs;
+		if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
+			tcp->u_nargs = sysent[tcp->scno].nargs;
+		else 
+     	        	tcp->u_nargs = MAX_ARGS;
 		for (i = 0; i < tcp->u_nargs; i++) {
 			if (upeek(pid, (i==0) ? (4*PT_ORIG_R3) : ((i+PT_R3)*4), &tcp->u_arg[i]) < 0)
 				return -1;
@@ -1137,15 +1221,21 @@
 #elif defined (SPARC)
 	{
 		int i;
-	         
-		tcp->u_nargs = sysent[tcp->scno].nargs;
+
+		if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
+			tcp->u_nargs = sysent[tcp->scno].nargs;
+		else 
+     	        	tcp->u_nargs = MAX_ARGS;
 		for (i = 0; i < tcp->u_nargs; i++)
 			tcp->u_arg[i] = *((&regs.r_o0) + i);
 	}
 #else /* Other architecture (like i386) (32bits specific) */
 	{
 		int i;
-		tcp->u_nargs = sysent[tcp->scno].nargs;
+		if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
+			tcp->u_nargs = sysent[tcp->scno].nargs;
+		else 
+     	        	tcp->u_nargs = MAX_ARGS;
 		for (i = 0; i < tcp->u_nargs; i++) {
 			if (upeek(pid, i*4, &tcp->u_arg[i]) < 0)
 				return -1;
@@ -1156,7 +1246,10 @@
 #ifdef SUNOS4
 	{
 		int i;
-		tcp->u_nargs = sysent[tcp->scno].nargs;
+		if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
+			tcp->u_nargs = sysent[tcp->scno].nargs;
+		else 
+     	        	tcp->u_nargs = MAX_ARGS;
 		for (i = 0; i < tcp->u_nargs; i++) {
 			struct user *u;
 
@@ -1172,7 +1265,7 @@
 	 * SGI is broken: even though it has pr_sysarg, it doesn't
 	 * set them on system call entry.  Get a clue.
 	 */
-	if (sysent[tcp->scno].nargs != -1)
+	if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
 		tcp->u_nargs = sysent[tcp->scno].nargs;
 	else
 		tcp->u_nargs = tcp->status.pr_nsysarg;
@@ -1188,7 +1281,7 @@
 	}
 #else /* !MIPS */
 #ifdef HAVE_PR_SYSCALL
-	if (sysent[tcp->scno].nargs != -1)
+	if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
 		tcp->u_nargs = sysent[tcp->scno].nargs;
 	else
 		tcp->u_nargs = tcp->status.pr_nsysarg;
@@ -1199,7 +1292,7 @@
 	}
 #else /* !HAVE_PR_SYSCALL */
 #ifdef I386
-	if (sysent[tcp->scno].nargs != -1)
+	if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
 		tcp->u_nargs = sysent[tcp->scno].nargs;
 	else
 #if UNIXWARE >= 2
@@ -1213,6 +1306,31 @@
 #endif /* !HAVE_PR_SYSCALL */
 #endif /* !MIPS */
 #endif /* SVR4 */
+#ifdef FREEBSD
+	if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
+	    sysent[tcp->scno].nargs > tcp->status.val)
+		tcp->u_nargs = sysent[tcp->scno].nargs;
+	else 
+	  	tcp->u_nargs = tcp->status.val;
+	if (tcp->u_nargs < 0)
+		tcp->u_nargs = 0;
+	if (tcp->u_nargs > MAX_ARGS)
+		tcp->u_nargs = MAX_ARGS;
+	switch(regs.r_eax) {
+	case SYS___syscall:
+		pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
+		      regs.r_esp + sizeof(int) + sizeof(quad_t));
+	  break;
+        case SYS_syscall:
+		pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
+		      regs.r_esp + 2 * sizeof(int));
+	  break;
+        default:
+		pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
+		      regs.r_esp + sizeof(int));
+	  break;
+	}
+#endif /* FREEBSD */
 	return 1;
 }
 
@@ -1245,7 +1363,8 @@
 
 
 		internal_syscall(tcp);
-		if (!(qual_flags[tcp->scno] & QUAL_TRACE)) {
+		if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
+		    !(qual_flags[tcp->scno] & QUAL_TRACE)) {
 			tcp->flags &= ~TCB_INSYSCALL;
 			return 0;
 		}
@@ -1253,14 +1372,14 @@
 		if (tcp->flags & TCB_REPRINT) {
 			printleader(tcp);
 			tprintf("<... ");
-			if (tcp->scno >= nsyscalls)
+			if (tcp->scno >= nsyscalls || tcp->scno < 0)
 				tprintf("syscall_%lu", tcp->scno);
 			else
 				tprintf("%s", sysent[tcp->scno].sys_name);
 			tprintf(" resumed> ");
 		}
 
-		if (cflag) {
+		if (cflag && tcp->scno < nsyscalls && tcp->scno >= 0) {
 			call_count[tcp->scno]++;
 			if (tcp->u_error)
 				error_count[tcp->scno]++;
@@ -1288,7 +1407,7 @@
 			return 0;
 		}
 
-		if (tcp->scno >= nsyscalls
+		if (tcp->scno >= nsyscalls || tcp->scno < 0
 		    || (qual_flags[tcp->scno] & QUAL_RAW))
 			sys_res = printargs(tcp);
 		else
@@ -1296,7 +1415,8 @@
 		u_error = tcp->u_error;
 		tprintf(") ");
 		tabto(acolumn);
-		if (qual_flags[tcp->scno] & QUAL_RAW) {
+		if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
+		    qual_flags[tcp->scno] & QUAL_RAW) {
 			if (u_error)
 				tprintf("= -1 (errno %ld)", u_error);
 			else
@@ -1349,10 +1469,18 @@
 					tprintf("= %ld", tcp->u_rval);
 					break;
 #ifdef HAVE_LONG_LONG
-				case RVAL_LDECIMAL:
-					tprintf ("= %lld", tcp->u_lrval);
+				case RVAL_LHEX:
+					tprintf("= %#llx", tcp->u_lrval);
 					break;
-					/* LHEX, LOCTAL, LUDECIMAL... */
+				case RVAL_LOCTAL:
+					tprintf("= %#llo", tcp->u_lrval);
+					break;
+				case RVAL_LUDECIMAL:
+					tprintf("= %llu", tcp->u_lrval);
+					break;
+				case RVAL_LDECIMAL:
+					tprintf("= %lld", tcp->u_lrval);
+					break;
 #endif
 				default:
 					fprintf(stderr,
@@ -1452,6 +1580,13 @@
 		break;
 #endif /* SYS_door_subcall */
 #endif /* SVR4 */
+#ifdef FREEBSD
+	case SYS_msgsys:
+	case SYS_shmsys:
+	case SYS_semsys:
+		decode_subcall(tcp, 0, 0, table_style);
+		break;
+#endif		
 #ifdef SUNOS4
 	case SYS_semsys:
 		decode_subcall(tcp, SYS_semsys_subcall,
@@ -1469,7 +1604,7 @@
 	}
 
 	internal_syscall(tcp);
-	if (!(qual_flags[tcp->scno] & QUAL_TRACE)) {
+	if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
 		tcp->flags |= TCB_INSYSCALL;
 		return 0;
 	}
@@ -1483,11 +1618,11 @@
 	printleader(tcp);
 	tcp->flags &= ~TCB_REPRINT;
 	tcp_last = tcp;
-	if (tcp->scno >= nsyscalls)
+	if (tcp->scno >= nsyscalls || tcp->scno < 0)
 		tprintf("syscall_%lu(", tcp->scno);
 	else
 		tprintf("%s(", sysent[tcp->scno].sys_name);
-	if (tcp->scno >= nsyscalls ||
+	if (tcp->scno >= nsyscalls || tcp->scno < 0 || 
 	    ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
 		sys_res = printargs(tcp);
 	else
@@ -1545,7 +1680,11 @@
 	val = tcp->status.PR_REG[CTX_V1];
 #endif /* MIPS */
 #endif /* SVR4 */
-
+#ifdef FREEBSD
+	struct reg regs;
+	pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
+	val = regs.r_edx;
+#endif	
 	return val;
 }
 
diff --git a/system.c b/system.c
index f16b711..39930b5 100644
--- a/system.c
+++ b/system.c
@@ -543,6 +543,19 @@
 	{ 0,		NULL		},
 };
 
+int
+sys_sysconf(tcp)
+struct tcb *tcp;
+{
+	if (entering(tcp)) {
+		printxval(sysconflimits, tcp->u_arg[0], "_SC_???");
+	}
+	return 0;
+}
+
+#endif /* SUNOS4 */
+
+#if defined(SUNOS4) || defined(FREEBSD)
 static struct xlat pathconflimits[] = {
 #ifdef	_PC_LINK_MAX
 	{ _PC_LINK_MAX,	"_PC_LINK_MAX"	},	/* max links to file/dir */
@@ -574,15 +587,6 @@
 	{ 0,		NULL		},
 };
 
-int
-sys_sysconf(tcp)
-struct tcb *tcp;
-{
-	if (entering(tcp)) {
-		printxval(sysconflimits, tcp->u_arg[0], "_SC_???");
-	}
-	return 0;
-}
 
 int
 sys_pathconf(tcp)
@@ -591,7 +595,7 @@
 	if (entering(tcp)) {
 		printstr(tcp, tcp->u_arg[0], -1);
 		tprintf(", ");
-		printxval(pathconflimits, tcp->u_arg[1], "_SC_???");
+		printxval(pathconflimits, tcp->u_arg[1], "_PC_???");
 	}
 	return 0;
 }
@@ -602,12 +606,12 @@
 {
 	if (entering(tcp)) {
 		tprintf("%lu, ", tcp->u_arg[0]);
-		printxval(pathconflimits, tcp->u_arg[1], "_SC_???");
+		printxval(pathconflimits, tcp->u_arg[1], "_PC_???");
 	}
 	return 0;
 }
 
-#endif /* SUNOS4 */
+#endif /* SUNOS4 || FREEBSD */
 
 #ifdef SVR4
 
@@ -1903,6 +1907,55 @@
 }
 #endif
 
+#ifdef FREEBSD
+#include <sys/sysctl.h>
+
+int sys___sysctl(tcp)
+struct tcb *tcp;
+{
+	int qoid[CTL_MAXNAME+2];
+	char ctl[1024];
+	size_t len;
+	int i, numeric;
+	
+	if (entering(tcp)) {
+		if (tcp->u_arg[1] < 0 || tcp->u_arg[1] > CTL_MAXNAME ||
+		    (umoven(tcp, tcp->u_arg[0], tcp->u_arg[1] * sizeof(int),
+			    (char *) (qoid + 2)) < 0))
+			tprintf("[...], ");
+		else {
+			/* Use sysctl to ask the name of the current MIB
+			   This uses the undocumented "Staff-functions" used
+			   by the sysctl program. See kern_sysctl.c for
+			   details. */
+			qoid[0] = 0; /* sysctl */
+			qoid[1] = 1; /* name */
+			i = sizeof(ctl);
+			tprintf("[");
+			if (sysctl(qoid, tcp->u_arg[1] + 2, ctl, &i, 0, 0) >= 0) {
+				numeric = !abbrev(tcp);
+				tprintf("%s%s", ctl, numeric ? ", " : "");
+			} else
+				numeric = 1;
+			if (numeric) {
+				for (i = 0; i < tcp->u_arg[1]; i++)
+					tprintf("%s%d", i ? "." : "", qoid[i + 2]);
+			}
+			tprintf("], ");
+			tprintf("%lu, ", tcp->u_arg[1]);
+		}
+	} else {
+		if (!syserror(tcp) && (umove(tcp, tcp->u_arg[3], &len) >= 0)) {
+			printstr(tcp, tcp->u_arg[2], len);
+			tprintf(", [%u], ", len);
+		} else 
+			tprintf("%#lx, %#lx, ", tcp->u_arg[2], tcp->u_arg[3]);
+		printstr(tcp, tcp->u_arg[4], tcp->u_arg[5]);
+		tprintf(", %lu", tcp->u_arg[5]);
+	}
+	return 0;
+}
+#endif
 
 #if UNIXWARE >= 2
 
diff --git a/term.c b/term.c
index 4cf10a9..db15ef9 100644
--- a/term.c
+++ b/term.c
@@ -47,12 +47,14 @@
 	{ 0,		NULL		},
 };
 
+#ifdef TCLFLSH
 static struct xlat tcflsh_options[] = {
 	{ TCIFLUSH,	"TCIFLUSH"	},
 	{ TCOFLUSH,	"TCOFLUSH"	},
 	{ TCIOFLUSH,	"TCIOFLUSH"	},
 	{ 0,		NULL		},
 };
+#endif
 
 static struct xlat baud_options[] = {
 	{ B0,		"B0"		},
@@ -173,7 +175,11 @@
 long code, arg;
 {
 	struct termios tios;
+#ifndef FREEBSD
 	struct termio tio;
+#else
+	struct termios tio;
+#endif	
 	struct winsize ws;
 #ifdef TIOCGSIZE
 	struct  ttysize ts;
@@ -290,15 +296,18 @@
 #endif
 
 	/* ioctls with a direct decodable arg */
-
+#ifdef TCXONC
 	case TCXONC:
 		tprintf(", ");
 		printxval(tcxonc_options, arg, "TC???");
 		return 1;
+#endif
+#ifdef TCLFLSH
 	case TCFLSH:
 		tprintf(", ");
 		printxval(tcflsh_options, arg, "TC???");
 		return 1;
+#endif
 
 	/* ioctls with an indirect parameter displayed as modem flags */
 
diff --git a/util.c b/util.c
index f0810b4..c0b7cc0 100644
--- a/util.c
+++ b/util.c
@@ -630,7 +630,7 @@
 #endif /* !oldway */
 #endif /* SUNOS4 */
 
-#ifdef SVR4
+#ifdef USE_PROCFS
 #ifdef HAVE_MP_PROCFS
 	if (pread(tcp->pfd_as, laddr, len, addr) == -1)
 		return -1;
@@ -651,7 +651,7 @@
 		return -1;
 #endif /* !HAVE_PREAD */
 #endif /* HAVE_MP_PROCFS */
-#endif /* SVR4 */
+#endif /* USE_PROCFS */
 
 	return 0;
 }
@@ -667,9 +667,9 @@
 int len;
 char *laddr;
 {
-#ifdef SVR4
+#ifdef USE_PROCFS
 	return umoven(tcp, addr, len, laddr);
-#else /* !SVR4 */
+#else /* !USE_PROCFS */
 	int started = 0;
 	int pid = tcp->pid;
 	int i, n, m;
@@ -719,7 +719,7 @@
 		addr += sizeof(long), laddr += m, len -= m;
 	}
 	return 0;
-#endif /* !SVR4 */
+#endif /* !USE_PROCFS */
 }
 
 #ifdef LINUX
@@ -821,7 +821,7 @@
 
 #endif /* SUNOS4 */
 
-#ifndef SVR4
+#ifndef USE_PROCFS
 
 int
 upeek(pid, off, res)
@@ -865,7 +865,7 @@
 	return 0;
 }
 
-#endif /* !SVR4 */
+#endif /* !USE_PROCFS */
 
 long
 getpc(tcp)
@@ -925,6 +925,11 @@
 	return 0;
 #endif /* SVR4 */
 
+#ifdef FREEBSD
+	struct reg regs;
+	pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
+	return regs.r_eip;
+#endif /* FREEBSD */
 }
 
 void
@@ -999,9 +1004,14 @@
 	tprintf("[????????] ");
 #endif
 
+#ifdef FREEBSD
+	struct reg regs;
+	pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
+	tprintf("[%08x] ", regs.r_eip);
+#endif /* FREEBSD */
 }
 
-#ifndef SVR4
+#ifndef USE_PROCFS
 
 int
 setbpt(tcp)
@@ -1388,7 +1398,7 @@
 	return 0;
 }
 
-#endif /* !SVR4 */
+#endif /* !USE_PROCFS */
 
 #ifdef SUNOS4