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 __FBSDID("$FreeBSD$"); 32 33 #include "opt_cpu.h" 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/elf.h> 38 #include <sys/lock.h> 39 #include <sys/malloc.h> 40 #include <sys/mutex.h> 41 #include <sys/proc.h> 42 #include <sys/ptrace.h> 43 #include <sys/reg.h> 44 #include <machine/frame.h> 45 #include <machine/md_var.h> 46 #include <machine/pcb.h> 47 48 static uint32_t 49 get_segbase(struct segment_descriptor *sdp) 50 { 51 return (sdp->sd_hibase << 24 | sdp->sd_lobase); 52 } 53 54 static bool 55 get_segbases(struct regset *rs, struct thread *td, void *buf, 56 size_t *sizep) 57 { 58 struct segbasereg *reg; 59 60 if (buf != NULL) { 61 KASSERT(*sizep == sizeof(*reg), ("%s: invalid size", __func__)); 62 reg = buf; 63 reg->r_fsbase = get_segbase(&td->td_pcb->pcb_fsd); 64 reg->r_gsbase = get_segbase(&td->td_pcb->pcb_gsd); 65 } 66 *sizep = sizeof(*reg); 67 return (true); 68 } 69 70 static bool 71 set_segbases(struct regset *rs, struct thread *td, void *buf, 72 size_t size) 73 { 74 struct segbasereg *reg; 75 76 KASSERT(size == sizeof(*reg), ("%s: invalid size", __func__)); 77 reg = buf; 78 79 fill_based_sd(&td->td_pcb->pcb_fsd, reg->r_fsbase); 80 td->td_frame->tf_fs = GSEL(GUFS_SEL, SEL_UPL); 81 fill_based_sd(&td->td_pcb->pcb_gsd, reg->r_gsbase); 82 td->td_pcb->pcb_gs = GSEL(GUGS_SEL, SEL_UPL); 83 84 return (true); 85 } 86 87 static struct regset regset_segbases = { 88 .note = NT_X86_SEGBASES, 89 .size = sizeof(struct segbasereg), 90 .get = get_segbases, 91 .set = set_segbases, 92 }; 93 ELF_REGSET(regset_segbases); 94 95 static int 96 cpu_ptrace_xstate(struct thread *td, int req, void *addr, int data) 97 { 98 struct ptrace_xstate_info info; 99 char *savefpu; 100 int error; 101 102 if (!use_xsave) 103 return (EOPNOTSUPP); 104 105 switch (req) { 106 case PT_GETXSTATE_OLD: 107 npxgetregs(td); 108 savefpu = (char *)(get_pcb_user_save_td(td) + 1); 109 error = copyout(savefpu, addr, 110 cpu_max_ext_state_size - sizeof(union savefpu)); 111 break; 112 113 case PT_SETXSTATE_OLD: 114 if (data > cpu_max_ext_state_size - sizeof(union savefpu)) { 115 error = EINVAL; 116 break; 117 } 118 savefpu = malloc(data, M_TEMP, M_WAITOK); 119 error = copyin(addr, savefpu, data); 120 if (error == 0) { 121 npxgetregs(td); 122 error = npxsetxstate(td, savefpu, data); 123 } 124 free(savefpu, M_TEMP); 125 break; 126 127 case PT_GETXSTATE_INFO: 128 if (data != sizeof(info)) { 129 error = EINVAL; 130 break; 131 } 132 info.xsave_len = cpu_max_ext_state_size; 133 info.xsave_mask = xsave_mask; 134 error = copyout(&info, addr, data); 135 break; 136 137 case PT_GETXSTATE: 138 npxgetregs(td); 139 savefpu = (char *)(get_pcb_user_save_td(td)); 140 error = copyout(savefpu, addr, cpu_max_ext_state_size); 141 break; 142 143 case PT_SETXSTATE: 144 if (data < sizeof(union savefpu) || 145 data > cpu_max_ext_state_size) { 146 error = EINVAL; 147 break; 148 } 149 savefpu = malloc(data, M_TEMP, M_WAITOK); 150 error = copyin(addr, savefpu, data); 151 if (error == 0) 152 error = npxsetregs(td, (union savefpu *)savefpu, 153 savefpu + sizeof(union savefpu), data - 154 sizeof(union savefpu)); 155 free(savefpu, M_TEMP); 156 break; 157 158 default: 159 error = EINVAL; 160 break; 161 } 162 163 return (error); 164 } 165 166 static int 167 cpu_ptrace_xmm(struct thread *td, int req, void *addr, int data) 168 { 169 struct savexmm *fpstate; 170 int error; 171 172 if (!cpu_fxsr) 173 return (EINVAL); 174 175 fpstate = &get_pcb_user_save_td(td)->sv_xmm; 176 switch (req) { 177 case PT_GETXMMREGS: 178 npxgetregs(td); 179 error = copyout(fpstate, addr, sizeof(*fpstate)); 180 break; 181 182 case PT_SETXMMREGS: 183 npxgetregs(td); 184 error = copyin(addr, fpstate, sizeof(*fpstate)); 185 fpstate->sv_env.en_mxcsr &= cpu_mxcsr_mask; 186 break; 187 188 case PT_GETXSTATE_OLD: 189 case PT_SETXSTATE_OLD: 190 case PT_GETXSTATE_INFO: 191 case PT_GETXSTATE: 192 case PT_SETXSTATE: 193 error = cpu_ptrace_xstate(td, req, addr, data); 194 break; 195 196 default: 197 return (EINVAL); 198 } 199 200 return (error); 201 } 202 203 int 204 cpu_ptrace(struct thread *td, int req, void *addr, int data) 205 { 206 struct segment_descriptor *sdp, sd; 207 register_t r; 208 int error; 209 210 switch (req) { 211 case PT_GETXMMREGS: 212 case PT_SETXMMREGS: 213 case PT_GETXSTATE_OLD: 214 case PT_SETXSTATE_OLD: 215 case PT_GETXSTATE_INFO: 216 case PT_GETXSTATE: 217 case PT_SETXSTATE: 218 error = cpu_ptrace_xmm(td, req, addr, data); 219 break; 220 221 case PT_GETFSBASE: 222 case PT_GETGSBASE: 223 sdp = req == PT_GETFSBASE ? &td->td_pcb->pcb_fsd : 224 &td->td_pcb->pcb_gsd; 225 r = get_segbase(sdp); 226 error = copyout(&r, addr, sizeof(r)); 227 break; 228 229 case PT_SETFSBASE: 230 case PT_SETGSBASE: 231 error = copyin(addr, &r, sizeof(r)); 232 if (error != 0) 233 break; 234 fill_based_sd(&sd, r); 235 if (req == PT_SETFSBASE) { 236 td->td_pcb->pcb_fsd = sd; 237 td->td_frame->tf_fs = GSEL(GUFS_SEL, SEL_UPL); 238 } else { 239 td->td_pcb->pcb_gsd = sd; 240 td->td_pcb->pcb_gs = GSEL(GUGS_SEL, SEL_UPL); 241 } 242 break; 243 244 default: 245 return (EINVAL); 246 } 247 248 return (error); 249 } 250 251 int 252 ptrace_set_pc(struct thread *td, u_long addr) 253 { 254 255 td->td_frame->tf_eip = addr; 256 return (0); 257 } 258 259 int 260 ptrace_single_step(struct thread *td) 261 { 262 263 PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 264 if ((td->td_frame->tf_eflags & PSL_T) == 0) { 265 td->td_frame->tf_eflags |= PSL_T; 266 td->td_dbgflags |= TDB_STEP; 267 } 268 return (0); 269 } 270 271 int 272 ptrace_clear_single_step(struct thread *td) 273 { 274 275 PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 276 td->td_frame->tf_eflags &= ~PSL_T; 277 td->td_dbgflags &= ~TDB_STEP; 278 return (0); 279 } 280