1 /* $OpenBSD: process_machdep.c,v 1.18 2024/11/27 05:25:56 anton Exp $ */ 2 /* $NetBSD: process_machdep.c,v 1.1 2003/04/26 18:39:31 fvdl Exp $ */ 3 4 /*- 5 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Charles M. Hannum. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * This file may seem a bit stylized, but that so that it's easier to port. 35 * Functions to be implemented here are: 36 * 37 * process_read_regs(proc, regs) 38 * Get the current user-visible register set from the process 39 * and copy it into the regs structure (<machine/reg.h>). 40 * The process is stopped at the time read_regs is called. 41 * 42 * process_write_regs(proc, regs) 43 * Update the current register set from the passed in regs 44 * structure. Take care to avoid clobbering special CPU 45 * registers or privileged bits in the PSL. 46 * The process is stopped at the time write_regs is called. 47 * 48 * process_sstep(proc) 49 * Arrange for the process to trap after executing a single instruction. 50 * 51 * process_set_pc(proc) 52 * Set the process's program counter. 53 */ 54 55 56 #include <sys/param.h> 57 #include <sys/systm.h> 58 #include <sys/proc.h> 59 #include <sys/ptrace.h> 60 #include <sys/user.h> 61 62 #include <uvm/uvm_extern.h> 63 64 #include <machine/reg.h> 65 #include <machine/fpu.h> 66 67 static __inline struct trapframe *process_frame(struct proc *); 68 static __inline struct fxsave64 *process_fpframe(struct proc *); 69 70 static __inline struct trapframe * 71 process_frame(struct proc *p) 72 { 73 74 return (p->p_md.md_regs); 75 } 76 77 static __inline struct fxsave64 * 78 process_fpframe(struct proc *p) 79 { 80 81 return (&p->p_addr->u_pcb.pcb_savefpu.fp_fxsave); 82 } 83 84 int 85 process_read_regs(struct proc *p, struct reg *regs) 86 { 87 struct trapframe *tf = process_frame(p); 88 89 regs->r_rdi = tf->tf_rdi; 90 regs->r_rsi = tf->tf_rsi; 91 regs->r_rdx = tf->tf_rdx; 92 regs->r_rcx = tf->tf_rcx; 93 regs->r_r8 = tf->tf_r8; 94 regs->r_r9 = tf->tf_r9; 95 regs->r_r10 = tf->tf_r10; 96 regs->r_r11 = tf->tf_r11; 97 regs->r_r12 = tf->tf_r12; 98 regs->r_r13 = tf->tf_r13; 99 regs->r_r14 = tf->tf_r14; 100 regs->r_r15 = tf->tf_r15; 101 regs->r_rbp = tf->tf_rbp; 102 regs->r_rbx = tf->tf_rbx; 103 regs->r_rax = tf->tf_rax; 104 regs->r_rsp = tf->tf_rsp; 105 regs->r_rip = tf->tf_rip; 106 regs->r_rflags = tf->tf_rflags; 107 regs->r_cs = tf->tf_cs; 108 regs->r_ss = tf->tf_ss; 109 regs->r_ds = GSEL(GUDATA_SEL, SEL_UPL); 110 regs->r_es = GSEL(GUDATA_SEL, SEL_UPL); 111 regs->r_fs = GSEL(GUDATA_SEL, SEL_UPL); 112 regs->r_gs = GSEL(GUDATA_SEL, SEL_UPL); 113 114 return (0); 115 } 116 117 int 118 process_read_fpregs(struct proc *p, struct fpreg *regs) 119 { 120 struct fxsave64 *frame = process_fpframe(p); 121 122 memcpy(®s->fxstate, frame, sizeof(*regs)); 123 return (0); 124 } 125 126 #ifdef PTRACE 127 128 int 129 process_write_regs(struct proc *p, struct reg *regs) 130 { 131 struct trapframe *tf = process_frame(p); 132 133 /* 134 * Check for security violations. 135 */ 136 if (check_context(regs, tf)) 137 return (EINVAL); 138 139 tf->tf_rdi = regs->r_rdi; 140 tf->tf_rsi = regs->r_rsi; 141 tf->tf_rdx = regs->r_rdx; 142 tf->tf_rcx = regs->r_rcx; 143 tf->tf_r8 = regs->r_r8; 144 tf->tf_r9 = regs->r_r9; 145 tf->tf_r10 = regs->r_r10; 146 tf->tf_r11 = regs->r_r11; 147 tf->tf_r12 = regs->r_r12; 148 tf->tf_r13 = regs->r_r13; 149 tf->tf_r14 = regs->r_r14; 150 tf->tf_r15 = regs->r_r15; 151 tf->tf_rbp = regs->r_rbp; 152 tf->tf_rbx = regs->r_rbx; 153 tf->tf_rax = regs->r_rax; 154 tf->tf_rsp = regs->r_rsp; 155 tf->tf_rip = regs->r_rip; 156 tf->tf_rflags = regs->r_rflags; 157 tf->tf_cs = regs->r_cs; 158 tf->tf_ss = regs->r_ss; 159 160 /* force target to return via iretq so all registers are updated */ 161 p->p_md.md_flags |= MDP_IRET; 162 163 return (0); 164 } 165 166 int 167 process_write_fpregs(struct proc *p, struct fpreg *regs) 168 { 169 struct fxsave64 *frame = process_fpframe(p); 170 171 memcpy(frame, ®s->fxstate, sizeof(*regs)); 172 frame->fx_mxcsr &= fpu_mxcsr_mask; 173 174 /* force target to return via iretq so bogus xstate can be handled */ 175 p->p_md.md_flags |= MDP_IRET; 176 return (0); 177 } 178 179 int 180 process_sstep(struct proc *p, int sstep) 181 { 182 struct trapframe *tf = process_frame(p); 183 184 if (sstep) 185 tf->tf_rflags |= PSL_T; 186 else 187 tf->tf_rflags &= ~PSL_T; 188 189 return (0); 190 } 191 192 int 193 process_set_pc(struct proc *p, caddr_t addr) 194 { 195 struct trapframe *tf = process_frame(p); 196 197 if ((u_int64_t)addr > VM_MAXUSER_ADDRESS) 198 return EINVAL; 199 tf->tf_rip = (u_int64_t)addr; 200 201 return (0); 202 } 203 204 int 205 process_read_xstate_info(struct proc *p, void *addr) 206 { 207 struct ptrace_xstate_info *info = addr; 208 209 if (xsave_mask == 0) 210 return (ENOTSUP); 211 212 info->xsave_mask = xsave_mask; 213 info->xsave_len = fpu_save_len; 214 return (0); 215 } 216 217 struct xsave_area { 218 uint8_t legacy_region[512]; 219 220 struct xsave_header { 221 uint64_t xstate_bv; 222 uint64_t xcomp_bv; 223 uint8_t rsvd0[48]; 224 } xsave_header; 225 226 uint8_t extended_region[]; 227 } __attribute__((packed)); 228 229 #define XSTATE_COMPONENT_X87 (1ULL << 0) 230 #define XSTATE_COMPONENT_SSE (1ULL << 1) 231 #define XSTATE_COMPONENT_AVX (1ULL << 2) 232 233 int 234 process_read_xstate(struct proc *p, void *addr) 235 { 236 struct xsave_area *area = 237 (struct xsave_area *)&p->p_addr->u_pcb.pcb_savefpu; 238 239 if (xsave_mask == 0) 240 return (ENOTSUP); 241 242 memcpy(addr, area, fpu_save_len); 243 return (0); 244 } 245 246 int 247 process_write_xstate(struct proc *p, void *addr) 248 { 249 struct xsave_area *area = 250 (struct xsave_area *)&p->p_addr->u_pcb.pcb_savefpu; 251 struct xsave_area *new_area = (struct xsave_area *)addr; 252 uint32_t offset_extended_region = offsetof(struct xsave_area, 253 extended_region); 254 uint32_t a, b, c, d; 255 256 if (xsave_mask == 0) 257 return (ENOTSUP); 258 259 /* 260 * Honor changes to x87, SSE and AVX components and mark them as in use. 261 * Required to ensure any changes are restored once the traced process 262 * continues execution. 263 */ 264 if ((xsave_mask & XSTATE_COMPONENT_X87) || 265 (xsave_mask & XSTATE_COMPONENT_SSE)) { 266 memcpy(area->legacy_region, new_area->legacy_region, 267 sizeof(area->legacy_region)); 268 area->xsave_header.xstate_bv |= xsave_mask & 269 (XSTATE_COMPONENT_X87 | XSTATE_COMPONENT_SSE); 270 } 271 if (xsave_mask & XSTATE_COMPONENT_AVX) { 272 CPUID_LEAF(0xd, 2, a, b, c, d); 273 if (offset_extended_region == b && 274 offset_extended_region + a <= fpu_save_len) { 275 memcpy(area->extended_region, 276 new_area->extended_region, a); 277 area->xsave_header.xstate_bv |= XSTATE_COMPONENT_AVX; 278 } 279 } 280 281 return (0); 282 } 283 284 #endif /* PTRACE */ 285