Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 13 Nov 2017 19:58:58 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r325771 - head/sys/kern
Message-ID:  <201711131958.vADJwwgV010196@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Mon Nov 13 19:58:58 2017
New Revision: 325771
URL: https://svnweb.freebsd.org/changeset/base/325771

Log:
  Only clear a pending thread event if one is pending.
  
  This fixes a panic when attaching to an already-stopped process after
  r325028.  While here, clean up a few other things in the control flow
  of the 'sendsig' section:
  - Only check for P_STOPPED_TRACE rather than either of P_STOPPED_SIG
    or P_STOPPED_TRACE for most ptrace requests.  The signal handling
    code in kern_sig.c never sets just P_STOPPED_SIG for a traced
    process, so if P_STOPPED_SIG is stopped, P_STOPPED_TRACE should be
    set anyway.  Remove a related debug printf.  Assuming P_STOPPED_TRACE
    permits simplifications in the 'sendsig:' block.
  - Move the block to clear the pending thread state up into a new
    block conditional on P_STOPPED_TRACE and handle delivering pending
    signals to the reporting thread and clearing the reporting thread's
    state in this block.
  - Consolidate case to send a signal to the process in a single case
    for PT_ATTACH.  The only case that could have been in the else before
    was a PT_ATTACH where P_STOPPED_SIG was not set, so both instances
    of kern_psignal() collapse down to just PT_ATTACH.
  
  Reported by:	pho, mmel
  Reviewed by:	kib
  Differential Revision:	https://reviews.freebsd.org/D12837

Modified:
  head/sys/kern/sys_process.c

Modified: head/sys/kern/sys_process.c
==============================================================================
--- head/sys/kern/sys_process.c	Mon Nov 13 19:44:33 2017	(r325770)
+++ head/sys/kern/sys_process.c	Mon Nov 13 19:58:58 2017	(r325771)
@@ -869,19 +869,13 @@ kern_ptrace(struct thread *td, int req, pid_t pid, voi
 		}
 
 		/* not currently stopped */
-		if ((p->p_flag & (P_STOPPED_SIG | P_STOPPED_TRACE)) == 0 ||
+		if ((p->p_flag & P_STOPPED_TRACE) == 0 ||
 		    p->p_suspcount != p->p_numthreads  ||
 		    (p->p_flag & P_WAITED) == 0) {
 			error = EBUSY;
 			goto fail;
 		}
 
-		if ((p->p_flag & P_STOPPED_TRACE) == 0) {
-			static int count = 0;
-			if (count++ == 0)
-				printf("P_STOPPED_TRACE not set.\n");
-		}
-
 		/* OK */
 		break;
 	}
@@ -1130,24 +1124,32 @@ kern_ptrace(struct thread *td, int req, pid_t pid, voi
 		}
 
 	sendsig:
-		/*
+		/* proctree_locked is true for all but PT_KILL. */
+		if (proctree_locked) {
+			sx_xunlock(&proctree_lock);
+			proctree_locked = 0;
+		}
+		
+		/* 
 		 * Clear the pending event for the thread that just
 		 * reported its event (p_xthread).  This may not be
 		 * the thread passed to PT_CONTINUE, PT_STEP, etc. if
 		 * the debugger is resuming a different thread.
+		 *
+		 * Deliver any pending signal via the reporting thread.
 		 */
-		td2 = p->p_xthread;
-		if (proctree_locked) {
-			sx_xunlock(&proctree_lock);
-			proctree_locked = 0;
+		if ((p->p_flag & P_STOPPED_TRACE) != 0) {
+			MPASS(p->p_xthread != NULL);
+			p->p_xthread->td_dbgflags &= ~TDB_XSIG;
+			p->p_xthread->td_xsig = data;
+			p->p_xthread = NULL;
+			p->p_xsig = data;
+		} else {
+			MPASS(p->p_xthread == NULL);
+			MPASS(req == PT_ATTACH);
 		}
-		p->p_xsig = data;
-		p->p_xthread = NULL;
-		if ((p->p_flag & (P_STOPPED_SIG | P_STOPPED_TRACE)) != 0) {
-			/* deliver or queue signal */
-			td2->td_dbgflags &= ~TDB_XSIG;
-			td2->td_xsig = data;
 
+		if ((p->p_flag & (P_STOPPED_SIG | P_STOPPED_TRACE)) != 0) {
 			/*
 			 * P_WKILLED is insurance that a PT_KILL/SIGKILL always
 			 * works immediately, even if another thread is
@@ -1162,21 +1164,28 @@ kern_ptrace(struct thread *td, int req, pid_t pid, voi
 				FOREACH_THREAD_IN_PROC(p, td3)
 					td3->td_dbgflags &= ~TDB_SUSPEND;
 			}
+
 			/*
-			 * unsuspend all threads, to not let a thread run,
-			 * you should use PT_SUSPEND to suspend it before
-			 * continuing process.
+			 * Unsuspend all threads.  To leave a thread
+			 * suspended, use PT_SUSPEND to suspend it
+			 * before continuing the process.
 			 */
 			PROC_SLOCK(p);
 			p->p_flag &= ~(P_STOPPED_TRACE|P_STOPPED_SIG|P_WAITED);
 			thread_unsuspend(p);
 			PROC_SUNLOCK(p);
-			if (req == PT_ATTACH)
-				kern_psignal(p, data);
-		} else {
-			if (data)
-				kern_psignal(p, data);
 		}
+
+		/*
+		 * For requests other than PT_ATTACH, P_STOPPED_TRACE
+		 * was set, so any pending signal in 'data' is
+		 * delivered via the reporting thread (p_xthread).
+		 * For PT_ATTACH the process is not yet stopped for
+		 * tracing, so P_STOPPED_TRACE cannot be set and the
+		 * SIGSTOP must be delivered to the process.
+		 */
+		if (req == PT_ATTACH)
+			kern_psignal(p, data);
 		break;
 
 	case PT_WRITE_I:



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