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
next prev parent reply other threads:[~2019-08-25 13:24 UTC|newest]
Thread overview: 18+ 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 ` [PATCH 01/11] ftrace: move recordmcount tools to scripts/ftrace Changbin Du
2019-08-26 22:44 ` Steven Rostedt
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 ` [PATCH 03/11] asm-generic: add generic dwarf definition Changbin Du
2019-08-26 7:42 ` Peter Zijlstra
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 ` [PATCH 05/11] ftrace: create memcache for hash entries Changbin Du
2019-08-26 7:44 ` Peter Zijlstra
2019-08-26 22:35 ` Changbin Du
2019-08-25 13:23 ` Changbin Du [this message]
2019-08-25 13:23 ` [PATCH 07/11] ftrace: prepare arch specific interfaces for function prototype feature 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 ` [PATCH 09/11] x86_64: add function prototype recording support 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 ` [PATCH 11/11] MAINTAINERS: make scripts/ftrace/ maintained 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).