All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC][PATCH 0/5] tracing: Allow module init functions to be traced
@ 2017-09-19 14:28 Steven Rostedt
  2017-09-19 14:28 ` [RFC][PATCH 1/5] ftrace: Add a ftrace_free_mem() function for modules to use Steven Rostedt
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Steven Rostedt @ 2017-09-19 14:28 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton, Jessica Yu, Rusty Russell

Last release, module functions can be enabled before they are loaded
by echoing in ":mod:module-name" into set_ftrace_filter before the
module is loaded. When the module is loaded, its functions will be
enabled for tracing. Now it makes sense to enable module init functions
as well (kernel init functions can already be traced).

The first patch adds a function ftrace_free_mem() to let module code
tell ftrace to free the init functions from its tables so that new
enabling or disabling of function tracing does not try to modify
text that no longer exists in memory.

The second patch enables tracing of init functions from within modules.

The third patch adds kallsyms of those init functions so they look
like funtion names and not function pointers within the trace.

The fourth patch frees the saved kallsym name maps of the function
names to the module init addresses.

The last patch has kallsyms display the module init functions.


Steven Rostedt (VMware) (5):
      ftrace: Add a ftrace_free_mem() function for modules to use
      ftrace: Allow module init functions to be traced
      ftrace: Save module init functions kallsyms symbols for tracing
      ftrace: Add freeing algorithm to free ftrace_mod_maps
      ftrace/kallsyms: Have /proc/kallsyms show saved mod init functions

----
 include/linux/ftrace.h |  26 ++++++
 include/linux/init.h   |   4 +-
 kernel/kallsyms.c      |  38 +++++++--
 kernel/module.c        |   2 +
 kernel/trace/ftrace.c  | 226 ++++++++++++++++++++++++++++++++++++++++++++++++-
 5 files changed, 284 insertions(+), 12 deletions(-)

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [RFC][PATCH 1/5] ftrace: Add a ftrace_free_mem() function for modules to use
  2017-09-19 14:28 [RFC][PATCH 0/5] tracing: Allow module init functions to be traced Steven Rostedt
@ 2017-09-19 14:28 ` Steven Rostedt
  2017-09-19 14:28 ` [RFC][PATCH 2/5] ftrace: Allow module init functions to be traced Steven Rostedt
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 11+ messages in thread
From: Steven Rostedt @ 2017-09-19 14:28 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton, Jessica Yu, Rusty Russell

[-- Attachment #1: 0001-ftrace-Add-a-ftrace_free_mem-function-for-modules-to.patch --]
[-- Type: text/plain, Size: 1977 bytes --]

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

In order to be able to trace module init functions, the module code needs to
tell ftrace what is being freed when the init sections are freed. Use the
code that the main init calls to tell ftrace to free the main init sections.
This requires passing in a start and end address to free.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 include/linux/ftrace.h |  2 ++
 kernel/trace/ftrace.c  | 14 +++++++++++---
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 2e028854bac7..47fc404ad233 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -151,8 +151,10 @@ struct ftrace_ops_hash {
 };
 
 void ftrace_free_init_mem(void);
+void ftrace_free_mem(void *start, void *end);
 #else
 static inline void ftrace_free_init_mem(void) { }
+static inline void ftrace_free_mem(void *start, void *end) { }
 #endif
 
 /*
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 6abfafd7f173..84cb5928665a 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -5868,10 +5868,10 @@ void ftrace_module_init(struct module *mod)
 }
 #endif /* CONFIG_MODULES */
 
-void __init ftrace_free_init_mem(void)
+void ftrace_free_mem(void *start_ptr, void *end_ptr)
 {
-	unsigned long start = (unsigned long)(&__init_begin);
-	unsigned long end = (unsigned long)(&__init_end);
+	unsigned long start = (unsigned long)(start_ptr);
+	unsigned long end = (unsigned long)(end_ptr);
 	struct ftrace_page **last_pg = &ftrace_pages_start;
 	struct ftrace_page *pg;
 	struct dyn_ftrace *rec;
@@ -5913,6 +5913,14 @@ void __init ftrace_free_init_mem(void)
 	mutex_unlock(&ftrace_lock);
 }
 
+void __init ftrace_free_init_mem(void)
+{
+	void *start = (void *)(&__init_begin);
+	void *end = (void *)(&__init_end);
+
+	ftrace_free_mem(start, end);
+}
+
 void __init ftrace_init(void)
 {
 	extern unsigned long __start_mcount_loc[];
-- 
2.13.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC][PATCH 2/5] ftrace: Allow module init functions to be traced
  2017-09-19 14:28 [RFC][PATCH 0/5] tracing: Allow module init functions to be traced Steven Rostedt
  2017-09-19 14:28 ` [RFC][PATCH 1/5] ftrace: Add a ftrace_free_mem() function for modules to use Steven Rostedt
@ 2017-09-19 14:28 ` Steven Rostedt
  2017-09-19 14:28 ` [RFC][PATCH 3/5] ftrace: Save module init functions kallsyms symbols for tracing Steven Rostedt
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 11+ messages in thread
From: Steven Rostedt @ 2017-09-19 14:28 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton, Jessica Yu, Rusty Russell

[-- Attachment #1: 0002-ftrace-Allow-module-init-functions-to-be-traced.patch --]
[-- Type: text/plain, Size: 2260 bytes --]

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

Allow for module init sections to be traced as well as core kernel init
sections. Now that filtering modules functions can be stored, for when they
are loaded, it makes sense to be able to trace them.

Cc: Jessica Yu <jeyu@kernel.org>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 include/linux/init.h  | 4 +---
 kernel/module.c       | 2 ++
 kernel/trace/ftrace.c | 3 ++-
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/include/linux/init.h b/include/linux/init.h
index 94769d687cf0..a779c1816437 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -39,7 +39,7 @@
 
 /* These are for everybody (although not all archs will actually
    discard it in modules) */
-#define __init		__section(.init.text) __cold __inittrace __latent_entropy
+#define __init		__section(.init.text) __cold  __latent_entropy
 #define __initdata	__section(.init.data)
 #define __initconst	__section(.init.rodata)
 #define __exitdata	__section(.exit.data)
@@ -68,10 +68,8 @@
 
 #ifdef MODULE
 #define __exitused
-#define __inittrace notrace
 #else
 #define __exitused  __used
-#define __inittrace
 #endif
 
 #define __exit          __section(.exit.text) __exitused __cold notrace
diff --git a/kernel/module.c b/kernel/module.c
index 40f983cbea81..c1267ae10239 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -3473,6 +3473,8 @@ static noinline int do_init_module(struct module *mod)
 	if (!mod->async_probe_requested && (current->flags & PF_USED_ASYNC))
 		async_synchronize_full();
 
+	ftrace_free_mem(mod->init_layout.base, mod->init_layout.base +
+			mod->init_layout.size);
 	mutex_lock(&module_mutex);
 	/* Drop initial reference. */
 	module_put(mod);
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 84cb5928665a..7f7c56d532fd 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -5821,7 +5821,8 @@ void ftrace_module_enable(struct module *mod)
 		 * not part of this module, then skip this pg,
 		 * which the "break" will do.
 		 */
-		if (!within_module_core(rec->ip, mod))
+		if (!within_module_core(rec->ip, mod) &&
+		    !within_module_init(rec->ip, mod))
 			break;
 
 		cnt = 0;
-- 
2.13.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC][PATCH 3/5] ftrace: Save module init functions kallsyms symbols for tracing
  2017-09-19 14:28 [RFC][PATCH 0/5] tracing: Allow module init functions to be traced Steven Rostedt
  2017-09-19 14:28 ` [RFC][PATCH 1/5] ftrace: Add a ftrace_free_mem() function for modules to use Steven Rostedt
  2017-09-19 14:28 ` [RFC][PATCH 2/5] ftrace: Allow module init functions to be traced Steven Rostedt
@ 2017-09-19 14:28 ` Steven Rostedt
  2017-10-06 20:55   ` Jessica Yu
  2017-09-19 14:28 ` [RFC][PATCH 4/5] ftrace: Add freeing algorithm to free ftrace_mod_maps Steven Rostedt
  2017-09-19 14:28 ` [RFC][PATCH 5/5] ftrace/kallsyms: Have /proc/kallsyms show saved mod init functions Steven Rostedt
  4 siblings, 1 reply; 11+ messages in thread
From: Steven Rostedt @ 2017-09-19 14:28 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton, Jessica Yu, Rusty Russell

