Module Name:    src
Committed By:   ozaki-r
Date:           Sat Mar 15 08:00:19 UTC 2014

Modified Files:
        src/external/cddl/osnet/dev/fbt: fbt.c
        src/external/cddl/osnet/dist/uts/common/sys: dtrace.h

Log Message:
Implement DTrace FBT provider for ARM

- Finding probable functions
- Replacing instructions
- Emulating instructions

It is tested only on ARMv7 CPUs yet, for example,
-m evbarm (-a earm) kernel=BEAGLEBONE.


To generate a diff of this commit:
cvs rdiff -u -r1.13 -r1.14 src/external/cddl/osnet/dev/fbt/fbt.c
cvs rdiff -u -r1.9 -r1.10 \
    src/external/cddl/osnet/dist/uts/common/sys/dtrace.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/external/cddl/osnet/dev/fbt/fbt.c
diff -u src/external/cddl/osnet/dev/fbt/fbt.c:1.13 src/external/cddl/osnet/dev/fbt/fbt.c:1.14
--- src/external/cddl/osnet/dev/fbt/fbt.c:1.13	Wed Mar  5 20:14:15 2014
+++ src/external/cddl/osnet/dev/fbt/fbt.c	Sat Mar 15 08:00:19 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: fbt.c,v 1.13 2014/03/05 20:14:15 tron Exp $	*/
+/*	$NetBSD: fbt.c,v 1.14 2014/03/15 08:00:19 ozaki-r Exp $	*/
 
 /*
  * CDDL HEADER START
@@ -58,12 +58,19 @@
 #include <sys/unistd.h>
 
 #include <machine/cpu.h>
+#if defined(__i386__) || defined(__amd64__)
 #include <machine/cpufunc.h>
 #include <machine/specialreg.h>
 #if 0
 #include <x86/cpuvar.h>
 #endif
 #include <x86/cputypes.h>
+#elif __arm__
+#include <machine/trap.h>
+#include <arm/cpufunc.h>
+#include <arm/armreg.h>
+#include <arm/frame.h>
+#endif
 
 #define ELFSIZE ARCH_ELFSIZE
 #include <sys/exec_elf.h>
@@ -77,6 +84,7 @@ mod_ctf_t *modptr;
 
 MALLOC_DEFINE(M_FBT, "fbt", "Function Boundary Tracing");
 
+#if defined(__i386__) || defined(__amd64__)
 #define	FBT_PUSHL_EBP		0x55
 #define	FBT_MOVL_ESP_EBP0_V0	0x8b
 #define	FBT_MOVL_ESP_EBP1_V0	0xec
@@ -88,11 +96,43 @@ MALLOC_DEFINE(M_FBT, "fbt", "Function Bo
 #define	FBT_RET			0xc3
 #define	FBT_RET_IMM16		0xc2
 #define	FBT_LEAVE		0xc9
+#endif
 
 #ifdef __amd64__
 #define	FBT_PATCHVAL		0xcc
-#else
+#elif defined(__i386__)
 #define	FBT_PATCHVAL		0xf0
+
+#elif defined(__arm__)
+#define	FBT_PATCHVAL		DTRACE_BREAKPOINT
+
+/* entry and return */
+#define	FBT_BX_LR_P(insn)	(((insn) & ~INSN_COND_MASK) == 0x012fff1e)
+#define	FBT_B_LABEL_P(insn)	(((insn) & 0xff000000) == 0xea000000)
+/* entry */
+#define	FBT_MOV_IP_SP_P(insn)	((insn) == 0xe1a0c00d)
+/* index=1, add=1, wback=0 */
+#define	FBT_LDR_IMM_P(insn)	(((insn) & 0xfff00000) == 0xe5900000)
+#define	FBT_MOVW_P(insn)	(((insn) & 0xfff00000) == 0xe3000000)
+#define	FBT_MOV_IMM_P(insn)	(((insn) & 0xffff0000) == 0xe3a00000)
+#define	FBT_CMP_IMM_P(insn)	(((insn) & 0xfff00000) == 0xe3500000)
+#define	FBT_PUSH_P(insn)	(((insn) & 0xffff0000) == 0xe92d0000)
+/* return */
+/* cond=always, writeback=no, rn=sp and register_list includes pc */
+#define	FBT_LDM_P(insn)	(((insn) & 0x0fff8000) == 0x089d8000)
+#define	FBT_LDMIB_P(insn)	(((insn) & 0x0fff8000) == 0x099d8000)
+#define	FBT_MOV_PC_LR_P(insn)	(((insn) & ~INSN_COND_MASK) == 0x01a0f00e)
+/* cond=always, writeback=no, rn=sp and register_list includes lr, but not pc */
+#define	FBT_LDM_LR_P(insn)	(((insn) & 0xffffc000) == 0xe89d4000)
+#define	FBT_LDMIB_LR_P(insn)	(((insn) & 0xffffc000) == 0xe99d4000)
+
+/* rval = insn | invop_id (overwriting cond with invop ID) */
+#define	BUILD_RVAL(insn, id)	(((insn) & ~INSN_COND_MASK) | __SHIFTIN((id), INSN_COND_MASK))
+/* encode cond in the first byte */
+#define	PATCHVAL_ENCODE_COND(insn)	(FBT_PATCHVAL | __SHIFTOUT((insn), INSN_COND_MASK))
+
+#else
+#error "architecture not supported"
 #endif
 
 static dev_type_open(fbt_open);
