[Midnightbsd-cvs] src [11271] trunk/usr.bin/truss/truss.h: update truss

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Tue Jul 3 20:01:34 EDT 2018


Revision: 11271
          http://svnweb.midnightbsd.org/src/?rev=11271
Author:   laffer1
Date:     2018-07-03 20:01:33 -0400 (Tue, 03 Jul 2018)
Log Message:
-----------
update truss

Modified Paths:
--------------
    trunk/usr.bin/truss/Makefile
    trunk/usr.bin/truss/amd64-fbsd.c
    trunk/usr.bin/truss/amd64-fbsd32.c
    trunk/usr.bin/truss/amd64-linux32.c
    trunk/usr.bin/truss/extern.h
    trunk/usr.bin/truss/i386-fbsd.c
    trunk/usr.bin/truss/i386-linux.c
    trunk/usr.bin/truss/ia64-fbsd.c
    trunk/usr.bin/truss/main.c
    trunk/usr.bin/truss/mips-fbsd.c
    trunk/usr.bin/truss/powerpc-fbsd.c
    trunk/usr.bin/truss/powerpc64-fbsd.c
    trunk/usr.bin/truss/setup.c
    trunk/usr.bin/truss/sparc64-fbsd.c
    trunk/usr.bin/truss/syscall.h
    trunk/usr.bin/truss/syscalls.c
    trunk/usr.bin/truss/truss.1
    trunk/usr.bin/truss/truss.h

Property Changed:
----------------
    trunk/usr.bin/truss/amd64linux32.conf
    trunk/usr.bin/truss/fbsd32.conf
    trunk/usr.bin/truss/i386.conf
    trunk/usr.bin/truss/i386linux.conf
    trunk/usr.bin/truss/truss.1

Modified: trunk/usr.bin/truss/Makefile
===================================================================
--- trunk/usr.bin/truss/Makefile	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/Makefile	2018-07-04 00:01:33 UTC (rev 11271)
@@ -1,4 +1,5 @@
-# $MidnightBSD: src/usr.bin/truss/Makefile,v 1.3 2012/11/23 01:13:54 laffer1 Exp $
+# $MidnightBSD$
+# $FreeBSD: stable/10/usr.bin/truss/Makefile 234060 2012-04-09 15:34:22Z dim $
 
 NO_WERROR=
 PROG=	truss
@@ -23,8 +24,8 @@
 		${.CURDIR}/i386.conf
 
 ioctl.c: ${.CURDIR}/../kdump/mkioctls
-	env CPP="${CPP}" \
-	    sh ${.CURDIR}/../kdump/mkioctls ${DESTDIR}/usr/include > ${.TARGET}
+	env MACHINE=${MACHINE} CPP="${CPP}" \
+		/bin/sh ${.CURDIR}/../kdump/mkioctls return ${DESTDIR}/usr/include > ${.TARGET}
 
 .if ${MACHINE_CPUARCH} == "i386"
 SRCS+=	i386-linux.c linux_syscalls.h
@@ -60,4 +61,16 @@
 		${.CURDIR}/fbsd32.conf
 .endif
 
+.if ${MACHINE_ARCH} == "powerpc64"
+SRCS+=	powerpc-fbsd.c freebsd32_syscalls.h
+CLEANFILES+=fbsd32-syscalls.master freebsd32_syscalls.h
+
+fbsd32-syscalls.master: ${.CURDIR}/../../sys/compat/freebsd32/syscalls.master
+	cat ${.ALLSRC} > ${.TARGET}
+
+freebsd32_syscalls.h:	fbsd32-syscalls.master
+	/bin/sh ${.CURDIR}/../../sys/kern/makesyscalls.sh ${.ALLSRC} \
+		${.CURDIR}/fbsd32.conf
+.endif
+
 .include <bsd.prog.mk>

Modified: trunk/usr.bin/truss/amd64-fbsd.c
===================================================================
--- trunk/usr.bin/truss/amd64-fbsd.c	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/amd64-fbsd.c	2018-07-04 00:01:33 UTC (rev 11271)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * Copyright 1997 Sean Eric Fagan
  *
@@ -29,20 +30,11 @@
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-static const char rcsid[] =
-  "$MidnightBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.bin/truss/amd64-fbsd.c 290052 2015-10-27 17:00:04Z jhb $");
 
-/*
- * FreeBSD/amd64-specific system call handling.  This is probably the most
- * complex part of the entire truss program, although I've got lots of
- * it handled relatively cleanly now.  The system call names are generated
- * automatically, thanks to /usr/src/sys/kern/syscalls.master.  The
- * names used for the various structures are confusing, I sadly admit.
- */
+/* FreeBSD/amd64-specific system call handling. */
 
-#include <sys/types.h>
 #include <sys/ptrace.h>
 #include <sys/syscall.h>
 
@@ -49,290 +41,92 @@
 #include <machine/reg.h>
 #include <machine/psl.h>
 
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
 
 #include "truss.h"
-#include "syscall.h"
-#include "extern.h"
 
 #include "syscalls.h"
 
-static int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct freebsd_syscall {
-	struct syscall *sc;
-	const char *name;
-	int number;
-	unsigned long *args;
-	int nargs;	/* number of arguments -- *not* number of words! */
-	char **s_args;	/* the printable arguments */
-};
-
-static struct freebsd_syscall *
-alloc_fsc(void)
+static int
+amd64_fetch_args(struct trussinfo *trussinfo, u_int narg)
 {
-
-	return (malloc(sizeof(struct freebsd_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct freebsd_syscall *fsc)
-{
-	int i;
-
-	free(fsc->args);
-	if (fsc->s_args) {
-		for (i = 0; i < fsc->nargs; i++)
-			free(fsc->s_args[i]);
-		free(fsc->s_args);
-	}
-	free(fsc);
-}
-
-/*
- * Called when a process has entered a system call.  nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases).  Note that if the STOPEVENT() code in amd64/amd64/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-amd64_syscall_entry(struct trussinfo *trussinfo, int nargs)
-{
 	struct ptrace_io_desc iorequest;
 	struct reg regs;
-	struct freebsd_syscall *fsc;
-	struct syscall *sc;
+	struct current_syscall *cs;
 	lwpid_t tid;
-	int i, reg, syscall_num;
+	u_int i, reg;
 
 	tid = trussinfo->curthread->tid;
-
+	cs = &trussinfo->curthread->cs;
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
 		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
-		return;
+		return (-1);
 	}
 
 	/*
-	 * FreeBSD has two special kinds of system call redirctions --
+	 * FreeBSD has two special kinds of system call redirections --
 	 * SYS_syscall, and SYS___syscall.  The former is the old syscall()
 	 * routine, basically; the latter is for quad-aligned arguments.
+	 *
+	 * The system call argument count and code from ptrace() already
+	 * account for these, but we need to skip over %rax if it contains
+	 * either of these values.
 	 */
 	reg = 0;
-	syscall_num = regs.r_rax;
-	switch (syscall_num) {
+	switch (regs.r_rax) {
 	case SYS_syscall:
 	case SYS___syscall:
-		syscall_num = regs.r_rdi;
 		reg++;
 		break;
 	}
 
-	fsc = alloc_fsc();
-	if (fsc == NULL)
-		return;
-	fsc->number = syscall_num;
-	fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
-	    NULL : syscallnames[syscall_num];
-	if (!fsc->name) {
-		fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
-		    syscall_num);
-	}
-
-	if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
-	    (strcmp(fsc->name, "fork") == 0 ||
-	    strcmp(fsc->name, "rfork") == 0 ||
-	    strcmp(fsc->name, "vfork") == 0))
-		trussinfo->curthread->in_fork = 1;
-
-	if (nargs == 0)
-		return;
-
-	fsc->args = malloc((1 + nargs) * sizeof(unsigned long));
-	for (i = 0; i < nargs && reg < 6; i++, reg++) {
+	for (i = 0; i < narg && reg < 6; i++, reg++) {
 		switch (reg) {
-		case 0: fsc->args[i] = regs.r_rdi; break;
-		case 1: fsc->args[i] = regs.r_rsi; break;
-		case 2: fsc->args[i] = regs.r_rdx; break;
-		case 3: fsc->args[i] = regs.r_rcx; break;
-		case 4: fsc->args[i] = regs.r_r8; break;
-		case 5: fsc->args[i] = regs.r_r9; break;
+		case 0: cs->args[i] = regs.r_rdi; break;
+		case 1: cs->args[i] = regs.r_rsi; break;
+		case 2: cs->args[i] = regs.r_rdx; break;
+		case 3: cs->args[i] = regs.r_rcx; break;
+		case 4: cs->args[i] = regs.r_r8; break;
+		case 5: cs->args[i] = regs.r_r9; break;
 		}
 	}
-	if (nargs > i) {
+	if (narg > i) {
 		iorequest.piod_op = PIOD_READ_D;
 		iorequest.piod_offs = (void *)(regs.r_rsp + sizeof(register_t));
-		iorequest.piod_addr = &fsc->args[i];
-		iorequest.piod_len = (nargs - i) * sizeof(register_t);
+		iorequest.piod_addr = &cs->args[i];
+		iorequest.piod_len = (narg - i) * sizeof(register_t);
 		ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
 		if (iorequest.piod_len == 0)
-			return;
+			return (-1);
 	}
 
-	sc = get_syscall(fsc->name);
-	if (sc)
-		fsc->nargs = sc->nargs;
-	else {
-#if DEBUG
-		fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
-		    "args to %d\n", fsc->name, nargs);
-#endif
-		fsc->nargs = nargs;
-	}
-
-	fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
-	fsc->sc = sc;
-
-	/*
-	 * At this point, we set up the system call arguments.
-	 * We ignore any OUT ones, however -- those are arguments that
-	 * are set by the system call, and so are probably meaningless
-	 * now.	This doesn't currently support arguments that are
-	 * passed in *and* out, however.
-	 */
-
-	if (fsc->name) {
-#if DEBUG
-		fprintf(stderr, "syscall %s(", fsc->name);
-#endif
-		for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
-			fprintf(stderr, "0x%lx%s", sc ?
-			    fsc->args[sc->args[i].offset] : fsc->args[i],
-			    i < (fsc->nargs - 1) ? "," : "");
-#endif
-			if (sc && !(sc->args[i].type & OUT)) {
-				fsc->s_args[i] = print_arg(&sc->args[i],
-				    fsc->args, 0, trussinfo);
-			}
-		}
-#if DEBUG
-		fprintf(stderr, ")\n");
-#endif
-	}
-
-#if DEBUG
-	fprintf(trussinfo->outfile, "\n");
-#endif
-
-	if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0)) {
-		/*
-		 * XXX
-		 * This could be done in a more general
-		 * manner but it still wouldn't be very pretty.
-		 */
-		if (strcmp(fsc->name, "execve") == 0) {
-			if ((trussinfo->flags & EXECVEARGS) == 0) {
-				if (fsc->s_args[1]) {
-					free(fsc->s_args[1]);
-					fsc->s_args[1] = NULL;
-				}
-			}
-			if ((trussinfo->flags & EXECVEENVS) == 0) {
-				if (fsc->s_args[2]) {
-					free(fsc->s_args[2]);
-					fsc->s_args[2] = NULL;
-				}
-			}
-		}
-	}
-	trussinfo->curthread->fsc = fsc;
+	return (0);
 }
 
-/*
- * And when the system call is done, we handle it here.
- * Currently, no attempt is made to ensure that the system calls
- * match -- this needs to be fixed (and is, in fact, why S_SCX includes
- * the system call number instead of, say, an error status).
- */
-
-long
-amd64_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
+static int
+amd64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp)
 {
 	struct reg regs;
-	struct freebsd_syscall *fsc;
-	struct syscall *sc;
 	lwpid_t tid;
-	long retval;
-	int errorp, i;
 
-	if (trussinfo->curthread->fsc == NULL)
-		return (-1);
-
 	tid = trussinfo->curthread->tid;
-
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
 		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
 		return (-1);
 	}
 
-	retval = regs.r_rax;
-	errorp = !!(regs.r_rflags & PSL_C);
+	retval[0] = regs.r_rax;
+	retval[1] = regs.r_rdx;
+	*errorp = !!(regs.r_rflags & PSL_C);
+	return (0);
+}
 
-	/*
-	 * This code, while simpler than the initial versions I used, could
-	 * stand some significant cleaning.
-	 */
+static struct procabi amd64_fbsd = {
+	"FreeBSD ELF64",
+	syscallnames,
+	nitems(syscallnames),
+	amd64_fetch_args,
+	amd64_fetch_retval
+};
 
-	fsc = trussinfo->curthread->fsc;
-	sc = fsc->sc;
-	if (!sc) {
-		for (i = 0; i < fsc->nargs; i++)
-			asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
-	} else {
-		/*
-		 * Here, we only look for arguments that have OUT masked in --
-		 * otherwise, they were handled in the syscall_entry function.
-		 */
-		for (i = 0; i < sc->nargs; i++) {
-			char *temp;
-			if (sc->args[i].type & OUT) {
-				/*
-				 * If an error occurred, then don't bother
-				 * getting the data; it may not be valid.
-				 */
-				if (errorp) {
-					asprintf(&temp, "0x%lx",
-					    fsc->args[sc->args[i].offset]);
-				} else {
-					temp = print_arg(&sc->args[i],
-					    fsc->args, retval, trussinfo);
-				}
-				fsc->s_args[i] = temp;
-			}
-		}
-	}
-
-	if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0))
-		trussinfo->curthread->in_syscall = 1;
-
-	/*
-	 * It would probably be a good idea to merge the error handling,
-	 * but that complicates things considerably.
-	 */
-
-	print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
-	    retval, fsc->sc);
-	free_fsc(fsc);
-
-	return (retval);
-}
+PROCABI(amd64_fbsd);

Modified: trunk/usr.bin/truss/amd64-fbsd32.c
===================================================================
--- trunk/usr.bin/truss/amd64-fbsd32.c	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/amd64-fbsd32.c	2018-07-04 00:01:33 UTC (rev 11271)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * Copyright 1997 Sean Eric Fagan
  *
@@ -29,20 +30,11 @@
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-static const char rcsid[] =
-  "$MidnightBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.bin/truss/amd64-fbsd32.c 290052 2015-10-27 17:00:04Z jhb $");
 
-/*
- * FreeBSD/i386-specific system call handling.  This is probably the most
- * complex part of the entire truss program, although I've got lots of
- * it handled relatively cleanly now.  The system call names are generated
- * automatically, thanks to /usr/src/sys/kern/syscalls.master.  The
- * names used for the various structures are confusing, I sadly admit.
- */
+/* FreeBSD/i386-specific system call handling. */
 
-#include <sys/types.h>
 #include <sys/ptrace.h>
 #include <sys/syscall.h>
 
@@ -49,291 +41,98 @@
 #include <machine/reg.h>
 #include <machine/psl.h>
 
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
 
 #include "truss.h"
-#include "syscall.h"
-#include "extern.h"
 
 #include "freebsd32_syscalls.h"
 
