Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 7 Feb 2010 11:59:55 +0000 (UTC)
From:      Marius Strobl <marius@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r203609 - stable/8/sys/sparc64/sparc64
Message-ID:  <201002071159.o17BxtZF013468@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: marius
Date: Sun Feb  7 11:59:55 2010
New Revision: 203609
URL: http://svn.freebsd.org/changeset/base/203609

Log:
  MFC: r202900
  
  Merge r203608 from amd64/i386:
  
  In syscall(), reread syscall number and arguments after ptracestop(),
  if debugger modified anything in the process environment.

Modified:
  stable/8/sys/sparc64/sparc64/trap.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/xen/xenpci/   (props changed)

Modified: stable/8/sys/sparc64/sparc64/trap.c
==============================================================================
--- stable/8/sys/sparc64/sparc64/trap.c	Sun Feb  7 11:37:38 2010	(r203608)
+++ stable/8/sys/sparc64/sparc64/trap.c	Sun Feb  7 11:59:55 2010	(r203609)
@@ -93,9 +93,18 @@ __FBSDID("$FreeBSD$");
 #include <machine/tsb.h>
 #include <machine/watch.h>
 
+struct syscall_args {
+	u_long code;
+	struct sysent *callp;
+	register_t args[8];
+	register_t *argp;
+	int narg;
+};
+
 void trap(struct trapframe *tf);
 void syscall(struct trapframe *tf);
 
+static int fetch_syscall_args(struct thread *td, struct syscall_args *sa);
 static int trap_pfault(struct thread *td, struct trapframe *tf);
 
 extern char copy_fault[];
@@ -525,137 +534,163 @@ trap_pfault(struct thread *td, struct tr
 /* Maximum number of arguments that can be passed via the out registers. */
 #define	REG_MAXARGS	6
 
-/*
- * Syscall handler. The arguments to the syscall are passed in the o registers
- * by the caller, and are saved in the trap frame. The syscall number is passed
- * in %g1 (and also saved in the trap frame).
- */
-void
-syscall(struct trapframe *tf)
+static int
+fetch_syscall_args(struct thread *td, struct syscall_args *sa)
 {
-	struct sysent *callp;
-	struct thread *td;
-	register_t args[8];
-	register_t *argp;
+	struct trapframe *tf;
 	struct proc *p;
-	u_long code;
 	int reg;
 	int regcnt;
-	int narg;
 	int error;
 
-	td = curthread;
-	KASSERT(td != NULL, ("trap: curthread NULL"));
-	KASSERT(td->td_proc != NULL, ("trap: curproc NULL"));
-
 	p = td->td_proc;
-
-	PCPU_INC(cnt.v_syscall);
-
-	td->td_pticks = 0;
-	td->td_frame = tf;
-	if (td->td_ucred != p->p_ucred)
-		cred_update_thread(td);
-	code = tf->tf_global[1];
-
-	/*
-	 * For syscalls, we don't want to retry the faulting instruction
-	 * (usually), instead we need to advance one instruction.
-	 */
-	td->td_pcb->pcb_tpc = tf->tf_tpc;
-	TF_DONE(tf);
-
+	tf = td->td_frame;
 	reg = 0;
 	regcnt = REG_MAXARGS;
+
+	sa->code = tf->tf_global[1];
+
 	if (p->p_sysent->sv_prepsyscall) {
-		/*
-		 * The prep code is MP aware.
-		 */
 #if 0
-		(*p->p_sysent->sv_prepsyscall)(tf, args, &code, &params);
+		(*p->p_sysent->sv_prepsyscall)(tf, sa->args, &sa->code,
+		    &params);
 #endif
-	} else if (code == SYS_syscall || code == SYS___syscall) {
-		code = tf->tf_out[reg++];
+	} else if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
+		sa->code = tf->tf_out[reg++];
 		regcnt--;
 	}
 
 	if (p->p_sysent->sv_mask)
-		code &= p->p_sysent->sv_mask;
+		sa->code &= p->p_sysent->sv_mask;
 
-	if (code >= p->p_sysent->sv_size)
-		callp = &p->p_sysent->sv_table[0];
+	if (sa->code >= p->p_sysent->sv_size)
+		sa->callp = &p->p_sysent->sv_table[0];
 	else
-		callp = &p->p_sysent->sv_table[code];
-
-	narg = callp->sy_narg;
+		sa->callp = &p->p_sysent->sv_table[sa->code];
 
-	KASSERT(narg <= sizeof(args) / sizeof(args[0]),
+	sa->narg = sa->callp->sy_narg;
+	KASSERT(sa->narg <= sizeof(sa->args) / sizeof(sa->args[0]),
 	    ("Too many syscall arguments!"));
 	error = 0;
-	argp = args;
-	bcopy(&tf->tf_out[reg], args, sizeof(args[0]) * regcnt);
-	if (narg > regcnt)
+	sa->argp = sa->args;
+	bcopy(&tf->tf_out[reg], sa->args, sizeof(sa->args[0]) * regcnt);
+	if (sa->narg > regcnt)
 		error = copyin((void *)(tf->tf_out[6] + SPOFF +
-		    offsetof(struct frame, fr_pad[6])),
-		    &args[regcnt], (narg - regcnt) * sizeof(args[0]));
-
-	CTR5(KTR_SYSC, "syscall: td=%p %s(%#lx, %#lx, %#lx)", td,
-	    syscallnames[code], argp[0], argp[1], argp[2]);
+		    offsetof(struct frame, fr_pad[6])), &sa->args[regcnt],
+		    (sa->narg - regcnt) * sizeof(sa->args[0]));
 