@@ -140,10 +180,17 @@ static dtrace_pops_t fbt_pops = {
 
 typedef struct fbt_probe {
 	struct fbt_probe *fbtp_hashnext;
+#if defined(__i386__) || defined(__amd64__)
 	uint8_t		*fbtp_patchpoint;
 	int8_t		fbtp_rval;
 	uint8_t		fbtp_patchval;
 	uint8_t		fbtp_savedval;
+#elif __arm__
+	uint32_t	*fbtp_patchpoint;
+	int32_t		fbtp_rval;
+	uint32_t	fbtp_patchval;
+	uint32_t	fbtp_savedval;
+#endif
 	uintptr_t	fbtp_roffset;
 	dtrace_id_t	fbtp_id;
 	const char	*fbtp_name;
@@ -164,6 +211,226 @@ static fbt_probe_t		**fbt_probetab;
 static int			fbt_probetab_size;
 static int			fbt_probetab_mask;
 
+#ifdef __arm__
+extern void (* dtrace_emulation_jump_addr)(int, struct trapframe *);
+
+static uint32_t
+expand_imm(uint32_t imm12)
+{
+	uint32_t unrot = imm12 & 0xff;
+	int amount = 2 * (imm12 >> 8);
+
+	if (amount)
+		return (unrot >> amount) | (unrot << (32 - amount));
+	else
+		return unrot;
+}
+
+static uint32_t
+add_with_carry(uint32_t x, uint32_t y, int carry_in,
+	int *carry_out, int *overflow)
+{
+	uint32_t result;
+	uint64_t unsigned_sum = x + y + (uint32_t)carry_in;
+	int64_t signed_sum = (int32_t)x + (int32_t)y + (int32_t)carry_in;
+	KASSERT(carry_in == 1);
+
+	result = (uint32_t)(unsigned_sum & 0xffffffff);
+	*carry_out = ((uint64_t)result == unsigned_sum) ? 1 : 0;
+	*overflow = ((int64_t)result == signed_sum) ? 0 : 1;
+	
+	return result;
+}
+
+static void
+fbt_emulate(int _op, struct trapframe *frame)
+{
+	uint32_t op = _op;
+
+	switch (op >> 28) {
+	case DTRACE_INVOP_MOV_IP_SP:
+		/* mov ip, sp */
+		frame->tf_ip = frame->tf_svc_sp;
+		frame->tf_pc += 4;
+		break;
+	case DTRACE_INVOP_BX_LR:
+		/* bx lr */
+		frame->tf_pc = frame->tf_svc_lr;
+		break;
+	case DTRACE_INVOP_MOV_PC_LR:
+		/* mov pc, lr */
+		frame->tf_pc = frame->tf_svc_lr;
+		break;
+	case DTRACE_INVOP_LDM:
+		/* ldm sp, {..., pc} */
+		/* FALLTHRU */
+	case DTRACE_INVOP_LDMIB: {
+		/* ldmib sp, {..., pc} */
+		uint32_t register_list = (op & 0xffff);
+		uint32_t *sp = (uint32_t *)(intptr_t)frame->tf_svc_sp;
+		uint32_t *regs = &frame->tf_r0;
+		int i;
+
+		/* IDMIB */
+		if ((op >> 28) == 5)
+			sp++;
+
+		for (i=0; i <= 12; i++) {
+			if (register_list & (1 << i))
+				regs[i] = *sp++;
+		}
+		if (register_list & (1 << 13))
+			frame->tf_svc_sp = *sp++;
+		if (register_list & (1 << 14))
+			frame->tf_svc_lr = *sp++;
+		frame->tf_pc = *sp;
+		break;
+	}
+	case DTRACE_INVOP_LDR_IMM: {
+		/* ldr r?, [{pc,r?}, #?] */
+		uint32_t rt = (op >> 12) & 0xf;
+		uint32_t rn = (op >> 16) & 0xf;
+		uint32_t imm = op & 0xfff;
+		uint32_t *regs = &frame->tf_r0;
+		KDASSERT(rt <= 12);
+		KDASSERT(rn == 15 || rn =< 12);
+		if (rn == 15)
+			regs[rt] = *((uint32_t *)(intptr_t)(frame->tf_pc + 8 + imm));
+		else
+			regs[rt] = *((uint32_t *)(intptr_t)(regs[rn] + imm));
+		frame->tf_pc += 4;
+		break;
+	}
+	case DTRACE_INVOP_MOVW: {
+		/* movw r?, #? */
+		uint32_t rd = (op >> 12) & 0xf;
+		uint32_t imm = (op & 0xfff) | ((op & 0xf0000) >> 4);
+		uint32_t *regs = &frame->tf_r0;
+		KDASSERT(rd <= 12);
+		regs[rd] = imm;
+		frame->tf_pc += 4;
+		break;
+	}
+	case DTRACE_INVOP_MOV_IMM: {
+		/* mov r?, #? */
+		uint32_t rd = (op >> 12) & 0xf;
+		uint32_t imm = expand_imm(op & 0xfff);
+		uint32_t *regs = &frame->tf_r0;
+		KDASSERT(rd <= 12);
+		regs[rd] = imm;
+		frame->tf_pc += 4;
+		break;
+	}
+	case DTRACE_INVOP_CMP_IMM: {
+		/* cmp r?, #? */
+		uint32_t rn = (op >> 16) & 0xf;
+		uint32_t *regs = &frame->tf_r0;
+		uint32_t imm = expand_imm(op & 0xfff);
+		uint32_t spsr = frame->tf_spsr;
+		uint32_t result;
+		int carry;
+		int overflow;
+		/*
+		 * (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), ’1’);
+		 * APSR.N = result<31>;
+		 * APSR.Z = IsZeroBit(result);
+		 * APSR.C = carry;
+		 * APSR.V = overflow; 
+		 */
+		KDASSERT(rn <= 12);
+		result = add_with_carry(regs[rn], ~imm, 1, &carry, &overflow);
+		if (result & 0x80000000)
+			spsr |= PSR_N_bit;
+		else
+			spsr &= ~PSR_N_bit;
+		if (result == 0)
+			spsr |= PSR_Z_bit;
+		else
+			spsr &= ~PSR_Z_bit;
+		if (carry)
+			spsr |= PSR_C_bit;
+		else
+			spsr &= ~PSR_C_bit;
+		if (overflow)
+			spsr |= PSR_V_bit;
+		else
+			spsr &= ~PSR_V_bit;
+
+#if 0
+		aprint_normal("pc=%x Rn=%x imm=%x %c%c%c%c\n", frame->tf_pc, regs[rn], imm,
+		    (spsr & PSR_N_bit) ? 'N' : 'n',
+		    (spsr & PSR_Z_bit) ? 'Z' : 'z',
+		    (spsr & PSR_C_bit) ? 'C' : 'c',
+		    (spsr & PSR_V_bit) ? 'V' : 'v');
+#endif
+		frame->tf_spsr = spsr;
+		frame->tf_pc += 4;
+		break;
+	}
+	case DTRACE_INVOP_B_LABEL: {
+		/* b ??? */
+		uint32_t imm = (op & 0x00ffffff) << 2;
+		int32_t diff;
+		/* SignExtend(imm26, 32) */
+		if (imm & 0x02000000)
+			imm |= 0xfc000000;
+		diff = (int32_t)imm;
+		frame->tf_pc += 8 + diff;
+		break;
+	}
+	/* FIXME: push will overwrite trapframe... */
+	case DTRACE_INVOP_PUSH: {
+		/* push {...} */
+		uint32_t register_list = (op & 0xffff);
+		uint32_t *sp = (uint32_t *)(intptr_t)frame->tf_svc_sp;
+		uint32_t *regs = &frame->tf_r0;
+		int i;
+		int count = 0;
+
+#if 0
+		if ((op & 0x0fff0fff) == 0x052d0004) {
+			/* A2: str r4, [sp, #-4]! */
+			*(sp - 1) = regs[4];
+			frame->tf_pc += 4;
+			break;
+		}
+#endif
+
+		for (i=0; i < 16; i++) {
+			if (register_list & (1 << i))
+				count++;
+		}
+		sp -= count;
+
+		for (i=0; i <= 12; i++) {
+			if (register_list & (1 << i))
+				*sp++ = regs[i];
+		}
+		if (register_list & (1 << 13))
+			*sp++ = frame->tf_svc_sp;
+		if (register_list & (1 << 14))
+			*sp++ = frame->tf_svc_lr;
+		if (register_list & (1 << 15))
+			*sp = frame->tf_pc + 8;
+
+		/* make sure the caches and memory are in sync */
+		cpu_dcache_wbinv_range(frame->tf_svc_sp, count * 4);
+
+		/* In case the current page tables have been modified ... */
+		cpu_tlb_flushID();
+		cpu_cpwait();
+
+		frame->tf_svc_sp -= count * 4;
+		frame->tf_pc += 4;
+
+		break;
+	}
+	default:
+		KDASSERTMSG(0, "op=%u\n", op >> 28);
+	}
+}
+#endif
+
 static void
 fbt_doubletrap(void)
 {
@@ -238,6 +505,7 @@ fbt_invop(uintptr_t addr, uintptr_t *sta
 	return (0);
 }
 
+#if defined(__i386__) || defined(__amd64__)
 static int
 fbt_provide_module_cb(const char *name, int symindx, void *value,
 	uint32_t symsize, int type, void *opaque)
@@ -446,6 +714,178 @@ fbt_provide_module_cb(const char *name, 
 	return 0;
 }
 
+#elif defined(__arm__)
+
+static int
+fbt_provide_module_cb(const char *name, int symindx, void *value,
+	uint32_t symsize, int type, void *opaque)
+{
+	fbt_probe_t *fbt, *retfbt;
+	uint32_t *instr, *limit;
+	bool was_ldm_lr = false;
+	dtrace_modctl_t *mod = opaque;
+	const char *modname = mod->mod_info->mi_name;
+	int size;
+
+	/* got a function? */
+	if (ELF_ST_TYPE(type) != STT_FUNC) {
+	    return 0;
+	}
+
+	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);
+
+	/*
+	 * Exclude some more symbols which can be called from probe context.
+	 */
+	if (strncmp(name, "db_", 3) == 0 /* debugger */
+	    || strncmp(name, "ddb_", 4) == 0 /* debugger */
+	    || strncmp(name, "kdb_", 4) == 0 /* debugger */
+	    || strncmp(name, "lockdebug_", 10) == 0 /* lockdebug XXX for now */
+	    || strncmp(name, "kauth_", 5) == 0 /* CRED XXX for now */
+	    /* Sensitive functions on ARM */
+	    || strncmp(name, "_spl", 4) == 0
+	    || strncmp(name, "dmt_", 4) == 0
+	    || strcmp(name, "binuptime") == 0
+	    || strcmp(name, "dosoftints") == 0
+	    || strcmp(name, "fbt_emulate") == 0
+	    || strcmp(name, "nanouptime") == 0
+	    || strcmp(name, "undefinedinstruction") == 0
+	    ) {
+		return 0;
+	}
+
+	instr = (uint32_t *) value;
+	limit = (uint32_t *)((uintptr_t)value + symsize);
+
+	if (!FBT_MOV_IP_SP_P(*instr)
+	    && !FBT_BX_LR_P(*instr)
+	    && !FBT_MOVW_P(*instr)
+	    && !FBT_MOV_IMM_P(*instr)
+	    && !FBT_B_LABEL_P(*instr)
+	    && !FBT_LDR_IMM_P(*instr)
+	    && !FBT_CMP_IMM_P(*instr)
+	    /* && !FBT_PUSH_P(*instr) */
+	    ) {
+		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 = mod;
+	/* fbt->fbtp_loadcnt = lf->loadcnt; */
+	if (FBT_MOV_IP_SP_P(*instr))
+		fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_MOV_IP_SP);
+	else if (FBT_LDR_IMM_P(*instr))
+		fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_LDR_IMM);
+	else if (FBT_MOVW_P(*instr))
+		fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_MOVW);
+	else if (FBT_MOV_IMM_P(*instr))
+		fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_MOV_IMM);
+	else if (FBT_CMP_IMM_P(*instr))
+		fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_CMP_IMM);
+	else if (FBT_BX_LR_P(*instr))
+		fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_BX_LR);
+	else if (FBT_PUSH_P(*instr))
+		fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_PUSH);
+	else if (FBT_B_LABEL_P(*instr))
+		fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_B_LABEL);
+
+	fbt->fbtp_patchval = PATCHVAL_ENCODE_COND(*instr);
+	fbt->fbtp_savedval = *instr;
+	fbt->fbtp_symindx = symindx;
+
+	fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
+	fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
+	mod->mod_fbtentries++;
+
+	retfbt = NULL;
+
+	while (instr < limit) {
+		if (instr >= limit)
+			return (0);
+
+		size = 1;
+
+		if (!FBT_BX_LR_P(*instr)
+		    && !FBT_MOV_PC_LR_P(*instr)
+		    && !FBT_LDM_P(*instr)
+		    && !FBT_LDMIB_P(*instr)
+		    && !(was_ldm_lr && FBT_B_LABEL_P(*instr))
+		    ) {
+			if (FBT_LDM_LR_P(*instr) || FBT_LDMIB_LR_P(*instr))
+				was_ldm_lr = true;
+			else
+				was_ldm_lr = false;
+			instr += size;
+			continue;
+		}
+
+		/*
+		 * 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, 3, fbt);
+		} else {
+			retfbt->fbtp_next = fbt;
+			fbt->fbtp_id = retfbt->fbtp_id;
+		}
+
+		retfbt = fbt;
+		fbt->fbtp_patchpoint = instr;
+		fbt->fbtp_ctl = mod;
+		/* fbt->fbtp_loadcnt = lf->loadcnt; */
+		fbt->fbtp_symindx = symindx;
+
+		if (FBT_BX_LR_P(*instr))
+			fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_BX_LR);
+		else if (FBT_MOV_PC_LR_P(*instr))
+			fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_MOV_PC_LR);
+		else if (FBT_LDM_P(*instr))
+			fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_LDM);
+		else if (FBT_LDMIB_P(*instr))
+			fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_LDMIB);
+		else if (FBT_B_LABEL_P(*instr))
+			fbt->fbtp_rval = BUILD_RVAL(*instr, DTRACE_INVOP_B_LABEL);
+
+		fbt->fbtp_roffset = (uintptr_t)(instr - (uint32_t *) value);
+		fbt->fbtp_patchval = PATCHVAL_ENCODE_COND(*instr);
+
+		fbt->fbtp_savedval = *instr;
+		fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
+		fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
+
+		mod->mod_fbtentries++;
+
+		instr += size;
+		was_ldm_lr = false;
+	}
+
+	return 0;
+}
+#else
+#error "architecture not supported"
+#endif
+
+
 static void
 fbt_provide_module(void *arg, dtrace_modctl_t *mod)
 {
@@ -536,6 +976,8 @@ fbt_destroy(void *arg, dtrace_id_t id, v
 	} while (fbt != NULL);
 }
 
