Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 08 Aug 2014 21:30:27 -0600
From:      Ian Lepore <ian@FreeBSD.org>
To:        Rui Paulo <rpaulo@felyko.com>
Cc:        freebsd-arm@FreeBSD.org
Subject:   Re: [Bug 192516] New: DTrace not yet supported on ARM
Message-ID:  <1407555027.56408.442.camel@revolution.hippie.lan>
In-Reply-To: <E90FC916-B4A0-493A-AC30-2EFC7CFE922E@felyko.com>
References:  <bug-192516-7@https.bugs.freebsd.org/bugzilla/> <1407515740.56408.378.camel@revolution.hippie.lan> <CBA4135C-C3DF-4521-AC24-94B7D41D6C76@felyko.com> <1407552970.56408.440.camel@revolution.hippie.lan> <E90FC916-B4A0-493A-AC30-2EFC7CFE922E@felyko.com>

next in thread | previous in thread | raw e-mail | index | archive | help

--=-1VnxsOIhDnJzpH5E7tuZ
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit

On Fri, 2014-08-08 at 20:22 -0700, Rui Paulo wrote:
> On Aug 8, 2014, at 19:56, Ian Lepore <ian@FreeBSD.org> wrote:
> > I'm talking about resources like asking for reviews of his patches (and
> > nobody ever did, myself included).  Answering questions, providing
> > advice, basic stuff that we're hard pressed to do, quite frankly.  I
> > could spend my entire waking existance doing just that kind of stuff,
> > and still not keep up, and also never get a line of code written.
> 
> Yup, that's why we have a bug tracker.  :-)
> 

That response strikes me as being a bit of a non sequitor.

> > If you didn't know, maybe you weren't reading arm@ back then...
> > 
> > http://lists.freebsd.org/pipermail/freebsd-arm/2013-November/006957.html
> 
> There's no patch here.  Do you have it?

Attached.

-- Ian


--=-1VnxsOIhDnJzpH5E7tuZ
Content-Disposition: attachment; filename="dtrace.1121.diff"
Content-Type: text/x-patch; name="dtrace.1121.diff"; charset="us-ascii"
Content-Transfer-Encoding: 7bit

diff --git a/cddl/contrib/opensolaris/lib/libdtrace/arm/dt_isadep.c b/cddl/contrib/opensolaris/lib/libdtrace/arm/dt_isadep.c
new file mode 100644
index 0000000..7e73794
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/arm/dt_isadep.c
@@ -0,0 +1,181 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <libgen.h>
+
+#include <dt_impl.h>
+#include <dt_pid.h>
+
+#define	OP(x)		((x) >> 30)
+#define	OP2(x)		(((x) >> 22) & 0x07)
+#define	COND(x)		(((x) >> 25) & 0x0f)
+#define	A(x)		(((x) >> 29) & 0x01)
+
+#define	OP_BRANCH	0
+
+#define	OP2_BPcc	0x1
+#define	OP2_Bicc	0x2
+#define	OP2_BPr		0x3
+#define	OP2_FBPfcc	0x5
+#define	OP2_FBfcc	0x6
+
+/*ARGSUSED*/
+int
+dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+    fasttrap_probe_spec_t *ftp, const GElf_Sym *symp)
+{
+	ftp->ftps_type = DTFTP_ENTRY;
+	ftp->ftps_pc = (uintptr_t)symp->st_value;
+	ftp->ftps_size = (size_t)symp->st_size;
+	ftp->ftps_noffs = 1;
+	ftp->ftps_offs[0] = 0;
+
+	if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+		dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+		    strerror(errno));
+		return (dt_set_errno(dtp, errno));
+	}
+
+	return (1);
+}
+
+int
+dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+    fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret)
+{
+
+	uint32_t *text;
+	int i;
+	int srdepth = 0;
+
+	dt_dprintf("%s: unimplemented\n", __func__);
+	return (DT_PROC_ERR);
+
+	if ((text = malloc(symp->st_size + 4)) == NULL) {
+		dt_dprintf("mr sparkle: malloc() failed\n");
+		return (DT_PROC_ERR);
+	}
+
+	if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) {
+		dt_dprintf("mr sparkle: Pread() failed\n");
+		free(text);
+		return (DT_PROC_ERR);
+	}
+
+	/*
+	 * Leave a dummy instruction in the last slot to simplify edge
+	 * conditions.
+	 */
+	text[symp->st_size / 4] = 0;
+
+	ftp->ftps_type = DTFTP_RETURN;
+	ftp->ftps_pc = symp->st_value;
+	ftp->ftps_size = symp->st_size;
+	ftp->ftps_noffs = 0;
+
+
+	free(text);
+	if (ftp->ftps_noffs > 0) {
+		if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+			dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+			    strerror(errno));
+			return (dt_set_errno(dtp, errno));
+		}
+	}
+
+
+	return (ftp->ftps_noffs);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+    fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off)
+{
+	if (off & 0x3)
+		return (DT_PROC_ALIGN);
+
+	ftp->ftps_type = DTFTP_OFFSETS;
+	ftp->ftps_pc = (uintptr_t)symp->st_value;
+	ftp->ftps_size = (size_t)symp->st_size;
+	ftp->ftps_noffs = 1;
+	ftp->ftps_offs[0] = off;
+
+	if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+		dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+		    strerror(errno));
+		return (dt_set_errno(dtp, errno));
+	}
+
+	return (1);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+    fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern)
+{
+	ulong_t i;
+
+	ftp->ftps_type = DTFTP_OFFSETS;
+	ftp->ftps_pc = (uintptr_t)symp->st_value;
+	ftp->ftps_size = (size_t)symp->st_size;
+	ftp->ftps_noffs = 0;
+
+	/*
+	 * If we're matching against everything, just iterate through each
+	 * instruction in the function, otherwise look for matching offset
+	 * names by constructing the string and comparing it against the
+	 * pattern.
+	 */
+	if (strcmp("*", pattern) == 0) {
+		for (i = 0; i < symp->st_size; i += 4) {
+			ftp->ftps_offs[ftp->ftps_noffs++] = i;
+		}
+	} else {
+		char name[sizeof (i) * 2 + 1];
+
+		for (i = 0; i < symp->st_size; i += 4) {
+			(void) sprintf(name, "%lx", i);
+			if (gmatch(name, pattern))
+				ftp->ftps_offs[ftp->ftps_noffs++] = i;
+		}
+	}
+
+	if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+		dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+		    strerror(errno));
+		return (dt_set_errno(dtp, errno));
+	}
+
+	return (ftp->ftps_noffs);
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c b/cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c
index 82ec5fa..c6f47af 100644
--- a/cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c
@@ -169,12 +169,12 @@ write_objects(iidesc_t *idp, ctf_buf_t *b)
 {
 	ushort_t id = (idp ? idp->ii_dtype->t_id : 0);
 
-	ctf_buf_write(b, &id, sizeof (id));
-
 	if (target_requires_swap) {
 		SWAP_16(id);
 	}
 
+	ctf_buf_write(b, &id, sizeof (id));
+
 	debug(3, "Wrote object %s (%d)\n", (idp ? idp->ii_name : "(null)"), id);
 }
 
diff --git a/cddl/lib/Makefile b/cddl/lib/Makefile
index 53d402a..ff34d68 100644
--- a/cddl/lib/Makefile
+++ b/cddl/lib/Makefile
@@ -22,7 +22,8 @@ _libzpool=	libzpool
 .endif
 
 .if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" || \
-	${MACHINE_CPUARCH} == "mips" || ${MACHINE_CPUARCH} == "powerpc"
+	${MACHINE_CPUARCH} == "mips" || ${MACHINE_CPUARCH} == "powerpc" || \
+	${MACHINE_CPUARCH} == "arm"
 _drti=		drti
 _libdtrace=	libdtrace
 .endif
