mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2025-01-09 07:14:48 +08:00
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 <mark.rutland@arm.com> Reviewed-by: Kalesh Singh <kaleshsingh@google.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Madhavan T. Venkataraman <madvenka@linux.microsoft.com> Cc: Mark Brown <broonie@kernel.org> Cc: Will Deacon <will@kernel.org> Link: https://lore.kernel.org/r/20230411162943.203199-2-mark.rutland@arm.com Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
parent
e8d018dd02
commit
9e09d445f1
@ -69,6 +69,32 @@ static __always_inline void unwind_init_from_task(struct unwind_state *state,
|
||||
state->pc = thread_saved_pc(task);
|
||||
}
|
||||
|
||||
static __always_inline int
|
||||
unwind_recover_return_address(struct unwind_state *state)
|
||||
{
|
||||
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||
if (state->task->ret_stack &&
|
||||
(state->pc == (unsigned long)return_to_handler)) {
|
||||
unsigned long orig_pc;
|
||||
orig_pc = ftrace_graph_ret_addr(state->task, NULL, state->pc,
|
||||
(void *)state->fp);
|
||||
if (WARN_ON_ONCE(state->pc == orig_pc))
|
||||
return -EINVAL;
|
||||
state->pc = orig_pc;
|
||||
}
|
||||
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
|
||||
|
||||
#ifdef CONFIG_KRETPROBES
|
||||
if (is_kretprobe_trampoline(state->pc)) {
|
||||
state->pc = kretprobe_find_ret_addr(state->task,
|
||||
(void *)state->fp,
|
||||
&state->kr_cur);
|
||||
}
|
||||
#endif /* CONFIG_KRETPROBES */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unwind from one frame record (A) to the next frame record (B).
|
||||
*
|
||||
@ -92,35 +118,16 @@ static int notrace unwind_next(struct unwind_state *state)
|
||||
|
||||
state->pc = ptrauth_strip_insn_pac(state->pc);
|
||||
|
||||
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||
if (tsk->ret_stack &&
|
||||
(state->pc == (unsigned long)return_to_handler)) {
|
||||
unsigned long orig_pc;
|
||||
/*
|
||||
* This is a case where function graph tracer has
|
||||
* modified a return address (LR) in a stack frame
|
||||
* to hook a function return.
|
||||
* So replace it to an original value.
|
||||
*/
|
||||
orig_pc = ftrace_graph_ret_addr(tsk, NULL, state->pc,
|
||||
(void *)state->fp);
|
||||
if (WARN_ON_ONCE(state->pc == orig_pc))
|
||||
return -EINVAL;
|
||||
state->pc = orig_pc;
|
||||
}
|
||||
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
|
||||
#ifdef CONFIG_KRETPROBES
|
||||
if (is_kretprobe_trampoline(state->pc))
|
||||
state->pc = kretprobe_find_ret_addr(tsk, (void *)state->fp, &state->kr_cur);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
return unwind_recover_return_address(state);
|
||||
}
|
||||
NOKPROBE_SYMBOL(unwind_next);
|
||||
|
||||
static void notrace unwind(struct unwind_state *state,
|
||||
stack_trace_consume_fn consume_entry, void *cookie)
|
||||
{
|
||||
if (unwind_recover_return_address(state))
|
||||
return;
|
||||
|
||||
while (1) {
|
||||
int ret;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user