Index: pmap.c =================================================================== RCS file: /cvs/cvsroot/syssrc/sys/arch/i386/i386/pmap.c,v retrieving revision 1.136 diff -u -p -r1.136 pmap.c --- pmap.c 2002/03/27 04:47:28 1.136 +++ pmap.c 2002/06/26 09:45:00 @@ -65,6 +65,7 @@ __KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.1 #include "opt_cputype.h" #include "opt_user_ldt.h" #include "opt_largepages.h" +#include "opt_kstack_dr0.h" #include #include @@ -1675,6 +1676,16 @@ pmap_activate(p) lcr3(pcb->pcb_cr3); if (pcb == curpcb) lldt(pcb->pcb_ldt_sel); + +#ifdef KSTACK_CHECK_DR0 + /* + * setup breakpoint on the top of stack + */ + if (p == &proc0) + dr0(0, 0, 0, 0); + else + dr0(KSTACK_END(p), 1, 3, 1); +#endif } /* Index: trap.c =================================================================== RCS file: /cvs/cvsroot/syssrc/sys/arch/i386/i386/trap.c,v retrieving revision 1.165 diff -u -p -r1.165 trap.c --- trap.c 2002/02/18 15:58:02 1.165 +++ trap.c 2002/06/26 09:45:00 @@ -86,6 +86,7 @@ __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.1 #include "opt_math_emulate.h" #include "opt_vm86.h" #include "opt_cputype.h" +#include "opt_kstack_dr0.h" #include #include @@ -202,6 +203,21 @@ trap(frame) default: we_re_toast: +#ifdef KSTACK_CHECK_DR0 + if (type == T_TRCTRAP) { + u_int mask, dr6 = rdr6(); + + mask = 1 << 0; /* dr0 */ + if (dr6 & mask) { + panic("trap on DR0: maybe kernel stack overflow\n"); +#if 0 + dr6 &= ~mask; + ldr6(dr6); + return; +#endif + } + } +#endif #ifdef KGDB if (kgdb_trap(type, &frame)) return; Index: cpufunc.h =================================================================== RCS file: /cvs/cvsroot/syssrc/sys/arch/i386/include/cpufunc.h,v retrieving revision 1.20 diff -u -p -r1.20 cpufunc.h --- cpufunc.h 2001/07/31 18:28:59 1.20 +++ cpufunc.h 2002/06/26 09:45:14 @@ -134,6 +134,24 @@ tlbflush(void) void setidt __P((int idx, /*XXX*/caddr_t func, int typ, int dpl)); #endif +/* debug register */ +void dr0(caddr_t, u_int32_t, u_int32_t, u_int32_t); + +static __inline u_int +rdr6(void) +{ + u_int val; + + __asm __volatile("movl %%dr6,%0" : "=r" (val)); + return val; +} + +static __inline void +ldr6(u_int val) +{ + + __asm __volatile("movl %0,%%dr6" : : "r" (val)); +} /* XXXX ought to be in psl.h with spl() functions */ Index: files.i386 =================================================================== RCS file: /cvs/cvsroot/syssrc/sys/arch/i386/conf/files.i386,v retrieving revision 1.208 diff -u -p -r1.208 files.i386 --- files.i386 2002/06/18 07:56:12 1.208 +++ files.i386 2002/06/26 09:45:29 @@ -57,11 +57,14 @@ defparam opt_pcibios.h PCIBIOS_IRQS_HINT # Large page size defflag LARGEPAGES +# kernel stack debug +defflag opt_kstack_dr0.h KSTACK_CHECK_DR0 + file arch/i386/i386/autoconf.c file arch/i386/i386/bus_machdep.c file arch/i386/i386/conf.c file arch/i386/i386/consinit.c -file arch/i386/i386/db_dbgreg.s ddb +file arch/i386/i386/db_dbgreg.s ddb | kstack_check_dr0 file arch/i386/i386/db_disasm.c ddb file arch/i386/i386/db_interface.c ddb file arch/i386/i386/db_memrw.c ddb | kgdb Index: files =================================================================== RCS file: /cvs/cvsroot/syssrc/sys/conf/files,v retrieving revision 1.535 diff -u -p -r1.535 files --- files 2002/06/18 00:33:57 1.535 +++ files 2002/06/26 09:45:37 @@ -139,6 +139,7 @@ defparam opt_kgdb.h KGDB_DEV KGDB_DEVNA KGDB_DEVADDR KGDB_DEVRATE KGDB_DEVMODE defflag LOCKDEBUG defflag SYSCALL_DEBUG +defflag opt_kstack.h KSTACK_CHECK_MAGIC # memory (ram) disk options # Index: kern_proc.c =================================================================== RCS file: /cvs/cvsroot/syssrc/sys/kern/kern_proc.c,v retrieving revision 1.47 diff -u -p -r1.47 kern_proc.c --- kern_proc.c 2002/04/12 17:02:33 1.47 +++ kern_proc.c 2002/06/26 09:45:47 @@ -75,6 +75,8 @@ #include __KERNEL_RCSID(0, "$NetBSD: kern_proc.c,v 1.47 2002/04/12 17:02:33 christos Exp $"); +#include "opt_kstack.h" + #include #include #include @@ -571,3 +573,66 @@ pgrpdump() } } #endif /* DEBUG */ + +#ifdef KSTACK_CHECK_MAGIC +#include + +#define KSTACK_MAGIC 0xdeadbeaf +#define KSTACK_SIZE (USPACE - sizeof(struct user)) + +/* XXX should be per process basis? */ +int kstackleftmin = KSTACK_SIZE; +int kstackleftthres = KSTACK_SIZE / 8; /* warn if remaining stack is less than this */ + +void +kstack_setup_magic(const struct proc *p) +{ + u_int32_t *ip; + u_int32_t const *end; + + KASSERT(p != 0); + KASSERT(p != &proc0); + + /* + * fill all the stack with magic number + * so that later modification on it can be detected. + */ + ip = (u_int32_t *)KSTACK_END(p); + end = (u_int32_t *)((caddr_t)KSTACK_END(p) + KSTACK_SIZE); + for (; ip < end; ip++) { + *ip = KSTACK_MAGIC; + } +} + +void +kstack_check_magic(const struct proc *p) +{ + u_int32_t const *ip, *end; + int stackleft; + + KASSERT(p != 0); + + /* don't check proc0 */ /*XXX*/ + if (p == &proc0) + return; + + ip = (u_int32_t *)KSTACK_END(p); + end = (u_int32_t *)((caddr_t)KSTACK_END(p) + KSTACK_SIZE); + for (; ip < end; ip++) + if (*ip != KSTACK_MAGIC) + break; + + stackleft = (caddr_t)ip - KSTACK_END(p); + if (kstackleftmin > stackleft) { + kstackleftmin = stackleft; + if (stackleft < kstackleftthres) + printf("warning: kernel stack left %d bytes(pid %u)\n", + stackleft, p->p_pid); + } + + if (stackleft <= 0) { + panic("magic on the top of kernel stack changed for pid %u: " + "maybe kernel stack overflow\n", p->p_pid); + } +} +#endif /*KSTACK_CHECK_MAGIC*/ Index: kern_synch.c =================================================================== RCS file: /cvs/cvsroot/syssrc/sys/kern/kern_synch.c,v retrieving revision 1.108 diff -u -p -r1.108 kern_synch.c --- kern_synch.c 2002/05/21 01:38:27 1.108 +++ kern_synch.c 2002/06/26 09:45:47 @@ -82,6 +82,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_synch.c #include "opt_ddb.h" #include "opt_ktrace.h" +#include "opt_kstack.h" #include "opt_lockdebug.h" #include "opt_multiprocessor.h" @@ -847,6 +848,10 @@ mi_switch(struct proc *p) * scheduling flags. */ spc->spc_flags &= ~SPCF_SWITCHCLEAR; + +#ifdef KSTACK_CHECK_MAGIC + kstack_check_magic(p); +#endif /* * Pick a new current process and switch to it. When we Index: uvm_glue.c =================================================================== RCS file: /cvs/cvsroot/syssrc/sys/uvm/uvm_glue.c,v retrieving revision 1.58 diff -u -p -r1.58 uvm_glue.c --- uvm_glue.c 2002/05/15 06:57:49 1.58 +++ uvm_glue.c 2002/06/26 09:45:53 @@ -70,6 +70,7 @@ __KERNEL_RCSID(0, "$NetBSD: uvm_glue.c,v 1.58 2002/05/15 06:57:49 matt Exp $"); #include "opt_kgdb.h" +#include "opt_kstack.h" #include "opt_sysv.h" #include "opt_uvmhist.h" @@ -294,6 +295,13 @@ uvm_fork(p1, p2, shared, stack, stacksiz VM_FAULT_WIRE, VM_PROT_READ | VM_PROT_WRITE); if (error) panic("uvm_fork: uvm_fault_wire failed: %d", error); + +#ifdef KSTACK_CHECK_MAGIC + /* + * fill stack with magic number + */ + kstack_setup_magic(p2); +#endif /* * p_stats currently points at a field in the user struct. Copy Index: proc.h =================================================================== RCS file: /cvs/cvsroot/syssrc/sys/sys/proc.h,v retrieving revision 1.138 diff -u -p -r1.138 proc.h --- proc.h 2002/06/17 16:23:58 1.138 +++ proc.h 2002/06/26 11:03:34 @@ -45,6 +45,7 @@ #if defined(_KERNEL_OPT) #include "opt_multiprocessor.h" +#include "opt_kstack.h" #endif #if defined(_KERNEL) @@ -472,6 +473,24 @@ void p_sugid(struct proc*); #if defined(MULTIPROCESSOR) void proc_trampoline_mp(void); /* XXX */ +#endif + +#ifdef KSTACK_CHECK_MAGIC +void kstack_setup_magic(const struct proc *); +void kstack_check_magic(const struct proc *); +#endif + +/* + * kernel stack paramaters + * XXX require sizeof(struct user) + */ +/* lowest address of kernel stack */ +#ifndef KSTACK_END +#define KSTACK_END(p) ((caddr_t)ALIGN((p)->p_addr + 1)) +#endif +/* size of kernel stack */ +#ifndef KSTACK_SIZE +#define KSTACK_SIZE (USPACE - sizeof(struct user)) #endif #endif /* _KERNEL */