Changeset View
Standalone View
sys/amd64/linux/linux_ptrace.c
Show First 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | |||||
#define LINUX_PTRACE_O_MASK (LINUX_PTRACE_O_TRACESYSGOOD | \ | #define LINUX_PTRACE_O_MASK (LINUX_PTRACE_O_TRACESYSGOOD | \ | ||||
LINUX_PTRACE_O_TRACEFORK | LINUX_PTRACE_O_TRACEVFORK | \ | LINUX_PTRACE_O_TRACEFORK | LINUX_PTRACE_O_TRACEVFORK | \ | ||||
LINUX_PTRACE_O_TRACECLONE | LINUX_PTRACE_O_TRACEEXEC | \ | LINUX_PTRACE_O_TRACECLONE | LINUX_PTRACE_O_TRACEEXEC | \ | ||||
LINUX_PTRACE_O_TRACEVFORKDONE | LINUX_PTRACE_O_TRACEEXIT | \ | LINUX_PTRACE_O_TRACEVFORKDONE | LINUX_PTRACE_O_TRACEEXIT | \ | ||||
LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL | \ | LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL | \ | ||||
LINUX_PTRACE_O_SUSPEND_SECCOMP) | 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 | |||||
emaste: Are these MD? | |||||
traszAuthorUnsubmitted Done Inline ActionsI'm guessing they are not, but for now all of amd64 implementation of ptrace is in a MD-file. This will probably change once it gets ported to arm64. trasz: I'm guessing they are not, but for now all of amd64 implementation of ptrace is in a MD-file. | |||||
#define LINUX_ARCH_AMD64 0xc000003e | |||||
static int | static int | ||||
map_signum(int lsig, int *bsigp) | map_signum(int lsig, int *bsigp) | ||||
{ | { | ||||
int bsig; | int bsig; | ||||
if (lsig == 0) { | if (lsig == 0) { | ||||
*bsigp = 0; | *bsigp = 0; | ||||
return (0); | return (0); | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | struct linux_pt_regset { | ||||
l_ulong fs_base; | l_ulong fs_base; | ||||
l_ulong gs_base; | l_ulong gs_base; | ||||
l_ulong ds; | l_ulong ds; | ||||
l_ulong es; | l_ulong es; | ||||
l_ulong fs; | l_ulong fs; | ||||
l_ulong gs; | 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. | * Translate amd64 ptrace registers between Linux and FreeBSD formats. | ||||
* The translation is pretty straighforward, for all registers but | * The translation is pretty straighforward, for all registers but | ||||
* orig_rax on Linux side and r_trapno and r_err in FreeBSD. | * orig_rax on Linux side and r_trapno and r_err in FreeBSD. | ||||
*/ | */ | ||||
static void | static void | ||||
map_regs_to_linux(struct reg *b_reg, struct linux_pt_reg *l_reg) | map_regs_to_linux(struct reg *b_reg, struct linux_pt_reg *l_reg) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 341 Lines • ▼ Show 20 Lines | linux_ptrace_seize(struct thread *td, pid_t pid, l_ulong addr, l_ulong data) | ||||
linux_msg(td, "PTRACE_SEIZE not implemented; returning EINVAL"); | linux_msg(td, "PTRACE_SEIZE not implemented; returning EINVAL"); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
static int | static int | ||||
linux_ptrace_get_syscall_info(struct thread *td, pid_t pid, l_ulong addr, l_ulong data) | 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"); | error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0); | ||||
return (EINVAL); | 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); | |||||
} | |||||
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 { | |||||
jhbUnsubmitted Not Done Inline ActionsThis should never occur as FreeBSD doesn't use negative errno values. I think instead you should make the previous 'sr.sr_error > 0' into an else as the only conditions are 'sr.sr_error == 0' and 'sr.sr_error != 0'. jhb: This should never occur as FreeBSD doesn't use negative errno values. I think instead you… | |||||
traszAuthorUnsubmitted Done Inline ActionsThanks for clarifying this. trasz: Thanks for clarifying this. | |||||
/* 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; | |||||
jhbUnsubmitted Not Done Inline ActionsI would move the kern_ptrace of PT_REG down to here where you actually use it. Presumably, this block to set ip/sp would end up being MD, but the rest of this function is MI and should be shared across platforms. jhb: I would move the kern_ptrace of PT_REG down to here where you actually use it. Presumably… | |||||
traszAuthorUnsubmitted Done Inline ActionsI agree about the block placement. I'd prefer not splitting this into MI/MD chunks just yet, there might be some unexplained differences in operation between versions - like with syscall numbers in Linux. trasz: I agree about the block placement. I'd prefer not splitting this into MI/MD chunks just yet… | |||||
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 | int | ||||
linux_ptrace(struct thread *td, struct linux_ptrace_args *uap) | linux_ptrace(struct thread *td, struct linux_ptrace_args *uap) | ||||
{ | { | ||||
void *addr; | void *addr; | ||||
pid_t pid; | pid_t pid; | ||||
int error, sig; | int error, sig; | ||||
▲ Show 20 Lines • Show All 91 Lines • Show Last 20 Lines |
Are these MD?