NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: kern/60595 (System lockup using gdb(1) on kernel with DEBUG+LOCKDEBUG)
Synopsis: System lockup using gdb(1) on kernel with DEBUG+LOCKDEBUG
Responsible-Changed-From-To: kern-bug-people->riastradh
Responsible-Changed-By: riastradh%NetBSD.org@localhost
Responsible-Changed-When: Thu, 20 Aug 2026 15:43:56 +0000
Responsible-Changed-Why:
Can you please try the attached patch?
(This is a latent bug that was exposed by lifting a rock when I fixed
PR port-amd64/60556: panic in process_read_fpregs_xmm,
<https://gnats.NetBSD.org/60556>.)
# HG changeset patch
# User Taylor R Campbell <riastradh%NetBSD.org@localhost>
# Date 1787240316 0
# Thu Aug 20 15:38:36 2026 +0000
# Branch trunk
# Node ID c8d5c9a5e81f1bb3969e4ff92f9824899648a0c0
# Parent d27322fd1985e6602014bf467a3fa01b43c58a94
# EXP-Topic riastradh-pr60595-dbregsalloclock
x86: Pull dbregs buffer allocation out from under lwp_lock.
Sprinkle assertions and notes about locking rules while here.
PR kern/60595: System lockup using gdb(1) on kernel with DEBUG+LOCKDEBUG
diff -r d27322fd1985 -r c8d5c9a5e81f sys/arch/amd64/amd64/process_machdep.c
--- a/sys/arch/amd64/amd64/process_machdep.c Thu Aug 20 14:35:05 2026 +0000
+++ b/sys/arch/amd64/amd64/process_machdep.c Thu Aug 20 15:38:36 2026 +0000
@@ -55,6 +55,9 @@
* registers or privileged bits in the PSL.
* The process is stopped at the time write_fpregs is called.
*
+ * process_alloc_dbregs(proc)
+ * Ensure a dbregs buffer is allocated.
+ *
* process_read_dbregs(proc, regs, sz)
* Get the current user-visible register set from the process
* and copy it into the regs structure (<machine/reg.h>).
@@ -173,6 +176,14 @@ process_read_dbregs(struct lwp *l, struc
return 0;
}
+void
+process_alloc_dbregs(struct lwp *l)
+{
+
+ KASSERT(rw_lock_held(&l->l_proc->p_reflock));
+ x86_dbregs_alloc(l);
+}
+
int
process_write_regs(struct lwp *l, const struct reg *regp)
{
diff -r d27322fd1985 -r c8d5c9a5e81f sys/arch/i386/i386/process_machdep.c
--- a/sys/arch/i386/i386/process_machdep.c Thu Aug 20 14:35:05 2026 +0000
+++ b/sys/arch/i386/i386/process_machdep.c Thu Aug 20 15:38:36 2026 +0000
@@ -55,6 +55,9 @@
* registers or privileged bits in the PSL.
* The process is stopped at the time write_fpregs is called.
*
+ * process_alloc_dbregs(proc)
+ * Ensure a dbregs buffer is allocated.
+ *
* process_read_dbregs(proc, regs)
* Get the current user-visible register set from the process
* and copy it into the regs structure (<machine/reg.h>).
@@ -149,6 +152,14 @@ process_read_dbregs(struct lwp *l, struc
return 0;
}
+void
+process_alloc_dbregs(struct lwp *l)
+{
+
+ KASSERT(rw_lock_held(&l->l_proc->p_reflock));
+ x86_dbregs_alloc(l);
+}
+
#ifdef PTRACE_HOOKS
int
process_write_regs(struct lwp *l, const struct reg *regs)
diff -r d27322fd1985 -r c8d5c9a5e81f sys/arch/x86/include/dbregs.h
--- a/sys/arch/x86/include/dbregs.h Thu Aug 20 14:35:05 2026 +0000
+++ b/sys/arch/x86/include/dbregs.h Thu Aug 20 15:38:36 2026 +0000
@@ -108,6 +108,7 @@ enum x86_dr7_length {
#define X86_DBREGS 4
void x86_dbregs_init(void);
+void x86_dbregs_alloc(struct lwp *);
void x86_dbregs_clear(struct lwp *);
void x86_dbregs_abandon(struct lwp *);
void x86_dbregs_read(struct lwp *, struct dbreg *);
diff -r d27322fd1985 -r c8d5c9a5e81f sys/arch/x86/x86/dbregs.c
--- a/sys/arch/x86/x86/dbregs.c Thu Aug 20 14:35:05 2026 +0000
+++ b/sys/arch/x86/x86/dbregs.c Thu Aug 20 15:38:36 2026 +0000
@@ -28,8 +28,12 @@
#include <sys/param.h>
#include <sys/types.h>
+
#include <sys/lwp.h>
#include <sys/pool.h>
+#include <sys/proc.h>
+#include <sys/rwlock.h>
+
#include <x86/cpufunc.h>
#include <x86/dbregs.h>
@@ -96,6 +100,38 @@ x86_dbregs_reset(void)
ldr6(rdr6() & ~X86_BREAKPOINT_CONDITION_DETECTED);
}
+/*
+ * x86_dbregs_alloc(l)
+ *
+ * Ensure l has a dbregs buffer, allocating one if necessary.
+ *
+ * Caller must hold l->l_proc->p_reflock, and, on return, must not
+ * drop it before calling before calling x86_dbregs_read or
+ * x86_dbregs_write. Caller must not hold the lwp lock.
+ */
+void
+x86_dbregs_alloc(struct lwp *l)
+{
+ struct pcb *pcb = lwp_getpcb(l);
+ struct dbreg *dbregs;
+
+ KASSERT(rw_lock_held(&l->l_proc->p_reflock));
+
+ dbregs = pool_get(&x86_dbregspl, PR_WAITOK);
+ memcpy(dbregs, &initdbstate, sizeof(initdbstate));
+
+ lwp_lock(l);
+ if (pcb->pcb_dbregs == NULL) {
+ pcb->pcb_dbregs = dbregs;
+ dbregs = NULL;
+ pcb->pcb_flags |= PCB_DBREGS;
+ }
+ lwp_unlock(l);
+
+ if (dbregs)
+ pool_put(&x86_dbregspl, dbregs);
+}
+
void
x86_dbregs_clear(struct lwp *l)
{
@@ -131,16 +167,25 @@ x86_dbregs_abandon(struct lwp *l)
kpreempt_enable();
}
+/*
+ * x86_dbregs_read(l, regs)
+ *
+ * Read l's dbregs into the buffer regs.
+ *
+ * Caller must hold l->l_proc->p_reflock, and must have previously
+ * called x86_dbregs_alloc without dropping l->l_proc->p_reflock
+ * in the interim. Caller must also hold the lwp lock.
+ */
void
x86_dbregs_read(struct lwp *l, struct dbreg *regs)
{
struct pcb *pcb = lwp_getpcb(l);
- if (pcb->pcb_dbregs == NULL) {
- pcb->pcb_dbregs = pool_get(&x86_dbregspl, PR_WAITOK);
- memcpy(pcb->pcb_dbregs, &initdbstate, sizeof(initdbstate));
- pcb->pcb_flags |= PCB_DBREGS;
- }
+ KASSERT(rw_lock_held(&l->l_proc->p_reflock));
+ KASSERT(lwp_locked(l, NULL));
+ KASSERT(pcb->pcb_dbregs != NULL);
+ KASSERT(pcb->pcb_flags & PCB_DBREGS);
+
memcpy(regs, pcb->pcb_dbregs, sizeof(*regs));
}
@@ -280,9 +325,10 @@ x86_dbregs_write(struct lwp *l, const st
{
struct pcb *pcb = lwp_getpcb(l);
- if (pcb->pcb_dbregs == NULL) {
- pcb->pcb_dbregs = pool_get(&x86_dbregspl, PR_WAITOK);
- }
+ KASSERT(rw_lock_held(&l->l_proc->p_reflock));
+ KASSERT(lwp_locked(l, NULL));
+ KASSERT(pcb->pcb_dbregs != NULL);
+ KASSERT(pcb->pcb_flags & PCB_DBREGS);
memcpy(pcb->pcb_dbregs, regs, sizeof(*regs));
pcb->pcb_flags |= PCB_DBREGS;
diff -r d27322fd1985 -r c8d5c9a5e81f sys/kern/sys_process_lwpstatus.c
--- a/sys/kern/sys_process_lwpstatus.c Thu Aug 20 14:35:05 2026 +0000
+++ b/sys/kern/sys_process_lwpstatus.c Thu Aug 20 15:38:36 2026 +0000
@@ -302,6 +302,9 @@ process_dodbregs(struct lwp *curl /*trac
ptrace_regrfunc_t r;
ptrace_regwfunc_t w;
+ KASSERT(rw_lock_held(&l->l_proc->p_reflock));
+ process_alloc_dbregs(l);
+
#ifdef COMPAT_NETBSD32
const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0;
diff -r d27322fd1985 -r c8d5c9a5e81f sys/sys/ptrace.h
--- a/sys/sys/ptrace.h Thu Aug 20 14:35:05 2026 +0000
+++ b/sys/sys/ptrace.h Thu Aug 20 15:38:36 2026 +0000
@@ -344,6 +344,10 @@ int process_write_regs(struct lwp *, con
#endif
#endif
+#if defined PT_GETDBREGS || defined PT_SETDBREGS
+void process_alloc_dbregs(struct lwp *);
+#endif
+
int ptrace_machdep_dorequest(struct lwp *, struct lwp **, int,
void *, int);
Home |
Main Index |
Thread Index |
Old Index