Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src Implement PT_GETXSTATE and PT_SETXSTATE



details:   https://anonhg.NetBSD.org/src/rev/bcb7c11a2814
branches:  trunk
changeset: 461628:bcb7c11a2814
user:      mgorny <mgorny%NetBSD.org@localhost>
date:      Wed Jun 26 12:30:12 2019 +0000

description:
Implement PT_GETXSTATE and PT_SETXSTATE

Introduce two new ptrace() requests: PT_GETXSTATE and PT_SETXSTATE,
that provide access to the extended (and extensible) set of FPU
registers on amd64 and i386.  At the moment, this covers AVX (YMM)
and AVX-512 (ZMM, opmask) registers.  It can be easily extended
to cover further register types without breaking backwards
compatibility.

PT_GETXSTATE issues the XSAVE instruction with all kernel-supported
extended components enabled.  The data is copied into 'struct xstate'
(which -- unlike the XSAVE area itself -- has stable format
and offsets).

PT_SETXSTATE issues the XRSTOR instruction to restore the register
values from user-provided 'struct xstate'.  The function replaces only
the specific XSAVE components that are listed in 'xs_rfbm' field,
making it possible to issue partial updates.

Both syscalls take a 'struct iovec' pointer rather than a direct
argument.  This requires the caller to explicitly specify the buffer
size.  As a result, existing code will continue to work correctly
when the structure is extended (performing partial reads/updates).

diffstat:

 lib/libc/sys/ptrace.2                     |   78 ++-
 sys/arch/amd64/amd64/netbsd32_machdep.c   |    6 +-
 sys/arch/amd64/amd64/process_machdep.c    |  135 ++++-
 sys/arch/amd64/include/netbsd32_machdep.h |    4 +-
 sys/arch/amd64/include/ptrace.h           |   25 +-
 sys/arch/i386/i386/process_machdep.c      |  129 +++-
 sys/arch/i386/include/ptrace.h            |   15 +-
 sys/arch/x86/include/cpu_extended_state.h |   84 ++-
 sys/arch/x86/include/fpu.h                |    6 +-
 sys/arch/x86/x86/fpu.c                    |  163 +++++-
 tests/lib/libc/sys/t_ptrace_wait.c        |    6 +-
 tests/lib/libc/sys/t_ptrace_x86_wait.h    |  894 +++++++++++++++++++++++++++++-
 12 files changed, 1502 insertions(+), 43 deletions(-)

diffs (truncated from 1860 to 300 lines):

diff -r 03c0ac62a5ae -r bcb7c11a2814 lib/libc/sys/ptrace.2
--- a/lib/libc/sys/ptrace.2     Wed Jun 26 12:29:00 2019 +0000
+++ b/lib/libc/sys/ptrace.2     Wed Jun 26 12:30:12 2019 +0000
@@ -1,7 +1,7 @@
-.\"    $NetBSD: ptrace.2,v 1.74 2019/06/12 12:33:42 wiz Exp $
+.\"    $NetBSD: ptrace.2,v 1.75 2019/06/26 12:30:12 mgorny Exp $
 .\"
 .\" This file is in the public domain.
-.Dd June 12, 2019
+.Dd June 26, 2019
 .Dt PTRACE 2
 .Os
 .Sh NAME
@@ -771,6 +771,69 @@
 argument contains the LWP ID of the thread whose registers are to
 be written.
 If zero is supplied, the first thread of the process is written.
