Author: kib
Date: Fri Nov  9 17:43:23 2018
New Revision: 340290
URL: https://svnweb.freebsd.org/changeset/base/340290

Log:
  MFC r325771, r325777, r325778 (all by jhb):
  
  Only clear a pending thread event if one is pending.
  This fixes a panic when attaching to an already-stopped process.
  
  Also do some other clean ups for control flow of sendsig section.
  
  Reviewed by:  jhb
  Sponsored by: The FreeBSD Foundation

Modified:
  stable/11/sys/kern/sys_process.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/kern/sys_process.c
==============================================================================
--- stable/11/sys/kern/sys_process.c    Fri Nov  9 17:43:19 2018        
(r340289)
+++ stable/11/sys/kern/sys_process.c    Fri Nov  9 17:43:23 2018        
(r340290)
@@ -870,19 +870,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;
        }
@@ -927,11 +921,28 @@ kern_ptrace(struct thread *td, int req, pid_t pid, voi
                if (p->p_pptr != td->td_proc) {
                        proc_reparent(p, td->td_proc);
                }
-               data = SIGSTOP;
                CTR2(KTR_PTRACE, "PT_ATTACH: pid %d, oppid %d", p->p_pid,
                    p->p_oppid);
-               goto sendsig;   /* in PT_CONTINUE below */
 
+               sx_xunlock(&proctree_lock);
+               proctree_locked = 0;
+               MPASS(p->p_xthread == NULL);
+               MPASS((p->p_flag & P_STOPPED_TRACE) == 0);
+
+               /*
+                * If already stopped due to a stop signal, clear the
+                * existing stop before triggering a traced SIGSTOP.
+                */
+               if ((p->p_flag & P_STOPPED_SIG) != 0) {
+                       PROC_SLOCK(p);
+                       p->p_flag &= ~(P_STOPPED_SIG | P_WAITED);
+                       thread_unsuspend(p);
+                       PROC_SUNLOCK(p);
+               }
+
+               kern_psignal(p, SIGSTOP);
+               break;
+
        case PT_CLEARSTEP:
                CTR2(KTR_PTRACE, "PT_CLEARSTEP: tid %d (pid %d)", td2->td_tid,
                    p->p_pid);
@@ -1118,8 +1129,10 @@ kern_ptrace(struct thread *td, int req, pid_t pid, voi
                                        sigqueue_delete(&td3->td_sigqueue,
                                            SIGSTOP);
                                }
-                               td3->td_dbgflags &= ~(TDB_XSIG | TDB_FSTP);
+                               td3->td_dbgflags &= ~(TDB_XSIG | TDB_FSTP |
+                                   TDB_SUSPEND);
                        }
+
                        if ((p->p_flag2 & P2_PTRACE_FSTP) != 0) {
                                sigqueue_delete(&p->p_sigqueue, SIGSTOP);
                                p->p_flag2 &= ~P2_PTRACE_FSTP;
@@ -1130,54 +1143,45 @@ kern_ptrace(struct thread *td, int req, pid_t pid, voi
                        break;
                }
 
+               sx_xunlock(&proctree_lock);
+               proctree_locked = 0;
+
        sendsig:
-               /*
+               MPASS(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;
-               }
-               p->p_xsig = data;
+               MPASS(p->p_xthread != NULL);
+               p->p_xthread->td_dbgflags &= ~TDB_XSIG;
+               p->p_xthread->td_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;
+               p->p_xsig = data;
 
-                       /*
-                        * P_WKILLED is insurance that a PT_KILL/SIGKILL always
-                        * works immediately, even if another thread is
-                        * unsuspended first and attempts to handle a different
-                        * signal or if the POSIX.1b style signal queue cannot
-                        * accommodate any new signals.
-                        */
-                       if (data == SIGKILL)
-                               proc_wkilled(p);
+               /*
+                * P_WKILLED is insurance that a PT_KILL/SIGKILL
+                * always works immediately, even if another thread is
+                * unsuspended first and attempts to handle a
+                * different signal or if the POSIX.1b style signal
+                * queue cannot accommodate any new signals.
+                */
+               if (data == SIGKILL)
+                       proc_wkilled(p);
 
-                       if (req == PT_DETACH) {
-                               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.
-                        */
-                       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);
-               }
+               /*
+                * 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);
                break;
 
        case PT_WRITE_I:
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to