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