svn commit: r347231 - head/sys/amd64/linux
Edward Tomasz Napierala
trasz at FreeBSD.org
Tue May 7 19:06:43 UTC 2019
Author: trasz
Date: Tue May 7 19:06:41 2019
New Revision: 347231
URL: https://svnweb.freebsd.org/changeset/base/347231
Log:
Support PTRACE_GETREGSET w/ NT_PRSTATUS in Linux ptrace(2).
While Linux strace(1) doesn't strictly require it - it has a fallback
to PTRACE_GETREGS - it's a newer interface, so we better support it
before the old one is deprecated.
Reviewed by: dchagin
MFC after: 2 weeks
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D20152
Modified:
head/sys/amd64/linux/linux_ptrace.c
Modified: head/sys/amd64/linux/linux_ptrace.c
==============================================================================
--- head/sys/amd64/linux/linux_ptrace.c Tue May 7 18:10:21 2019 (r347230)
+++ head/sys/amd64/linux/linux_ptrace.c Tue May 7 19:06:41 2019 (r347231)
@@ -131,6 +131,36 @@ struct linux_pt_reg {
l_ulong ss;
};
+struct linux_pt_regset {
+ l_ulong r15;
+ l_ulong r14;
+ l_ulong r13;
+ l_ulong r12;
+ l_ulong rbp;
+ l_ulong rbx;
+ l_ulong r11;
+ l_ulong r10;
+ l_ulong r9;
+ l_ulong r8;
+ l_ulong rax;
+ l_ulong rcx;
+ l_ulong rdx;
+ l_ulong rsi;
+ l_ulong rdi;
+ l_ulong orig_rax;
+ l_ulong rip;
+ l_ulong cs;
+ l_ulong eflags;
+ l_ulong rsp;
+ l_ulong ss;
+ l_ulong fs_base;
+ l_ulong gs_base;
+ l_ulong ds;
+ l_ulong es;
+ l_ulong fs;
+ l_ulong gs;
+};
+
/*
* Translate amd64 ptrace registers between Linux and FreeBSD formats.
* The translation is pretty straighforward, for all registers but
@@ -164,6 +194,40 @@ map_regs_to_linux(struct reg *b_reg, struct linux_pt_r
}
static void
+map_regs_to_linux_regset(struct reg *b_reg, unsigned long fs_base,
+ unsigned long gs_base, struct linux_pt_regset *l_regset)
+{
+
+ l_regset->r15 = b_reg->r_r15;
+ l_regset->r14 = b_reg->r_r14;
+ l_regset->r13 = b_reg->r_r13;
+ l_regset->r12 = b_reg->r_r12;
+ l_regset->rbp = b_reg->r_rbp;
+ l_regset->rbx = b_reg->r_rbx;
+ l_regset->r11 = b_reg->r_r11;
+ l_regset->r10 = b_reg->r_r10;
+ l_regset->r9 = b_reg->r_r9;
+ l_regset->r8 = b_reg->r_r8;
+ l_regset->rax = b_reg->r_rax;
+ l_regset->rcx = b_reg->r_rcx;
+ l_regset->rdx = b_reg->r_rdx;
+ l_regset->rsi = b_reg->r_rsi;
+ l_regset->rdi = b_reg->r_rdi;
+ l_regset->orig_rax = b_reg->r_rax;
+ l_regset->rip = b_reg->r_rip;
+ l_regset->cs = b_reg->r_cs;
+ l_regset->eflags = b_reg->r_rflags;
+ l_regset->rsp = b_reg->r_rsp;
+ l_regset->ss = b_reg->r_ss;
+ l_regset->fs_base = fs_base;
+ l_regset->gs_base = gs_base;
+ l_regset->ds = b_reg->r_ds;
+ l_regset->es = b_reg->r_es;
+ l_regset->fs = b_reg->r_fs;
+ l_regset->gs = b_reg->r_gs;
+}
+
+static void
map_regs_from_linux(struct reg *b_reg, struct linux_pt_reg *l_reg)
{
b_reg->r_r15 = l_reg->r15;
@@ -306,14 +370,75 @@ linux_ptrace_setregs(struct thread *td, pid_t pid, voi
}
static int
+linux_ptrace_getregset_prstatus(struct thread *td, pid_t pid, l_ulong data)
+{
+ struct ptrace_lwpinfo lwpinfo;
+ struct reg b_reg;
+ struct linux_pt_regset l_regset;
+ struct iovec iov;
+ struct pcb *pcb;
+ unsigned long fsbase, gsbase;
+ size_t len;
+ int error;
+
+ error = copyin((const void *)data, &iov, sizeof(iov));
+ if (error != 0) {
+ printf("%s: copyin error %d\n", __func__, error);
+ return (error);
+ }
+
+ error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
+ if (error != 0)
+ return (error);
+
+ pcb = td->td_pcb;
+ if (td == curthread)
+ update_pcb_bases(pcb);
+ fsbase = pcb->pcb_fsbase;
+ gsbase = pcb->pcb_gsbase;
+
+ map_regs_to_linux_regset(&b_reg, fsbase, gsbase, &l_regset);
+
+ /*
+ * The strace(1) utility depends on RAX being set to -ENOSYS
+ * on syscall entry; otherwise it loops printing those:
+ *
+ * [ Process PID=928 runs in 64 bit mode. ]
+ * [ Process PID=928 runs in x32 mode. ]
+ */
+ error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
+ if (error != 0) {
+ printf("%s: PT_LWPINFO failed with error %d\n",
+ __func__, error);
+ return (error);
+ }
+ if (lwpinfo.pl_flags & PL_FLAG_SCE)
+ l_regset.rax = -38; // XXX: Don't hardcode?
+
+ len = MIN(iov.iov_len, sizeof(l_regset));
+ error = copyout(&l_regset, (void *)iov.iov_base, len);
+ if (error != 0) {
+ printf("%s: copyout error %d\n", __func__, error);
+ return (error);
+ }
+
+ iov.iov_len -= len;
+ error = copyout(&iov, (void *)data, sizeof(iov));
+ if (error != 0) {
+ printf("%s: iov copyout error %d\n", __func__, error);
+ return (error);
+ }
+
+ return (error);
+}
+
+static int
linux_ptrace_getregset(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
{
switch (addr) {
case LINUX_NT_PRSTATUS:
- printf("%s: NT_PRSTATUS not implemented; returning EINVAL\n",
- __func__);
- return (EINVAL);
+ return (linux_ptrace_getregset_prstatus(td, pid, data));
default:
printf("%s: PTRACE_GETREGSET request %ld not implemented; "
"returning EINVAL\n", __func__, addr);
More information about the svn-src-all
mailing list