diff --git a/sys/amd64/amd64/elf_machdep.c b/sys/amd64/amd64/elf_machdep.c
index 4f6d178..0aea61d 100644
--- a/sys/amd64/amd64/elf_machdep.c
+++ b/sys/amd64/amd64/elf_machdep.c
@@ -84,7 +84,8 @@ static Elf64_Brandinfo freebsd_brand_info = {
 	.interp_path	= "/libexec/ld-elf.so.1",
 	.sysvec		= &elf64_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_ANY,
@@ -99,7 +100,8 @@ static Elf64_Brandinfo freebsd_brand_oinfo = {
 	.interp_path	= "/usr/libexec/ld-elf.so.1",
 	.sysvec		= &elf64_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY,
diff --git a/sys/amd64/linux32/linux.h b/sys/amd64/linux32/linux.h
index e0ffcdf..94372d6 100644
--- a/sys/amd64/linux32/linux.h
+++ b/sys/amd64/linux32/linux.h
@@ -108,6 +108,10 @@ typedef struct {
 
 #define	LINUX_CTL_MAXNAME	10
 
+#define	LINUX_AT_COUNT		16	/* Count of used aux entry types.
+					 * Keep this synchronized with
+					 * elf_linux_fixup() code.
+					 */
 struct l___sysctl_args
 {
 	l_uintptr_t	name;
diff --git a/sys/amd64/linux32/linux32_machdep.c b/sys/amd64/linux32/linux32_machdep.c
index c8869e2..f3b766a 100644
--- a/sys/amd64/linux32/linux32_machdep.c
+++ b/sys/amd64/linux32/linux32_machdep.c
@@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/fcntl.h>
 #include <sys/clock.h>
 #include <sys/imgact.h>
+#include <sys/ktr.h>
 #include <sys/limits.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
@@ -211,10 +212,7 @@ linux_execve(struct thread *td, struct linux_execve_args *args)
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(execve))
-		printf(ARGS(execve, "%s"), path);
-#endif
+	LINUX_CTR(execve);
 
 	error = linux_exec_copyin_args(&eargs, path, UIO_SYSSPACE, args->argp,
 	    args->envp);
@@ -309,6 +307,8 @@ linux_readv(struct thread *td, struct linux_readv_args *uap)
 	struct uio *auio;
 	int error;
 
+	LINUX_CTR(readv);
+
 	error = linux32_copyinuio(uap->iovp, uap->iovcnt, &auio);
 	if (error)
 		return (error);
@@ -323,6 +323,8 @@ linux_writev(struct thread *td, struct linux_writev_args *uap)
 	struct uio *auio;
 	int error;
 
+	LINUX_CTR(writev);
+
 	error = linux32_copyinuio(uap->iovp, uap->iovcnt, &auio);
 	if (error)
 		return (error);
@@ -340,6 +342,8 @@ int
 linux_ipc(struct thread *td, struct linux_ipc_args *args)
 {
 
+	LINUX_CTR1(ipc, "%d", args->what & 0xFFFF);
+
 	switch (args->what & 0xFFFF) {
 	case LINUX_SEMOP: {
 		struct linux_semop_args a;
@@ -461,10 +465,7 @@ linux_old_select(struct thread *td, struct linux_old_select_args *args)
 	struct linux_select_args newsel;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(old_select))
-		printf(ARGS(old_select, "%p"), args->ptr);
-#endif
+	LINUX_CTR(old_select);
 
 	error = copyin(args->ptr, &linux_args, sizeof(linux_args));
 	if (error)
@@ -485,10 +486,7 @@ linux_fork(struct thread *td, struct linux_fork_args *args)
 	struct proc *p2;
 	struct thread *td2;
 
-#ifdef DEBUG
-	if (ldebug(fork))
-		printf(ARGS(fork, ""));
-#endif
+	LINUX_CTR(fork);
 
 	if ((error = fork1(td, RFFDG | RFPROC | RFSTOPPED, 0, &p2)) != 0)
 		return (error);
@@ -524,10 +522,7 @@ linux_vfork(struct thread *td, struct linux_vfork_args *args)
 	struct proc *p2;
 	struct thread *td2;
 
-#ifdef DEBUG
-	if (ldebug(vfork))
-		printf(ARGS(vfork, ""));
-#endif
+	LINUX_CTR(vfork);
 
 	/* Exclude RFPPWAIT */
 	if ((error = fork1(td, RFFDG | RFPROC | RFMEM | RFSTOPPED, 0, &p2)) != 0)
@@ -575,13 +570,9 @@ linux_clone(struct thread *td, struct linux_clone_args *args)
 	int exit_signal;
 	struct linux_emuldata *em;
 
-#ifdef DEBUG
-	if (ldebug(clone)) {
-		printf(ARGS(clone, "flags %x, stack %p, parent tid: %p, "
-		    "child tid: %p"), (unsigned)args->flags,
-		    args->stack, args->parent_tidptr, args->child_tidptr);
-	}
-#endif
+	LINUX_CTR4(clone, "flags %x stack %p parent tid %p child tid %p",
+	    (unsigned)args->flags, args->stack, args->parent_tidptr,
+	    args->child_tidptr);
 
 	exit_signal = args->flags & 0x000000ff;
 	if (LINUX_SIG_VALID(exit_signal)) {
@@ -704,17 +695,16 @@ linux_clone(struct thread *td, struct linux_clone_args *args)
 			a[1] = LINUX_LDT_entry_b(&info);
 
 			memcpy(&sd, &a, sizeof(a));
-#ifdef DEBUG
-			if (ldebug(clone))
-				printf("Segment created in clone with "
-				    "CLONE_SETTLS: lobase: %x, hibase: %x, "
-				    "lolimit: %x, hilimit: %x, type: %i, "
-				    "dpl: %i, p: %i, xx: %i, long: %i, "
-				    "def32: %i, gran: %i\n", sd.sd_lobase,
-				    sd.sd_hibase, sd.sd_lolimit, sd.sd_hilimit,
-				    sd.sd_type, sd.sd_dpl, sd.sd_p, sd.sd_xx,
-				    sd.sd_long, sd.sd_def32, sd.sd_gran);
-#endif
+
+			LINUX_CTR5(clone, "tls segment created with "
+			    "lobase %x hibase %x lolimit %x hilimit %x type %i",
+			    sd.sd_lobase, sd.sd_hibase, sd.sd_lolimit,
+			    sd.sd_hilimit, sd.sd_type);
+			LINUX_CTR5(clone, "tls segment created with "
+			    "dpl %i p %i xx %i long %i def32 %i",
+			    sd.sd_dpl, sd.sd_p, sd.sd_xx,
+			    sd.sd_long, sd.sd_def32);
+
 			td2->td_pcb->pcb_gsbase = (register_t)info.base_addr;
 			td2->td_pcb->pcb_gs32sd = sd;
 			td2->td_pcb->pcb_gs = GSEL(GUGS32_SEL, SEL_UPL);
@@ -722,12 +712,9 @@ linux_clone(struct thread *td, struct linux_clone_args *args)
 		}
 	}
 
-#ifdef DEBUG
-	if (ldebug(clone))
-		printf(LMSG("clone: successful rfork to %d, "
-		    "stack %p sig = %d"), (int)p2->p_pid, args->stack,
-		    exit_signal);
-#endif
+	LINUX_CTR3(clone, "successful rfork to %d stack %p sig = %d",
+	    (int)p2->p_pid, args->stack, exit_signal);
+
 	if (args->flags & LINUX_CLONE_VFORK) {
 	   	PROC_LOCK(p2);
 	   	p2->p_flag |= P_PPWAIT;
@@ -766,12 +753,9 @@ linux_mmap2(struct thread *td, struct linux_mmap2_args *args)
 {
 	struct l_mmap_argv linux_args;
 
-#ifdef DEBUG
-	if (ldebug(mmap2))
-		printf(ARGS(mmap2, "0x%08x, %d, %d, 0x%08x, %d, %d"),
-		    args->addr, args->len, args->prot,
-		    args->flags, args->fd, args->pgoff);
-#endif
+	LINUX_CTR6(mmap2, "0x%08x %d %d 0x%08x %d %d",
+	    args->addr, args->len, args->prot,
+	    args->flags, args->fd, args->pgoff);
 
 	linux_args.addr = PTROUT(args->addr);
 	linux_args.len = args->len;
@@ -793,12 +777,10 @@ linux_mmap(struct thread *td, struct linux_mmap_args *args)
 	if (error)
 		return (error);
 
-#ifdef DEBUG
-	if (ldebug(mmap))
-		printf(ARGS(mmap, "0x%08x, %d, %d, 0x%08x, %d, %d"),
-		    linux_args.addr, linux_args.len, linux_args.prot,
-		    linux_args.flags, linux_args.fd, linux_args.pgoff);
-#endif
+	LINUX_CTR6(mmap, "0x%08x %d %d 0x%08x %d %d",
+	    linux_args.addr, linux_args.len, linux_args.prot,
+	    linux_args.flags, linux_args.fd, linux_args.pgoff);
+
 	if ((linux_args.pgoff % PAGE_SIZE) != 0)
 		return (EINVAL);
 	linux_args.pgoff /= PAGE_SIZE;
@@ -951,19 +933,11 @@ linux_mmap_common(struct thread *td, struct l_mmap_argv *linux_args)
 	}
 	bsd_args.pos = (off_t)linux_args->pgoff * PAGE_SIZE;
 
-#ifdef DEBUG
-	if (ldebug(mmap))
-		printf("-> %s(%p, %d, %d, 0x%08x, %d, 0x%x)\n",
-		    __func__,
-		    (void *)bsd_args.addr, (int)bsd_args.len, bsd_args.prot,
-		    bsd_args.flags, bsd_args.fd, (int)bsd_args.pos);
-#endif
 	error = mmap(td, &bsd_args);
-#ifdef DEBUG
-	if (ldebug(mmap))
-		printf("-> %s() return: 0x%x (0x%08x)\n",
-			__func__, error, (u_int)td->td_retval[0]);
-#endif
+
+	LINUX_CTR2(mmap, "return 0x%x (0x%08x)",
+	    error, (u_int)td->td_retval[0]);
+
 	return (error);
 }
 
@@ -972,6 +946,8 @@ linux_mprotect(struct thread *td, struct linux_mprotect_args *uap)
 {
 	struct mprotect_args bsd_args;
 
+	LINUX_CTR2(mprotect, "addr %p len 0x%x", uap->addr, uap->len);
+
 	bsd_args.addr = uap->addr;
 	bsd_args.len = uap->len;
 	bsd_args.prot = uap->prot;
@@ -985,6 +961,8 @@ linux_iopl(struct thread *td, struct linux_iopl_args *args)
 {
 	int error;
 
+	LINUX_CTR1(iopl, "%d", args->level);
+
 	if (args->level < 0 || args->level > 3)
 		return (EINVAL);
 	if ((error = priv_check(td, PRIV_IO)) != 0)
@@ -1003,10 +981,7 @@ linux_pipe(struct thread *td, struct linux_pipe_args *args)
 	int error;
 	int fildes[2];
 
-#ifdef DEBUG
-	if (ldebug(pipe))
-		printf(ARGS(pipe, "*"));
-#endif
+	LINUX_CTR(pipe);
 
 	error = kern_pipe(td, fildes);
 	if (error)
@@ -1023,11 +998,8 @@ linux_sigaction(struct thread *td, struct linux_sigaction_args *args)
 	l_sigaction_t act, oact;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(sigaction))
-		printf(ARGS(sigaction, "%d, %p, %p"),
-		    args->sig, (void *)args->nsa, (void *)args->osa);
-#endif
+	LINUX_CTR3(sigaction, "%d %p %p", args->sig,
+	    (void *)args->nsa, (void *)args->osa);
 
 	if (args->nsa != NULL) {
 		error = copyin(args->nsa, &osa, sizeof(l_osigaction_t));
@@ -1065,10 +1037,7 @@ linux_sigsuspend(struct thread *td, struct linux_sigsuspend_args *args)
 	sigset_t sigmask;
 	l_sigset_t mask;
 
-#ifdef DEBUG
-	if (ldebug(sigsuspend))
-		printf(ARGS(sigsuspend, "%08lx"), (unsigned long)args->mask);
-#endif
+	LINUX_CTR1(sigsuspend, "0x%08lx", (unsigned long)args->mask);
 
 	LINUX_SIGEMPTYSET(mask);
 	mask.__bits[0] = args->mask;
@@ -1083,11 +1052,8 @@ linux_rt_sigsuspend(struct thread *td, struct linux_rt_sigsuspend_args *uap)
 	sigset_t sigmask;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(rt_sigsuspend))
-		printf(ARGS(rt_sigsuspend, "%p, %d"),
-		    (void *)uap->newset, uap->sigsetsize);
-#endif
+	LINUX_CTR2(rt_sigsuspend, "%p %d",
+	    (void *)uap->newset, uap->sigsetsize);
 
 	if (uap->sigsetsize != sizeof(l_sigset_t))
 		return (EINVAL);
@@ -1106,10 +1072,7 @@ linux_pause(struct thread *td, struct linux_pause_args *args)
 	struct proc *p = td->td_proc;
 	sigset_t sigmask;
 
-#ifdef DEBUG
-	if (ldebug(pause))
-		printf(ARGS(pause, ""));
-#endif
+	LINUX_CTR(pause);
 
 	PROC_LOCK(p);
 	sigmask = td->td_sigmask;
@@ -1124,10 +1087,7 @@ linux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap)
 	l_stack_t lss;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(sigaltstack))
-		printf(ARGS(sigaltstack, "%p, %p"), uap->uss, uap->uoss);
-#endif
+	LINUX_CTR2(sigaltstack, "%p %p", uap->uss, uap->uoss);
 
 	if (uap->uss != NULL) {
 		error = copyin(uap->uss, &lss, sizeof(l_stack_t));
@@ -1155,11 +1115,7 @@ linux_ftruncate64(struct thread *td, struct linux_ftruncate64_args *args)
 {
 	struct ftruncate_args sa;
 
-#ifdef DEBUG
-	if (ldebug(ftruncate64))
-		printf(ARGS(ftruncate64, "%u, %jd"), args->fd,
-		    (intmax_t)args->length);
-#endif
+	LINUX_CTR2(ftruncate64, "%u %jd", args->fd, (intmax_t)args->length);
 
 	sa.fd = args->fd;
 	sa.length = args->length;
@@ -1174,6 +1130,8 @@ linux_gettimeofday(struct thread *td, struct linux_gettimeofday_args *uap)
 	struct timezone rtz;
 	int error = 0;
 
+	LINUX_CTR(gettimeofday);
+
 	if (uap->tp) {
 		microtime(&atv);
 		atv32.tv_sec = atv.tv_sec;
@@ -1196,6 +1154,8 @@ linux_settimeofday(struct thread *td, struct linux_settimeofday_args *uap)
 	struct timezone atz, *tzp;
 	int error;
 
+	LINUX_CTR(settimeofday);
+
 	if (uap->tp) {
 		error = copyin(uap->tp, &atv32, sizeof(atv32));
 		if (error)
@@ -1222,6 +1182,8 @@ linux_getrusage(struct thread *td, struct linux_getrusage_args *uap)
 	struct rusage s;
 	int error;
 
+	LINUX_CTR(getrusage);
+
 	error = kern_getrusage(td, uap->who, &s);
 	if (error != 0)
 		return (error);
@@ -1257,6 +1219,8 @@ linux_sched_rr_get_interval(struct thread *td,
 	struct l_timespec ts32;
 	int error;
 
+	LINUX_CTR(sched_rr_get_interval);
+
 	error = kern_sched_rr_get_interval(td, uap->pid, &ts);
 	if (error != 0)
 		return (error);
@@ -1278,15 +1242,11 @@ linux_set_thread_area(struct thread *td,
 	if (error)
 		return (error);
 
-#ifdef DEBUG
-	if (ldebug(set_thread_area))
-		printf(ARGS(set_thread_area, "%i, %x, %x, %i, %i, %i, "
-		    "%i, %i, %i"), info.entry_number, info.base_addr,
-		    info.limit, info.seg_32bit, info.contents,
-		    info.read_exec_only, info.limit_in_pages,
-		    info.seg_not_present, info.useable);
-#endif
-
+	LINUX_CTR6(set_thread_area, "%i, %x, %x, %i, %i, %i",
+	    info.entry_number, info.base_addr, info.limit, info.seg_32bit,
+	    info.contents, info.read_exec_only);
+	LINUX_CTR3(set_thread_area, "%i, %i, %i", info.limit_in_pages,
+	    info.seg_not_present, info.useable);
 	/*
 	 * Semantics of Linux version: every thread in the system has array
 	 * of three TLS descriptors. 1st is GLIBC TLS, 2nd is WINE, 3rd unknown.
@@ -1340,24 +1300,6 @@ linux_set_thread_area(struct thread *td,
 	}
 
 	memcpy(&sd, &a, sizeof(a));
-#ifdef DEBUG
-	if (ldebug(set_thread_area))
-		printf("Segment created in set_thread_area: "
-		    "lobase: %x, hibase: %x, lolimit: %x, hilimit: %x, "
-		    "type: %i, dpl: %i, p: %i, xx: %i, long: %i, "
-		    "def32: %i, gran: %i\n",
-		    sd.sd_lobase,
-		    sd.sd_hibase,
-		    sd.sd_lolimit,
-		    sd.sd_hilimit,
-		    sd.sd_type,
-		    sd.sd_dpl,
-		    sd.sd_p,
-		    sd.sd_xx,
-		    sd.sd_long,
-		    sd.sd_def32,
-		    sd.sd_gran);
-#endif
 
 	critical_enter();
 	td->td_pcb->pcb_gsbase = (register_t)info.base_addr;
diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c
index bcb6069..9e3e095 100644
--- a/sys/amd64/linux32/linux32_sysvec.c
+++ b/sys/amd64/linux32/linux32_sysvec.c
@@ -42,11 +42,13 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/elf.h>
 #include <sys/exec.h>
 #include <sys/fcntl.h>
 #include <sys/imgact.h>
 #include <sys/imgact_elf.h>
 #include <sys/kernel.h>
+#include <sys/ktr.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
@@ -76,6 +78,7 @@ __FBSDID("$FreeBSD$");
 
 #include <amd64/linux32/linux.h>
 #include <amd64/linux32/linux32_proto.h>
+#include <compat/linux/linux_elf.h>
 #include <compat/linux/linux_emul.h>
 #include <compat/linux/linux_mib.h>
 #include <compat/linux/linux_signal.h>
@@ -91,6 +94,8 @@ MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
 		suword32(pos++, val);	\
 	} while (0)
 
+#define	aligned(a, t)	(rounddown((unsigned long)(a), sizeof(t)) == (unsigned long)(a))
+
 #if BYTE_ORDER == LITTLE_ENDIAN
 #define SHELLMAGIC      0x2123 /* #! */
 #else
@@ -106,6 +111,8 @@ MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
 #define	LINUX_SYS_linux_rt_sendsig	0
 #define	LINUX_SYS_linux_sendsig		0
 
+const char linux_platform[] = "i686";
+static int linux_szplatform;
 extern char linux_sigcode[];
 extern int linux_szsigcode;
 
@@ -125,7 +132,7 @@ static void	exec_linux_setregs(struct thread *td, u_long entry,
 static void	linux32_fixlimit(struct rlimit *rl, int which);
 
 extern LIST_HEAD(futex_list, futex) futex_list;
-extern struct sx futex_sx;
+extern struct mtx futex_mtx;
 
 static eventhandler_tag linux_exit_tag;
 static eventhandler_tag linux_schedtail_tag;
@@ -246,7 +253,12 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
 {
 	Elf32_Auxargs *args;
 	Elf32_Addr *base;
-	Elf32_Addr *pos;
+	Elf32_Addr *pos, *uplatform;
+	struct linux32_ps_strings *arginfo;
+
+	arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS;
+	uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szsigcode -
+	    linux_szplatform);
 
 	KASSERT(curthread->td_proc == imgp->proc,
 	    ("unsafe elf_linux_fixup(), should be curproc"));
@@ -254,8 +266,8 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
 	args = (Elf32_Auxargs *)imgp->auxargs;
 	pos = base + (imgp->args->argc + imgp->args->envc + 2);
 
-	if (args->execfd != -1)
-		AUXARGS_ENTRY_32(pos, AT_EXECFD, args->execfd);
+	AUXARGS_ENTRY_32(pos, LINUX_AT_HWCAP, cpu_feature);
+	AUXARGS_ENTRY_32(pos, LINUX_AT_CLKTCK, hz);
 	AUXARGS_ENTRY_32(pos, AT_PHDR, args->phdr);
 	AUXARGS_ENTRY_32(pos, AT_PHENT, args->phent);
 	AUXARGS_ENTRY_32(pos, AT_PHNUM, args->phnum);
@@ -263,10 +275,14 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
 	AUXARGS_ENTRY_32(pos, AT_FLAGS, args->flags);
 	AUXARGS_ENTRY_32(pos, AT_ENTRY, args->entry);
 	AUXARGS_ENTRY_32(pos, AT_BASE, args->base);
+	AUXARGS_ENTRY_32(pos, LINUX_AT_SECURE, 0);
 	AUXARGS_ENTRY_32(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
 	AUXARGS_ENTRY_32(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
 	AUXARGS_ENTRY_32(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
 	AUXARGS_ENTRY_32(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
+	AUXARGS_ENTRY_32(pos, LINUX_AT_PLATFORM, PTROUT(uplatform));
+	if (args->execfd != -1)
+		AUXARGS_ENTRY_32(pos, AT_EXECFD, args->execfd);
 	AUXARGS_ENTRY_32(pos, AT_NULL, 0);
 
 	free(imgp->auxargs, M_TEMP);
@@ -301,11 +317,9 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 	regs = td->td_frame;
 	oonstack = sigonstack(regs->tf_rsp);
 
-#ifdef DEBUG
-	if (ldebug(rt_sendsig))
-		printf(ARGS(rt_sendsig, "%p, %d, %p, %u"),
-		    catcher, sig, (void*)mask, code);
-#endif
+	LINUX_CTR3(rt_sendsig, "catcher %p sig %d code %u", catcher, sig, code);
+	LINUX_CTR2(rt_sendsig, "sp 0x%x ip 0x%x", regs->tf_rsp, regs->tf_rip);
+
 	/*
 	 * Allocate space for the signal handler context.
 	 */
@@ -371,23 +385,19 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 	frame.sf_sc.uc_mcontext.sc_cr2    = (u_int32_t)(uintptr_t)ksi->ksi_addr;
 	frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code);
 
-#ifdef DEBUG
-	if (ldebug(rt_sendsig))
-		printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x"),
-		    frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp,
-		    td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask);
-#endif
+	LINUX_CTR4(rt_sendsig, "flags 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x",
+	    frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp,
+	    td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask);
 
 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
 		/*
 		 * Process has trashed its stack; give it an illegal
 		 * instruction to halt it in its tracks.
 		 */
-#ifdef DEBUG
-		if (ldebug(rt_sendsig))
-			printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"),
-			    fp, oonstack);
-#endif
+
+		LINUX_CTR2(rt_sendsig, "bad stack %p, oonstack=%x",
+		    fp, oonstack);
+
 		PROC_LOCK(p);
 		sigexit(td, SIGILL);
 	}
@@ -447,12 +457,8 @@ linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 	regs = td->td_frame;
 	oonstack = sigonstack(regs->tf_rsp);
 
-#ifdef DEBUG
-	if (ldebug(sendsig))
-		printf(ARGS(sendsig, "%p, %d, %p, %u"),
-		    catcher, sig, (void*)mask, code);
-#endif
-
+	LINUX_CTR3(sendsig, "catcher %p sig %d code %u", catcher, sig, code);
+	LINUX_CTR2(sendsig, "sp 0x%x ip 0x%x", regs->tf_rsp, regs->tf_rip);
 	/*
 	 * Allocate space for the signal handler context.
 	 */
@@ -511,6 +517,10 @@ linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 		 * Process has trashed its stack; give it an illegal
 		 * instruction to halt it in its tracks.
 		 */
+
+		LINUX_CTR2(sendsig, "bad stack %p, oonstack=%x",
+		    fp, oonstack);
+
 		PROC_LOCK(p);
 		sigexit(td, SIGILL);
 	}
@@ -554,10 +564,7 @@ linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args)
 
 	regs = td->td_frame;
 
-#ifdef DEBUG
-	if (ldebug(sigreturn))
-		printf(ARGS(sigreturn, "%p"), (void *)args->sfp);
-#endif
+	LINUX_CTR1(sigreturn, "%p", (void *)args->sfp);
 	/*
 	 * The trampoline code hands us the sigframe.
 	 * It is unsafe to keep track of it ourselves, in the event that a
@@ -653,10 +660,7 @@ linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
 
 	regs = td->td_frame;
 
-#ifdef DEBUG
-	if (ldebug(rt_sigreturn))
-		printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp);
-#endif
+	LINUX_CTR1(rt_sigreturn, "%p", (void *)args->ucp);
 	/*
 	 * The trampoline code hands us the ucontext.
 	 * It is unsafe to keep track of it ourselves, in the event that a
@@ -732,11 +736,9 @@ linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
 	ss.ss_size = lss->ss_size;
 	ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags);
 
-#ifdef DEBUG
-	if (ldebug(rt_sigreturn))
-		printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x"),
-		    ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask);
-#endif
+	LINUX_CTR4(rt_sigreturn, "flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x",
+	    ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask);
+
 	(void)kern_sigaltstack(td, &ss, NULL);
 
 	return (EJUSTRETURN);
@@ -857,23 +859,27 @@ linux_copyout_strings(struct image_params *imgp)
 	char *stringp, *destp;
 	u_int32_t *stack_base;
 	struct linux32_ps_strings *arginfo;
-	int sigcodesz;
 
 	/*
 	 * Calculate string base and vector table pointers.
 	 * Also deal with signal trampoline code for this exec type.
 	 */
 	arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS;
-	sigcodesz = *(imgp->proc->p_sysent->sv_szsigcode);
-	destp =	(caddr_t)arginfo - sigcodesz - SPARE_USRSPACE -
-	    roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *));
+	destp =	(caddr_t)arginfo - linux_szsigcode - SPARE_USRSPACE -
+	    linux_szplatform - roundup((ARG_MAX - imgp->args->stringspace),
+	    sizeof(char *));
 
 	/*
 	 * install sigcode
 	 */
-	if (sigcodesz)
-		copyout(imgp->proc->p_sysent->sv_sigcode,
-			((caddr_t)arginfo - sigcodesz), sigcodesz);
+	copyout(imgp->proc->p_sysent->sv_sigcode,
+	    ((caddr_t)arginfo - linux_szsigcode), linux_szsigcode);
+
+	/*
+	 * Install LINUX_PLATFORM
+	 */
+	copyout(linux_platform, ((caddr_t)arginfo - linux_szsigcode -
+	    linux_szplatform), linux_szplatform);
 
 	/*
 	 * If we have a valid auxargs ptr, prepare some room
@@ -885,7 +891,7 @@ linux_copyout_strings(struct image_params *imgp)
 		 * lower compatibility.
 		 */
 		imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size :
-		    (AT_COUNT * 2);
+		    (LINUX_AT_COUNT * 2);
 		/*
 		 * The '+ 2' is for the null pointers at the end of each of
 		 * the arg and env vector sets,and imgp->auxarg_size is room
@@ -919,14 +925,14 @@ linux_copyout_strings(struct image_params *imgp)
 	/*
 	 * Fill in "ps_strings" struct for ps, w, etc.
 	 */
-	suword32(&arginfo->ps_argvstr, (u_int32_t)(intptr_t)vectp);
+	suword32(&arginfo->ps_argvstr, (uint32_t)(intptr_t)vectp);
 	suword32(&arginfo->ps_nargvstr, argc);
 
 	/*
 	 * Fill in argument portion of vector table.
 	 */
 	for (; argc > 0; --argc) {
-		suword32(vectp++, (u_int32_t)(intptr_t)destp);
+		suword32(vectp++, (uint32_t)(intptr_t)destp);
 		while (*stringp++ != 0)
 			destp++;
 		destp++;
@@ -935,14 +941,14 @@ linux_copyout_strings(struct image_params *imgp)
 	/* a null vector table pointer separates the argp's from the envp's */
 	suword32(vectp++, 0);
 
-	suword32(&arginfo->ps_envstr, (u_int32_t)(intptr_t)vectp);
+	suword32(&arginfo->ps_envstr, (uint32_t)(intptr_t)vectp);
 	suword32(&arginfo->ps_nenvstr, envc);
 
 	/*
 	 * Fill in environment portion of vector table.
 	 */
 	for (; envc > 0; --envc) {
-		suword32(vectp++, (u_int32_t)(intptr_t)destp);
+		suword32(vectp++, (uint32_t)(intptr_t)destp);
 		while (*stringp++ != 0)
 			destp++;
 		destp++;
@@ -999,6 +1005,54 @@ linux32_fixlimit(struct rlimit *rl, int which)
 	}
 }
 
+static const char GNULINUX_ABI_VENDOR[] = "GNU";
+static const int GNULINUX_ABI_LEN = 16;
+
+static int
+linux32_abi_note(struct image_params *imgp, int32_t *osrel)
+{
+	const Elf_Note *note, *note_end;
+	const Elf32_Phdr *phdr, *pnote;
+	const Elf32_Ehdr *hdr;
+	const char *note_name;
+	int i;
+
+	pnote = NULL;
+	hdr = (const Elf32_Ehdr *)imgp->image_header;
+	phdr = (const Elf32_Phdr *)(imgp->image_header + hdr->e_phoff);
+
+	for (i = 0; i < hdr->e_phnum; i++)
+		if (phdr[i].p_type == PT_NOTE) {
+			pnote = &phdr[i];
+			break;
+		}
+
+	if (pnote == NULL || pnote->p_offset >= PAGE_SIZE ||
+	    pnote->p_offset + pnote->p_filesz >= PAGE_SIZE)
+		return (0);
+
+	note = (const Elf_Note *)(imgp->image_header + pnote->p_offset);
+	if (!aligned(note, Elf32_Addr))
+		return (0);
+	note_end = (const Elf_Note *)(imgp->image_header +
+	    pnote->p_offset + pnote->p_filesz);
+	while (note < note_end) {
+		if (note->n_namesz == sizeof(GNULINUX_ABI_VENDOR) &&
+		    note->n_descsz == GNULINUX_ABI_LEN &&
+		    note->n_type == 1 /* ABI_NOTETYPE */) {
+			note_name = (const char *)(note + 1);
+			if (strncmp(GNULINUX_ABI_VENDOR, note_name,
+			    sizeof(GNULINUX_ABI_VENDOR)) == 0)
+				return (1);
+		}
+		note = (const Elf_Note *)((const char *)(note + 1) +
+		    roundup2(note->n_namesz, sizeof(Elf32_Addr)) +
+		    roundup2(note->n_descsz, sizeof(Elf32_Addr)));
+	}
+
+	return (0);
+}
+
 struct sysentvec elf_linux_sysvec = {
 	.sv_size	= LINUX_SYS_MAXSYSCALL,
 	.sv_table	= linux_sysent,
@@ -1038,7 +1092,8 @@ static Elf32_Brandinfo linux_brand = {
 	.interp_path	= "/lib/ld-linux.so.1",
 	.sysvec		= &elf_linux_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= linux32_abi_note,
+	.flags		= BI_CAN_EXEC_DYN | BI_CAN_EXEC_INTERP
 };
 
 static Elf32_Brandinfo linux_glibc2brand = {
@@ -1049,7 +1104,8 @@ static Elf32_Brandinfo linux_glibc2brand = {
 	.interp_path	= "/lib/ld-linux.so.2",
 	.sysvec		= &elf_linux_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= linux32_abi_note,
+	.flags		= BI_CAN_EXEC_DYN | BI_CAN_EXEC_INTERP
 };
 
 Elf32_Brandinfo *linux_brandlist[] = {
@@ -1082,7 +1138,7 @@ linux_elf_modevent(module_t mod, int type, void *data)
 			mtx_init(&emul_lock, "emuldata lock", NULL, MTX_DEF);
 			sx_init(&emul_shared_lock, "emuldata->shared lock");
 			LIST_INIT(&futex_list);
-			sx_init(&futex_sx, "futex protection lock");
+			mtx_init(&futex_mtx, "futex list protection lock", NULL, MTX_DEF);
 			linux_exit_tag = EVENTHANDLER_REGISTER(process_exit,
 			    linux_proc_exit, NULL, 1000);
 			linux_schedtail_tag = EVENTHANDLER_REGISTER(schedtail,
@@ -1091,6 +1147,8 @@ linux_elf_modevent(module_t mod, int type, void *data)
 			    linux_proc_exec, NULL, 1000);
 			if (bootverbose)
 				printf("Linux ELF exec handler installed\n");
+			linux_szplatform = roundup(strlen(linux_platform) + 1,
+			    sizeof(char *));
 		} else
 			printf("cannot insert Linux ELF brand handler\n");
 		break;
@@ -1112,7 +1170,7 @@ linux_elf_modevent(module_t mod, int type, void *data)
 				linux_device_unregister_handler(*ldhp);
 			mtx_destroy(&emul_lock);
 			sx_destroy(&emul_shared_lock);
-			sx_destroy(&futex_sx);
+			mtx_destroy(&futex_mtx);
 			EVENTHANDLER_DEREGISTER(process_exit, linux_exit_tag);
 			EVENTHANDLER_DEREGISTER(schedtail, linux_schedtail_tag);
 			EVENTHANDLER_DEREGISTER(process_exec, linux_exec_tag);
diff --git a/sys/arm/arm/elf_machdep.c b/sys/arm/arm/elf_machdep.c
index 693eab1..e65f947 100644
--- a/sys/arm/arm/elf_machdep.c
+++ b/sys/arm/arm/elf_machdep.c
@@ -84,7 +84,8 @@ static Elf32_Brandinfo freebsd_brand_info = {
 	.interp_path	= "/libexec/ld-elf.so.1",
 	.sysvec		= &elf32_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_ANY,
@@ -99,7 +100,8 @@ static Elf32_Brandinfo freebsd_brand_oinfo = {
 	.interp_path	= "/usr/libexec/ld-elf.so.1",
 	.sysvec		= &elf32_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY,
diff --git a/sys/compat/ia32/ia32_sysvec.c b/sys/compat/ia32/ia32_sysvec.c
index 0b32b9a..92b990a 100644
--- a/sys/compat/ia32/ia32_sysvec.c
+++ b/sys/compat/ia32/ia32_sysvec.c
@@ -148,6 +148,7 @@ static Elf32_Brandinfo ia32_brand_info = {
 	.interp_path	= "/libexec/ld-elf.so.1",
 	.sysvec		= &ia32_freebsd_sysvec,
 	.interp_newpath	= "/libexec/ld-elf32.so.1",
+	.brand_abi_note	= __elfN(freebsd_abi_note),
 	.flags		= BI_CAN_EXEC_DYN
 };
 
@@ -163,7 +164,8 @@ static Elf32_Brandinfo ia32_brand_oinfo = {
 	.interp_path	= "/usr/libexec/ld-elf.so.1",
 	.sysvec		= &ia32_freebsd_sysvec,
 	.interp_newpath	= "/libexec/ld-elf32.so.1",
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(oia32, SI_SUB_EXEC, SI_ORDER_ANY,
diff --git a/sys/compat/linux/linux_elf.h b/sys/compat/linux/linux_elf.h
new file mode 100644
index 0000000..f601633
--- /dev/null
+++ b/sys/compat/linux/linux_elf.h
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2008 Chagin Dmitry
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_ELF_H_
+#define	_LINUX_ELF_H_
+
+/*
+ * Non-standard aux entry types used in Linux ELF binaries.
+ */
+
+#define	LINUX_AT_PLATFORM	15	/* String identifying CPU */
+#define	LINUX_AT_HWCAP		16	/* CPU capabilities */
+#define	LINUX_AT_CLKTCK		17	/* frequency at which times() increments */
+#define	LINUX_AT_SECURE		23	/* secure mode boolean */
+#define	LINUX_AT_BASE_PLATFORM	24	/* string identifying real platform, may
+					 * differ from AT_PLATFORM.
+					 */
+#define	LINUX_AT_EXECFN		31	/* filename of program */
+
+#endif /* !_LINUX_ELF_H_ */
diff --git a/sys/compat/linux/linux_emul.c b/sys/compat/linux/linux_emul.c
index 1ca48a3..51b197d 100644
--- a/sys/compat/linux/linux_emul.c
+++ b/sys/compat/linux/linux_emul.c
@@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/systm.h>
 #include <sys/imgact.h>
 #include <sys/kernel.h>
+#include <sys/ktr.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/mutex.h>
@@ -54,6 +55,7 @@ __FBSDID("$FreeBSD$");
 
 #include <compat/linux/linux_emul.h>
 #include <compat/linux/linux_futex.h>
+#include <compat/linux/linux_util.h>
 
 struct sx	emul_shared_lock;
 struct mtx	emul_lock;
@@ -317,10 +319,7 @@ linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args
 {
 	struct linux_emuldata *em;
 
-#ifdef DEBUG
-	if (ldebug(set_tid_address))
-		printf(ARGS(set_tid_address, "%p"), args->tidptr);
-#endif
+	LINUX_CTR1(set_tid_address, "%p", args->tidptr);
 
 	/* find the emuldata */
 	em = em_find(td->td_proc, EMUL_DOLOCK);
diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c
index 6643e71..e1d8a05 100644
--- a/sys/compat/linux/linux_file.c
+++ b/sys/compat/linux/linux_file.c
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/fcntl.h>
 #include <sys/file.h>
 #include <sys/filedesc.h>
+#include <sys/ktr.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/mount.h>
@@ -72,19 +73,17 @@ __FBSDID("$FreeBSD$");
 int
 linux_creat(struct thread *td, struct linux_creat_args *args)
 {
-    char *path;
-    int error;
+	char *path;
+	int error;
 
-    LCONVPATHEXIST(td, args->path, &path);
+	LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(creat))
-		printf(ARGS(creat, "%s, %d"), path, args->mode);
-#endif
-    error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC,
-	args->mode);
-    LFREEPATH(path);
-    return (error);
+	LINUX_CTR(creat);
+
+	error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC,
+	    args->mode);
+	LFREEPATH(path);
+	return (error);
 }
 
 
@@ -170,10 +169,8 @@ linux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mod
 	    }
     }
 
-#ifdef DEBUG
-    if (ldebug(open))
-	    printf(LMSG("open returns error %d"), error);
-#endif
+	LINUX_CTR1(open, "returns error %d", error);
+
     LFREEPATH(path);
     return (error);
 }
@@ -189,29 +186,23 @@ linux_openat(struct thread *td, struct linux_openat_args *args)
 		LCONVPATH_AT(td, args->filename, &path, 1, dfd);
 	else
 		LCONVPATH_AT(td, args->filename, &path, 0, dfd);
-#ifdef DEBUG
-	if (ldebug(openat))
-		printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd,
-		    path, args->flags, args->mode);
-#endif
+
+	LINUX_CTR(openat);
+
 	return (linux_common_open(td, dfd, path, args->flags, args->mode));
 }
 
 int
 linux_open(struct thread *td, struct linux_open_args *args)
 {
-    char *path;
+	char *path;
 
-    if (args->flags & LINUX_O_CREAT)
-	LCONVPATHCREAT(td, args->path, &path);
-    else
-	LCONVPATHEXIST(td, args->path, &path);
+	if (args->flags & LINUX_O_CREAT)
+		LCONVPATHCREAT(td, args->path, &path);
+	else
+		LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(open))
-		printf(ARGS(open, "%s, 0x%x, 0x%x"),
-		    path, args->flags, args->mode);
-#endif
+	LINUX_CTR(open);
 
 	return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode));
 }
@@ -219,25 +210,20 @@ linux_open(struct thread *td, struct linux_open_args *args)
 int
 linux_lseek(struct thread *td, struct linux_lseek_args *args)
 {
+	struct lseek_args /* {
+		int fd;
+		int pad;
+		off_t offset;
+		int whence;
+	} */ tmp_args;
 
-    struct lseek_args /* {
-	int fd;
-	int pad;
-	off_t offset;
-	int whence;
-    } */ tmp_args;
-    int error;
-
-#ifdef DEBUG
-	if (ldebug(lseek))
-		printf(ARGS(lseek, "%d, %ld, %d"),
-		    args->fdes, (long)args->off, args->whence);
-#endif
-    tmp_args.fd = args->fdes;
-    tmp_args.offset = (off_t)args->off;
-    tmp_args.whence = args->whence;
-    error = lseek(td, &tmp_args);
-    return error;
+	LINUX_CTR3(lseek, "%d %ld %d", args->fdes,
+	    (long)args->off, args->whence);
+
+	tmp_args.fd = args->fdes;
+	tmp_args.offset = (off_t)args->off;
+	tmp_args.whence = args->whence;
+	return (lseek(td, &tmp_args));
 }
 
 int
@@ -247,11 +233,9 @@ linux_llseek(struct thread *td, struct linux_llseek_args *args)
 	int error;
 	off_t off;
 
-#ifdef DEBUG
-	if (ldebug(llseek))
-		printf(ARGS(llseek, "%d, %d:%d, %d"),
-		    args->fd, args->ohigh, args->olow, args->whence);
-#endif
+	LINUX_CTR4(llseek, "%d %d:%d %d", args->fd, args->ohigh,
+	    args->olow, args->whence);
+
 	off = (args->olow) | (((off_t) args->ohigh) << 32);
 
 	bsd_args.fd = args->fd;
@@ -259,13 +243,13 @@ linux_llseek(struct thread *td, struct linux_llseek_args *args)
 	bsd_args.whence = args->whence;
 
 	if ((error = lseek(td, &bsd_args)))
-		return error;
+		return (error);
 
 	if ((error = copyout(td->td_retval, args->res, sizeof (off_t))))
-		return error;
+		return (error);
 
 	td->td_retval[0] = 0;
-	return 0;
+	return (0);
 }
 
 int
@@ -276,7 +260,7 @@ linux_readdir(struct thread *td, struct linux_readdir_args *args)
 	lda.fd = args->fd;
 	lda.dent = args->dent;
 	lda.count = 1;
-	return linux_getdents(td, &lda);
+	return (linux_getdents(td, &lda));
 }
 
 /*
@@ -537,10 +521,7 @@ int
 linux_getdents(struct thread *td, struct linux_getdents_args *args)
 {
 
-#ifdef DEBUG
-	if (ldebug(getdents))
-		printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
-#endif
+	LINUX_CTR2(getdents, "%d %d", args->fd, args->count);
 
 	return (getdents_common(td, (struct linux_getdents64_args*)args, 0));
 }
@@ -549,10 +530,7 @@ int
 linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
 {
 
-#ifdef DEBUG
-	if (ldebug(getdents64))
-		printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
-#endif
+	LINUX_CTR2(getdents64, "%d %d", args->fd, args->count);
 
 	return (getdents_common(td, args, 1));
 }
@@ -573,10 +551,8 @@ linux_access(struct thread *td, struct linux_access_args *args)
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(access))
-		printf(ARGS(access, "%s, %d"), path, args->flags);
-#endif
+	LINUX_CTR(access);
+
 	error = kern_access(td, path, UIO_SYSSPACE, args->flags);
 	LFREEPATH(path);
 
@@ -596,10 +572,7 @@ linux_faccessat(struct thread *td, struct linux_faccessat_args *args)
 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
 	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
 
-#ifdef DEBUG
-	if (ldebug(access))
-		printf(ARGS(access, "%s, %d"), path, args->mode);
-#endif
+	LINUX_CTR(faccessat);
 
 	error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0 /* XXX */,
 	    args->mode);
