Home | History | Annotate | Line # | Download | only in kern
      1  1.5  christos /*	$NetBSD: sys_process_lwpstatus.c,v 1.5 2025/01/11 19:42:04 christos Exp $	*/
      2  1.1     kamil 
      3  1.1     kamil /*-
      4  1.1     kamil  * Copyright (c) 2019 The NetBSD Foundation, Inc.
      5  1.1     kamil  * All rights reserved.
      6  1.1     kamil  *
      7  1.1     kamil  * Redistribution and use in source and binary forms, with or without
      8  1.1     kamil  * modification, are permitted provided that the following conditions
      9  1.1     kamil  * are met:
     10  1.1     kamil  * 1. Redistributions of source code must retain the above copyright
     11  1.1     kamil  *    notice, this list of conditions and the following disclaimer.
     12  1.1     kamil  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1     kamil  *    notice, this list of conditions and the following disclaimer in the
     14  1.1     kamil  *    documentation and/or other materials provided with the distribution.
     15  1.1     kamil  *
     16  1.1     kamil  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  1.1     kamil  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  1.1     kamil  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  1.1     kamil  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  1.1     kamil  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  1.1     kamil  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  1.1     kamil  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  1.1     kamil  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  1.1     kamil  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  1.1     kamil  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  1.1     kamil  * POSSIBILITY OF SUCH DAMAGE.
     27  1.1     kamil  */
     28  1.1     kamil 
     29  1.1     kamil #include <sys/cdefs.h>
     30  1.5  christos __KERNEL_RCSID(0, "$NetBSD: sys_process_lwpstatus.c,v 1.5 2025/01/11 19:42:04 christos Exp $");
     31  1.2  christos 
     32  1.2  christos #ifdef _KERNEL_OPT
     33  1.2  christos #include "opt_ptrace.h"
     34  1.2  christos #include "opt_ktrace.h"
     35  1.2  christos #include "opt_pax.h"
     36  1.2  christos #include "opt_compat_netbsd32.h"
     37  1.2  christos #endif
     38  1.2  christos 
     39  1.2  christos #if defined(__HAVE_COMPAT_NETBSD32) && !defined(COMPAT_NETBSD32) \
     40  1.2  christos     && !defined(_RUMPKERNEL)
     41  1.2  christos #define COMPAT_NETBSD32
     42  1.2  christos #endif
     43  1.1     kamil 
     44  1.1     kamil #include <sys/param.h>
     45  1.1     kamil #include <sys/systm.h>
     46  1.1     kamil #include <sys/errno.h>
     47  1.1     kamil #include <sys/lwp.h>
     48  1.3       rin #include <sys/proc.h>
     49  1.1     kamil #include <sys/ptrace.h>
     50  1.1     kamil 
     51  1.2  christos #ifndef PTRACE_REGS_ALIGN
     52  1.2  christos #define PTRACE_REGS_ALIGN /* nothing */
     53  1.2  christos #endif
     54  1.1     kamil 
     55  1.1     kamil void
     56  1.1     kamil ptrace_read_lwpstatus(struct lwp *l, struct ptrace_lwpstatus *pls)
     57  1.1     kamil {
     58  1.1     kamil 
     59  1.4  riastrad 	pls->pl_lwpid = l->l_lid;
     60  1.1     kamil 	memcpy(&pls->pl_sigmask, &l->l_sigmask, sizeof(pls->pl_sigmask));
     61  1.1     kamil 	memcpy(&pls->pl_sigpend, &l->l_sigpend.sp_set, sizeof(pls->pl_sigpend));
     62  1.1     kamil 
     63  1.1     kamil 	if (l->l_name == NULL)
     64  1.1     kamil 		memset(&pls->pl_name, 0, PL_LNAMELEN);
     65  1.1     kamil 	else {
     66  1.1     kamil 		KASSERT(strlen(l->l_name) < PL_LNAMELEN);
     67  1.1     kamil 		strncpy(pls->pl_name, l->l_name, PL_LNAMELEN);
     68  1.1     kamil 	}
     69  1.1     kamil 
     70  1.1     kamil #ifdef PTRACE_LWP_GETPRIVATE
     71  1.1     kamil 	pls->pl_private = (void *)(intptr_t)PTRACE_LWP_GETPRIVATE(l);
     72  1.1     kamil #else
     73  1.1     kamil 	pls->pl_private = l->l_private;
     74  1.1     kamil #endif
     75  1.1     kamil }
     76  1.1     kamil 
     77  1.1     kamil void
     78  1.1     kamil process_read_lwpstatus(struct lwp *l, struct ptrace_lwpstatus *pls)
     79  1.1     kamil {
     80  1.1     kamil 
     81  1.1     kamil 	ptrace_read_lwpstatus(l, pls);
     82  1.1     kamil }
     83  1.2  christos 
     84  1.2  christos int
     85  1.2  christos ptrace_update_lwp(struct proc *t, struct lwp **lt, lwpid_t lid)
     86  1.2  christos {
     87  1.2  christos 	if (lid == 0 || lid == (*lt)->l_lid || t->p_nlwps == 1)
     88  1.2  christos 		return 0;
     89  1.2  christos 
     90  1.2  christos 	mutex_enter(t->p_lock);
     91  1.2  christos 	lwp_delref2(*lt);
     92  1.2  christos 
     93  1.2  christos 	*lt = lwp_find(t, lid);
     94  1.2  christos 	if (*lt == NULL) {
     95  1.2  christos 		mutex_exit(t->p_lock);
     96  1.2  christos 		return ESRCH;
     97  1.2  christos 	}
     98  1.2  christos 
     99  1.2  christos 	if ((*lt)->l_flag & LW_SYSTEM) {
    100  1.2  christos 		mutex_exit(t->p_lock);
    101  1.2  christos 		*lt = NULL;
    102  1.2  christos 		return EINVAL;
    103  1.2  christos 	}
    104  1.2  christos 
    105  1.2  christos 	lwp_addref(*lt);
    106  1.2  christos 	mutex_exit(t->p_lock);
    107  1.2  christos 
    108  1.2  christos 	return 0;
    109  1.2  christos }
    110  1.2  christos 
    111  1.2  christos int
    112  1.2  christos process_validfpregs(struct lwp *l)
    113  1.2  christos {
    114  1.2  christos 
    115  1.5  christos #if defined(PT_FPREGS)
    116  1.2  christos 	return (l->l_flag & LW_SYSTEM) == 0;
    117  1.2  christos #else
    118  1.2  christos 	return 0;
    119  1.2  christos #endif
    120  1.2  christos }
    121  1.2  christos 
    122  1.2  christos int
    123  1.2  christos process_validregs(struct lwp *l)
    124  1.2  christos {
    125  1.2  christos 
    126  1.5  christos #if defined(PT_REGS)
    127  1.2  christos 	return (l->l_flag & LW_SYSTEM) == 0;
    128  1.2  christos #else
    129  1.2  christos 	return 0;
    130  1.2  christos #endif
    131  1.2  christos }
    132  1.2  christos 
    133  1.2  christos int
    134  1.2  christos process_validdbregs(struct lwp *l)
    135  1.2  christos {
    136  1.2  christos 
    137  1.5  christos #if defined(PT_DBREGS)
    138  1.2  christos 	return (l->l_flag & LW_SYSTEM) == 0;
    139  1.2  christos #else
    140  1.2  christos 	return 0;
    141  1.2  christos #endif
    142  1.2  christos }
    143  1.2  christos 
    144  1.2  christos #ifdef PT_REGISTERS
    145  1.2  christos static int
    146  1.2  christos proc_regio(struct lwp *l, struct uio *uio, size_t ks, ptrace_regrfunc_t r,
    147  1.2  christos     ptrace_regwfunc_t w)
    148  1.2  christos {
    149  1.2  christos 	char buf[1024] PTRACE_REGS_ALIGN;
    150  1.2  christos 	int error;
    151  1.2  christos 	char *kv;
    152  1.2  christos 	size_t kl;
    153  1.2  christos 
    154  1.2  christos 	if (ks > sizeof(buf))
    155  1.2  christos 		return E2BIG;
    156  1.2  christos 
    157  1.2  christos 	if (uio->uio_offset < 0 || uio->uio_offset > (off_t)ks)
    158  1.2  christos 		return EINVAL;
    159  1.2  christos 
    160  1.2  christos 	kv = buf + uio->uio_offset;
    161  1.2  christos 	kl = ks - uio->uio_offset;
    162  1.2  christos 
    163  1.2  christos 	if (kl > uio->uio_resid)
    164  1.2  christos 		kl = uio->uio_resid;
    165  1.2  christos 
    166  1.2  christos 	error = (*r)(l, buf, &ks);
    167  1.2  christos 	if (error == 0)
    168  1.2  christos 		error = uiomove(kv, kl, uio);
    169  1.2  christos 	if (error == 0 && uio->uio_rw == UIO_WRITE) {
    170  1.2  christos 		if (l->l_stat != LSSTOP)
    171  1.2  christos 			error = EBUSY;
    172  1.2  christos 		else
    173  1.2  christos 			error = (*w)(l, buf, ks);
    174  1.2  christos 	}
    175  1.2  christos 
    176  1.2  christos 	uio->uio_offset = 0;
    177  1.2  christos 	return error;
    178  1.2  christos }
    179  1.2  christos #endif
    180  1.2  christos 
    181  1.2  christos int
    182  1.2  christos process_doregs(struct lwp *curl /*tracer*/,
    183  1.2  christos     struct lwp *l /*traced*/,
    184  1.2  christos     struct uio *uio)
    185  1.2  christos {
    186  1.5  christos #if defined(PT_REGS)
    187  1.2  christos 	size_t s;
    188  1.2  christos 	ptrace_regrfunc_t r;
    189  1.2  christos 	ptrace_regwfunc_t w;
    190  1.2  christos 
    191  1.2  christos #ifdef COMPAT_NETBSD32
    192  1.2  christos 	const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0;
    193  1.2  christos 
    194  1.2  christos 	if (__predict_false(pk32)) {
    195  1.2  christos 		if ((l->l_proc->p_flag & PK_32) == 0) {
    196  1.2  christos 			// 32 bit tracer can't trace 64 bit process
    197  1.2  christos 			return EINVAL;
    198  1.2  christos 		}
    199  1.2  christos 		s = sizeof(process_reg32);
    200  1.2  christos 		r = __FPTRCAST(ptrace_regrfunc_t, process_read_regs32);
    201  1.2  christos 		w = __FPTRCAST(ptrace_regwfunc_t, process_write_regs32);
    202  1.2  christos 	} else
    203  1.2  christos #endif
    204  1.2  christos 	{
    205  1.2  christos 		s = sizeof(struct reg);
    206  1.2  christos 		r = __FPTRCAST(ptrace_regrfunc_t, process_read_regs);
    207  1.2  christos 		w = __FPTRCAST(ptrace_regwfunc_t, process_write_regs);
    208  1.2  christos 	}
    209  1.2  christos 	return proc_regio(l, uio, s, r, w);
    210  1.2  christos #else
    211  1.2  christos 	return EINVAL;
    212  1.2  christos #endif
    213  1.2  christos }
    214  1.2  christos 
    215  1.2  christos int
    216  1.2  christos process_dofpregs(struct lwp *curl /*tracer*/,
    217  1.2  christos     struct lwp *l /*traced*/,
    218  1.2  christos     struct uio *uio)
    219  1.2  christos {
    220  1.5  christos #if defined(PT_FPREGS)
    221  1.2  christos 	size_t s;
    222  1.2  christos 	ptrace_regrfunc_t r;
    223  1.2  christos 	ptrace_regwfunc_t w;
    224  1.2  christos 
    225  1.2  christos #ifdef COMPAT_NETBSD32
    226  1.2  christos 	const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0;
    227  1.2  christos 
    228  1.2  christos 	if (__predict_false(pk32)) {
    229  1.2  christos 		if ((l->l_proc->p_flag & PK_32) == 0) {
    230  1.2  christos 			// 32 bit tracer can't trace 64 bit process
    231  1.2  christos 			return EINVAL;
    232  1.2  christos 		}
    233  1.2  christos 		s = sizeof(process_fpreg32);
    234  1.2  christos 		r = (ptrace_regrfunc_t)process_read_fpregs32;
    235  1.2  christos 		w = (ptrace_regwfunc_t)process_write_fpregs32;
    236  1.2  christos 	} else
    237  1.2  christos #endif
    238  1.2  christos 	{
    239  1.2  christos 		s = sizeof(struct fpreg);
    240  1.2  christos 		r = (ptrace_regrfunc_t)process_read_fpregs;
    241  1.2  christos 		w = (ptrace_regwfunc_t)process_write_fpregs;
    242  1.2  christos 	}
    243  1.2  christos 	return proc_regio(l, uio, s, r, w);
    244  1.2  christos #else
    245  1.2  christos 	return EINVAL;
    246  1.2  christos #endif
    247  1.2  christos }
    248  1.2  christos 
    249  1.2  christos 
    250  1.2  christos int
    251  1.2  christos process_dodbregs(struct lwp *curl /*tracer*/,
    252  1.2  christos     struct lwp *l /*traced*/,
    253  1.2  christos     struct uio *uio)
    254  1.2  christos {
    255  1.5  christos #if defined(PT_DBREGS)
    256  1.2  christos 	size_t s;
    257  1.2  christos 	ptrace_regrfunc_t r;
    258  1.2  christos 	ptrace_regwfunc_t w;
    259  1.2  christos 
    260  1.2  christos #ifdef COMPAT_NETBSD32
    261  1.2  christos 	const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0;
    262  1.2  christos 
    263  1.2  christos 	if (__predict_false(pk32)) {
    264  1.2  christos 		if ((l->l_proc->p_flag & PK_32) == 0) {
    265  1.2  christos 			// 32 bit tracer can't trace 64 bit process
    266  1.2  christos 			return EINVAL;
    267  1.2  christos 		}
    268  1.2  christos 		s = sizeof(process_dbreg32);
    269  1.2  christos 		r = (ptrace_regrfunc_t)process_read_dbregs32;
    270  1.2  christos 		w = (ptrace_regwfunc_t)process_write_dbregs32;
    271  1.2  christos 	} else
    272  1.2  christos #endif
    273  1.2  christos 	{
    274  1.2  christos 		s = sizeof(struct dbreg);
    275  1.2  christos 		r = (ptrace_regrfunc_t)process_read_dbregs;
    276  1.2  christos 		w = (ptrace_regwfunc_t)process_write_dbregs;
    277  1.2  christos 	}
    278  1.2  christos 	return proc_regio(l, uio, s, r, w);
    279  1.2  christos #else
    280  1.2  christos 	return EINVAL;
    281  1.2  christos #endif
    282  1.2  christos }
    283