-static int nsyscalls = sizeof(freebsd32_syscallnames) /
-    sizeof(freebsd32_syscallnames[0]);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct freebsd32_syscall {
-	struct syscall *sc;
-	const char *name;
-	int number;
-	unsigned long *args;
-	unsigned int *args32;
-	int nargs;	/* number of arguments -- *not* number of words! */
-	char **s_args;	/* the printable arguments */
-};
-
-static struct freebsd32_syscall *
-alloc_fsc(void)
+static int
+amd64_fbsd32_fetch_args(struct trussinfo *trussinfo, u_int narg)
 {
-
-	return (malloc(sizeof(struct freebsd32_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct freebsd32_syscall *fsc)
-{
-	int i;
-
-	free(fsc->args);
-	free(fsc->args32);
-	if (fsc->s_args) {
-		for (i = 0; i < fsc->nargs; i++)
-			free(fsc->s_args[i]);
-		free(fsc->s_args);
-	}
-	free(fsc);
-}
-
-/*
- * Called when a process has entered a system call.  nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases).  Note that if the STOPEVENT() code in i386/i386/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-amd64_fbsd32_syscall_entry(struct trussinfo *trussinfo, int nargs)
-{
 	struct ptrace_io_desc iorequest;
 	struct reg regs;
-	struct freebsd32_syscall *fsc;
-	struct syscall *sc;
+	struct current_syscall *cs;
+	unsigned int args32[narg];
+	unsigned long parm_offset;
 	lwpid_t tid;
-	unsigned long parm_offset;
-	int i, syscall_num;
+	u_int i;
 
 	tid = trussinfo->curthread->tid;
-
+	cs = &trussinfo->curthread->cs;
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
 		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
-		return;
+		return (-1);
 	}
 	parm_offset = regs.r_rsp + sizeof(int);
 
 	/*
-	 * FreeBSD has two special kinds of system call redirctions --
+	 * FreeBSD has two special kinds of system call redirections --
 	 * SYS_syscall, and SYS___syscall.  The former is the old syscall()
 	 * routine, basically; the latter is for quad-aligned arguments.
+	 *
+	 * The system call argument count and code from ptrace() already
+	 * account for these, but we need to skip over the first argument.
 	 */
-	syscall_num = regs.r_rax;
-	switch (syscall_num) {
+	switch (regs.r_rax) {
 	case SYS_syscall:
-		syscall_num = ptrace(PT_READ_D, tid, (caddr_t)parm_offset, 0);
 		parm_offset += sizeof(int);
 		break;
 	case SYS___syscall:
-		syscall_num = ptrace(PT_READ_D, tid, (caddr_t)parm_offset, 0);
 		parm_offset += sizeof(quad_t);
 		break;
 	}
 
-	fsc = alloc_fsc();
-	if (fsc == NULL)
-		return;
-	fsc->number = syscall_num;
-	fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
-	    NULL : freebsd32_syscallnames[syscall_num];
-	if (!fsc->name) {
-		fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
-		    syscall_num);
-	}
-
-	if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
-	    (strcmp(fsc->name, "fork") == 0 ||
-	    strcmp(fsc->name, "rfork") == 0 ||
-	    strcmp(fsc->name, "vfork") == 0))
-		trussinfo->curthread->in_fork = 1;
-
-	if (nargs == 0)
-		return;
-
-	fsc->args32 = malloc((1 + nargs) * sizeof(unsigned int));
 	iorequest.piod_op = PIOD_READ_D;
 	iorequest.piod_offs = (void *)parm_offset;
-	iorequest.piod_addr = fsc->args32;
-	iorequest.piod_len = (1 + nargs) * sizeof(unsigned int);
+	iorequest.piod_addr = args32;
+	iorequest.piod_len = sizeof(args32);
 	ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
-	if (iorequest.piod_len == 0)
-		return;
-
-	fsc->args = malloc((1 + nargs) * sizeof(unsigned long));
-	for (i = 0; i < nargs + 1; i++)
-		 fsc->args[i] = fsc->args32[i];
-
-	sc = NULL;
-	if (fsc->name)
-		sc = get_syscall(fsc->name);
-	if (sc)
-		fsc->nargs = sc->nargs;
-	else {
-#if DEBUG
-		fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
-		    "args to %d\n", fsc->name, nargs);
-#endif
-		fsc->nargs = nargs;
+	if (iorequest.piod_len == 0) {
+		return (-1);
 	}
 
-	fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
-	fsc->sc = sc;
-
-	/*
-	 * At this point, we set up the system call arguments.
-	 * We ignore any OUT ones, however -- those are arguments that
-	 * are set by the system call, and so are probably meaningless
-	 * now.	This doesn't currently support arguments that are
-	 * passed in *and* out, however.
-	 */
-
-	if (fsc->name) {
-#if DEBUG
-		fprintf(stderr, "syscall %s(", fsc->name);
-#endif
-		for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
-			fprintf(stderr, "0x%x%s", sc ?
-			    fsc->args[sc->args[i].offset] : fsc->args[i],
-			    i < (fsc->nargs - 1) ? "," : "");
-#endif
-			if (sc && !(sc->args[i].type & OUT)) {
-				fsc->s_args[i] = print_arg(&sc->args[i],
-				    fsc->args, 0, trussinfo);
-			}
-		}
-#if DEBUG
-		fprintf(stderr, ")\n");
-#endif
-	}
-
-#if DEBUG
-	fprintf(trussinfo->outfile, "\n");
-#endif
-
-	if (fsc->name != NULL && (strcmp(fsc->name, "freebsd32_execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0)) {
-		/*
-		 * XXX
-		 * This could be done in a more general
-		 * manner but it still wouldn't be very pretty.
-		 */
-		if (strcmp(fsc->name, "freebsd32_execve") == 0) {
-			if ((trussinfo->flags & EXECVEARGS) == 0) {
-				if (fsc->s_args[1]) {
-					free(fsc->s_args[1]);
-					fsc->s_args[1] = NULL;
-				}
-			}
-			if ((trussinfo->flags & EXECVEENVS) == 0) {
-				if (fsc->s_args[2]) {
-					free(fsc->s_args[2]);
-					fsc->s_args[2] = NULL;
-				}
-			}
-		}
-	}
-	trussinfo->curthread->fsc = fsc;
+	for (i = 0; i < narg; i++)
+		 cs->args[i] = args32[i];
+	return (0);
 }
 
-/*
- * And when the system call is done, we handle it here.
- * Currently, no attempt is made to ensure that the system calls
- * match -- this needs to be fixed (and is, in fact, why S_SCX includes
- * the system call number instead of, say, an error status).
- */
-
-long
-amd64_fbsd32_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
+static int
+amd64_fbsd32_fetch_retval(struct trussinfo *trussinfo, long *retval,
+    int *errorp)
 {
 	struct reg regs;
-	struct freebsd32_syscall *fsc;
-	struct syscall *sc;
 	lwpid_t tid;
-	long retval;
-	int errorp, i;
 
-	if (trussinfo->curthread->fsc == NULL)
-		return (-1);
-
 	tid = trussinfo->curthread->tid;
-
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
 		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
 		return (-1);
 	}
 
-	retval = regs.r_rax;
-	errorp = !!(regs.r_rflags & PSL_C);
+	retval[0] = regs.r_rax & 0xffffffff;
+	retval[1] = regs.r_rdx & 0xffffffff;
+	*errorp = !!(regs.r_rflags & PSL_C);
+	return (0);
+}
 
-	/*
-	 * This code, while simpler than the initial versions I used, could
-	 * stand some significant cleaning.
-	 */
+static struct procabi amd64_fbsd32 = {
+	"FreeBSD ELF32",
+	freebsd32_syscallnames,
+	nitems(freebsd32_syscallnames),
+	amd64_fbsd32_fetch_args,
+	amd64_fbsd32_fetch_retval
+};
 
-	fsc = trussinfo->curthread->fsc;
-	sc = fsc->sc;
-	if (!sc) {
-		for (i = 0; i < fsc->nargs; i++)
-			asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
-	} else {
-		/*
-		 * Here, we only look for arguments that have OUT masked in --
-		 * otherwise, they were handled in the syscall_entry function.
-		 */
-		for (i = 0; i < sc->nargs; i++) {
-			char *temp;
-			if (sc->args[i].type & OUT) {
-				/*
-				 * If an error occurred, then don't bother
-				 * getting the data; it may not be valid.
-				 */
-				if (errorp) {
-					asprintf(&temp, "0x%lx",
-					    fsc->args[sc->args[i].offset]);
-				} else {
-					temp = print_arg(&sc->args[i],
-					    fsc->args, retval, trussinfo);
-				}
-				fsc->s_args[i] = temp;
-			}
-		}
-	}
+PROCABI(amd64_fbsd32);
 
-	if (fsc->name != NULL && (strcmp(fsc->name, "freebsd32_execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0))
-		trussinfo->curthread->in_syscall = 1;
+static struct procabi amd64_fbsd32_aout = {
+	"FreeBSD a.out",
+	freebsd32_syscallnames,
+	nitems(freebsd32_syscallnames),
+	amd64_fbsd32_fetch_args,
+	amd64_fbsd32_fetch_retval
+};
 
-	/*
-	 * It would probably be a good idea to merge the error handling,
-	 * but that complicates things considerably.
-	 */
-
-	print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
-	    retval, fsc->sc);
-	free_fsc(fsc);
-
-	return (retval);
-}
+PROCABI(amd64_fbsd32_aout);

Modified: trunk/usr.bin/truss/amd64-linux32.c
===================================================================
--- trunk/usr.bin/truss/amd64-linux32.c	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/amd64-linux32.c	2018-07-04 00:01:33 UTC (rev 11271)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * Copyright 1997 Sean Eric Fagan
  *
@@ -29,124 +30,36 @@
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-static const char rcsid[] =
-  "$MidnightBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.bin/truss/amd64-linux32.c 296010 2016-02-24 22:01:45Z jhb $");
 
-/*
- * Linux/i386-specific system call handling.  Given how much of this code
- * is taken from the freebsd equivalent, I can probably put even more of
- * it in support routines that can be used by any personality support.
- */
+/* Linux/i386-specific system call handling. */
 
-#include <sys/types.h>
 #include <sys/ptrace.h>
 
 #include <machine/reg.h>
 #include <machine/psl.h>
 
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
 
 #include "truss.h"
-#include "syscall.h"
-#include "extern.h"
 
 #include "linux32_syscalls.h"
 
-static int nsyscalls =
-	sizeof(linux32_syscallnames) / sizeof(linux32_syscallnames[0]);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct linux_syscall {
-	struct syscall *sc;
-	const char *name;
-	int number;
-	unsigned long args[5];
-	int nargs;	/* number of arguments -- *not* number of words! */
-	char **s_args;	/* the printable arguments */
-};
-
-static struct linux_syscall *
-alloc_fsc(void)
+static int
+amd64_linux32_fetch_args(struct trussinfo *trussinfo, u_int narg)
 {
-
-	return (malloc(sizeof(struct linux_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct linux_syscall *fsc)
-{
-	int i;
-
-	if (fsc->s_args) {
-		for (i = 0; i < fsc->nargs; i++)
-			free(fsc->s_args[i]);
-		free(fsc->s_args);
-	}
-	free(fsc);
-}
-
-/*
- * Called when a process has entered a system call.  nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases).  Note that if the STOPEVENT() code in i386/i386/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-amd64_linux32_syscall_entry(struct trussinfo *trussinfo, int nargs)
-{
 	struct reg regs;
-	struct linux_syscall *fsc;
-	struct syscall *sc;
+	struct current_syscall *cs;
 	lwpid_t tid;
-	int i, syscall_num;
 
 	tid = trussinfo->curthread->tid;
-
+	cs = &trussinfo->curthread->cs;
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
 		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
-		return;
+		return (-1);
 	}
 
-	syscall_num = regs.r_rax;
-
-	fsc = alloc_fsc();
-	if (fsc == NULL)
-		return;
-	fsc->number = syscall_num;
-	fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
-	    NULL : linux32_syscallnames[syscall_num];
-	if (!fsc->name) {
-		fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
-		    syscall_num);
-	}
-
-	if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
-	    (strcmp(fsc->name, "linux_fork") == 0 ||
-	    strcmp(fsc->name, "linux_vfork") == 0))
-		trussinfo->curthread->in_fork = 1;
-
-	if (nargs == 0)
-		return;
-
 	/*
 	 * Linux passes syscall arguments in registers, not
 	 * on the stack.  Fortunately, we've got access to the
@@ -154,88 +67,28 @@
 	 * number of arguments.	And what does linux do for syscalls
 	 * that have more than five arguments?
 	 */
-
-	fsc->args[0] = regs.r_rbx;
-	fsc->args[1] = regs.r_rcx;
-	fsc->args[2] = regs.r_rdx;
-	fsc->args[3] = regs.r_rsi;
-	fsc->args[4] = regs.r_rdi;
-
-	sc = get_syscall(fsc->name);
-	if (sc)
-		fsc->nargs = sc->nargs;
-	else {
-#if DEBUG
-		fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
-		    "args to %d\n", fsc->name, nargs);
-#endif
-		fsc->nargs = nargs;
+	switch (narg) {
+	default:
+		cs->args[5] = regs.r_rbp;	/* Unconfirmed */
+	case 5:
+		cs->args[4] = regs.r_rdi;
+	case 4:
+		cs->args[3] = regs.r_rsi;
+	case 3:
+		cs->args[2] = regs.r_rdx;
+	case 2:
+		cs->args[1] = regs.r_rcx;
+	case 1:
+		cs->args[0] = regs.r_rbx;
 	}
 
-	fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
-	fsc->sc = sc;
-
-	/*
-	 * At this point, we set up the system call arguments.
-	 * We ignore any OUT ones, however -- those are arguments that
-	 * are set by the system call, and so are probably meaningless
-	 * now.	This doesn't currently support arguments that are
-	 * passed in *and* out, however.
-	 */
-
-	if (fsc->name) {
-#if DEBUG
-		fprintf(stderr, "syscall %s(", fsc->name);
-#endif
-		for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
-			fprintf(stderr, "0x%x%s", sc ?
-			    fsc->args[sc->args[i].offset] : fsc->args[i],
-			    i < (fsc->nargs - 1) ? "," : "");
-#endif
-			if (sc && !(sc->args[i].type & OUT)) {
-				fsc->s_args[i] = print_arg(&sc->args[i],
-				    fsc->args, 0, trussinfo);
-			}
-		}
-#if DEBUG
-		fprintf(stderr, ")\n");
-#endif
-	}
-
-#if DEBUG
-	fprintf(trussinfo->outfile, "\n");
-#endif
-
-	if (fsc->name != NULL && (strcmp(fsc->name, "linux_execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0)) {
-		/*
-		 * XXX
-		 * This could be done in a more general
-		 * manner but it still wouldn't be very pretty.
-		 */
-		if (strcmp(fsc->name, "linux_execve") == 0) {
-			if ((trussinfo->flags & EXECVEARGS) == 0) {
-				if (fsc->s_args[1]) {
-					free(fsc->s_args[1]);
-					fsc->s_args[1] = NULL;
-				}
-			}
-			if ((trussinfo->flags & EXECVEENVS) == 0) {
-				if (fsc->s_args[2]) {
-					free(fsc->s_args[2]);
-					fsc->s_args[2] = NULL;
-				}
-			}
-		}
-	}
-	trussinfo->curthread->fsc = fsc;
+	return (0);
 }
 
 /*
  * Linux syscalls return negative errno's, we do positive and map them
  */
-const int bsd_to_linux_errno[] = {
+static const int bsd_to_linux_errno[] = {
 	-0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9,
 	-10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
 	-20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
@@ -247,83 +100,45 @@
 	-6,
 };
 
-long
-amd64_linux32_syscall_exit(struct trussinfo *trussinfo,
-    int syscall_num __unused)
+static int
+amd64_linux32_fetch_retval(struct trussinfo *trussinfo, long *retval,
+    int *errorp)
 {
 	struct reg regs;
-	struct linux_syscall *fsc;
-	struct syscall *sc;
 	lwpid_t tid;
-	long retval;
-	int errorp, i;
+	size_t i;
 
-	if (trussinfo->curthread->fsc == NULL)
-		return (-1);
-
 	tid = trussinfo->curthread->tid;
-
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
 		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
 		return (-1);
 	}
 
-	retval = regs.r_rax;
-	errorp = !!(regs.r_rflags & PSL_C);
+	retval[0] = regs.r_rax & 0xffffffff;
+	retval[1] = regs.r_rdx & 0xffffffff;
+	*errorp = !!(regs.r_rflags & PSL_C);
+	if (*errorp)
+		retval[0] = (int)retval[0];
 
-	/*
-	 * This code, while simpler than the initial versions I used, could
-	 * stand some significant cleaning.
-	 */
-
-	fsc = trussinfo->curthread->fsc;
-	sc = fsc->sc;
-	if (!sc) {
-		for (i = 0; i < fsc->nargs; i++)
-			asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
-	} else {
-		/*
-		 * Here, we only look for arguments that have OUT masked in --
-		 * otherwise, they were handled in the syscall_entry function.
-		 */
-		for (i = 0; i < sc->nargs; i++) {
-			char *temp;
-			if (sc->args[i].type & OUT) {
-				/*
-				 * If an error occurred, then don't bother
-				 * getting the data; it may not be valid.
-				 */
-				if (errorp) {
-					asprintf(&temp, "0x%lx",
-					    fsc->args[sc->args[i].offset]);
-				} else {
-					temp = print_arg(&sc->args[i],
-					    fsc->args, retval, trussinfo);
-				}
-				fsc->s_args[i] = temp;
+	if (*errorp) {
+		for (i = 0; i < nitems(bsd_to_linux_errno); i++) {
+			if (retval[0] == bsd_to_linux_errno[i]) {
+				retval[0] = i;
+				return (0);
 			}
 		}
-	}
 
-	/*
-	 * It would probably be a good idea to merge the error handling,
-	 * but that complicates things considerably.
-	 */
-	if (errorp) {
-		for (i = 0;
-		    (size_t)i < sizeof(bsd_to_linux_errno) / sizeof(int); i++) {
-			if (retval == bsd_to_linux_errno[i])
-				break;
-		}
+		/* XXX: How to handle unknown errors? */
 	}
+	return (0);
+}
 
-	if (fsc->name != NULL && (strcmp(fsc->name, "linux_execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0))
-		trussinfo->curthread->in_syscall = 1;
+static struct procabi amd64_linux32 = {
+	"Linux ELF32",
+	linux32_syscallnames,
+	nitems(linux32_syscallnames),
+	amd64_linux32_fetch_args,
+	amd64_linux32_fetch_retval
+};
 
-	print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
-	    errorp ? i : retval, fsc->sc);
-	free_fsc(fsc);
-
-	return (retval);
-}
+PROCABI(amd64_linux32);

Index: trunk/usr.bin/truss/amd64linux32.conf
===================================================================
--- trunk/usr.bin/truss/amd64linux32.conf	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/amd64linux32.conf	2018-07-04 00:01:33 UTC (rev 11271)

Property changes on: trunk/usr.bin/truss/amd64linux32.conf
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/usr.bin/truss/extern.h
===================================================================
--- trunk/usr.bin/truss/extern.h	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/extern.h	2018-07-04 00:01:33 UTC (rev 11271)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * Copyright 1997 Sean Eric Fagan
  *
@@ -28,45 +29,13 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/usr.bin/truss/extern.h 298427 2016-04-21 18:44:53Z jhb $
  */
 
-extern int setup_and_wait(char **);
-extern int start_tracing(pid_t);
+extern int print_line_prefix(struct trussinfo *);
+extern void setup_and_wait(struct trussinfo *, char **);
+extern void start_tracing(struct trussinfo *, pid_t);
 extern void restore_proc(int);
-extern void waitevent(struct trussinfo *);
-extern const char *ioctlname(register_t val);
+extern void eventloop(struct trussinfo *);
+extern const char *ioctlname(unsigned long val);
 extern char *strsig(int sig);
-#ifdef __amd64__
-extern void amd64_syscall_entry(struct trussinfo *, int);
-extern long amd64_syscall_exit(struct trussinfo *, int);
-extern void amd64_linux32_syscall_entry(struct trussinfo *, int);
-extern long amd64_linux32_syscall_exit(struct trussinfo *, int);
-extern void amd64_fbsd32_syscall_entry(struct trussinfo *, int);
-extern long amd64_fbsd32_syscall_exit(struct trussinfo *, int);
-#endif
-#ifdef __i386__
-extern void i386_syscall_entry(struct trussinfo *, int);
-extern long i386_syscall_exit(struct trussinfo *, int);
-extern void i386_linux_syscall_entry(struct trussinfo *, int);
-extern long i386_linux_syscall_exit(struct trussinfo *, int);
-#endif
-#ifdef __ia64__
-extern void ia64_syscall_entry(struct trussinfo *, int);
-extern long ia64_syscall_exit(struct trussinfo *, int);
-#endif
-#ifdef __powerpc__
-extern void powerpc_syscall_entry(struct trussinfo *, int);
-extern long powerpc_syscall_exit(struct trussinfo *, int);
-extern void powerpc64_syscall_entry(struct trussinfo *, int);
-extern long powerpc64_syscall_exit(struct trussinfo *, int);
-#endif
-#ifdef __sparc64__
-extern void sparc64_syscall_entry(struct trussinfo *, int);
-extern long sparc64_syscall_exit(struct trussinfo *, int);
-#endif
-#ifdef __mips__
-extern void mips_syscall_entry(struct trussinfo *, int);
-extern long mips_syscall_exit(struct trussinfo *, int);
-#endif
-

Index: trunk/usr.bin/truss/fbsd32.conf
===================================================================
--- trunk/usr.bin/truss/fbsd32.conf	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/fbsd32.conf	2018-07-04 00:01:33 UTC (rev 11271)

Property changes on: trunk/usr.bin/truss/fbsd32.conf
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/usr.bin/truss/i386-fbsd.c
===================================================================
--- trunk/usr.bin/truss/i386-fbsd.c	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/i386-fbsd.c	2018-07-04 00:01:33 UTC (rev 11271)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * Copyright 1997 Sean Eric Fagan
  *
@@ -29,20 +30,11 @@
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-static const char rcsid[] =
-  "$MidnightBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.bin/truss/i386-fbsd.c 290052 2015-10-27 17:00:04Z jhb $");
 
-/*
- * FreeBSD/i386-specific system call handling.  This is probably the most
- * complex part of the entire truss program, although I've got lots of
- * it handled relatively cleanly now.  The system call names are generated
- * automatically, thanks to /usr/src/sys/kern/syscalls.master.  The
- * names used for the various structures are confusing, I sadly admit.
- */
+/* FreeBSD/i386-specific system call handling. */
 
-#include <sys/types.h>
 #include <sys/ptrace.h>
 #include <sys/syscall.h>
 
@@ -49,284 +41,92 @@
 #include <machine/reg.h>
 #include <machine/psl.h>
 
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
 
 #include "truss.h"
-#include "syscall.h"
-#include "extern.h"
 
 #include "syscalls.h"
 
-static int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct freebsd_syscall {
-	struct syscall *sc;
-	const char *name;
-	int number;
-	unsigned long *args;
-	int nargs;	/* number of arguments -- *not* number of words! */
-	char **s_args;	/* the printable arguments */
-};
-
-static struct freebsd_syscall *
-alloc_fsc(void)
+static int
+i386_fetch_args(struct trussinfo *trussinfo, u_int narg)
 {
-
-	return (malloc(sizeof(struct freebsd_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct freebsd_syscall *fsc)
-{
-	int i;
-
-	free(fsc->args);
-	if (fsc->s_args) {
-		for (i = 0; i < fsc->nargs; i++)
-			free(fsc->s_args[i]);
-		free(fsc->s_args);
-	}
-	free(fsc);
-}
-
-/*
- * Called when a process has entered a system call.  nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases).  Note that if the STOPEVENT() code in i386/i386/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-i386_syscall_entry(struct trussinfo *trussinfo, int nargs)
-{
 	struct ptrace_io_desc iorequest;
 	struct reg regs;
-	struct freebsd_syscall *fsc;
-	struct syscall *sc;
+	struct current_syscall *cs;
 	lwpid_t tid;
 	unsigned int parm_offset;
-	int i, syscall_num;
 
 	tid = trussinfo->curthread->tid;
-
+	cs = &trussinfo->curthread->cs;
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
 		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
-		return;
+		return (-1);
 	}
 	parm_offset = regs.r_esp + sizeof(int);
 
 	/*
-	 * FreeBSD has two special kinds of system call redirctions --
+	 * FreeBSD has two special kinds of system call redirections --
 	 * SYS_syscall, and SYS___syscall.  The former is the old syscall()
 	 * routine, basically; the latter is for quad-aligned arguments.
+	 *
+	 * The system call argument count and code from ptrace() already
+	 * account for these, but we need to skip over the first argument.
 	 */
-	syscall_num = regs.r_eax;
-	switch (syscall_num) {
+	switch (regs.r_eax) {
 	case SYS_syscall:
-		syscall_num = ptrace(PT_READ_D, tid, (caddr_t)parm_offset, 0);
 		parm_offset += sizeof(int);
 		break;
 	case SYS___syscall:
-		syscall_num = ptrace(PT_READ_D, tid, (caddr_t)parm_offset, 0);
 		parm_offset += sizeof(quad_t);
 		break;
 	}
 
-	fsc = alloc_fsc();
-	if (fsc == NULL)
-		return;
-	fsc->number = syscall_num;
-	fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
-	    NULL : syscallnames[syscall_num];
-	if (!fsc->name) {
-		fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
-		    syscall_num);
-	}
-
-	if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
-	    (strcmp(fsc->name, "fork") == 0 ||
-	    strcmp(fsc->name, "rfork") == 0 ||
-	    strcmp(fsc->name, "vfork") == 0))
-		trussinfo->curthread->in_fork = 1;
-
-	if (nargs == 0)
-		return;
-
-	fsc->args = malloc((1 + nargs) * sizeof(unsigned long));
 	iorequest.piod_op = PIOD_READ_D;
 	iorequest.piod_offs = (void *)parm_offset;
-	iorequest.piod_addr = fsc->args;
-	iorequest.piod_len = (1 + nargs) * sizeof(unsigned long);
+	iorequest.piod_addr = cs->args;
+	iorequest.piod_len = narg * sizeof(unsigned long);
 	ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
 	if (iorequest.piod_len == 0)
-		return;
+		return (-1);
 
-	sc = NULL;
-	if (fsc->name)
-		sc = get_syscall(fsc->name);
-	if (sc)
-		fsc->nargs = sc->nargs;
-	else {
-#if DEBUG
-		fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
-		    "args to %d\n", fsc->name, nargs);
-#endif
-		fsc->nargs = nargs;
-	}
-
-	fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
-	fsc->sc = sc;
-
-	/*
-	 * At this point, we set up the system call arguments.
-	 * We ignore any OUT ones, however -- those are arguments that
-	 * are set by the system call, and so are probably meaningless
-	 * now.	This doesn't currently support arguments that are
-	 * passed in *and* out, however.
-	 */
-
-	if (fsc->name) {
-#if DEBUG
-		fprintf(stderr, "syscall %s(", fsc->name);
-#endif
-		for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
-			fprintf(stderr, "0x%x%s", sc ?
-			    fsc->args[sc->args[i].offset] : fsc->args[i],
-			    i < (fsc->nargs - 1) ? "," : "");
-#endif
-			if (sc && !(sc->args[i].type & OUT)) {
-				fsc->s_args[i] = print_arg(&sc->args[i],
-				    fsc->args, 0, trussinfo);
-			}
-		}
-#if DEBUG
-		fprintf(stderr, ")\n");
-#endif
-	}
-
-#if DEBUG
-	fprintf(trussinfo->outfile, "\n");
-#endif
-
-	if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0)) {
-		/*
-		 * XXX
-		 * This could be done in a more general
-		 * manner but it still wouldn't be very pretty.
-		 */
-		if (strcmp(fsc->name, "execve") == 0) {
-			if ((trussinfo->flags & EXECVEARGS) == 0) {
-				if (fsc->s_args[1]) {
-					free(fsc->s_args[1]);
-					fsc->s_args[1] = NULL;
-				}
-			}
-			if ((trussinfo->flags & EXECVEENVS) == 0) {
-				if (fsc->s_args[2]) {
-					free(fsc->s_args[2]);
-					fsc->s_args[2] = NULL;
-				}
-			}
-		}
-	}
-	trussinfo->curthread->fsc = fsc;
+	return (0);
 }
 
-/*
- * And when the system call is done, we handle it here.
- * Currently, no attempt is made to ensure that the system calls
- * match -- this needs to be fixed (and is, in fact, why S_SCX includes
- * the system call number instead of, say, an error status).
- */
-
-long
-i386_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
+static int
+i386_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp)
 {
 	struct reg regs;
-	struct freebsd_syscall *fsc;
-	struct syscall *sc;
 	lwpid_t tid;
-	long retval;
-	int errorp, i;
 
-	if (trussinfo->curthread->fsc == NULL)
-		return (-1);
-
 	tid = trussinfo->curthread->tid;
-
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
 		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
 		return (-1);
 	}
 
-	retval = regs.r_eax;
-	errorp = !!(regs.r_eflags & PSL_C);
+	retval[0] = regs.r_eax;
+	retval[1] = regs.r_edx;
+	*errorp = !!(regs.r_eflags & PSL_C);
+	return (0);
+}
 
-	/*
-	 * This code, while simpler than the initial versions I used, could
-	 * stand some significant cleaning.
-	 */
+static struct procabi i386_fbsd = {
+	"FreeBSD ELF32",
+	syscallnames,
+	nitems(syscallnames),
+	i386_fetch_args,
+	i386_fetch_retval
+};
 
-	fsc = trussinfo->curthread->fsc;
-	sc = fsc->sc;
-	if (!sc) {
-		for (i = 0; i < fsc->nargs; i++)
-			asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
-	} else {
-		/*
-		 * Here, we only look for arguments that have OUT masked in --
-		 * otherwise, they were handled in the syscall_entry function.
-		 */
-		for (i = 0; i < sc->nargs; i++) {
-			char *temp;
-			if (sc->args[i].type & OUT) {
-				/*
-				 * If an error occurred, then don't bother
-				 * getting the data; it may not be valid.
-				 */
-				if (errorp) {
-					asprintf(&temp, "0x%lx",
-					    fsc->args[sc->args[i].offset]);
-				} else {
-					temp = print_arg(&sc->args[i],
-					    fsc->args, retval, trussinfo);
-				}
-				fsc->s_args[i] = temp;
-			}
-		}
-	}
+PROCABI(i386_fbsd);
 
-	if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0))
-		trussinfo->curthread->in_syscall = 1;
+static struct procabi i386_fbsd_aout = {
+	"FreeBSD a.out",
+	syscallnames,
+	nitems(syscallnames),
+	i386_fetch_args,
+	i386_fetch_retval
+};
 
-	/*
-	 * It would probably be a good idea to merge the error handling,
-	 * but that complicates things considerably.
-	 */
+PROCABI(i386_fbsd_aout);
 
-	print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
-	    retval, fsc->sc);
-	free_fsc(fsc);
-
-	return (retval);
-}

Modified: trunk/usr.bin/truss/i386-linux.c
===================================================================
--- trunk/usr.bin/truss/i386-linux.c	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/i386-linux.c	2018-07-04 00:01:33 UTC (rev 11271)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * Copyright 1997 Sean Eric Fagan
  *
@@ -29,124 +30,36 @@
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-static const char rcsid[] =
-  "$MidnightBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.bin/truss/i386-linux.c 296010 2016-02-24 22:01:45Z jhb $");
 
-/*
- * Linux/i386-specific system call handling.  Given how much of this code
- * is taken from the freebsd equivalent, I can probably put even more of
- * it in support routines that can be used by any personality support.
- */
+/* Linux/i386-specific system call handling. */
 
-#include <sys/types.h>
 #include <sys/ptrace.h>
 
 #include <machine/reg.h>
 #include <machine/psl.h>
 
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
 
 #include "truss.h"
-#include "syscall.h"
-#include "extern.h"
 
 #include "linux_syscalls.h"
 
-static int nsyscalls =
-	sizeof(linux_syscallnames) / sizeof(linux_syscallnames[0]);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct linux_syscall {
-	struct syscall *sc;
-	const char *name;
-	int number;
-	unsigned long args[5];
-	int nargs;	/* number of arguments -- *not* number of words! */
-	char **s_args;	/* the printable arguments */
-};
-
-static struct linux_syscall *
-alloc_fsc(void)
+static int
+i386_linux_fetch_args(struct trussinfo *trussinfo, u_int narg)
 {
-
-	return (malloc(sizeof(struct linux_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct linux_syscall *fsc)
-{
-	int i;
-
-	if (fsc->s_args) {
-		for (i = 0; i < fsc->nargs; i++)
-			free(fsc->s_args[i]);
-		free(fsc->s_args);
-	}
-	free(fsc);
-}
-
-/*
- * Called when a process has entered a system call.  nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases).  Note that if the STOPEVENT() code in i386/i386/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-i386_linux_syscall_entry(struct trussinfo *trussinfo, int nargs)
-{
 	struct reg regs;
-	struct linux_syscall *fsc;
-	struct syscall *sc;
+	struct current_syscall *cs;
 	lwpid_t tid;
-	int i, syscall_num;
 
 	tid = trussinfo->curthread->tid;
-
+	cs = &trussinfo->curthread->cs;
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
 		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
-		return;
+		return (-1);
 	}
 
-	syscall_num = regs.r_eax;
-
-	fsc = alloc_fsc();
-	if (fsc == NULL)
-		return;
-	fsc->number = syscall_num;
-	fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
-	    NULL : linux_syscallnames[syscall_num];
-	if (!fsc->name) {
-		fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
-		    syscall_num);
-	}
-
-	if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
-	    (strcmp(fsc->name, "linux_fork") == 0 ||
-	    strcmp(fsc->name, "linux_vfork") == 0))
-		trussinfo->curthread->in_fork = 1;
-
-	if (nargs == 0)
-		return;
-
 	/*
 	 * Linux passes syscall arguments in registers, not
 	 * on the stack.  Fortunately, we've got access to the
@@ -154,88 +67,28 @@
 	 * number of arguments.	And what does linux do for syscalls
 	 * that have more than five arguments?
 	 */
-
-	fsc->args[0] = regs.r_ebx;
-	fsc->args[1] = regs.r_ecx;
-	fsc->args[2] = regs.r_edx;
-	fsc->args[3] = regs.r_esi;
-	fsc->args[4] = regs.r_edi;
-
-	sc = get_syscall(fsc->name);
-	if (sc)
-		fsc->nargs = sc->nargs;
-	else {
-#if DEBUG
-		fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
-		    "args to %d\n", fsc->name, nargs);
-#endif
-		fsc->nargs = nargs;
+	switch (narg) {
+	default:
+		cs->args[5] = regs.r_ebp;	/* Unconfirmed */
+	case 5:
+		cs->args[4] = regs.r_edi;
+	case 4:
+		cs->args[3] = regs.r_esi;
+	case 3:
+		cs->args[2] = regs.r_edx;
+	case 2:
+		cs->args[1] = regs.r_ecx;
+	case 1:
+		cs->args[0] = regs.r_ebx;
 	}
 
-	fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
-	fsc->sc = sc;
-
-	/*
-	 * At this point, we set up the system call arguments.
-	 * We ignore any OUT ones, however -- those are arguments that
-	 * are set by the system call, and so are probably meaningless
-	 * now.	This doesn't currently support arguments that are
-	 * passed in *and* out, however.
-	 */
-
-	if (fsc->name) {
-#if DEBUG
-		fprintf(stderr, "syscall %s(", fsc->name);
-#endif
-		for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
-			fprintf(stderr, "0x%x%s", sc ?
-			    fsc->args[sc->args[i].offset] : fsc->args[i],
-			    i < (fsc->nargs - 1) ? "," : "");
-#endif
-			if (sc && !(sc->args[i].type & OUT)) {
-				fsc->s_args[i] = print_arg(&sc->args[i],
-				    fsc->args, 0, trussinfo);
-			}
-		}
-#if DEBUG
-		fprintf(stderr, ")\n");
-#endif
-	}
-
-#if DEBUG
-	fprintf(trussinfo->outfile, "\n");
-#endif
-
-	if (fsc->name != NULL && (strcmp(fsc->name, "linux_execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0)) {
-		/*
-		 * XXX
-		 * This could be done in a more general
-		 * manner but it still wouldn't be very pretty.
-		 */
-		if (strcmp(fsc->name, "linux_execve") == 0) {
-			if ((trussinfo->flags & EXECVEARGS) == 0) {
-				if (fsc->s_args[1]) {
-					free(fsc->s_args[1]);
-					fsc->s_args[1] = NULL;
-				}
-			}
-			if ((trussinfo->flags & EXECVEENVS) == 0) {
-				if (fsc->s_args[2]) {
-					free(fsc->s_args[2]);
-					fsc->s_args[2] = NULL;
-				}
-			}
-		}
-	}
-	trussinfo->curthread->fsc = fsc;
+	return (0);
 }
 
 /*
  * Linux syscalls return negative errno's, we do positive and map them
  */
-const int bsd_to_linux_errno[] = {
+static const int bsd_to_linux_errno[] = {
 	-0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9,
 	-10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
 	-20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
@@ -247,82 +100,42 @@
 	-6,
 };
 
-long
-i386_linux_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
+static int
+i386_linux_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp)
 {
 	struct reg regs;
-	struct linux_syscall *fsc;
-	struct syscall *sc;
 	lwpid_t tid;
-	long retval;
-	int errorp, i;
+	size_t i;
 
-	if (trussinfo->curthread->fsc == NULL)
-		return (-1);
-
 	tid = trussinfo->curthread->tid;
-
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
 		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
 		return (-1);
 	}
 
-	retval = regs.r_eax;
-	errorp = !!(regs.r_eflags & PSL_C);
+	retval[0] = regs.r_eax;
+	retval[1] = regs.r_edx;
+	*errorp = !!(regs.r_eflags & PSL_C);
 
-	/*
-	 * This code, while simpler than the initial versions I used, could
-	 * stand some significant cleaning.
-	 */
-
-	fsc = trussinfo->curthread->fsc;
-	sc = fsc->sc;
-	if (!sc) {
-		for (i = 0; i < fsc->nargs; i++)
-			asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
-	} else {
-		/*
-		 * Here, we only look for arguments that have OUT masked in --
-		 * otherwise, they were handled in the syscall_entry function.
-		 */
-		for (i = 0; i < sc->nargs; i++) {
-			char *temp;
-			if (sc->args[i].type & OUT) {
-				/*
-				 * If an error occurred, then don't bother
-				 * getting the data; it may not be valid.
-				 */
-				if (errorp) {
-					asprintf(&temp, "0x%lx",
-					    fsc->args[sc->args[i].offset]);
-				} else {
-					temp = print_arg(&sc->args[i],
-					    fsc->args, retval, trussinfo);
-				}
-				fsc->s_args[i] = temp;
+	if (*errorp) {
+		for (i = 0; i < nitems(bsd_to_linux_errno); i++) {
+			if (retval[0] == bsd_to_linux_errno[i]) {
+				retval[0] = i;
+				return (0);
 			}
 		}
-	}
 
-	/*
-	 * It would probably be a good idea to merge the error handling,
-	 * but that complicates things considerably.
-	 */
-	if (errorp) {
-		for (i = 0;
-		    (size_t)i < sizeof(bsd_to_linux_errno) / sizeof(int); i++) {
-			if (retval == bsd_to_linux_errno[i])
-				break;
-		}
+		/* XXX: How to handle unknown errors? */
 	}
+	return (0);
+}
 
-	if (fsc->name != NULL && (strcmp(fsc->name, "linux_execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0))
-		trussinfo->curthread->in_syscall = 1;
+static struct procabi i386_linux = {
+	"Linux ELF",
+	linux_syscallnames,
+	nitems(linux_syscallnames),
+	i386_linux_fetch_args,
+	i386_linux_fetch_retval
+};
 
-	print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
-	    errorp ? i : retval, fsc->sc);
-	free_fsc(fsc);
-
-	return (retval);
-}
+PROCABI(i386_linux);

Index: trunk/usr.bin/truss/i386.conf
===================================================================
--- trunk/usr.bin/truss/i386.conf	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/i386.conf	2018-07-04 00:01:33 UTC (rev 11271)

Property changes on: trunk/usr.bin/truss/i386.conf
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Index: trunk/usr.bin/truss/i386linux.conf
===================================================================
--- trunk/usr.bin/truss/i386linux.conf	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/i386linux.conf	2018-07-04 00:01:33 UTC (rev 11271)

Property changes on: trunk/usr.bin/truss/i386linux.conf
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/usr.bin/truss/ia64-fbsd.c
===================================================================
--- trunk/usr.bin/truss/ia64-fbsd.c	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/ia64-fbsd.c	2018-07-04 00:01:33 UTC (rev 11271)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * Copyright 1997 Sean Eric Fagan
  *
@@ -29,101 +30,33 @@
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-static const char rcsid[] =
-  "$MidnightBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.bin/truss/ia64-fbsd.c 290052 2015-10-27 17:00:04Z jhb $");
 
-/*
- * FreeBSD/ia64-specific system call handling.  This is probably the most
- * complex part of the entire truss program, although I've got lots of
- * it handled relatively cleanly now.  The system call names are generated
- * automatically, thanks to /usr/src/sys/kern/syscalls.master.  The
- * names used for the various structures are confusing, I sadly admit.
- */
+/* FreeBSD/ia64-specific system call handling. */
 
-#include <sys/types.h>
 #include <sys/ptrace.h>
 #include <sys/syscall.h>
 
 #include <machine/reg.h>
 
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
 
 #include "truss.h"
-#include "syscall.h"
-#include "extern.h"
 
 #include "syscalls.h"
 
-static int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct freebsd_syscall {
-	struct syscall *sc;
-	const char *name;
-	int number;
-	unsigned long *args;
-	int nargs;	/* number of arguments -- *not* number of words! */
-	char **s_args;	/* the printable arguments */
-};
-
-static struct freebsd_syscall *
-alloc_fsc(void)
+static int
+ia64_fetch_args(struct trussinfo *trussinfo, u_int narg)
 {
-
-	return (malloc(sizeof(struct freebsd_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct freebsd_syscall *fsc)
-{
-	int i;
-
-	free(fsc->args);
-	if (fsc->s_args) {
-		for (i = 0; i < fsc->nargs; i++)
-			free(fsc->s_args[i]);
-		free(fsc->s_args);
-	}
-	free(fsc);
-}
-
-/*
- * Called when a process has entered a system call.  nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases).  Note that if the STOPEVENT() code in ia64/ia64/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-ia64_syscall_entry(struct trussinfo *trussinfo, int nargs)
-{
 	struct reg regs;
-	struct freebsd_syscall *fsc;
-	struct syscall *sc;
+	struct current_syscall *cs;
 	unsigned long *parm_offset;
 	lwpid_t tid;
-	int i, syscall_num;
+	int i;
 
 	tid = trussinfo->curthread->tid;
-
+	cs = &trussinfo->curthread->cs;
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
 		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
 		return;
@@ -131,184 +64,50 @@
 	parm_offset = &regs.r_scratch.gr16;
 
 	/*
-	 * FreeBSD has two special kinds of system call redirctions --
+	 * FreeBSD has two special kinds of system call redirections --
 	 * SYS_syscall, and SYS___syscall.  The former is the old syscall()
 	 * routine, basically; the latter is for quad-aligned arguments.
+	 *
+	 * The system call argument count and code from ptrace() already
+	 * account for these, but we need to skip over %rax if it contains
+	 * either of these values.
 	 */
-	syscall_num = regs.r_scratch.gr15;	/* XXX double-check. */
-	if (syscall_num == SYS_syscall || syscall_num == SYS___syscall)
-		syscall_num = (int)*parm_offset++;
-
-	fsc = alloc_fsc();
-	if (fsc == NULL)
-		return;
-	fsc->number = syscall_num;
-	fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
-	    NULL : syscallnames[syscall_num];
-	if (!fsc->name) {
-		fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
-		    syscall_num);
+	switch (regs.r_scratch.gr15) {
+	case SYS_syscall:
+	case SYS___syscall:
+		parm_offset++;
+		break;
 	}
 
-	if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
-	    (strcmp(fsc->name, "fork") == 0 ||
-	    strcmp(fsc->name, "rfork") == 0 ||
-	    strcmp(fsc->name, "vfork") == 0))
-		trussinfo->curthread->in_fork = 1;
+	memcpy(cs->args, parm_offset, narg * sizeof(long));
 
-	if (nargs == 0)
-		return;
-
-	fsc->args = malloc((1 + nargs) * sizeof(unsigned long));
-	memcpy(fsc->args, parm_offset, nargs * sizeof(long));
-
-	sc = get_syscall(fsc->name);
-	if (sc)
-		fsc->nargs = sc->nargs;
-	else {
-#if DEBUG
-		fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
-		    "args to %d\n", fsc->name, nargs);
-#endif
-		fsc->nargs = nargs;
-	}
-
-	fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
-	fsc->sc = sc;
-
-	/*
-	 * At this point, we set up the system call arguments.
-	 * We ignore any OUT ones, however -- those are arguments that
-	 * are set by the system call, and so are probably meaningless
-	 * now.	This doesn't currently support arguments that are
-	 * passed in *and* out, however.
-	 */
-
-	if (fsc->name) {
-#if DEBUG
-		fprintf(stderr, "syscall %s(", fsc->name);
-#endif
-		for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
-			fprintf(stderr, "0x%x%s", sc ?
-			    fsc->args[sc->args[i].offset] : fsc->args[i],
-			    i < (fsc->nargs - 1) ? "," : "");
-#endif
-			if (sc && !(sc->args[i].type & OUT)) {
-				fsc->s_args[i] = print_arg(&sc->args[i],
-				    fsc->args, 0, trussinfo);
-			}
-		}
-#if DEBUG
-		fprintf(stderr, ")\n");
-#endif
-	}
-
-#if DEBUG
-	fprintf(trussinfo->outfile, "\n");
-#endif
-
-	if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0)) {
-		/*
-		 * XXX
-		 * This could be done in a more general
-		 * manner but it still wouldn't be very pretty.
-		 */
-		if (strcmp(fsc->name, "execve") == 0) {
-			if ((trussinfo->flags & EXECVEARGS) == 0) {
-				if (fsc->s_args[1]) {
-					free(fsc->s_args[1]);
-					fsc->s_args[1] = NULL;
-				}
-			}
-			if ((trussinfo->flags & EXECVEENVS) == 0) {
-				if (fsc->s_args[2]) {
-					free(fsc->s_args[2]);
-					fsc->s_args[2] = NULL;
-				}
-			}
-		}
-	}
-	trussinfo->curthread->fsc = fsc;
+	return (0);
 }
 
-/*
- * And when the system call is done, we handle it here.
- * Currently, no attempt is made to ensure that the system calls
- * match -- this needs to be fixed (and is, in fact, why S_SCX includes
- * the system call number instead of, say, an error status).
- */
-
-long
-ia64_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
+static int
+ia64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp)
 {
 	struct reg regs;
-	struct freebsd_syscall *fsc;
-	struct syscall *sc;
 	lwpid_t tid;
-	long retval;
-	int errorp, i;
 
-	if (trussinfo->curthread->fsc == NULL)
-		return (-1);
-
 	tid = trussinfo->curthread->tid;
-
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
 		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
 		return (-1);
 	}
 
-	retval = regs.r_scratch.gr8;
-	errorp = (regs.r_scratch.gr10 != 0) ? 1 : 0;
+	retval[0] = regs.r_scratch.gr8;
+	retval[1] = regs.r_scratch.gr9;
+	*errorp = (regs.r_scratch.gr10 != 0) ? 1 : 0;
+	return (0);
+}
 