@@ -617,10 +590,7 @@ linux_unlink(struct thread *td, struct linux_unlink_args *args)
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(unlink))
-		printf(ARGS(unlink, "%s"), path);
-#endif
+	LINUX_CTR(unlink);
 
 	error = kern_unlink(td, path, UIO_SYSSPACE);
 	if (error == EPERM)
@@ -645,10 +615,7 @@ linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
 	LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
 
-#ifdef DEBUG
-	if (ldebug(unlinkat))
-		printf(ARGS(unlinkat, "%s"), path);
-#endif
+	LINUX_CTR(unlinkat);
 
 	if (args->flag & LINUX_AT_REMOVEDIR)
 		error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE);
@@ -671,10 +638,8 @@ linux_chdir(struct thread *td, struct linux_chdir_args *args)
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(chdir))
-		printf(ARGS(chdir, "%s"), path);
-#endif
+	LINUX_CTR(chdir);
+
 	error = kern_chdir(td, path, UIO_SYSSPACE);
 	LFREEPATH(path);
 	return (error);
@@ -688,10 +653,8 @@ linux_chmod(struct thread *td, struct linux_chmod_args *args)
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(chmod))
-		printf(ARGS(chmod, "%s, %d"), path, args->mode);
-#endif
+	LINUX_CTR(chmod);
+
 	error = kern_chmod(td, path, UIO_SYSSPACE, args->mode);
 	LFREEPATH(path);
 	return (error);
@@ -706,10 +669,7 @@ linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args)
 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
 	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
 
-#ifdef DEBUG
-	if (ldebug(fchmodat))
-		printf(ARGS(fchmodat, "%s, %d"), path, args->mode);
-#endif
+	LINUX_CTR(fchmodat);
 
 	error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0);
 	LFREEPATH(path);
@@ -724,10 +684,8 @@ linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
 
 	LCONVPATHCREAT(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(mkdir))
-		printf(ARGS(mkdir, "%s, %d"), path, args->mode);
-#endif
+	LINUX_CTR(mkdir);
+
 	error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode);
 	LFREEPATH(path);
 	return (error);
@@ -742,10 +700,8 @@ linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args)
 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
 	LCONVPATHCREAT_AT(td, args->pathname, &path, dfd);
 
-#ifdef DEBUG
-	if (ldebug(mkdirat))
-		printf(ARGS(mkdirat, "%s, %d"), path, args->mode);
-#endif
+	LINUX_CTR(mkdirat);
+
 	error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode);
 	LFREEPATH(path);
 	return (error);
@@ -759,10 +715,8 @@ linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(rmdir))
-		printf(ARGS(rmdir, "%s"), path);
-#endif
+	LINUX_CTR(rmdir);
+
 	error = kern_rmdir(td, path, UIO_SYSSPACE);
 	LFREEPATH(path);
 	return (error);
@@ -782,10 +736,8 @@ linux_rename(struct thread *td, struct linux_rename_args *args)
 		return (error);
 	}
 
-#ifdef DEBUG
-	if (ldebug(rename))
-		printf(ARGS(rename, "%s, %s"), from, to);
-#endif
+	LINUX_CTR(rename);
+
 	error = kern_rename(td, from, to, UIO_SYSSPACE);
 	LFREEPATH(from);
 	LFREEPATH(to);
@@ -808,10 +760,8 @@ linux_renameat(struct thread *td, struct linux_renameat_args *args)
 		return (error);
 	}
 
-#ifdef DEBUG
-	if (ldebug(renameat))
-		printf(ARGS(renameat, "%s, %s"), from, to);
-#endif
+	LINUX_CTR(renameat);
+
 	error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE);
 	LFREEPATH(from);
 	LFREEPATH(to);
@@ -832,10 +782,8 @@ linux_symlink(struct thread *td, struct linux_symlink_args *args)
 		return (error);
 	}
 
-#ifdef DEBUG
-	if (ldebug(symlink))
-		printf(ARGS(symlink, "%s, %s"), path, to);
-#endif
+	LINUX_CTR(symlink);
+
 	error = kern_symlink(td, path, to, UIO_SYSSPACE);
 	LFREEPATH(path);
 	LFREEPATH(to);
@@ -857,10 +805,7 @@ linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
 		return (error);
 	}
 
-#ifdef DEBUG
-	if (ldebug(symlinkat))
-		printf(ARGS(symlinkat, "%s, %s"), path, to);
-#endif
+	LINUX_CTR(symlinkat);
 
 	error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE);
 	LFREEPATH(path);
@@ -876,11 +821,8 @@ linux_readlink(struct thread *td, struct linux_readlink_args *args)
 
 	LCONVPATHEXIST(td, args->name, &name);
 
-#ifdef DEBUG
-	if (ldebug(readlink))
-		printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf,
-		    args->count);
-#endif
+	LINUX_CTR(readlink);
+
 	error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE,
 	    args->count);
 	LFREEPATH(name);
@@ -896,11 +838,7 @@ linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
 	LCONVPATHEXIST_AT(td, args->path, &name, dfd);
 
-#ifdef DEBUG
-	if (ldebug(readlinkat))
-		printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf,
-		    args->bufsiz);
-#endif
+	LINUX_CTR(readlinkat);
 
 	error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf,
 	    UIO_USERSPACE, args->bufsiz);
