Skip to content

Commit 9e09d44

Browse files
mrutland-armwilldeacon
authored andcommitted
arm64: stacktrace: recover return address for first entry
The function which calls the top-level backtracing function may have been instrumented with ftrace and/or kprobes, and hence the first return address may have been rewritten. Factor out the existing fgraph / kretprobes address recovery, and use this for the first address. As the comment for the fgraph case isn't all that helpful, I've also dropped that. Signed-off-by: Mark Rutland <[email protected]> Reviewed-by: Kalesh Singh <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: Madhavan T. Venkataraman <[email protected]> Cc: Mark Brown <[email protected]> Cc: Will Deacon <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent e8d018d commit 9e09d44

File tree

1 file changed

+30
-23
lines changed

1 file changed

+30
-23
lines changed

arch/arm64/kernel/stacktrace.c

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,32 @@ static __always_inline void unwind_init_from_task(struct unwind_state *state,
6969
state->pc = thread_saved_pc(task);
7070
}
7171

72+
static __always_inline int
73+
unwind_recover_return_address(struct unwind_state *state)
74+
{
75+
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
76+
if (state->task->ret_stack &&
77+
(state->pc == (unsigned long)return_to_handler)) {
78+
unsigned long orig_pc;
79+
orig_pc = ftrace_graph_ret_addr(state->task, NULL, state->pc,
80+
(void *)state->fp);
81+
if (WARN_ON_ONCE(state->pc == orig_pc))
82+
return -EINVAL;
83+
state->pc = orig_pc;
84+
}
85+
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
86+
87+
#ifdef CONFIG_KRETPROBES
88+
if (is_kretprobe_trampoline(state->pc)) {
89+
state->pc = kretprobe_find_ret_addr(state->task,
90+
(void *)state->fp,
91+
&state->kr_cur);
92+
}
93+
#endif /* CONFIG_KRETPROBES */
94+
95+
return 0;
96+
}
97+
7298
/*
7399
* Unwind from one frame record (A) to the next frame record (B).
74100
*
@@ -92,35 +118,16 @@ static int notrace unwind_next(struct unwind_state *state)
92118

93119
state->pc = ptrauth_strip_insn_pac(state->pc);
94120

95-
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
96-
if (tsk->ret_stack &&
97-
(state->pc == (unsigned long)return_to_handler)) {
98-
unsigned long orig_pc;
99-
/*
100-
* This is a case where function graph tracer has
101-
* modified a return address (LR) in a stack frame
102-
* to hook a function return.
103-
* So replace it to an original value.
104-
*/
105-
orig_pc = ftrace_graph_ret_addr(tsk, NULL, state->pc,
106-
(void *)state->fp);
107-
if (WARN_ON_ONCE(state->pc == orig_pc))
108-
return -EINVAL;
109-
state->pc = orig_pc;
110-
}
111-
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
112-
#ifdef CONFIG_KRETPROBES
113-
if (is_kretprobe_trampoline(state->pc))
114-
state->pc = kretprobe_find_ret_addr(tsk, (void *)state->fp, &state->kr_cur);
115-
#endif
116-
117-
return 0;
121+
return unwind_recover_return_address(state);
118122
}
119123
NOKPROBE_SYMBOL(unwind_next);
120124

121125
static void notrace unwind(struct unwind_state *state,
122126
stack_trace_consume_fn consume_entry, void *cookie)
123127
{
128+
if (unwind_recover_return_address(state))
129+
return;
130+
124131
while (1) {
125132
int ret;
126133

0 commit comments

Comments
 (0)