This stack check implementation leverages the compiler's profiling (gcc -p)
authorMarc Fiuczynski <mef@cs.princeton.edu>
Tue, 14 Dec 2004 19:13:38 +0000 (19:13 +0000)
committerMarc Fiuczynski <mef@cs.princeton.edu>
Tue, 14 Dec 2004 19:13:38 +0000 (19:13 +0000)
support to determine precisely when there is a stack overflow.  The compiler
generates a call to the special function 'mcount' in the prologue of each
function.  This special 'mcount' function checks whether the stack has
grown beyond STACK_WARN size; and, if so, it will call the stack_overflowed
function, which generates a stack trace.  If the stack has grown to STACK_PANIC
size, the stack_overflowed function will panic() the system.

The hope is that with this support we can track down precisely the execution
context when the stack overflows.

Makefile
arch/i386/Kconfig
arch/i386/boot/compressed/misc.c
arch/i386/kernel/entry.S
arch/i386/kernel/i386_ksyms.c
arch/i386/kernel/init_task.c
arch/i386/kernel/process.c
configs/kernel-2.6.8-i686-planetlab.config
include/asm-i386/thread_info.h

index d9f29b0..00c5f30 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 8
-EXTRAVERSION = -1.521.3.planetlab
+EXTRAVERSION = -1.521.3.planetlab.2004.12.14
 NAME=Zonked Quokka
 
 # *DOCUMENTATION*
@@ -453,6 +453,10 @@ ifndef CONFIG_FRAME_POINTER
 CFLAGS         += -fomit-frame-pointer
 endif
 
+ifdef CONFIG_X86_STACK_CHECK
+CFLAGS         += -p
+endif
+
 ifdef CONFIG_DEBUG_INFO
 CFLAGS         += -g
 endif
index 4599ce6..5922c84 100644 (file)
@@ -952,6 +952,31 @@ config STACK_WARN
        The kernel will print a stack trace when the current stack exceeds
        the specified size.
 
+config X86_STACK_CHECK
+       bool "Check for stack overflows"
+       default n
+       help
+       Say Y here to have the kernel attempt to detect when the per-task
+       kernel stack overflows.
+
+       Some older versions of gcc don't handle the -p option correctly.
+       Kernprof is affected by the same problem, which is described here:
+       http://oss.sgi.com/projects/kernprof/faq.html#Q9
+
+       Basically, if you get oopses in __free_pages_ok during boot when
+       you have this turned on, you need to fix gcc. The Redhat 2.96
+       version and gcc-3.x seem to work.
+
+       If not debugging a stack overflow problem, say N
+
+config STACK_PANIC
+       int "Panic when stack approaches with specified bytes of the stack limit"
+       depends on X86_STACK_CHECK
+       default 512 if IRQSTACKS
+       default 512
+       help
+       Panic if the stack grows to within specified byte range.
+
 endmenu
 
 
index fa67045..8745683 100644 (file)
@@ -380,3 +380,6 @@ asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode)
        if (high_loaded) close_output_buffer_if_we_run_high(mv);
        return high_loaded;
 }
+
+/* We don't actually check for stack overflows this early. */
+__asm__(".globl mcount ; mcount: ret\n");
index 3ac7418..dc7ff8f 100644 (file)
@@ -734,9 +734,62 @@ ENTRY(spurious_interrupt_bug)
        pushl $do_spurious_interrupt_bug
        jmp error_code
 
