Module Name:    src
Committed By:   kamil
Date:           Tue Dec 24 14:51:00 UTC 2019

Modified Files:
        src/external/gpl3/gdb/dist/gdb: nbsd-nat.c
        src/sys/arch/alpha/include: ptrace.h
        src/sys/arch/hppa/include: ptrace.h
        src/sys/arch/powerpc/include: ptrace.h
        src/sys/arch/sh3/include: ptrace.h
        src/sys/arch/sparc/include: ptrace.h
        src/sys/compat/netbsd32: netbsd32.h netbsd32_ptrace.c
        src/sys/kern: core_elf32.c sys_ptrace.c sys_ptrace_common.c
        src/sys/sys: ptrace.h
        src/tests/lib/libc/sys: t_ptrace_wait.c

Log Message:
Introduce PT_LWPSTATUS + PT_LWPNEXT, obsolete PT_LWPINFO

PT_LWPINFO is a legacy ptrace(2) operation that was originally intended
to retrieve the thread (LWP) information inside a traced process.

It has a number of flaws and is confused with PT_LWPINFO from FreeBSD.

PT_LWPSTATUS and PT_LWPNEXT address the problems (shortly by: rename,
removal of pl_event) and introduces new features: signal context
(pl_sigpend, pl_sigmask), LWP name (pl_name), LWP TLS base address
(pl_private). The private pointer was so far missing information for
a debugger.

PT_LWPSTATUS@nnn is now shipped with core(5) files and contain LWP specific
information, so far missed in the core(5) files.

PT_LWPSTATUS retrieves LWP information for the prompted thread.
PT_LWPNEXT retrieves LWP information for the next thread, borrowing the
semantics from NetBSD specific PT_LWPINFO.

PT_LWPINFO is namespaced with __LEGACY_PT_LWPINFO and still available for
the foreseeable future, without plans of removing it.

Add ATF tests for PT_LWPSTATUS + PT_LWPNEXT.

Keep ATF tests for PT_LWPINFO.

Switch GDB to new API.

Proposed on tech-kern@.


