summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Tomasz Napierala <trasz@FreeBSD.org>2019-05-07 19:06:41 +0000
committerEdward Tomasz Napierala <trasz@FreeBSD.org>2019-05-07 19:06:41 +0000
commitfaf2fa21d70b1e625cb7af032e6608e631931486 (patch)
treecc0df16374e6d68334c112b5f9f03f5791ce7873
parent0e26cd440f86b50be0adb2ef55714daa9e9f5d10 (diff)
Notes
-rw-r--r--sys/amd64/linux/linux_ptrace.c131
1 files changed, 128 insertions, 3 deletions
diff --git a/sys/amd64/linux/linux_ptrace.c b/sys/amd64/linux/linux_ptrace.c
index a50ecb3ae461..4d8d15527f02 100644
--- a/sys/amd64/linux/linux_ptrace.c
+++ b/sys/amd64/linux/linux_ptrace.c
@@ -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_reg *l_reg)
}
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, void *data)
}
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);