
From: Corey Minyard <minyard@acm.org>

Add a debugging interface for PowerPC that allows signal handlers (or any
jump to a context, really) to perform debug functions.  It allows the a
user program to turn on single-stepping, for instance, and the thread will
get a trap after executing the next instruction.  It can also (on supported
PPC processors) turn on branch tracing and get a trap after the next branch
instruction is executed.  This is useful for in-application debugging.

Note that you can enable single-stepping on x86 processors directly from
signal handlers.  Newer x86 processors have the equivalent of a
branch-trace bit in the IA32_DEBUGCTL MSR and could have similar function
to this syscall.  Most other processors could benefit from a similar
interface, except for ARM which is extraordinarily broken for debugging.

Future uses of this could be adding the ability to set the hardware
breakpoint registers from a signal handler.

Signed-off-by: Corey Minyard <minyard@mvista.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/arch/ppc/kernel/entry.S  |   30 +++++++------
 25-akpm/arch/ppc/kernel/misc.S   |    2 
 25-akpm/arch/ppc/kernel/signal.c |   90 +++++++++++++++++++++++++++++++++++++++
 25-akpm/arch/ppc/kernel/traps.c  |    2 
 25-akpm/include/asm-ppc/signal.h |   19 ++++++++
 25-akpm/include/asm-ppc/unistd.h |    2 
 6 files changed, 129 insertions(+), 16 deletions(-)

diff -puN arch/ppc/kernel/entry.S~ppc32-debug-setcontext-syscall-implementation arch/ppc/kernel/entry.S
--- 25/arch/ppc/kernel/entry.S~ppc32-debug-setcontext-syscall-implementation	Thu Dec  9 13:45:32 2004
+++ 25-akpm/arch/ppc/kernel/entry.S	Thu Dec  9 13:45:32 2004
@@ -111,8 +111,10 @@ transfer_to_handler:
 	addi	r11,r1,STACK_FRAME_OVERHEAD
 	stw	r11,PT_REGS(r12)
 #if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
-	lwz	r12,PTRACE-THREAD(r12)
-	andi.	r12,r12,PT_PTRACED
+	/* Check to see if the dbcr0 register is set up to debug.  Use the
+	   single-step bit to do this. */
+	lwz	r12,THREAD_DBCR0(r12)
+	andis.	r12,r12,DBCR0_IC@h
 	beq+	3f
 	/* From user and task is ptraced - load up global dbcr0 */
 	li	r12,-1			/* clear all pending debug events */
@@ -242,9 +244,10 @@ ret_from_syscall:
 	bne-	syscall_exit_work
 syscall_exit_cont:
 #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
-	/* If the process has its own DBCR0 value, load it up */
-	lwz	r0,PTRACE(r2)
-	andi.	r0,r0,PT_PTRACED
+	/* If the process has its own DBCR0 value, load it up.  The single
+	   step bit tells us that dbcr0 should be loaded. */
+	lwz	r0,THREAD+THREAD_DBCR0(r2)
+	andis.	r10,r0,DBCR0_IC@h
 	bnel-	load_dbcr0
 #endif
 	stwcx.	r0,0,r1			/* to clear the reservation */
@@ -599,9 +602,10 @@ user_exc_return:		/* r10 contains MSR_KE
 
 restore_user:
 #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
-	/* Check whether this process has its own DBCR0 value */
-	lwz	r0,PTRACE(r2)
-	andi.	r0,r0,PT_PTRACED
+	/* Check whether this process has its own DBCR0 value.  The single
+	   step bit tells us that dbcr0 should be loaded. */
+	lwz	r0,THREAD+THREAD_DBCR0(r2)
+	andis.	r10,r0,DBCR0_IC@h
 	bnel-	load_dbcr0
 #endif
 
@@ -876,17 +880,17 @@ ret_from_mcheck_exc:
 
 /*
  * Load the DBCR0 value for a task that is being ptraced,
- * having first saved away the global DBCR0.
+ * having first saved away the global DBCR0.  Note that r0
+ * has the dbcr0 value to set upon entry to this.
  */
 load_dbcr0:
-	mfmsr	r0		/* first disable debug exceptions */
-	rlwinm	r0,r0,0,~MSR_DE
-	mtmsr	r0
+	mfmsr	r10		/* first disable debug exceptions */
+	rlwinm	r10,r10,0,~MSR_DE
+	mtmsr	r10
 	isync
 	mfspr	r10,SPRN_DBCR0
 	lis	r11,global_dbcr0@ha
 	addi	r11,r11,global_dbcr0@l
-	lwz	r0,THREAD+THREAD_DBCR0(r2)
 	stw	r10,0(r11)
 	mtspr	SPRN_DBCR0,r0
 	lwz	r10,4(r11)
diff -puN arch/ppc/kernel/misc.S~ppc32-debug-setcontext-syscall-implementation arch/ppc/kernel/misc.S
--- 25/arch/ppc/kernel/misc.S~ppc32-debug-setcontext-syscall-implementation	Thu Dec  9 13:45:32 2004
+++ 25-akpm/arch/ppc/kernel/misc.S	Thu Dec  9 13:45:32 2004
@@ -1434,7 +1434,7 @@ _GLOBAL(sys_call_table)
 	.long sys_fstatfs64
 	.long ppc_fadvise64_64
 	.long sys_ni_syscall		/* 255 - rtas (used on ppc64) */
-	.long sys_ni_syscall		/* 256 reserved for sys_debug_setcontext */
+	.long sys_debug_setcontext
 	.long sys_ni_syscall		/* 257 reserved for vserver */
 	.long sys_ni_syscall		/* 258 reserved for new sys_remap_file_pages */
 	.long sys_ni_syscall		/* 259 reserved for new sys_mbind */
diff -puN arch/ppc/kernel/signal.c~ppc32-debug-setcontext-syscall-implementation arch/ppc/kernel/signal.c
--- 25/arch/ppc/kernel/signal.c~ppc32-debug-setcontext-syscall-implementation	Thu Dec  9 13:45:32 2004
+++ 25-akpm/arch/ppc/kernel/signal.c	Thu Dec  9 13:45:32 2004
@@ -509,6 +509,96 @@ int sys_rt_sigreturn(int r3, int r4, int
 	return 0;
 }
 
+int sys_debug_setcontext(struct ucontext __user *ctx,
+			 int ndbg, struct sig_dbg_op *dbg,
+			 int r6, int r7, int r8,
+			 struct pt_regs *regs)
+{
+	struct sig_dbg_op op;
+	int i;
+	unsigned long new_msr = regs->msr;
+#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+	unsigned long new_dbcr0 = current->thread.dbcr0;
+#endif
+
+	for (i=0; i<ndbg; i++) {
+		if (__copy_from_user(&op, dbg, sizeof(op)))
+			return -EFAULT;
+		switch (op.dbg_type) {
+		case SIG_DBG_SINGLE_STEPPING:
+#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+			if (op.dbg_value) {
+				new_msr |= MSR_DE;
+				new_dbcr0 |= (DBCR0_IDM | DBCR0_IC);
+			} else {
+				new_msr &= ~MSR_DE;
+				new_dbcr0 &= ~(DBCR0_IDM | DBCR0_IC);
+			}
+#else
+			if (op.dbg_value)
+				new_msr |= MSR_SE;
+			else
+				new_msr &= ~MSR_SE;
+#endif
+			break;
+		case SIG_DBG_BRANCH_TRACING:
+#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+			return -EINVAL;
+#else
+			if (op.dbg_value)
+				new_msr |= MSR_BE;
+			else
+				new_msr &= ~MSR_BE;
+#endif
+			break;
+
+		default:
+			return -EINVAL;
+		}
+	}
+
+	/* We wait until here to actually install the values in the
+	   registers so if we fail in the above loop, it will not
+	   affect the contents of these registers.  After this point,
+	   failure is a problem, anyway, and it's very unlikely unless
+	   the user is really doing something wrong. */
+	regs->msr = new_msr;
+#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+	current->thread.dbcr0 = new_dbcr0;
+#endif
+
+	/*
+	 * If we get a fault copying the context into the kernel's
+	 * image of the user's registers, we can't just return -EFAULT
+	 * because the user's registers will be corrupted.  For instance
+	 * the NIP value may have been updated but not some of the
+	 * other registers.  Given that we have done the verify_area
+	 * and successfully read the first and last bytes of the region
+	 * above, this should only happen in an out-of-memory situation
+	 * or if another thread unmaps the region containing the context.
+	 * We kill the task with a SIGSEGV in this situation.
+	 */
+	if (do_setcontext(ctx, regs, 1)) {
+		force_sig(SIGSEGV, current);
+		goto out;
+	}
+
+	/*
+	 * It's not clear whether or why it is desirable to save the
+	 * sigaltstack setting on signal delivery and restore it on
+	 * signal return.  But other architectures do this and we have
+	 * always done it up until now so it is probably better not to
+	 * change it.  -- paulus
+	 */
+	do_sigaltstack(&ctx->uc_stack, NULL, regs->gpr[1]);
+
+	sigreturn_exit(regs);
+	/* doesn't actually return back to here */
+
+ out:
+	return 0;
+}
+
 /*
  * OK, we're invoking a handler
  */