[-- Attachment #1: 0003-ftrace-Save-module-init-functions-kallsyms-symbols-f.patch --]
[-- Type: text/plain, Size: 10813 bytes --]

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

If function tracing is active when the module init functions are freed, then
store them to be referenced by kallsyms. As module init functions can now be
traced on module load, they were useless:

 ># echo ':mod:snd_seq' > set_ftrace_filter
 ># echo function > current_tracer
 ># modprobe snd_seq
 ># cat trace
 # tracer: function
 #
 #                              _-----=> irqs-off
 #                             / _----=> need-resched
 #                            | / _---=> hardirq/softirq
 #                            || / _--=> preempt-depth
 #                            ||| /     delay
 #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
 #              | |       |   ||||       |         |
         modprobe-2786  [000] ....  3189.037874: 0xffffffffa0860000 <-do_one_initcall
         modprobe-2786  [000] ....  3189.037876: 0xffffffffa086004d <-0xffffffffa086000f
         modprobe-2786  [000] ....  3189.037876: 0xffffffffa086010d <-0xffffffffa0860018
         modprobe-2786  [000] ....  3189.037877: 0xffffffffa086011a <-0xffffffffa0860021
         modprobe-2786  [000] ....  3189.037877: 0xffffffffa0860080 <-0xffffffffa086002a
         modprobe-2786  [000] ....  3189.039523: 0xffffffffa0860400 <-0xffffffffa0860033
         modprobe-2786  [000] ....  3189.039523: 0xffffffffa086038a <-0xffffffffa086041c
         modprobe-2786  [000] ....  3189.039591: 0xffffffffa086038a <-0xffffffffa0860436
         modprobe-2786  [000] ....  3189.039657: 0xffffffffa086038a <-0xffffffffa0860450
         modprobe-2786  [000] ....  3189.039719: 0xffffffffa0860127 <-0xffffffffa086003c
         modprobe-2786  [000] ....  3189.039742: snd_seq_create_kernel_client <-0xffffffffa08601f6

When the output is shown, the kallsyms for the module init functions have
already been freed, and the output of the trace can not convert them to
their function names.

Now this looks like this:

 # tracer: function
 #
 #                              _-----=> irqs-off
 #                             / _----=> need-resched
 #                            | / _---=> hardirq/softirq
 #                            || / _--=> preempt-depth
 #                            ||| /     delay
 #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
 #              | |       |   ||||       |         |
         modprobe-2463  [002] ....   174.243237: alsa_seq_init <-do_one_initcall
         modprobe-2463  [002] ....   174.243239: client_init_data <-alsa_seq_init
         modprobe-2463  [002] ....   174.243240: snd_sequencer_memory_init <-alsa_seq_init
         modprobe-2463  [002] ....   174.243240: snd_seq_queues_init <-alsa_seq_init
         modprobe-2463  [002] ....   174.243240: snd_sequencer_device_init <-alsa_seq_init
         modprobe-2463  [002] ....   174.244860: snd_seq_info_init <-alsa_seq_init
         modprobe-2463  [002] ....   174.244861: create_info_entry <-snd_seq_info_init
         modprobe-2463  [002] ....   174.244936: create_info_entry <-snd_seq_info_init
         modprobe-2463  [002] ....   174.245003: create_info_entry <-snd_seq_info_init
         modprobe-2463  [002] ....   174.245072: snd_seq_system_client_init <-alsa_seq_init
         modprobe-2463  [002] ....   174.245094: snd_seq_create_kernel_client <-snd_seq_system_client_init

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 include/linux/ftrace.h |  19 ++++++-
 kernel/kallsyms.c      |   5 ++
 kernel/module.c        |   2 +-
 kernel/trace/ftrace.c  | 145 ++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 166 insertions(+), 5 deletions(-)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 47fc404ad233..99b770228739 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -51,6 +51,21 @@ static inline void early_trace_init(void) { }
 struct module;
 struct ftrace_hash;
 
+#if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_MODULES) && \
+	defined(CONFIG_DYNAMIC_FTRACE)
+const char *
+ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
+		   unsigned long *off, char **modname, char *sym);
+#else
+static inline const char *
+ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
+		   unsigned long *off, char **modname, char *sym)
+{
+	return NULL;
+}
+#endif
+
+
 #ifdef CONFIG_FUNCTION_TRACER
 
 extern int ftrace_enabled;
@@ -151,10 +166,10 @@ struct ftrace_ops_hash {
 };
 
 void ftrace_free_init_mem(void);
-void ftrace_free_mem(void *start, void *end);
+void ftrace_free_mem(struct module *mod, void *start, void *end);
 #else
 static inline void ftrace_free_init_mem(void) { }
-static inline void ftrace_free_mem(void *start, void *end) { }
+static inline void ftrace_free_mem(struct module *mod, void *start, void *end) { }
 #endif
 
 /*
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index 127e7cfafa55..976ecb9275d9 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -24,6 +24,7 @@
 #include <linux/ctype.h>
 #include <linux/slab.h>
 #include <linux/filter.h>
+#include <linux/ftrace.h>
 #include <linux/compiler.h>
 
 #include <asm/sections.h>
@@ -337,6 +338,10 @@ const char *kallsyms_lookup(unsigned long addr,
 	if (!ret)
 		ret = bpf_address_lookup(addr, symbolsize,
 					 offset, modname, namebuf);
+
+	if (!ret)
+		ret = ftrace_mod_address_lookup(addr, symbolsize,
+						offset, modname, namebuf);
 	return ret;
 }
 
diff --git a/kernel/module.c b/kernel/module.c
index c1267ae10239..d0f48e402572 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -3473,7 +3473,7 @@ static noinline int do_init_module(struct module *mod)
 	if (!mod->async_probe_requested && (current->flags & PF_USED_ASYNC))
 		async_synchronize_full();
 
-	ftrace_free_mem(mod->init_layout.base, mod->init_layout.base +
+	ftrace_free_mem(mod, mod->init_layout.base, mod->init_layout.base +
 			mod->init_layout.size);
 	mutex_lock(&module_mutex);
 	/* Drop initial reference. */
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 7f7c56d532fd..2aad52802d70 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -5675,6 +5675,21 @@ static int ftrace_process_locs(struct module *mod,
 	return ret;
 }
 
+struct ftrace_mod_func {
+	struct list_head	list;
+	char			*name;
+	unsigned long		ip;
+	unsigned int		size;
+};
+
+struct ftrace_mod_map {
+	struct list_head	list;
+	struct module		*mod;
+	unsigned long		start_addr;
+	unsigned long		end_addr;
+	struct list_head	funcs;
+};
+
 #ifdef CONFIG_MODULES
 
 #define next_to_ftrace_page(p) container_of(p, struct ftrace_page, next)
@@ -5867,9 +5882,122 @@ void ftrace_module_init(struct module *mod)
 	ftrace_process_locs(mod, mod->ftrace_callsites,
 			    mod->ftrace_callsites + mod->num_ftrace_callsites);
 }
+
+static void save_ftrace_mod_rec(struct ftrace_mod_map *mod_map,
+				struct dyn_ftrace *rec)
+{
+	struct ftrace_mod_func *mod_func;
+	unsigned long symsize;
+	unsigned long offset;
+	char str[KSYM_SYMBOL_LEN];
+	char *modname;
+	const char *ret;
+
+	ret = kallsyms_lookup(rec->ip, &symsize, &offset, &modname, str);
+	if (!ret)
+		return;
+
+	mod_func = kmalloc(sizeof(*mod_func), GFP_KERNEL);
+	if (!mod_func)
+		return;
+
+	mod_func->name = kstrdup(str, GFP_KERNEL);
+	if (!mod_func->name) {
+		kfree(mod_func);
+		return;
+	}
+
+	mod_func->ip = rec->ip - offset;
+	mod_func->size = symsize;
+
+	list_add_rcu(&mod_func->list, &mod_map->funcs);
+}
+
+static LIST_HEAD(ftrace_mod_maps);
+
+static struct ftrace_mod_map *
+allocate_ftrace_mod_map(struct module *mod,
+			unsigned long start, unsigned long end)
+{
+	struct ftrace_mod_map *mod_map;
+
+	mod_map = kmalloc(sizeof(*mod_map), GFP_KERNEL);
+	if (!mod_map)
+		return NULL;
+
+	mod_map->mod = mod;
+	mod_map->start_addr = start;
+	mod_map->end_addr = end;
+
+	INIT_LIST_HEAD_RCU(&mod_map->funcs);
+
+	list_add_rcu(&mod_map->list, &ftrace_mod_maps);
+
+	return mod_map;
+}
+
+static const char *
+ftrace_func_address_lookup(struct ftrace_mod_map *mod_map,
+			   unsigned long addr, unsigned long *size,
+			   unsigned long *off, char *sym)
+{
+	struct ftrace_mod_func *found_func =  NULL;
+	struct ftrace_mod_func *mod_func;
+
+	list_for_each_entry_rcu(mod_func, &mod_map->funcs, list) {
+		if (addr >= mod_func->ip &&
+		    addr < mod_func->ip + mod_func->size) {
+			found_func = mod_func;
+			break;
+		}
+	}
+
+	if (found_func) {
+		if (size)
+			*size = found_func->size;
+		if (off)
+			*off = addr - found_func->ip;
+		if (sym)
+			strlcpy(sym, found_func->name, KSYM_NAME_LEN);
+
+		return found_func->name;
+	}
+
+	return NULL;
+}
+
+const char *
+ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
+		   unsigned long *off, char **modname, char *sym)
+{
+	struct ftrace_mod_map *mod_map;
+	const char *ret = NULL;
+
+	preempt_disable();
+	list_for_each_entry_rcu(mod_map, &ftrace_mod_maps, list) {
+		ret = ftrace_func_address_lookup(mod_map, addr, size, off, sym);
+		if (ret) {
+			if (modname)
+				*modname = mod_map->mod->name;
+			break;
+		}
+	}
+	preempt_enable();
+
+	return ret;
+}
+
+#else
+static inline void save_ftrace_mod_rec(struct dyn_ftrace *rec) { }
+static inline struct ftrace_mod_map *
+allocate_ftrace_mod_map(struct module *mod,
+			unsigned long start, unsigned long end)
+{
+	return NULL;
+}
 #endif /* CONFIG_MODULES */
 