-	/*
-	 * This code, while simpler than the initial versions I used, could
-	 * stand some significant cleaning.
-	 */
+static struct procabi ia64_fbsd = {
+	"FreeBSD ELF64",
+	syscallnames,
+	nitems(syscallnames),
+	ia64_fetch_args,
+	ia64_fetch_retval
+};
 
-	fsc = trussinfo->curthread->fsc;
-	sc = fsc->sc;
-	if (!sc) {
-		for (i = 0; i < fsc->nargs; i++)
-			asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
-	} else {
-		/*
-		 * Here, we only look for arguments that have OUT masked in --
-		 * otherwise, they were handled in the syscall_entry function.
-		 */
-		for (i = 0; i < sc->nargs; i++) {
-			char *temp;
-			if (sc->args[i].type & OUT) {
-				/*
-				 * If an error occurred, then don't bother
-				 * getting the data; it may not be valid.
-				 */
-				if (errorp) {
-					asprintf(&temp, "0x%lx",
-					    fsc->args[sc->args[i].offset]);
-				} else {
-					temp = print_arg(&sc->args[i],
-					    fsc->args, retval, trussinfo);
-				}
-				fsc->s_args[i] = temp;
-			}
-		}
-	}
-
-	if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0))
-		trussinfo->curthread->in_syscall = 1;
-
-	/*
-	 * It would probably be a good idea to merge the error handling,
-	 * but that complicates things considerably.
-	 */
-
-	print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
-	    retval, fsc->sc);
-	free_fsc(fsc);
-
-	return (retval);
-}
+PROCABI(ia64_fbsd);

Modified: trunk/usr.bin/truss/main.c
===================================================================
--- trunk/usr.bin/truss/main.c	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/main.c	2018-07-04 00:01:33 UTC (rev 11271)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright 1997 Sean Eric Fagan
  *
@@ -30,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/usr.bin/truss/main.c 324779 2017-10-20 00:33:49Z emaste $");
 
 /*
  * The main module for truss.  Surprisingly simple, but, then, the other
@@ -38,20 +39,12 @@
  * do a lot of the work :).
  */
 
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/sysctl.h>
-#include <sys/wait.h>
+#include <sys/ptrace.h>
 
 #include <err.h>
-#include <errno.h>
-#include <fcntl.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
 #include <time.h>
 #include <unistd.h>
 
@@ -59,122 +52,38 @@
 #include "extern.h"
 #include "syscall.h"
 
-#define	MAXARGS	6
-
 static void
 usage(void)
 {
 	fprintf(stderr, "%s\n%s\n",
-	    "usage: truss [-cfaedDS] [-o file] [-s strsize] -p pid",
-	    "       truss [-cfaedDS] [-o file] [-s strsize] command [args]");
+	    "usage: truss [-cfaedDHS] [-o file] [-s strsize] -p pid",
+	    "       truss [-cfaedDHS] [-o file] [-s strsize] command [args]");
 	exit(1);
 }
 
-/*
- * WARNING! "FreeBSD a.out" must be first, or set_etype will not
- * work correctly.
- */
-struct ex_types {
-	const char *type;
-	void (*enter_syscall)(struct trussinfo *, int);
-	long (*exit_syscall)(struct trussinfo *, int);
-} ex_types[] = {
-#ifdef __amd64__
-	{ "FreeBSD ELF64", amd64_syscall_entry, amd64_syscall_exit },
-	{ "FreeBSD ELF32", amd64_fbsd32_syscall_entry, amd64_fbsd32_syscall_exit },
-	{ "Linux ELF32", amd64_linux32_syscall_entry, amd64_linux32_syscall_exit },
-#endif
-#ifdef __i386__
-	{ "FreeBSD a.out", i386_syscall_entry, i386_syscall_exit },
-	{ "FreeBSD ELF", i386_syscall_entry, i386_syscall_exit },
-	{ "FreeBSD ELF32", i386_syscall_entry, i386_syscall_exit },
-	{ "Linux ELF", i386_linux_syscall_entry, i386_linux_syscall_exit },
-#endif
-#ifdef __ia64__
-	{ "FreeBSD ELF64", ia64_syscall_entry, ia64_syscall_exit },
-#endif
-#ifdef __powerpc__
-	{ "FreeBSD ELF", powerpc_syscall_entry, powerpc_syscall_exit },
-	{ "FreeBSD ELF32", powerpc_syscall_entry, powerpc_syscall_exit },
-#ifdef __powerpc64__
-	{ "FreeBSD ELF64", powerpc64_syscall_entry, powerpc64_syscall_exit },
-#endif
-#endif
-#ifdef __sparc64__
-	{ "FreeBSD ELF64", sparc64_syscall_entry, sparc64_syscall_exit },
-#endif
-#ifdef __mips__
-	{ "FreeBSD ELF", mips_syscall_entry, mips_syscall_exit },
-	{ "FreeBSD ELF32", mips_syscall_entry, mips_syscall_exit },
-	{ "FreeBSD ELF64", mips_syscall_entry, mips_syscall_exit }, // XXX
-#endif
-	{ 0, 0, 0 },
-};
-
-/*
- * Set the execution type.  This is called after every exec, and when
- * a process is first monitored.
- */
-
-static struct ex_types *
-set_etype(struct trussinfo *trussinfo)
-{
-	struct ex_types *funcs;
-	size_t len;
-	int error;
-	int mib[4];
-	char progt[32];
-
-	len = sizeof(progt);
-	mib[0] = CTL_KERN;
-	mib[1] = KERN_PROC;
-	mib[2] = KERN_PROC_SV_NAME;
-	mib[3] = trussinfo->pid;
-	error = sysctl(mib, 4, progt, &len, NULL, 0);
-	if (error != 0)
-		err(2, "can not get etype");
-
-	for (funcs = ex_types; funcs->type; funcs++)
-		if (strcmp(funcs->type, progt) == 0)
-			break;
-
-	if (funcs->type == NULL) {
-		funcs = &ex_types[0];
-		warn("execution type %s is not supported -- using %s",
-		    progt, funcs->type);
-	}
-	return (funcs);
-}
-
 char *
 strsig(int sig)
 {
-	char *ret;
+	static char tmp[64];
 
-	ret = NULL;
 	if (sig > 0 && sig < NSIG) {
-		asprintf(&ret, "SIG%s", sys_signame[sig]);
-		if (ret == NULL)
-			return (NULL);
+		snprintf(tmp, sizeof(tmp), "SIG%s", sys_signame[sig]);
+		return (tmp);
 	}
-	return (ret);
+	return (NULL);
 }
 
 int
 main(int ac, char **av)
 {
-	struct timespec timediff;
 	struct sigaction sa;
-	struct ex_types *funcs;
 	struct trussinfo *trussinfo;
 	char *fname;
-	char *signame;
 	char **command;
-	pid_t childpid;
-	int c, initial_open, status;
+	pid_t pid;
+	int c;
 
 	fname = NULL;
-	initial_open = 1;
 
 	/* Initialize the trussinfo struct */
 	trussinfo = (struct trussinfo *)calloc(1, sizeof(struct trussinfo));
@@ -181,19 +90,19 @@
 	if (trussinfo == NULL)
 		errx(1, "calloc() failed");
 
+	pid = 0;
 	trussinfo->outfile = stderr;
 	trussinfo->strsize = 32;
-	trussinfo->pr_why = S_NONE;
 	trussinfo->curthread = NULL;
-	SLIST_INIT(&trussinfo->threadlist);
-	while ((c = getopt(ac, av, "p:o:facedDs:S")) != -1) {
+	LIST_INIT(&trussinfo->proclist);
+	init_syscalls();
+	while ((c = getopt(ac, av, "p:o:facedDs:SH")) != -1) {
 		switch (c) {
 		case 'p':	/* specified pid */
-			trussinfo->pid = atoi(optarg);
+			pid = atoi(optarg);
 			/* make sure i don't trace me */
-			if (trussinfo->pid == getpid()) {
-				fprintf(stderr, "attempt to grab self.\n");
-				exit(2);
+			if (pid == getpid()) {
+				errx(2, "attempt to grab self.");
 			}
 			break;
 		case 'f': /* Follow fork()'s */
@@ -203,7 +112,7 @@
 			trussinfo->flags |= EXECVEARGS;
 			break;
 		case 'c': /* Count number of system calls and time. */
-			trussinfo->flags |= COUNTONLY;
+			trussinfo->flags |= (COUNTONLY | NOSIGS);
 			break;
 		case 'e': /* Print execve() environment strings. */
 			trussinfo->flags |= EXECVEENVS;
@@ -223,6 +132,9 @@
 		case 'S':	/* Don't trace signals */
 			trussinfo->flags |= NOSIGS;
 			break;
+		case 'H':
+			trussinfo->flags |= DISPLAYTIDS;
+			break;
 		default:
 			usage();
 		}
@@ -229,20 +141,17 @@
 	}
 
 	ac -= optind; av += optind;
-	if ((trussinfo->pid == 0 && ac == 0) ||
-	    (trussinfo->pid != 0 && ac != 0))
+	if ((pid == 0 && ac == 0) ||
+	    (pid != 0 && ac != 0))
 		usage();
 
 	if (fname != NULL) { /* Use output file */
-		if ((trussinfo->outfile = fopen(fname, "w")) == NULL)
-			err(1, "cannot open %s", fname);
 		/*
-		 * Set FD_CLOEXEC, so that the output file is not shared with
-		 * the traced process.
+		 * Set close-on-exec ('e'), so that the output file is not
+		 * shared with the traced process.
 		 */
-		if (fcntl(fileno(trussinfo->outfile), F_SETFD, FD_CLOEXEC) ==
-		    -1)
-			warn("fcntl()");
+		if ((trussinfo->outfile = fopen(fname, "we")) == NULL)
+			err(1, "cannot open %s", fname);
 	}
 
 	/*
@@ -251,10 +160,10 @@
 	 * exit.  If, however, we are examining an already-running process,
 	 * then we restore the event mask on these same signals.
 	 */
-
-	if (trussinfo->pid == 0) {	/* Start a command ourselves */
+	if (pid == 0) {
+		/* Start a command ourselves */
 		command = av;
-		trussinfo->pid = setup_and_wait(command);
+		setup_and_wait(trussinfo, command);
 		signal(SIGINT, SIG_IGN);
 		signal(SIGTERM, SIG_IGN);
 		signal(SIGQUIT, SIG_IGN);
@@ -265,120 +174,38 @@
 		sigaction(SIGINT, &sa, NULL);
 		sigaction(SIGQUIT, &sa, NULL);
 		sigaction(SIGTERM, &sa, NULL);
-		start_tracing(trussinfo->pid);
+		start_tracing(trussinfo, pid);
 	}
 
-
 	/*
 	 * At this point, if we started the process, it is stopped waiting to
 	 * be woken up, either in exit() or in execve().
 	 */
+	if (LIST_FIRST(&trussinfo->proclist)->abi == NULL) {
+		/*
+		 * If we are not able to handle this ABI, detach from the
+		 * process and exit.  If we just created a new process to
+		 * run a command, kill the new process rather than letting
+		 * it run untraced.
+		 */
+		if (pid == 0)
+			kill(LIST_FIRST(&trussinfo->proclist)->pid, SIGKILL);
+		ptrace(PT_DETACH, LIST_FIRST(&trussinfo->proclist)->pid, NULL,
+		    0);
+		return (1);
+	}
+	ptrace(PT_SYSCALL, LIST_FIRST(&trussinfo->proclist)->pid, (caddr_t)1,
+	    0);
 
-START_TRACE:
-	funcs = set_etype(trussinfo);
-
-	initial_open = 0;
 	/*
 	 * At this point, it's a simple loop, waiting for the process to
 	 * stop, finding out why, printing out why, and then continuing it.
 	 * All of the grunt work is done in the support routines.
 	 */
-
 	clock_gettime(CLOCK_REALTIME, &trussinfo->start_time);
 
-	do {
-		waitevent(trussinfo);
+	eventloop(trussinfo);
 
-		switch (trussinfo->pr_why) {
-		case S_SCE:
-			funcs->enter_syscall(trussinfo, MAXARGS);
-			clock_gettime(CLOCK_REALTIME,
-			    &trussinfo->curthread->before);
-			break;
-		case S_SCX:
-			clock_gettime(CLOCK_REALTIME,
-			    &trussinfo->curthread->after);
-
-			if (trussinfo->curthread->in_fork &&
-			    (trussinfo->flags & FOLLOWFORKS)) {
-				trussinfo->curthread->in_fork = 0;
-				childpid = funcs->exit_syscall(trussinfo,
-				    trussinfo->pr_data);
-
-				/*
-				 * Fork a new copy of ourself to trace
-				 * the child of the original traced
-				 * process.
-				 */
-				if (fork() == 0) {
-					trussinfo->pid = childpid;
-					start_tracing(trussinfo->pid);
-					goto START_TRACE;
-				}
-				break;
-			}
-			funcs->exit_syscall(trussinfo, MAXARGS);
-			break;
-		case S_SIG:
-			if (trussinfo->flags & NOSIGS)
-				break;
-			if (trussinfo->flags & FOLLOWFORKS)
-				fprintf(trussinfo->outfile, "%5d: ",
-				    trussinfo->pid);
-			if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
-				timespecsubt(&trussinfo->curthread->after,
-				    &trussinfo->start_time, &timediff);
-				fprintf(trussinfo->outfile, "%ld.%09ld ",
-				    (long)timediff.tv_sec,
-				    timediff.tv_nsec);
-			}
-			if (trussinfo->flags & RELATIVETIMESTAMPS) {
-				timespecsubt(&trussinfo->curthread->after,
-				    &trussinfo->curthread->before, &timediff);
-				fprintf(trussinfo->outfile, "%ld.%09ld ",
-				    (long)timediff.tv_sec,
-				    timediff.tv_nsec);
-			}
-			signame = strsig(trussinfo->pr_data);
-			fprintf(trussinfo->outfile,
-			    "SIGNAL %u (%s)\n", trussinfo->pr_data,
-			    signame == NULL ? "?" : signame);
-			free(signame);
-			break;
-		case S_EXIT:
-			if (trussinfo->flags & COUNTONLY)
-				break;
-			if (trussinfo->flags & FOLLOWFORKS)
-				fprintf(trussinfo->outfile, "%5d: ",
-				    trussinfo->pid);
-			if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
-				timespecsubt(&trussinfo->curthread->after,
-				    &trussinfo->start_time, &timediff);
-				fprintf(trussinfo->outfile, "%ld.%09ld ",
-				    (long)timediff.tv_sec,
-				    timediff.tv_nsec);
-			}
-			if (trussinfo->flags & RELATIVETIMESTAMPS) {
-				timespecsubt(&trussinfo->curthread->after,
-				    &trussinfo->curthread->before, &timediff);
-				fprintf(trussinfo->outfile, "%ld.%09ld ",
-				    (long)timediff.tv_sec, timediff.tv_nsec);
-			}
-			fprintf(trussinfo->outfile,
-			    "process exit, rval = %u\n", trussinfo->pr_data);
-			break;
-		default:
-			break;
-		}
-	} while (trussinfo->pr_why != S_EXIT &&
-	    trussinfo->pr_why != S_DETACHED);
-
-	if (trussinfo->flags & FOLLOWFORKS) {
-		do {
-			childpid = wait(&status);
-		} while (childpid != -1);
-	}
-
 	if (trussinfo->flags & COUNTONLY)
 		print_summary(trussinfo);
 

Modified: trunk/usr.bin/truss/mips-fbsd.c
===================================================================
--- trunk/usr.bin/truss/mips-fbsd.c	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/mips-fbsd.c	2018-07-04 00:01:33 UTC (rev 11271)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * Copyright 1998 Sean Eric Fagan
  *
@@ -29,22 +30,11 @@
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-static const char rcsid[] =
-  "$MidnightBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.bin/truss/mips-fbsd.c 290052 2015-10-27 17:00:04Z jhb $");
 
-/*
- * FreeBSD/sparc64-specific system call handling.  This is probably the most
- * complex part of the entire truss program, although I've got lots of
- * it handled relatively cleanly now.  The system call names are generated
- * automatically, thanks to /usr/src/sys/kern/syscalls.master.  The
- * names used for the various structures are confusing, I sadly admit.
- *
- * This file is almost nothing more than a slightly-edited i386-fbsd.c.
- */
+/* FreeBSD/mips-specific system call handling. */
 
-#include <sys/types.h>
 #include <sys/ptrace.h>
 #include <sys/syscall.h>
 
@@ -51,316 +41,102 @@
 #include <machine/frame.h>
 #include <machine/reg.h>
 
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stddef.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
 
 #include "truss.h"
-#include "syscall.h"
-#include "extern.h"
 
 #include "syscalls.h"
 
-static int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct freebsd_syscall {
-	struct syscall *sc;
-	const char *name;
-	int number;
-	unsigned long *args;
-	int nargs;	/* number of arguments -- *not* number of words! */
-	char **s_args;	/* the printable arguments */
-};
-
-static struct freebsd_syscall *
-alloc_fsc(void)
+static int
+mips_fetch_args(struct trussinfo *trussinfo, u_int narg)
 {
-
-	return (malloc(sizeof(struct freebsd_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct freebsd_syscall *fsc)
-{
-	int i;
-
-	free(fsc->args);
-	if (fsc->s_args) {
-		for (i = 0; i < fsc->nargs; i++)
-			free(fsc->s_args[i]);
-		free(fsc->s_args);
-	}
-	free(fsc);
-}
-
-/*
- * Called when a process has entered a system call.  nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases).  Note that if the STOPEVENT() code in sparc64/sparc64/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-mips_syscall_entry(struct trussinfo *trussinfo, int nargs)
-{
 	struct ptrace_io_desc iorequest;
 	struct reg regs;
-	struct freebsd_syscall *fsc;
-	struct syscall *sc;
+	struct current_syscall *cs;
 	lwpid_t tid;
-	int i, syscall_num;
-	int indir;	/* indirect system call */
+	u_int i, reg;
 
 	tid = trussinfo->curthread->tid;
-
+	cs = &trussinfo->curthread->cs;
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
 		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
-		return;
+		return (-1);
 	}
 
-	indir = 0;
-	syscall_num = regs.r_regs[V0];
-	if (syscall_num == SYS_syscall) {
-		indir = 1;
-		syscall_num = regs.r_regs[A0];
+	/*
+	 * FreeBSD has two special kinds of system call redirections --
+	 * SYS_syscall, and SYS___syscall.  The former is the old syscall()
+	 * routine, basically; the latter is for quad-aligned arguments.
+	 *
+	 * The system call argument count and code from ptrace() already
+	 * account for these, but we need to skip over the first argument.
+	 */
+	reg = A0;
+	switch (regs.r_regs[V0]) {
+	case SYS_syscall:
+		reg = A1;
+		break;
+	case SYS___syscall:
+#if defined(__mips_n32) || defined(__mips_n64)
+		reg = A1;
+#else
+		reg = A2;
+#endif
+		break;
 	}
 
-	fsc = alloc_fsc();
-	if (fsc == NULL)
-		return;
-	fsc->number = syscall_num;
-	fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
-	    NULL : syscallnames[syscall_num];
-	if (!fsc->name) {
-		fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
-		    syscall_num);
-	}
-
-	if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
-	    (strcmp(fsc->name, "fork") == 0 ||
-	    strcmp(fsc->name, "rfork") == 0 ||
-	    strcmp(fsc->name, "vfork") == 0))
-		trussinfo->curthread->in_fork = 1;
-
-	if (nargs == 0)
-		return;
-
-	fsc->args = malloc((1 + nargs) * sizeof(unsigned long));
-#if 0 // XXX
-	iorequest.piod_op = PIOD_READ_D;
-	iorequest.piod_offs = (void *)parm_offset;
-	iorequest.piod_addr = fsc->args;
-	iorequest.piod_len = (1 + nargs) * sizeof(unsigned long);
-	ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
-	if (iorequest.piod_len == 0)
-		return;
+#if defined(__mips_n32) || defined(__mips_n64)
+#define	MAXREG		A7
 #else
-	iorequest.piod_op = PIOD_READ_D;
+#define	MAXREG		A3
 #endif
 
-	switch (nargs) {
-	default:
-		/*
-		 * The OS doesn't seem to allow more than 10 words of
-		 * parameters (yay!).	So we shouldn't be here.
-		 */
-		warn("More than 10 words (%d) of arguments!\n", nargs);
-		break;
-	case 10:
-	case 9:
-	case 8:
-	case 7:
-	case 6:
-	case 5:
-		/*
-		 * If there are 7-10 words of arguments, they are placed
-		 * on the stack, as is normal for other processors.
-		 * The fall-through for all of these is deliberate!!!
-		 */
-		// XXX BAD constant used here
+	for (i = 0; i < narg && reg <= MAXREG; i++, reg++)
+		cs->args[i] = regs.r_regs[reg];
+	if (narg > i) {
 		iorequest.piod_op = PIOD_READ_D;
-		iorequest.piod_offs = (void *)(regs.r_regs[SP] +
-		    4 * sizeof(uint32_t));
-		iorequest.piod_addr = &fsc->args[4];
-		iorequest.piod_len = (nargs - 4) * sizeof(fsc->args[0]);
+		iorequest.piod_offs = (void *)((uintptr_t)regs.r_regs[SP] +
+		    4 * sizeof(cs->args[0]));
+		iorequest.piod_addr = &cs->args[i];
+		iorequest.piod_len = (narg - i) * sizeof(cs->args[0]);
 		ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
 		if (iorequest.piod_len == 0)
-			return;
-	case 4:	fsc->args[3] = regs.r_regs[A3];
-	case 3:	fsc->args[2] = regs.r_regs[A2];
-	case 2:	fsc->args[1] = regs.r_regs[A1];
-	case 1:	fsc->args[0] = regs.r_regs[A0];
-	case 0: break;
+			return (-1);
 	}
-	if (indir) {
-		memmove(&fsc->args[0], &fsc->args[1],
-		    (nargs - 1) * sizeof(fsc->args[0]));
-	}
 
-	sc = get_syscall(fsc->name);
-	if (sc)
-		fsc->nargs = sc->nargs;
-	else {
-#if DEBUG
-		fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
-		    "args to %d\n", fsc->name, nargs);
-#endif
-		fsc->nargs = nargs;
-	}
-
-	fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
-	fsc->sc = sc;
-
-	/*
-	 * At this point, we set up the system call arguments.
-	 * We ignore any OUT ones, however -- those are arguments that
-	 * are set by the system call, and so are probably meaningless
-	 * now.	This doesn't currently support arguments that are
-	 * passed in *and* out, however.
-	 */
-
-	if (fsc->name) {
-#if DEBUG
-		fprintf(stderr, "syscall %s(", fsc->name);
-#endif
-		for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
-			fprintf(stderr, "0x%x%s", sc ?
-			    fsc->args[sc->args[i].offset] : fsc->args[i],
-			    i < (fsc->nargs - 1) ? "," : "");
-#endif
-			if (sc && !(sc->args[i].type & OUT)) {
-				fsc->s_args[i] = print_arg(&sc->args[i],
-				    fsc->args, 0, trussinfo);
-			}
-		}
-#if DEBUG
-		fprintf(stderr, ")\n");
-#endif
-	}
-
-#if DEBUG
-	fprintf(trussinfo->outfile, "\n");
-#endif
-
-	if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0)) {
-		/*
-		 * XXX
-		 * This could be done in a more general
-		 * manner but it still wouldn't be very pretty.
-		 */
-		if (strcmp(fsc->name, "execve") == 0) {
-			if ((trussinfo->flags & EXECVEARGS) == 0) {
-				if (fsc->s_args[1]) {
-					free(fsc->s_args[1]);
-					fsc->s_args[1] = NULL;
-				}
-			}
-			if ((trussinfo->flags & EXECVEENVS) == 0) {
-				if (fsc->s_args[2]) {
-					free(fsc->s_args[2]);
-					fsc->s_args[2] = NULL;
-				}
-			}
-		}
-	}
-	trussinfo->curthread->fsc = fsc;
+	return (0);
 }
 
-/*
- * And when the system call is done, we handle it here.
- * Currently, no attempt is made to ensure that the system calls
- * match -- this needs to be fixed (and is, in fact, why S_SCX includes
- * the system call number instead of, say, an error status).
- */
-
-long
-mips_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
+static int
+mips_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp)
 {
 	struct reg regs;
-	struct freebsd_syscall *fsc;
-	struct syscall *sc;
 	lwpid_t tid;
-	long retval;
-	int errorp, i;
 
-	if (trussinfo->curthread->fsc == NULL)
-		return (-1);
-
 	tid = trussinfo->curthread->tid;
-
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
-		fprintf(trussinfo->outfile, "\n");
+		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
 		return (-1);
 	}
 
-	retval = regs.r_regs[V0];
-	errorp = !!regs.r_regs[A3];
+	/* XXX: Does not have special handling for __syscall(). */
+	retval[0] = regs.r_regs[V0];
+	retval[1] = regs.r_regs[V1];
+	*errorp = !!regs.r_regs[A3];
+	return (0);
+}
 
-	/*
-	 * This code, while simpler than the initial versions I used, could
-	 * stand some significant cleaning.
-	 */
 
-	fsc = trussinfo->curthread->fsc;
-	sc = fsc->sc;
-	if (!sc) {
-		for (i = 0; i < fsc->nargs; i++)
-			asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
-	} else {
-		/*
-		 * Here, we only look for arguments that have OUT masked in --
-		 * otherwise, they were handled in the syscall_entry function.
-		 */
-		for (i = 0; i < sc->nargs; i++) {
-			char *temp;
-			if (sc->args[i].type & OUT) {
-				/*
-				 * If an error occurred, then don't bother
-				 * getting the data; it may not be valid.
-				 */
-				if (errorp) {
-					asprintf(&temp, "0x%lx",
-					    fsc->args[sc->args[i].offset]);
-				} else {
-					temp = print_arg(&sc->args[i],
-					    fsc->args, retval, trussinfo);
-				}
-				fsc->s_args[i] = temp;
-			}
-		}
-	}
+static struct procabi mips_fbsd = {
+#ifdef __mips_n64
+	"FreeBSD ELF64",
+#else
+	"FreeBSD ELF32",
+#endif
+	syscallnames,
+	nitems(syscallnames),
+	mips_fetch_args,
+	mips_fetch_retval
+};
 
-	if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0))
-		trussinfo->curthread->in_syscall = 1;
-
-	/*
-	 * It would probably be a good idea to merge the error handling,
-	 * but that complicates things considerably.
-	 */
-
-	print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
-	    retval, fsc->sc);
-	free_fsc(fsc);
-
-	return (retval);
-}
+PROCABI(mips_fbsd);

Modified: trunk/usr.bin/truss/powerpc-fbsd.c
===================================================================
--- trunk/usr.bin/truss/powerpc-fbsd.c	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/powerpc-fbsd.c	2018-07-04 00:01:33 UTC (rev 11271)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * Copyright 2006 Peter Grehan <grehan at freebsd.org>
  * Copyright 2005 Orlando Bassotto <orlando at break.net>
