1 /* $NetBSD: process_machdep.c,v 1.97 2023/11/20 03:05:48 simonb Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 2000, 2001, 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum; by Jason R. Thorpe of Wasabi Systems, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This file may seem a bit stylized, but that so that it's easier to port. 34 * Functions to be implemented here are: 35 * 36 * process_read_regs(proc, regs) 37 * Get the current user-visible register set from the process 38 * and copy it into the regs structure (<machine/reg.h>). 39 * The process is stopped at the time read_regs is called. 40 * 41 * process_write_regs(proc, regs) 42 * Update the current register set from the passed in regs 43 * structure. Take care to avoid clobbering special CPU 44 * registers or privileged bits in the PSL. 45 * The process is stopped at the time write_regs is called. 46 * 47 * process_read_fpregs(proc, regs, sz) 48 * Get the current user-visible register set from the process 49 * and copy it into the regs structure (<machine/reg.h>). 50 * The process is stopped at the time read_fpregs is called. 51 * 52 * process_write_fpregs(proc, regs, sz) 53 * Update the current register set from the passed in regs 54 * structure. Take care to avoid clobbering special CPU 55 * registers or privileged bits in the PSL. 56 * The process is stopped at the time write_fpregs is called. 57 * 58 * process_read_dbregs(proc, regs) 59 * Get the current user-visible register set from the process 60 * and copy it into the regs structure (<machine/reg.h>). 61 * The process is stopped at the time read_dbregs is called. 62 * 63 * process_write_dbregs(proc, regs) 64 * Update the current register set from the passed in regs 65 * structure. Take care to avoid clobbering special CPU 66 * registers or privileged bits in the PSL. 67 * The process is stopped at the time write_dbregs is called. 68 * 69 * process_sstep(proc) 70 * Arrange for the process to trap after executing a single instruction. 71 * 72 * process_set_pc(proc) 73 * Set the process's program counter. 74 * 75 */ 76 77 #include <sys/cdefs.h> 78 __KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.97 2023/11/20 03:05:48 simonb Exp $"); 79 80 #ifdef _KERNEL_OPT 81 #include "opt_ptrace.h" 82 #endif 83 84 #include <sys/param.h> 85 #include <sys/systm.h> 86 #include <sys/time.h> 87 #include <sys/kernel.h> 88 #include <sys/proc.h> 89 #include <sys/vnode.h> 90 #include <sys/ptrace.h> 91 92 #include <uvm/uvm_extern.h> 93 94 #include <machine/psl.h> 95 #include <machine/reg.h> 96 #include <machine/segments.h> 97 98 #include <x86/dbregs.h> 99 #include <x86/fpu.h> 100 101 static inline struct trapframe * 102 process_frame(struct lwp *l) 103 { 104 105 return (l->l_md.md_regs); 106 } 107 108 int 109 process_read_regs(struct lwp *l, struct reg *regs) 110 { 111 struct trapframe *tf = process_frame(l); 112 113 regs->r_gs = tf->tf_gs & 0xffff; 114 regs->r_fs = tf->tf_fs & 0xffff; 115 regs->r_es = tf->tf_es & 0xffff; 116 regs->r_ds = tf->tf_ds & 0xffff; 117 regs->r_eflags = tf->tf_eflags; 118 119 regs->r_edi = tf->tf_edi; 120 regs->r_esi = tf->tf_esi; 121 regs->r_ebp = tf->tf_ebp; 122 regs->r_ebx = tf->tf_ebx; 123 regs->r_edx = tf->tf_edx; 124 regs->r_ecx = tf->tf_ecx; 125 regs->r_eax = tf->tf_eax; 126 regs->r_eip = tf->tf_eip; 127 regs->r_cs = tf->tf_cs & 0xffff; 128 regs->r_esp = tf->tf_esp; 129 regs->r_ss = tf->tf_ss & 0xffff; 130 131 return (0); 132 } 133 134 int 135 process_read_fpregs(struct lwp *l, struct fpreg *regs, size_t *sz) 136 { 137 138 __CTASSERT(sizeof *regs == sizeof (struct save87)); 139 process_read_fpregs_s87(l, (struct save87 *)regs); 140 return 0; 141 } 142 143 int 144 process_read_dbregs(struct lwp *l, struct dbreg *regs, size_t *sz) 145 { 146 147 x86_dbregs_read(l, regs); 148 149 return 0; 150 } 151 152 #ifdef PTRACE_HOOKS 153 int 154 process_write_regs(struct lwp *l, const struct reg *regs) 155 { 156 struct trapframe *tf = process_frame(l); 157 158 /* 159 * Check for security violations. 160 */ 161 if (((regs->r_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 || 162 !USERMODE(regs->r_cs)) 163 return (EINVAL); 164 165 tf->tf_gs = regs->r_gs; 166 tf->tf_fs = regs->r_fs; 167 tf->tf_es = regs->r_es; 168 tf->tf_ds = regs->r_ds; 169 tf->tf_eflags = regs->r_eflags; 170 171 tf->tf_edi = regs->r_edi; 172 tf->tf_esi = regs->r_esi; 173 tf->tf_ebp = regs->r_ebp; 174 tf->tf_ebx = regs->r_ebx; 175 tf->tf_edx = regs->r_edx; 176 tf->tf_ecx = regs->r_ecx; 177 tf->tf_eax = regs->r_eax; 178 tf->tf_eip = regs->r_eip; 179 tf->tf_cs = regs->r_cs; 180 tf->tf_esp = regs->r_esp; 181 tf->tf_ss = regs->r_ss; 182 183 return (0); 184 } 185 186 int 187 process_write_fpregs(struct lwp *l, const struct fpreg *regs, size_t sz) 188 { 189 190 __CTASSERT(sizeof *regs == sizeof (struct save87)); 191 process_write_fpregs_s87(l, (const struct save87 *)regs); 192 return 0; 193 } 194 195 int 196 process_write_dbregs(struct lwp *l, const struct dbreg *regs, size_t sz) 197 { 198 int error; 199 200 /* 201 * Check for security violations. 202 */ 203 error = x86_dbregs_validate(regs); 204 if (error != 0) 205 return error; 206 207 x86_dbregs_write(l, regs); 208 209 return 0; 210 } 211 212 int 213 process_sstep(struct lwp *l, int sstep) 214 { 215 struct trapframe *tf = process_frame(l); 216 217 if (sstep) 218 tf->tf_eflags |= PSL_T; 219 else 220 tf->tf_eflags &= ~PSL_T; 221 222 return (0); 223 } 224 225 int 226 process_set_pc(struct lwp *l, void *addr) 227 { 228 struct trapframe *tf = process_frame(l); 229 230 tf->tf_eip = (int)addr; 231 232 return (0); 233 } 234 235 #ifdef __HAVE_PTRACE_MACHDEP 236 static int 237 process_machdep_read_xstate(struct lwp *l, struct xstate *regs) 238 { 239 return process_read_xstate(l, regs); 240 } 241 242 static int 243 process_machdep_read_xmmregs(struct lwp *l, struct xmmregs *regs) 244 { 245 246 __CTASSERT(sizeof *regs == sizeof (struct fxsave)); 247 process_read_fpregs_xmm(l, (struct fxsave *)regs); 248 return 0; 249 } 250 251 static int 252 process_machdep_write_xstate(struct lwp *l, const struct xstate *regs) 253 { 254 int error; 255 256 /* 257 * Check for security violations. 258 */ 259 error = process_verify_xstate(regs); 260 if (error != 0) 261 return error; 262 263 return process_write_xstate(l, regs); 264 } 265 266 static int 267 process_machdep_write_xmmregs(struct lwp *l, struct xmmregs *regs) 268 { 269 270 __CTASSERT(sizeof *regs == sizeof (struct fxsave)); 271 process_write_fpregs_xmm(l, (const struct fxsave *)regs); 272 return 0; 273 } 274 275 int 276 ptrace_machdep_dorequest( 277 struct lwp *l, 278 struct lwp **lt, 279 int req, 280 void *addr, 281 int data 282 ) 283 { 284 struct uio uio; 285 struct iovec iov; 286 struct iovec user_iov; 287 struct vmspace *vm; 288 int error; 289 int write = 0; 290 291 switch (req) { 292 case PT_SETXMMREGS: 293 write = 1; 294 295 /* FALLTHROUGH */ 296 case PT_GETXMMREGS: 297 /* write = 0 done above. */ 298 if ((error = ptrace_update_lwp((*lt)->l_proc, lt, data)) != 0) 299 return error; 300 if (!process_machdep_validxmmregs((*lt)->l_proc)) 301 return (EINVAL); 302 error = proc_vmspace_getref(l->l_proc, &vm); 303 if (error) { 304 return error; 305 } 306 iov.iov_base = addr; 307 iov.iov_len = sizeof(struct xmmregs); 308 uio.uio_iov = &iov; 309 uio.uio_iovcnt = 1; 310 uio.uio_offset = 0; 311 uio.uio_resid = sizeof(struct xmmregs); 312 uio.uio_rw = write ? UIO_WRITE : UIO_READ; 313 uio.uio_vmspace = vm; 314 error = process_machdep_doxmmregs(l, *lt, &uio); 315 uvmspace_free(vm); 316 return error; 317 318 case PT_SETXSTATE: 319 write = 1; 320 321 /* FALLTHROUGH */ 322 case PT_GETXSTATE: 323 /* write = 0 done above. */ 324 if ((error = ptrace_update_lwp((*lt)->l_proc, lt, data)) != 0) 325 return error; 326 if (!process_machdep_validxstate((*lt)->l_proc)) 327 return EINVAL; 328 if ((error = copyin(addr, &user_iov, sizeof(user_iov))) != 0) 329 return error; 330 error = proc_vmspace_getref(l->l_proc, &vm); 331 if (error) { 332 return error; 333 } 334 iov.iov_base = user_iov.iov_base; 335 iov.iov_len = user_iov.iov_len; 336 if (iov.iov_len > sizeof(struct xstate)) 337 iov.iov_len = sizeof(struct xstate); 338 uio.uio_iov = &iov; 339 uio.uio_iovcnt = 1; 340 uio.uio_offset = 0; 341 uio.uio_resid = iov.iov_len; 342 uio.uio_rw = write ? UIO_WRITE : UIO_READ; 343 uio.uio_vmspace = vm; 344 error = process_machdep_doxstate(l, *lt, &uio); 345 uvmspace_free(vm); 346 return error; 347 } 348 349 #ifdef DIAGNOSTIC 350 panic("ptrace_machdep: impossible"); 351 #endif 352 353 return 0; 354 } 355 356 /* 357 * The following functions are used by both ptrace(2) and procfs. 358 */ 359 360 int 361 process_machdep_doxmmregs(struct lwp *curl, struct lwp *l, struct uio *uio) 362 /* curl: tracer */ 363 /* l: traced */ 364 { 365 int error; 366 struct xmmregs r; 367 char *kv; 368 int kl; 369 370 kl = sizeof(r); 371 kv = (char *) &r; 372 373 kv += uio->uio_offset; 374 kl -= uio->uio_offset; 375 if (kl > uio->uio_resid) 376 kl = uio->uio_resid; 377 378 if (kl < 0) 379 error = EINVAL; 380 else 381 error = process_machdep_read_xmmregs(l, &r); 382 if (error == 0) 383 error = uiomove(kv, kl, uio); 384 if (error == 0 && uio->uio_rw == UIO_WRITE) { 385 if (l->l_proc->p_stat != SSTOP) 386 error = EBUSY; 387 else 388 error = process_machdep_write_xmmregs(l, &r); 389 } 390 391 uio->uio_offset = 0; 392 return (error); 393 } 394 395 int 396 process_machdep_validxmmregs(struct proc *p) 397 { 398 399 if (p->p_flag & PK_SYSTEM) 400 return (0); 401 402 return (i386_use_fxsave); 403 } 404 405 int 406 process_machdep_doxstate(struct lwp *curl, struct lwp *l, struct uio *uio) 407 /* curl: tracer */ 408 /* l: traced */ 409 { 410 int error; 411 struct xstate r; /* XXX FIXME big stack object */ 412 char *kv; 413 ssize_t kl; 414 415 memset(&r, 0, sizeof(r)); 416 kl = MIN(uio->uio_iov->iov_len, sizeof(r)); 417 kv = (char *) &r; 418 419 kv += uio->uio_offset; 420 kl -= uio->uio_offset; 421 if (kl > uio->uio_resid) 422 kl = uio->uio_resid; 423 424 if (kl < 0) 425 error = EINVAL; 426 else 427 error = process_machdep_read_xstate(l, &r); 428 if (error == 0) 429 error = uiomove(kv, kl, uio); 430 if (error == 0 && uio->uio_rw == UIO_WRITE) 431 error = process_machdep_write_xstate(l, &r); 432 433 uio->uio_offset = 0; 434 return error; 435 } 436 437 int 438 process_machdep_validxstate(struct proc *p) 439 { 440 441 if (p->p_flag & PK_SYSTEM) 442 return 0; 443 444 return 1; 445 } 446 #endif /* __HAVE_PTRACE_MACHDEP */ 447 #endif /* PTRACE_HOOKS */ 448