Skip to content

Commit 9828413

Browse files
committed
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>
1 parent 91df608 commit 9828413

File tree

2 files changed

+269
-4
lines changed

2 files changed

+269
-4
lines changed

kernel/trace/Kconfig

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,34 @@ config RING_BUFFER_STARTUP_TEST
599599

600600
If unsure, say N
601601

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+
602630
endif # FTRACE
603631

604632
endif # TRACING_SUPPORT

kernel/trace/trace.c

Lines changed: 241 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,42 @@ enum ftrace_dump_mode ftrace_dump_on_oops;
123123
/* When set, tracing will stop when a WARN*() is hit */
124124
int __disable_trace_on_warning;
125125

126+
#ifdef CONFIG_TRACE_ENUM_MAP_FILE
127+
/* Map of enums to their values, for "enum_map" file */
128+
struct trace_enum_map_head {
129+
struct module *mod;
130+
unsigned long length;
131+
};
132+
133+
union trace_enum_map_item;
134+
135+
struct 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+
144+
static 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+
*/
153+
union 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+
159+
static union trace_enum_map_item *trace_enum_maps;
160+
#endif /* CONFIG_TRACE_ENUM_MAP_FILE */
161+
126162
static int tracing_set_tracer(struct trace_array *tr, const char *buf);
127163

128164
#define MAX_TRACER_SIZE 100
@@ -3908,7 +3944,169 @@ static const struct file_operations tracing_saved_cmdlines_size_fops = {
39083944
.write = tracing_saved_cmdlines_size_write,
39093945
};
39103946

3911-
static void trace_insert_enum_map(struct trace_enum_map **start, int len)
3947+
#ifdef CONFIG_TRACE_ENUM_MAP_FILE
3948+
static union trace_enum_map_item *
3949+
update_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+
3962+
static 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+
3983+
static 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+
4001+
static void enum_map_stop(struct seq_file *m, void *v)
4002+
{
4003+
mutex_unlock(&trace_enum_mutex);
4004+
}
4005+
4006+
static 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+
4017+
static 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+
4024+
static 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+
4032+
static 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+
4039+
static inline union trace_enum_map_item *
4040+
trace_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+
4046+
static void
4047+
trace_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+
4096+
static 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 */
4103+
static inline void trace_create_enum_file(struct dentry *d_tracer) { }
4104+
static 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+
4108+
static void trace_insert_enum_map(struct module *mod,
4109+
struct trace_enum_map **start, int len)
39124110
{
39134111
struct trace_enum_map **map;
39144112

@@ -3918,6 +4116,8 @@ static void trace_insert_enum_map(struct trace_enum_map **start, int len)
39184116
map = start;
39194117

39204118
trace_event_enum_update(map, len);
4119+
4120+
trace_insert_enum_map_file(mod, start, len);
39214121
}
39224122

39234123
static ssize_t
@@ -6562,7 +6762,7 @@ static void __init trace_enum_init(void)
65626762
int len;
65636763

65646764
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);
65666766
}
65676767

65686768
#ifdef CONFIG_MODULES
@@ -6578,9 +6778,41 @@ static void trace_module_add_enums(struct module *mod)
65786778
if (trace_module_has_bad_taint(mod))
65796779
return;
65806780

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);
65826782
}
65836783

6784+
#ifdef CONFIG_TRACE_ENUM_MAP_FILE
6785+
static 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
6813+
static inline void trace_module_remove_enums(struct module *mod) { }
6814+
#endif /* CONFIG_TRACE_ENUM_MAP_FILE */
6815+
65846816
static int trace_module_notify(struct notifier_block *self,
65856817
unsigned long val, void *data)
65866818
{
@@ -6590,6 +6822,9 @@ static int trace_module_notify(struct notifier_block *self,
65906822
case MODULE_STATE_COMING:
65916823
trace_module_add_enums(mod);
65926824
break;
6825+
case MODULE_STATE_GOING:
6826+
trace_module_remove_enums(mod);
6827+
break;
65936828
}
65946829

65956830
return 0;
@@ -6599,7 +6834,7 @@ static struct notifier_block trace_module_nb = {
65996834
.notifier_call = trace_module_notify,
66006835
.priority = 0,
66016836
};
6602-
#endif
6837+
#endif /* CONFIG_MODULES */
66036838

66046839
static __init int tracer_init_debugfs(void)
66056840
{
@@ -6627,6 +6862,8 @@ static __init int tracer_init_debugfs(void)
66276862

66286863
trace_enum_init();
66296864

6865+
trace_create_enum_file(d_tracer);
6866+
66306867
#ifdef CONFIG_MODULES
66316868
register_module_notifier(&trace_module_nb);
66326869
#endif

0 commit comments

Comments
 (0)