@@ -25,22 +26,11 @@
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-static const char rcsid[] =
-  "$MidnightBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.bin/truss/powerpc-fbsd.c 290052 2015-10-27 17:00:04Z jhb $");
 
-/*
- * FreeBSD/powerpc-specific system call handling.  This is probably the most
- * complex part of the entire truss program, although I've got lots of
- * it handled relatively cleanly now.  The system call names are generated
- * automatically, thanks to /usr/src/sys/kern/syscalls.master.  The
- * names used for the various structures are confusing, I sadly admit.
- *
- * This file is almost nothing more than a slightly-edited i386-fbsd.c.
- */
+/* FreeBSD/powerpc-specific system call handling. */
 
-#include <sys/types.h>
 #include <sys/ptrace.h>
 #include <sys/syscall.h>
 
@@ -47,19 +37,9 @@
 #include <machine/reg.h>
 #include <machine/frame.h>
 
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
 
 #include "truss.h"
-#include "syscall.h"
-#include "extern.h"
 
 #ifdef __powerpc64__	/* 32-bit compatibility */
 #include "freebsd32_syscalls.h"
@@ -68,284 +48,104 @@
 #include "syscalls.h"
 #endif
 
-static int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct freebsd_syscall {
-	struct syscall *sc;
-	const char *name;
-	int number;
-	unsigned long *args;
-	int nargs;	/* number of arguments -- *not* number of words! */
-	char **s_args;	/* the printable arguments */
-};
-
-static struct freebsd_syscall *
-alloc_fsc(void)
+static int
+powerpc_fetch_args(struct trussinfo *trussinfo, u_int narg)
 {
-
-	return (malloc(sizeof(struct freebsd_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct freebsd_syscall *fsc)
-{
-	int i;
-
-	free(fsc->args);
-	if (fsc->s_args) {
-		for (i = 0; i < fsc->nargs; i++)
-			free(fsc->s_args[i]);
-		free(fsc->s_args);
-	}
-	free(fsc);
-}
-
-/*
- * Called when a process has entered a system call.  nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases).  Note that if the STOPEVENT() code in powerpc/powerpc/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-powerpc_syscall_entry(struct trussinfo *trussinfo, int nargs)
-{
 	struct ptrace_io_desc iorequest;
 	struct reg regs;
-	struct freebsd_syscall *fsc;
-	struct syscall *sc;
-	void *args;
+	struct current_syscall *cs;
 	lwpid_t tid;
-	int i, regargs, syscall_num;
+	u_int i, reg;
 
-	/* Account for a 64-bit argument with corresponding alignment. */
-	nargs += 2;
-
 	tid = trussinfo->curthread->tid;
-
+	cs = &trussinfo->curthread->cs;
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
 		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
-		return;
+		return (-1);
 	}
 
 	/*
-	 * FreeBSD has two special kinds of system call redirctions --
+	 * FreeBSD has two special kinds of system call redirections --
 	 * SYS_syscall, and SYS___syscall.  The former is the old syscall()
 	 * routine, basically; the latter is for quad-aligned arguments.
+	 *
+	 * The system call argument count and code from ptrace() already
+	 * account for these, but we need to skip over the first argument.
 	 */
-	regargs = NARGREG;
-	syscall_num = regs.fixreg[0];
-	args = &regs.fixreg[3];
-	if (syscall_num == SYS_syscall) {
-		args = &regs.fixreg[4];
-		regargs -= 1;
-		syscall_num = regs.fixreg[3];
-	} else if (syscall_num == SYS___syscall) {
-		args = &regs.fixreg[5];
-		regargs -= 2;
-		syscall_num = regs.fixreg[4];
+	reg = 0;
+	switch (regs.fixreg[0]) {
+	case SYS_syscall:
+		reg += 1;
+		break;
+	case SYS___syscall:
+		reg += 2;
+		break;
 	}
 
-	fsc = alloc_fsc();
-	if (fsc == NULL)
-		return;
-	fsc->number = syscall_num;
-	fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
-	    NULL : syscallnames[syscall_num];
-	if (!fsc->name) {
-		fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
-		    syscall_num);
+	for (i = 0; i < narg && reg < NARGREG; i++, reg++) {
+#ifdef __powerpc64__
+		cs->args[i] = regs.fixreg[FIRSTARG + reg] & 0xffffffff;
+#else
+		cs->args[i] = regs.fixreg[FIRSTARG + reg];
+#endif
 	}
+	if (narg > i) {
+#ifdef __powerpc64__
+		uint32_t args32[narg - i];
+		u_int j;
 
-	if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
-	    (strcmp(fsc->name, "fork") == 0 ||
-	    strcmp(fsc->name, "rfork") == 0 ||
-	    strcmp(fsc->name, "vfork") == 0))
-		trussinfo->curthread->in_fork = 1;
-
-	if (nargs == 0)
-		return;
-
-	fsc->args = malloc((1 + nargs) * sizeof(unsigned long));
-
-	if (nargs > regargs) {
-		memmove(&fsc->args[0], args, regargs * sizeof(fsc->args[0]));
-
+#endif
 		iorequest.piod_op = PIOD_READ_D;
 		iorequest.piod_offs = (void *)(regs.fixreg[1] + 8);
-		iorequest.piod_addr = &fsc->args[regargs];
-		iorequest.piod_len = (nargs - regargs) * sizeof(fsc->args[0]);
+#ifdef __powerpc64__
+		iorequest.piod_addr = args32;
+		iorequest.piod_len = sizeof(args32);
+#else
+		iorequest.piod_addr = &cs->args[i];
+		iorequest.piod_len = (narg - i) * sizeof(cs->args[0]);
+#endif
 		ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
 		if (iorequest.piod_len == 0)
-			return;
-	} else
-		memmove(&fsc->args[0], args, nargs * sizeof(fsc->args[0]));
-
-	sc = get_syscall(fsc->name);
-	if (sc)
-		fsc->nargs = sc->nargs;
-	else {
-#if DEBUG
-		fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
-		    "args to %d\n", fsc->name, nargs);
+			return (-1);
+#ifdef __powerpc64__
+		for (j = 0; j < narg - i; j++)
+			cs->args[i + j] = args32[j];
 #endif
-		fsc->nargs = nargs;
 	}
 
-	fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
-	fsc->sc = sc;
-
-	/*
-	 * At this point, we set up the system call arguments.
-	 * We ignore any OUT ones, however -- those are arguments that
-	 * are set by the system call, and so are probably meaningless
-	 * now.	This doesn't currently support arguments that are
-	 * passed in *and* out, however.
-	 */
-
-	if (fsc->name) {
-#if DEBUG
-		fprintf(stderr, "syscall %s(", fsc->name);
-#endif
-		for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
-			fprintf(stderr, "0x%x%s", sc ?
-			    fsc->args[sc->args[i].offset] : fsc->args[i],
-			    i < (fsc->nargs - 1) ? "," : "");
-#endif
-			if (sc && !(sc->args[i].type & OUT)) {
-				fsc->s_args[i] = print_arg(&sc->args[i],
-				    fsc->args, 0, trussinfo);
-			}
-		}
-#if DEBUG
-		fprintf(stderr, ")\n");
-#endif
-	}
-
-#if DEBUG
-	fprintf(trussinfo->outfile, "\n");
-#endif
-
-	if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0)) {
-		/*
-		 * XXX
-		 * This could be done in a more general
-		 * manner but it still wouldn't be very pretty.
-		 */
-		if (strcmp(fsc->name, "execve") == 0) {
-			if ((trussinfo->flags & EXECVEARGS) == 0) {
-				if (fsc->s_args[1]) {
-					free(fsc->s_args[1]);
-					fsc->s_args[1] = NULL;
-				}
-			}
-			if ((trussinfo->flags & EXECVEENVS) == 0) {
-				if (fsc->s_args[2]) {
-					free(fsc->s_args[2]);
-					fsc->s_args[2] = NULL;
-				}
-			}
-		}
-	}
-	trussinfo->curthread->fsc = fsc;
+	return (0);
 }
 
-/*
- * And when the system call is done, we handle it here.
- * Currently, no attempt is made to ensure that the system calls
- * match -- this needs to be fixed (and is, in fact, why S_SCX includes
- * the system call number instead of, say, an error status).
- */
-
-long
-powerpc_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
+static int
+powerpc_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp)
 {
 	struct reg regs;
-	struct freebsd_syscall *fsc;
-	struct syscall *sc;
 	lwpid_t tid;
-	long retval;
-	int errorp, i;
 
-	if (trussinfo->curthread->fsc == NULL)
-		return (-1);
-
 	tid = trussinfo->curthread->tid;
-
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
-		fprintf(trussinfo->outfile, "\n");
+		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
 		return (-1);
 	}
 
-	retval = regs.fixreg[3];
-	errorp = !!(regs.cr & 0x10000000);
+	/* XXX: Does not have fixup for __syscall(). */
+#ifdef __powerpc64__
+	retval[0] = regs.fixreg[3] & 0xffffffff;
+	retval[1] = regs.fixreg[4] & 0xffffffff;
+#else
+	retval[0] = regs.fixreg[3];
+	retval[1] = regs.fixreg[4];
+#endif
+	*errorp = !!(regs.cr & 0x10000000);
+	return (0);
+}
 
-	/*
-	 * This code, while simpler than the initial versions I used, could
-	 * stand some significant cleaning.
-	 */
+static struct procabi powerpc_fbsd = {
+	"FreeBSD ELF32",
+	syscallnames,
+	nitems(syscallnames),
+	powerpc_fetch_args,
+	powerpc_fetch_retval
+};
 
-	fsc = trussinfo->curthread->fsc;
-	sc = fsc->sc;
-	if (!sc) {
-		for (i = 0; i < fsc->nargs; i++)
-			asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
-	} else {
-		/*
-		 * On 32-bit big-endian, the low word of a 64-bit return is
-		 * in the greater address. Switch to this. XXX note that
-		 * print_syscall_ret can't handle 64-bit return values (llseek)
-		 */
-		if (sc->ret_type == 2)
-			retval = regs.fixreg[4];
-
-		/*
-		 * Here, we only look for arguments that have OUT masked in --
-		 * otherwise, they were handled in the syscall_entry function.
-		 */
-		for (i = 0; i < sc->nargs; i++) {
-			char *temp;
-			if (sc->args[i].type & OUT) {
-				/*
-				 * If an error occurred, then don't bother
-				 * getting the data; it may not be valid.
-				 */
-				if (errorp) {
-					asprintf(&temp, "0x%lx",
-					    fsc->args[sc->args[i].offset]);
-				} else {
-					temp = print_arg(&sc->args[i],
-					    fsc->args, retval, trussinfo);
-				}
-				fsc->s_args[i] = temp;
-			}
-		}
-	}
-
-	if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0))
-		trussinfo->curthread->in_syscall = 1;
-
-	/*
-	 * It would probably be a good idea to merge the error handling,
-	 * but that complicates things considerably.
-	 */
-
-	print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
-	    retval, fsc->sc);
-	free_fsc(fsc);
-
-	return (retval);
-}
+PROCABI(powerpc_fbsd);

Modified: trunk/usr.bin/truss/powerpc64-fbsd.c
===================================================================
--- trunk/usr.bin/truss/powerpc64-fbsd.c	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/powerpc64-fbsd.c	2018-07-04 00:01:33 UTC (rev 11271)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * Copyright 2006 Peter Grehan <grehan at freebsd.org>
  * Copyright 2005 Orlando Bassotto <orlando at break.net>
@@ -25,22 +26,11 @@
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-static const char rcsid[] =
-  "$MidnightBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.bin/truss/powerpc64-fbsd.c 290052 2015-10-27 17:00:04Z jhb $");
 
-/*
- * FreeBSD/powerpc-specific system call handling.  This is probably the most
- * complex part of the entire truss program, although I've got lots of
- * it handled relatively cleanly now.  The system call names are generated
- * automatically, thanks to /usr/src/sys/kern/syscalls.master.  The
- * names used for the various structures are confusing, I sadly admit.
- *
- * This file is almost nothing more than a slightly-edited i386-fbsd.c.
- */
+/* FreeBSD/powerpc64-specific system call handling. */
 
-#include <sys/types.h>
 #include <sys/ptrace.h>
 #include <sys/syscall.h>
 
@@ -47,285 +37,83 @@
 #include <machine/reg.h>
 #include <machine/frame.h>
 
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
 
 #include "truss.h"
-#include "syscall.h"
-#include "extern.h"
 
 #include "syscalls.h"
 
-static int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct freebsd_syscall {
-	struct syscall *sc;
-	const char *name;
-	int number;
-	unsigned long *args;
-	int nargs;	/* number of arguments -- *not* number of words! */
-	char **s_args;	/* the printable arguments */
-};
-
-static struct freebsd_syscall *
-alloc_fsc(void)
+static int
+powerpc64_fetch_args(struct trussinfo *trussinfo, u_int narg)
 {
-
-	return (malloc(sizeof(struct freebsd_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct freebsd_syscall *fsc)
-{
-	int i;
-
-	free(fsc->args);
-	if (fsc->s_args) {
-		for (i = 0; i < fsc->nargs; i++)
-			free(fsc->s_args[i]);
-		free(fsc->s_args);
-	}
-	free(fsc);
-}
-
-/*
- * Called when a process has entered a system call.  nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases).  Note that if the STOPEVENT() code in powerpc/powerpc/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-powerpc64_syscall_entry(struct trussinfo *trussinfo, int nargs)
-{
 	struct ptrace_io_desc iorequest;
 	struct reg regs;
-	struct freebsd_syscall *fsc;
-	struct syscall *sc;
-	void *args;
+	struct current_syscall *cs;
 	lwpid_t tid;
-	int i, regargs, syscall_num;
+	u_int i, reg;
 
 	tid = trussinfo->curthread->tid;
-
+	cs = &trussinfo->curthread->cs;
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
 		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
-		return;
+		return (-1);
 	}
 
 	/*
-	 * FreeBSD has two special kinds of system call redirctions --
+	 * FreeBSD has two special kinds of system call redirections --
 	 * SYS_syscall, and SYS___syscall.  The former is the old syscall()
 	 * routine, basically; the latter is for quad-aligned arguments.
+	 *
+	 * The system call argument count and code from ptrace() already
+	 * account for these, but we need to skip over the first argument.
 	 */
-	regargs = NARGREG;
-	syscall_num = regs.fixreg[0];
-	args = &regs.fixreg[3];
-	if (syscall_num == SYS_syscall || syscall_num == SYS___syscall) {
-		args = &regs.fixreg[4];
-		regargs -= 1;
-		syscall_num = regs.fixreg[3];
+	reg = 0;
+	switch (regs.fixreg[0]) {
+	case SYS_syscall:
+	case SYS___syscall:
+		reg += 1;
+		break;
 	}
 
-	fsc = alloc_fsc();
-	if (fsc == NULL)
-		return;
-	fsc->number = syscall_num;
-	fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
-	    NULL : syscallnames[syscall_num];
-	if (!fsc->name) {
-		fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
-		    syscall_num);
-	}
-
-	if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
-	    (strcmp(fsc->name, "fork") == 0 ||
-	    strcmp(fsc->name, "rfork") == 0 ||
-	    strcmp(fsc->name, "vfork") == 0))
-		trussinfo->curthread->in_fork = 1;
-
-	if (nargs == 0)
-		return;
-
-	fsc->args = malloc((1 + nargs) * sizeof(unsigned long));
-
-	if (nargs > regargs) {
-		memmove(&fsc->args[0], args, regargs * sizeof(fsc->args[0]));
-
+	for (i = 0; i < narg && reg < NARGREG; i++, reg++)
+		cs->args[i] = regs.fixreg[FIRSTARG + reg];
+	if (narg > i) {
 		iorequest.piod_op = PIOD_READ_D;
 		iorequest.piod_offs = (void *)(regs.fixreg[1] + 48);
-		iorequest.piod_addr = &fsc->args[regargs];
-		iorequest.piod_len = (nargs - regargs) * sizeof(fsc->args[0]);
+		iorequest.piod_addr = &cs->args[i];
+		iorequest.piod_len = (narg - i) * sizeof(cs->args[0]);
 		ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
 		if (iorequest.piod_len == 0)
-			return;
-	} else
-		memmove(&fsc->args[0], args, nargs * sizeof(fsc->args[0]));
-
-	sc = get_syscall(fsc->name);
-	if (sc)
-		fsc->nargs = sc->nargs;
-	else {
-#if DEBUG
-		fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
-		    "args to %d\n", fsc->name, nargs);
-#endif
-		fsc->nargs = nargs;
+			return (-1);
 	}
 
-	fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
-	fsc->sc = sc;
-
-	/*
-	 * At this point, we set up the system call arguments.
-	 * We ignore any OUT ones, however -- those are arguments that
-	 * are set by the system call, and so are probably meaningless
-	 * now.	This doesn't currently support arguments that are
-	 * passed in *and* out, however.
-	 */
-
-	if (fsc->name) {
-#if DEBUG
-		fprintf(stderr, "syscall %s(", fsc->name);
-#endif
-		for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
-			fprintf(stderr, "0x%x%s", sc ?
-			    fsc->args[sc->args[i].offset] : fsc->args[i],
-			    i < (fsc->nargs - 1) ? "," : "");
-#endif
-			if (sc && !(sc->args[i].type & OUT)) {
-				fsc->s_args[i] = print_arg(&sc->args[i],
-				    fsc->args, 0, trussinfo);
-			}
-		}
-#if DEBUG
-		fprintf(stderr, ")\n");
-#endif
-	}
-
-#if DEBUG
-	fprintf(trussinfo->outfile, "\n");
-#endif
-
-	if (fsc->name && (strcmp(fsc->name, "execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0)) {
-		/*
-		 * XXX
-		 * This could be done in a more general
-		 * manner but it still wouldn't be very pretty.
-		 */
-		if (strcmp(fsc->name, "execve") == 0) {
-			if ((trussinfo->flags & EXECVEARGS) == 0) {
-				if (fsc->s_args[1]) {
-					free(fsc->s_args[1]);
-					fsc->s_args[1] = NULL;
-				}
-			}
-			if ((trussinfo->flags & EXECVEENVS) == 0) {
-				if (fsc->s_args[2]) {
-					free(fsc->s_args[2]);
-					fsc->s_args[2] = NULL;
-				}
-			}
-		}
-	}
-	trussinfo->curthread->fsc = fsc;
+	return (0);
 }
 
-/*
- * And when the system call is done, we handle it here.
- * Currently, no attempt is made to ensure that the system calls
- * match -- this needs to be fixed (and is, in fact, why S_SCX includes
- * the system call number instead of, say, an error status).
- */
-
-long
-powerpc64_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
+static int
+powerpc64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp)
 {
 	struct reg regs;
-	struct freebsd_syscall *fsc;
-	struct syscall *sc;
 	lwpid_t tid;
-	long retval;
-	int errorp, i;
 
-	if (trussinfo->curthread->fsc == NULL)
-		return (-1);
-
 	tid = trussinfo->curthread->tid;
-
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
-		fprintf(trussinfo->outfile, "\n");
+		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
 		return (-1);
 	}
 
-	retval = regs.fixreg[3];
-	errorp = !!(regs.cr & 0x10000000);
+	retval[0] = regs.fixreg[3];
+	retval[1] = regs.fixreg[4];
+	*errorp = !!(regs.cr & 0x10000000);
+	return (0);
+}
 
-	/*
-	 * This code, while simpler than the initial versions I used, could
-	 * stand some significant cleaning.
-	 */
+static struct procabi powerpc64_fbsd = {
+	"FreeBSD ELF64",
+	syscallnames,
+	nitems(syscallnames),
+	powerpc64_fetch_args,
+	powerpc64_fetch_retval
+};
 
-	fsc = trussinfo->curthread->fsc;
-	sc = fsc->sc;
-	if (!sc) {
-		for (i = 0; i < fsc->nargs; i++)
-			asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
-	} else {
-		/*
-		 * Here, we only look for arguments that have OUT masked in --
-		 * otherwise, they were handled in the syscall_entry function.
-		 */
-		for (i = 0; i < sc->nargs; i++) {
-			char *temp;
-			if (sc->args[i].type & OUT) {
-				/*
-				 * If an error occurred, then don't bother
-				 * getting the data; it may not be valid.
-				 */
-				if (errorp) {
-					asprintf(&temp, "0x%lx",
-					    fsc->args[sc->args[i].offset]);
-				} else {
-					temp = print_arg(&sc->args[i],
-					    fsc->args, retval, trussinfo);
-				}
-				fsc->s_args[i] = temp;
-			}
-		}
-	}
-
-	if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0))
-		trussinfo->curthread->in_syscall = 1;
-
-	/*
-	 * It would probably be a good idea to merge the error handling,
-	 * but that complicates things considerably.
-	 */
-
-	print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
-	    retval, fsc->sc);
-	free_fsc(fsc);
-
-	return (retval);
-}
+PROCABI(powerpc64_fbsd);

Modified: trunk/usr.bin/truss/setup.c
===================================================================
--- trunk/usr.bin/truss/setup.c	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/setup.c	2018-07-04 00:01:33 UTC (rev 11271)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright 1997 Sean Eric Fagan
  *
@@ -30,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/usr.bin/truss/setup.c 298427 2016-04-21 18:44:53Z jhb $");
 
 /*
  * Various setup functions for truss.  Not the cleanest-written code,
@@ -37,15 +38,15 @@
  * I'm afraid.
  */
 
-#include <sys/param.h>
-#include <sys/types.h>
 #include <sys/ptrace.h>
+#include <sys/sysctl.h>
 #include <sys/wait.h>
 
+#include <assert.h>
 #include <err.h>
 #include <errno.h>
-#include <fcntl.h>
 #include <signal.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -52,22 +53,24 @@
 #include <time.h>
 #include <unistd.h>
 
-#include <machine/reg.h>
-
 #include "truss.h"
+#include "syscall.h"
 #include "extern.h"
 
+SET_DECLARE(procabi, struct procabi);
+
 static sig_atomic_t detaching;
 
+static void	new_proc(struct trussinfo *, pid_t);
+
 /*
  * setup_and_wait() is called to start a process.  All it really does
- * is fork(), set itself up to stop on exec or exit, and then exec
- * the given command.  At that point, the child process stops, and
- * the parent can wake up and deal with it.
+ * is fork(), enable tracing in the child, and then exec the given
+ * command.  At that point, the child process stops, and the parent
+ * can wake up and deal with it.
  */
-
-int
-setup_and_wait(char *command[])
+void
+setup_and_wait(struct trussinfo *info, char *command[])
 {
 	pid_t pid;
 
@@ -84,17 +87,14 @@
 	if (waitpid(pid, NULL, 0) < 0)
 		err(1, "unexpect stop in waitpid");
 
-	return (pid);
+	new_proc(info, pid);
 }
 
 /*
- * start_tracing picks up where setup_and_wait() dropped off -- namely,
- * it sets the event mask for the given process id.  Called for both
- * monitoring an existing process and when we create our own.
+ * start_tracing is called to attach to an existing process.
  */
-
-int
-start_tracing(pid_t pid)
+void
+start_tracing(struct trussinfo *info, pid_t pid)
 {
 	int ret, retry;
 
@@ -109,7 +109,7 @@
 	if (waitpid(pid, NULL, 0) < 0)
 		err(1, "Unexpect stop in waitpid");
 
-	return (0);
+	new_proc(info, pid);
 }
 
 /*
@@ -118,7 +118,6 @@
  * applies if truss was told to monitor an already-existing
  * process.
  */
-
 void
 restore_proc(int signo __unused)
 {
@@ -126,14 +125,13 @@
 	detaching = 1;
 }
 
-static int
+static void
 detach_proc(pid_t pid)
 {
-	int waitval;
 
 	/* stop the child so that we can detach */
 	kill(pid, SIGSTOP);
-	if (waitpid(pid, &waitval, 0) < 0)
+	if (waitpid(pid, NULL, 0) < 0)
 		err(1, "Unexpected stop in waitpid");
 
 	if (ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0)
@@ -140,102 +138,453 @@
 		err(1, "Can not detach the process");
 
 	kill(pid, SIGCONT);
+}
 
-	return (waitval);
+/*
+ * Determine the ABI.  This is called after every exec, and when
+ * a process is first monitored.
+ */
+static struct procabi *
+find_abi(pid_t pid)
+{
+	struct procabi **pabi;
+	size_t len;
+	int error;
+	int mib[4];
+	char progt[32];
+
+	len = sizeof(progt);
+	mib[0] = CTL_KERN;
+	mib[1] = KERN_PROC;
+	mib[2] = KERN_PROC_SV_NAME;
+	mib[3] = pid;
+	error = sysctl(mib, 4, progt, &len, NULL, 0);
+	if (error != 0)
+		err(2, "can not get sysvec name");
+
+	SET_FOREACH(pabi, procabi) {
+		if (strcmp((*pabi)->type, progt) == 0)
+			return (*pabi);
+	}
+	warnx("ABI %s for pid %ld is not supported", progt, (long)pid);
+	return (NULL);
 }
 
+static void
+new_proc(struct trussinfo *info, pid_t pid)
+{
+	struct procinfo *np;
+
+	/*
+	 * If this happens it means there is a bug in truss.  Unfortunately
+	 * this will kill any processes are attached to.
+	 */
+	LIST_FOREACH(np, &info->proclist, entries) {
+		if (np->pid == pid)
+			errx(1, "Duplicate process for pid %ld", (long)pid);
+	}
+
+	if (info->flags & FOLLOWFORKS)
+		if (ptrace(PT_FOLLOW_FORK, pid, NULL, 1) == -1)
+			err(1, "Unable to follow forks for pid %ld", (long)pid);
+	np = calloc(1, sizeof(struct procinfo));
+	np->pid = pid;
+	np->abi = find_abi(pid);
+	SLIST_INIT(&np->threadlist);
+	LIST_INSERT_HEAD(&info->proclist, np, entries);
+}
+
+static void
+free_proc(struct procinfo *p)
+{
+	struct threadinfo *t, *t2;
+
+	SLIST_FOREACH_SAFE(t, &p->threadlist, entries, t2) {
+		free(t);
+	}
+	LIST_REMOVE(p, entries);
+	free(p);
+}
+
+static void
+detach_all_procs(struct trussinfo *info)
+{
+	struct procinfo *p, *p2;
+
+	LIST_FOREACH_SAFE(p, &info->proclist, entries, p2) {
+		detach_proc(p->pid);
+		free_proc(p);
+	}
+}
+
+static struct procinfo *
+find_proc(struct trussinfo *info, pid_t pid)
+{
+	struct procinfo *np;
+
+	LIST_FOREACH(np, &info->proclist, entries) {
+		if (np->pid == pid)
+			return (np);
+	}
+
+	return (NULL);
+}
+
 /*
- * Change curthread member based on lwpid.
- * If it is a new thread, create a threadinfo structure
+ * Change curthread member based on (pid, lwpid).
+ * If it is a new thread, create a threadinfo structure.
  */
 static void
