kprobes: add (un)register_jprobes for batch registration
authorMasami Hiramatsu <mhiramat@redhat.com>
Mon, 28 Apr 2008 09:14:29 +0000 (02:14 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 28 Apr 2008 15:58:32 +0000 (08:58 -0700)
Introduce unregister_/register_jprobes() for jprobe batch registration.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Jim Keniston <jkenisto@us.ibm.com>
Cc: Prasanna S Panchamukhi <prasanna@in.ibm.com>
Cc: Shaohua Li <shaohua.li@intel.com>
Cc: David Miller <davem@davemloft.net>
Cc: "Frank Ch. Eigler" <fche@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
include/linux/kprobes.h
kernel/kprobes.c

index 94c855a..1036631 100644 (file)
@@ -240,6 +240,8 @@ int setjmp_pre_handler(struct kprobe *, struct pt_regs *);
 int longjmp_break_handler(struct kprobe *, struct pt_regs *);
 int register_jprobe(struct jprobe *p);
 void unregister_jprobe(struct jprobe *p);
 int longjmp_break_handler(struct kprobe *, struct pt_regs *);
 int register_jprobe(struct jprobe *p);
 void unregister_jprobe(struct jprobe *p);
+int register_jprobes(struct jprobe **jps, int num);
+void unregister_jprobes(struct jprobe **jps, int num);
 void jprobe_return(void);
 unsigned long arch_deref_entry_point(void *);
 
 void jprobe_return(void);
 unsigned long arch_deref_entry_point(void *);
 
@@ -279,9 +281,16 @@ static inline int register_jprobe(struct jprobe *p)
 {
        return -ENOSYS;
 }
 {
        return -ENOSYS;
 }
+static inline int register_jprobes(struct jprobe **jps, int num)
+{
+       return -ENOSYS;
+}
 static inline void unregister_jprobe(struct jprobe *p)
 {
 }
 static inline void unregister_jprobe(struct jprobe *p)
 {
 }
+static inline void unregister_jprobes(struct jprobe **jps, int num)
+{
+}
 static inline void jprobe_return(void)
 {
 }
 static inline void jprobe_return(void)
 {
 }
index 5e3144a..1e0250c 100644 (file)
@@ -755,24 +755,69 @@ unsigned long __weak arch_deref_entry_point(void *entry)
        return (unsigned long)entry;
 }
 
        return (unsigned long)entry;
 }
 
-int __kprobes register_jprobe(struct jprobe *jp)
+static int __register_jprobes(struct jprobe **jps, int num,
+       unsigned long called_from)
 {
 {
-       unsigned long addr = arch_deref_entry_point(jp->entry);
+       struct jprobe *jp;
+       int ret = 0, i;
 
 
-       if (!kernel_text_address(addr))
+       if (num <= 0)
                return -EINVAL;
                return -EINVAL;
+       for (i = 0; i < num; i++) {
+               unsigned long addr;
+               jp = jps[i];
+               addr = arch_deref_entry_point(jp->entry);
+
+               if (!kernel_text_address(addr))
+                       ret = -EINVAL;
+               else {
+                       /* Todo: Verify probepoint is a function entry point */
+                       jp->kp.pre_handler = setjmp_pre_handler;
+                       jp->kp.break_handler = longjmp_break_handler;
+                       ret = __register_kprobe(&jp->kp, called_from);
+               }
+               if (ret < 0 && i > 0) {
+                       unregister_jprobes(jps, i);
+                       break;
+               }
+       }
+       return ret;
+}
 
 
-       /* Todo: Verify probepoint is a function entry point */
-       jp->kp.pre_handler = setjmp_pre_handler;
-       jp->kp.break_handler = longjmp_break_handler;
-
-       return __register_kprobe(&jp->kp,
+int __kprobes register_jprobe(struct jprobe *jp)
+{
+       return __register_jprobes(&jp, 1,
                (unsigned long)__builtin_return_address(0));
 }
 
 void __kprobes unregister_jprobe(struct jprobe *jp)
 {
                (unsigned long)__builtin_return_address(0));
 }
 
 void __kprobes unregister_jprobe(struct jprobe *jp)
 {
-       unregister_kprobe(&jp->kp);
+       unregister_jprobes(&jp, 1);
+}
+
+int __kprobes register_jprobes(struct jprobe **jps, int num)
+{
+       return __register_jprobes(jps, num,
+               (unsigned long)__builtin_return_address(0));
+}
+
+void __kprobes unregister_jprobes(struct jprobe **jps, int num)
+{
+       int i;
+
+       if (num <= 0)
+               return;
+       mutex_lock(&kprobe_mutex);
+       for (i = 0; i < num; i++)
+               if (__unregister_kprobe_top(&jps[i]->kp) < 0)
+                       jps[i]->kp.addr = NULL;
+       mutex_unlock(&kprobe_mutex);
+
+       synchronize_sched();
+       for (i = 0; i < num; i++) {
+               if (jps[i]->kp.addr)
+                       __unregister_kprobe_bottom(&jps[i]->kp);
+       }
 }
 
 #ifdef CONFIG_KRETPROBES
 }
 
 #ifdef CONFIG_KRETPROBES
@@ -1236,6 +1281,8 @@ EXPORT_SYMBOL_GPL(register_kprobes);
 EXPORT_SYMBOL_GPL(unregister_kprobes);
 EXPORT_SYMBOL_GPL(register_jprobe);
 EXPORT_SYMBOL_GPL(unregister_jprobe);
 EXPORT_SYMBOL_GPL(unregister_kprobes);
 EXPORT_SYMBOL_GPL(register_jprobe);
 EXPORT_SYMBOL_GPL(unregister_jprobe);
+EXPORT_SYMBOL_GPL(register_jprobes);
+EXPORT_SYMBOL_GPL(unregister_jprobes);
 #ifdef CONFIG_KPROBES
 EXPORT_SYMBOL_GPL(jprobe_return);
 #endif
 #ifdef CONFIG_KPROBES
 EXPORT_SYMBOL_GPL(jprobe_return);
 #endif