From: Vyacheslav Cherkashin Date: Fri, 16 Aug 2013 17:55:03 +0000 (+0400) Subject: [IMPROVE] handling '__switch_to' retprobe X-Git-Tag: Tizen_SDK_2.3~314 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7296a44875c0571a28a233a57b82128d63c2e7b6;p=kernel%2Fswap-modules.git [IMPROVE] handling '__switch_to' retprobe --- diff --git a/kprobe/arch/asm-arm/dbi_kprobes.c b/kprobe/arch/asm-arm/dbi_kprobes.c index 399df62..df16592 100644 --- a/kprobe/arch/asm-arm/dbi_kprobes.c +++ b/kprobe/arch/asm-arm/dbi_kprobes.c @@ -357,11 +357,6 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) entry_point_t entry = (entry_point_t)jp->entry; pre_entry = (kprobe_pre_entry_handler_t)jp->pre_entry; - if (((unsigned long)p->addr == sched_addr) && sched_rp) { - struct thread_info *tinfo = (struct thread_info *)regs->ARM_r2; - patch_suspended_task(sched_rp, tinfo->task, regs); - } - if (pre_entry) { p->ss_addr = (void *)pre_entry (jp->priv_arg, regs); } @@ -413,11 +408,25 @@ void __naked kretprobe_trampoline(void) void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) { - ri->ret_addr = (kprobe_opcode_t *)regs->ARM_lr; - ri->sp = (kprobe_opcode_t *)regs->ARM_sp; + unsigned long *ptr_ret_addr; + + /* for __switch_to probe */ + if ((unsigned long)ri->rp->kp.addr == sched_addr) { + struct thread_info *tinfo = (struct thread_info *)regs->ARM_r2; + + ptr_ret_addr = (unsigned long *)&tinfo->cpu_context.pc; + ri->sp = NULL; + ri->task = tinfo->task; + } else { + ptr_ret_addr = (unsigned long *)®s->ARM_lr; + ri->sp = (unsigned long *)regs->ARM_sp; + } + + /* Save the return address */ + ri->ret_addr = (unsigned long *)*ptr_ret_addr; /* Replace the return addr with trampoline addr */ - regs->ARM_lr = (unsigned long)&kretprobe_trampoline; + *ptr_ret_addr = (unsigned long)&kretprobe_trampoline; } void swap_register_undef_hook(struct undef_hook *hook) diff --git a/kprobe/arch/asm-arm/dbi_kprobes.h b/kprobe/arch/asm-arm/dbi_kprobes.h index 013e85f..b22f728 100644 --- a/kprobe/arch/asm-arm/dbi_kprobes.h +++ b/kprobe/arch/asm-arm/dbi_kprobes.h @@ -68,12 +68,6 @@ struct prev_kprobe { unsigned long status; }; -static inline unsigned long *arch_get_patch_addr(struct task_struct *p, - struct pt_regs *regs) -{ - return &task_thread_info(p)->cpu_context.pc; -} - static inline unsigned long arch_get_task_pc(struct task_struct *p) { return task_thread_info(p)->cpu_context.pc; diff --git a/kprobe/arch/asm-x86/dbi_kprobes.c b/kprobe/arch/asm-x86/dbi_kprobes.c index 2353ff9..5993561 100644 --- a/kprobe/arch/asm-x86/dbi_kprobes.c +++ b/kprobe/arch/asm-x86/dbi_kprobes.c @@ -521,12 +521,6 @@ int setjmp_pre_handler (struct kprobe *p, struct pt_regs *regs) pre_entry = (kprobe_pre_entry_handler_t) jp->pre_entry; entry = (entry_point_t) jp->entry; - /* handle __switch_to probe */ - if ((p->addr == sched_addr) && sched_rp) { - /* FIXME: Actually 2nd parameter is not used for x86 */ - patch_suspended_task(sched_rp, (struct task_struct *)regs->dx, regs); - } - kcb->jprobe_saved_regs = *regs; kcb->jprobe_saved_esp = ®s->EREG(sp); addr = (unsigned long)(kcb->jprobe_saved_esp); @@ -867,12 +861,23 @@ static __used void *trampoline_probe_handler_x86(struct pt_regs *regs) void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) { - unsigned long *sara = (unsigned long *)®s->EREG(sp); - ri->ret_addr = (kprobe_opcode_t *)*sara; - ri->sp = ®s->EREG(sp); + unsigned long *ptr_ret_addr; + + /* for __switch_to probe */ + if ((unsigned long)ri->rp->kp.addr == sched_addr) { + ptr_ret_addr = (unsigned long *)kernel_stack_pointer(regs); + ri->sp = NULL; + ri->task = (struct task_struct *)regs->dx; + } else { + ptr_ret_addr = (unsigned long *)®s->sp; + ri->sp = ®s->sp; + } + + /* Save the return address */ + ri->ret_addr = (unsigned long *)*ptr_ret_addr; /* Replace the return addr with trampoline addr */ - *sara = (unsigned long)&kretprobe_trampoline; + *ptr_ret_addr = (unsigned long)&kretprobe_trampoline; } int arch_init_module_deps() diff --git a/kprobe/arch/asm-x86/dbi_kprobes.h b/kprobe/arch/asm-x86/dbi_kprobes.h index 52c7f84..8463020 100644 --- a/kprobe/arch/asm-x86/dbi_kprobes.h +++ b/kprobe/arch/asm-x86/dbi_kprobes.h @@ -91,12 +91,6 @@ typedef u8 kprobe_opcode_t; #define KPROBES_TRAMP_LEN MAX_INSN_SIZE #define KPROBES_TRAMP_INSN_IDX 0 -static inline unsigned long *arch_get_patch_addr(struct task_struct *p, - struct pt_regs *regs) -{ - return (unsigned long *)kernel_stack_pointer(regs); -} - static inline unsigned long arch_get_task_pc(struct task_struct *p) { /* FIXME: Not implemented yet */ diff --git a/kprobe/dbi_kprobes.c b/kprobe/dbi_kprobes.c index e078166..3fa8499 100644 --- a/kprobe/dbi_kprobes.c +++ b/kprobe/dbi_kprobes.c @@ -723,8 +723,6 @@ int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) return (int)orig_ret_address; } -struct kretprobe *sched_rp; - #define SCHED_RP_NR 200 #define COMMON_RP_NR 10 @@ -775,10 +773,7 @@ int dbi_register_kretprobe(struct kretprobe *rp) rp->kp.break_handler = NULL; /* Pre-allocate memory for max kretprobe instances */ - if ((unsigned long)rp->kp.addr == sched_addr) { - rp->maxactive = SCHED_RP_NR;//max (100, 2 * NR_CPUS); - rp->kp.pre_handler = NULL; //not needed for __switch_to - } else if ((unsigned long)rp->kp.addr == exit_addr) { + if ((unsigned long)rp->kp.addr == exit_addr) { rp->kp.pre_handler = NULL; //not needed for do_exit rp->maxactive = 0; } else if ((unsigned long)rp->kp.addr == do_group_exit_addr) { @@ -816,9 +811,6 @@ int dbi_register_kretprobe(struct kretprobe *rp) free_rp_inst(rp); DBPRINTF ("addr=%p, *addr=[%lx %lx %lx]", rp->kp.addr, (unsigned long) (*(rp->kp.addr)), (unsigned long) (*(rp->kp.addr + 1)), (unsigned long) (*(rp->kp.addr + 2))); - if ((unsigned long)rp->kp.addr == sched_addr) { - sched_rp = rp; - } return ret; } @@ -835,9 +827,6 @@ void dbi_unregister_kretprobe(struct kretprobe *rp) /* No race here */ spin_lock_irqsave(&kretprobe_lock, flags); - if ((unsigned long)rp->kp.addr == sched_addr) - sched_rp = NULL; - while ((ri = get_used_rp_inst (rp)) != NULL) { if (!dbi_disarm_krp_inst(ri)) { printk("%s (%d/%d): cannot disarm krp instance (%08lx)\n", @@ -881,20 +870,6 @@ struct kretprobe *clone_kretprobe(struct kretprobe *rp) } EXPORT_SYMBOL_GPL(clone_kretprobe); -static void inline set_task_trampoline(unsigned long *patch_addr, - struct kretprobe_instance *ri, - unsigned long tramp_addr) -{ - unsigned long pc = *patch_addr; - if (pc == tramp_addr) - panic("[%d] %s (%d/%d): pc = %08lx --- [%d] %s (%d/%d)\n", - task_cpu(ri->task), ri->task->comm, ri->task->tgid, - ri->task->pid, pc, task_cpu(current), current->comm, - current->tgid, current->pid); - ri->ret_addr = (kprobe_opcode_t *)pc; - *patch_addr = tramp_addr; -} - static void inline rm_task_trampoline(struct task_struct *p, struct kretprobe_instance *ri) { arch_set_task_pc(p, (unsigned long)ri->ret_addr); @@ -952,32 +927,6 @@ static int dbi_disarm_krp_inst(struct kretprobe_instance *ri) return retval; } -int patch_suspended_task(struct kretprobe *rp, - struct task_struct *task, - struct pt_regs *regs) -{ - struct kretprobe_instance *ri; - unsigned long flags; - kprobe_opcode_t *tramp = (kprobe_opcode_t *)&kretprobe_trampoline; - unsigned long *patch_addr; - - spin_lock_irqsave(&kretprobe_lock, flags); - - ri = get_free_rp_inst(rp); - if (!ri) - return -ENOMEM; - - ri->rp = rp; - ri->task = task; - ri->sp = NULL; - patch_addr = arch_get_patch_addr(task, regs); - set_task_trampoline(patch_addr, ri, (unsigned long)tramp); - add_rp_inst(ri); - - spin_unlock_irqrestore(&kretprobe_lock, flags); - return 0; -} - static int init_module_deps(void) { int ret; diff --git a/kprobe/dbi_kprobes.h b/kprobe/dbi_kprobes.h index 460375a..7622740 100644 --- a/kprobe/dbi_kprobes.h +++ b/kprobe/dbi_kprobes.h @@ -284,7 +284,6 @@ extern spinlock_t kretprobe_lock; extern struct hlist_head kprobe_table[KPROBE_TABLE_SIZE]; //extern struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; extern atomic_t kprobe_count; -extern struct kretprobe *sched_rp; extern unsigned long sched_addr; struct kprobe *kprobe_running (void); @@ -292,9 +291,6 @@ void reset_current_kprobe (void); struct kprobe_ctlblk *get_kprobe_ctlblk (void); void prepare_singlestep(struct kprobe *p, struct pt_regs *regs); -int patch_suspended_task(struct kretprobe *rp, - struct task_struct *task, - struct pt_regs *regs); #endif /* _DBI_KPROBES_H */