Subject: single stepping a setcontext
To: None <tech-kern@netbsd.org>
From: Nick Hudson <nick.hudson@dsl.pipex.com>
List: tech-kern
Date: 11/20/2006 22:54:25
--Boundary-00=_hIjYFpov2guGzKa
Content-Type: text/plain;
  charset="us-ascii"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Hi,

While looking through the results of a gdb testsuite output on i386 I noticed 
that the single stepping through the return from a signal handler (via 
__sigtramp_siginfo_2) doesn't work. Everything works until the setcontext 
call where the PSL_T bit is restored from the original context and the trap 
never occurs. There are two solutions I can see

	1) use the PSL_T bit from the trapframe when doing a setcontext instead of
	   from the mcontext.
	2) preserve the PSL_T bit for all syscalls

I've attached patches for both options.

Does anyone see any problems with either? Which is more preferable?

Thanks,
Nick


--Boundary-00=_hIjYFpov2guGzKa
Content-Type: text/x-diff;
  charset="us-ascii";
  name="sigstep.diffs"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="sigstep.diffs"

Index: sys/arch/i386/i386/machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/i386/machdep.c,v
retrieving revision 1.586
diff -u -p -u -r1.586 machdep.c
--- sys/arch/i386/i386/machdep.c	16 Nov 2006 01:32:38 -0000	1.586
+++ sys/arch/i386/i386/machdep.c	20 Nov 2006 22:50:54 -0000
@@ -2329,8 +2329,13 @@ cpu_setmcontext(struct lwp *l, const mco
 			tf->tf_fs = gr[_REG_FS];
 			tf->tf_es = gr[_REG_ES];
 			tf->tf_ds = gr[_REG_DS];
-			/* Only change the user-alterable part of eflags */
-			tf->tf_eflags &= ~PSL_USER;
+			/*
+			 * Only change the user-alterable part of eflags, but
+			 * preserve PSL_T in case we're trying to trace a
+			 * setcontext. For example, when returning from a signal
+			 * handler.
+			 */
+			tf->tf_eflags &= ~(PSL_USER & ~PSL_T);
 			tf->tf_eflags |= (gr[_REG_EFL] & PSL_USER);
 		}
 		tf->tf_edi    = gr[_REG_EDI];
Index: sys/arch/i386/i386/syscall.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/i386/syscall.c,v
retrieving revision 1.41
diff -u -p -u -r1.41 syscall.c
--- sys/arch/i386/i386/syscall.c	19 Jul 2006 21:11:42 -0000	1.41
+++ sys/arch/i386/i386/syscall.c	20 Nov 2006 22:50:54 -0000
@@ -92,7 +92,7 @@ syscall_plain(frame)
 	register struct proc *p;
 	int error;
 	size_t argsize;
-	register_t code, args[8], rval[2];
+	register_t code, args[8], rval[2], trace;
 
 	uvmexp.syscalls++;
 	l = curlwp;
@@ -100,6 +100,7 @@ syscall_plain(frame)
 	LWP_CACHE_CREDS(l, p);
 
 	code = frame->tf_eax;
+	trace = frame->tf_eflags & PSL_T;
 	callp = p->p_emul->e_sysent;
 	params = (caddr_t)frame->tf_esp + sizeof(int);
 
@@ -174,6 +175,7 @@ syscall_plain(frame)
 		frame->tf_eflags |= PSL_C;	/* carry bit */
 		break;
 	}
+	frame->tf_eflags |= trace;
 
 	userret(l);
 }
@@ -188,7 +190,7 @@ syscall_fancy(frame)
 	register struct proc *p;
 	int error;
 	size_t argsize;
-	register_t code, args[8], rval[2];
+	register_t code, args[8], rval[2], trace;
 
 	uvmexp.syscalls++;
 	l = curlwp;
@@ -196,6 +198,7 @@ syscall_fancy(frame)
 	LWP_CACHE_CREDS(l, p);
 
 	code = frame->tf_eax;
+	trace = frame->tf_eflags & PSL_T;
 	callp = p->p_emul->e_sysent;
 	params = (caddr_t)frame->tf_esp + sizeof(int);
 
@@ -276,6 +279,7 @@ out:
 		frame->tf_eflags |= PSL_C;	/* carry bit */
 		break;
 	}
+	frame->tf_eflags |= trace;
 
 	trace_exit(l, code, args, rval, error);
 

--Boundary-00=_hIjYFpov2guGzKa--