sh: stack debugging support.
authorPaul Mundt <lethal@linux-sh.org>
Wed, 27 Sep 2006 09:20:16 +0000 (18:20 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Wed, 27 Sep 2006 09:20:16 +0000 (18:20 +0900)
This adds a DEBUG_STACK_USAGE and DEBUG_STACKOVERFLOW for SH.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/sh/Kconfig.debug
arch/sh/kernel/head.S
arch/sh/kernel/irq.c
arch/sh/kernel/vmlinux.lds.S
include/asm-sh/page.h
include/asm-sh/thread_info.h

index 75ed1be8a49e80f87c7dd503e9c50c7d4d331aca..f0188e626be09506b8ccae2871284b511d038f6c 100644 (file)
@@ -30,6 +30,22 @@ config EARLY_PRINTK
          when the kernel may crash or hang before the serial console is
          initialised. If unsure, say N.
 
+config DEBUG_STACKOVERFLOW
+       bool "Check for stack overflows"
+       depends on DEBUG_KERNEL
+       help
+         This option will cause messages to be printed if free stack space
+         drops below a certain limit.
+
+config DEBUG_STACK_USAGE
+       bool "Stack utilization instrumentation"
+       depends on DEBUG_KERNEL
+       help
+         Enables the display of the minimum amount of free stack which each
+         task has ever had available in the sysrq-T and sysrq-P debug output.
+
+         This option will slow down process creation somewhat.
+
 config KGDB
        bool "Include KGDB kernel debugger"
        select FRAME_POINTER
index c5e363872b9167814423581d48e1e7c1e776e226..3e7d00b7985a21f6282c782c1529d2068e7f7f06 100644 (file)
@@ -11,6 +11,8 @@
  * Head.S contains the SH exception handlers and startup code.
  */
 #include <linux/linkage.h>
+#include <asm/thread_info.h>
+#include <asm/page.h>
 
 #ifdef CONFIG_CPU_SH4A
 #define SYNCO()                synco
@@ -95,7 +97,7 @@ ENTRY(_stext)
 
        .balign 4
 1:     .long   0x400080F0              ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF
-2:     .long   init_thread_union+8192
+2:     .long   init_thread_union+THREAD_SIZE
 3:     .long   __bss_start
 4:     .long   _end
 5:     .long   start_kernel
index c2e07f7f3496a45efa79b87be2cc953b2ebd49e0..7066611aeb728acbcc0db88d5bd58f3ec0228885 100644 (file)
@@ -60,7 +60,6 @@ unlock:
 }
 #endif
 
-
 asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
                      unsigned long r6, unsigned long r7,
                      struct pt_regs regs)
@@ -69,6 +68,22 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
 
        irq_enter();
 
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+       /* Debugging check for stack overflow: is there less than 1KB free? */
+       {
+               long sp;
+
+               __asm__ __volatile__ ("and r15, %0" :
+                                       "=r" (sp) : "0" (THREAD_SIZE - 1));
+
+               if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) {
+                       printk("do_IRQ: stack overflow: %ld\n",
+                              sp - sizeof(struct thread_info));
+                       dump_stack();
+               }
+       }
+#endif
+
 #ifdef CONFIG_CPU_HAS_INTEVT
        __asm__ __volatile__ (
 #ifdef CONFIG_CPU_HAS_SR_RB
index eb860c51c69714d34ce0a3cfaed8c4e3fa99d4ea..0220d8a838a780dcfe79121ab13b6617da05632b 100644 (file)
@@ -2,6 +2,8 @@
  * ld script to make SuperH Linux kernel
  * Written by Niibe Yutaka
  */
+#include <asm/thread_info.h>
+#include <asm/page.h>
 #include <asm-generic/vmlinux.lds.h>
 
 #ifdef CONFIG_CPU_LITTLE_ENDIAN
@@ -40,16 +42,16 @@ SECTIONS
        *(.data)
 
         /* Align the initial ramdisk image (INITRD) on page boundaries. */
-        . = ALIGN(4096);
+        . = ALIGN(PAGE_SIZE);
         __rd_start = .;
         *(.initrd)
-        . = ALIGN(4096);
+        . = ALIGN(PAGE_SIZE);
         __rd_end = .;
 
        CONSTRUCTORS
        }
 
-  . = ALIGN(4096);
+  . = ALIGN(PAGE_SIZE);
   .data.page_aligned : { *(.data.idt) }
 
   . = ALIGN(32);
@@ -60,10 +62,10 @@ SECTIONS
 
   _edata = .;                  /* End of data section */
 
-  . = ALIGN(8192);             /* init_task */
+  . = ALIGN(THREAD_SIZE);              /* init_task */
   .data.init_task : { *(.data.init_task) }
 
-  . = ALIGN(4096);             /* Init code and data */
+  . = ALIGN(PAGE_SIZE);                /* Init code and data */
   __init_begin = .;
   _sinittext = .;
   .init.text : { *(.init.text) }
@@ -94,7 +96,7 @@ SECTIONS
   __machvec_start = .;
   .init.machvec : { *(.init.machvec) }
   __machvec_end = .;
-  . = ALIGN(4096);
+  . = ALIGN(PAGE_SIZE);
   __init_end = .;
 
   . = ALIGN(4);
index e9135532d00c91181070646c99ebdaf39e42fdaf..888d6fe0030e053a24865d06884e2e067bffa2b8 100644 (file)
@@ -16,7 +16,7 @@
 
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT     12
-#define PAGE_SIZE      (1UL << PAGE_SHIFT)
+#define PAGE_SIZE      (1 << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE-1))
 #define PTE_MASK       PAGE_MASK
 
index 5eb874b065a6914f16398715f6f7d5c3648d5d6d..605259f88113efda4e71f2a9bd1005d00b5c8f2b 100644 (file)
@@ -29,6 +29,8 @@ struct thread_info {
 #endif
 
 #define PREEMPT_ACTIVE         0x10000000
+#define THREAD_SIZE            (PAGE_SIZE * 2)
+#define STACK_WARN             (THREAD_SIZE / 8)
 
 /*
  * macros/functions for gaining access to the thread information structure
@@ -50,8 +52,6 @@ struct thread_info {
 #define init_thread_info       (init_thread_union.thread_info)
 #define init_stack             (init_thread_union.stack)
 
-#define THREAD_SIZE (2*PAGE_SIZE)
-
 /* how to get the thread information struct from C */
 static inline struct thread_info *current_thread_info(void)
 {
@@ -73,8 +73,12 @@ static inline struct thread_info *current_thread_info(void)
 }
 
 /* thread information allocation */
-#define alloc_thread_info(ti) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1))
-#define free_thread_info(ti) free_pages((unsigned long) (ti), 1)
+#ifdef CONFIG_DEBUG_STACK_USAGE
+#define alloc_thread_info(ti)  kzalloc(THREAD_SIZE, GFP_KERNEL)
+#else
+#define alloc_thread_info(ti)  kmalloc(THREAD_SIZE, GFP_KERNEL)
+#endif
+#define free_thread_info(ti)   kfree(ti)
 
 #else /* !__ASSEMBLY__ */