@@ -916,10 +854,7 @@ linux_truncate(struct thread *td, struct linux_truncate_args *args)
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(truncate))
-		printf(ARGS(truncate, "%s, %ld"), path, (long)args->length);
-#endif
+	LINUX_CTR(truncate);
 
 	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
 	LFREEPATH(path);
@@ -934,10 +869,7 @@ linux_truncate64(struct thread *td, struct linux_truncate64_args *args)
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(truncate64))
-		printf(ARGS(truncate64, "%s, %jd"), path, args->length);
-#endif
+	LINUX_CTR(truncate64);
 
 	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
 	LFREEPATH(path);
@@ -950,7 +882,9 @@ linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
 		int fd;
 		int pad;
 		off_t length;
-		} */ nuap;
+	} */ nuap;
+
+	LINUX_CTR(ftruncate);
 	   
 	nuap.fd = args->fd;
 	nuap.length = args->length;
@@ -971,10 +905,8 @@ linux_link(struct thread *td, struct linux_link_args *args)
 		return (error);
 	}
 
-#ifdef DEBUG
-	if (ldebug(link))
-		printf(ARGS(link, "%s, %s"), path, to);
-#endif
+	LINUX_CTR(link);
+
 	error = kern_link(td, path, to, UIO_SYSSPACE);
 	LFREEPATH(path);
 	LFREEPATH(to);
@@ -1004,11 +936,7 @@ linux_linkat(struct thread *td, struct linux_linkat_args *args)
 		return (error);
 	}
 
-#ifdef DEBUG
-	if (ldebug(linkat))
-		printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path,
-			args->newdfd, to, args->flags);
-#endif
+	LINUX_CTR(linkat);
 
 	error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, FOLLOW);
 	LFREEPATH(path);
@@ -1023,8 +951,10 @@ linux_fdatasync(td, uap)
 {
 	struct fsync_args bsd;
 
+	LINUX_CTR(fdatasync);
+
 	bsd.fd = uap->fd;
-	return fsync(td, &bsd);
+	return (fsync(td, &bsd));
 }
 
 int
@@ -1068,7 +998,7 @@ linux_pwrite(td, uap)
 	bsd.buf = uap->buf;
 	bsd.nbyte = uap->nbyte;
 	bsd.offset = uap->offset;
-	return pwrite(td, &bsd);
+	return (pwrite(td, &bsd));
 }
 
 int
@@ -1092,11 +1022,7 @@ linux_mount(struct thread *td, struct linux_mount_args *args)
 	if (error)
 		return (error);
 
-#ifdef DEBUG
-	if (ldebug(mount))
-		printf(ARGS(mount, "%s, %s, %s"),
-		    fstypename, mntfromname, mntonname);
-#endif
+	LINUX_CTR(mount);
 
 	if (strcmp(fstypename, "ext2") == 0) {
 		strcpy(fstypename, "ext2fs");
@@ -1405,10 +1331,7 @@ linux_fcntl(struct thread *td, struct linux_fcntl_args *args)
 {
 	struct linux_fcntl64_args args64;
 
-#ifdef DEBUG
-	if (ldebug(fcntl))
-		printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
-#endif
+	LINUX_CTR2(fcntl, "%d %08x", args->fd, args->cmd);
 
 	args64.fd = args->fd;
 	args64.cmd = args->cmd;
@@ -1424,10 +1347,7 @@ linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
 	struct flock bsd_flock;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(fcntl64))
-		printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
-#endif
+	LINUX_CTR2(fcntl64, "%d %08x", args->fd, args->cmd);
 
 	switch (args->cmd) {
 	case LINUX_F_GETLK64:
@@ -1474,10 +1394,8 @@ linux_chown(struct thread *td, struct linux_chown_args *args)
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(chown))
-		printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
-#endif
+	LINUX_CTR(chown);
+
 	error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid);
 	LFREEPATH(path);
 	return (error);
@@ -1495,10 +1413,7 @@ linux_fchownat(struct thread *td, struct linux_fchownat_args *args)
 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD :  args->dfd;
 	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
 
-#ifdef DEBUG
-	if (ldebug(fchownat))
-		printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid);
-#endif
+	LINUX_CTR(fchownat);
 
 	follow = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
 	    AT_SYMLINK_NOFOLLOW;
@@ -1516,10 +1431,8 @@ linux_lchown(struct thread *td, struct linux_lchown_args *args)
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(lchown))
-		printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
-#endif
+	LINUX_CTR(lchown);
+
 	error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid);
 	LFREEPATH(path);
 	return (error);
diff --git a/sys/compat/linux/linux_futex.c b/sys/compat/linux/linux_futex.c
index b19d290..312ec42 100644
--- a/sys/compat/linux/linux_futex.c
+++ b/sys/compat/linux/linux_futex.c
@@ -40,19 +40,21 @@ __KERNEL_RCSID(1, "$NetBSD: linux_futex.c,v 1.7 2006/07/24 19:01:49 manu Exp $")
 #include "opt_compat.h"
 
 #include <sys/param.h>
-#include <sys/types.h>
-#include <sys/time.h>
 #include <sys/systm.h>
-#include <sys/proc.h>
-#include <sys/queue.h>
+#include <sys/types.h>
 #include <sys/imgact.h>
+#include <sys/ktr.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
+#include <sys/malloc.h>
 #include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+#include <sys/refcount.h>
 #include <sys/sched.h>
 #include <sys/sx.h>
-#include <sys/malloc.h>
 
+#include <machine/atomic.h>
 #ifdef COMPAT_LINUX32
 #include <machine/../linux32/linux.h>
 #include <machine/../linux32/linux32_proto.h>
@@ -60,424 +62,341 @@ __KERNEL_RCSID(1, "$NetBSD: linux_futex.c,v 1.7 2006/07/24 19:01:49 manu Exp $")
 #include <machine/../linux/linux.h>
 #include <machine/../linux/linux_proto.h>
 #endif
-#include <compat/linux/linux_emul.h>
 #include <compat/linux/linux_futex.h>
+#include <compat/linux/linux_emul.h>
+#include <compat/linux/linux_util.h>
 
 struct futex;
 
 struct waiting_proc {
-	struct thread *wp_t;
-	struct futex *wp_new_futex;
+	struct futex	*w_ftx;
+	pid_t		w_pid;
+	uint32_t	w_flags;
 	TAILQ_ENTRY(waiting_proc) wp_list;
 };
+
 struct futex {
-	void   *f_uaddr;
-	int	f_refcount;
+	struct sx	lock;
+	uint32_t	*f_uaddr;
+	uint32_t	f_refcount;
 	LIST_ENTRY(futex) f_list;
 	TAILQ_HEAD(lf_waiting_proc, waiting_proc) f_waiting_proc;
 };
 
+struct fx {
+	uint32_t	flags;
+	struct futex	*ftx;
+	struct waiting_proc *wp;
+};
+
 LIST_HEAD(futex_list, futex) futex_list;
-struct sx futex_sx;		/* this protects the LIST of futexes */
 
-#define FUTEX_LOCK sx_xlock(&futex_sx)
-#define FUTEX_UNLOCK sx_xunlock(&futex_sx)
+#define FUTEX_LOCK(f)		sx_xlock(&f->lock)
+#define FUTEX_UNLOCK(f)		sx_xunlock(&f->lock)
+#define FUTEX_LOCK_INIT(f, o)	sx_init_flags(&f->lock, "futex lock", o)
+#define FUTEX_LOCK_DESTROY(f)	sx_destroy(&f->lock)
+#define FUTEX_LOCK_ASSERT(f, type) sx_assert(&f->lock, type)
 
-#define FUTEX_LOCKED	1
-#define FUTEX_UNLOCKED	0
+struct mtx futex_mtx;			/* this protects the futex list */
+#define FUTEXES_LOCK	mtx_lock(&futex_mtx)
+#define FUTEXES_UNLOCK	mtx_unlock(&futex_mtx)
 
-#define FUTEX_SYSTEM_LOCK mtx_lock(&Giant)
-#define FUTEX_SYSTEM_UNLOCK mtx_unlock(&Giant)
+#define FUTEX_CREATE_WP		0x1	/* create waiting_proc */
+#define FUTEX_DONTCREATE	0x2	/* don't create futex if not exists */
 
-static struct futex	*futex_get(void *, int);
-static void futex_put(struct futex *);
-static int futex_sleep(struct futex *, struct thread *, unsigned long);
-static int futex_wake(struct futex *, int, struct futex *, int);
-static int futex_atomic_op(struct thread *td, int encoded_op, caddr_t uaddr);
+#define FUTEX_WP_REQUEUED	0x1	/* waiting_proc requeued */
+#define FUTEX_WP_REMOVED	0x2	/* waiting_proc removed from tailq*/
 
 /* support.s */
