On Thu, 14 Apr 2022 12:22:16 -0400 Xu Kuohai <xukuohai@xxxxxxxxxx> wrote: > After direct call is enabled for arm64, ftrace selftest enters a > dead loop: > > <trace_selftest_dynamic_test_func>: > 00 bti c > 01 mov x9, x30 <trace_direct_tramp>: > 02 bl <trace_direct_tramp> ----------> ret > | > lr/x30 is 03, return to 03 > | > 03 mov w0, #0x0 <-----------------------------| > | | > | dead loop! | > | | > 04 ret ---- lr/x30 is still 03, go back to 03 ----| > > The reason is that when the direct caller trace_direct_tramp() returns > to the patched function trace_selftest_dynamic_test_func(), lr is still > the address after the instrumented instruction in the patched function, > so when the patched function exits, it returns to itself! > > To fix this issue, we need to restore lr before trace_direct_tramp() > exits, so make trace_direct_tramp() a weak symbol and rewrite it for > arm64. > > To detect this issue directly, call DYN_FTRACE_TEST_NAME() before > register_ftrace_graph(). > > Reported-by: Li Huafei <lihuafei1@xxxxxxxxxx> > Signed-off-by: Xu Kuohai <xukuohai@xxxxxxxxxx> > --- > arch/arm64/kernel/entry-ftrace.S | 10 ++++++++++ > kernel/trace/trace_selftest.c | 4 +++- > 2 files changed, 13 insertions(+), 1 deletion(-) > > diff --git a/arch/arm64/kernel/entry-ftrace.S b/arch/arm64/kernel/entry-ftrace.S > index dfe62c55e3a2..e58eb06ec9b2 100644 > --- a/arch/arm64/kernel/entry-ftrace.S > +++ b/arch/arm64/kernel/entry-ftrace.S > @@ -357,3 +357,13 @@ SYM_CODE_START(return_to_handler) > ret > SYM_CODE_END(return_to_handler) > #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ > + > +#ifdef CONFIG_FTRACE_SELFTEST > +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS > +SYM_FUNC_START(trace_direct_tramp) > + mov x10, x30 > + mov x30, x9 > + ret x10 > +SYM_FUNC_END(trace_direct_tramp) > +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ > +#endif /* CONFIG_FTRACE_SELFTEST */ > diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c > index abcadbe933bb..38b0d5c9a1e0 100644 > --- a/kernel/trace/trace_selftest.c > +++ b/kernel/trace/trace_selftest.c > @@ -785,7 +785,7 @@ static struct fgraph_ops fgraph_ops __initdata = { > }; > > #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS > -noinline __noclone static void trace_direct_tramp(void) { } > +void __weak trace_direct_tramp(void) { } > #endif > > /* > @@ -868,6 +868,8 @@ trace_selftest_startup_function_graph(struct tracer *trace, > if (ret) > goto out; > > + DYN_FTRACE_TEST_NAME(); This doesn't look like it belongs in this patch. -- Steve > + > ret = register_ftrace_graph(&fgraph_ops); > if (ret) { > warn_failed_init_tracer(trace, ret);