diff options
author | Steven Rostedt <srostedt@redhat.com> | 2009-02-16 15:28:00 -0500 |
---|---|---|
committer | Steven Rostedt <srostedt@redhat.com> | 2009-02-16 22:50:06 -0500 |
commit | 8fc0c701c5b6c0c3e242758c3acef6f9047940a9 (patch) | |
tree | aa9c495fc2d898b39873e1ce9f154bed64b33f8e /kernel/trace/ftrace.c | |
parent | 23b4ff3aa479c9e3bb23cb6b2d0a97878399784a (diff) |
ftrace: show selected functions in set_ftrace_filter
This patch adds output to show what functions have tracer hooks
attached to them.
# echo 'sys_open:traceon:4' > /debug/tracing/set_ftrace_filter
# cat set_ftrace_filter
#### all functions enabled ####
sys_open:ftrace_traceon:0000000000000004
# echo 'do_fork:traceoff:' > set_ftrace_filter
# cat set_ftrace_filter
#### all functions enabled ####
sys_open:ftrace_traceon:0000000000000002
do_fork:ftrace_traceoff:ffffffffffffffff
Note the 4 changed to a 2. This is because The code was executed twice
since the traceoff was added. If a cat is done again:
#### all functions enabled ####
sys_open:ftrace_traceon
do_fork:ftrace_traceoff:ffffffffffffffff
The number disappears. That is because it will not print a NULL.
Callbacks to allow the tracer to pretty print will be implemented soon.
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 123 |
1 files changed, 103 insertions, 20 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 0b80e325f296..1e058848cddb 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -45,14 +45,14 @@ | |||
45 | ftrace_kill(); \ | 45 | ftrace_kill(); \ |
46 | } while (0) | 46 | } while (0) |
47 | 47 | ||
48 | /* hash bits for specific function selection */ | ||
49 | #define FTRACE_HASH_BITS 7 | ||
50 | #define FTRACE_FUNC_HASHSIZE (1 << FTRACE_HASH_BITS) | ||
51 | |||
48 | /* ftrace_enabled is a method to turn ftrace on or off */ | 52 | /* ftrace_enabled is a method to turn ftrace on or off */ |
49 | int ftrace_enabled __read_mostly; | 53 | int ftrace_enabled __read_mostly; |
50 | static int last_ftrace_enabled; | 54 | static int last_ftrace_enabled; |
51 | 55 | ||
52 | /* set when tracing only a pid */ | ||
53 | struct pid *ftrace_pid_trace; | ||
54 | static struct pid * const ftrace_swapper_pid = &init_struct_pid; | ||
55 | |||
56 | /* Quick disabling of function tracer. */ | 56 | /* Quick disabling of function tracer. */ |
57 | int function_trace_stop; | 57 | int function_trace_stop; |
58 | 58 | ||
@@ -248,6 +248,21 @@ static void ftrace_update_pid_func(void) | |||
248 | # error Dynamic ftrace depends on MCOUNT_RECORD | 248 | # error Dynamic ftrace depends on MCOUNT_RECORD |
249 | #endif | 249 | #endif |
250 | 250 | ||
251 | /* set when tracing only a pid */ | ||
252 | struct pid *ftrace_pid_trace; | ||
253 | static struct pid * const ftrace_swapper_pid = &init_struct_pid; | ||
254 | static struct hlist_head ftrace_func_hash[FTRACE_FUNC_HASHSIZE] __read_mostly; | ||
255 | |||
256 | struct ftrace_func_hook { | ||
257 | struct hlist_node node; | ||
258 | struct ftrace_hook_ops *ops; | ||
259 | unsigned long flags; | ||
260 | unsigned long ip; | ||
261 | void *data; | ||
262 | struct rcu_head rcu; | ||
263 | }; | ||
264 | |||
265 | |||
251 | enum { | 266 | enum { |
252 | FTRACE_ENABLE_CALLS = (1 << 0), | 267 | FTRACE_ENABLE_CALLS = (1 << 0), |
253 | FTRACE_DISABLE_CALLS = (1 << 1), | 268 | FTRACE_DISABLE_CALLS = (1 << 1), |
@@ -750,12 +765,14 @@ enum { | |||
750 | FTRACE_ITER_NOTRACE = (1 << 2), | 765 | FTRACE_ITER_NOTRACE = (1 << 2), |
751 | FTRACE_ITER_FAILURES = (1 << 3), | 766 | FTRACE_ITER_FAILURES = (1 << 3), |
752 | FTRACE_ITER_PRINTALL = (1 << 4), | 767 | FTRACE_ITER_PRINTALL = (1 << 4), |
768 | FTRACE_ITER_HASH = (1 << 5), | ||
753 | }; | 769 | }; |
754 | 770 | ||
755 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ | 771 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ |
756 | 772 | ||
757 | struct ftrace_iterator { | 773 | struct ftrace_iterator { |
758 | struct ftrace_page *pg; | 774 | struct ftrace_page *pg; |
775 | int hidx; | ||
759 | int idx; | 776 | int idx; |
760 | unsigned flags; | 777 | unsigned flags; |
761 | unsigned char buffer[FTRACE_BUFF_MAX+1]; | 778 | unsigned char buffer[FTRACE_BUFF_MAX+1]; |
@@ -764,17 +781,86 @@ struct ftrace_iterator { | |||
764 | }; | 781 | }; |
765 | 782 | ||
766 | static void * | 783 | static void * |
784 | t_hash_next(struct seq_file *m, void *v, loff_t *pos) | ||
785 | { | ||
786 | struct ftrace_iterator *iter = m->private; | ||
787 | struct hlist_node *hnd = v; | ||
788 | struct hlist_head *hhd; | ||
789 | |||
790 | WARN_ON(!(iter->flags & FTRACE_ITER_HASH)); | ||
791 | |||
792 | (*pos)++; | ||
793 | |||
794 | retry: | ||
795 | if (iter->hidx >= FTRACE_FUNC_HASHSIZE) | ||
796 | return NULL; | ||
797 | |||
798 | hhd = &ftrace_func_hash[iter->hidx]; | ||
799 | |||
800 | if (hlist_empty(hhd)) { | ||
801 | iter->hidx++; | ||
802 | hnd = NULL; | ||
803 | goto retry; | ||
804 | } | ||
805 | |||
806 | if (!hnd) | ||
807 | hnd = hhd->first; | ||
808 | else { | ||
809 | hnd = hnd->next; | ||
810 | if (!hnd) { | ||
811 | iter->hidx++; | ||
812 | goto retry; | ||
813 | } | ||
814 | } | ||
815 | |||
816 | return hnd; | ||
817 | } | ||
818 | |||
819 | static void *t_hash_start(struct seq_file *m, loff_t *pos) | ||
820 | { | ||
821 | struct ftrace_iterator *iter = m->private; | ||
822 | void *p = NULL; | ||
823 | |||
824 | iter->flags |= FTRACE_ITER_HASH; | ||
825 | |||
826 | return t_hash_next(m, p, pos); | ||
827 | } | ||
828 | |||
829 | static int t_hash_show(struct seq_file *m, void *v) | ||
830 | { | ||
831 | struct ftrace_func_hook *rec; | ||
832 | struct hlist_node *hnd = v; | ||
833 | char str[KSYM_SYMBOL_LEN]; | ||
834 | |||
835 | rec = hlist_entry(hnd, struct ftrace_func_hook, node); | ||
836 | |||
837 | kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); | ||
838 | seq_printf(m, "%s:", str); | ||
839 | |||
840 | kallsyms_lookup((unsigned long)rec->ops->func, NULL, NULL, NULL, str); | ||
841 | seq_printf(m, "%s", str); | ||
842 | |||
843 | if (rec->data) | ||
844 | seq_printf(m, ":%p", rec->data); | ||
845 | seq_putc(m, '\n'); | ||
846 | |||
847 | return 0; | ||
848 | } | ||
849 | |||
850 | static void * | ||
767 | t_next(struct seq_file *m, void *v, loff_t *pos) | 851 | t_next(struct seq_file *m, void *v, loff_t *pos) |
768 | { | 852 | { |
769 | struct ftrace_iterator *iter = m->private; | 853 | struct ftrace_iterator *iter = m->private; |
770 | struct dyn_ftrace *rec = NULL; | 854 | struct dyn_ftrace *rec = NULL; |
771 | 855 | ||
856 | if (iter->flags & FTRACE_ITER_HASH) | ||
857 | return t_hash_next(m, v, pos); | ||
858 | |||
772 | (*pos)++; | 859 | (*pos)++; |
773 | 860 | ||
774 | if (iter->flags & FTRACE_ITER_PRINTALL) | 861 | if (iter->flags & FTRACE_ITER_PRINTALL) |
775 | return NULL; | 862 | return NULL; |
776 | 863 | ||
777 | mutex_lock(&ftrace_lock); | ||
778 | retry: | 864 | retry: |
779 | if (iter->idx >= iter->pg->index) { | 865 | if (iter->idx >= iter->pg->index) { |
780 | if (iter->pg->next) { | 866 | if (iter->pg->next) { |
@@ -803,7 +889,6 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
803 | goto retry; | 889 | goto retry; |
804 | } | 890 | } |
805 | } | 891 | } |
806 | mutex_unlock(&ftrace_lock); | ||
807 | 892 | ||
808 | return rec; | 893 | return rec; |
809 | } | 894 | } |
@@ -813,6 +898,7 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
813 | struct ftrace_iterator *iter = m->private; | 898 | struct ftrace_iterator *iter = m->private; |
814 | void *p = NULL; | 899 | void *p = NULL; |
815 | 900 | ||
901 | mutex_lock(&ftrace_lock); | ||
816 | /* | 902 | /* |
817 | * For set_ftrace_filter reading, if we have the filter | 903 | * For set_ftrace_filter reading, if we have the filter |
818 | * off, we can short cut and just print out that all | 904 | * off, we can short cut and just print out that all |
@@ -820,12 +906,15 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
820 | */ | 906 | */ |
821 | if (iter->flags & FTRACE_ITER_FILTER && !ftrace_filtered) { | 907 | if (iter->flags & FTRACE_ITER_FILTER && !ftrace_filtered) { |
822 | if (*pos > 0) | 908 | if (*pos > 0) |
823 | return NULL; | 909 | return t_hash_start(m, pos); |
824 | iter->flags |= FTRACE_ITER_PRINTALL; | 910 | iter->flags |= FTRACE_ITER_PRINTALL; |
825 | (*pos)++; | 911 | (*pos)++; |
826 | return iter; | 912 | return iter; |
827 | } | 913 | } |
828 | 914 | ||
915 | if (iter->flags & FTRACE_ITER_HASH) | ||
916 | return t_hash_start(m, pos); | ||
917 | |||
829 | if (*pos > 0) { | 918 | if (*pos > 0) { |
830 | if (iter->idx < 0) | 919 | if (iter->idx < 0) |
831 | return p; | 920 | return p; |
@@ -835,11 +924,15 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
835 | 924 | ||
836 | p = t_next(m, p, pos); | 925 | p = t_next(m, p, pos); |
837 | 926 | ||
927 | if (!p) | ||
928 | return t_hash_start(m, pos); | ||
929 | |||
838 | return p; | 930 | return p; |
839 | } | 931 | } |
840 | 932 | ||
841 | static void t_stop(struct seq_file *m, void *p) | 933 | static void t_stop(struct seq_file *m, void *p) |
842 | { | 934 | { |
935 | mutex_unlock(&ftrace_lock); | ||
843 | } | 936 | } |
844 | 937 | ||
845 | static int t_show(struct seq_file *m, void *v) | 938 | static int t_show(struct seq_file *m, void *v) |
@@ -848,6 +941,9 @@ static int t_show(struct seq_file *m, void *v) | |||
848 | struct dyn_ftrace *rec = v; | 941 | struct dyn_ftrace *rec = v; |
849 | char str[KSYM_SYMBOL_LEN]; | 942 | char str[KSYM_SYMBOL_LEN]; |
850 | 943 | ||
944 | if (iter->flags & FTRACE_ITER_HASH) | ||
945 | return t_hash_show(m, v); | ||
946 | |||
851 | if (iter->flags & FTRACE_ITER_PRINTALL) { | 947 | if (iter->flags & FTRACE_ITER_PRINTALL) { |
852 | seq_printf(m, "#### all functions enabled ####\n"); | 948 | seq_printf(m, "#### all functions enabled ####\n"); |
853 | return 0; | 949 | return 0; |
@@ -1246,19 +1342,6 @@ static int __init ftrace_mod_cmd_init(void) | |||
1246 | } | 1342 | } |
1247 | device_initcall(ftrace_mod_cmd_init); | 1343 | device_initcall(ftrace_mod_cmd_init); |
1248 | 1344 | ||
1249 | #define FTRACE_HASH_BITS 7 | ||
1250 | #define FTRACE_FUNC_HASHSIZE (1 << FTRACE_HASH_BITS) | ||
1251 | static struct hlist_head ftrace_func_hash[FTRACE_FUNC_HASHSIZE] __read_mostly; | ||
1252 | |||
1253 | struct ftrace_func_hook { | ||
1254 | struct hlist_node node; | ||
1255 | struct ftrace_hook_ops *ops; | ||
1256 | unsigned long flags; | ||
1257 | unsigned long ip; | ||
1258 | void *data; | ||
1259 | struct rcu_head rcu; | ||
1260 | }; | ||
1261 | |||
1262 | static void | 1345 | static void |
1263 | function_trace_hook_call(unsigned long ip, unsigned long parent_ip) | 1346 | function_trace_hook_call(unsigned long ip, unsigned long parent_ip) |
1264 | { | 1347 | { |