1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include <sys/param.h> 36 #include <sys/lock.h> 37 #include <sys/proc.h> 38 #include <sys/ptrace.h> 39 #include <sys/sx.h> 40 #include <sys/syscallsubr.h> 41 42 #include <machine/pcb.h> 43 44 #include <machine/../linux/linux.h> 45 #include <machine/../linux/linux_proto.h> 46 #include <compat/linux/linux_emul.h> 47 #include <compat/linux/linux_errno.h> 48 #include <compat/linux/linux_misc.h> 49 #include <compat/linux/linux_signal.h> 50 #include <compat/linux/linux_util.h> 51 52 #define LINUX_PTRACE_TRACEME 0 53 #define LINUX_PTRACE_PEEKTEXT 1 54 #define LINUX_PTRACE_PEEKDATA 2 55 #define LINUX_PTRACE_PEEKUSER 3 56 #define LINUX_PTRACE_POKETEXT 4 57 #define LINUX_PTRACE_POKEDATA 5 58 #define LINUX_PTRACE_POKEUSER 6 59 #define LINUX_PTRACE_CONT 7 60 #define LINUX_PTRACE_KILL 8 61 #define LINUX_PTRACE_SINGLESTEP 9 62 #define LINUX_PTRACE_GETREGS 12 63 #define LINUX_PTRACE_SETREGS 13 64 #define LINUX_PTRACE_GETFPREGS 14 65 #define LINUX_PTRACE_SETFPREGS 15 66 #define LINUX_PTRACE_ATTACH 16 67 #define LINUX_PTRACE_DETACH 17 68 #define LINUX_PTRACE_SYSCALL 24 69 #define LINUX_PTRACE_SETOPTIONS 0x4200 70 #define LINUX_PTRACE_GETEVENTMSG 0x4201 71 #define LINUX_PTRACE_GETSIGINFO 0x4202 72 #define LINUX_PTRACE_GETREGSET 0x4204 73 #define LINUX_PTRACE_SEIZE 0x4206 74 #define LINUX_PTRACE_GET_SYSCALL_INFO 0x420e 75 76 #define LINUX_PTRACE_EVENT_EXEC 4 77 #define LINUX_PTRACE_EVENT_EXIT 6 78 79 #define LINUX_PTRACE_O_TRACESYSGOOD 1 80 #define LINUX_PTRACE_O_TRACEFORK 2 81 #define LINUX_PTRACE_O_TRACEVFORK 4 82 #define LINUX_PTRACE_O_TRACECLONE 8 83 #define LINUX_PTRACE_O_TRACEEXEC 16 84 #define LINUX_PTRACE_O_TRACEVFORKDONE 32 85 #define LINUX_PTRACE_O_TRACEEXIT 64 86 #define LINUX_PTRACE_O_TRACESECCOMP 128 87 #define LINUX_PTRACE_O_EXITKILL 1048576 88 #define LINUX_PTRACE_O_SUSPEND_SECCOMP 2097152 89 90 #define LINUX_NT_PRSTATUS 0x1 91 #define LINUX_NT_PRFPREG 0x2 92 #define LINUX_NT_X86_XSTATE 0x202 93 94 #define LINUX_PTRACE_O_MASK (LINUX_PTRACE_O_TRACESYSGOOD | \ 95 LINUX_PTRACE_O_TRACEFORK | LINUX_PTRACE_O_TRACEVFORK | \ 96 LINUX_PTRACE_O_TRACECLONE | LINUX_PTRACE_O_TRACEEXEC | \ 97 LINUX_PTRACE_O_TRACEVFORKDONE | LINUX_PTRACE_O_TRACEEXIT | \ 98 LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL | \ 99 LINUX_PTRACE_O_SUSPEND_SECCOMP) 100 101 #define LINUX_PTRACE_SYSCALL_INFO_NONE 0 102 #define LINUX_PTRACE_SYSCALL_INFO_ENTRY 1 103 #define LINUX_PTRACE_SYSCALL_INFO_EXIT 2 104 105 #define LINUX_PTRACE_PEEKUSER_ORIG_RAX 120 106 #define LINUX_PTRACE_PEEKUSER_RIP 128 107 #define LINUX_PTRACE_PEEKUSER_CS 136 108 #define LINUX_PTRACE_PEEKUSER_DS 184 109 110 static int 111 map_signum(int lsig, int *bsigp) 112 { 113 int bsig; 114 115 if (lsig == 0) { 116 *bsigp = 0; 117 return (0); 118 } 119 120 if (lsig < 0 || lsig > LINUX_SIGRTMAX) 121 return (EINVAL); 122 123 bsig = linux_to_bsd_signal(lsig); 124 if (bsig == SIGSTOP) 125 bsig = 0; 126 127 *bsigp = bsig; 128 return (0); 129 } 130 131 int 132 linux_ptrace_status(struct thread *td, pid_t pid, int status) 133 { 134 struct ptrace_lwpinfo lwpinfo; 135 struct linux_pemuldata *pem; 136 register_t saved_retval; 137 int error; 138 139 saved_retval = td->td_retval[0]; 140 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo)); 141 td->td_retval[0] = saved_retval; 142 if (error != 0) { 143 linux_msg(td, "PT_LWPINFO failed with error %d", error); 144 return (status); 145 } 146 147 pem = pem_find(td->td_proc); 148 KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__)); 149 150 LINUX_PEM_SLOCK(pem); 151 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) && 152 lwpinfo.pl_flags & PL_FLAG_SCE) 153 status |= (LINUX_SIGTRAP | 0x80) << 8; 154 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) && 155 lwpinfo.pl_flags & PL_FLAG_SCX) { 156 if (lwpinfo.pl_flags & PL_FLAG_EXEC) 157 status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXEC << 8) << 8; 158 else 159 status |= (LINUX_SIGTRAP | 0x80) << 8; 160 } 161 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACEEXIT) && 162 lwpinfo.pl_flags & PL_FLAG_EXITED) 163 status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXIT << 8) << 8; 164 LINUX_PEM_SUNLOCK(pem); 165 166 return (status); 167 } 168 169 static int 170 linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data) 171 { 172 int error; 173 174 error = kern_ptrace(td, PT_READ_I, pid, addr, 0); 175 if (error == 0) 176 error = copyout(td->td_retval, data, sizeof(l_int)); 177 else if (error == ENOMEM) 178 error = EIO; 179 td->td_retval[0] = error; 180 181 return (error); 182 } 183 184 static int 185 linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data) 186 { 187 struct reg b_reg; 188 uint64_t val; 189 int error; 190 191 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0); 192 if (error != 0) 193 return (error); 194 195 switch ((uintptr_t)addr) { 196 #ifdef __amd64__ 197 case LINUX_PTRACE_PEEKUSER_ORIG_RAX: 198 val = b_reg.r_rax; 199 break; 200 case LINUX_PTRACE_PEEKUSER_RIP: 201 val = b_reg.r_rip; 202 break; 203 case LINUX_PTRACE_PEEKUSER_CS: 204 val = b_reg.r_cs; 205 break; 206 case LINUX_PTRACE_PEEKUSER_DS: 207 val = b_reg.r_ds; 208 break; 209 #endif /* __amd64__ */ 210 default: 211 linux_msg(td, "PTRACE_PEEKUSER offset %ld not implemented; " 212 "returning EINVAL", (uintptr_t)addr); 213 return (EINVAL); 214 } 215 216 error = copyout(&val, data, sizeof(val)); 217 td->td_retval[0] = error; 218 219 return (error); 220 } 221 222 static int 223 linux_ptrace_pokeuser(struct thread *td, pid_t pid, void *addr, void *data) 224 { 225 226 linux_msg(td, "PTRACE_POKEUSER not implemented; returning EINVAL"); 227 return (EINVAL); 228 } 229 230 static int 231 linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data) 232 { 233 struct linux_pemuldata *pem; 234 int mask; 235 236 mask = 0; 237 238 if (data & ~LINUX_PTRACE_O_MASK) { 239 linux_msg(td, "unknown ptrace option %lx set; " 240 "returning EINVAL", 241 data & ~LINUX_PTRACE_O_MASK); 242 return (EINVAL); 243 } 244 245 pem = pem_find(td->td_proc); 246 KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__)); 247 248 /* 249 * PTRACE_O_EXITKILL is ignored, we do that by default. 250 */ 251 252 LINUX_PEM_XLOCK(pem); 253 if (data & LINUX_PTRACE_O_TRACESYSGOOD) { 254 pem->ptrace_flags |= LINUX_PTRACE_O_TRACESYSGOOD; 255 } else { 256 pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACESYSGOOD; 257 } 258 LINUX_PEM_XUNLOCK(pem); 259 260 if (data & LINUX_PTRACE_O_TRACEFORK) 261 mask |= PTRACE_FORK; 262 263 if (data & LINUX_PTRACE_O_TRACEVFORK) 264 mask |= PTRACE_VFORK; 265 266 if (data & LINUX_PTRACE_O_TRACECLONE) 267 mask |= PTRACE_VFORK; 268 269 if (data & LINUX_PTRACE_O_TRACEEXEC) 270 mask |= PTRACE_EXEC; 271 272 if (data & LINUX_PTRACE_O_TRACEVFORKDONE) 273 mask |= PTRACE_VFORK; /* XXX: Close enough? */ 274 275 if (data & LINUX_PTRACE_O_TRACEEXIT) { 276 pem->ptrace_flags |= LINUX_PTRACE_O_TRACEEXIT; 277 } else { 278 pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACEEXIT; 279 } 280 281 return (kern_ptrace(td, PT_SET_EVENT_MASK, pid, &mask, sizeof(mask))); 282 } 283 284 static int 285 linux_ptrace_geteventmsg(struct thread *td, pid_t pid, l_ulong data) 286 { 287 288 linux_msg(td, "PTRACE_GETEVENTMSG not implemented; returning EINVAL"); 289 return (EINVAL); 290 } 291 292 static int 293 linux_ptrace_getsiginfo(struct thread *td, pid_t pid, l_ulong data) 294 { 295 struct ptrace_lwpinfo lwpinfo; 296 l_siginfo_t l_siginfo; 297 int error, sig; 298 299 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo)); 300 if (error != 0) { 301 linux_msg(td, "PT_LWPINFO failed with error %d", error); 302 return (error); 303 } 304 305 if ((lwpinfo.pl_flags & PL_FLAG_SI) == 0) { 306 error = EINVAL; 307 linux_msg(td, "no PL_FLAG_SI, returning %d", error); 308 return (error); 309 } 310 311 sig = bsd_to_linux_signal(lwpinfo.pl_siginfo.si_signo); 312 memset(&l_siginfo, 0, sizeof(l_siginfo)); 313 siginfo_to_lsiginfo(&lwpinfo.pl_siginfo, &l_siginfo, sig); 314 error = copyout(&l_siginfo, (void *)data, sizeof(l_siginfo)); 315 return (error); 316 } 317 318 static int 319 linux_ptrace_getregs(struct thread *td, pid_t pid, void *data) 320 { 321 struct reg b_reg; 322 struct linux_pt_regset l_regset; 323 int error; 324 325 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0); 326 if (error != 0) 327 return (error); 328 329 bsd_to_linux_regset(&b_reg, &l_regset); 330 error = linux_ptrace_getregs_machdep(td, pid, &l_regset); 331 if (error != 0) 332 return (error); 333 334 error = copyout(&l_regset, (void *)data, sizeof(l_regset)); 335 return (error); 336 } 337 338 static int 339 linux_ptrace_setregs(struct thread *td, pid_t pid, void *data) 340 { 341 struct reg b_reg; 342 struct linux_pt_regset l_regset; 343 int error; 344 345 error = copyin(data, &l_regset, sizeof(l_regset)); 346 if (error != 0) 347 return (error); 348 linux_to_bsd_regset(&b_reg, &l_regset); 349 error = kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0); 350 return (error); 351 } 352 353 static int 354 linux_ptrace_getregset_prstatus(struct thread *td, pid_t pid, l_ulong data) 355 { 356 struct reg b_reg; 357 struct linux_pt_regset l_regset; 358 struct iovec iov; 359 size_t len; 360 int error; 361 362 error = copyin((const void *)data, &iov, sizeof(iov)); 363 if (error != 0) { 364 linux_msg(td, "copyin error %d", error); 365 return (error); 366 } 367 368 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0); 369 if (error != 0) 370 return (error); 371 372 bsd_to_linux_regset(&b_reg, &l_regset); 373 error = linux_ptrace_getregs_machdep(td, pid, &l_regset); 374 if (error != 0) 375 return (error); 376 377 len = MIN(iov.iov_len, sizeof(l_regset)); 378 error = copyout(&l_regset, (void *)iov.iov_base, len); 379 if (error != 0) { 380 linux_msg(td, "copyout error %d", error); 381 return (error); 382 } 383 384 iov.iov_len = len; 385 error = copyout(&iov, (void *)data, sizeof(iov)); 386 if (error != 0) { 387 linux_msg(td, "iov copyout error %d", error); 388 return (error); 389 } 390 391 return (error); 392 } 393 394 static int 395 linux_ptrace_getregset(struct thread *td, pid_t pid, l_ulong addr, l_ulong data) 396 { 397 398 switch (addr) { 399 case LINUX_NT_PRSTATUS: 400 return (linux_ptrace_getregset_prstatus(td, pid, data)); 401 case LINUX_NT_PRFPREG: 402 linux_msg(td, "PTRAGE_GETREGSET NT_PRFPREG not implemented; " 403 "returning EINVAL"); 404 return (EINVAL); 405 case LINUX_NT_X86_XSTATE: 406 linux_msg(td, "PTRAGE_GETREGSET NT_X86_XSTATE not implemented; " 407 "returning EINVAL"); 408 return (EINVAL); 409 default: 410 linux_msg(td, "PTRACE_GETREGSET request %#lx not implemented; " 411 "returning EINVAL", addr); 412 return (EINVAL); 413 } 414 } 415 416 static int 417 linux_ptrace_seize(struct thread *td, pid_t pid, l_ulong addr, l_ulong data) 418 { 419 420 linux_msg(td, "PTRACE_SEIZE not implemented; returning EINVAL"); 421 return (EINVAL); 422 } 423 424 static int 425 linux_ptrace_get_syscall_info(struct thread *td, pid_t pid, 426 l_ulong len, l_ulong data) 427 { 428 struct ptrace_lwpinfo lwpinfo; 429 struct ptrace_sc_ret sr; 430 struct reg b_reg; 431 struct syscall_info si; 432 int error; 433 434 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo)); 435 if (error != 0) { 436 linux_msg(td, "PT_LWPINFO failed with error %d", error); 437 return (error); 438 } 439 440 memset(&si, 0, sizeof(si)); 441 442 if (lwpinfo.pl_flags & PL_FLAG_SCE) { 443 si.op = LINUX_PTRACE_SYSCALL_INFO_ENTRY; 444 si.entry.nr = lwpinfo.pl_syscall_code; 445 /* 446 * The use of PT_GET_SC_ARGS there is special, 447 * implementation of PT_GET_SC_ARGS for Linux-ABI 448 * callers emulates Linux bug which strace(1) depends 449 * on: at initialization it tests whether ptrace works 450 * by calling close(2), or some other single-argument 451 * syscall, _with six arguments_, and then verifies 452 * whether it can fetch them all using this API; 453 * otherwise it bails out. 454 */ 455 error = kern_ptrace(td, PT_GET_SC_ARGS, pid, 456 &si.entry.args, sizeof(si.entry.args)); 457 if (error != 0) { 458 linux_msg(td, "PT_GET_SC_ARGS failed with error %d", 459 error); 460 return (error); 461 } 462 } else if (lwpinfo.pl_flags & PL_FLAG_SCX) { 463 si.op = LINUX_PTRACE_SYSCALL_INFO_EXIT; 464 error = kern_ptrace(td, PT_GET_SC_RET, pid, &sr, sizeof(sr)); 465 466 if (error != 0) { 467 linux_msg(td, "PT_GET_SC_RET failed with error %d", 468 error); 469 return (error); 470 } 471 472 if (sr.sr_error == 0) { 473 si.exit.rval = sr.sr_retval[0]; 474 si.exit.is_error = 0; 475 } else if (sr.sr_error == EJUSTRETURN) { 476 /* 477 * EJUSTRETURN means the actual value to return 478 * has already been put into td_frame; instead 479 * of extracting it and trying to determine whether 480 * it's an error or not just bail out and let 481 * the ptracing process fall back to another method. 482 */ 483 si.op = LINUX_PTRACE_SYSCALL_INFO_NONE; 484 } else if (sr.sr_error == ERESTART) { 485 si.exit.rval = -LINUX_ERESTARTSYS; 486 si.exit.is_error = 1; 487 } else { 488 si.exit.rval = bsd_to_linux_errno(sr.sr_error); 489 si.exit.is_error = 1; 490 } 491 } else { 492 si.op = LINUX_PTRACE_SYSCALL_INFO_NONE; 493 } 494 495 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0); 496 if (error != 0) 497 return (error); 498 499 linux_ptrace_get_syscall_info_machdep(&b_reg, &si); 500 501 len = MIN(len, sizeof(si)); 502 error = copyout(&si, (void *)data, len); 503 if (error == 0) 504 td->td_retval[0] = sizeof(si); 505 506 return (error); 507 } 508 509 int 510 linux_ptrace(struct thread *td, struct linux_ptrace_args *uap) 511 { 512 void *addr; 513 pid_t pid; 514 int error, sig; 515 516 pid = (pid_t)uap->pid; 517 addr = (void *)uap->addr; 518 519 switch (uap->req) { 520 case LINUX_PTRACE_TRACEME: 521 error = kern_ptrace(td, PT_TRACE_ME, 0, 0, 0); 522 break; 523 case LINUX_PTRACE_PEEKTEXT: 524 case LINUX_PTRACE_PEEKDATA: 525 error = linux_ptrace_peek(td, pid, addr, (void *)uap->data); 526 if (error != 0) 527 goto out; 528 /* 529 * Linux expects this syscall to read 64 bits, not 32. 530 */ 531 error = linux_ptrace_peek(td, pid, 532 (void *)(uap->addr + 4), (void *)(uap->data + 4)); 533 break; 534 case LINUX_PTRACE_PEEKUSER: 535 error = linux_ptrace_peekuser(td, pid, addr, (void *)uap->data); 536 break; 537 case LINUX_PTRACE_POKETEXT: 538 case LINUX_PTRACE_POKEDATA: 539 error = kern_ptrace(td, PT_WRITE_D, pid, addr, uap->data); 540 if (error != 0) 541 goto out; 542 /* 543 * Linux expects this syscall to write 64 bits, not 32. 544 */ 545 error = kern_ptrace(td, PT_WRITE_D, pid, 546 (void *)(uap->addr + 4), uap->data >> 32); 547 break; 548 case LINUX_PTRACE_POKEUSER: 549 error = linux_ptrace_pokeuser(td, pid, addr, (void *)uap->data); 550 break; 551 case LINUX_PTRACE_CONT: 552 error = map_signum(uap->data, &sig); 553 if (error != 0) 554 break; 555 error = kern_ptrace(td, PT_CONTINUE, pid, (void *)1, sig); 556 break; 557 case LINUX_PTRACE_KILL: 558 error = kern_ptrace(td, PT_KILL, pid, addr, uap->data); 559 break; 560 case LINUX_PTRACE_SINGLESTEP: 561 error = map_signum(uap->data, &sig); 562 if (error != 0) 563 break; 564 error = kern_ptrace(td, PT_STEP, pid, (void *)1, sig); 565 break; 566 case LINUX_PTRACE_GETREGS: 567 error = linux_ptrace_getregs(td, pid, (void *)uap->data); 568 break; 569 case LINUX_PTRACE_SETREGS: 570 error = linux_ptrace_setregs(td, pid, (void *)uap->data); 571 break; 572 case LINUX_PTRACE_ATTACH: 573 error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data); 574 break; 575 case LINUX_PTRACE_DETACH: 576 error = map_signum(uap->data, &sig); 577 if (error != 0) 578 break; 579 error = kern_ptrace(td, PT_DETACH, pid, (void *)1, sig); 580 break; 581 case LINUX_PTRACE_SYSCALL: 582 error = map_signum(uap->data, &sig); 583 if (error != 0) 584 break; 585 error = kern_ptrace(td, PT_SYSCALL, pid, (void *)1, sig); 586 break; 587 case LINUX_PTRACE_SETOPTIONS: 588 error = linux_ptrace_setoptions(td, pid, uap->data); 589 break; 590 case LINUX_PTRACE_GETEVENTMSG: 591 error = linux_ptrace_geteventmsg(td, pid, uap->data); 592 break; 593 case LINUX_PTRACE_GETSIGINFO: 594 error = linux_ptrace_getsiginfo(td, pid, uap->data); 595 break; 596 case LINUX_PTRACE_GETREGSET: 597 error = linux_ptrace_getregset(td, pid, uap->addr, uap->data); 598 break; 599 case LINUX_PTRACE_SEIZE: 600 error = linux_ptrace_seize(td, pid, uap->addr, uap->data); 601 break; 602 case LINUX_PTRACE_GET_SYSCALL_INFO: 603 error = linux_ptrace_get_syscall_info(td, pid, uap->addr, uap->data); 604 break; 605 default: 606 linux_msg(td, "ptrace(%ld, ...) not implemented; " 607 "returning EINVAL", uap->req); 608 error = EINVAL; 609 break; 610 } 611 612 out: 613 if (error == EBUSY) 614 error = ESRCH; 615 616 return (error); 617 } 618