linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / kernel / kprobes.c
index 3f57dfd..fef1af8 100644 (file)
 
 static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
 static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
-static atomic_t kprobe_count;
 
-DEFINE_MUTEX(kprobe_mutex);            /* Protects kprobe_table */
+DECLARE_MUTEX(kprobe_mutex);           /* Protects kprobe_table */
 DEFINE_SPINLOCK(kretprobe_lock);       /* Protects kretprobe_inst_table */
 static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL;
 
-static struct notifier_block kprobe_page_fault_nb = {
-       .notifier_call = kprobe_exceptions_notify,
-       .priority = 0x7fffffff /* we need to notified first */
-};
-
 #ifdef __ARCH_WANT_KPROBES_INSN_SLOT
 /*
  * kprobe->ainsn.insn points to the copy of the instruction to be
@@ -329,10 +323,10 @@ struct hlist_head __kprobes *kretprobe_inst_table_head(struct task_struct *tsk)
 }
 
 /*
- * This function is called from finish_task_switch when task tk becomes dead,
- * so that we can recycle any function-return probe instances associated
- * with this task. These left over instances represent probed functions
- * that have been called but will never return.
+ * This function is called from exit_thread or flush_thread when task tk's
+ * stack is being recycled so that we can recycle any function-return probe
+ * instances associated with this task. These left over instances represent
+ * probed functions that have been called but will never return.
  */
 void __kprobes kprobe_flush_task(struct task_struct *tk)
 {
@@ -342,7 +336,7 @@ void __kprobes kprobe_flush_task(struct task_struct *tk)
        unsigned long flags = 0;
 
        spin_lock_irqsave(&kretprobe_lock, flags);
-        head = kretprobe_inst_table_head(tk);
+        head = kretprobe_inst_table_head(current);
         hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
                 if (ri->task == tk)
                         recycle_rp_inst(ri);
@@ -374,15 +368,16 @@ static inline void copy_kprobe(struct kprobe *old_p, struct kprobe *p)
 */
 static int __kprobes add_new_kprobe(struct kprobe *old_p, struct kprobe *p)
 {
+        struct kprobe *kp;
+
        if (p->break_handler) {
-               if (old_p->break_handler)
-                       return -EEXIST;
+               list_for_each_entry_rcu(kp, &old_p->list, list) {
+                       if (kp->break_handler)
+                               return -EEXIST;
+               }
                list_add_tail_rcu(&p->list, &old_p->list);
-               old_p->break_handler = aggr_break_handler;
        } else
                list_add_rcu(&p->list, &old_p->list);
-       if (p->post_handler && !old_p->post_handler)
-               old_p->post_handler = aggr_post_handler;
        return 0;
 }
 
@@ -393,14 +388,11 @@ static int __kprobes add_new_kprobe(struct kprobe *old_p, struct kprobe *p)
 static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p)
 {
        copy_kprobe(p, ap);
-       flush_insn_slot(ap);
        ap->addr = p->addr;
        ap->pre_handler = aggr_pre_handler;
+       ap->post_handler = aggr_post_handler;
        ap->fault_handler = aggr_fault_handler;
-       if (p->post_handler)
-               ap->post_handler = aggr_post_handler;
-       if (p->break_handler)
-               ap->break_handler = aggr_break_handler;
+       ap->break_handler = aggr_break_handler;
 
        INIT_LIST_HEAD(&ap->list);
        list_add_rcu(&p->list, &ap->list);
@@ -468,12 +460,10 @@ static int __kprobes __register_kprobe(struct kprobe *p,
        }
 
        p->nmissed = 0;
-       mutex_lock(&kprobe_mutex);
+       down(&kprobe_mutex);
        old_p = get_kprobe(p->addr);
        if (old_p) {
                ret = register_aggr_kprobe(old_p, p);
-               if (!ret)
-                       atomic_inc(&kprobe_count);
                goto out;
        }
 
@@ -484,14 +474,10 @@ static int __kprobes __register_kprobe(struct kprobe *p,
        hlist_add_head_rcu(&p->hlist,
                       &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);
 
-       if (atomic_add_return(1, &kprobe_count) == \
-                               (ARCH_INACTIVE_KPROBE_COUNT + 1))
-               register_page_fault_notifier(&kprobe_page_fault_nb);
-
        arch_arm_kprobe(p);
 
 out:
-       mutex_unlock(&kprobe_mutex);
+       up(&kprobe_mutex);
 
        if (ret && probed_mod)
                module_put(probed_mod);
@@ -510,10 +496,10 @@ void __kprobes unregister_kprobe(struct kprobe *p)
        struct kprobe *old_p, *list_p;
        int cleanup_p;
 
-       mutex_lock(&kprobe_mutex);
+       down(&kprobe_mutex);
        old_p = get_kprobe(p->addr);
        if (unlikely(!old_p)) {
-               mutex_unlock(&kprobe_mutex);
+               up(&kprobe_mutex);
                return;
        }
        if (p != old_p) {
@@ -521,7 +507,7 @@ void __kprobes unregister_kprobe(struct kprobe *p)
                        if (list_p == p)
                        /* kprobe p is a valid probe */
                                goto valid_p;
-               mutex_unlock(&kprobe_mutex);
+               up(&kprobe_mutex);
                return;
        }
 valid_p:
@@ -537,7 +523,7 @@ valid_p:
                cleanup_p = 0;
        }
 
-       mutex_unlock(&kprobe_mutex);
+       up(&kprobe_mutex);
 
        synchronize_sched();
        if (p->mod_refcounted &&
@@ -550,40 +536,14 @@ valid_p:
                        kfree(old_p);
                }
                arch_remove_kprobe(p);
-       } else {
-               mutex_lock(&kprobe_mutex);
-               if (p->break_handler)
-                       old_p->break_handler = NULL;
-               if (p->post_handler){
-                       list_for_each_entry_rcu(list_p, &old_p->list, list){
-                               if (list_p->post_handler){
-                                       cleanup_p = 2;
-                                       break;
-                               }
-                       }
-                       if (cleanup_p == 0)
-                               old_p->post_handler = NULL;
-               }
-               mutex_unlock(&kprobe_mutex);
        }