+#ifdef CONFIG_X86_STACK_CHECK
+ENTRY(mcount)
+       push %eax
+       movl $(THREAD_SIZE - 1),%eax
+       andl %esp,%eax
+       cmpl $STACK_WARN,%eax /* esp reaches into STACK_WARN space */
+       jle 1f
+2:
+       popl %eax
+       ret
+1:
+       lock; btsl $0,stack_overflowed
+       jc 2b
+
+       # switch to overflow stack
+       movl %esp,%eax
+       movl $(stack_overflow_stack + THREAD_SIZE - 4),%esp
+       
+       pushf
+       cli
+       pushl %eax
+
+       # push eip then esp of error for stack_overflow_panic
+       pushl 4(%eax)
+       pushl %eax
+
+       # update the task pointer and cpu in the overflow stack's thread_info.
+       GET_THREAD_INFO_WITH_ESP(%eax)
+       movl TI_task(%eax),%ebx
+       movl %ebx,stack_overflow_stack+TI_task
+       movl TI_cpu(%eax),%ebx
+       movl %ebx,stack_overflow_stack+TI_cpu
+
+       call stack_overflow
+
+       # pop off call arguments
+       addl $8,%esp
+
+       popl %eax
+       popf
+       movl %eax,%esp
+       popl %eax
+       movl $0,stack_overflowed
+       ret
+#warning stack check enabled
+#endif
+
 .previous
 
 .data
+#ifdef CONFIG_X86_STACK_CHECK
+       .globl stack_overflowed
+stack_overflowed:
+       .long 0
+#endif
+
 ENTRY(sys_call_table)
        .long sys_restart_syscall       /* 0 - old "setup()" system call, used for restarting */
        .long sys_exit
index 5a50c53..584982c 100644 (file)
@@ -188,6 +188,12 @@ EXPORT_SYMBOL(atomic_dec_and_lock);
 
 EXPORT_SYMBOL(__PAGE_KERNEL);
 
+#ifdef CONFIG_X86_STACK_CHECK
+extern void mcount(void);
+EXPORT_SYMBOL(mcount);
+#endif
+
+
 #ifdef CONFIG_HIGHMEM
 EXPORT_SYMBOL(kmap);
 EXPORT_SYMBOL(kunmap);
index 7422d73..30cfd40 100644 (file)
@@ -29,6 +29,13 @@ union thread_union init_thread_union
        __attribute__((__section__(".data.init_task"))) =
                { INIT_THREAD_INFO(init_task, init_thread_union) };
 
+#ifdef CONFIG_X86_STACK_CHECK
+union thread_union stack_overflow_stack
+ __attribute__((__section__(".data.init_task"))) =
+               { INIT_THREAD_INFO(init_task, stack_overflow_stack) };
+#endif
+
+
 /*
  * Initial task structure.
  *
index 3093d1f..51c17cc 100644 (file)
@@ -219,6 +219,24 @@ static int __init idle_setup (char *str)
 
 __setup("idle=", idle_setup);
 
+void stack_overflow(unsigned long esp, unsigned long eip)
+{
+       int panicing = ((esp&(THREAD_SIZE-1)) <= STACK_PANIC);
+
+       printk( "esp: 0x%lx masked: 0x%lx STACK_PANIC:0x%lx %d %d\n",
+               esp, (esp&(THREAD_SIZE-1)), STACK_PANIC, (((esp&(THREAD_SIZE-1)) <= STACK_PANIC)), panicing );
+
+       if (panicing)
+         print_symbol("stack overflow from %s\n", eip);
+       else
+         print_symbol("excessive stack use from %s\n", eip);
+       printk("esp: %p\n", (void*)esp);
+       show_trace(current,(void*)esp);
+
+       if (panicing)
+         panic("stack overflow\n");
+}
+
 void show_regs(struct pt_regs * regs)
 {
        unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
index c23865c..f5a0c30 100644 (file)
@@ -144,6 +144,8 @@ CONFIG_REGPARM=y
 CONFIG_IRQSTACKS=y
 CONFIG_STACK_SIZE_SHIFT=13
 CONFIG_STACK_WARN=4000
+# CONFIG_X86_STACK_CHECK is not set
+CONFIG_STACK_PANIC=512
 
 #
 # Power management options (ACPI, APM)
index d4fe6a5..da74573 100644 (file)
@@ -56,6 +56,7 @@ struct thread_info {
 #define PREEMPT_ACTIVE         0x4000000
 #define THREAD_SIZE            (1<<CONFIG_STACK_SIZE_SHIFT)
 #define STACK_WARN             (CONFIG_STACK_WARN)
+#define STACK_PANIC            (0x200ul)
 
 /*
  * macros/functions for gaining access to the thread information structure