Skip to content

Commit cf59764

Browse files
Xu KuohaiKernel Patches Daemon
authored andcommitted
ftrace: Fix deadloop caused by direct call in ftrace selftest
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@huawei.com> Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
1 parent cf9a578 commit cf59764

File tree

2 files changed

+13
-1
lines changed

2 files changed

+13
-1
lines changed

arch/arm64/kernel/entry-ftrace.S

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,3 +357,13 @@ SYM_CODE_START(return_to_handler)
357357
ret
358358
SYM_CODE_END(return_to_handler)
359359
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
360+
361+
#ifdef CONFIG_FTRACE_SELFTEST
362+
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
363+
SYM_FUNC_START(trace_direct_tramp)
364+
mov x10, x30
365+
mov x30, x9
366+
ret x10
367+
SYM_FUNC_END(trace_direct_tramp)
368+
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
369+
#endif /* CONFIG_FTRACE_SELFTEST */

kernel/trace/trace_selftest.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,7 @@ static struct fgraph_ops fgraph_ops __initdata = {
785785
};
786786

787787
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
788-
noinline __noclone static void trace_direct_tramp(void) { }
788+
void __weak trace_direct_tramp(void) { }
789789
#endif
790790

791791
/*
@@ -868,6 +868,8 @@ trace_selftest_startup_function_graph(struct tracer *trace,
868868
if (ret)
869869
goto out;
870870

871+
DYN_FTRACE_TEST_NAME();
872+
871873
ret = register_ftrace_graph(&fgraph_ops);
872874
if (ret) {
873875
warn_failed_init_tracer(trace, ret);

0 commit comments

Comments
 (0)