All of lore.kernel.org
 help / color / mirror / Atom feed
From: Changbin Du <changbin.du@gmail.com>
To: Steven Rostedt <rostedt@goodmis.org>, Ingo Molnar <mingo@redhat.com>
Cc: Jonathan Corbet <corbet@lwn.net>, Jessica Yu <jeyu@kernel.org>,
	Thomas Gleixner <tglx@linutronix.de>,
	x86@kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, linux-mips@vger.kernel.org,
	linux-parisc@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
	linux-riscv@lists.infradead.org, linux-s390@vger.kernel.org,
	linux-sh@vger.kernel.org, sparclinux@vger.kernel.org,
	linux-arch@vger.kernel.org, linux-kbuild@vger.kernel.org,
	Changbin Du <changbin.du@gmail.com>
Subject: [PATCH 06/11] ftrace: process function prototype data in vmlinux and modules
Date: Sun, 25 Aug 2019 13:23:25 +0000	[thread overview]
Message-ID: <20190825132330.5015-7-changbin.du@gmail.com> (raw)
In-Reply-To: <20190825132330.5015-1-changbin.du@gmail.com>

Walk through the '__funcproto' section in vmlinux and kernel modules.
For each item we add it to a new ftrace hash table ftrace_prototype_hash.
When unloading a module, its items are removed from hash table.

Signed-off-by: Changbin Du <changbin.du@gmail.com>
---
 include/asm-generic/vmlinux.lds.h | 18 ++++++++
 include/linux/ftrace.h            | 18 ++++++++
 include/linux/module.h            |  4 ++
 kernel/module.c                   | 25 ++++++++--
 kernel/trace/ftrace.c             | 76 ++++++++++++++++++++++++++++++-
 kernel/trace/trace.h              |  4 ++
 6 files changed, 140 insertions(+), 5 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index cd28f63bfbc7..3b0a10cbf0ca 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -125,6 +125,23 @@
 #define MCOUNT_REC()
 #endif
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+#define FUNC_PROTOTYPE							\
+	. = ALIGN(8);							\
+	__funcprotostr : AT(ADDR(__funcprotostr) - LOAD_OFFSET) {	\
+		KEEP(*(__funcprotostr)) 				\
+	}								\
+									\
+	. = ALIGN(8);							\
+	__funcproto : AT(ADDR(__funcproto) - LOAD_OFFSET) {		\
+		__start_funcproto = .;					\
+		KEEP(*(__funcproto))					\
+		__stop_funcproto = .;					\
+	}
+#else
+#define	FUNC_PROTOTYPE
+#endif
+
 #ifdef CONFIG_TRACE_BRANCH_PROFILING
 #define LIKELY_PROFILE()	__start_annotated_branch_profile = .;	\
 				KEEP(*(_ftrace_annotated_branch))	\
@@ -396,6 +413,7 @@
 	}								\
 									\
 	TRACEDATA							\
+	FUNC_PROTOTYPE							\
 									\
 	/* Kernel symbol table: Normal symbols */			\
 	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 8a8cb3c401b2..f5aab37a8c34 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -361,6 +361,24 @@ struct dyn_ftrace {
 	struct dyn_arch_ftrace	arch;
 };
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+struct func_param {
+	char *name;
+	uint8_t type;
+	uint8_t loc[2];
+} __packed;
+
+struct func_prototype {
+	unsigned long ip;
+	uint8_t ret_type;
+	uint8_t nr_param;
+	struct func_param params[0];
+} __packed;
+
+#define FTRACE_PROTOTYPE_SIGNED(t)	(t & BIT(7))
+#define FTRACE_PROTOTYPE_SIZE(t)	(t & GENMASK(6, 0))
+#endif
+
 int ftrace_force_update(void);
 int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip,
 			 int remove, int reset);
diff --git a/include/linux/module.h b/include/linux/module.h
index 1455812dd325..516062dfe567 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -477,6 +477,10 @@ struct module {
 	unsigned int num_ftrace_callsites;
 	unsigned long *ftrace_callsites;
 #endif
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	struct func_prototype *funcproto_start;
+	size_t funcproto_sec_size;
+#endif
 
 #ifdef CONFIG_LIVEPATCH
 	bool klp; /* Is this a livepatch module? */
diff --git a/kernel/module.c b/kernel/module.c
index 9ee93421269c..1c5eea7b6a28 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -360,17 +360,30 @@ static void *section_addr(const struct load_info *info, const char *name)
 	return (void *)info->sechdrs[find_sec(info, name)].sh_addr;
 }
 
+/* Get info of a module section. */
+static void *section_info(const struct load_info *info,
+			  const char *name,
+			  size_t *size)
+{
+	unsigned int sec = find_sec(info, name);
+
+	/* Section 0 has sh_addr 0 and sh_size 0. */
+	*size = info->sechdrs[sec].sh_size;
+	return (void *)info->sechdrs[sec].sh_addr;
+}
+
 /* Find a module section, or NULL.  Fill in number of "objects" in section. */
 static void *section_objs(const struct load_info *info,
 			  const char *name,
 			  size_t object_size,
 			  unsigned int *num)
 {
-	unsigned int sec = find_sec(info, name);
+	void *addr;
+	size_t sz;
 
-	/* Section 0 has sh_addr 0 and sh_size 0. */
-	*num = info->sechdrs[sec].sh_size / object_size;
-	return (void *)info->sechdrs[sec].sh_addr;
+	addr = section_info(info, name, &sz);
+	*num = sz / object_size;
+	return addr;
 }
 
 /* Provided by the linker */
