Since the kretprobe replaces the function return address with the kretprobe_trampoline on the stack, the ORC unwinder can not continue the stack unwinding at that point. To fix this issue, correct state->ip as like as function-graph tracer in the unwind_next_frame(). Signed-off-by: Masami Hiramatsu <mhiramat@xxxxxxxxxx> --- Changes in v2: - Remove kretprobe wrapper functions from unwind_orc.c - Do not fixup state->ip when unwinding with regs because kretprobe fixup instruction pointer before calling handler. --- arch/x86/include/asm/unwind.h | 4 ++++ arch/x86/kernel/unwind_orc.c | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/arch/x86/include/asm/unwind.h b/arch/x86/include/asm/unwind.h index 70fc159ebe69..ab5e45b848d5 100644 --- a/arch/x86/include/asm/unwind.h +++ b/arch/x86/include/asm/unwind.h @@ -4,6 +4,7 @@ #include <linux/sched.h> #include <linux/ftrace.h> +#include <linux/llist.h> #include <asm/ptrace.h> #include <asm/stacktrace.h> @@ -20,6 +21,9 @@ struct unwind_state { bool signal, full_regs; unsigned long sp, bp, ip; struct pt_regs *regs, *prev_regs; +#if defined(CONFIG_KRETPROBES) + struct llist_node *kr_iter; +#endif #elif defined(CONFIG_UNWINDER_FRAME_POINTER) bool got_irq; unsigned long *bp, *orig_sp, ip; diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c index 2a1d47f47eee..1d1b9388a1b1 100644 --- a/arch/x86/kernel/unwind_orc.c +++ b/arch/x86/kernel/unwind_orc.c @@ -2,6 +2,7 @@ #include <linux/objtool.h> #include <linux/module.h> #include <linux/sort.h> +#include <linux/kprobes.h> #include <asm/ptrace.h> #include <asm/stacktrace.h> #include <asm/unwind.h> @@ -536,6 +537,21 @@ bool unwind_next_frame(struct unwind_state *state) state->ip = ftrace_graph_ret_addr(state->task, &state->graph_idx, state->ip, (void *)ip_p); + /* + * When the stack unwinder is called from the kretprobe handler + * or the interrupt handler which occurs in the kretprobe + * trampoline code, %sp is shown on the stack instead of the + * return address because kretprobe_trampoline() does + * "push %sp" at first. + * And also the unwinder may find the kretprobe_trampoline + * instead of the real return address on stack. + * In those cases, find the correct return address from + * task->kretprobe_instances list. + */ + if (state->ip == sp || + is_kretprobe_trampoline(state->ip)) + state->ip = kretprobe_find_ret_addr(state->task, + &state->kr_iter); state->sp = sp; state->regs = NULL;