To generate a diff of this commit:
cvs rdiff -u -r1.13 -r1.14 src/external/gpl3/gdb/dist/gdb/nbsd-nat.c
cvs rdiff -u -r1.10 -r1.11 src/sys/arch/alpha/include/ptrace.h
cvs rdiff -u -r1.9 -r1.10 src/sys/arch/hppa/include/ptrace.h
cvs rdiff -u -r1.15 -r1.16 src/sys/arch/powerpc/include/ptrace.h
cvs rdiff -u -r1.16 -r1.17 src/sys/arch/sh3/include/ptrace.h
cvs rdiff -u -r1.14 -r1.15 src/sys/arch/sparc/include/ptrace.h
cvs rdiff -u -r1.131 -r1.132 src/sys/compat/netbsd32/netbsd32.h
cvs rdiff -u -r1.7 -r1.8 src/sys/compat/netbsd32/netbsd32_ptrace.c
cvs rdiff -u -r1.60 -r1.61 src/sys/kern/core_elf32.c
cvs rdiff -u -r1.5 -r1.6 src/sys/kern/sys_ptrace.c
cvs rdiff -u -r1.73 -r1.74 src/sys/kern/sys_ptrace_common.c
cvs rdiff -u -r1.67 -r1.68 src/sys/sys/ptrace.h
cvs rdiff -u -r1.142 -r1.143 src/tests/lib/libc/sys/t_ptrace_wait.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/external/gpl3/gdb/dist/gdb/nbsd-nat.c
diff -u src/external/gpl3/gdb/dist/gdb/nbsd-nat.c:1.13 src/external/gpl3/gdb/dist/gdb/nbsd-nat.c:1.14
--- src/external/gpl3/gdb/dist/gdb/nbsd-nat.c:1.13	Sun Jul 14 18:50:58 2019
+++ src/external/gpl3/gdb/dist/gdb/nbsd-nat.c	Tue Dec 24 14:51:00 2019
@@ -145,10 +145,10 @@ nbsd_nat_target::thread_alive (ptid_t pt
 {
   if (ptid.lwp_p ())
     {
-      struct ptrace_lwpinfo pl;
+      struct ptrace_lwpstatus pl;
 
       pl.pl_lwpid = ptid.lwp ();
-      if (ptrace (PT_LWPINFO, ptid.pid (), (caddr_t) &pl, sizeof pl)
+      if (ptrace (PT_LWPSTATUS, ptid.pid (), (caddr_t) &pl, sizeof pl)
 	  == -1)
 	return 0;
     }
@@ -255,10 +255,10 @@ static void
 nbsd_add_threads (pid_t pid)
 {
   int val;
-  struct ptrace_lwpinfo pl;
+  struct ptrace_lwpstatus pl;
 
   pl.pl_lwpid = 0;
-  while ((val = ptrace (PT_LWPINFO, pid, (void *)&pl, sizeof(pl))) != -1
+  while ((val = ptrace (PT_LWPNEXT, pid, (void *)&pl, sizeof(pl))) != -1
     && pl.pl_lwpid != 0)
     {
       ptid_t ptid = ptid_t (pid, pl.pl_lwpid, 0);

Index: src/sys/arch/alpha/include/ptrace.h
diff -u src/sys/arch/alpha/include/ptrace.h:1.10 src/sys/arch/alpha/include/ptrace.h:1.11
--- src/sys/arch/alpha/include/ptrace.h:1.10	Tue Jun 18 21:18:11 2019
+++ src/sys/arch/alpha/include/ptrace.h	Tue Dec 24 14:50:59 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: ptrace.h,v 1.10 2019/06/18 21:18:11 kamil Exp $ */
+/* $NetBSD: ptrace.h,v 1.11 2019/12/24 14:50:59 kamil Exp $ */
 
 /*
  * Copyright (c) 1994 Christopher G. Demetriou
@@ -56,3 +56,7 @@
 #define PTRACE_BREAKPOINT	((const uint8_t[]) { 0x80, 0x00, 0x00, 0x00 })
 #define PTRACE_BREAKPOINT_ASM	__asm __volatile("bpt" ::: "memory")
 #define PTRACE_BREAKPOINT_SIZE	4
+
+#ifdef _KERNEL
+#define PTRACE_LWP_GETPRIVATE(l) ((struct pcb *)lwp_getpcb(l))->pcb_hw.apcb_unique
+#endif

Index: src/sys/arch/hppa/include/ptrace.h
diff -u src/sys/arch/hppa/include/ptrace.h:1.9 src/sys/arch/hppa/include/ptrace.h:1.10
--- src/sys/arch/hppa/include/ptrace.h:1.9	Tue Jun 18 21:18:12 2019
+++ src/sys/arch/hppa/include/ptrace.h	Tue Dec 24 14:50:59 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: ptrace.h,v 1.9 2019/06/18 21:18:12 kamil Exp $	*/
+/*	$NetBSD: ptrace.h,v 1.10 2019/12/24 14:50:59 kamil Exp $	*/
 
 /*	$OpenBSD: ptrace.h,v 1.2 1998/12/01 03:05:44 mickey Exp $	*/
 
@@ -61,3 +61,7 @@
 #define PTRACE_BREAKPOINT	((const uint8_t[]) { 0x00, 0x01, 0x00, 0x04 })
 #define PTRACE_BREAKPOINT_ASM	__asm __volatile("break	%0, %1" :: "i" (HPPA_BREAK_KERNEL), "i" (HPPA_BREAK_SS) : "memory")
 #define PTRACE_BREAKPOINT_SIZE	4
+
+#ifdef _KERNEL
+#define PTRACE_LWP_GETPRIVATE(l) (l)->l_md.md_regs->tf_cr27
+#endif

Index: src/sys/arch/powerpc/include/ptrace.h
diff -u src/sys/arch/powerpc/include/ptrace.h:1.15 src/sys/arch/powerpc/include/ptrace.h:1.16
--- src/sys/arch/powerpc/include/ptrace.h:1.15	Fri Nov 29 12:04:32 2019
+++ src/sys/arch/powerpc/include/ptrace.h	Tue Dec 24 14:50:59 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: ptrace.h,v 1.15 2019/11/29 12:04:32 martin Exp $	*/
+/*	$NetBSD: ptrace.h,v 1.16 2019/12/24 14:50:59 kamil Exp $	*/
 
 #ifndef _POWERPC_PTRACE_H
 #define	_POWERPC_PTRACE_H
@@ -77,4 +77,8 @@ int procfs_machdep_validvecregs(struct l
 #define PTRACE_BREAKPOINT_ASM	__asm __volatile("trap")
 #define PTRACE_BREAKPOINT_SIZE	4
 
+#ifdef _KERNEL
+#define PTRACE_LWP_GETPRIVATE(l) (l)->l_md.md_utf->tf_fixreg[_REG_R2]
+#endif
+
 #endif /* _POWERPC_PTRACE_H */

Index: src/sys/arch/sh3/include/ptrace.h
diff -u src/sys/arch/sh3/include/ptrace.h:1.16 src/sys/arch/sh3/include/ptrace.h:1.17
--- src/sys/arch/sh3/include/ptrace.h:1.16	Fri Oct  4 15:25:30 2019
+++ src/sys/arch/sh3/include/ptrace.h	Tue Dec 24 14:50:59 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: ptrace.h,v 1.16 2019/10/04 15:25:30 maya Exp $	*/
+/*	$NetBSD: ptrace.h,v 1.17 2019/12/24 14:50:59 kamil Exp $	*/
 
 /*
  * Copyright (c) 1993 Christopher G. Demetriou
@@ -98,5 +98,6 @@
 int ptrace_machdep_dorequest(struct lwp *, struct lwp *, int, void *, int);
 #endif
 
+#define PTRACE_LWP_GETPRIVATE(l) (l)->l_md.md_regs->tf_gbr
 #endif /* _KERNEL */
 #endif /* !_SH3_PTRACE_H_ */

Index: src/sys/arch/sparc/include/ptrace.h
diff -u src/sys/arch/sparc/include/ptrace.h:1.14 src/sys/arch/sparc/include/ptrace.h:1.15
--- src/sys/arch/sparc/include/ptrace.h:1.14	Tue Jun 18 21:18:13 2019
+++ src/sys/arch/sparc/include/ptrace.h	Tue Dec 24 14:50:59 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: ptrace.h,v 1.14 2019/06/18 21:18:13 kamil Exp $ */
+/*	$NetBSD: ptrace.h,v 1.15 2019/12/24 14:50:59 kamil Exp $ */
 
 /*
  * Copyright (c) 1992, 1993
@@ -69,3 +69,7 @@
 #define PTRACE_BREAKPOINT	((const uint8_t[]) { 0x91, 0xd0, 0x20, 0x01 })
 #define PTRACE_BREAKPOINT_ASM	__asm __volatile("ta 1")
 #define PTRACE_BREAKPOINT_SIZE	4
+
+#ifdef _KERNEL
+#define PTRACE_LWP_GETPRIVATE(l) (l)->l_md.md_tf->tf_global[7]
+#endif

Index: src/sys/compat/netbsd32/netbsd32.h
diff -u src/sys/compat/netbsd32/netbsd32.h:1.131 src/sys/compat/netbsd32/netbsd32.h:1.132
--- src/sys/compat/netbsd32/netbsd32.h:1.131	Mon Nov 18 12:06:26 2019
+++ src/sys/compat/netbsd32/netbsd32.h	Tue Dec 24 14:50:59 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: netbsd32.h,v 1.131 2019/11/18 12:06:26 rin Exp $	*/
+/*	$NetBSD: netbsd32.h,v 1.132 2019/12/24 14:50:59 kamil Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001, 2008, 2015 Matthew R. Green
@@ -39,6 +39,7 @@
 #include <sys/param.h> /* precautionary upon removal from ucred.h */
 #include <sys/systm.h>
 #include <sys/mount.h>
+#include <sys/ptrace.h>
 #include <sys/stat.h>
 #include <sys/statvfs.h>
 #include <sys/syscallargs.h>
@@ -331,6 +332,16 @@ struct netbsd32_ptrace_siginfo {
 					 * (route signal to all LWPs) */
 };
 
+#define PL32_LNAMELEN 20
+
+struct netbsd32_ptrace_lwpstatus {
+	lwpid_t		pl_lwpid;
+	sigset_t	pl_sigpend;
+	sigset_t	pl_sigmask;
+	char		pl_name[PL32_LNAMELEN];
+	netbsd32_voidp	pl_private;
+};
+
 /* from <sys/quotactl.h> */
 typedef netbsd32_pointer_t netbsd32_quotactlargsp_t;
 struct netbsd32_quotactlargs {
@@ -1213,6 +1224,8 @@ void	netbsd32_si32_to_si(siginfo_t *, co
 
 void	netbsd32_ksi32_to_ksi(struct _ksiginfo *si, const struct __ksiginfo32 *si32);
 
+void	netbsd32_read_lwpstatus(struct lwp *, struct netbsd32_ptrace_lwpstatus *);
+
 #ifdef KTRACE
 void netbsd32_ktrpsig(int, sig_t, const sigset_t *, const ksiginfo_t *);
 #else

Index: src/sys/compat/netbsd32/netbsd32_ptrace.c
diff -u src/sys/compat/netbsd32/netbsd32_ptrace.c:1.7 src/sys/compat/netbsd32/netbsd32_ptrace.c:1.8
--- src/sys/compat/netbsd32/netbsd32_ptrace.c:1.7	Tue Jun  4 16:29:53 2019
+++ src/sys/compat/netbsd32/netbsd32_ptrace.c	Tue Dec 24 14:50:59 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: netbsd32_ptrace.c,v 1.7 2019/06/04 16:29:53 mgorny Exp $	*/
+/*	$NetBSD: netbsd32_ptrace.c,v 1.8 2019/12/24 14:50:59 kamil Exp $	*/
 
 /*
  * Copyright (c) 2016 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_ptrace.c,v 1.7 2019/06/04 16:29:53 mgorny Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_ptrace.c,v 1.8 2019/12/24 14:50:59 kamil Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_ptrace.h"
@@ -51,6 +51,27 @@ __KERNEL_RCSID(0, "$NetBSD: netbsd32_ptr
 #define PTRACE_TRANSLATE_REQUEST32(x) x
 #endif
 
+static void
+netbsd32_lwpstatus_to_lwpstatus32(struct netbsd32_ptrace_lwpstatus *pls32,
+    const struct ptrace_lwpstatus *pls)
+{
+	pls32->pl_lwpid = pls->pl_lwpid;
+	pls32->pl_sigpend = pls->pl_sigpend;
+	pls32->pl_sigmask = pls->pl_sigmask;
+	memcpy(&pls32->pl_name, &pls->pl_name, PL_LNAMELEN);
+	NETBSD32PTR32(pls32->pl_private, pls->pl_private);
+}
+
+void
+netbsd32_read_lwpstatus(struct lwp *l, struct netbsd32_ptrace_lwpstatus *pls32)
+{
+	struct ptrace_lwpstatus pls;
+
+	process_read_lwpstatus(l, &pls);
+
+	netbsd32_lwpstatus_to_lwpstatus32(pls32, &pls);
+}
+
 /*
  * PTRACE methods
  */
@@ -119,6 +140,19 @@ netbsd32_copyout_siginfo(const struct pt
 }
 
 static int
+netbsd32_copyout_lwpstatus(const struct ptrace_lwpstatus *pls, void *addr, size_t len)
+{
+	struct netbsd32_ptrace_lwpstatus pls32;
+
+	if (len > sizeof(pls32))
+		return EINVAL;
+
+	netbsd32_lwpstatus_to_lwpstatus32(&pls32, pls);
+
+	return copyout(&pls32, addr, MIN(len, sizeof(pls32)));
+}
+
+static int
 netbsd32_doregs(struct lwp *curl /*tracer*/,
     struct lwp *l /*traced*/,
     struct uio *uio)
@@ -237,6 +271,7 @@ static struct ptrace_methods netbsd32_pt
 	.ptm_copyout_piod = netbsd32_copyout_piod,
 	.ptm_copyin_siginfo = netbsd32_copyin_siginfo,
 	.ptm_copyout_siginfo = netbsd32_copyout_siginfo,
+	.ptm_copyout_lwpstatus = netbsd32_copyout_lwpstatus,
 	.ptm_doregs = netbsd32_doregs,
 	.ptm_dofpregs = netbsd32_dofpregs,
 	.ptm_dodbregs = netbsd32_dodbregs

Index: src/sys/kern/core_elf32.c
diff -u src/sys/kern/core_elf32.c:1.60 src/sys/kern/core_elf32.c:1.61
--- src/sys/kern/core_elf32.c:1.60	Fri Nov 22 15:57:49 2019
+++ src/sys/kern/core_elf32.c	Tue Dec 24 14:50:59 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: core_elf32.c,v 1.60 2019/11/22 15:57:49 pgoyette Exp $	*/
+/*	$NetBSD: core_elf32.c,v 1.61 2019/12/24 14:50:59 kamil Exp $	*/
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -40,7 +40,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: core_elf32.c,v 1.60 2019/11/22 15:57:49 pgoyette Exp $");
+__KERNEL_RCSID(1, "$NetBSD: core_elf32.c,v 1.61 2019/12/24 14:50:59 kamil Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_compat_netbsd32.h"
@@ -96,6 +96,9 @@ static int	ELFNAMEEND(coredump_note)(str
 /* The 'note' section names and data are always 4-byte aligned. */
 #define	ELFROUNDSIZE	4	/* XXX Should it be sizeof(Elf_Word)? */
 
+#define elf_read_lwpstatus	CONCAT(process_read_lwpstatus, ELFSIZE)
+#define elf_lwpstatus		CONCAT(process_lwpstatus, ELFSIZE)
+
 #define elf_process_read_regs	CONCAT(process_read_regs, ELFSIZE)
 #define elf_process_read_fpregs	CONCAT(process_read_fpregs, ELFSIZE)
 #define elf_reg			CONCAT(process_reg, ELFSIZE)
@@ -369,8 +372,6 @@ coredump_note_procinfo(struct lwp *l, st
 {
 	struct proc *p;
 	struct netbsd_elfcore_procinfo cpi;
-	struct lwp *l0;
-	sigset_t ss1, ss2;
 
 	p = l->l_proc;
 
@@ -382,16 +383,16 @@ coredump_note_procinfo(struct lwp *l, st
 	cpi.cpi_siglwp = p->p_sigctx.ps_lwp;
 
 	/*
-	 * XXX This should be per-LWP.
+	 * per-LWP pending signals are stored in PT_LWPSTATUS@nnn.
 	 */
-	ss1 = p->p_sigpend.sp_set;
-	sigemptyset(&ss2);
-	LIST_FOREACH(l0, &p->p_lwps, l_sibling) {
-		sigplusset(&l0->l_sigpend.sp_set, &ss1);
-		sigplusset(&l0->l_sigmask, &ss2);
-	}
-	memcpy(&cpi.cpi_sigpend, &ss1, sizeof(cpi.cpi_sigpend));
-	memcpy(&cpi.cpi_sigmask, &ss2, sizeof(cpi.cpi_sigmask));
+	memcpy(&cpi.cpi_sigpend, &p->p_sigpend.sp_set, sizeof(cpi.cpi_sigpend));
+
+	/*
+	 * Signal mask is stored on a per-LWP basis in PT_LWPSTATUS@nnn.
+	 * For compatibility purposes, cpi_sigmask is present, but zeroed.
+	 */
+	memset(&cpi.cpi_sigmask, 0, sizeof(cpi.cpi_sigmask));
+
 	memcpy(&cpi.cpi_sigignore, &p->p_sigctx.ps_sigignore,
 	    sizeof(cpi.cpi_sigignore));
 	memcpy(&cpi.cpi_sigcatch, &p->p_sigctx.ps_sigcatch,
@@ -482,6 +483,7 @@ ELFNAMEEND(coredump_note)(struct lwp *l,
 {
 	int error;
 	char name[64];
+	elf_lwpstatus els;
 	elf_reg intreg;
 #ifdef PT_GETFPREGS
 	elf_fpreg freg;
@@ -491,6 +493,11 @@ ELFNAMEEND(coredump_note)(struct lwp *l,
 	snprintf(name, sizeof(name), "%s@%d",
 	    ELF_NOTE_NETBSD_CORE_NAME, l->l_lid);
 
+	elf_read_lwpstatus(l, &els);
+
+	ELFNAMEEND(coredump_savenote)(ns, PT_LWPSTATUS, name, &els,
+	    sizeof(els));
+
 	error = elf_process_read_regs(l, &intreg);
 	if (error)
 		return (error);

Index: src/sys/kern/sys_ptrace.c
diff -u src/sys/kern/sys_ptrace.c:1.5 src/sys/kern/sys_ptrace.c:1.6
--- src/sys/kern/sys_ptrace.c:1.5	Sun Dec 17 20:59:27 2017
+++ src/sys/kern/sys_ptrace.c	Tue Dec 24 14:50:59 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: sys_ptrace.c,v 1.5 2017/12/17 20:59:27 christos Exp $	*/
+/*	$NetBSD: sys_ptrace.c,v 1.6 2019/12/24 14:50:59 kamil Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -118,7 +118,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_ptrace.c,v 1.5 2017/12/17 20:59:27 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_ptrace.c,v 1.6 2019/12/24 14:50:59 kamil Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ptrace.h"
@@ -185,11 +185,20 @@ ptrace_copyout_siginfo(const struct ptra
 	return copyout(psi, addr, sizeof(*psi));
 }
 
+static int
+ptrace_copyout_lwpstatus(const struct ptrace_lwpstatus *pls, void *addr,
+    size_t len)
+{
+
+	return copyout(pls, addr, len);
+}
+
 static struct ptrace_methods native_ptm = {
 	.ptm_copyin_piod = ptrace_copyin_piod,
 	.ptm_copyout_piod = ptrace_copyout_piod,
 	.ptm_copyin_siginfo = ptrace_copyin_siginfo,
 	.ptm_copyout_siginfo = ptrace_copyout_siginfo,
+	.ptm_copyout_lwpstatus = ptrace_copyout_lwpstatus,
 	.ptm_doregs = process_doregs,
 	.ptm_dofpregs = process_dofpregs,
 	.ptm_dodbregs = process_dodbregs,

Index: src/sys/kern/sys_ptrace_common.c
diff -u src/sys/kern/sys_ptrace_common.c:1.73 src/sys/kern/sys_ptrace_common.c:1.74
--- src/sys/kern/sys_ptrace_common.c:1.73	Fri Nov 22 05:01:44 2019
+++ src/sys/kern/sys_ptrace_common.c	Tue Dec 24 14:50:59 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: sys_ptrace_common.c,v 1.73 2019/11/22 05:01:44 rin Exp $	*/
+/*	$NetBSD: sys_ptrace_common.c,v 1.74 2019/12/24 14:50:59 kamil Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -118,7 +118,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.73 2019/11/22 05:01:44 rin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.74 2019/12/24 14:50:59 kamil Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ptrace.h"
@@ -288,6 +288,8 @@ ptrace_listener_cb(kauth_cred_t cred, ka
 	case PT_RESUME:
 	case PT_SUSPEND:
 	case PT_STOP:
+	case PT_LWPSTATUS:
+	case PT_LWPNEXT:
 		result = KAUTH_RESULT_ALLOW;
 		break;
 
@@ -496,6 +498,8 @@ ptrace_allowed(struct lwp *l, int req, s
 	case PT_RESUME:
 	case PT_SUSPEND:
 	case PT_STOP:
+	case PT_LWPSTATUS:
+	case PT_LWPNEXT:
 		/*
 		 * You can't do what you want to the process if:
 		 *	(1) It's not being traced at all,
@@ -786,6 +790,104 @@ ptrace_lwpinfo(struct proc *t, struct lw
 	return copyout(&pl, addr, sizeof(pl));
 }
 
+static void
+ptrace_read_lwpstatus(struct lwp *l, struct ptrace_lwpstatus *pls)
+{
+
+	KASSERT(l->l_lid == pls->pl_lwpid);
+
+	memcpy(&pls->pl_sigmask, &l->l_sigmask, sizeof(pls->pl_sigmask));
+	memcpy(&pls->pl_sigpend, &l->l_sigpend.sp_set, sizeof(pls->pl_sigpend));
+
+	if (l->l_name == NULL)
+		memset(&pls->pl_name, 0, PL_LNAMELEN);
+	else {
+		KASSERT(strlen(l->l_name) < PL_LNAMELEN);
+		strncpy(pls->pl_name, l->l_name, PL_LNAMELEN);
+	}
+
+#ifdef PTRACE_LWP_GETPRIVATE
+	pls->pl_private = PTRACE_LWP_GETPRIVATE(l);
+#else
+	pls->pl_private = l->l_private;
+#endif
+}
+
+void
+process_read_lwpstatus(struct lwp *l, struct ptrace_lwpstatus *pls)
+{
+
+	pls->pl_lwpid = l->l_lid;
+
+	ptrace_read_lwpstatus(l, pls);
+}
+
+static int
+ptrace_lwpstatus(struct proc *t, struct ptrace_methods *ptm, struct lwp **lt,
+    void *addr, size_t data, bool next)
+{
+	struct ptrace_lwpstatus pls;
+	struct lwp *l;
+	int error;
+
+	if (data > sizeof(pls) || data < sizeof(lwpid_t)) {
+		DPRINTF(("%s: invalid data: %zu < %zu < %zu\n",
+		        __func__, sizeof(lwpid_t), data, sizeof(pls)));
+		return EINVAL;
+	}
+	error = copyin(addr, &pls, sizeof(lwpid_t));
+	if (error)
+		return error;
+
+	if (next) {
+		lwp_delref(*lt);
+		lwpid_t tmp = pls.pl_lwpid;
+		mutex_enter(t->p_lock);
+		if (tmp == 0)
+			*lt = lwp_find_first(t);
+		else {
+			*lt = lwp_find(t, tmp);
+			if (*lt == NULL) {
+				mutex_exit(t->p_lock);
+				return ESRCH;
+			}
+			*lt = LIST_NEXT(*lt, l_sibling);
+		}
+
+		while (*lt != NULL && !lwp_alive(*lt) &&
+		       ((*lt)->l_flag & LW_SYSTEM) != 0)
+			*lt = LIST_NEXT(*lt, l_sibling);
+
+		if (*lt == NULL) {
+			memset(&pls, 0, sizeof(pls));
+			mutex_exit(t->p_lock);
+			goto out;
+		}
+		lwp_addref(*lt);
+		mutex_exit(t->p_lock);
+
+		pls.pl_lwpid = (*lt)->l_lid;
+	} else {
+		if ((error = ptrace_update_lwp(t, lt, pls.pl_lwpid)) != 0)
+			return error;
+	}
+
+	l = *lt;
+
+	ptrace_read_lwpstatus(l, &pls);
+
+out:
+	DPRINTF(("%s: lwp=%d sigpend=%02x%02x%02x%02x sigmask=%02x%02x%02x%02x "
+	   "name='%s' private=%p\n", __func__, pls.pl_lwpid,
+	    pls.pl_sigpend.__bits[0], pls.pl_sigpend.__bits[1],
+	    pls.pl_sigpend.__bits[2], pls.pl_sigpend.__bits[3],
+	    pls.pl_sigmask.__bits[0], pls.pl_sigmask.__bits[1],
+	    pls.pl_sigmask.__bits[2], pls.pl_sigmask.__bits[3],
+	    pls.pl_name, pls.pl_private));
+
+	return ptm->ptm_copyout_lwpstatus(&pls, addr, data);
+}
+
 static int
 ptrace_startstop(struct proc *t, struct lwp **lt, int rq, void *addr,
     size_t data)
@@ -1419,6 +1521,14 @@ do_ptrace(struct ptrace_methods *ptm, st
 		error = ptrace_startstop(t, &lt, req, addr, data);
 		break;
 
+	case PT_LWPSTATUS:
+		error = ptrace_lwpstatus(t, ptm, &lt, addr, data, false);
+		break;
+
+	case PT_LWPNEXT:
+		error = ptrace_lwpstatus(t, ptm, &lt, addr, data, true);
+		break;
+
 #ifdef PT_REGISTERS
 	case_PT_SETREGS
 	case_PT_GETREGS

Index: src/sys/sys/ptrace.h
diff -u src/sys/sys/ptrace.h:1.67 src/sys/sys/ptrace.h:1.68
--- src/sys/sys/ptrace.h:1.67	Wed Dec  4 13:52:27 2019
+++ src/sys/sys/ptrace.h	Tue Dec 24 14:50:59 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: ptrace.h,v 1.67 2019/12/04 13:52:27 kamil Exp $	*/
+/*	$NetBSD: ptrace.h,v 1.68 2019/12/24 14:50:59 kamil Exp $	*/
 
 /*-
  * Copyright (c) 1984, 1993
@@ -35,6 +35,7 @@
 #define	_SYS_PTRACE_H_
 
 #include <sys/siginfo.h>
+#include <sys/signal.h>
 
 #define	PT_TRACE_ME		0	/* child declares it's being traced */
 #define	PT_READ_I		1	/* read word in child's I space */
@@ -47,7 +48,9 @@
 #define	PT_DETACH		10	/* detach from running process */
 #define	PT_IO			11	/* do I/O to/from the stopped process */
 #define	PT_DUMPCORE		12	/* make child generate a core dump */
-#define	PT_LWPINFO		13	/* get info about the LWP */
+#if defined(__LEGACY_PT_LWPINFO) || defined(_KERNEL)
+#define	PT_LWPINFO		13	/* OBSOLETE: get info about the LWP */
+#endif
 #define	PT_SYSCALL		14	/* stop on syscall entry/exit */
 #define	PT_SYSCALLEMU		15	/* cancel syscall, tracer emulates it */
 #define	PT_SET_EVENT_MASK	16	/* set the event mask, defined below */
@@ -58,6 +61,8 @@
 #define	PT_RESUME		21	/* allow execution of the LWP */
 #define	PT_SUSPEND		22	/* prevent execution of the LWP */
 #define	PT_STOP			23	/* stop the child process */
+#define	PT_LWPSTATUS		24	/* get info about the LWP */
+#define	PT_LWPNEXT		25	/* get info about next LWP */
 
 #define	PT_FIRSTMACH		32	/* for machine-specific requests */
 #include <machine/ptrace.h>		/* machine-specific requests, if any */
@@ -86,7 +91,9 @@
 /* 20 */    "PT_GET_SIGINFO", \
 /* 21 */    "PT_RESUME", \
 /* 22 */    "PT_SUSPEND", \
-/* 23 */    "PT_STOP",
+/* 23 */    "PT_STOP", \
+/* 24 */    "PT_LWPSTATUS", \
+/* 25 */    "PT_LWPNEXT"
 
 /* PT_{G,S}EVENT_MASK */
 typedef struct ptrace_event {
@@ -129,18 +136,36 @@ struct ptrace_io_desc {
 #define	PIOD_WRITE_I	4	/* write to I space */
 #define PIOD_READ_AUXV	5	/* Read from aux array */
 
+#if defined(__LEGACY_PT_LWPINFO) || defined(_KERNEL)
 /*
  * Argument structure for PT_LWPINFO.
+ *
+ * DEPRECATED: Use ptrace_lwpstatus.
  */
 struct ptrace_lwpinfo {
 	lwpid_t	pl_lwpid;	/* LWP described */
 	int	pl_event;	/* Event that stopped the LWP */
-	/* Add fields at the end */
 };
 
 #define PL_EVENT_NONE		0
 #define PL_EVENT_SIGNAL		1
 #define PL_EVENT_SUSPENDED	2
+#endif
+
+/*
+ * Argument structure for PT_LWPSTATUS.
+ */
+
+#define PL_LNAMELEN	20	/* extra 4 for alignment */
+
+struct ptrace_lwpstatus {
+	lwpid_t		pl_lwpid;		/* LWP described */
+	sigset_t	pl_sigpend;		/* LWP signals pending */
+	sigset_t	pl_sigmask;		/* LWP signal mask */
+	char		pl_name[PL_LNAMELEN];	/* LWP name, may be empty */
+	void		*pl_private;		/* LWP private data */
+	/* Add fields at the end */
+};
 
 /*
  * Signal Information structure
@@ -154,6 +179,23 @@ typedef struct ptrace_siginfo {
 
 #ifdef _KERNEL
 
+#ifdef _KERNEL_OPT
+#include "opt_compat_netbsd32.h"
+#endif
+
+#ifdef COMPAT_NETBSD32
+#include <compat/netbsd32/netbsd32.h>
+#define process_read_lwpstatus32	netbsd32_read_lwpstatus
+#define process_lwpstatus32		struct netbsd32_ptrace_lwpstatus
+#endif
+
+#ifndef process_lwpstatus32
+#define process_lwpstatus32 struct ptrace_lwpstatus
+#endif
+#ifndef process_lwpstatus64
+#define process_lwpstatus64 struct ptrace_lwpstatus
+#endif
+
 #if defined(PT_GETREGS) || defined(PT_SETREGS)
 struct reg;
 #ifndef process_reg32
@@ -189,6 +231,7 @@ struct ptrace_methods {
 	int (*ptm_copyout_piod)(const struct ptrace_io_desc *, void *, size_t);
 	int (*ptm_copyin_siginfo)(struct ptrace_siginfo *, const void *, size_t);
 	int (*ptm_copyout_siginfo)(const struct ptrace_siginfo *, void *, size_t);
+	int (*ptm_copyout_lwpstatus)(const struct ptrace_lwpstatus *, void *, size_t);
 	int (*ptm_doregs)(struct lwp *, struct lwp *, struct uio *);
 	int (*ptm_dofpregs)(struct lwp *, struct lwp *, struct uio *);
 	int (*ptm_dodbregs)(struct lwp *, struct lwp *, struct uio *);
@@ -217,11 +260,20 @@ void	proc_changeparent(struct proc *, st
 int	do_ptrace(struct ptrace_methods *, struct lwp *, int, pid_t, void *,
 	    int, register_t *);
 
+void	process_read_lwpstatus(struct lwp *, struct ptrace_lwpstatus *);
+#ifndef process_read_lwpstatus32
+#define process_read_lwpstatus32 process_read_lwpstatus
+#endif
+#ifndef process_read_lwpstatus64
+#define process_read_lwpstatus64 process_read_lwpstatus
+#endif
+
 /*
  * 64bit architectures that support 32bit emulation (amd64 and sparc64)
  * will #define process_read_regs32 to netbsd32_process_read_regs (etc).
  * In all other cases these #defines drop the size suffix.
  */
+
 #ifdef PT_GETDBREGS
 int	process_read_dbregs(struct lwp *, struct dbreg *, size_t *);
 #ifndef process_read_dbregs32

Index: src/tests/lib/libc/sys/t_ptrace_wait.c
diff -u src/tests/lib/libc/sys/t_ptrace_wait.c:1.142 src/tests/lib/libc/sys/t_ptrace_wait.c:1.143
--- src/tests/lib/libc/sys/t_ptrace_wait.c:1.142	Fri Dec  6 01:09:50 2019
+++ src/tests/lib/libc/sys/t_ptrace_wait.c	Tue Dec 24 14:50:59 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: t_ptrace_wait.c,v 1.142 2019/12/06 01:09:50 kamil Exp $	*/
+/*	$NetBSD: t_ptrace_wait.c,v 1.143 2019/12/24 14:50:59 kamil Exp $	*/
 
 /*-
  * Copyright (c) 2016, 2017, 2018, 2019 The NetBSD Foundation, Inc.
@@ -27,7 +27,9 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: t_ptrace_wait.c,v 1.142 2019/12/06 01:09:50 kamil Exp $");
+__RCSID("$NetBSD: t_ptrace_wait.c,v 1.143 2019/12/24 14:50:59 kamil Exp $");
+
+#define __LEGACY_PT_LWPINFO
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -4801,8 +4803,52 @@ PTRACE_KILL(kill3, "killpg(SIGKILL)")
 
 /// ----------------------------------------------------------------------------
 
+static void *
+get_private(void)
+{
+
+#ifdef __HAVE___LWP_GETTCB_FAST
+	return __lwp_gettcb_fast();
+#elif defined(__HAVE___LWP_GETPRIVATE_FAST)
+	return __lwp_getprivate_fast();
+#else
+#error Unknown code path!
+#endif
+}
+
+static int lwpinfo_thread_sigmask[] = {SIGXCPU, SIGPIPE, SIGALRM, SIGURG};
+
+static pthread_mutex_t lwpinfo_thread_mtx = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t lwpinfo_thread_cnd = PTHREAD_COND_INITIALIZER;
+static volatile size_t lwpinfo_thread_done;
+
+static void *
+lwpinfo_thread(void *arg)
+{
+	sigset_t s;
+	volatile void **tcb;
+
+	tcb = (volatile void **)arg;
+
+	*tcb = get_private();
+	DPRINTF("Storing tcb[] = %p from thread %d\n", *tcb, _lwp_self());
+
+	pthread_setname_np(pthread_self(), "thread %d",
+	    (void *)(intptr_t)_lwp_self());
+
+	sigemptyset(&s);
+	pthread_mutex_lock(&lwpinfo_thread_mtx);
+	sigaddset(&s, lwpinfo_thread_sigmask[lwpinfo_thread_done]);
+	lwpinfo_thread_done++;
+	pthread_sigmask(SIG_BLOCK, &s, NULL);
+	pthread_cond_signal(&lwpinfo_thread_cnd);
+	pthread_mutex_unlock(&lwpinfo_thread_mtx);
+
+	return infinite_thread(NULL);
+}
+
 static void
-traceme_lwpinfo(const int threads)
+traceme_lwpinfo(const size_t threads, const char *iter)
 {
 	const int sigval = SIGSTOP;
 	const int sigval2 = SIGINT;
@@ -4811,13 +4857,26 @@ traceme_lwpinfo(const int threads)
 	int status;
 #endif
 	struct ptrace_lwpinfo lwp = {0, 0};
+	struct ptrace_lwpstatus lwpstatus = {0};
 	struct ptrace_siginfo info;
+	void *private;
+	char *name;
+	char namebuf[PL_LNAMELEN];
+	volatile void *tcb[4];
+	bool found;
+	sigset_t s;
 
 	/* Maximum number of supported threads in this test */
-	pthread_t t[3];
-	int n, rv;
+	pthread_t t[__arraycount(tcb) - 1];
+	size_t n, m;
+	int rv;
+	size_t bytes_read;
 
-	ATF_REQUIRE((int)__arraycount(t) >= threads);
+	struct ptrace_io_desc io;
+	sigset_t sigmask;
+
+	ATF_REQUIRE(__arraycount(t) >= threads);
+	memset(tcb, 0, sizeof(tcb));
 
 	DPRINTF("Before forking process PID=%d\n", getpid());
 	SYSCALL_REQUIRE((child = fork()) != -1);
@@ -4825,14 +4884,32 @@ traceme_lwpinfo(const int threads)
 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
 
+		tcb[0] = get_private();
+		DPRINTF("Storing tcb[0] = %p\n", tcb[0]);
+
+		pthread_setname_np(pthread_self(), "thread %d",
+		    (void *)(intptr_t)_lwp_self());
+
+		sigemptyset(&s);
+		sigaddset(&s, lwpinfo_thread_sigmask[lwpinfo_thread_done]);
+		pthread_sigmask(SIG_BLOCK, &s, NULL);
+
 		DPRINTF("Before raising %s from child\n", strsignal(sigval));
 		FORKEE_ASSERT(raise(sigval) == 0);
 
 		for (n = 0; n < threads; n++) {
-			rv = pthread_create(&t[n], NULL, infinite_thread, NULL);
+			rv = pthread_create(&t[n], NULL, lwpinfo_thread,
+			    &tcb[n + 1]);
 			FORKEE_ASSERT(rv == 0);
 		}
 
+		pthread_mutex_lock(&lwpinfo_thread_mtx);
+		while (lwpinfo_thread_done < threads) {
+			pthread_cond_wait(&lwpinfo_thread_cnd,
+			    &lwpinfo_thread_mtx);
+		}
+		pthread_mutex_unlock(&lwpinfo_thread_mtx);
+
 		DPRINTF("Before raising %s from child\n", strsignal(sigval2));
 		FORKEE_ASSERT(raise(sigval2) == 0);
 
@@ -4858,21 +4935,47 @@ traceme_lwpinfo(const int threads)
 	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
 	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
 
-	DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
-	SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
+	if (strstr(iter, "LWPINFO") != NULL) {
+		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
+		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
+		    != -1);
 
-	DPRINTF("Assert that there exists a single thread only\n");
-	ATF_REQUIRE(lwp.pl_lwpid > 0);
+		DPRINTF("Assert that there exists a single thread only\n");
+		ATF_REQUIRE(lwp.pl_lwpid > 0);
 
-	DPRINTF("Assert that lwp thread %d received event PL_EVENT_SIGNAL\n",
-	    lwp.pl_lwpid);
-	FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
+		DPRINTF("Assert that lwp thread %d received event "
+		    "PL_EVENT_SIGNAL\n", lwp.pl_lwpid);
+		FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
+
+		if (strstr(iter, "LWPSTATUS") != NULL) {
+			DPRINTF("Before calling ptrace(2) with PT_LWPSTATUS "
+			    "for child\n");
+			lwpstatus.pl_lwpid = lwp.pl_lwpid;
+			SYSCALL_REQUIRE(ptrace(PT_LWPSTATUS, child, &lwpstatus,
+			    sizeof(lwpstatus)) != -1);
+		}
 
-	DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
-	SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
+		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
+		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
+		    != -1);
 
-	DPRINTF("Assert that there exists a single thread only\n");
-	ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
+		DPRINTF("Assert that there exists a single thread only\n");
+		ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
+	} else {
+		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
+		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
+		    sizeof(lwpstatus)) != -1);
+
+		DPRINTF("Assert that there exists a single thread only %d\n", lwpstatus.pl_lwpid);
+		ATF_REQUIRE(lwpstatus.pl_lwpid > 0);
+
+		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
+		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
+		    sizeof(lwpstatus)) != -1);
+
+		DPRINTF("Assert that there exists a single thread only\n");
+		ATF_REQUIRE_EQ(lwpstatus.pl_lwpid, 0);
+	}
 
 	DPRINTF("Before resuming the child process where it left off and "
 	    "without signal to be sent\n");
@@ -4896,26 +4999,131 @@ traceme_lwpinfo(const int threads)
 	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
 
 	memset(&lwp, 0, sizeof(lwp));
+	memset(&lwpstatus, 0, sizeof(lwpstatus));
+
+	memset(&io, 0, sizeof(io));
+
+	bytes_read = 0;
+	io.piod_op = PIOD_READ_D;
+	io.piod_len = sizeof(tcb);
+
+	do {
+		io.piod_addr = (char *)&tcb + bytes_read;
+		io.piod_offs = io.piod_addr;
+
+		rv = ptrace(PT_IO, child, &io, sizeof(io));
+		ATF_REQUIRE(rv != -1 && io.piod_len != 0);
+
+		bytes_read += io.piod_len;
+		io.piod_len = sizeof(tcb) - bytes_read;
+	} while (bytes_read < sizeof(tcb));
 
 	for (n = 0; n <= threads; n++) {
-		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
-		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
-		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
+		if (strstr(iter, "LWPINFO") != NULL) {
+			DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
+			    "child\n");
+			SYSCALL_REQUIRE(
+			    ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
+			DPRINTF("LWP=%d\n", lwp.pl_lwpid);
 
-		DPRINTF("Assert that the thread exists\n");
-		ATF_REQUIRE(lwp.pl_lwpid > 0);
+			DPRINTF("Assert that the thread exists\n");
+			ATF_REQUIRE(lwp.pl_lwpid > 0);
 
-		DPRINTF("Assert that lwp thread %d received expected event\n",
-		    lwp.pl_lwpid);
-		FORKEE_ASSERT_EQ(lwp.pl_event, info.psi_lwpid == lwp.pl_lwpid ?
-		    PL_EVENT_SIGNAL : PL_EVENT_NONE);
-	}
-	DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
-	SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
-	DPRINTF("LWP=%d\n", lwp.pl_lwpid);
+			DPRINTF("Assert that lwp thread %d received expected "
+			    "event\n", lwp.pl_lwpid);
+			FORKEE_ASSERT_EQ(lwp.pl_event,
+			    info.psi_lwpid == lwp.pl_lwpid ?
+			    PL_EVENT_SIGNAL : PL_EVENT_NONE);
 
-	DPRINTF("Assert that there are no more threads\n");
-	ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
+			if (strstr(iter, "LWPSTATUS") != NULL) {
+				DPRINTF("Before calling ptrace(2) with "
+				    "PT_LWPSTATUS for child\n");
+				lwpstatus.pl_lwpid = lwp.pl_lwpid;
+				SYSCALL_REQUIRE(ptrace(PT_LWPSTATUS, child,
+				    &lwpstatus, sizeof(lwpstatus)) != -1);
+
+				goto check_lwpstatus;
+			}
+		} else {
+			DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for "
+			    "child\n");
+			SYSCALL_REQUIRE(
+			    ptrace(PT_LWPNEXT, child, &lwpstatus,
+			    sizeof(lwpstatus)) != -1);
+			DPRINTF("LWP=%d\n", lwpstatus.pl_lwpid);
+
+			DPRINTF("Assert that the thread exists\n");
+			ATF_REQUIRE(lwpstatus.pl_lwpid > 0);
+
+		check_lwpstatus:
+
+			if (strstr(iter, "pl_sigmask") != NULL) {
+				sigmask = lwpstatus.pl_sigmask;
+
+				DPRINTF("Retrieved sigmask: "
+				    "%02x%02x%02x%02x\n",
+				    sigmask.__bits[0], sigmask.__bits[1],
+				    sigmask.__bits[2], sigmask.__bits[3]);
+
+				found = false;
+				for (m = 0;
+				     m < __arraycount(lwpinfo_thread_sigmask);
+				     m++) {
+					if (sigismember(&sigmask,
+					    lwpinfo_thread_sigmask[m])) {
+						found = true;
+						lwpinfo_thread_sigmask[m] = 0;
+						break;
+					}
+				}
+				ATF_REQUIRE(found == true);
+			} else if (strstr(iter, "pl_name") != NULL) {
+				name = lwpstatus.pl_name;
+
+				DPRINTF("Retrieved thread name: "
+				    "%s\n", name);
+
+				snprintf(namebuf, sizeof namebuf, "thread %d",
+				    lwpstatus.pl_lwpid);
+
+				ATF_REQUIRE(strcmp(name, namebuf) == 0);
+			} else if (strstr(iter, "pl_private") != NULL) {
+				private = lwpstatus.pl_private;
+
+				DPRINTF("Retrieved thread private pointer: "
+				    "%p\n", private);
+
+				found = false;
+				for (m = 0; m < __arraycount(tcb); m++) {
+					DPRINTF("Comparing %p and %p\n",
+					    private, tcb[m]);
+					if (private == tcb[m]) {
+						found = true;
+						break;
+					}
+				}
+				ATF_REQUIRE(found == true);
+			}
+		}
+	}
+
+	if (strstr(iter, "LWPINFO") != NULL) {
+		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
+		    "child\n");
+		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
+		    != -1);
+		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
+
+		DPRINTF("Assert that there are no more threads\n");
+		ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
+	} else {
+		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
+		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
+		    sizeof(lwpstatus)) != -1);
+
+		DPRINTF("Assert that there exists a single thread only\n");
+		ATF_REQUIRE_EQ(lwpstatus.pl_lwpid, 0);
+	}
 
 	DPRINTF("Before resuming the child process where it left off and "
 	    "without signal to be sent\n");
@@ -4930,25 +5138,77 @@ traceme_lwpinfo(const int threads)
 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
 }
 
-#define TRACEME_LWPINFO(test, threads)					\
+#define TRACEME_LWPINFO(test, threads, iter)				\
 ATF_TC(test);								\
 ATF_TC_HEAD(test, tc)							\
 {									\
 	atf_tc_set_md_var(tc, "descr",					\
-	    "Verify LWPINFO with the child with " #threads		\
+	    "Verify " iter " with the child with " #threads		\
 	    " spawned extra threads");					\
 }									\
 									\
 ATF_TC_BODY(test, tc)							\
 {									\
 									\
-	traceme_lwpinfo(threads);					\
+	traceme_lwpinfo(threads, iter);					\
 }
 
-TRACEME_LWPINFO(traceme_lwpinfo0, 0)
-TRACEME_LWPINFO(traceme_lwpinfo1, 1)
-TRACEME_LWPINFO(traceme_lwpinfo2, 2)
-TRACEME_LWPINFO(traceme_lwpinfo3, 3)
+TRACEME_LWPINFO(traceme_lwpinfo0, 0, "LWPINFO")
+TRACEME_LWPINFO(traceme_lwpinfo1, 1, "LWPINFO")
+TRACEME_LWPINFO(traceme_lwpinfo2, 2, "LWPINFO")
+TRACEME_LWPINFO(traceme_lwpinfo3, 3, "LWPINFO")
+
+TRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus, 0, "LWPINFO+LWPSTATUS")
+TRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus, 1, "LWPINFO+LWPSTATUS")
+TRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus, 2, "LWPINFO+LWPSTATUS")
+TRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus, 3, "LWPINFO+LWPSTATUS")
+
+TRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_sigmask, 0,
+    "LWPINFO+LWPSTATUS+pl_sigmask")
+TRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_sigmask, 1,
+    "LWPINFO+LWPSTATUS+pl_sigmask")
+TRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_sigmask, 2,
+    "LWPINFO+LWPSTATUS+pl_sigmask")
+TRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_sigmask, 3,
+    "LWPINFO+LWPSTATUS+pl_sigmask")
+
+TRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_name, 0,
+    "LWPINFO+LWPSTATUS+pl_name")
+TRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_name, 1,
+    "LWPINFO+LWPSTATUS+pl_name")
+TRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_name, 2,
+    "LWPINFO+LWPSTATUS+pl_name")
+TRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_name, 3,
+    "LWPINFO+LWPSTATUS+pl_name")
+
+TRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_private, 0,
+    "LWPINFO+LWPSTATUS+pl_private")
+TRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_private, 1,
+    "LWPINFO+LWPSTATUS+pl_private")
+TRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_private, 2,
+    "LWPINFO+LWPSTATUS+pl_private")
+TRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_private, 3,
+    "LWPINFO+LWPSTATUS+pl_private")
+
+TRACEME_LWPINFO(traceme_lwpnext0, 0, "LWPNEXT")
+TRACEME_LWPINFO(traceme_lwpnext1, 1, "LWPNEXT")
+TRACEME_LWPINFO(traceme_lwpnext2, 2, "LWPNEXT")
+TRACEME_LWPINFO(traceme_lwpnext3, 3, "LWPNEXT")
+
+TRACEME_LWPINFO(traceme_lwpnext0_pl_sigmask, 0, "LWPNEXT+pl_sigmask")
+TRACEME_LWPINFO(traceme_lwpnext1_pl_sigmask, 1, "LWPNEXT+pl_sigmask")
+TRACEME_LWPINFO(traceme_lwpnext2_pl_sigmask, 2, "LWPNEXT+pl_sigmask")
+TRACEME_LWPINFO(traceme_lwpnext3_pl_sigmask, 3, "LWPNEXT+pl_sigmask")
+
+TRACEME_LWPINFO(traceme_lwpnext0_pl_name, 0, "LWPNEXT+pl_name")
+TRACEME_LWPINFO(traceme_lwpnext1_pl_name, 1, "LWPNEXT+pl_name")
+TRACEME_LWPINFO(traceme_lwpnext2_pl_name, 2, "LWPNEXT+pl_name")
+TRACEME_LWPINFO(traceme_lwpnext3_pl_name, 3, "LWPNEXT+pl_name")
+
+TRACEME_LWPINFO(traceme_lwpnext0_pl_private, 0, "LWPNEXT+pl_private")
+TRACEME_LWPINFO(traceme_lwpnext1_pl_private, 1, "LWPNEXT+pl_private")
+TRACEME_LWPINFO(traceme_lwpnext2_pl_private, 2, "LWPNEXT+pl_private")
+TRACEME_LWPINFO(traceme_lwpnext3_pl_private, 3, "LWPNEXT+pl_private")
 
 /// ----------------------------------------------------------------------------
 
@@ -8192,6 +8452,46 @@ ATF_TP_ADD_TCS(tp)
 	ATF_TP_ADD_TC(tp, traceme_lwpinfo2);
 	ATF_TP_ADD_TC(tp, traceme_lwpinfo3);
 
+	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus);
+	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus);
+	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus);
+	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus);
+
+	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_sigmask);
+	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_sigmask);
+	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_sigmask);
+	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_sigmask);
+
+	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_name);
+	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_name);
+	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_name);
+	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_name);
+
+	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_private);
+	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_private);
+	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_private);
+	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_private);
+
+	ATF_TP_ADD_TC(tp, traceme_lwpnext0);
+	ATF_TP_ADD_TC(tp, traceme_lwpnext1);
+	ATF_TP_ADD_TC(tp, traceme_lwpnext2);
+	ATF_TP_ADD_TC(tp, traceme_lwpnext3);
+
+	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_sigmask);
+	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_sigmask);
+	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_sigmask);
+	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_sigmask);
+
+	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_name);
+	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_name);
+	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_name);
+	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_name);
+
+	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_private);
+	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_private);
+	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_private);
+	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_private);
+
 	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo0);
 	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo1);
 	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo2);

Reply via email to