compute_return_epc

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The current kernel code is calling compute_return_epc() in most exception
handlers for skipping over the instruction.  We're doing thins in practically
all cases.  To my knowledge we're the only MIPS UNIX flavor doing that
which my result in software portabilitiy problems.  It also means that
debuggers and signal handlers in such a case will only ever see the new
program counter but never a pointer to the actually faulting instruction.

So I'd like to apply the following patch which limits the use of
compute_return_epc to those cases where we actually did some sort of
instruction emulation.  Comments?

  Ralf

Index: arch/mips/kernel/traps.c
===================================================================
RCS file: /home/cvs/linux/arch/mips/kernel/traps.c,v
retrieving revision 1.99.2.36
diff -u -r1.99.2.36 traps.c
--- arch/mips/kernel/traps.c	17 Dec 2002 01:43:05 -0000	1.99.2.36
+++ arch/mips/kernel/traps.c	17 Dec 2002 12:07:48 -0000
@@ -96,7 +96,7 @@
 
 static struct task_struct *ll_task = NULL;
 
-static inline void simulate_ll(struct pt_regs *regp, unsigned int opcode)
+static inline void simulate_ll(struct pt_regs *regs, unsigned int opcode)
 {
 	unsigned long value, *vaddr;
 	long offset;
@@ -112,32 +112,37 @@
 	offset <<= 16;
 	offset >>= 16;
 
-	vaddr = (unsigned long *)((long)(regp->regs[(opcode & BASE) >> 21]) + offset);
+	vaddr = (unsigned long *)((long)(regs->regs[(opcode & BASE) >> 21]) + offset);
 
 #ifdef CONFIG_PROC_FS
 	ll_ops++;
 #endif
 
-	if ((unsigned long)vaddr & 3)
+	if ((unsigned long)vaddr & 3) {
 		signal = SIGBUS;
-	else if (get_user(value, vaddr))
+		goto sig;
+	}
+	if (get_user(value, vaddr)) {
 		signal = SIGSEGV;
-	else {
-		if (ll_task == NULL || ll_task == current) {
-			ll_bit = 1;
-		} else {
-			ll_bit = 0;
-		}
-		ll_task = current;
-		regp->regs[(opcode & RT) >> 16] = value;
+		goto sig;
 	}
-	if (compute_return_epc(regp))
-		return;
-	if (signal)
-		send_sig(signal, current, 1);
+
+	if (ll_task == NULL || ll_task == current) {
+		ll_bit = 1;
+	} else {
+		ll_bit = 0;
+	}
+	ll_task = current;
+	regs->regs[(opcode & RT) >> 16] = value;
+
+	compute_return_epc(regs);
+	return;
+
+sig:
+	send_sig(signal, current, 1);
 }
 
-static inline void simulate_sc(struct pt_regs *regp, unsigned int opcode)
+static inline void simulate_sc(struct pt_regs *regs, unsigned int opcode)
 {
 	unsigned long *vaddr, reg;
 	long offset;
@@ -153,25 +158,32 @@
 	offset <<= 16;
 	offset >>= 16;
 
-	vaddr = (unsigned long *)((long)(regp->regs[(opcode & BASE) >> 21]) + offset);
+	vaddr = (unsigned long *)((long)(regs->regs[(opcode & BASE) >> 21]) + offset);
 	reg = (opcode & RT) >> 16;
 
 #ifdef CONFIG_PROC_FS
 	sc_ops++;
 #endif
 
-	if ((unsigned long)vaddr & 3)
+	if ((unsigned long)vaddr & 3) {
 		signal = SIGBUS;
-	else if (ll_bit == 0 || ll_task != current)
-		regp->regs[reg] = 0;
-	else if (put_user(regp->regs[reg], vaddr))
+		goto sig;
+	}
+	if (ll_bit == 0 || ll_task != current) {
+		regs->regs[reg] = 0;
+		goto sig;
+	}
+
+	if (put_user(regs->regs[reg], vaddr))
 		signal = SIGSEGV;
 	else
-		regp->regs[reg] = 1;
-	if (compute_return_epc(regp))
-		return;
-	if (signal)
-		send_sig(signal, current, 1);
+		regs->regs[reg] = 1;
+
+	compute_return_epc(regs);
+	return;
+
+sig:
+	send_sig(signal, current, 1);
 }
 
 /*
@@ -489,9 +501,6 @@
 {
 	siginfo_t info;
 
-	if (compute_return_epc(regs))
-		return;
-
 	info.si_code = FPE_INTOVF;
 	info.si_signo = SIGFPE;
 	info.si_errno = 0;
@@ -534,20 +543,11 @@
 
 		/* If something went wrong, signal */
 		if (sig)
-		{
-			/*
-			 * Return EPC is not calculated in the FPU emulator,
-			 * if a signal is being send. So we calculate it here.
-			 */
-			compute_return_epc(regs);
 			force_sig(sig, current);
-		}
 
 		return;
 	}
 
