[PATCH] arm:dump the stack usage after stack overflows

From: Haibo Li
Date: Tue Feb 20 2024 - 06:34:22 EST


With the help of vmap stack,it is able to detect stack overflow.

To make it easy to debug stack overflow,dump the stack usage of
each frame by walking the stack.

After this patch,the log after stack overflows like below:

Insufficient stack space to handle exception!
Task stack: [0xf4a70000..0xf4a72000]
IRQ stack: [0xf0800000..0xf0802000]
Overflow stack: [0x818c1000..0x818c2000]
Depth usage size Location
0 8232 96 _prb_read_valid
1 8136 24 prb_read_valid
2 8112 200 printk_get_next_message
3 7912 104 console_flush_all
4 7808 64 console_unlock
5 7744 40 vprintk_emit
6 7704 16 vprintk_default
7 7688 32 _printk
8 7656 1048 do_circle_loop
9 6608 1048 do_circle_loop
10 5560 1048 do_circle_loop
11 4512 1048 do_circle_loop
12 3464 1048 do_circle_loop
13 2416 1048 do_circle_loop
14 1368 1048 do_circle_loop
15 320 8 stack_ovf_selftest
16 312 24 param_attr_store
17 288 40 kernfs_fop_write_iter
18 248 112 vfs_write
19 136 48 ksys_write
----- ----- ----- ------
Internal error: kernel stack overflow: 0 [#1] SMP ARM
..

Signed-off-by: Haibo Li <haibo.li@xxxxxxxxxxxx>
---
arch/arm/kernel/traps.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 3bad79db5d6e..641ca68b44ba 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -921,6 +921,33 @@ static int __init allocate_overflow_stacks(void)
}
early_initcall(allocate_overflow_stacks);

+static void dump_stack_usage(struct pt_regs *regs)
+{
+ struct stackframe frame;
+ unsigned int depth = 0;
+ unsigned long prev_pc;
+ unsigned long prev_sp;
+ unsigned long stack_high = (unsigned long)current->stack + THREAD_SIZE;
+
+ arm_get_current_stackframe(regs, &frame);
+ pr_emerg("Depth usage size Location\n");
+ while (1) {
+ prev_pc = frame.pc;
+ prev_sp = frame.sp;
+#if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
+ //meet the requirement of frame_pointer_check
+ if (frame.sp < (unsigned long)current->stack)
+ frame.sp = (unsigned long)current->stack + 4;
+#endif
+ if (unwind_frame(&frame) < 0)
+ break;
+ pr_emerg("%3d %5ld %5ld %ps\n",
+ depth++, stack_high - prev_sp,
+ frame.sp - prev_sp, (void *)prev_pc);
+ }
+ pr_emerg("----- ----- ----- ------\n");
+}
+
asmlinkage void handle_bad_stack(struct pt_regs *regs)
{
unsigned long tsk_stk = (unsigned long)current->stack;
@@ -940,6 +967,7 @@ asmlinkage void handle_bad_stack(struct pt_regs *regs)
#endif
pr_emerg("Overflow stack: [0x%08lx..0x%08lx]\n",
ovf_stk - OVERFLOW_STACK_SIZE, ovf_stk);
+ dump_stack_usage(regs);

die("kernel stack overflow", regs, 0);
}
--
2.18.0