ptrace_machdep.c revision 286311
1/*- 2 * Copyright (c) 2005 Doug Rabson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: stable/10/sys/i386/i386/ptrace_machdep.c 286311 2015-08-05 08:17:10Z kib $"); 30 31#include "opt_cpu.h" 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/malloc.h> 36#include <sys/proc.h> 37#include <sys/ptrace.h> 38#include <machine/frame.h> 39#include <machine/md_var.h> 40#include <machine/pcb.h> 41 42#if !defined(CPU_DISABLE_SSE) && defined(I686_CPU) 43#define CPU_ENABLE_SSE 44#endif 45 46#ifdef CPU_ENABLE_SSE 47static int 48cpu_ptrace_xstate(struct thread *td, int req, void *addr, int data) 49{ 50 struct ptrace_xstate_info info; 51 char *savefpu; 52 int error; 53 54 if (!use_xsave) 55 return (EOPNOTSUPP); 56 57 switch (req) { 58 case PT_GETXSTATE_OLD: 59 npxgetregs(td); 60 savefpu = (char *)(get_pcb_user_save_td(td) + 1); 61 error = copyout(savefpu, addr, 62 cpu_max_ext_state_size - sizeof(union savefpu)); 63 break; 64 65 case PT_SETXSTATE_OLD: 66 if (data > cpu_max_ext_state_size - sizeof(union savefpu)) { 67 error = EINVAL; 68 break; 69 } 70 savefpu = malloc(data, M_TEMP, M_WAITOK); 71 error = copyin(addr, savefpu, data); 72 if (error == 0) { 73 npxgetregs(td); 74 error = npxsetxstate(td, savefpu, data); 75 } 76 free(savefpu, M_TEMP); 77 break; 78 79 case PT_GETXSTATE_INFO: 80 if (data != sizeof(info)) { 81 error = EINVAL; 82 break; 83 } 84 info.xsave_len = cpu_max_ext_state_size; 85 info.xsave_mask = xsave_mask; 86 error = copyout(&info, addr, data); 87 break; 88 89 case PT_GETXSTATE: 90 npxgetregs(td); 91 savefpu = (char *)(get_pcb_user_save_td(td)); 92 error = copyout(savefpu, addr, cpu_max_ext_state_size); 93 break; 94 95 case PT_SETXSTATE: 96 if (data < sizeof(union savefpu) || 97 data > cpu_max_ext_state_size) { 98 error = EINVAL; 99 break; 100 } 101 savefpu = malloc(data, M_TEMP, M_WAITOK); 102 error = copyin(addr, savefpu, data); 103 if (error == 0) 104 error = npxsetregs(td, (union savefpu *)savefpu, 105 savefpu + sizeof(union savefpu), data - 106 sizeof(union savefpu)); 107 free(savefpu, M_TEMP); 108 break; 109 110 default: 111 error = EINVAL; 112 break; 113 } 114 115 return (error); 116} 117#endif 118 119static int 120cpu_ptrace_xmm(struct thread *td, int req, void *addr, int data) 121{ 122#ifdef CPU_ENABLE_SSE 123 struct savexmm *fpstate; 124 int error; 125 126 if (!cpu_fxsr) 127 return (EINVAL); 128 129 fpstate = &get_pcb_user_save_td(td)->sv_xmm; 130 switch (req) { 131 case PT_GETXMMREGS: 132 npxgetregs(td); 133 error = copyout(fpstate, addr, sizeof(*fpstate)); 134 break; 135 136 case PT_SETXMMREGS: 137 npxgetregs(td); 138 error = copyin(addr, fpstate, sizeof(*fpstate)); 139 fpstate->sv_env.en_mxcsr &= cpu_mxcsr_mask; 140 break; 141 142 case PT_GETXSTATE_OLD: 143 case PT_SETXSTATE_OLD: 144 case PT_GETXSTATE_INFO: 145 case PT_GETXSTATE: 146 case PT_SETXSTATE: 147 error = cpu_ptrace_xstate(td, req, addr, data); 148 break; 149 150 default: 151 return (EINVAL); 152 } 153 154 return (error); 155#else 156 return (EINVAL); 157#endif 158} 159 160int 161cpu_ptrace(struct thread *td, int req, void *addr, int data) 162{ 163 struct segment_descriptor *sdp, sd; 164 register_t r; 165 int error; 166 167 switch (req) { 168 case PT_GETXMMREGS: 169 case PT_SETXMMREGS: 170 case PT_GETXSTATE_OLD: 171 case PT_SETXSTATE_OLD: 172 case PT_GETXSTATE_INFO: 173 case PT_GETXSTATE: 174 case PT_SETXSTATE: 175 error = cpu_ptrace_xmm(td, req, addr, data); 176 break; 177 178 case PT_GETFSBASE: 179 case PT_GETGSBASE: 180 sdp = req == PT_GETFSBASE ? &td->td_pcb->pcb_fsd : 181 &td->td_pcb->pcb_gsd; 182 r = sdp->sd_hibase << 24 | sdp->sd_lobase; 183 error = copyout(&r, addr, sizeof(r)); 184 break; 185 186 case PT_SETFSBASE: 187 case PT_SETGSBASE: 188 error = copyin(addr, &r, sizeof(r)); 189 if (error != 0) 190 break; 191 fill_based_sd(&sd, r); 192 if (req == PT_SETFSBASE) { 193 td->td_pcb->pcb_fsd = sd; 194 td->td_frame->tf_fs = GSEL(GUFS_SEL, SEL_UPL); 195 } else { 196 td->td_pcb->pcb_gsd = sd; 197 td->td_pcb->pcb_gs = GSEL(GUGS_SEL, SEL_UPL); 198 } 199 break; 200 201 default: 202 return (EINVAL); 203 } 204 205 return (error); 206} 207