-find_thread(struct trussinfo *info, lwpid_t lwpid)
+find_thread(struct trussinfo *info, pid_t pid, lwpid_t lwpid)
 {
-	struct threadinfo *np;
+	struct procinfo *np;
+	struct threadinfo *nt;
 
-	info->curthread = NULL;
-	SLIST_FOREACH(np, &info->threadlist, entries) {
-		if (np->tid == lwpid) {
-			info->curthread = np;
+	np = find_proc(info, pid);
+	assert(np != NULL);
+
+	SLIST_FOREACH(nt, &np->threadlist, entries) {
+		if (nt->tid == lwpid) {
+			info->curthread = nt;
 			return;
 		}
 	}
 
-	np = (struct threadinfo *)calloc(1, sizeof(struct threadinfo));
-	if (np == NULL)
+	nt = calloc(1, sizeof(struct threadinfo));
+	if (nt == NULL)
 		err(1, "calloc() failed");
-	np->tid = lwpid;
-	SLIST_INSERT_HEAD(&info->threadlist, np, entries);
-	info->curthread = np;
+	nt->proc = np;
+	nt->tid = lwpid;
+	SLIST_INSERT_HEAD(&np->threadlist, nt, entries);
+	info->curthread = nt;
 }
 
 /*
- * Start the traced process and wait until it stoped.
- * Fill trussinfo structure.
- * When this even returns, the traced process is in stop state.
+ * When a process exits, it no longer has any threads left.  However,
+ * the main loop expects a valid curthread.  In cases when a thread
+ * triggers the termination (e.g. calling exit or triggering a fault)
+ * we would ideally use that thread.  However, if a process is killed
+ * by a signal sent from another process then there is no "correct"
+ * thread.  We just punt and use the first thread.
  */
-void
-waitevent(struct trussinfo *info)
+static void
+find_exit_thread(struct trussinfo *info, pid_t pid)
 {
-	struct ptrace_lwpinfo lwpinfo;
-	static int pending_signal = 0;
-	int waitval;
+	struct procinfo *np;
+	struct threadinfo *nt;
 
-	ptrace(PT_SYSCALL, info->pid, (caddr_t)1, pending_signal);
-	pending_signal = 0;
+	np = find_proc(info, pid);
+	assert(np != NULL);
 
-detach:
-	if (detaching) {
-		waitval = detach_proc(info->pid);
-		info->pr_why = S_DETACHED;
-		info->pr_data = WEXITSTATUS(waitval);
+	if (SLIST_EMPTY(&np->threadlist)) {
+		/*
+		 * If an existing process exits right after we attach
+		 * to it but before it posts any events, there won't
+		 * be any threads.  Create a dummy thread and set its
+		 * "before" time to the global start time.
+		 */
+		nt = calloc(1, sizeof(struct threadinfo));
+		if (nt == NULL)
+			err(1, "calloc() failed");
+		nt->proc = np;
+		nt->tid = 0;
+		SLIST_INSERT_HEAD(&np->threadlist, nt, entries);
+		nt->before = info->start_time;
+	}
+	info->curthread = SLIST_FIRST(&np->threadlist);
+}
+
+static void
+alloc_syscall(struct threadinfo *t, struct ptrace_lwpinfo *pl)
+{
+	u_int i;
+
+	assert(t->in_syscall == 0);
+	assert(t->cs.number == 0);
+	assert(t->cs.name == NULL);
+	assert(t->cs.nargs == 0);
+	for (i = 0; i < nitems(t->cs.s_args); i++)
+		assert(t->cs.s_args[i] == NULL);
+	memset(t->cs.args, 0, sizeof(t->cs.args));
+	t->cs.number = pl->pl_syscall_code;
+	t->in_syscall = 1;
+}
+
+static void
+free_syscall(struct threadinfo *t)
+{
+	u_int i;
+
+	for (i = 0; i < t->cs.nargs; i++)
+		free(t->cs.s_args[i]);
+	memset(&t->cs, 0, sizeof(t->cs));
+	t->in_syscall = 0;
+}
+
+static void
+enter_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl)
+{
+	struct threadinfo *t;
+	struct syscall *sc;
+	u_int i, narg;
+
+	t = info->curthread;
+	alloc_syscall(t, pl);
+	narg = MIN(pl->pl_syscall_narg, nitems(t->cs.args));
+	if (narg != 0 && t->proc->abi->fetch_args(info, narg) != 0) {
+		free_syscall(t);
 		return;
 	}
 
-	if (waitpid(info->pid, &waitval, 0) == -1) {
-		if (errno == EINTR)
-			goto detach;
-		err(1, "Unexpected stop in waitpid");
+	if (t->cs.number >= 0 && t->cs.number < t->proc->abi->nsyscalls)
+		t->cs.name = t->proc->abi->syscallnames[t->cs.number];
+	if (t->cs.name == NULL)
+		fprintf(info->outfile, "-- UNKNOWN %s SYSCALL %d --\n",
+		    t->proc->abi->type, t->cs.number);
+
+	sc = get_syscall(t->cs.name, narg);
+	t->cs.nargs = sc->nargs;
+	assert(sc->nargs <= nitems(t->cs.s_args));
+
+	t->cs.sc = sc;
+
+	/*
+	 * At this point, we set up the system call arguments.
+	 * We ignore any OUT ones, however -- those are arguments that
+	 * are set by the system call, and so are probably meaningless
+	 * now.	This doesn't currently support arguments that are
+	 * passed in *and* out, however.
+	 */
+	if (t->cs.name != NULL) {
+#if DEBUG
+		fprintf(stderr, "syscall %s(", t->cs.name);
+#endif
+		for (i = 0; i < t->cs.nargs; i++) {
+#if DEBUG
+			fprintf(stderr, "0x%lx%s", sc ?
+			    t->cs.args[sc->args[i].offset] : t->cs.args[i],
+			    i < (t->cs.nargs - 1) ? "," : "");
+#endif
+			if (!(sc->args[i].type & OUT)) {
+				t->cs.s_args[i] = print_arg(&sc->args[i],
+				    t->cs.args, 0, info);
+			}
+		}
+#if DEBUG
+		fprintf(stderr, ")\n");
+#endif
 	}
 
-	if (WIFCONTINUED(waitval)) {
-		info->pr_why = S_NONE;
+	clock_gettime(CLOCK_REALTIME, &t->before);
+}
+
+static void
+exit_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl)
+{
+	struct threadinfo *t;
+	struct procinfo *p;
+	struct syscall *sc;
+	long retval[2];
+	u_int i;
+	int errorp;
+
+	t = info->curthread;
+	if (!t->in_syscall)
 		return;
-	}
-	if (WIFEXITED(waitval)) {
-		info->pr_why = S_EXIT;
-		info->pr_data = WEXITSTATUS(waitval);
+
+	clock_gettime(CLOCK_REALTIME, &t->after);
+	p = t->proc;
+	if (p->abi->fetch_retval(info, retval, &errorp) < 0) {
+		free_syscall(t);
 		return;
 	}
-	if (WIFSTOPPED(waitval)) {
-		ptrace(PT_LWPINFO, info->pid, (caddr_t)&lwpinfo,
-		    sizeof(lwpinfo));
-		find_thread(info, lwpinfo.pl_lwpid);
-		switch (WSTOPSIG(waitval)) {
-		case SIGTRAP:
-			if (lwpinfo.pl_flags & PL_FLAG_SCE) {
-				info->pr_why = S_SCE;
-				info->curthread->in_syscall = 1;
-				break;
-			} else if (lwpinfo.pl_flags & PL_FLAG_SCX) {
-				info->pr_why = S_SCX;
-				info->curthread->in_syscall = 0;
-				break;
+
+	sc = t->cs.sc;
+	/*
+	 * Here, we only look for arguments that have OUT masked in --
+	 * otherwise, they were handled in enter_syscall().
+	 */
+	for (i = 0; i < sc->nargs; i++) {
+		char *temp;
+
+		if (sc->args[i].type & OUT) {
+			/*
+			 * If an error occurred, then don't bother
+			 * getting the data; it may not be valid.
+			 */
+			if (errorp) {
+				asprintf(&temp, "0x%lx",
+				    t->cs.args[sc->args[i].offset]);
 			} else {
-				errx(1,
-		   "pl_flags %x contains neither PL_FLAG_SCE nor PL_FLAG_SCX",
-				    lwpinfo.pl_flags);
+				temp = print_arg(&sc->args[i],
+				    t->cs.args, retval, info);
 			}
-		default:
-			info->pr_why = S_SIG;
-			info->pr_data = WSTOPSIG(waitval);
-			pending_signal = info->pr_data;
-			break;
+			t->cs.s_args[i] = temp;
 		}
 	}
-	if (WIFSIGNALED(waitval)) {
-		info->pr_why = S_EXIT;
-		info->pr_data = 0;
-		return;
+
+	print_syscall_ret(info, errorp, retval);
+	free_syscall(t);
+
+	/*
+	 * If the process executed a new image, check the ABI.  If the
+	 * new ABI isn't supported, stop tracing this process.
+	 */
+	if (pl->pl_flags & PL_FLAG_EXEC) {
+		p->abi = find_abi(p->pid);
+		if (p->abi == NULL) {
+			if (ptrace(PT_DETACH, p->pid, (caddr_t)1, 0) < 0)
+				err(1, "Can not detach the process");
+			free_proc(p);
+		}
 	}
 }
+
+int
+print_line_prefix(struct trussinfo *info)
+{
+	struct timespec timediff;
+	struct threadinfo *t;
+	int len;
+
+	len = 0;
+	t = info->curthread;
+	if (info->flags & (FOLLOWFORKS | DISPLAYTIDS)) {
+		if (info->flags & FOLLOWFORKS)
+			len += fprintf(info->outfile, "%5d", t->proc->pid);
+		if ((info->flags & (FOLLOWFORKS | DISPLAYTIDS)) ==
+		    (FOLLOWFORKS | DISPLAYTIDS))
+			len += fprintf(info->outfile, " ");
+		if (info->flags & DISPLAYTIDS)
+			len += fprintf(info->outfile, "%6d", t->tid);
+		len += fprintf(info->outfile, ": ");
+	}
+	if (info->flags & ABSOLUTETIMESTAMPS) {
+		timespecsubt(&t->after, &info->start_time, &timediff);
+		len += fprintf(info->outfile, "%jd.%09ld ",
+		    (intmax_t)timediff.tv_sec, timediff.tv_nsec);
+	}
+	if (info->flags & RELATIVETIMESTAMPS) {
+		timespecsubt(&t->after, &t->before, &timediff);
+		len += fprintf(info->outfile, "%jd.%09ld ",
+		    (intmax_t)timediff.tv_sec, timediff.tv_nsec);
+	}
+	return (len);
+}
+
+static void
+report_exit(struct trussinfo *info, siginfo_t *si)
+{
+	struct threadinfo *t;
+
+	t = info->curthread;
+	clock_gettime(CLOCK_REALTIME, &t->after);
+	print_line_prefix(info);
+	if (si->si_code == CLD_EXITED)
+		fprintf(info->outfile, "process exit, rval = %u\n",
+		    si->si_status);
+	else
+		fprintf(info->outfile, "process killed, signal = %u%s\n",
+		    si->si_status, si->si_code == CLD_DUMPED ?
+		    " (core dumped)" : "");
+}
+
+static void
+report_new_child(struct trussinfo *info)
+{
+	struct threadinfo *t;
+
+	t = info->curthread;
+	clock_gettime(CLOCK_REALTIME, &t->after);
+	t->before = t->after;
+	print_line_prefix(info);
+	fprintf(info->outfile, "<new process>\n");
+}
+
+static void
+report_signal(struct trussinfo *info, siginfo_t *si)
+{
+	struct threadinfo *t;
+	char *signame;
+
+	t = info->curthread;
+	clock_gettime(CLOCK_REALTIME, &t->after);
+	print_line_prefix(info);
+	signame = strsig(si->si_status);
+	fprintf(info->outfile, "SIGNAL %u (%s)\n", si->si_status,
+	    signame == NULL ? "?" : signame);
+}
+
+/*
+ * Wait for events until all the processes have exited or truss has been
+ * asked to stop.
+ */
+void
+eventloop(struct trussinfo *info)
+{
+	struct ptrace_lwpinfo pl;
+	siginfo_t si;
+	int pending_signal;
+
+	while (!LIST_EMPTY(&info->proclist)) {
+		if (detaching) {
+			detach_all_procs(info);
+			return;
+		}
+
+		if (waitid(P_ALL, 0, &si, WTRAPPED | WEXITED) == -1) {
+			if (errno == EINTR)
+				continue;
+			err(1, "Unexpected error from waitid");
+		}
+
+		assert(si.si_signo == SIGCHLD);
+
+		switch (si.si_code) {
+		case CLD_EXITED:
+		case CLD_KILLED:
+		case CLD_DUMPED:
+			find_exit_thread(info, si.si_pid);
+			if ((info->flags & COUNTONLY) == 0)
+				report_exit(info, &si);
+			free_proc(info->curthread->proc);
+			info->curthread = NULL;
+			break;
+		case CLD_TRAPPED:
+			if (ptrace(PT_LWPINFO, si.si_pid, (caddr_t)&pl,
+			    sizeof(pl)) == -1)
+				err(1, "ptrace(PT_LWPINFO)");
+
+			if (pl.pl_flags & PL_FLAG_CHILD) {
+				new_proc(info, si.si_pid);
+				assert(LIST_FIRST(&info->proclist)->abi !=
+				    NULL);
+			}
+			find_thread(info, si.si_pid, pl.pl_lwpid);
+
+			if (si.si_status == SIGTRAP &&
+			    (pl.pl_flags & (PL_FLAG_SCE|PL_FLAG_SCX)) != 0) {
+				if (pl.pl_flags & PL_FLAG_SCE)
+					enter_syscall(info, &pl);
+				else if (pl.pl_flags & PL_FLAG_SCX)
+					exit_syscall(info, &pl);
+				pending_signal = 0;
+			} else if (pl.pl_flags & PL_FLAG_CHILD) {
+				if ((info->flags & COUNTONLY) == 0)
+					report_new_child(info);
+				pending_signal = 0;
+			} else {
+				if ((info->flags & NOSIGS) == 0)
+					report_signal(info, &si);
+				pending_signal = si.si_status;
+			}
+			ptrace(PT_SYSCALL, si.si_pid, (caddr_t)1,
+			    pending_signal);
+			break;
+		case CLD_STOPPED:
+			errx(1, "waitid reported CLD_STOPPED");
+		case CLD_CONTINUED:
+			break;
+		}
+	}
+}

Modified: trunk/usr.bin/truss/sparc64-fbsd.c
===================================================================
--- trunk/usr.bin/truss/sparc64-fbsd.c	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/sparc64-fbsd.c	2018-07-04 00:01:33 UTC (rev 11271)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * Copyright 1998 Sean Eric Fagan
  *
@@ -29,22 +30,11 @@
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-static const char rcsid[] =
-  "$MidnightBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.bin/truss/sparc64-fbsd.c 290052 2015-10-27 17:00:04Z jhb $");
 
-/*
- * FreeBSD/sparc64-specific system call handling.  This is probably the most
- * complex part of the entire truss program, although I've got lots of
- * it handled relatively cleanly now.  The system call names are generated
- * automatically, thanks to /usr/src/sys/kern/syscalls.master.  The
- * names used for the various structures are confusing, I sadly admit.
- *
- * This file is almost nothing more than a slightly-edited i386-fbsd.c.
- */
+/* FreeBSD/sparc64-specific system call handling. */
 
-#include <sys/types.h>
 #include <sys/ptrace.h>
 #include <sys/syscall.h>
 
@@ -52,309 +42,85 @@
 #include <machine/reg.h>
 #include <machine/tstate.h>
 
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
 #include <stddef.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
 
 #include "truss.h"
-#include "syscall.h"
-#include "extern.h"
 
 #include "syscalls.h"
 
-static int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct freebsd_syscall {
-	struct syscall *sc;
-	const char *name;
-	int number;
-	unsigned long *args;
-	int nargs;	/* number of arguments -- *not* number of words! */
-	char **s_args;	/* the printable arguments */
-};
-
-static struct freebsd_syscall *
-alloc_fsc(void)
+static int
+sparc64_fetch_args(struct trussinfo *trussinfo, u_int narg)
 {
-
-	return (malloc(sizeof(struct freebsd_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct freebsd_syscall *fsc)
-{
-	int i;
-
-	free(fsc->args);
-	if (fsc->s_args) {
-		for (i = 0; i < fsc->nargs; i++)
-			free(fsc->s_args[i]);
-		free(fsc->s_args);
-	}
-	free(fsc);
-}
-
-/*
- * Called when a process has entered a system call.  nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases).  Note that if the STOPEVENT() code in sparc64/sparc64/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-sparc64_syscall_entry(struct trussinfo *trussinfo, int nargs)
-{
 	struct ptrace_io_desc iorequest;
 	struct reg regs;
-	struct freebsd_syscall *fsc;
-	struct syscall *sc;
+	struct current_syscall *cs;
 	lwpid_t tid;
-	int i, syscall_num;
-	int indir;	/* indirect system call */
+	u_int i, reg;
 
 	tid = trussinfo->curthread->tid;
-
+	cs = &trussinfo->curthread->cs;
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
 		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
-		return;
+		return (-1);
 	}
 
 	/*
-	 * FreeBSD has two special kinds of system call redirctions --
+	 * FreeBSD has two special kinds of system call redirections --
 	 * SYS_syscall, and SYS___syscall.  The former is the old syscall()
 	 * routine, basically; the latter is for quad-aligned arguments.
+	 *
+	 * The system call argument count and code from ptrace() already
+	 * account for these, but we need to skip over the first argument.
 	 */
-	indir = 0;
-	syscall_num = regs.r_global[1];
-	if (syscall_num == SYS_syscall || syscall_num == SYS___syscall) {
-		indir = 1;
-		syscall_num = regs.r_out[0];
+	reg = 0;
+	switch (regs.r_global[1]) {
+	case SYS_syscall:
+	case SYS___syscall:
+		reg = 1;
+		break;
 	}
 
-	fsc = alloc_fsc();
-	if (fsc == NULL)
-		return;
-	fsc->number = syscall_num;
-	fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
-	    NULL : syscallnames[syscall_num];
-	if (!fsc->name) {
-		fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
-		    syscall_num);
-	}
-
-	if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
-	    (strcmp(fsc->name, "fork") == 0 ||
-	    strcmp(fsc->name, "rfork") == 0 ||
-	    strcmp(fsc->name, "vfork") == 0))
-		trussinfo->curthread->in_fork = 1;
-
-	if (nargs == 0)
-		return;
-
-	fsc->args = malloc((1 + nargs) * sizeof(unsigned long));
-	switch (nargs) {
-	default:
-		/*
-		 * The OS doesn't seem to allow more than 10 words of
-		 * parameters (yay!).	So we shouldn't be here.
-		 */
-		warn("More than 10 words (%d) of arguments!\n", nargs);
-		break;
-	case 10:
-	case 9:
-	case 8:
-	case 7:
-		/*
-		 * If there are 7-10 words of arguments, they are placed
-		 * on the stack, as is normal for other processors.
-		 * The fall-through for all of these is deliberate!!!
-		 */
+	for (i = 0; i < narg && reg < 6; i++, reg++)
+		cs->args[i] = regs.r_out[reg];
+	if (narg > i) {
 		iorequest.piod_op = PIOD_READ_D;
 		iorequest.piod_offs = (void *)(regs.r_out[6] + SPOFF +
 		    offsetof(struct frame, fr_pad[6]));
-		iorequest.piod_addr = &fsc->args[6];
-		iorequest.piod_len = (nargs - 6) * sizeof(fsc->args[0]);
+		iorequest.piod_addr = &cs->args[i];
+		iorequest.piod_len = (narg - i) * sizeof(cs->args[0]);
 		ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
 		if (iorequest.piod_len == 0)
-			return;
-	case 6:	fsc->args[5] = regs.r_out[5];
-	case 5:	fsc->args[4] = regs.r_out[4];
-	case 4:	fsc->args[3] = regs.r_out[3];
-	case 3:	fsc->args[2] = regs.r_out[2];
-	case 2:	fsc->args[1] = regs.r_out[1];
-	case 1:	fsc->args[0] = regs.r_out[0];
-	case 0:
-		break;
+			return (-1);
 	}
 
-	if (indir)
-		memmove(&fsc->args[0], &fsc->args[1], (nargs - 1) *
-		    sizeof(fsc->args[0]));
-
-	sc = get_syscall(fsc->name);
-	if (sc)
-		fsc->nargs = sc->nargs;
-	else {
-#if DEBUG
-		fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
-		    "args to %d\n", fsc->name, nargs);
-#endif
-		fsc->nargs = nargs;
-	}
-
-	fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
-	fsc->sc = sc;
-
-	/*
-	 * At this point, we set up the system call arguments.
-	 * We ignore any OUT ones, however -- those are arguments that
-	 * are set by the system call, and so are probably meaningless
-	 * now.	This doesn't currently support arguments that are
-	 * passed in *and* out, however.
-	 */
-
-	if (fsc->name) {
-#if DEBUG
-		fprintf(stderr, "syscall %s(", fsc->name);
-#endif
-		for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
-			fprintf(stderr, "0x%x%s", sc ?
-			    fsc->args[sc->args[i].offset] : fsc->args[i],
-			    i < (fsc->nargs - 1) ? "," : "");
-#endif
-			if (sc && !(sc->args[i].type & OUT)) {
-				fsc->s_args[i] = print_arg(&sc->args[i],
-				    fsc->args, 0, trussinfo);
-			}
-		}
-#if DEBUG
-		fprintf(stderr, ")\n");
-#endif
-	}
-
-#if DEBUG
-	fprintf(trussinfo->outfile, "\n");
-#endif
-
-	if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0)) {
-		/*
-		 * XXX
-		 * This could be done in a more general
-		 * manner but it still wouldn't be very pretty.
-		 */
-		if (strcmp(fsc->name, "execve") == 0) {
-			if ((trussinfo->flags & EXECVEARGS) == 0) {
-				if (fsc->s_args[1]) {
-					free(fsc->s_args[1]);
-					fsc->s_args[1] = NULL;
-				}
-			}
-			if ((trussinfo->flags & EXECVEENVS) == 0) {
-				if (fsc->s_args[2]) {
-					free(fsc->s_args[2]);
-					fsc->s_args[2] = NULL;
-				}
-			}
-		}
-	}
-	trussinfo->curthread->fsc = fsc;
+	return (0);
 }
 
-/*
- * And when the system call is done, we handle it here.
- * Currently, no attempt is made to ensure that the system calls
- * match -- this needs to be fixed (and is, in fact, why S_SCX includes
- * the system call number instead of, say, an error status).
- */
-
-long
-sparc64_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
+static int
+sparc64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp)
 {
 	struct reg regs;
-	struct freebsd_syscall *fsc;
-	struct syscall *sc;
 	lwpid_t tid;
-	long retval;
-	int errorp, i;
 
-	if (trussinfo->curthread->fsc == NULL)
-		return (-1);
-
 	tid = trussinfo->curthread->tid;
-
 	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
-		fprintf(trussinfo->outfile, "\n");
+		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
 		return (-1);
 	}
 
-	retval = regs.r_out[0];
-	errorp = !!(regs.r_tstate & TSTATE_XCC_C);
+	retval[0] = regs.r_out[0];
+	retval[1] = regs.r_out[1];
+	*errorp = !!(regs.r_tstate & TSTATE_XCC_C);
+	return (0);
+}
 
-	/*
-	 * This code, while simpler than the initial versions I used, could
-	 * stand some significant cleaning.
-	 */
+static struct procabi sparc64_fbsd = {
+	"FreeBSD ELF64",
+	syscallnames,
+	nitems(syscallnames),
+	sparc64_fetch_args,
+	sparc64_fetch_retval
+};
 
-	fsc = trussinfo->curthread->fsc;
-	sc = fsc->sc;
-	if (!sc) {
-		for (i = 0; i < fsc->nargs; i++)
-			asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
-	} else {
-		/*
-		 * Here, we only look for arguments that have OUT masked in --
-		 * otherwise, they were handled in the syscall_entry function.
-		 */
-		for (i = 0; i < sc->nargs; i++) {
-			char *temp;
-			if (sc->args[i].type & OUT) {
-				/*
-				 * If an error occurred, then don't bother
-				 * getting the data; it may not be valid.
-				 */
-				if (errorp) {
-					asprintf(&temp, "0x%lx",
-					    fsc->args[sc->args[i].offset]);
-				} else {
-					temp = print_arg(&sc->args[i],
-					    fsc->args, retval, trussinfo);
-				}
-				fsc->s_args[i] = temp;
-			}
-		}
-	}
-
-	if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
-	    strcmp(fsc->name, "exit") == 0))
-		trussinfo->curthread->in_syscall = 1;
-
-	/*
-	 * It would probably be a good idea to merge the error handling,
-	 * but that complicates things considerably.
-	 */
-
-	print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
-	    retval, fsc->sc);
-	free_fsc(fsc);
-
-	return (retval);
-}
+PROCABI(sparc64_fbsd);

Modified: trunk/usr.bin/truss/syscall.h
===================================================================
--- trunk/usr.bin/truss/syscall.h	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/syscall.h	2018-07-04 00:01:33 UTC (rev 11271)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * See i386-fbsd.c for copyright and license terms.
  *
@@ -5,10 +6,12 @@
  * Hex -- values that should be printed in hex (addresses)
  * Octal -- Same as above, but octal
  * Int -- normal integer values (file descriptors, for example)
+ * LongHex -- long value that should be printed in hex
  * Name -- pointer to a NULL-terminated string.
  * BinString -- pointer to an array of chars, printed via strvisx().
  * Ptr -- pointer to some unspecified structure.  Just print as hex for now.
  * Stat -- a pointer to a stat buffer.  Prints a couple fields.
+ * StatFs -- a pointer to a statfs buffer.  Prints a few fields.
  * Ioctl -- an ioctl command.  Woefully limited.
  * Quad -- a double-word value.  e.g., lseek(int, offset_t, int)
  * Signal -- a signal number.  Prints the signal name (SIGxxx)
@@ -32,15 +35,17 @@
  * IN (meaning that the data is passed *into* the system call).
  */
 /*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/usr.bin/truss/syscall.h 298410 2016-04-21 15:25:17Z jhb $
  */
 
-enum Argtype { None = 1, Hex, Octal, Int, Name, Ptr, Stat, Ioctl, Quad,
+enum Argtype { None = 1, Hex, Octal, Int, LongHex, Name, Ptr, Stat, Ioctl, Quad,
 	Signal, Sockaddr, StringArray, Timespec, Timeval, Itimerval, Pollfd,
 	Fd_set, Sigaction, Fcntl, Mprot, Mmapflags, Whence, Readlinkres,
-	Umtx, Sigset, Sigprocmask, Kevent, Sockdomain, Socktype, Open,
+	Umtx, Sigset, Sigprocmask, StatFs, Kevent, Sockdomain, Socktype, Open,
 	Fcntlflag, Rusage, BinString, Shutdown, Resource, Rlimit, Timeval2,
-	Pathconf };
+	Pathconf, Rforkflags, ExitStatus, Waitoptions, Idtype, Procctl,
+	LinuxSockArgs, Umtxop, Atfd, Atflags, Timespec2, Accessmode, Long,
+	Sysarch, ExecArgs, ExecEnv, PipeFds, QuadHex };
 
 #define	ARG_MASK	0xff
 #define	OUT	0x100
@@ -52,9 +57,10 @@
 };
 
 struct syscall {
+	STAILQ_ENTRY(syscall) entries;
 	const char *name;
-	int ret_type;	/* 0, 1, or 2 return values */
-	int nargs;	/* actual number of meaningful arguments */
+	u_int ret_type;	/* 0, 1, or 2 return values */
+	u_int nargs;	/* actual number of meaningful arguments */
 			/* Hopefully, no syscalls with > 10 args */
 	struct syscall_args args[10];
 	struct timespec time; /* Time spent for this call */
@@ -62,9 +68,50 @@
 	int nerror;	/* Number of calls that returned with error */
 };
 
-struct syscall *get_syscall(const char*);
-char *print_arg(struct syscall_args *, unsigned long*, long, struct trussinfo *);
-void print_syscall(struct trussinfo *, const char *, int, char **);
-void print_syscall_ret(struct trussinfo *, const char *, int, char **, int,
-    long, struct syscall *);
+struct syscall *get_syscall(const char *, int nargs);
+char *print_arg(struct syscall_args *, unsigned long*, long *, struct trussinfo *);
+
+/*
+ * Linux Socket defines
+ */
+#define LINUX_SOCKET		1
+#define LINUX_BIND		2
+#define LINUX_CONNECT		3
+#define LINUX_LISTEN		4
+#define LINUX_ACCEPT		5
+#define LINUX_GETSOCKNAME	6
+#define LINUX_GETPEERNAME	7
+#define LINUX_SOCKETPAIR	8
+#define LINUX_SEND		9
+#define LINUX_RECV		10
+#define LINUX_SENDTO		11
+#define LINUX_RECVFROM		12
+#define LINUX_SHUTDOWN		13
+#define LINUX_SETSOCKOPT	14
+#define LINUX_GETSOCKOPT	15
+#define LINUX_SENDMSG		16
+#define LINUX_RECVMSG		17
+
+#define PAD_(t) (sizeof(register_t) <= sizeof(t) ? \
+    0 : sizeof(register_t) - sizeof(t))
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define PADL_(t)	0
+#define PADR_(t)	PAD_(t)
+#else
+#define PADL_(t)	PAD_(t)
+#define PADR_(t)	0
+#endif
+
+typedef int     l_int;
+typedef uint32_t    l_ulong;
+
+struct linux_socketcall_args {
+    char what_l_[PADL_(l_int)]; l_int what; char what_r_[PADR_(l_int)];
+    char args_l_[PADL_(l_ulong)]; l_ulong args; char args_r_[PADR_(l_ulong)];
+};
+
+void init_syscalls(void);
+void print_syscall(struct trussinfo *);
+void print_syscall_ret(struct trussinfo *, int, long *);
 void print_summary(struct trussinfo *trussinfo);

Modified: trunk/usr.bin/truss/syscalls.c
===================================================================
--- trunk/usr.bin/truss/syscalls.c	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/syscalls.c	2018-07-04 00:01:33 UTC (rev 11271)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * Copyright 1997 Sean Eric Fagan
  *
@@ -29,10 +30,8 @@
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-static const char rcsid[] =
-  "$MidnightBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.bin/truss/syscalls.c 304150 2016-08-15 11:54:29Z bdrewery $");
 
 /*
  * This file has routines used to print out system calls and their
@@ -39,21 +38,24 @@
  * arguments.
  */
 
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/ioccom.h>
 #include <sys/mman.h>
-#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/procctl.h>
 #include <sys/ptrace.h>
+#include <sys/resource.h>
 #include <sys/socket.h>
-#include <sys/time.h>
+#include <sys/stat.h>
+#include <machine/atomic.h>
+#include <errno.h>
+#include <sys/umtx.h>
 #include <sys/un.h>
+#include <sys/wait.h>
+#include <machine/sysarch.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
-#include <sys/ioccom.h>
-#include <machine/atomic.h>
-#include <errno.h>
-#include <sys/umtx.h>
-#include <sys/event.h>
-#include <sys/stat.h>
-#include <sys/resource.h>
 
 #include <ctype.h>
 #include <err.h>
@@ -60,6 +62,7 @@
 #include <fcntl.h>
 #include <poll.h>
 #include <signal.h>
+#include <stddef.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -73,7 +76,7 @@
 #include "syscall.h"
 
 /* 64-bit alignment on 32-bit platforms. */
-#ifdef __powerpc__
+#if !defined(__LP64__) && defined(__powerpc__)
 #define	QUAD_ALIGN	1
 #else
 #define	QUAD_ALIGN	0
@@ -89,179 +92,303 @@
 /*
  * This should probably be in its own file, sorted alphabetically.
  */
