1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2017 Edward Tomasz Napierala <trasz@FreeBSD.org> 5 * 6 * This software was developed by SRI International and the University of 7 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 8 * ("CTSRD"), as part of the DARPA CRASH research programme. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/param.h> 33 #include <sys/lock.h> 34 #include <sys/proc.h> 35 #include <sys/ptrace.h> 36 #include <sys/sx.h> 37 #include <sys/syscallsubr.h> 38 39 #include <machine/../linux/linux.h> 40 #include <machine/../linux/linux_proto.h> 41 #include <compat/linux/linux_emul.h> 42 #include <compat/linux/linux_errno.h> 43 #include <compat/linux/linux_misc.h> 44 #include <compat/linux/linux_signal.h> 45 #include <compat/linux/linux_util.h> 46 47 #define LINUX_PTRACE_TRACEME 0 48 #define LINUX_PTRACE_PEEKTEXT 1 49 #define LINUX_PTRACE_PEEKDATA 2 50 #define LINUX_PTRACE_PEEKUSER 3 51 #define LINUX_PTRACE_POKETEXT 4 52 #define LINUX_PTRACE_POKEDATA 5 53 #define LINUX_PTRACE_POKEUSER 6 54 #define LINUX_PTRACE_CONT 7 55 #define LINUX_PTRACE_KILL 8 56 #define LINUX_PTRACE_SINGLESTEP 9 57 #define LINUX_PTRACE_GETREGS 12 58 #define LINUX_PTRACE_SETREGS 13 59 #define LINUX_PTRACE_GETFPREGS 14 60 #define LINUX_PTRACE_SETFPREGS 15 61 #define LINUX_PTRACE_ATTACH 16 62 #define LINUX_PTRACE_DETACH 17 63 #define LINUX_PTRACE_SYSCALL 24 64 #define LINUX_PTRACE_SETOPTIONS 0x4200 65 #define LINUX_PTRACE_GETEVENTMSG 0x4201 66 #define LINUX_PTRACE_GETSIGINFO 0x4202 67 #define LINUX_PTRACE_GETREGSET 0x4204 68 #define LINUX_PTRACE_SEIZE 0x4206 69 #define LINUX_PTRACE_GET_SYSCALL_INFO 0x420e 70 71 #define LINUX_PTRACE_EVENT_EXEC 4 72 #define LINUX_PTRACE_EVENT_EXIT 6 73 74 #define LINUX_PTRACE_O_TRACESYSGOOD 1 75 #define LINUX_PTRACE_O_TRACEFORK 2 76 #define LINUX_PTRACE_O_TRACEVFORK 4 77 #define LINUX_PTRACE_O_TRACECLONE 8 78 #define LINUX_PTRACE_O_TRACEEXEC 16 79 #define LINUX_PTRACE_O_TRACEVFORKDONE 32 80 #define LINUX_PTRACE_O_TRACEEXIT 64 81 #define LINUX_PTRACE_O_TRACESECCOMP 128 82 #define LINUX_PTRACE_O_EXITKILL 1048576 83 #define LINUX_PTRACE_O_SUSPEND_SECCOMP 2097152 84 85 #define LINUX_NT_PRSTATUS 0x1 86 #define LINUX_NT_PRFPREG 0x2 87 #define LINUX_NT_X86_XSTATE 0x202 88 89 #define LINUX_PTRACE_O_MASK (LINUX_PTRACE_O_TRACESYSGOOD | \ 90 LINUX_PTRACE_O_TRACEFORK | LINUX_PTRACE_O_TRACEVFORK | \ 91 LINUX_PTRACE_O_TRACECLONE | LINUX_PTRACE_O_TRACEEXEC | \ 92 LINUX_PTRACE_O_TRACEVFORKDONE | LINUX_PTRACE_O_TRACEEXIT | \ 93 LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL | \ 94 LINUX_PTRACE_O_SUSPEND_SECCOMP) 95 96 #define LINUX_PTRACE_SYSCALL_INFO_NONE 0 97 #define LINUX_PTRACE_SYSCALL_INFO_ENTRY 1 98 #define LINUX_PTRACE_SYSCALL_INFO_EXIT 2 99 100 static int 101 map_signum(int lsig, int *bsigp) 102 { 103 int bsig; 104 105 if (lsig == 0) { 106 *bsigp = 0; 107 return (0); 108 } 109 110 if (lsig < 0 || lsig > LINUX_SIGRTMAX) 111 return (EINVAL); 112 113 bsig = linux_to_bsd_signal(lsig); 114 if (bsig == SIGSTOP) 115 bsig = 0; 116 117 *bsigp = bsig; 118 return (0); 119 } 120 121 int 122 linux_ptrace_status(struct thread *td, pid_t pid, int status) 123 { 124 struct ptrace_lwpinfo lwpinfo; 125 struct linux_pemuldata *pem; 126 register_t saved_retval; 127 int error; 128 129 saved_retval = td->td_retval[0]; 130 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo)); 131 td->td_retval[0] = saved_retval; 132 if (error != 0) { 133 linux_msg(td, "PT_LWPINFO failed with error %d", error); 134 return (status); 135 } 136 137 pem = pem_find(td->td_proc); 138 KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__)); 139 140 LINUX_PEM_SLOCK(pem); 141 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) && 142 lwpinfo.pl_flags & PL_FLAG_SCE) 143 status |= (LINUX_SIGTRAP | 0x80) << 8; 144 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) && 145 lwpinfo.pl_flags & PL_FLAG_SCX) { 146 if (lwpinfo.pl_flags & PL_FLAG_EXEC) 147 status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXEC << 8) << 8; 148 else 149 status |= (LINUX_SIGTRAP | 0x80) << 8; 150 } 151 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACEEXIT) && 152 lwpinfo.pl_flags & PL_FLAG_EXITED) 153 status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXIT << 8) << 8; 154 LINUX_PEM_SUNLOCK(pem); 155 156 return (status); 157 } 158 159 static int 160 linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data) 161 { 162 int error; 163 164 error = kern_ptrace(td, PT_READ_I, pid, addr, 0); 165 if (error == 0) 166 error = copyout(td->td_retval, data, sizeof(l_int)); 167 else if (error == ENOMEM) 168 error = EIO; 169 td->td_retval[0] = error; 170 171 return (error); 172 } 173 174 static int 175 linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data) 176 { 177 struct linux_pemuldata *pem; 178 int mask; 179 180 mask = 0; 181 182 if (data & ~LINUX_PTRACE_O_MASK) { 183 linux_msg(td, "unknown ptrace option %lx set; " 184 "returning EINVAL", 185 data & ~LINUX_PTRACE_O_MASK); 186 return (EINVAL); 187 } 188 189 pem = pem_find(td->td_proc); 190 KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__)); 191 192 /* 193 * PTRACE_O_EXITKILL is ignored, we do that by default. 194 */ 195 196 LINUX_PEM_XLOCK(pem); 197 if (data & LINUX_PTRACE_O_TRACESYSGOOD) { 198 pem->ptrace_flags |= LINUX_PTRACE_O_TRACESYSGOOD; 199 } else { 200 pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACESYSGOOD; 201 } 202 LINUX_PEM_XUNLOCK(pem); 203 204 if (data & LINUX_PTRACE_O_TRACEFORK) 205 mask |= PTRACE_FORK; 206 207 if (data & LINUX_PTRACE_O_TRACEVFORK) 208 mask |= PTRACE_VFORK; 209 210 if (data & LINUX_PTRACE_O_TRACECLONE) 211 mask |= PTRACE_VFORK; 212 213 if (data & LINUX_PTRACE_O_TRACEEXEC) 214 mask |= PTRACE_EXEC; 215 216 if (data & LINUX_PTRACE_O_TRACEVFORKDONE) 217 mask |= PTRACE_VFORK; /* XXX: Close enough? */ 218 219 if (data & LINUX_PTRACE_O_TRACEEXIT) { 220 pem->ptrace_flags |= LINUX_PTRACE_O_TRACEEXIT; 221 } else { 222 pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACEEXIT; 223 } 224 225 return (kern_ptrace(td, PT_SET_EVENT_MASK, pid, &mask, sizeof(mask))); 226 } 227 228 static int 229 linux_ptrace_geteventmsg(struct thread *td, pid_t pid, l_ulong data) 230 { 231 232 linux_msg(td, "PTRACE_GETEVENTMSG not implemented; returning EINVAL"); 233 return (EINVAL); 234 } 235 236 static int 237 linux_ptrace_getsiginfo(struct thread *td, pid_t pid, l_ulong data) 238 { 239 struct ptrace_lwpinfo lwpinfo; 240 l_siginfo_t l_siginfo; 241 int error, sig; 242 243 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo)); 244 if (error != 0) { 245 linux_msg(td, "PT_LWPINFO failed with error %d", error); 246 return (error); 247 } 248 249 if ((lwpinfo.pl_flags & PL_FLAG_SI) == 0) { 250 error = EINVAL; 251 linux_msg(td, "no PL_FLAG_SI, returning %d", error); 252 return (error); 253 } 254 255 sig = bsd_to_linux_signal(lwpinfo.pl_siginfo.si_signo); 256 memset(&l_siginfo, 0, sizeof(l_siginfo)); 257 siginfo_to_lsiginfo(&lwpinfo.pl_siginfo, &l_siginfo, sig); 258 error = copyout(&l_siginfo, (void *)data, sizeof(l_siginfo)); 259 return (error); 260 } 261 262 static int 263 linux_ptrace_getregs(struct thread *td, pid_t pid, void *data) 264 { 265 struct reg b_reg; 266 struct linux_pt_regset l_regset; 267 int error; 268 269 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0); 270 if (error != 0) 271 return (error); 272 273 bsd_to_linux_regset(&b_reg, &l_regset); 274 error = linux_ptrace_getregs_machdep(td, pid, &l_regset); 275 if (error != 0) 276 return (error); 277 278 error = copyout(&l_regset, (void *)data, sizeof(l_regset)); 279 return (error); 280 } 281 282 static int 283 linux_ptrace_setregs(struct thread *td, pid_t pid, void *data) 284 { 285 struct reg b_reg; 286 struct linux_pt_regset l_regset; 287 int error; 288 289 error = copyin(data, &l_regset, sizeof(l_regset)); 290 if (error != 0) 291 return (error); 292 linux_to_bsd_regset(&b_reg, &l_regset); 293 error = kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0); 294 return (error); 295 } 296 297 static int 298 linux_ptrace_getregset_prstatus(struct thread *td, pid_t pid, l_ulong data) 299 { 300 struct reg b_reg; 301 struct linux_pt_regset l_regset; 302 struct iovec iov; 303 size_t len; 304 int error; 305 306 error = copyin((const void *)data, &iov, sizeof(iov)); 307 if (error != 0) { 308 linux_msg(td, "copyin error %d", error); 309 return (error); 310 } 311 312 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0); 313 if (error != 0) 314 return (error); 315 316 bsd_to_linux_regset(&b_reg, &l_regset); 317 error = linux_ptrace_getregs_machdep(td, pid, &l_regset); 318 if (error != 0) 319 return (error); 320 321 len = MIN(iov.iov_len, sizeof(l_regset)); 322 error = copyout(&l_regset, (void *)iov.iov_base, len); 323 if (error != 0) { 324 linux_msg(td, "copyout error %d", error); 325 return (error); 326 } 327 328 iov.iov_len = len; 329 error = copyout(&iov, (void *)data, sizeof(iov)); 330 if (error != 0) { 331 linux_msg(td, "iov copyout error %d", error); 332 return (error); 333 } 334 335 return (error); 336 } 337 338 #ifdef __amd64__ 339 static int 340 linux_ptrace_getregset_prfpreg(struct thread *td, pid_t pid, l_ulong data) 341 { 342 struct fpreg b_fpreg; 343 struct linux_pt_fpregset l_fpregset; 344 struct iovec iov; 345 size_t len; 346 int error; 347 348 error = copyin((const void *)data, &iov, sizeof(iov)); 349 if (error != 0) { 350 linux_msg(td, "copyin error %d", error); 351 return (error); 352 } 353 354 error = kern_ptrace(td, PT_GETFPREGS, pid, &b_fpreg, 0); 355 if (error != 0) 356 return (error); 357 358 bsd_to_linux_fpregset(&b_fpreg, &l_fpregset); 359 360 len = MIN(iov.iov_len, sizeof(l_fpregset)); 361 error = copyout(&l_fpregset, iov.iov_base, len); 362 if (error != 0) { 363 linux_msg(td, "copyout error %d", error); 364 return (error); 365 } 366 367 iov.iov_len = len; 368 error = copyout(&iov, (void *)data, sizeof(iov)); 369 if (error != 0) 370 linux_msg(td, "iov copyout error %d", error); 371 372 return (error); 373 } 374 375 static int 376 linux_ptrace_getregset_xstate(struct thread *td, pid_t pid, l_ulong data) 377 { 378 struct ptrace_xstate_info info; 379 struct iovec iov; 380 void *xstate; 381 size_t len; 382 int error; 383 384 error = copyin((const void *)data, &iov, sizeof(iov)); 385 if (error != 0) { 386 linux_msg(td, "copyin error %d", error); 387 return (error); 388 } 389 390 error = kern_ptrace(td, PT_GETXSTATE_INFO, pid, &info, sizeof(info)); 391 if (error != 0) 392 return (error); 393 394 xstate = malloc(info.xsave_len, M_LINUX, M_WAITOK | M_ZERO); 395 396 error = kern_ptrace(td, PT_GETXSTATE, pid, xstate, info.xsave_len); 397 if (error != 0) { 398 free(xstate, M_LINUX); 399 return (error); 400 } 401 402 len = MIN(iov.iov_len, info.xsave_len); 403 error = copyout(xstate, iov.iov_base, len); 404 free(xstate, M_LINUX); 405 if (error != 0) { 406 linux_msg(td, "copyout error %d", error); 407 return (error); 408 } 409 410 iov.iov_len = len; 411 error = copyout(&iov, (void *)data, sizeof(iov)); 412 if (error != 0) 413 linux_msg(td, "iov copyout error %d", error); 414 415 return (error); 416 } 417 #endif /* __amd64__ */ 418 419 static int 420 linux_ptrace_getregset(struct thread *td, pid_t pid, l_ulong addr, l_ulong data) 421 { 422 423 switch (addr) { 424 case LINUX_NT_PRSTATUS: 425 return (linux_ptrace_getregset_prstatus(td, pid, data)); 426 #ifdef __amd64__ 427 case LINUX_NT_PRFPREG: 428 return (linux_ptrace_getregset_prfpreg(td, pid, data)); 429 case LINUX_NT_X86_XSTATE: 430 return (linux_ptrace_getregset_xstate(td, pid, data)); 431 #endif 432 default: 433 linux_msg(td, "PTRACE_GETREGSET request %#lx not implemented; " 434 "returning EINVAL", addr); 435 return (EINVAL); 436 } 437 } 438 439 static int 440 linux_ptrace_seize(struct thread *td, pid_t pid, l_ulong addr, l_ulong data) 441 { 442 443 linux_msg(td, "PTRACE_SEIZE not implemented; returning EINVAL"); 444 return (EINVAL); 445 } 446 447 static int 448 linux_ptrace_get_syscall_info(struct thread *td, pid_t pid, 449 l_ulong len, l_ulong data) 450 { 451 struct ptrace_lwpinfo lwpinfo; 452 struct ptrace_sc_ret sr; 453 struct reg b_reg; 454 struct syscall_info si; 455 int error; 456 457 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo)); 458 if (error != 0) { 459 linux_msg(td, "PT_LWPINFO failed with error %d", error); 460 return (error); 461 } 462 463 memset(&si, 0, sizeof(si)); 464 465 if (lwpinfo.pl_flags & PL_FLAG_SCE) { 466 si.op = LINUX_PTRACE_SYSCALL_INFO_ENTRY; 467 si.entry.nr = lwpinfo.pl_syscall_code; 468 error = kern_ptrace(td, PTLINUX_GET_SC_ARGS, pid, 469 si.entry.args, sizeof(si.entry.args)); 470 if (error != 0) { 471 linux_msg(td, 472 "PT_LINUX_GET_SC_ARGS failed with error %d", error); 473 return (error); 474 } 475 } else if (lwpinfo.pl_flags & PL_FLAG_SCX) { 476 si.op = LINUX_PTRACE_SYSCALL_INFO_EXIT; 477 error = kern_ptrace(td, PT_GET_SC_RET, pid, &sr, sizeof(sr)); 478 479 if (error != 0) { 480 linux_msg(td, "PT_GET_SC_RET failed with error %d", 481 error); 482 return (error); 483 } 484 485 if (sr.sr_error == 0) { 486 si.exit.rval = sr.sr_retval[0]; 487 si.exit.is_error = 0; 488 } else if (sr.sr_error == EJUSTRETURN) { 489 /* 490 * EJUSTRETURN means the actual value to return 491 * has already been put into td_frame; instead 492 * of extracting it and trying to determine whether 493 * it's an error or not just bail out and let 494 * the ptracing process fall back to another method. 495 */ 496 si.op = LINUX_PTRACE_SYSCALL_INFO_NONE; 497 } else if (sr.sr_error == ERESTART) { 498 si.exit.rval = -LINUX_ERESTARTSYS; 499 si.exit.is_error = 1; 500 } else { 501 si.exit.rval = bsd_to_linux_errno(sr.sr_error); 502 si.exit.is_error = 1; 503 } 504 } else { 505 si.op = LINUX_PTRACE_SYSCALL_INFO_NONE; 506 } 507 508 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0); 509 if (error != 0) 510 return (error); 511 512 linux_ptrace_get_syscall_info_machdep(&b_reg, &si); 513 514 len = MIN(len, sizeof(si)); 515 error = copyout(&si, (void *)data, len); 516 if (error == 0) 517 td->td_retval[0] = sizeof(si); 518 519 return (error); 520 } 521 522 int 523 linux_ptrace(struct thread *td, struct linux_ptrace_args *uap) 524 { 525 void *addr; 526 pid_t pid; 527 int error, sig; 528 529 if (!allow_ptrace) 530 return (ENOSYS); 531 532 pid = (pid_t)uap->pid; 533 addr = (void *)uap->addr; 534 535 switch (uap->req) { 536 case LINUX_PTRACE_TRACEME: 537 error = kern_ptrace(td, PT_TRACE_ME, 0, 0, 0); 538 break; 539 case LINUX_PTRACE_PEEKTEXT: 540 case LINUX_PTRACE_PEEKDATA: 541 error = linux_ptrace_peek(td, pid, addr, (void *)uap->data); 542 if (error != 0) 543 goto out; 544 /* 545 * Linux expects this syscall to read 64 bits, not 32. 546 */ 547 error = linux_ptrace_peek(td, pid, 548 (void *)(uap->addr + 4), (void *)(uap->data + 4)); 549 break; 550 case LINUX_PTRACE_PEEKUSER: 551 error = linux_ptrace_peekuser(td, pid, addr, (void *)uap->data); 552 break; 553 case LINUX_PTRACE_POKETEXT: 554 case LINUX_PTRACE_POKEDATA: 555 error = kern_ptrace(td, PT_WRITE_D, pid, addr, uap->data); 556 if (error != 0) 557 goto out; 558 /* 559 * Linux expects this syscall to write 64 bits, not 32. 560 */ 561 error = kern_ptrace(td, PT_WRITE_D, pid, 562 (void *)(uap->addr + 4), uap->data >> 32); 563 break; 564 case LINUX_PTRACE_POKEUSER: 565 error = linux_ptrace_pokeuser(td, pid, addr, (void *)uap->data); 566 break; 567 case LINUX_PTRACE_CONT: 568 error = map_signum(uap->data, &sig); 569 if (error != 0) 570 break; 571 error = kern_ptrace(td, PT_CONTINUE, pid, (void *)1, sig); 572 break; 573 case LINUX_PTRACE_KILL: 574 error = kern_ptrace(td, PT_KILL, pid, addr, uap->data); 575 break; 576 case LINUX_PTRACE_SINGLESTEP: 577 error = map_signum(uap->data, &sig); 578 if (error != 0) 579 break; 580 error = kern_ptrace(td, PT_STEP, pid, (void *)1, sig); 581 break; 582 case LINUX_PTRACE_GETREGS: 583 error = linux_ptrace_getregs(td, pid, (void *)uap->data); 584 break; 585 case LINUX_PTRACE_SETREGS: 586 error = linux_ptrace_setregs(td, pid, (void *)uap->data); 587 break; 588 case LINUX_PTRACE_ATTACH: 589 error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data); 590 break; 591 case LINUX_PTRACE_DETACH: 592 error = map_signum(uap->data, &sig); 593 if (error != 0) 594 break; 595 error = kern_ptrace(td, PT_DETACH, pid, (void *)1, sig); 596 break; 597 case LINUX_PTRACE_SYSCALL: 598 error = map_signum(uap->data, &sig); 599 if (error != 0) 600 break; 601 error = kern_ptrace(td, PT_SYSCALL, pid, (void *)1, sig); 602 break; 603 case LINUX_PTRACE_SETOPTIONS: 604 error = linux_ptrace_setoptions(td, pid, uap->data); 605 break; 606 case LINUX_PTRACE_GETEVENTMSG: 607 error = linux_ptrace_geteventmsg(td, pid, uap->data); 608 break; 609 case LINUX_PTRACE_GETSIGINFO: 610 error = linux_ptrace_getsiginfo(td, pid, uap->data); 611 break; 612 case LINUX_PTRACE_GETREGSET: 613 error = linux_ptrace_getregset(td, pid, uap->addr, uap->data); 614 break; 615 case LINUX_PTRACE_SEIZE: 616 error = linux_ptrace_seize(td, pid, uap->addr, uap->data); 617 break; 618 case LINUX_PTRACE_GET_SYSCALL_INFO: 619 error = linux_ptrace_get_syscall_info(td, pid, uap->addr, uap->data); 620 break; 621 default: 622 linux_msg(td, "ptrace(%ld, ...) not implemented; " 623 "returning EINVAL", uap->req); 624 error = EINVAL; 625 break; 626 } 627 628 out: 629 if (error == EBUSY) 630 error = ESRCH; 631 632 return (error); 633 } 634