Skip to content

Instantly share code, notes, and snippets.

@ozaki-r
Last active January 3, 2016 23:29
Show Gist options
  • Save ozaki-r/8535846 to your computer and use it in GitHub Desktop.
Save ozaki-r/8535846 to your computer and use it in GitHub Desktop.
Porting DTrace on NetBSD to ARM.
Index: external/cddl/osnet/dev/dtrace/arm/dtrace_asm.S
===================================================================
RCS file: /cvs/cvsroot/src/external/cddl/osnet/dev/dtrace/arm/dtrace_asm.S,v
retrieving revision 1.3
diff -u -r1.3 dtrace_asm.S
--- external/cddl/osnet/dev/dtrace/arm/dtrace_asm.S 5 Mar 2014 03:09:17 -0000 1.3
+++ external/cddl/osnet/dev/dtrace/arm/dtrace_asm.S 10 Mar 2014 05:47:33 -0000
@@ -203,13 +202,24 @@
void dtrace_invop_init(void)
*/
ENTRY(dtrace_invop_init)
- RET
+ ldr r1, .Ldtrace_invop
+ ldr r2, .Ldtrace_invop_jump_addr
+ str r1, [r2]
+ RET
+ .align 0
+.Ldtrace_invop:
+ .word dtrace_invop
+.Ldtrace_invop_jump_addr:
+ .word dtrace_invop_jump_addr
END(dtrace_invop_init)
/*
void dtrace_invop_uninit(void)
*/
ENTRY(dtrace_invop_uninit)
+ mov r0, #0
+ ldr r1, .Ldtrace_invop_jump_addr
+ str r0, [r1]
RET
END(dtrace_invop_uninit)
Index: external/cddl/osnet/dev/dtrace/arm/dtrace_isa.c
===================================================================
RCS file: /cvs/cvsroot/src/external/cddl/osnet/dev/dtrace/arm/dtrace_isa.c,v
retrieving revision 1.3
diff -u -r1.3 dtrace_isa.c
--- external/cddl/osnet/dev/dtrace/arm/dtrace_isa.c 8 Mar 2014 11:46:01 -0000 1.3
+++ external/cddl/osnet/dev/dtrace/arm/dtrace_isa.c 10 Mar 2014 05:47:33 -0000
@@ -39,6 +39,17 @@
#include <ddb/db_sym.h>
#include <ddb/ddb.h>
+uintptr_t kernelbase = (uintptr_t)KERNEL_BASE;
+
+/* TODO: support AAPCS */
+/* XXX: copied from sys/arch/arm/arm/db_trace.c */
+#define INKERNEL(va) (((vaddr_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
+
+#define FR_SCP (0)
+#define FR_RLV (-1)
+#define FR_RSP (-2)
+#define FR_RFP (-3)
+
#include "regset.h"
/*
Index: external/cddl/osnet/dev/fbt/fbt.c
===================================================================
RCS file: /cvs/cvsroot/src/external/cddl/osnet/dev/fbt/fbt.c,v
retrieving revision 1.13
diff -u -r1.13 fbt.c
--- external/cddl/osnet/dev/fbt/fbt.c 5 Mar 2014 20:14:15 -0000 1.13
+++ external/cddl/osnet/dev/fbt/fbt.c 10 Mar 2014 05:47:33 -0000
@@ -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 @@
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 @@
#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 @@
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 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 @@
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 @@
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 @@
} while (fbt != NULL);
}
+#if defined(__i386__) || defined(__amd64__)
+
static int
fbt_enable(void *arg, dtrace_id_t id, void *parg)
{
@@ -699,6 +1141,132 @@
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 @@
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 @@
{
int error = 0;
+#ifdef __arm__
+ dtrace_emulation_jump_addr = NULL;
+#endif
/* De-register the invalid opcode handler. */
dtrace_invop_remove(fbt_invop);
Index: external/cddl/osnet/dist/uts/common/sys/dtrace.h
===================================================================
RCS file: /cvs/cvsroot/src/external/cddl/osnet/dist/uts/common/sys/dtrace.h,v
retrieving revision 1.9
diff -u -r1.9 dtrace.h
--- external/cddl/osnet/dist/uts/common/sys/dtrace.h 5 Mar 2014 06:12:00 -0000 1.9
+++ external/cddl/osnet/dist/uts/common/sys/dtrace.h 10 Mar 2014 05:47:33 -0000
@@ -2331,6 +2331,20 @@
#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
Index: sys/arch/arm/arm/undefined.c
===================================================================
RCS file: /cvs/cvsroot/src/sys/arch/arm/arm/undefined.c,v
retrieving revision 1.52
diff -u -r1.52 undefined.c
--- sys/arch/arm/arm/undefined.c 5 Mar 2014 02:18:30 -0000 1.52
+++ sys/arch/arm/arm/undefined.c 10 Mar 2014 05:47:58 -0000
@@ -48,6 +48,7 @@
#include "opt_ddb.h"
#include "opt_kgdb.h"
+#include "opt_dtrace.h"
#include <sys/param.h>
#ifdef KGDB
@@ -220,6 +221,45 @@
static struct undefined_handler gdb_uh_thumb;
#endif
+#ifdef KDTRACE_HOOKS
+#include <sys/dtrace_bsd.h>
+
+/* Not used for now, but needed for dtrace/fbt modules */
+dtrace_doubletrap_func_t dtrace_doubletrap_func = NULL;
+dtrace_trap_func_t dtrace_trap_func = NULL;
+
+int (* dtrace_invop_jump_addr)(uintptr_t, uintptr_t *, uintptr_t);
+void (* dtrace_emulation_jump_addr)(int, struct trapframe *);
+
+static int
+dtrace_trapper(u_int addr, struct trapframe *frame)
+{
+ int op;
+ struct trapframe back;
+ u_int insn = read_insn(addr, false);
+
+ if (dtrace_invop_jump_addr == NULL || dtrace_emulation_jump_addr == NULL)
+ return 1;
+
+ if (!DTRACE_IS_BREAKPOINT(insn))
+ return 1;
+
+ /* cond value is encoded in the first byte */
+ if (!arm_cond_ok_p(__SHIFTIN(insn, INSN_COND_MASK), frame->tf_spsr)) {
+ frame->tf_pc += INSN_SIZE;
+ return 0;
+ }
+
+ back = *frame;
+ op = dtrace_invop_jump_addr(addr, (uintptr_t *) frame->tf_svc_sp, frame->tf_r0);
+ *frame = back;
+
+ dtrace_emulation_jump_addr(op, frame);
+
+ return 0;
+}
+#endif
+
void
undefined_init(void)
{
@@ -262,6 +302,15 @@
und_ev.ev_count++;
+#ifdef KDTRACE_HOOKS
+ if ((tf->tf_spsr & PSR_MODE) != PSR_USR32_MODE) {
+ tf->tf_pc -= INSN_SIZE;
+ if (dtrace_trapper(tf->tf_pc, tf) == 0)
+ return;
+ tf->tf_pc += INSN_SIZE; /* Reset for the rest code */
+ }
+#endif
+
/* Enable interrupts if they were enabled before the exception. */
#ifdef acorn26
if ((tf->tf_r15 & R15_IRQ_DISABLE) == 0)
Index: sys/arch/arm/include/trap.h
===================================================================
RCS file: /cvs/cvsroot/src/sys/arch/arm/include/trap.h,v
retrieving revision 1.8
diff -u -r1.8 trap.h
--- sys/arch/arm/include/trap.h 19 Jan 2008 13:11:09 -0000 1.8
+++ sys/arch/arm/include/trap.h 10 Mar 2014 05:47:58 -0000
@@ -62,6 +62,14 @@
#define GDB_THUMB_BREAKPOINT 0xdefe /* Thumb in GDB */
#define KERNEL_BREAKPOINT 0xe7ffffff /* Used by DDB */
+/*
+ * DTrace uses 0xe7fffef0 to 0xe7fffeff as breakpoints.
+ * The first byte is used to encode a cond value.
+ */
+#define DTRACE_BREAKPOINT 0xe7fffef0
+#define DTRACE_BREAKPOINT_MASK 0xfffffff0
+#define DTRACE_IS_BREAKPOINT(insn) ((insn & DTRACE_BREAKPOINT_MASK) == DTRACE_BREAKPOINT)
+
#define KBPT_ASM ".word 0xe7ffdefe"
#define USER_BREAKPOINT GDB_BREAKPOINT
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment