aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2015-03-31 17:23:45 -0400
committerSteven Rostedt <rostedt@goodmis.org>2015-04-08 10:58:35 -0400
commit9828413d4715d4ed12bc92b161f4ed377d777ffb (patch)
tree78c05d662c762ed127ad215b3e34b367f39bbb70 /kernel
parent91df6089aa330f12f31cf4b710350a3d6e3d66e6 (diff)
tracing: Add enum_map file to show enums that have been mapped
Add a enum_map file in the tracing directory to see what enums have been saved to convert in the print fmt files. As this requires the enum mapping to be persistent in memory, it is only created if the new config option CONFIG_TRACE_ENUM_MAP_FILE is enabled. This is for debugging and will increase the persistent memory footprint of the kernel. Link: http://lkml.kernel.org/r/20150403013802.220157513@goodmis.org Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Tested-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/trace/Kconfig28
-rw-r--r--kernel/trace/trace.c245
2 files changed, 269 insertions, 4 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
602config 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
602endif # FTRACE 630endif # FTRACE
603 631
604endif # TRACING_SUPPORT 632endif # TRACING_SUPPORT
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 28e6654e640d..39e69568302e 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -123,6 +123,42 @@ enum ftrace_dump_mode ftrace_dump_on_oops;
123/* When set, tracing will stop when a WARN*() is hit */ 123/* When set, tracing will stop when a WARN*() is hit */
124int __disable_trace_on_warning; 124int __disable_trace_on_warning;
125 125
126#ifdef CONFIG_TRACE_ENUM_MAP_FILE
127/* Map of enums to their values, for "enum_map" file */
128struct trace_enum_map_head {
129 struct module *mod;
130 unsigned long length;
131};
132
133union trace_enum_map_item;
134
135struct trace_enum_map_tail {
136 /*
137 * "end" is first and points to NULL as it must be different
138 * than "mod" or "enum_string"
139 */
140 union trace_enum_map_item *next;
141 const char *end; /* points to NULL */
142};
143
144static DEFINE_MUTEX(trace_enum_mutex);
145
146/*
147 * The trace_enum_maps are saved in an array with two extra elements,
148 * one at the beginning, and one at the end. The beginning item contains
149 * the count of the saved maps (head.length), and the module they
150 * belong to if not built in (head.mod). The ending item contains a
151 * pointer to the next array of saved enum_map items.
152 */
153union trace_enum_map_item {
154 struct trace_enum_map map;
155 struct trace_enum_map_head head;
156 struct trace_enum_map_tail tail;
157};
158
159static union trace_enum_map_item *trace_enum_maps;
160#endif /* CONFIG_TRACE_ENUM_MAP_FILE */
161
126static int tracing_set_tracer(struct trace_array *tr, const char *buf); 162static int tracing_set_tracer(struct trace_array *tr, const char *buf);
127 163
128#define MAX_TRACER_SIZE 100 164#define MAX_TRACER_SIZE 100
@@ -3908,7 +3944,169 @@ static const struct file_operations tracing_saved_cmdlines_size_fops = {
3908 .write = tracing_saved_cmdlines_size_write, 3944 .write = tracing_saved_cmdlines_size_write,
3909}; 3945};
3910 3946
3911static void trace_insert_enum_map(struct trace_enum_map **start, int len) 3947#ifdef CONFIG_TRACE_ENUM_MAP_FILE
3948static union trace_enum_map_item *
3949update_enum_map(union trace_enum_map_item *ptr)
3950{
3951 if (!ptr->map.enum_string) {
3952 if (ptr->tail.next) {
3953 ptr = ptr->tail.next;
3954 /* Set ptr to the next real item (skip head) */
3955 ptr++;
3956 } else
3957 return NULL;
3958 }
3959 return ptr;
3960}
3961
3962static void *enum_map_next(struct seq_file *m, void *v, loff_t *pos)
3963{
3964 union trace_enum_map_item *ptr = v;
3965
3966 /*
3967 * Paranoid! If ptr points to end, we don't want to increment past it.
3968 * This really should never happen.
3969 */
3970 ptr = update_enum_map(ptr);
3971 if (WARN_ON_ONCE(!ptr))
3972 return NULL;
3973
3974 ptr++;
3975
3976 (*pos)++;
3977
3978 ptr = update_enum_map(ptr);
3979
3980 return ptr;
3981}
3982
3983static void *enum_map_start(struct seq_file *m, loff_t *pos)
3984{
3985 union trace_enum_map_item *v;
3986 loff_t l = 0;
3987
3988 mutex_lock(&trace_enum_mutex);
3989
3990 v = trace_enum_maps;
3991 if (v)
3992 v++;
3993
3994 while (v && l < *pos) {
3995 v = enum_map_next(m, v, &l);
3996 }
3997
3998 return v;
3999}
4000
4001static void enum_map_stop(struct seq_file *m, void *v)
4002{
4003 mutex_unlock(&trace_enum_mutex);
4004}
4005
4006static int enum_map_show(struct seq_file *m, void *v)
4007{
4008 union trace_enum_map_item *ptr = v;
4009
4010 seq_printf(m, "%s %ld (%s)\n",
4011 ptr->map.enum_string, ptr->map.enum_value,
4012 ptr->map.system);
4013
4014 return 0;
4015}
4016
4017static const struct seq_operations tracing_enum_map_seq_ops = {
4018 .start = enum_map_start,
4019 .next = enum_map_next,
4020 .stop = enum_map_stop,
4021 .show = enum_map_show,
4022};
4023
4024static int tracing_enum_map_open(struct inode *inode, struct file *filp)
4025{
4026 if (tracing_disabled)
4027 return -ENODEV;
4028
4029 return seq_open(filp, &tracing_enum_map_seq_ops);
4030}
4031
4032static const struct file_operations tracing_enum_map_fops = {
4033 .open = tracing_enum_map_open,
4034 .read = seq_read,
4035 .llseek = seq_lseek,
4036 .release = seq_release,
4037};
4038
4039static inline union trace_enum_map_item *
4040trace_enum_jmp_to_tail(union trace_enum_map_item *ptr)
4041{
4042 /* Return tail of array given the head */
4043 return ptr + ptr->head.length + 1;
4044}
4045
4046static void
4047trace_insert_enum_map_file(struct module *mod, struct trace_enum_map **start,
4048 int len)
4049{
4050 struct trace_enum_map **stop;
4051 struct trace_enum_map **map;
4052 union trace_enum_map_item *map_array;
4053 union trace_enum_map_item *ptr;
4054
4055 stop = start + len;
4056
4057 /*
4058 * The trace_enum_maps contains the map plus a head and tail item,
4059 * where the head holds the module and length of array, and the
4060 * tail holds a pointer to the next list.
4061 */
4062 map_array = kmalloc(sizeof(*map_array) * (len + 2), GFP_KERNEL);
4063 if (!map_array) {
4064 pr_warning("Unable to allocate trace enum mapping\n");
4065 return;
4066 }
4067
4068 mutex_lock(&trace_enum_mutex);
4069
4070 if (!trace_enum_maps)
4071 trace_enum_maps = map_array;
4072 else {
4073 ptr = trace_enum_maps;
4074 for (;;) {
4075 ptr = trace_enum_jmp_to_tail(ptr);
4076 if (!ptr->tail.next)
4077 break;
4078 ptr = ptr->tail.next;
4079
4080 }
4081 ptr->tail.next = map_array;
4082 }
4083 map_array->head.mod = mod;
4084 map_array->head.length = len;
4085 map_array++;
4086
4087 for (map = start; (unsigned long)map < (unsigned long)stop; map++) {
4088 map_array->map = **map;
4089 map_array++;
4090 }
4091 memset(map_array, 0, sizeof(*map_array));
4092
4093 mutex_unlock(&trace_enum_mutex);
4094}
4095
4096static void trace_create_enum_file(struct dentry *d_tracer)
4097{
4098 trace_create_file("enum_map", 0444, d_tracer,
4099 NULL, &tracing_enum_map_fops);
4100}
4101
4102#else /* CONFIG_TRACE_ENUM_MAP_FILE */
4103static inline void trace_create_enum_file(struct dentry *d_tracer) { }
4104static inline void trace_insert_enum_map_file(struct module *mod,
4105 struct trace_enum_map **start, int len) { }
4106#endif /* !CONFIG_TRACE_ENUM_MAP_FILE */
4107
4108static void trace_insert_enum_map(struct module *mod,
4109 struct trace_enum_map **start, int len)
3912{ 4110{
3913 struct trace_enum_map **map; 4111 struct trace_enum_map **map;
3914 4112
@@ -3918,6 +4116,8 @@ static void trace_insert_enum_map(struct trace_enum_map **start, int len)
3918 map = start; 4116 map = start;
3919 4117
3920 trace_event_enum_update(map, len); 4118 trace_event_enum_update(map, len);
4119
4120 trace_insert_enum_map_file(mod, start, len);
3921} 4121}
3922 4122
3923static ssize_t 4123static ssize_t
@@ -6562,7 +6762,7 @@ static void __init trace_enum_init(void)
6562 int len; 6762 int len;
6563 6763
6564 len = __stop_ftrace_enum_maps - __start_ftrace_enum_maps; 6764 len = __stop_ftrace_enum_maps - __start_ftrace_enum_maps;
6565 trace_insert_enum_map(__start_ftrace_enum_maps, len); 6765 trace_insert_enum_map(NULL, __start_ftrace_enum_maps, len);
6566} 6766}
6567 6767
6568#ifdef CONFIG_MODULES 6768#ifdef CONFIG_MODULES
@@ -6578,9 +6778,41 @@ static void trace_module_add_enums(struct module *mod)
6578 if (trace_module_has_bad_taint(mod)) 6778 if (trace_module_has_bad_taint(mod))
6579 return; 6779 return;
6580 6780
6581 trace_insert_enum_map(mod->trace_enums, mod->num_trace_enums); 6781 trace_insert_enum_map(mod, mod->trace_enums, mod->num_trace_enums);
6582} 6782}
6583 6783
6784#ifdef CONFIG_TRACE_ENUM_MAP_FILE
6785static void trace_module_remove_enums(struct module *mod)
6786{
6787 union trace_enum_map_item *map;
6788 union trace_enum_map_item **last = &trace_enum_maps;
6789
6790 if (!mod->num_trace_enums)
6791 return;
6792
6793 mutex_lock(&trace_enum_mutex);
6794
6795 map = trace_enum_maps;
6796
6797 while (map) {
6798 if (map->head.mod == mod)
6799 break;
6800 map = trace_enum_jmp_to_tail(map);
6801 last = &map->tail.next;
6802 map = map->tail.next;
6803 }
6804 if (!map)
6805 goto out;
6806
6807 *last = trace_enum_jmp_to_tail(map)->tail.next;
6808 kfree(map);
6809 out:
6810 mutex_unlock(&trace_enum_mutex);
6811}
6812#else
6813static inline void trace_module_remove_enums(struct module *mod) { }
6814#endif /* CONFIG_TRACE_ENUM_MAP_FILE */
6815
6584static int trace_module_notify(struct notifier_block *self, 6816static int trace_module_notify(struct notifier_block *self,
6585 unsigned long val, void *data) 6817 unsigned long val, void *data)
6586{ 6818{
@@ -6590,6 +6822,9 @@ static int trace_module_notify(struct notifier_block *self,
6590 case MODULE_STATE_COMING: 6822 case MODULE_STATE_COMING:
6591 trace_module_add_enums(mod); 6823 trace_module_add_enums(mod);
6592 break; 6824 break;
6825 case MODULE_STATE_GOING:
6826 trace_module_remove_enums(mod);
6827 break;
6593 } 6828 }
6594 6829
6595 return 0; 6830 return 0;
@@ -6599,7 +6834,7 @@ static struct notifier_block trace_module_nb = {
6599 .notifier_call = trace_module_notify, 6834 .notifier_call = trace_module_notify,
6600 .priority = 0, 6835 .priority = 0,
6601}; 6836};
6602#endif 6837#endif /* CONFIG_MODULES */
6603 6838
6604static __init int tracer_init_debugfs(void) 6839static __init int tracer_init_debugfs(void)
6605{ 6840{
@@ -6627,6 +6862,8 @@ static __init int tracer_init_debugfs(void)
6627 6862
6628 trace_enum_init(); 6863 trace_enum_init();
6629 6864
6865 trace_create_enum_file(d_tracer);
6866
6630#ifdef CONFIG_MODULES 6867#ifdef CONFIG_MODULES
6631 register_module_notifier(&trace_module_nb); 6868 register_module_notifier(&trace_module_nb);
6632#endif 6869#endif