1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2011 Konstantin Belousov <kib@FreeBSD.org> 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 <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/elf.h> 34 #include <sys/lock.h> 35 #include <sys/malloc.h> 36 #include <sys/mutex.h> 37 #include <sys/proc.h> 38 #include <sys/ptrace.h> 39 #include <sys/reg.h> 40 #include <sys/sysent.h> 41 #include <vm/vm.h> 42 #include <vm/pmap.h> 43 #include <machine/md_var.h> 44 #include <machine/pcb.h> 45 #include <machine/frame.h> 46 #include <machine/vmparam.h> 47 48 #ifdef COMPAT_FREEBSD32 49 struct ptrace_xstate_info32 { 50 uint32_t xsave_mask1, xsave_mask2; 51 uint32_t xsave_len; 52 }; 53 #endif 54 55 static bool 56 get_segbases(struct regset *rs, struct thread *td, void *buf, 57 size_t *sizep) 58 { 59 struct segbasereg *reg; 60 struct pcb *pcb; 61 62 if (buf != NULL) { 63 KASSERT(*sizep == sizeof(*reg), ("%s: invalid size", __func__)); 64 reg = buf; 65 66 pcb = td->td_pcb; 67 if (td == curthread) 68 update_pcb_bases(pcb); 69 reg->r_fsbase = pcb->pcb_fsbase; 70 reg->r_gsbase = pcb->pcb_gsbase; 71 } 72 *sizep = sizeof(*reg); 73 return (true); 74 } 75 76 static bool 77 set_segbases(struct regset *rs, struct thread *td, void *buf, 78 size_t size) 79 { 80 struct segbasereg *reg; 81 struct pcb *pcb; 82 83 KASSERT(size == sizeof(*reg), ("%s: invalid size", __func__)); 84 reg = buf; 85 86 pcb = td->td_pcb; 87 set_pcb_flags(pcb, PCB_FULL_IRET); 88 pcb->pcb_fsbase = reg->r_fsbase; 89 td->td_frame->tf_fs = _ufssel; 90 pcb->pcb_gsbase = reg->r_gsbase; 91 td->td_frame->tf_gs = _ugssel; 92 93 return (true); 94 } 95 96 static struct regset regset_segbases = { 97 .note = NT_X86_SEGBASES, 98 .size = sizeof(struct segbasereg), 99 .get = get_segbases, 100 .set = set_segbases, 101 }; 102 ELF_REGSET(regset_segbases); 103 104 #ifdef COMPAT_FREEBSD32 105 static bool 106 get_segbases32(struct regset *rs, struct thread *td, void *buf, 107 size_t *sizep) 108 { 109 struct segbasereg32 *reg; 110 struct pcb *pcb; 111 112 if (buf != NULL) { 113 KASSERT(*sizep == sizeof(*reg), ("%s: invalid size", __func__)); 114 reg = buf; 115 116 pcb = td->td_pcb; 117 if (td == curthread) 118 update_pcb_bases(pcb); 119 reg->r_fsbase = (uint32_t)pcb->pcb_fsbase; 120 reg->r_gsbase = (uint32_t)pcb->pcb_gsbase; 121 } 122 *sizep = sizeof(*reg); 123 return (true); 124 } 125 126 static bool 127 set_segbases32(struct regset *rs, struct thread *td, void *buf, 128 size_t size) 129 { 130 struct segbasereg32 *reg; 131 struct pcb *pcb; 132 133 KASSERT(size == sizeof(*reg), ("%s: invalid size", __func__)); 134 reg = buf; 135 136 pcb = td->td_pcb; 137 set_pcb_flags(pcb, PCB_FULL_IRET); 138 pcb->pcb_fsbase = reg->r_fsbase; 139 td->td_frame->tf_fs = _ufssel; 140 pcb->pcb_gsbase = reg->r_gsbase; 141 td->td_frame->tf_gs = _ugssel; 142 143 return (true); 144 } 145 146 static struct regset regset_segbases32 = { 147 .note = NT_X86_SEGBASES, 148 .size = sizeof(struct segbasereg32), 149 .get = get_segbases32, 150 .set = set_segbases32, 151 }; 152 ELF32_REGSET(regset_segbases32); 153 #endif 154 155 static int 156 cpu_ptrace_xstate(struct thread *td, int req, void *addr, int data) 157 { 158 struct ptrace_xstate_info info; 159 #ifdef COMPAT_FREEBSD32 160 struct ptrace_xstate_info32 info32; 161 #endif 162 char *savefpu; 163 int error; 164 165 if (!use_xsave) 166 return (EOPNOTSUPP); 167 168 switch (req) { 169 case PT_GETXSTATE_OLD: 170 fpugetregs(td); 171 savefpu = (char *)(get_pcb_user_save_td(td) + 1); 172 error = copyout(savefpu, addr, 173 cpu_max_ext_state_size - sizeof(struct savefpu)); 174 break; 175 176 case PT_SETXSTATE_OLD: 177 if (data > cpu_max_ext_state_size - sizeof(struct savefpu)) { 178 error = EINVAL; 179 break; 180 } 181 savefpu = malloc(data, M_TEMP, M_WAITOK); 182 error = copyin(addr, savefpu, data); 183 if (error == 0) { 184 fpugetregs(td); 185 error = fpusetxstate(td, savefpu, data); 186 } 187 free(savefpu, M_TEMP); 188 break; 189 190 case PT_GETXSTATE_INFO: 191 #ifdef COMPAT_FREEBSD32 192 if (SV_CURPROC_FLAG(SV_ILP32)) { 193 if (data != sizeof(info32)) { 194 error = EINVAL; 195 } else { 196 info32.xsave_len = cpu_max_ext_state_size; 197 info32.xsave_mask1 = xsave_mask; 198 info32.xsave_mask2 = xsave_mask >> 32; 199 error = copyout(&info32, addr, data); 200 } 201 } else 202 #endif 203 { 204 if (data != sizeof(info)) { 205 error = EINVAL; 206 } else { 207 bzero(&info, sizeof(info)); 208 info.xsave_len = cpu_max_ext_state_size; 209 info.xsave_mask = xsave_mask; 210 error = copyout(&info, addr, data); 211 } 212 } 213 break; 214 215 case PT_GETXSTATE: 216 fpugetregs(td); 217 savefpu = (char *)(get_pcb_user_save_td(td)); 218 error = copyout(savefpu, addr, cpu_max_ext_state_size); 219 break; 220 221 case PT_SETXSTATE: 222 if (data < sizeof(struct savefpu) || 223 data > cpu_max_ext_state_size) { 224 error = EINVAL; 225 break; 226 } 227 savefpu = malloc(data, M_TEMP, M_WAITOK); 228 error = copyin(addr, savefpu, data); 229 if (error == 0) 230 error = fpusetregs(td, (struct savefpu *)savefpu, 231 savefpu + sizeof(struct savefpu), data - 232 sizeof(struct savefpu)); 233 free(savefpu, M_TEMP); 234 break; 235 236 default: 237 error = EINVAL; 238 break; 239 } 240 241 return (error); 242 } 243 244 static void 245 cpu_ptrace_setbase(struct thread *td, int req, register_t r) 246 { 247 struct pcb *pcb; 248 249 pcb = td->td_pcb; 250 set_pcb_flags(pcb, PCB_FULL_IRET); 251 if (req == PT_SETFSBASE) { 252 pcb->pcb_fsbase = r; 253 td->td_frame->tf_fs = _ufssel; 254 } else { 255 pcb->pcb_gsbase = r; 256 td->td_frame->tf_gs = _ugssel; 257 } 258 } 259 260 #ifdef COMPAT_FREEBSD32 261 #define PT_I386_GETXMMREGS (PT_FIRSTMACH + 0) 262 #define PT_I386_SETXMMREGS (PT_FIRSTMACH + 1) 263 264 static int 265 cpu32_ptrace(struct thread *td, int req, void *addr, int data) 266 { 267 struct savefpu *fpstate; 268 struct pcb *pcb; 269 uint32_t r; 270 int error; 271 272 switch (req) { 273 case PT_I386_GETXMMREGS: 274 fpugetregs(td); 275 error = copyout(get_pcb_user_save_td(td), addr, 276 sizeof(*fpstate)); 277 break; 278 279 case PT_I386_SETXMMREGS: 280 fpugetregs(td); 281 fpstate = get_pcb_user_save_td(td); 282 error = copyin(addr, fpstate, sizeof(*fpstate)); 283 fpstate->sv_env.en_mxcsr &= cpu_mxcsr_mask; 284 break; 285 286 case PT_GETXSTATE_OLD: 287 case PT_SETXSTATE_OLD: 288 case PT_GETXSTATE_INFO: 289 case PT_GETXSTATE: 290 case PT_SETXSTATE: 291 error = cpu_ptrace_xstate(td, req, addr, data); 292 break; 293 294 case PT_GETFSBASE: 295 case PT_GETGSBASE: 296 if (!SV_PROC_FLAG(td->td_proc, SV_ILP32)) { 297 error = EINVAL; 298 break; 299 } 300 pcb = td->td_pcb; 301 if (td == curthread) 302 update_pcb_bases(pcb); 303 r = req == PT_GETFSBASE ? pcb->pcb_fsbase : pcb->pcb_gsbase; 304 error = copyout(&r, addr, sizeof(r)); 305 break; 306 307 case PT_SETFSBASE: 308 case PT_SETGSBASE: 309 if (!SV_PROC_FLAG(td->td_proc, SV_ILP32)) { 310 error = EINVAL; 311 break; 312 } 313 error = copyin(addr, &r, sizeof(r)); 314 if (error != 0) 315 break; 316 cpu_ptrace_setbase(td, req, r); 317 break; 318 319 default: 320 error = EINVAL; 321 break; 322 } 323 324 return (error); 325 } 326 #endif 327 328 int 329 cpu_ptrace(struct thread *td, int req, void *addr, int data) 330 { 331 register_t *r, rv; 332 struct pcb *pcb; 333 int error; 334 335 #ifdef COMPAT_FREEBSD32 336 if (SV_CURPROC_FLAG(SV_ILP32)) 337 return (cpu32_ptrace(td, req, addr, data)); 338 #endif 339 340 /* Support old values of PT_GETXSTATE_OLD and PT_SETXSTATE_OLD. */ 341 if (req == PT_FIRSTMACH + 0) 342 req = PT_GETXSTATE_OLD; 343 if (req == PT_FIRSTMACH + 1) 344 req = PT_SETXSTATE_OLD; 345 346 switch (req) { 347 case PT_GETXSTATE_OLD: 348 case PT_SETXSTATE_OLD: 349 case PT_GETXSTATE_INFO: 350 case PT_GETXSTATE: 351 case PT_SETXSTATE: 352 error = cpu_ptrace_xstate(td, req, addr, data); 353 break; 354 355 case PT_GETFSBASE: 356 case PT_GETGSBASE: 357 pcb = td->td_pcb; 358 if (td == curthread) 359 update_pcb_bases(pcb); 360 r = req == PT_GETFSBASE ? &pcb->pcb_fsbase : &pcb->pcb_gsbase; 361 error = copyout(r, addr, sizeof(*r)); 362 break; 363 364 case PT_SETFSBASE: 365 case PT_SETGSBASE: 366 error = copyin(addr, &rv, sizeof(rv)); 367 if (error != 0) 368 break; 369 if (rv >= td->td_proc->p_sysent->sv_maxuser) { 370 error = EINVAL; 371 break; 372 } 373 cpu_ptrace_setbase(td, req, rv); 374 break; 375 376 default: 377 error = EINVAL; 378 break; 379 } 380 381 return (error); 382 } 383 384 int 385 ptrace_set_pc(struct thread *td, unsigned long addr) 386 { 387 388 td->td_frame->tf_rip = addr; 389 set_pcb_flags(td->td_pcb, PCB_FULL_IRET); 390 return (0); 391 } 392 393 int 394 ptrace_single_step(struct thread *td) 395 { 396 397 PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 398 if ((td->td_frame->tf_rflags & PSL_T) == 0) { 399 td->td_frame->tf_rflags |= PSL_T; 400 td->td_dbgflags |= TDB_STEP; 401 } 402 return (0); 403 } 404 405 int 406 ptrace_clear_single_step(struct thread *td) 407 { 408 409 PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 410 td->td_frame->tf_rflags &= ~PSL_T; 411 td->td_dbgflags &= ~TDB_STEP; 412 return (0); 413 } 414