+#if defined(__i386__) || defined(__amd64__)
+
 static int
 fbt_enable(void *arg, dtrace_id_t id, void *parg)
 {
@@ -699,6 +1141,132 @@ fbt_resume(void *arg, dtrace_id_t id, vo
 	lcr0(cr0);
 }
 
+#elif defined(__arm__)
+
+static int
+fbt_enable(void *arg, dtrace_id_t id, void *parg)
+{
+	fbt_probe_t *fbt = parg;
+#if 0
+	dtrace_modctl_t *ctl = fbt->fbtp_ctl;
+#endif
+	dtrace_icookie_t c;
+
+
+#if 0	/* XXX TBD */
+	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;
+	}
+#endif
+
+	c = dtrace_interrupt_disable();
+
+	for (fbt = parg; fbt != NULL; fbt = fbt->fbtp_next) {
+		*fbt->fbtp_patchpoint = fbt->fbtp_patchval;
+		cpu_idcache_wbinv_range((vaddr_t)fbt->fbtp_patchpoint, 4);
+	}
+
+	dtrace_interrupt_enable(c);
+
+	return 0;
+}
+
+static void
+fbt_disable(void *arg, dtrace_id_t id, void *parg)
+{
+	fbt_probe_t *fbt = parg;
+#if 0
+	dtrace_modctl_t *ctl = fbt->fbtp_ctl;
+#endif
+	dtrace_icookie_t c;
+
+#if 0	/* XXX TBD */
+	ASSERT(ctl->nenabled > 0);
+	ctl->nenabled--;
+
+	if ((ctl->loadcnt != fbt->fbtp_loadcnt))
+		return;
+#endif
+
+	c = dtrace_interrupt_disable();
+
+	for (; fbt != NULL; fbt = fbt->fbtp_next) {
+		*fbt->fbtp_patchpoint = fbt->fbtp_savedval;
+		cpu_idcache_wbinv_range((vaddr_t)fbt->fbtp_patchpoint, 4);
+	}
+
+	dtrace_interrupt_enable(c);
+}
+
+static void
+fbt_suspend(void *arg, dtrace_id_t id, void *parg)
+{
+	fbt_probe_t *fbt = parg;
+#if 0
+	dtrace_modctl_t *ctl = fbt->fbtp_ctl;
+#endif
+	dtrace_icookie_t c;
+
+#if 0	/* XXX TBD */
+	ASSERT(ctl->nenabled > 0);
+
+	if ((ctl->loadcnt != fbt->fbtp_loadcnt))
+		return;
+#endif
+
+	c = dtrace_interrupt_disable();
+
+	for (; fbt != NULL; fbt = fbt->fbtp_next) {
+		*fbt->fbtp_patchpoint = fbt->fbtp_savedval;
+		cpu_idcache_wbinv_range((vaddr_t)fbt->fbtp_patchpoint, 4);
+	}
+
+	dtrace_interrupt_enable(c);
+}
+
+static void
+fbt_resume(void *arg, dtrace_id_t id, void *parg)
+{
+	fbt_probe_t *fbt = parg;
+#if 0
+	dtrace_modctl_t *ctl = fbt->fbtp_ctl;
+#endif
+	dtrace_icookie_t c;
+
+#if 0	/* XXX TBD */
+	ASSERT(ctl->nenabled > 0);
+
+	if ((ctl->loadcnt != fbt->fbtp_loadcnt))
+		return;
+#endif
+
+	c = dtrace_interrupt_disable();
+
+	for (; fbt != NULL; fbt = fbt->fbtp_next) {
+		*fbt->fbtp_patchpoint = fbt->fbtp_patchval;
+		cpu_idcache_wbinv_range((vaddr_t)fbt->fbtp_patchpoint, 4);
+	}
+
+	dtrace_interrupt_enable(c);
+}
+
+#else
+#error "architecture not supported"
+#endif
+
 static int
 fbt_ctfoff_init(dtrace_modctl_t *mod, mod_ctf_t *mc)
 {
@@ -1498,6 +2066,9 @@ fbt_load(void)
 
 	dtrace_doubletrap_func = fbt_doubletrap;
 	dtrace_invop_add(fbt_invop);
+#ifdef __arm__
+	dtrace_emulation_jump_addr = fbt_emulate;
+#endif
 
 	if (dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_USER,
 	    NULL, &fbt_pops, NULL, &fbt_id) != 0)
