]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86_64/kernel/kprobes.c
Pull ec into release branch
[linux-2.6-omap-h63xx.git] / arch / x86_64 / kernel / kprobes.c
index d04f0ab2ff4037d0c69343c2891d615b06be8375..a30e004682e2dc60fe81a7e1caf007fbbcf314a7 100644 (file)
 #include <linux/slab.h>
 #include <linux/preempt.h>
 #include <linux/module.h>
+#include <linux/kdebug.h>
 
-#include <asm/cacheflush.h>
 #include <asm/pgtable.h>
-#include <asm/kdebug.h>
 #include <asm/uaccess.h>
+#include <asm/alternative.h>
 
 void jprobe_return_end(void);
 static void __kprobes arch_copy_kprobe(struct kprobe *p);
@@ -209,22 +209,18 @@ static void __kprobes arch_copy_kprobe(struct kprobe *p)
 
 void __kprobes arch_arm_kprobe(struct kprobe *p)
 {
-       *p->addr = BREAKPOINT_INSTRUCTION;
-       flush_icache_range((unsigned long) p->addr,
-                          (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+       text_poke(p->addr, ((unsigned char []){BREAKPOINT_INSTRUCTION}), 1);
 }
 
 void __kprobes arch_disarm_kprobe(struct kprobe *p)
 {
-       *p->addr = p->opcode;
-       flush_icache_range((unsigned long) p->addr,
-                          (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+       text_poke(p->addr, &p->opcode, 1);
 }
 
 void __kprobes arch_remove_kprobe(struct kprobe *p)
 {
        mutex_lock(&kprobe_mutex);
-       free_insn_slot(p->ainsn.insn);
+       free_insn_slot(p->ainsn.insn, 0);
        mutex_unlock(&kprobe_mutex);
 }
 
@@ -266,23 +262,14 @@ static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
 }
 
 /* Called with kretprobe_lock held */
-void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
                                      struct pt_regs *regs)
 {
        unsigned long *sara = (unsigned long *)regs->rsp;
-       struct kretprobe_instance *ri;
 
-       if ((ri = get_free_rp_inst(rp)) != NULL) {
-               ri->rp = rp;
-               ri->task = current;
-               ri->ret_addr = (kprobe_opcode_t *) *sara;
-
-               /* Replace the return addr with trampoline addr */
-               *sara = (unsigned long) &kretprobe_trampoline;
-               add_rp_inst(ri);
-       } else {
-               rp->nmissed++;
-       }
+       ri->ret_addr = (kprobe_opcode_t *) *sara;
+       /* Replace the return addr with trampoline addr */
+       *sara = (unsigned long) &kretprobe_trampoline;
 }
 
 int __kprobes kprobe_handler(struct pt_regs *regs)
@@ -405,11 +392,12 @@ no_kprobe:
 int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 {
        struct kretprobe_instance *ri = NULL;
-       struct hlist_head *head;
+       struct hlist_head *head, empty_rp;
        struct hlist_node *node, *tmp;
        unsigned long flags, orig_ret_address = 0;
        unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
 
+       INIT_HLIST_HEAD(&empty_rp);
        spin_lock_irqsave(&kretprobe_lock, flags);
        head = kretprobe_inst_table_head(current);
 
@@ -435,7 +423,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
                        ri->rp->handler(ri, regs);
 
                orig_ret_address = (unsigned long)ri->ret_addr;
-               recycle_rp_inst(ri);
+               recycle_rp_inst(ri, &empty_rp);
 
                if (orig_ret_address != trampoline_address)
                        /*
@@ -446,13 +434,17 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
                        break;
        }
 
-       BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
+       kretprobe_assert(ri, orig_ret_address, trampoline_address);
        regs->rip = orig_ret_address;
 
        reset_current_kprobe();
        spin_unlock_irqrestore(&kretprobe_lock, flags);
        preempt_enable_no_resched();
 
+       hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
+               hlist_del(&ri->hlist);
+               kfree(ri);
+       }
        /*
         * By returning a non-zero value, we are telling
         * kprobe_handler() that we don't want the post_handler
@@ -747,3 +739,11 @@ int __init arch_init_kprobes(void)
 {
        return register_kprobe(&trampoline_p);
 }
+
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+       if (p->addr == (kprobe_opcode_t *)&kretprobe_trampoline)
+               return 1;
+
+       return 0;
+}