ptrace_machdep.c revision 331735
162053Smarkm/*- 262765Smarkm * Copyright (c) 2011 Konstantin Belousov <kib@FreeBSD.org> 362053Smarkm * All rights reserved. 462053Smarkm * 562053Smarkm * Redistribution and use in source and binary forms, with or without 662053Smarkm * modification, are permitted provided that the following conditions 762053Smarkm * are met: 862053Smarkm * 1. Redistributions of source code must retain the above copyright 962053Smarkm * notice, this list of conditions and the following disclaimer. 1062053Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1162053Smarkm * notice, this list of conditions and the following disclaimer in the 1262053Smarkm * documentation and/or other materials provided with the distribution. 1362053Smarkm * 1462053Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1562053Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1662053Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1762053Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1862053Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1962053Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2062053Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2162053Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2262053Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2362053Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2462053Smarkm * SUCH DAMAGE. 2562053Smarkm * 2662053Smarkm */ 2762053Smarkm 2862053Smarkm#include <sys/cdefs.h> 2962053Smarkm__FBSDID("$FreeBSD: stable/11/sys/amd64/amd64/ptrace_machdep.c 331735 2018-03-29 15:08:40Z kib $"); 3062053Smarkm 3176166Smarkm#include "opt_compat.h" 3262053Smarkm 3376166Smarkm#include <sys/param.h> 3474771Smarkm#include <sys/systm.h> 3562053Smarkm#include <sys/malloc.h> 3674072Smarkm#include <sys/proc.h> 3776166Smarkm#include <sys/ptrace.h> 3862053Smarkm#include <sys/sysent.h> 3962053Smarkm#include <vm/vm.h> 4076166Smarkm#include <vm/pmap.h> 4167112Smarkm#include <machine/md_var.h> 4276166Smarkm#include <machine/pcb.h> 4376166Smarkm#include <machine/frame.h> 4470834Swollman#include <machine/vmparam.h> 4571037Smarkm 4676166Smarkm#ifdef COMPAT_FREEBSD32 4776166Smarkmstruct ptrace_xstate_info32 { 4867112Smarkm uint32_t xsave_mask1, xsave_mask2; 4974072Smarkm uint32_t xsave_len; 5062053Smarkm}; 5174072Smarkm#endif 5262053Smarkm 5362053Smarkmstatic int 5474072Smarkmcpu_ptrace_xstate(struct thread *td, int req, void *addr, int data) 5562053Smarkm{ 5674072Smarkm struct ptrace_xstate_info info; 5774072Smarkm#ifdef COMPAT_FREEBSD32 5874072Smarkm struct ptrace_xstate_info32 info32; 5974072Smarkm#endif 6074072Smarkm char *savefpu; 6174072Smarkm int error; 6262053Smarkm 6362053Smarkm if (!use_xsave) 6462053Smarkm return (EOPNOTSUPP); 6562053Smarkm 6662053Smarkm switch (req) { 6763855Smarkm case PT_GETXSTATE_OLD: 6869172Smarkm fpugetregs(td); 6962765Smarkm savefpu = (char *)(get_pcb_user_save_td(td) + 1); 7062765Smarkm error = copyout(savefpu, addr, 7165686Smarkm cpu_max_ext_state_size - sizeof(struct savefpu)); 7267112Smarkm break; 7362053Smarkm 7462053Smarkm case PT_SETXSTATE_OLD: 7562053Smarkm if (data > cpu_max_ext_state_size - sizeof(struct savefpu)) { 7662053Smarkm error = EINVAL; 7762053Smarkm break; 7862053Smarkm } 7962053Smarkm savefpu = malloc(data, M_TEMP, M_WAITOK); 8062053Smarkm error = copyin(addr, savefpu, data); 8162053Smarkm if (error == 0) { 8274072Smarkm fpugetregs(td); 8374072Smarkm error = fpusetxstate(td, savefpu, data); 8474072Smarkm } 8574072Smarkm free(savefpu, M_TEMP); 8674072Smarkm break; 8774072Smarkm 8874072Smarkm case PT_GETXSTATE_INFO: 8974072Smarkm#ifdef COMPAT_FREEBSD32 9074072Smarkm if (SV_CURPROC_FLAG(SV_ILP32)) { 9174072Smarkm if (data != sizeof(info32)) { 9274072Smarkm error = EINVAL; 9374072Smarkm } else { 9474072Smarkm info32.xsave_len = cpu_max_ext_state_size; 9574072Smarkm info32.xsave_mask1 = xsave_mask; 9674072Smarkm info32.xsave_mask2 = xsave_mask >> 32; 9774072Smarkm error = copyout(&info32, addr, data); 9874072Smarkm } 9974072Smarkm } else 10074072Smarkm#endif 10174072Smarkm { 10274072Smarkm if (data != sizeof(info)) { 10374072Smarkm error = EINVAL; 10462053Smarkm } else { 10574072Smarkm bzero(&info, sizeof(info)); 10674072Smarkm info.xsave_len = cpu_max_ext_state_size; 10762053Smarkm info.xsave_mask = xsave_mask; 10874072Smarkm error = copyout(&info, addr, data); 10974072Smarkm } 11074072Smarkm } 11174072Smarkm break; 11274072Smarkm 11374072Smarkm case PT_GETXSTATE: 11474072Smarkm fpugetregs(td); 11562053Smarkm savefpu = (char *)(get_pcb_user_save_td(td)); 11674072Smarkm error = copyout(savefpu, addr, cpu_max_ext_state_size); 11774072Smarkm break; 11874072Smarkm 11974072Smarkm case PT_SETXSTATE: 12074072Smarkm if (data < sizeof(struct savefpu) || 12174072Smarkm data > cpu_max_ext_state_size) { 12274072Smarkm error = EINVAL; 12374072Smarkm break; 12474072Smarkm } 12574072Smarkm savefpu = malloc(data, M_TEMP, M_WAITOK); 12674072Smarkm error = copyin(addr, savefpu, data); 12774072Smarkm if (error == 0) 12874072Smarkm error = fpusetregs(td, (struct savefpu *)savefpu, 12974072Smarkm savefpu + sizeof(struct savefpu), data - 13074072Smarkm sizeof(struct savefpu)); 13174072Smarkm free(savefpu, M_TEMP); 13274072Smarkm break; 13374072Smarkm 13474072Smarkm default: 13574072Smarkm error = EINVAL; 13674072Smarkm break; 13774072Smarkm } 13874072Smarkm 13974072Smarkm return (error); 14062053Smarkm} 14163855Smarkm 14263855Smarkmstatic void 14363855Smarkmcpu_ptrace_setbase(struct thread *td, int req, register_t r) 14463855Smarkm{ 14563855Smarkm struct pcb *pcb; 14663855Smarkm 14763855Smarkm pcb = td->td_pcb; 14863855Smarkm set_pcb_flags(pcb, PCB_FULL_IRET); 14963855Smarkm if (req == PT_SETFSBASE) { 15069172Smarkm pcb->pcb_fsbase = r; 15169172Smarkm td->td_frame->tf_fs = _ufssel; 15269174Smarkm } else { 15369172Smarkm pcb->pcb_gsbase = r; 15469172Smarkm td->td_frame->tf_gs = _ugssel; 15569172Smarkm } 15669172Smarkm} 15769172Smarkm 15862765Smarkm#ifdef COMPAT_FREEBSD32 15962053Smarkm#define PT_I386_GETXMMREGS (PT_FIRSTMACH + 0) 16074072Smarkm#define PT_I386_SETXMMREGS (PT_FIRSTMACH + 1) 16174072Smarkm 16274072Smarkmstatic int 16362053Smarkmcpu32_ptrace(struct thread *td, int req, void *addr, int data) 16474072Smarkm{ 16567286Speter struct savefpu *fpstate; 16667286Speter struct pcb *pcb; 16767112Smarkm uint32_t r; 16874072Smarkm int error; 16974072Smarkm 17067286Speter switch (req) { 17167286Speter case PT_I386_GETXMMREGS: 17267112Smarkm fpugetregs(td); 17367286Speter error = copyout(get_pcb_user_save_td(td), addr, 17467286Speter sizeof(*fpstate)); 17567286Speter break; 17667286Speter 17767286Speter case PT_I386_SETXMMREGS: 17867286Speter fpugetregs(td); 17967286Speter fpstate = get_pcb_user_save_td(td); 18062053Smarkm error = copyin(addr, fpstate, sizeof(*fpstate)); 18162053Smarkm fpstate->sv_env.en_mxcsr &= cpu_mxcsr_mask; 18262053Smarkm break; 18362053Smarkm 18462765Smarkm case PT_GETXSTATE_OLD: 18562053Smarkm case PT_SETXSTATE_OLD: 18674072Smarkm case PT_GETXSTATE_INFO: 18774072Smarkm case PT_GETXSTATE: 18874072Smarkm case PT_SETXSTATE: 18962053Smarkm error = cpu_ptrace_xstate(td, req, addr, data); 19074072Smarkm break; 19162765Smarkm 19262053Smarkm case PT_GETFSBASE: 19362053Smarkm case PT_GETGSBASE: 19462765Smarkm if (!SV_PROC_FLAG(td->td_proc, SV_ILP32)) { 19562053Smarkm error = EINVAL; 19662053Smarkm break; 19774072Smarkm } 19862053Smarkm pcb = td->td_pcb; 19962765Smarkm if (td == curthread) 20062053Smarkm update_pcb_bases(pcb); 20162053Smarkm r = req == PT_GETFSBASE ? pcb->pcb_fsbase : pcb->pcb_gsbase; 20262053Smarkm error = copyout(&r, addr, sizeof(r)); 20362053Smarkm break; 20465686Smarkm 20565686Smarkm case PT_SETFSBASE: 20674771Smarkm case PT_SETGSBASE: 20774771Smarkm if (!SV_PROC_FLAG(td->td_proc, SV_ILP32)) { 20874771Smarkm error = EINVAL; 20974771Smarkm break; 21074771Smarkm } 21174771Smarkm error = copyin(addr, &r, sizeof(r)); 21274771Smarkm if (error != 0) 21374771Smarkm break; 21465686Smarkm cpu_ptrace_setbase(td, req, r); 21565686Smarkm break; 21665686Smarkm 21767112Smarkm default: 21867112Smarkm error = EINVAL; 21974072Smarkm break; 22067112Smarkm } 22167112Smarkm 22267112Smarkm return (error); 22374072Smarkm} 22467112Smarkm#endif 22567112Smarkm 22674072Smarkmint 22767112Smarkmcpu_ptrace(struct thread *td, int req, void *addr, int data) 22867112Smarkm{ 22967112Smarkm register_t *r, rv; 23067112Smarkm struct pcb *pcb; 23167112Smarkm int error; 23262053Smarkm 23362053Smarkm#ifdef COMPAT_FREEBSD32 23474072Smarkm if (SV_CURPROC_FLAG(SV_ILP32)) 23565686Smarkm return (cpu32_ptrace(td, req, addr, data)); 23662053Smarkm#endif 23762053Smarkm 23874072Smarkm /* Support old values of PT_GETXSTATE_OLD and PT_SETXSTATE_OLD. */ 23971037Smarkm if (req == PT_FIRSTMACH + 0) 24074072Smarkm req = PT_GETXSTATE_OLD; 24174072Smarkm if (req == PT_FIRSTMACH + 1) 24274072Smarkm req = PT_SETXSTATE_OLD; 24374072Smarkm 24471037Smarkm switch (req) { 24574072Smarkm case PT_GETXSTATE_OLD: 24674072Smarkm case PT_SETXSTATE_OLD: 24774072Smarkm case PT_GETXSTATE_INFO: 24874072Smarkm case PT_GETXSTATE: 24974072Smarkm case PT_SETXSTATE: 25074072Smarkm error = cpu_ptrace_xstate(td, req, addr, data); 25174072Smarkm break; 25274072Smarkm 25374072Smarkm case PT_GETFSBASE: 25462053Smarkm case PT_GETGSBASE: 25562053Smarkm pcb = td->td_pcb; 25662765Smarkm if (td == curthread) 25762149Smarkm update_pcb_bases(pcb); 25874072Smarkm r = req == PT_GETFSBASE ? &pcb->pcb_fsbase : &pcb->pcb_gsbase; 25974072Smarkm error = copyout(r, addr, sizeof(*r)); 26074072Smarkm break; 26174072Smarkm 26274072Smarkm case PT_SETFSBASE: 26374072Smarkm case PT_SETGSBASE: 26474072Smarkm error = copyin(addr, &rv, sizeof(rv)); 26574072Smarkm if (error != 0) 26674072Smarkm break; 26774072Smarkm if (rv >= td->td_proc->p_sysent->sv_maxuser) { 26874072Smarkm error = EINVAL; 26974072Smarkm break; 27062053Smarkm } 27162053Smarkm cpu_ptrace_setbase(td, req, rv); 27262053Smarkm break; 27374072Smarkm 27474072Smarkm default: 27574072Smarkm error = EINVAL; 27674072Smarkm break; 27774072Smarkm } 27874072Smarkm 27974072Smarkm return (error); 28074072Smarkm} 28174072Smarkm