-int futex_xchgl(int oparg, caddr_t uaddr, int *oldval);
-int futex_addl(int oparg, caddr_t uaddr, int *oldval);
-int futex_orl(int oparg, caddr_t uaddr, int *oldval);
-int futex_andl(int oparg, caddr_t uaddr, int *oldval);
-int futex_xorl(int oparg, caddr_t uaddr, int *oldval);
-
-int
-linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
-{
-	int val;
-	int ret;
-	struct l_timespec timeout = {0, 0};
-	int error = 0;
-	struct futex *f;
-	struct futex *newf;
-	int timeout_hz;
-	struct timeval tv = {0, 0};
-	struct futex *f2;
-	int op_ret;
-
-#ifdef	DEBUG
-	if (ldebug(sys_futex))
-		printf(ARGS(futex, "%p, %i, %i, *, %p, %i"), args->uaddr, args->op,
-		    args->val, args->uaddr2, args->val3);
-#endif
-
-	/* 
-	 * Our implementation provides only privates futexes. Most of the apps
-	 * should use private futexes but don't claim so. Therefore we treat
-	 * all futexes as private by clearing the FUTEX_PRIVATE_FLAG. It works
-	 * in most cases (ie. when futexes are not shared on file descriptor
-	 * or between different processes.).
-	 */
-	args->op = (args->op & ~LINUX_FUTEX_PRIVATE_FLAG);
-
-	switch (args->op) {
-	case LINUX_FUTEX_WAIT:
-		FUTEX_SYSTEM_LOCK;
-
-		if ((error = copyin(args->uaddr,
-		    &val, sizeof(val))) != 0) {
-			FUTEX_SYSTEM_UNLOCK;
-			return error;
-		}
-
-		if (val != args->val) {
-			FUTEX_SYSTEM_UNLOCK;
-			return EWOULDBLOCK;
-		}
-
-		if (args->timeout != NULL) {
-			if ((error = copyin(args->timeout,
-			    &timeout, sizeof(timeout))) != 0) {
-				FUTEX_SYSTEM_UNLOCK;
-				return error;
-			}
-		}
+int futex_xchgl(int oparg, uint32_t *uaddr, int *oldval);
+int futex_addl(int oparg, uint32_t *uaddr, int *oldval);
+int futex_orl(int oparg, uint32_t *uaddr, int *oldval);
+int futex_andl(int oparg, uint32_t *uaddr, int *oldval);
+int futex_xorl(int oparg, uint32_t *uaddr, int *oldval);
 
 #ifdef DEBUG
-		if (ldebug(sys_futex))
-			printf("FUTEX_WAIT %d: val = %d, uaddr = %p, "
-			    "*uaddr = %d, timeout = %d.%09lu\n",
-			    td->td_proc->p_pid, args->val,
-			    args->uaddr, val, timeout.tv_sec,
-			    (unsigned long)timeout.tv_nsec);
+#define LINUX_SYS_linux_release_futexes	0
 #endif
-		tv.tv_usec = timeout.tv_sec * 1000000 + timeout.tv_nsec / 1000;
-		timeout_hz = tvtohz(&tv);
-
-		if (timeout.tv_sec == 0 && timeout.tv_nsec == 0)
-			timeout_hz = 0;
-		/*
-		 * If the user process requests a non null timeout,
-		 * make sure we do not turn it into an infinite
-		 * timeout because timeout_hz gets null.
-		 *
-		 * We use a minimal timeout of 1/hz. Maybe it would
-		 * make sense to just return ETIMEDOUT without sleeping.
-		 */
-		if (((timeout.tv_sec != 0) || (timeout.tv_nsec != 0)) &&
-		    (timeout_hz == 0))
-			timeout_hz = 1;
 
+static void
+futex_put0(struct futex *f)
+{
 
-		f = futex_get(args->uaddr, FUTEX_UNLOCKED);
-		ret = futex_sleep(f, td, timeout_hz);
-		futex_put(f);
+	FUTEXES_LOCK;
+	if (refcount_release(&f->f_refcount)) {
+		LIST_REMOVE(f, f_list);
+		FUTEXES_UNLOCK;
 
-#ifdef DEBUG
-		if (ldebug(sys_futex))
-			printf("FUTEX_WAIT %d: uaddr = %p, "
-			    "ret = %d\n", td->td_proc->p_pid, args->uaddr, ret);
-#endif
+		FUTEX_UNLOCK(f);
+		LINUX_CTR2(sys_futex, "futex_put destroy uaddr %p ref %d",
+		    f->f_uaddr, f->f_refcount);
+		FUTEX_LOCK_DESTROY(f);
+		free(f, M_LINUX);
+		return;
+	}
 
-		FUTEX_SYSTEM_UNLOCK;
-		switch (ret) {
-		case EWOULDBLOCK:	/* timeout */
-			return ETIMEDOUT;
-			break;
-		case EINTR:		/* signal */
-			return EINTR;
-			break;
-		case 0:		/* FUTEX_WAKE received */
-#ifdef DEBUG
-			if (ldebug(sys_futex))
-				printf("FUTEX_WAIT %d: uaddr = %p, "
-				    "got FUTEX_WAKE\n",
-				    td->td_proc->p_pid, args->uaddr);
-#endif
-			return 0;
-			break;
-		default:
-#ifdef DEBUG
-			if (ldebug(sys_futex))
-				printf("FUTEX_WAIT: unexpected ret = %d\n",
-				    ret);
-#endif
-			break;
-		}
+	LINUX_CTR2(sys_futex, "futex_put uaddr %p ref %d",
+	    f->f_uaddr, f->f_refcount);
+	FUTEXES_UNLOCK;
+	FUTEX_UNLOCK(f);
+}
 
-		/* NOTREACHED */
-		break;
+static void
+futex_put(struct fx *f)
+{
 
-	case LINUX_FUTEX_WAKE:
-		FUTEX_SYSTEM_LOCK;
+	FUTEX_LOCK_ASSERT(f->ftx, SA_XLOCKED);
+	if (f->flags & FUTEX_CREATE_WP && f->wp != NULL) {
+		if ((f->wp->w_flags & FUTEX_WP_REMOVED) == 0)
+			TAILQ_REMOVE(&f->ftx->f_waiting_proc, f->wp, wp_list);
+		free(f->wp, M_LINUX);
+		f->wp = NULL;
+	}
 
-		/*
-		 * XXX: Linux is able to cope with different addresses
-		 * corresponding to the same mapped memory in the sleeping
-		 * and waker process(es).
-		 */
-#ifdef DEBUG
-		if (ldebug(sys_futex))
-			printf("FUTEX_WAKE %d: uaddr = %p, val = %d\n",
-			    td->td_proc->p_pid, args->uaddr, args->val);
-#endif
-		f = futex_get(args->uaddr, FUTEX_UNLOCKED);
-		td->td_retval[0] = futex_wake(f, args->val, NULL, 0);
-		futex_put(f);
+	futex_put0(f->ftx);
+}
 
-		FUTEX_SYSTEM_UNLOCK;
-		break;
 
-	case LINUX_FUTEX_CMP_REQUEUE:
-		FUTEX_SYSTEM_LOCK;
+static void
+futex_get0(uint32_t *uaddr, struct fx *fx, struct futex **newf,
+    uint32_t flags, int sx_opts)
+{
+	struct futex *f;
 
-		if ((error = copyin(args->uaddr,
-		    &val, sizeof(val))) != 0) {
-			FUTEX_SYSTEM_UNLOCK;
-			return error;
-		}
+	fx->flags = flags;
 
-		if (val != args->val3) {
-			FUTEX_SYSTEM_UNLOCK;
-			return EAGAIN;
+retry:
+	FUTEXES_LOCK;
+	LIST_FOREACH(f, &futex_list, f_list) {
+		if (f->f_uaddr == uaddr) {
+			refcount_acquire(&f->f_refcount);
+			FUTEXES_UNLOCK;
+
+			fx->ftx = f;
+			if (*newf != NULL)
+				free(*newf, M_LINUX);
+
+			FUTEX_LOCK(f);
+			if (flags & FUTEX_CREATE_WP) {
+				TAILQ_INSERT_HEAD(&f->f_waiting_proc, fx->wp,
+				    wp_list);
+				fx->wp->w_ftx = f;
+			}
+			LINUX_CTR3(sys_futex, "futex_get uaddr %p wp %p ref %d",
+			    uaddr, fx->wp, f->f_refcount);
+			return;
 		}
+	}
 
-		f = futex_get(args->uaddr, FUTEX_UNLOCKED);
-		newf = futex_get(args->uaddr2, FUTEX_UNLOCKED);
-		td->td_retval[0] = futex_wake(f, args->val, newf,
-		    (int)(unsigned long)args->timeout);
-		futex_put(f);
-		futex_put(newf);
-
-		FUTEX_SYSTEM_UNLOCK;
-		break;
-
-	case LINUX_FUTEX_REQUEUE:
-		FUTEX_SYSTEM_LOCK;
+	fx->ftx = *newf;
+	if (flags & FUTEX_DONTCREATE) {
+		FUTEXES_UNLOCK;
+		LINUX_CTR1(sys_futex, "futex_get uaddr %p null", uaddr);
+		return;
+	}
 
-		f = futex_get(args->uaddr, FUTEX_UNLOCKED);
-		newf = futex_get(args->uaddr2, FUTEX_UNLOCKED);
-		td->td_retval[0] = futex_wake(f, args->val, newf,
-		    (int)(unsigned long)args->timeout);
-		futex_put(f);
-		futex_put(newf);
+	if (fx->ftx == NULL) {
+		FUTEXES_UNLOCK;
+		*newf = malloc(sizeof(struct futex), M_LINUX, M_WAITOK | M_ZERO);
+		(*newf)->f_uaddr = uaddr;
+		refcount_init(&(*newf)->f_refcount, 1);
+		goto retry;
+	}
 
-		FUTEX_SYSTEM_UNLOCK;
-		break;
+	FUTEX_LOCK_INIT((*newf), sx_opts);
+	TAILQ_INIT(&(*newf)->f_waiting_proc);
+	LIST_INSERT_HEAD(&futex_list, *newf, f_list);
+	FUTEXES_UNLOCK;
 
-	case LINUX_FUTEX_FD:
-#ifdef DEBUG
-		printf("linux_sys_futex: unimplemented op %d\n",
-		    args->op);
-#endif
-		return (ENOSYS);
+	FUTEX_LOCK((*newf));
+	if (flags & FUTEX_CREATE_WP) {
+		TAILQ_INSERT_HEAD(&(*newf)->f_waiting_proc, fx->wp, wp_list);
+		fx->wp->w_ftx = *newf;
+	}
 
-	case LINUX_FUTEX_WAKE_OP:
-		FUTEX_SYSTEM_LOCK;
-#ifdef DEBUG
-		if (ldebug(sys_futex))
-			printf("FUTEX_WAKE_OP: %d: uaddr = %p, op = %d, "
-			    "val = %x, uaddr2 = %p, val3 = %x\n",
-			    td->td_proc->p_pid, args->uaddr, args->op,
-			    args->val, args->uaddr2, args->val3);
-#endif
-		f = futex_get(args->uaddr, FUTEX_UNLOCKED);
-		f2 = futex_get(args->uaddr2, FUTEX_UNLOCKED);
+	LINUX_CTR3(sys_futex, "futex_get uaddr %p wp %p ref %d new",
+	    uaddr, fx->wp, (*newf)->f_refcount);
+}
 
-		/*
-		 * This function returns positive number as results and
-		 * negative as errors
-		 */
-		op_ret = futex_atomic_op(td, args->val3, args->uaddr2);
-#ifdef DEBUG
-		if (ldebug(sys_futex))
-			printf("futex_atomic_op ret %d\n", op_ret);
-#endif
-		if (op_ret < 0) {
-			/* XXX: We don't handle the EFAULT yet. */
-			if (op_ret != -EFAULT) {
-				futex_put(f);
-				futex_put(f2);
-				FUTEX_SYSTEM_UNLOCK;
-				return (-op_ret);
-			}
+static struct futex *
+futex_get(struct proc *p, uint32_t *uaddr, struct fx *fx, uint32_t flags)
+{
+	struct futex *f = NULL;
 
-			futex_put(f);
-			futex_put(f2);
+	KASSERT(flags != (FUTEX_CREATE_WP | FUTEX_DONTCREATE),
+	    ("FUTEX_CREATE_WP|FUTEX_DONTCREATE"));
 
-			FUTEX_SYSTEM_UNLOCK;
-			return (EFAULT);
-		}
+	if (flags & FUTEX_CREATE_WP) {
+		fx->wp = malloc(sizeof(*fx->wp), M_LINUX, M_WAITOK);
+		fx->wp->w_pid = p->p_pid;
+		fx->wp->w_flags = 0;
+		LINUX_CTR1(sys_futex, "futex_get alloc wp %p", fx->wp);
+	} else
+		fx->wp = NULL;
 
-		ret = futex_wake(f, args->val, NULL, 0);
-		futex_put(f);
-		if (op_ret > 0) {
-			op_ret = 0;
-			/*
-			 * Linux abuses the address of the timespec parameter
-			 * as the number of retries.
-			 */
-			op_ret += futex_wake(f2,
-			    (int)(unsigned long)args->timeout, NULL, 0);
-			ret += op_ret;
-		}
-		futex_put(f2);
-		td->td_retval[0] = ret;
+	futex_get0(uaddr, fx, &f, flags, 0);
+	return (fx->ftx);
+}
 
-		FUTEX_SYSTEM_UNLOCK;
-		break;
+static void
+futex_get_op(uint32_t *uaddr, struct fx *fx, uint32_t *uaddr2, struct fx *fx2)
+{
+	struct futex *f, *f2;
 
-	case LINUX_FUTEX_LOCK_PI:
-		/* not yet implemented */
-		return (ENOSYS);
+	KASSERT(uaddr != uaddr2, ("futex_get_op uaddr != uaddr2"));
 
-	case LINUX_FUTEX_UNLOCK_PI:
-		/* not yet implemented */
-		return (ENOSYS);
+	fx->flags = 0;
+	fx2->flags = 0;
+	f = NULL;
 
-	case LINUX_FUTEX_TRYLOCK_PI:
-		/* not yet implemented */
-		return (ENOSYS);
+	f2 = malloc(sizeof(*f2), M_LINUX, M_WAITOK | M_ZERO);
+	f2->f_uaddr = uaddr2;
+	refcount_init(&f2->f_refcount, 1);
 
-	default:
-		printf("linux_sys_futex: unknown op %d\n",
-		    args->op);
-		return (ENOSYS);
-	}
-	return (0);
+	futex_get0(uaddr, fx, &f, 0, SX_DUPOK);
+	futex_get0(uaddr2, fx2, &f2, 0, 0);
 }
 
-static struct futex *
-futex_get(void *uaddr, int locked)
+static int
+futex_sleep(struct fx *fx, unsigned long timeout)
 {
+	struct waiting_proc *wp;
 	struct futex *f;
-
-	if (locked == FUTEX_UNLOCKED)
-		FUTEX_LOCK;
-	LIST_FOREACH(f, &futex_list, f_list) {
-		if (f->f_uaddr == uaddr) {
-			f->f_refcount++;
-			if (locked == FUTEX_UNLOCKED)
-				FUTEX_UNLOCK;
-			return f;
-		}
-	}
-
-	f = malloc(sizeof(*f), M_LINUX, M_WAITOK);
-	f->f_uaddr = uaddr;
-	f->f_refcount = 1;
-	TAILQ_INIT(&f->f_waiting_proc);
-	LIST_INSERT_HEAD(&futex_list, f, f_list);
-	if (locked == FUTEX_UNLOCKED)
-		FUTEX_UNLOCK;
-
-	return f;
+	uint32_t *uaddr;
+	int error;
+
+	f = fx->ftx;
+	wp = fx->wp;
+	uaddr = f->f_uaddr;
+
+	FUTEX_LOCK_ASSERT(f, SA_XLOCKED);
+	LINUX_CTR4(sys_futex, "futex_sleep enter uaddr %p wp %p timo %ld ref %d",
+	    uaddr, wp, timeout, f->f_refcount);
+
+	error = sx_sleep(wp, &f->lock, PCATCH, "futex", timeout);
+
+	if (wp->w_flags & FUTEX_WP_REQUEUED) {
+		KASSERT(f != wp->w_ftx, ("f != w_ftx"));
+		LINUX_CTR5(sys_futex, "futex_sleep out error %d uaddr %p w"
+		    " %p requeued uaddr %p ref %d",
+		    error, uaddr, wp, wp->w_ftx->f_uaddr, wp->w_ftx->f_refcount);
+		futex_put0(f);
+
+		f = wp->w_ftx;
+		FUTEX_LOCK(f);
+	} else
+		LINUX_CTR3(sys_futex, "futex_sleep out error %d uaddr %p wp %p",
+		    error, uaddr, wp);
+
+	if ((wp->w_flags & FUTEX_WP_REMOVED) == 0)
+		TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
+	free(wp, M_LINUX);
+	futex_put0(f);
+	return (error);
 }
 
-static void
-futex_put(f)
-	struct futex *f;
+static int
+futex_wake(struct fx *f, int n)
 {
-	FUTEX_LOCK;
-	f->f_refcount--;
-	if (f->f_refcount == 0) {
-		LIST_REMOVE(f, f_list);
-		free(f, M_LINUX);
+	struct waiting_proc *wp, *wpt;
+	int count = 0;
+
+	FUTEX_LOCK_ASSERT(f->ftx, SA_XLOCKED);
+	TAILQ_FOREACH_SAFE(wp, &f->ftx->f_waiting_proc, wp_list, wpt) {
+		LINUX_CTR4(sys_futex, "futex_wake uaddr %p wp %p pid %d ref %d",
+		    f->ftx->f_uaddr, wp, wp->w_pid, f->ftx->f_refcount);
+		TAILQ_REMOVE(&f->ftx->f_waiting_proc, wp, wp_list);
+		wp->w_flags |= FUTEX_WP_REMOVED;
+		wakeup_one(wp);
+		if (++count == n)
+			break;
 	}
-	FUTEX_UNLOCK;
 
-	return;
+	return (count);
 }
 
 static int
-futex_sleep(struct futex *f, struct thread *td, unsigned long timeout)
+futex_requeue(struct fx *f, int n, struct fx *f2, int n2)
 {
-	struct waiting_proc *wp;
-	int ret;
-
-	wp = malloc(sizeof(*wp), M_LINUX, M_WAITOK);
-	wp->wp_t = td;
-	wp->wp_new_futex = NULL;
-	FUTEX_LOCK;
-	TAILQ_INSERT_TAIL(&f->f_waiting_proc, wp, wp_list);
-	FUTEX_UNLOCK;
-
-#ifdef DEBUG
-	if (ldebug(sys_futex))
-		printf("FUTEX --> %d tlseep timeout = %ld\n",
-		    td->td_proc->p_pid, timeout);
-#endif
-	ret = tsleep(wp, PCATCH | PZERO, "linuxfutex", timeout);
-#ifdef DEBUG
-	if (ldebug(sys_futex))
-		printf("FUTEX -> %d tsleep returns %d\n",
-		    td->td_proc->p_pid, ret);
-#endif
-
-	FUTEX_LOCK;
-	TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
-	FUTEX_UNLOCK;
-
-	/* if we got woken up in futex_wake */
-	if ((ret == 0) && (wp->wp_new_futex != NULL)) {
-		/* suspend us on the new futex */
-		ret = futex_sleep(wp->wp_new_futex, td, timeout);
-		/* and release the old one */
-		futex_put(wp->wp_new_futex);
+	struct waiting_proc *wp, *wpt;
+	int count = 0;
+
+	TAILQ_FOREACH_SAFE(wp, &f->ftx->f_waiting_proc, wp_list, wpt) {
+		if (++count <= n) {
+			LINUX_CTR3(sys_futex, "futex_requeue_wake uaddr %p wp %p (%d)",
+			    f->ftx->f_uaddr, wp, wp->w_pid);
+			TAILQ_REMOVE(&f->ftx->f_waiting_proc, wp, wp_list);
+			wp->w_flags |= FUTEX_WP_REMOVED;
+			wakeup_one(wp);
+		} else {
+			LINUX_CTR4(sys_futex, "futex_requeue uaddr %p wp %p (%d) to %p",
+			    f->ftx->f_uaddr, wp, wp->w_pid, f2->ftx->f_uaddr);
+			wp->w_flags |= FUTEX_WP_REQUEUED;
+			/* Move waiting_proc to f2 futex */
+			TAILQ_REMOVE(&f->ftx->f_waiting_proc, wp, wp_list);
+			TAILQ_INSERT_HEAD(&f2->ftx->f_waiting_proc, wp, wp_list);
+			wp->w_ftx = f2->ftx;
+			refcount_acquire(&f2->ftx->f_refcount);
+			if (count - n >= n2)
+				break;
+		}
 	}
 
-	free(wp, M_LINUX);
-
-	return ret;
+	return (count);
 }
 
 static int
-futex_wake(struct futex *f, int n, struct futex *newf, int n2)
+futex_wait(struct fx *f, struct l_timespec *ts)
 {
-	struct waiting_proc *wp;
-	int count;
+	struct l_timespec timeout = {0, 0};
+	struct timeval tv = {0, 0};
+	int timeout_hz;
+	int error;
+
+	if (ts != NULL) {
+		error = copyin(ts, &timeout, sizeof(timeout));
+		if (error)
+			return (error);
+	}
+
+	tv.tv_usec = timeout.tv_sec * 1000000 + timeout.tv_nsec / 1000;
+	timeout_hz = tvtohz(&tv);
 
+	if (timeout.tv_sec == 0 && timeout.tv_nsec == 0)
+		timeout_hz = 0;
 	/*
-	 * Linux is very strange it wakes up N threads for
-	 * all operations BUT requeue ones where its N+1
-	 * mimic this.
+	 * If the user process requests a non null timeout,
+	 * make sure we do not turn it into an infinite
+	 * timeout because timeout_hz gets null.
+	 *
+	 * We use a minimal timeout of 1/hz. Maybe it would
+	 * make sense to just return ETIMEDOUT without sleeping.
 	 */
-	count = newf ? 0 : 1;
+	if (((timeout.tv_sec != 0) || (timeout.tv_nsec != 0)) &&
+	    (timeout_hz == 0))
+		timeout_hz = 1;
 
-	FUTEX_LOCK;
-	TAILQ_FOREACH(wp, &f->f_waiting_proc, wp_list) {
-		if (count <= n) {
-			wakeup_one(wp);
-			count++;
-		} else {
-			if (newf != NULL) {
-				/* futex_put called after tsleep */
-				wp->wp_new_futex = futex_get(newf->f_uaddr,
-				    FUTEX_LOCKED);
-				wakeup_one(wp);
-				if (count - n >= n2)
-					break;
-			}
-		}
+	error = futex_sleep(f, timeout_hz);
+
+	switch (error) {
+	case EWOULDBLOCK:
+		error = ETIMEDOUT;
+		break;
+	case EINTR:
+		/* FALLTHROUGH */
+	case 0:
+		break;
+	default:
+		LINUX_CTR1(sys_futex, "futex_wait: unexpected ret = %d",
+		    error);
+		break;
 	}
-	FUTEX_UNLOCK;
 
-	return count;
+	return (error);
 }
 
 static int
-futex_atomic_op(struct thread *td, int encoded_op, caddr_t uaddr)
+futex_atomic_op(int encoded_op, uint32_t *uaddr)
 {
 	int op = (encoded_op >> 28) & 7;
 	int cmp = (encoded_op >> 24) & 15;
@@ -488,12 +407,8 @@ futex_atomic_op(struct thread *td, int encoded_op, caddr_t uaddr)
 	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
 		oparg = 1 << oparg;
 
-#ifdef DEBUG
-	if (ldebug(sys_futex))
-		printf("futex_atomic_op: op = %d, cmp = %d, oparg = %x, "
-		       "cmparg = %x, uaddr = %p\n",
-		       op, cmp, oparg, cmparg, uaddr);
-#endif
+	LINUX_CTR1(sys_futex, "futex_wake_op oparg %d", oparg);
+
 	/* XXX: linux verifies access here and returns EFAULT */
 
 	switch (op) {
@@ -539,14 +454,184 @@ futex_atomic_op(struct thread *td, int encoded_op, caddr_t uaddr)
 }
 
 int
+linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
+{
+	struct proc *p = td->td_proc;
+	int op_ret, val, ret;
+	struct fx f, f2;
+	int error = 0;
+
+	/*
+	 * Our implementation provides only privates futexes. Most of the apps
+	 * should use private futexes but don't claim so. Therefore we treat
+	 * all futexes as private by clearing the FUTEX_PRIVATE_FLAG. It works
+	 * in most cases (ie. when futexes are not shared on file descriptor
+	 * or between different processes.).
+	 */
+	args->op = (args->op & ~LINUX_FUTEX_PRIVATE_FLAG);
+
+	switch (args->op) {
+	case LINUX_FUTEX_WAIT:
+
+		LINUX_CTR2(sys_futex, "futex_wait val %d uaddr %p",
+		    args->val, args->uaddr);
+
+		futex_get(p, args->uaddr, &f, FUTEX_CREATE_WP);
+
+		error = copyin(args->uaddr, &val, sizeof(val));
+		if (error) {
+			LINUX_CTR1(sys_futex, "futex_wait COPYIN FAILED %d",
+			    error);
+			futex_put(&f);
+			return (error);
+		}
+		if (val != args->val) {
+			LINUX_CTR3(sys_futex, "futex_wait uaddr %p WHOOPS %d != %d",
+			    args->uaddr, args->val, val);
+			futex_put(&f);
+			return (EWOULDBLOCK);
+		}
+
+		error = futex_wait(&f, args->timeout);
+		break;
+
+	case LINUX_FUTEX_WAKE:
+
+		/*
+		 * XXX: Linux is able to cope with different addresses
+		 * corresponding to the same mapped memory in the sleeping
+		 * and waker process(es).
+		 */
+		LINUX_CTR2(sys_futex, "futex_wake val %d uaddr %p",
+		    args->val, args->uaddr);
+
+		if (futex_get(p, args->uaddr, &f, FUTEX_DONTCREATE)) {
+			td->td_retval[0] = futex_wake(&f, args->val);
+			futex_put(&f);
+		}
+		break;
+
+	case LINUX_FUTEX_CMP_REQUEUE:
+
+		LINUX_CTR5(sys_futex, "futex_cmp_requeue uaddr %p "
+		    "val %d val3 %d uaddr2 %p val2 %d",
+		    args->uaddr, args->val, args->val3, args->uaddr2,
+		    (int)(unsigned long)args->timeout);
+
+		futex_get_op(args->uaddr, &f, args->uaddr2, &f2);
+
+		error = copyin(args->uaddr, &val, sizeof(val));
+		if (error) {
+			LINUX_CTR1(sys_futex, "futex_cmp_requeue "
+			    " COPYIN FAILED %d", error);
+			futex_put(&f2);
+			futex_put(&f);
+			return (error);
+		}
+		if (val != args->val3) {
+			LINUX_CTR2(sys_futex, "futex_cmp_requeue WHOOPS"
+			    " VAL %d != UVAL %d", args->val, val);
+			futex_put(&f2);
+			futex_put(&f);
+			return (EAGAIN);
+		}
+
+		td->td_retval[0] = futex_requeue(&f, args->val, &f2,
+		    (int)(unsigned long)args->timeout);
+
+		futex_put(&f2);
+		futex_put(&f);
+		break;
+
+	case LINUX_FUTEX_REQUEUE:
+
+		LINUX_CTR4(sys_futex, "FUTEX_REQUEUE uaddr %p "
+		    "val %d uaddr2 %p val2 %d",
+		    args->uaddr, args->val, args->uaddr2,
+		    (int)(unsigned long)args->timeout);
+
+		futex_get_op(args->uaddr, &f, args->uaddr2, &f2);
+
+		td->td_retval[0] = futex_requeue(&f, args->val, &f2,
+		    (int)(unsigned long)args->timeout);
+
+		futex_put(&f2);
+		futex_put(&f);
+		break;
+
+	case LINUX_FUTEX_WAKE_OP:
+
+		LINUX_CTR5(sys_futex, "futex_wake_op "
+		    "uaddr %p op %d val %x uaddr2 %p val3 %x",
+		    args->uaddr, args->op, args->val,
+		    args->uaddr2, args->val3);
+
+		futex_get_op(args->uaddr, &f, args->uaddr2, &f2);
+
+		/*
+		 * This function returns positive number as results and
+		 * negative as errors
+		 */
+		op_ret = futex_atomic_op(args->val3, args->uaddr2);
+
+		LINUX_CTR1(sys_futex, "futex_wake_op opret %d", op_ret);
+
+		if (op_ret < 0) {
+			/* XXX: We don't handle the EFAULT yet. */
+			if (op_ret != -EFAULT) {
+				futex_put(&f);
+				return (-op_ret);
+			}
+			futex_put(&f);
+			return (EFAULT);
+		}
+
+		ret = futex_wake(&f, args->val);
+
+		if (op_ret > 0) {
+			op_ret = 0;
+			/*
+			 * Linux abuses the address of the timespec parameter
+			 * as the number of retries.
+			 */
+			op_ret += futex_wake( &f2,
+			    (int)(unsigned long)args->timeout);
+			ret += op_ret;
+
+		}
+		futex_put(&f2);
+		futex_put(&f);
+		td->td_retval[0] = ret;
+		LINUX_CTR1(sys_futex, "futex_wake_op returns %d", ret);
+		break;
+
+	case LINUX_FUTEX_LOCK_PI:
+		/* not yet implemented */
+		return (ENOSYS);
+
+	case LINUX_FUTEX_UNLOCK_PI:
+		/* not yet implemented */
+		return (ENOSYS);
+
+	case LINUX_FUTEX_TRYLOCK_PI:
+		/* not yet implemented */
+		return (ENOSYS);
+
+	default:
+		printf("linux_sys_futex: unknown op %d\n", args->op);
+		return (ENOSYS);
+	}
+
+	return (error);
+}
+
+int
 linux_set_robust_list(struct thread *td, struct linux_set_robust_list_args *args)
 {
 	struct linux_emuldata *em;
 
-#ifdef	DEBUG
-	if (ldebug(set_robust_list))
-		printf(ARGS(set_robust_list, ""));
-#endif
+	LINUX_CTR2(set_robust_list, "head %p len %d", args->head, args->len);
+
 	if (args->len != sizeof(struct linux_robust_list_head))
 		return (EINVAL);
 
@@ -565,10 +650,7 @@ linux_get_robust_list(struct thread *td, struct linux_get_robust_list_args *args
 	l_size_t len = sizeof(struct linux_robust_list_head);
 	int error = 0;
 
-#ifdef	DEBUG
-	if (ldebug(get_robust_list))
-		printf(ARGS(get_robust_list, ""));
-#endif
+	LINUX_CTR(get_robust_list);
 
 	if (!args->pid) {
 		em = em_find(td->td_proc, EMUL_DONTLOCK);
@@ -601,16 +683,16 @@ linux_get_robust_list(struct thread *td, struct linux_get_robust_list_args *args
 }
 
 static int
-handle_futex_death(void *uaddr, pid_t pid, int pi)
+handle_futex_death(struct proc *p, uint32_t *uaddr, int pi)
 {
-	int uval, nval, mval;
-	struct futex *f;
+	uint32_t uval, nval, mval;
+	struct fx f;
 
+	LINUX_CTR1(release_futexes, "futex_death uaddr %p", uaddr);
 retry:
 	if (copyin(uaddr, &uval, 4))
 		return (EFAULT);
-
-	if ((uval & FUTEX_TID_MASK) == pid) {
+	if ((uval & FUTEX_TID_MASK) == p->p_pid) {
 		mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
 		nval = casuword32(uaddr, uval, mval);
 
@@ -621,8 +703,10 @@ retry:
 			goto retry;
 
 		if (!pi && (uval & FUTEX_WAITERS)) {
-			f = futex_get(uaddr, FUTEX_UNLOCKED);
-			futex_wake(f, 1, NULL, 0);
+			if (futex_get(p, uaddr, &f, FUTEX_DONTCREATE)) {
+				futex_wake(&f, 1);
+				futex_put(&f);
+			}
 		}
 	}
 
@@ -658,6 +742,8 @@ release_futexes(struct proc *p)
 	em = em_find(p, EMUL_DONTLOCK);
 	head = em->robust_futexes;
 
+	LINUX_CTR1(release_futexes, "head %p", head);
+
 	if (head == NULL)
 		return;
 
@@ -674,8 +760,7 @@ release_futexes(struct proc *p)
 		rc = fetch_robust_entry(&next_entry, PTRIN(&entry->next), &next_pi);
 
 		if (entry != pending)
-			if (handle_futex_death((char *)entry + futex_offset,
-			    p->p_pid, pi))
+			if (handle_futex_death(p, (uint32_t *)entry + futex_offset, pi))
 				return;
 
 		if (rc)
@@ -691,6 +776,5 @@ release_futexes(struct proc *p)
 	}
 
 	if (pending)
-		handle_futex_death((char *) pending + futex_offset,
-		    p->p_pid, pip);
+		handle_futex_death(p, (uint32_t *)pending + futex_offset, pip);
 }
diff --git a/sys/compat/linux/linux_futex.h b/sys/compat/linux/linux_futex.h
index d658925..ca8b768 100644
--- a/sys/compat/linux/linux_futex.h
+++ b/sys/compat/linux/linux_futex.h
@@ -38,7 +38,7 @@
 
 #define LINUX_FUTEX_WAIT	0
 #define LINUX_FUTEX_WAKE	1
-#define LINUX_FUTEX_FD		2
+#define LINUX_FUTEX_FD		2	/* unused */
 #define LINUX_FUTEX_REQUEUE	3
 #define LINUX_FUTEX_CMP_REQUEUE	4
 #define LINUX_FUTEX_WAKE_OP	5
diff --git a/sys/compat/linux/linux_getcwd.c b/sys/compat/linux/linux_getcwd.c
index 2ab69c5..bf23f75 100644
--- a/sys/compat/linux/linux_getcwd.c
+++ b/sys/compat/linux/linux_getcwd.c
@@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/namei.h>
 #include <sys/filedesc.h>
 #include <sys/kernel.h>
+#include <sys/ktr.h>
 #include <sys/file.h>
 #include <sys/stat.h>
 #include <sys/syscallsubr.h>
@@ -424,10 +425,7 @@ linux_getcwd(struct thread *td, struct linux_getcwd_args *args)
 	caddr_t bp, bend, path;
 	int error, len, lenused;
 
-#ifdef DEBUG
-	if (ldebug(getcwd))
-		printf(ARGS(getcwd, "%p, %ld"), args->buf, (long)args->bufsize);
-#endif
+	LINUX_CTR2(getcwd, "%p, %ld", args->buf, (long)args->bufsize);
 
 	len = args->bufsize;
 
diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c
index 967ab71..c52dc5b 100644
--- a/sys/compat/linux/linux_ioctl.c
+++ b/sys/compat/linux/linux_ioctl.c
@@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/kbio.h>
 #include <sys/kernel.h>
 #include <sys/linker_set.h>
+#include <sys/ktr.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/proc.h>
@@ -200,12 +201,10 @@ linux_ioctl_hdio(struct thread *td, struct linux_ioctl_args *args)
 		 */
 		bytespercyl = (off_t) sectorsize * fwheads * fwsectors;
 		fwcylinders = mediasize / bytespercyl;
-#if defined(DEBUG)
-		linux_msg(td, "HDIO_GET_GEO: mediasize %jd, c/h/s %d/%d/%d, "
+		LINUX_CTR5(ioctl, "HDIO_GET_GEO: mediasize %jd, c/h/s %d/%d/%d, "
 			  "bpc %jd",
 			  (intmax_t)mediasize, fwcylinders, fwheads, fwsectors, 
 			  (intmax_t)bytespercyl);
-#endif
 		if ((args->cmd & 0xffff) == LINUX_HDIO_GET_GEO) {
 			struct linux_hd_geometry hdg;
 
@@ -355,18 +354,10 @@ bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios)
 {
 	int i;
 
-#ifdef DEBUG
-	if (ldebug(ioctl)) {
-		printf("LINUX: BSD termios structure (input):\n");
-		printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
-		    bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
-		    bios->c_ispeed, bios->c_ospeed);
-		printf("c_cc ");
-		for (i=0; i<NCCS; i++)
-			printf("%02x ", bios->c_cc[i]);
-		printf("\n");
-	}
-#endif
+	LINUX_CTR0(ioctl, "LINUX: BSD termios structure (input):");
+	LINUX_CTR6(ioctl, "i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d",
+	    bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
+	    bios->c_ispeed, bios->c_ospeed);
 
 	lios->c_iflag = 0;
 	if (bios->c_iflag & IGNBRK)
@@ -477,18 +468,10 @@ bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios)
 	}
 	lios->c_line = 0;
 
-#ifdef DEBUG
-	if (ldebug(ioctl)) {
-		printf("LINUX: LINUX termios structure (output):\n");
-		printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
-		    lios->c_iflag, lios->c_oflag, lios->c_cflag,
-		    lios->c_lflag, (int)lios->c_line);
-		printf("c_cc ");
-		for (i=0; i<LINUX_NCCS; i++)
-			printf("%02x ", lios->c_cc[i]);
-		printf("\n");
-	}
-#endif
+	LINUX_CTR0(ioctl, "LINUX: LINUX termios structure (output):");
+	LINUX_CTR5(ioctl, "i=%08x o=%08x c=%08x l=%08x line=%d",
+	    lios->c_iflag, lios->c_oflag, lios->c_cflag,
+	    lios->c_lflag, (int)lios->c_line);
 }
 
 static void
@@ -496,18 +479,10 @@ linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios)
 {
 	int i;
 
-#ifdef DEBUG
-	if (ldebug(ioctl)) {
-		printf("LINUX: LINUX termios structure (input):\n");
-		printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
-		    lios->c_iflag, lios->c_oflag, lios->c_cflag,
-		    lios->c_lflag, (int)lios->c_line);
-		printf("c_cc ");
-		for (i=0; i<LINUX_NCCS; i++)
-			printf("%02x ", lios->c_cc[i]);
-		printf("\n");
-	}
-#endif
+	LINUX_CTR0(ioctl, "LINUX: LINUX termios structure (input):");
+	LINUX_CTR5(ioctl, "i=%08x o=%08x c=%08x l=%08x line=%d",
+	    lios->c_iflag, lios->c_oflag, lios->c_cflag,
+	    lios->c_lflag, (int)lios->c_line);
 
 	bios->c_iflag = 0;
 	if (lios->c_iflag & LINUX_IGNBRK)
@@ -619,18 +594,10 @@ linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios)
 	bios->c_ispeed = bios->c_ospeed =
 	    linux_to_bsd_speed(lios->c_cflag & LINUX_CBAUD, sptab);
 
-#ifdef DEBUG
-	if (ldebug(ioctl)) {
-		printf("LINUX: BSD termios structure (output):\n");
-		printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
-		    bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
-		    bios->c_ispeed, bios->c_ospeed);
-		printf("c_cc ");
-		for (i=0; i<NCCS; i++)
-			printf("%02x ", bios->c_cc[i]);
-		printf("\n");
-	}
-#endif
+	LINUX_CTR0(ioctl, "LINUX: BSD termios structure (output):");
+	LINUX_CTR6(ioctl, "i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d",
+	    bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
+	    bios->c_ispeed, bios->c_ospeed);
 }
 
 static void
@@ -2343,10 +2310,8 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
 	case LINUX_SIOCSPGRP:
 	case LINUX_SIOCGIFCOUNT:
 		/* these ioctls don't take an interface name */
-#ifdef DEBUG
-		printf("%s(): ioctl %d\n", __func__,
-		    args->cmd & 0xffff);
-#endif
+		LINUX_CTR2(ioctl, "%s(): ioctl %d",
+		    __func__, args->cmd & 0xffff);
 		break;
 
 	case LINUX_SIOCGIFFLAGS:
@@ -2368,10 +2333,8 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
 		error = copyin((void *)args->arg, lifname, LINUX_IFNAMSIZ);
 		if (error != 0)
 			return (error);
-#ifdef DEBUG
-		printf("%s(): ioctl %d on %.*s\n", __func__,
-		    args->cmd & 0xffff, LINUX_IFNAMSIZ, lifname);
-#endif
+		LINUX_CTR4(ioctl, "%s(): ioctl %d on %.*s",
+		    __func__, args->cmd & 0xffff, LINUX_IFNAMSIZ, lifname);
 		ifp = ifname_linux_to_bsd(lifname, ifname);
 		if (ifp == NULL)
 			return (EINVAL);
@@ -2384,10 +2347,8 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
 		error = copyout(ifname, (void *)args->arg, IFNAMSIZ);
 		if (error != 0)
 			return (error);
-#ifdef DEBUG
-		printf("%s(): %s translated to %s\n", __func__,
-		    lifname, ifname);
-#endif
+		LINUX_CTR3(ioctl, "%s(): %s translated to %s",
+		    __func__, lifname, ifname);
 		break;
 
 	default:
@@ -2526,9 +2487,7 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
 		/* restore the original interface name */
 		copyout(lifname, (void *)args->arg, LINUX_IFNAMSIZ);
 
-#ifdef DEBUG
-	printf("%s(): returning %d\n", __func__, error);
-#endif
+	LINUX_CTR2(ioctl, "%s(): returning %d", __func__, error);
 	return (error);
 }
 
@@ -2617,11 +2576,7 @@ linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
 	struct handler_element *he;
 	int error, cmd;
 
-#ifdef DEBUG
-	if (ldebug(ioctl))
-		printf(ARGS(ioctl, "%d, %04lx, *"), args->fd,
-		    (unsigned long)args->cmd);
-#endif
+	LINUX_CTR2(ioctl, "%d %04lx", args->fd, (unsigned long)args->cmd);
 
 	if ((error = fget(td, args->fd, &fp)) != 0)
 		return (error);
diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
index bdbb5dd..fe76101 100644
--- a/sys/compat/linux/linux_misc.c
+++ b/sys/compat/linux/linux_misc.c
@@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
 #endif
 #include <sys/jail.h>
 #include <sys/kernel.h>
+#include <sys/ktr.h>
 #include <sys/limits.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
@@ -92,10 +93,6 @@ __FBSDID("$FreeBSD$");
 #include <compat/linux/linux_emul.h>
 #include <compat/linux/linux_misc.h>
 
-#ifdef __i386__
-#include <machine/cputypes.h>
-#endif
-
 #define BSD_TO_LINUX_SIGNAL(sig)	\
 	(((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig)
 
@@ -174,11 +171,8 @@ linux_alarm(struct thread *td, struct linux_alarm_args *args)
 	u_int secs;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(alarm))
-		printf(ARGS(alarm, "%u"), args->secs);
-#endif
-	
+	LINUX_CTR1(alarm, "%d", args->secs);
+
 	secs = args->secs;
 
 	if (secs > INT_MAX)
@@ -208,10 +202,8 @@ linux_brk(struct thread *td, struct linux_brk_args *args)
 		char * nsize;
 	} */ tmp;
 
-#ifdef DEBUG
-	if (ldebug(brk))
-		printf(ARGS(brk, "%p"), (void *)(uintptr_t)args->dsend);
-#endif
+	LINUX_CTR1(brk, "%p", (void *)(uintptr_t)args->dsend);
+
 	old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
 	new = (vm_offset_t)args->dsend;
 	tmp.nsize = (char *)new;
@@ -243,10 +235,7 @@ linux_uselib(struct thread *td, struct linux_uselib_args *args)
 
 	LCONVPATHEXIST(td, args->library, &library);
 
-#ifdef DEBUG
-	if (ldebug(uselib))
-		printf(ARGS(uselib, "%s"), library);
-#endif
+	LINUX_CTR(uselib);
 
 	a_out = NULL;
 	vfslocked = 0;
@@ -391,9 +380,7 @@ linux_uselib(struct thread *td, struct linux_uselib_args *args)
 	 * (what a waste).
 	 */
 	if (file_offset & PAGE_MASK) {
-#ifdef DEBUG
-		printf("uselib: Non page aligned binary %lu\n", file_offset);
-#endif
+		LINUX_CTR1(uselib, "non page aligned binary %lu", file_offset);
 		/* Map text+data read/write/execute */
 
 		/* a_entry is the load address and is page aligned */
@@ -425,9 +412,7 @@ linux_uselib(struct thread *td, struct linux_uselib_args *args)
 		if (error)
 			goto cleanup;
 	} else {
-#ifdef DEBUG
-		printf("uselib: Page aligned binary %lu\n", file_offset);
-#endif
+		LINUX_CTR1(uselib, "page aligned binary %lu", file_offset);
 		/*
 		 * for QMAGIC, a_entry is 20 bytes beyond the load address
 		 * to skip the executable header
@@ -444,10 +429,8 @@ linux_uselib(struct thread *td, struct linux_uselib_args *args)
 		if (error)
 			goto cleanup;
 	}
-#ifdef DEBUG
-	printf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long *)vmaddr)[0],
-	    ((long *)vmaddr)[1]);
-#endif
+	LINUX_CTR3(uselib, "mem=%08lx = %08lx %08lx",
+	    (long)vmaddr, ((long *)vmaddr)[0], ((long *)vmaddr)[1]);
 	if (bss_size != 0) {
 		/* Calculate BSS start address */
 		vmaddr = trunc_page(a_out->a_entry) + a_out->a_text +
@@ -484,12 +467,7 @@ linux_select(struct thread *td, struct linux_select_args *args)
 	struct timeval tv0, tv1, utv, *tvp;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(select))
-		printf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds,
-		    (void *)args->readfds, (void *)args->writefds,
-		    (void *)args->exceptfds, (void *)args->timeout);
-#endif
+	LINUX_CTR1(select, "nfds %d", args->nfds);
 
 	/*
 	 * Store current time for computation of the amount of
@@ -500,11 +478,9 @@ linux_select(struct thread *td, struct linux_select_args *args)
 			goto select_out;
 		utv.tv_sec = ltv.tv_sec;
 		utv.tv_usec = ltv.tv_usec;
-#ifdef DEBUG
-		if (ldebug(select))
-			printf(LMSG("incoming timeout (%jd/%ld)"),
-			    (intmax_t)utv.tv_sec, utv.tv_usec);
-#endif
+
+		LINUX_CTR2(select, "incoming timeout (%jd/%ld)",
+		    (intmax_t)utv.tv_sec, utv.tv_usec);
 
 		if (itimerfix(&utv)) {
 			/*
@@ -528,10 +504,8 @@ linux_select(struct thread *td, struct linux_select_args *args)
 	error = kern_select(td, args->nfds, args->readfds, args->writefds,
 	    args->exceptfds, tvp);
 
-#ifdef DEBUG
-	if (ldebug(select))
-		printf(LMSG("real select returns %d"), error);
-#endif
+	LINUX_CTR1(select, "real select returns %d", error);
+
 	if (error)
 		goto select_out;
 
@@ -550,11 +524,10 @@ linux_select(struct thread *td, struct linux_select_args *args)
 				timevalclear(&utv);
 		} else
 			timevalclear(&utv);
-#ifdef DEBUG
-		if (ldebug(select))
-			printf(LMSG("outgoing timeout (%jd/%ld)"),
-			    (intmax_t)utv.tv_sec, utv.tv_usec);
-#endif
+
+		LINUX_CTR2(select, "outgoing timeout (%jd/%ld)",
+		    (intmax_t)utv.tv_sec, utv.tv_usec);
+
 		ltv.tv_sec = utv.tv_sec;
 		ltv.tv_usec = utv.tv_usec;
 		if ((error = copyout(&ltv, args->timeout, sizeof(ltv))))
@@ -562,10 +535,7 @@ linux_select(struct thread *td, struct linux_select_args *args)
 	}
 
 select_out:
-#ifdef DEBUG
-	if (ldebug(select))
-		printf(LMSG("select_out -> %d"), error);
-#endif
+	LINUX_CTR1(select, "out %d", error);
 	return error;
 }
 
@@ -578,14 +548,11 @@ linux_mremap(struct thread *td, struct linux_mremap_args *args)
 	} */ bsd_args;
 	int error = 0;
 
