1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2005 Doug Rabson 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 */ 29 30 #include <sys/cdefs.h> 31 #include "opt_cpu.h" 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/elf.h> 36 #include <sys/lock.h> 37 #include <sys/malloc.h> 38 #include <sys/mutex.h> 39 #include <sys/proc.h> 40 #include <sys/ptrace.h> 41 #include <sys/reg.h> 42 #include <machine/frame.h> 43 #include <machine/md_var.h> 44 #include <machine/pcb.h> 45 46 static uint32_t 47 get_segbase(struct segment_descriptor *sdp) 48 { 49 return (sdp->sd_hibase << 24 | sdp->sd_lobase); 50 } 51 52 static bool 53 get_segbases(struct regset *rs, struct thread *td, void *buf, 54 size_t *sizep) 55 { 56 struct segbasereg *reg; 57 58 if (buf != NULL) { 59 KASSERT(*sizep == sizeof(*reg), ("%s: invalid size", __func__)); 60 reg = buf; 61 reg->r_fsbase = get_segbase(&td->td_pcb->pcb_fsd); 62 reg->r_gsbase = get_segbase(&td->td_pcb->pcb_gsd); 63 } 64 *sizep = sizeof(*reg); 65 return (true); 66 } 67 68 static bool 69 set_segbases(struct regset *rs, struct thread *td, void *buf, 70 size_t size) 71 { 72 struct segbasereg *reg; 73 74 KASSERT(size == sizeof(*reg), ("%s: invalid size", __func__)); 75 reg = buf; 76 77 fill_based_sd(&td->td_pcb->pcb_fsd, reg->r_fsbase); 78 td->td_frame->tf_fs = GSEL(GUFS_SEL, SEL_UPL); 79 fill_based_sd(&td->td_pcb->pcb_gsd, reg->r_gsbase); 80 td->td_pcb->pcb_gs = GSEL(GUGS_SEL, SEL_UPL); 81 82 return (true); 83 } 84 85 static struct regset regset_segbases = { 86 .note = NT_X86_SEGBASES, 87 .size = sizeof(struct segbasereg), 88 .get = get_segbases, 89 .set = set_segbases, 90 }; 91 ELF_REGSET(regset_segbases); 92 93 static int 94 cpu_ptrace_xstate(struct thread *td, int req, void *addr, int data) 95 { 96 struct ptrace_xstate_info info; 97 char *savefpu; 98 int error; 99 100 if (!use_xsave) 101 return (EOPNOTSUPP); 102 103 switch (req) { 104 case PT_GETXSTATE_OLD: 105 npxgetregs(td); 106 savefpu = (char *)(get_pcb_user_save_td(td) + 1); 107 error = copyout(savefpu, addr, 108 cpu_max_ext_state_size - sizeof(union savefpu)); 109 break; 110 111 case PT_SETXSTATE_OLD: 112 if (data > cpu_max_ext_state_size - sizeof(union savefpu)) { 113 error = EINVAL; 114 break; 115 } 116 savefpu = malloc(data, M_TEMP, M_WAITOK); 117 error = copyin(addr, savefpu, data); 118 if (error == 0) { 119 npxgetregs(td); 120 error = npxsetxstate(td, savefpu, data); 121 } 122 free(savefpu, M_TEMP); 123 break; 124 125 case PT_GETXSTATE_INFO: 126 if (data != sizeof(info)) { 127 error = EINVAL; 128 break; 129 } 130 info.xsave_len = cpu_max_ext_state_size; 131 info.xsave_mask = xsave_mask; 132 error = copyout(&info, addr, data); 133 break; 134 135 case PT_GETXSTATE: 136 npxgetregs(td); 137 savefpu = (char *)(get_pcb_user_save_td(td)); 138 error = copyout(savefpu, addr, cpu_max_ext_state_size); 139 break; 140 141 case PT_SETXSTATE: 142 if (data < sizeof(union savefpu) || 143 data > cpu_max_ext_state_size) { 144 error = EINVAL; 145 break; 146 } 147 savefpu = malloc(data, M_TEMP, M_WAITOK); 148 error = copyin(addr, savefpu, data); 149 if (error == 0) 150 error = npxsetregs(td, (union savefpu *)savefpu, 151 savefpu + sizeof(union savefpu), data - 152 sizeof(union savefpu)); 153 free(savefpu, M_TEMP); 154 break; 155 156 default: 157 error = EINVAL; 158 break; 159 } 160 161 return (error); 162 } 163 164 static int 165 cpu_ptrace_xmm(struct thread *td, int req, void *addr, int data) 166 { 167 struct savexmm *fpstate; 168 int error; 169 170 if (!cpu_fxsr) 171 return (EINVAL); 172 173 fpstate = &get_pcb_user_save_td(td)->sv_xmm; 174 switch (req) { 175 case PT_GETXMMREGS: 176 npxgetregs(td); 177 error = copyout(fpstate, addr, sizeof(*fpstate)); 178 break; 179 180 case PT_SETXMMREGS: 181 npxgetregs(td); 182 error = copyin(addr, fpstate, sizeof(*fpstate)); 183 fpstate->sv_env.en_mxcsr &= cpu_mxcsr_mask; 184 break; 185 186 case PT_GETXSTATE_OLD: 187 case PT_SETXSTATE_OLD: 188 case PT_GETXSTATE_INFO: 189 case PT_GETXSTATE: 190 case PT_SETXSTATE: 191 error = cpu_ptrace_xstate(td, req, addr, data); 192 break; 193 194 default: 195 return (EINVAL); 196 } 197 198 return (error); 199 } 200 201 int 202 cpu_ptrace(struct thread *td, int req, void *addr, int data) 203 { 204 struct segment_descriptor *sdp, sd; 205 register_t r; 206 int error; 207 208 switch (req) { 209 case PT_GETXMMREGS: 210 case PT_SETXMMREGS: 211 case PT_GETXSTATE_OLD: 212 case PT_SETXSTATE_OLD: 213 case PT_GETXSTATE_INFO: 214 case PT_GETXSTATE: 215 case PT_SETXSTATE: 216 error = cpu_ptrace_xmm(td, req, addr, data); 217 break; 218 219 case PT_GETFSBASE: 220 case PT_GETGSBASE: 221 sdp = req == PT_GETFSBASE ? &td->td_pcb->pcb_fsd : 222 &td->td_pcb->pcb_gsd; 223 r = get_segbase(sdp); 224 error = copyout(&r, addr, sizeof(r)); 225 break; 226 227 case PT_SETFSBASE: 228 case PT_SETGSBASE: 229 error = copyin(addr, &r, sizeof(r)); 230 if (error != 0) 231 break; 232 fill_based_sd(&sd, r); 233 if (req == PT_SETFSBASE) { 234 td->td_pcb->pcb_fsd = sd; 235 td->td_frame->tf_fs = GSEL(GUFS_SEL, SEL_UPL); 236 } else { 237 td->td_pcb->pcb_gsd = sd; 238 td->td_pcb->pcb_gs = GSEL(GUGS_SEL, SEL_UPL); 239 } 240 break; 241 242 default: 243 return (EINVAL); 244 } 245 246 return (error); 247 } 248 249 int 250 ptrace_set_pc(struct thread *td, u_long addr) 251 { 252 253 td->td_frame->tf_eip = addr; 254 return (0); 255 } 256 257 int 258 ptrace_single_step(struct thread *td) 259 { 260 261 PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 262 if ((td->td_frame->tf_eflags & PSL_T) == 0) { 263 td->td_frame->tf_eflags |= PSL_T; 264 td->td_dbgflags |= TDB_STEP; 265 } 266 return (0); 267 } 268 269 int 270 ptrace_clear_single_step(struct thread *td) 271 { 272 273 PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 274 td->td_frame->tf_eflags &= ~PSL_T; 275 td->td_dbgflags &= ~TDB_STEP; 276 return (0); 277 } 278