From: Guo Ren Date: Wed, 9 Nov 2022 06:49:37 +0000 (-0500) Subject: riscv: stacktrace: Make walk_stackframe cross pt_regs frame X-Git-Tag: v6.6.17~5917^2~14 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7ecdadf7f8c659524f6b2aebf6be7bf619764d90;p=platform%2Fkernel%2Flinux-rpi.git riscv: stacktrace: Make walk_stackframe cross pt_regs frame The current walk_stackframe with FRAME_POINTER would stop unwinding at ret_from_exception: BUG: sleeping function called from invalid context at kernel/locking/rwsem.c:1518 in_atomic(): 0, irqs_disabled(): 1, non_block: 0, pid: 1, name: init CPU: 0 PID: 1 Comm: init Not tainted 5.10.113-00021-g15c15974895c-dirty #192 Call Trace: [] walk_stackframe+0x0/0xee [] show_stack+0x32/0x4a [] dump_stack_lvl+0x72/0x8e [] dump_stack+0x14/0x1c [] ___might_sleep+0x12e/0x138 [] __might_sleep+0x10/0x18 [] down_read+0x22/0xa4 [] do_page_fault+0xb0/0x2fe [] ret_from_exception+0x0/0xc The optimization would help walk_stackframe cross the pt_regs frame and get more backtrace of debug info: BUG: sleeping function called from invalid context at kernel/locking/rwsem.c:1518 in_atomic(): 0, irqs_disabled(): 1, non_block: 0, pid: 1, name: init CPU: 0 PID: 1 Comm: init Not tainted 5.10.113-00021-g15c15974895c-dirty #192 Call Trace: [] walk_stackframe+0x0/0xee [] show_stack+0x32/0x4a [] dump_stack_lvl+0x72/0x8e [] dump_stack+0x14/0x1c [] ___might_sleep+0x12e/0x138 [] __might_sleep+0x10/0x18 [] down_read+0x22/0xa4 [] do_page_fault+0xb0/0x2fe [] ret_from_exception+0x0/0xc [] riscv_intc_irq+0x1a/0x72 [] ret_from_exception+0x0/0xc [] vma_link+0x54/0x160 [] mmap_region+0x2cc/0x4d0 [] do_mmap+0x2d8/0x3ac [] vm_mmap_pgoff+0x70/0xb8 [] vm_mmap+0x2a/0x36 [] elf_map+0x72/0x84 [] load_elf_binary+0x69a/0xec8 [] bprm_execve+0x246/0x53a [] kernel_execve+0xe8/0x124 [] run_init_process+0xfa/0x10c [] try_to_run_init_process+0x12/0x3c [] kernel_init+0xb4/0xf8 [] ret_from_exception+0x0/0xc Here is the error injection test code for the above output: drivers/irqchip/irq-riscv-intc.c: static asmlinkage void riscv_intc_irq(struct pt_regs *regs) { unsigned long cause = regs->cause & ~CAUSE_IRQ_FLAG; + u32 tmp; __get_user(tmp, (u32 *)0); Signed-off-by: Guo Ren Signed-off-by: Guo Ren Link: https://lore.kernel.org/r/20221109064937.3643993-3-guoren@kernel.org [Palmer: use SYM_CODE_*] Signed-off-by: Palmer Dabbelt --- diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index b9eda3f..da44fe2 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -248,7 +248,7 @@ ret_from_syscall_rejected: andi t0, t0, _TIF_SYSCALL_WORK bnez t0, handle_syscall_trace_exit -ret_from_exception: +SYM_CODE_START_NOALIGN(ret_from_exception) REG_L s0, PT_STATUS(sp) csrc CSR_STATUS, SR_IE #ifdef CONFIG_TRACE_IRQFLAGS @@ -262,6 +262,7 @@ ret_from_exception: andi s0, s0, SR_SPP #endif bnez s0, resume_kernel +SYM_CODE_END(ret_from_exception) resume_userspace: /* Interrupts must be disabled here so flags are checked atomically */ diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c index bcfe9eb..75c8dd6 100644 --- a/arch/riscv/kernel/stacktrace.c +++ b/arch/riscv/kernel/stacktrace.c @@ -16,6 +16,8 @@ #ifdef CONFIG_FRAME_POINTER +extern asmlinkage void ret_from_exception(void); + void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, bool (*fn)(void *, unsigned long), void *arg) { @@ -59,6 +61,13 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, fp = frame->fp; pc = ftrace_graph_ret_addr(current, NULL, frame->ra, &frame->ra); + if (pc == (unsigned long)ret_from_exception) { + if (unlikely(!__kernel_text_address(pc) || !fn(arg, pc))) + break; + + pc = ((struct pt_regs *)sp)->epc; + fp = ((struct pt_regs *)sp)->s0; + } } }