-	if (compute_return_epc(regs))
-		return;
 	force_sig(SIGFPE, current);
 }
 
@@ -670,8 +670,6 @@
 	}
 #endif /* CONFIG_CPU_HAS_LLSC */
 
-	if (compute_return_epc(regs))
-		return;
 	force_sig(SIGILL, current);
 }
 
@@ -695,14 +693,8 @@
 
 	if (!(mips_cpu.options & MIPS_CPU_FPU)) {
 		int sig = fpu_emulator_cop1Handler(0, regs, &current->thread.fpu.soft);
-		if (sig) {
-			/*
-		 	 * Return EPC is not calculated in the FPU emulator, if
-		   	 * a signal is being send. So we calculate it here.
-		 	 */
-			compute_return_epc(regs);
+		if (sig)
 			force_sig(sig, current);
-		}
 	}
 
 	return;
@@ -716,7 +708,6 @@
 		return;
 	}
 #endif
-	compute_return_epc(regs);
 	force_sig(SIGILL, current);
 }
 
@@ -823,28 +814,28 @@
  */
 void ejtag_exception_handler(struct pt_regs *regs)
 {
-        unsigned long depc, old_epc;
-        unsigned int debug;
+	unsigned long depc, old_epc;
+	unsigned int debug;
 
-        printk("SDBBP EJTAG debug exception - not handled yet, just ignored!\n");
-        depc = read_c0_depc();
-        debug = read_c0_debug();
-        printk("c0_depc = %08lx, DEBUG = %08x\n", depc, debug);
-        if (debug & 0x80000000) {
-                /*
-                 * In branch delay slot.
-                 * We cheat a little bit here and use EPC to calculate the
-                 * debug return address (DEPC). EPC is restored after the
-                 * calculation.
-                 */
-                old_epc = regs->cp0_epc;
-                regs->cp0_epc = depc;
-                __compute_return_epc(regs);
-                depc = regs->cp0_epc;
-                regs->cp0_epc = old_epc;
-        } else
-                depc += 4;
-        write_c0_depc(depc);
+	printk("SDBBP EJTAG debug exception - not handled yet, just ignored!\n");
+	depc = read_c0_depc();
+	debug = read_c0_debug();
+	printk("c0_depc = %08lx, DEBUG = %08x\n", depc, debug);
+	if (debug & 0x80000000) {
+		/*
+		 * In branch delay slot.
+		 * We cheat a little bit here and use EPC to calculate the
+		 * debug return address (DEPC). EPC is restored after the
+		 * calculation.
+		 */
+		old_epc = regs->cp0_epc;
+		regs->cp0_epc = depc;
+		__compute_return_epc(regs);
+		depc = regs->cp0_epc;
+		regs->cp0_epc = old_epc;
+	} else
+		depc += 4;
+	write_c0_depc(depc);
 
 #if 0
 	printk("\n\n----- Enable EJTAG single stepping ----\n\n");
Index: arch/mips/kernel/unaligned.c
===================================================================
RCS file: /home/cvs/linux/arch/mips/kernel/unaligned.c,v
retrieving revision 1.15.2.9
diff -u -r1.15.2.9 unaligned.c
--- arch/mips/kernel/unaligned.c	7 Dec 2002 17:46:47 -0000	1.15.2.9
+++ arch/mips/kernel/unaligned.c	17 Dec 2002 12:07:48 -0000
@@ -88,6 +88,10 @@
 #define STR(x)  __STR(x)
 #define __STR(x)  #x
 
+#ifdef CONFIG_PROC_FS
+unsigned long unaligned_instructions;
+#endif
+
 static inline int emulate_load_store_insn(struct pt_regs *regs,
 	unsigned long addr, unsigned long pc)
 {
@@ -447,6 +451,13 @@
 		 */
 		goto sigill;
 	}
+
+	compute_return_epc(regs);
+
+#ifdef CONFIG_PROC_FS
+	unaligned_instructions++;
+#endif
+
 	return 0;
 
 fault:
@@ -479,10 +490,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_PROC_FS
-unsigned long unaligned_instructions;
-#endif
-
 asmlinkage void do_ade(struct pt_regs *regs)
 {
 	unsigned long pc;
@@ -516,12 +523,7 @@
 	 * Do branch emulation only if we didn't forward the exception.
 	 * This is all so but ugly ...
 	 */
-	if (!emulate_load_store_insn(regs, regs->cp0_badvaddr, pc))
-		compute_return_epc(regs);
-
-#ifdef CONFIG_PROC_FS
-	unaligned_instructions++;
-#endif
+	emulate_load_store_insn(regs, regs->cp0_badvaddr, pc);
 
 	return;
 
Index: arch/mips64/kernel/traps.c
===================================================================
RCS file: /home/cvs/linux/arch/mips64/kernel/traps.c,v
retrieving revision 1.30.2.39
diff -u -r1.30.2.39 traps.c
--- arch/mips64/kernel/traps.c	17 Dec 2002 01:43:05 -0000	1.30.2.39
+++ arch/mips64/kernel/traps.c	17 Dec 2002 12:07:49 -0000
@@ -400,9 +400,6 @@
 {
 	siginfo_t info;
 
-	if (compute_return_epc(regs))
-		return;
-
 	info.si_code = FPE_INTOVF;
 	info.si_signo = SIGFPE;
 	info.si_errno = 0;
@@ -445,20 +442,11 @@
 
 		/* If something went wrong, signal */
 		if (sig)
-		{
-			/*
-			 * Return EPC is not calculated in the FPU emulator,
-			 * if a signal is being send. So we calculate it here.
-			 */
-			compute_return_epc(regs);
 			force_sig(sig, current);
-		}
 
 		return;
 	}
 
-	if (compute_return_epc(regs))
-		return;
 	force_sig(SIGFPE, current);
 }
 
@@ -552,9 +540,6 @@
 {
 	die_if_kernel("Reserved instruction in kernel code", regs);
 
-	if (compute_return_epc(regs))
-		return;
-
 	force_sig(SIGILL, current);
 }
 
@@ -578,20 +563,13 @@
 
 	if (!(mips_cpu.options & MIPS_CPU_FPU)) {
 		int sig = fpu_emulator_cop1Handler(0, regs, &current->thread.fpu.soft);
-		if (sig) {
-			/*
-			 * Return EPC is not calculated in the FPU emulator, if
-			 * a signal is being send. So we calculate it here.
-			 */
-			compute_return_epc(regs);
+		if (sig)
 			force_sig(sig, current);
-		}
 	}
 
 	return;
 
 bad_cid:
-	compute_return_epc(regs);
 	force_sig(SIGILL, current);
 }
 