@@ -1510,6 +2081,9 @@ fbt_unload(void)
 {
 	int error = 0;
 
+#ifdef __arm__
+	dtrace_emulation_jump_addr = NULL;
+#endif
 	/* De-register the invalid opcode handler. */
 	dtrace_invop_remove(fbt_invop);
 

Index: src/external/cddl/osnet/dist/uts/common/sys/dtrace.h
diff -u src/external/cddl/osnet/dist/uts/common/sys/dtrace.h:1.9 src/external/cddl/osnet/dist/uts/common/sys/dtrace.h:1.10
--- src/external/cddl/osnet/dist/uts/common/sys/dtrace.h:1.9	Wed Mar  5 06:12:00 2014
+++ src/external/cddl/osnet/dist/uts/common/sys/dtrace.h	Sat Mar 15 08:00:19 2014
@@ -2331,6 +2331,20 @@ extern void dtrace_getfsr(uint64_t *);
 #define	DTRACE_INVOP_NOP		4
 #define	DTRACE_INVOP_RET		5
 
+#elif defined(__arm__)
+
+#define	DTRACE_INVOP_MOV_IP_SP		1
+#define	DTRACE_INVOP_BX_LR		2
+#define	DTRACE_INVOP_MOV_PC_LR		3
+#define	DTRACE_INVOP_LDM		4
+#define	DTRACE_INVOP_LDMIB		5
+#define	DTRACE_INVOP_LDR_IMM		6
+#define	DTRACE_INVOP_MOVW		7
+#define	DTRACE_INVOP_MOV_IMM		8
+#define	DTRACE_INVOP_CMP_IMM		9
+#define	DTRACE_INVOP_B_LABEL		10
+#define	DTRACE_INVOP_PUSH		11
+
 #endif
 
 #ifdef	__cplusplus

Reply via email to