diff options
author | Alan Kao <alankao@andestech.com> | 2018-02-13 06:13:18 +0100 |
---|---|---|
committer | Palmer Dabbelt <palmer@sifive.com> | 2018-04-03 04:59:12 +0200 |
commit | bc1a4c3a842556852bb02039887d73899d513532 (patch) | |
tree | 122084b028e4384e9acfd6fa0ebc73a435c5715c /arch/riscv/kernel/ftrace.c | |
parent | riscv/ftrace: Add dynamic function tracer support (diff) | |
download | linux-bc1a4c3a842556852bb02039887d73899d513532.tar.xz linux-bc1a4c3a842556852bb02039887d73899d513532.zip |
riscv/ftrace: Add dynamic function graph tracer support
Once the function_graph tracer is enabled, a filtered function has the
following call sequence:
* ftracer_caller ==> on/off by ftrace_make_call/ftrace_make_nop
* ftrace_graph_caller
* ftrace_graph_call ==> on/off by ftrace_en/disable_ftrace_graph_caller
* prepare_ftrace_return
Considering the following DYNAMIC_FTRACE_WITH_REGS feature, it would be
more extendable to have a ftrace_graph_caller function, instead of
calling prepare_ftrace_return directly in ftrace_caller.
Cc: Greentime Hu <greentime@andestech.com>
Signed-off-by: Alan Kao <alankao@andestech.com>
Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
Diffstat (limited to 'arch/riscv/kernel/ftrace.c')
-rw-r--r-- | arch/riscv/kernel/ftrace.c | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index be4b24332d97..5bbe1afd9463 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -139,4 +139,57 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, return; *parent = return_hooker; } -#endif + +#ifdef CONFIG_DYNAMIC_FTRACE +extern void ftrace_graph_call(void); +int ftrace_enable_ftrace_graph_caller(void) +{ + unsigned int call[2]; + static int init_graph = 1; + int ret; + + make_call(&ftrace_graph_call, &ftrace_stub, call); + + /* + * When enabling graph tracer for the first time, ftrace_graph_call + * should contains a call to ftrace_stub. Once it has been disabled, + * the 8-bytes at the position becomes NOPs. + */ + if (init_graph) { + ret = ftrace_check_current_call((unsigned long)&ftrace_graph_call, + call); + init_graph = 0; + } else { + ret = ftrace_check_current_call((unsigned long)&ftrace_graph_call, + NULL); + } + + if (ret) + return ret; + + return __ftrace_modify_call((unsigned long)&ftrace_graph_call, + (unsigned long)&prepare_ftrace_return, true); +} + +int ftrace_disable_ftrace_graph_caller(void) +{ + unsigned int call[2]; + int ret; + + make_call(&ftrace_graph_call, &prepare_ftrace_return, call); + + /* + * This is to make sure that ftrace_enable_ftrace_graph_caller + * did the right thing. + */ + ret = ftrace_check_current_call((unsigned long)&ftrace_graph_call, + call); + + if (ret) + return ret; + + return __ftrace_modify_call((unsigned long)&ftrace_graph_call, + (unsigned long)&prepare_ftrace_return, false); +} +#endif /* CONFIG_DYNAMIC_FTRACE */ +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |