diff options
| author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2011-06-27 03:26:56 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2011-07-15 15:17:14 -0400 |
| commit | 614243181050436785f5a621749a7da2336a7916 (patch) | |
| tree | d64445cc0bc14420b993e82bd4bb4723ea8e34fa | |
| parent | bc81d48d13d8839fae6833c95794c403b2133f36 (diff) | |
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>
| -rw-r--r-- | Documentation/trace/kprobetrace.txt | 9 | ||||
| -rw-r--r-- | kernel/trace/trace_kprobe.c | 164 |
2 files changed, 143 insertions, 30 deletions
diff --git a/Documentation/trace/kprobetrace.txt b/Documentation/trace/kprobetrace.txt index c83bd6b4e6e..d0d0bb9e3e2 100644 --- a/Documentation/trace/kprobetrace.txt +++ b/Documentation/trace/kprobetrace.txt | |||
| @@ -22,14 +22,15 @@ current_tracer. Instead of that, add probe points via | |||
| 22 | 22 | ||
| 23 | Synopsis of kprobe_events | 23 | Synopsis of kprobe_events |
| 24 | ------------------------- | 24 | ------------------------- |
| 25 | p[:[GRP/]EVENT] SYMBOL[+offs]|MEMADDR [FETCHARGS] : Set a probe | 25 | p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS] : Set a probe |
| 26 | r[:[GRP/]EVENT] SYMBOL[+0] [FETCHARGS] : Set a return probe | 26 | r[:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS] : Set a return probe |
| 27 | -:[GRP/]EVENT : Clear a probe | 27 | -:[GRP/]EVENT : Clear a probe |
| 28 | 28 | ||
| 29 | GRP : Group name. If omitted, use "kprobes" for it. | 29 | GRP : Group name. If omitted, use "kprobes" for it. |
| 30 | EVENT : Event name. If omitted, the event name is generated | 30 | EVENT : Event name. If omitted, the event name is generated |
| 31 | based on SYMBOL+offs or MEMADDR. | 31 | based on SYM+offs or MEMADDR. |
| 32 | SYMBOL[+offs] : Symbol+offset where the probe is inserted. | 32 | MOD : Module name which has given SYM. |
| 33 | SYM[+offs] : Symbol+offset where the probe is inserted. | ||
| 33 | MEMADDR : Address where the probe is inserted. | 34 | MEMADDR : Address where the probe is inserted. |
| 34 | 35 | ||
| 35 | FETCHARGS : Arguments. Each probe can have up to 128 args. | 36 | FETCHARGS : Arguments. Each probe can have up to 128 args. |
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 3be50c52d08..acc6664a6b2 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
| @@ -536,6 +536,7 @@ struct probe_arg { | |||
| 536 | /* Flags for trace_probe */ | 536 | /* Flags for trace_probe */ |
| 537 | #define TP_FLAG_TRACE 1 | 537 | #define TP_FLAG_TRACE 1 |
| 538 | #define TP_FLAG_PROFILE 2 | 538 | #define TP_FLAG_PROFILE 2 |
| 539 | #define TP_FLAG_REGISTERED 4 | ||
| 539 | 540 | ||
| 540 | struct trace_probe { | 541 | struct trace_probe { |
| 541 | struct list_head list; | 542 | struct list_head list; |
| @@ -565,6 +566,39 @@ static __kprobes const char *trace_probe_symbol(struct trace_probe *tp) | |||
| 565 | return tp->symbol ? tp->symbol : "unknown"; | 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 | static int register_probe_event(struct trace_probe *tp); | 602 | static int register_probe_event(struct trace_probe *tp); |
| 569 | static void unregister_probe_event(struct trace_probe *tp); | 603 | static void unregister_probe_event(struct trace_probe *tp); |
| 570 | 604 | ||
| @@ -689,7 +723,8 @@ static int enable_trace_probe(struct trace_probe *tp, int flag) | |||
| 689 | int ret = 0; | 723 | int ret = 0; |
| 690 | 724 | ||
| 691 | tp->flags |= flag; | 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 | if (trace_probe_is_return(tp)) | 728 | if (trace_probe_is_return(tp)) |
| 694 | ret = enable_kretprobe(&tp->rp); | 729 | ret = enable_kretprobe(&tp->rp); |
| 695 | else | 730 | else |
| @@ -703,7 +738,7 @@ static int enable_trace_probe(struct trace_probe *tp, int flag) | |||
| 703 | static void disable_trace_probe(struct trace_probe *tp, int flag) | 738 | static void disable_trace_probe(struct trace_probe *tp, int flag) |
| 704 | { | 739 | { |
| 705 | tp->flags &= ~flag; | 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 | if (trace_probe_is_return(tp)) | 742 | if (trace_probe_is_return(tp)) |
| 708 | disable_kretprobe(&tp->rp); | 743 | disable_kretprobe(&tp->rp); |
| 709 | else | 744 | else |
| @@ -711,13 +746,64 @@ static void disable_trace_probe(struct trace_probe *tp, int flag) | |||
| 711 | } | 746 | } |
| 712 | } | 747 | } |
| 713 | 748 | ||
| 714 | /* Unregister a trace_probe and probe_event: call with locking probe_lock */ | 749 | /* Internal register function - just handle k*probes and flags */ |
| 715 | static void unregister_trace_probe(struct trace_probe *tp) | 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 | if (trace_probe_is_return(tp)) | 763 | if (trace_probe_is_return(tp)) |
| 718 | unregister_kretprobe(&tp->rp); | 764 | ret = register_kretprobe(&tp->rp); |
| 719 | else | 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 | list_del(&tp->list); | 807 | list_del(&tp->list); |
| 722 | unregister_probe_event(tp); | 808 | unregister_probe_event(tp); |
| 723 | } | 809 | } |
| @@ -730,41 +816,65 @@ static int register_trace_probe(struct trace_probe *tp) | |||
| 730 | 816 | ||
| 731 | mutex_lock(&probe_lock); | 817 | mutex_lock(&probe_lock); |
| 732 | 818 | ||
| 733 | /* register as an event */ | 819 | /* Delete old (same name) event if exist */ |
| 734 | old_tp = find_trace_probe(tp->call.name, tp->call.class->system); | 820 | old_tp = find_trace_probe(tp->call.name, tp->call.class->system); |
| 735 | if (old_tp) { | 821 | if (old_tp) { |
| 736 | /* delete old event */ | ||
| 737 | unregister_trace_probe(old_tp); | 822 | unregister_trace_probe(old_tp); |
| 738 | free_trace_probe(old_tp); | 823 | free_trace_probe(old_tp); |
| 739 | } | 824 | } |
| 825 | |||
| 826 | /* Register new event */ | ||
| 740 | ret = register_probe_event(tp); | 827 | ret = register_probe_event(tp); |
| 741 | if (ret) { | 828 | if (ret) { |
| 742 | pr_warning("Failed to register probe event(%d)\n", ret); | 829 | pr_warning("Failed to register probe event(%d)\n", ret); |
| 743 | goto end; | 830 | goto end; |
| 744 | } | 831 | } |
| 745 | 832 | ||
| 746 | tp->rp.kp.flags |= KPROBE_FLAG_DISABLED; | 833 | /* Register k*probe */ |
| 747 | if (trace_probe_is_return(tp)) | 834 | ret = __register_trace_probe(tp); |
| 748 | ret = register_kretprobe(&tp->rp); | 835 | if (ret < 0) |
| 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 | } | ||
| 760 | unregister_probe_event(tp); | 836 | unregister_probe_event(tp); |
| 761 | } else | 837 | else |
| 762 | list_add_tail(&tp->list, &probe_list); | 838 | list_add_tail(&tp->list, &probe_list); |
| 839 | |||
| 763 | end: | 840 | end: |
| 764 | mutex_unlock(&probe_lock); | 841 | mutex_unlock(&probe_lock); |
| 765 | return ret; | 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 | /* Split symbol and offset. */ | 878 | /* Split symbol and offset. */ |
| 769 | static int split_symbol_offset(char *symbol, unsigned long *offset) | 879 | static int split_symbol_offset(char *symbol, unsigned long *offset) |
| 770 | { | 880 | { |
| @@ -990,8 +1100,8 @@ static int create_trace_probe(int argc, char **argv) | |||
| 990 | { | 1100 | { |
| 991 | /* | 1101 | /* |
| 992 | * Argument syntax: | 1102 | * Argument syntax: |
| 993 | * - Add kprobe: p[:[GRP/]EVENT] KSYM[+OFFS]|KADDR [FETCHARGS] | 1103 | * - Add kprobe: p[:[GRP/]EVENT] [MOD:]KSYM[+OFFS]|KADDR [FETCHARGS] |
| 994 | * - Add kretprobe: r[:[GRP/]EVENT] KSYM[+0] [FETCHARGS] | 1104 | * - Add kretprobe: r[:[GRP/]EVENT] [MOD:]KSYM[+0] [FETCHARGS] |
| 995 | * Fetch args: | 1105 | * Fetch args: |
| 996 | * $retval : fetch return value | 1106 | * $retval : fetch return value |
| 997 | * $stack : fetch stack address | 1107 | * $stack : fetch stack address |
| @@ -1186,7 +1296,6 @@ static void release_all_trace_probes(void) | |||
| 1186 | mutex_unlock(&probe_lock); | 1296 | mutex_unlock(&probe_lock); |
| 1187 | } | 1297 | } |
| 1188 | 1298 | ||
| 1189 | |||
| 1190 | /* Probes listing interfaces */ | 1299 | /* Probes listing interfaces */ |
| 1191 | static void *probes_seq_start(struct seq_file *m, loff_t *pos) | 1300 | static void *probes_seq_start(struct seq_file *m, loff_t *pos) |
| 1192 | { | 1301 | { |
| @@ -1827,6 +1936,9 @@ static __init int init_kprobe_trace(void) | |||
| 1827 | struct dentry *d_tracer; | 1936 | struct dentry *d_tracer; |
| 1828 | struct dentry *entry; | 1937 | struct dentry *entry; |
| 1829 | 1938 | ||
| 1939 | if (register_module_notifier(&trace_probe_module_nb)) | ||
| 1940 | return -EINVAL; | ||
| 1941 | |||
| 1830 | d_tracer = tracing_init_dentry(); | 1942 | d_tracer = tracing_init_dentry(); |
| 1831 | if (!d_tracer) | 1943 | if (!d_tracer) |
| 1832 | return 0; | 1944 | return 0; |