diff --git a/cddl/lib/libdtrace/Makefile b/cddl/lib/libdtrace/Makefile
index 46f7046..f9b0214 100644
--- a/cddl/lib/libdtrace/Makefile
+++ b/cddl/lib/libdtrace/Makefile
@@ -79,6 +79,10 @@ CFLAGS+=	-I${OPENSOLARIS_SYS_DISTDIR}/uts/sparc
 CFLAGS+=	-I${OPENSOLARIS_SYS_DISTDIR}/uts/mips
 .PATH:		${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/mips
 .PATH:		${.CURDIR}/../../../sys/cddl/dev/dtrace/mips
+.elif ${MACHINE_CPUARCH} == "arm"
+CFLAGS+=	-I${OPENSOLARIS_SYS_DISTDIR}/uts/arm
+.PATH:		${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/arm
+.PATH:		${.CURDIR}/../../../sys/cddl/dev/dtrace/arm
 .elif ${MACHINE_CPUARCH} == "powerpc"
 CFLAGS+=	-I${OPENSOLARIS_SYS_DISTDIR}/uts/powerpc
 .PATH:		${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/powerpc
diff --git a/cddl/usr.sbin/Makefile b/cddl/usr.sbin/Makefile
index fb2c437..ad8a998 100644
--- a/cddl/usr.sbin/Makefile
+++ b/cddl/usr.sbin/Makefile
@@ -21,6 +21,12 @@ _dtruss=	dtruss
 _lockstat=	lockstat
 .endif
 
+.if ${MACHINE_CPUARCH} == "arm"
+_dtrace=	dtrace
+_lockstat=	lockstat
+_dtruss=	dtruss
+.endif
+
 .if ${MACHINE_CPUARCH} == "mips"
 _dtrace=	dtrace
 .endif
diff --git a/lib/Makefile b/lib/Makefile
index bb8a7e1..db0f16d 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -233,6 +233,12 @@ _libsmb=	libsmb
 _libsmb=	libsmb
 .endif
 
+.if ${MACHINE_CPUARCH} == "arm"
+_libsmb=	libsmb
+_libproc=	libproc
+_librtld_db=	librtld_db
+.endif
+
 .if ${MK_OPENSSL} != "no"
 _libmp=		libmp
 .endif
diff --git a/lib/libproc/proc_bkpt.c b/lib/libproc/proc_bkpt.c
index 2c2761a..02a7ed6 100644
--- a/lib/libproc/proc_bkpt.c
+++ b/lib/libproc/proc_bkpt.c
@@ -51,6 +51,9 @@ __FBSDID("$FreeBSD$");
 #elif defined(__powerpc__)
 #define BREAKPOINT_INSTR	0x7fe00008	/* trap */
 #define BREAKPOINT_INSTR_SZ 4
+#elif defined(__arm__)
+#define BREAKPOINT_INSTR	0xe7ffffff	/* bkpt */
+#define BREAKPOINT_INSTR_SZ	4
 #else
 #error "Add support for your architecture"
 #endif
diff --git a/lib/libproc/proc_regs.c b/lib/libproc/proc_regs.c
index 145c8fe..35d8d38 100644
--- a/lib/libproc/proc_regs.c
+++ b/lib/libproc/proc_regs.c
@@ -56,6 +56,8 @@ proc_regget(struct proc_handle *phdl, proc_reg_t reg, unsigned long *regvalue)
 	case REG_PC:
 #if defined(__amd64__)
 		*regvalue = regs.r_rip;
+#elif defined(__arm__)
+		*regvalue = regs.r_pc;
 #elif defined(__i386__)
 		*regvalue = regs.r_eip;
 #elif defined(__mips__)
@@ -67,6 +69,8 @@ proc_regget(struct proc_handle *phdl, proc_reg_t reg, unsigned long *regvalue)
 	case REG_SP:
 #if defined(__amd64__)
 		*regvalue = regs.r_rsp;
+#elif defined(__arm__)
+		*regvalue = regs.r_sp;
 #elif defined(__i386__)
 		*regvalue = regs.r_esp;
 #elif defined(__mips__)
@@ -99,6 +103,8 @@ proc_regset(struct proc_handle *phdl, proc_reg_t reg, unsigned long regvalue)
 	case REG_PC:
 #if defined(__amd64__)
 		regs.r_rip = regvalue;
+#elif defined(__arm__)
+		regs.r_pc = regvalue;
 #elif defined(__i386__)
 		regs.r_eip = regvalue;
 #elif defined(__mips__)
@@ -110,6 +116,8 @@ proc_regset(struct proc_handle *phdl, proc_reg_t reg, unsigned long regvalue)
 	case REG_SP:
 #if defined(__amd64__)
 		regs.r_rsp = regvalue;
+#elif defined(__arm__)
+		regs.r_sp = regvalue;
 #elif defined(__i386__)
 		regs.r_esp = regvalue;
 #elif defined(__mips__)
diff --git a/sys/arm/arm/exception.S b/sys/arm/arm/exception.S
index 55a4f64..80b1734 100644
--- a/sys/arm/arm/exception.S
+++ b/sys/arm/arm/exception.S
@@ -47,12 +47,26 @@
  */
 
 #include "assym.s"
-
+#include "opt_kdtrace.h"
 #include <machine/asm.h>
 #include <machine/armreg.h>
 #include <machine/asmacros.h>
 __FBSDID("$FreeBSD$");
 
+#ifdef KDTRACE_HOOKS
+	.bss
+	.align 4
+	.global	_C_LABEL(dtrace_invop_jump_addr)
+_C_LABEL(dtrace_invop_jump_addr):
+	.word 0
+	.word 0
+
+	.global	_C_LABEL(dtrace_invop_calltrap_addr)
+_C_LABEL(dtrace_invop_calltrap_addr):
+	.word 0
+	.word 0
+#endif
+
 	.text	
 	.align	0
 
@@ -239,7 +253,20 @@ END(undefined_entry)
 
 ENTRY_NP(undefinedinstruction_bounce)
 	PUSHFRAMEINSVC
+#ifdef notyet
+	adr	r1, dtrace_invop_jump_addr	
+	ldr	r0, r1
+	cmp	r0, #0
+	beq	normal
+	
+	mrs	r2, spsr_all
+	tst 	r2, #PSR_MODE
+	bne     normal
 
+	bl      r0
+	
+normal:		
+#endif
 	mov	r0, sp
 	adr	lr, exception_exit
 	b	_C_LABEL(undefinedinstruction)
diff --git a/sys/arm/arm/identcpu.c b/sys/arm/arm/identcpu.c
index 219d49c..1febfcf 100644
--- a/sys/arm/arm/identcpu.c
+++ b/sys/arm/arm/identcpu.c
@@ -461,7 +461,7 @@ identify_arm_cpu(void)
 	u_int8_t type, linesize;
 	int i;
 
-	cpuid = cpu_id();
+	cpuid = cpu_ident();
 
 	if (cpuid == 0) {
 		printf("Processor failed probe - no CPU ID\n");
diff --git a/sys/arm/arm/machdep.c b/sys/arm/arm/machdep.c
index c935a82..d9656db 100644
--- a/sys/arm/arm/machdep.c
+++ b/sys/arm/arm/machdep.c
@@ -835,8 +835,8 @@ fake_preload_metadata(struct arm_boot_params *abp __unused)
 	strcpy((char*)&fake_preload[i++], "kernel");
 	i += 1;
 	fake_preload[i++] = MODINFO_TYPE;
-	fake_preload[i++] = strlen("elf kernel") + 1;
-	strcpy((char*)&fake_preload[i++], "elf kernel");
+	fake_preload[i++] = strlen("/boot/kernel/kernel") + 1;
+	strcpy((char*)&fake_preload[i++], "/boot/kernel/kernel");
 	i += 2;
 	fake_preload[i++] = MODINFO_ADDR;
 	fake_preload[i++] = sizeof(vm_offset_t);
diff --git a/sys/arm/arm/trap.c b/sys/arm/arm/trap.c
index 5021eec..d34846c 100644
--- a/sys/arm/arm/trap.c
+++ b/sys/arm/arm/trap.c
@@ -80,6 +80,7 @@
 
 
 #include "opt_ktrace.h"
+#include "opt_kdtrace.h"
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
@@ -122,6 +123,31 @@ __FBSDID("$FreeBSD$");
 #include <sys/kdb.h>
 #endif
 
+#ifdef KDTRACE_HOOKS
+#include <sys/dtrace_bsd.h>
+ 
+/*
+ * This is a hook which is initialised by the dtrace module
+ * to handle traps which might occur during DTrace probe
+ * execution.
+ */
+dtrace_trap_func_t	dtrace_trap_func;
+
+dtrace_doubletrap_func_t	dtrace_doubletrap_func;
+
+/*
+ * This is a hook which is initialised by the systrace module
+ * when it is loaded. This keeps the DTrace syscall provider
+ * implementation opaque. 
+ */
+systrace_probe_func_t	systrace_probe_func;
+
+/*
+ * These hooks are necessary for the pid and usdt providers.
+ */
+dtrace_pid_probe_ptr_t		dtrace_pid_probe_ptr;
+dtrace_return_probe_ptr_t	dtrace_return_probe_ptr;
+#endif
 
 void swi_handler(struct trapframe *);
 void undefinedinstruction(struct trapframe *);
@@ -452,6 +478,7 @@ data_abort_handler(struct trapframe *tf)
 		printf("\nvm_fault(%p, %x, %x, 0) -> %x\n", map, va, ftype,
 		    error);
 		dab_fatal(tf, fsr, far, td, &ksig);
+		return;
 	}
 
 
@@ -492,6 +519,14 @@ dab_fatal(struct trapframe *tf, u_int fsr, u_int far, struct thread *td,
 {
 	const char *mode;
 
+#ifdef KDTRACE_HOOKS
+	if (!TRAP_USERMODE(tf))
+	{
+		if (dtrace_trap_func != NULL && (*dtrace_trap_func)(tf, far & FAULT_TYPE_MASK))
+			return (0);
+	}
+#endif
+
 	mode = TRAP_USERMODE(tf) ? "user" : "kernel";
 
 	disable_interrupts(I32_bit|F32_bit);
diff --git a/sys/arm/conf/BEAGLEBONE b/sys/arm/conf/BEAGLEBONE
index 272d3e8..16c9a46 100644
--- a/sys/arm/conf/BEAGLEBONE
+++ b/sys/arm/conf/BEAGLEBONE
@@ -59,8 +59,8 @@ options 	KDB
 options 	DDB			#Enable the kernel debugger
 options 	INVARIANTS		#Enable calls of extra sanity checking
 options 	INVARIANT_SUPPORT	#Extra sanity checks of internal structures, required by INVARIANTS
-options 	WITNESS			#Enable checks to detect deadlocks and cycles
-options 	WITNESS_SKIPSPIN	#Don't run witness on spinlocks for speed
+#options 	WITNESS			#Enable checks to detect deadlocks and cycles
+#options 	WITNESS_SKIPSPIN	#Don't run witness on spinlocks for speed
 #options 	DIAGNOSTIC
 
 # NFS support
@@ -69,12 +69,12 @@ options 	NFSCL
 options 	NFSLOCKD
 
 # Uncomment this for NFS root
-#options 	NFS_ROOT		#NFS usable as /, requires NFSCL
-#options 	BOOTP_NFSROOT
-#options 	BOOTP_COMPAT
-#options 	BOOTP
-#options 	BOOTP_NFSV3
-#options 	BOOTP_WIRED_TO=cpsw0
+options 	NFS_ROOT		#NFS usable as /, requires NFSCL
+options 	BOOTP_NFSROOT
+options 	BOOTP_COMPAT
+options 	BOOTP
+options 	BOOTP_NFSV3
+options 	BOOTP_WIRED_TO=cpsw0
 
 
 # MMC/SD/SDIO card slot support
@@ -83,7 +83,8 @@ device		mmcsd			# mmc/sd flash cards
 device		sdhci			# mmc/sd host controller
 
 # Boot device is 2nd slice on MMC/SD card
-options 	ROOTDEVNAME=\"ufs:mmcsd0s2\"
+#options 	ROOTDEVNAME=\"ufs:mmcsd0s2\"
+options 	ROOTDEVNAME=\"nfs:192.168.0.123:/bbb\"
 
 # Console and misc
 device		uart
@@ -131,4 +132,10 @@ device		usfs
 # Flattened Device Tree
 options         FDT
 options         FDT_DTB_STATIC
-makeoptions     FDT_DTS_FILE=beaglebone.dts
+makeoptions     FDT_DTS_FILE=beaglebone-black.dts
+
+#dtrace support
+options 	KDTRACE_HOOKS		# Kernel DTrace hooks
+options		DDB_CTF              	# all architectures - kernel ELF linker loads CTF data
+makeoptions 	WITH_CTF=1
+makeoptions     MODULES_OVERRIDE="opensolaris dtrace cyclic dtrace/dtnfsclient dtrace/dtnfscl dtrace/lockstat dtrace/profile dtrace/fbt"
diff --git a/sys/arm/include/cpufunc.h b/sys/arm/include/cpufunc.h
index d3e9ebe..4c96373 100644
--- a/sys/arm/include/cpufunc.h
+++ b/sys/arm/include/cpufunc.h
@@ -167,7 +167,7 @@ struct cpu_functions {
 extern struct cpu_functions cpufuncs;
 extern u_int cputype;
 
-#define cpu_id()		cpufuncs.cf_id()
+#define cpu_ident()		cpufuncs.cf_id()
 #define	cpu_cpwait()		cpufuncs.cf_cpwait()
 
 #define cpu_control(c, e)	cpufuncs.cf_control(c, e)
diff --git a/sys/cddl/contrib/opensolaris/uts/arm/sys/fasttrap_isa.c b/sys/cddl/contrib/opensolaris/uts/arm/sys/fasttrap_isa.c
new file mode 100644
index 0000000..18e3837
--- /dev/null
+++ b/sys/cddl/contrib/opensolaris/uts/arm/sys/fasttrap_isa.c
@@ -0,0 +1,30 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ *	XXX: Placeholder for ARM fasttrap code
+ */
diff --git a/sys/cddl/contrib/opensolaris/uts/arm/sys/fasttrap_isa.h b/sys/cddl/contrib/opensolaris/uts/arm/sys/fasttrap_isa.h
new file mode 100644
index 0000000..10361cbe
--- /dev/null
+++ b/sys/cddl/contrib/opensolaris/uts/arm/sys/fasttrap_isa.h
@@ -0,0 +1,94 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_FASTTRAP_ISA_H
+#define	_FASTTRAP_ISA_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * This is our reserved trap instruction: ta 0x38
+ */
+#define	FASTTRAP_INSTR			0x91d02038
+
+#define	FASTTRAP_SUNWDTRACE_SIZE	128
+
+typedef uint32_t	fasttrap_instr_t;
+
+typedef struct fasttrap_machtp {
+	fasttrap_instr_t	ftmt_instr;	/* original instruction */
+	uintptr_t		ftmt_dest;	/* destination of DCTI */
+	uint8_t			ftmt_type;	/* emulation type */
+	uint8_t			ftmt_flags;	/* emulation flags */
+	uint8_t			ftmt_cc;	/* which cc to look at */
+	uint8_t			ftmt_code;	/* branch condition */
+} fasttrap_machtp_t;
+
+#define	ftt_instr	ftt_mtp.ftmt_instr
+#define	ftt_dest	ftt_mtp.ftmt_dest
+#define	ftt_type	ftt_mtp.ftmt_type
+#define	ftt_flags	ftt_mtp.ftmt_flags
+#define	ftt_cc		ftt_mtp.ftmt_cc
+#define	ftt_code	ftt_mtp.ftmt_code
+
+#define	FASTTRAP_T_COMMON	0x00	/* common case -- no emulation */
+#define	FASTTRAP_T_CCR		0x01	/* integer condition code branch */
+#define	FASTTRAP_T_FCC		0x02	/* floating-point branch */
+#define	FASTTRAP_T_REG		0x03	/* register predicated branch */
+#define	FASTTRAP_T_ALWAYS	0x04	/* branch always */
+#define	FASTTRAP_T_CALL		0x05	/* call instruction */
+#define	FASTTRAP_T_JMPL		0x06	/* jmpl instruction */
+#define	FASTTRAP_T_RDPC		0x07	/* rdpc instruction */
+#define	FASTTRAP_T_RETURN	0x08	/* return instruction */
+
+/*
+ * For performance rather than correctness.
+ */
+#define	FASTTRAP_T_SAVE		0x10	/* save instruction (func entry only) */
+#define	FASTTRAP_T_RESTORE	0x11	/* restore instruction */
+#define	FASTTRAP_T_OR		0x12	/* mov instruction */
+#define	FASTTRAP_T_SETHI	0x13	/* sethi instruction (includes nop) */
+
+#define	FASTTRAP_F_ANNUL	0x01	/* branch is annulled */
+#define	FASTTRAP_F_RETMAYBE	0x02	/* not definitely a return site */
+
+#define	FASTTRAP_AFRAMES		3
+#define	FASTTRAP_RETURN_AFRAMES		4
+#define	FASTTRAP_ENTRY_AFRAMES		3
+#define	FASTTRAP_OFFSET_AFRAMES		3
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _FASTTRAP_ISA_H */
diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
index f35cf73..9e4b23d 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
@@ -10933,7 +10933,7 @@ err:
 #else
 	int i;
 
-#if defined(__amd64__) || defined(__mips__) || defined(__powerpc__)
+#if defined(__amd64__) || defined(__mips__) || defined(__powerpc__) || defined(__arm__)
 	/*
 	 * FreeBSD isn't good at limiting the amount of memory we
 	 * ask to malloc, so let's place a limit here before trying
diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h
index 295457c..671faa9 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h
@@ -2390,6 +2390,13 @@ extern void dtrace_helpers_destroy(proc_t *);
 #define DTRACE_INVOP_MFLR_R0	5
 #define DTRACE_INVOP_NOP	6
 
+#elif defined(__arm__)
+
+#define DTRACE_INVOP_PUSHM	1
+#define DTRACE_INVOP_POPM	2
+#define DTRACE_INVOP_B  	3
+
+
 #endif
 
 #ifdef	__cplusplus
diff --git a/sys/cddl/dev/dtrace/arm/dtrace_asm.S b/sys/cddl/dev/dtrace/arm/dtrace_asm.S
new file mode 100644
index 0000000..7898bc4
--- /dev/null
+++ b/sys/cddl/dev/dtrace/arm/dtrace_asm.S
@@ -0,0 +1,185 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * $FreeBSD$
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#define _ASM
+#define _LOCORE
+#define LOCORE
+
+#include <sys/cpuvar_defs.h>
+#include <sys/dtrace.h>
+
+#include <machine/asm.h>
+
+#include "assym.s"
+
+/*
+void dtrace_membar_producer(void)
+*/
+ENTRY(dtrace_membar_producer)
+	RET
+
+/*
+void dtrace_membar_consumer(void)
+*/
+ENTRY(dtrace_membar_consumer)
+	RET
+
+/*
+dtrace_icookie_t dtrace_interrupt_disable(void)
+*/
+ENTRY(dtrace_interrupt_disable)
+	mrs	r0, cpsr
+	mov	r1, r0
+	orr	r1, r1, #(I32_bit|F32_bit)
+	msr	cpsr_c, r1
+	RET
+/*
+void dtrace_interrupt_enable(dtrace_icookie_t cookie)
+*/
+ENTRY(dtrace_interrupt_enable)
+	and	r0, r0, #(I32_bit|F32_bit)
+	mrs	r1, cpsr
+	bic	r1, r1, #(I32_bit|F32_bit)
+	orr	r1, r1, r0
+	msr	cpsr_c, r1
+	RET
+
+/*
+uint8_t
+dtrace_fuword8_nocheck(void *addr)
+*/
+ENTRY(dtrace_fuword8_nocheck)
+	ldrb	r3, [r0]
+	mov 	r0, r3
+	RET
+
+/*
+uint16_t
+dtrace_fuword16_nocheck(void *addr)
+*/
+ENTRY(dtrace_fuword16_nocheck)
+	ldrh	r3, [r0]
+	mov 	r0, r3
+	RET
+
+/*
+uint32_t
+dtrace_fuword32_nocheck(void *addr)
+*/
+ENTRY(dtrace_fuword32_nocheck)
+	ldr	r3, [r0]
+	mov 	r0, r3
+	RET
+
+/*
+uint64_t
+dtrace_fuword64_nocheck(void *addr)
+*/
+ENTRY(dtrace_fuword64_nocheck)
+	ldm	r0, {r2, r3}
+
+	mov	r0, r2
+	mov	r1, r3
+#if defined(__BIG_ENDIAN__)
+/* big endian */
+	mov	r0, r3
+	mov	r1, r2
+#else
+/* little endian */
+	mov	r0, r2
+	mov	r1, r3
+
+#endif
+	RET
+
+/*
+void
+dtrace_copy(uintptr_t uaddr, uintptr_t kaddr, size_t size)
+*/
+ENTRY(dtrace_copy)
+	stmfd   sp!, {r4-r5}			/* stack is 8 byte aligned */
+	teq     r2, #0x00000000
+	mov     r5, #0x00000000
+	beq     2f
+
+1:	ldrb    r4, [r0], #0x0001
+	add     r5, r5, #0x00000001
+	strb    r4, [r1], #0x0001
+	teqne   r5, r2
+	bne     1b
+
+2:	ldmfd   sp!, {r4-r5}			/* stack is 8 byte aligned */
+	RET
+
+
+/*
+void
+dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
+    volatile uint16_t *flags)
+XXX: Check for flags?
+*/
+ENTRY(dtrace_copystr)
+	stmfd   sp!, {r4-r5}			/* stack is 8 byte aligned */
+	teq     r2, #0x00000000
+	mov     r5, #0x00000000
+	beq     2f
+
+1:	ldrb    r4, [r0], #0x0001
+	add     r5, r5, #0x00000001
+	teq     r4, #0x00000000
+	strb    r4, [r1], #0x0001
+	teqne   r5, r2
+	bne     1b
+
+2:	ldmfd   sp!, {r4-r5}			/* stack is 8 byte aligned */
+	RET
+
+#if 0
+/*
+void
+vpanic(const char *format, va_list alist)
+*/
+ENTRY(vpanic)				/* Initial stack layout: */
+vpanic_common:
+	RET
+#endif
+/*
+void
+dtrace_vpanic(const char *format, va_list alist)
+*/
+ENTRY(dtrace_vpanic)			/* Initial stack layout: */
+	b	vpanic	
+	RET
+
+/*
+uintptr_t
+dtrace_caller(int aframes)
+*/
+ENTRY(dtrace_caller)
+	mov	r0, #-1
+	RET
diff --git a/sys/cddl/dev/dtrace/arm/dtrace_isa.c b/sys/cddl/dev/dtrace/arm/dtrace_isa.c
new file mode 100644
index 0000000..e885a60
--- /dev/null
+++ b/sys/cddl/dev/dtrace/arm/dtrace_isa.c
@@ -0,0 +1,373 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * $FreeBSD$
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/stack.h>
+#include <sys/pcpu.h>
+
+#include <machine/frame.h>
+#include <machine/md_var.h>
+#include <machine/reg.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
+#include <machine/atomic.h>
+#include <machine/db_machdep.h>
+#include <machine/md_var.h>
+#include <machine/vmparam.h>
+#include <machine/stack.h>
+#include <ddb/db_sym.h>
+#include <ddb/ddb.h>
+#include <sys/kdb.h>
+
+#include "regset.h"
+
+/*
+ * Wee need some reasonable default to prevent backtrace code
+ * from wandering too far
+ */
+#define	MAX_FUNCTION_SIZE 0x10000
+#define	MAX_PROLOGUE_SIZE 0x100
+
+
+uint8_t dtrace_fuword8_nocheck(void *);
+uint16_t dtrace_fuword16_nocheck(void *);
+uint32_t dtrace_fuword32_nocheck(void *);
+uint64_t dtrace_fuword64_nocheck(void *);
+
+void
+dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
+    uint32_t *intrpc)
+{
+	u_int32_t	*frame, *lastframe;
+	int	scp_offset;
+	int	depth = 0;
+	pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
+
+	if (intrpc != 0)
+		pcstack[depth++] = (pc_t) intrpc;
+
+	aframes++;
+
+	frame = (u_int32_t *)__builtin_frame_address(0);;
+	lastframe = NULL;
+	scp_offset = -(get_pc_str_offset() >> 2);
+
+	while ((frame != NULL) && (depth < pcstack_limit)) {
+		db_addr_t	scp;
+#if 0 
+		u_int32_t	savecode;
+		int		r;
+		u_int32_t	*rp;
+#endif
+
+		/*
+		 * In theory, the SCP isn't guaranteed to be in the function
+		 * that generated the stack frame.  We hope for the best.
+		 */
+		scp = frame[FR_SCP];
+		printf("--> %08x\n", (uint32_t)scp);
+
+		if (aframes > 0) {
+			aframes--;
+			if ((aframes == 0) && (caller != 0)) {
+				pcstack[depth++] = caller;
+			}
+		}
+		else {
+			printf("++ --> %08x\n", (uint32_t)scp);
+			pcstack[depth++] = scp;
+		}
+
+#if 0
+		savecode = ((u_int32_t *)scp)[scp_offset];
+		if ((savecode & 0x0e100000) == 0x08000000) {
+			/* Looks like an STM */
+			rp = frame - 4;
+			for (r = 10; r >= 0; r--) {
+				if (savecode & (1 << r)) {
+					/* register r == *rp-- */
+				}
+			}
+		}
+#endif
+
+		/*
+		 * Switch to next frame up
+		 */
+		if (frame[FR_RFP] == 0)
+			break; /* Top of stack */
+
+		lastframe = frame;
+		frame = (u_int32_t *)(frame[FR_RFP]);
+
+		if (INKERNEL((int)frame)) {
+			/* staying in kernel */
+			if (frame <= lastframe) {
+				/* bad frame pointer */
+				break;
+			}
+		}
+		else
+			break;
+	}
+
+	for (; depth < pcstack_limit; depth++) {
+		pcstack[depth] = 0;
+	}
+}
+
+void
+dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
+{
+	printf("IMPLEMENT ME: %s\n", __func__);
+}
+
+int
+dtrace_getustackdepth(void)
+{
+	printf("IMPLEMENT ME: %s\n", __func__);
+	return (0);
+}
+
+void
+dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
+{
+	printf("IMPLEMENT ME: %s\n", __func__);
+}
+
+/*ARGSUSED*/
+uint64_t
+dtrace_getarg(int arg, int aframes)
+{
+	struct arm_frame *fp = (struct arm_frame *)dtrace_getfp();
+
+	return (0);
+}
+
+int
+dtrace_getstackdepth(int aframes)
+{
+	u_int32_t	*frame, *lastframe;
+	int	scp_offset;
+	int	depth = 1;
+
+	frame = (u_int32_t *)__builtin_frame_address(0);;
+	lastframe = NULL;
+	scp_offset = -(get_pc_str_offset() >> 2);
+
+	while (frame != NULL) {
+		db_addr_t	scp;
+#if 0 
+		u_int32_t	savecode;
+		int		r;
+		u_int32_t	*rp;
+#endif
+
+		/*
+		 * In theory, the SCP isn't guaranteed to be in the function
+		 * that generated the stack frame.  We hope for the best.
+		 */
+		scp = frame[FR_SCP];
+
+		depth++;
+
+		/*
+		 * Switch to next frame up
+		 */
+		if (frame[FR_RFP] == 0)
+			break; /* Top of stack */
+
+		lastframe = frame;
+		frame = (u_int32_t *)(frame[FR_RFP]);
+
+		if (INKERNEL((int)frame)) {
+			/* staying in kernel */
+			if (frame <= lastframe) {
+				/* bad frame pointer */
+				break;
+			}
+		}
+		else
+			break;
+	}
+
+	if (depth < aframes)
+		return 0;
+	else
+		return depth - aframes;
+
+}
+
+ulong_t
+dtrace_getreg(struct trapframe *rp, uint_t reg)
+{
+	printf("IMPLEMENT ME: %s\n", __func__);
+
+	return (0);
+}
+
+static int
+dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
+{
+
+	if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
+		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
+		cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
+		return (0);
+	}
+
+	return (1);
+}
+
+void
+dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
+    volatile uint16_t *flags)
+{
+	if (dtrace_copycheck(uaddr, kaddr, size))
+		dtrace_copy(uaddr, kaddr, size);
+}
+
+void
+dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
+    volatile uint16_t *flags)
+{
+	if (dtrace_copycheck(uaddr, kaddr, size))
+		dtrace_copy(kaddr, uaddr, size);
+}
+
+void
+dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
+    volatile uint16_t *flags)
+{
+	if (dtrace_copycheck(uaddr, kaddr, size))
+		dtrace_copystr(uaddr, kaddr, size, flags);
+}
+
+void
+dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
+    volatile uint16_t *flags)
+{
+	if (dtrace_copycheck(uaddr, kaddr, size))
+		dtrace_copystr(kaddr, uaddr, size, flags);
+}
+
+uint8_t
+dtrace_fuword8(void *uaddr)
+{
+	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
+		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
+		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
+		return (0);
+	}
+	return (dtrace_fuword8_nocheck(uaddr));
+}
+
+uint16_t
+dtrace_fuword16(void *uaddr)
+{
+	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
+		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
+		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
+		return (0);
+	}
+	return (dtrace_fuword16_nocheck(uaddr));
+}
+
+uint32_t
+dtrace_fuword32(void *uaddr)
+{
+	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
+		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
+		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
+		return (0);
+	}
+	return (dtrace_fuword32_nocheck(uaddr));
+}
+
+uint64_t
+dtrace_fuword64(void *uaddr)
+{
+	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
+		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
+		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
+		return (0);
+	}
+	return (dtrace_fuword64_nocheck(uaddr));
+}
+
+#ifndef I32_bit
+#define I32_bit (1 << 7)        /* IRQ disable */
+#endif
+#ifndef F32_bit
+#define F32_bit (1 << 6)        /* FIQ disable */
+#endif
+
+#define __with_interrupts_disabled(expr) \
+        do {                                            \
+                u_int cpsr_save, tmp;                   \
+                                                        \
+                __asm __volatile(                       \
+                        "mrs  %0, cpsr;"                \
+                        "orr  %1, %0, %2;"              \
+                        "msr  cpsr_all, %1;"            \
+                        : "=r" (cpsr_save), "=r" (tmp)  \
+                        : "I" (I32_bit | F32_bit)               \
+                        : "cc" );               \
+                (expr);                         \
+                 __asm __volatile(              \
+                        "msr  cpsr_all, %0"     \
+                        : /* no output */       \
+                        : "r" (cpsr_save)       \
+                        : "cc" );               \
+        } while(0)
+
+uint32_t dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new)
+{
+	uint32_t ret;
+	__with_interrupts_disabled(
+	{
+		ret = *target;
+		if (*target == cmp) {
+			*target = new;
+		}
+	});
+
+	return ret;
+}
+
+void * dtrace_casptr(volatile void *target, volatile void *cmp, volatile void *new)
+{
+	return (void*)dtrace_cas32((uint32_t*)target, (uint32_t)cmp, (uint32_t)new);
+}
+
diff --git a/sys/cddl/dev/dtrace/arm/dtrace_subr.c b/sys/cddl/dev/dtrace/arm/dtrace_subr.c
new file mode 100644
index 0000000..c24dd9b
--- /dev/null
+++ b/sys/cddl/dev/dtrace/arm/dtrace_subr.c
@@ -0,0 +1,264 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * $FreeBSD$
+ *
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/kmem.h>
+#include <sys/smp.h>
+#include <sys/dtrace_impl.h>
+#include <sys/dtrace_bsd.h>
+#include <machine/armreg.h>
+#include <machine/clock.h>
+#include <machine/frame.h>
+#include <machine/trap.h>
+#include <vm/pmap.h>
+
+#define	DELAYBRANCH(x)	((int)(x) < 0)
+		
+extern uintptr_t 	dtrace_in_probe_addr;
+extern int		dtrace_in_probe;
+extern dtrace_id_t	dtrace_probeid_error;
+extern int (*dtrace_invop_jump_addr)(struct trapframe *);
+
+int dtrace_invop(uintptr_t, uintptr_t *, uintptr_t);
+void dtrace_invop_init(void);
+void dtrace_invop_uninit(void);
+
+typedef struct dtrace_invop_hdlr {
+	int (*dtih_func)(uintptr_t, uintptr_t *, uintptr_t);
+	struct dtrace_invop_hdlr *dtih_next;
+} dtrace_invop_hdlr_t;
+
+dtrace_invop_hdlr_t *dtrace_invop_hdlr;
+
+int
+dtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax)
+{
+	dtrace_invop_hdlr_t *hdlr;
+	int rval;
+
+	for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next)
+		if ((rval = hdlr->dtih_func(addr, stack, eax)) != 0)
+			return (rval);
+
+	return (0);
+}
+
+
+void
+dtrace_invop_add(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
+{
+	dtrace_invop_hdlr_t *hdlr;
+
+	hdlr = kmem_alloc(sizeof (dtrace_invop_hdlr_t), KM_SLEEP);
+	hdlr->dtih_func = func;
+	hdlr->dtih_next = dtrace_invop_hdlr;
+	dtrace_invop_hdlr = hdlr;
+}
+
+void
+dtrace_invop_remove(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
+{
+	dtrace_invop_hdlr_t *hdlr = dtrace_invop_hdlr, *prev = NULL;
+
+	for (;;) {
+		if (hdlr == NULL)
+			panic("attempt to remove non-existent invop handler");
+
+		if (hdlr->dtih_func == func)
+			break;
+
+		prev = hdlr;
+		hdlr = hdlr->dtih_next;
+	}
+
+	if (prev == NULL) {
+		ASSERT(dtrace_invop_hdlr == hdlr);
+		dtrace_invop_hdlr = hdlr->dtih_next;
+	} else {
+		ASSERT(dtrace_invop_hdlr != hdlr);
+		prev->dtih_next = hdlr->dtih_next;
+	}
+
+	kmem_free(hdlr, 0);
+}
+
+
+/*ARGSUSED*/
+void
+dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit))
+{
+	printf("IMPLEMENT ME: dtrace_toxic_ranges\n");
+}
+
+void
+dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg)
+{
+	cpuset_t cpus;
+
+	if (cpu == DTRACE_CPUALL)
+		cpus = all_cpus;
+	else
+		CPU_SETOF(cpu, &cpus);
+
+	smp_rendezvous_cpus(cpus, smp_no_rendevous_barrier, func,
+	    smp_no_rendevous_barrier, arg);
+}
+
+static void
+dtrace_sync_func(void)
+{
+}
+
+void
+dtrace_sync(void)
+{
+        dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL);
+}
+
+/*
+ * DTrace needs a high resolution time function which can
+ * be called from a probe context and guaranteed not to have
+ * instrumented with probes itself.
+ *
+ * Returns nanoseconds since boot.
+ */
+uint64_t
+dtrace_gethrtime()
+{
+	struct      timespec curtime;
+
+	nanouptime(&curtime);
+
+	return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec);
+
+}
+
+uint64_t
+dtrace_gethrestime(void)
+{
+	struct      timespec curtime;
+
+	getnanotime(&curtime);
+
+	return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec);
+}
+
+/* Function to handle DTrace traps during probes. See amd64/amd64/trap.c */
+int
+dtrace_trap(struct trapframe *frame, u_int type)
+{
+	/*
+	 * A trap can occur while DTrace executes a probe. Before
+	 * executing the probe, DTrace blocks re-scheduling and sets
+	 * a flag in it's per-cpu flags to indicate that it doesn't
+	 * want to fault. On returning from the probe, the no-fault
+	 * flag is cleared and finally re-scheduling is enabled.
+	 *
+	 * Check if DTrace has enabled 'no-fault' mode:
+	 *
+	 */
+	if ((cpu_core[curcpu].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0) {
+		/*
+		 * There are only a couple of trap types that are expected.
+		 * All the rest will be handled in the usual way.
+		 */
+		switch (type) {
+		/* Page fault. */
+		case FAULT_WRTBUF_0:
+		case FAULT_WRTBUF_1:
+		case FAULT_ALIGN_0:
+		case FAULT_ALIGN_1:
+			/* Flag a bad address. */
+			cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
+			cpu_core[curcpu].cpuc_dtrace_illval = 0;
+
+			/*
+			 * Offset the instruction pointer to the instruction
+			 * following the one causing the fault.
+			 */
+			frame->tf_pc += sizeof(int);
+			return (1);
+		default:
+			/* Handle all other traps in the usual way. */
+			break;
+		}
+	}
+
+	/* Handle the trap in the usual way. */
+	return (0);
+}
+
+void
+dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which,
+    int fault, int fltoffs, uintptr_t illval)
+{
+
+	dtrace_probe(dtrace_probeid_error, (uint64_t)(uintptr_t)state,
+	    (uintptr_t)epid,
+	    (uintptr_t)which, (uintptr_t)fault, (uintptr_t)fltoffs);
+}
+
+static int
+dtrace_invop_start(struct trapframe *frame)
+{
+	printf("IMPLEMENT ME: %s\n", __func__);
+	switch (dtrace_invop(frame->tf_pc, (uintptr_t *)frame, frame->tf_pc)) {
+	case DTRACE_INVOP_PUSHM:
+		// TODO:
+		break;
+	case DTRACE_INVOP_POPM:
+		// TODO:
+		break;
+	case DTRACE_INVOP_B:
+		// TODO
+		break;
+	default:
+		return (-1);
+		break;
+	}
+
+	return (0);
+}
+
+void dtrace_invop_init(void)
+{
+	dtrace_invop_jump_addr = dtrace_invop_start;
+}
+
+void dtrace_invop_uninit(void)
+{
+	dtrace_invop_jump_addr = 0;
+}
diff --git a/sys/cddl/dev/dtrace/arm/regset.h b/sys/cddl/dev/dtrace/arm/regset.h
new file mode 100644
index 0000000..1ff6463
--- /dev/null
+++ b/sys/cddl/dev/dtrace/arm/regset.h
@@ -0,0 +1,56 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * $FreeBSD$ 
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*	Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
+
+/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T		*/
+/*	All Rights Reserved	*/
+
+#ifndef	_REGSET_H
+#define	_REGSET_H
+
+/*
+ * #pragma ident	"@(#)regset.h	1.11	05/06/08 SMI"
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define REG_PC  R14
+#define REG_FP  R13
+#define REG_SP  R12
+#define REG_PS  R0
+#define REG_R0  R0
+#define REG_R1  R1
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _REGSET_H */
diff --git a/sys/cddl/dev/fbt/fbt_arm.c b/sys/cddl/dev/fbt/fbt_arm.c
new file mode 100644
index 0000000..2daefa8
--- /dev/null
+++ b/sys/cddl/dev/fbt/fbt_arm.c
@@ -0,0 +1,1303 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Portions Copyright 2006-2008 John Birrell jb@freebsd.org
+ * Portions Copyright 2013 Justin Hibbits jhibbits@freebsd.org
+ * Portions Copyright 2013 Howard Su howardsu@freebsd.org
+ *
+ * $FreeBSD$
+ *
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/cpuvar.h>
+#include <sys/fcntl.h>
+#include <sys/filio.h>
+#include <sys/kdb.h>
+#include <sys/kernel.h>
+#include <sys/kmem.h>
+#include <sys/kthread.h>
+#include <sys/limits.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/pcpu.h>
+#include <sys/poll.h>
+#include <sys/proc.h>
+#include <sys/selinfo.h>
+#include <sys/smp.h>
+#include <sys/syscall.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/uio.h>
+#include <sys/unistd.h>
+#include <machine/frame.h>
+#include <machine/md_var.h>
+#include <machine/stdarg.h>
+
+#include <sys/dtrace.h>
+#include <sys/dtrace_bsd.h>
+
+static MALLOC_DEFINE(M_FBT, "fbt", "Function Boundary Tracing");
+
+#define FBT_PATCHVAL		0xe06a0cfe // illegal instruction
+
+#define FBT_PUSHM		0xe92d0000
+#define FBT_POPM		0xe8bd0000
+#define FBT_JUMP		0xea000000
+
+static d_open_t	fbt_open;
+static int	fbt_unload(void);
+static void	fbt_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *);
+static void	fbt_provide_module(void *, modctl_t *);
+static void	fbt_destroy(void *, dtrace_id_t, void *);
+static void	fbt_enable(void *, dtrace_id_t, void *);
+static void	fbt_disable(void *, dtrace_id_t, void *);
+static void	fbt_load(void *);
+static void	fbt_suspend(void *, dtrace_id_t, void *);
+static void	fbt_resume(void *, dtrace_id_t, void *);
+
+#define	FBT_ENTRY	"entry"
+#define	FBT_RETURN	"return"
+#define	FBT_ADDR2NDX(addr)	((((uintptr_t)(addr)) >> 4) & fbt_probetab_mask)
+#define	FBT_PROBETAB_SIZE	0x8000		/* 32k entries -- 128K total */
+
+static struct cdevsw fbt_cdevsw = {
+	.d_version	= D_VERSION,
+	.d_open		= fbt_open,
+	.d_name		= "fbt",
+};
+
+static dtrace_pattr_t fbt_attr = {
+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
+};
+
+static dtrace_pops_t fbt_pops = {
+	NULL,
+	fbt_provide_module,
+	fbt_enable,
+	fbt_disable,
+	fbt_suspend,
+	fbt_resume,
+	fbt_getargdesc,
+	NULL,
+	NULL,
+	fbt_destroy
+};
+
+typedef struct fbt_probe {
+	struct fbt_probe *fbtp_hashnext;
+	uint32_t	*fbtp_patchpoint;
+	int8_t		fbtp_rval;
+	uint32_t	fbtp_patchval;
+	uint32_t	fbtp_savedval;
+	uintptr_t	fbtp_roffset;
+	dtrace_id_t	fbtp_id;
+	const char	*fbtp_name;
+	modctl_t	*fbtp_ctl;
+	int		fbtp_loadcnt;
+	int		fbtp_primary;
+	int		fbtp_invop_cnt;
+	int		fbtp_symindx;
+	struct fbt_probe *fbtp_next;
+} fbt_probe_t;
+
+static struct cdev		*fbt_cdev;
+static dtrace_provider_id_t	fbt_id;
+static fbt_probe_t		**fbt_probetab;
+static int			fbt_probetab_size;
+static int			fbt_probetab_mask;
+static int			fbt_verbose = 0;
+
+static int
+fbt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval)
+{
+	struct trapframe *frame = (struct trapframe *)stack;
+	solaris_cpu_t *cpu = &solaris_cpu[curcpu];
+	fbt_probe_t *fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
+
+	for (; fbt != NULL; fbt = fbt->fbtp_hashnext) {
+		if ((uintptr_t)fbt->fbtp_patchpoint == addr) {
+			fbt->fbtp_invop_cnt++;
+			cpu->cpu_dtrace_caller = addr;
+
+			dtrace_probe(fbt->fbtp_id, frame->tf_r0,
+			    frame->tf_r1, frame->tf_r2,
+			    frame->tf_r3, 0); // TODO: Need 5th parameter from stack
+
+			cpu->cpu_dtrace_caller = 0;
+
+			return (fbt->fbtp_rval);
+		}
+	}
+
+	return (0);
+}
+
+static int
+fbt_provide_module_function(linker_file_t lf, int symindx,
+    linker_symval_t *symval, void *opaque)
+{
+	char *modname = opaque;
+	const char *name = symval->name;
+	fbt_probe_t *fbt, *retfbt;
+	int popm;
+	u_int32_t *instr, *limit;
+
+	if (strncmp(name, "dtrace_", 7) == 0 &&
+	    strncmp(name, "dtrace_safe_", 12) != 0) {
+		/*
+		 * Anything beginning with "dtrace_" may be called
+		 * from probe context unless it explicitly indicates
+		 * that it won't be called from probe context by
+		 * using the prefix "dtrace_safe_".
+		 */
+		return (0);
+	}
+
+	if (name[0] == '_' && name[1] == '_')
+		return (0);
+
+	instr = (u_int32_t *) symval->value;
+	limit = (u_int32_t *)(symval->value + symval->size);
+
+	for (; instr < limit; instr++)
+		if ((*instr & 0xffff0000) == FBT_PUSHM && (*instr & 0x4000) != 0)
+			break;
+
+	if (instr >= limit)
+		return (0);
+
+	fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
+	fbt->fbtp_name = name;
+	fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
+	    name, FBT_ENTRY, 3, fbt);
+	fbt->fbtp_patchpoint = instr;
+	fbt->fbtp_ctl = lf;
+	fbt->fbtp_loadcnt = lf->loadcnt;
+	fbt->fbtp_savedval = *instr;
+	fbt->fbtp_patchval = FBT_PATCHVAL;
+	fbt->fbtp_rval = DTRACE_INVOP_PUSHM;
+	fbt->fbtp_symindx = symindx;
+
+	fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
+	fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
+
+	lf->fbt_nentries++;
+
+	popm = FBT_POPM | ((*instr) & 0x3FFF) | 0x8000;
+
+
+	retfbt = NULL;
+again:	
+	for(; instr < limit; instr++)
+	{
+		if  (*instr == popm)
+			break;
+		else if ((*instr & 0xff000000) == FBT_JUMP)
+		{
+			int offset;
+			u_int32_t *target, *start;
+			offset = (*instr & 0xffffff);
+			offset <<= 8;
+			offset /= 64;
+			target = instr + (2 + offset);
+			start = (u_int32_t *) symval->value;
+			if (target >= limit || target < start)
+				break;
+			instr++; //skip delay slot
+		}
+	}
+
+	if (instr >= limit)
+		return (0);
+
+	/*
+	 * We have a winner!
+	 */
+	fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
+	fbt->fbtp_name = name;
+	if (retfbt == NULL) {
+		fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
+		    name, FBT_RETURN, 5, fbt);
+	} else {
+		retfbt->fbtp_next = fbt;
+		fbt->fbtp_id = retfbt->fbtp_id;
+	}
+	retfbt = fbt;
+
+	fbt->fbtp_patchpoint = instr;
+	fbt->fbtp_ctl = lf;
+	fbt->fbtp_loadcnt = lf->loadcnt;
+	fbt->fbtp_symindx = symindx;
+	if ((*instr & 0xff000000) == FBT_JUMP)
+		fbt->fbtp_rval = DTRACE_INVOP_B;
+	else	
+		fbt->fbtp_rval = DTRACE_INVOP_POPM;
+	fbt->fbtp_savedval = *instr;
+	fbt->fbtp_patchval = FBT_PATCHVAL;
+	fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
+	fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
+
+	lf->fbt_nentries++;
+
+	instr++;
+	goto again;
+}
+
+static void
+fbt_provide_module(void *arg, modctl_t *lf)
+{
+	char modname[MAXPATHLEN];
+	int i;
+	size_t len;
+
+	strlcpy(modname, lf->filename, sizeof(modname));
+	len = strlen(modname);
+	if (len > 3 && strcmp(modname + len - 3, ".ko") == 0)
+		modname[len - 3] = '\0';
+
+	/*
+	 * Employees of dtrace and their families are ineligible.  Void
+	 * where prohibited.
+	 */
+	if (strcmp(modname, "dtrace") == 0)
+		return;
+
+	/*
+	 * The cyclic timer subsystem can be built as a module and DTrace
+	 * depends on that, so it is ineligible too.
+	 */
+	if (strcmp(modname, "cyclic") == 0)
+		return;
+
+	/*
+	 * To register with DTrace, a module must list 'dtrace' as a
+	 * dependency in order for the kernel linker to resolve
+	 * symbols like dtrace_register(). All modules with such a
+	 * dependency are ineligible for FBT tracing.
+	 */
+	for (i = 0; i < lf->ndeps; i++)
+		if (strncmp(lf->deps[i]->filename, "dtrace", 6) == 0)
+			return;
+
+	if (lf->fbt_nentries) {
+		/*
+		 * This module has some FBT entries allocated; we're afraid
+		 * to screw with it.
+		 */
+		return;
+	}
+
+	/*
+	 * List the functions in the module and the symbol values.
+	 */
+	(void) linker_file_function_listall(lf, fbt_provide_module_function, modname);
+}
+
+static void
+fbt_destroy(void *arg, dtrace_id_t id, void *parg)
+{
+	fbt_probe_t *fbt = parg, *next, *hash, *last;
+	modctl_t *ctl;
+	int ndx;
+
+	do {
+		ctl = fbt->fbtp_ctl;
+
+		ctl->fbt_nentries--;
+
+		/*
+		 * Now we need to remove this probe from the fbt_probetab.
+		 */
+		ndx = FBT_ADDR2NDX(fbt->fbtp_patchpoint);
+		last = NULL;
+		hash = fbt_probetab[ndx];
+
+		while (hash != fbt) {
+			ASSERT(hash != NULL);
+			last = hash;
+			hash = hash->fbtp_hashnext;
+		}
+
+		if (last != NULL) {
+			last->fbtp_hashnext = fbt->fbtp_hashnext;
+		} else {
+			fbt_probetab[ndx] = fbt->fbtp_hashnext;
+		}
+
+		next = fbt->fbtp_next;
+		free(fbt, M_FBT);
+
+		fbt = next;
+	} while (fbt != NULL);
+}
+
+static void
+fbt_enable(void *arg, dtrace_id_t id, void *parg)
+{
+	fbt_probe_t *fbt = parg;
+	modctl_t *ctl = fbt->fbtp_ctl;
+
+	ctl->nenabled++;
+
+	/*
+	 * Now check that our modctl has the expected load count.  If it
+	 * doesn't, this module must have been unloaded and reloaded -- and
+	 * we're not going to touch it.
+	 */
+	if (ctl->loadcnt != fbt->fbtp_loadcnt) {
+		if (fbt_verbose) {
+			printf("fbt is failing for probe %s "
+			    "(module %s reloaded)",
+			    fbt->fbtp_name, ctl->filename);
+		}
+
+		return;
+	}
+
+	for (; fbt != NULL; fbt = fbt->fbtp_next) {
+		*fbt->fbtp_patchpoint = fbt->fbtp_patchval;
+		cpu_icache_sync_range((vm_offset_t)fbt->fbtp_patchpoint, 4);
+	}
+}
+
+static void
+fbt_disable(void *arg, dtrace_id_t id, void *parg)
+{
+	fbt_probe_t *fbt = parg;
+	modctl_t *ctl = fbt->fbtp_ctl;
+
+	ASSERT(ctl->nenabled > 0);
+	ctl->nenabled--;
+
+	if ((ctl->loadcnt != fbt->fbtp_loadcnt))
+		return;
+
+	for (; fbt != NULL; fbt = fbt->fbtp_next) {
+		*fbt->fbtp_patchpoint = fbt->fbtp_savedval;
+		cpu_icache_sync_range((vm_offset_t)fbt->fbtp_patchpoint, 4);
+	}
+}
+
+static void
+fbt_suspend(void *arg, dtrace_id_t id, void *parg)
+{
+	fbt_probe_t *fbt = parg;
+	modctl_t *ctl = fbt->fbtp_ctl;
+
+	ASSERT(ctl->nenabled > 0);
+
+	if ((ctl->loadcnt != fbt->fbtp_loadcnt))
+		return;
+
+	for (; fbt != NULL; fbt = fbt->fbtp_next) {
+		*fbt->fbtp_patchpoint = fbt->fbtp_savedval;
+		cpu_icache_sync_range((vm_offset_t)fbt->fbtp_patchpoint, 4);
+	}
+}
+
+static void
+fbt_resume(void *arg, dtrace_id_t id, void *parg)
+{
+	fbt_probe_t *fbt = parg;
+	modctl_t *ctl = fbt->fbtp_ctl;
+
+	ASSERT(ctl->nenabled > 0);
+
+	if ((ctl->loadcnt != fbt->fbtp_loadcnt))
+		return;
+
+	for (; fbt != NULL; fbt = fbt->fbtp_next) {
+		*fbt->fbtp_patchpoint = fbt->fbtp_patchval;
+		cpu_icache_sync_range((vm_offset_t)fbt->fbtp_patchpoint, 4);
+	}
+}
+
+static int
+fbt_ctfoff_init(modctl_t *lf, linker_ctf_t *lc)
+{
+	const Elf_Sym *symp = lc->symtab;;
+	const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;
+	const uint8_t *ctfdata = lc->ctftab + sizeof(ctf_header_t);
+	int i;
+	uint32_t *ctfoff;
+	uint32_t objtoff = hp->cth_objtoff;
+	uint32_t funcoff = hp->cth_funcoff;
+	ushort_t info;
+	ushort_t vlen;
+
+	/* Sanity check. */
+	if (hp->cth_magic != CTF_MAGIC) {
+		printf("Bad magic value in CTF data of '%s'\n",lf->pathname);
+		return (EINVAL);
+	}
+
+	if (lc->symtab == NULL) {
+		printf("No symbol table in '%s'\n",lf->pathname);
+		return (EINVAL);
+	}
+
+	if ((ctfoff = malloc(sizeof(uint32_t) * lc->nsym, M_LINKER, M_WAITOK)) == NULL)
+		return (ENOMEM);
+
+	*lc->ctfoffp = ctfoff;
+
+	for (i = 0; i < lc->nsym; i++, ctfoff++, symp++) {
+		if (symp->st_name == 0 || symp->st_shndx == SHN_UNDEF) {
+			*ctfoff = 0xffffffff;
+			continue;
+		}
+
+		switch (ELF_ST_TYPE(symp->st_info)) {
+		case STT_OBJECT:
+			if (objtoff >= hp->cth_funcoff ||
+                            (symp->st_shndx == SHN_ABS && symp->st_value == 0)) {
+				*ctfoff = 0xffffffff;
+                                break;
+                        }
+
+                        *ctfoff = objtoff;
+                        objtoff += sizeof (ushort_t);
+			break;
+
+		case STT_FUNC:
+			if (funcoff >= hp->cth_typeoff) {
+				*ctfoff = 0xffffffff;
+				break;
+			}
+
+			*ctfoff = funcoff;
+
+			info = *((const ushort_t *)(ctfdata + funcoff));
+			vlen = CTF_INFO_VLEN(info);
+
+			/*
+			 * If we encounter a zero pad at the end, just skip it.
+			 * Otherwise skip over the function and its return type
+			 * (+2) and the argument list (vlen).
+			 */
+			if (CTF_INFO_KIND(info) == CTF_K_UNKNOWN && vlen == 0)
+				funcoff += sizeof (ushort_t); /* skip pad */
+			else
+				funcoff += sizeof (ushort_t) * (vlen + 2);
+			break;
+
+		default:
+			*ctfoff = 0xffffffff;
+			break;
+		}
+	}
+
+	return (0);
+}
+
+static ssize_t
+fbt_get_ctt_size(uint8_t version, const ctf_type_t *tp, ssize_t *sizep,
+    ssize_t *incrementp)
+{
+	ssize_t size, increment;
+
+	if (version > CTF_VERSION_1 &&
+	    tp->ctt_size == CTF_LSIZE_SENT) {
+		size = CTF_TYPE_LSIZE(tp);
+		increment = sizeof (ctf_type_t);
+	} else {
+		size = tp->ctt_size;
+		increment = sizeof (ctf_stype_t);
+	}
+
+	if (sizep)
+		*sizep = size;
+	if (incrementp)
+		*incrementp = increment;
+
+	return (size);
+}
+
+static int
+fbt_typoff_init(linker_ctf_t *lc)
+{
+	const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;
+	const ctf_type_t *tbuf;
+	const ctf_type_t *tend;
+	const ctf_type_t *tp;
+	const uint8_t *ctfdata = lc->ctftab + sizeof(ctf_header_t);
+	int ctf_typemax = 0;
+	uint32_t *xp;
+	ulong_t pop[CTF_K_MAX + 1] = { 0 };
+
+
+	/* Sanity check. */
+	if (hp->cth_magic != CTF_MAGIC)
+		return (EINVAL);
+
+	tbuf = (const ctf_type_t *) (ctfdata + hp->cth_typeoff);
+	tend = (const ctf_type_t *) (ctfdata + hp->cth_stroff);
+
+	int child = hp->cth_parname != 0;
+
+	/*
+	 * We make two passes through the entire type section.  In this first
+	 * pass, we count the number of each type and the total number of types.
+	 */
+	for (tp = tbuf; tp < tend; ctf_typemax++) {
+		ushort_t kind = CTF_INFO_KIND(tp->ctt_info);
+		ulong_t vlen = CTF_INFO_VLEN(tp->ctt_info);
+		ssize_t size, increment;
+
+		size_t vbytes;
+		uint_t n;
+
+		(void) fbt_get_ctt_size(hp->cth_version, tp, &size, &increment);
+
+		switch (kind) {
+		case CTF_K_INTEGER:
+		case CTF_K_FLOAT:
+			vbytes = sizeof (uint_t);
+			break;
+		case CTF_K_ARRAY:
+			vbytes = sizeof (ctf_array_t);
+			break;
+		case CTF_K_FUNCTION:
+			vbytes = sizeof (ushort_t) * (vlen + (vlen & 1));
+			break;
+		case CTF_K_STRUCT:
+		case CTF_K_UNION:
+			if (size < CTF_LSTRUCT_THRESH) {
+				ctf_member_t *mp = (ctf_member_t *)
+				    ((uintptr_t)tp + increment);
+
+				vbytes = sizeof (ctf_member_t) * vlen;
+				for (n = vlen; n != 0; n--, mp++)
+					child |= CTF_TYPE_ISCHILD(mp->ctm_type);
+			} else {
+				ctf_lmember_t *lmp = (ctf_lmember_t *)
+				    ((uintptr_t)tp + increment);
+
+				vbytes = sizeof (ctf_lmember_t) * vlen;
+				for (n = vlen; n != 0; n--, lmp++)
+					child |=
+					    CTF_TYPE_ISCHILD(lmp->ctlm_type);
+			}
+			break;
+		case CTF_K_ENUM:
+			vbytes = sizeof (ctf_enum_t) * vlen;
+			break;
+		case CTF_K_FORWARD:
+			/*
+			 * For forward declarations, ctt_type is the CTF_K_*
+			 * kind for the tag, so bump that population count too.
+			 * If ctt_type is unknown, treat the tag as a struct.
+			 */
+			if (tp->ctt_type == CTF_K_UNKNOWN ||
+			    tp->ctt_type >= CTF_K_MAX)
+				pop[CTF_K_STRUCT]++;
+			else
+				pop[tp->ctt_type]++;
+			/*FALLTHRU*/
+		case CTF_K_UNKNOWN:
+			vbytes = 0;
+			break;
+		case CTF_K_POINTER:
+		case CTF_K_TYPEDEF:
+		case CTF_K_VOLATILE:
+		case CTF_K_CONST:
+		case CTF_K_RESTRICT:
+			child |= CTF_TYPE_ISCHILD(tp->ctt_type);
+			vbytes = 0;
+			break;
+		default:
+			printf("%s(%d): detected invalid CTF kind -- %u\n", __func__, __LINE__, kind);
+			return (EIO);
+		}
+		tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes);
+		pop[kind]++;
+	}
+
+	/* account for a sentinel value below */
+	ctf_typemax++;
+	*lc->typlenp = ctf_typemax;
+
+	if ((xp = malloc(sizeof(uint32_t) * ctf_typemax, M_LINKER, M_ZERO | M_WAITOK)) == NULL)
+		return (ENOMEM);
+
+	*lc->typoffp = xp;
+
+	/* type id 0 is used as a sentinel value */
+	*xp++ = 0;
+
+	/*
+	 * In the second pass, fill in the type offset.
+	 */
+	for (tp = tbuf; tp < tend; xp++) {
+		ushort_t kind = CTF_INFO_KIND(tp->ctt_info);
+		ulong_t vlen = CTF_INFO_VLEN(tp->ctt_info);
+		ssize_t size, increment;
+
+		size_t vbytes;
+		uint_t n;
+
+		(void) fbt_get_ctt_size(hp->cth_version, tp, &size, &increment);
+
+		switch (kind) {
+		case CTF_K_INTEGER:
+		case CTF_K_FLOAT:
+			vbytes = sizeof (uint_t);
+			break;
+		case CTF_K_ARRAY:
+			vbytes = sizeof (ctf_array_t);
+			break;
+		case CTF_K_FUNCTION:
+			vbytes = sizeof (ushort_t) * (vlen + (vlen & 1));
+			break;
+		case CTF_K_STRUCT:
+		case CTF_K_UNION:
+			if (size < CTF_LSTRUCT_THRESH) {
+				ctf_member_t *mp = (ctf_member_t *)
+				    ((uintptr_t)tp + increment);
+
+				vbytes = sizeof (ctf_member_t) * vlen;
+				for (n = vlen; n != 0; n--, mp++)
+					child |= CTF_TYPE_ISCHILD(mp->ctm_type);
+			} else {
+				ctf_lmember_t *lmp = (ctf_lmember_t *)
+				    ((uintptr_t)tp + increment);
+
+				vbytes = sizeof (ctf_lmember_t) * vlen;
+				for (n = vlen; n != 0; n--, lmp++)
+					child |=
+					    CTF_TYPE_ISCHILD(lmp->ctlm_type);
+			}
+			break;
+		case CTF_K_ENUM:
+			vbytes = sizeof (ctf_enum_t) * vlen;
+			break;
+		case CTF_K_FORWARD:
+		case CTF_K_UNKNOWN:
+			vbytes = 0;
+			break;
+		case CTF_K_POINTER:
+		case CTF_K_TYPEDEF:
+		case CTF_K_VOLATILE:
+		case CTF_K_CONST:
+		case CTF_K_RESTRICT:
+			vbytes = 0;
+			break;
+		default:
+			printf("%s(%d): detected invalid CTF kind -- %u\n", __func__, __LINE__, kind);
+			return (EIO);
+		}
+		*xp = (uint32_t)((uintptr_t) tp - (uintptr_t) ctfdata);
+		tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes);
+	}
+
+	return (0);
+}
+
+/*
+ * CTF Declaration Stack
+ *
+ * In order to implement ctf_type_name(), we must convert a type graph back
+ * into a C type declaration.  Unfortunately, a type graph represents a storage
+ * class ordering of the type whereas a type declaration must obey the C rules
+ * for operator precedence, and the two orderings are frequently in conflict.
+ * For example, consider these CTF type graphs and their C declarations:
+ *
+ * CTF_K_POINTER -> CTF_K_FUNCTION -> CTF_K_INTEGER  : int (*)()
+ * CTF_K_POINTER -> CTF_K_ARRAY -> CTF_K_INTEGER     : int (*)[]
+ *
+ * In each case, parentheses are used to raise operator * to higher lexical
+ * precedence, so the string form of the C declaration cannot be constructed by
+ * walking the type graph links and forming the string from left to right.
+ *
+ * The functions in this file build a set of stacks from the type graph nodes
+ * corresponding to the C operator precedence levels in the appropriate order.
+ * The code in ctf_type_name() can then iterate over the levels and nodes in
+ * lexical precedence order and construct the final C declaration string.
+ */
+typedef struct ctf_list {
+	struct ctf_list *l_prev; /* previous pointer or tail pointer */
+	struct ctf_list *l_next; /* next pointer or head pointer */
+} ctf_list_t;
+
+#define	ctf_list_prev(elem)	((void *)(((ctf_list_t *)(elem))->l_prev))
+#define	ctf_list_next(elem)	((void *)(((ctf_list_t *)(elem))->l_next))
+
+typedef enum {
+	CTF_PREC_BASE,
+	CTF_PREC_POINTER,
+	CTF_PREC_ARRAY,
+	CTF_PREC_FUNCTION,
+	CTF_PREC_MAX
+} ctf_decl_prec_t;
+
+typedef struct ctf_decl_node {
+	ctf_list_t cd_list;			/* linked list pointers */
+	ctf_id_t cd_type;			/* type identifier */
+	uint_t cd_kind;				/* type kind */
+	uint_t cd_n;				/* type dimension if array */
+} ctf_decl_node_t;
+
+typedef struct ctf_decl {
+	ctf_list_t cd_nodes[CTF_PREC_MAX];	/* declaration node stacks */
+	int cd_order[CTF_PREC_MAX];		/* storage order of decls */
+	ctf_decl_prec_t cd_qualp;		/* qualifier precision */
+	ctf_decl_prec_t cd_ordp;		/* ordered precision */
+	char *cd_buf;				/* buffer for output */
+	char *cd_ptr;				/* buffer location */
+	char *cd_end;				/* buffer limit */
+	size_t cd_len;				/* buffer space required */
+	int cd_err;				/* saved error value */
+} ctf_decl_t;
+
+/*
+ * Simple doubly-linked list append routine.  This implementation assumes that
+ * each list element contains an embedded ctf_list_t as the first member.
+ * An additional ctf_list_t is used to store the head (l_next) and tail
+ * (l_prev) pointers.  The current head and tail list elements have their
+ * previous and next pointers set to NULL, respectively.
+ */
+static void
+ctf_list_append(ctf_list_t *lp, void *new)
+{
+	ctf_list_t *p = lp->l_prev;	/* p = tail list element */
+	ctf_list_t *q = new;		/* q = new list element */
+
+	lp->l_prev = q;
+	q->l_prev = p;
+	q->l_next = NULL;
+
+	if (p != NULL)
+		p->l_next = q;
+	else
+		lp->l_next = q;
+}
+
+/*
+ * Prepend the specified existing element to the given ctf_list_t.  The
+ * existing pointer should be pointing at a struct with embedded ctf_list_t.
+ */
+static void
+ctf_list_prepend(ctf_list_t *lp, void *new)
+{
+	ctf_list_t *p = new;		/* p = new list element */
+	ctf_list_t *q = lp->l_next;	/* q = head list element */
+
+	lp->l_next = p;
+	p->l_prev = NULL;
+	p->l_next = q;
+
+	if (q != NULL)
+		q->l_prev = p;
+	else
+		lp->l_prev = p;
+}
+
+static void
+ctf_decl_init(ctf_decl_t *cd, char *buf, size_t len)
+{
+	int i;
+
+	bzero(cd, sizeof (ctf_decl_t));
+
+	for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++)
+		cd->cd_order[i] = CTF_PREC_BASE - 1;
+
+	cd->cd_qualp = CTF_PREC_BASE;
+	cd->cd_ordp = CTF_PREC_BASE;
+
+	cd->cd_buf = buf;
+	cd->cd_ptr = buf;
+	cd->cd_end = buf + len;
+}
+
+static void
+ctf_decl_fini(ctf_decl_t *cd)
+{
+	ctf_decl_node_t *cdp, *ndp;
+	int i;
+
+	for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++) {
+		for (cdp = ctf_list_next(&cd->cd_nodes[i]);
+		    cdp != NULL; cdp = ndp) {
+			ndp = ctf_list_next(cdp);
+			free(cdp, M_FBT);
+		}
+	}
+}
+
+static const ctf_type_t *
+ctf_lookup_by_id(linker_ctf_t *lc, ctf_id_t type)
+{
+	const ctf_type_t *tp;
+	uint32_t offset;
+	uint32_t *typoff = *lc->typoffp;
+
+	if (type >= *lc->typlenp) {
+		printf("%s(%d): type %d exceeds max %ld\n",__func__,__LINE__,(int) type,*lc->typlenp);
+		return(NULL);
+	}
+
+	/* Check if the type isn't cross-referenced. */
+	if ((offset = typoff[type]) == 0) {
+		printf("%s(%d): type %d isn't cross referenced\n",__func__,__LINE__, (int) type);
+		return(NULL);
+	}
+
+	tp = (const ctf_type_t *)(lc->ctftab + offset + sizeof(ctf_header_t));
+
+	return (tp);
+}
+
+static void
+fbt_array_info(linker_ctf_t *lc, ctf_id_t type, ctf_arinfo_t *arp)
+{
+	const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;
+	const ctf_type_t *tp;
+	const ctf_array_t *ap;
+	ssize_t increment;
+
+	bzero(arp, sizeof(*arp));
+
+	if ((tp = ctf_lookup_by_id(lc, type)) == NULL)
+		return;
+
+	if (CTF_INFO_KIND(tp->ctt_info) != CTF_K_ARRAY)
+		return;
+
+	(void) fbt_get_ctt_size(hp->cth_version, tp, NULL, &increment);
+
+	ap = (const ctf_array_t *)((uintptr_t)tp + increment);
+	arp->ctr_contents = ap->cta_contents;
+	arp->ctr_index = ap->cta_index;
+	arp->ctr_nelems = ap->cta_nelems;
+}
+
+static const char *
+ctf_strptr(linker_ctf_t *lc, int name)
+{
+	const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;;
+	const char *strp = "";
+
+	if (name < 0 || name >= hp->cth_strlen)
+		return(strp);
+
+	strp = (const char *)(lc->ctftab + hp->cth_stroff + name + sizeof(ctf_header_t));
+
+	return (strp);
+}
+
+static void
+ctf_decl_push(ctf_decl_t *cd, linker_ctf_t *lc, ctf_id_t type)
+{
+	ctf_decl_node_t *cdp;
+	ctf_decl_prec_t prec;
+	uint_t kind, n = 1;
+	int is_qual = 0;
+
+	const ctf_type_t *tp;
+	ctf_arinfo_t ar;
+
+	if ((tp = ctf_lookup_by_id(lc, type)) == NULL) {
+		cd->cd_err = ENOENT;
+		return;
+	}
+
+	switch (kind = CTF_INFO_KIND(tp->ctt_info)) {
+	case CTF_K_ARRAY:
+		fbt_array_info(lc, type, &ar);
+		ctf_decl_push(cd, lc, ar.ctr_contents);
+		n = ar.ctr_nelems;
+		prec = CTF_PREC_ARRAY;
+		break;
+
+	case CTF_K_TYPEDEF:
+		if (ctf_strptr(lc, tp->ctt_name)[0] == '\0') {
+			ctf_decl_push(cd, lc, tp->ctt_type);
+			return;
+		}
+		prec = CTF_PREC_BASE;
+		break;
+
+	case CTF_K_FUNCTION:
+		ctf_decl_push(cd, lc, tp->ctt_type);
+		prec = CTF_PREC_FUNCTION;
+		break;
+
+	case CTF_K_POINTER:
+		ctf_decl_push(cd, lc, tp->ctt_type);
+		prec = CTF_PREC_POINTER;
+		break;
+
+	case CTF_K_VOLATILE:
+	case CTF_K_CONST:
+	case CTF_K_RESTRICT:
+		ctf_decl_push(cd, lc, tp->ctt_type);
+		prec = cd->cd_qualp;
+		is_qual++;
+		break;
+
+	default:
+		prec = CTF_PREC_BASE;
+	}
+
+	if ((cdp = malloc(sizeof (ctf_decl_node_t), M_FBT, M_WAITOK)) == NULL) {
+		cd->cd_err = EAGAIN;
+		return;
+	}
+
+	cdp->cd_type = type;
+	cdp->cd_kind = kind;
+	cdp->cd_n = n;
+
+	if (ctf_list_next(&cd->cd_nodes[prec]) == NULL)
+		cd->cd_order[prec] = cd->cd_ordp++;
+
+	/*
+	 * Reset cd_qualp to the highest precedence level that we've seen so
+	 * far that can be qualified (CTF_PREC_BASE or CTF_PREC_POINTER).
+	 */
+	if (prec > cd->cd_qualp && prec < CTF_PREC_ARRAY)
+		cd->cd_qualp = prec;
+
+	/*
+	 * C array declarators are ordered inside out so prepend them.  Also by
+	 * convention qualifiers of base types precede the type specifier (e.g.
+	 * const int vs. int const) even though the two forms are equivalent.
+	 */
+	if (kind == CTF_K_ARRAY || (is_qual && prec == CTF_PREC_BASE))
+		ctf_list_prepend(&cd->cd_nodes[prec], cdp);
+	else
+		ctf_list_append(&cd->cd_nodes[prec], cdp);
+}
+
+static void
+ctf_decl_sprintf(ctf_decl_t *cd, const char *format, ...)
+{
+	size_t len = (size_t)(cd->cd_end - cd->cd_ptr);
+	va_list ap;
+	size_t n;
+
+	va_start(ap, format);
+	n = vsnprintf(cd->cd_ptr, len, format, ap);
+	va_end(ap);
+
+	cd->cd_ptr += MIN(n, len);
+	cd->cd_len += n;
+}
+
+static ssize_t
+fbt_type_name(linker_ctf_t *lc, ctf_id_t type, char *buf, size_t len)
+{
+	ctf_decl_t cd;
+	ctf_decl_node_t *cdp;
+	ctf_decl_prec_t prec, lp, rp;
+	int ptr, arr;
+	uint_t k;
+
+	if (lc == NULL && type == CTF_ERR)
+		return (-1); /* simplify caller code by permitting CTF_ERR */
+
+	ctf_decl_init(&cd, buf, len);
+	ctf_decl_push(&cd, lc, type);
+
+	if (cd.cd_err != 0) {
+		ctf_decl_fini(&cd);
+		return (-1);
+	}
+
+	/*
+	 * If the type graph's order conflicts with lexical precedence order
+	 * for pointers or arrays, then we need to surround the declarations at
+	 * the corresponding lexical precedence with parentheses.  This can
+	 * result in either a parenthesized pointer (*) as in int (*)() or
+	 * int (*)[], or in a parenthesized pointer and array as in int (*[])().
+	 */
+	ptr = cd.cd_order[CTF_PREC_POINTER] > CTF_PREC_POINTER;
+	arr = cd.cd_order[CTF_PREC_ARRAY] > CTF_PREC_ARRAY;
+
+	rp = arr ? CTF_PREC_ARRAY : ptr ? CTF_PREC_POINTER : -1;
+	lp = ptr ? CTF_PREC_POINTER : arr ? CTF_PREC_ARRAY : -1;
+
+	k = CTF_K_POINTER; /* avoid leading whitespace (see below) */
+
+	for (prec = CTF_PREC_BASE; prec < CTF_PREC_MAX; prec++) {
+		for (cdp = ctf_list_next(&cd.cd_nodes[prec]);
+		    cdp != NULL; cdp = ctf_list_next(cdp)) {
+
+			const ctf_type_t *tp =
+			    ctf_lookup_by_id(lc, cdp->cd_type);
+			const char *name = ctf_strptr(lc, tp->ctt_name);
+
+			if (k != CTF_K_POINTER && k != CTF_K_ARRAY)
+				ctf_decl_sprintf(&cd, " ");
+
+			if (lp == prec) {
+				ctf_decl_sprintf(&cd, "(");
+				lp = -1;
+			}
+
+			switch (cdp->cd_kind) {
+			case CTF_K_INTEGER:
+			case CTF_K_FLOAT:
+			case CTF_K_TYPEDEF:
+				ctf_decl_sprintf(&cd, "%s", name);
+				break;
+			case CTF_K_POINTER:
+				ctf_decl_sprintf(&cd, "*");
+				break;
+			case CTF_K_ARRAY:
+				ctf_decl_sprintf(&cd, "[%u]", cdp->cd_n);
+				break;
+			case CTF_K_FUNCTION:
+				ctf_decl_sprintf(&cd, "()");
+				break;
+			case CTF_K_STRUCT:
+			case CTF_K_FORWARD:
+				ctf_decl_sprintf(&cd, "struct %s", name);
+				break;
+			case CTF_K_UNION:
+				ctf_decl_sprintf(&cd, "union %s", name);
+				break;
+			case CTF_K_ENUM:
+				ctf_decl_sprintf(&cd, "enum %s", name);
+				break;
+			case CTF_K_VOLATILE:
+				ctf_decl_sprintf(&cd, "volatile");
+				break;
+			case CTF_K_CONST:
+				ctf_decl_sprintf(&cd, "const");
+				break;
+			case CTF_K_RESTRICT:
+				ctf_decl_sprintf(&cd, "restrict");
+				break;
+			}
+
+			k = cdp->cd_kind;
+		}
+
+		if (rp == prec)
+			ctf_decl_sprintf(&cd, ")");
+	}
+
+	ctf_decl_fini(&cd);
+	return (cd.cd_len);
+}
+
+static void
+fbt_getargdesc(void *arg __unused, dtrace_id_t id __unused, void *parg, dtrace_argdesc_t *desc)
+{
+	const ushort_t *dp;
+	fbt_probe_t *fbt = parg;
+	linker_ctf_t lc;
+	modctl_t *ctl = fbt->fbtp_ctl;
+	int ndx = desc->dtargd_ndx;
+	int symindx = fbt->fbtp_symindx;
+	uint32_t *ctfoff;
+	uint32_t offset;
+	ushort_t info, kind, n;
+
+	if (fbt->fbtp_roffset != 0 && desc->dtargd_ndx == 0) {
+		(void) strcpy(desc->dtargd_native, "int");
+		return;
+	}
+
+	desc->dtargd_ndx = DTRACE_ARGNONE;
+
+	/* Get a pointer to the CTF data and it's length. */
+	if (linker_ctf_get(ctl, &lc) != 0)
+		/* No CTF data? Something wrong? *shrug* */
+		return;
+
+	/* Check if this module hasn't been initialised yet. */
+	if (*lc.ctfoffp == NULL) {
+		/*
+		 * Initialise the CTF object and function symindx to
+		 * byte offset array.
+		 */
+		if (fbt_ctfoff_init(ctl, &lc) != 0)
+			return;
+
+		/* Initialise the CTF type to byte offset array. */
+		if (fbt_typoff_init(&lc) != 0)
+			return;
+	}
+
+	ctfoff = *lc.ctfoffp;
+
+	if (ctfoff == NULL || *lc.typoffp == NULL)
+		return;
+
+	/* Check if the symbol index is out of range. */
+	if (symindx >= lc.nsym)
+		return;
+
+	/* Check if the symbol isn't cross-referenced. */
+	if ((offset = ctfoff[symindx]) == 0xffffffff)
+		return;
+
+	dp = (const ushort_t *)(lc.ctftab + offset + sizeof(ctf_header_t));
+
+	info = *dp++;
+	kind = CTF_INFO_KIND(info);
+	n = CTF_INFO_VLEN(info);
+
+	if (kind == CTF_K_UNKNOWN && n == 0) {
+		printf("%s(%d): Unknown function!\n",__func__,__LINE__);
+		return;
+	}
+
+	if (kind != CTF_K_FUNCTION) {
+		printf("%s(%d): Expected a function!\n",__func__,__LINE__);
+		return;
+	}
+
+	if (fbt->fbtp_roffset != 0) {
+		/* Only return type is available for args[1] in return probe. */
+		if (ndx > 1)
+			return;
+		ASSERT(ndx == 1);
+	} else {
+		/* Check if the requested argument doesn't exist. */
+		if (ndx >= n)
+			return;
+
+		/* Skip the return type and arguments up to the one requested. */
+		dp += ndx + 1;
+	}
+
+	if (fbt_type_name(&lc, *dp, desc->dtargd_native, sizeof(desc->dtargd_native)) > 0)
+		desc->dtargd_ndx = ndx;
+
+	return;
+}
+
+static int
+fbt_linker_file_cb(linker_file_t lf, void *arg)
+{
+
+	fbt_provide_module(arg, lf);
+
+	return (0);
+}
+
+static void
+fbt_load(void *dummy)
+{
+	/* Create the /dev/dtrace/fbt entry. */
+	fbt_cdev = make_dev(&fbt_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
+	    "dtrace/fbt");
+
+	/* Default the probe table size if not specified. */
+	if (fbt_probetab_size == 0)
+		fbt_probetab_size = FBT_PROBETAB_SIZE;
+
+	/* Choose the hash mask for the probe table. */
+	fbt_probetab_mask = fbt_probetab_size - 1;
+
+	/* Allocate memory for the probe table. */
+	fbt_probetab =
+	    malloc(fbt_probetab_size * sizeof (fbt_probe_t *), M_FBT, M_WAITOK | M_ZERO);
+
+	dtrace_invop_add(fbt_invop);
+
+	if (dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_USER,
+	    NULL, &fbt_pops, NULL, &fbt_id) != 0)
+		return;
+
+	/* Create probes for the kernel and already-loaded modules. */
+	linker_file_foreach(fbt_linker_file_cb, NULL);
+}
+
+
+static int
+fbt_unload()
+{
+	int error = 0;
+
+	/* De-register the invalid opcode handler. */
+	dtrace_invop_remove(fbt_invop);
+
+	/* De-register this DTrace provider. */
+	if ((error = dtrace_unregister(fbt_id)) != 0)
+		return (error);
+
+	/* Free the probe table. */
+	free(fbt_probetab, M_FBT);
+	fbt_probetab = NULL;
+	fbt_probetab_mask = 0;
+
+	destroy_dev(fbt_cdev);
+
+	return (error);
+}
+
+static int
+fbt_modevent(module_t mod __unused, int type, void *data __unused)
+{
+	int error = 0;
+
+	switch (type) {
+	case MOD_LOAD:
+		break;
+
+	case MOD_UNLOAD:
+		break;
+
+	case MOD_SHUTDOWN:
+		break;
+
+	default:
+		error = EOPNOTSUPP;
+		break;
+
+	}
+
+	return (error);
+}
+
+static int
+fbt_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused, struct thread *td __unused)
+{
+	return (0);
+}
+
+SYSINIT(fbt_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, fbt_load, NULL);
+SYSUNINIT(fbt_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, fbt_unload, NULL);
+
+DEV_MODULE(fbt, fbt_modevent, NULL);
+MODULE_VERSION(fbt, 1);
+MODULE_DEPEND(fbt, dtrace, 1, 1, 1);
+MODULE_DEPEND(fbt, opensolaris, 1, 1, 1);
diff --git a/sys/cddl/dev/lockstat/lockstat.c b/sys/cddl/dev/lockstat/lockstat.c
index 9b3f7d7..a7e5896 100644
--- a/sys/cddl/dev/lockstat/lockstat.c
+++ b/sys/cddl/dev/lockstat/lockstat.c
@@ -46,7 +46,8 @@
 #include <sys/lockstat.h>
 
 #if defined(__i386__) || defined(__amd64__) || \