-void ftrace_free_mem(void *start_ptr, void *end_ptr)
+void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr)
 {
 	unsigned long start = (unsigned long)(start_ptr);
 	unsigned long end = (unsigned long)(end_ptr);
@@ -5877,6 +6005,7 @@ void ftrace_free_mem(void *start_ptr, void *end_ptr)
 	struct ftrace_page *pg;
 	struct dyn_ftrace *rec;
 	struct dyn_ftrace key;
+	struct ftrace_mod_map *mod_map = NULL;
 	int order;
 
 	key.ip = start;
@@ -5884,6 +6013,14 @@ void ftrace_free_mem(void *start_ptr, void *end_ptr)
 
 	mutex_lock(&ftrace_lock);
 
+	/*
+	 * If we are freeing module init memory, then check if
+	 * any tracer is active. If so, we need to save a mapping of
+	 * the module functions being freed with the address.
+	 */
+	if (mod && ftrace_ops_list != &ftrace_list_end)
+		mod_map = allocate_ftrace_mod_map(mod, start, end);
+
 	for (pg = ftrace_pages_start; pg; last_pg = &pg->next, pg = *last_pg) {
 		if (end < pg->records[0].ip ||
 		    start >= (pg->records[pg->index - 1].ip + MCOUNT_INSN_SIZE))
@@ -5894,6 +6031,10 @@ void ftrace_free_mem(void *start_ptr, void *end_ptr)
 			      ftrace_cmp_recs);
 		if (!rec)
 			continue;
+
+		if (mod_map)
+			save_ftrace_mod_rec(mod_map, rec);
+
 		pg->index--;
 		ftrace_update_tot_cnt--;
 		if (!pg->index) {
@@ -5919,7 +6060,7 @@ void __init ftrace_free_init_mem(void)
 	void *start = (void *)(&__init_begin);
 	void *end = (void *)(&__init_end);
 
-	ftrace_free_mem(start, end);
+	ftrace_free_mem(NULL, start, end);
 }
 
 void __init ftrace_init(void)
-- 
2.13.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC][PATCH 4/5] ftrace: Add freeing algorithm to free ftrace_mod_maps
  2017-09-19 14:28 [RFC][PATCH 0/5] tracing: Allow module init functions to be traced Steven Rostedt
                   ` (2 preceding siblings ...)
  2017-09-19 14:28 ` [RFC][PATCH 3/5] ftrace: Save module init functions kallsyms symbols for tracing Steven Rostedt
@ 2017-09-19 14:28 ` Steven Rostedt
  2017-09-19 14:28 ` [RFC][PATCH 5/5] ftrace/kallsyms: Have /proc/kallsyms show saved mod init functions Steven Rostedt
  4 siblings, 0 replies; 11+ messages in thread
From: Steven Rostedt @ 2017-09-19 14:28 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton, Jessica Yu, Rusty Russell

