diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -174,7 +174,7 @@ "Discard ignored signals on delivery, otherwise queue them to " "the target queue"); -static bool pt_attach_transparent = true; +bool pt_attach_transparent = true; SYSCTL_BOOL(_debug, OID_AUTO, ptrace_attach_transparent, CTLFLAG_RWTUN, &pt_attach_transparent, 0, "Hide wakes from PT_ATTACH on interruptible sleeps"); diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -1233,6 +1234,7 @@ (u_long)(uintfptr_t)addr); if (error) goto out; + td2->td_dbgflags |= TDB_USERWR; } switch (req) { case PT_TO_SCE: @@ -1345,6 +1347,27 @@ if (data == SIGKILL) proc_wkilled(p); + /* + * If the PT_CONTINUE-like operation is attempted on + * the thread on sleepq, this is possible only after + * the transparent PT_ATTACH. In this case, if the + * caller modified the thread state, e.g. by writing + * register file or specifying the pc, make the thread + * xstopped by waking it up. + */ + if ((td2->td_dbgflags & TDB_USERWR) != 0) { + if (pt_attach_transparent) { + thread_lock(td2); + if (TD_ON_SLEEPQ(td2) && + (td2->td_flags & TDF_SINTR) != 0) { + sleepq_abort(td2, EINTR); + } else { + thread_unlock(td2); + } + } + td2->td_dbgflags &= ~TDB_USERWR; + } + /* * Unsuspend all threads. To leave a thread * suspended, use PT_SUSPEND to suspend it before diff --git a/sys/sys/signalvar.h b/sys/sys/signalvar.h --- a/sys/sys/signalvar.h +++ b/sys/sys/signalvar.h @@ -270,6 +270,7 @@ #ifdef _KERNEL extern bool sigfastblock_fetch_always; +extern bool pt_attach_transparent; /* Return nonzero if process p has an unmasked pending signal. */ #define SIGPENDING(td) \