diff -puN arch/ppc/kernel/traps.c~ppc32-debug-setcontext-syscall-implementation arch/ppc/kernel/traps.c
--- 25/arch/ppc/kernel/traps.c~ppc32-debug-setcontext-syscall-implementation	Thu Dec  9 13:45:32 2004
+++ 25-akpm/arch/ppc/kernel/traps.c	Thu Dec  9 13:45:32 2004
@@ -566,7 +566,7 @@ void ProgramCheckException(struct pt_reg
 
 void SingleStepException(struct pt_regs *regs)
 {
-	regs->msr &= ~MSR_SE;  /* Turn off 'trace' bit */
+	regs->msr &= ~(MSR_SE | MSR_BE);  /* Turn off 'trace' bits */
 	if (debugger_sstep(regs))
 		return;
 	_exception(SIGTRAP, regs, TRAP_TRACE, 0);
diff -puN include/asm-ppc/signal.h~ppc32-debug-setcontext-syscall-implementation include/asm-ppc/signal.h
--- 25/include/asm-ppc/signal.h~ppc32-debug-setcontext-syscall-implementation	Thu Dec  9 13:45:32 2004
+++ 25-akpm/include/asm-ppc/signal.h	Thu Dec  9 13:45:32 2004
@@ -157,4 +157,23 @@ typedef struct sigaltstack {
 #define ptrace_signal_deliver(regs, cookie) do { } while (0)
 #endif /* __KERNEL__ */
 
+/*
+ * These are parameters to dbg_sigreturn syscall.  They enable or
+ * disable certain debugging things that can be done from signal
+ * handlers.  The dbg_sigreturn syscall *must* be called from a
+ * SA_SIGINFO signal so the ucontext can be passed to it.  It takes an
+ * array of struct sig_dbg_op, which has the debug operations to
+ * perform before returning from the signal.
+ */
+struct sig_dbg_op {
+	int dbg_type;
+	unsigned long dbg_value;
+};
+
+/* Enable or disable single-stepping.  The value sets the state. */
+#define SIG_DBG_SINGLE_STEPPING		1
+
+/* Enable or disable branch tracing.  The value sets the state. */
+#define SIG_DBG_BRANCH_TRACING		2
+
 #endif
diff -puN include/asm-ppc/unistd.h~ppc32-debug-setcontext-syscall-implementation include/asm-ppc/unistd.h
--- 25/include/asm-ppc/unistd.h~ppc32-debug-setcontext-syscall-implementation	Thu Dec  9 13:45:32 2004
+++ 25-akpm/include/asm-ppc/unistd.h	Thu Dec  9 13:45:32 2004
@@ -260,7 +260,7 @@
 #define __NR_fstatfs64		253
 #define __NR_fadvise64_64	254
 #define __NR_rtas		255
-/* Number 256 is reserved for sys_debug_setcontext */
+#define __NR_sys_debug_setcontext 256
 /* Number 257 is reserved for vserver */
 /* Number 258 is reserved for new sys_remap_file_pages */
 /* Number 259 is reserved for new sys_mbind */
_