+.It Dv PT_GETXSTATE
+This request reads the traced process' FPU extended state into
+the
+.Dq Li "struct xstate"
+(defined in
+.In machine/cpu_extended_state.h ) .
+.Fa addr
+should be a pointer to
+.Dq Li "struct iovec"
+(defined in
+.In sys/uio.h )
+specifying the pointer to the aforementioned struct as
+.Fa iov_base
+and its size as
+.Fa iov_len .
+The
+.Fa data
+argument contains the LWP ID of the thread whose registers are to
+be read.
+If zero is supplied, the first thread of the process is read.
+The struct will be filled up to the specified
+.Fa iov_len .
+The caller needs to check
+.Fa xs_rfbm
+bitmap in order to determine which fields were provided by the CPU,
+and may check
+.Fa xs_xstate_bv
+to determine which component states were changed from the initial state.
+.It Dv PT_SETXSTATE
+This request is the converse of
+.Dv PT_GETXSTATE ;
+it loads the traced process' extended FPU state from the
+.Dq Li "struct xstate"
+(defined in
+.In machine/cpu_extended_state.h ) .
+.Fa addr
+should be a pointer to
+.Dq Li "struct iovec"
+(defined in
+.In sys/uio.h )
+specifying the pointer to the aforementioned struct as
+.Fa iov_base
+and its size as
+.Fa iov_len .
+The
+.Fa data
+argument contains the LWP ID of the thread whose registers are to
+be written.
+If zero is supplied, the first thread of the process is written.
+The
+.Fa xs_rfbm
+field of the supplied xstate specifies which state components are to
+be updated.  Other components (fields) will be ignored.  The
+.Fa xs_xstate_bv
+specifies whether component state should be set to provided values
+(when 1) or reset to unitialized (when 0).  The request
+will fail if
+.Fa xs_xstate_bv
+is not a subset of
+.Fa xs_rfbm ,
+or any of the specified components is not supported by the CPU or kernel
+(i.e. not returned by
+.Dv PT_GETXSTATE .
 .El
 .Sh ERRORS
 Some requests can cause
@@ -819,8 +882,10 @@
 .Dv PT_GETREGS ,
 .Dv PT_SETREGS ,
 .Dv PT_GETFPREGS ,
+.Dv PT_SETFPREGS ,
+.Dv PT_GETXSTATE ,
 or
-.Dv PT_SETFPREGS
+.Dv PT_SETXSTATE
 was attempted on a process with no valid register set.
 (This is normally true only of system processes.)
 .It
@@ -832,6 +897,13 @@
 with
 .Dv vm.user_va0_disable
 set to 1.
+.It
+.Dv PT_SETXSTATE
+attempted to set state components not supported by the kernel,
+or
+.Dv xs_xstate_bv
+was not a subset of
+.Dv xs_rfbm .
 .El
 .It Bq Er EPERM
 .Bl -bullet -compact
diff -r 03c0ac62a5ae -r bcb7c11a2814 sys/arch/amd64/amd64/netbsd32_machdep.c
--- a/sys/arch/amd64/amd64/netbsd32_machdep.c   Wed Jun 26 12:29:00 2019 +0000
+++ b/sys/arch/amd64/amd64/netbsd32_machdep.c   Wed Jun 26 12:30:12 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: netbsd32_machdep.c,v 1.123 2019/06/04 16:30:19 mgorny Exp $    */
+/*     $NetBSD: netbsd32_machdep.c,v 1.124 2019/06/26 12:30:12 mgorny Exp $    */
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.123 2019/06/04 16:30:19 mgorny Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.124 2019/06/26 12:30:12 mgorny Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_compat_netbsd.h"
@@ -353,6 +353,8 @@
        case PT32_SETDBREGS:            return PT_SETDBREGS;
        case PT32_SETSTEP:              return PT_SETSTEP;
        case PT32_CLEARSTEP:            return PT_CLEARSTEP;
+       case PT32_GETXSTATE:            return PT_GETXSTATE;
+       case PT32_SETXSTATE:            return PT_SETXSTATE;
        default:                        return -1;
        }
 }
