From e973a934a1bf8b7646ce510a07ea7850ba8a8cbe Mon Sep 17 00:00:00 2001 From: Dmitry Kovalenko Date: Tue, 25 Jun 2013 15:29:18 +0400 Subject: [PATCH] [FEAUTRE] ARM branches instrumentation --- kprobe/arch/asm-arm/dbi_kprobes.c | 39 +++++++++++++++++++++++++---------- kprobe/arch/asm-arm/dbi_kprobes.h | 10 ++++----- kprobe/arch/asm-arm/dbi_kprobes_arm.S | 33 +++++++++++++++++++++++++++-- kprobe/arch/asm-arm/dbi_kprobes_arm.h | 3 +++ 4 files changed, 67 insertions(+), 18 deletions(-) diff --git a/kprobe/arch/asm-arm/dbi_kprobes.c b/kprobe/arch/asm-arm/dbi_kprobes.c index 36b9e41..898dd1e 100644 --- a/kprobe/arch/asm-arm/dbi_kprobes.c +++ b/kprobe/arch/asm-arm/dbi_kprobes.c @@ -439,10 +439,6 @@ static int arch_check_insn_arm (struct arch_specific_insn *ainsn) ARM_INSN_MATCH (AUNDEF, ainsn->insn_arm[0]) || ARM_INSN_MATCH (SWI, ainsn->insn_arm[0]) || ARM_INSN_MATCH (BREAK, ainsn->insn_arm[0]) || - ARM_INSN_MATCH (BL, ainsn->insn_arm[0]) || - ARM_INSN_MATCH (BLX1, ainsn->insn_arm[0]) || - ARM_INSN_MATCH (BLX2, ainsn->insn_arm[0]) || - ARM_INSN_MATCH (BX, ainsn->insn_arm[0]) || ARM_INSN_MATCH (BXJ, ainsn->insn_arm[0])) { DBPRINTF ("Bad insn arch_check_insn_arm: %lx\n", ainsn->insn_arm[0]); @@ -857,15 +853,36 @@ int arch_copy_trampoline_arm_uprobe (struct kprobe *p, struct task_struct *task, insns[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION; insns[7] = (kprobe_opcode_t) (p->addr + 1); - // B - if(ARM_INSN_MATCH (B, ainsn.insn_arm[0])) - { - memcpy (insns, pc_dep_insn_execbuf, sizeof (insns)); + if (ARM_INSN_MATCH(B, ainsn.insn_arm[0]) && /* B */ + !ARM_INSN_MATCH(BLX1, ainsn.insn_arm[0])) { + /* B check can be false positive on BLX1 instruction */ + memcpy(insns, b_cond_insn_execbuf, sizeof (insns)); insns[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION; - insns[6] = (kprobe_opcode_t) (p->addr + 2); - insns[7] = get_addr_b(p->opcode, p->addr); + insns[0] |= insn[0] & 0xf0000000; + insns[6] = get_addr_b(p->opcode, p->addr); + insns[7] = (kprobe_opcode_t) (p->addr + 1); + } else if (ARM_INSN_MATCH(BX, ainsn.insn_arm[0]) || // BX, BLX (Rm) + ARM_INSN_MATCH(BLX2, ainsn.insn_arm[0])) { + memcpy(insns, b_r_insn_execbuf, sizeof (insns)); + insns[0] = insn[0]; + insns[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION; + insns[7] = (kprobe_opcode_t) (p->addr + 1); + } else if (ARM_INSN_MATCH(BLX1, ainsn.insn_arm[0])) { // BL, BLX (Off) + memcpy(insns, blx_off_insn_execbuf, sizeof(insns)); + insns[0] |= 0xe0000000; + insns[1] |= 0xe0000000; + insns[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION; + insns[6] = get_addr_b(p->opcode, p->addr) + + 2 * (p->opcode & 01000000) + 1; /* jump to thumb */ + insns[7] = (kprobe_opcode_t) (p->addr + 1); + } else if (ARM_INSN_MATCH(BL, ainsn.insn_arm[0])){ // BL + memcpy(insns, blx_off_insn_execbuf, sizeof(insns)); + insns[0] |= insn[0] & 0xf0000000; + insns[1] |= insn[0] & 0xf0000000; + insns[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION; + insns[6] = get_addr_b(p->opcode, p->addr); + insns[7] = (kprobe_opcode_t) (p->addr + 1); } - DBPRINTF ("arch_prepare_uprobe: to %p - %lx %lx %lx %lx %lx %lx %lx %lx %lx", p->ainsn.insn_arm, insns[0], insns[1], insns[2], insns[3], insns[4], insns[5], insns[6], insns[7], insns[8]); diff --git a/kprobe/arch/asm-arm/dbi_kprobes.h b/kprobe/arch/asm-arm/dbi_kprobes.h index 7f6f59e..1314df3 100644 --- a/kprobe/arch/asm-arm/dbi_kprobes.h +++ b/kprobe/arch/asm-arm/dbi_kprobes.h @@ -162,8 +162,8 @@ static inline int dbi_fp_backtrace(struct task_struct *task, unsigned long *buf, # define PTRN_ARM_INSN_AUNDEF 0x07F000F0 // branches -# define MASK_ARM_INSN_B 0x0E000000 // xxxx111xxxxxxxxxxxxxxxxxxxxxxxxx -# define PTRN_ARM_INSN_B 0x0A000000 // cccc101xxxxxxxxxxxxxxxxxxxxxxxxx +# define MASK_ARM_INSN_B 0x0F000000 // xxxx1111xxxxxxxxxxxxxxxxxxxxxxxx +# define PTRN_ARM_INSN_B 0x0A000000 // cccc1010xxxxxxxxxxxxxxxxxxxxxxxx # define MASK_THUMB_INSN_B1 0xF000 // 1111xxxxxxxxxxxx # define PTRN_THUMB_INSN_B1 0xD000 // 1101xxxxxxxxxxxx // b label @@ -180,7 +180,7 @@ static inline int dbi_fp_backtrace(struct task_struct *task, unsigned long *buf, # define MASK_THUMB2_INSN_B2 0xD000F800 // 11x1xxxxxxxxxxxx 11111xxxxxxxxxxx // swapped # define PTRN_THUMB2_INSN_B2 0x9000F000 // 10x1xxxxxxxxxxxx 11110xxxxxxxxxxx // swapped -# define MASK_ARM_INSN_BL 0x0E000000 // xxxx111xxxxxxxxxxxxxxxxxxxxxxxxx +# define MASK_ARM_INSN_BL 0x0F000000 // xxxx1111xxxxxxxxxxxxxxxxxxxxxxxx # define PTRN_ARM_INSN_BL 0x0B000000 // cccc1011xxxxxxxxxxxxxxxxxxxxxxxx //# define MASK_THUMB_INSN_BL 0xF800 // 11111xxxxxxxxxxx @@ -190,8 +190,8 @@ static inline int dbi_fp_backtrace(struct task_struct *task, unsigned long *buf, # define MASK_THUMB2_INSN_BL 0xD000F800 // 11x1xxxxxxxxxxxx 11111xxxxxxxxxxx // swapped # define PTRN_THUMB2_INSN_BL 0xD000F000 // 11x1xxxxxxxxxxxx 11110xxxxxxxxxxx // bl imm swapped -# define MASK_ARM_INSN_BLX1 0xFF000000 // 11111111xxxxxxxxxxxxxxxxxxxxxxxx -# define PTRN_ARM_INSN_BLX1 0xFA000000 // 11111011xxxxxxxxxxxxxxxxxxxxxxxx +# define MASK_ARM_INSN_BLX1 0xFE000000 // 1111111axxxxxxxxxxxxxxxxxxxxxxxx +# define PTRN_ARM_INSN_BLX1 0xFA000000 // 1111101axxxxxxxxxxxxxxxxxxxxxxxx //# define MASK_THUMB_INSN_BLX1 0xF800 // 11111xxxxxxxxxxx / blx imm //# define PTRN_THUMB_INSN_BLX1 0xF000 // 11101xxxxxxxxxxx diff --git a/kprobe/arch/asm-arm/dbi_kprobes_arm.S b/kprobe/arch/asm-arm/dbi_kprobes_arm.S index 5b4c7bc..e483177 100644 --- a/kprobe/arch/asm-arm/dbi_kprobes_arm.S +++ b/kprobe/arch/asm-arm/dbi_kprobes_arm.S @@ -29,6 +29,35 @@ pc_dep_insn_execbuf: nop // stored PC nop // stored PC-4 (next insn addr) + .global b_r_insn_execbuf +b_r_insn_execbuf: + nop // bx, blx (Rm) + ldr pc, np1 + nop + nop + nop + nop // retbreak + nop +np1: nop // stored PC-4 (next insn addr) - - + .global b_cond_insn_execbuf +b_cond_insn_execbuf: + beq condway + ldr pc, np2 +condway: ldr pc, bd2 + nop + nop + nop // retbreak +bd2: nop // branch displacement +np2: nop // stored PC-4 (next insn addr) + + .global blx_off_insn_execbuf +blx_off_insn_execbuf: + ldreq lr, bd3 + blxeq lr + ldr pc, np3 + nop + nop + nop // retbreak +bd3: nop // branch displacement +np3: nop // stored PC-4 (next insn addr) diff --git a/kprobe/arch/asm-arm/dbi_kprobes_arm.h b/kprobe/arch/asm-arm/dbi_kprobes_arm.h index 914303a..b60ce7c 100644 --- a/kprobe/arch/asm-arm/dbi_kprobes_arm.h +++ b/kprobe/arch/asm-arm/dbi_kprobes_arm.h @@ -1,2 +1,5 @@ void gen_insn_execbuf(void); void pc_dep_insn_execbuf(void); +void b_r_insn_execbuf(void); +void b_cond_insn_execbuf(void); +void blx_off_insn_execbuf(void); -- 2.7.4