xref: /netbsd-src/sys/kern/sys_process_lwpstatus.c (revision 5b38d912c8c95969e4667aadbd354225a2eb73b0)
1*5b38d912Schristos /*	$NetBSD: sys_process_lwpstatus.c,v 1.5 2025/01/11 19:42:04 christos Exp $	*/
271b1583fSkamil 
371b1583fSkamil /*-
471b1583fSkamil  * Copyright (c) 2019 The NetBSD Foundation, Inc.
571b1583fSkamil  * All rights reserved.
671b1583fSkamil  *
771b1583fSkamil  * Redistribution and use in source and binary forms, with or without
871b1583fSkamil  * modification, are permitted provided that the following conditions
971b1583fSkamil  * are met:
1071b1583fSkamil  * 1. Redistributions of source code must retain the above copyright
1171b1583fSkamil  *    notice, this list of conditions and the following disclaimer.
1271b1583fSkamil  * 2. Redistributions in binary form must reproduce the above copyright
1371b1583fSkamil  *    notice, this list of conditions and the following disclaimer in the
1471b1583fSkamil  *    documentation and/or other materials provided with the distribution.
1571b1583fSkamil  *
1671b1583fSkamil  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1771b1583fSkamil  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1871b1583fSkamil  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1971b1583fSkamil  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2071b1583fSkamil  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2171b1583fSkamil  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2271b1583fSkamil  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2371b1583fSkamil  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2471b1583fSkamil  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2571b1583fSkamil  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2671b1583fSkamil  * POSSIBILITY OF SUCH DAMAGE.
2771b1583fSkamil  */
2871b1583fSkamil 
2971b1583fSkamil #include <sys/cdefs.h>
30*5b38d912Schristos __KERNEL_RCSID(0, "$NetBSD: sys_process_lwpstatus.c,v 1.5 2025/01/11 19:42:04 christos Exp $");
31eeb74127Schristos 
32eeb74127Schristos #ifdef _KERNEL_OPT
33eeb74127Schristos #include "opt_ptrace.h"
34eeb74127Schristos #include "opt_ktrace.h"
35eeb74127Schristos #include "opt_pax.h"
36eeb74127Schristos #include "opt_compat_netbsd32.h"
37eeb74127Schristos #endif
38eeb74127Schristos 
39eeb74127Schristos #if defined(__HAVE_COMPAT_NETBSD32) && !defined(COMPAT_NETBSD32) \
40eeb74127Schristos     && !defined(_RUMPKERNEL)
41eeb74127Schristos #define COMPAT_NETBSD32
42eeb74127Schristos #endif
4371b1583fSkamil 
4471b1583fSkamil #include <sys/param.h>
4571b1583fSkamil #include <sys/systm.h>
4671b1583fSkamil #include <sys/errno.h>
4771b1583fSkamil #include <sys/lwp.h>
48866172b2Srin #include <sys/proc.h>
4971b1583fSkamil #include <sys/ptrace.h>
5071b1583fSkamil 
51eeb74127Schristos #ifndef PTRACE_REGS_ALIGN
52eeb74127Schristos #define PTRACE_REGS_ALIGN /* nothing */
53eeb74127Schristos #endif
5471b1583fSkamil 
5571b1583fSkamil void
5671b1583fSkamil ptrace_read_lwpstatus(struct lwp *l, struct ptrace_lwpstatus *pls)
5771b1583fSkamil {
5871b1583fSkamil 
59143b452aSriastradh 	pls->pl_lwpid = l->l_lid;
6071b1583fSkamil 	memcpy(&pls->pl_sigmask, &l->l_sigmask, sizeof(pls->pl_sigmask));
6171b1583fSkamil 	memcpy(&pls->pl_sigpend, &l->l_sigpend.sp_set, sizeof(pls->pl_sigpend));
6271b1583fSkamil 
6371b1583fSkamil 	if (l->l_name == NULL)
6471b1583fSkamil 		memset(&pls->pl_name, 0, PL_LNAMELEN);
6571b1583fSkamil 	else {
6671b1583fSkamil 		KASSERT(strlen(l->l_name) < PL_LNAMELEN);
6771b1583fSkamil 		strncpy(pls->pl_name, l->l_name, PL_LNAMELEN);
6871b1583fSkamil 	}
6971b1583fSkamil 
7071b1583fSkamil #ifdef PTRACE_LWP_GETPRIVATE
7171b1583fSkamil 	pls->pl_private = (void *)(intptr_t)PTRACE_LWP_GETPRIVATE(l);
7271b1583fSkamil #else
7371b1583fSkamil 	pls->pl_private = l->l_private;
7471b1583fSkamil #endif
7571b1583fSkamil }
7671b1583fSkamil 
7771b1583fSkamil void
7871b1583fSkamil process_read_lwpstatus(struct lwp *l, struct ptrace_lwpstatus *pls)
7971b1583fSkamil {
8071b1583fSkamil 
8171b1583fSkamil 	ptrace_read_lwpstatus(l, pls);
8271b1583fSkamil }
83eeb74127Schristos 
84eeb74127Schristos int
85eeb74127Schristos ptrace_update_lwp(struct proc *t, struct lwp **lt, lwpid_t lid)
86eeb74127Schristos {
87eeb74127Schristos 	if (lid == 0 || lid == (*lt)->l_lid || t->p_nlwps == 1)
88eeb74127Schristos 		return 0;
89eeb74127Schristos 
90eeb74127Schristos 	mutex_enter(t->p_lock);
91eeb74127Schristos 	lwp_delref2(*lt);
92eeb74127Schristos 
93eeb74127Schristos 	*lt = lwp_find(t, lid);
94eeb74127Schristos 	if (*lt == NULL) {
95eeb74127Schristos 		mutex_exit(t->p_lock);
96eeb74127Schristos 		return ESRCH;
97eeb74127Schristos 	}
98eeb74127Schristos 
99eeb74127Schristos 	if ((*lt)->l_flag & LW_SYSTEM) {
100eeb74127Schristos 		mutex_exit(t->p_lock);
101eeb74127Schristos 		*lt = NULL;
102eeb74127Schristos 		return EINVAL;
103eeb74127Schristos 	}
104eeb74127Schristos 
105eeb74127Schristos 	lwp_addref(*lt);
106eeb74127Schristos 	mutex_exit(t->p_lock);
107eeb74127Schristos 
108eeb74127Schristos 	return 0;
109eeb74127Schristos }
110eeb74127Schristos 
111eeb74127Schristos int
112eeb74127Schristos process_validfpregs(struct lwp *l)
113eeb74127Schristos {
114eeb74127Schristos 
115*5b38d912Schristos #if defined(PT_FPREGS)
116eeb74127Schristos 	return (l->l_flag & LW_SYSTEM) == 0;
117eeb74127Schristos #else
118eeb74127Schristos 	return 0;
119eeb74127Schristos #endif
120eeb74127Schristos }
121eeb74127Schristos 
122eeb74127Schristos int
123eeb74127Schristos process_validregs(struct lwp *l)
124eeb74127Schristos {
125eeb74127Schristos 
126*5b38d912Schristos #if defined(PT_REGS)
127eeb74127Schristos 	return (l->l_flag & LW_SYSTEM) == 0;
128eeb74127Schristos #else
129eeb74127Schristos 	return 0;
130eeb74127Schristos #endif
131eeb74127Schristos }
132eeb74127Schristos 
133eeb74127Schristos int
134eeb74127Schristos process_validdbregs(struct lwp *l)
135eeb74127Schristos {
136eeb74127Schristos 
137*5b38d912Schristos #if defined(PT_DBREGS)
138eeb74127Schristos 	return (l->l_flag & LW_SYSTEM) == 0;
139eeb74127Schristos #else
140eeb74127Schristos 	return 0;
141eeb74127Schristos #endif
142eeb74127Schristos }
143eeb74127Schristos 
144eeb74127Schristos #ifdef PT_REGISTERS
145eeb74127Schristos static int
146eeb74127Schristos proc_regio(struct lwp *l, struct uio *uio, size_t ks, ptrace_regrfunc_t r,
147eeb74127Schristos     ptrace_regwfunc_t w)
148eeb74127Schristos {
149eeb74127Schristos 	char buf[1024] PTRACE_REGS_ALIGN;
150eeb74127Schristos 	int error;
151eeb74127Schristos 	char *kv;
152eeb74127Schristos 	size_t kl;
153eeb74127Schristos 
154eeb74127Schristos 	if (ks > sizeof(buf))
155eeb74127Schristos 		return E2BIG;
156eeb74127Schristos 
157eeb74127Schristos 	if (uio->uio_offset < 0 || uio->uio_offset > (off_t)ks)
158eeb74127Schristos 		return EINVAL;
159eeb74127Schristos 
160eeb74127Schristos 	kv = buf + uio->uio_offset;
161eeb74127Schristos 	kl = ks - uio->uio_offset;
162eeb74127Schristos 
163eeb74127Schristos 	if (kl > uio->uio_resid)
164eeb74127Schristos 		kl = uio->uio_resid;
165eeb74127Schristos 
166eeb74127Schristos 	error = (*r)(l, buf, &ks);
167eeb74127Schristos 	if (error == 0)
168eeb74127Schristos 		error = uiomove(kv, kl, uio);
169eeb74127Schristos 	if (error == 0 && uio->uio_rw == UIO_WRITE) {
170eeb74127Schristos 		if (l->l_stat != LSSTOP)
171eeb74127Schristos 			error = EBUSY;
172eeb74127Schristos 		else
173eeb74127Schristos 			error = (*w)(l, buf, ks);
174eeb74127Schristos 	}
175eeb74127Schristos 
176eeb74127Schristos 	uio->uio_offset = 0;
177eeb74127Schristos 	return error;
178eeb74127Schristos }
179eeb74127Schristos #endif
180eeb74127Schristos 
181eeb74127Schristos int
182eeb74127Schristos process_doregs(struct lwp *curl /*tracer*/,
183eeb74127Schristos     struct lwp *l /*traced*/,
184eeb74127Schristos     struct uio *uio)
185eeb74127Schristos {
186*5b38d912Schristos #if defined(PT_REGS)
187eeb74127Schristos 	size_t s;
188eeb74127Schristos 	ptrace_regrfunc_t r;
189eeb74127Schristos 	ptrace_regwfunc_t w;
190eeb74127Schristos 
191eeb74127Schristos #ifdef COMPAT_NETBSD32
192eeb74127Schristos 	const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0;
193eeb74127Schristos 
194eeb74127Schristos 	if (__predict_false(pk32)) {
195eeb74127Schristos 		if ((l->l_proc->p_flag & PK_32) == 0) {
196eeb74127Schristos 			// 32 bit tracer can't trace 64 bit process
197eeb74127Schristos 			return EINVAL;
198eeb74127Schristos 		}
199eeb74127Schristos 		s = sizeof(process_reg32);
200eeb74127Schristos 		r = __FPTRCAST(ptrace_regrfunc_t, process_read_regs32);
201eeb74127Schristos 		w = __FPTRCAST(ptrace_regwfunc_t, process_write_regs32);
202eeb74127Schristos 	} else
203eeb74127Schristos #endif
204eeb74127Schristos 	{
205eeb74127Schristos 		s = sizeof(struct reg);
206eeb74127Schristos 		r = __FPTRCAST(ptrace_regrfunc_t, process_read_regs);
207eeb74127Schristos 		w = __FPTRCAST(ptrace_regwfunc_t, process_write_regs);
208eeb74127Schristos 	}
209eeb74127Schristos 	return proc_regio(l, uio, s, r, w);
210eeb74127Schristos #else
211eeb74127Schristos 	return EINVAL;
212eeb74127Schristos #endif
213eeb74127Schristos }
214eeb74127Schristos 
215eeb74127Schristos int
216eeb74127Schristos process_dofpregs(struct lwp *curl /*tracer*/,
217eeb74127Schristos     struct lwp *l /*traced*/,
218eeb74127Schristos     struct uio *uio)
219eeb74127Schristos {
220*5b38d912Schristos #if defined(PT_FPREGS)
221eeb74127Schristos 	size_t s;
222eeb74127Schristos 	ptrace_regrfunc_t r;
223eeb74127Schristos 	ptrace_regwfunc_t w;
224eeb74127Schristos 
225eeb74127Schristos #ifdef COMPAT_NETBSD32
226eeb74127Schristos 	const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0;
227eeb74127Schristos 
228eeb74127Schristos 	if (__predict_false(pk32)) {
229eeb74127Schristos 		if ((l->l_proc->p_flag & PK_32) == 0) {
230eeb74127Schristos 			// 32 bit tracer can't trace 64 bit process
231eeb74127Schristos 			return EINVAL;
232eeb74127Schristos 		}
233eeb74127Schristos 		s = sizeof(process_fpreg32);
234eeb74127Schristos 		r = (ptrace_regrfunc_t)process_read_fpregs32;
235eeb74127Schristos 		w = (ptrace_regwfunc_t)process_write_fpregs32;
236eeb74127Schristos 	} else
237eeb74127Schristos #endif
238eeb74127Schristos 	{
239eeb74127Schristos 		s = sizeof(struct fpreg);
240eeb74127Schristos 		r = (ptrace_regrfunc_t)process_read_fpregs;
241eeb74127Schristos 		w = (ptrace_regwfunc_t)process_write_fpregs;
242eeb74127Schristos 	}
243eeb74127Schristos 	return proc_regio(l, uio, s, r, w);
244eeb74127Schristos #else
245eeb74127Schristos 	return EINVAL;
246eeb74127Schristos #endif
247eeb74127Schristos }
248eeb74127Schristos 
249eeb74127Schristos 
250eeb74127Schristos int
251eeb74127Schristos process_dodbregs(struct lwp *curl /*tracer*/,
252eeb74127Schristos     struct lwp *l /*traced*/,
253eeb74127Schristos     struct uio *uio)
254eeb74127Schristos {
255*5b38d912Schristos #if defined(PT_DBREGS)
256eeb74127Schristos 	size_t s;
257eeb74127Schristos 	ptrace_regrfunc_t r;
258eeb74127Schristos 	ptrace_regwfunc_t w;
259eeb74127Schristos 
260eeb74127Schristos #ifdef COMPAT_NETBSD32
261eeb74127Schristos 	const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0;
262eeb74127Schristos 
263eeb74127Schristos 	if (__predict_false(pk32)) {
264eeb74127Schristos 		if ((l->l_proc->p_flag & PK_32) == 0) {
265eeb74127Schristos 			// 32 bit tracer can't trace 64 bit process
266eeb74127Schristos 			return EINVAL;
267eeb74127Schristos 		}
268eeb74127Schristos 		s = sizeof(process_dbreg32);
269eeb74127Schristos 		r = (ptrace_regrfunc_t)process_read_dbregs32;
270eeb74127Schristos 		w = (ptrace_regwfunc_t)process_write_dbregs32;
271eeb74127Schristos 	} else
272eeb74127Schristos #endif
273eeb74127Schristos 	{
274eeb74127Schristos 		s = sizeof(struct dbreg);
275eeb74127Schristos 		r = (ptrace_regrfunc_t)process_read_dbregs;
276eeb74127Schristos 		w = (ptrace_regwfunc_t)process_write_dbregs;
277eeb74127Schristos 	}
278eeb74127Schristos 	return proc_regio(l, uio, s, r, w);
279eeb74127Schristos #else
280eeb74127Schristos 	return EINVAL;
281eeb74127Schristos #endif
282eeb74127Schristos }
283