diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-14 13:49:03 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-14 13:49:03 -0400 |
commit | eeee78cf77df0450ca285a7cd6d73842181e825c (patch) | |
tree | 330540323eae82977756e5086492654b9e461871 /kernel/trace | |
parent | 3f3c73de77b5598e9f87812ac4da9445090c3b4a (diff) | |
parent | 9828413d4715d4ed12bc92b161f4ed377d777ffb (diff) |
Merge tag 'trace-v4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace
Pull tracing updates from Steven Rostedt:
"Some clean ups and small fixes, but the biggest change is the addition
of the TRACE_DEFINE_ENUM() macro that can be used by tracepoints.
Tracepoints have helper functions for the TP_printk() called
__print_symbolic() and __print_flags() that lets a numeric number be
displayed as a a human comprehensible text. What is placed in the
TP_printk() is also shown in the tracepoint format file such that user
space tools like perf and trace-cmd can parse the binary data and
express the values too. Unfortunately, the way the TRACE_EVENT()
macro works, anything placed in the TP_printk() will be shown pretty
much exactly as is. The problem arises when enums are used. That's
because unlike macros, enums will not be changed into their values by
the C pre-processor. Thus, the enum string is exported to the format
file, and this makes it useless for user space tools.
The TRACE_DEFINE_ENUM() solves this by converting the enum strings in
the TP_printk() format into their number, and that is what is shown to
user space. For example, the tracepoint tlb_flush currently has this
in its format file:
__print_symbolic(REC->reason,
{ TLB_FLUSH_ON_TASK_SWITCH, "flush on task switch" },
{ TLB_REMOTE_SHOOTDOWN, "remote shootdown" },
{ TLB_LOCAL_SHOOTDOWN, "local shootdown" },
{ TLB_LOCAL_MM_SHOOTDOWN, "local mm shootdown" })
After adding:
TRACE_DEFINE_ENUM(TLB_FLUSH_ON_TASK_SWITCH);
TRACE_DEFINE_ENUM(TLB_REMOTE_SHOOTDOWN);
TRACE_DEFINE_ENUM(TLB_LOCAL_SHOOTDOWN);
TRACE_DEFINE_ENUM(TLB_LOCAL_MM_SHOOTDOWN);
Its format file will contain this:
__print_symbolic(REC->reason,
{ 0, "flush on task switch" },
{ 1, "remote shootdown" },
{ 2, "local shootdown" },
{ 3, "local mm shootdown" })"
* tag 'trace-v4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: (27 commits)
tracing: Add enum_map file to show enums that have been mapped
writeback: Export enums used by tracepoint to user space
v4l: Export enums used by tracepoints to user space
SUNRPC: Export enums in tracepoints to user space
mm: tracing: Export enums in tracepoints to user space
irq/tracing: Export enums in tracepoints to user space
f2fs: Export the enums in the tracepoints to userspace
net/9p/tracing: Export enums in tracepoints to userspace
x86/tlb/trace: Export enums in used by tlb_flush tracepoint
tracing/samples: Update the trace-event-sample.h with TRACE_DEFINE_ENUM()
tracing: Allow for modules to convert their enums to values
tracing: Add TRACE_DEFINE_ENUM() macro to map enums to their values
tracing: Update trace-event-sample with TRACE_SYSTEM_VAR documentation
tracing: Give system name a pointer
brcmsmac: Move each system tracepoints to their own header
iwlwifi: Move each system tracepoints to their own header
mac80211: Move message tracepoints to their own header
tracing: Add TRACE_SYSTEM_VAR to xhci-hcd
tracing: Add TRACE_SYSTEM_VAR to kvm-s390
tracing: Add TRACE_SYSTEM_VAR to intel-sst
...
Diffstat (limited to 'kernel/trace')
-rw-r--r-- | kernel/trace/Kconfig | 28 | ||||
-rw-r--r-- | kernel/trace/ftrace.c | 22 | ||||
-rw-r--r-- | kernel/trace/ring_buffer.c | 10 | ||||
-rw-r--r-- | kernel/trace/trace.c | 304 | ||||
-rw-r--r-- | kernel/trace/trace.h | 2 | ||||
-rw-r--r-- | kernel/trace/trace_entries.h | 6 | ||||
-rw-r--r-- | kernel/trace/trace_events.c | 121 | ||||
-rw-r--r-- | kernel/trace/trace_export.c | 2 | ||||
-rw-r--r-- | kernel/trace/trace_kprobe.c | 5 | ||||
-rw-r--r-- | kernel/trace/trace_probe.c | 19 | ||||
-rw-r--r-- | kernel/trace/trace_probe.h | 10 | ||||
-rw-r--r-- | kernel/trace/trace_uprobe.c | 5 |
12 files changed, 489 insertions, 45 deletions
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index a5da09c899dd..fedbdd7d5d1e 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig | |||
@@ -599,6 +599,34 @@ config RING_BUFFER_STARTUP_TEST | |||
599 | 599 | ||
600 | If unsure, say N | 600 | If unsure, say N |
601 | 601 | ||
602 | config TRACE_ENUM_MAP_FILE | ||
603 | bool "Show enum mappings for trace events" | ||
604 | depends on TRACING | ||
605 | help | ||
606 | The "print fmt" of the trace events will show the enum names instead | ||
607 | of their values. This can cause problems for user space tools that | ||
608 | use this string to parse the raw data as user space does not know | ||
609 | how to convert the string to its value. | ||
610 | |||
611 | To fix this, there's a special macro in the kernel that can be used | ||
612 | to convert the enum into its value. If this macro is used, then the | ||
613 | print fmt strings will have the enums converted to their values. | ||
614 | |||
615 | If something does not get converted properly, this option can be | ||
616 | used to show what enums the kernel tried to convert. | ||
617 | |||
618 | This option is for debugging the enum conversions. A file is created | ||
619 | in the tracing directory called "enum_map" that will show the enum | ||
620 | names matched with their values and what trace event system they | ||
621 | belong too. | ||
622 | |||
623 | Normally, the mapping of the strings to values will be freed after | ||
624 | boot up or module load. With this option, they will not be freed, as | ||
625 | they are needed for the "enum_map" file. Enabling this option will | ||
626 | increase the memory footprint of the running kernel. | ||
627 | |||
628 | If unsure, say N | ||
629 | |||
602 | endif # FTRACE | 630 | endif # FTRACE |
603 | 631 | ||
604 | endif # TRACING_SUPPORT | 632 | endif # TRACING_SUPPORT |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 5a2e0b53af30..02bece4a99ea 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -249,6 +249,19 @@ static void update_function_graph_func(void); | |||
249 | static inline void update_function_graph_func(void) { } | 249 | static inline void update_function_graph_func(void) { } |
250 | #endif | 250 | #endif |
251 | 251 | ||
252 | |||
253 | static ftrace_func_t ftrace_ops_get_list_func(struct ftrace_ops *ops) | ||
254 | { | ||
255 | /* | ||
256 | * If this is a dynamic ops or we force list func, | ||
257 | * then it needs to call the list anyway. | ||
258 | */ | ||
259 | if (ops->flags & FTRACE_OPS_FL_DYNAMIC || FTRACE_FORCE_LIST_FUNC) | ||
260 | return ftrace_ops_list_func; | ||
261 | |||
262 | return ftrace_ops_get_func(ops); | ||
263 | } | ||
264 | |||
252 | static void update_ftrace_function(void) | 265 | static void update_ftrace_function(void) |
253 | { | 266 | { |
254 | ftrace_func_t func; | 267 | ftrace_func_t func; |
@@ -270,7 +283,7 @@ static void update_ftrace_function(void) | |||
270 | * then have the mcount trampoline call the function directly. | 283 | * then have the mcount trampoline call the function directly. |
271 | */ | 284 | */ |
272 | } else if (ftrace_ops_list->next == &ftrace_list_end) { | 285 | } else if (ftrace_ops_list->next == &ftrace_list_end) { |
273 | func = ftrace_ops_get_func(ftrace_ops_list); | 286 | func = ftrace_ops_get_list_func(ftrace_ops_list); |
274 | 287 | ||
275 | } else { | 288 | } else { |
276 | /* Just use the default ftrace_ops */ | 289 | /* Just use the default ftrace_ops */ |
@@ -5209,13 +5222,6 @@ static void ftrace_ops_recurs_func(unsigned long ip, unsigned long parent_ip, | |||
5209 | ftrace_func_t ftrace_ops_get_func(struct ftrace_ops *ops) | 5222 | ftrace_func_t ftrace_ops_get_func(struct ftrace_ops *ops) |
5210 | { | 5223 | { |
5211 | /* | 5224 | /* |
5212 | * If this is a dynamic ops or we force list func, | ||
5213 | * then it needs to call the list anyway. | ||
5214 | */ | ||
5215 | if (ops->flags & FTRACE_OPS_FL_DYNAMIC || FTRACE_FORCE_LIST_FUNC) | ||
5216 | return ftrace_ops_list_func; | ||
5217 | |||
5218 | /* | ||
5219 | * If the func handles its own recursion, call it directly. | 5225 | * If the func handles its own recursion, call it directly. |
5220 | * Otherwise call the recursion protected function that | 5226 | * Otherwise call the recursion protected function that |
5221 | * will call the ftrace ops function. | 5227 | * will call the ftrace ops function. |
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 5040d44fe5a3..0315d43176d8 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c | |||
@@ -2679,7 +2679,7 @@ static DEFINE_PER_CPU(unsigned int, current_context); | |||
2679 | 2679 | ||
2680 | static __always_inline int trace_recursive_lock(void) | 2680 | static __always_inline int trace_recursive_lock(void) |
2681 | { | 2681 | { |
2682 | unsigned int val = this_cpu_read(current_context); | 2682 | unsigned int val = __this_cpu_read(current_context); |
2683 | int bit; | 2683 | int bit; |
2684 | 2684 | ||
2685 | if (in_interrupt()) { | 2685 | if (in_interrupt()) { |
@@ -2696,18 +2696,14 @@ static __always_inline int trace_recursive_lock(void) | |||
2696 | return 1; | 2696 | return 1; |
2697 | 2697 | ||
2698 | val |= (1 << bit); | 2698 | val |= (1 << bit); |
2699 | this_cpu_write(current_context, val); | 2699 | __this_cpu_write(current_context, val); |
2700 | 2700 | ||
2701 | return 0; | 2701 | return 0; |
2702 | } | 2702 | } |
2703 | 2703 | ||
2704 | static __always_inline void trace_recursive_unlock(void) | 2704 | static __always_inline void trace_recursive_unlock(void) |
2705 | { | 2705 | { |
2706 | unsigned int val = this_cpu_read(current_context); | 2706 | __this_cpu_and(current_context, __this_cpu_read(current_context) - 1); |
2707 | |||
2708 | val--; | ||
2709 | val &= this_cpu_read(current_context); | ||
2710 | this_cpu_write(current_context, val); | ||
2711 | } | 2707 | } |
2712 | 2708 | ||
2713 | #else | 2709 | #else |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index bcfa2add6dda..91eecaaa43e0 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -125,6 +125,42 @@ enum ftrace_dump_mode ftrace_dump_on_oops; | |||
125 | /* When set, tracing will stop when a WARN*() is hit */ | 125 | /* When set, tracing will stop when a WARN*() is hit */ |
126 | int __disable_trace_on_warning; | 126 | int __disable_trace_on_warning; |
127 | 127 | ||
128 | #ifdef CONFIG_TRACE_ENUM_MAP_FILE | ||
129 | /* Map of enums to their values, for "enum_map" file */ | ||
130 | struct trace_enum_map_head { | ||
131 | struct module *mod; | ||
132 | unsigned long length; | ||
133 | }; | ||
134 | |||
135 | union trace_enum_map_item; | ||
136 | |||
137 | struct trace_enum_map_tail { | ||
138 | /* | ||
139 | * "end" is first and points to NULL as it must be different | ||
140 | * than "mod" or "enum_string" | ||
141 | */ | ||
142 | union trace_enum_map_item *next; | ||
143 | const char *end; /* points to NULL */ | ||
144 | }; | ||
145 | |||
146 | static DEFINE_MUTEX(trace_enum_mutex); | ||
147 | |||
148 | /* | ||
149 | * The trace_enum_maps are saved in an array with two extra elements, | ||
150 | * one at the beginning, and one at the end. The beginning item contains | ||
151 | * the count of the saved maps (head.length), and the module they | ||
152 | * belong to if not built in (head.mod). The ending item contains a | ||
153 | * pointer to the next array of saved enum_map items. | ||
154 | */ | ||
155 | union trace_enum_map_item { | ||
156 | struct trace_enum_map map; | ||
157 | struct trace_enum_map_head head; | ||
158 | struct trace_enum_map_tail tail; | ||
159 | }; | ||
160 | |||
161 | static union trace_enum_map_item *trace_enum_maps; | ||
162 | #endif /* CONFIG_TRACE_ENUM_MAP_FILE */ | ||
163 | |||
128 | static int tracing_set_tracer(struct trace_array *tr, const char *buf); | 164 | static int tracing_set_tracer(struct trace_array *tr, const char *buf); |
129 | 165 | ||
130 | #define MAX_TRACER_SIZE 100 | 166 | #define MAX_TRACER_SIZE 100 |
@@ -3910,6 +3946,182 @@ static const struct file_operations tracing_saved_cmdlines_size_fops = { | |||
3910 | .write = tracing_saved_cmdlines_size_write, | 3946 | .write = tracing_saved_cmdlines_size_write, |
3911 | }; | 3947 | }; |
3912 | 3948 | ||
3949 | #ifdef CONFIG_TRACE_ENUM_MAP_FILE | ||
3950 | static union trace_enum_map_item * | ||
3951 | update_enum_map(union trace_enum_map_item *ptr) | ||
3952 | { | ||
3953 | if (!ptr->map.enum_string) { | ||
3954 | if (ptr->tail.next) { | ||
3955 | ptr = ptr->tail.next; | ||
3956 | /* Set ptr to the next real item (skip head) */ | ||
3957 | ptr++; | ||
3958 | } else | ||
3959 | return NULL; | ||
3960 | } | ||
3961 | return ptr; | ||
3962 | } | ||
3963 | |||
3964 | static void *enum_map_next(struct seq_file *m, void *v, loff_t *pos) | ||
3965 | { | ||
3966 | union trace_enum_map_item *ptr = v; | ||
3967 | |||
3968 | /* | ||
3969 | * Paranoid! If ptr points to end, we don't want to increment past it. | ||
3970 | * This really should never happen. | ||
3971 | */ | ||
3972 | ptr = update_enum_map(ptr); | ||
3973 | if (WARN_ON_ONCE(!ptr)) | ||
3974 | return NULL; | ||
3975 | |||
3976 | ptr++; | ||
3977 | |||
3978 | (*pos)++; | ||
3979 | |||
3980 | ptr = update_enum_map(ptr); | ||
3981 | |||
3982 | return ptr; | ||
3983 | } | ||
3984 | |||
3985 | static void *enum_map_start(struct seq_file *m, loff_t *pos) | ||
3986 | { | ||
3987 | union trace_enum_map_item *v; | ||
3988 | loff_t l = 0; | ||
3989 | |||
3990 | mutex_lock(&trace_enum_mutex); | ||
3991 | |||
3992 | v = trace_enum_maps; | ||
3993 | if (v) | ||
3994 | v++; | ||
3995 | |||
3996 | while (v && l < *pos) { | ||
3997 | v = enum_map_next(m, v, &l); | ||
3998 | } | ||
3999 | |||
4000 | return v; | ||
4001 | } | ||
4002 | |||
4003 | static void enum_map_stop(struct seq_file *m, void *v) | ||
4004 | { | ||
4005 | mutex_unlock(&trace_enum_mutex); | ||
4006 | } | ||
4007 | |||
4008 | static int enum_map_show(struct seq_file *m, void *v) | ||
4009 | { | ||
4010 | union trace_enum_map_item *ptr = v; | ||
4011 | |||
4012 | seq_printf(m, "%s %ld (%s)\n", | ||
4013 | ptr->map.enum_string, ptr->map.enum_value, | ||
4014 | ptr->map.system); | ||
4015 | |||
4016 | return 0; | ||
4017 | } | ||
4018 | |||
4019 | static const struct seq_operations tracing_enum_map_seq_ops = { | ||
4020 | .start = enum_map_start, | ||
4021 | .next = enum_map_next, | ||
4022 | .stop = enum_map_stop, | ||
4023 | .show = enum_map_show, | ||
4024 | }; | ||
4025 | |||
4026 | static int tracing_enum_map_open(struct inode *inode, struct file *filp) | ||
4027 | { | ||
4028 | if (tracing_disabled) | ||
4029 | return -ENODEV; | ||
4030 | |||
4031 | return seq_open(filp, &tracing_enum_map_seq_ops); | ||
4032 | } | ||
4033 | |||
4034 | static const struct file_operations tracing_enum_map_fops = { | ||
4035 | .open = tracing_enum_map_open, | ||
4036 | .read = seq_read, | ||
4037 | .llseek = seq_lseek, | ||
4038 | .release = seq_release, | ||
4039 | }; | ||
4040 | |||
4041 | static inline union trace_enum_map_item * | ||
4042 | trace_enum_jmp_to_tail(union trace_enum_map_item *ptr) | ||
4043 | { | ||
4044 | /* Return tail of array given the head */ | ||
4045 | return ptr + ptr->head.length + 1; | ||
4046 | } | ||
4047 | |||
4048 | static void | ||
4049 | trace_insert_enum_map_file(struct module *mod, struct trace_enum_map **start, | ||
4050 | int len) | ||
4051 | { | ||
4052 | struct trace_enum_map **stop; | ||
4053 | struct trace_enum_map **map; | ||
4054 | union trace_enum_map_item *map_array; | ||
4055 | union trace_enum_map_item *ptr; | ||
4056 | |||
4057 | stop = start + len; | ||
4058 | |||
4059 | /* | ||
4060 | * The trace_enum_maps contains the map plus a head and tail item, | ||
4061 | * where the head holds the module and length of array, and the | ||
4062 | * tail holds a pointer to the next list. | ||
4063 | */ | ||
4064 | map_array = kmalloc(sizeof(*map_array) * (len + 2), GFP_KERNEL); | ||
4065 | if (!map_array) { | ||
4066 | pr_warning("Unable to allocate trace enum mapping\n"); | ||
4067 | return; | ||
4068 | } | ||
4069 | |||
4070 | mutex_lock(&trace_enum_mutex); | ||
4071 | |||
4072 | if (!trace_enum_maps) | ||
4073 | trace_enum_maps = map_array; | ||
4074 | else { | ||
4075 | ptr = trace_enum_maps; | ||
4076 | for (;;) { | ||
4077 | ptr = trace_enum_jmp_to_tail(ptr); | ||
4078 | if (!ptr->tail.next) | ||
4079 | break; | ||
4080 | ptr = ptr->tail.next; | ||
4081 | |||
4082 | } | ||
4083 | ptr->tail.next = map_array; | ||
4084 | } | ||
4085 | map_array->head.mod = mod; | ||
4086 | map_array->head.length = len; | ||
4087 | map_array++; | ||
4088 | |||
4089 | for (map = start; (unsigned long)map < (unsigned long)stop; map++) { | ||
4090 | map_array->map = **map; | ||
4091 | map_array++; | ||
4092 | } | ||
4093 | memset(map_array, 0, sizeof(*map_array)); | ||
4094 | |||
4095 | mutex_unlock(&trace_enum_mutex); | ||
4096 | } | ||
4097 | |||
4098 | static void trace_create_enum_file(struct dentry *d_tracer) | ||
4099 | { | ||
4100 | trace_create_file("enum_map", 0444, d_tracer, | ||
4101 | NULL, &tracing_enum_map_fops); | ||
4102 | } | ||
4103 | |||
4104 | #else /* CONFIG_TRACE_ENUM_MAP_FILE */ | ||
4105 | static inline void trace_create_enum_file(struct dentry *d_tracer) { } | ||
4106 | static inline void trace_insert_enum_map_file(struct module *mod, | ||
4107 | struct trace_enum_map **start, int len) { } | ||
4108 | #endif /* !CONFIG_TRACE_ENUM_MAP_FILE */ | ||
4109 | |||
4110 | static void trace_insert_enum_map(struct module *mod, | ||
4111 | struct trace_enum_map **start, int len) | ||
4112 | { | ||
4113 | struct trace_enum_map **map; | ||
4114 | |||
4115 | if (len <= 0) | ||
4116 | return; | ||
4117 | |||
4118 | map = start; | ||
4119 | |||
4120 | trace_event_enum_update(map, len); | ||
4121 | |||
4122 | trace_insert_enum_map_file(mod, start, len); | ||
4123 | } | ||
4124 | |||
3913 | static ssize_t | 4125 | static ssize_t |
3914 | tracing_set_trace_read(struct file *filp, char __user *ubuf, | 4126 | tracing_set_trace_read(struct file *filp, char __user *ubuf, |
3915 | size_t cnt, loff_t *ppos) | 4127 | size_t cnt, loff_t *ppos) |
@@ -6527,6 +6739,88 @@ struct dentry *tracing_init_dentry(void) | |||
6527 | return NULL; | 6739 | return NULL; |
6528 | } | 6740 | } |
6529 | 6741 | ||
6742 | extern struct trace_enum_map *__start_ftrace_enum_maps[]; | ||
6743 | extern struct trace_enum_map *__stop_ftrace_enum_maps[]; | ||
6744 | |||
6745 | static void __init trace_enum_init(void) | ||
6746 | { | ||
6747 | int len; | ||
6748 | |||
6749 | len = __stop_ftrace_enum_maps - __start_ftrace_enum_maps; | ||
6750 | trace_insert_enum_map(NULL, __start_ftrace_enum_maps, len); | ||
6751 | } | ||
6752 | |||
6753 | #ifdef CONFIG_MODULES | ||
6754 | static void trace_module_add_enums(struct module *mod) | ||
6755 | { | ||
6756 | if (!mod->num_trace_enums) | ||
6757 | return; | ||
6758 | |||
6759 | /* | ||
6760 | * Modules with bad taint do not have events created, do | ||
6761 | * not bother with enums either. | ||
6762 | */ | ||
6763 | if (trace_module_has_bad_taint(mod)) | ||
6764 | return; | ||
6765 | |||
6766 | trace_insert_enum_map(mod, mod->trace_enums, mod->num_trace_enums); | ||
6767 | } | ||
6768 | |||
6769 | #ifdef CONFIG_TRACE_ENUM_MAP_FILE | ||
6770 | static void trace_module_remove_enums(struct module *mod) | ||
6771 | { | ||
6772 | union trace_enum_map_item *map; | ||
6773 | union trace_enum_map_item **last = &trace_enum_maps; | ||
6774 | |||
6775 | if (!mod->num_trace_enums) | ||
6776 | return; | ||
6777 | |||
6778 | mutex_lock(&trace_enum_mutex); | ||
6779 | |||
6780 | map = trace_enum_maps; | ||
6781 | |||
6782 | while (map) { | ||
6783 | if (map->head.mod == mod) | ||
6784 | break; | ||
6785 | map = trace_enum_jmp_to_tail(map); | ||
6786 | last = &map->tail.next; | ||
6787 | map = map->tail.next; | ||
6788 | } | ||
6789 | if (!map) | ||
6790 | goto out; | ||
6791 | |||
6792 | *last = trace_enum_jmp_to_tail(map)->tail.next; | ||
6793 | kfree(map); | ||
6794 | out: | ||
6795 | mutex_unlock(&trace_enum_mutex); | ||
6796 | } | ||
6797 | #else | ||
6798 | static inline void trace_module_remove_enums(struct module *mod) { } | ||
6799 | #endif /* CONFIG_TRACE_ENUM_MAP_FILE */ | ||
6800 | |||
6801 | static int trace_module_notify(struct notifier_block *self, | ||
6802 | unsigned long val, void *data) | ||
6803 | { | ||
6804 | struct module *mod = data; | ||
6805 | |||
6806 | switch (val) { | ||
6807 | case MODULE_STATE_COMING: | ||
6808 | trace_module_add_enums(mod); | ||
6809 | break; | ||
6810 | case MODULE_STATE_GOING: | ||
6811 | trace_module_remove_enums(mod); | ||
6812 | break; | ||
6813 | } | ||
6814 | |||
6815 | return 0; | ||
6816 | } | ||
6817 | |||
6818 | static struct notifier_block trace_module_nb = { | ||
6819 | .notifier_call = trace_module_notify, | ||
6820 | .priority = 0, | ||
6821 | }; | ||
6822 | #endif /* CONFIG_MODULES */ | ||
6823 | |||
6530 | static __init int tracer_init_tracefs(void) | 6824 | static __init int tracer_init_tracefs(void) |
6531 | { | 6825 | { |
6532 | struct dentry *d_tracer; | 6826 | struct dentry *d_tracer; |
@@ -6551,6 +6845,14 @@ static __init int tracer_init_tracefs(void) | |||
6551 | trace_create_file("saved_cmdlines_size", 0644, d_tracer, | 6845 | trace_create_file("saved_cmdlines_size", 0644, d_tracer, |
6552 | NULL, &tracing_saved_cmdlines_size_fops); | 6846 | NULL, &tracing_saved_cmdlines_size_fops); |
6553 | 6847 | ||
6848 | trace_enum_init(); | ||
6849 | |||
6850 | trace_create_enum_file(d_tracer); | ||
6851 | |||
6852 | #ifdef CONFIG_MODULES | ||
6853 | register_module_notifier(&trace_module_nb); | ||
6854 | #endif | ||
6855 | |||
6554 | #ifdef CONFIG_DYNAMIC_FTRACE | 6856 | #ifdef CONFIG_DYNAMIC_FTRACE |
6555 | trace_create_file("dyn_ftrace_total_info", 0444, d_tracer, | 6857 | trace_create_file("dyn_ftrace_total_info", 0444, d_tracer, |
6556 | &ftrace_update_tot_cnt, &tracing_dyn_info_fops); | 6858 | &ftrace_update_tot_cnt, &tracing_dyn_info_fops); |
@@ -6877,7 +7179,7 @@ void __init trace_init(void) | |||
6877 | tracepoint_printk = 0; | 7179 | tracepoint_printk = 0; |
6878 | } | 7180 | } |
6879 | tracer_alloc_buffers(); | 7181 | tracer_alloc_buffers(); |
6880 | trace_event_init(); | 7182 | trace_event_init(); |
6881 | } | 7183 | } |
6882 | 7184 | ||
6883 | __init static int clear_boot_tracer(void) | 7185 | __init static int clear_boot_tracer(void) |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index d951deddec89..d2612016de94 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -1309,8 +1309,10 @@ static inline void init_ftrace_syscalls(void) { } | |||
1309 | 1309 | ||
1310 | #ifdef CONFIG_EVENT_TRACING | 1310 | #ifdef CONFIG_EVENT_TRACING |
1311 | void trace_event_init(void); | 1311 | void trace_event_init(void); |
1312 | void trace_event_enum_update(struct trace_enum_map **map, int len); | ||
1312 | #else | 1313 | #else |
1313 | static inline void __init trace_event_init(void) { } | 1314 | static inline void __init trace_event_init(void) { } |
1315 | static inlin void trace_event_enum_update(struct trace_enum_map **map, int len) { } | ||
1314 | #endif | 1316 | #endif |
1315 | 1317 | ||
1316 | extern struct trace_iterator *tracepoint_print_iter; | 1318 | extern struct trace_iterator *tracepoint_print_iter; |
diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h index e2d027ac66a2..ee7b94a4810a 100644 --- a/kernel/trace/trace_entries.h +++ b/kernel/trace/trace_entries.h | |||
@@ -223,7 +223,7 @@ FTRACE_ENTRY(bprint, bprint_entry, | |||
223 | __dynamic_array( u32, buf ) | 223 | __dynamic_array( u32, buf ) |
224 | ), | 224 | ), |
225 | 225 | ||
226 | F_printk("%pf: %s", | 226 | F_printk("%ps: %s", |
227 | (void *)__entry->ip, __entry->fmt), | 227 | (void *)__entry->ip, __entry->fmt), |
228 | 228 | ||
229 | FILTER_OTHER | 229 | FILTER_OTHER |
@@ -238,7 +238,7 @@ FTRACE_ENTRY(print, print_entry, | |||
238 | __dynamic_array( char, buf ) | 238 | __dynamic_array( char, buf ) |
239 | ), | 239 | ), |
240 | 240 | ||
241 | F_printk("%pf: %s", | 241 | F_printk("%ps: %s", |
242 | (void *)__entry->ip, __entry->buf), | 242 | (void *)__entry->ip, __entry->buf), |
243 | 243 | ||
244 | FILTER_OTHER | 244 | FILTER_OTHER |
@@ -253,7 +253,7 @@ FTRACE_ENTRY(bputs, bputs_entry, | |||
253 | __field( const char *, str ) | 253 | __field( const char *, str ) |
254 | ), | 254 | ), |
255 | 255 | ||
256 | F_printk("%pf: %s", | 256 | F_printk("%ps: %s", |
257 | (void *)__entry->ip, __entry->str), | 257 | (void *)__entry->ip, __entry->str), |
258 | 258 | ||
259 | FILTER_OTHER | 259 | FILTER_OTHER |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 0d2e47370ee7..7da1dfeb322e 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -1704,6 +1704,125 @@ __register_event(struct ftrace_event_call *call, struct module *mod) | |||
1704 | return 0; | 1704 | return 0; |
1705 | } | 1705 | } |
1706 | 1706 | ||
1707 | static char *enum_replace(char *ptr, struct trace_enum_map *map, int len) | ||
1708 | { | ||
1709 | int rlen; | ||
1710 | int elen; | ||
1711 | |||
1712 | /* Find the length of the enum value as a string */ | ||
1713 | elen = snprintf(ptr, 0, "%ld", map->enum_value); | ||
1714 | /* Make sure there's enough room to replace the string with the value */ | ||
1715 | if (len < elen) | ||
1716 | return NULL; | ||
1717 | |||
1718 | snprintf(ptr, elen + 1, "%ld", map->enum_value); | ||
1719 | |||
1720 | /* Get the rest of the string of ptr */ | ||
1721 | rlen = strlen(ptr + len); | ||
1722 | memmove(ptr + elen, ptr + len, rlen); | ||
1723 | /* Make sure we end the new string */ | ||
1724 | ptr[elen + rlen] = 0; | ||
1725 | |||
1726 | return ptr + elen; | ||
1727 | } | ||
1728 | |||
1729 | static void update_event_printk(struct ftrace_event_call *call, | ||
1730 | struct trace_enum_map *map) | ||
1731 | { | ||
1732 | char *ptr; | ||
1733 | int quote = 0; | ||
1734 | int len = strlen(map->enum_string); | ||
1735 | |||
1736 | for (ptr = call->print_fmt; *ptr; ptr++) { | ||
1737 | if (*ptr == '\\') { | ||
1738 | ptr++; | ||
1739 | /* paranoid */ | ||
1740 | if (!*ptr) | ||
1741 | break; | ||
1742 | continue; | ||
1743 | } | ||
1744 | if (*ptr == '"') { | ||
1745 | quote ^= 1; | ||
1746 | continue; | ||
1747 | } | ||
1748 | if (quote) | ||
1749 | continue; | ||
1750 | if (isdigit(*ptr)) { | ||
1751 | /* skip numbers */ | ||
1752 | do { | ||
1753 | ptr++; | ||
1754 | /* Check for alpha chars like ULL */ | ||
1755 | } while (isalnum(*ptr)); | ||
1756 | /* | ||
1757 | * A number must have some kind of delimiter after | ||
1758 | * it, and we can ignore that too. | ||
1759 | */ | ||
1760 | continue; | ||
1761 | } | ||
1762 | if (isalpha(*ptr) || *ptr == '_') { | ||
1763 | if (strncmp(map->enum_string, ptr, len) == 0 && | ||
1764 | !isalnum(ptr[len]) && ptr[len] != '_') { | ||
1765 | ptr = enum_replace(ptr, map, len); | ||
1766 | /* Hmm, enum string smaller than value */ | ||
1767 | if (WARN_ON_ONCE(!ptr)) | ||
1768 | return; | ||
1769 | /* | ||
1770 | * No need to decrement here, as enum_replace() | ||
1771 | * returns the pointer to the character passed | ||
1772 | * the enum, and two enums can not be placed | ||
1773 | * back to back without something in between. | ||
1774 | * We can skip that something in between. | ||
1775 | */ | ||
1776 | continue; | ||
1777 | } | ||
1778 | skip_more: | ||
1779 | do { | ||
1780 | ptr++; | ||
1781 | } while (isalnum(*ptr) || *ptr == '_'); | ||
1782 | /* | ||
1783 | * If what comes after this variable is a '.' or | ||
1784 | * '->' then we can continue to ignore that string. | ||
1785 | */ | ||
1786 | if (*ptr == '.' || (ptr[0] == '-' && ptr[1] == '>')) { | ||
1787 | ptr += *ptr == '.' ? 1 : 2; | ||
1788 | goto skip_more; | ||
1789 | } | ||
1790 | /* | ||
1791 | * Once again, we can skip the delimiter that came | ||
1792 | * after the string. | ||
1793 | */ | ||
1794 | continue; | ||
1795 | } | ||
1796 | } | ||
1797 | } | ||
1798 | |||
1799 | void trace_event_enum_update(struct trace_enum_map **map, int len) | ||
1800 | { | ||
1801 | struct ftrace_event_call *call, *p; | ||
1802 | const char *last_system = NULL; | ||
1803 | int last_i; | ||
1804 | int i; | ||
1805 | |||
1806 | down_write(&trace_event_sem); | ||
1807 | list_for_each_entry_safe(call, p, &ftrace_events, list) { | ||
1808 | /* events are usually grouped together with systems */ | ||
1809 | if (!last_system || call->class->system != last_system) { | ||
1810 | last_i = 0; | ||
1811 | last_system = call->class->system; | ||
1812 | } | ||
1813 | |||
1814 | for (i = last_i; i < len; i++) { | ||
1815 | if (call->class->system == map[i]->system) { | ||
1816 | /* Save the first system if need be */ | ||
1817 | if (!last_i) | ||
1818 | last_i = i; | ||
1819 | update_event_printk(call, map[i]); | ||
1820 | } | ||
1821 | } | ||
1822 | } | ||
1823 | up_write(&trace_event_sem); | ||
1824 | } | ||
1825 | |||
1707 | static struct ftrace_event_file * | 1826 | static struct ftrace_event_file * |
1708 | trace_create_new_event(struct ftrace_event_call *call, | 1827 | trace_create_new_event(struct ftrace_event_call *call, |
1709 | struct trace_array *tr) | 1828 | struct trace_array *tr) |
@@ -1915,7 +2034,7 @@ static int trace_module_notify(struct notifier_block *self, | |||
1915 | 2034 | ||
1916 | static struct notifier_block trace_module_nb = { | 2035 | static struct notifier_block trace_module_nb = { |
1917 | .notifier_call = trace_module_notify, | 2036 | .notifier_call = trace_module_notify, |
1918 | .priority = 0, | 2037 | .priority = 1, /* higher than trace.c module notify */ |
1919 | }; | 2038 | }; |
1920 | #endif /* CONFIG_MODULES */ | 2039 | #endif /* CONFIG_MODULES */ |
1921 | 2040 | ||
diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c index 12e2b99be862..174a6a71146c 100644 --- a/kernel/trace/trace_export.c +++ b/kernel/trace/trace_export.c | |||
@@ -177,7 +177,7 @@ struct ftrace_event_call __used event_##call = { \ | |||
177 | }, \ | 177 | }, \ |
178 | .event.type = etype, \ | 178 | .event.type = etype, \ |
179 | .print_fmt = print, \ | 179 | .print_fmt = print, \ |
180 | .flags = TRACE_EVENT_FL_IGNORE_ENABLE | TRACE_EVENT_FL_USE_CALL_FILTER, \ | 180 | .flags = TRACE_EVENT_FL_IGNORE_ENABLE, \ |
181 | }; \ | 181 | }; \ |
182 | struct ftrace_event_call __used \ | 182 | struct ftrace_event_call __used \ |
183 | __attribute__((section("_ftrace_events"))) *__event_##call = &event_##call; | 183 | __attribute__((section("_ftrace_events"))) *__event_##call = &event_##call; |
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index ed998fbf09ce..9ba3f43f580e 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -250,7 +250,7 @@ DEFINE_FETCH_symbol(string_size) | |||
250 | #define fetch_file_offset_string_size NULL | 250 | #define fetch_file_offset_string_size NULL |
251 | 251 | ||
252 | /* Fetch type information table */ | 252 | /* Fetch type information table */ |
253 | const struct fetch_type kprobes_fetch_type_table[] = { | 253 | static const struct fetch_type kprobes_fetch_type_table[] = { |
254 | /* Special types */ | 254 | /* Special types */ |
255 | [FETCH_TYPE_STRING] = __ASSIGN_FETCH_TYPE("string", string, string, | 255 | [FETCH_TYPE_STRING] = __ASSIGN_FETCH_TYPE("string", string, string, |
256 | sizeof(u32), 1, "__data_loc char[]"), | 256 | sizeof(u32), 1, "__data_loc char[]"), |
@@ -760,7 +760,8 @@ static int create_trace_kprobe(int argc, char **argv) | |||
760 | 760 | ||
761 | /* Parse fetch argument */ | 761 | /* Parse fetch argument */ |
762 | ret = traceprobe_parse_probe_arg(arg, &tk->tp.size, parg, | 762 | ret = traceprobe_parse_probe_arg(arg, &tk->tp.size, parg, |
763 | is_return, true); | 763 | is_return, true, |
764 | kprobes_fetch_type_table); | ||
764 | if (ret) { | 765 | if (ret) { |
765 | pr_info("Parse error at argument[%d]. (%d)\n", i, ret); | 766 | pr_info("Parse error at argument[%d]. (%d)\n", i, ret); |
766 | goto error; | 767 | goto error; |
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index b983b2fd2ca1..1769a81da8a7 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c | |||
@@ -356,17 +356,14 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t, | |||
356 | 356 | ||
357 | /* Recursive argument parser */ | 357 | /* Recursive argument parser */ |
358 | static int parse_probe_arg(char *arg, const struct fetch_type *t, | 358 | static int parse_probe_arg(char *arg, const struct fetch_type *t, |
359 | struct fetch_param *f, bool is_return, bool is_kprobe) | 359 | struct fetch_param *f, bool is_return, bool is_kprobe, |
360 | const struct fetch_type *ftbl) | ||
360 | { | 361 | { |
361 | const struct fetch_type *ftbl; | ||
362 | unsigned long param; | 362 | unsigned long param; |
363 | long offset; | 363 | long offset; |
364 | char *tmp; | 364 | char *tmp; |
365 | int ret = 0; | 365 | int ret = 0; |
366 | 366 | ||
367 | ftbl = is_kprobe ? kprobes_fetch_type_table : uprobes_fetch_type_table; | ||
368 | BUG_ON(ftbl == NULL); | ||
369 | |||
370 | switch (arg[0]) { | 367 | switch (arg[0]) { |
371 | case '$': | 368 | case '$': |
372 | ret = parse_probe_vars(arg + 1, t, f, is_return, is_kprobe); | 369 | ret = parse_probe_vars(arg + 1, t, f, is_return, is_kprobe); |
@@ -447,7 +444,7 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t, | |||
447 | dprm->fetch_size = get_fetch_size_function(t, | 444 | dprm->fetch_size = get_fetch_size_function(t, |
448 | dprm->fetch, ftbl); | 445 | dprm->fetch, ftbl); |
449 | ret = parse_probe_arg(arg, t2, &dprm->orig, is_return, | 446 | ret = parse_probe_arg(arg, t2, &dprm->orig, is_return, |
450 | is_kprobe); | 447 | is_kprobe, ftbl); |
451 | if (ret) | 448 | if (ret) |
452 | kfree(dprm); | 449 | kfree(dprm); |
453 | else { | 450 | else { |
@@ -505,15 +502,12 @@ static int __parse_bitfield_probe_arg(const char *bf, | |||
505 | 502 | ||
506 | /* String length checking wrapper */ | 503 | /* String length checking wrapper */ |
507 | int traceprobe_parse_probe_arg(char *arg, ssize_t *size, | 504 | int traceprobe_parse_probe_arg(char *arg, ssize_t *size, |
508 | struct probe_arg *parg, bool is_return, bool is_kprobe) | 505 | struct probe_arg *parg, bool is_return, bool is_kprobe, |
506 | const struct fetch_type *ftbl) | ||
509 | { | 507 | { |
510 | const struct fetch_type *ftbl; | ||
511 | const char *t; | 508 | const char *t; |
512 | int ret; | 509 | int ret; |
513 | 510 | ||
514 | ftbl = is_kprobe ? kprobes_fetch_type_table : uprobes_fetch_type_table; | ||
515 | BUG_ON(ftbl == NULL); | ||
516 | |||
517 | if (strlen(arg) > MAX_ARGSTR_LEN) { | 511 | if (strlen(arg) > MAX_ARGSTR_LEN) { |
518 | pr_info("Argument is too long.: %s\n", arg); | 512 | pr_info("Argument is too long.: %s\n", arg); |
519 | return -ENOSPC; | 513 | return -ENOSPC; |
@@ -535,7 +529,8 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size, | |||
535 | } | 529 | } |
536 | parg->offset = *size; | 530 | parg->offset = *size; |
537 | *size += parg->type->size; | 531 | *size += parg->type->size; |
538 | ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return, is_kprobe); | 532 | ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return, |
533 | is_kprobe, ftbl); | ||
539 | 534 | ||
540 | if (ret >= 0 && t != NULL) | 535 | if (ret >= 0 && t != NULL) |
541 | ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch); | 536 | ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch); |
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index 19aff635841a..ab283e146b70 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h | |||
@@ -229,13 +229,6 @@ ASSIGN_FETCH_FUNC(file_offset, ftype), \ | |||
229 | #define FETCH_TYPE_STRING 0 | 229 | #define FETCH_TYPE_STRING 0 |
230 | #define FETCH_TYPE_STRSIZE 1 | 230 | #define FETCH_TYPE_STRSIZE 1 |
231 | 231 | ||
232 | /* | ||
233 | * Fetch type information table. | ||
234 | * It's declared as a weak symbol due to conditional compilation. | ||
235 | */ | ||
236 | extern __weak const struct fetch_type kprobes_fetch_type_table[]; | ||
237 | extern __weak const struct fetch_type uprobes_fetch_type_table[]; | ||
238 | |||
239 | #ifdef CONFIG_KPROBE_EVENT | 232 | #ifdef CONFIG_KPROBE_EVENT |
240 | struct symbol_cache; | 233 | struct symbol_cache; |
241 | unsigned long update_symbol_cache(struct symbol_cache *sc); | 234 | unsigned long update_symbol_cache(struct symbol_cache *sc); |
@@ -333,7 +326,8 @@ find_event_file_link(struct trace_probe *tp, struct ftrace_event_file *file) | |||
333 | } | 326 | } |
334 | 327 | ||
335 | extern int traceprobe_parse_probe_arg(char *arg, ssize_t *size, | 328 | extern int traceprobe_parse_probe_arg(char *arg, ssize_t *size, |
336 | struct probe_arg *parg, bool is_return, bool is_kprobe); | 329 | struct probe_arg *parg, bool is_return, bool is_kprobe, |
330 | const struct fetch_type *ftbl); | ||
337 | 331 | ||
338 | extern int traceprobe_conflict_field_name(const char *name, | 332 | extern int traceprobe_conflict_field_name(const char *name, |
339 | struct probe_arg *args, int narg); | 333 | struct probe_arg *args, int narg); |
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index 7dc1c8abecd6..74865465e0b7 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c | |||
@@ -196,7 +196,7 @@ DEFINE_FETCH_file_offset(string) | |||
196 | DEFINE_FETCH_file_offset(string_size) | 196 | DEFINE_FETCH_file_offset(string_size) |
197 | 197 | ||
198 | /* Fetch type information table */ | 198 | /* Fetch type information table */ |
199 | const struct fetch_type uprobes_fetch_type_table[] = { | 199 | static const struct fetch_type uprobes_fetch_type_table[] = { |
200 | /* Special types */ | 200 | /* Special types */ |
201 | [FETCH_TYPE_STRING] = __ASSIGN_FETCH_TYPE("string", string, string, | 201 | [FETCH_TYPE_STRING] = __ASSIGN_FETCH_TYPE("string", string, string, |
202 | sizeof(u32), 1, "__data_loc char[]"), | 202 | sizeof(u32), 1, "__data_loc char[]"), |
@@ -535,7 +535,8 @@ static int create_trace_uprobe(int argc, char **argv) | |||
535 | 535 | ||
536 | /* Parse fetch argument */ | 536 | /* Parse fetch argument */ |
537 | ret = traceprobe_parse_probe_arg(arg, &tu->tp.size, parg, | 537 | ret = traceprobe_parse_probe_arg(arg, &tu->tp.size, parg, |
538 | is_return, false); | 538 | is_return, false, |
539 | uprobes_fetch_type_table); | ||
539 | if (ret) { | 540 | if (ret) { |
540 | pr_info("Parse error at argument[%d]. (%d)\n", i, ret); | 541 | pr_info("Parse error at argument[%d]. (%d)\n", i, ret); |
541 | goto error; | 542 | goto error; |