[PATCH] show_register causes hard lock-up on SMP

Manfred Spraul (manfreds@colorfullife.com)
Sun, 26 Dec 1999 19:51:30 +0100


This is a multi-part message in MIME format.
--------------870148B834605872B3C5E7C4
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

a corrupted function pointer causes a hard lock-up on SMP:

* the kernel jumps to the bad function pointer [eg. unloaded module or
an uninitialized structure member]
* page fault
* die()
* spin_lock_irq(&die_lock);
* show_registers()
* another page-fault in show_registers() when it tries to dump the
"Code: " line.
* die()
* lock-up on die_lock
--> NMI lock-up detection,...

The result is a completely mangled and misleading oops report.
Below is my patch, but it seems that Linus dismissed it because I walk
the page tables from an interrupt.
Any better ideas?
I could abuse __get_user(), but I'm not sure if this is really better.

--
	Manfred
--------------870148B834605872B3C5E7C4
Content-Type: text/plain; charset=us-ascii;
 name="patch-shr"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="patch-shr"

--- 2.3/arch/i386/kernel/traps.c Tue Dec 14 18:20:08 1999 +++ build-2.3/arch/i386/kernel/traps.c Fri Dec 17 23:40:20 1999 @@ -124,19 +124,55 @@ /* * These constants are for searching for possible module text - * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is - * a guess of how much space is likely to be vmalloced. + * segments. MODULE_RANGE is a guess of how much space is likely + * to be vmalloced. */ -#define VMALLOC_OFFSET (8*1024*1024) #define MODULE_RANGE (8*1024*1024) +void show_stack(unsigned long * esp) +{ + unsigned long *stack, addr, module_start, module_end; + int i; + + stack = esp; + for(i=0; i < kstack_depth_to_print; i++) { + if (((long) stack & (THREAD_SIZE-1)) == 0) + break; + if (i && ((i % 8) == 0)) + printk("\n "); + printk("%08lx ", *stack++); + } + printk("\nCall Trace: "); + stack = esp; + i = 1; + module_start = VMALLOC_START; + module_end = module_start + MODULE_RANGE; + while (((long) stack & (THREAD_SIZE-1)) != 0) { + addr = *stack++; + /* + * If the address is either in the text segment of the + * kernel, or in the region which contains vmalloc'ed + * memory, it *may* be the address of a calling + * routine; if so, print it so that someone tracing + * down the cause of the crash will be able to figure + * out the call path that was taken. + */ + if (((addr >= (unsigned long) &_stext) && + (addr <= (unsigned long) &_etext)) || + ((addr >= module_start) && (addr <= module_end))) { + if (i && ((i % 8) == 0)) + printk("\n "); + printk("[<%08lx>] ", addr); + i++; + } + } +} static void show_registers(struct pt_regs *regs) { int i; int in_kernel = 1; unsigned long esp; unsigned short ss; - unsigned long *stack, addr, module_start, module_end; esp = (unsigned long) (1+regs); ss = __KERNEL_DS; @@ -160,43 +196,38 @@ * time of the fault.. */ if (in_kernel) { + pgd_t * pgdir; + pmd_t * pgmiddle; + pte_t * pgtable; + printk("\nStack: "); - stack = (unsigned long *) esp; - for(i=0; i < kstack_depth_to_print; i++) { - if (((long) stack & 4095) == 0) - break; - if (i && ((i % 8) == 0)) - printk("\n "); - printk("%08lx ", *stack++); - } - printk("\nCall Trace: "); - stack = (unsigned long *) esp; - i = 1; - module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT); - module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)); - module_end = module_start + MODULE_RANGE; - while (((long) stack & 4095) != 0) { - addr = *stack++; - /* - * If the address is either in the text segment of the - * kernel, or in the region which contains vmalloc'ed - * memory, it *may* be the address of a calling - * routine; if so, print it so that someone tracing - * down the cause of the crash will be able to figure - * out the call path that was taken. - */ - if (((addr >= (unsigned long) &_stext) && - (addr <= (unsigned long) &_etext)) || - ((addr >= module_start) && (addr <= module_end))) { - if (i && ((i % 8) == 0)) - printk("\n "); - printk("[<%08lx>] ", addr); - i++; - } - } + if(esp >= PAGE_OFFSET && esp < high_memory) + show_stack((unsigned long*)esp); + else + printk("Bad stack pointer."); + printk("\nCode: "); - for(i=0;i<20;i++) - printk("%02x ", ((unsigned char *)regs->eip)[i]); + if(regs->eip < PAGE_OFFSET) + goto bad; + + pgdir = pgd_offset(current->active_mm,regs->eip); + if(pgd_none(*pgdir) || pgd_bad(*pgdir)) + goto bad; + + pgmiddle = pmd_offset(pgdir,regs->eip); + if(pmd_none(*pgmiddle) || pmd_bad(*pgmiddle)) + goto bad; + + pgtable = pte_offset(pgmiddle,regs->eip); + if(!pte_present(*pgtable)) + { +bad: + printk(" Bad EIP pointer."); + } else + { + for(i=0;i<20;i++) + printk("%02x ", ((unsigned char *)regs->eip)[i]); + } } printk("\n"); }

--------------870148B834605872B3C5E7C4--

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/