1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2001 Alexander Kabaev 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 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include "opt_cpu.h" 33 34 #include <sys/param.h> 35 #include <sys/lock.h> 36 #include <sys/mutex.h> 37 #include <sys/proc.h> 38 #include <sys/ptrace.h> 39 #include <sys/syscallsubr.h> 40 #include <sys/systm.h> 41 42 #include <machine/md_var.h> 43 #include <machine/pcb.h> 44 45 #include <i386/linux/linux.h> 46 #include <i386/linux/linux_proto.h> 47 #include <compat/linux/linux_signal.h> 48 49 /* 50 * Linux ptrace requests numbers. Mostly identical to FreeBSD, 51 * except for MD ones and PT_ATTACH/PT_DETACH. 52 */ 53 #define PTRACE_TRACEME 0 54 #define PTRACE_PEEKTEXT 1 55 #define PTRACE_PEEKDATA 2 56 #define PTRACE_PEEKUSR 3 57 #define PTRACE_POKETEXT 4 58 #define PTRACE_POKEDATA 5 59 #define PTRACE_POKEUSR 6 60 #define PTRACE_CONT 7 61 #define PTRACE_KILL 8 62 #define PTRACE_SINGLESTEP 9 63 64 #define PTRACE_ATTACH 16 65 #define PTRACE_DETACH 17 66 67 #define LINUX_PTRACE_SYSCALL 24 68 69 #define PTRACE_GETREGS 12 70 #define PTRACE_SETREGS 13 71 #define PTRACE_GETFPREGS 14 72 #define PTRACE_SETFPREGS 15 73 #define PTRACE_GETFPXREGS 18 74 #define PTRACE_SETFPXREGS 19 75 76 #define PTRACE_SETOPTIONS 21 77 78 /* 79 * Linux keeps debug registers at the following 80 * offset in the user struct 81 */ 82 #define LINUX_DBREG_OFFSET 252 83 #define LINUX_DBREG_SIZE (8*sizeof(l_int)) 84 85 static __inline int 86 map_signum(int signum) 87 { 88 89 signum = linux_to_bsd_signal(signum); 90 return ((signum == SIGSTOP)? 0 : signum); 91 } 92 93 struct linux_pt_reg { 94 l_long ebx; 95 l_long ecx; 96 l_long edx; 97 l_long esi; 98 l_long edi; 99 l_long ebp; 100 l_long eax; 101 l_int xds; 102 l_int xes; 103 l_int xfs; 104 l_int xgs; 105 l_long orig_eax; 106 l_long eip; 107 l_int xcs; 108 l_long eflags; 109 l_long esp; 110 l_int xss; 111 }; 112 113 /* 114 * Translate i386 ptrace registers between Linux and FreeBSD formats. 115 * The translation is pretty straighforward, for all registers, but 116 * orig_eax on Linux side and r_trapno and r_err in FreeBSD 117 */ 118 static void 119 map_regs_to_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r) 120 { 121 linux_r->ebx = bsd_r->r_ebx; 122 linux_r->ecx = bsd_r->r_ecx; 123 linux_r->edx = bsd_r->r_edx; 124 linux_r->esi = bsd_r->r_esi; 125 linux_r->edi = bsd_r->r_edi; 126 linux_r->ebp = bsd_r->r_ebp; 127 linux_r->eax = bsd_r->r_eax; 128 linux_r->xds = bsd_r->r_ds; 129 linux_r->xes = bsd_r->r_es; 130 linux_r->xfs = bsd_r->r_fs; 131 linux_r->xgs = bsd_r->r_gs; 132 linux_r->orig_eax = bsd_r->r_eax; 133 linux_r->eip = bsd_r->r_eip; 134 linux_r->xcs = bsd_r->r_cs; 135 linux_r->eflags = bsd_r->r_eflags; 136 linux_r->esp = bsd_r->r_esp; 137 linux_r->xss = bsd_r->r_ss; 138 } 139 140 static void 141 map_regs_from_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r) 142 { 143 bsd_r->r_ebx = linux_r->ebx; 144 bsd_r->r_ecx = linux_r->ecx; 145 bsd_r->r_edx = linux_r->edx; 146 bsd_r->r_esi = linux_r->esi; 147 bsd_r->r_edi = linux_r->edi; 148 bsd_r->r_ebp = linux_r->ebp; 149 bsd_r->r_eax = linux_r->eax; 150 bsd_r->r_ds = linux_r->xds; 151 bsd_r->r_es = linux_r->xes; 152 bsd_r->r_fs = linux_r->xfs; 153 bsd_r->r_gs = linux_r->xgs; 154 bsd_r->r_eip = linux_r->eip; 155 bsd_r->r_cs = linux_r->xcs; 156 bsd_r->r_eflags = linux_r->eflags; 157 bsd_r->r_esp = linux_r->esp; 158 bsd_r->r_ss = linux_r->xss; 159 } 160 161 struct linux_pt_fpreg { 162 l_long cwd; 163 l_long swd; 164 l_long twd; 165 l_long fip; 166 l_long fcs; 167 l_long foo; 168 l_long fos; 169 l_long st_space[2*10]; 170 }; 171 172 static void 173 map_fpregs_to_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r) 174 { 175 linux_r->cwd = bsd_r->fpr_env[0]; 176 linux_r->swd = bsd_r->fpr_env[1]; 177 linux_r->twd = bsd_r->fpr_env[2]; 178 linux_r->fip = bsd_r->fpr_env[3]; 179 linux_r->fcs = bsd_r->fpr_env[4]; 180 linux_r->foo = bsd_r->fpr_env[5]; 181 linux_r->fos = bsd_r->fpr_env[6]; 182 bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(linux_r->st_space)); 183 } 184 185 static void 186 map_fpregs_from_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r) 187 { 188 bsd_r->fpr_env[0] = linux_r->cwd; 189 bsd_r->fpr_env[1] = linux_r->swd; 190 bsd_r->fpr_env[2] = linux_r->twd; 191 bsd_r->fpr_env[3] = linux_r->fip; 192 bsd_r->fpr_env[4] = linux_r->fcs; 193 bsd_r->fpr_env[5] = linux_r->foo; 194 bsd_r->fpr_env[6] = linux_r->fos; 195 bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(bsd_r->fpr_acc)); 196 } 197 198 struct linux_pt_fpxreg { 199 l_ushort cwd; 200 l_ushort swd; 201 l_ushort twd; 202 l_ushort fop; 203 l_long fip; 204 l_long fcs; 205 l_long foo; 206 l_long fos; 207 l_long mxcsr; 208 l_long reserved; 209 l_long st_space[32]; 210 l_long xmm_space[32]; 211 l_long padding[56]; 212 }; 213 214 static int 215 linux_proc_read_fpxregs(struct thread *td, struct linux_pt_fpxreg *fpxregs) 216 { 217 218 PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 219 if (cpu_fxsr == 0 || (td->td_proc->p_flag & P_INMEM) == 0) 220 return (EIO); 221 bcopy(&get_pcb_user_save_td(td)->sv_xmm, fpxregs, sizeof(*fpxregs)); 222 return (0); 223 } 224 225 static int 226 linux_proc_write_fpxregs(struct thread *td, struct linux_pt_fpxreg *fpxregs) 227 { 228 229 PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 230 if (cpu_fxsr == 0 || (td->td_proc->p_flag & P_INMEM) == 0) 231 return (EIO); 232 bcopy(fpxregs, &get_pcb_user_save_td(td)->sv_xmm, sizeof(*fpxregs)); 233 return (0); 234 } 235 236 int 237 linux_ptrace(struct thread *td, struct linux_ptrace_args *uap) 238 { 239 union { 240 struct linux_pt_reg reg; 241 struct linux_pt_fpreg fpreg; 242 struct linux_pt_fpxreg fpxreg; 243 } r; 244 union { 245 struct reg bsd_reg; 246 struct fpreg bsd_fpreg; 247 struct dbreg bsd_dbreg; 248 } u; 249 void *addr; 250 pid_t pid; 251 int error, req; 252 253 error = 0; 254 255 /* by default, just copy data intact */ 256 req = uap->req; 257 pid = (pid_t)uap->pid; 258 addr = (void *)uap->addr; 259 260 switch (req) { 261 case PTRACE_TRACEME: 262 case PTRACE_POKETEXT: 263 case PTRACE_POKEDATA: 264 case PTRACE_KILL: 265 error = kern_ptrace(td, req, pid, addr, uap->data); 266 break; 267 case PTRACE_PEEKTEXT: 268 case PTRACE_PEEKDATA: { 269 /* need to preserve return value */ 270 int rval = td->td_retval[0]; 271 error = kern_ptrace(td, req, pid, addr, 0); 272 if (error == 0) 273 error = copyout(td->td_retval, (void *)uap->data, 274 sizeof(l_int)); 275 td->td_retval[0] = rval; 276 break; 277 } 278 case PTRACE_DETACH: 279 error = kern_ptrace(td, PT_DETACH, pid, (void *)1, 280 map_signum(uap->data)); 281 break; 282 case PTRACE_SINGLESTEP: 283 case PTRACE_CONT: 284 error = kern_ptrace(td, req, pid, (void *)1, 285 map_signum(uap->data)); 286 break; 287 case PTRACE_ATTACH: 288 error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data); 289 break; 290 case PTRACE_GETREGS: 291 /* Linux is using data where FreeBSD is using addr */ 292 error = kern_ptrace(td, PT_GETREGS, pid, &u.bsd_reg, 0); 293 if (error == 0) { 294 map_regs_to_linux(&u.bsd_reg, &r.reg); 295 error = copyout(&r.reg, (void *)uap->data, 296 sizeof(r.reg)); 297 } 298 break; 299 case PTRACE_SETREGS: 300 /* Linux is using data where FreeBSD is using addr */ 301 error = copyin((void *)uap->data, &r.reg, sizeof(r.reg)); 302 if (error == 0) { 303 map_regs_from_linux(&u.bsd_reg, &r.reg); 304 error = kern_ptrace(td, PT_SETREGS, pid, &u.bsd_reg, 0); 305 } 306 break; 307 case PTRACE_GETFPREGS: 308 /* Linux is using data where FreeBSD is using addr */ 309 error = kern_ptrace(td, PT_GETFPREGS, pid, &u.bsd_fpreg, 0); 310 if (error == 0) { 311 map_fpregs_to_linux(&u.bsd_fpreg, &r.fpreg); 312 error = copyout(&r.fpreg, (void *)uap->data, 313 sizeof(r.fpreg)); 314 } 315 break; 316 case PTRACE_SETFPREGS: 317 /* Linux is using data where FreeBSD is using addr */ 318 error = copyin((void *)uap->data, &r.fpreg, sizeof(r.fpreg)); 319 if (error == 0) { 320 map_fpregs_from_linux(&u.bsd_fpreg, &r.fpreg); 321 error = kern_ptrace(td, PT_SETFPREGS, pid, 322 &u.bsd_fpreg, 0); 323 } 324 break; 325 case PTRACE_SETFPXREGS: 326 error = copyin((void *)uap->data, &r.fpxreg, sizeof(r.fpxreg)); 327 if (error) 328 break; 329 /* FALL THROUGH */ 330 case PTRACE_GETFPXREGS: { 331 struct proc *p; 332 struct thread *td2; 333 334 if (sizeof(struct linux_pt_fpxreg) != sizeof(struct savexmm)) { 335 static int once = 0; 336 if (!once) { 337 printf("linux: savexmm != linux_pt_fpxreg\n"); 338 once = 1; 339 } 340 error = EIO; 341 break; 342 } 343 344 if ((p = pfind(uap->pid)) == NULL) { 345 error = ESRCH; 346 break; 347 } 348 349 /* Exiting processes can't be debugged. */ 350 if ((p->p_flag & P_WEXIT) != 0) { 351 error = ESRCH; 352 goto fail; 353 } 354 355 if ((error = p_candebug(td, p)) != 0) 356 goto fail; 357 358 /* System processes can't be debugged. */ 359 if ((p->p_flag & P_SYSTEM) != 0) { 360 error = EINVAL; 361 goto fail; 362 } 363 364 /* not being traced... */ 365 if ((p->p_flag & P_TRACED) == 0) { 366 error = EPERM; 367 goto fail; 368 } 369 370 /* not being traced by YOU */ 371 if (p->p_pptr != td->td_proc) { 372 error = EBUSY; 373 goto fail; 374 } 375 376 /* not currently stopped */ 377 if (!P_SHOULDSTOP(p) || (p->p_flag & P_WAITED) == 0) { 378 error = EBUSY; 379 goto fail; 380 } 381 382 if (req == PTRACE_GETFPXREGS) { 383 _PHOLD(p); /* may block */ 384 td2 = FIRST_THREAD_IN_PROC(p); 385 error = linux_proc_read_fpxregs(td2, &r.fpxreg); 386 _PRELE(p); 387 PROC_UNLOCK(p); 388 if (error == 0) 389 error = copyout(&r.fpxreg, (void *)uap->data, 390 sizeof(r.fpxreg)); 391 } else { 392 /* clear dangerous bits exactly as Linux does*/ 393 r.fpxreg.mxcsr &= 0xffbf; 394 _PHOLD(p); /* may block */ 395 td2 = FIRST_THREAD_IN_PROC(p); 396 error = linux_proc_write_fpxregs(td2, &r.fpxreg); 397 _PRELE(p); 398 PROC_UNLOCK(p); 399 } 400 break; 401 402 fail: 403 PROC_UNLOCK(p); 404 break; 405 } 406 case PTRACE_PEEKUSR: 407 case PTRACE_POKEUSR: { 408 error = EIO; 409 410 /* check addr for alignment */ 411 if (uap->addr < 0 || uap->addr & (sizeof(l_int) - 1)) 412 break; 413 /* 414 * Allow Linux programs to access register values in 415 * user struct. We simulate this through PT_GET/SETREGS 416 * as necessary. 417 */ 418 if (uap->addr < sizeof(struct linux_pt_reg)) { 419 error = kern_ptrace(td, PT_GETREGS, pid, &u.bsd_reg, 0); 420 if (error != 0) 421 break; 422 423 map_regs_to_linux(&u.bsd_reg, &r.reg); 424 if (req == PTRACE_PEEKUSR) { 425 error = copyout((char *)&r.reg + uap->addr, 426 (void *)uap->data, sizeof(l_int)); 427 break; 428 } 429 430 *(l_int *)((char *)&r.reg + uap->addr) = 431 (l_int)uap->data; 432 433 map_regs_from_linux(&u.bsd_reg, &r.reg); 434 error = kern_ptrace(td, PT_SETREGS, pid, &u.bsd_reg, 0); 435 } 436 437 /* 438 * Simulate debug registers access 439 */ 440 if (uap->addr >= LINUX_DBREG_OFFSET && 441 uap->addr <= LINUX_DBREG_OFFSET + LINUX_DBREG_SIZE) { 442 error = kern_ptrace(td, PT_GETDBREGS, pid, &u.bsd_dbreg, 443 0); 444 if (error != 0) 445 break; 446 447 uap->addr -= LINUX_DBREG_OFFSET; 448 if (req == PTRACE_PEEKUSR) { 449 error = copyout((char *)&u.bsd_dbreg + 450 uap->addr, (void *)uap->data, 451 sizeof(l_int)); 452 break; 453 } 454 455 *(l_int *)((char *)&u.bsd_dbreg + uap->addr) = 456 uap->data; 457 error = kern_ptrace(td, PT_SETDBREGS, pid, 458 &u.bsd_dbreg, 0); 459 } 460 461 break; 462 } 463 case LINUX_PTRACE_SYSCALL: 464 /* fall through */ 465 default: 466 printf("linux: ptrace(%u, ...) not implemented\n", 467 (unsigned int)uap->req); 468 error = EINVAL; 469 break; 470 } 471 472 return (error); 473 } 474