Print this page
15254 %ymm registers not restored after signal handler
15367 x86 getfpregs() summons corrupting %xmm ghosts
15333 want x86 /proc xregs support (libc_db, libproc, mdb, etc.)
15336 want libc functions for extended ucontext_t
15334 want ps_lwphandle-specific reg routines
15328 FPU_CW_INIT mistreats reserved bit
15335 i86pc fpu_subr.c isn't really platform-specific
15332 setcontext(2) isn't actually noreturn
15331 need <sys/stdalign.h>
Change-Id: I7060aa86042dfb989f77fc3323c065ea2eafa9ad
Conflicts:
    usr/src/uts/common/fs/proc/prcontrol.c
    usr/src/uts/intel/os/archdep.c
    usr/src/uts/intel/sys/ucontext.h
    usr/src/uts/intel/syscall/getcontext.c

@@ -22,14 +22,16 @@
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /*
  * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright 2023 Oxide Computer Company
  */
 
 #include <stdarg.h>
 #include <string.h>
+#include <errno.h>
 #include "Pcontrol.h"
 
 /*
  * This file implements the process services declared in <proc_service.h>.
  * This enables libproc to be used in conjunction with libc_db and

@@ -165,12 +167,10 @@
                 return (PS_OK);
 
         return (PS_BADLID);
 }
 
-#if defined(sparc) || defined(__sparc)
-
 ps_err_e
 ps_lgetxregsize(struct ps_prochandle *P, lwpid_t lwpid, int *xrsize)
 {
         char fname[PATH_MAX];
         struct stat statb;

@@ -180,14 +180,20 @@
                 lwp_info_t *lwp;
 
                 for (lwp = list_head(&core->core_lwp_head); lwp != NULL;
                     lwp = list_next(&core->core_lwp_head, lwp)) {
                         if (lwp->lwp_id == lwpid) {
-                                if (lwp->lwp_xregs != NULL)
-                                        *xrsize = sizeof (prxregset_t);
-                                else
+                                if (lwp->lwp_xregs != NULL &&
+                                    lwp->lwp_xregsize > 0) {
+                                        if (lwp->lwp_xregsize >= INT_MAX) {
+                                                return (PS_ERR);
+                                        }
+
+                                        *xrsize = (int)lwp->lwp_xregsize;
+                                } else {
                                         *xrsize = 0;
+                                }
                                 return (PS_OK);
                         }
                 }
 
                 return (PS_BADLID);

@@ -197,29 +203,70 @@
             procfs_path, (int)P->status.pr_pid, (int)lwpid);
 
         if (stat(fname, &statb) != 0)
                 return (PS_BADLID);
 
+        if (statb.st_size > INT_MAX)
+                return (PS_ERR);
+
         *xrsize = (int)statb.st_size;
         return (PS_OK);
 }
 
 ps_err_e
 ps_lgetxregs(struct ps_prochandle *P, lwpid_t lwpid, caddr_t xregs)
 {
+        size_t xregsize;
+        prxregset_t *prx;
+
         if (P->state != PS_STOP && P->state != PS_DEAD)
                 return (PS_ERR);
 
-        /* LINTED - alignment */
-        if (Plwp_getxregs(P, lwpid, (prxregset_t *)xregs) == 0)
+        if (Plwp_getxregs(P, lwpid, &prx, &xregsize) == 0) {
+                (void) memcpy(xregs, prx, xregsize);
+                Plwp_freexregs(P, prx, xregsize);
                 return (PS_OK);
+        }
 
+        if (errno == ENODATA)
+                return (PS_NOXREGS);
+
         return (PS_BADLID);
 }
 
 ps_err_e
 ps_lsetxregs(struct ps_prochandle *P, lwpid_t lwpid, caddr_t xregs)
+{
+        size_t xregsize = 0;
+
+        if (P->state != PS_STOP)
+                return (PS_ERR);
+
+        /*
+         * libproc asks the caller for the size of the extended register set.
+         * Unfortunately, right now we aren't given the actual size of this
+         * ourselves and we don't want to break the ABI that folks have used
+         * historically. Therefore, we reach in and ask the structure in a
+         * platform-specific way about what this should be. Sorry, this is a bit
+         * unfortunate. This really shouldn't be a platform-specific #ifdef.
+         */
+#if defined(__i386) || defined(__amd64)
+        prxregset_hdr_t *hdr = (prxregset_hdr_t *)xregs;
+        xregsize = hdr->pr_size;
+#endif
+        if (xregsize == 0)
+                return (PS_ERR);
+
+        if (Plwp_setxregs(P, lwpid, (prxregset_t *)xregs, xregsize) == 0)
+                return (PS_OK);
+
+        return (PS_BADLID);
+}
+
+#if defined(sparc) || defined(__sparc)
+ps_err_e
+ps_lsetxregs(struct ps_prochandle *P, lwpid_t lwpid, caddr_t xregs)
 {
         if (P->state != PS_STOP)
                 return (PS_ERR);
 
         /* LINTED - alignment */