patch-2.4.0-test12 linux/arch/arm/kernel/traps.c

Next file: linux/arch/arm/kernel/via82c505.c
Previous file: linux/arch/arm/kernel/oldlatches.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test11/linux/arch/arm/kernel/traps.c linux/arch/arm/kernel/traps.c
@@ -31,6 +31,7 @@
 #include "ptrace.h"
 
 extern void c_backtrace (unsigned long fp, int pmode);
+extern void show_pte(struct mm_struct *mm, unsigned long addr);
 
 const char *processor_modes[]=
 { "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
@@ -41,12 +42,6 @@
 
 static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
 
-static inline void console_verbose(void)
-{
-	extern int console_loglevel;
-	console_loglevel = 15;
-}
-
 /*
  * Stack pointers should always be within the kernels view of
  * physical memory.  If it is not there, then we can't dump
@@ -72,10 +67,14 @@
 		printk("%08lx: ", p);
 
 		for (i = 0; i < 8; i++, p += 4) {
+			unsigned int val;
+
 			if (p < bottom || p >= top)
 				printk("         ");
-			else
-				printk("%08lx ", *(unsigned long *)p);
+			else {
+				__get_user(val, (unsigned long *)p);
+				printk("%08x ", val);
+			}
 			if (i == 3)
 				printk(" ");
 		}
@@ -91,45 +90,57 @@
 #define VMALLOC_OFFSET (8*1024*1024)
 #define MODULE_RANGE (8*1024*1024)
 
-static void dump_instr(unsigned long pc, int user)
+static void dump_instr(struct pt_regs *regs)
 {
-	int pmin = -2, pmax = 3, ok = 0;
-	extern char start_kernel, _etext;
+	unsigned long addr = instruction_pointer(regs);
+	const int thumb = thumb_mode(regs);
+	const int width = thumb ? 4 : 8;
+	int i;
 
-	if (!user) {
-		unsigned long module_start, module_end;
-		unsigned long kernel_start, kernel_end;
-
-		module_start = VMALLOC_START;
-		module_end   = module_start + MODULE_RANGE;
-
-		kernel_start = (unsigned long)&start_kernel;
-		kernel_end   = (unsigned long)&_etext;
-
-		if (pc >= kernel_start && pc < kernel_end) {
-			if (pc + pmin < kernel_start)
-				pmin = kernel_start - pc;
-			if (pc + pmax > kernel_end)
-				pmax = kernel_end - pc;
-			ok = 1;
-		} else if (pc >= module_start && pc < module_end) {
-			if (pc + pmin < module_start)
-				pmin = module_start - pc;
-			if (pc + pmax > module_end)
-				pmax = module_end - pc;
-			ok = 1;
+	printk("Code: ");
+	for (i = -2; i < 3; i++) {
+		unsigned int val, bad;
+
+		if (thumb)
+			bad = __get_user(val, &((u16 *)addr)[i]);
+		else
+			bad = __get_user(val, &((u32 *)addr)[i]);
+
+		if (!bad)
+			printk(i == 0 ? "(%0*x) " : "%0*x", width, val);
+		else {
+			printk("bad PC value.");
+			break;
 		}
-	} else
-		ok = verify_area(VERIFY_READ, (void *)(pc + pmin), pmax - pmin) == 0;
+	}
+	printk("\n");
+}
 
-	printk ("Code: ");
-	if (ok) {
-		int i;
-		for (i = pmin; i < pmax; i++)
-			printk(i == 0 ? "(%08lx) " : "%08lx ", ((unsigned long *)pc)[i]);
-		printk ("\n");
-	} else
-		printk ("pc not in code space\n");
+static void dump_stack(struct task_struct *tsk, unsigned long sp)
+{
+	printk("Stack:\n");
+	dump_mem(sp - 16, 8192+(unsigned long)tsk);
+}
+
+static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
+{
+	unsigned int fp;
+	int ok = 1;
+
+	printk("Backtrace: ");
+	fp = regs->ARM_fp;
+	if (!fp) {
+		printk("no frame pointer");
+		ok = 0;
+	} else if (verify_stack(fp)) {
+		printk("invalid frame pointer %08lx", fp);
+		ok = 0;
+	} else if (fp < 4096+(unsigned long)tsk)
+		printk("frame pointer underflow");
+	printk("\n");
+
+	if (ok)
+		c_backtrace(fp, processor_mode(regs));
 }
 
 spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
@@ -141,9 +152,9 @@
 {
 	struct task_struct *tsk = current;
 
+	console_verbose();
 	spin_lock_irq(&die_lock);
 
-	console_verbose();
 	printk("Internal error: %s: %x\n", str, err);
 	printk("CPU: %d\n", smp_processor_id());
 	show_regs(regs);
@@ -151,39 +162,22 @@
 		current->comm, current->pid, 4096+(unsigned long)tsk);
 
 	if (!user_mode(regs)) {
-		unsigned long sp = (unsigned long)(regs + 1);
-		unsigned long fp;
-		int dump_info = 1;
-
-		printk("Stack: ");
-		if (verify_stack(sp)) {
-			printk("invalid kernel stack pointer %08lx", sp);
-			dump_info = 0;
-		} else if (sp < 4096+(unsigned long)tsk)
-			printk("kernel stack pointer underflow");
-		printk("\n");
-
-		if (dump_info)
-			dump_mem(sp - 16, 8192+(unsigned long)tsk);
-
-		dump_info = 1;
-
-		printk("Backtrace: ");
-		fp = regs->ARM_fp;
-		if (!fp) {
-			printk("no frame pointer");
-			dump_info = 0;
-		} else if (verify_stack(fp)) {
-			printk("invalid frame pointer %08lx", fp);
-			dump_info = 0;
-		} else if (fp < 4096+(unsigned long)tsk)
-			printk("frame pointer underflow");
-		printk("\n");
+		mm_segment_t fs;
 
-		if (dump_info)
-			c_backtrace(fp, processor_mode(regs));
+		/*
+		 * We need to switch to kernel mode so that we can
+		 * use __get_user to safely read from kernel space.
+		 * Note that we now dump the code first, just in case
+		 * the backtrace kills us.
+		 */
+		fs = get_fs();
+		set_fs(KERNEL_DS);
+
+		dump_instr(regs);
+		dump_stack(tsk, (unsigned long)(regs + 1));
+		dump_backtrace(regs, tsk);
 
-		dump_instr(instruction_pointer(regs), 0);
+		set_fs(fs);
 	}
 
 	spin_unlock_irq(&die_lock);
