aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@redhat.com>2008-04-28 05:14:29 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-28 11:58:32 -0400
commit4a296e07c3a410c09b9155da4c2fa84a07964f38 (patch)
treed6070555a2ddf026a7c8534689b425c0e931dcfe
parent9861668f747895608cea425f8457989d8dd2edf2 (diff)
kprobes: add (un)register_kretprobes for batch registration
Introduce unregister_/register_kretprobes() for kretprobe 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>
-rw-r--r--include/linux/kprobes.h9
-rw-r--r--kernel/kprobes.c108
2 files changed, 97 insertions, 20 deletions
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index 2ba7df645a84..94c855a236ae 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -245,6 +245,8 @@ unsigned long arch_deref_entry_point(void *);
245 245
246int register_kretprobe(struct kretprobe *rp); 246int register_kretprobe(struct kretprobe *rp);
247void unregister_kretprobe(struct kretprobe *rp); 247void unregister_kretprobe(struct kretprobe *rp);
248int register_kretprobes(struct kretprobe **rps, int num);
249void unregister_kretprobes(struct kretprobe **rps, int num);
248 250
249void kprobe_flush_task(struct task_struct *tk); 251void kprobe_flush_task(struct task_struct *tk);
250void recycle_rp_inst(struct kretprobe_instance *ri, struct hlist_head *head); 252void recycle_rp_inst(struct kretprobe_instance *ri, struct hlist_head *head);
@@ -287,9 +289,16 @@ static inline int register_kretprobe(struct kretprobe *rp)
287{ 289{
288 return -ENOSYS; 290 return -ENOSYS;
289} 291}
292static inline int register_kretprobes(struct kretprobe **rps, int num)
293{
294 return -ENOSYS;
295}
290static inline void unregister_kretprobe(struct kretprobe *rp) 296static inline void unregister_kretprobe(struct kretprobe *rp)
291{ 297{
292} 298}
299static inline void unregister_kretprobes(struct kretprobe **rps, int num)
300{
301}
293static inline void kprobe_flush_task(struct task_struct *tk) 302static inline void kprobe_flush_task(struct task_struct *tk)
294{ 303{
295} 304}
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 76275fc025a5..5e3144ad9b64 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -429,6 +429,21 @@ static inline void free_rp_inst(struct kretprobe *rp)
429 } 429 }
430} 430}
431 431
432static void __kprobes cleanup_rp_inst(struct kretprobe *rp)
433{
434 unsigned long flags;
435 struct kretprobe_instance *ri;
436 struct hlist_node *pos, *next;
437 /* No race here */
438 spin_lock_irqsave(&kretprobe_lock, flags);
439 hlist_for_each_entry_safe(ri, pos, next, &rp->used_instances, uflist) {
440 ri->rp = NULL;
441 hlist_del(&ri->uflist);
442 }
443 spin_unlock_irqrestore(&kretprobe_lock, flags);
444 free_rp_inst(rp);
445}
446
432/* 447/*
433 * Keep all fields in the kprobe consistent 448 * Keep all fields in the kprobe consistent
434 */ 449 */
@@ -798,7 +813,8 @@ static int __kprobes pre_handler_kretprobe(struct kprobe *p,
798 return 0; 813 return 0;
799} 814}
800 815
801int __kprobes register_kretprobe(struct kretprobe *rp) 816static int __kprobes __register_kretprobe(struct kretprobe *rp,
817 unsigned long called_from)
802{ 818{
803 int ret = 0; 819 int ret = 0;
804 struct kretprobe_instance *inst; 820 struct kretprobe_instance *inst;
@@ -844,43 +860,93 @@ int __kprobes register_kretprobe(struct kretprobe *rp)
844 860
845 rp->nmissed = 0; 861 rp->nmissed = 0;
846 /* Establish function entry probe point */ 862 /* Establish function entry probe point */
847 if ((ret = __register_kprobe(&rp->kp, 863 ret = __register_kprobe(&rp->kp, called_from);
848 (unsigned long)__builtin_return_address(0))) != 0) 864 if (ret != 0)
849 free_rp_inst(rp); 865 free_rp_inst(rp);
850 return ret; 866 return ret;
851} 867}
852 868
869static int __register_kretprobes(struct kretprobe **rps, int num,
870 unsigned long called_from)
871{
872 int ret = 0, i;
873
874 if (num <= 0)
875 return -EINVAL;
876 for (i = 0; i < num; i++) {
877 ret = __register_kretprobe(rps[i], called_from);
878 if (ret < 0 && i > 0) {
879 unregister_kretprobes(rps, i);
880 break;
881 }
882 }
883 return ret;
884}
885
886int __kprobes register_kretprobe(struct kretprobe *rp)
887{
888 return __register_kretprobes(&rp, 1,
889 (unsigned long)__builtin_return_address(0));
890}
891
892void __kprobes unregister_kretprobe(struct kretprobe *rp)
893{
894 unregister_kretprobes(&rp, 1);
895}
896
897int __kprobes register_kretprobes(struct kretprobe **rps, int num)
898{
899 return __register_kretprobes(rps, num,
900 (unsigned long)__builtin_return_address(0));
901}
902
903void __kprobes unregister_kretprobes(struct kretprobe **rps, int num)
904{
905 int i;
906
907 if (num <= 0)
908 return;
909 mutex_lock(&kprobe_mutex);
910 for (i = 0; i < num; i++)
911 if (__unregister_kprobe_top(&rps[i]->kp) < 0)
912 rps[i]->kp.addr = NULL;
913 mutex_unlock(&kprobe_mutex);
914
915 synchronize_sched();
916 for (i = 0; i < num; i++) {
917 if (rps[i]->kp.addr) {
918 __unregister_kprobe_bottom(&rps[i]->kp);
919 cleanup_rp_inst(rps[i]);
920 }
921 }
922}
923
853#else /* CONFIG_KRETPROBES */ 924#else /* CONFIG_KRETPROBES */
854int __kprobes register_kretprobe(struct kretprobe *rp) 925int __kprobes register_kretprobe(struct kretprobe *rp)
855{ 926{
856 return -ENOSYS; 927 return -ENOSYS;
857} 928}
858 929
859static int __kprobes pre_handler_kretprobe(struct kprobe *p, 930int __kprobes register_kretprobes(struct kretprobe **rps, int num)
860 struct pt_regs *regs)
861{ 931{
862 return 0; 932 return -ENOSYS;
863} 933}
864#endif /* CONFIG_KRETPROBES */
865
866void __kprobes unregister_kretprobe(struct kretprobe *rp) 934void __kprobes unregister_kretprobe(struct kretprobe *rp)
867{ 935{
868 unsigned long flags; 936}
869 struct kretprobe_instance *ri;
870 struct hlist_node *pos, *next;
871 937
872 unregister_kprobe(&rp->kp); 938void __kprobes unregister_kretprobes(struct kretprobe **rps, int num)
939{
940}
873 941
874 /* No race here */ 942static int __kprobes pre_handler_kretprobe(struct kprobe *p,
875 spin_lock_irqsave(&kretprobe_lock, flags); 943 struct pt_regs *regs)
876 hlist_for_each_entry_safe(ri, pos, next, &rp->used_instances, uflist) { 944{
877 ri->rp = NULL; 945 return 0;
878 hlist_del(&ri->uflist);
879 }
880 spin_unlock_irqrestore(&kretprobe_lock, flags);
881 free_rp_inst(rp);
882} 946}
883 947
948#endif /* CONFIG_KRETPROBES */
949
884static int __init init_kprobes(void) 950static int __init init_kprobes(void)
885{ 951{
886 int i, err = 0; 952 int i, err = 0;
@@ -1177,4 +1243,6 @@ EXPORT_SYMBOL_GPL(jprobe_return);
1177#ifdef CONFIG_KPROBES 1243#ifdef CONFIG_KPROBES
1178EXPORT_SYMBOL_GPL(register_kretprobe); 1244EXPORT_SYMBOL_GPL(register_kretprobe);
1179EXPORT_SYMBOL_GPL(unregister_kretprobe); 1245EXPORT_SYMBOL_GPL(unregister_kretprobe);
1246EXPORT_SYMBOL_GPL(register_kretprobes);
1247EXPORT_SYMBOL_GPL(unregister_kretprobes);
1180#endif 1248#endif