-struct syscall syscalls[] = {
-	{ .name = "fcntl", .ret_type = 1, .nargs = 3,
-	  .args = { { Int, 0 } , { Fcntl, 1 }, { Fcntlflag | OUT, 2 } } },
-	{ .name = "fork", .ret_type = 1, .nargs = 0 },
-	{ .name = "getegid", .ret_type = 1, .nargs = 0 },
-	{ .name = "geteuid", .ret_type = 1, .nargs = 0 },
-	{ .name = "getgid", .ret_type = 1, .nargs = 0 },
-	{ .name = "getpid", .ret_type = 1, .nargs = 0 },
-	{ .name = "getpgid", .ret_type = 1, .nargs = 1,
-	  .args = { { Int, 0 } } },
-	{ .name = "getpgrp", .ret_type = 1, .nargs = 0 },
-	{ .name = "getppid", .ret_type = 1, .nargs = 0 },
-	{ .name = "getsid", .ret_type = 1, .nargs = 1,
-	  .args = { { Int, 0 } } },
-	{ .name = "getuid", .ret_type = 1, .nargs = 0 },
-	{ .name = "readlink", .ret_type = 1, .nargs = 3,
-	  .args = { { Name, 0 } , { Readlinkres | OUT, 1 }, { Int, 2 } } },
-	{ .name = "lseek", .ret_type = 2, .nargs = 3,
-	  .args = { { Int, 0 }, { Quad, 1 + QUAD_ALIGN }, { Whence, 1 + QUAD_SLOTS + QUAD_ALIGN } } },
-	{ .name = "linux_lseek", .ret_type = 2, .nargs = 3,
-	  .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
-	{ .name = "mmap", .ret_type = 2, .nargs = 6,
-	  .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 }, { Mmapflags, 3 }, { Int, 4 }, { Quad, 5 + QUAD_ALIGN } } },
-	{ .name = "mprotect", .ret_type = 1, .nargs = 3,
-	  .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 } } },
-	{ .name = "open", .ret_type = 1, .nargs = 3,
-	  .args = { { Name | IN, 0 } , { Open, 1 }, { Octal, 2 } } },
-	{ .name = "mkdir", .ret_type = 1, .nargs = 2,
-	  .args = { { Name, 0 } , { Octal, 1 } } },
-	{ .name = "linux_open", .ret_type = 1, .nargs = 3,
-	  .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
-	{ .name = "close", .ret_type = 1, .nargs = 1,
-	  .args = { { Int, 0 } } },
-	{ .name = "link", .ret_type = 0, .nargs = 2,
-	  .args = { { Name, 0 }, { Name, 1 } } },
-	{ .name = "unlink", .ret_type = 0, .nargs = 1,
-	  .args = { { Name, 0 } } },
-	{ .name = "chdir", .ret_type = 0, .nargs = 1,
-	  .args = { { Name, 0 } } },
-	{ .name = "chroot", .ret_type = 0, .nargs = 1,
-	  .args = { { Name, 0 } } },
-	{ .name = "mknod", .ret_type = 0, .nargs = 3,
-	  .args = { { Name, 0 }, { Octal, 1 }, { Int, 3 } } },
-	{ .name = "chmod", .ret_type = 0, .nargs = 2,
-	  .args = { { Name, 0 }, { Octal, 1 } } },
-	{ .name = "chown", .ret_type = 0, .nargs = 3,
-	  .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
-	{ .name = "mount", .ret_type = 0, .nargs = 4,
-	  .args = { { Name, 0 }, { Name, 1 }, { Int, 2 }, { Ptr, 3 } } },
-	{ .name = "umount", .ret_type = 0, .nargs = 2,
-	  .args = { { Name, 0 }, { Int, 2 } } },
-	{ .name = "fstat", .ret_type = 1, .nargs = 2,
-	  .args = { { Int, 0 }, { Stat | OUT , 1 } } },
-	{ .name = "stat", .ret_type = 1, .nargs = 2,
-	  .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
-	{ .name = "lstat", .ret_type = 1, .nargs = 2,
-	  .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
-	{ .name = "linux_newstat", .ret_type = 1, .nargs = 2,
-	  .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
-	{ .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
-	  .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
-	{ .name = "write", .ret_type = 1, .nargs = 3,
-	  .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 } } },
-	{ .name = "ioctl", .ret_type = 1, .nargs = 3,
-	  .args = { { Int, 0 }, { Ioctl, 1 }, { Hex, 2 } } },
-	{ .name = "break", .ret_type = 1, .nargs = 1,
-	  .args = { { Ptr, 0 } } },
-	{ .name = "exit", .ret_type = 0, .nargs = 1,
-	  .args = { { Hex, 0 } } },
-	{ .name = "access", .ret_type = 1, .nargs = 2,
-	  .args = { { Name | IN, 0 }, { Int, 1 } } },
-	{ .name = "sigaction", .ret_type = 1, .nargs = 3,
-	  .args = { { Signal, 0 }, { Sigaction | IN, 1 }, { Sigaction | OUT, 2 } } },
+static struct syscall decoded_syscalls[] = {
+	/* Native ABI */
+	{ .name = "__getcwd", .ret_type = 1, .nargs = 2,
+	  .args = { { Name | OUT, 0 }, { Int, 1 } } },
+	{ .name = "_umtx_lock", .ret_type = 1, .nargs = 1,
+	  .args = { { Umtx, 0 } } },
+	{ .name = "_umtx_op", .ret_type = 1, .nargs = 5,
+	  .args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 },
+		    { Ptr, 4 } } },
+	{ .name = "_umtx_unlock", .ret_type = 1, .nargs = 1,
+	  .args = { { Umtx, 0 } } },
 	{ .name = "accept", .ret_type = 1, .nargs = 3,
 	  .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
+	{ .name = "access", .ret_type = 1, .nargs = 2,
+	  .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
 	{ .name = "bind", .ret_type = 1, .nargs = 3,
 	  .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
+	{ .name = "bindat", .ret_type = 1, .nargs = 4,
+	  .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
+		    { Int, 3 } } },
+	{ .name = "break", .ret_type = 1, .nargs = 1,
+	  .args = { { Ptr, 0 } } },
+	{ .name = "chdir", .ret_type = 1, .nargs = 1,
+	  .args = { { Name, 0 } } },
+	{ .name = "chflags", .ret_type = 1, .nargs = 2,
+	  .args = { { Name | IN, 0 }, { Hex, 1 } } },
+	{ .name = "chmod", .ret_type = 1, .nargs = 2,
+	  .args = { { Name, 0 }, { Octal, 1 } } },
+	{ .name = "chown", .ret_type = 1, .nargs = 3,
+	  .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
+	{ .name = "chroot", .ret_type = 1, .nargs = 1,
+	  .args = { { Name, 0 } } },
+	{ .name = "clock_gettime", .ret_type = 1, .nargs = 2,
+	  .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
+	{ .name = "close", .ret_type = 1, .nargs = 1,
+	  .args = { { Int, 0 } } },
 	{ .name = "connect", .ret_type = 1, .nargs = 3,
 	  .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
+	{ .name = "connectat", .ret_type = 1, .nargs = 4,
+	  .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
+		    { Int, 3 } } },
+	{ .name = "eaccess", .ret_type = 1, .nargs = 2,
+	  .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
+	{ .name = "execve", .ret_type = 1, .nargs = 3,
+	  .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
+		    { ExecEnv | IN, 2 } } },
+	{ .name = "exit", .ret_type = 0, .nargs = 1,
+	  .args = { { Hex, 0 } } },
+	{ .name = "faccessat", .ret_type = 1, .nargs = 4,
+	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Accessmode, 2 },
+		    { Atflags, 3 } } },
+	{ .name = "fchmod", .ret_type = 1, .nargs = 2,
+	  .args = { { Int, 0 }, { Octal, 1 } } },
+	{ .name = "fchmodat", .ret_type = 1, .nargs = 4,
+	  .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } },
+	{ .name = "fchown", .ret_type = 1, .nargs = 3,
+	  .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
+	{ .name = "fchownat", .ret_type = 1, .nargs = 5,
+	  .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 },
+		    { Atflags, 4 } } },
+	{ .name = "fcntl", .ret_type = 1, .nargs = 3,
+	  .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } },
+	{ .name = "fstat", .ret_type = 1, .nargs = 2,
+	  .args = { { Int, 0 }, { Stat | OUT, 1 } } },
+	{ .name = "fstatat", .ret_type = 1, .nargs = 4,
+	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat | OUT, 2 },
+		    { Atflags, 3 } } },
+	{ .name = "fstatfs", .ret_type = 1, .nargs = 2,
+	  .args = { { Int, 0 }, { StatFs | OUT, 1 } } },
+	{ .name = "ftruncate", .ret_type = 1, .nargs = 2,
+	  .args = { { Int | IN, 0 }, { QuadHex | IN, 1 + QUAD_ALIGN } } },
+	{ .name = "futimens", .ret_type = 1, .nargs = 2,
+	  .args = { { Int, 0 }, { Timespec2 | IN, 1 } } },
+	{ .name = "futimes", .ret_type = 1, .nargs = 2,
+	  .args = { { Int, 0 }, { Timeval2 | IN, 1 } } },
+	{ .name = "futimesat", .ret_type = 1, .nargs = 3,
+	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timeval2 | IN, 2 } } },
+	{ .name = "getitimer", .ret_type = 1, .nargs = 2,
+	  .args = { { Int, 0 }, { Itimerval | OUT, 2 } } },
 	{ .name = "getpeername", .ret_type = 1, .nargs = 3,
 	  .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
+	{ .name = "getpgid", .ret_type = 1, .nargs = 1,
+	  .args = { { Int, 0 } } },
+	{ .name = "getrlimit", .ret_type = 1, .nargs = 2,
+	  .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } },
+	{ .name = "getrusage", .ret_type = 1, .nargs = 2,
+	  .args = { { Int, 0 }, { Rusage | OUT, 1 } } },
+	{ .name = "getsid", .ret_type = 1, .nargs = 1,
+	  .args = { { Int, 0 } } },
 	{ .name = "getsockname", .ret_type = 1, .nargs = 3,
 	  .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
-	{ .name = "recvfrom", .ret_type = 1, .nargs = 6,
-	  .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, { Hex, 3 }, { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } },
-	{ .name = "sendto", .ret_type = 1, .nargs = 6,
-	  .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, { Hex, 3 }, { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } },
-	{ .name = "execve", .ret_type = 1, .nargs = 3,
-	  .args = { { Name | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } },
-	{ .name = "linux_execve", .ret_type = 1, .nargs = 3,
-	  .args = { { Name | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } },
-	{ .name = "kldload", .ret_type = 0, .nargs = 1,
+	{ .name = "gettimeofday", .ret_type = 1, .nargs = 2,
+	  .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } },
+	{ .name = "ioctl", .ret_type = 1, .nargs = 3,
+	  .args = { { Int, 0 }, { Ioctl, 1 }, { Hex, 2 } } },
+	{ .name = "kevent", .ret_type = 1, .nargs = 6,
+	  .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 },
+		    { Int, 4 }, { Timespec, 5 } } },
+	{ .name = "kill", .ret_type = 1, .nargs = 2,
+	  .args = { { Int | IN, 0 }, { Signal | IN, 1 } } },
+	{ .name = "kldfind", .ret_type = 1, .nargs = 1,
 	  .args = { { Name | IN, 0 } } },
-	{ .name = "kldunload", .ret_type = 0, .nargs = 1,
+	{ .name = "kldfirstmod", .ret_type = 1, .nargs = 1,
 	  .args = { { Int, 0 } } },
-	{ .name = "kldfind", .ret_type = 0, .nargs = 1,
+	{ .name = "kldload", .ret_type = 1, .nargs = 1,
 	  .args = { { Name | IN, 0 } } },
-	{ .name = "kldnext", .ret_type = 0, .nargs = 1,
+	{ .name = "kldnext", .ret_type = 1, .nargs = 1,
 	  .args = { { Int, 0 } } },
-	{ .name = "kldstat", .ret_type = 0, .nargs = 2,
+	{ .name = "kldstat", .ret_type = 1, .nargs = 2,
 	  .args = { { Int, 0 }, { Ptr, 1 } } },
-	{ .name = "kldfirstmod", .ret_type = 0, .nargs = 1,
+	{ .name = "kldunload", .ret_type = 1, .nargs = 1,
 	  .args = { { Int, 0 } } },
-	{ .name = "nanosleep", .ret_type = 0, .nargs = 1,
-	  .args = { { Timespec, 0 } } },
-	{ .name = "select", .ret_type = 1, .nargs = 5,
-	  .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 }, { Timeval, 4 } } },
-	{ .name = "poll", .ret_type = 1, .nargs = 3,
-	  .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } },
-	{ .name = "gettimeofday", .ret_type = 1, .nargs = 2,
-	  .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } },
-	{ .name = "clock_gettime", .ret_type = 1, .nargs = 2,
-	  .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
-	{ .name = "getitimer", .ret_type = 1, .nargs = 2,
-	  .args = { { Int, 0 }, { Itimerval | OUT, 2 } } },
-	{ .name = "setitimer", .ret_type = 1, .nargs = 3,
-	  .args = { { Int, 0 }, { Itimerval, 1 } , { Itimerval | OUT, 2 } } },
 	{ .name = "kse_release", .ret_type = 0, .nargs = 1,
 	  .args = { { Timespec, 0 } } },
-	{ .name = "kevent", .ret_type = 0, .nargs = 6,
-	  .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 }, { Int, 4 }, { Timespec, 5 } } },
-	{ .name = "_umtx_lock", .ret_type = 0, .nargs = 1,
-	  .args = { { Umtx, 0 } } },
-	{ .name = "_umtx_unlock", .ret_type = 0, .nargs = 1,
-	  .args = { { Umtx, 0 } } },
-	{ .name = "sigprocmask", .ret_type = 0, .nargs = 3,
-	  .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } },
-	{ .name = "unmount", .ret_type = 1, .nargs = 2,
-	  .args = { { Name, 0 }, { Int, 1 } } },
-	{ .name = "socket", .ret_type = 1, .nargs = 3,
-	  .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Int, 2 } } },
-	{ .name = "getrusage", .ret_type = 1, .nargs = 2,
-	  .args = { { Int, 0 }, { Rusage | OUT, 1 } } },
-	{ .name = "__getcwd", .ret_type = 1, .nargs = 2,
-	  .args = { { Name | OUT, 0 }, { Int, 1 } } },
-	{ .name = "shutdown", .ret_type = 1, .nargs = 2,
-	  .args = { { Int, 0 }, { Shutdown, 1 } } },
-	{ .name = "getrlimit", .ret_type = 1, .nargs = 2,
-	  .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } },
-	{ .name = "setrlimit", .ret_type = 1, .nargs = 2,
-	  .args = { { Resource, 0 }, { Rlimit | IN, 1 } } },
-	{ .name = "utimes", .ret_type = 1, .nargs = 2,
-	  .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
+	{ .name = "lchflags", .ret_type = 1, .nargs = 2,
+	  .args = { { Name | IN, 0 }, { Hex, 1 } } },
+	{ .name = "lchmod", .ret_type = 1, .nargs = 2,
+	  .args = { { Name, 0 }, { Octal, 1 } } },
+	{ .name = "lchown", .ret_type = 1, .nargs = 3,
+	  .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
+	{ .name = "link", .ret_type = 1, .nargs = 2,
+	  .args = { { Name, 0 }, { Name, 1 } } },
+	{ .name = "linkat", .ret_type = 1, .nargs = 5,
+	  .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 },
+		    { Atflags, 4 } } },
+	{ .name = "lseek", .ret_type = 2, .nargs = 3,
+	  .args = { { Int, 0 }, { QuadHex, 1 + QUAD_ALIGN },
+		    { Whence, 1 + QUAD_SLOTS + QUAD_ALIGN } } },
+	{ .name = "lstat", .ret_type = 1, .nargs = 2,
+	  .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
 	{ .name = "lutimes", .ret_type = 1, .nargs = 2,
 	  .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
-	{ .name = "futimes", .ret_type = 1, .nargs = 2,
-	  .args = { { Int, 0 }, { Timeval | IN, 1 } } },
-	{ .name = "chflags", .ret_type = 1, .nargs = 2,
-	  .args = { { Name | IN, 0 }, { Hex, 1 } } },
-	{ .name = "lchflags", .ret_type = 1, .nargs = 2,
-	  .args = { { Name | IN, 0 }, { Hex, 1 } } },
+	{ .name = "mkdir", .ret_type = 1, .nargs = 2,
+	  .args = { { Name, 0 }, { Octal, 1 } } },
+	{ .name = "mkdirat", .ret_type = 1, .nargs = 3,
+	  .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
+	{ .name = "mkfifo", .ret_type = 1, .nargs = 2,
+	  .args = { { Name, 0 }, { Octal, 1 } } },
+	{ .name = "mkfifoat", .ret_type = 1, .nargs = 3,
+	  .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
+	{ .name = "mknod", .ret_type = 1, .nargs = 3,
+	  .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } },
+	{ .name = "mknodat", .ret_type = 1, .nargs = 4,
+	  .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } },
+	{ .name = "mmap", .ret_type = 1, .nargs = 6,
+	  .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 }, { Mmapflags, 3 },
+		    { Int, 4 }, { QuadHex, 5 + QUAD_ALIGN } } },
+	{ .name = "modfind", .ret_type = 1, .nargs = 1,
+	  .args = { { Name | IN, 0 } } },
+	{ .name = "mount", .ret_type = 1, .nargs = 4,
+	  .args = { { Name, 0 }, { Name, 1 }, { Int, 2 }, { Ptr, 3 } } },
+	{ .name = "mprotect", .ret_type = 1, .nargs = 3,
+	  .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 } } },
+	{ .name = "munmap", .ret_type = 1, .nargs = 2,
+	  .args = { { Ptr, 0 }, { Int, 1 } } },
+	{ .name = "nanosleep", .ret_type = 1, .nargs = 1,
+	  .args = { { Timespec, 0 } } },
+	{ .name = "open", .ret_type = 1, .nargs = 3,
+	  .args = { { Name | IN, 0 }, { Open, 1 }, { Octal, 2 } } },
+	{ .name = "openat", .ret_type = 1, .nargs = 4,
+	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Open, 2 },
+		    { Octal, 3 } } },
 	{ .name = "pathconf", .ret_type = 1, .nargs = 2,
 	  .args = { { Name | IN, 0 }, { Pathconf, 1 } } },
 	{ .name = "pipe", .ret_type = 1, .nargs = 1,
-	  .args = { { Ptr, 0 } } },
-	{ .name = "truncate", .ret_type = 1, .nargs = 3,
-	  .args = { { Name | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 } } },
-	{ .name = "ftruncate", .ret_type = 1, .nargs = 3,
-	  .args = { { Int | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 } } },
-	{ .name = "kill", .ret_type = 1, .nargs = 2,
-	  .args = { { Int | IN, 0 }, { Signal | IN, 1 } } },
-	{ .name = "munmap", .ret_type = 1, .nargs = 2,
-	  .args = { { Ptr, 0 }, { Int, 1 } } },
+	  .args = { { PipeFds | OUT, 0 } } },
+	{ .name = "pipe2", .ret_type = 1, .nargs = 2,
+	  .args = { { Ptr, 0 }, { Open, 1 } } },
+	{ .name = "poll", .ret_type = 1, .nargs = 3,
+	  .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } },
+	{ .name = "posix_openpt", .ret_type = 1, .nargs = 1,
+	  .args = { { Open, 0 } } },
+	{ .name = "procctl", .ret_type = 1, .nargs = 4,
+	  .args = { { Idtype, 0 }, { Quad, 1 + QUAD_ALIGN },
+		    { Procctl, 1 + QUAD_ALIGN + QUAD_SLOTS },
+		    { Ptr, 2 + QUAD_ALIGN + QUAD_SLOTS } } },
 	{ .name = "read", .ret_type = 1, .nargs = 3,
 	  .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 } } },
+	{ .name = "readlink", .ret_type = 1, .nargs = 3,
+	  .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Int, 2 } } },
+	{ .name = "readlinkat", .ret_type = 1, .nargs = 4,
+	  .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 },
+		    { Int, 3 } } },
+	{ .name = "recvfrom", .ret_type = 1, .nargs = 6,
+	  .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, { Hex, 3 },
+		    { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } },
 	{ .name = "rename", .ret_type = 1, .nargs = 2,
-	  .args = { { Name , 0 } , { Name, 1 } } },
+	  .args = { { Name, 0 }, { Name, 1 } } },
+	{ .name = "renameat", .ret_type = 1, .nargs = 4,
+	  .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } },
+	{ .name = "rfork", .ret_type = 1, .nargs = 1,
+	  .args = { { Rforkflags, 0 } } },
+	{ .name = "rmdir", .ret_type = 1, .nargs = 1,
+	  .args = { { Name, 0 } } },
+	{ .name = "select", .ret_type = 1, .nargs = 5,
+	  .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
+		    { Timeval, 4 } } },
+	{ .name = "sendto", .ret_type = 1, .nargs = 6,
+	  .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, { Hex, 3 },
+		    { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } },
+	{ .name = "setitimer", .ret_type = 1, .nargs = 3,
+	  .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } },
+	{ .name = "setrlimit", .ret_type = 1, .nargs = 2,
+	  .args = { { Resource, 0 }, { Rlimit | IN, 1 } } },
+	{ .name = "shutdown", .ret_type = 1, .nargs = 2,
+	  .args = { { Int, 0 }, { Shutdown, 1 } } },
+	{ .name = "sigaction", .ret_type = 1, .nargs = 3,
+	  .args = { { Signal, 0 }, { Sigaction | IN, 1 },
+		    { Sigaction | OUT, 2 } } },
+	{ .name = "sigpending", .ret_type = 1, .nargs = 1,
+	  .args = { { Sigset | OUT, 0 } } },
+	{ .name = "sigprocmask", .ret_type = 1, .nargs = 3,
+	  .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } },
+	{ .name = "sigqueue", .ret_type = 1, .nargs = 3,
+	  .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } },
+	{ .name = "sigreturn", .ret_type = 1, .nargs = 1,
+	  .args = { { Ptr, 0 } } },
+	{ .name = "sigsuspend", .ret_type = 1, .nargs = 1,
+	  .args = { { Sigset | IN, 0 } } },
+	{ .name = "sigtimedwait", .ret_type = 1, .nargs = 3,
+	  .args = { { Sigset | IN, 0 }, { Ptr, 1 }, { Timespec | IN, 2 } } },
+	{ .name = "sigwait", .ret_type = 1, .nargs = 2,
+	  .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
+	{ .name = "sigwaitinfo", .ret_type = 1, .nargs = 2,
+	  .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
+	{ .name = "socket", .ret_type = 1, .nargs = 3,
+	  .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Int, 2 } } },
+	{ .name = "stat", .ret_type = 1, .nargs = 2,
+	  .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
+	{ .name = "statfs", .ret_type = 1, .nargs = 2,
+	  .args = { { Name | IN, 0 }, { StatFs | OUT, 1 } } },
 	{ .name = "symlink", .ret_type = 1, .nargs = 2,
-	  .args = { { Name , 0 } , { Name, 1 } } },
-	{ .name = "posix_openpt", .ret_type = 1, .nargs = 1,
-	  .args = { { Open, 0 } } },
+	  .args = { { Name, 0 }, { Name, 1 } } },
+	{ .name = "symlinkat", .ret_type = 1, .nargs = 3,
+	  .args = { { Name, 0 }, { Atfd, 1 }, { Name, 2 } } },
+	{ .name = "sysarch", .ret_type = 1, .nargs = 2,
+	  .args = { { Sysarch, 0 }, { Ptr, 1 } } },
+	{ .name = "thr_kill", .ret_type = 1, .nargs = 2,
+	  .args = { { Long, 0 }, { Signal, 1 } } },
+	{ .name = "thr_self", .ret_type = 1, .nargs = 1,
+	  .args = { { Ptr, 0 } } },
+	{ .name = "truncate", .ret_type = 1, .nargs = 2,
+	  .args = { { Name | IN, 0 }, { QuadHex | IN, 1 + QUAD_ALIGN } } },
+#if 0
+	/* Does not exist */
+	{ .name = "umount", .ret_type = 1, .nargs = 2,
+	  .args = { { Name, 0 }, { Int, 2 } } },
+#endif
+	{ .name = "unlink", .ret_type = 1, .nargs = 1,
+	  .args = { { Name, 0 } } },
+	{ .name = "unlinkat", .ret_type = 1, .nargs = 3,
+	  .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } },
+	{ .name = "unmount", .ret_type = 1, .nargs = 2,
+	  .args = { { Name, 0 }, { Int, 1 } } },
+	{ .name = "utimensat", .ret_type = 1, .nargs = 4,
+	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timespec2 | IN, 2 },
+		    { Atflags, 3 } } },
+	{ .name = "utimes", .ret_type = 1, .nargs = 2,
+	  .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
+	{ .name = "wait4", .ret_type = 1, .nargs = 4,
+	  .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 },
+		    { Rusage | OUT, 3 } } },
+	{ .name = "wait6", .ret_type = 1, .nargs = 6,
+	  .args = { { Idtype, 0 }, { Quad, 1 + QUAD_ALIGN },
+		    { ExitStatus | OUT, 1 + QUAD_ALIGN + QUAD_SLOTS },
+		    { Waitoptions, 2 + QUAD_ALIGN + QUAD_SLOTS },
+		    { Rusage | OUT, 3 + QUAD_ALIGN + QUAD_SLOTS },
+		    { Ptr, 4 + QUAD_ALIGN + QUAD_SLOTS } } },
+	{ .name = "write", .ret_type = 1, .nargs = 3,
+	  .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 } } },
+
+	/* Linux ABI */
+	{ .name = "linux_access", .ret_type = 1, .nargs = 2,
+	  .args = { { Name, 0 }, { Accessmode, 1 } } },
+	{ .name = "linux_execve", .ret_type = 1, .nargs = 3,
+	  .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
+		    { ExecEnv | IN, 2 } } },
+	{ .name = "linux_lseek", .ret_type = 2, .nargs = 3,
+	  .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
+	{ .name = "linux_mkdir", .ret_type = 1, .nargs = 2,
+	  .args = { { Name | IN, 0 }, { Int, 1 } } },
+	{ .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
+	  .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
+	{ .name = "linux_newstat", .ret_type = 1, .nargs = 2,
+	  .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
+	{ .name = "linux_open", .ret_type = 1, .nargs = 3,
+	  .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
+	{ .name = "linux_readlink", .ret_type = 1, .nargs = 3,
+	  .args = { { Name, 0 }, { Name | OUT, 1 }, { Int, 2 } } },
+	{ .name = "linux_socketcall", .ret_type = 1, .nargs = 2,
+	  .args = { { Int, 0 }, { LinuxSockArgs, 1 } } },
+	{ .name = "linux_stat64", .ret_type = 1, .nargs = 3,
+	  .args = { { Name | IN, 0 }, { Ptr | OUT, 1 }, { Ptr | IN, 1 } } },
+
 	{ .name = 0 },
 };
+static STAILQ_HEAD(, syscall) syscalls;
 
 /* Xlat idea taken from strace */
 struct xlat {
@@ -275,15 +402,40 @@
 static struct xlat kevent_filters[] = {
 	X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE)
 	X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER)
-	X(EVFILT_FS) X(EVFILT_READ) XEND
+	X(EVFILT_FS) X(EVFILT_LIO) X(EVFILT_USER) XEND
 };
 
 static struct xlat kevent_flags[] = {
 	X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT)
-	X(EV_CLEAR) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND
+	X(EV_CLEAR) X(EV_RECEIPT) X(EV_DISPATCH)
+	X(EV_DROP) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND
 };
 
-struct xlat poll_flags[] = {
+static struct xlat kevent_user_ffctrl[] = {
+	X(NOTE_FFNOP) X(NOTE_FFAND) X(NOTE_FFOR) X(NOTE_FFCOPY)
+	XEND
+};
+
+static struct xlat kevent_rdwr_fflags[] = {
+	X(NOTE_LOWAT) XEND
+};
+
+static struct xlat kevent_vnode_fflags[] = {
+	X(NOTE_DELETE) X(NOTE_WRITE) X(NOTE_EXTEND) X(NOTE_ATTRIB)
+	X(NOTE_LINK) X(NOTE_RENAME) X(NOTE_REVOKE) XEND
+};
+
+static struct xlat kevent_proc_fflags[] = {
+	X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_TRACK) X(NOTE_TRACKERR)
+	X(NOTE_CHILD) XEND
+};
+
+static struct xlat kevent_timer_fflags[] = {
+	X(NOTE_SECONDS) X(NOTE_MSECONDS) X(NOTE_USECONDS) X(NOTE_NSECONDS)
+	XEND
+};
+
+static struct xlat poll_flags[] = {
 	X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
 	X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
 	X(POLLWRBAND) X(POLLINIGNEOF) XEND
@@ -293,7 +445,11 @@
 	X(MAP_SHARED) X(MAP_PRIVATE) X(MAP_FIXED) X(MAP_RENAME)
 	X(MAP_NORESERVE) X(MAP_RESERVED0080) X(MAP_RESERVED0100)
 	X(MAP_HASSEMAPHORE) X(MAP_STACK) X(MAP_NOSYNC) X(MAP_ANON)
-	X(MAP_NOCORE) XEND
+	X(MAP_EXCL) X(MAP_NOCORE) X(MAP_PREFAULT_READ)
+#ifdef MAP_32BIT
+	X(MAP_32BIT)
+#endif
+	XEND
 };
 
 static struct xlat mprot_flags[] = {
@@ -301,7 +457,7 @@
 };
 
 static struct xlat whence_arg[] = {
-	X(SEEK_SET) X(SEEK_CUR) X(SEEK_END) XEND
+	X(SEEK_SET) X(SEEK_CUR) X(SEEK_END) X(SEEK_DATA) X(SEEK_HOLE) XEND
 };
 
 static struct xlat sigaction_flags[] = {
@@ -311,7 +467,10 @@
 
 static struct xlat fcntl_arg[] = {
 	X(F_DUPFD) X(F_GETFD) X(F_SETFD) X(F_GETFL) X(F_SETFL)
-	X(F_GETOWN) X(F_SETOWN) X(F_GETLK) X(F_SETLK) X(F_SETLKW) XEND
+	X(F_GETOWN) X(F_SETOWN) X(F_OGETLK) X(F_OSETLK) X(F_OSETLKW)
+	X(F_DUP2FD) X(F_GETLK) X(F_SETLK) X(F_SETLKW) X(F_SETLK_REMOTE)
+	X(F_READAHEAD) X(F_RDAHEAD) X(F_DUPFD_CLOEXEC) X(F_DUP2FD_CLOEXEC)
+	XEND
 };
 
 static struct xlat fcntlfd_arg[] = {
@@ -320,7 +479,7 @@
 
 static struct xlat fcntlfl_arg[] = {
 	X(O_APPEND) X(O_ASYNC) X(O_FSYNC) X(O_NONBLOCK) X(O_NOFOLLOW)
-	X(O_DIRECT) XEND
+	X(FRDAHEAD) X(O_DIRECT) XEND
 };
 
 static struct xlat sockdomain_arg[] = {
@@ -331,7 +490,8 @@
 	X(PF_LINK) X(PF_XTP) X(PF_COIP) X(PF_CNT) X(PF_SIP) X(PF_IPX)
 	X(PF_RTIP) X(PF_PIP) X(PF_ISDN) X(PF_KEY) X(PF_INET6)
 	X(PF_NATM) X(PF_ATM) X(PF_NETGRAPH) X(PF_SLOW) X(PF_SCLUSTER)
-	X(PF_ARP) X(PF_BLUETOOTH) XEND
+	X(PF_ARP) X(PF_BLUETOOTH) X(PF_IEEE80211) X(PF_INET_SDP)
+	X(PF_INET6_SDP) XEND
 };
 
 static struct xlat socktype_arg[] = {
@@ -343,7 +503,8 @@
 	X(O_RDONLY) X(O_WRONLY) X(O_RDWR) X(O_ACCMODE) X(O_NONBLOCK)
 	X(O_APPEND) X(O_SHLOCK) X(O_EXLOCK) X(O_ASYNC) X(O_FSYNC)
 	X(O_NOFOLLOW) X(O_CREAT) X(O_TRUNC) X(O_EXCL) X(O_NOCTTY)
-	X(O_DIRECT) XEND
+	X(O_DIRECT) X(O_DIRECTORY) X(O_EXEC) X(O_TTY_INIT) X(O_CLOEXEC)
+	XEND
 };
 
 static struct xlat shutdown_arg[] = {
@@ -353,7 +514,8 @@
 static struct xlat resource_arg[] = {
 	X(RLIMIT_CPU) X(RLIMIT_FSIZE) X(RLIMIT_DATA) X(RLIMIT_STACK)
 	X(RLIMIT_CORE) X(RLIMIT_RSS) X(RLIMIT_MEMLOCK) X(RLIMIT_NPROC)
-	X(RLIMIT_NOFILE) X(RLIMIT_SBSIZE) X(RLIMIT_VMEM) XEND
+	X(RLIMIT_NOFILE) X(RLIMIT_SBSIZE) X(RLIMIT_VMEM) X(RLIMIT_NPTS)
+	X(RLIMIT_SWAP) XEND
 };
 
 static struct xlat pathconf_arg[] = {
@@ -366,9 +528,77 @@
 	X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN)
 	X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX)
 	X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT)
+	X(_PC_ACL_NFS4) X(_PC_MIN_HOLE_SIZE) XEND
+};
+
+static struct xlat rfork_flags[] = {
+	X(RFFDG) X(RFPROC) X(RFMEM) X(RFNOWAIT) X(RFCFDG) X(RFTHREAD)
+	X(RFSIGSHARE) X(RFLINUXTHPN) X(RFTSIGZMB) X(RFPPWAIT) XEND
+};
+
+static struct xlat wait_options[] = {
+	X(WNOHANG) X(WUNTRACED) X(WCONTINUED) X(WNOWAIT) X(WEXITED)
+	X(WTRAPPED) XEND
+};
+
+static struct xlat idtype_arg[] = {
+	X(P_PID) X(P_PPID) X(P_PGID) X(P_SID) X(P_CID) X(P_UID) X(P_GID)
+	X(P_ALL) X(P_LWPID) X(P_TASKID) X(P_PROJID) X(P_POOLID) X(P_JAILID)
+	X(P_CTID) X(P_CPUID) X(P_PSETID) XEND
+};
+
+static struct xlat procctl_arg[] = {
+	X(PROC_SPROTECT) X(PROC_REAP_ACQUIRE) X(PROC_REAP_RELEASE)
+	X(PROC_REAP_STATUS) X(PROC_REAP_GETPIDS) X(PROC_REAP_KILL)
+	X(PROC_TRACE_CTL) X(PROC_TRACE_STATUS) XEND
+};
+
+static struct xlat umtx_ops[] = {
+	X(UMTX_OP_LOCK) X(UMTX_OP_UNLOCK) X(UMTX_OP_WAIT)
+	X(UMTX_OP_WAKE) X(UMTX_OP_MUTEX_TRYLOCK) X(UMTX_OP_MUTEX_LOCK)
+	X(UMTX_OP_MUTEX_UNLOCK) X(UMTX_OP_SET_CEILING) X(UMTX_OP_CV_WAIT)
+	X(UMTX_OP_CV_SIGNAL) X(UMTX_OP_CV_BROADCAST) X(UMTX_OP_WAIT_UINT)
+	X(UMTX_OP_RW_RDLOCK) X(UMTX_OP_RW_WRLOCK) X(UMTX_OP_RW_UNLOCK)
+	X(UMTX_OP_WAIT_UINT_PRIVATE) X(UMTX_OP_WAKE_PRIVATE)
+	X(UMTX_OP_MUTEX_WAIT) X(UMTX_OP_MUTEX_WAKE) X(UMTX_OP_SEM_WAIT)
+	X(UMTX_OP_SEM_WAKE) X(UMTX_OP_NWAKE_PRIVATE) X(UMTX_OP_MUTEX_WAKE2)
 	XEND
 };
 
+static struct xlat at_flags[] = {
+	X(AT_EACCESS) X(AT_SYMLINK_NOFOLLOW) X(AT_SYMLINK_FOLLOW)
+	X(AT_REMOVEDIR) XEND
+};
+
+static struct xlat access_modes[] = {
+	X(R_OK) X(W_OK) X(X_OK) XEND
+};
+
+static struct xlat sysarch_ops[] = {
+#if defined(__i386__) || defined(__amd64__)
+	X(I386_GET_LDT) X(I386_SET_LDT) X(I386_GET_IOPERM) X(I386_SET_IOPERM)
+	X(I386_VM86) X(I386_GET_FSBASE) X(I386_SET_FSBASE) X(I386_GET_GSBASE)
+	X(I386_SET_GSBASE) X(I386_GET_XFPUSTATE) X(AMD64_GET_FSBASE)
+	X(AMD64_SET_FSBASE) X(AMD64_GET_GSBASE) X(AMD64_SET_GSBASE)
+	X(AMD64_GET_XFPUSTATE)
+#endif
+	XEND
+};
+
+static struct xlat linux_socketcall_ops[] = {
+	X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN)
+	X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME)
+	X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO)
+	X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT)
+	X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG)
+	XEND
+};
+
+static struct xlat sigprocmask_ops[] = {
+	X(SIG_BLOCK) X(SIG_UNBLOCK) X(SIG_SETMASK)
+	XEND
+};
+
 #undef X
 #undef XEND
 