Index: arch/mips64/kernel/unaligned.c
===================================================================
RCS file: /home/cvs/linux/arch/mips64/kernel/unaligned.c,v
retrieving revision 1.6.2.8
diff -u -r1.6.2.8 unaligned.c
--- arch/mips64/kernel/unaligned.c	7 Dec 2002 17:46:47 -0000	1.6.2.8
+++ arch/mips64/kernel/unaligned.c	17 Dec 2002 12:07:50 -0000
@@ -88,6 +88,10 @@
 #define STR(x)  __STR(x)
 #define __STR(x)  #x
 
+#ifdef CONFIG_PROC_FS
+unsigned long unaligned_instructions;
+#endif
+
 static inline int emulate_load_store_insn(struct pt_regs *regs,
 	unsigned long addr, unsigned long pc)
 {
@@ -447,6 +451,13 @@
 		 */
 		goto sigill;
 	}
+
+	compute_return_epc(regs);
+
+#ifdef CONFIG_PROC_FS
+	unaligned_instructions++;
+#endif
+
 	return 0;
 
 fault:
@@ -479,10 +490,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_PROC_FS
-unsigned long unaligned_instructions;
-#endif
-
 asmlinkage void do_ade(struct pt_regs *regs)
 {
 	unsigned long pc;
@@ -516,12 +523,7 @@
 	 * Do branch emulation only if we didn't forward the exception.
 	 * This is all so but ugly ...
 	 */
-	if (!emulate_load_store_insn(regs, regs->cp0_badvaddr, pc))
-		compute_return_epc(regs);
-
-#ifdef CONFIG_PROC_FS
-	unaligned_instructions++;
-#endif
+	emulate_load_store_insn(regs, regs->cp0_badvaddr, pc);
 
 	return;
 


[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux