Index: sys/kern/kern_event.c =================================================================== --- sys/kern/kern_event.c +++ sys/kern/kern_event.c @@ -1528,7 +1528,7 @@ if (error == 0) goto retry; /* don't restart after signals... */ - if (error == ERESTART) + if (error == ERESTART && !THREAD_DEBUGGING_SIG(td)) error = EINTR; else if (error == EWOULDBLOCK) error = 0; Index: sys/kern/kern_sig.c =================================================================== --- sys/kern/kern_sig.c +++ sys/kern/kern_sig.c @@ -2499,6 +2499,9 @@ td->td_xsig = sig; CTR4(KTR_PTRACE, "ptracestop: tid %d (pid %d) flags %#x sig %d", td->td_tid, p->p_pid, td->td_dbgflags, sig); + thread_lock(td); + td->td_flags |= TDF_PTRACESIG; + thread_unlock(td); PROC_SLOCK(p); while ((p->p_flag & P_TRACED) && (td->td_dbgflags & TDB_XSIG)) { if (p->p_flag & P_SINGLE_EXIT) { Index: sys/kern/kern_thread.c =================================================================== --- sys/kern/kern_thread.c +++ sys/kern/kern_thread.c @@ -918,8 +918,11 @@ if (p->p_singlethread == td) return (0); /* Exempt from stopping. */ } - if ((p->p_flag & P_SINGLE_EXIT) && return_instead) + if ((p->p_flag & P_SINGLE_EXIT) && return_instead) { + if (THREAD_DEBUGGING_SIG(td)) + return (ERESTART); return (EINTR); + } /* Should we goto user boundary if we didn't come from there? */ if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE && Index: sys/kern/kern_time.c =================================================================== --- sys/kern/kern_time.c +++ sys/kern/kern_time.c @@ -503,7 +503,7 @@ error = tsleep_sbt(&nanowait[curcpu], PWAIT | PCATCH, "nanslp", sbt, prec, C_ABSOLUTE); if (error != EWOULDBLOCK) { - if (error == ERESTART) + if (error == ERESTART && !THREAD_DEBUGGING_SIG(td)) error = EINTR; TIMESEL(&sbtt, tmp); if (rmt != NULL) { Index: sys/kern/subr_sleepqueue.c =================================================================== --- sys/kern/subr_sleepqueue.c +++ sys/kern/subr_sleepqueue.c @@ -453,9 +453,12 @@ ret = thread_suspend_check(1); MPASS(ret == 0 || ret == EINTR || ret == ERESTART); } else { - if (SIGISMEMBER(ps->ps_sigintr, sig)) - ret = EINTR; - else + if (SIGISMEMBER(ps->ps_sigintr, sig)) { + if (THREAD_DEBUGGING_SIGERR(td, EINTR)) + ret = ERESTART; + else + ret = EINTR; + } else ret = ERESTART; mtx_unlock(&ps->ps_mtx); } @@ -611,6 +614,8 @@ if (td->td_flags & TDF_SLEEPABORT) { td->td_flags &= ~TDF_SLEEPABORT; + if (THREAD_DEBUGGING_SIGERR(td, td->td_intrval)) + td->td_intrval = ERESTART; return (td->td_intrval); } Index: sys/kern/subr_trap.c =================================================================== --- sys/kern/subr_trap.c +++ sys/kern/subr_trap.c @@ -216,7 +216,8 @@ thread_lock(td); flags = td->td_flags; td->td_flags &= ~(TDF_ASTPENDING | TDF_NEEDSIGCHK | TDF_NEEDSUSPCHK | - TDF_NEEDRESCHED | TDF_ALRMPEND | TDF_PROFPEND | TDF_MACPEND); + TDF_NEEDRESCHED | TDF_ALRMPEND | TDF_PROFPEND | TDF_MACPEND | + TDF_PTRACESIG); thread_unlock(td); PCPU_INC(cnt.v_trap); Index: sys/kern/sys_generic.c =================================================================== --- sys/kern/sys_generic.c +++ sys/kern/sys_generic.c @@ -1119,7 +1119,7 @@ done: /* select is not restarted after signals... */ - if (error == ERESTART) + if (error == ERESTART && !THREAD_DEBUGGING_SIG(td)) error = EINTR; if (error == EWOULDBLOCK) error = 0; @@ -1403,7 +1403,7 @@ done: /* poll is not restarted after signals... */ - if (error == ERESTART) + if (error == ERESTART && !THREAD_DEBUGGING_SIG(td)) error = EINTR; if (error == EWOULDBLOCK) error = 0; Index: sys/kern/sys_process.c =================================================================== --- sys/kern/sys_process.c +++ sys/kern/sys_process.c @@ -856,6 +856,9 @@ data = SIGSTOP; CTR2(KTR_PTRACE, "PT_ATTACH: pid %d, oppid %d", p->p_pid, p->p_oppid); + thread_lock(td2); + td2->td_flags |= TDF_PTRACESIG; + thread_unlock(td2); goto sendsig; /* in PT_CONTINUE below */ case PT_CLEARSTEP: @@ -905,6 +908,10 @@ if (data < 0 || data > _SIG_MAXSIG) { error = EINVAL; break; + } else if (data == 0) { + thread_lock(td2); + td2->td_flags |= TDF_PTRACESIG; + thread_unlock(td2); } switch (req) { @@ -1035,19 +1042,8 @@ uio.uio_rw = write ? UIO_WRITE : UIO_READ; uio.uio_td = td; error = proc_rwmem(p, &uio); - if (uio.uio_resid != 0) { - /* - * XXX proc_rwmem() doesn't currently return ENOSPC, - * so I think write() can bogusly return 0. - * XXX what happens for short writes? We don't want - * to write partial data. - * XXX proc_rwmem() returns EPERM for other invalid - * addresses. Convert this to EINVAL. Does this - * clobber returns of EPERM for other reasons? - */ - if (error == 0 || error == ENOSPC || error == EPERM) - error = EINVAL; /* EOF */ - } + if (uio.uio_resid != 0 && error == 0) + error = EINVAL; /* EOF */ if (!write) td->td_retval[0] = tmp; if (error == 0) { Index: sys/sys/proc.h =================================================================== --- sys/sys/proc.h +++ sys/sys/proc.h @@ -391,7 +391,7 @@ #define TDF_THRWAKEUP 0x00100000 /* Libthr thread must not suspend itself. */ #define TDF_UNUSED21 0x00200000 /* --available-- */ #define TDF_SWAPINREQ 0x00400000 /* Swapin request due to wakeup. */ -#define TDF_UNUSED23 0x00800000 /* --available-- */ +#define TDF_PTRACESIG 0x00800000 /* ERESTART from ptrace-generated signal */ #define TDF_SCHED0 0x01000000 /* Reserved for scheduler private use */ #define TDF_SCHED1 0x02000000 /* Reserved for scheduler private use */ #define TDF_SCHED2 0x04000000 /* Reserved for scheduler private use */ @@ -769,6 +769,14 @@ #define SESS_LEADER(p) ((p)->p_session->s_leader == (p)) +#define THREAD_DEBUGGING_SIGERR(td, err) \ + (((td)->td_proc->p_flag & P_TRACED) != 0 && \ + ((td)->td_flags & TDF_PTRACESIG) != 0 && \ + (err) == EINTR) + +#define THREAD_DEBUGGING_SIG(td) \ + (((td)->td_proc->p_flag & P_TRACED) != 0 && \ + ((td)->td_flags & TDF_PTRACESIG) != 0) #define STOPEVENT(p, e, v) do { \ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, \