-#ifdef DEBUG
-	if (ldebug(mremap))
-		printf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"),
-		    (void *)(uintptr_t)args->addr,
-		    (unsigned long)args->old_len,
-		    (unsigned long)args->new_len,
-		    (unsigned long)args->flags);
-#endif
+	LINUX_CTR4(mremap, "%p %08lx %08lx  08lx",
+	    (void *)(uintptr_t)args->addr,
+	    (unsigned long)args->old_len,
+	    (unsigned long)args->new_len,
+	    (unsigned long)args->flags);
 
 	if (args->flags & ~(LINUX_MREMAP_FIXED | LINUX_MREMAP_MAYMOVE)) {
 		td->td_retval[0] = 0;
@@ -629,6 +596,9 @@ linux_msync(struct thread *td, struct linux_msync_args *args)
 {
 	struct msync_args bsd_args;
 
+	LINUX_CTR3(msync, "%p %d %d", (void *)(uintptr_t)args->addr,
+	    (uintptr_t)args->len, args->fl);
+
 	bsd_args.addr = (caddr_t)(uintptr_t)args->addr;
 	bsd_args.len = (uintptr_t)args->len;
 	bsd_args.flags = args->fl & ~LINUX_MS_SYNC;
@@ -643,11 +613,6 @@ linux_time(struct thread *td, struct linux_time_args *args)
 	l_time_t tm;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(time))
-		printf(ARGS(time, "*"));
-#endif
-
 	microtime(&tv);
 	tm = tv.tv_sec;
 	if (args->tm && (error = copyout(&tm, args->tm, sizeof(tm))))
@@ -675,11 +640,6 @@ linux_times(struct thread *td, struct linux_times_args *args)
 	struct proc *p;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(times))
-		printf(ARGS(times, "*"));
-#endif
-
 	if (args->buf != NULL) {
 		p = td->td_proc;
 		PROC_LOCK(p);
@@ -713,11 +673,6 @@ linux_newuname(struct thread *td, struct linux_newuname_args *args)
 	char osrelease[LINUX_MAX_UTSNAME];
 	char *p;
 
-#ifdef DEBUG
-	if (ldebug(newuname))
-		printf(ARGS(newuname, "*"));
-#endif
-
 	linux_get_osname(td, osname);
 	linux_get_osrelease(td, osrelease);
 
@@ -731,34 +686,8 @@ linux_newuname(struct thread *td, struct linux_newuname_args *args)
 			*p = '\0';
 			break;
 		}
-#ifdef __i386__
-	{
-		const char *class;
+	strlcpy(utsname.machine, linux_platform, LINUX_MAX_UTSNAME);
 
-		switch (cpu_class) {
-		case CPUCLASS_686:
-			class = "i686";
-			break;
-		case CPUCLASS_586:
-			class = "i586";
-			break;
-		case CPUCLASS_486:
-			class = "i486";
-			break;
-		default:
-			class = "i386";
-		}
-		strlcpy(utsname.machine, class, LINUX_MAX_UTSNAME);
-	}
-#elif defined(__amd64__)	/* XXX: Linux can change 'personality'. */
-#ifdef COMPAT_LINUX32
-	strlcpy(utsname.machine, "i686", LINUX_MAX_UTSNAME);
-#else
-	strlcpy(utsname.machine, "x86_64", LINUX_MAX_UTSNAME);
-#endif /* COMPAT_LINUX32 */
-#else /* something other than i386 or amd64 - assume we and Linux agree */
-	strlcpy(utsname.machine, machine, LINUX_MAX_UTSNAME);
-#endif /* __i386__ */
 	mtx_lock(&hostname_mtx);
 	strlcpy(utsname.domainname, V_domainname, LINUX_MAX_UTSNAME);
 	mtx_unlock(&hostname_mtx);
@@ -782,10 +711,7 @@ linux_utime(struct thread *td, struct linux_utime_args *args)
 
 	LCONVPATHEXIST(td, args->fname, &fname);
 
