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


   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * Copyright 2018 Joyent, Inc.
  28  * Copyright (c) 2013 by Delphix. All rights reserved.

  29  */
  30 
  31 #include <sys/types.h>
  32 #include <sys/uio.h>
  33 #include <string.h>
  34 #include <errno.h>
  35 #include <limits.h>
  36 
  37 #include "Pcontrol.h"
  38 #include "P32ton.h"
  39 
  40 /*
  41  * This file implements the routines to read and write per-lwp register
  42  * information from either a live process or core file opened with libproc.
  43  * We build up a few common routines for reading and writing register
  44  * information, and then the public functions are all trivial calls to these.






  45  */
  46 
  47 /*
  48  * Utility function to return a pointer to the structure of cached information
  49  * about an lwp in the core file, given its lwpid.
  50  */
  51 static lwp_info_t *
  52 getlwpcore(struct ps_prochandle *P, lwpid_t lwpid)
  53 {
  54         core_info_t *core = P->data;
  55         lwp_info_t *lwp;
  56 
  57         for (lwp = list_head(&core->core_lwp_head); lwp != NULL;
  58             lwp = list_next(&core->core_lwp_head, lwp)) {
  59                 if (lwp->lwp_id == lwpid)
  60                         return (lwp);
  61         }
  62 
  63         errno = EINVAL;
  64         return (NULL);
  65 }
  66 
  67 /*
  68  * Utility function to open and read the contents of a per-lwp /proc file.
  69  * This function is used to slurp in lwpstatus, xregs, and asrs.

  70  */
  71 static int
  72 getlwpfile(struct ps_prochandle *P, lwpid_t lwpid,
  73     const char *fbase, void *rp, size_t n)
  74 {
  75         char fname[PATH_MAX];
  76         int fd;
  77 
  78         (void) snprintf(fname, sizeof (fname), "%s/%d/lwp/%d/%s",
  79             procfs_path, (int)P->status.pr_pid, (int)lwpid, fbase);
  80 
  81         if ((fd = open(fname, O_RDONLY)) >= 0) {
  82                 if (read(fd, rp, n) > 0) {
  83                         (void) close(fd);
  84                         return (0);
  85                 }


  86                 (void) close(fd);

  87         }
  88         return (-1);
  89 }
  90 
  91 /*
























































  92  * Get the lwpstatus_t for an lwp from either the live process or our
  93  * cached information from the core file.  This is used to get the
  94  * general-purpose registers or floating point registers.
  95  */
  96 int
  97 getlwpstatus(struct ps_prochandle *P, lwpid_t lwpid, lwpstatus_t *lps)
  98 {
  99         lwp_info_t *lwp;
 100 
 101         /*
 102          * For both live processes and cores, our job is easy if the lwpid
 103          * matches that of the representative lwp:
 104          */
 105         if (P->status.pr_lwp.pr_lwpid == lwpid) {
 106                 (void) memcpy(lps, &P->status.pr_lwp, sizeof (lwpstatus_t));
 107                 return (0);
 108         }
 109 
 110         /*
 111          * If this is a live process, then just read the information out
 112          * of the per-lwp status file:
 113          */
 114         if (P->state != PS_DEAD) {
 115                 return (getlwpfile(P, lwpid, "lwpstatus",
 116                     lps, sizeof (lwpstatus_t)));
 117         }
 118 
 119         /*
 120          * If this is a core file, we need to iterate through our list of
 121          * cached lwp information and then copy out the status.
 122          */
 123         if (P->data != NULL && (lwp = getlwpcore(P, lwpid)) != NULL) {
 124                 (void) memcpy(lps, &lwp->lwp_status, sizeof (lwpstatus_t));
 125                 return (0);
 126         }
 127 
 128         return (-1);
 129 }
 130 
 131 /*































 132  * Utility function to modify lwp registers.  This is done using either the
 133  * process control file or per-lwp control file as necessary.

 134  */
 135 static int
 136 setlwpregs(struct ps_prochandle *P, lwpid_t lwpid, long cmd,
 137     const void *rp, size_t n)
 138 {
 139         iovec_t iov[2];
 140         char fname[PATH_MAX];
 141         int fd;

 142 
 143         if (P->state != PS_STOP) {
 144                 errno = EBUSY;
 145                 return (-1);
 146         }
 147 
 148         iov[0].iov_base = (caddr_t)&cmd;
 149         iov[0].iov_len = sizeof (long);
 150         iov[1].iov_base = (caddr_t)rp;
 151         iov[1].iov_len = n;
 152 
 153         /*










 154          * Writing the process control file writes the representative lwp.
 155          * Psync before we write to make sure we are consistent with the
 156          * primary interfaces.  Similarly, make sure to update P->status
 157          * afterward if we are modifying one of its register sets.


 158          */
 159         if (P->status.pr_lwp.pr_lwpid == lwpid) {
 160                 Psync(P);


 161 
 162                 if (writev(P->ctlfd, iov, 2) == -1)

 163                         return (-1);
 164 
 165                 if (cmd == PCSREG)
 166                         (void) memcpy(P->status.pr_lwp.pr_reg, rp, n);
 167                 else if (cmd == PCSFPREG)
 168                         (void) memcpy(&P->status.pr_lwp.pr_fpreg, rp, n);
 169 
 170                 return (0);
 171         }
 172 
 173         /*
 174          * If the lwp we want is not the representative lwp, we need to
 175          * open the ctl file for that specific lwp.
 176          */
 177         (void) snprintf(fname, sizeof (fname), "%s/%d/lwp/%d/lwpctl",
 178             procfs_path, (int)P->status.pr_pid, (int)lwpid);
 179 
 180         if ((fd = open(fname, O_WRONLY)) >= 0) {
 181                 if (writev(fd, iov, 2) > 0) {
 182                         (void) close(fd);
 183                         return (0);
 184                 }

 185                 (void) close(fd);

 186         }
 187         return (-1);
 188 }
 189 



























 190 int
 191 Plwp_getregs(struct ps_prochandle *P, lwpid_t lwpid, prgregset_t gregs)
 192 {
 193         lwpstatus_t lps;
 194 
 195         if (getlwpstatus(P, lwpid, &lps) == -1)
 196                 return (-1);
 197 
 198         (void) memcpy(gregs, lps.pr_reg, sizeof (prgregset_t));
 199         return (0);
 200 }
 201 
 202 int







 203 Plwp_setregs(struct ps_prochandle *P, lwpid_t lwpid, const prgregset_t gregs)
 204 {
 205         return (setlwpregs(P, lwpid, PCSREG, gregs, sizeof (prgregset_t)));
 206 }
 207 
 208 int






 209 Plwp_getfpregs(struct ps_prochandle *P, lwpid_t lwpid, prfpregset_t *fpregs)
 210 {
 211         lwpstatus_t lps;
 212 
 213         if (getlwpstatus(P, lwpid, &lps) == -1)
 214                 return (-1);
 215 
 216         (void) memcpy(fpregs, &lps.pr_fpreg, sizeof (prfpregset_t));
 217         return (0);
 218 }
 219 
 220 int Plwp_setfpregs(struct ps_prochandle *P, lwpid_t lwpid,








 221     const prfpregset_t *fpregs)
 222 {
 223         return (setlwpregs(P, lwpid, PCSFPREG, fpregs, sizeof (prfpregset_t)));

 224 }
 225 
 226 #if defined(sparc) || defined(__sparc)
 227 int
 228 Plwp_getxregs(struct ps_prochandle *P, lwpid_t lwpid, prxregset_t *xregs)
 229 {



















 230         lwp_info_t *lwp;
 231 
 232         if (P->state == PS_IDLE) {
 233                 errno = ENODATA;
 234                 return (-1);
 235         }
 236 
 237         if (P->state != PS_DEAD) {
 238                 if (P->state != PS_STOP) {
 239                         errno = EBUSY;
 240                         return (-1);
 241                 }
 242 
 243                 return (getlwpfile(P, lwpid, "xregs",
 244                     xregs, sizeof (prxregset_t)));
 245         }
 246 
 247         if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_xregs != NULL) {
 248                 (void) memcpy(xregs, lwp->lwp_xregs, sizeof (prxregset_t));





 249                 return (0);
 250         }
 251 
 252         if (lwp != NULL)
 253                 errno = ENODATA;
 254         return (-1);
 255 }
 256 
 257 int
 258 Plwp_setxregs(struct ps_prochandle *P, lwpid_t lwpid, const prxregset_t *xregs)
 259 {
 260         return (setlwpregs(P, lwpid, PCSXREG, xregs, sizeof (prxregset_t)));























 261 }
 262 
 263 int














 264 Plwp_getgwindows(struct ps_prochandle *P, lwpid_t lwpid, gwindows_t *gwins)
 265 {
 266         lwp_info_t *lwp;
 267 
 268         if (P->state == PS_IDLE) {
 269                 errno = ENODATA;
 270                 return (-1);
 271         }
 272 
 273         if (P->state != PS_DEAD) {
 274                 if (P->state != PS_STOP) {
 275                         errno = EBUSY;
 276                         return (-1);
 277                 }
 278 
 279                 return (getlwpfile(P, lwpid, "gwindows",
 280                     gwins, sizeof (gwindows_t)));
 281         }
 282 
 283         if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_gwins != NULL) {


 307                         return (-1);
 308                 }
 309 
 310                 return (getlwpfile(P, lwpid, "asrs", asrs, sizeof (asrset_t)));
 311         }
 312 
 313         if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_asrs != NULL) {
 314                 (void) memcpy(asrs, lwp->lwp_asrs, sizeof (asrset_t));
 315                 return (0);
 316         }
 317 
 318         if (lwp != NULL)
 319                 errno = ENODATA;
 320         return (-1);
 321 
 322 }
 323 
 324 int
 325 Plwp_setasrs(struct ps_prochandle *P, lwpid_t lwpid, const asrset_t asrs)
 326 {
 327         return (setlwpregs(P, lwpid, PCSASRS, asrs, sizeof (asrset_t)));
 328 }
 329 #endif  /* __sparcv9 */
 330 #endif  /* __sparc */
 331 
 332 int
 333 Plwp_getpsinfo(struct ps_prochandle *P, lwpid_t lwpid, lwpsinfo_t *lps)
 334 {
 335         lwp_info_t *lwp;
 336 
 337         if (P->state == PS_IDLE) {
 338                 errno = ENODATA;
 339                 return (-1);
 340         }
 341 
 342         if (P->state != PS_DEAD) {
 343                 return (getlwpfile(P, lwpid, "lwpsinfo",
 344                     lps, sizeof (lwpsinfo_t)));
 345         }
 346 
 347         if ((lwp = getlwpcore(P, lwpid)) != NULL) {




   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * Copyright 2018 Joyent, Inc.
  28  * Copyright (c) 2013 by Delphix. All rights reserved.
  29  * Copyright 2023 Oxide Computer Company
  30  */
  31 
  32 #include <sys/types.h>
  33 #include <sys/uio.h>
  34 #include <string.h>
  35 #include <errno.h>
  36 #include <limits.h>
  37 
  38 #include "Pcontrol.h"
  39 #include "P32ton.h"
  40 
  41 /*
  42  * This file implements the routines to read and write per-lwp register
  43  * information from either a live process or core file opened with libproc.  We
  44  * build up a few common routines for reading and writing register information,
  45  * and then the public functions are all trivial calls to these.  It also
  46  * implements similar logic that is used with an lwp handle.
  47  *
  48  * The primary registers and floating point registers (e.g. regs,fpregs) are
  49  * retreived from the lwp and process status files.  The library caches the
  50  * values of these files.  When we perorm updates, we ensure that cached copies
  51  * are refreshed or updated as part of this.
  52  */
  53 
  54 /*
  55  * Utility function to return a pointer to the structure of cached information
  56  * about an lwp in the core file, given its lwpid.
  57  */
  58 static lwp_info_t *
  59 getlwpcore(struct ps_prochandle *P, lwpid_t lwpid)
  60 {
  61         core_info_t *core = P->data;
  62         lwp_info_t *lwp;
  63 
  64         for (lwp = list_head(&core->core_lwp_head); lwp != NULL;
  65             lwp = list_next(&core->core_lwp_head, lwp)) {
  66                 if (lwp->lwp_id == lwpid)
  67                         return (lwp);
  68         }
  69 
  70         errno = ENOENT;
  71         return (NULL);
  72 }
  73 
  74 /*
  75  * Utility function to open and read the contents of a per-lwp /proc file.
  76  * This function is used to slurp in lwpstatus, lwpname, lwpsinfo, spymaster,
  77  * and others.
  78  */
  79 static int
  80 getlwpfile(struct ps_prochandle *P, lwpid_t lwpid,
  81     const char *fbase, void *rp, size_t n)
  82 {
  83         char fname[PATH_MAX];
  84         int fd;
  85 
  86         (void) snprintf(fname, sizeof (fname), "%s/%d/lwp/%d/%s",
  87             procfs_path, (int)P->status.pr_pid, (int)lwpid, fbase);
  88 
  89         if ((fd = open(fname, O_RDONLY)) >= 0) {
  90                 if (read(fd, rp, n) > 0) {
  91                         (void) close(fd);
  92                         return (0);
  93                 }
  94 
  95                 int e = errno;
  96                 (void) close(fd);
  97                 errno = e;
  98         }
  99         return (-1);
 100 }
 101 
 102 /*
 103  * This is a variant of getlwpfile that has three different semantics:
 104  *
 105  *  o It will stat the file to determine the size and allocate that for the
 106  *    caller.
 107  *  o If the stat size is zero (e.g. traditional xregs behavior when
 108  *    unsupported) then it will return the libproc ENODATA error.
 109  *  o It is an error if not all the data is read.
 110  *
 111  * Currently this is just used by xregs.
 112  */
 113 static int
 114 getlwpfile_alloc(struct ps_prochandle *P, lwpid_t lwpid, const char *fbase,
 115     void **datap, size_t *sizep)
 116 {
 117         char fname[PATH_MAX];
 118         int fd;
 119 
 120         (void) snprintf(fname, sizeof (fname), "%s/%d/lwp/%d/%s",
 121             procfs_path, (int)P->status.pr_pid, (int)lwpid, fbase);
 122 
 123         if ((fd = open(fname, O_RDONLY)) >= 0) {
 124                 int e;
 125                 struct stat st;
 126 
 127                 if (fstat(fd, &st) == 0) {
 128                         prxregset_t *prx;
 129 
 130                         if (st.st_size == 0) {
 131                                 errno = ENODATA;
 132                                 goto clean;
 133                         }
 134 
 135                         prx = malloc(st.st_size);
 136                         if (prx == NULL) {
 137                                 goto clean;
 138                         }
 139 
 140                         if (read(fd, prx, st.st_size) == st.st_size) {
 141                                 (void) close(fd);
 142                                 *datap = prx;
 143                                 *sizep = st.st_size;
 144                                 return (0);
 145                         }
 146 
 147                         free(prx);
 148                 }
 149 clean:
 150                 e = errno;
 151                 (void) close(fd);
 152                 errno = e;
 153         }
 154 
 155         return (-1);
 156 }
 157 
 158 /*
 159  * Get the lwpstatus_t for an lwp from either the live process or our
 160  * cached information from the core file.  This is used to get the
 161  * general-purpose registers or floating point registers.
 162  */
 163 int
 164 getlwpstatus(struct ps_prochandle *P, lwpid_t lwpid, lwpstatus_t *lps)
 165 {
 166         lwp_info_t *lwp;
 167 
 168         /*
 169          * For both live processes and cores, our job is easy if the lwpid
 170          * matches that of the representative lwp:
 171          */
 172         if (P->status.pr_lwp.pr_lwpid == lwpid) {
 173                 (void) memcpy(lps, &P->status.pr_lwp, sizeof (lwpstatus_t));
 174                 return (0);
 175         }
 176 
 177         /*
 178          * If this is a live process, then just read the information out
 179          * of the per-lwp status file:
 180          */
 181         if (P->state != PS_DEAD) {
 182                 return (getlwpfile(P, lwpid, "lwpstatus",
 183                     lps, sizeof (lwpstatus_t)));
 184         }
 185 
 186         /*
 187          * If this is a core file, we need to iterate through our list of
 188          * cached lwp information and then copy out the status.
 189          */
 190         if (P->data != NULL && (lwp = getlwpcore(P, lwpid)) != NULL) {
 191                 (void) memcpy(lps, &lwp->lwp_status, sizeof (lwpstatus_t));
 192                 return (0);
 193         }
 194 
 195         return (-1);
 196 }
 197 
 198 /*
 199  * libproc caches information about the registers for representative LWPs and
 200  * threads which we have the thread handle for. When we do a write to certain
 201  * files, we need to refresh state and take care of both the process and the
 202  * representative LWP's info. Because the xregs may or may not mutate the state
 203  * of the other regsiters, we just always do a refresh of the entire cached
 204  * psinfo.
 205  */
 206 static void
 207 refresh_status(struct ps_prochandle *P, lwpid_t lwpid, struct ps_lwphandle *L,
 208     long cmd, const void *rp, size_t n)
 209 {
 210         if (P->status.pr_lwp.pr_lwpid == lwpid) {
 211                 if (cmd == PCSREG)
 212                         (void) memcpy(P->status.pr_lwp.pr_reg, rp, n);
 213                 else if (cmd == PCSFPREG)
 214                         (void) memcpy(&P->status.pr_lwp.pr_fpreg, rp, n);
 215                 else if (cmd == PCSXREG)
 216                         (void) Pstopstatus(P, PCNULL, 0);
 217         }
 218 
 219         if (L != NULL) {
 220                 if (cmd == PCSREG)
 221                         (void) memcpy(&L->lwp_status.pr_reg, rp, n);
 222                 else if (cmd == PCSFPREG)
 223                         (void) memcpy(&L->lwp_status.pr_fpreg, rp, n);
 224                 else if (cmd == PCSXREG)
 225                         (void) Lstopstatus(L, PCNULL, 0);
 226         }
 227 }
 228 
 229 /*
 230  * Utility function to modify lwp registers.  This is done using either the
 231  * process control file or per-lwp control file as necessary.  This assumes that
 232  * we have a process-level hold on things, which may not always be true.
 233  */
 234 static int
 235 setlwpregs_proc(struct ps_prochandle *P, lwpid_t lwpid, long cmd,
 236     const void *rp, size_t n)
 237 {
 238         iovec_t iov[2];
 239         char fname[PATH_MAX];
 240         struct ps_lwphandle *L;
 241         int fd = -1;
 242 
 243         if (P->state != PS_STOP) {
 244                 errno = EBUSY;
 245                 return (-1);
 246         }
 247 
 248         iov[0].iov_base = (caddr_t)&cmd;
 249         iov[0].iov_len = sizeof (long);
 250         iov[1].iov_base = (caddr_t)rp;
 251         iov[1].iov_len = n;
 252 
 253         /*
 254          * If we have an lwp handle for this thread, then make sure that we use
 255          * that to update the state so cached information is updated.  We sync
 256          * the thread ahead of the process.
 257          */
 258         if ((L = Lfind(P, lwpid)) != NULL) {
 259                 Lsync(L);
 260                 fd = L->lwp_ctlfd;
 261         }
 262 
 263         /*
 264          * Writing the process control file writes the representative lwp.
 265          * Psync before we write to make sure we are consistent with the
 266          * primary interfaces.  Similarly, make sure to update P->status
 267          * afterward if we are modifying one of its register sets.  On some
 268          * platforms the xregs modify the other register states.  As a result,
 269          * always refresh the representative LWP's status.
 270          */
 271         if (P->status.pr_lwp.pr_lwpid == lwpid) {
 272                 Psync(P);
 273                 fd = P->ctlfd;
 274         }
 275 
 276         if (fd > -1) {
 277                 if (writev(fd, iov, 2) == -1)
 278                         return (-1);
 279                 refresh_status(P, lwpid, L, cmd, rp, n);





 280                 return (0);
 281         }
 282 
 283         /*
 284          * If the lwp we want is not the representative lwp, we need to
 285          * open the ctl file for that specific lwp.
 286          */
 287         (void) snprintf(fname, sizeof (fname), "%s/%d/lwp/%d/lwpctl",
 288             procfs_path, (int)P->status.pr_pid, (int)lwpid);
 289 
 290         if ((fd = open(fname, O_WRONLY)) >= 0) {
 291                 if (writev(fd, iov, 2) > 0) {
 292                         (void) close(fd);
 293                         return (0);
 294                 }
 295                 int e = errno;
 296                 (void) close(fd);
 297                 errno = e;
 298         }
 299         return (-1);
 300 }
 301 
 302 /*
 303  * This is a variant of the above that only assumes we have a hold on the thread
 304  * as opposed to a process.
 305  */
 306 static int
 307 setlwpregs_lwp(struct ps_lwphandle *L, long cmd, const void *rp, size_t n)
 308 {
 309         iovec_t iov[2];
 310 
 311         if (L->lwp_state != PS_STOP) {
 312                 errno = EBUSY;
 313                 return (-1);
 314         }
 315 
 316         iov[0].iov_base = (caddr_t)&cmd;
 317         iov[0].iov_len = sizeof (long);
 318         iov[1].iov_base = (caddr_t)rp;
 319         iov[1].iov_len = n;
 320 
 321         Lsync(L);
 322         if (writev(L->lwp_ctlfd, iov, 2) == -1)
 323                 return (-1);
 324         refresh_status(L->lwp_proc, L->lwp_id, L, cmd, rp, n);
 325 
 326         return (0);
 327 }
 328 
 329 int
 330 Plwp_getregs(struct ps_prochandle *P, lwpid_t lwpid, prgregset_t gregs)
 331 {
 332         lwpstatus_t lps;
 333 
 334         if (getlwpstatus(P, lwpid, &lps) == -1)
 335                 return (-1);
 336 
 337         (void) memcpy(gregs, lps.pr_reg, sizeof (prgregset_t));
 338         return (0);
 339 }
 340 
 341 int
 342 Lgetregs(struct ps_lwphandle *L, prgregset_t *gregs)
 343 {
 344         (void) memcpy(gregs, L->lwp_status.pr_reg, sizeof (prgregset_t));
 345         return (0);
 346 }
 347 
 348 int
 349 Plwp_setregs(struct ps_prochandle *P, lwpid_t lwpid, const prgregset_t gregs)
 350 {
 351         return (setlwpregs_proc(P, lwpid, PCSREG, gregs, sizeof (prgregset_t)));
 352 }
 353 
 354 int
 355 Lsetregs(struct ps_lwphandle *L, const prgregset_t *gregs)
 356 {
 357         return (setlwpregs_lwp(L, PCSREG, gregs, sizeof (prgregset_t)));
 358 }
 359 
 360 int
 361 Plwp_getfpregs(struct ps_prochandle *P, lwpid_t lwpid, prfpregset_t *fpregs)
 362 {
 363         lwpstatus_t lps;
 364 
 365         if (getlwpstatus(P, lwpid, &lps) == -1)
 366                 return (-1);
 367 
 368         (void) memcpy(fpregs, &lps.pr_fpreg, sizeof (prfpregset_t));
 369         return (0);
 370 }
 371 
 372 int
 373 Lgetfpregs(struct ps_lwphandle *L, prfpregset_t *fpregs)
 374 {
 375         (void) memcpy(fpregs, &L->lwp_status.pr_fpreg, sizeof (prfpregset_t));
 376         return (0);
 377 }
 378 
 379 int
 380 Plwp_setfpregs(struct ps_prochandle *P, lwpid_t lwpid,
 381     const prfpregset_t *fpregs)
 382 {
 383         return (setlwpregs_proc(P, lwpid, PCSFPREG, fpregs,
 384             sizeof (prfpregset_t)));
 385 }
 386 

 387 int
 388 Lsetfpregs(struct ps_lwphandle *L, const prfpregset_t *fpregs)
 389 {
 390         return (setlwpregs_lwp(L, PCSFPREG, fpregs, sizeof (prfpregset_t)));
 391 }
 392 
 393 /*
 394  * The reason that this is structured to take both the size and the process
 395  * handle is so that way we have enough information to tie this back to its
 396  * underlying source and we can eventually use umem with this.
 397  */
 398 void
 399 Plwp_freexregs(struct ps_prochandle *P __unused, prxregset_t *prx,
 400     size_t size __unused)
 401 {
 402         free(prx);
 403 }
 404 
 405 int
 406 Plwp_getxregs(struct ps_prochandle *P, lwpid_t lwpid, prxregset_t **xregs,
 407     size_t *sizep)
 408 {
 409         lwp_info_t *lwp;
 410 
 411         if (P->state == PS_IDLE) {
 412                 errno = ENODATA;
 413                 return (-1);
 414         }
 415 
 416         if (P->state != PS_DEAD) {
 417                 if (P->state != PS_STOP) {
 418                         errno = EBUSY;
 419                         return (-1);
 420                 }
 421 
 422                 return (getlwpfile_alloc(P, lwpid, "xregs",
 423                     (void **)xregs, sizep));
 424         }
 425 
 426         if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_xregs != NULL &&
 427             lwp->lwp_xregsize > 0) {
 428                 *xregs = malloc(lwp->lwp_xregsize);
 429                 if (*xregs == NULL)
 430                         return (-1);
 431                 (void) memcpy(*xregs, lwp->lwp_xregs, lwp->lwp_xregsize);
 432                 *sizep = lwp->lwp_xregsize;
 433                 return (0);
 434         }
 435 
 436         if (lwp != NULL)
 437                 errno = ENODATA;
 438         return (-1);
 439 }
 440 
 441 int
 442 Lgetxregs(struct ps_lwphandle *L, prxregset_t **xregs, size_t *sizep)
 443 {
 444         lwp_info_t *lwp;
 445 
 446         if (L->lwp_state != PS_DEAD) {
 447                 if (L->lwp_state != PS_STOP) {
 448                         errno = EBUSY;
 449                         return (-1);
 450                 }
 451                 return (getlwpfile_alloc(L->lwp_proc, L->lwp_id, "xregs",
 452                     (void **)xregs, sizep));
 453         }
 454 
 455         if ((lwp = getlwpcore(L->lwp_proc, L->lwp_id)) != NULL &&
 456             lwp->lwp_xregs != NULL && lwp->lwp_xregsize > 0) {
 457                 *xregs = malloc(lwp->lwp_xregsize);
 458                 if (*xregs == NULL)
 459                         return (-1);
 460                 (void) memcpy(*xregs, lwp->lwp_xregs, lwp->lwp_xregsize);
 461                 *sizep = lwp->lwp_xregsize;
 462                 return (0);
 463         }
 464 
 465         if (lwp != NULL)
 466                 errno = ENODATA;
 467         return (-1);
 468 }
 469 
 470 int
 471 Plwp_setxregs(struct ps_prochandle *P, lwpid_t lwpid, const prxregset_t *xregs,
 472     size_t len)
 473 {
 474         return (setlwpregs_proc(P, lwpid, PCSXREG, xregs, len));
 475 }
 476 
 477 int
 478 Lsetxregs(struct ps_lwphandle *L, const prxregset_t *xregs, size_t len)
 479 {
 480         return (setlwpregs_lwp(L, PCSXREG, xregs, len));
 481 }
 482 
 483 #if defined(sparc) || defined(__sparc)
 484 int
 485 Plwp_getgwindows(struct ps_prochandle *P, lwpid_t lwpid, gwindows_t *gwins)
 486 {
 487         lwp_info_t *lwp;
 488 
 489         if (P->state == PS_IDLE) {
 490                 errno = ENODATA;
 491                 return (-1);
 492         }
 493 
 494         if (P->state != PS_DEAD) {
 495                 if (P->state != PS_STOP) {
 496                         errno = EBUSY;
 497                         return (-1);
 498                 }
 499 
 500                 return (getlwpfile(P, lwpid, "gwindows",
 501                     gwins, sizeof (gwindows_t)));
 502         }
 503 
 504         if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_gwins != NULL) {


 528                         return (-1);
 529                 }
 530 
 531                 return (getlwpfile(P, lwpid, "asrs", asrs, sizeof (asrset_t)));
 532         }
 533 
 534         if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_asrs != NULL) {
 535                 (void) memcpy(asrs, lwp->lwp_asrs, sizeof (asrset_t));
 536                 return (0);
 537         }
 538 
 539         if (lwp != NULL)
 540                 errno = ENODATA;
 541         return (-1);
 542 
 543 }
 544 
 545 int
 546 Plwp_setasrs(struct ps_prochandle *P, lwpid_t lwpid, const asrset_t asrs)
 547 {
 548         return (setlwpregs_proc(P, lwpid, PCSASRS, asrs, sizeof (asrset_t)));
 549 }
 550 #endif  /* __sparcv9 */
 551 #endif  /* __sparc */
 552 
 553 int
 554 Plwp_getpsinfo(struct ps_prochandle *P, lwpid_t lwpid, lwpsinfo_t *lps)
 555 {
 556         lwp_info_t *lwp;
 557 
 558         if (P->state == PS_IDLE) {
 559                 errno = ENODATA;
 560                 return (-1);
 561         }
 562 
 563         if (P->state != PS_DEAD) {
 564                 return (getlwpfile(P, lwpid, "lwpsinfo",
 565                     lps, sizeof (lwpsinfo_t)));
 566         }
 567 
 568         if ((lwp = getlwpcore(P, lwpid)) != NULL) {