Author: kib
Date: Mon Aug 15 21:44:06 2016
New Revision: 304190
URL: https://svnweb.freebsd.org/changeset/base/304190

Log:
  MFC r303423:
  Force SIGSTOP to be the first signal reported after the attach.

Modified:
  stable/10/bin/ps/ps.1
  stable/10/sys/kern/kern_exit.c
  stable/10/sys/kern/kern_fork.c
  stable/10/sys/kern/kern_sig.c
  stable/10/sys/kern/sys_process.c
  stable/10/sys/sys/proc.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/bin/ps/ps.1
==============================================================================
--- stable/10/bin/ps/ps.1       Mon Aug 15 21:33:20 2016        (r304189)
+++ stable/10/bin/ps/ps.1       Mon Aug 15 21:44:06 2016        (r304190)
@@ -347,6 +347,7 @@ the include file
 .In sys/proc.h :
 .Bl -column P2_INHERIT_PROTECTED 0x00000001
 .It Dv "P2_INHERIT_PROTECTED" Ta No "0x00000001" Ta "New children get 
P_PROTECTED"
+.It Dv "P2_PTRACE_FSTP" Ta No "0x00000010" Ta "SIGSTOP from PT_ATTACH not yet 
handled"
 .El
 .It Cm label
 The MAC label of the process.

Modified: stable/10/sys/kern/kern_exit.c
==============================================================================
--- stable/10/sys/kern/kern_exit.c      Mon Aug 15 21:33:20 2016        
(r304189)
+++ stable/10/sys/kern/kern_exit.c      Mon Aug 15 21:44:06 2016        
(r304190)
@@ -520,9 +520,12 @@ exit1(struct thread *td, int rv)
                         */
                        clear_orphan(q);
                        q->p_flag &= ~(P_TRACED | P_STOPPED_TRACE);
+                       q->p_flag2 &= ~P2_PTRACE_FSTP;
                        q->p_ptevents = 0;
-                       FOREACH_THREAD_IN_PROC(q, tdt)
-                               tdt->td_dbgflags &= ~TDB_SUSPEND;
+                       FOREACH_THREAD_IN_PROC(q, tdt) {
+                               tdt->td_dbgflags &= ~(TDB_SUSPEND | TDB_XSIG |
+                                   TDB_FSTP);
+                       }
                        kern_psignal(q, SIGKILL);
                }
                PROC_UNLOCK(q);

Modified: stable/10/sys/kern/kern_fork.c
==============================================================================
--- stable/10/sys/kern/kern_fork.c      Mon Aug 15 21:33:20 2016        
(r304189)
+++ stable/10/sys/kern/kern_fork.c      Mon Aug 15 21:44:06 2016        
(r304190)
@@ -1063,15 +1063,13 @@ fork_return(struct thread *td, struct tr
                         * parent's children, do it now.
                         */
                        dbg = p->p_pptr->p_pptr;
-                       p->p_flag |= P_TRACED;
-                       p->p_ptevents = PTRACE_DEFAULT;
-                       p->p_oppid = p->p_pptr->p_pid;
+                       proc_set_traced(p);
                        CTR2(KTR_PTRACE,
                    "fork_return: attaching to new child pid %d: oppid %d",
                            p->p_pid, p->p_oppid);
                        proc_reparent(p, dbg);
                        sx_xunlock(&proctree_lock);
-                       td->td_dbgflags |= TDB_CHILD | TDB_SCX;
+                       td->td_dbgflags |= TDB_CHILD | TDB_SCX | TDB_FSTP;
                        ptracestop(td, SIGSTOP);
                        td->td_dbgflags &= ~(TDB_CHILD | TDB_SCX);
                } else {

Modified: stable/10/sys/kern/kern_sig.c
==============================================================================
--- stable/10/sys/kern/kern_sig.c       Mon Aug 15 21:33:20 2016        
(r304189)
+++ stable/10/sys/kern/kern_sig.c       Mon Aug 15 21:44:06 2016        
(r304190)
@@ -2499,14 +2499,26 @@ ptracestop(struct thread *td, int sig)
                        PROC_SUNLOCK(p);
                        return (sig);
                }
+
                /*
-                * Just make wait() to work, the last stopped thread
-                * will win.
+                * Make wait(2) work.  Ensure that right after the
+                * attach, the thread which was decided to become the
+                * leader of attach gets reported to the waiter.
+                * Otherwise, just avoid overwriting another thread's
+                * assignment to p_xthread.  If another thread has
+                * already set p_xthread, the current thread will get
+                * a chance to report itself upon the next iteration.
                 */
-               p->p_xstat = sig;
-               p->p_xthread = td;
-               p->p_flag |= (P_STOPPED_SIG|P_STOPPED_TRACE);
-               sig_suspend_threads(td, p, 0);
+               if ((td->td_dbgflags & TDB_FSTP) != 0 ||
+                   ((p->p_flag & P2_PTRACE_FSTP) == 0 &&
+                   p->p_xthread == NULL)) {
+                       p->p_xstat = sig;
+                       p->p_xthread = td;
+                       td->td_dbgflags &= ~TDB_FSTP;
+                       p->p_flag2 &= ~P2_PTRACE_FSTP;
+                       p->p_flag |= P_STOPPED_SIG | P_STOPPED_TRACE;
+                       sig_suspend_threads(td, p, 0);
+               }
                if ((td->td_dbgflags & TDB_STOPATFORK) != 0) {
                        td->td_dbgflags &= ~TDB_STOPATFORK;
                        cv_broadcast(&p->p_dbgwait);
@@ -2657,7 +2669,20 @@ issignal(struct thread *td)
                        SIG_STOPSIGMASK(sigpending);
                if (SIGISEMPTY(sigpending))     /* no signal to send */
                        return (0);
-               sig = sig_ffs(&sigpending);
+               if ((p->p_flag & (P_TRACED | P_PPTRACE)) == P_TRACED &&
+                   (p->p_flag2 & P2_PTRACE_FSTP) != 0 &&
+                   SIGISMEMBER(sigpending, SIGSTOP)) {
+                       /*
+                        * If debugger just attached, always consume
+                        * SIGSTOP from ptrace(PT_ATTACH) first, to
+                        * execute the debugger attach ritual in
+                        * order.
+                        */
+                       sig = SIGSTOP;
+                       td->td_dbgflags |= TDB_FSTP;
+               } else {
+                       sig = sig_ffs(&sigpending);
+               }
 
                if (p->p_stops & S_SIG) {
                        mtx_unlock(&ps->ps_mtx);
@@ -2674,7 +2699,7 @@ issignal(struct thread *td)
                        sigqueue_delete(&p->p_sigqueue, sig);
                        continue;
                }
-               if (p->p_flag & P_TRACED && (p->p_flag & P_PPTRACE) == 0) {
+               if ((p->p_flag & (P_TRACED | P_PPTRACE)) == P_TRACED) {
                        /*
                         * If traced, always stop.
                         * Remove old signal from queue before the stop.
@@ -2772,6 +2797,8 @@ issignal(struct thread *td)
                                mtx_unlock(&ps->ps_mtx);
                                WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK,
                                    &p->p_mtx.lock_object, "Catching SIGSTOP");
+                               sigqueue_delete(&td->td_sigqueue, sig);
+                               sigqueue_delete(&p->p_sigqueue, sig);
                                p->p_flag |= P_STOPPED_SIG;
                                p->p_xstat = sig;
                                PROC_SLOCK(p);
@@ -2779,7 +2806,7 @@ issignal(struct thread *td)
                                thread_suspend_switch(td, p);
                                PROC_SUNLOCK(p);
                                mtx_lock(&ps->ps_mtx);
-                               break;
+                               goto next;
                        } else if (prop & SA_IGNORE) {
                                /*
                                 * Except for SIGCONT, shouldn't get here.
@@ -2810,6 +2837,7 @@ issignal(struct thread *td)
                }
                sigqueue_delete(&td->td_sigqueue, sig); /* take the signal! */
                sigqueue_delete(&p->p_sigqueue, sig);
+next:;
        }
        /* NOTREACHED */
 }

Modified: stable/10/sys/kern/sys_process.c
==============================================================================
--- stable/10/sys/kern/sys_process.c    Mon Aug 15 21:33:20 2016        
(r304189)
+++ stable/10/sys/kern/sys_process.c    Mon Aug 15 21:44:06 2016        
(r304190)
@@ -648,6 +648,17 @@ sys_ptrace(struct thread *td, struct ptr
 #define        PROC_WRITE(w, t, a)     proc_write_ ## w (t, a)
 #endif
 
+void
+proc_set_traced(struct proc *p)
+{
+
+       PROC_LOCK_ASSERT(p, MA_OWNED);
+       p->p_flag |= P_TRACED;
+       p->p_flag2 |= P2_PTRACE_FSTP;
+       p->p_ptevents = PTRACE_DEFAULT;
+       p->p_oppid = p->p_pptr->p_pid;
+}
+
 int
 kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
 {
@@ -856,11 +867,9 @@ kern_ptrace(struct thread *td, int req, 
        switch (req) {
        case PT_TRACE_ME:
                /* set my trace flag and "owner" so it can read/write me */
-               p->p_flag |= P_TRACED;
-               p->p_ptevents = PTRACE_DEFAULT;
+               proc_set_traced(p);
                if (p->p_flag & P_PPWAIT)
                        p->p_flag |= P_PPTRACE;
-               p->p_oppid = p->p_pptr->p_pid;
                CTR1(KTR_PTRACE, "PT_TRACE_ME: pid %d", p->p_pid);
                break;
 
@@ -875,9 +884,7 @@ kern_ptrace(struct thread *td, int req, 
                 * The old parent is remembered so we can put things back
                 * on a "detach".
                 */
-               p->p_flag |= P_TRACED;
-               p->p_ptevents = PTRACE_DEFAULT;
-               p->p_oppid = p->p_pptr->p_pid;
+               proc_set_traced(p);
                if (p->p_pptr != td->td_proc) {
                        proc_reparent(p, td->td_proc);
                }
@@ -1045,6 +1052,17 @@ kern_ptrace(struct thread *td, int req, 
                                    p->p_pid, data);
                        p->p_oppid = 0;
                        p->p_ptevents = 0;
+                       FOREACH_THREAD_IN_PROC(p, td3) {
+                               if ((td3->td_dbgflags & TDB_FSTP) != 0) {
+                                       sigqueue_delete(&td3->td_sigqueue,
+                                           SIGSTOP);
+                               }
+                               td3->td_dbgflags &= ~(TDB_XSIG | TDB_FSTP);
+                       }
+                       if ((p->p_flag2 & P2_PTRACE_FSTP) != 0) {
+                               sigqueue_delete(&p->p_sigqueue, SIGSTOP);
+                               p->p_flag2 &= ~P2_PTRACE_FSTP;
+                       }
 
                        /* should we send SIGCHLD? */
                        /* childproc_continued(p); */
@@ -1065,7 +1083,7 @@ kern_ptrace(struct thread *td, int req, 
 
                        if (req == PT_DETACH) {
                                FOREACH_THREAD_IN_PROC(p, td3)
-                                       td3->td_dbgflags &= ~TDB_SUSPEND; 
+                                       td3->td_dbgflags &= ~TDB_SUSPEND;
                        }
                        /*
                         * unsuspend all threads, to not let a thread run,

Modified: stable/10/sys/sys/proc.h
==============================================================================
--- stable/10/sys/sys/proc.h    Mon Aug 15 21:33:20 2016        (r304189)
+++ stable/10/sys/sys/proc.h    Mon Aug 15 21:44:06 2016        (r304190)
@@ -398,6 +398,7 @@ do {                                                        
                \
 #define        TDB_CHILD       0x00000100 /* New child indicator for ptrace() 
*/
 #define        TDB_BORN        0x00000200 /* New LWP indicator for ptrace() */
 #define        TDB_EXIT        0x00000400 /* Exiting LWP indicator for 
ptrace() */
+#define        TDB_FSTP        0x00001000 /* The thread is PT_ATTACH leader */
 
 /*
  * "Private" flags kept in td_pflags:
@@ -678,6 +679,7 @@ struct proc {
 #define        P2_NOTRACE      0x00000002      /* No ptrace(2) attach or 
coredumps. */
 #define        P2_NOTRACE_EXEC 0x00000004      /* Keep P2_NOPTRACE on exec(2). 
*/
 #define        P2_AST_SU       0x00000008      /* Handles SU ast for kthreads. 
*/
+#define        P2_PTRACE_FSTP  0x00000010 /* SIGSTOP from PT_ATTACH not yet 
handled. */
 
 /* Flags protected by proctree_lock, kept in p_treeflags. */
 #define        P_TREE_ORPHANED         0x00000001      /* Reparented, on 
orphan list */
@@ -930,6 +932,7 @@ void        proc_linkup(struct proc *p, struct 
 struct proc *proc_realparent(struct proc *child);
 void   proc_reap(struct thread *td, struct proc *p, int *status, int options);
 void   proc_reparent(struct proc *child, struct proc *newparent);
+void   proc_set_traced(struct proc *p);
 struct pstats *pstats_alloc(void);
 void   pstats_fork(struct pstats *src, struct pstats *dst);
 void   pstats_free(struct pstats *ps);
_______________________________________________
svn-src-stable-10@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"

Reply via email to