Last active
January 3, 2016 23:29
-
-
Save ozaki-r/8535846 to your computer and use it in GitHub Desktop.
Porting DTrace on NetBSD to ARM.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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