linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Steven Rostedt <rostedt@goodmis.org>
To: linux-kernel@vger.kernel.org
Cc: Ingo Molnar <mingo@kernel.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	Arnaldo Carvalho de Melo <acme@kernel.org>,
	Namhyung Kim <namhyung@kernel.org>,
	Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>,
	Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Subject: [PATCH 18/18 v3] tracing: Add enum_map file to show enums that have been mapped
Date: Thu, 02 Apr 2015 21:38:20 -0400	[thread overview]
Message-ID: <20150403014125.862025292@goodmis.org> (raw)
In-Reply-To: 20150403013802.220157513@goodmis.org

[-- Attachment #1: 0018-tracing-Add-enum_map-file-to-show-enums-that-have-be.patch --]
[-- Type: text/plain, Size: 9834 bytes --]

From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>

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.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 kernel/trace/Kconfig |  28 ++++++
 kernel/trace/trace.c | 245 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 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
 
 	 If unsure, say N
 
+config TRACE_ENUM_MAP_FILE
+       bool "Show enum mappings for trace events"
+       depends on TRACING
+       help
+        The "print fmt" of the trace events will show the enum names instead
+	of their values. This can cause problems for user space tools that
+	use this string to parse the raw data as user space does not know
+	how to convert the string to its value.
+
+	To fix this, there's a special macro in the kernel that can be used
+	to convert the enum into its value. If this macro is used, then the
+	print fmt strings will have the enums converted to their values.
+
+	If something does not get converted properly, this option can be
+	used to show what enums the kernel tried to convert.
+
+	This option is for debugging the enum conversions. A file is created
+	in the tracing directory called "enum_map" that will show the enum
+	names matched with their values and what trace event system they
+	belong too.
+
+	Normally, the mapping of the strings to values will be freed after
+	boot up or module load. With this option, they will not be freed, as
+	they are needed for the "enum_map" file. Enabling this option will
+	increase the memory footprint of the running kernel.
+
+	If unsure, say N
+
 endif # FTRACE
 
 endif # 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;
 /* When set, tracing will stop when a WARN*() is hit */
 int __disable_trace_on_warning;
 
+#ifdef CONFIG_TRACE_ENUM_MAP_FILE
+/* Map of enums to their values, for "enum_map" file */
+struct trace_enum_map_head {
+	struct module			*mod;
+	unsigned long			length;
+};
+
+union trace_enum_map_item;
+
+struct trace_enum_map_tail {
+	/*
+	 * "end" is first and points to NULL as it must be different
+	 * than "mod" or "enum_string"
+	 */
+	union trace_enum_map_item	*next;
+	const char			*end;	/* points to NULL */
+};
+
+static DEFINE_MUTEX(trace_enum_mutex);
+
+/*
+ * The trace_enum_maps are saved in an array with two extra elements,
+ * one at the beginning, and one at the end. The beginning item contains
+ * the count of the saved maps (head.length), and the module they
+ * belong to if not built in (head.mod). The ending item contains a
+ * pointer to the next array of saved enum_map items.
+ */
+union trace_enum_map_item {
+	struct trace_enum_map		map;
+	struct trace_enum_map_head	head;
+	struct trace_enum_map_tail	tail;
+};
+
+static union trace_enum_map_item *trace_enum_maps;
+#endif /* CONFIG_TRACE_ENUM_MAP_FILE */
+
 static int tracing_set_tracer(struct trace_array *tr, const char *buf);
 
 #define MAX_TRACER_SIZE		100
@@ -3908,7 +3944,169 @@ static const struct file_operations tracing_saved_cmdlines_size_fops = {
 	.write		= tracing_saved_cmdlines_size_write,
 };
 
-static void trace_insert_enum_map(struct trace_enum_map **start, int len)
+#ifdef CONFIG_TRACE_ENUM_MAP_FILE
+static union trace_enum_map_item *
+update_enum_map(union trace_enum_map_item *ptr)
+{
+	if (!ptr->map.enum_string) {
+		if (ptr->tail.next) {
+			ptr = ptr->tail.next;
+			/* Set ptr to the next real item (skip head) */
+			ptr++;
+		} else
+			return NULL;
+	}
+	return ptr;
+}
+
+static void *enum_map_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	union trace_enum_map_item *ptr = v;
+
+	/*
+	 * Paranoid! If ptr points to end, we don't want to increment past it.
+	 * This really should never happen.
+	 */
+	ptr = update_enum_map(ptr);
+	if (WARN_ON_ONCE(!ptr))
+		return NULL;
+
+	ptr++;
+
+	(*pos)++;
+
+	ptr = update_enum_map(ptr);
+
+	return ptr;
+}
+
+static void *enum_map_start(struct seq_file *m, loff_t *pos)
+{
+	union trace_enum_map_item *v;
+	loff_t l = 0;
+
+	mutex_lock(&trace_enum_mutex);
+
+	v = trace_enum_maps;
+	if (v)
+		v++;
+
+	while (v && l < *pos) {
+		v = enum_map_next(m, v, &l);
+	}
+
+	return v;
+}
+
+static void enum_map_stop(struct seq_file *m, void *v)
+{
+	mutex_unlock(&trace_enum_mutex);
+}
+
+static int enum_map_show(struct seq_file *m, void *v)
+{
+	union trace_enum_map_item *ptr = v;
+
+	seq_printf(m, "%s %ld (%s)\n",
+		   ptr->map.enum_string, ptr->map.enum_value,
+		   ptr->map.system);
+
+	return 0;
+}
+
+static const struct seq_operations tracing_enum_map_seq_ops = {
+	.start		= enum_map_start,
+	.next		= enum_map_next,
+	.stop		= enum_map_stop,
+	.show		= enum_map_show,
+};
+
+static int tracing_enum_map_open(struct inode *inode, struct file *filp)
+{
+	if (tracing_disabled)
+		return -ENODEV;
+
+	return seq_open(filp, &tracing_enum_map_seq_ops);
+}
+
+static const struct file_operations tracing_enum_map_fops = {
+	.open		= tracing_enum_map_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
+static inline union trace_enum_map_item *
+trace_enum_jmp_to_tail(union trace_enum_map_item *ptr)
+{
+	/* Return tail of array given the head */
+	return ptr + ptr->head.length + 1;
+}
+
+static void
+trace_insert_enum_map_file(struct module *mod, struct trace_enum_map **start,
+			   int len)
+{
+	struct trace_enum_map **stop;
+	struct trace_enum_map **map;
+	union trace_enum_map_item *map_array;
+	union trace_enum_map_item *ptr;
+
+	stop = start + len;
+
+	/*
+	 * The trace_enum_maps contains the map plus a head and tail item,
+	 * where the head holds the module and length of array, and the
+	 * tail holds a pointer to the next list.
+	 */
+	map_array = kmalloc(sizeof(*map_array) * (len + 2), GFP_KERNEL);
+	if (!map_array) {
+		pr_warning("Unable to allocate trace enum mapping\n");
+		return;
+	}
+
+	mutex_lock(&trace_enum_mutex);
+
+	if (!trace_enum_maps)
+		trace_enum_maps = map_array;
+	else {
+		ptr = trace_enum_maps;
+		for (;;) {
+			ptr = trace_enum_jmp_to_tail(ptr);
+			if (!ptr->tail.next)
+				break;
+			ptr = ptr->tail.next;
+
+		}
+		ptr->tail.next = map_array;
+	}
+	map_array->head.mod = mod;
+	map_array->head.length = len;
+	map_array++;
+
+	for (map = start; (unsigned long)map < (unsigned long)stop; map++) {
+		map_array->map = **map;
+		map_array++;
+	}
+	memset(map_array, 0, sizeof(*map_array));
+
+	mutex_unlock(&trace_enum_mutex);
+}
+
+static void trace_create_enum_file(struct dentry *d_tracer)
+{
+	trace_create_file("enum_map", 0444, d_tracer,
+			  NULL, &tracing_enum_map_fops);
+}
+
+#else /* CONFIG_TRACE_ENUM_MAP_FILE */
+static inline void trace_create_enum_file(struct dentry *d_tracer) { }
+static inline void trace_insert_enum_map_file(struct module *mod,
+			      struct trace_enum_map **start, int len) { }
+#endif /* !CONFIG_TRACE_ENUM_MAP_FILE */
+
+static void trace_insert_enum_map(struct module *mod,
+				  struct trace_enum_map **start, int len)
 {
 	struct trace_enum_map **map;
 
@@ -3918,6 +4116,8 @@ static void trace_insert_enum_map(struct trace_enum_map **start, int len)
 	map = start;
 
 	trace_event_enum_update(map, len);
+
+	trace_insert_enum_map_file(mod, start, len);
 }
 
 static ssize_t
@@ -6562,7 +6762,7 @@ static void __init trace_enum_init(void)
 	int len;
 
 	len = __stop_ftrace_enum_maps - __start_ftrace_enum_maps;
-	trace_insert_enum_map(__start_ftrace_enum_maps, len);
+	trace_insert_enum_map(NULL, __start_ftrace_enum_maps, len);
 }
 
 #ifdef CONFIG_MODULES
