Index: sys/amd64/linux/linux_ptrace.c =================================================================== --- sys/amd64/linux/linux_ptrace.c +++ sys/amd64/linux/linux_ptrace.c @@ -94,6 +94,12 @@ LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL | \ LINUX_PTRACE_O_SUSPEND_SECCOMP) +#define LINUX_PTRACE_SYSCALL_INFO_NONE 0 +#define LINUX_PTRACE_SYSCALL_INFO_ENTRY 1 +#define LINUX_PTRACE_SYSCALL_INFO_EXIT 2 + +#define LINUX_ARCH_AMD64 0xc000003e + static int map_signum(int lsig, int *bsigp) { @@ -203,6 +209,28 @@ l_ulong gs; }; +struct syscall_info { + uint8_t op; + uint32_t arch; + uint64_t instruction_pointer; + uint64_t stack_pointer; + union { + struct { + uint64_t nr; + uint64_t args[6]; + } entry; + struct { + int64_t rval; + uint8_t is_error; + } exit; + struct { + uint64_t nr; + uint64_t args[6]; + uint32_t ret_data; + } seccomp; + }; +}; + /* * Translate amd64 ptrace registers between Linux and FreeBSD formats. * The translation is pretty straighforward, for all registers but @@ -560,9 +588,67 @@ static int linux_ptrace_get_syscall_info(struct thread *td, pid_t pid, l_ulong addr, l_ulong data) { + struct ptrace_lwpinfo lwpinfo; + struct ptrace_sc_ret sr; + struct reg b_reg; + struct syscall_info si; + int error; - linux_msg(td, "PTRACE_GET_SYSCALL_INFO not implemented; returning EINVAL"); - return (EINVAL); + error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0); + if (error != 0) + return (error); + + error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo)); + if (error != 0) { + linux_msg(td, "PT_LWPINFO failed with error %d", error); + return (error); + } + + memset(&si, 0, sizeof(si)); + + if (lwpinfo.pl_flags & PL_FLAG_SCE) { + si.op = LINUX_PTRACE_SYSCALL_INFO_ENTRY; + si.entry.nr = lwpinfo.pl_syscall_code; + + error = kern_ptrace(td, PT_GET_SC_ARGS, pid, &si.entry.args, sizeof(si.entry.args)); + if (error != 0) { + linux_msg(td, "PT_GET_SC_ARGS failed with error %d", error); + return (error); + } + } else if (lwpinfo.pl_flags & PL_FLAG_SCX) { + si.op = LINUX_PTRACE_SYSCALL_INFO_EXIT; + error = kern_ptrace(td, PT_GET_SC_RET, pid, &sr, sizeof(sr)); + + if (error != 0) { + linux_msg(td, "PT_GET_SC_RET failed with error %d", error); + return (error); + } + linux_msg(td, "sr_error %d, sr_retval[0] %#lx, sr_retval[1] %#lx", sr.sr_error, (long)sr.sr_retval[0], (long)sr.sr_retval[1]); + + if (sr.sr_error == 0) { + si.exit.rval = sr.sr_retval[0]; + si.exit.is_error = 0; + } else if (sr.sr_error > 0) { + si.exit.rval = bsd_to_linux_errno(sr.sr_error); + si.exit.is_error = 1; + } else { + /* XXX: Not sure what to do here. */ + si.exit.rval = sr.sr_retval[0]; + si.exit.is_error = 0; + } + } else { + si.op = LINUX_PTRACE_SYSCALL_INFO_NONE; + } + + si.arch = LINUX_ARCH_AMD64; + si.instruction_pointer = b_reg.r_rip; + si.stack_pointer = b_reg.r_rsp; + + error = copyout(&si, (void *)data, sizeof(si)); + if (error == 0) + td->td_retval[0] = sizeof(si); + + return (error); } int Index: sys/kern/sys_process.c =================================================================== --- sys/kern/sys_process.c +++ sys/kern/sys_process.c @@ -924,9 +924,7 @@ error = EINVAL; break; } - bzero(addr, sizeof(td2->td_sa.args)); - bcopy(td2->td_sa.args, addr, td2->td_sa.callp->sy_narg * - sizeof(register_t)); + bcopy(td2->td_sa.args, addr, sizeof(td2->td_sa.args)); break; case PT_GET_SC_RET: