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