Stop trying to inform debugger about events from an exiting child

Do not emit signals to parent for if a process is demising:

 - fork/vfork/similar
 - lwp created/exited
 - exec
 - syscall entry/exit

With these changes Go applications can be traced without a clash under
a debugger, at least without deadlocking always. The culprit reason was
an attempt to inform a debugger in the middle of exit1() call about
a dying LWP. Go applications perform exit(2) without collecting threads
first. Verified with GDB and picotrace-based utilities like sigtracer.

PR kern/53120
PR port-arm/51677
PR bin/54060
PR bin/49662
PR kern/52548
This commit is contained in:
kamil 2019-06-04 11:54:03 +00:00
parent 43729d11af
commit bcb2d04797
2 changed files with 68 additions and 7 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_lwp.c,v 1.201 2019/05/17 03:34:26 ozaki-r Exp $ */
/* $NetBSD: kern_lwp.c,v 1.202 2019/06/04 11:54:03 kamil Exp $ */
/*-
* Copyright (c) 2001, 2006, 2007, 2008, 2009 The NetBSD Foundation, Inc.
@ -211,7 +211,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.201 2019/05/17 03:34:26 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.202 2019/06/04 11:54:03 kamil Exp $");
#include "opt_ddb.h"
#include "opt_lockdebug.h"
@ -1084,9 +1084,17 @@ lwp_exit(struct lwp *l)
if ((p->p_slflag & (PSL_TRACED|PSL_TRACELWP_EXIT)) ==
(PSL_TRACED|PSL_TRACELWP_EXIT)) {
mutex_enter(p->p_lock);
p->p_lwp_exited = l->l_lid;
eventswitch(TRAP_LWP);
mutex_enter(proc_lock);
if (ISSET(p->p_sflag, PS_WEXIT)) {
mutex_exit(p->p_lock);
/*
* We are exiting, bail out without informing parent
* about a terminating LWP as it would deadlock.
*/
} else {
p->p_lwp_exited = l->l_lid;
eventswitch(TRAP_LWP);
mutex_enter(proc_lock);
}
}
LIST_REMOVE(l, l_list);

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_sig.c,v 1.358 2019/05/06 08:05:03 kamil Exp $ */
/* $NetBSD: kern_sig.c,v 1.359 2019/06/04 11:54:03 kamil Exp $ */
/*-
* Copyright (c) 2006, 2007, 2008 The NetBSD Foundation, Inc.
@ -70,7 +70,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.358 2019/05/06 08:05:03 kamil Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.359 2019/06/04 11:54:03 kamil Exp $");
#include "opt_ptrace.h"
#include "opt_dtrace.h"
@ -913,6 +913,19 @@ trapsignal(struct lwp *l, ksiginfo_t *ksi)
mutex_enter(proc_lock);
mutex_enter(p->p_lock);
/*
* If we are exiting, demise now.
*
* This avoids notifying tracer and deadlocking.
*/
if (__predict_false(ISSET(p->p_sflag, PS_WEXIT))) {
mutex_exit(p->p_lock);
mutex_exit(proc_lock);
lwp_exit(l);
panic("trapsignal");
/* NOTREACHED */
}
mask = &l->l_sigmask;
ps = p->p_sigacts;
action = SIGACTION_PS(ps, signo).sa_handler;
@ -1568,6 +1581,19 @@ eventswitch(int code)
KASSERT((code == TRAP_CHLD) || (code == TRAP_LWP) ||
(code == TRAP_EXEC));
/*
* If we are exiting, demise now.
*
* This avoids notifying tracer and deadlocking.
*/
if (__predict_false(ISSET(p->p_sflag, PS_WEXIT))) {
mutex_exit(p->p_lock);
mutex_exit(proc_lock);
lwp_exit(l);
panic("eventswitch");
/* NOTREACHED */
}
/*
* If there's a pending SIGKILL process it immediately.
*/
@ -1621,6 +1647,21 @@ sigswitch(int ppmask, int signo, bool relock)
KASSERT(l->l_stat == LSONPROC);
KASSERT(p->p_nrlwps > 0);
/*
* If we are exiting, demise now.
*
* This avoids notifying tracer and deadlocking.
*/
if (__predict_false(ISSET(p->p_sflag, PS_WEXIT))) {
mutex_exit(p->p_lock);
if (relock) {
mutex_exit(proc_lock);
}
lwp_exit(l);
panic("sigswitch");
/* NOTREACHED */
}
/*
* On entry we know that the process needs to stop. If it's
* the result of a 'sideways' stop signal that has been sourced
@ -2394,6 +2435,18 @@ proc_stoptrace(int trapno, int sysnum, const register_t args[],
mutex_enter(p->p_lock);
/*
* If we are exiting, demise now.
*
* This avoids notifying tracer and deadlocking.
*/
if (__predict_false(ISSET(p->p_sflag, PS_WEXIT))) {
mutex_exit(p->p_lock);
lwp_exit(l);
panic("proc_stoptrace");
/* NOTREACHED */
}
/*
* If there's a pending SIGKILL process it immediately.
*/