diff -r 03c0ac62a5ae -r bcb7c11a2814 sys/arch/amd64/amd64/process_machdep.c
--- a/sys/arch/amd64/amd64/process_machdep.c    Wed Jun 26 12:29:00 2019 +0000
+++ b/sys/arch/amd64/amd64/process_machdep.c    Wed Jun 26 12:30:12 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: process_machdep.c,v 1.39 2019/02/11 14:59:32 cherry Exp $      */
+/*     $NetBSD: process_machdep.c,v 1.40 2019/06/26 12:30:12 mgorny Exp $      */
 
 /*
  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -74,7 +74,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.39 2019/02/11 14:59:32 cherry Exp $");
+__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.40 2019/06/26 12:30:12 mgorny Exp $");
 
 #include "opt_xen.h"
 #include <sys/param.h>
@@ -84,6 +84,9 @@
 #include <sys/proc.h>
 #include <sys/ptrace.h>
 
+#include <uvm/uvm_extern.h>
+
+#include <compat/netbsd32/netbsd32.h>
 #include <machine/psl.h>
 #include <machine/reg.h>
 #include <machine/segments.h>
@@ -288,3 +291,131 @@
 
        return 0;
 }
+
+#ifdef __HAVE_PTRACE_MACHDEP
+static int
+process_machdep_read_xstate(struct lwp *l, struct xstate *regs)
+{
+       return process_read_xstate(l, regs);
+}
+
+static int
+process_machdep_write_xstate(struct lwp *l, const struct xstate *regs)
+{
+       int error;
+
+       /*
+        * Check for security violations.
+        */
+       error = process_verify_xstate(regs);
+       if (error != 0)
+               return error;
+
+       return process_write_xstate(l, regs);
+}
+
+int
+ptrace_machdep_dorequest(
+    struct lwp *l,
+    struct lwp *lt,
+    int req,
+    void *addr,
+    int data
+)
+{
+       struct uio uio;
+       struct iovec iov;
+       struct vmspace *vm;
+       int error;
+       int write = 0;
+
+       switch (req) {
+       case PT_SETXSTATE:
+               write = 1;
+
+               /* FALLTHROUGH */
+       case PT_GETXSTATE:
+               /* write = 0 done above. */
+               if (!process_machdep_validxstate(lt->l_proc))
+                       return EINVAL;
+               if (__predict_false(l->l_proc->p_flag & PK_32)) {
+                       struct netbsd32_iovec *user_iov;
+                       user_iov = (struct netbsd32_iovec*)addr;
+                       iov.iov_base = NETBSD32PTR64(user_iov->iov_base);
+                       iov.iov_len = user_iov->iov_len;
+               } else {
+                       struct iovec *user_iov;
+                       user_iov = (struct iovec*)addr;
+                       iov.iov_base = user_iov->iov_base;
+                       iov.iov_len = user_iov->iov_len;
+               }
+
+               error = proc_vmspace_getref(l->l_proc, &vm);
+               if (error)
+                       return error;
+               if (iov.iov_len > sizeof(struct xstate))
+                       iov.iov_len = sizeof(struct xstate);
+               uio.uio_iov = &iov;
+               uio.uio_iovcnt = 1;
+               uio.uio_offset = 0;
+               uio.uio_resid = iov.iov_len;
+               uio.uio_rw = write ? UIO_WRITE : UIO_READ;
+               uio.uio_vmspace = vm;
+               error = process_machdep_doxstate(l, lt, &uio);
+               uvmspace_free(vm);
+               return error;
+       }
+
+#ifdef DIAGNOSTIC
+       panic("ptrace_machdep: impossible");
+#endif
+
+       return 0;
+}
+
+/*
+ * The following functions are used by both ptrace(2) and procfs.
+ */
+
+int
+process_machdep_doxstate(struct lwp *curl, struct lwp *l, struct uio *uio)
+       /* curl:                 tracer */
+       /* l:                    traced */
+{
+       int error;
+       struct xstate r;
+       char *kv;
+       ssize_t kl;
+
+       memset(&r, 0, sizeof(r));
+       kl = MIN(uio->uio_iov->iov_len, sizeof(r));
+       kv = (char *) &r;
+
+       kv += uio->uio_offset;
+       kl -= uio->uio_offset;
+       if (kl > uio->uio_resid)
+               kl = uio->uio_resid;
+
+       if (kl < 0)
+               error = EINVAL;
+       else
+               error = process_machdep_read_xstate(l, &r);
+       if (error == 0)
+               error = uiomove(kv, kl, uio);
+       if (error == 0 && uio->uio_rw == UIO_WRITE)
+               error = process_machdep_write_xstate(l, &r);
+
+       uio->uio_offset = 0;
+       return error;
+}
+
+int
+process_machdep_validxstate(struct proc *p)
+{
+
+       if (p->p_flag & PK_SYSTEM)
+               return 0;
+
+       return 1;
+}
+#endif /* __HAVE_PTRACE_MACHDEP */
diff -r 03c0ac62a5ae -r bcb7c11a2814 sys/arch/amd64/include/netbsd32_machdep.h
--- a/sys/arch/amd64/include/netbsd32_machdep.h Wed Jun 26 12:29:00 2019 +0000
+++ b/sys/arch/amd64/include/netbsd32_machdep.h Wed Jun 26 12:30:12 2019 +0000
@@ -1,4 +1,4 @@



Home | Main Index | Thread Index | Old Index