[-- Attachment #1: 0004-ftrace-Add-freeing-algorithm-to-free-ftrace_mod_maps.patch --]
[-- Type: text/plain, Size: 2935 bytes --]

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

The ftrace_mod_map is a descriptor to save module init function names in
case they were traced, and the trace output needs to reference the function
name from the function address. But after the function is unloaded, it
the maps should be freed, as the rest of the function names are as well.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 kernel/trace/ftrace.c | 32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 2aad52802d70..f0af3573b808 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -5683,6 +5683,7 @@ struct ftrace_mod_func {
 };
 
 struct ftrace_mod_map {
+	struct rcu_head		rcu;
 	struct list_head	list;
 	struct module		*mod;
 	unsigned long		start_addr;
@@ -5694,6 +5695,8 @@ struct ftrace_mod_map {
 
 #define next_to_ftrace_page(p) container_of(p, struct ftrace_page, next)
 
+static LIST_HEAD(ftrace_mod_maps);
+
 static int referenced_filters(struct dyn_ftrace *rec)
 {
 	struct ftrace_ops *ops;
@@ -5747,8 +5750,26 @@ static void clear_mod_from_hashes(struct ftrace_page *pg)
 	mutex_unlock(&trace_types_lock);
 }
 
+static void ftrace_free_mod_map(struct rcu_head *rcu)
+{
+	struct ftrace_mod_map *mod_map = container_of(rcu, struct ftrace_mod_map, rcu);
+	struct ftrace_mod_func *mod_func;
+	struct ftrace_mod_func *n;
+
+	/* All the contents of mod_map are now not visible to readers */
+	list_for_each_entry_safe(mod_func, n, &mod_map->funcs, list) {
+		kfree(mod_func->name);
+		list_del(&mod_func->list);
+		kfree(mod_func);
+	}
+
+	kfree(mod_map);
+}
+
 void ftrace_release_mod(struct module *mod)
 {
+	struct ftrace_mod_map *mod_map;
+	struct ftrace_mod_map *n;
 	struct dyn_ftrace *rec;
 	struct ftrace_page **last_pg;
 	struct ftrace_page *tmp_page = NULL;
@@ -5760,6 +5781,14 @@ void ftrace_release_mod(struct module *mod)
 	if (ftrace_disabled)
 		goto out_unlock;
 
+	list_for_each_entry_safe(mod_map, n, &ftrace_mod_maps, list) {
+		if (mod_map->mod == mod) {
+			list_del_rcu(&mod_map->list);
+			call_rcu_sched(&mod_map->rcu, ftrace_free_mod_map);
+			break;
+		}
+	}
+
 	/*
 	 * Each module has its own ftrace_pages, remove
 	 * them from the list.
@@ -5913,8 +5942,6 @@ static void save_ftrace_mod_rec(struct ftrace_mod_map *mod_map,
 	list_add_rcu(&mod_func->list, &mod_map->funcs);
 }
 
-static LIST_HEAD(ftrace_mod_maps);
-
 static struct ftrace_mod_map *
 allocate_ftrace_mod_map(struct module *mod,
 			unsigned long start, unsigned long end)
@@ -5973,6 +6000,7 @@ ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
 	struct ftrace_mod_map *mod_map;
 	const char *ret = NULL;
 
+	/* mod_map is freed via call_rcu_sched() */
 	preempt_disable();
 	list_for_each_entry_rcu(mod_map, &ftrace_mod_maps, list) {
 		ret = ftrace_func_address_lookup(mod_map, addr, size, off, sym);
-- 
2.13.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC][PATCH 5/5] ftrace/kallsyms: Have /proc/kallsyms show saved mod init functions
  2017-09-19 14:28 [RFC][PATCH 0/5] tracing: Allow module init functions to be traced Steven Rostedt
                   ` (3 preceding siblings ...)
  2017-09-19 14:28 ` [RFC][PATCH 4/5] ftrace: Add freeing algorithm to free ftrace_mod_maps Steven Rostedt
@ 2017-09-19 14:28 ` Steven Rostedt
  4 siblings, 0 replies; 11+ messages in thread
From: Steven Rostedt @ 2017-09-19 14:28 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton, Jessica Yu, Rusty Russell

[-- Attachment #1: 0005-ftrace-kallsyms-Have-proc-kallsyms-show-saved-mod-in.patch --]
[-- Type: text/plain, Size: 5428 bytes --]

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

If a module is loaded while tracing is enabled, then there's a possibility
that the module init functions were traced. These functions have their name
and address stored by ftrace such that it can translate the function address
that is written into the buffer into a human readable function name.

As userspace tools may be doing the same, they need a way to map function
names to their address as well. This is done through reading /proc/kallsyms.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 include/linux/ftrace.h |  9 +++++++++
 kernel/kallsyms.c      | 33 ++++++++++++++++++++++++++++-----
 kernel/trace/ftrace.c  | 40 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 77 insertions(+), 5 deletions(-)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 99b770228739..3bfafeff26cc 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -56,6 +56,9 @@ struct ftrace_hash;
 const char *
 ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
 		   unsigned long *off, char **modname, char *sym);
+int ftrace_mod_get_kallsym(unsigned int symnum, unsigned long *value,
+			   char *type, char *name,
+			   char *module_name, int *exported);
 #else
 static inline const char *
 ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
@@ -63,6 +66,12 @@ ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
 {
 	return NULL;
 }
+static inline int ftrace_mod_get_kallsym(unsigned int symnum, unsigned long *value,
+					 char *type, char *name,
+					 char *module_name, int *exported)
+{
+	return 0;
+}
 #endif
 
 
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index 976ecb9275d9..97983dc1555c 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -479,6 +479,7 @@ EXPORT_SYMBOL(__print_symbol);
 struct kallsym_iter {
 	loff_t pos;
 	loff_t pos_mod_end;
+	loff_t pos_ftrace_mod_end;
 	unsigned long value;
 	unsigned int nameoff; /* If iterating in core kernel symbols. */
 	char type;
@@ -501,11 +502,25 @@ static int get_ksymbol_mod(struct kallsym_iter *iter)
 	return 1;
 }
 
+static int get_ksymbol_ftrace_mod(struct kallsym_iter *iter)
+{
+	int ret = ftrace_mod_get_kallsym(iter->pos - iter->pos_mod_end,
+					 &iter->value, &iter->type,
+					 iter->name, iter->module_name,
+					 &iter->exported);
+	if (ret < 0) {
+		iter->pos_ftrace_mod_end = iter->pos;
+		return 0;
+	}
+
+	return 1;
+}
+
 static int get_ksymbol_bpf(struct kallsym_iter *iter)
 {
 	iter->module_name[0] = '\0';
 	iter->exported = 0;
-	return bpf_get_kallsym(iter->pos - iter->pos_mod_end,
+	return bpf_get_kallsym(iter->pos - iter->pos_ftrace_mod_end,
 			       &iter->value, &iter->type,
 			       iter->name) < 0 ? 0 : 1;
 }
@@ -530,20 +545,28 @@ static void reset_iter(struct kallsym_iter *iter, loff_t new_pos)
 	iter->name[0] = '\0';
 	iter->nameoff = get_symbol_offset(new_pos);
 	iter->pos = new_pos;
-	if (new_pos == 0)
+	if (new_pos == 0) {
 		iter->pos_mod_end = 0;
+		iter->pos_ftrace_mod_end = 0;
+	}
 }
 
 static int update_iter_mod(struct kallsym_iter *iter, loff_t pos)
 {
 	iter->pos = pos;
 
+	if (iter->pos_ftrace_mod_end > 0 &&
+	    iter->pos_ftrace_mod_end < iter->pos)
+		return get_ksymbol_bpf(iter);
+
 	if (iter->pos_mod_end > 0 &&
 	    iter->pos_mod_end < iter->pos)
-		return get_ksymbol_bpf(iter);
+		return get_ksymbol_ftrace_mod(iter);
 
-	if (!get_ksymbol_mod(iter))
-		return get_ksymbol_bpf(iter);
+	if (!get_ksymbol_mod(iter)) {
+		if (!get_ksymbol_ftrace_mod(iter))
+			return get_ksymbol_bpf(iter);
+	}
 
 	return 1;
 }
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index f0af3573b808..fabf315b9cb1 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -5689,6 +5689,7 @@ struct ftrace_mod_map {
 	unsigned long		start_addr;
 	unsigned long		end_addr;
 	struct list_head	funcs;
+	unsigned int		num_funcs;
 };
 
 #ifdef CONFIG_MODULES
@@ -5939,6 +5940,8 @@ static void save_ftrace_mod_rec(struct ftrace_mod_map *mod_map,
 	mod_func->ip = rec->ip - offset;
 	mod_func->size = symsize;
 
+	mod_map->num_funcs++;
+
 	list_add_rcu(&mod_func->list, &mod_map->funcs);
 }
 
@@ -5955,6 +5958,7 @@ allocate_ftrace_mod_map(struct module *mod,
 	mod_map->mod = mod;
 	mod_map->start_addr = start;
 	mod_map->end_addr = end;
+	mod_map->num_funcs = 0;
 
 	INIT_LIST_HEAD_RCU(&mod_map->funcs);
 
@@ -6015,6 +6019,42 @@ ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
 	return ret;
 }
 
+int ftrace_mod_get_kallsym(unsigned int symnum, unsigned long *value,
+			   char *type, char *name,
+			   char *module_name, int *exported)
+{
+	struct ftrace_mod_map *mod_map;
+	struct ftrace_mod_func *mod_func;
+
+	preempt_disable();
+	list_for_each_entry_rcu(mod_map, &ftrace_mod_maps, list) {
+
+		if (symnum >= mod_map->num_funcs) {
+			symnum -= mod_map->num_funcs;
+			continue;
+		}
+
+		list_for_each_entry_rcu(mod_func, &mod_map->funcs, list) {
+			if (symnum > 1) {
+				symnum--;
+				continue;
+			}
+
+			*value = mod_func->ip;
+			*type = 'T';
+			strlcpy(name, mod_func->name, KSYM_NAME_LEN);
+			strlcpy(module_name, mod_map->mod->name, MODULE_NAME_LEN);
+			*exported = 1;
+			preempt_enable();
+			return 0;
+		}
+		WARN_ON(1);
+		break;
+	}
+	preempt_enable();
+	return -ERANGE;
+}
+
 #else
 static inline void save_ftrace_mod_rec(struct dyn_ftrace *rec) { }
 static inline struct ftrace_mod_map *
-- 
2.13.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: ftrace: Save module init functions kallsyms symbols for tracing
  2017-09-19 14:28 ` [RFC][PATCH 3/5] ftrace: Save module init functions kallsyms symbols for tracing Steven Rostedt
@ 2017-10-06 20:55   ` Jessica Yu
  2017-10-09 19:51     ` Steven Rostedt
  0 siblings, 1 reply; 11+ messages in thread
From: Jessica Yu @ 2017-10-06 20:55 UTC (permalink / raw)
  To: Steven Rostedt; +Cc: linux-kernel, Ingo Molnar, Andrew Morton, Rusty Russell

+++ Steven Rostedt [19/09/17 14:28 +0000]:
>From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
>
>If function tracing is active when the module init functions are freed, then
>store them to be referenced by kallsyms. As module init functions can now be
>traced on module load, they were useless:
>
> ># echo ':mod:snd_seq' > set_ftrace_filter
> ># echo function > current_tracer
> ># modprobe snd_seq
> ># cat trace
> # tracer: function
> #
> #                              _-----=> irqs-off
> #                             / _----=> need-resched
> #                            | / _---=> hardirq/softirq
> #                            || / _--=> preempt-depth
> #                            ||| /     delay
> #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
> #              | |       |   ||||       |         |
>         modprobe-2786  [000] ....  3189.037874: 0xffffffffa0860000 <-do_one_initcall
>         modprobe-2786  [000] ....  3189.037876: 0xffffffffa086004d <-0xffffffffa086000f
>         modprobe-2786  [000] ....  3189.037876: 0xffffffffa086010d <-0xffffffffa0860018
>         modprobe-2786  [000] ....  3189.037877: 0xffffffffa086011a <-0xffffffffa0860021
>         modprobe-2786  [000] ....  3189.037877: 0xffffffffa0860080 <-0xffffffffa086002a
>         modprobe-2786  [000] ....  3189.039523: 0xffffffffa0860400 <-0xffffffffa0860033
>         modprobe-2786  [000] ....  3189.039523: 0xffffffffa086038a <-0xffffffffa086041c
>         modprobe-2786  [000] ....  3189.039591: 0xffffffffa086038a <-0xffffffffa0860436
>         modprobe-2786  [000] ....  3189.039657: 0xffffffffa086038a <-0xffffffffa0860450
>         modprobe-2786  [000] ....  3189.039719: 0xffffffffa0860127 <-0xffffffffa086003c
>         modprobe-2786  [000] ....  3189.039742: snd_seq_create_kernel_client <-0xffffffffa08601f6
>
>When the output is shown, the kallsyms for the module init functions have
>already been freed, and the output of the trace can not convert them to
>their function names.
>
>Now this looks like this:
>
> # tracer: function
> #
> #                              _-----=> irqs-off
> #                             / _----=> need-resched
> #                            | / _---=> hardirq/softirq
> #                            || / _--=> preempt-depth
> #                            ||| /     delay
> #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
> #              | |       |   ||||       |         |
>         modprobe-2463  [002] ....   174.243237: alsa_seq_init <-do_one_initcall
>         modprobe-2463  [002] ....   174.243239: client_init_data <-alsa_seq_init
>         modprobe-2463  [002] ....   174.243240: snd_sequencer_memory_init <-alsa_seq_init
>         modprobe-2463  [002] ....   174.243240: snd_seq_queues_init <-alsa_seq_init
>         modprobe-2463  [002] ....   174.243240: snd_sequencer_device_init <-alsa_seq_init
>         modprobe-2463  [002] ....   174.244860: snd_seq_info_init <-alsa_seq_init
>         modprobe-2463  [002] ....   174.244861: create_info_entry <-snd_seq_info_init
>         modprobe-2463  [002] ....   174.244936: create_info_entry <-snd_seq_info_init
>         modprobe-2463  [002] ....   174.245003: create_info_entry <-snd_seq_info_init
>         modprobe-2463  [002] ....   174.245072: snd_seq_system_client_init <-alsa_seq_init
>         modprobe-2463  [002] ....   174.245094: snd_seq_create_kernel_client <-snd_seq_system_client_init
>
>Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>

Hi Steven,

Hm, I think there may be a way to make this easier and avoid all this
copying and freeing of ftrace_mod* descriptors. It is trivially easy
to save module init symbol information in the module's copy of the
symbol table (mod->kallsyms). Currently the module loader just ignores
symbols in init sections when building the module symtab. If we just
make that information available, ftrace can easily walk the module's
symtab to look for the init function symbol, its (former, before it
was freed) address, and its name in the module's strtab. If this
change is implemented we could probably omit patch 05 as well.

This might look like the following (patch applies on top of patches 01-04)
(not thoroughly tested yet!):

-->8--
diff --git a/include/linux/module.h b/include/linux/module.h
index fe5aa3736707..8a8bdf8397d3 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -541,6 +541,10 @@ const struct kernel_symbol *find_symbol(const char *name,
 					bool gplok,
 					bool warn);
 
+const char *get_module_ksymbol(struct module *mod,
+			       unsigned long addr,
+			       unsigned long *size,
+			       unsigned long *offset);
 /*
  * Walk the exported symbol table
  *
diff --git a/kernel/module.c b/kernel/module.c
index 279a469dc375..db85e47d4f2f 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2596,7 +2596,7 @@ static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
 #ifndef CONFIG_KALLSYMS_ALL
 	    || !(sec->sh_flags & SHF_EXECINSTR)
 #endif
-	    || (sec->sh_entsize & INIT_OFFSET_MASK))
+	    )
 		return false;
 
 	return true;
@@ -3885,25 +3885,20 @@ static const char *symname(struct mod_kallsyms *kallsyms, unsigned int symnum)
 	return kallsyms->strtab + kallsyms->symtab[symnum].st_name;
 }
 
-static const char *get_ksymbol(struct module *mod,
+const char *get_module_ksymbol(struct module *mod,
 			       unsigned long addr,
 			       unsigned long *size,
 			       unsigned long *offset)
 {
-	unsigned int i, best = 0;
-	unsigned long nextval;
+	unsigned int i, found = 0;
 	struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
+	Elf_Sym *sym, *symtab = kallsyms->symtab;
 
-	/* At worse, next value is at end of module */
-	if (within_module_init(addr, mod))
-		nextval = (unsigned long)mod->init_layout.base+mod->init_layout.text_size;
-	else
-		nextval = (unsigned long)mod->core_layout.base+mod->core_layout.text_size;
-
-	/* Scan for closest preceding symbol, and next symbol. (ELF
-	   starts real symbols at 1). */
+	/* Note: ELF symbols in a symbol table start at index 1). */
 	for (i = 1; i < kallsyms->num_symtab; i++) {
-		if (kallsyms->symtab[i].st_shndx == SHN_UNDEF)
+		sym = &symtab[i];
+
+		if (sym->st_shndx == SHN_UNDEF)
 			continue;
 
 		/* We ignore unnamed symbols: they're uninformative
@@ -3912,22 +3907,30 @@ static const char *get_ksymbol(struct module *mod,
 		    || is_arm_mapping_symbol(symname(kallsyms, i)))
 			continue;
 
-		if (kallsyms->symtab[i].st_value <= addr
-		    && kallsyms->symtab[i].st_value > kallsyms->symtab[best].st_value)
-			best = i;
-		if (kallsyms->symtab[i].st_value > addr
-		    && kallsyms->symtab[i].st_value < nextval)
-			nextval = kallsyms->symtab[i].st_value;
+		/*
+		 * These are "internal" symbols aliased to the real init and
+		 * exit functions in a module. But they're not particularly
+		 * informative in oopses/tracing. Skip them and use the module's
+		 * real init/exit functions instead.
+		 */
+		if (strcmp(symname(kallsyms, i), "init_module") == 0 ||
+		    strcmp(symname(kallsyms, i), "cleanup_module") == 0)
+			continue;
+
+		if (sym->st_value <= addr &&
+		    addr < sym->st_value + sym->st_size)
+			found = i;
 	}
 
-	if (!best)
+	if (!found)
 		return NULL;
 
 	if (size)
-		*size = nextval - kallsyms->symtab[best].st_value;
+		*size = symtab[found].st_size;
 	if (offset)
-		*offset = addr - kallsyms->symtab[best].st_value;
-	return symname(kallsyms, best);
+		*offset = addr - symtab[found].st_value;
+
+	return symname(kallsyms, found);
 }
 
 /* For kallsyms to ask for address resolution.  NULL means not found.  Careful
@@ -3946,7 +3949,7 @@ const char *module_address_lookup(unsigned long addr,
 	if (mod) {
 		if (modname)
 			*modname = mod->name;
-		ret = get_ksymbol(mod, addr, size, offset);
+		ret = get_module_ksymbol(mod, addr, size, offset);
 	}
 	/* Make a copy in here where it's safe */
 	if (ret) {
@@ -3969,7 +3972,7 @@ int lookup_module_symbol_name(unsigned long addr, char *symname)
 		if (within_module(addr, mod)) {
 			const char *sym;
 
-			sym = get_ksymbol(mod, addr, NULL, NULL);
+			sym = get_module_ksymbol(mod, addr, NULL, NULL);
 			if (!sym)
 				goto out;
 			strlcpy(symname, sym, KSYM_NAME_LEN);
@@ -3994,7 +3997,7 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
 		if (within_module(addr, mod)) {
 			const char *sym;
 
-			sym = get_ksymbol(mod, addr, size, offset);
+			sym = get_module_ksymbol(mod, addr, size, offset);
 			if (!sym)
 				goto out;
 			if (modname)
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index f0af3573b808..c9862ddd3954 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -5675,20 +5675,12 @@ static int ftrace_process_locs(struct module *mod,
 	return ret;
 }
 
-struct ftrace_mod_func {
-	struct list_head	list;
-	char			*name;
-	unsigned long		ip;
-	unsigned int		size;
-};
-
 struct ftrace_mod_map {
 	struct rcu_head		rcu;
 	struct list_head	list;
 	struct module		*mod;
 	unsigned long		start_addr;
 	unsigned long		end_addr;
-	struct list_head	funcs;
 };
 
 #ifdef CONFIG_MODULES
@@ -5753,15 +5745,6 @@ static void clear_mod_from_hashes(struct ftrace_page *pg)
 static void ftrace_free_mod_map(struct rcu_head *rcu)
 {
 	struct ftrace_mod_map *mod_map = container_of(rcu, struct ftrace_mod_map, rcu);
-	struct ftrace_mod_func *mod_func;
-	struct ftrace_mod_func *n;
-
-	/* All the contents of mod_map are now not visible to readers */
-	list_for_each_entry_safe(mod_func, n, &mod_map->funcs, list) {
-		kfree(mod_func->name);
-		list_del(&mod_func->list);
-		kfree(mod_func);
-	}
 
 	kfree(mod_map);
 }
@@ -5912,36 +5895,6 @@ void ftrace_module_init(struct module *mod)
 			    mod->ftrace_callsites + mod->num_ftrace_callsites);
 }
 
-static void save_ftrace_mod_rec(struct ftrace_mod_map *mod_map,
-				struct dyn_ftrace *rec)
-{
-	struct ftrace_mod_func *mod_func;
-	unsigned long symsize;
-	unsigned long offset;
-	char str[KSYM_SYMBOL_LEN];
-	char *modname;
-	const char *ret;
-
-	ret = kallsyms_lookup(rec->ip, &symsize, &offset, &modname, str);
-	if (!ret)
-		return;
-
-	mod_func = kmalloc(sizeof(*mod_func), GFP_KERNEL);
-	if (!mod_func)
-		return;
-
-	mod_func->name = kstrdup(str, GFP_KERNEL);
-	if (!mod_func->name) {
-		kfree(mod_func);
-		return;
-	}
-
-	mod_func->ip = rec->ip - offset;
-	mod_func->size = symsize;
-
-	list_add_rcu(&mod_func->list, &mod_map->funcs);
-}
-
 static struct ftrace_mod_map *
 allocate_ftrace_mod_map(struct module *mod,
 			unsigned long start, unsigned long end)
@@ -5956,43 +5909,11 @@ allocate_ftrace_mod_map(struct module *mod,
 	mod_map->start_addr = start;
 	mod_map->end_addr = end;
 
-	INIT_LIST_HEAD_RCU(&mod_map->funcs);
-
 	list_add_rcu(&mod_map->list, &ftrace_mod_maps);
 
 	return mod_map;
 }
 
-static const char *
-ftrace_func_address_lookup(struct ftrace_mod_map *mod_map,
-			   unsigned long addr, unsigned long *size,
-			   unsigned long *off, char *sym)
-{
-	struct ftrace_mod_func *found_func =  NULL;
-	struct ftrace_mod_func *mod_func;
-
-	list_for_each_entry_rcu(mod_func, &mod_map->funcs, list) {
-		if (addr >= mod_func->ip &&
-		    addr < mod_func->ip + mod_func->size) {
-			found_func = mod_func;
-			break;
-		}
-	}
-
-	if (found_func) {
-		if (size)
-			*size = found_func->size;
-		if (off)
-			*off = addr - found_func->ip;
-		if (sym)
-			strlcpy(sym, found_func->name, KSYM_NAME_LEN);
-
-		return found_func->name;
-	}
-
-	return NULL;
-}
-
 const char *
 ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
 		   unsigned long *off, char **modname, char *sym)
@@ -6003,10 +5924,12 @@ ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
 	/* mod_map is freed via call_rcu_sched() */
 	preempt_disable();
 	list_for_each_entry_rcu(mod_map, &ftrace_mod_maps, list) {
-		ret = ftrace_func_address_lookup(mod_map, addr, size, off, sym);
+		ret = get_module_ksymbol(mod_map->mod, addr, size, off);
 		if (ret) {
 			if (modname)
 				*modname = mod_map->mod->name;
+			if (sym)
+				strlcpy(sym, ret, KSYM_NAME_LEN);
 			break;
 		}
 	}
@@ -6060,9 +5983,6 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr)
 		if (!rec)
 			continue;
 
-		if (mod_map)
-			save_ftrace_mod_rec(mod_map, rec);
-
 		pg->index--;
 		ftrace_update_tot_cnt--;
 		if (!pg->index) {
-->8--

Using the snd_seq example from patch 03, I get the same human-readable trace:

# tracer: function
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |
        modprobe-12748 [005] ....   138.964923: alsa_seq_init <-do_one_initcall
        modprobe-12748 [005] ....   138.964924: client_init_data <-alsa_seq_init
        modprobe-12748 [005] ....   138.964924: snd_sequencer_memory_init <-alsa_seq_init
        modprobe-12748 [005] ....   138.964924: snd_seq_queues_init <-alsa_seq_init
        modprobe-12748 [005] ....   138.964924: snd_sequencer_device_init <-alsa_seq_init
        modprobe-12748 [005] ....   138.964956: snd_seq_info_init <-alsa_seq_init
        modprobe-12748 [005] ....   138.964956: create_info_entry <-snd_seq_info_init
        modprobe-12748 [005] ....   138.964958: create_info_entry <-snd_seq_info_init
        modprobe-12748 [005] ....   138.964959: create_info_entry <-snd_seq_info_init
        modprobe-12748 [005] ....   138.964960: snd_seq_system_client_init <-alsa_seq_init
        modprobe-12748 [005] ....   138.964960: snd_seq_create_kernel_client <-snd_seq_system_client_init

In addition, the module init functions appear in /proc/kallsyms as
well. Thoughts? Would saving init symbol information in the module
symtab be sufficient for ftrace?

Thanks,

Jessica

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: ftrace: Save module init functions kallsyms symbols for tracing
  2017-10-06 20:55   ` Jessica Yu
@ 2017-10-09 19:51     ` Steven Rostedt
  2017-10-10 15:45       ` Steven Rostedt
  0 siblings, 1 reply; 11+ messages in thread
From: Steven Rostedt @ 2017-10-09 19:51 UTC (permalink / raw)
  To: Jessica Yu
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Rusty Russell, Joel Fernandes

On Fri, 6 Oct 2017 22:55:15 +0200
Jessica Yu <jeyu@kernel.org> wrote:

> +++ Steven Rostedt [19/09/17 14:28 +0000]:
> >From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
> >
> >If function tracing is active when the module init functions are freed, then
> >store them to be referenced by kallsyms. As module init functions can now be
> >traced on module load, they were useless:
> >  
> > ># echo ':mod:snd_seq' > set_ftrace_filter
> > ># echo function > current_tracer
> > ># modprobe snd_seq
> > ># cat trace  
> > # tracer: function
> > #
> > #                              _-----=> irqs-off
> > #                             / _----=> need-resched
> > #                            | / _---=> hardirq/softirq
> > #                            || / _--=> preempt-depth
> > #                            ||| /     delay
> > #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
> > #              | |       |   ||||       |         |
> >         modprobe-2786  [000] ....  3189.037874: 0xffffffffa0860000 <-do_one_initcall
> >         modprobe-2786  [000] ....  3189.037876: 0xffffffffa086004d <-0xffffffffa086000f
> >         modprobe-2786  [000] ....  3189.037876: 0xffffffffa086010d <-0xffffffffa0860018
> >         modprobe-2786  [000] ....  3189.037877: 0xffffffffa086011a <-0xffffffffa0860021
> >         modprobe-2786  [000] ....  3189.037877: 0xffffffffa0860080 <-0xffffffffa086002a
> >         modprobe-2786  [000] ....  3189.039523: 0xffffffffa0860400 <-0xffffffffa0860033
> >         modprobe-2786  [000] ....  3189.039523: 0xffffffffa086038a <-0xffffffffa086041c
> >         modprobe-2786  [000] ....  3189.039591: 0xffffffffa086038a <-0xffffffffa0860436
> >         modprobe-2786  [000] ....  3189.039657: 0xffffffffa086038a <-0xffffffffa0860450
> >         modprobe-2786  [000] ....  3189.039719: 0xffffffffa0860127 <-0xffffffffa086003c
> >         modprobe-2786  [000] ....  3189.039742: snd_seq_create_kernel_client <-0xffffffffa08601f6
> >
> >When the output is shown, the kallsyms for the module init functions have
> >already been freed, and the output of the trace can not convert them to
> >their function names.
> >
> >Now this looks like this:
> >
> > # tracer: function
> > #
> > #                              _-----=> irqs-off
> > #                             / _----=> need-resched
> > #                            | / _---=> hardirq/softirq
> > #                            || / _--=> preempt-depth
> > #                            ||| /     delay
> > #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
> > #              | |       |   ||||       |         |
> >         modprobe-2463  [002] ....   174.243237: alsa_seq_init <-do_one_initcall
> >         modprobe-2463  [002] ....   174.243239: client_init_data <-alsa_seq_init
> >         modprobe-2463  [002] ....   174.243240: snd_sequencer_memory_init <-alsa_seq_init
> >         modprobe-2463  [002] ....   174.243240: snd_seq_queues_init <-alsa_seq_init
> >         modprobe-2463  [002] ....   174.243240: snd_sequencer_device_init <-alsa_seq_init
> >         modprobe-2463  [002] ....   174.244860: snd_seq_info_init <-alsa_seq_init
> >         modprobe-2463  [002] ....   174.244861: create_info_entry <-snd_seq_info_init
> >         modprobe-2463  [002] ....   174.244936: create_info_entry <-snd_seq_info_init
> >         modprobe-2463  [002] ....   174.245003: create_info_entry <-snd_seq_info_init
> >         modprobe-2463  [002] ....   174.245072: snd_seq_system_client_init <-alsa_seq_init
> >         modprobe-2463  [002] ....   174.245094: snd_seq_create_kernel_client <-snd_seq_system_client_init
> >
> >Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>  
> 
> Hi Steven,
> 
> Hm, I think there may be a way to make this easier and avoid all this
> copying and freeing of ftrace_mod* descriptors. It is trivially easy
> to save module init symbol information in the module's copy of the
> symbol table (mod->kallsyms). Currently the module loader just ignores
> symbols in init sections when building the module symtab. If we just
> make that information available, ftrace can easily walk the module's
> symtab to look for the init function symbol, its (former, before it
> was freed) address, and its name in the module's strtab. If this
> change is implemented we could probably omit patch 05 as well.
> 
> This might look like the following (patch applies on top of patches 01-04)
> (not thoroughly tested yet!):

I just tried it. ;-)

This does simplify things, but it also causes some of the same issues
I've been trying to fix as well. But perhaps we can live with them.

I did:

 # rmmod kvm_intel
 # echo ":mod:kvm_intel" > set_ftrace_filter
 # echo function > current_tracer
 # modprobe kvm_intel
 # rmmod ip6table_filter
 # modprobe ip6table_filter
 # cat trace
# tracer: function
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |
        modprobe-2856  [001] .... 15513.473966: vmx_init <-do_one_initcall
        modprobe-2856  [001] .... 15513.473968: ip6table_filter_init <-kvm_arch_init
        modprobe-2856  [001] .... 15513.473968: vmx_disabled_by_bios <-kvm_arch_init
        modprobe-2856  [001] .... 15513.479503: hardware_setup <-kvm_arch_hardware_setup
        modprobe-2856  [001] .... 15513.479514: setup_vmcs_config <-hardware_setup

Notice the "ip6table_filter_init" called by kvm_arch_init ;-)

I guess that's fine, as I don't have a solution for that either.

I did notice this though:

# grep ffffffffa0308000 /proc/kallsyms
ffffffffa0308000 t ip6table_filter_init	[ip6table_filter]
ffffffffa0308000 t init_module	[ip6table_filter]
ffffffffa0308000 t cpu_has_kvm_support	[kvm_intel]
ffffffffa0308000 t generic_driver_init	[snd_hda_codec_generic]
ffffffffa0308000 t init_module	[snd_hda_codec_generic]

As long as the last module loaded is the first one that gets picked up
by kallsyms, we should be good.

As I finished all my tests, I want to still post the changes. But if
this proves to be a better method, I can just revert them.

-- Steve


> 
> -->8--  
> diff --git a/include/linux/module.h b/include/linux/module.h
> index fe5aa3736707..8a8bdf8397d3 100644
> --- a/include/linux/module.h
> +++ b/include/linux/module.h
> @@ -541,6 +541,10 @@ const struct kernel_symbol *find_symbol(const char *name,
>  					bool gplok,
>  					bool warn);
>  
> +const char *get_module_ksymbol(struct module *mod,
> +			       unsigned long addr,
> +			       unsigned long *size,
> +			       unsigned long *offset);
>  /*
>   * Walk the exported symbol table
>   *
> diff --git a/kernel/module.c b/kernel/module.c
> index 279a469dc375..db85e47d4f2f 100644
> --- a/kernel/module.c
> +++ b/kernel/module.c
> @@ -2596,7 +2596,7 @@ static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
>  #ifndef CONFIG_KALLSYMS_ALL
>  	    || !(sec->sh_flags & SHF_EXECINSTR)
>  #endif
> -	    || (sec->sh_entsize & INIT_OFFSET_MASK))
> +	    )
>  		return false;
>  
>  	return true;
> @@ -3885,25 +3885,20 @@ static const char *symname(struct mod_kallsyms *kallsyms, unsigned int symnum)
>  	return kallsyms->strtab + kallsyms->symtab[symnum].st_name;
>  }
>  
> -static const char *get_ksymbol(struct module *mod,
> +const char *get_module_ksymbol(struct module *mod,
>  			       unsigned long addr,
>  			       unsigned long *size,
>  			       unsigned long *offset)
>  {
> -	unsigned int i, best = 0;
> -	unsigned long nextval;
> +	unsigned int i, found = 0;
>  	struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
> +	Elf_Sym *sym, *symtab = kallsyms->symtab;
>  
> -	/* At worse, next value is at end of module */
> -	if (within_module_init(addr, mod))
> -		nextval = (unsigned long)mod->init_layout.base+mod->init_layout.text_size;
> -	else
> -		nextval = (unsigned long)mod->core_layout.base+mod->core_layout.text_size;
> -
> -	/* Scan for closest preceding symbol, and next symbol. (ELF
> -	   starts real symbols at 1). */
> +	/* Note: ELF symbols in a symbol table start at index 1). */
>  	for (i = 1; i < kallsyms->num_symtab; i++) {
> -		if (kallsyms->symtab[i].st_shndx == SHN_UNDEF)
> +		sym = &symtab[i];
> +
> +		if (sym->st_shndx == SHN_UNDEF)
>  			continue;
>  
>  		/* We ignore unnamed symbols: they're uninformative
> @@ -3912,22 +3907,30 @@ static const char *get_ksymbol(struct module *mod,
>  		    || is_arm_mapping_symbol(symname(kallsyms, i)))
>  			continue;
>  
> -		if (kallsyms->symtab[i].st_value <= addr
> -		    && kallsyms->symtab[i].st_value > kallsyms->symtab[best].st_value)
> -			best = i;
> -		if (kallsyms->symtab[i].st_value > addr
> -		    && kallsyms->symtab[i].st_value < nextval)
> -			nextval = kallsyms->symtab[i].st_value;
> +		/*
> +		 * These are "internal" symbols aliased to the real init and
> +		 * exit functions in a module. But they're not particularly
> +		 * informative in oopses/tracing. Skip them and use the module's
> +		 * real init/exit functions instead.
> +		 */
> +		if (strcmp(symname(kallsyms, i), "init_module") == 0 ||
> +		    strcmp(symname(kallsyms, i), "cleanup_module") == 0)
> +			continue;
> +
> +		if (sym->st_value <= addr &&
> +		    addr < sym->st_value + sym->st_size)
> +			found = i;
>  	}
>  
> -	if (!best)
> +	if (!found)
>  		return NULL;
>  
>  	if (size)
> -		*size = nextval - kallsyms->symtab[best].st_value;
> +		*size = symtab[found].st_size;
>  	if (offset)
> -		*offset = addr - kallsyms->symtab[best].st_value;
> -	return symname(kallsyms, best);
> +		*offset = addr - symtab[found].st_value;
> +
> +	return symname(kallsyms, found);
>  }
>  
>  /* For kallsyms to ask for address resolution.  NULL means not found.  Careful
> @@ -3946,7 +3949,7 @@ const char *module_address_lookup(unsigned long addr,
>  	if (mod) {
>  		if (modname)
>  			*modname = mod->name;
> -		ret = get_ksymbol(mod, addr, size, offset);
> +		ret = get_module_ksymbol(mod, addr, size, offset);
>  	}
>  	/* Make a copy in here where it's safe */
>  	if (ret) {
> @@ -3969,7 +3972,7 @@ int lookup_module_symbol_name(unsigned long addr, char *symname)
>  		if (within_module(addr, mod)) {
>  			const char *sym;
>  
> -			sym = get_ksymbol(mod, addr, NULL, NULL);
> +			sym = get_module_ksymbol(mod, addr, NULL, NULL);
>  			if (!sym)
>  				goto out;
>  			strlcpy(symname, sym, KSYM_NAME_LEN);
> @@ -3994,7 +3997,7 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
>  		if (within_module(addr, mod)) {
>  			const char *sym;
>  
> -			sym = get_ksymbol(mod, addr, size, offset);
> +			sym = get_module_ksymbol(mod, addr, size, offset);
>  			if (!sym)
>  				goto out;
>  			if (modname)
> diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> index f0af3573b808..c9862ddd3954 100644
> --- a/kernel/trace/ftrace.c
> +++ b/kernel/trace/ftrace.c
> @@ -5675,20 +5675,12 @@ static int ftrace_process_locs(struct module *mod,
>  	return ret;
>  }
>  
> -struct ftrace_mod_func {
> -	struct list_head	list;
> -	char			*name;
> -	unsigned long		ip;
> -	unsigned int		size;
> -};
> -
>  struct ftrace_mod_map {
>  	struct rcu_head		rcu;
>  	struct list_head	list;
>  	struct module		*mod;
>  	unsigned long		start_addr;
>  	unsigned long		end_addr;
> -	struct list_head	funcs;
>  };
>  
>  #ifdef CONFIG_MODULES
> @@ -5753,15 +5745,6 @@ static void clear_mod_from_hashes(struct ftrace_page *pg)
>  static void ftrace_free_mod_map(struct rcu_head *rcu)
>  {
>  	struct ftrace_mod_map *mod_map = container_of(rcu, struct ftrace_mod_map, rcu);
> -	struct ftrace_mod_func *mod_func;
> -	struct ftrace_mod_func *n;
> -
> -	/* All the contents of mod_map are now not visible to readers */
> -	list_for_each_entry_safe(mod_func, n, &mod_map->funcs, list) {
> -		kfree(mod_func->name);
> -		list_del(&mod_func->list);
> -		kfree(mod_func);
> -	}
>  
>  	kfree(mod_map);
>  }
> @@ -5912,36 +5895,6 @@ void ftrace_module_init(struct module *mod)
>  			    mod->ftrace_callsites + mod->num_ftrace_callsites);
>  }
>  
> -static void save_ftrace_mod_rec(struct ftrace_mod_map *mod_map,
> -				struct dyn_ftrace *rec)
> -{
> -	struct ftrace_mod_func *mod_func;
> -	unsigned long symsize;
> -	unsigned long offset;
> -	char str[KSYM_SYMBOL_LEN];
> -	char *modname;
> -	const char *ret;
> -
> -	ret = kallsyms_lookup(rec->ip, &symsize, &offset, &modname, str);
> -	if (!ret)
> -		return;
> -
> -	mod_func = kmalloc(sizeof(*mod_func), GFP_KERNEL);
> -	if (!mod_func)
> -		return;
> -
> -	mod_func->name = kstrdup(str, GFP_KERNEL);
> -	if (!mod_func->name) {
> -		kfree(mod_func);
> -		return;
> -	}
> -
> -	mod_func->ip = rec->ip - offset;
> -	mod_func->size = symsize;
> -
> -	list_add_rcu(&mod_func->list, &mod_map->funcs);
> -}
> -
>  static struct ftrace_mod_map *
>  allocate_ftrace_mod_map(struct module *mod,
>  			unsigned long start, unsigned long end)
> @@ -5956,43 +5909,11 @@ allocate_ftrace_mod_map(struct module *mod,
>  	mod_map->start_addr = start;
>  	mod_map->end_addr = end;
>  
> -	INIT_LIST_HEAD_RCU(&mod_map->funcs);
> -
>  	list_add_rcu(&mod_map->list, &ftrace_mod_maps);
>  
>  	return mod_map;
>  }
>  
> -static const char *
> -ftrace_func_address_lookup(struct ftrace_mod_map *mod_map,
> -			   unsigned long addr, unsigned long *size,
> -			   unsigned long *off, char *sym)
> -{
> -	struct ftrace_mod_func *found_func =  NULL;
> -	struct ftrace_mod_func *mod_func;
> -
> -	list_for_each_entry_rcu(mod_func, &mod_map->funcs, list) {
> -		if (addr >= mod_func->ip &&
> -		    addr < mod_func->ip + mod_func->size) {
> -			found_func = mod_func;
> -			break;
> -		}
> -	}
> -
> -	if (found_func) {
> -		if (size)
> -			*size = found_func->size;
> -		if (off)
> -			*off = addr - found_func->ip;
> -		if (sym)
> -			strlcpy(sym, found_func->name, KSYM_NAME_LEN);
> -
> -		return found_func->name;
> -	}
> -
> -	return NULL;
> -}
> -
>  const char *
>  ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
>  		   unsigned long *off, char **modname, char *sym)
> @@ -6003,10 +5924,12 @@ ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
>  	/* mod_map is freed via call_rcu_sched() */
>  	preempt_disable();
>  	list_for_each_entry_rcu(mod_map, &ftrace_mod_maps, list) {
> -		ret = ftrace_func_address_lookup(mod_map, addr, size, off, sym);
> +		ret = get_module_ksymbol(mod_map->mod, addr, size, off);
>  		if (ret) {
>  			if (modname)
>  				*modname = mod_map->mod->name;
> +			if (sym)
> +				strlcpy(sym, ret, KSYM_NAME_LEN);
>  			break;
>  		}
>  	}
> @@ -6060,9 +5983,6 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr)
>  		if (!rec)
>  			continue;
>  
> -		if (mod_map)
> -			save_ftrace_mod_rec(mod_map, rec);
> -
>  		pg->index--;
>  		ftrace_update_tot_cnt--;
>  		if (!pg->index) {
> -->8--  
> 
> Using the snd_seq example from patch 03, I get the same human-readable trace:
> 
> # tracer: function
> #
> #                              _-----=> irqs-off
> #                             / _----=> need-resched
> #                            | / _---=> hardirq/softirq
> #                            || / _--=> preempt-depth
> #                            ||| /     delay
> #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
> #              | |       |   ||||       |         |
>         modprobe-12748 [005] ....   138.964923: alsa_seq_init <-do_one_initcall
>         modprobe-12748 [005] ....   138.964924: client_init_data <-alsa_seq_init
>         modprobe-12748 [005] ....   138.964924: snd_sequencer_memory_init <-alsa_seq_init
>         modprobe-12748 [005] ....   138.964924: snd_seq_queues_init <-alsa_seq_init
>         modprobe-12748 [005] ....   138.964924: snd_sequencer_device_init <-alsa_seq_init
>         modprobe-12748 [005] ....   138.964956: snd_seq_info_init <-alsa_seq_init
>         modprobe-12748 [005] ....   138.964956: create_info_entry <-snd_seq_info_init
>         modprobe-12748 [005] ....   138.964958: create_info_entry <-snd_seq_info_init
>         modprobe-12748 [005] ....   138.964959: create_info_entry <-snd_seq_info_init
>         modprobe-12748 [005] ....   138.964960: snd_seq_system_client_init <-alsa_seq_init
>         modprobe-12748 [005] ....   138.964960: snd_seq_create_kernel_client <-snd_seq_system_client_init
> 
> In addition, the module init functions appear in /proc/kallsyms as
> well. Thoughts? Would saving init symbol information in the module
> symtab be sufficient for ftrace?
> 
> Thanks,
> 
> Jessica

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: ftrace: Save module init functions kallsyms symbols for tracing
  2017-10-09 19:51     ` Steven Rostedt
@ 2017-10-10 15:45       ` Steven Rostedt
  2017-10-11 11:19         ` Jessica Yu
  0 siblings, 1 reply; 11+ messages in thread
From: Steven Rostedt @ 2017-10-10 15:45 UTC (permalink / raw)
  To: Jessica Yu
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Rusty Russell, Joel Fernandes

On Mon, 9 Oct 2017 15:51:00 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:


> > Using the snd_seq example from patch 03, I get the same human-readable trace:
> > 
> > # tracer: function
> > #
> > #                              _-----=> irqs-off
> > #                             / _----=> need-resched
> > #                            | / _---=> hardirq/softirq
> > #                            || / _--=> preempt-depth
> > #                            ||| /     delay
> > #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
> > #              | |       |   ||||       |         |
> >         modprobe-12748 [005] ....   138.964923: alsa_seq_init <-do_one_initcall
> >         modprobe-12748 [005] ....   138.964924: client_init_data <-alsa_seq_init
> >         modprobe-12748 [005] ....   138.964924: snd_sequencer_memory_init <-alsa_seq_init
> >         modprobe-12748 [005] ....   138.964924: snd_seq_queues_init <-alsa_seq_init
> >         modprobe-12748 [005] ....   138.964924: snd_sequencer_device_init <-alsa_seq_init
> >         modprobe-12748 [005] ....   138.964956: snd_seq_info_init <-alsa_seq_init
> >         modprobe-12748 [005] ....   138.964956: create_info_entry <-snd_seq_info_init
> >         modprobe-12748 [005] ....   138.964958: create_info_entry <-snd_seq_info_init
> >         modprobe-12748 [005] ....   138.964959: create_info_entry <-snd_seq_info_init
> >         modprobe-12748 [005] ....   138.964960: snd_seq_system_client_init <-alsa_seq_init
> >         modprobe-12748 [005] ....   138.964960: snd_seq_create_kernel_client <-snd_seq_system_client_init
> > 
> > In addition, the module init functions appear in /proc/kallsyms as
> > well. Thoughts? Would saving init symbol information in the module
> > symtab be sufficient for ftrace?

Hi Jessica,

Are you going to have time to work on this more?

Should we allow multiple init addresses to appear, or should there be
some check to see if they already exist, and remove the older one?

Ideally, I could have a way to know if a module init function was
traced and its address was stored in a ring buffer, and keep the init
mapping around and used for that buffer, and free it when the buffer
is cleared, and there's no other buffers that have a reference to it.
But I need to find a low overhead way to account for this.

Personally, I would rather have the mappings saved in the symbol tables
in the module code.

If we can come up with a better module way, I'll convert to that. But
as I want to get this code upstream by 4.15, I'm going to continue with
what I have.

Thoughts?

-- Steve

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: ftrace: Save module init functions kallsyms symbols for tracing
  2017-10-10 15:45       ` Steven Rostedt
@ 2017-10-11 11:19         ` Jessica Yu
  2017-10-11 13:11           ` Steven Rostedt
  0 siblings, 1 reply; 11+ messages in thread
From: Jessica Yu @ 2017-10-11 11:19 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Rusty Russell, Joel Fernandes

+++ Steven Rostedt [10/10/17 15:45 +0000]:
>On Mon, 9 Oct 2017 15:51:00 -0400
>Steven Rostedt <rostedt@goodmis.org> wrote:
>
>
>> > Using the snd_seq example from patch 03, I get the same human-readable trace:
>> >
>> > # tracer: function
>> > #
>> > #                              _-----=> irqs-off
>> > #                             / _----=> need-resched
>> > #                            | / _---=> hardirq/softirq
>> > #                            || / _--=> preempt-depth
>> > #                            ||| /     delay
>> > #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
>> > #              | |       |   ||||       |         |
>> >         modprobe-12748 [005] ....   138.964923: alsa_seq_init <-do_one_initcall
>> >         modprobe-12748 [005] ....   138.964924: client_init_data <-alsa_seq_init
>> >         modprobe-12748 [005] ....   138.964924: snd_sequencer_memory_init <-alsa_seq_init
>> >         modprobe-12748 [005] ....   138.964924: snd_seq_queues_init <-alsa_seq_init
>> >         modprobe-12748 [005] ....   138.964924: snd_sequencer_device_init <-alsa_seq_init
>> >         modprobe-12748 [005] ....   138.964956: snd_seq_info_init <-alsa_seq_init
>> >         modprobe-12748 [005] ....   138.964956: create_info_entry <-snd_seq_info_init
>> >         modprobe-12748 [005] ....   138.964958: create_info_entry <-snd_seq_info_init
>> >         modprobe-12748 [005] ....   138.964959: create_info_entry <-snd_seq_info_init
>> >         modprobe-12748 [005] ....   138.964960: snd_seq_system_client_init <-alsa_seq_init
>> >         modprobe-12748 [005] ....   138.964960: snd_seq_create_kernel_client <-snd_seq_system_client_init
>> >
>> > In addition, the module init functions appear in /proc/kallsyms as
>> > well. Thoughts? Would saving init symbol information in the module
>> > symtab be sufficient for ftrace?
>
>Hi Jessica,
>
>Are you going to have time to work on this more?
>
>Should we allow multiple init addresses to appear, or should there be
>some check to see if they already exist, and remove the older one?

In /proc/kallsyms? IMO it would be better to make the behavior as
general as possible, as in, we just keep all symbols in each module's
symtab without regard to other modules. I think the code could quickly
get messy and complex if we're cross-checking other module symtabs
every time a module is loaded/unloaded to find which __init symbols
we should no longer keep.

Also worth noting, kallsyms already returns "live" symbols first
before __init ones in this patch, since module_address_lookup() is
called before ftrace_mod_address_lookup(). But I still need to look
into handling collisions in the case of multiple module init funcs
with the same addr, in this case I think we agree that kallsyms should
favor the last loaded module.

>Ideally, I could have a way to know if a module init function was
>traced and its address was stored in a ring buffer, and keep the init
>mapping around and used for that buffer, and free it when the buffer
>is cleared, and there's no other buffers that have a reference to it.
>But I need to find a low overhead way to account for this.
>
>Personally, I would rather have the mappings saved in the symbol tables
>in the module code.
>
>If we can come up with a better module way, I'll convert to that. But
>as I want to get this code upstream by 4.15, I'm going to continue with
>what I have.
>
>Thoughts?

Hm, I am not sure how to fix the symbol mix-up issue when reading out the
trace. I will try to clarify the limitation with an example...

 # rmmod snd_seq
 # echo ':mod:snd_seq' > set_ftrace_filter
 # echo function > current_tracer
 # modprobe snd_seq
 # cat trace
# tracer: function
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |
        modprobe-15680 [000] ....   882.128680: alsa_seq_init <-do_one_initcall
        modprobe-15680 [000] ....   882.128683: client_init_data <-alsa_seq_init
        modprobe-15680 [000] ....   882.128683: snd_sequencer_memory_init <-alsa_seq_init
        modprobe-15680 [000] ....   882.128683: snd_seq_queues_init <-alsa_seq_init
        modprobe-15680 [000] ....   882.128683: snd_sequencer_device_init <-alsa_seq_init
        modprobe-15680 [000] ....   882.128765: snd_seq_info_init <-alsa_seq_init
        modprobe-15680 [000] ....   882.128765: create_info_entry <-snd_seq_info_init
        modprobe-15680 [000] ....   882.128770: create_info_entry <-snd_seq_info_init
        modprobe-15680 [000] ....   882.128771: create_info_entry <-snd_seq_info_init
        modprobe-15680 [000] ....   882.128772: snd_seq_system_client_init <-alsa_seq_init
        modprobe-15680 [000] ....   882.128772: snd_seq_create_kernel_client <-snd_seq_system_client_init
        modprobe-15680 [000] ....   882.128773: seq_create_client1 <-snd_seq_create_kernel_client
        modprobe-15680 [000] ....   882.128773: snd_seq_pool_new <-seq_create_client1

		[output snipped]

OK, so far so good. But as we load/unload modules, and as addresses get reused,
our trace output starts to get messed up:

 # modprobe xxhash
 # cat trace
# tracer: function
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |
        modprobe-15680 [000] ....   882.128680: xxh32 <-do_one_initcall
        modprobe-15680 [000] ....   882.128683: xxh32 <-xxh32
        modprobe-15680 [000] ....   882.128683: xxh32 <-xxh32
        modprobe-15680 [000] ....   882.128683: xxh32 <-xxh32
        modprobe-15680 [000] ....   882.128683: xxh32 <-xxh32
        modprobe-15680 [000] ....   882.128765: xxh64 <-xxh32
        modprobe-15680 [000] ....   882.128765: xxh64 <-xxh64
        modprobe-15680 [000] ....   882.128770: xxh64 <-xxh64
        modprobe-15680 [000] ....   882.128771: xxh64 <-xxh64
        modprobe-15680 [000] ....   882.128772: xxh32 <-xxh32
        modprobe-15680 [000] ....   882.128772: snd_seq_create_kernel_client <-xxh64
        modprobe-15680 [000] ....   882.128773: seq_create_client1 <-snd_seq_create_kernel_client

% grep ffffffffc0d16000 /proc/kallsyms
ffffffffc0d16000 T xxh32        [xxhash]
ffffffffc0d16000 t alsa_seq_init        [snd_seq]
ffffffffc0d16000 t init_module  [snd_seq]
ffffffffc0d16000 t crypto_ccm_module_init       [ccm]
ffffffffc0d16000 t init_module  [ccm]

Since the address lookups in the trace output are being done by kallsyms,
kallsyms will return the "live" symbol xxh32 from the xxhash module (which is
in the module core memory, it's not an __init function) rather than the defunct
alsa_seq_init symbol in freed module init memory. This is because
module_address_lookup(), called from kallsyms_lookup, only takes core module
syms into account. I think this behavior makes sense, but perhaps it's not
completely suited for ftrace's use case here?

Maybe if there is some way to know which module(s) are being actively traced,
then it is possible to narrow the symbol search space to just those modules'
symbol table(s) when displaying the trace output. So if we know that functions
from snd_seq are being traced and *not* functions from xxhash, then we'd find
alsa_seq_init and not xxh32 for example. Do you think something like this would
be possible to do? In this case, ftrace might need something more specialized
than kallsyms_lookup().. 

And yeah, I would rather eventually keep the module init function ->
address mapping in the module symbol tables. The information is
already there, we just don't make it available. __init syms from the
core kernel stay listed in /proc/kallsyms, so I think it's OK to do
this for modules too. And ftrace wouldn't need to do the extra
bookkeeping.

Unfortunately, my next two weeks are looking grim, so I don't think I
can invest too much time on this before the 4.15 merge window :-/ I
don't want to slow you down, so for now please continue with what you
have, but I can gladly revisit this issue with you after the merge
window.

Thanks!

Jessica

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: ftrace: Save module init functions kallsyms symbols for tracing
  2017-10-11 11:19         ` Jessica Yu
@ 2017-10-11 13:11           ` Steven Rostedt
  0 siblings, 0 replies; 11+ messages in thread
From: Steven Rostedt @ 2017-10-11 13:11 UTC (permalink / raw)
  To: Jessica Yu
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Rusty Russell, Joel Fernandes

On Wed, 11 Oct 2017 13:19:42 +0200
Jessica Yu <jeyu@kernel.org> wrote:

> Unfortunately, my next two weeks are looking grim, so I don't think I
> can invest too much time on this before the 4.15 merge window :-/ I
> don't want to slow you down, so for now please continue with what you
> have, but I can gladly revisit this issue with you after the merge
> window.

OK, I'm going to continue the current path. Then we can move the work
back into the module code for 4.16.

Thanks!

-- Steve

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2017-10-11 13:11 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-19 14:28 [RFC][PATCH 0/5] tracing: Allow module init functions to be traced Steven Rostedt
2017-09-19 14:28 ` [RFC][PATCH 1/5] ftrace: Add a ftrace_free_mem() function for modules to use Steven Rostedt
2017-09-19 14:28 ` [RFC][PATCH 2/5] ftrace: Allow module init functions to be traced Steven Rostedt
2017-09-19 14:28 ` [RFC][PATCH 3/5] ftrace: Save module init functions kallsyms symbols for tracing Steven Rostedt
2017-10-06 20:55   ` Jessica Yu
2017-10-09 19:51     ` Steven Rostedt
2017-10-10 15:45       ` Steven Rostedt
2017-10-11 11:19         ` Jessica Yu
2017-10-11 13:11           ` Steven Rostedt
2017-09-19 14:28 ` [RFC][PATCH 4/5] ftrace: Add freeing algorithm to free ftrace_mod_maps Steven Rostedt
2017-09-19 14:28 ` [RFC][PATCH 5/5] ftrace/kallsyms: Have /proc/kallsyms show saved mod init functions Steven Rostedt

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.