From: Vyacheslav Cherkashin Date: Fri, 1 Jul 2016 18:48:20 +0000 (+0300) Subject: ARM64: implement uretprobe X-Git-Tag: submit/tizen/20170815.123151~31 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c84fd0450b802d6c514fd2e451fd76b121e40908;p=platform%2Fkernel%2Fswap-modules.git ARM64: implement uretprobe Change-Id: I9775576f8901eac71e62356ee0ae56942f1e5406 Signed-off-by: Vyacheslav Cherkashin --- diff --git a/uprobe/arch/arm64/swap-asm/swap_uprobes.c b/uprobe/arch/arm64/swap-asm/swap_uprobes.c index b75cb28..f2e7a9a 100644 --- a/uprobe/arch/arm64/swap-asm/swap_uprobes.c +++ b/uprobe/arch/arm64/swap-asm/swap_uprobes.c @@ -31,8 +31,10 @@ #define BRK_BP 0x45 #define BRK_PSEUDO_SS 0x54 +#define BRK_URP 0x67 #define BRK64_OPCODE_BP MAKE_BRK(BRK_BP) #define BRK64_OPCODE_PSEUDO_SS MAKE_BRK(BRK_PSEUDO_SS) +#define BRK64_OPCODE_URP MAKE_BRK(BRK_URP) struct uprobe_ctlblk { @@ -62,6 +64,72 @@ static void reset_current_uprobe(void) } +int arch_prepare_uretprobe(struct uretprobe_instance *ri, + struct pt_regs *regs) +{ + unsigned long bp_addr = (unsigned long)(ri->rp->up.ainsn.insn + + URP_RET_BREAK_IDX); + + ri->sp = (kprobe_opcode_t *)regs->sp; + + /* replace the return address (regs[30] - lr) */ + ri->ret_addr = (kprobe_opcode_t *)regs->regs[30]; + regs->regs[30] = bp_addr; + + return 0; +} + +void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs) +{ + regs->pc = orig_ret_addr; +} + +static int make_urp_arm64(struct uprobe *p) +{ + u32 *utramp, urp_brk; + + if (p->ainsn.insn == NULL) { + utramp = swap_slot_alloc(p->sm); + if (utramp == NULL) + return -ENOMEM; + + p->ainsn.insn = utramp; + } + + utramp = p->ainsn.insn; + urp_brk = BRK64_OPCODE_URP; + + if (!write_proc_vm_atomic(p->task, + (long)&utramp[URP_RET_BREAK_IDX], + &urp_brk, sizeof(urp_brk))) { + pr_err("%s failed to write memory %p!\n", __func__, utramp); + } + + add_uprobe_table(p); + + return 0; +} + +static enum dbg_code urp_handler(struct pt_regs *regs, unsigned int esr) +{ + struct uprobe *p; + unsigned long pc = regs->pc; + unsigned long insn_addr = pc - sizeof(u32) * URP_RET_BREAK_IDX; + + p = get_uprobe_by_insn_slot((void *)insn_addr, current->tgid, regs); + if (p == NULL) { + pr_err("no_uretprobe: Not one of ours: let " + "kernel handle it %lx\n", pc); + return DBG_ERROR; + } + + local_irq_enable(); + trampoline_uprobe_handler(p, regs); + + return DBG_HANDLED; +} + + int arch_arm_uprobe(struct uprobe *p) { uprobe_opcode_t insn = BRK64_OPCODE_BP; @@ -247,6 +315,12 @@ static enum dbg_code uprobe_handler_arm64(struct pt_regs *regs) pr_err("no_uprobe live\n"); goto out_ok; } + + if (make_urp_arm64(p)) { + disarm_uprobe(p, p->task); + pr_err("no_uretprobe\n"); + goto out_ok; + } } if (!p->pre_handler || !p->pre_handler(p, regs)) @@ -298,6 +372,14 @@ static struct brk_hook dbg_up_ss = { .fn = uprobe_ss_handler, }; +static struct brk_hook dbg_urp_bp = { + .spsr_mask = PSR_MODE_MASK, + .spsr_val = PSR_MODE_EL0t, + .esr_mask = DBG_BRK_ESR_MASK, + .esr_val = DBG_BRK_ESR(BRK_URP), + .fn = urp_handler, +}; + int swap_arch_init_uprobes(void) { @@ -309,12 +391,14 @@ int swap_arch_init_uprobes(void) dbg_brk_hook_reg(&dbg_up_ss); dbg_brk_hook_reg(&dbg_up_bp); + dbg_brk_hook_reg(&dbg_urp_bp); return 0; } void swap_arch_exit_uprobes(void) { + dbg_brk_hook_unreg(&dbg_urp_bp); dbg_brk_hook_unreg(&dbg_up_bp); dbg_brk_hook_unreg(&dbg_up_ss); swap_td_raw_unreg(&td_raw); diff --git a/uprobe/arch/arm64/swap-asm/swap_uprobes.h b/uprobe/arch/arm64/swap-asm/swap_uprobes.h index bfa205b..bca4f84 100644 --- a/uprobe/arch/arm64/swap-asm/swap_uprobes.h +++ b/uprobe/arch/arm64/swap-asm/swap_uprobes.h @@ -26,8 +26,9 @@ #include -#define UP_TRAMP_INSN_CNT 2 /* | opcode | ss_bp | */ +#define UP_TRAMP_INSN_CNT 3 /* | opcode | ss_bp | urp_bp | */ #define UPROBES_TRAMP_LEN (UP_TRAMP_INSN_CNT * 4) /* 4 - instruction size */ +#define URP_RET_BREAK_IDX 2 struct uprobe; @@ -127,18 +128,9 @@ static inline unsigned long arch_get_trampoline_addr(struct uprobe *p, return 0; } -static inline void arch_set_orig_ret_addr(unsigned long orig_ret_addr, - struct pt_regs *regs) -{ - WARN(1, "not implemented"); /* FIXME: to implement */ -} - -static inline int arch_prepare_uretprobe(struct uretprobe_instance *ri, - struct pt_regs *regs) -{ - WARN(1, "not implemented"); /* FIXME: to implement */ - return 0; -} +void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs); +int arch_prepare_uretprobe(struct uretprobe_instance *ri, + struct pt_regs *regs); static inline int arch_opcode_analysis_uretprobe(struct uretprobe *rp) {