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