-	defined(__mips__) || defined(__powerpc__)
+	defined(__mips__) || defined(__powerpc__) || \
+	defined(__arm__)
 #define LOCKSTAT_AFRAMES 1
 #else
 #error "architecture not supported"
diff --git a/sys/cddl/dev/profile/profile.c b/sys/cddl/dev/profile/profile.c
index 051ffa1..870c533 100644
--- a/sys/cddl/dev/profile/profile.c
+++ b/sys/cddl/dev/profile/profile.c
@@ -126,6 +126,16 @@
 #define	PROF_ARTIFICIAL_FRAMES	3
 #endif
 
+#ifdef __mips
+/* bogus */
+#define	PROF_ARTIFICIAL_FRAMES	3
+#endif
+
+#ifdef __arm__
+/* bogus */
+#define	PROF_ARTIFICIAL_FRAMES	3
+#endif
+
 typedef struct profile_probe {
 	char		prof_name[PROF_NAMELEN];
 	dtrace_id_t	prof_id;
diff --git a/sys/modules/dtrace/Makefile b/sys/modules/dtrace/Makefile
index 1b12371..b819316 100644
--- a/sys/modules/dtrace/Makefile
+++ b/sys/modules/dtrace/Makefile
@@ -24,5 +24,7 @@ SUBDIR+=	fbt fasttrap
 .if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_ARCH} == "powerpc64"
 SUBDIR+=	systrace_freebsd32
 .endif
