diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2024-11-06 17:14:02 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2024-11-06 17:14:02 +0000 |
commit | 01329a5aeec53e7f3a4179e30bf02b4a236ce365 (patch) | |
tree | 8d8c1fa893ae82a2930f86dd2eef7a0a047585d6 /sys/kern | |
parent | be67c1623e5cff64b38112356f5fa4175040881d (diff) |
Factor out the ptrace trap into proc_trap() and simplify the signal
delivery in cursig() a lot since most of that is no longer needed.
On top of this properly handle sending a blocked signal from gdb to
the debugged process by putting the signal into to proc p_siglist.
OK kettenis@
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_sig.c | 80 |
1 files changed, 36 insertions, 44 deletions
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index e8e45c9517b..f3dd6f79b45 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sig.c,v 1.347 2024/11/05 09:14:19 claudio Exp $ */ +/* $OpenBSD: kern_sig.c,v 1.348 2024/11/06 17:14:01 claudio Exp $ */ /* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */ /* @@ -115,6 +115,7 @@ const int sigprop[NSIG] = { void setsigvec(struct proc *, int, struct sigaction *); +int proc_trap(struct proc *, int); void proc_stop(struct proc *p, int); void proc_stop_sweep(void *); void *proc_stop_si; @@ -834,30 +835,20 @@ trapsignal(struct proc *p, int signum, u_long trapno, int code, */ if (((pr->ps_flags & (PS_TRACED | PS_PPWAIT)) == PS_TRACED) && signum != SIGKILL && (p->p_sigmask & mask) != 0) { - single_thread_set(p, SINGLE_SUSPEND | SINGLE_NOWAIT); - pr->ps_xsig = signum; - - SCHED_LOCK(); - proc_stop(p, 1); - SCHED_UNLOCK(); + signum = proc_trap(p, signum); - signum = pr->ps_xsig; - pr->ps_xsig = 0; - if ((p->p_flag & P_TRACESINGLE) == 0) - single_thread_clear(p, 0); - atomic_clearbits_int(&p->p_flag, P_TRACESINGLE); + mask = sigmask(signum); + setsigctx(p, signum, &ctx); /* * If we are no longer being traced, or the parent * didn't give us a signal, skip sending the signal. */ - if ((pr->ps_flags & PS_TRACED) == 0 || - signum == 0) + if ((pr->ps_flags & PS_TRACED) == 0 || signum == 0) return; /* update signal info */ p->p_sisig = signum; - mask = sigmask(signum); } /* @@ -1386,48 +1377,28 @@ cursig(struct proc *p, struct sigctx *sctx, int deep) */ if (((pr->ps_flags & (PS_TRACED | PS_PPWAIT)) == PS_TRACED) && signum != SIGKILL) { - single_thread_set(p, SINGLE_SUSPEND | SINGLE_NOWAIT); - pr->ps_xsig = signum; - - SCHED_LOCK(); - proc_stop(p, 1); - SCHED_UNLOCK(); + signum = proc_trap(p, signum); - /* - * re-take the signal before releasing - * the other threads. Must check the continue - * conditions below and only take the signal if - * those are not true. - */ - signum = pr->ps_xsig; - pr->ps_xsig = 0; mask = sigmask(signum); setsigctx(p, signum, sctx); - if (!((pr->ps_flags & PS_TRACED) == 0 || - signum == 0 || - (p->p_sigmask & mask) != 0)) { - atomic_clearbits_int(&p->p_siglist, mask); - atomic_clearbits_int(&pr->ps_siglist, mask); - } - - if ((p->p_flag & P_TRACESINGLE) == 0) - single_thread_clear(p, 0); - atomic_clearbits_int(&p->p_flag, P_TRACESINGLE); /* * If we are no longer being traced, or the parent - * didn't give us a signal, look for more signals. + * didn't give us a signal, or the signal is ignored, + * look for more signals. */ - if ((pr->ps_flags & PS_TRACED) == 0 || - signum == 0) + if ((pr->ps_flags & PS_TRACED) == 0 || signum == 0 || + sctx->sig_ignore) continue; /* * If the new signal is being masked, look for other - * signals. + * signals but leave it for later. */ - if ((p->p_sigmask & mask) != 0) + if ((p->p_sigmask & mask) != 0) { + atomic_setbits_int(&p->p_siglist, mask); continue; + } } @@ -1507,6 +1478,27 @@ keep: return (signum); } +int +proc_trap(struct proc *p, int signum) +{ + struct process *pr = p->p_p; + + single_thread_set(p, SINGLE_SUSPEND | SINGLE_NOWAIT); + pr->ps_xsig = signum; + + SCHED_LOCK(); + proc_stop(p, 1); + SCHED_UNLOCK(); + + signum = pr->ps_xsig; + pr->ps_xsig = 0; + if ((p->p_flag & P_TRACESINGLE) == 0) + single_thread_clear(p, 0); + atomic_clearbits_int(&p->p_flag, P_TRACESINGLE); + + return signum; +} + /* * Put the argument process into the stopped state and notify the parent * via wakeup. Signals are handled elsewhere. The process must not be |