@@ -206,6 +200,7 @@
 #ifdef CONFIG_DEBUG_USER
 	printk(KERN_INFO "%s (%d): undefined instruction: pc=%08lx\n",
 		current->comm, current->pid, addr);
+	dump_instr(regs);
 #endif
 
 	current->thread.error_code = 0;
@@ -228,6 +223,7 @@
 #ifdef CONFIG_DEBUG_USER
 	printk(KERN_INFO "%s (%d): address exception: pc=%08lx\n",
 		current->comm, current->pid, instruction_pointer(regs));
+	dump_instr(regs);
 #endif
 
 	current->thread.error_code = 0;
@@ -275,7 +271,7 @@
 
 	die("Oops", regs, 0);
 	cli();
-	while(1);
+	panic("bad mode");
 }
 
 /*
@@ -332,6 +328,7 @@
 		 * something catastrophic has happened
 		 */
 		printk("[%d] %s: arm syscall %d\n", current->pid, current->comm, no);
+		dump_instr(regs);
 		if (user_mode(regs)) {
 			show_regs(regs);
 			c_backtrace(regs->ARM_fp, processor_mode(regs));
@@ -359,8 +356,9 @@
 	}
 
 #ifdef CONFIG_DEBUG_USER
-	printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n", current->pid, 
-	       current->comm, n);
+	printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n",
+		current->pid, current->comm, n);
+	dump_instr(regs);
 #endif
 	force_sig(SIGILL, current);
 	die_if_kernel("Oops", regs, n);
@@ -384,21 +382,10 @@
 	siginfo_t info;
 
 #ifdef CONFIG_DEBUG_USER
-	dump_instr(addr, 1);
-	{
-		pgd_t *pgd;
-
-		pgd = pgd_offset(current->mm, addr);
-		printk ("*pgd = %08lx", pgd_val (*pgd));
-		if (!pgd_none (*pgd)) {
-			pmd_t *pmd;
-			pmd = pmd_offset (pgd, addr);
-			printk (", *pmd = %08lx", pmd_val (*pmd));
-			if (!pmd_none (*pmd))
-				printk (", *pte = %08lx", pte_val(*pte_offset (pmd, addr)));
-		}
-		printk ("\n");
-	}
+	printk(KERN_ERR "[%d] %s: bad data abort: code %d instr 0x%08lx\n",
+		current->pid, current->comm, code, instr);
+	dump_instr(regs);
+	show_pte(current->mm, addr);
 #endif
 
 	info.si_signo = SIGILL;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)