Messages in this thread Patch in this message | | | From | Chen Zhongjin <> | Subject | [PATCH -next 7/7] riscv: stacktrace: Fix unwinding on __kretporbe_trampoline | Date | Tue, 20 Sep 2022 23:12:02 +0800 |
| |
When unwinding on __kretprobe_trampoline, the caller of traced function will be skipped because unwinder doesn't read the saved pt_regs.
Things going like this:
caller's caller | ... |<---+ caller +---------------------------+ | | ra caller's caller | | | s0 of caller's caller | | | ... | | probed func returned +---------------------------+ | __kretprobe_trampoline | pt_regs: | | | epc caller | | | ra __kretprobe_trampoline| | | ... | | | s0 of caller | {ra, fp} | ... |
Since from caller to __kretprobe_trampoline, the {ra, fp} are not changed, unwinder will go directly to caller's caller.
Now we can have an ENCODED_FRAME_POINTER on stack and read the pt_regs, kretporbe will set the epc to correct_ret_addr so that we can unwind to the correct caller.
Stacktrace before this patch:
Call Trace: ... [<ffffffff800d5d48>] __kretprobe_trampoline_handler+0xc2/0x13e [<ffffffff808b766c>] trampoline_probe_handler+0x30/0x46 [<ffffffff800070de>] __kretprobe_trampoline+0x52/0x92 [<ffffffff0163809c>] kprobe_init+0x9c/0x1000 [kprobe_unwind] [<ffffffff800027c8>] do_one_initcall+0x4c/0x1f2 ...
Stacktrace after this patch:
Call Trace: ... [<ffffffff800d5d48>] __kretprobe_trampoline_handler+0xc2/0x13e [<ffffffff808b766c>] trampoline_probe_handler+0x30/0x46 [<ffffffff800070de>] __kretprobe_trampoline+0x52/0x92 + [<ffffffff01633076>] the_caller+0x2c/0x38 [kprobe_unwind] [<ffffffff0163809c>] kprobe_init+0x9c/0x1000 [kprobe_unwind] [<ffffffff800027c8>] do_one_initcall+0x4c/0x1f2 ...
Signed-off-by: Chen Zhongjin <chenzhongjin@huawei.com> --- arch/riscv/include/asm/stacktrace.h | 4 ++++ arch/riscv/kernel/probes/kprobes_trampoline.S | 8 ++++++++ arch/riscv/kernel/stacktrace.c | 5 +++++ 3 files changed, 17 insertions(+)
diff --git a/arch/riscv/include/asm/stacktrace.h b/arch/riscv/include/asm/stacktrace.h index a39e4ef1dbd5..506c7c38b6cb 100644 --- a/arch/riscv/include/asm/stacktrace.h +++ b/arch/riscv/include/asm/stacktrace.h @@ -16,6 +16,10 @@ struct unwind_state { unsigned long sp; unsigned long pc; struct pt_regs *regs; +#ifdef CONFIG_KRETPROBES + struct llist_node *kr_cur; + struct task_struct *task; +#endif }; extern void dump_backtrace(struct pt_regs *regs, struct task_struct *task, diff --git a/arch/riscv/kernel/probes/kprobes_trampoline.S b/arch/riscv/kernel/probes/kprobes_trampoline.S index 7bdb09ded39b..3c0677a714a6 100644 --- a/arch/riscv/kernel/probes/kprobes_trampoline.S +++ b/arch/riscv/kernel/probes/kprobes_trampoline.S @@ -6,6 +6,8 @@ #include <asm/asm.h> #include <asm/asm-offsets.h> +#include <asm/frame.h> +#include <asm/csr.h> .text .altmacro @@ -79,6 +81,12 @@ ENTRY(__kretprobe_trampoline) addi sp, sp, -(PT_SIZE_ON_STACK) save_all_base_regs +#ifdef CONFIG_FRAME_POINTER + li s0, SR_PP + REG_S s0, PT_STATUS(sp) + ENCODE_FRAME_POINTER +#endif + move a0, sp /* pt_regs */ call trampoline_probe_handler diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c index 976dc298ab3b..53edc685ca18 100644 --- a/arch/riscv/kernel/stacktrace.c +++ b/arch/riscv/kernel/stacktrace.c @@ -11,6 +11,7 @@ #include <linux/sched/task_stack.h> #include <linux/stacktrace.h> #include <linux/ftrace.h> +#include <linux/kprobes.h> #include <asm/stacktrace.h> @@ -123,6 +124,10 @@ noinline notrace void arch_stack_walk(stack_trace_consume_fn consume_entry, state.sp = task->thread.sp; state.pc = task->thread.ra; } +#ifdef CONFIG_KRETPROBES + state.kr_cur = NULL; + state.task = task; +#endif unwind(&state, consume_entry, cookie); } -- 2.17.1
| |