+	/*
+	 * This may result in two records if debugger modified
+	 * registers or memory during sleep at stop/ptrace point.
+	 */
 #ifdef KTRACE
 	if (KTRPOINT(td, KTR_SYSCALL))
-		ktrsyscall(code, narg, argp);
+		ktrsyscall(sa->code, sa->narg, sa->argp);
 #endif
+	return (error);
+}
 
+/*
+ * Syscall handler
+ * The arguments to the syscall are passed in the out registers by the caller,
+ * and are saved in the trap frame.  The syscall number is passed in %g1 (and
+ * also saved in the trap frame).
+ */
+void
+syscall(struct trapframe *tf)
+{
+	struct syscall_args sa;
+	struct thread *td;
+	struct proc *p;
+	int error;
+
+	td = curthread;
+	KASSERT(td != NULL, ("trap: curthread NULL"));
+	KASSERT(td->td_proc != NULL, ("trap: curproc NULL"));
+
+	PCPU_INC(cnt.v_syscall);
+	p = td->td_proc;
 	td->td_syscalls++;
 
+	td->td_pticks = 0;
+	td->td_frame = tf;
+	if (td->td_ucred != p->p_ucred)
+		cred_update_thread(td);
+	if ((p->p_flag & P_TRACED) != 0) {
+		PROC_LOCK(p);
+		td->td_dbgflags &= ~TDB_USERWR;
+		PROC_UNLOCK(p);
+	}
+
+	/*
+	 * For syscalls, we don't want to retry the faulting instruction
+	 * (usually), instead we need to advance one instruction.
+	 */
+	td->td_pcb->pcb_tpc = tf->tf_tpc;
+	TF_DONE(tf);
+
+	error = fetch_syscall_args(td, &sa);
+	CTR5(KTR_SYSC, "syscall: td=%p %s(%#lx, %#lx, %#lx)", td,
+	    syscallnames[sa.code], sa.argp[0], sa.argp[1], sa.argp[2]);
+
 	if (error == 0) {
 		td->td_retval[0] = 0;
 		td->td_retval[1] = 0;
 
-		STOPEVENT(p, S_SCE, narg);	/* MP aware */
-
+		STOPEVENT(p, S_SCE, sa.narg);
 		PTRACESTOP_SC(p, td, S_PT_SCE);
+		if ((td->td_dbgflags & TDB_USERWR) != 0) {
+			/*
+			 * Reread syscall number and arguments if
+			 * debugger modified registers or memory.
+			 */
+			error = fetch_syscall_args(td, &sa);
+			if (error != 0)
+				goto retval;
+			td->td_retval[1] = 0;
+		}
 
-		AUDIT_SYSCALL_ENTER(code, td);
-		error = (*callp->sy_call)(td, argp);
+		AUDIT_SYSCALL_ENTER(sa.code, td);
+		error = (*sa.callp->sy_call)(td, sa.argp);
 		AUDIT_SYSCALL_EXIT(error, td);
 
-		CTR5(KTR_SYSC, "syscall: p=%p error=%d %s return %#lx %#lx ", p,
-		    error, syscallnames[code], td->td_retval[0],
+		CTR5(KTR_SYSC, "syscall: p=%p error=%d %s return %#lx %#lx",
+		    p, error, syscallnames[sa.code], td->td_retval[0],
 		    td->td_retval[1]);
 	}
-
+ retval:
 	cpu_set_syscall_retval(td, error);
 
 	/*
 	 * Check for misbehavior.
 	 */
 	WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
-	    (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???");
+	    (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
+	     syscallnames[sa.code] : "???");
 	KASSERT(td->td_critnest == 0,
 	    ("System call %s returning in a critical section",
-	    (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???"));
+	    (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
+	    syscallnames[sa.code] : "???"));
 	KASSERT(td->td_locks == 0,
 	    ("System call %s returning with %d locks held",
-	    (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???",
-	    td->td_locks));
+	    (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
+	    syscallnames[sa.code] : "???", td->td_locks));
 
 	/*
-	 * Handle reschedule and other end-of-syscall issues
+	 * Handle reschedule and other end-of-syscall issues.
 	 */
 	userret(td, tf);
 
 #ifdef KTRACE
 	if (KTRPOINT(td, KTR_SYSRET))
-		ktrsysret(code, error, td->td_retval[0]);
+		ktrsysret(sa.code, error, td->td_retval[0]);
 #endif
 	/*
 	 * This works because errno is findable through the
 	 * register set.  If we ever support an emulation where this
 	 * is not the case, this code will need to be revisited.
 	 */
-	STOPEVENT(p, S_SCX, code);
+	STOPEVENT(p, S_SCX, sa.code);
 
 	PTRACESTOP_SC(p, td, S_PT_SCX);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201002071159.o17BxtZF013468>