@@ -3140,6 +3153,10 @@ static int find_module_sections(struct module *mod, struct load_info *info)
 					     sizeof(*mod->ftrace_callsites),
 					     &mod->num_ftrace_callsites);
 #endif
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	mod->funcproto_start = section_info(info, "__funcproto",
+					    &mod->funcproto_sec_size);
+#endif
 #ifdef CONFIG_FUNCTION_ERROR_INJECTION
 	mod->ei_funcs = section_objs(info, "_error_injection_whitelist",
 					    sizeof(*mod->ei_funcs),
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index cfcb8dad93ea..438b8b47198f 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -5060,6 +5060,9 @@ static DEFINE_MUTEX(graph_lock);
 
 struct ftrace_hash *ftrace_graph_hash = EMPTY_HASH;
 struct ftrace_hash *ftrace_graph_notrace_hash = EMPTY_HASH;
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+struct ftrace_hash *ftrace_prototype_hash = EMPTY_HASH;
+#endif
 
 enum graph_filter_type {
 	GRAPH_FILTER_NOTRACE	= 0,
@@ -5615,6 +5618,46 @@ static int ftrace_process_locs(struct module *mod,
 	return ret;
 }
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+static int ftrace_process_funcproto(struct module *mod,
+			       struct func_prototype *start,
+			       struct func_prototype *end,
+			       bool remove)
+{
+	struct ftrace_func_entry *ent;
+	struct func_prototype *proto;
+	int ret = 0;
+
+	mutex_lock(&ftrace_lock);
+
+restart:
+	proto = start;
+	while (proto < end) {
+		if (remove) {
+			ent = ftrace_lookup_ip(ftrace_prototype_hash,
+					       proto->ip);
+			if (ent)
+				free_hash_entry(ftrace_prototype_hash, ent);
+		} else {
+			ret = add_hash_entry(ftrace_prototype_hash,
+					     proto->ip, proto);
+			if (ret < 0) {
+				end = proto;
+				remove = 1;
+				goto restart;
+			}
+		}
+		proto = (struct func_prototype *)((char *)proto +
+			sizeof(*proto) +
+			sizeof(proto->params[0]) * proto->nr_param);
+	}
+
+	mutex_unlock(&ftrace_lock);
+
+	return ret;
+}
+#endif
+
 struct ftrace_mod_func {
 	struct list_head	list;
 	char			*name;
@@ -5707,7 +5750,7 @@ static void ftrace_free_mod_map(struct rcu_head *rcu)
 	kfree(mod_map);
 }
 
-void ftrace_release_mod(struct module *mod)
+void ftrace_release_dyn(struct module *mod)
 {
 	struct ftrace_mod_map *mod_map;
 	struct ftrace_mod_map *n;
@@ -5773,6 +5816,17 @@ void ftrace_release_mod(struct module *mod)
 	}
 }
 
+void ftrace_release_mod(struct module *mod)
+{
+	ftrace_release_dyn(mod);
+
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	ftrace_process_funcproto(mod, mod->funcproto_start,
+			(void *)mod->funcproto_start + mod->funcproto_sec_size,
+			true);
+#endif
+}
+
 void ftrace_module_enable(struct module *mod)
 {
 	struct dyn_ftrace *rec;
@@ -5852,6 +5906,11 @@ void ftrace_module_init(struct module *mod)
 
 	ftrace_process_locs(mod, mod->ftrace_callsites,
 			    mod->ftrace_callsites + mod->num_ftrace_callsites);
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	ftrace_process_funcproto(mod, mod->funcproto_start,
+			(void *)mod->funcproto_start + mod->funcproto_sec_size,
+			false);
+#endif
 }
 
 static void save_ftrace_mod_rec(struct ftrace_mod_map *mod_map,
@@ -6146,6 +6205,10 @@ void __init ftrace_init(void)
 {
 	extern unsigned long __start_mcount_loc[];
 	extern unsigned long __stop_mcount_loc[];
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	extern struct func_prototype __start_funcproto[];
+	extern struct func_prototype __stop_funcproto[];
+#endif
 	unsigned long count, flags;
 	int ret;
 
@@ -6179,6 +6242,17 @@ void __init ftrace_init(void)
 				  __start_mcount_loc,
 				  __stop_mcount_loc);
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	ftrace_prototype_hash = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS);
+	if (WARN_ON(!ftrace_prototype_hash))
+		goto failed;
+
+	ftrace_process_funcproto(NULL,
+				 __start_funcproto,
+				 __stop_funcproto,
+				 false);
+#endif
+
 	set_ftrace_early_filters();
 
 	return;
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index ad619c73a505..22433a15e340 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -940,6 +940,10 @@ extern void __trace_graph_return(struct trace_array *tr,
 extern struct ftrace_hash *ftrace_graph_hash;
 extern struct ftrace_hash *ftrace_graph_notrace_hash;
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+extern struct ftrace_hash *ftrace_prototype_hash;
+#endif
+
 static inline int ftrace_graph_addr(struct ftrace_graph_ent *trace)
 {
 	unsigned long addr = trace->func;
-- 
2.20.1

WARNING: multiple messages have this Message-ID (diff)
From: Changbin Du <changbin.du@gmail.com>
To: Steven Rostedt <rostedt@goodmis.org>, Ingo Molnar <mingo@redhat.com>
Cc: Jonathan Corbet <corbet@lwn.net>, Jessica Yu <jeyu@kernel.org>,
	Thomas Gleixner <tglx@linutronix.de>,
	x86@kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, linux-mips@vger.kernel.org,
	linux-parisc@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
	linux-riscv@lists.infradead.org, linux-s390@vger.kernel.org,
	linux-sh@vger.kernel.org, sparclinux@vger.kernel.org,
	linux-arch@vger.kernel.org, linux-kbuild@vger.kernel.org,
	Changbin Du <changbin.du@gmail.com>
Subject: [PATCH 06/11] ftrace: process function prototype data in vmlinux and modules
Date: Sun, 25 Aug 2019 21:23:25 +0800	[thread overview]
Message-ID: <20190825132330.5015-7-changbin.du@gmail.com> (raw)
In-Reply-To: <20190825132330.5015-1-changbin.du@gmail.com>

Walk through the '__funcproto' section in vmlinux and kernel modules.
For each item we add it to a new ftrace hash table ftrace_prototype_hash.
When unloading a module, its items are removed from hash table.

Signed-off-by: Changbin Du <changbin.du@gmail.com>
---
 include/asm-generic/vmlinux.lds.h | 18 ++++++++
 include/linux/ftrace.h            | 18 ++++++++
 include/linux/module.h            |  4 ++
 kernel/module.c                   | 25 ++++++++--
 kernel/trace/ftrace.c             | 76 ++++++++++++++++++++++++++++++-
 kernel/trace/trace.h              |  4 ++
 6 files changed, 140 insertions(+), 5 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index cd28f63bfbc7..3b0a10cbf0ca 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -125,6 +125,23 @@
 #define MCOUNT_REC()
 #endif
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+#define FUNC_PROTOTYPE							\
+	. = ALIGN(8);							\
+	__funcprotostr : AT(ADDR(__funcprotostr) - LOAD_OFFSET) {	\
+		KEEP(*(__funcprotostr)) 				\
+	}								\
+									\
+	. = ALIGN(8);							\
+	__funcproto : AT(ADDR(__funcproto) - LOAD_OFFSET) {		\
+		__start_funcproto = .;					\
+		KEEP(*(__funcproto))					\
+		__stop_funcproto = .;					\
+	}
+#else
+#define	FUNC_PROTOTYPE
+#endif
+
 #ifdef CONFIG_TRACE_BRANCH_PROFILING
 #define LIKELY_PROFILE()	__start_annotated_branch_profile = .;	\
 				KEEP(*(_ftrace_annotated_branch))	\
@@ -396,6 +413,7 @@
 	}								\
 									\
 	TRACEDATA							\
+	FUNC_PROTOTYPE							\
 									\
 	/* Kernel symbol table: Normal symbols */			\
 	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 8a8cb3c401b2..f5aab37a8c34 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -361,6 +361,24 @@ struct dyn_ftrace {
 	struct dyn_arch_ftrace	arch;
 };
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+struct func_param {
+	char *name;
+	uint8_t type;
+	uint8_t loc[2];
+} __packed;
+
+struct func_prototype {
+	unsigned long ip;
+	uint8_t ret_type;
+	uint8_t nr_param;
+	struct func_param params[0];
+} __packed;
+
+#define FTRACE_PROTOTYPE_SIGNED(t)	(t & BIT(7))
+#define FTRACE_PROTOTYPE_SIZE(t)	(t & GENMASK(6, 0))
+#endif
+
 int ftrace_force_update(void);
 int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip,
 			 int remove, int reset);
diff --git a/include/linux/module.h b/include/linux/module.h
index 1455812dd325..516062dfe567 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -477,6 +477,10 @@ struct module {
 	unsigned int num_ftrace_callsites;
 	unsigned long *ftrace_callsites;
 #endif
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	struct func_prototype *funcproto_start;
+	size_t funcproto_sec_size;
+#endif
 
 #ifdef CONFIG_LIVEPATCH
 	bool klp; /* Is this a livepatch module? */
diff --git a/kernel/module.c b/kernel/module.c
index 9ee93421269c..1c5eea7b6a28 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -360,17 +360,30 @@ static void *section_addr(const struct load_info *info, const char *name)
 	return (void *)info->sechdrs[find_sec(info, name)].sh_addr;
 }
 
+/* Get info of a module section. */
+static void *section_info(const struct load_info *info,
+			  const char *name,
+			  size_t *size)
+{
+	unsigned int sec = find_sec(info, name);
+
+	/* Section 0 has sh_addr 0 and sh_size 0. */
+	*size = info->sechdrs[sec].sh_size;
+	return (void *)info->sechdrs[sec].sh_addr;
+}
+
 /* Find a module section, or NULL.  Fill in number of "objects" in section. */
 static void *section_objs(const struct load_info *info,
 			  const char *name,
 			  size_t object_size,
 			  unsigned int *num)
 {
-	unsigned int sec = find_sec(info, name);
+	void *addr;
+	size_t sz;
 
-	/* Section 0 has sh_addr 0 and sh_size 0. */
-	*num = info->sechdrs[sec].sh_size / object_size;
-	return (void *)info->sechdrs[sec].sh_addr;
+	addr = section_info(info, name, &sz);
+	*num = sz / object_size;
+	return addr;
 }
 
 /* Provided by the linker */
@@ -3140,6 +3153,10 @@ static int find_module_sections(struct module *mod, struct load_info *info)
 					     sizeof(*mod->ftrace_callsites),
 					     &mod->num_ftrace_callsites);
 #endif
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	mod->funcproto_start = section_info(info, "__funcproto",
+					    &mod->funcproto_sec_size);
+#endif
 #ifdef CONFIG_FUNCTION_ERROR_INJECTION
 	mod->ei_funcs = section_objs(info, "_error_injection_whitelist",
 					    sizeof(*mod->ei_funcs),
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index cfcb8dad93ea..438b8b47198f 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -5060,6 +5060,9 @@ static DEFINE_MUTEX(graph_lock);
 
 struct ftrace_hash *ftrace_graph_hash = EMPTY_HASH;
 struct ftrace_hash *ftrace_graph_notrace_hash = EMPTY_HASH;
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+struct ftrace_hash *ftrace_prototype_hash = EMPTY_HASH;
+#endif
 
 enum graph_filter_type {
 	GRAPH_FILTER_NOTRACE	= 0,
@@ -5615,6 +5618,46 @@ static int ftrace_process_locs(struct module *mod,
 	return ret;
 }
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+static int ftrace_process_funcproto(struct module *mod,
+			       struct func_prototype *start,
+			       struct func_prototype *end,
+			       bool remove)
+{
+	struct ftrace_func_entry *ent;
+	struct func_prototype *proto;
+	int ret = 0;
+
+	mutex_lock(&ftrace_lock);
+
+restart:
+	proto = start;
+	while (proto < end) {
+		if (remove) {
+			ent = ftrace_lookup_ip(ftrace_prototype_hash,
+					       proto->ip);
+			if (ent)
+				free_hash_entry(ftrace_prototype_hash, ent);
+		} else {
+			ret = add_hash_entry(ftrace_prototype_hash,
+					     proto->ip, proto);
+			if (ret < 0) {
+				end = proto;
+				remove = 1;
+				goto restart;
+			}
+		}
+		proto = (struct func_prototype *)((char *)proto +
+			sizeof(*proto) +
+			sizeof(proto->params[0]) * proto->nr_param);
+	}
+
+	mutex_unlock(&ftrace_lock);
+
+	return ret;
+}
+#endif
+
 struct ftrace_mod_func {
 	struct list_head	list;
 	char			*name;
@@ -5707,7 +5750,7 @@ static void ftrace_free_mod_map(struct rcu_head *rcu)
 	kfree(mod_map);
 }
 
-void ftrace_release_mod(struct module *mod)
+void ftrace_release_dyn(struct module *mod)
 {
 	struct ftrace_mod_map *mod_map;
 	struct ftrace_mod_map *n;
@@ -5773,6 +5816,17 @@ void ftrace_release_mod(struct module *mod)
 	}
 }
 
+void ftrace_release_mod(struct module *mod)
+{
+	ftrace_release_dyn(mod);
+
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	ftrace_process_funcproto(mod, mod->funcproto_start,
+			(void *)mod->funcproto_start + mod->funcproto_sec_size,
+			true);
+#endif
+}
+
 void ftrace_module_enable(struct module *mod)
 {
 	struct dyn_ftrace *rec;
@@ -5852,6 +5906,11 @@ void ftrace_module_init(struct module *mod)
 
 	ftrace_process_locs(mod, mod->ftrace_callsites,
 			    mod->ftrace_callsites + mod->num_ftrace_callsites);
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	ftrace_process_funcproto(mod, mod->funcproto_start,
+			(void *)mod->funcproto_start + mod->funcproto_sec_size,
+			false);
+#endif
 }
 
 static void save_ftrace_mod_rec(struct ftrace_mod_map *mod_map,
@@ -6146,6 +6205,10 @@ void __init ftrace_init(void)
 {
 	extern unsigned long __start_mcount_loc[];
 	extern unsigned long __stop_mcount_loc[];
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	extern struct func_prototype __start_funcproto[];
+	extern struct func_prototype __stop_funcproto[];
+#endif
 	unsigned long count, flags;
 	int ret;
 
@@ -6179,6 +6242,17 @@ void __init ftrace_init(void)
 				  __start_mcount_loc,
 				  __stop_mcount_loc);
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	ftrace_prototype_hash = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS);
+	if (WARN_ON(!ftrace_prototype_hash))
+		goto failed;
+
+	ftrace_process_funcproto(NULL,
+				 __start_funcproto,
+				 __stop_funcproto,
+				 false);
+#endif
+
 	set_ftrace_early_filters();
 
 	return;
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index ad619c73a505..22433a15e340 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -940,6 +940,10 @@ extern void __trace_graph_return(struct trace_array *tr,
 extern struct ftrace_hash *ftrace_graph_hash;
 extern struct ftrace_hash *ftrace_graph_notrace_hash;
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+extern struct ftrace_hash *ftrace_prototype_hash;
+#endif
+
 static inline int ftrace_graph_addr(struct ftrace_graph_ent *trace)
 {
 	unsigned long addr = trace->func;
-- 
2.20.1


WARNING: multiple messages have this Message-ID (diff)
From: Changbin Du <changbin.du@gmail.com>
To: Steven Rostedt <rostedt@goodmis.org>, Ingo Molnar <mingo@redhat.com>
Cc: linux-arch@vger.kernel.org, Jonathan Corbet <corbet@lwn.net>,
	linux-parisc@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-sh@vger.kernel.org, linux-s390@vger.kernel.org,
	x86@kernel.org, linux-kernel@vger.kernel.org,
	linux-mips@vger.kernel.org, Jessica Yu <jeyu@kernel.org>,
	sparclinux@vger.kernel.org, linux-kbuild@vger.kernel.org,
	Thomas Gleixner <tglx@linutronix.de>,
	linuxppc-dev@lists.ozlabs.org, linux-riscv@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Changbin Du <changbin.du@gmail.com>
Subject: [PATCH 06/11] ftrace: process function prototype data in vmlinux and modules
Date: Sun, 25 Aug 2019 21:23:25 +0800	[thread overview]
Message-ID: <20190825132330.5015-7-changbin.du@gmail.com> (raw)
In-Reply-To: <20190825132330.5015-1-changbin.du@gmail.com>

Walk through the '__funcproto' section in vmlinux and kernel modules.
For each item we add it to a new ftrace hash table ftrace_prototype_hash.
When unloading a module, its items are removed from hash table.

Signed-off-by: Changbin Du <changbin.du@gmail.com>
---
 include/asm-generic/vmlinux.lds.h | 18 ++++++++
 include/linux/ftrace.h            | 18 ++++++++
 include/linux/module.h            |  4 ++
 kernel/module.c                   | 25 ++++++++--
 kernel/trace/ftrace.c             | 76 ++++++++++++++++++++++++++++++-
 kernel/trace/trace.h              |  4 ++
 6 files changed, 140 insertions(+), 5 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index cd28f63bfbc7..3b0a10cbf0ca 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -125,6 +125,23 @@
 #define MCOUNT_REC()
 #endif
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+#define FUNC_PROTOTYPE							\
+	. = ALIGN(8);							\
+	__funcprotostr : AT(ADDR(__funcprotostr) - LOAD_OFFSET) {	\
+		KEEP(*(__funcprotostr)) 				\
+	}								\
+									\
+	. = ALIGN(8);							\
+	__funcproto : AT(ADDR(__funcproto) - LOAD_OFFSET) {		\
+		__start_funcproto = .;					\
+		KEEP(*(__funcproto))					\
+		__stop_funcproto = .;					\
+	}
+#else
+#define	FUNC_PROTOTYPE
+#endif
+
 #ifdef CONFIG_TRACE_BRANCH_PROFILING
 #define LIKELY_PROFILE()	__start_annotated_branch_profile = .;	\
 				KEEP(*(_ftrace_annotated_branch))	\
@@ -396,6 +413,7 @@
 	}								\
 									\
 	TRACEDATA							\
+	FUNC_PROTOTYPE							\
 									\
 	/* Kernel symbol table: Normal symbols */			\
 	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 8a8cb3c401b2..f5aab37a8c34 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -361,6 +361,24 @@ struct dyn_ftrace {
 	struct dyn_arch_ftrace	arch;
 };
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+struct func_param {
+	char *name;
+	uint8_t type;
+	uint8_t loc[2];
+} __packed;
+
+struct func_prototype {
+	unsigned long ip;
+	uint8_t ret_type;
+	uint8_t nr_param;
+	struct func_param params[0];
+} __packed;
+
+#define FTRACE_PROTOTYPE_SIGNED(t)	(t & BIT(7))
+#define FTRACE_PROTOTYPE_SIZE(t)	(t & GENMASK(6, 0))
+#endif
+
 int ftrace_force_update(void);
 int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip,
 			 int remove, int reset);
diff --git a/include/linux/module.h b/include/linux/module.h
index 1455812dd325..516062dfe567 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -477,6 +477,10 @@ struct module {
 	unsigned int num_ftrace_callsites;
 	unsigned long *ftrace_callsites;
 #endif
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	struct func_prototype *funcproto_start;
+	size_t funcproto_sec_size;
+#endif
 
 #ifdef CONFIG_LIVEPATCH
 	bool klp; /* Is this a livepatch module? */
diff --git a/kernel/module.c b/kernel/module.c
index 9ee93421269c..1c5eea7b6a28 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -360,17 +360,30 @@ static void *section_addr(const struct load_info *info, const char *name)
 	return (void *)info->sechdrs[find_sec(info, name)].sh_addr;
 }
 
+/* Get info of a module section. */
+static void *section_info(const struct load_info *info,
+			  const char *name,
+			  size_t *size)
+{
+	unsigned int sec = find_sec(info, name);
+
+	/* Section 0 has sh_addr 0 and sh_size 0. */
+	*size = info->sechdrs[sec].sh_size;
+	return (void *)info->sechdrs[sec].sh_addr;
+}
+
 /* Find a module section, or NULL.  Fill in number of "objects" in section. */
 static void *section_objs(const struct load_info *info,
 			  const char *name,
 			  size_t object_size,
 			  unsigned int *num)
 {
-	unsigned int sec = find_sec(info, name);
+	void *addr;
+	size_t sz;
 
-	/* Section 0 has sh_addr 0 and sh_size 0. */
-	*num = info->sechdrs[sec].sh_size / object_size;
-	return (void *)info->sechdrs[sec].sh_addr;
+	addr = section_info(info, name, &sz);
+	*num = sz / object_size;
+	return addr;
 }
 
 /* Provided by the linker */
@@ -3140,6 +3153,10 @@ static int find_module_sections(struct module *mod, struct load_info *info)
 					     sizeof(*mod->ftrace_callsites),
 					     &mod->num_ftrace_callsites);
 #endif
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	mod->funcproto_start = section_info(info, "__funcproto",
+					    &mod->funcproto_sec_size);
+#endif
 #ifdef CONFIG_FUNCTION_ERROR_INJECTION
 	mod->ei_funcs = section_objs(info, "_error_injection_whitelist",
 					    sizeof(*mod->ei_funcs),
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index cfcb8dad93ea..438b8b47198f 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -5060,6 +5060,9 @@ static DEFINE_MUTEX(graph_lock);
 
 struct ftrace_hash *ftrace_graph_hash = EMPTY_HASH;
 struct ftrace_hash *ftrace_graph_notrace_hash = EMPTY_HASH;
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+struct ftrace_hash *ftrace_prototype_hash = EMPTY_HASH;
+#endif
 
 enum graph_filter_type {
 	GRAPH_FILTER_NOTRACE	= 0,
@@ -5615,6 +5618,46 @@ static int ftrace_process_locs(struct module *mod,
 	return ret;
 }
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+static int ftrace_process_funcproto(struct module *mod,
+			       struct func_prototype *start,
+			       struct func_prototype *end,
+			       bool remove)
+{
+	struct ftrace_func_entry *ent;
+	struct func_prototype *proto;
+	int ret = 0;
+
+	mutex_lock(&ftrace_lock);
+
+restart:
+	proto = start;
+	while (proto < end) {
+		if (remove) {
+			ent = ftrace_lookup_ip(ftrace_prototype_hash,
+					       proto->ip);
+			if (ent)
+				free_hash_entry(ftrace_prototype_hash, ent);
+		} else {
+			ret = add_hash_entry(ftrace_prototype_hash,
+					     proto->ip, proto);
+			if (ret < 0) {
+				end = proto;
+				remove = 1;
+				goto restart;
+			}
+		}
+		proto = (struct func_prototype *)((char *)proto +
+			sizeof(*proto) +
+			sizeof(proto->params[0]) * proto->nr_param);
+	}
+
+	mutex_unlock(&ftrace_lock);
+
+	return ret;
+}
+#endif
+
 struct ftrace_mod_func {
 	struct list_head	list;
 	char			*name;
@@ -5707,7 +5750,7 @@ static void ftrace_free_mod_map(struct rcu_head *rcu)
 	kfree(mod_map);
 }
 
-void ftrace_release_mod(struct module *mod)
+void ftrace_release_dyn(struct module *mod)
 {
 	struct ftrace_mod_map *mod_map;
 	struct ftrace_mod_map *n;
@@ -5773,6 +5816,17 @@ void ftrace_release_mod(struct module *mod)
 	}
 }
 
+void ftrace_release_mod(struct module *mod)
+{
+	ftrace_release_dyn(mod);
+
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	ftrace_process_funcproto(mod, mod->funcproto_start,
+			(void *)mod->funcproto_start + mod->funcproto_sec_size,
+			true);
+#endif
+}
+
 void ftrace_module_enable(struct module *mod)
 {
 	struct dyn_ftrace *rec;
@@ -5852,6 +5906,11 @@ void ftrace_module_init(struct module *mod)
 
 	ftrace_process_locs(mod, mod->ftrace_callsites,
 			    mod->ftrace_callsites + mod->num_ftrace_callsites);
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	ftrace_process_funcproto(mod, mod->funcproto_start,
+			(void *)mod->funcproto_start + mod->funcproto_sec_size,
+			false);
+#endif
 }
 
 static void save_ftrace_mod_rec(struct ftrace_mod_map *mod_map,
@@ -6146,6 +6205,10 @@ void __init ftrace_init(void)
 {
 	extern unsigned long __start_mcount_loc[];
 	extern unsigned long __stop_mcount_loc[];
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	extern struct func_prototype __start_funcproto[];
+	extern struct func_prototype __stop_funcproto[];
+#endif
 	unsigned long count, flags;
 	int ret;
 
@@ -6179,6 +6242,17 @@ void __init ftrace_init(void)
 				  __start_mcount_loc,
 				  __stop_mcount_loc);
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	ftrace_prototype_hash = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS);
+	if (WARN_ON(!ftrace_prototype_hash))
+		goto failed;
+
+	ftrace_process_funcproto(NULL,
+				 __start_funcproto,
+				 __stop_funcproto,
+				 false);
+#endif
+
 	set_ftrace_early_filters();
 
 	return;
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index ad619c73a505..22433a15e340 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -940,6 +940,10 @@ extern void __trace_graph_return(struct trace_array *tr,
 extern struct ftrace_hash *ftrace_graph_hash;
 extern struct ftrace_hash *ftrace_graph_notrace_hash;
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+extern struct ftrace_hash *ftrace_prototype_hash;
+#endif
+
 static inline int ftrace_graph_addr(struct ftrace_graph_ent *trace)
 {
 	unsigned long addr = trace->func;
-- 
2.20.1


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

WARNING: multiple messages have this Message-ID (diff)
From: Changbin Du <changbin.du@gmail.com>
To: Steven Rostedt <rostedt@goodmis.org>, Ingo Molnar <mingo@redhat.com>
Cc: linux-arch@vger.kernel.org, Jonathan Corbet <corbet@lwn.net>,
	linux-parisc@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-sh@vger.kernel.org, linux-s390@vger.kernel.org,
	x86@kernel.org, linux-kernel@vger.kernel.org,
	linux-mips@vger.kernel.org, Jessica Yu <jeyu@kernel.org>,
	sparclinux@vger.kernel.org, linux-kbuild@vger.kernel.org,
	Thomas Gleixner <tglx@linutronix.de>,
	linuxppc-dev@lists.ozlabs.org, linux-riscv@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Changbin Du <changbin.du@gmail.com>
Subject: [PATCH 06/11] ftrace: process function prototype data in vmlinux and modules
Date: Sun, 25 Aug 2019 21:23:25 +0800	[thread overview]
Message-ID: <20190825132330.5015-7-changbin.du@gmail.com> (raw)
In-Reply-To: <20190825132330.5015-1-changbin.du@gmail.com>

Walk through the '__funcproto' section in vmlinux and kernel modules.
For each item we add it to a new ftrace hash table ftrace_prototype_hash.
When unloading a module, its items are removed from hash table.

Signed-off-by: Changbin Du <changbin.du@gmail.com>
---
 include/asm-generic/vmlinux.lds.h | 18 ++++++++
 include/linux/ftrace.h            | 18 ++++++++
 include/linux/module.h            |  4 ++
 kernel/module.c                   | 25 ++++++++--
 kernel/trace/ftrace.c             | 76 ++++++++++++++++++++++++++++++-
 kernel/trace/trace.h              |  4 ++
 6 files changed, 140 insertions(+), 5 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index cd28f63bfbc7..3b0a10cbf0ca 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -125,6 +125,23 @@
 #define MCOUNT_REC()
 #endif
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+#define FUNC_PROTOTYPE							\
+	. = ALIGN(8);							\
+	__funcprotostr : AT(ADDR(__funcprotostr) - LOAD_OFFSET) {	\
+		KEEP(*(__funcprotostr)) 				\
+	}								\
+									\
+	. = ALIGN(8);							\
+	__funcproto : AT(ADDR(__funcproto) - LOAD_OFFSET) {		\
+		__start_funcproto = .;					\
+		KEEP(*(__funcproto))					\
+		__stop_funcproto = .;					\
+	}
+#else
+#define	FUNC_PROTOTYPE
+#endif
+
 #ifdef CONFIG_TRACE_BRANCH_PROFILING
 #define LIKELY_PROFILE()	__start_annotated_branch_profile = .;	\
 				KEEP(*(_ftrace_annotated_branch))	\
@@ -396,6 +413,7 @@
 	}								\
 									\
 	TRACEDATA							\
+	FUNC_PROTOTYPE							\
 									\
 	/* Kernel symbol table: Normal symbols */			\
 	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 8a8cb3c401b2..f5aab37a8c34 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -361,6 +361,24 @@ struct dyn_ftrace {
 	struct dyn_arch_ftrace	arch;
 };
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+struct func_param {
+	char *name;
+	uint8_t type;
+	uint8_t loc[2];
+} __packed;
+
+struct func_prototype {
+	unsigned long ip;
+	uint8_t ret_type;
+	uint8_t nr_param;
+	struct func_param params[0];
+} __packed;
+
+#define FTRACE_PROTOTYPE_SIGNED(t)	(t & BIT(7))
+#define FTRACE_PROTOTYPE_SIZE(t)	(t & GENMASK(6, 0))
+#endif
+
 int ftrace_force_update(void);
 int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip,
 			 int remove, int reset);
diff --git a/include/linux/module.h b/include/linux/module.h
index 1455812dd325..516062dfe567 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -477,6 +477,10 @@ struct module {
 	unsigned int num_ftrace_callsites;
 	unsigned long *ftrace_callsites;
 #endif
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	struct func_prototype *funcproto_start;
+	size_t funcproto_sec_size;
+#endif
 
 #ifdef CONFIG_LIVEPATCH
 	bool klp; /* Is this a livepatch module? */
diff --git a/kernel/module.c b/kernel/module.c
index 9ee93421269c..1c5eea7b6a28 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -360,17 +360,30 @@ static void *section_addr(const struct load_info *info, const char *name)
 	return (void *)info->sechdrs[find_sec(info, name)].sh_addr;
 }
 
+/* Get info of a module section. */
+static void *section_info(const struct load_info *info,
+			  const char *name,
+			  size_t *size)
+{
+	unsigned int sec = find_sec(info, name);
+
+	/* Section 0 has sh_addr 0 and sh_size 0. */
+	*size = info->sechdrs[sec].sh_size;
+	return (void *)info->sechdrs[sec].sh_addr;
+}
+
 /* Find a module section, or NULL.  Fill in number of "objects" in section. */
 static void *section_objs(const struct load_info *info,
 			  const char *name,
 			  size_t object_size,
 			  unsigned int *num)
 {
-	unsigned int sec = find_sec(info, name);
+	void *addr;
+	size_t sz;
 
-	/* Section 0 has sh_addr 0 and sh_size 0. */
-	*num = info->sechdrs[sec].sh_size / object_size;
-	return (void *)info->sechdrs[sec].sh_addr;
+	addr = section_info(info, name, &sz);
+	*num = sz / object_size;
+	return addr;
 }
 
 /* Provided by the linker */
@@ -3140,6 +3153,10 @@ static int find_module_sections(struct module *mod, struct load_info *info)
 					     sizeof(*mod->ftrace_callsites),
 					     &mod->num_ftrace_callsites);
 #endif
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	mod->funcproto_start = section_info(info, "__funcproto",
+					    &mod->funcproto_sec_size);
+#endif
 #ifdef CONFIG_FUNCTION_ERROR_INJECTION
 	mod->ei_funcs = section_objs(info, "_error_injection_whitelist",
 					    sizeof(*mod->ei_funcs),
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index cfcb8dad93ea..438b8b47198f 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -5060,6 +5060,9 @@ static DEFINE_MUTEX(graph_lock);
 
 struct ftrace_hash *ftrace_graph_hash = EMPTY_HASH;
 struct ftrace_hash *ftrace_graph_notrace_hash = EMPTY_HASH;
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+struct ftrace_hash *ftrace_prototype_hash = EMPTY_HASH;
+#endif
 
 enum graph_filter_type {
 	GRAPH_FILTER_NOTRACE	= 0,
@@ -5615,6 +5618,46 @@ static int ftrace_process_locs(struct module *mod,
 	return ret;
 }
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+static int ftrace_process_funcproto(struct module *mod,
+			       struct func_prototype *start,
+			       struct func_prototype *end,
+			       bool remove)
+{
+	struct ftrace_func_entry *ent;
+	struct func_prototype *proto;
+	int ret = 0;
+
+	mutex_lock(&ftrace_lock);
+
+restart:
+	proto = start;
+	while (proto < end) {
+		if (remove) {
+			ent = ftrace_lookup_ip(ftrace_prototype_hash,
+					       proto->ip);
+			if (ent)
+				free_hash_entry(ftrace_prototype_hash, ent);
+		} else {
+			ret = add_hash_entry(ftrace_prototype_hash,
+					     proto->ip, proto);
+			if (ret < 0) {
+				end = proto;
+				remove = 1;
+				goto restart;
+			}
+		}
+		proto = (struct func_prototype *)((char *)proto +
+			sizeof(*proto) +
+			sizeof(proto->params[0]) * proto->nr_param);
+	}
+
+	mutex_unlock(&ftrace_lock);
+
+	return ret;
+}
+#endif
+
 struct ftrace_mod_func {
 	struct list_head	list;
 	char			*name;
@@ -5707,7 +5750,7 @@ static void ftrace_free_mod_map(struct rcu_head *rcu)
 	kfree(mod_map);
 }
 
-void ftrace_release_mod(struct module *mod)
+void ftrace_release_dyn(struct module *mod)
 {
 	struct ftrace_mod_map *mod_map;
 	struct ftrace_mod_map *n;
@@ -5773,6 +5816,17 @@ void ftrace_release_mod(struct module *mod)
 	}
 }
 
+void ftrace_release_mod(struct module *mod)
+{
+	ftrace_release_dyn(mod);
+
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	ftrace_process_funcproto(mod, mod->funcproto_start,
+			(void *)mod->funcproto_start + mod->funcproto_sec_size,
+			true);
+#endif
+}
+
 void ftrace_module_enable(struct module *mod)
 {
 	struct dyn_ftrace *rec;
@@ -5852,6 +5906,11 @@ void ftrace_module_init(struct module *mod)
 
 	ftrace_process_locs(mod, mod->ftrace_callsites,
 			    mod->ftrace_callsites + mod->num_ftrace_callsites);
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	ftrace_process_funcproto(mod, mod->funcproto_start,
+			(void *)mod->funcproto_start + mod->funcproto_sec_size,
+			false);
+#endif
 }
 
 static void save_ftrace_mod_rec(struct ftrace_mod_map *mod_map,
@@ -6146,6 +6205,10 @@ void __init ftrace_init(void)
 {
 	extern unsigned long __start_mcount_loc[];
 	extern unsigned long __stop_mcount_loc[];
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	extern struct func_prototype __start_funcproto[];
+	extern struct func_prototype __stop_funcproto[];
+#endif
 	unsigned long count, flags;
 	int ret;
 
@@ -6179,6 +6242,17 @@ void __init ftrace_init(void)
 				  __start_mcount_loc,
 				  __stop_mcount_loc);
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	ftrace_prototype_hash = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS);
+	if (WARN_ON(!ftrace_prototype_hash))
+		goto failed;
+
+	ftrace_process_funcproto(NULL,
+				 __start_funcproto,
+				 __stop_funcproto,
+				 false);
+#endif
+
 	set_ftrace_early_filters();
 
 	return;
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index ad619c73a505..22433a15e340 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -940,6 +940,10 @@ extern void __trace_graph_return(struct trace_array *tr,
 extern struct ftrace_hash *ftrace_graph_hash;
 extern struct ftrace_hash *ftrace_graph_notrace_hash;
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+extern struct ftrace_hash *ftrace_prototype_hash;
+#endif
+
 static inline int ftrace_graph_addr(struct ftrace_graph_ent *trace)
 {
 	unsigned long addr = trace->func;
-- 
2.20.1


WARNING: multiple messages have this Message-ID (diff)
From: Changbin Du <changbin.du@gmail.com>
To: Steven Rostedt <rostedt@goodmis.org>, Ingo Molnar <mingo@redhat.com>
Cc: linux-arch@vger.kernel.org, Jonathan Corbet <corbet@lwn.net>,
	linux-parisc@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-sh@vger.kernel.org, linux-s390@vger.kernel.org,
	x86@kernel.org, linux-kernel@vger.kernel.org,
	linux-mips@vger.kernel.org, Jessica Yu <jeyu@kernel.org>,
	sparclinux@vger.kernel.org, linux-kbuild@vger.kernel.org,
	Thomas Gleixner <tglx@linutronix.de>,
	linuxppc-dev@lists.ozlabs.org, linux-riscv@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Changbin Du <changbin.du@gmail.com>
Subject: [PATCH 06/11] ftrace: process function prototype data in vmlinux and modules
Date: Sun, 25 Aug 2019 21:23:25 +0800	[thread overview]
Message-ID: <20190825132330.5015-7-changbin.du@gmail.com> (raw)
In-Reply-To: <20190825132330.5015-1-changbin.du@gmail.com>

Walk through the '__funcproto' section in vmlinux and kernel modules.
For each item we add it to a new ftrace hash table ftrace_prototype_hash.
When unloading a module, its items are removed from hash table.

Signed-off-by: Changbin Du <changbin.du@gmail.com>
---
 include/asm-generic/vmlinux.lds.h | 18 ++++++++
 include/linux/ftrace.h            | 18 ++++++++
 include/linux/module.h            |  4 ++
 kernel/module.c                   | 25 ++++++++--
 kernel/trace/ftrace.c             | 76 ++++++++++++++++++++++++++++++-
 kernel/trace/trace.h              |  4 ++
 6 files changed, 140 insertions(+), 5 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index cd28f63bfbc7..3b0a10cbf0ca 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -125,6 +125,23 @@
 #define MCOUNT_REC()
 #endif
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+#define FUNC_PROTOTYPE							\
+	. = ALIGN(8);							\
+	__funcprotostr : AT(ADDR(__funcprotostr) - LOAD_OFFSET) {	\
+		KEEP(*(__funcprotostr)) 				\
+	}								\
+									\
+	. = ALIGN(8);							\
+	__funcproto : AT(ADDR(__funcproto) - LOAD_OFFSET) {		\
+		__start_funcproto = .;					\
+		KEEP(*(__funcproto))					\
+		__stop_funcproto = .;					\
+	}
+#else
+#define	FUNC_PROTOTYPE
+#endif
+
 #ifdef CONFIG_TRACE_BRANCH_PROFILING
 #define LIKELY_PROFILE()	__start_annotated_branch_profile = .;	\
 				KEEP(*(_ftrace_annotated_branch))	\
@@ -396,6 +413,7 @@
 	}								\
 									\
 	TRACEDATA							\
+	FUNC_PROTOTYPE							\
 									\
 	/* Kernel symbol table: Normal symbols */			\
 	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 8a8cb3c401b2..f5aab37a8c34 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -361,6 +361,24 @@ struct dyn_ftrace {
 	struct dyn_arch_ftrace	arch;
 };
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+struct func_param {
+	char *name;
+	uint8_t type;
+	uint8_t loc[2];
+} __packed;
+
+struct func_prototype {
+	unsigned long ip;
+	uint8_t ret_type;
+	uint8_t nr_param;
+	struct func_param params[0];
+} __packed;
+
+#define FTRACE_PROTOTYPE_SIGNED(t)	(t & BIT(7))
+#define FTRACE_PROTOTYPE_SIZE(t)	(t & GENMASK(6, 0))
+#endif
+
 int ftrace_force_update(void);
 int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip,
 			 int remove, int reset);
diff --git a/include/linux/module.h b/include/linux/module.h
index 1455812dd325..516062dfe567 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -477,6 +477,10 @@ struct module {
 	unsigned int num_ftrace_callsites;
 	unsigned long *ftrace_callsites;
 #endif
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	struct func_prototype *funcproto_start;
+	size_t funcproto_sec_size;
+#endif
 
 #ifdef CONFIG_LIVEPATCH
 	bool klp; /* Is this a livepatch module? */
diff --git a/kernel/module.c b/kernel/module.c
index 9ee93421269c..1c5eea7b6a28 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -360,17 +360,30 @@ static void *section_addr(const struct load_info *info, const char *name)
 	return (void *)info->sechdrs[find_sec(info, name)].sh_addr;
 }
 
+/* Get info of a module section. */
+static void *section_info(const struct load_info *info,
+			  const char *name,
+			  size_t *size)
+{
+	unsigned int sec = find_sec(info, name);
+
+	/* Section 0 has sh_addr 0 and sh_size 0. */
+	*size = info->sechdrs[sec].sh_size;
+	return (void *)info->sechdrs[sec].sh_addr;
+}
+
 /* Find a module section, or NULL.  Fill in number of "objects" in section. */
 static void *section_objs(const struct load_info *info,
 			  const char *name,
 			  size_t object_size,
 			  unsigned int *num)
 {
-	unsigned int sec = find_sec(info, name);
+	void *addr;
+	size_t sz;
 
-	/* Section 0 has sh_addr 0 and sh_size 0. */
-	*num = info->sechdrs[sec].sh_size / object_size;
-	return (void *)info->sechdrs[sec].sh_addr;
+	addr = section_info(info, name, &sz);
+	*num = sz / object_size;
+	return addr;
 }
 
 /* Provided by the linker */
@@ -3140,6 +3153,10 @@ static int find_module_sections(struct module *mod, struct load_info *info)
 					     sizeof(*mod->ftrace_callsites),
 					     &mod->num_ftrace_callsites);
 #endif
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	mod->funcproto_start = section_info(info, "__funcproto",
+					    &mod->funcproto_sec_size);
+#endif
 #ifdef CONFIG_FUNCTION_ERROR_INJECTION
 	mod->ei_funcs = section_objs(info, "_error_injection_whitelist",
 					    sizeof(*mod->ei_funcs),
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index cfcb8dad93ea..438b8b47198f 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -5060,6 +5060,9 @@ static DEFINE_MUTEX(graph_lock);
 
 struct ftrace_hash *ftrace_graph_hash = EMPTY_HASH;
 struct ftrace_hash *ftrace_graph_notrace_hash = EMPTY_HASH;
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+struct ftrace_hash *ftrace_prototype_hash = EMPTY_HASH;
+#endif
 
 enum graph_filter_type {
 	GRAPH_FILTER_NOTRACE	= 0,
@@ -5615,6 +5618,46 @@ static int ftrace_process_locs(struct module *mod,
 	return ret;
 }
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+static int ftrace_process_funcproto(struct module *mod,
+			       struct func_prototype *start,
+			       struct func_prototype *end,
+			       bool remove)
+{
+	struct ftrace_func_entry *ent;
+	struct func_prototype *proto;
+	int ret = 0;
+
+	mutex_lock(&ftrace_lock);
+
+restart:
+	proto = start;
+	while (proto < end) {
+		if (remove) {
+			ent = ftrace_lookup_ip(ftrace_prototype_hash,
+					       proto->ip);
+			if (ent)
+				free_hash_entry(ftrace_prototype_hash, ent);
+		} else {
+			ret = add_hash_entry(ftrace_prototype_hash,
+					     proto->ip, proto);
+			if (ret < 0) {
+				end = proto;
+				remove = 1;
+				goto restart;
+			}
+		}
+		proto = (struct func_prototype *)((char *)proto +
+			sizeof(*proto) +
+			sizeof(proto->params[0]) * proto->nr_param);
+	}
+
+	mutex_unlock(&ftrace_lock);
+
+	return ret;
+}
+#endif
+
 struct ftrace_mod_func {
 	struct list_head	list;
 	char			*name;
@@ -5707,7 +5750,7 @@ static void ftrace_free_mod_map(struct rcu_head *rcu)
 	kfree(mod_map);
 }
 
-void ftrace_release_mod(struct module *mod)
+void ftrace_release_dyn(struct module *mod)
 {
 	struct ftrace_mod_map *mod_map;
 	struct ftrace_mod_map *n;
@@ -5773,6 +5816,17 @@ void ftrace_release_mod(struct module *mod)
 	}
 }
 
+void ftrace_release_mod(struct module *mod)
+{
+	ftrace_release_dyn(mod);
+
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	ftrace_process_funcproto(mod, mod->funcproto_start,
+			(void *)mod->funcproto_start + mod->funcproto_sec_size,
+			true);
+#endif
+}
+
 void ftrace_module_enable(struct module *mod)
 {
 	struct dyn_ftrace *rec;
@@ -5852,6 +5906,11 @@ void ftrace_module_init(struct module *mod)
 
 	ftrace_process_locs(mod, mod->ftrace_callsites,
 			    mod->ftrace_callsites + mod->num_ftrace_callsites);
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	ftrace_process_funcproto(mod, mod->funcproto_start,
+			(void *)mod->funcproto_start + mod->funcproto_sec_size,
+			false);
+#endif
 }
 
 static void save_ftrace_mod_rec(struct ftrace_mod_map *mod_map,
@@ -6146,6 +6205,10 @@ void __init ftrace_init(void)
 {
 	extern unsigned long __start_mcount_loc[];
 	extern unsigned long __stop_mcount_loc[];
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	extern struct func_prototype __start_funcproto[];
+	extern struct func_prototype __stop_funcproto[];
+#endif
 	unsigned long count, flags;
 	int ret;
 
@@ -6179,6 +6242,17 @@ void __init ftrace_init(void)
 				  __start_mcount_loc,
 				  __stop_mcount_loc);
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+	ftrace_prototype_hash = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS);
+	if (WARN_ON(!ftrace_prototype_hash))
+		goto failed;
+
+	ftrace_process_funcproto(NULL,
+				 __start_funcproto,
+				 __stop_funcproto,
+				 false);
+#endif
+
 	set_ftrace_early_filters();
 
 	return;
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index ad619c73a505..22433a15e340 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -940,6 +940,10 @@ extern void __trace_graph_return(struct trace_array *tr,
 extern struct ftrace_hash *ftrace_graph_hash;
 extern struct ftrace_hash *ftrace_graph_notrace_hash;
 
+#ifdef CONFIG_FTRACE_FUNC_PROTOTYPE
+extern struct ftrace_hash *ftrace_prototype_hash;
+#endif
+
 static inline int ftrace_graph_addr(struct ftrace_graph_ent *trace)
 {
 	unsigned long addr = trace->func;
-- 
2.20.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  parent reply	other threads:[~2019-08-25 13:23 UTC|newest]

Thread overview: 89+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-08-25 13:23 [PATCH 00/11] ftrace: add support for recording function parameters and return value Changbin Du
2019-08-25 13:23 ` Changbin Du
2019-08-25 13:23 ` Changbin Du
2019-08-25 13:23 ` Changbin Du
2019-08-25 13:23 ` Changbin Du
2019-08-25 13:23 ` [PATCH 01/11] ftrace: move recordmcount tools to scripts/ftrace Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-26 22:44   ` Steven Rostedt
2019-08-26 22:44     ` Steven Rostedt
2019-08-26 22:44     ` Steven Rostedt
2019-08-26 22:44     ` Steven Rostedt
2019-08-26 22:44     ` Steven Rostedt
2019-08-28 23:41     ` Changbin Du
2019-08-28 23:41       ` Changbin Du
2019-08-28 23:41       ` Changbin Du
2019-08-28 23:41       ` Changbin Du
2019-08-25 13:23 ` [PATCH 02/11] ftrace: introduce new building tool funcprototype Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23 ` [PATCH 03/11] asm-generic: add generic dwarf definition Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-26  7:42   ` Peter Zijlstra
2019-08-26  7:42     ` Peter Zijlstra
2019-08-26  7:42     ` Peter Zijlstra
2019-08-26  7:42     ` Peter Zijlstra
2019-08-26  7:42     ` Peter Zijlstra
2019-08-26 22:25     ` Changbin Du
2019-08-26 22:25       ` Changbin Du
2019-08-26 22:25       ` Changbin Du
2019-08-26 22:25       ` Changbin Du
2019-08-26 22:25       ` Changbin Du
2019-08-25 13:23 ` [PATCH 04/11] ftrace/hash: add private data field Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23 ` [PATCH 05/11] ftrace: create memcache for hash entries Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-26  7:44   ` Peter Zijlstra
2019-08-26  7:44     ` Peter Zijlstra
2019-08-26  7:44     ` Peter Zijlstra
2019-08-26  7:44     ` Peter Zijlstra
2019-08-26  7:44     ` Peter Zijlstra
2019-08-26 22:35     ` Changbin Du
2019-08-26 22:35       ` Changbin Du
2019-08-26 22:35       ` Changbin Du
2019-08-26 22:35       ` Changbin Du
2019-08-26 22:35       ` Changbin Du
2019-08-25 13:23 ` Changbin Du [this message]
2019-08-25 13:23   ` [PATCH 06/11] ftrace: process function prototype data in vmlinux and modules Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23 ` [PATCH 07/11] ftrace: prepare arch specific interfaces for function prototype feature Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23 ` [PATCH 08/11] ftrace: introduce core part of function prototype recording Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23 ` [PATCH 09/11] x86_64: add function prototype recording support Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23 ` [PATCH 10/11] ftrace: add doc for new option record-funcproto Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23 ` [PATCH 11/11] MAINTAINERS: make scripts/ftrace/ maintained Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du
2019-08-25 13:23   ` Changbin Du

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=20190825132330.5015-7-changbin.du@gmail.com \
    --to=changbin.du@gmail.com \
    --cc=corbet@lwn.net \
    --cc=jeyu@kernel.org \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kbuild@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mips@vger.kernel.org \
    --cc=linux-parisc@vger.kernel.org \
    --cc=linux-riscv@lists.infradead.org \
    --cc=linux-s390@vger.kernel.org \
    --cc=linux-sh@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=mingo@redhat.com \
    --cc=rostedt@goodmis.org \
    --cc=sparclinux@vger.kernel.org \
    --cc=tglx@linutronix.de \
    --cc=x86@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 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.