1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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/lock.h> 38 #include <sys/malloc.h> 39 #include <sys/mutex.h> 40 #include <sys/proc.h> 41 #include <sys/ptrace.h> 42 #include <machine/frame.h> 43 #include <machine/md_var.h> 44 #include <machine/pcb.h> 45 46 static int 47 cpu_ptrace_xstate(struct thread *td, int req, void *addr, int data) 48 { 49 struct ptrace_xstate_info info; 50 char *savefpu; 51 int error; 52 53 if (!use_xsave) 54 return (EOPNOTSUPP); 55 56 switch (req) { 57 case PT_GETXSTATE_OLD: 58 npxgetregs(td); 59 savefpu = (char *)(get_pcb_user_save_td(td) + 1); 60 error = copyout(savefpu, addr, 61 cpu_max_ext_state_size - sizeof(union savefpu)); 62 break; 63 64 case PT_SETXSTATE_OLD: 65 if (data > cpu_max_ext_state_size - sizeof(union savefpu)) { 66 error = EINVAL; 67 break; 68 } 69 savefpu = malloc(data, M_TEMP, M_WAITOK); 70 error = copyin(addr, savefpu, data); 71 if (error == 0) { 72 npxgetregs(td); 73 error = npxsetxstate(td, savefpu, data); 74 } 75 free(savefpu, M_TEMP); 76 break; 77 78 case PT_GETXSTATE_INFO: 79 if (data != sizeof(info)) { 80 error = EINVAL; 81 break; 82 } 83 info.xsave_len = cpu_max_ext_state_size; 84 info.xsave_mask = xsave_mask; 85 error = copyout(&info, addr, data); 86 break; 87 88 case PT_GETXSTATE: 89 npxgetregs(td); 90 savefpu = (char *)(get_pcb_user_save_td(td)); 91 error = copyout(savefpu, addr, cpu_max_ext_state_size); 92 break; 93 94 case PT_SETXSTATE: 95 if (data < sizeof(union savefpu) || 96 data > cpu_max_ext_state_size) { 97 error = EINVAL; 98 break; 99 } 100 savefpu = malloc(data, M_TEMP, M_WAITOK); 101 error = copyin(addr, savefpu, data); 102 if (error == 0) 103 error = npxsetregs(td, (union savefpu *)savefpu, 104 savefpu + sizeof(union savefpu), data - 105 sizeof(union savefpu)); 106 free(savefpu, M_TEMP); 107 break; 108 109 default: 110 error = EINVAL; 111 break; 112 } 113 114 return (error); 115 } 116 117 static int 118 cpu_ptrace_xmm(struct thread *td, int req, void *addr, int data) 119 { 120 struct savexmm *fpstate; 121 int error; 122 123 if (!cpu_fxsr) 124 return (EINVAL); 125 126 fpstate = &get_pcb_user_save_td(td)->sv_xmm; 127 switch (req) { 128 case PT_GETXMMREGS: 129 npxgetregs(td); 130 error = copyout(fpstate, addr, sizeof(*fpstate)); 131 break; 132 133 case PT_SETXMMREGS: 134 npxgetregs(td); 135 error = copyin(addr, fpstate, sizeof(*fpstate)); 136 fpstate->sv_env.en_mxcsr &= cpu_mxcsr_mask; 137 break; 138 139 case PT_GETXSTATE_OLD: 140 case PT_SETXSTATE_OLD: 141 case PT_GETXSTATE_INFO: 142 case PT_GETXSTATE: 143 case PT_SETXSTATE: 144 error = cpu_ptrace_xstate(td, req, addr, data); 145 break; 146 147 default: 148 return (EINVAL); 149 } 150 151 return (error); 152 } 153 154 int 155 cpu_ptrace(struct thread *td, int req, void *addr, int data) 156 { 157 struct segment_descriptor *sdp, sd; 158 register_t r; 159 int error; 160 161 switch (req) { 162 case PT_GETXMMREGS: 163 case PT_SETXMMREGS: 164 case PT_GETXSTATE_OLD: 165 case PT_SETXSTATE_OLD: 166 case PT_GETXSTATE_INFO: 167 case PT_GETXSTATE: 168 case PT_SETXSTATE: 169 error = cpu_ptrace_xmm(td, req, addr, data); 170 break; 171 172 case PT_GETFSBASE: 173 case PT_GETGSBASE: 174 sdp = req == PT_GETFSBASE ? &td->td_pcb->pcb_fsd : 175 &td->td_pcb->pcb_gsd; 176 r = sdp->sd_hibase << 24 | sdp->sd_lobase; 177 error = copyout(&r, addr, sizeof(r)); 178 break; 179 180 case PT_SETFSBASE: 181 case PT_SETGSBASE: 182 error = copyin(addr, &r, sizeof(r)); 183 if (error != 0) 184 break; 185 fill_based_sd(&sd, r); 186 if (req == PT_SETFSBASE) { 187 td->td_pcb->pcb_fsd = sd; 188 td->td_frame->tf_fs = GSEL(GUFS_SEL, SEL_UPL); 189 } else { 190 td->td_pcb->pcb_gsd = sd; 191 td->td_pcb->pcb_gs = GSEL(GUGS_SEL, SEL_UPL); 192 } 193 break; 194 195 default: 196 return (EINVAL); 197 } 198 199 return (error); 200 } 201 202 int 203 ptrace_set_pc(struct thread *td, u_long addr) 204 { 205 206 td->td_frame->tf_eip = addr; 207 return (0); 208 } 209 210 int 211 ptrace_single_step(struct thread *td) 212 { 213 214 PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 215 if ((td->td_frame->tf_eflags & PSL_T) == 0) { 216 td->td_frame->tf_eflags |= PSL_T; 217 td->td_dbgflags |= TDB_STEP; 218 } 219 return (0); 220 } 221 222 int 223 ptrace_clear_single_step(struct thread *td) 224 { 225 226 PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 227 td->td_frame->tf_eflags &= ~PSL_T; 228 td->td_dbgflags &= ~TDB_STEP; 229 return (0); 230 } 231