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