-
+.if ${MACHINE_CPUARCH} == "arm"
+SUBDIR+=        fbt
+.endif
 .include <bsd.subdir.mk>
diff --git a/sys/modules/dtrace/dtrace/Makefile b/sys/modules/dtrace/dtrace/Makefile
index 3299a1e..aa6b83b 100644
--- a/sys/modules/dtrace/dtrace/Makefile
+++ b/sys/modules/dtrace/dtrace/Makefile
@@ -22,7 +22,7 @@ CFLAGS+=	-I${.CURDIR}/../../../cddl/contrib/opensolaris/uts/intel
 SRCS+=		bus_if.h device_if.h vnode_if.h
 
 # Needed for dtrace_asm.S
-SRCS+=		assym.s
+#SRCS+=		assym.s
 
 # These are needed for assym.s
 SRCS+=		opt_compat.h opt_kstack_pages.h opt_nfs.h opt_hwpmc_hooks.h
diff --git a/sys/modules/dtrace/fbt/Makefile b/sys/modules/dtrace/fbt/Makefile
index 7c03d31..4bb8195 100644
--- a/sys/modules/dtrace/fbt/Makefile
+++ b/sys/modules/dtrace/fbt/Makefile
@@ -3,8 +3,8 @@
 .PATH: ${.CURDIR}/../../../cddl/dev/fbt
 
 KMOD=		fbt
-.if ${MACHINE_CPUARCH} == "powerpc"
-SRCS=		fbt_powerpc.c
+.if ${MACHINE_CPUARCH} == "powerpc" || ${MACHINE_CPUARCH} == "arm"
+SRCS=		fbt_${MACHINE_CPUARCH}.c
 .else
 SRCS=		fbt.c
 .endif

--=-1VnxsOIhDnJzpH5E7tuZ--




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1407555027.56408.442.camel>