show_registers(i386): patch + question

From: manfreds (manfreds@colorfullife.com)
Date: Fri Jan 14 2000 - 11:01:51 EST


Hi Linus,

2 weeks ago I sent you a bugfix for show_registers()
[arch/i386/kernel/traps.c, used by die() to print the back trace]:

show_registers() locks up on SMP and prints a mangled oops report on UP if
the EIP value got corrupted, eg because a function pointer was
uninitialized [eg. gdth-scsi driver], or because a module was unloaded.

AFAICS there a 3 options to prevent this crash:

* walk the page tables. Ugly, and you dismissed that patch last year ;)
* walk the module list. IMHO even worse than the page table walk.
 Andi Keen uses a similar approach in his kbacktrace patch.

* use __get_user(). I've implemented this approach in the attached patch.

Could you reconsider this patch, or do you have a better idea how to solve
the problem?

The patch is tested on i386 SMP (2.3.39) and 2.3.40-3 doesn't touch
traps.c

--
	Manfred
<<<<<<<<<<<<<<<<<
--- 2.3/arch/i386/kernel/traps.c	Tue Dec 14 18:20:08 1999
+++ build-2.3/arch/i386/kernel/traps.c	Mon Jan  3 13:28:07 2000
@@ -124,19 +124,63 @@
 
 /*
  * 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;
+
+	// debugging aid: "show_stack(NULL);" prints the full
+	// back trace.
+
+	if(esp==NULL)
+		esp=(unsigned long*)&esp;
+
+	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 +204,24 @@
 	 * time of the fault..
 	 */
 	if (in_kernel) {
+
 		printk("\nStack: ");
-		stack = (unsigned long *) esp;
-		for(i=0; i < kstack_depth_to_print; i++) {
-			if (((long) stack & 4095) == 0)
+		show_stack((unsigned long*)esp);
+
+		printk("\nCode: ");
+		if(regs->eip < PAGE_OFFSET)
+			goto bad;
+
+		for(i=0;i<20;i++)
+		{
+			unsigned char c;
+			if(__get_user(c, &((unsigned char*)regs->eip)[i])) {
+bad:
+				printk(" Bad EIP value.");
 				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++;
 			}
+			printk("%02x ", c);
 		}
-		printk("\nCode: ");
-		for(i=0;i<20;i++)
-			printk("%02x ", ((unsigned char *)regs->eip)[i]);
 	}
 	printk("\n");
 }	

<<<<<<<<<<<<<<<<<

- 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/



This archive was generated by hypermail 2b29 : Sat Jan 15 2000 - 21:00:25 EST