-#ifdef DEBUG
-	if (ldebug(utime))
-		printf(ARGS(utime, "%s, *"), fname);
-#endif
+	LINUX_CTR(utime);
 
 	if (args->times) {
 		if ((error = copyin(args->times, &lut, sizeof lut))) {
@@ -815,10 +741,7 @@ linux_utimes(struct thread *td, struct linux_utimes_args *args)
 
 	LCONVPATHEXIST(td, args->fname, &fname);
 
-#ifdef DEBUG
-	if (ldebug(utimes))
-		printf(ARGS(utimes, "%s, *"), fname);
-#endif
+	LINUX_CTR(utimes);
 
 	if (args->tptr != NULL) {
 		if ((error = copyin(args->tptr, ltv, sizeof ltv))) {
@@ -848,10 +771,7 @@ linux_futimesat(struct thread *td, struct linux_futimesat_args *args)
 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
 	LCONVPATHEXIST_AT(td, args->filename, &fname, dfd);
 
-#ifdef DEBUG
-	if (ldebug(futimesat))
-		printf(ARGS(futimesat, "%s, *"), fname);
-#endif
+	LINUX_CTR(futimesat);
 
 	if (args->utimes != NULL) {
 		if ((error = copyin(args->utimes, ltv, sizeof ltv))) {
@@ -878,11 +798,8 @@ linux_waitpid(struct thread *td, struct linux_waitpid_args *args)
 {
 	int error, options, tmpstat;
 
-#ifdef DEBUG
-	if (ldebug(waitpid))
-		printf(ARGS(waitpid, "%d, %p, %d"),
-		    args->pid, (void *)args->status, args->options);
-#endif
+	LINUX_CTR3(waitpid, "%d, %p, %d", args->pid, (void *)args->status,
+	    args->options);
 	/*
 	 * this is necessary because the test in kern_wait doesn't work
 	 * because we mess with the options here
@@ -920,12 +837,8 @@ linux_wait4(struct thread *td, struct linux_wait4_args *args)
 	struct rusage ru, *rup;
 	struct proc *p;
 
-#ifdef DEBUG
-	if (ldebug(wait4))
-		printf(ARGS(wait4, "%d, %p, %d, %p"),
-		    args->pid, (void *)args->status, args->options,
-		    (void *)args->rusage);
-#endif
+	LINUX_CTR4(wait4, "%d, %p, %d %p", args->pid, (void *)args->status,
+	    args->options, (void *)args->rusage);
 
 	options = (args->options & (WNOHANG | WUNTRACED));
 	/* WLINUXCLONE should be equal to __WCLONE, but we make sure */
@@ -969,10 +882,7 @@ linux_mknod(struct thread *td, struct linux_mknod_args *args)
 
 	LCONVPATHCREAT(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(mknod))
-		printf(ARGS(mknod, "%s, %d, %d"), path, args->mode, args->dev);
-#endif
+	LINUX_CTR(mknod);
 
 	switch (args->mode & S_IFMT) {
 	case S_IFIFO:
@@ -1017,10 +927,7 @@ linux_mknodat(struct thread *td, struct linux_mknodat_args *args)
 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
 	LCONVPATHCREAT_AT(td, args->filename, &path, dfd);
 
-#ifdef DEBUG
-	if (ldebug(mknodat))
-		printf(ARGS(mknodat, "%s, %d, %d"), path, args->mode, args->dev);
-#endif
+	LINUX_CTR(mknodat);
 
 	switch (args->mode & S_IFMT) {
 	case S_IFIFO:
@@ -1062,10 +969,9 @@ linux_mknodat(struct thread *td, struct linux_mknodat_args *args)
 int
 linux_personality(struct thread *td, struct linux_personality_args *args)
 {
-#ifdef DEBUG
-	if (ldebug(personality))
-		printf(ARGS(personality, "%lu"), (unsigned long)args->per);
-#endif
+
+	LINUX_CTR1(personality, "%ld", (unsigned long)args->per);
+
 	if (args->per != 0)
 		return EINVAL;
 
@@ -1092,11 +998,7 @@ linux_setitimer(struct thread *td, struct linux_setitimer_args *uap)
 	struct l_itimerval ls;
 	struct itimerval aitv, oitv;
 
-#ifdef DEBUG
-	if (ldebug(setitimer))
-		printf(ARGS(setitimer, "%p, %p"),
-		    (void *)uap->itv, (void *)uap->oitv);
-#endif
+	LINUX_CTR2(setitimer, "%p %p", (void *)uap->itv, (void *)uap->oitv);
 
 	if (uap->itv == NULL) {
 		uap->itv = uap->oitv;
@@ -1107,14 +1009,12 @@ linux_setitimer(struct thread *td, struct linux_setitimer_args *uap)
 	if (error != 0)
 		return (error);
 	B2L_ITIMERVAL(&aitv, &ls);
-#ifdef DEBUG
-	if (ldebug(setitimer)) {
-		printf("setitimer: value: sec: %jd, usec: %ld\n",
-		    (intmax_t)aitv.it_value.tv_sec, aitv.it_value.tv_usec);
-		printf("setitimer: interval: sec: %jd, usec: %ld\n",
-		    (intmax_t)aitv.it_interval.tv_sec, aitv.it_interval.tv_usec);
-	}
-#endif
+
+	LINUX_CTR2(setitimer, "value: sec: %jd, usec: %ld",
+	    (intmax_t)aitv.it_value.tv_sec, aitv.it_value.tv_usec);
+	LINUX_CTR2(setitimer, "interval: sec: %jd, usec: %ld",
+	    (intmax_t)aitv.it_interval.tv_sec, aitv.it_interval.tv_usec);
+
 	error = kern_setitimer(td, uap->which, &aitv, &oitv);
 	if (error != 0 || uap->oitv == NULL)
 		return (error);
@@ -1130,10 +1030,8 @@ linux_getitimer(struct thread *td, struct linux_getitimer_args *uap)
 	struct l_itimerval ls;
 	struct itimerval aitv;
 
-#ifdef DEBUG
-	if (ldebug(getitimer))
-		printf(ARGS(getitimer, "%p"), (void *)uap->itv);
-#endif
+	LINUX_CTR1(getitimer, "%p", (void *)uap->itv);
+
 	error = kern_getitimer(td, uap->which, &aitv);
 	if (error != 0)
 		return (error);
@@ -1146,6 +1044,8 @@ linux_nice(struct thread *td, struct linux_nice_args *args)
 {
 	struct setpriority_args bsd_args;
 
+	LINUX_CTR1(nice, "%d", args->inc);
+
 	bsd_args.which = PRIO_PROCESS;
 	bsd_args.who = 0;		/* current process */
 	bsd_args.prio = args->inc;
@@ -1252,11 +1152,7 @@ linux_setrlimit(struct thread *td, struct linux_setrlimit_args *args)
 	u_int which;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(setrlimit))
-		printf(ARGS(setrlimit, "%d, %p"),
-		    args->resource, (void *)args->rlim);
-#endif
+	LINUX_CTR1(setrlimit, "%p", (void *)args->rlim);
 
 	if (args->resource >= LINUX_RLIM_NLIMITS)
 		return (EINVAL);
@@ -1282,11 +1178,7 @@ linux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args)
 	struct rlimit bsd_rlim;
 	u_int which;
 
-#ifdef DEBUG
-	if (ldebug(old_getrlimit))
-		printf(ARGS(old_getrlimit, "%d, %p"),
-		    args->resource, (void *)args->rlim);
-#endif
+	LINUX_CTR1(old_getrlimit, "%p", (void *)args->rlim);
 
 	if (args->resource >= LINUX_RLIM_NLIMITS)
 		return (EINVAL);
@@ -1325,11 +1217,7 @@ linux_getrlimit(struct thread *td, struct linux_getrlimit_args *args)
 	struct rlimit bsd_rlim;
 	u_int which;
 
-#ifdef DEBUG
-	if (ldebug(getrlimit))
-		printf(ARGS(getrlimit, "%d, %p"),
-		    args->resource, (void *)args->rlim);
-#endif
+	LINUX_CTR2(getrlimit, "%d %p", args->resource, (void *)args->rlim);
 
 	if (args->resource >= LINUX_RLIM_NLIMITS)
 		return (EINVAL);
@@ -1353,11 +1241,8 @@ linux_sched_setscheduler(struct thread *td,
 {
 	struct sched_setscheduler_args bsd;
 
-#ifdef DEBUG
-	if (ldebug(sched_setscheduler))
-		printf(ARGS(sched_setscheduler, "%d, %d, %p"),
-		    args->pid, args->policy, (const void *)args->param);
-#endif
+	LINUX_CTR3(sched_setscheduler, "%d %d %p", args->pid, args->policy,
+	    (const void *)args->param);
 
 	switch (args->policy) {
 	case LINUX_SCHED_OTHER:
@@ -1385,10 +1270,7 @@ linux_sched_getscheduler(struct thread *td,
 	struct sched_getscheduler_args bsd;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(sched_getscheduler))
-		printf(ARGS(sched_getscheduler, "%d"), args->pid);
-#endif
+	LINUX_CTR1(sched_getscheduler, "%d", args->pid);
 
 	bsd.pid = args->pid;
 	error = sched_getscheduler(td, &bsd);
@@ -1414,10 +1296,7 @@ linux_sched_get_priority_max(struct thread *td,
 {
 	struct sched_get_priority_max_args bsd;
 
-#ifdef DEBUG
-	if (ldebug(sched_get_priority_max))
-		printf(ARGS(sched_get_priority_max, "%d"), args->policy);
-#endif
+	LINUX_CTR1(sched_get_priority_max, "%d", args->policy);
 
 	switch (args->policy) {
 	case LINUX_SCHED_OTHER:
@@ -1441,10 +1320,7 @@ linux_sched_get_priority_min(struct thread *td,
 {
 	struct sched_get_priority_min_args bsd;
 
-#ifdef DEBUG
-	if (ldebug(sched_get_priority_min))
-		printf(ARGS(sched_get_priority_min, "%d"), args->policy);
-#endif
+	LINUX_CTR1(sched_get_priority_min, "%d", args->policy);
 
 	switch (args->policy) {
 	case LINUX_SCHED_OTHER:
@@ -1478,10 +1354,7 @@ linux_reboot(struct thread *td, struct linux_reboot_args *args)
 {
 	struct reboot_args bsd_args;
 
-#ifdef DEBUG
-	if (ldebug(reboot))
-		printf(ARGS(reboot, "0x%x"), args->cmd);
-#endif
+	LINUX_CTR1(reboot, "0x%x", args->cmd);
 
 	if (args->magic1 != REBOOT_MAGIC1)
 		return EINVAL;
@@ -1532,11 +1405,6 @@ linux_getpid(struct thread *td, struct linux_getpid_args *args)
 {
 	struct linux_emuldata *em;
 
-#ifdef DEBUG
-	if (ldebug(getpid))
-		printf(ARGS(getpid, ""));
-#endif
-
 	if (linux_use26(td)) {
 		em = em_find(td->td_proc, EMUL_DONTLOCK);
 		KASSERT(em != NULL, ("getpid: emuldata not found.\n"));
@@ -1552,11 +1420,6 @@ int
 linux_gettid(struct thread *td, struct linux_gettid_args *args)
 {
 
-#ifdef DEBUG
-	if (ldebug(gettid))
-		printf(ARGS(gettid, ""));
-#endif
-
 	td->td_retval[0] = td->td_proc->p_pid;
 	return (0);
 }
@@ -1568,11 +1431,6 @@ linux_getppid(struct thread *td, struct linux_getppid_args *args)
 	struct linux_emuldata *em;
 	struct proc *p, *pp;
 
-#ifdef DEBUG
-	if (ldebug(getppid))
-		printf(ARGS(getppid, ""));
-#endif
-
 	if (!linux_use26(td)) {
 		PROC_LOCK(td->td_proc);
 		td->td_retval[0] = td->td_proc->p_pptr->p_pid;
@@ -1588,9 +1446,7 @@ linux_getppid(struct thread *td, struct linux_getppid_args *args)
 	p = pfind(em->shared->group_pid);
 
 	if (p == NULL) {
-#ifdef DEBUG
-	   	printf(LMSG("parent process not found.\n"));
-#endif
+		LINUX_CTR0(getppid, "parent process not found");
 		return (0);
 	}
 
@@ -1616,11 +1472,6 @@ int
 linux_getgid(struct thread *td, struct linux_getgid_args *args)
 {
 
-#ifdef DEBUG
-	if (ldebug(getgid))
-		printf(ARGS(getgid, ""));
-#endif
-
 	td->td_retval[0] = td->td_ucred->cr_rgid;
 	return (0);
 }
@@ -1629,11 +1480,6 @@ int
 linux_getuid(struct thread *td, struct linux_getuid_args *args)
 {
 
-#ifdef DEBUG
-	if (ldebug(getuid))
-		printf(ARGS(getuid, ""));
-#endif
-
 	td->td_retval[0] = td->td_ucred->cr_ruid;
 	return (0);
 }
@@ -1644,11 +1490,6 @@ linux_getsid(struct thread *td, struct linux_getsid_args *args)
 {
 	struct getsid_args bsd;
 
-#ifdef DEBUG
-	if (ldebug(getsid))
-		printf(ARGS(getsid, "%i"), args->pid);
-#endif
-
 	bsd.pid = args->pid;
 	return getsid(td, &bsd);
 }
@@ -1666,10 +1507,7 @@ linux_getpriority(struct thread *td, struct linux_getpriority_args *args)
 	struct getpriority_args bsd_args;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(getpriority))
-		printf(ARGS(getpriority, "%i, %i"), args->which, args->who);
-#endif
+	LINUX_CTR2(getpriority, "%i %i", args->which, args->who);
 
 	bsd_args.which = args->which;
 	bsd_args.who = args->who;
@@ -1683,11 +1521,6 @@ linux_sethostname(struct thread *td, struct linux_sethostname_args *args)
 {
 	int name[2];
 
-#ifdef DEBUG
-	if (ldebug(sethostname))
-		printf(ARGS(sethostname, "*, %i"), args->len);
-#endif
-
 	name[0] = CTL_KERN;
 	name[1] = KERN_HOSTNAME;
 	return (userland_sysctl(td, name, 2, 0, 0, 0, args->hostname,
@@ -1699,11 +1532,6 @@ linux_setdomainname(struct thread *td, struct linux_setdomainname_args *args)
 {
 	int name[2];
 
-#ifdef DEBUG
-	if (ldebug(setdomainname))
-		printf(ARGS(setdomainname, "*, %i"), args->len);
-#endif
-
 	name[0] = CTL_KERN;
 	name[1] = KERN_NISDOMAINNAME;
 	return (userland_sysctl(td, name, 2, 0, 0, 0, args->name,
@@ -1716,10 +1544,7 @@ linux_exit_group(struct thread *td, struct linux_exit_group_args *args)
 	struct linux_emuldata *em, *td_em, *tmp_em;
 	struct proc *sp;
 
-#ifdef DEBUG
-	if (ldebug(exit_group))
-		printf(ARGS(exit_group, "%i"), args->error_code);
-#endif
+	LINUX_CTR1(exit_group, "%i", args->error_code);
 
 	if (linux_use26(td)) {
 		td_em = em_find(td->td_proc, EMUL_DONTLOCK);
@@ -1734,9 +1559,8 @@ linux_exit_group(struct thread *td, struct linux_exit_group_args *args)
 			sp = pfind(em->pid);
 			psignal(sp, SIGKILL);
 			PROC_UNLOCK(sp);
-#ifdef DEBUG
-			printf(LMSG("linux_sys_exit_group: kill PID %d\n"), em->pid);
-#endif
+
+			LINUX_CTR1(exit_group, "kill %d", em->pid);
 		}
 
 		EMUL_SHARED_RUNLOCK(&emul_shared_lock);
@@ -1760,11 +1584,8 @@ linux_prctl(struct thread *td, struct linux_prctl_args *args)
 	struct linux_emuldata *em;
 	int pdeath_signal;
 
-#ifdef DEBUG
-	if (ldebug(prctl))
-		printf(ARGS(prctl, "%d, %d, %d, %d, %d"), args->option,
-		    args->arg2, args->arg3, args->arg4, args->arg5);
-#endif
+	LINUX_CTR5(prctl, "%d %d %d %d %d", args->option, args->arg2,
+	    args->arg3, args->arg4, args->arg5);
 
 	switch (args->option) {
 	case LINUX_PR_SET_PDEATHSIG:
@@ -1839,11 +1660,8 @@ linux_sched_getaffinity(struct thread *td,
 	int error;
 	struct cpuset_getaffinity_args cga;
 
-#ifdef DEBUG
-	if (ldebug(sched_getaffinity))
-		printf(ARGS(sched_getaffinity, "%d, %d, *"), args->pid,
-		    args->len);
-#endif
+	LINUX_CTR2(sched_getaffinity, "%d %d", args->pid, args->len);
+
 	if (args->len < sizeof(cpuset_t))
 		return (EINVAL);
 
@@ -1868,11 +1686,8 @@ linux_sched_setaffinity(struct thread *td,
 {
 	struct cpuset_setaffinity_args csa;
 
-#ifdef DEBUG
-	if (ldebug(sched_setaffinity))
-		printf(ARGS(sched_setaffinity, "%d, %d, *"), args->pid,
-		    args->len);
-#endif
+	LINUX_CTR2(sched_setaffinity, "%d %d", args->pid, args->len);
+
 	if (args->len < sizeof(cpuset_t))
 		return (EINVAL);
 
diff --git a/sys/compat/linux/linux_misc.h b/sys/compat/linux/linux_misc.h
index c80a432..2cdb3c3 100644
--- a/sys/compat/linux/linux_misc.h
+++ b/sys/compat/linux/linux_misc.h
@@ -45,4 +45,6 @@
 #define	LINUX_MREMAP_MAYMOVE	1
 #define	LINUX_MREMAP_FIXED	2
 
+extern const char linux_platform[];
+
 #endif	/* _LINUX_MISC_H_ */
diff --git a/sys/compat/linux/linux_signal.c b/sys/compat/linux/linux_signal.c
index 9bbc268..7948d48 100644
--- a/sys/compat/linux/linux_signal.c
+++ b/sys/compat/linux/linux_signal.c
@@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/ktr.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/sx.h>
@@ -178,11 +179,7 @@ linux_signal(struct thread *td, struct linux_signal_args *args)
 	l_sigaction_t nsa, osa;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(signal))
-		printf(ARGS(signal, "%d, %p"),
-		    args->sig, (void *)(uintptr_t)args->handler);
-#endif
+	LINUX_CTR2(signal, "%d %p", args->sig, (void *)(uintptr_t)args->handler);
 
 	nsa.lsa_handler = args->handler;
 	nsa.lsa_flags = LINUX_SA_ONESHOT | LINUX_SA_NOMASK;
@@ -200,12 +197,8 @@ linux_rt_sigaction(struct thread *td, struct linux_rt_sigaction_args *args)
 	l_sigaction_t nsa, osa;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(rt_sigaction))
-		printf(ARGS(rt_sigaction, "%ld, %p, %p, %ld"),
-		    (long)args->sig, (void *)args->act,
-		    (void *)args->oact, (long)args->sigsetsize);
-#endif
+	LINUX_CTR4(rt_sigaction, "%d %p %p %ld", args->sig, (void *)args->act,
+	    (void *)args->oact, (long)args->sigsetsize);
 
 	if (args->sigsetsize != sizeof(l_sigset_t))
 		return (EINVAL);
@@ -269,10 +262,7 @@ linux_sigprocmask(struct thread *td, struct linux_sigprocmask_args *args)
 	l_sigset_t set, oset;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(sigprocmask))
-		printf(ARGS(sigprocmask, "%d, *, *"), args->how);
-#endif
+	LINUX_CTR1(sigprocmask, "%d", args->how);
 
 	if (args->mask != NULL) {
 		error = copyin(args->mask, &mask, sizeof(l_osigset_t));
@@ -300,12 +290,7 @@ linux_rt_sigprocmask(struct thread *td, struct linux_rt_sigprocmask_args *args)
 	l_sigset_t set, oset;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(rt_sigprocmask))
-		printf(ARGS(rt_sigprocmask, "%d, %p, %p, %ld"),
-		    args->how, (void *)args->mask,
-		    (void *)args->omask, (long)args->sigsetsize);
-#endif
+	LINUX_CTR1(rt_sigprocmask, "%d", args->how);
 
 	if (args->sigsetsize != sizeof(l_sigset_t))
 		return EINVAL;
@@ -333,11 +318,6 @@ linux_sgetmask(struct thread *td, struct linux_sgetmask_args *args)
 	struct proc *p = td->td_proc;
 	l_sigset_t mask;
 
-#ifdef DEBUG
-	if (ldebug(sgetmask))
-		printf(ARGS(sgetmask, ""));
-#endif
-
 	PROC_LOCK(p);
 	bsd_to_linux_sigset(&td->td_sigmask, &mask);
 	PROC_UNLOCK(p);
@@ -352,11 +332,6 @@ linux_ssetmask(struct thread *td, struct linux_ssetmask_args *args)
 	l_sigset_t lset;
 	sigset_t bset;
 
-#ifdef DEBUG
-	if (ldebug(ssetmask))
-		printf(ARGS(ssetmask, "%08lx"), (unsigned long)args->mask);
-#endif
-
 	PROC_LOCK(p);
 	bsd_to_linux_sigset(&td->td_sigmask, &lset);
 	td->td_retval[0] = lset.__bits[0];
@@ -381,11 +356,6 @@ linux_sigpending(struct thread *td, struct linux_sigpending_args *args)
 	l_sigset_t lset;
 	l_osigset_t mask;
 
-#ifdef DEBUG
-	if (ldebug(sigpending))
-		printf(ARGS(sigpending, "*"));
-#endif
-
 	PROC_LOCK(p);
 	bset = p->p_siglist;
 	SIGSETOR(bset, td->td_siglist);
@@ -409,12 +379,6 @@ linux_rt_sigpending(struct thread *td, struct linux_rt_sigpending_args *args)
 	if (args->sigsetsize > sizeof(lset))
 		return EINVAL;
 		/* NOT REACHED */
-
-#ifdef DEBUG
-	if (ldebug(rt_sigpending))
-		printf(ARGS(rt_sigpending, "*"));
-#endif
-
 	PROC_LOCK(p);
 	bset = p->p_siglist;
 	SIGSETOR(bset, td->td_siglist);
@@ -440,10 +404,6 @@ linux_rt_sigtimedwait(struct thread *td,
 	l_siginfo_t linfo;
 	ksiginfo_t info;
 
-#ifdef DEBUG
-	if (ldebug(rt_sigtimedwait))
-		printf(ARGS(rt_sigtimedwait, "*"));
-#endif
 	if (args->sigsetsize != sizeof(l_sigset_t))
 		return (EINVAL);
 
@@ -455,11 +415,10 @@ linux_rt_sigtimedwait(struct thread *td,
 	if (args->timeout) {
 		if ((error = copyin(args->timeout, &ltv, sizeof(ltv))))
 			return (error);
-#ifdef DEBUG
-		if (ldebug(rt_sigtimedwait))
-			printf(LMSG("linux_rt_sigtimedwait: incoming timeout (%d/%d)\n"),
-				ltv.tv_sec, ltv.tv_usec);
-#endif
+
+		LINUX_CTR2(rt_sigtimedwait, "incoming timeout (%d/%d)",
+		    ltv.tv_sec, ltv.tv_usec);
+
 		tv.tv_sec = (long)ltv.tv_sec;
 		tv.tv_usec = (suseconds_t)ltv.tv_usec;
 		if (itimerfix(&tv)) {
@@ -475,20 +434,17 @@ linux_rt_sigtimedwait(struct thread *td,
 			}
 			if (tv.tv_sec < 0)
 				timevalclear(&tv);
-#ifdef DEBUG
-			if (ldebug(rt_sigtimedwait))
-				printf(LMSG("linux_rt_sigtimedwait: converted timeout (%jd/%ld)\n"),
-					(intmax_t)tv.tv_sec, tv.tv_usec);
-#endif
+
+			LINUX_CTR2(rt_sigtimedwait, "converted (%jd/%ld)",
+			    (intmax_t)tv.tv_sec, tv.tv_usec);
 		}
 		TIMEVAL_TO_TIMESPEC(&tv, &ts);
 		tsa = &ts;
 	}
 	error = kern_sigtimedwait(td, bset, &info, tsa);
-#ifdef DEBUG
-	if (ldebug(rt_sigtimedwait))
-		printf(LMSG("linux_rt_sigtimedwait: sigtimedwait returning (%d)\n"), error);
-#endif
+
+	LINUX_CTR1(rt_sigtimedwait, "returns %d", error);
+
 	if (error)
 		return (error);
 
@@ -517,11 +473,7 @@ linux_kill(struct thread *td, struct linux_kill_args *args)
 	    int signum;
 	} */ tmp;
 
-#ifdef DEBUG
-	if (ldebug(kill))
-		printf(ARGS(kill, "%d, %d"), args->pid, args->signum);
-#endif
-
+	LINUX_CTR2(kill, "%d %d", args->pid, args->signum);
 	/*
 	 * Allow signal 0 as a means to check for privileges
 	 */
@@ -598,10 +550,8 @@ int
 linux_tgkill(struct thread *td, struct linux_tgkill_args *args)
 {
 
-#ifdef DEBUG
-	if (ldebug(tgkill))
-		printf(ARGS(tgkill, "%d, %d, %d"), args->tgid, args->pid, args->sig);
-#endif
+	LINUX_CTR3(tgkill, "%d %d %d", args->tgid, args->pid, args->sig);
+
 	if (args->pid <= 0 || args->tgid <=0)
 		return (EINVAL);
 
@@ -611,10 +561,9 @@ linux_tgkill(struct thread *td, struct linux_tgkill_args *args)
 int
 linux_tkill(struct thread *td, struct linux_tkill_args *args)
 {
-#ifdef DEBUG
-	if (ldebug(tkill))
-		printf(ARGS(tkill, "%i, %i"), args->tid, args->sig);
-#endif
+
+	LINUX_CTR2(tkill, "%i %i", args->tid, args->sig);
+
 	if (args->tid <= 0)
 		return (EINVAL);
 
diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c
index af133d9..a6bfd90 100644
--- a/sys/compat/linux/linux_socket.c
+++ b/sys/compat/linux/linux_socket.c
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/sysproto.h>
 #include <sys/fcntl.h>
 #include <sys/file.h>
+#include <sys/ktr.h>
 #include <sys/limits.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
@@ -1361,6 +1362,8 @@ linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
 {
 	void *arg = (void *)(intptr_t)args->args;
 
+	LINUX_CTR1(socketcall, "%d", args->what);
+
 	switch (args->what) {
 	case LINUX_SOCKET:
 		return (linux_socket(td, arg));
diff --git a/sys/compat/linux/linux_stats.c b/sys/compat/linux/linux_stats.c
index 5f1ce53..dae050e 100644
--- a/sys/compat/linux/linux_stats.c
+++ b/sys/compat/linux/linux_stats.c
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/dirent.h>
 #include <sys/file.h>
 #include <sys/filedesc.h>
+#include <sys/ktr.h>
 #include <sys/proc.h>
 #include <sys/jail.h>
 #include <sys/malloc.h>
@@ -182,10 +183,7 @@ linux_newstat(struct thread *td, struct linux_newstat_args *args)
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(newstat))
-		printf(ARGS(newstat, "%s, *"), path);
-#endif
+	LINUX_CTR(newstat);
 
 	error = kern_stat(td, path, UIO_SYSSPACE, &buf);
 	if (!error)
@@ -205,10 +203,7 @@ linux_newlstat(struct thread *td, struct linux_newlstat_args *args)
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(newlstat))
-		printf(ARGS(newlstat, "%s, *"), path);
-#endif
+	LINUX_CTR(newlstat);
 
 	error = kern_lstat(td, path, UIO_SYSSPACE, &sb);
 	if (!error)
@@ -225,10 +220,7 @@ linux_newfstat(struct thread *td, struct linux_newfstat_args *args)
 	struct stat buf;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(newfstat))
-		printf(ARGS(newfstat, "%d, *"), args->fd);
-#endif
+	LINUX_CTR1(newfstat, "%d", args->fd);
 
 	error = kern_fstat(td, args->fd, &buf);
 	translate_fd_major_minor(td, args->fd, &buf);
@@ -275,10 +267,8 @@ linux_stat(struct thread *td, struct linux_stat_args *args)
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(stat))
-		printf(ARGS(stat, "%s, *"), path);
-#endif
+	LINUX_CTR(stat);
+
 	error = kern_stat(td, path, UIO_SYSSPACE, &buf);
 	if (error) {
 		LFREEPATH(path);
@@ -298,10 +288,8 @@ linux_lstat(struct thread *td, struct linux_lstat_args *args)
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(lstat))
-		printf(ARGS(lstat, "%s, *"), path);
-#endif
+	LINUX_CTR(lstat);
+
 	error = kern_lstat(td, path, UIO_SYSSPACE, &buf);
 	if (error) {
 		LFREEPATH(path);
@@ -389,10 +377,8 @@ linux_statfs(struct thread *td, struct linux_statfs_args *args)
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(statfs))
-		printf(ARGS(statfs, "%s, *"), path);
-#endif
+	LINUX_CTR(statfs);
+
 	error = kern_statfs(td, path, UIO_SYSSPACE, &bsd_statfs);
 	LFREEPATH(path);
 	if (error)
@@ -430,10 +416,8 @@ linux_statfs64(struct thread *td, struct linux_statfs64_args *args)
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(statfs64))
-		printf(ARGS(statfs64, "%s, *"), path);
-#endif
+	LINUX_CTR(statfs64);
+
 	error = kern_statfs(td, path, UIO_SYSSPACE, &bsd_statfs);
 	LFREEPATH(path);
 	if (error)
@@ -449,10 +433,8 @@ linux_fstatfs(struct thread *td, struct linux_fstatfs_args *args)
 	struct statfs bsd_statfs;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(fstatfs))
-		printf(ARGS(fstatfs, "%d, *"), args->fd);
-#endif
+	LINUX_CTR1(fstatfs, "%d", args->fd);
+
 	error = kern_fstatfs(td, args->fd, &bsd_statfs);
 	if (error)
 		return error;
@@ -471,10 +453,8 @@ struct l_ustat
 int
 linux_ustat(struct thread *td, struct linux_ustat_args *args)
 {
-#ifdef DEBUG
-	if (ldebug(ustat))
-		printf(ARGS(ustat, "%d, *"), args->dev);
-#endif
+
+	LINUX_CTR1(ustat, "%d", args->dev);
 
 	return (EOPNOTSUPP);
 }
@@ -521,10 +501,7 @@ linux_stat64(struct thread *td, struct linux_stat64_args *args)
 
 	LCONVPATHEXIST(td, args->filename, &filename);
 
-#ifdef DEBUG
-	if (ldebug(stat64))
-		printf(ARGS(stat64, "%s, *"), filename);
-#endif
+	LINUX_CTR(stat64);
 
 	error = kern_stat(td, filename, UIO_SYSSPACE, &buf);
 	if (!error)
@@ -544,10 +521,7 @@ linux_lstat64(struct thread *td, struct linux_lstat64_args *args)
 
 	LCONVPATHEXIST(td, args->filename, &filename);
 
-#ifdef DEBUG
-	if (ldebug(lstat64))
-		printf(ARGS(lstat64, "%s, *"), args->filename);
-#endif
+	LINUX_CTR(lstat64);
 
 	error = kern_lstat(td, filename, UIO_SYSSPACE, &sb);
 	if (!error)
@@ -564,10 +538,7 @@ linux_fstat64(struct thread *td, struct linux_fstat64_args *args)
 	struct stat buf;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(fstat64))
-		printf(ARGS(fstat64, "%d, *"), args->fd);
-#endif
+	LINUX_CTR1(fstat64, "%d", args->fd);
 
 	error = kern_fstat(td, args->fd, &buf);
 	translate_fd_major_minor(td, args->fd, &buf);
@@ -592,10 +563,7 @@ linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
 	LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
 
-#ifdef DEBUG
-	if (ldebug(fstatat64))
-		printf(ARGS(fstatat64, "%i, %s, %i"), args->dfd, path, args->flag);
-#endif
+	LINUX_CTR(fstatat64);
 
 	error = kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
 	translate_path_major_minor_at(td, args->pathname, &buf, dfd);
diff --git a/sys/compat/linux/linux_time.c b/sys/compat/linux/linux_time.c
index e9bc71b..6ec2507 100644
--- a/sys/compat/linux/linux_time.c
+++ b/sys/compat/linux/linux_time.c
@@ -46,6 +46,7 @@ __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp
 
 #include <sys/param.h>
 #include <sys/ucred.h>
+#include <sys/ktr.h>
 #include <sys/mount.h>
 #include <sys/signal.h>
 #include <sys/stdint.h>
@@ -63,6 +64,8 @@ __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp
 #include <machine/../linux/linux_proto.h>
 #endif
 
+#include <compat/linux/linux_util.h>
+
 static void native_to_linux_timespec(struct l_timespec *,
 				     struct timespec *);
 static int linux_to_native_timespec(struct timespec *,
@@ -117,6 +120,8 @@ linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args)
 	clockid_t nwhich = 0;	/* XXX: GCC */
 	struct timespec tp;
 
+	LINUX_CTR(clock_gettime);
+
 	error = linux_to_native_clockid(&nwhich, args->which);
 	if (error != 0)
 		return (error);
@@ -136,6 +141,8 @@ linux_clock_settime(struct thread *td, struct linux_clock_settime_args *args)
 	int error;
 	clockid_t nwhich = 0;	/* XXX: GCC */
 
+	LINUX_CTR(clock_settime);
+
 	error = linux_to_native_clockid(&nwhich, args->which);
 	if (error != 0)
 		return (error);
@@ -157,6 +164,8 @@ linux_clock_getres(struct thread *td, struct linux_clock_getres_args *args)
 	int error;
 	clockid_t nwhich = 0;	/* XXX: GCC */
 
+	LINUX_CTR(clock_getres);
+
 	if (args->tp == NULL)
 	  	return (0);
 
@@ -179,6 +188,8 @@ linux_nanosleep(struct thread *td, struct linux_nanosleep_args *args)
 	struct timespec rqts, rmts;
 	int error;
 
+	LINUX_CTR(nanosleep);
+
 	error = copyin(args->rqtp, &lrqts, sizeof lrqts);
 	if (error != 0)
 		return (error);
@@ -213,6 +224,8 @@ linux_clock_nanosleep(struct thread *td, struct linux_clock_nanosleep_args *args
 	struct timespec rqts, rmts;
 	int error;
 
+	LINUX_CTR(clock_nanosleep);
+
 	if (args->flags != 0)
 		return (EINVAL);	/* XXX deal with TIMER_ABSTIME */
 
diff --git a/sys/compat/linux/linux_uid16.c b/sys/compat/linux/linux_uid16.c
index 2685eaa..0459efe 100644
--- a/sys/compat/linux/linux_uid16.c
+++ b/sys/compat/linux/linux_uid16.c
@@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/fcntl.h>
 #include <sys/param.h>
+#include <sys/ktr.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/mutex.h>
@@ -65,10 +66,8 @@ linux_chown16(struct thread *td, struct linux_chown16_args *args)
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(chown16))
-		printf(ARGS(chown16, "%s, %d, %d"), path, args->uid, args->gid);
-#endif
+	LINUX_CTR2(chown16, "%d, %d", args->uid, args->gid);
+
 	error = kern_chown(td, path, UIO_SYSSPACE, CAST_NOCHG(args->uid),
 	    CAST_NOCHG(args->gid));
 	LFREEPATH(path);
@@ -83,11 +82,8 @@ linux_lchown16(struct thread *td, struct linux_lchown16_args *args)
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-#ifdef DEBUG
-	if (ldebug(lchown16))
-		printf(ARGS(lchown16, "%s, %d, %d"), path, args->uid,
-		    args->gid);
-#endif
+	LINUX_CTR2(lchown16, "%d, %d", args->uid, args->gid);
+
 	error = kern_lchown(td, path, UIO_SYSSPACE, CAST_NOCHG(args->uid),
 	    CAST_NOCHG(args->gid));
 	LFREEPATH(path);
@@ -103,10 +99,7 @@ linux_setgroups16(struct thread *td, struct linux_setgroups16_args *args)
 	int ngrp, error;
 	struct proc *p;
 
-#ifdef DEBUG
-	if (ldebug(setgroups16))
-		printf(ARGS(setgroups16, "%d, *"), args->gidsetsize);
-#endif
+	LINUX_CTR1(setgroups16, "%d", args->gidsetsize);
 
 	ngrp = args->gidsetsize;
 	if (ngrp < 0 || ngrp >= NGROUPS)
@@ -160,10 +153,7 @@ linux_getgroups16(struct thread *td, struct linux_getgroups16_args *args)
 	gid_t *bsd_gidset;
 	int bsd_gidsetsz, ngrp, error;
 
-#ifdef DEBUG
-	if (ldebug(getgroups16))
-		printf(ARGS(getgroups16, "%d, *"), args->gidsetsize);
-#endif
+	LINUX_CTR1(getgroups16, "%d", args->gidsetsize);
 
 	cred = td->td_ucred;
 	bsd_gidset = cred->cr_groups;
diff --git a/sys/compat/linux/linux_util.h b/sys/compat/linux/linux_util.h
index 4caad9d..306b7b0 100644
--- a/sys/compat/linux/linux_util.h
+++ b/sys/compat/linux/linux_util.h
@@ -106,4 +106,33 @@ int	linux_driver_get_major_minor(char *node, int *major, int *minor);
 char	*linux_get_char_devices(void);
 void	linux_free_get_char_devices(char *string);
 
+#if defined(DEBUG) && defined(KTR)
+
+#define	KTR_LINUX				KTR_SUBSYS
+#define	LINUX_CTRFMT(nm, fmt)	#nm"("fmt")"
+
+#define	LINUX_CTR6(f, m, p1, p2, p3, p4, p5, p6) do {			\
+	if (ldebug(f))							\
+		CTR6(KTR_LINUX, LINUX_CTRFMT(f, m),			\
+		    p1, p2, p3, p4, p5, p6);				\
+} while (0)
+
+#define	LINUX_CTR(f)			LINUX_CTR6(f, "", 0, 0, 0, 0, 0, 0)
+#define	LINUX_CTR0(f, m)		LINUX_CTR6(f, m, 0, 0, 0, 0, 0, 0)
+#define	LINUX_CTR1(f, m, p1)		LINUX_CTR6(f, m, p1, 0, 0, 0, 0, 0)
+#define	LINUX_CTR2(f, m, p1, p2)	LINUX_CTR6(f, m, p1, p2, 0, 0, 0, 0)
+#define	LINUX_CTR3(f, m, p1, p2, p3)	LINUX_CTR6(f, m, p1, p2, p3, 0, 0, 0)
+#define	LINUX_CTR4(f, m, p1, p2, p3, p4)	LINUX_CTR6(f, m, p1, p2, p3, p4, 0, 0)
+#define	LINUX_CTR5(f, m, p1, p2, p3, p4, p5)	LINUX_CTR6(f, m, p1, p2, p3, p4, p5, 0)
+#else
+#define	LINUX_CTR(f)
+#define	LINUX_CTR0(f, m)
+#define	LINUX_CTR1(f, m, p1)
+#define	LINUX_CTR2(f, m, p1, p2)
+#define	LINUX_CTR3(f, m, p1, p2, p3)
+#define	LINUX_CTR4(f, m, p1, p2, p3, p4)
+#define	LINUX_CTR5(f, m, p1, p2, p3, p4, p5)
+#define	LINUX_CTR6(f, m, p1, p2, p3, p4, p5, p6)
+#endif
+
 #endif /* !_LINUX_UTIL_H_ */
diff --git a/sys/compat/svr4/svr4_sysvec.c b/sys/compat/svr4/svr4_sysvec.c
index 0030e3a..a406576 100644
--- a/sys/compat/svr4/svr4_sysvec.c
+++ b/sys/compat/svr4/svr4_sysvec.c
@@ -204,6 +204,7 @@ Elf32_Brandinfo svr4_brand = {
 	.interp_path	= "/lib/libc.so.1",
 	.sysvec		= &svr4_sysvec,
 	.interp_newpath	= NULL,
+	.brand_abi_note	= NULL,
 	.flags		= 0
 };
 
diff --git a/sys/i386/i386/elf_machdep.c b/sys/i386/i386/elf_machdep.c
index 19eddd0..593f9bd 100644
--- a/sys/i386/i386/elf_machdep.c
+++ b/sys/i386/i386/elf_machdep.c
@@ -84,7 +84,8 @@ static Elf32_Brandinfo freebsd_brand_info = {
 	.interp_path	= "/libexec/ld-elf.so.1",
 	.sysvec		= &elf32_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_ANY,
@@ -99,7 +100,8 @@ static Elf32_Brandinfo freebsd_brand_oinfo = {
 	.interp_path	= "/usr/libexec/ld-elf.so.1",
 	.sysvec		= &elf32_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY,
diff --git a/sys/i386/linux/linux.h b/sys/i386/linux/linux.h
index f9c7ee5..ca01c89 100644
--- a/sys/i386/linux/linux.h
+++ b/sys/i386/linux/linux.h
@@ -102,6 +102,10 @@ typedef struct {
 
 #define	LINUX_CTL_MAXNAME	10
 
+#define LINUX_AT_COUNT		16	/* Count of used aux entry types.
+					 * Keep this synchronized with
+					 * elf_linux_fixup() code.
+					 */
 struct l___sysctl_args
 {
 	l_int		*name;
diff --git a/sys/i386/linux/linux_machdep.c b/sys/i386/linux/linux_machdep.c
index 7f727ac..0093898 100644
--- a/sys/i386/linux/linux_machdep.c
+++ b/sys/i386/linux/linux_machdep.c
@@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/file.h>
 #include <sys/fcntl.h>
 #include <sys/imgact.h>
+#include <sys/ktr.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/mman.h>
@@ -126,10 +127,7 @@ linux_execve(struct thread *td, struct linux_execve_args *args)
 
 	LCONVPATHEXIST(td, args->path, &newpath);
 
-#ifdef DEBUG
-	if (ldebug(execve))
-		printf(ARGS(execve, "%s"), newpath);
-#endif
+	LINUX_CTR(execve);
 
 	error = exec_copyin_args(&eargs, newpath, UIO_SYSSPACE,
 	    args->argp, args->envp);
@@ -277,10 +275,7 @@ linux_old_select(struct thread *td, struct linux_old_select_args *args)
 	struct linux_select_args newsel;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(old_select))
-		printf(ARGS(old_select, "%p"), args->ptr);
-#endif
+	LINUX_CTR1(old_select, "%p", args->ptr);
 
 	error = copyin(args->ptr, &linux_args, sizeof(linux_args));
 	if (error)
@@ -301,10 +296,7 @@ linux_fork(struct thread *td, struct linux_fork_args *args)
 	struct proc *p2;
 	struct thread *td2;
 
-#ifdef DEBUG
-	if (ldebug(fork))
-		printf(ARGS(fork, ""));
-#endif
+	LINUX_CTR(fork);
 
 	if ((error = fork1(td, RFFDG | RFPROC | RFSTOPPED, 0, &p2)) != 0)
 		return (error);
@@ -340,10 +332,7 @@ linux_vfork(struct thread *td, struct linux_vfork_args *args)
 	struct proc *p2;
 	struct thread *td2;
 
-#ifdef DEBUG
-	if (ldebug(vfork))
-		printf(ARGS(vfork, ""));
-#endif
+	LINUX_CTR(vfork);
 
 	/* exclude RFPPWAIT */
 	if ((error = fork1(td, RFFDG | RFPROC | RFMEM | RFSTOPPED, 0, &p2)) != 0)
@@ -391,13 +380,9 @@ linux_clone(struct thread *td, struct linux_clone_args *args)
 	int exit_signal;
 	struct linux_emuldata *em;
 
-#ifdef DEBUG
-	if (ldebug(clone)) {
-   	   	printf(ARGS(clone, "flags %x, stack %x, parent tid: %x, child tid: %x"),
-		    (unsigned int)args->flags, (unsigned int)args->stack, 
-		    (unsigned int)args->parent_tidptr, (unsigned int)args->child_tidptr);
-	}
-#endif
+	LINUX_CTR4(clone, "flags %x, stack %x, parent tid: %x, child tid: %x",
+	    (unsigned int)args->flags, (unsigned int)args->stack,
+	    (unsigned int)args->parent_tidptr, (unsigned int)args->child_tidptr);
 
 	exit_signal = args->flags & 0x000000ff;
 	if (LINUX_SIG_VALID(exit_signal)) {
@@ -535,19 +520,6 @@ linux_clone(struct thread *td, struct linux_clone_args *args)
 			a[1] = LINUX_LDT_entry_b(&info);
 
 			memcpy(&sd, &a, sizeof(a));
-#ifdef DEBUG
-		if (ldebug(clone))
-		   	printf("Segment created in clone with CLONE_SETTLS: lobase: %x, hibase: %x, lolimit: %x, hilimit: %x, type: %i, dpl: %i, p: %i, xx: %i, def32: %i, gran: %i\n", sd.sd_lobase,
-			sd.sd_hibase,
-			sd.sd_lolimit,
-			sd.sd_hilimit,
-			sd.sd_type,
-			sd.sd_dpl,
-			sd.sd_p,
-			sd.sd_xx,
-			sd.sd_def32,
-			sd.sd_gran);
-#endif
 
 			/* set %gs */
 			td2->td_pcb->pcb_gsd = sd;
@@ -555,11 +527,9 @@ linux_clone(struct thread *td, struct linux_clone_args *args)
 		}
 	} 
 
-#ifdef DEBUG
-	if (ldebug(clone))
-		printf(LMSG("clone: successful rfork to %ld, stack %p sig = %d"),
-		    (long)p2->p_pid, args->stack, exit_signal);
-#endif
+	LINUX_CTR3(clone, "successful rfork to %ld, stack %p sig = %d",
+	    (long)p2->p_pid, args->stack, exit_signal);
+
 	if (args->flags & LINUX_CLONE_VFORK) {
 	   	PROC_LOCK(p2);
 		p2->p_flag |= P_PPWAIT;
@@ -598,12 +568,9 @@ linux_mmap2(struct thread *td, struct linux_mmap2_args *args)
 {
 	struct l_mmap_argv linux_args;
 
-#ifdef DEBUG
-	if (ldebug(mmap2))
-		printf(ARGS(mmap2, "%p, %d, %d, 0x%08x, %d, %d"),
-		    (void *)args->addr, args->len, args->prot,
-		    args->flags, args->fd, args->pgoff);
-#endif
+	LINUX_CTR6(mmap2, "%p, %d, %d, 0x%08x, %d, %d",
+	    (void *)args->addr, args->len, args->prot,
+	    args->flags, args->fd, args->pgoff);
 
 	linux_args.addr = args->addr;
 	linux_args.len = args->len;
@@ -625,12 +592,9 @@ linux_mmap(struct thread *td, struct linux_mmap_args *args)
 	if (error)
 		return (error);
 
-#ifdef DEBUG
-	if (ldebug(mmap))
-		printf(ARGS(mmap, "%p, %d, %d, 0x%08x, %d, %d"),
-		    (void *)linux_args.addr, linux_args.len, linux_args.prot,
-		    linux_args.flags, linux_args.fd, linux_args.pgoff);
-#endif
+	LINUX_CTR6(mmap, "%p, %d, %d, 0x%08x, %d, %d",
+	    linux_args.addr, linux_args.len, linux_args.prot,
+	    linux_args.flags, linux_args.fd, linux_args.pgoff);
 
 	return (linux_mmap_common(td, &linux_args));
 }
@@ -780,19 +744,10 @@ linux_mmap_common(struct thread *td, struct l_mmap_argv *linux_args)
 	}
 	bsd_args.pos = linux_args->pgoff;
 
-#ifdef DEBUG
-	if (ldebug(mmap))
-		printf("-> %s(%p, %d, %d, 0x%08x, %d, 0x%x)\n",
-		    __func__,
-		    (void *)bsd_args.addr, bsd_args.len, bsd_args.prot,
-		    bsd_args.flags, bsd_args.fd, (int)bsd_args.pos);
-#endif
 	error = mmap(td, &bsd_args);
-#ifdef DEBUG
-	if (ldebug(mmap))
-		printf("-> %s() return: 0x%x (0x%08x)\n",
-			__func__, error, (u_int)td->td_retval[0]);
-#endif
+
+	LINUX_CTR3(mmap, "-> %s() return: 0x%x (0x%08x)\n",
+	    __func__, error, (u_int)td->td_retval[0]);
 	return (error);
 }
 
@@ -815,10 +770,7 @@ linux_pipe(struct thread *td, struct linux_pipe_args *args)
 	int error;
 	int fildes[2];
 
-#ifdef DEBUG
-	if (ldebug(pipe))
-		printf(ARGS(pipe, "*"));
-#endif
+	LINUX_CTR(pipe);
 
 	error = kern_pipe(td, fildes);
 	if (error)
@@ -930,11 +882,8 @@ linux_sigaction(struct thread *td, struct linux_sigaction_args *args)
 	l_sigaction_t act, oact;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(sigaction))
-		printf(ARGS(sigaction, "%d, %p, %p"),
-		    args->sig, (void *)args->nsa, (void *)args->osa);
-#endif
+	LINUX_CTR3(sigaction, "%d, %p, %p",
+	    args->sig, (void *)args->nsa, (void *)args->osa);
 
 	if (args->nsa != NULL) {
 		error = copyin(args->nsa, &osa, sizeof(l_osigaction_t));
@@ -972,10 +921,7 @@ linux_sigsuspend(struct thread *td, struct linux_sigsuspend_args *args)
 	sigset_t sigmask;
 	l_sigset_t mask;
 
-#ifdef DEBUG
-	if (ldebug(sigsuspend))
-		printf(ARGS(sigsuspend, "%08lx"), (unsigned long)args->mask);
-#endif
+	LINUX_CTR1(sigsuspend, "%08lx", (unsigned long)args->mask);
 
 	LINUX_SIGEMPTYSET(mask);
 	mask.__bits[0] = args->mask;
@@ -990,11 +936,8 @@ linux_rt_sigsuspend(struct thread *td, struct linux_rt_sigsuspend_args *uap)
 	sigset_t sigmask;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(rt_sigsuspend))
-		printf(ARGS(rt_sigsuspend, "%p, %d"),
-		    (void *)uap->newset, uap->sigsetsize);
-#endif
+	LINUX_CTR2(rt_sigsuspend, "%p, %d",
+	    (void *)uap->newset, uap->sigsetsize);
 
 	if (uap->sigsetsize != sizeof(l_sigset_t))
 		return (EINVAL);
@@ -1013,10 +956,7 @@ linux_pause(struct thread *td, struct linux_pause_args *args)
 	struct proc *p = td->td_proc;
 	sigset_t sigmask;
 
-#ifdef DEBUG
-	if (ldebug(pause))
-		printf(ARGS(pause, ""));
-#endif
+	LINUX_CTR(pause);
 
 	PROC_LOCK(p);
 	sigmask = td->td_sigmask;
@@ -1031,10 +971,7 @@ linux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap)
 	l_stack_t lss;
 	int error;
 
-#ifdef DEBUG
-	if (ldebug(sigaltstack))
-		printf(ARGS(sigaltstack, "%p, %p"), uap->uss, uap->uoss);
-#endif
+	LINUX_CTR2(sigaltstack, "%p, %p", uap->uss, uap->uoss);
 
 	if (uap->uss != NULL) {
 		error = copyin(uap->uss, &lss, sizeof(l_stack_t));
@@ -1062,11 +999,8 @@ linux_ftruncate64(struct thread *td, struct linux_ftruncate64_args *args)
 {
 	struct ftruncate_args sa;
 
-#ifdef DEBUG
-	if (ldebug(ftruncate64))
-		printf(ARGS(ftruncate64, "%u, %jd"), args->fd,
-		    (intmax_t)args->length);
-#endif
+	LINUX_CTR2(ftruncate64, "%u, %jd",
+	    args->fd, (intmax_t)args->length);
 
 	sa.fd = args->fd;
 	sa.length = args->length;
@@ -1086,19 +1020,18 @@ linux_set_thread_area(struct thread *td, struct linux_set_thread_area_args *args
 	if (error)
 		return (error);
 
-#ifdef DEBUG
-	if (ldebug(set_thread_area))
-	   	printf(ARGS(set_thread_area, "%i, %x, %x, %i, %i, %i, %i, %i, %i\n"),
-		      info.entry_number,
-      		      info.base_addr,
-      		      info.limit,
-      		      info.seg_32bit,
-		      info.contents,
-      		      info.read_exec_only,
-      		      info.limit_in_pages,
-      		      info.seg_not_present,
-      		      info.useable);
-#endif
+	LINUX_CTR6(set_thread_area, "%i, %x, %x, %i, %i, %i",
+	    info.entry_number,
+	    info.base_addr,
+	    info.limit,
+	    info.seg_32bit,
+	    info.contents,
+	    info.read_exec_only);
+
+	LINUX_CTR3(set_thread_area, "%i, %i, %i",
+	    info.limit_in_pages,
+	    info.seg_not_present,
+	    info.useable);
 
 	idx = info.entry_number;
 	/* 
@@ -1148,19 +1081,20 @@ linux_set_thread_area(struct thread *td, struct linux_set_thread_area_args *args
 	}
 
 	memcpy(&sd, &a, sizeof(a));
-#ifdef DEBUG
-	if (ldebug(set_thread_area))
-	   	printf("Segment created in set_thread_area: lobase: %x, hibase: %x, lolimit: %x, hilimit: %x, type: %i, dpl: %i, p: %i, xx: %i, def32: %i, gran: %i\n", sd.sd_lobase,
-			sd.sd_hibase,
-			sd.sd_lolimit,
-			sd.sd_hilimit,
-			sd.sd_type,
-			sd.sd_dpl,
-			sd.sd_p,
-			sd.sd_xx,
-			sd.sd_def32,
-			sd.sd_gran);
-#endif
+
+	LINUX_CTR6(set_thread_area, "Segment created %x %x %x %x %i %i",
+	    sd.sd_lobase,
+	    sd.sd_hibase,
+	    sd.sd_lolimit,
+	    sd.sd_hilimit,
+	    sd.sd_type,
+	    sd.sd_dpl);
+
+	LINUX_CTR4(set_thread_area, "Segment created %i %i %i %i",
+	    sd.sd_p,
+	    sd.sd_xx,
+	    sd.sd_def32,
+	    sd.sd_gran);
 
 	/* this is taken from i386 version of cpu_set_user_tls() */
 	critical_enter();
@@ -1183,10 +1117,7 @@ linux_get_thread_area(struct thread *td, struct linux_get_thread_area_args *args
 	struct l_desc_struct desc;
 	struct segment_descriptor sd;
 
-#ifdef DEBUG
-	if (ldebug(get_thread_area))
-		printf(ARGS(get_thread_area, "%p"), args->desc);
-#endif
+	LINUX_CTR1(get_thread_area, "%p", args->desc);
 
 	error = copyin(args->desc, &info, sizeof(struct l_user_desc));
 	if (error)
diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c
index 42365fb..ce1b995 100644
--- a/sys/i386/linux/linux_sysvec.c
+++ b/sys/i386/linux/linux_sysvec.c
@@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/imgact_aout.h>
 #include <sys/imgact_elf.h>
 #include <sys/kernel.h>
+#include <sys/ktr.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
@@ -58,11 +59,13 @@ __FBSDID("$FreeBSD$");
 #include <vm/vm_param.h>
 
 #include <machine/cpu.h>
+#include <machine/cputypes.h>
 #include <machine/md_var.h>
 #include <machine/pcb.h>
 
 #include <i386/linux/linux.h>
 #include <i386/linux/linux_proto.h>
+#include <compat/linux/linux_elf.h>
 #include <compat/linux/linux_emul.h>
 #include <compat/linux/linux_mib.h>
 #include <compat/linux/linux_signal.h>
@@ -89,6 +92,7 @@ MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
 
 #define	fldcw(addr)		__asm("fldcw %0" : : "m" (*(addr)))
 #define	__LINUX_NPXCW__		0x37f
+#define aligned(a, t)	(rounddown((unsigned long)(a), sizeof(t)) == (unsigned long)(a))
 
 extern char linux_sigcode[];
 extern int linux_szsigcode;
@@ -107,9 +111,13 @@ static void	linux_prepsyscall(struct trapframe *tf, int *args, u_int *code,
 static void     linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
 static void	exec_linux_setregs(struct thread *td, u_long entry,
 				   u_long stack, u_long ps_strings);
+static register_t *linux_copyout_strings(struct image_params *imgp);
+
+static int linux_szplatform;
+const char *linux_platform;
 
 extern LIST_HEAD(futex_list, futex) futex_list;
-extern struct sx futex_sx;
+extern struct mtx futex_mtx;
 
 static eventhandler_tag linux_exit_tag;
 static eventhandler_tag linux_schedtail_tag;
@@ -231,22 +239,30 @@ linux_fixup(register_t **stack_base, struct image_params *imgp)
 	**stack_base = (intptr_t)(void *)argv;
 	(*stack_base)--;
 	**stack_base = imgp->args->argc;
-	return 0;
+	return (0);
 }
 
 static int
 elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
 {
+	struct proc *p;
 	Elf32_Auxargs *args;
+	Elf32_Addr *uplatform;
+	struct ps_strings *arginfo;
 	register_t *pos;
 
 	KASSERT(curthread->td_proc == imgp->proc,
 	    ("unsafe elf_linux_fixup(), should be curproc"));
+
+	p = imgp->proc;
+	arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
+	uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szsigcode -
+	    linux_szplatform);
 	args = (Elf32_Auxargs *)imgp->auxargs;
 	pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2);
 
-	if (args->execfd != -1)
-		AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
+	AUXARGS_ENTRY(pos, LINUX_AT_HWCAP, cpu_feature);
+	AUXARGS_ENTRY(pos, LINUX_AT_CLKTCK, hz);
 	AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
 	AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
 	AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
@@ -254,10 +270,14 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
 	AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
 	AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
 	AUXARGS_ENTRY(pos, AT_BASE, args->base);
+	AUXARGS_ENTRY(pos, LINUX_AT_SECURE, 0);
 	AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
 	AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
 	AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
 	AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
+	AUXARGS_ENTRY(pos, LINUX_AT_PLATFORM, PTROUT(uplatform));
+	if (args->execfd != -1)
+		AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
 	AUXARGS_ENTRY(pos, AT_NULL, 0);
 
 	free(imgp->auxargs, M_TEMP);
@@ -265,9 +285,125 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
 
 	(*stack_base)--;
 	**stack_base = (register_t)imgp->args->argc;
-	return 0;
+	return (0);
 }
 
+/*
+ * Copied from kern/kern_exec.c
+ */
+static register_t *
+linux_copyout_strings(struct image_params *imgp)
+{
+	int argc, envc;
+	char **vectp;
+	char *stringp, *destp;
+	register_t *stack_base;
+	struct ps_strings *arginfo;
+	struct proc *p;
+
+	/*
+	 * Calculate string base and vector table pointers.
+	 * Also deal with signal trampoline code for this exec type.
+	 */
+	p = imgp->proc;
+	arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
+	destp = (caddr_t)arginfo - linux_szsigcode - SPARE_USRSPACE -
+	    linux_szplatform - roundup((ARG_MAX - imgp->args->stringspace),
+	    sizeof(char *));
+
+	/*
+	 * install sigcode
+	 */
+	copyout(p->p_sysent->sv_sigcode, ((caddr_t)arginfo -
+	    linux_szsigcode), linux_szsigcode);
+
+	/*
+	 * install LINUX_PLATFORM
+	 */
+	copyout(linux_platform, ((caddr_t)arginfo - linux_szsigcode -
+	    linux_szplatform), linux_szplatform);
+
+	/*
+	 * If we have a valid auxargs ptr, prepare some room
+	 * on the stack.
+	 */
+	if (imgp->auxargs) {
+		/*
+		 * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for
+		 * lower compatibility.
+		 */
+		imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size :
+		    (LINUX_AT_COUNT * 2);
+		/*
+		 * The '+ 2' is for the null pointers at the end of each of
+		 * the arg and env vector sets,and imgp->auxarg_size is room
+		 * for argument of Runtime loader.
+		 */
+		vectp = (char **)(destp - (imgp->args->argc +
+		    imgp->args->envc + 2 + imgp->auxarg_size) * sizeof(char *));
+	} else {
+		/*
+		 * The '+ 2' is for the null pointers at the end of each of
+		 * the arg and env vector sets
+		 */
+		vectp = (char **)(destp - (imgp->args->argc + imgp->args->envc + 2) *
+		    sizeof(char *));
+	}
+
+	/*
+	 * vectp also becomes our initial stack base
+	 */
+	stack_base = (register_t *)vectp;
+
+	stringp = imgp->args->begin_argv;
+	argc = imgp->args->argc;
+	envc = imgp->args->envc;
+
+	/*
+	 * Copy out strings - arguments and environment.
+	 */
+	copyout(stringp, destp, ARG_MAX - imgp->args->stringspace);
+
+	/*
+	 * Fill in "ps_strings" struct for ps, w, etc.
+	 */
+	suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp);
+	suword(&arginfo->ps_nargvstr, argc);
+
+	/*
+	 * Fill in argument portion of vector table.
+	 */
+	for (; argc > 0; --argc) {
+		suword(vectp++, (long)(intptr_t)destp);
+		while (*stringp++ != 0)
+			destp++;
+		destp++;
+	}
+
+	/* a null vector table pointer separates the argp's from the envp's */
+	suword(vectp++, 0);
+
+	suword(&arginfo->ps_envstr, (long)(intptr_t)vectp);
+	suword(&arginfo->ps_nenvstr, envc);
+
+	/*
+	 * Fill in environment portion of vector table.
+	 */
+	for (; envc > 0; --envc) {
+		suword(vectp++, (long)(intptr_t)destp);
+		while (*stringp++ != 0)
+			destp++;
+		destp++;
+	}
+
+	/* end of vector table is a null pointer */
+	suword(vectp, 0);
+
+	return (stack_base);
+}
+
+
+
 extern int _ucodesel, _udatasel;
 extern unsigned long linux_sznonrtsigcode;
 
@@ -290,11 +426,8 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 	regs = td->td_frame;
 	oonstack = sigonstack(regs->tf_esp);
 
-#ifdef DEBUG
-	if (ldebug(rt_sendsig))
-		printf(ARGS(rt_sendsig, "%p, %d, %p, %u"),
-		    catcher, sig, (void*)mask, code);
-#endif
+	LINUX_CTR4(rt_sendsig, "%p, %d, %p, %u",
+	    catcher, sig, (void*)mask, code);
 	/*
 	 * Allocate space for the signal handler context.
 	 */
@@ -358,23 +491,13 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 	frame.sf_sc.uc_mcontext.sc_cr2    = (register_t)ksi->ksi_addr;
 	frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code);
 
-#ifdef DEBUG
-	if (ldebug(rt_sendsig))
-		printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
-		    frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp,
-		    td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask);
-#endif
-
 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
 		/*
 		 * Process has trashed its stack; give it an illegal
 		 * instruction to halt it in its tracks.
 		 */
-#ifdef DEBUG
-		if (ldebug(rt_sendsig))
-			printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"),
-			    fp, oonstack);
-#endif
+		LINUX_CTR2(rt_sendsig, "bad stack %p, oonstack=%x",
+		    fp, oonstack);
 		PROC_LOCK(p);
 		sigexit(td, SIGILL);
 	}
@@ -395,6 +518,53 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 	mtx_lock(&psp->ps_mtx);
 }
 
+static const char GNULINUX_ABI_VENDOR[] = "GNU";
+static const int GNULINUX_ABI_LEN = 16;
+
+static int
+linux_abi_note(struct image_params *imgp, int32_t *osrel)
+{
+	const Elf_Note *note, *note_end;
+	const Elf32_Phdr *phdr, *pnote;
+	const Elf32_Ehdr *hdr;
+	const char *note_name;
+	int i;
+
+	pnote = NULL;
+	hdr = (const Elf32_Ehdr *)imgp->image_header;
+	phdr = (const Elf32_Phdr *)(imgp->image_header + hdr->e_phoff);
+
+	for (i = 0; i < hdr->e_phnum; i++)
+		if (phdr[i].p_type == PT_NOTE) {
+			pnote = &phdr[i];
+			break;
+		}
+	if (pnote == NULL || pnote->p_offset >= PAGE_SIZE ||
+	    pnote->p_offset + pnote->p_filesz >= PAGE_SIZE)
+		return (0);
+
+	note = (const Elf_Note *)(imgp->image_header + pnote->p_offset);
+	if (!aligned(note, Elf32_Addr))
+		return (0);
+	note_end = (const Elf_Note *)(imgp->image_header +
+	    pnote->p_offset + pnote->p_filesz);
+	while (note < note_end) {
+		if (note->n_namesz == sizeof(GNULINUX_ABI_VENDOR) &&
+		    note->n_descsz == GNULINUX_ABI_LEN &&
+		    note->n_type == 1 /* ABI_NOTETYPE */) {
+			note_name = (const char *)(note + 1);
+			if (strncmp(GNULINUX_ABI_VENDOR, note_name,
+			    sizeof(GNULINUX_ABI_VENDOR)) == 0)
+				return (1);
+		}
+		note = (const Elf_Note *)((const char *)(note + 1) +
+		    roundup2(note->n_namesz, sizeof(Elf32_Addr)) +
+		    roundup2(note->n_descsz, sizeof(Elf32_Addr)));
+	}
+
+	return (0);
+}
+
 
 /*
  * Send an interrupt to process.
@@ -431,12 +601,8 @@ linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 	regs = td->td_frame;
 	oonstack = sigonstack(regs->tf_esp);
 
-#ifdef DEBUG
-	if (ldebug(sendsig))
-		printf(ARGS(sendsig, "%p, %d, %p, %u"),
-		    catcher, sig, (void*)mask, code);
-#endif
-
+	LINUX_CTR4(sendsig, "%p, %d, %p, %u",
+	    catcher, sig, (void*)mask, code);
 	/*
 	 * Allocate space for the signal handler context.
 	 */
@@ -536,10 +702,7 @@ linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args)
 
 	regs = td->td_frame;
 
-#ifdef DEBUG
-	if (ldebug(sigreturn))
-		printf(ARGS(sigreturn, "%p"), (void *)args->sfp);
-#endif
+	LINUX_CTR1(sigreturn, "%p", args->sfp);
 	/*
 	 * The trampoline code hands us the sigframe.
 	 * It is unsafe to keep track of it ourselves, in the event that a
@@ -638,10 +801,7 @@ linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
 
 	regs = td->td_frame;
 
-#ifdef DEBUG
-	if (ldebug(rt_sigreturn))
-		printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp);
-#endif
+	LINUX_CTR1(rt_sigreturn, "%p", args->ucp);
 	/*
 	 * The trampoline code hands us the ucontext.
 	 * It is unsafe to keep track of it ourselves, in the event that a
@@ -720,11 +880,6 @@ linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
 	ss.ss_size = lss->ss_size;
 	ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags);
 
-#ifdef DEBUG
-	if (ldebug(rt_sigreturn))
-		printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
-		    ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask);
-#endif
 	(void)kern_sigaltstack(td, &ss, NULL);
 
 	return (EJUSTRETURN);
@@ -808,6 +963,28 @@ exec_linux_setregs(struct thread *td, u_long entry,
 	fldcw(&control);
 }
 
+static int
+linux_get_machine(const char **dst)
+{
+	const char *class;
+
+	switch (cpu_class) {
+	case CPUCLASS_686:
+		class = "i686";
+		break;
+	case CPUCLASS_586:
+		class = "i586";
+		break;
+	case CPUCLASS_486:
+		class = "i486";
+		break;
+	default:
+		class = "i386";
+	}
+	*dst = class;
+	return (0);
+}
+
 struct sysentvec linux_sysvec = {
 	.sv_size	= LINUX_SYS_MAXSYSCALL,
 	.sv_table	= linux_sysent,
@@ -863,7 +1040,7 @@ struct sysentvec elf_linux_sysvec = {
 	.sv_usrstack	= USRSTACK,
 	.sv_psstrings	= PS_STRINGS,
 	.sv_stackprot	= VM_PROT_ALL,
-	.sv_copyout_strings = exec_copyout_strings,
+	.sv_copyout_strings = linux_copyout_strings,
 	.sv_setregs	= exec_linux_setregs,
 	.sv_fixlimit	= NULL,
 	.sv_maxssiz	= NULL,
@@ -878,7 +1055,8 @@ static Elf32_Brandinfo linux_brand = {
 	.interp_path	= "/lib/ld-linux.so.1",
 	.sysvec		= &elf_linux_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= linux_abi_note,
+	.flags		= BI_CAN_EXEC_DYN | BI_CAN_EXEC_INTERP
 };
 
 static Elf32_Brandinfo linux_glibc2brand = {
@@ -889,7 +1067,8 @@ static Elf32_Brandinfo linux_glibc2brand = {
 	.interp_path	= "/lib/ld-linux.so.2",
 	.sysvec		= &elf_linux_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= linux_abi_note,
+	.flags		= BI_CAN_EXEC_DYN | BI_CAN_EXEC_INTERP
 };
 
 Elf32_Brandinfo *linux_brandlist[] = {
@@ -922,13 +1101,16 @@ linux_elf_modevent(module_t mod, int type, void *data)
 			mtx_init(&emul_lock, "emuldata lock", NULL, MTX_DEF);
 			sx_init(&emul_shared_lock, "emuldata->shared lock");
 			LIST_INIT(&futex_list);
-			sx_init(&futex_sx, "futex protection lock");
+			mtx_init(&futex_mtx, "futex list protection lock", NULL, MTX_DEF);
 			linux_exit_tag = EVENTHANDLER_REGISTER(process_exit, linux_proc_exit,
 			      NULL, 1000);
 			linux_schedtail_tag = EVENTHANDLER_REGISTER(schedtail, linux_schedtail,
 			      NULL, 1000);
 			linux_exec_tag = EVENTHANDLER_REGISTER(process_exec, linux_proc_exec,
 			      NULL, 1000);
+			linux_get_machine(&linux_platform);
+			linux_szplatform = roundup(strlen(linux_platform) + 1,
+			    sizeof(char *));
 			if (bootverbose)
 				printf("Linux ELF exec handler installed\n");
 		} else
@@ -952,7 +1134,7 @@ linux_elf_modevent(module_t mod, int type, void *data)
 				linux_device_unregister_handler(*ldhp);
 			mtx_destroy(&emul_lock);
 			sx_destroy(&emul_shared_lock);
-			sx_destroy(&futex_sx);
+			mtx_destroy(&futex_mtx);
 			EVENTHANDLER_DEREGISTER(process_exit, linux_exit_tag);
 			EVENTHANDLER_DEREGISTER(schedtail, linux_schedtail_tag);
 			EVENTHANDLER_DEREGISTER(process_exec, linux_exec_tag);
diff --git a/sys/ia64/ia64/elf_machdep.c b/sys/ia64/ia64/elf_machdep.c
index a3a6e57..a0289de 100644
--- a/sys/ia64/ia64/elf_machdep.c
+++ b/sys/ia64/ia64/elf_machdep.c
@@ -92,7 +92,8 @@ static Elf64_Brandinfo freebsd_brand_info = {
 	.interp_path	= "/libexec/ld-elf.so.1",
 	.sysvec		= &elf64_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_ANY,
     (sysinit_cfunc_t)elf64_insert_brand_entry, &freebsd_brand_info);
@@ -105,7 +106,8 @@ static Elf64_Brandinfo freebsd_brand_oinfo = {
 	.interp_path	= "/usr/libexec/ld-elf.so.1",
 	.sysvec		= &elf64_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY,
     (sysinit_cfunc_t)elf64_insert_brand_entry, &freebsd_brand_oinfo);
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index ec96974..176ec84 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -78,8 +78,8 @@ __FBSDID("$FreeBSD$");
 #define OLD_EI_BRAND	8
 
 static int __elfN(check_header)(const Elf_Ehdr *hdr);
-static Elf_Brandinfo *__elfN(get_brandinfo)(const Elf_Ehdr *hdr,
-    const char *interp);
+static Elf_Brandinfo *__elfN(get_brandinfo)(struct image_params *imgp,
+    const char *interp, int32_t *osrel);
 static int __elfN(load_file)(struct proc *p, const char *file, u_long *addr,
     u_long *entry, size_t pagesize);
 static int __elfN(load_section)(struct vmspace *vmspace, vm_object_t object,
@@ -158,19 +158,31 @@ __elfN(brand_inuse)(Elf_Brandinfo *entry)
 }
 
 static Elf_Brandinfo *
-__elfN(get_brandinfo)(const Elf_Ehdr *hdr, const char *interp)
+__elfN(get_brandinfo)(struct image_params *imgp, const char *interp,
+    int32_t *osrel)
 {
+	const Elf_Ehdr *hdr = (const Elf_Ehdr *)imgp->image_header;
 	Elf_Brandinfo *bi;
+	int ret, fname_len, interp_len;
 	int i;
 
 	/*
-	 * We support three types of branding -- (1) the ELF EI_OSABI field
+	 * We support four types of branding -- (1) the ELF EI_OSABI field
 	 * that SCO added to the ELF spec, (2) FreeBSD 3.x's traditional string
-	 * branding w/in the ELF header, and (3) path of the `interp_path'
-	 * field.  We should also look for an ".note.ABI-tag" ELF section now
-	 * in all Linux ELF binaries, FreeBSD 4.1+, and some NetBSD ones.
+	 * branding w/in the ELF header, (3) path of the `interp_path'
+	 * field, and (4) the ".note.ABI-tag" ELF section.
 	 */
 
+	/* Look for an ".note.ABI-tag" ELF section */
+	for (i = 0; i < MAX_BRANDS; i++) {
+		bi = elf_brand_list[i];
+		if (bi != NULL && hdr->e_machine == bi->machine && bi->brand_abi_note) {
+			ret = (*bi->brand_abi_note)(imgp, osrel);
+			if (ret)
+				return (bi);
+		}
+	}
+
 	/* If the executable has a brand, search for it in the brand list. */
 	for (i = 0; i < MAX_BRANDS; i++) {
 		bi = elf_brand_list[i];
@@ -191,6 +203,23 @@ __elfN(get_brandinfo)(const Elf_Ehdr *hdr, const char *interp)
 		}
 	}
 
+	/* Some ABI (Linux) allow to run the interpreter. */
+	for (i = 0; i < MAX_BRANDS; i++) {
+		bi = elf_brand_list[i];
+		if (bi == NULL || hdr->e_machine != bi->machine ||
+		    (bi->flags & BI_CAN_EXEC_INTERP) == 0)
+			continue;
+
+		fname_len = strlen(imgp->args->fname);
+		interp_len = strlen(bi->interp_path);
+		if (fname_len < interp_len)
+			continue;
+		ret = strncmp(imgp->args->fname + (fname_len - interp_len),
+		    bi->interp_path, interp_len);
+		if (ret == 0)
+			return (bi);
+	}
+
 	/* Lacking a recognized interpreter, try the default brand */
 	for (i = 0; i < MAX_BRANDS; i++) {
 		bi = elf_brand_list[i];
@@ -590,13 +619,11 @@ fail:
 	return (error);
 }
 
-static const char FREEBSD_ABI_VENDOR[] = "FreeBSD";
-
 static int
 __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
 {
 	const Elf_Ehdr *hdr = (const Elf_Ehdr *)imgp->image_header;
-	const Elf_Phdr *phdr, *pnote = NULL;
+	const Elf_Phdr *phdr;
 	Elf_Auxargs *elf_auxargs;
 	struct vmspace *vmspace;
 	vm_prot_t prot;
@@ -604,12 +631,11 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
 	u_long text_addr = 0, data_addr = 0;
 	u_long seg_size, seg_addr;
 	u_long addr, entry = 0, proghdr = 0;
+	int32_t osrel = 0;
 	int error = 0, i;
 	const char *interp = NULL, *newinterp = NULL;
 	Elf_Brandinfo *brand_info;
-	const Elf_Note *note, *note_end;
 	char *path;
-	const char *note_name;
 	struct sysentvec *sv;
 
 	/*
@@ -646,7 +672,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
 		}
 	}
 
-	brand_info = __elfN(get_brandinfo)(hdr, interp);
+	brand_info = __elfN(get_brandinfo)(imgp, interp, &osrel);
 	if (brand_info == NULL) {
 		uprintf("ELF binary type \"%u\" not known.\n",
 		    hdr->e_ident[EI_OSABI]);
@@ -750,9 +776,6 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
 		case PT_PHDR: 	/* Program header table info */
 			proghdr = phdr[i].p_vaddr;
 			break;
-		case PT_NOTE:
-			pnote = &phdr[i];
-			break;
 		default:
 			break;
 		}
@@ -840,41 +863,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
 
 	imgp->auxargs = elf_auxargs;
 	imgp->interpreted = 0;
-
-	/*
-	 * Try to fetch the osreldate for FreeBSD binary from the ELF
-	 * OSABI-note. Only the first page of the image is searched,
-	 * the same as for headers.
-	 */
-	if (pnote != NULL && pnote->p_offset < PAGE_SIZE &&
-	    pnote->p_offset + pnote->p_filesz < PAGE_SIZE ) {
-		note = (const Elf_Note *)(imgp->image_header + pnote->p_offset);
-		if (!aligned(note, Elf32_Addr)) {
-			free(imgp->auxargs, M_TEMP);
-			imgp->auxargs = NULL;
-			return (ENOEXEC);
-		}
-		note_end = (const Elf_Note *)(imgp->image_header + pnote->p_offset +
-		    pnote->p_filesz);
-		while (note < note_end) {
-			if (note->n_namesz == sizeof(FREEBSD_ABI_VENDOR) &&
-			    note->n_descsz == sizeof(int32_t) &&
-			    note->n_type == 1 /* ABI_NOTETYPE */) {
-				note_name = (const char *)(note + 1);
-				if (strncmp(FREEBSD_ABI_VENDOR, note_name,
-				    sizeof(FREEBSD_ABI_VENDOR)) == 0) {
-					imgp->proc->p_osrel = *(const int32_t *)
-					    (note_name +
-					    round_page_ps(sizeof(FREEBSD_ABI_VENDOR),
-						sizeof(Elf32_Addr)));
-					break;
-				}
-			}
-			note = (const Elf_Note *)((const char *)(note + 1) +
-			    round_page_ps(note->n_namesz, sizeof(Elf32_Addr)) +
-			    round_page_ps(note->n_descsz, sizeof(Elf32_Addr)));
-		}
-	}
+	imgp->proc->p_osrel = osrel;
 
 	return (error);
 }
@@ -1335,6 +1324,63 @@ __elfN(putnote)(void *dst, size_t *off, const char *name, int type,
 	*off += roundup2(note.n_descsz, sizeof(Elf_Size));
 }
 
+static const char FREEBSD_ABI_VENDOR[] = "FreeBSD";
+
+int
+__elfN(freebsd_abi_note)(struct image_params *imgp, int32_t *osrel)
+{
+	const Elf_Note *note, *note_end;
+	const Elf32_Phdr *phdr, *pnote;
+	const Elf32_Ehdr *hdr;
+	const char *note_name;
+	int i;
+
+	pnote = NULL;
+	hdr = (const Elf32_Ehdr *)imgp->image_header;
+	phdr = (const Elf32_Phdr *)(imgp->image_header + hdr->e_phoff);
+
+	for (i = 0; i < hdr->e_phnum; i++)
+		if (phdr[i].p_type == PT_NOTE) {
+			pnote = &phdr[i];
+			break;
+		}
+
+	if (pnote == NULL || pnote->p_offset >= PAGE_SIZE ||
+	    pnote->p_offset + pnote->p_filesz >= PAGE_SIZE)
+		return (0);
+
+	note = (const Elf_Note *)(imgp->image_header + pnote->p_offset);
+	if (!aligned(note, Elf32_Addr))
+		return (0);
+	note_end = (const Elf_Note *)(imgp->image_header +
+	    pnote->p_offset + pnote->p_filesz);
+	while (note < note_end) {
+		if (note->n_namesz == sizeof(FREEBSD_ABI_VENDOR) &&
+		    note->n_descsz == sizeof(int32_t) &&
+		    note->n_type == 1 /* ABI_NOTETYPE */) {
+			note_name = (const char *)(note + 1);
+			if (strncmp(FREEBSD_ABI_VENDOR, note_name,
+			    sizeof(FREEBSD_ABI_VENDOR)) != 0)
+				continue;
+			/*
+			 * Fetch the osreldate for FreeBSD binary
+			 * from the ELF OSABI-note.
+			 */
+			if (osrel != NULL)
+				*osrel = *(const int32_t *)
+				    (note_name +
+				    round_page_ps(sizeof(FREEBSD_ABI_VENDOR),
+				    sizeof(Elf32_Addr)));
+			return (1);
+		}
+		note = (const Elf_Note *)((const char *)(note + 1) +
+		    round_page_ps(note->n_namesz, sizeof(Elf32_Addr)) +
+		    round_page_ps(note->n_descsz, sizeof(Elf32_Addr)));
+	}
+
+	return (0);
+}
+
 /*
  * Tell kern_execve.c about it, with a little help from the linker.
  */
diff --git a/sys/mips/mips/elf_machdep.c b/sys/mips/mips/elf_machdep.c
index 163d0ee..807ae67 100644
--- a/sys/mips/mips/elf_machdep.c
+++ b/sys/mips/mips/elf_machdep.c
@@ -86,6 +86,8 @@ static Elf32_Brandinfo freebsd_brand_info = {
 	.interp_path	= "/libexec/ld-elf.so.1",
 	.sysvec		= &elf32_freebsd_sysvec,
 	.interp_newpath	= NULL,
+	.brand_abi_note	= NULL,
+	.brand_abi_note	= NULL,
 	.flags		= 0
 };
 
diff --git a/sys/modules/linux/Makefile b/sys/modules/linux/Makefile
index fbf5a58..280cb09 100644
--- a/sys/modules/linux/Makefile
+++ b/sys/modules/linux/Makefile
@@ -17,7 +17,7 @@ SRCS=	linux${SFX}_dummy.c linux_emul.c linux_file.c \
 	device_if.h bus_if.h assym.s
 
 # XXX: for assym.s
-SRCS+=  opt_kstack_pages.h opt_nfs.h opt_apic.h opt_compat.h
+SRCS+=  opt_kstack_pages.h opt_nfs.h opt_apic.h opt_compat.h opt_hwpmc_hooks.h
 
 OBJS=	linux${SFX}_locore.o linux${SFX}_support.o
 
@@ -55,6 +55,18 @@ linux${SFX}_genassym.o: linux${SFX}_genassym.c linux.h @ machine
 .if !defined(KERNBUILDDIR)
 opt_inet6.h:
 	echo "#define INET6 1" > ${.TARGET}
+
+.if defined(DEBUG)
+CFLAGS+=-DDEBUG
+.endif
+
+.if defined(KTR)
+CFLAGS+=-DKTR
+.endif
+
+.if defined(INVARIANTS)
+CFLAGS+=-DINVARIANTS
+.endif
 .endif
 
 .include <bsd.kmod.mk>
diff --git a/sys/powerpc/powerpc/elf_machdep.c b/sys/powerpc/powerpc/elf_machdep.c
index 69ac55b..f0dc474 100644
--- a/sys/powerpc/powerpc/elf_machdep.c
+++ b/sys/powerpc/powerpc/elf_machdep.c
@@ -87,7 +87,8 @@ static Elf32_Brandinfo freebsd_brand_info = {
 	.interp_path	= "/libexec/ld-elf.so.1",
 	.sysvec		= &elf32_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_ANY,
@@ -102,7 +103,8 @@ static Elf32_Brandinfo freebsd_brand_oinfo = {
 	.interp_path	= "/usr/libexec/ld-elf.so.1",
 	.sysvec		= &elf32_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY,
diff --git a/sys/sparc64/sparc64/elf_machdep.c b/sys/sparc64/sparc64/elf_machdep.c
index a956c5c..03b9056 100644
--- a/sys/sparc64/sparc64/elf_machdep.c
+++ b/sys/sparc64/sparc64/elf_machdep.c
@@ -99,7 +99,8 @@ static Elf64_Brandinfo freebsd_brand_info = {
 	.interp_path	= "/libexec/ld-elf.so.1",
 	.sysvec		= &elf64_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_ANY,
@@ -114,7 +115,8 @@ static Elf64_Brandinfo freebsd_brand_oinfo = {
 	.interp_path	= "/usr/libexec/ld-elf.so.1",
 	.sysvec		= &elf64_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY,
diff --git a/sys/sys/imgact_elf.h b/sys/sys/imgact_elf.h
index deb5b10..d290185 100644
--- a/sys/sys/imgact_elf.h
+++ b/sys/sys/imgact_elf.h
@@ -62,8 +62,10 @@ typedef struct {
 	const char *interp_path;
 	struct sysentvec *sysvec;
 	const char *interp_newpath;
+	int (*brand_abi_note)(struct image_params *, int32_t *);
 	int flags;
-#define	BI_CAN_EXEC_DYN	0x0001
+#define	BI_CAN_EXEC_DYN		0x0001
+#define	BI_CAN_EXEC_INTERP	0x0002
 } __ElfN(Brandinfo);
 
 __ElfType(Auxargs);
@@ -76,6 +78,7 @@ int	__elfN(insert_brand_entry)(Elf_Brandinfo *entry);
 int	__elfN(remove_brand_entry)(Elf_Brandinfo *entry);
 int	__elfN(freebsd_fixup)(register_t **, struct image_params *);
 int	__elfN(coredump)(struct thread *, struct vnode *, off_t);
+int	__elfN(freebsd_abi_note)(struct image_params *, int32_t *);
 
 /* Machine specific function to dump per-thread information. */
 void	__elfN(dump_thread)(struct thread *, void *, size_t *);

