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

Haibo Li haibo.li at mediatek.com
Tue Feb 20 03:33:41 PST 2024


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 at mediatek.com>
---
 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




More information about the linux-arm-kernel mailing list