From: Vyacheslav Cherkashin Date: Tue, 20 Aug 2013 10:39:29 +0000 (+0400) Subject: Merge commit 'd307e458a' into kernel X-Git-Tag: Tizen_SDK_2.3~304 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9bfad7f95d4e7db1dded045415d5f90ffa8467b3;p=kernel%2Fswap-modules.git Merge commit 'd307e458a' into kernel Conflicts: src/modules/kprobe/arch/asm-arm/dbi_kprobes.c src/modules/kprobe/dbi_insn_slots.c src/modules/kprobe/dbi_kprobes.c src/modules/kprobe/dbi_kprobes.h --- 9bfad7f95d4e7db1dded045415d5f90ffa8467b3 diff --cc kprobe/arch/asm-arm/dbi_kprobes.c index 91af351,5d876bc..e8468ba --- a/kprobe/arch/asm-arm/dbi_kprobes.c +++ b/kprobe/arch/asm-arm/dbi_kprobes.c @@@ -372,24 -1399,246 +372,36 @@@ void dbi_jprobe_return (void { } -void dbi_arch_uprobe_return (void) -{ -} - int longjmp_break_handler (struct kprobe *p, struct pt_regs *regs) { -# ifndef REENTER - //kprobe_opcode_t insn = BREAKPOINT_INSTRUCTION; - kprobe_opcode_t insns[2]; - - if (p->pid) - { - insns[0] = BREAKPOINT_INSTRUCTION; - insns[1] = p->opcode; - //p->opcode = *p->addr; - if (read_proc_vm_atomic (current, (unsigned long) (p->addr), &(p->opcode), sizeof (p->opcode)) < sizeof (p->opcode)) - { - printk ("ERROR[%lu]: failed to read vm of proc %s/%u addr %p.", nCount, current->comm, current->pid, p->addr); - return -1; - } - //*p->addr = BREAKPOINT_INSTRUCTION; - //*(p->addr+1) = p->opcode; - if (write_proc_vm_atomic (current, (unsigned long) (p->addr), insns, sizeof (insns)) < sizeof (insns)) - { - printk ("ERROR[%lu]: failed to write vm of proc %s/%u addr %p.", nCount, current->comm, current->pid, p->addr); - return -1; - } - } - else - { - DBPRINTF ("p->opcode = 0x%lx *p->addr = 0x%lx p->addr = 0x%p\n", p->opcode, *p->addr, p->addr); - *(p->addr + 1) = p->opcode; - p->opcode = *p->addr; - *p->addr = BREAKPOINT_INSTRUCTION; - - flush_icache_range ((unsigned int) p->addr, (unsigned int) (((unsigned int) p->addr) + (sizeof (kprobe_opcode_t) * 2))); - } - - reset_current_kprobe(); - -#endif //REENTER - return 0; } +EXPORT_SYMBOL_GPL(longjmp_break_handler); + #ifdef CONFIG_STRICT_MEMORY_RWX + extern void mem_text_write_kernel_word(unsigned long *addr, unsigned long word); + #endif + -void arch_arm_kprobe (struct kprobe *p) +void arch_arm_kprobe(struct kprobe *p) { + #ifdef CONFIG_STRICT_MEMORY_RWX + mem_text_write_kernel_word(p->addr, BREAKPOINT_INSTRUCTION); + #else *p->addr = BREAKPOINT_INSTRUCTION; - flush_icache_range ((unsigned long) p->addr, (unsigned long) p->addr + sizeof (kprobe_opcode_t)); + flush_icache_range((unsigned long)p->addr, (unsigned long)p->addr + sizeof(kprobe_opcode_t)); + #endif } -void arch_disarm_kprobe (struct kprobe *p) +void arch_disarm_kprobe(struct kprobe *p) { + #ifdef CONFIG_STRICT_MEMORY_RWX + mem_text_write_kernel_word(p->addr, p->opcode); + #else *p->addr = p->opcode; - flush_icache_range ((unsigned long) p->addr, (unsigned long) p->addr + sizeof (kprobe_opcode_t)); + flush_icache_range((unsigned long)p->addr, (unsigned long)p->addr + sizeof(kprobe_opcode_t)); + #endif } - -int trampoline_probe_handler (struct kprobe *p, struct pt_regs *regs) -{ - struct kretprobe_instance *ri = NULL; - struct hlist_head *head; - struct hlist_node *node, *tmp; - unsigned long flags, orig_ret_address = 0; - unsigned long trampoline_address = (unsigned long) &kretprobe_trampoline; - unsigned long ret = 1; - - struct kretprobe *crp = NULL; - struct kprobe_ctlblk *kcb = get_kprobe_ctlblk (); - - DBPRINTF ("start"); - - if (p && p->tgid){ - // in case of user space retprobe trampoline is at the Nth instruction of US tramp - if (!thumb_mode( regs )) - trampoline_address = (unsigned long)(p->ainsn.insn + UPROBES_TRAMP_RET_BREAK_IDX); - else - trampoline_address = (unsigned long)(p->ainsn.insn) + 0x1b; - } - - spin_lock_irqsave (&kretprobe_lock, flags); - - /* - * We are using different hash keys (current and mm) for finding kernel - * space and user space probes. Kernel space probes can change mm field in - * task_struct. User space probes can be shared between threads of one - * process so they have different current but same mm. - */ - if (p && p->tgid) { - head = kretprobe_inst_table_head(current->mm); - } else { - head = kretprobe_inst_table_head(current); - } - - /* - * It is possible to have multiple instances associated with a given - * task either because an multiple functions in the call path - * have a return probe installed on them, and/or more then one - * return probe was registered for a target function. - * - * We can handle this because: - * - instances are always inserted at the head of the list - * - when multiple return probes are registered for the same - * function, the first instance's ret_addr will point to the - * real return address, and all the rest will point to - * kretprobe_trampoline - */ - swap_hlist_for_each_entry_safe (ri, node, tmp, head, hlist) - { - if (ri->task != current) - /* another task is sharing our hash bucket */ - continue; - if (ri->rp && ri->rp->handler){ - ri->rp->handler (ri, regs, ri->rp->priv_arg); - } - - orig_ret_address = (unsigned long) ri->ret_addr; - recycle_rp_inst (ri); - if (orig_ret_address != trampoline_address) - /* - * This is the real return address. Any other - * instances associated with this task are for - * other calls deeper on the call stack - */ - break; - } - kretprobe_assert (ri, orig_ret_address, trampoline_address); - //BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); - //E.G. Check this code in case of __switch_to function instrumentation -- currently this code generates dump in this case - //if (trampoline_address != (unsigned long) &kretprobe_trampoline){ - //if (ri->rp2) BUG_ON (ri->rp2->kp.tgid == 0); - //if (ri->rp) BUG_ON (ri->rp->kp.tgid == 0); - //else if (ri->rp2) BUG_ON (ri->rp2->kp.tgid == 0); - //} - if ((ri->rp && ri->rp->kp.tgid) || (ri->rp2 && ri->rp2->kp.tgid)) - BUG_ON (trampoline_address == (unsigned long) &kretprobe_trampoline); - - if (p && p->tgid) - regs->uregs[14] = orig_ret_address; - - DBPRINTF ("regs->uregs[14] = 0x%lx\n", regs->uregs[14]); - DBPRINTF ("regs->uregs[15] = 0x%lx\n", regs->uregs[15]); - - if (trampoline_address != (unsigned long) &kretprobe_trampoline) - { - regs->uregs[15] = orig_ret_address; - }else{ - ret = (unsigned long)orig_ret_address; - } - - DBPRINTF ("regs->uregs[15] = 0x%lx\n", regs->uregs[15]); - - if(p){ // ARM, MIPS, X86 user space - if (thumb_mode( regs ) && !(regs->uregs[14] & 0x01)) - { - regs->ARM_cpsr &= 0xFFFFFFDF; - }else{ - if (user_mode( regs ) && (regs->uregs[14] & 0x01)) - { - regs->ARM_cpsr |= 0x20; - } - } - - //TODO: test - enter function, delete us retprobe, exit function - // for user space retprobes only - deferred deletion - - if (trampoline_address != (unsigned long) &kretprobe_trampoline) - { - // if we are not at the end of the list and current retprobe should be disarmed - if (node && ri->rp2) - { - struct hlist_node *current_node = node; - crp = ri->rp2; - /*sprintf(die_msg, "deferred disarm p->addr = %p [%lx %lx %lx]\n", - crp->kp.addr, *kaddrs[0], *kaddrs[1], *kaddrs[2]); - DIE(die_msg, regs); */ - // look for other instances for the same retprobe - swap_hlist_for_each_entry_safe (ri, node, tmp, head, hlist) - { - /* - * Trying to find another retprobe instance associated with - * the same retprobe. - */ - if (ri->rp2 == crp && node != current_node) - break; - } - - if (!node) - { - // if there are no more instances for this retprobe - // delete retprobe - struct kprobe *is_p = &crp->kp; - DBPRINTF ("defered retprobe deletion p->addr = %p", crp->kp.addr); - /* - If there is no any retprobe instances of this retprobe - we can free the resources related to the probe. - */ - if (!(hlist_unhashed(&is_p->is_hlist_arm))) { - hlist_del_rcu(&is_p->is_hlist_arm); - } - if (!(hlist_unhashed(&is_p->is_hlist_thumb))) { - hlist_del_rcu(&is_p->is_hlist_thumb); - } - unregister_uprobe (&crp->kp, current, 1); - kfree (crp); - } - hlist_del(current_node); - } - } - - if (kcb->kprobe_status == KPROBE_REENTER) { - restore_previous_kprobe(kcb); - } else { - reset_current_kprobe(); - } - } - - spin_unlock_irqrestore (&kretprobe_lock, flags); - - /* - * By returning a non-zero value, we are telling - * kprobe_handler() that we don't want the post_handler - * to run (and have re-enabled preemption) - */ - - return ret; -} - void __naked kretprobe_trampoline(void) { __asm__ __volatile__ ( diff --cc kprobe/dbi_kprobes.c index 644657b,3a8b984..0266032 --- a/kprobe/dbi_kprobes.c +++ b/kprobe/dbi_kprobes.c @@@ -83,32 -80,23 +83,46 @@@ struct hlist_head kprobe_table[KPROBE_T static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; atomic_t kprobe_count; +EXPORT_SYMBOL_GPL(kprobe_count); + + -static void *(*module_alloc)(unsigned long size); ++static void *(*module_alloc)(unsigned long size) = NULL; ++static void *(*module_free)(struct module *mod, void *module_region) = NULL; + -void *__wrapper_module_alloc(unsigned long size) ++static void *__wrapper_module_alloc(unsigned long size) + { + return module_alloc(size); + } + -static void *(*module_free)(struct module *mod, void *module_region); - -void *__wrapper_module_free(void *module_region) ++static void *__wrapper_module_free(void *module_region) + { + return module_free(NULL, module_region); + } + +static void *sm_alloc(struct slot_manager *sm) +{ - return kmalloc(PAGE_SIZE, GFP_ATOMIC); ++ return __wrapper_module_alloc(PAGE_SIZE); +} + +static void sm_free(struct slot_manager *sm, void *ptr) +{ - kfree(ptr); ++ __wrapper_module_free(ptr); +} + +static void init_sm() +{ + sm.slot_size = KPROBES_TRAMP_LEN; + sm.alloc = sm_alloc; + sm.free = sm_free; + INIT_HLIST_NODE(&sm.page_list); +} + +static void exit_sm() +{ + /* FIXME: free */ +} -void kretprobe_assert (struct kretprobe_instance *ri, unsigned long orig_ret_address, unsigned long trampoline_address) +void kretprobe_assert(struct kretprobe_instance *ri, unsigned long orig_ret_address, unsigned long trampoline_address) { if (!orig_ret_address || (orig_ret_address == trampoline_address)) { struct task_struct *task; @@@ -842,23 -801,16 +856,22 @@@ static void dbi_unregister_kretprobe_bo { unsigned long flags; struct kretprobe_instance *ri; - struct hlist_node *node; spin_lock_irqsave(&kretprobe_lock, flags); - while ((ri = get_used_rp_inst (rp)) != NULL) { + while ((ri = get_used_rp_inst(rp)) != NULL) { recycle_rp_inst(ri); } - spin_unlock_irqrestore (&kretprobe_lock, flags); - free_rp_inst (rp); + spin_unlock_irqrestore(&kretprobe_lock, flags); + free_rp_inst(rp); +} + +void dbi_unregister_kretprobe(struct kretprobe *rp) +{ + dbi_unregister_kretprobe_top(rp); + dbi_unregister_kretprobe_bottom(rp); } -struct kretprobe * clone_kretprobe (struct kretprobe *rp) +struct kretprobe *clone_kretprobe(struct kretprobe *rp) { struct kprobe *old_p; struct kretprobe *clone = NULL; @@@ -977,22 -946,29 +990,33 @@@ static int __init init_kprobes(void { int i, err = 0; + module_alloc = (void *)swap_ksyms("module_alloc"); + if (!module_alloc) { + printk("module_alloc is not found! Oops.\n"); + return -1; + } + module_free = (void *)swap_ksyms("module_free"); + if (!module_alloc) { + printk("module_free is not found! Oops.\n"); + return -1; + } + + init_sm(); + /* FIXME allocate the probe table, currently defined statically */ /* initialize all list heads */ - for (i = 0; i < KPROBE_TABLE_SIZE; i++) - { - INIT_HLIST_HEAD (&kprobe_table[i]); - INIT_HLIST_HEAD (&kretprobe_inst_table[i]); + for (i = 0; i < KPROBE_TABLE_SIZE; ++i) { + INIT_HLIST_HEAD(&kprobe_table[i]); + INIT_HLIST_HEAD(&kretprobe_inst_table[i]); + } + atomic_set(&kprobe_count, 0); - init_uprobes_insn_slots(i); + err = init_module_deps(); + if (err) { + return err; } - atomic_set (&kprobe_count, 0); - err = arch_init_kprobes (); + err = arch_init_kprobes(); DBPRINTF ("init_kprobes: arch_init_kprobes - %d", err);