Commit 614243181050436785f5a621749a7da2336a7916
Committed by
Steven Rostedt
1 parent
bc81d48d13
Exists in
master
and in
4 other branches
tracing/kprobes: Support module init function probing
To support probing module init functions, kprobe-tracer allows user to define a probe on non-existed function when it is given with a module name. This also enables user to set a probe on a function on a specific module, even if a same name (but different) function is locally defined in another module. The module name must be in the front of function name and separated by a ':'. e.g. btrfs:btrfs_init_sysfs Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Link: http://lkml.kernel.org/r/20110627072656.6528.89970.stgit@fedora15 Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Showing 2 changed files with 143 additions and 30 deletions Side-by-side Diff
Documentation/trace/kprobetrace.txt
... | ... | @@ -22,14 +22,15 @@ |
22 | 22 | |
23 | 23 | Synopsis of kprobe_events |
24 | 24 | ------------------------- |
25 | - p[:[GRP/]EVENT] SYMBOL[+offs]|MEMADDR [FETCHARGS] : Set a probe | |
26 | - r[:[GRP/]EVENT] SYMBOL[+0] [FETCHARGS] : Set a return probe | |
25 | + p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS] : Set a probe | |
26 | + r[:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS] : Set a return probe | |
27 | 27 | -:[GRP/]EVENT : Clear a probe |
28 | 28 | |
29 | 29 | GRP : Group name. If omitted, use "kprobes" for it. |
30 | 30 | EVENT : Event name. If omitted, the event name is generated |
31 | - based on SYMBOL+offs or MEMADDR. | |
32 | - SYMBOL[+offs] : Symbol+offset where the probe is inserted. | |
31 | + based on SYM+offs or MEMADDR. | |
32 | + MOD : Module name which has given SYM. | |
33 | + SYM[+offs] : Symbol+offset where the probe is inserted. | |
33 | 34 | MEMADDR : Address where the probe is inserted. |
34 | 35 | |
35 | 36 | FETCHARGS : Arguments. Each probe can have up to 128 args. |
kernel/trace/trace_kprobe.c
... | ... | @@ -536,6 +536,7 @@ |
536 | 536 | /* Flags for trace_probe */ |
537 | 537 | #define TP_FLAG_TRACE 1 |
538 | 538 | #define TP_FLAG_PROFILE 2 |
539 | +#define TP_FLAG_REGISTERED 4 | |
539 | 540 | |
540 | 541 | struct trace_probe { |
541 | 542 | struct list_head list; |
... | ... | @@ -565,6 +566,39 @@ |
565 | 566 | return tp->symbol ? tp->symbol : "unknown"; |
566 | 567 | } |
567 | 568 | |
569 | +static __kprobes unsigned long trace_probe_offset(struct trace_probe *tp) | |
570 | +{ | |
571 | + return tp->rp.kp.offset; | |
572 | +} | |
573 | + | |
574 | +static __kprobes bool trace_probe_is_enabled(struct trace_probe *tp) | |
575 | +{ | |
576 | + return !!(tp->flags & (TP_FLAG_TRACE | TP_FLAG_PROFILE)); | |
577 | +} | |
578 | + | |
579 | +static __kprobes bool trace_probe_is_registered(struct trace_probe *tp) | |
580 | +{ | |
581 | + return !!(tp->flags & TP_FLAG_REGISTERED); | |
582 | +} | |
583 | + | |
584 | +static __kprobes bool trace_probe_has_gone(struct trace_probe *tp) | |
585 | +{ | |
586 | + return !!(kprobe_gone(&tp->rp.kp)); | |
587 | +} | |
588 | + | |
589 | +static __kprobes bool trace_probe_within_module(struct trace_probe *tp, | |
590 | + struct module *mod) | |
591 | +{ | |
592 | + int len = strlen(mod->name); | |
593 | + const char *name = trace_probe_symbol(tp); | |
594 | + return strncmp(mod->name, name, len) == 0 && name[len] == ':'; | |
595 | +} | |
596 | + | |
597 | +static __kprobes bool trace_probe_is_on_module(struct trace_probe *tp) | |
598 | +{ | |
599 | + return !!strchr(trace_probe_symbol(tp), ':'); | |
600 | +} | |
601 | + | |
568 | 602 | static int register_probe_event(struct trace_probe *tp); |
569 | 603 | static void unregister_probe_event(struct trace_probe *tp); |
570 | 604 | |
... | ... | @@ -689,7 +723,8 @@ |
689 | 723 | int ret = 0; |
690 | 724 | |
691 | 725 | tp->flags |= flag; |
692 | - if (tp->flags & (TP_FLAG_TRACE | TP_FLAG_PROFILE)) { | |
726 | + if (trace_probe_is_enabled(tp) && trace_probe_is_registered(tp) && | |
727 | + !trace_probe_has_gone(tp)) { | |
693 | 728 | if (trace_probe_is_return(tp)) |
694 | 729 | ret = enable_kretprobe(&tp->rp); |
695 | 730 | else |
... | ... | @@ -703,7 +738,7 @@ |
703 | 738 | static void disable_trace_probe(struct trace_probe *tp, int flag) |
704 | 739 | { |
705 | 740 | tp->flags &= ~flag; |
706 | - if (!(tp->flags & (TP_FLAG_TRACE | TP_FLAG_PROFILE))) { | |
741 | + if (!trace_probe_is_enabled(tp) && trace_probe_is_registered(tp)) { | |
707 | 742 | if (trace_probe_is_return(tp)) |
708 | 743 | disable_kretprobe(&tp->rp); |
709 | 744 | else |
710 | 745 | |
711 | 746 | |
712 | 747 | |
... | ... | @@ -711,13 +746,64 @@ |
711 | 746 | } |
712 | 747 | } |
713 | 748 | |
714 | -/* Unregister a trace_probe and probe_event: call with locking probe_lock */ | |
715 | -static void unregister_trace_probe(struct trace_probe *tp) | |
749 | +/* Internal register function - just handle k*probes and flags */ | |
750 | +static int __register_trace_probe(struct trace_probe *tp) | |
716 | 751 | { |
752 | + int ret; | |
753 | + | |
754 | + if (trace_probe_is_registered(tp)) | |
755 | + return -EINVAL; | |
756 | + | |
757 | + /* Set/clear disabled flag according to tp->flag */ | |
758 | + if (trace_probe_is_enabled(tp)) | |
759 | + tp->rp.kp.flags &= ~KPROBE_FLAG_DISABLED; | |
760 | + else | |
761 | + tp->rp.kp.flags |= KPROBE_FLAG_DISABLED; | |
762 | + | |
717 | 763 | if (trace_probe_is_return(tp)) |
718 | - unregister_kretprobe(&tp->rp); | |
764 | + ret = register_kretprobe(&tp->rp); | |
719 | 765 | else |
720 | - unregister_kprobe(&tp->rp.kp); | |
766 | + ret = register_kprobe(&tp->rp.kp); | |
767 | + | |
768 | + if (ret == 0) | |
769 | + tp->flags |= TP_FLAG_REGISTERED; | |
770 | + else { | |
771 | + pr_warning("Could not insert probe at %s+%lu: %d\n", | |
772 | + trace_probe_symbol(tp), trace_probe_offset(tp), ret); | |
773 | + if (ret == -ENOENT && trace_probe_is_on_module(tp)) { | |
774 | + pr_warning("This probe might be able to register after" | |
775 | + "target module is loaded. Continue.\n"); | |
776 | + ret = 0; | |
777 | + } else if (ret == -EILSEQ) { | |
778 | + pr_warning("Probing address(0x%p) is not an " | |
779 | + "instruction boundary.\n", | |
780 | + tp->rp.kp.addr); | |
781 | + ret = -EINVAL; | |
782 | + } | |
783 | + } | |
784 | + | |
785 | + return ret; | |
786 | +} | |
787 | + | |
788 | +/* Internal unregister function - just handle k*probes and flags */ | |
789 | +static void __unregister_trace_probe(struct trace_probe *tp) | |
790 | +{ | |
791 | + if (trace_probe_is_registered(tp)) { | |
792 | + if (trace_probe_is_return(tp)) | |
793 | + unregister_kretprobe(&tp->rp); | |
794 | + else | |
795 | + unregister_kprobe(&tp->rp.kp); | |
796 | + tp->flags &= ~TP_FLAG_REGISTERED; | |
797 | + /* Cleanup kprobe for reuse */ | |
798 | + if (tp->rp.kp.symbol_name) | |
799 | + tp->rp.kp.addr = NULL; | |
800 | + } | |
801 | +} | |
802 | + | |
803 | +/* Unregister a trace_probe and probe_event: call with locking probe_lock */ | |
804 | +static void unregister_trace_probe(struct trace_probe *tp) | |
805 | +{ | |
806 | + __unregister_trace_probe(tp); | |
721 | 807 | list_del(&tp->list); |
722 | 808 | unregister_probe_event(tp); |
723 | 809 | } |
724 | 810 | |
725 | 811 | |
726 | 812 | |
727 | 813 | |
728 | 814 | |
729 | 815 | |
... | ... | @@ -730,41 +816,65 @@ |
730 | 816 | |
731 | 817 | mutex_lock(&probe_lock); |
732 | 818 | |
733 | - /* register as an event */ | |
819 | + /* Delete old (same name) event if exist */ | |
734 | 820 | old_tp = find_trace_probe(tp->call.name, tp->call.class->system); |
735 | 821 | if (old_tp) { |
736 | - /* delete old event */ | |
737 | 822 | unregister_trace_probe(old_tp); |
738 | 823 | free_trace_probe(old_tp); |
739 | 824 | } |
825 | + | |
826 | + /* Register new event */ | |
740 | 827 | ret = register_probe_event(tp); |
741 | 828 | if (ret) { |
742 | 829 | pr_warning("Failed to register probe event(%d)\n", ret); |
743 | 830 | goto end; |
744 | 831 | } |
745 | 832 | |
746 | - tp->rp.kp.flags |= KPROBE_FLAG_DISABLED; | |
747 | - if (trace_probe_is_return(tp)) | |
748 | - ret = register_kretprobe(&tp->rp); | |
749 | - else | |
750 | - ret = register_kprobe(&tp->rp.kp); | |
751 | - | |
752 | - if (ret) { | |
753 | - pr_warning("Could not insert probe(%d)\n", ret); | |
754 | - if (ret == -EILSEQ) { | |
755 | - pr_warning("Probing address(0x%p) is not an " | |
756 | - "instruction boundary.\n", | |
757 | - tp->rp.kp.addr); | |
758 | - ret = -EINVAL; | |
759 | - } | |
833 | + /* Register k*probe */ | |
834 | + ret = __register_trace_probe(tp); | |
835 | + if (ret < 0) | |
760 | 836 | unregister_probe_event(tp); |
761 | - } else | |
837 | + else | |
762 | 838 | list_add_tail(&tp->list, &probe_list); |
839 | + | |
763 | 840 | end: |
764 | 841 | mutex_unlock(&probe_lock); |
765 | 842 | return ret; |
766 | 843 | } |
767 | 844 | |
845 | +/* Module notifier call back, checking event on the module */ | |
846 | +static int trace_probe_module_callback(struct notifier_block *nb, | |
847 | + unsigned long val, void *data) | |
848 | +{ | |
849 | + struct module *mod = data; | |
850 | + struct trace_probe *tp; | |
851 | + int ret; | |
852 | + | |
853 | + if (val != MODULE_STATE_COMING) | |
854 | + return NOTIFY_DONE; | |
855 | + | |
856 | + /* Update probes on coming module */ | |
857 | + mutex_lock(&probe_lock); | |
858 | + list_for_each_entry(tp, &probe_list, list) { | |
859 | + if (trace_probe_within_module(tp, mod)) { | |
860 | + __unregister_trace_probe(tp); | |
861 | + ret = __register_trace_probe(tp); | |
862 | + if (ret) | |
863 | + pr_warning("Failed to re-register probe %s on" | |
864 | + "%s: %d\n", | |
865 | + tp->call.name, mod->name, ret); | |
866 | + } | |
867 | + } | |
868 | + mutex_unlock(&probe_lock); | |
869 | + | |
870 | + return NOTIFY_DONE; | |
871 | +} | |
872 | + | |
873 | +static struct notifier_block trace_probe_module_nb = { | |
874 | + .notifier_call = trace_probe_module_callback, | |
875 | + .priority = 1 /* Invoked after kprobe module callback */ | |
876 | +}; | |
877 | + | |
768 | 878 | /* Split symbol and offset. */ |
769 | 879 | static int split_symbol_offset(char *symbol, unsigned long *offset) |
770 | 880 | { |
... | ... | @@ -990,8 +1100,8 @@ |
990 | 1100 | { |
991 | 1101 | /* |
992 | 1102 | * Argument syntax: |
993 | - * - Add kprobe: p[:[GRP/]EVENT] KSYM[+OFFS]|KADDR [FETCHARGS] | |
994 | - * - Add kretprobe: r[:[GRP/]EVENT] KSYM[+0] [FETCHARGS] | |
1103 | + * - Add kprobe: p[:[GRP/]EVENT] [MOD:]KSYM[+OFFS]|KADDR [FETCHARGS] | |
1104 | + * - Add kretprobe: r[:[GRP/]EVENT] [MOD:]KSYM[+0] [FETCHARGS] | |
995 | 1105 | * Fetch args: |
996 | 1106 | * $retval : fetch return value |
997 | 1107 | * $stack : fetch stack address |
... | ... | @@ -1186,7 +1296,6 @@ |
1186 | 1296 | mutex_unlock(&probe_lock); |
1187 | 1297 | } |
1188 | 1298 | |
1189 | - | |
1190 | 1299 | /* Probes listing interfaces */ |
1191 | 1300 | static void *probes_seq_start(struct seq_file *m, loff_t *pos) |
1192 | 1301 | { |
... | ... | @@ -1826,6 +1935,9 @@ |
1826 | 1935 | { |
1827 | 1936 | struct dentry *d_tracer; |
1828 | 1937 | struct dentry *entry; |
1938 | + | |
1939 | + if (register_module_notifier(&trace_probe_module_nb)) | |
1940 | + return -EINVAL; | |
1829 | 1941 | |
1830 | 1942 | d_tracer = tracing_init_dentry(); |
1831 | 1943 | if (!d_tracer) |