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);
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to