-
-       /* Call unregister_page_fault_notifier()
-        * if no probes are active
-        */
-       mutex_lock(&kprobe_mutex);
-       if (atomic_add_return(-1, &kprobe_count) == \
-                               ARCH_INACTIVE_KPROBE_COUNT)
-               unregister_page_fault_notifier(&kprobe_page_fault_nb);
-       mutex_unlock(&kprobe_mutex);
-       return;
 }
 
 static struct notifier_block kprobe_exceptions_nb = {
        .notifier_call = kprobe_exceptions_notify,
-       .priority = 0x7fffffff /* we need to be notified first */
+       .priority = 0x7fffffff /* we need to notified first */
 };
 
-
 int __kprobes register_jprobe(struct jprobe *jp)
 {
        /* Todo: Verify probepoint is a function entry point */
@@ -625,9 +585,6 @@ int __kprobes register_kretprobe(struct kretprobe *rp)
        int i;
 
        rp->kp.pre_handler = pre_handler_kretprobe;
-       rp->kp.post_handler = NULL;
-       rp->kp.fault_handler = NULL;
-       rp->kp.break_handler = NULL;
 
        /* Pre-allocate memory for max kretprobe instances */
        if (rp->maxactive <= 0) {
@@ -692,7 +649,6 @@ static int __init init_kprobes(void)
                INIT_HLIST_HEAD(&kprobe_table[i]);
                INIT_HLIST_HEAD(&kretprobe_inst_table[i]);
        }
-       atomic_set(&kprobe_count, 0);
 
        err = arch_init_kprobes();
        if (!err)