@@ -408,9 +638,11 @@
 	return (lookup(xlat, val, 16));
 }
 
-/* Searches an xlat array containing bitfield values.  Remaining bits
-   set after removing the known ones are printed at the end:
-   IN|0x400 */
+/*
+ * Searches an xlat array containing bitfield values.  Remaining bits
+ * set after removing the known ones are printed at the end:
+ * IN|0x400.
+ */
 static char *
 xlookup_bits(struct xlat *xlat, int val)
 {
@@ -421,8 +653,10 @@
 	rem = val;
 	for (; xlat->str != NULL; xlat++) {
 		if ((xlat->val & rem) == xlat->val) {
-			/* don't print the "all-bits-zero" string unless all
-			   bits are really zero */
+			/*
+			 * Don't print the "all-bits-zero" string unless all
+			 * bits are really zero.
+			 */
 			if (xlat->val == 0 && val != 0)
 				continue;
 			len += sprintf(str + len, "%s|", xlat->str);
@@ -429,7 +663,11 @@
 			rem &= ~(xlat->val);
 		}
 	}
-	/* if we have leftover bits or didn't match anything */
+
+	/*
+	 * If we have leftover bits or didn't match anything, print
+	 * the remainder.
+	 */
 	if (rem || len == 0)
 		len += sprintf(str + len, "0x%x", rem);
 	if (len && str[len - 1] == '|')
@@ -438,33 +676,54 @@
 	return (str);
 }
 
+void
+init_syscalls(void)
+{
+	struct syscall *sc;
+
+	STAILQ_INIT(&syscalls);
+	for (sc = decoded_syscalls; sc->name != NULL; sc++)
+		STAILQ_INSERT_HEAD(&syscalls, sc, entries);
+}
 /*
  * If/when the list gets big, it might be desirable to do it
  * as a hash table or binary search.
  */
-
 struct syscall *
-get_syscall(const char *name)
+get_syscall(const char *name, int nargs)
 {
 	struct syscall *sc;
+	int i;
 
-	sc = syscalls;
 	if (name == NULL)
 		return (NULL);
-	while (sc->name) {
+	STAILQ_FOREACH(sc, &syscalls, entries)
 		if (strcmp(name, sc->name) == 0)
 			return (sc);
-		sc++;
+
+	/* It is unknown.  Add it into the list. */
+#if DEBUG
+	fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name,
+	    nargs);
+#endif
+
+	sc = calloc(1, sizeof(struct syscall));
+	sc->name = strdup(name);
+	sc->ret_type = 1;
+	sc->nargs = nargs;
+	for (i = 0; i < nargs; i++) {
+		sc->args[i].offset = i;
+		/* Treat all unknown arguments as LongHex. */
+		sc->args[i].type = LongHex;
 	}
-	return (NULL);
+	STAILQ_INSERT_HEAD(&syscalls, sc, entries);
+
+	return (sc);
 }
 
 /*
- * get_struct
- *
  * Copy a fixed amount of bytes from the process.
  */
-
 static int
 get_struct(pid_t pid, void *offset, void *buf, int len)
 {
@@ -480,44 +739,55 @@
 }
 
 #define	MAXSIZE		4096
-#define	BLOCKSIZE	1024
+
 /*
- * get_string
  * Copy a string from the process.  Note that it is
  * expected to be a C string, but if max is set, it will
  * only get that much.
  */
-
 static char *
-get_string(pid_t pid, void *offset, int max)
+get_string(pid_t pid, void *addr, int max)
 {
 	struct ptrace_io_desc iorequest;
-	char *buf;
-	int diff, i, size, totalsize;
+	char *buf, *nbuf;
+	size_t offset, size, totalsize;
 
-	diff = 0;
-	totalsize = size = max ? (max + 1) : BLOCKSIZE;
+	offset = 0;
+	if (max)
+		size = max + 1;
+	else {
+		/* Read up to the end of the current page. */
+		size = PAGE_SIZE - ((uintptr_t)addr % PAGE_SIZE);
+		if (size > MAXSIZE)
+			size = MAXSIZE;
+	}
+	totalsize = size;
 	buf = malloc(totalsize);
 	if (buf == NULL)
 		return (NULL);
 	for (;;) {
-		diff = totalsize - size;
 		iorequest.piod_op = PIOD_READ_D;
-		iorequest.piod_offs = (char *)offset + diff;
-		iorequest.piod_addr = buf + diff;
+		iorequest.piod_offs = (char *)addr + offset;
+		iorequest.piod_addr = buf + offset;
 		iorequest.piod_len = size;
 		if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
 			free(buf);
 			return (NULL);
 		}
-		for (i = 0 ; i < size; i++) {
-			if (buf[diff + i] == '\0')
+		if (memchr(buf + offset, '\0', size) != NULL)
+			return (buf);
+		offset += size;
+		if (totalsize < MAXSIZE && max == 0) {
+			size = MAXSIZE - totalsize;
+			if (size > PAGE_SIZE)
+				size = PAGE_SIZE;
+			nbuf = realloc(buf, totalsize + size);
+			if (nbuf == NULL) {
+				buf[totalsize - 1] = '\0';
 				return (buf);
-		}
-		if (totalsize < MAXSIZE - BLOCKSIZE && max == 0) {
-			totalsize += BLOCKSIZE;
-			buf = realloc(buf, totalsize);
-			size = BLOCKSIZE;
+			}
+			buf = nbuf;
+			totalsize += size;
 		} else {
 			buf[totalsize - 1] = '\0';
 			return (buf);
@@ -525,62 +795,139 @@
 	}
 }
 
+static char *
+strsig2(int sig)
+{
+	static char tmp[sizeof(int) * 3 + 1];
+	char *ret;
 
+	ret = strsig(sig);
+	if (ret == NULL) {
+		snprintf(tmp, sizeof(tmp), "%d", sig);
+		ret = tmp;
+	}
+	return (ret);
+}
+
+static void
+print_kevent(FILE *fp, struct kevent *ke, int input)
+{
+
+	switch (ke->filter) {
+	case EVFILT_READ:
+	case EVFILT_WRITE:
+	case EVFILT_VNODE:
+	case EVFILT_PROC:
+	case EVFILT_TIMER:
+		fprintf(fp, "%ju", (uintmax_t)ke->ident);
+		break;
+	case EVFILT_SIGNAL:
+		fputs(strsig2(ke->ident), fp);
+		break;
+	default:
+		fprintf(fp, "%p", (void *)ke->ident);
+	}
+	fprintf(fp, ",%s,%s,", xlookup(kevent_filters, ke->filter),
+	    xlookup_bits(kevent_flags, ke->flags));
+	switch (ke->filter) {
+	case EVFILT_READ:
+	case EVFILT_WRITE:
+		fputs(xlookup_bits(kevent_rdwr_fflags, ke->fflags), fp);
+		break;
+	case EVFILT_VNODE:
+		fputs(xlookup_bits(kevent_vnode_fflags, ke->fflags), fp);
+		break;
+	case EVFILT_PROC:
+		fputs(xlookup_bits(kevent_proc_fflags, ke->fflags), fp);
+		break;
+	case EVFILT_TIMER:
+		fputs(xlookup_bits(kevent_timer_fflags, ke->fflags), fp);
+		break;
+	case EVFILT_USER: {
+		int ctrl, data;
+
+		ctrl = ke->fflags & NOTE_FFCTRLMASK;
+		data = ke->fflags & NOTE_FFLAGSMASK;
+		if (input) {
+			fputs(xlookup(kevent_user_ffctrl, ctrl), fp);
+			if (ke->fflags & NOTE_TRIGGER)
+				fputs("|NOTE_TRIGGER", fp);
+			if (data != 0)
+				fprintf(fp, "|%#x", data);
+		} else {
+			fprintf(fp, "%#x", data);
+		}
+		break;
+	}
+	default:
+		fprintf(fp, "%#x", ke->fflags);
+	}
+	fprintf(fp, ",%p,%p", (void *)ke->data, (void *)ke->udata);
+}
+
 /*
- * print_arg
  * Converts a syscall argument into a string.  Said string is
- * allocated via malloc(), so needs to be free()'d.  The file
- * descriptor is for the process' memory (via /proc), and is used
- * to get any data (where the argument is a pointer).  sc is
+ * allocated via malloc(), so needs to be free()'d.  sc is
  * a pointer to the syscall description (see above); args is
  * an array of all of the system call arguments.
  */
-
 char *
-print_arg(struct syscall_args *sc, unsigned long *args, long retval,
+print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
     struct trussinfo *trussinfo)
 {
+	FILE *fp;
 	char *tmp;
+	size_t tmplen;
 	pid_t pid;
 
-	tmp = NULL;
-	pid = trussinfo->pid;
+	fp = open_memstream(&tmp, &tmplen);
+	pid = trussinfo->curthread->proc->pid;
 	switch (sc->type & ARG_MASK) {
 	case Hex:
-		asprintf(&tmp, "0x%x", (int)args[sc->offset]);
+		fprintf(fp, "0x%x", (int)args[sc->offset]);
 		break;
 	case Octal:
-		asprintf(&tmp, "0%o", (int)args[sc->offset]);
+		fprintf(fp, "0%o", (int)args[sc->offset]);
 		break;
 	case Int:
-		asprintf(&tmp, "%d", (int)args[sc->offset]);
+		fprintf(fp, "%d", (int)args[sc->offset]);
 		break;
+	case LongHex:
+		fprintf(fp, "0x%lx", args[sc->offset]);
+		break;
+	case Long:
+		fprintf(fp, "%ld", args[sc->offset]);
+		break;
 	case Name: {
 		/* NULL-terminated string. */
 		char *tmp2;
+
 		tmp2 = get_string(pid, (void*)args[sc->offset], 0);
-		asprintf(&tmp, "\"%s\"", tmp2);
+		fprintf(fp, "\"%s\"", tmp2);
 		free(tmp2);
 		break;
 	}
 	case BinString: {
-		/* Binary block of data that might have printable characters.
-		   XXX If type|OUT, assume that the length is the syscall's
-		   return value.  Otherwise, assume that the length of the block
-		   is in the next syscall argument. */
+		/*
+		 * Binary block of data that might have printable characters.
+		 * XXX If type|OUT, assume that the length is the syscall's
+		 * return value.  Otherwise, assume that the length of the block
+		 * is in the next syscall argument.
+		 */
 		int max_string = trussinfo->strsize;
-		char tmp2[max_string+1], *tmp3;
+		char tmp2[max_string + 1], *tmp3;
 		int len;
 		int truncated = 0;
 
 		if (sc->type & OUT)
-			len = retval;
+			len = retval[0];
 		else
 			len = args[sc->offset + 1];
 
-		/* Don't print more than max_string characters, to avoid word
-		   wrap.  If we have to truncate put some ... after the string.
-		*/
+		/*
+		 * Don't print more than max_string characters, to avoid word
+		 * wrap.  If we have to truncate put some ... after the string.
+		 */
 		if (len > max_string) {
 			len = max_string;
 			truncated = 1;
@@ -595,84 +942,132 @@
 				len--;
 				truncated = 1;
 			};
-			asprintf(&tmp, "\"%s\"%s", tmp3, truncated ?
+			fprintf(fp, "\"%s\"%s", tmp3, truncated ?
 			    "..." : "");
 			free(tmp3);
 		} else {
-			asprintf(&tmp, "0x%lx", args[sc->offset]);
+			fprintf(fp, "0x%lx", args[sc->offset]);
 		}
 		break;
 	}
+	case ExecArgs:
+	case ExecEnv:
 	case StringArray: {
-		int num, size, i;
-		char *tmp2;
+		uintptr_t addr;
+		union {
+			char *strarray[0];
+			char buf[PAGE_SIZE];
+		} u;
 		char *string;
-		char *strarray[100];	/* XXX This is ugly. */
+		size_t len;
+		u_int first, i;
 
-		if (get_struct(pid, (void *)args[sc->offset],
-		    (void *)&strarray, sizeof(strarray)) == -1)
-			err(1, "get_struct %p", (void *)args[sc->offset]);
-		num = 0;
-		size = 0;
+		/*
+		 * Only parse argv[] and environment arrays from exec calls
+		 * if requested.
+		 */
+		if (((sc->type & ARG_MASK) == ExecArgs &&
+		    (trussinfo->flags & EXECVEARGS) == 0) ||
+		    ((sc->type & ARG_MASK) == ExecEnv &&
+		    (trussinfo->flags & EXECVEENVS) == 0)) {
+			fprintf(fp, "0x%lx", args[sc->offset]);
+			break;
+		}
 
-		/* Find out how large of a buffer we'll need. */
-		while (strarray[num] != NULL) {
-			string = get_string(pid, (void*)strarray[num], 0);
-			size += strlen(string);
-			free(string);
-			num++;
+		/*
+		 * Read a page of pointers at a time.  Punt if the top-level
+		 * pointer is not aligned.  Note that the first read is of
+		 * a partial page.
+		 */
+		addr = args[sc->offset];
+		if (addr % sizeof(char *) != 0) {
+			fprintf(fp, "0x%lx", args[sc->offset]);
+			break;
 		}
-		size += 4 + (num * 4);
-		tmp = (char *)malloc(size);
-		tmp2 = tmp;
 
-		tmp2 += sprintf(tmp2, " [");
-		for (i = 0; i < num; i++) {
-			string = get_string(pid, (void*)strarray[i], 0);
-			tmp2 += sprintf(tmp2, " \"%s\"%c", string,
-			    (i + 1 == num) ? ' ' : ',');
+		len = PAGE_SIZE - (addr & PAGE_MASK);
+		if (get_struct(pid, (void *)addr, u.buf, len) == -1) {
+			fprintf(fp, "0x%lx", args[sc->offset]);
+			break;
+		}
+
+		fputc('[', fp);
+		first = 1;
+		i = 0;
+		while (u.strarray[i] != NULL) {
+			string = get_string(pid, u.strarray[i], 0);
+			fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
 			free(string);
+			first = 0;
+
+			i++;
+			if (i == len / sizeof(char *)) {
+				addr += len;
+				len = PAGE_SIZE;
+				if (get_struct(pid, (void *)addr, u.buf, len) ==
+				    -1) {
+					fprintf(fp, ", <inval>");
+					break;
+				}
+				i = 0;
+			}
 		}
-		tmp2 += sprintf(tmp2, "]");
+		fputs(" ]", fp);
 		break;
 	}
 #ifdef __LP64__
 	case Quad:
-		asprintf(&tmp, "0x%lx", args[sc->offset]);
+		fprintf(fp, "%ld", args[sc->offset]);
 		break;
+	case QuadHex:
+		fprintf(fp, "0x%lx", args[sc->offset]);
+		break;
 #else
-	case Quad: {
+	case Quad:
+	case QuadHex: {
 		unsigned long long ll;
-		ll = *(unsigned long long *)(args + sc->offset);
-		asprintf(&tmp, "0x%llx", ll);
+
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+		ll = (unsigned long long)args[sc->offset + 1] << 32 |
+		    args[sc->offset];
+#else
+		ll = (unsigned long long)args[sc->offset] << 32 |
+		    args[sc->offset + 1];
+#endif
+		if ((sc->type & ARG_MASK) == Quad)
+			fprintf(fp, "%lld", ll);
+		else
+			fprintf(fp, "0x%llx", ll);
 		break;
 	}
 #endif
 	case Ptr:
-		asprintf(&tmp, "0x%lx", args[sc->offset]);
+		fprintf(fp, "0x%lx", args[sc->offset]);
 		break;
 	case Readlinkres: {
 		char *tmp2;
-		if (retval == -1) {
-			tmp = strdup("");
+
+		if (retval[0] == -1)
 			break;
-		}
-		tmp2 = get_string(pid, (void*)args[sc->offset], retval);
-		asprintf(&tmp, "\"%s\"", tmp2);
+		tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]);
+		fprintf(fp, "\"%s\"", tmp2);
 		free(tmp2);
 		break;
 	}
 	case Ioctl: {
-		const char *temp = ioctlname(args[sc->offset]);
+		const char *temp;
+		unsigned long cmd;
+
+		cmd = args[sc->offset];
+		temp = ioctlname(cmd);
 		if (temp)
-			tmp = strdup(temp);
+			fputs(temp, fp);
 		else {
-			unsigned long arg = args[sc->offset];
-			asprintf(&tmp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
-			    arg, arg & IOC_OUT ? "R" : "",
-			    arg & IOC_IN ? "W" : "", IOCGROUP(arg),
-			    isprint(IOCGROUP(arg)) ? (char)IOCGROUP(arg) : '?',
-			    arg & 0xFF, IOCPARM_LEN(arg));
+			fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
+			    cmd, cmd & IOC_OUT ? "R" : "",
+			    cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
+			    isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
+			    cmd & 0xFF, IOCPARM_LEN(cmd));
 		}
 		break;
 	}
@@ -680,55 +1075,103 @@
 		struct umtx umtx;
 		if (get_struct(pid, (void *)args[sc->offset], &umtx,
 		    sizeof(umtx)) != -1)
-			asprintf(&tmp, "{ 0x%lx }", (long)umtx.u_owner);
+			fprintf(fp, "{ 0x%lx }", (long)umtx.u_owner);
 		else
-			asprintf(&tmp, "0x%lx", args[sc->offset]);
+			fprintf(fp, "0x%lx", args[sc->offset]);
 		break;
 	}
 	case Timespec: {
 		struct timespec ts;
+
 		if (get_struct(pid, (void *)args[sc->offset], &ts,
 		    sizeof(ts)) != -1)
-			asprintf(&tmp, "{%ld.%09ld }", (long)ts.tv_sec,
+			fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
 			    ts.tv_nsec);
 		else
-			asprintf(&tmp, "0x%lx", args[sc->offset]);
+			fprintf(fp, "0x%lx", args[sc->offset]);
 		break;
 	}
+	case Timespec2: {
+		struct timespec ts[2];
+		const char *sep;
+		unsigned int i;
+
+		if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts))
+		    != -1) {
+			fputs("{ ", fp);
+			sep = "";
+			for (i = 0; i < nitems(ts); i++) {
+				fputs(sep, fp);
+				sep = ", ";
+				switch (ts[i].tv_nsec) {
+				case UTIME_NOW:
+					fprintf(fp, "UTIME_NOW");
+					break;
+				case UTIME_OMIT:
+					fprintf(fp, "UTIME_OMIT");
+					break;
+				default:
+					fprintf(fp, "%jd.%09ld",
+					    (intmax_t)ts[i].tv_sec,
+					    ts[i].tv_nsec);
+					break;
+				}
+			}
+			fputs(" }", fp);
+		} else
+			fprintf(fp, "0x%lx", args[sc->offset]);
+		break;
+	}
 	case Timeval: {
 		struct timeval tv;
+
 		if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
 		    != -1)
-			asprintf(&tmp, "{%ld.%06ld }", (long)tv.tv_sec,
+			fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
 			    tv.tv_usec);
 		else
-			asprintf(&tmp, "0x%lx", args[sc->offset]);
+			fprintf(fp, "0x%lx", args[sc->offset]);
 		break;
 	}
 	case Timeval2: {
 		struct timeval tv[2];
+
 		if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
 		    != -1)
