Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/external/cddl/osnet Implement DTrace FBT provider for ARM
details: https://anonhg.NetBSD.org/src/rev/8ddee1b9da74
branches: trunk
changeset: 327709:8ddee1b9da74
user: ozaki-r <ozaki-r%NetBSD.org@localhost>
date: Sat Mar 15 08:00:19 2014 +0000
description:
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.
diffstat:
external/cddl/osnet/dev/fbt/fbt.c | 578 ++++++++++++++++++++++-
external/cddl/osnet/dist/uts/common/sys/dtrace.h | 14 +
2 files changed, 590 insertions(+), 2 deletions(-)
diffs (truncated from 700 to 300 lines):
diff -r ba209a24da85 -r 8ddee1b9da74 external/cddl/osnet/dev/fbt/fbt.c
--- a/external/cddl/osnet/dev/fbt/fbt.c Sat Mar 15 07:49:15 2014 +0000
+++ b/external/cddl/osnet/dev/fbt/fbt.c Sat Mar 15 08:00:19 2014 +0000
@@ -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 @@
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
+#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
-#define FBT_PATCHVAL 0xf0
+#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))
Home |
Main Index |
Thread Index |
Old Index