@@ -6578,9 +6778,41 @@ static void trace_module_add_enums(struct module *mod)
 	if (trace_module_has_bad_taint(mod))
 		return;
 
-	trace_insert_enum_map(mod->trace_enums, mod->num_trace_enums);
+	trace_insert_enum_map(mod, mod->trace_enums, mod->num_trace_enums);
 }
 
+#ifdef CONFIG_TRACE_ENUM_MAP_FILE
+static void trace_module_remove_enums(struct module *mod)
+{
+	union trace_enum_map_item *map;
+	union trace_enum_map_item **last = &trace_enum_maps;
+
+	if (!mod->num_trace_enums)
+		return;
+
+	mutex_lock(&trace_enum_mutex);
+
+	map = trace_enum_maps;
+
+	while (map) {
+		if (map->head.mod == mod)
+			break;
+		map = trace_enum_jmp_to_tail(map);
+		last = &map->tail.next;
+		map = map->tail.next;
+	}
+	if (!map)
+		goto out;
+
+	*last = trace_enum_jmp_to_tail(map)->tail.next;
+	kfree(map);
+ out:
+	mutex_unlock(&trace_enum_mutex);
+}
+#else
+static inline void trace_module_remove_enums(struct module *mod) { }
+#endif /* CONFIG_TRACE_ENUM_MAP_FILE */
+
 static int trace_module_notify(struct notifier_block *self,
 			       unsigned long val, void *data)
 {
@@ -6590,6 +6822,9 @@ static int trace_module_notify(struct notifier_block *self,
 	case MODULE_STATE_COMING:
 		trace_module_add_enums(mod);
 		break;
+	case MODULE_STATE_GOING:
+		trace_module_remove_enums(mod);
+		break;
 	}
 
 	return 0;
@@ -6599,7 +6834,7 @@ static struct notifier_block trace_module_nb = {
 	.notifier_call = trace_module_notify,
 	.priority = 0,
 };
-#endif
+#endif /* CONFIG_MODULES */
 
 static __init int tracer_init_debugfs(void)
 {
@@ -6627,6 +6862,8 @@ static __init int tracer_init_debugfs(void)
 
 	trace_enum_init();
 
+	trace_create_enum_file(d_tracer);
+
 #ifdef CONFIG_MODULES
 	register_module_notifier(&trace_module_nb);
 #endif
-- 
2.1.4



  parent reply	other threads:[~2015-04-03  1:42 UTC|newest]

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-04-03  1:38 [PATCH 00/18 v3] tracing: Use TRACE_DEFINE_ENUM() to show enum values Steven Rostedt
2015-04-03  1:38 ` [PATCH 02/18 v3] tracing: Add TRACE_SYSTEM_VAR to intel-sst Steven Rostedt
2015-04-03  1:38 ` [PATCH 03/18 v3] tracing: Add TRACE_SYSTEM_VAR to kvm-s390 Steven Rostedt
2015-04-03  1:38 ` [PATCH 04/18 v3] tracing: Add TRACE_SYSTEM_VAR to xhci-hcd Steven Rostedt
2015-04-03  1:38 ` [PATCH 05/18 v3] tracing: Give system name a pointer Steven Rostedt
2015-04-03  1:38 ` [PATCH 06/18 v3] tracing: Update trace-event-sample with TRACE_SYSTEM_VAR documentation Steven Rostedt
2015-04-03  1:38 ` [PATCH 07/18 v3] tracing: Add TRACE_DEFINE_ENUM() macro to map enums to their values Steven Rostedt
2015-04-06  4:54   ` Namhyung Kim
2015-04-06 11:52     ` Steven Rostedt
2015-04-07 14:16       ` Namhyung Kim
2015-04-07 14:22         ` Steven Rostedt
2015-04-15 13:22   ` Sasha Levin
2015-04-15 14:05     ` Steven Rostedt
2015-04-16  0:58       ` Sasha Levin
2015-04-17  3:21         ` Steven Rostedt
2015-04-17  3:59           ` Sasha Levin
2015-04-17  4:44             ` [PATCH] kasan: Show gcc version requirements in Kconfig and Documentation Joe Perches
2015-04-17  7:54               ` Andrey Ryabinin
2015-04-17  9:37                 ` Joe Perches
2015-04-17 16:10                   ` [PATCH v2] " Andrey Ryabinin
2015-05-07 15:51                     ` Jonathan Corbet
2015-05-07 19:00                       ` Andrey Ryabinin
2015-04-17  7:44             ` [PATCH 07/18 v3] tracing: Add TRACE_DEFINE_ENUM() macro to map enums to their values Andrey Ryabinin
2015-04-17 13:29               ` Steven Rostedt
2015-04-17 13:51                 ` Steven Rostedt
2015-04-17 14:14                   ` Andrey Ryabinin
2015-04-03  1:38 ` [PATCH 08/18 v3] tracing: Allow for modules to convert their enums to values Steven Rostedt
2015-04-03  1:38 ` [PATCH 09/18 v3] tracing/samples: Update the trace-event-sample.h with TRACE_DEFINE_ENUM() Steven Rostedt
2015-04-03  1:38 ` [PATCH 10/18 v3] x86/tlb/trace: Export enums in used by tlb_flush tracepoint Steven Rostedt
2015-04-03  1:38 ` [PATCH 11/18 v3] net/9p/tracing: Export enums in tracepoints to userspace Steven Rostedt
2015-04-03  1:38 ` [PATCH 12/18 v3] f2fs: Export the enums in the " Steven Rostedt
2015-04-03  1:38 ` [PATCH 13/18 v3] irq/tracing: Export enums in tracepoints to user space Steven Rostedt
2015-04-03  1:38 ` [PATCH 14/18 v3] mm: tracing: " Steven Rostedt
2015-04-03  1:38 ` [PATCH 15/18 v3] SUNRPC: " Steven Rostedt
2015-04-07 16:40   ` Steven Rostedt
2015-04-07 16:58     ` Trond Myklebust
2015-04-03  1:38 ` [PATCH 16/18 v3] v4l: Export enums used by " Steven Rostedt
2015-04-03  1:38 ` [PATCH 17/18 v3] writeback: Export enums used by tracepoint " Steven Rostedt
2015-04-03  1:38 ` Steven Rostedt [this message]
     [not found] ` <20150403014123.069113130@goodmis.org>
2015-04-07  0:47   ` [PATCH 01/18 v3] tracing/drm: Remove unused TRACE_SYSTEM_STRING define Masami Hiramatsu
2015-04-07 11:26 ` [PATCH 00/18 v3] tracing: Use TRACE_DEFINE_ENUM() to show enum values Masami Hiramatsu
2015-04-07 12:52   ` Steven Rostedt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20150403014125.862025292@goodmis.org \
    --to=rostedt@goodmis.org \
    --cc=acme@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=masami.hiramatsu.pt@hitachi.com \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=mingo@kernel.org \
    --cc=namhyung@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).