-			asprintf(&tmp, "{%ld.%06ld, %ld.%06ld }",
-			    (long)tv[0].tv_sec, tv[0].tv_usec,
-			    (long)tv[1].tv_sec, tv[1].tv_usec);
+			fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
+			    (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
+			    (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
 		else
-			asprintf(&tmp, "0x%lx", args[sc->offset]);
+			fprintf(fp, "0x%lx", args[sc->offset]);
 		break;
 	}
 	case Itimerval: {
 		struct itimerval itv;
+
 		if (get_struct(pid, (void *)args[sc->offset], &itv,
 		    sizeof(itv)) != -1)
-			asprintf(&tmp, "{%ld.%06ld, %ld.%06ld }",
-			    (long)itv.it_interval.tv_sec,
+			fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
+			    (intmax_t)itv.it_interval.tv_sec,
 			    itv.it_interval.tv_usec,
-			    (long)itv.it_value.tv_sec,
+			    (intmax_t)itv.it_value.tv_sec,
 			    itv.it_value.tv_usec);
 		else
-			asprintf(&tmp, "0x%lx", args[sc->offset]);
+			fprintf(fp, "0x%lx", args[sc->offset]);
 		break;
 	}
+	case LinuxSockArgs:
+	{
+		struct linux_socketcall_args largs;
+
+		if (get_struct(pid, (void *)args[sc->offset], (void *)&largs,
+		    sizeof(largs)) != -1)
+			fprintf(fp, "{ %s, 0x%lx }",
+			    lookup(linux_socketcall_ops, largs.what, 10),
+			    (long unsigned int)largs.args);
+		else
+			fprintf(fp, "0x%lx", args[sc->offset]);
+		break;
+	}
 	case Pollfd: {
 		/*
 		 * XXX: A Pollfd argument expects the /next/ syscall argument
@@ -736,35 +1179,23 @@
 		 * syscall.
 		 */
 		struct pollfd *pfd;
-		int numfds = args[sc->offset+1];
-		int bytes = sizeof(struct pollfd) * numfds;
-		int i, tmpsize, u, used;
-		const int per_fd = 100;
+		int numfds = args[sc->offset + 1];
+		size_t bytes = sizeof(struct pollfd) * numfds;
+		int i;
 
 		if ((pfd = malloc(bytes)) == NULL)
-			err(1, "Cannot malloc %d bytes for pollfd array",
+			err(1, "Cannot malloc %zu bytes for pollfd array",
 			    bytes);
 		if (get_struct(pid, (void *)args[sc->offset], pfd, bytes)
 		    != -1) {
-			used = 0;
-			tmpsize = 1 + per_fd * numfds + 2;
-			if ((tmp = malloc(tmpsize)) == NULL)
-				err(1, "Cannot alloc %d bytes for poll output",
-				    tmpsize);
-
-			tmp[used++] = '{';
+			fputs("{", fp);
 			for (i = 0; i < numfds; i++) {
-
-				u = snprintf(tmp + used, per_fd, "%s%d/%s",
-				    i > 0 ? " " : "", pfd[i].fd,
+				fprintf(fp, " %d/%s", pfd[i].fd,
 				    xlookup_bits(poll_flags, pfd[i].events));
-				if (u > 0)
-					used += u < per_fd ? u : per_fd;
 			}
-			tmp[used++] = '}';
-			tmp[used++] = '\0';
+			fputs(" }", fp);
 		} else {
-			asprintf(&tmp, "0x%lx", args[sc->offset]);
+			fprintf(fp, "0x%lx", args[sc->offset]);
 		}
 		free(pfd);
 		break;
@@ -777,237 +1208,243 @@
 		 */
 		fd_set *fds;
 		int numfds = args[0];
-		int bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
-		int i, tmpsize, u, used;
-		const int per_fd = 20;
+		size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
+		int i;
 
 		if ((fds = malloc(bytes)) == NULL)
-			err(1, "Cannot malloc %d bytes for fd_set array",
+			err(1, "Cannot malloc %zu bytes for fd_set array",
 			    bytes);
 		if (get_struct(pid, (void *)args[sc->offset], fds, bytes)
 		    != -1) {
-			used = 0;
-			tmpsize = 1 + numfds * per_fd + 2;
-			if ((tmp = malloc(tmpsize)) == NULL)
-				err(1, "Cannot alloc %d bytes for fd_set "
-				    "output", tmpsize);
-
-			tmp[used++] = '{';
+			fputs("{", fp);
 			for (i = 0; i < numfds; i++) {
-				if (FD_ISSET(i, fds)) {
-					u = snprintf(tmp + used, per_fd, "%d ",
-					    i);
-					if (u > 0)
-						used += u < per_fd ? u : per_fd;
-				}
+				if (FD_ISSET(i, fds))
+					fprintf(fp, " %d", i);
 			}
-			if (tmp[used-1] == ' ')
-				used--;
-			tmp[used++] = '}';
-			tmp[used++] = '\0';
+			fputs(" }", fp);
 		} else
-			asprintf(&tmp, "0x%lx", args[sc->offset]);
+			fprintf(fp, "0x%lx", args[sc->offset]);
 		free(fds);
 		break;
 	}
-	case Signal: {
-		long sig;
-
-		sig = args[sc->offset];
-		tmp = strsig(sig);
-		if (tmp == NULL)
-			asprintf(&tmp, "%ld", sig);
+	case Signal:
+		fputs(strsig2(args[sc->offset]), fp);
 		break;
-	}
 	case Sigset: {
 		long sig;
 		sigset_t ss;
-		int i, used;
+		int i, first;
 
 		sig = args[sc->offset];
 		if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
 		    sizeof(ss)) == -1) {
-			asprintf(&tmp, "0x%lx", args[sc->offset]);
+			fprintf(fp, "0x%lx", args[sc->offset]);
 			break;
 		}
-		tmp = malloc(sys_nsig * 8); /* 7 bytes avg per signal name */
-		used = 0;
+		fputs("{ ", fp);
+		first = 1;
 		for (i = 1; i < sys_nsig; i++) {
-			if (sigismember(&ss, i))
-				used += sprintf(tmp + used, "%s|", strsig(i));
+			if (sigismember(&ss, i)) {
+				fprintf(fp, "%s%s", !first ? "|" : "",
+				    strsig(i));
+				first = 0;
+			}
 		}
-		if (used)
-			tmp[used-1] = 0;
-		else
-			strcpy(tmp, "0x0");
+		if (!first)
+			fputc(' ', fp);
+		fputc('}', fp);
 		break;
 	}
 	case Sigprocmask: {
-		switch (args[sc->offset]) {
-#define	S(a)	case a: tmp = strdup(#a); break;
-			S(SIG_BLOCK);
-			S(SIG_UNBLOCK);
-			S(SIG_SETMASK);
-#undef S
-		}
-		if (tmp == NULL)
-			asprintf(&tmp, "0x%lx", args[sc->offset]);
+		fputs(xlookup(sigprocmask_ops, args[sc->offset]), fp);
 		break;
 	}
 	case Fcntlflag: {
-		/* XXX output depends on the value of the previous argument */
-		switch (args[sc->offset-1]) {
+		/* XXX: Output depends on the value of the previous argument. */
+		switch (args[sc->offset - 1]) {
 		case F_SETFD:
-			tmp = strdup(xlookup_bits(fcntlfd_arg,
-			    args[sc->offset]));
+			fputs(xlookup_bits(fcntlfd_arg, args[sc->offset]), fp);
 			break;
 		case F_SETFL:
-			tmp = strdup(xlookup_bits(fcntlfl_arg,
-			    args[sc->offset]));
+			fputs(xlookup_bits(fcntlfl_arg, args[sc->offset]), fp);
 			break;
 		case F_GETFD:
 		case F_GETFL:
 		case F_GETOWN:
-			tmp = strdup("");
 			break;
 		default:
-			asprintf(&tmp, "0x%lx", args[sc->offset]);
+			fprintf(fp, "0x%lx", args[sc->offset]);
 			break;
 		}
 		break;
 	}
 	case Open:
-		tmp = strdup(xlookup_bits(open_flags, args[sc->offset]));
+		fputs(xlookup_bits(open_flags, args[sc->offset]), fp);
 		break;
 	case Fcntl:
-		tmp = strdup(xlookup(fcntl_arg, args[sc->offset]));
+		fputs(xlookup(fcntl_arg, args[sc->offset]), fp);
 		break;
 	case Mprot:
-		tmp = strdup(xlookup_bits(mprot_flags, args[sc->offset]));
+		fputs(xlookup_bits(mprot_flags, args[sc->offset]), fp);
 		break;
-	case Mmapflags:
-		tmp = strdup(xlookup_bits(mmap_flags, args[sc->offset]));
+	case Mmapflags: {
+		int align, flags;
+
+		/*
+		 * MAP_ALIGNED can't be handled by xlookup_bits(), so
+		 * generate that string manually and prepend it to the
+		 * string from xlookup_bits().  Have to be careful to
+		 * avoid outputting MAP_ALIGNED|0 if MAP_ALIGNED is
+		 * the only flag.
+		 */
+		flags = args[sc->offset] & ~MAP_ALIGNMENT_MASK;
+		align = args[sc->offset] & MAP_ALIGNMENT_MASK;
+		if (align != 0) {
+			if (align == MAP_ALIGNED_SUPER)
+				fputs("MAP_ALIGNED_SUPER", fp);
+			else
+				fprintf(fp, "MAP_ALIGNED(%d)",
+				    align >> MAP_ALIGNMENT_SHIFT);
+			if (flags == 0)
+				break;
+			fputc('|', fp);
+		}
+		fputs(xlookup_bits(mmap_flags, flags), fp);
 		break;
+	}
 	case Whence:
-		tmp = strdup(xlookup(whence_arg, args[sc->offset]));
+		fputs(xlookup(whence_arg, args[sc->offset]), fp);
 		break;
 	case Sockdomain:
-		tmp = strdup(xlookup(sockdomain_arg, args[sc->offset]));
+		fputs(xlookup(sockdomain_arg, args[sc->offset]), fp);
 		break;
-	case Socktype:
-		tmp = strdup(xlookup(socktype_arg, args[sc->offset]));
+	case Socktype: {
+		int type, flags;
+
+		flags = args[sc->offset] & (SOCK_CLOEXEC | SOCK_NONBLOCK);
+		type = args[sc->offset] & ~flags;
+		fputs(xlookup(socktype_arg, type), fp);
+		if (flags & SOCK_CLOEXEC)
+			fprintf(fp, "|SOCK_CLOEXEC");
+		if (flags & SOCK_NONBLOCK)
+			fprintf(fp, "|SOCK_NONBLOCK");
 		break;
+	}
 	case Shutdown:
-		tmp = strdup(xlookup(shutdown_arg, args[sc->offset]));
+		fputs(xlookup(shutdown_arg, args[sc->offset]), fp);
 		break;
 	case Resource:
-		tmp = strdup(xlookup(resource_arg, args[sc->offset]));
+		fputs(xlookup(resource_arg, args[sc->offset]), fp);
 		break;
 	case Pathconf:
-		tmp = strdup(xlookup(pathconf_arg, args[sc->offset]));
+		fputs(xlookup(pathconf_arg, args[sc->offset]), fp);
 		break;
+	case Rforkflags:
+		fputs(xlookup_bits(rfork_flags, args[sc->offset]), fp);
+		break;
 	case Sockaddr: {
-		struct sockaddr_storage ss;
 		char addr[64];
 		struct sockaddr_in *lsin;
 		struct sockaddr_in6 *lsin6;
 		struct sockaddr_un *sun;
 		struct sockaddr *sa;
-		char *p;
+		socklen_t len;
 		u_char *q;
-		int i;
 
 		if (args[sc->offset] == 0) {
-			asprintf(&tmp, "NULL");
+			fputs("NULL", fp);
 			break;
 		}
 
-		/* yuck: get ss_len */
-		if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
-		    sizeof(ss.ss_len) + sizeof(ss.ss_family)) == -1)
-			err(1, "get_struct %p", (void *)args[sc->offset]);
 		/*
-		 * If ss_len is 0, then try to guess from the sockaddr type.
-		 * AF_UNIX may be initialized incorrectly, so always frob
-		 * it by using the "right" size.
+		 * Extract the address length from the next argument.  If
+		 * this is an output sockaddr (OUT is set), then the
+		 * next argument is a pointer to a socklen_t.  Otherwise
+		 * the next argument contains a socklen_t by value.
 		 */
-		if (ss.ss_len == 0 || ss.ss_family == AF_UNIX) {
-			switch (ss.ss_family) {
-			case AF_INET:
-				ss.ss_len = sizeof(*lsin);
+		if (sc->type & OUT) {
+			if (get_struct(pid, (void *)args[sc->offset + 1],
+			    &len, sizeof(len)) == -1) {
+				fprintf(fp, "0x%lx", args[sc->offset]);
 				break;
-			case AF_UNIX:
-				ss.ss_len = sizeof(*sun);
-				break;
-			default:
-				/* hurrrr */
-				break;
 			}
+		} else
+			len = args[sc->offset + 1];
+
+		/* If the length is too small, just bail. */
+		if (len < sizeof(*sa)) {
+			fprintf(fp, "0x%lx", args[sc->offset]);
+			break;
 		}
-		if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
-		    ss.ss_len) == -1) {
-			err(2, "get_struct %p", (void *)args[sc->offset]);
+
+		sa = calloc(1, len);
+		if (get_struct(pid, (void *)args[sc->offset], sa, len) == -1) {
+			free(sa);
+			fprintf(fp, "0x%lx", args[sc->offset]);
+			break;
 		}
 
-		switch (ss.ss_family) {
+		switch (sa->sa_family) {
 		case AF_INET:
-			lsin = (struct sockaddr_in *)&ss;
-			inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof addr);
-			asprintf(&tmp, "{ AF_INET %s:%d }", addr,
+			if (len < sizeof(*lsin))
+				goto sockaddr_short;
+			lsin = (struct sockaddr_in *)(void *)sa;
+			inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
+			fprintf(fp, "{ AF_INET %s:%d }", addr,
 			    htons(lsin->sin_port));
 			break;
 		case AF_INET6:
-			lsin6 = (struct sockaddr_in6 *)&ss;
+			if (len < sizeof(*lsin6))
+				goto sockaddr_short;
+			lsin6 = (struct sockaddr_in6 *)(void *)sa;
 			inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
-			    sizeof addr);
-			asprintf(&tmp, "{ AF_INET6 [%s]:%d }", addr,
+			    sizeof(addr));
+			fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
 			    htons(lsin6->sin6_port));
 			break;
 		case AF_UNIX:
-			sun = (struct sockaddr_un *)&ss;
-			asprintf(&tmp, "{ AF_UNIX \"%s\" }", sun->sun_path);
+			sun = (struct sockaddr_un *)sa;
+			fprintf(fp, "{ AF_UNIX \"%.*s\" }",
+			    (int)(len - offsetof(struct sockaddr_un, sun_path)),
+			    sun->sun_path);
 			break;
 		default:
-			sa = (struct sockaddr *)&ss;
-			asprintf(&tmp, "{ sa_len = %d, sa_family = %d, sa_data "
-			    "= {%n%*s } }", (int)sa->sa_len, (int)sa->sa_family,
-			    &i, 6 * (int)(sa->sa_len - ((char *)&sa->sa_data -
-			    (char *)sa)), "");
-			if (tmp != NULL) {
-				p = tmp + i;
-				for (q = (u_char *)&sa->sa_data;
-				    q < (u_char *)sa + sa->sa_len; q++)
-					p += sprintf(p, " %#02x,", *q);
-			}
+		sockaddr_short:
+			fprintf(fp,
+			    "{ sa_len = %d, sa_family = %d, sa_data = {",
+			    (int)sa->sa_len, (int)sa->sa_family);
+			for (q = (u_char *)sa->sa_data;
+			     q < (u_char *)sa + len; q++)
+				fprintf(fp, "%s 0x%02x",
+				    q == (u_char *)sa->sa_data ? "" : ",",
+				    *q);
+			fputs(" } }", fp);
 		}
+		free(sa);
 		break;
 	}
 	case Sigaction: {
 		struct sigaction sa;
-		char *hand;
-		const char *h;
 
 		if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa))
 		    != -1) {
-			asprintf(&hand, "%p", sa.sa_handler);
+			fputs("{ ", fp);
 			if (sa.sa_handler == SIG_DFL)
-				h = "SIG_DFL";
+				fputs("SIG_DFL", fp);
 			else if (sa.sa_handler == SIG_IGN)
-				h = "SIG_IGN";
+				fputs("SIG_IGN", fp);
 			else
-				h = hand;
-
-			asprintf(&tmp, "{ %s %s ss_t }", h,
+				fprintf(fp, "%p", sa.sa_handler);
+			fprintf(fp, " %s ss_t }",
 			    xlookup_bits(sigaction_flags, sa.sa_flags));
-			free(hand);
 		} else
-			asprintf(&tmp, "0x%lx", args[sc->offset]);
+			fprintf(fp, "0x%lx", args[sc->offset]);
 		break;
 	}
 	case Kevent: {
 		/*
-		 * XXX XXX: the size of the array is determined by either the
-		 * next syscall argument, or by the syscall returnvalue,
+		 * XXX XXX: The size of the array is determined by either the
+		 * next syscall argument, or by the syscall return value,
 		 * depending on which argument number we are.  This matches the
 		 * kevent syscall, but luckily that's the only syscall that uses
 		 * them.
@@ -1014,46 +1451,32 @@
 		 */
 		struct kevent *ke;
 		int numevents = -1;
-		int bytes = 0;
-		int i, tmpsize, u, used;
-		const int per_ke = 100;
+		size_t bytes;
+		int i;
 
 		if (sc->offset == 1)
 			numevents = args[sc->offset+1];
-		else if (sc->offset == 3 && retval != -1)
-			numevents = retval;
+		else if (sc->offset == 3 && retval[0] != -1)
+			numevents = retval[0];
 
-		if (numevents >= 0)
+		if (numevents >= 0) {
 			bytes = sizeof(struct kevent) * numevents;
-		if ((ke = malloc(bytes)) == NULL)
-			err(1, "Cannot malloc %d bytes for kevent array",
-			    bytes);
+			if ((ke = malloc(bytes)) == NULL)
+				err(1,
+				    "Cannot malloc %zu bytes for kevent array",
+				    bytes);
+		} else
+			ke = NULL;
 		if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset],
 		    ke, bytes) != -1) {
-			used = 0;
-			tmpsize = 1 + per_ke * numevents + 2;
-			if ((tmp = malloc(tmpsize)) == NULL)
-				err(1, "Cannot alloc %d bytes for kevent "
-				    "output", tmpsize);
-
-			tmp[used++] = '{';
+			fputc('{', fp);
 			for (i = 0; i < numevents; i++) {
-				u = snprintf(tmp + used, per_ke,
-				    "%s%p,%s,%s,%d,%p,%p",
-				    i > 0 ? " " : "",
-				    (void *)ke[i].ident,
-				    xlookup(kevent_filters, ke[i].filter),
-				    xlookup_bits(kevent_flags, ke[i].flags),
-				    ke[i].fflags,
-				    (void *)ke[i].data,
-				    (void *)ke[i].udata);
-				if (u > 0)
-					used += u < per_ke ? u : per_ke;
+				fputc(' ', fp);
+				print_kevent(fp, &ke[i], sc->offset == 1);
 			}
-			tmp[used++] = '}';
-			tmp[used++] = '\0';
+			fputs(" }", fp);
 		} else {
-			asprintf(&tmp, "0x%lx", args[sc->offset]);
+			fprintf(fp, "0x%lx", args[sc->offset]);
 		}
 		free(ke);
 		break;
@@ -1060,89 +1483,167 @@
 	}
 	case Stat: {
 		struct stat st;
+
 		if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
 		    != -1) {
 			char mode[12];
+
 			strmode(st.st_mode, mode);
-			asprintf(&tmp,
-			    "{ mode=%s,inode=%jd,size=%jd,blksize=%ld }", mode,
-			    (intmax_t)st.st_ino, (intmax_t)st.st_size,
+			fprintf(fp,
+			    "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
+			    (uintmax_t)st.st_ino, (intmax_t)st.st_size,
 			    (long)st.st_blksize);
 		} else {
-			asprintf(&tmp, "0x%lx", args[sc->offset]);
+			fprintf(fp, "0x%lx", args[sc->offset]);
 		}
 		break;
 	}
+	case StatFs: {
+		unsigned int i;
+		struct statfs buf;
+
+		if (get_struct(pid, (void *)args[sc->offset], &buf,
+		    sizeof(buf)) != -1) {
+			char fsid[17];
+
+			bzero(fsid, sizeof(fsid));
+			if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) {
+			        for (i = 0; i < sizeof(buf.f_fsid); i++)
+					snprintf(&fsid[i*2],
+					    sizeof(fsid) - (i*2), "%02x",
+					    ((u_char *)&buf.f_fsid)[i]);
+			}
+			fprintf(fp,
+			    "{ fstypename=%s,mntonname=%s,mntfromname=%s,"
+			    "fsid=%s }", buf.f_fstypename, buf.f_mntonname,
+			    buf.f_mntfromname, fsid);
+		} else
+			fprintf(fp, "0x%lx", args[sc->offset]);
+		break;
+	}
+
 	case Rusage: {
 		struct rusage ru;
+
 		if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru))
 		    != -1) {
-			asprintf(&tmp,
-			    "{ u=%ld.%06ld,s=%ld.%06ld,in=%ld,out=%ld }",
-			    (long)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
-			    (long)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
+			fprintf(fp,
+			    "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
+			    (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
+			    (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
 			    ru.ru_inblock, ru.ru_oublock);
 		} else
-			asprintf(&tmp, "0x%lx", args[sc->offset]);
+			fprintf(fp, "0x%lx", args[sc->offset]);
 		break;
 	}
 	case Rlimit: {
 		struct rlimit rl;
+
 		if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl))
 		    != -1) {
-			asprintf(&tmp, "{ cur=%ju,max=%ju }",
+			fprintf(fp, "{ cur=%ju,max=%ju }",
 			    rl.rlim_cur, rl.rlim_max);
 		} else
-			asprintf(&tmp, "0x%lx", args[sc->offset]);
+			fprintf(fp, "0x%lx", args[sc->offset]);
 		break;
 	}
+	case ExitStatus: {
+		int status;
+
+		if (get_struct(pid, (void *)args[sc->offset], &status,
+		    sizeof(status)) != -1) {
+			fputs("{ ", fp);
+			if (WIFCONTINUED(status))
+				fputs("CONTINUED", fp);
+			else if (WIFEXITED(status))
+				fprintf(fp, "EXITED,val=%d",
+				    WEXITSTATUS(status));
+			else if (WIFSIGNALED(status))
+				fprintf(fp, "SIGNALED,sig=%s%s",
+				    strsig2(WTERMSIG(status)),
+				    WCOREDUMP(status) ? ",cored" : "");
+			else
+				fprintf(fp, "STOPPED,sig=%s",
+				    strsig2(WTERMSIG(status)));
+			fputs(" }", fp);
+		} else
+			fprintf(fp, "0x%lx", args[sc->offset]);
+		break;
+	}
+	case Waitoptions:
+		fputs(xlookup_bits(wait_options, args[sc->offset]), fp);
+		break;
+	case Idtype:
+		fputs(xlookup(idtype_arg, args[sc->offset]), fp);
+		break;
+	case Procctl:
+		fputs(xlookup(procctl_arg, args[sc->offset]), fp);
+		break;
+	case Umtxop:
+		fputs(xlookup(umtx_ops, args[sc->offset]), fp);
+		break;
+	case Atfd:
+		if ((int)args[sc->offset] == AT_FDCWD)
+			fputs("AT_FDCWD", fp);
+		else
+			fprintf(fp, "%d", (int)args[sc->offset]);
+		break;
+	case Atflags:
+		fputs(xlookup_bits(at_flags, args[sc->offset]), fp);
+		break;
+	case Accessmode:
+		if (args[sc->offset] == F_OK)
+			fputs("F_OK", fp);
+		else
+			fputs(xlookup_bits(access_modes, args[sc->offset]), fp);
+		break;
+	case Sysarch:
+		fputs(xlookup(sysarch_ops, args[sc->offset]), fp);
+		break;
+	case PipeFds:
+		/*
+		 * The pipe() system call in the kernel returns its
+		 * two file descriptors via return values.  However,
+		 * the interface exposed by libc is that pipe()
+		 * accepts a pointer to an array of descriptors.
+		 * Format the output to match the libc API by printing
+		 * the returned file descriptors as a fake argument.
+		 *
+		 * Overwrite the first retval to signal a successful
+		 * return as well.
+		 */
+		fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]);
+		retval[0] = 0;
+		break;
 	default:
 		errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
 	}
+	fclose(fp);
 	return (tmp);
 }
 
 /*
- * print_syscall
- * Print (to outfile) the system call and its arguments.  Note that
- * nargs is the number of arguments (not the number of words; this is
- * potentially confusing, I know).
+ * Print (to outfile) the system call and its arguments.
  */
-
 void
-print_syscall(struct trussinfo *trussinfo, const char *name, int nargs,
-    char **s_args)
+print_syscall(struct trussinfo *trussinfo)
 {
-	struct timespec timediff;
-	int i, len;
+	struct threadinfo *t;
+	const char *name;
+	char **s_args;
+	int i, len, nargs;
 
-	len = 0;
-	if (trussinfo->flags & FOLLOWFORKS)
-		len += fprintf(trussinfo->outfile, "%5d: ", trussinfo->pid);
+	t = trussinfo->curthread;
 
-	if (name != NULL && (strcmp(name, "execve") == 0 ||
-	    strcmp(name, "exit") == 0)) {
-		clock_gettime(CLOCK_REALTIME, &trussinfo->curthread->after);
-	}
+	name = t->cs.name;
+	nargs = t->cs.nargs;
+	s_args = t->cs.s_args;
 
-	if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
-		timespecsubt(&trussinfo->curthread->after,
-		    &trussinfo->start_time, &timediff);
-		len += fprintf(trussinfo->outfile, "%ld.%09ld ",
-		    (long)timediff.tv_sec, timediff.tv_nsec);
-	}
-
-	if (trussinfo->flags & RELATIVETIMESTAMPS) {
-		timespecsubt(&trussinfo->curthread->after,
-		    &trussinfo->curthread->before, &timediff);
-		len += fprintf(trussinfo->outfile, "%ld.%09ld ",
-		    (long)timediff.tv_sec, timediff.tv_nsec);
-	}
-
+	len = print_line_prefix(trussinfo);
 	len += fprintf(trussinfo->outfile, "%s(", name);
 
 	for (i = 0; i < nargs; i++) {
-		if (s_args[i])
+		if (s_args[i] != NULL)
 			len += fprintf(trussinfo->outfile, "%s", s_args[i]);
 		else
 			len += fprintf(trussinfo->outfile,
@@ -1156,17 +1657,16 @@
 }
 
 void
-print_syscall_ret(struct trussinfo *trussinfo, const char *name, int nargs,
-    char **s_args, int errorp, long retval, struct syscall *sc)
+print_syscall_ret(struct trussinfo *trussinfo, int errorp, long *retval)
 {
 	struct timespec timediff;
+	struct threadinfo *t;
+	struct syscall *sc;
 
+	t = trussinfo->curthread;
+	sc = t->cs.sc;
 	if (trussinfo->flags & COUNTONLY) {
-		if (!sc)
-			return;
-		clock_gettime(CLOCK_REALTIME, &trussinfo->curthread->after);
-		timespecsubt(&trussinfo->curthread->after,
-		    &trussinfo->curthread->before, &timediff);
+		timespecsubt(&t->after, &t->before, &timediff);
 		timespecadd(&sc->time, &timediff, &sc->time);
 		sc->ncalls++;
 		if (errorp)
@@ -1174,20 +1674,27 @@
 		return;
 	}
 
-	print_syscall(trussinfo, name, nargs, s_args);
+	print_syscall(trussinfo);
 	fflush(trussinfo->outfile);
 	if (errorp)
-		fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval,
-		    strerror(retval));
-	else {
-		/*
-		 * Because pipe(2) has a special assembly glue to provide the
-		 * libc API, we have to adjust retval.
-		 */
-		if (name != NULL && strcmp(name, "pipe") == 0)
-			retval = 0;
-		fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval, retval);
+		fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0],
+		    strerror(retval[0]));
+#ifndef __LP64__
+	else if (sc->ret_type == 2) {
+		off_t off;
+
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+		off = (off_t)retval[1] << 32 | retval[0];
+#else
+		off = (off_t)retval[0] << 32 | retval[1];
+#endif
+		fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
+		    (intmax_t)off);
 	}
+#endif
+	else
+		fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0],
+		    retval[0]);
 }
 
 void
@@ -1200,7 +1707,7 @@
 	fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
 	    "syscall", "seconds", "calls", "errors");
 	ncall = nerror = 0;
-	for (sc = syscalls; sc->name != NULL; sc++)
+	STAILQ_FOREACH(sc, &syscalls, entries)
 		if (sc->ncalls) {
 			fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
 			    sc->name, (intmax_t)sc->time.tv_sec,

Modified: trunk/usr.bin/truss/truss.1
===================================================================
--- trunk/usr.bin/truss/truss.1	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/truss.1	2018-07-04 00:01:33 UTC (rev 11271)
@@ -1,6 +1,7 @@
 .\" $MidnightBSD$
+.\" $FreeBSD: stable/10/usr.bin/truss/truss.1 298427 2016-04-21 18:44:53Z jhb $
 .\"
-.Dd May 12, 2009
+.Dd February 23, 2016
 .Dt TRUSS 1
 .Os
 .Sh NAME
@@ -8,12 +9,12 @@
 .Nd trace system calls
 .Sh SYNOPSIS
 .Nm
-.Op Fl facedDS
+.Op Fl facedDHS
 .Op Fl o Ar file
 .Op Fl s Ar strsize
 .Fl p Ar pid
 .Nm
-.Op Fl facedDS
+.Op Fl facedDHS
 .Op Fl o Ar file
 .Op Fl s Ar strsize
 .Ar command Op Ar args
@@ -32,12 +33,16 @@
 .Xr fork 2 ,
 .Xr vfork 2 ,
 etc.
+To distinguish events between processes,
+the process ID
+.Pq PID
+of the process is included in the output of each event.
 .It Fl a
 Show the argument strings that are passed in each
 .Xr execve 2
 system call.
 .It Fl c
-Do not display individual system calls.
+Do not display individual system calls or signals.
 Instead, before exiting, print a summary containing for each system call:
 the total system time used,
 the number of times the call was invoked,
@@ -52,6 +57,8 @@
 .It Fl D
 Include timestamps in the output showing the time elapsed
 since the last recorded event.
+.It Fl H
+Include the thread ID of in the output of each event.
 .It Fl S
 Do not display information about signals received by the process.
 (Normally,


Property changes on: trunk/usr.bin/truss/truss.1
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/usr.bin/truss/truss.h
===================================================================
--- trunk/usr.bin/truss/truss.h	2018-07-03 23:59:39 UTC (rev 11270)
+++ trunk/usr.bin/truss/truss.h	2018-07-04 00:01:33 UTC (rev 11271)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * Copyright 2001 Jamey Wood
  *
@@ -22,9 +23,10 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/usr.bin/truss/truss.h 298427 2016-04-21 18:44:53Z jhb $
  */
 
+#include <sys/linker_set.h>
 #include <sys/queue.h>
 
 #define	FOLLOWFORKS		0x00000001
@@ -34,24 +36,65 @@
 #define	EXECVEARGS		0x00000010
 #define	EXECVEENVS		0x00000020
 #define	COUNTONLY		0x00000040
+#define	DISPLAYTIDS		0x00000080
 
+struct procinfo;
+struct trussinfo;
+
+struct procabi {
+	const char *type;
+	const char **syscallnames;
+	int nsyscalls;
+	int (*fetch_args)(struct trussinfo *, u_int);
+	int (*fetch_retval)(struct trussinfo *, long *, int *);
+};
+
+#define	PROCABI(abi)	DATA_SET(procabi, abi)
+
+/*
+ * This is confusingly named.  It holds per-thread state about the
+ * currently executing system call.  syscall.h defines a struct
+ * syscall that holds metadata used to format system call arguments.
+ *
+ * NB: args[] stores the raw argument values (e.g. from registers)
+ * passed to the system call.  s_args[] stores a string representation
+ * of a system call's arguments.  These do not necessarily map one to
+ * one.  A system call description may omit individual arguments
+ * (padding) or combine adjacent arguments (e.g. when passing an off_t
+ * argument on a 32-bit system).  The nargs member contains the count
+ * of valid pointers in s_args[], not args[].
+ */
+struct current_syscall {
+	struct syscall *sc;
+	const char *name;
+	int number;
+	unsigned long args[10];
+	unsigned int nargs;
+	char *s_args[10];	/* the printable arguments */
+};
+
 struct threadinfo
 {
 	SLIST_ENTRY(threadinfo) entries;
+	struct procinfo *proc;
 	lwpid_t tid;
 	int in_syscall;
-	int in_fork;
-	void *fsc;
+	struct current_syscall cs;
 	struct timespec before;
 	struct timespec after;
 };
 
+struct procinfo {
+	LIST_ENTRY(procinfo) entries;
+	pid_t pid;
+	struct procabi *abi;
+
+	SLIST_HEAD(, threadinfo) threadlist;
+};
+
 struct trussinfo
 {
-	pid_t pid;
 	int flags;
-	int pr_why;
-	int pr_data;
 	int strsize;
 	FILE *outfile;
 
@@ -59,7 +102,7 @@
 
 	struct threadinfo *curthread;
 
-	SLIST_HEAD(, threadinfo) threadlist;
+	LIST_HEAD(, procinfo) proclist;
 };
 
 #define	timespecsubt(tvp, uvp, vvp)					\
@@ -81,11 +124,3 @@
 			(vvp)->tv_nsec -= 1000000000;			\
 		}							\
 	} while (0)
-
-#define	S_NONE	0
-#define	S_SCE	1
-#define	S_SCX	2
-#define	S_EXIT	3
-#define	S_SIG	4
-#define	S_EXEC	5
-#define	S_DETACHED	6



More information about the Midnightbsd-cvs mailing list