17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
59acbbeafSnn  * Common Development and Distribution License (the "License").
69acbbeafSnn  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
229acbbeafSnn  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
26f971a346SBryan Cantrill /*
27ab618543SJohn Levon  * Copyright 2018 Joyent, Inc.
282a12f85aSJeremy Jones  * Copyright (c) 2013 by Delphix. All rights reserved.
29*ed093b41SRobert Mustacchi  * Copyright 2023 Oxide Computer Company
30f971a346SBryan Cantrill  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/uio.h>
347c478bd9Sstevel@tonic-gate #include <string.h>
357c478bd9Sstevel@tonic-gate #include <errno.h>
369acbbeafSnn #include <limits.h>
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include "Pcontrol.h"
397c478bd9Sstevel@tonic-gate #include "P32ton.h"
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate  * This file implements the routines to read and write per-lwp register
43*ed093b41SRobert Mustacchi  * information from either a live process or core file opened with libproc.  We
44*ed093b41SRobert Mustacchi  * build up a few common routines for reading and writing register information,
45*ed093b41SRobert Mustacchi  * and then the public functions are all trivial calls to these.  It also
46*ed093b41SRobert Mustacchi  * implements similar logic that is used with an lwp handle.
47*ed093b41SRobert Mustacchi  *
48*ed093b41SRobert Mustacchi  * The primary registers and floating point registers (e.g. regs,fpregs) are
49*ed093b41SRobert Mustacchi  * retreived from the lwp and process status files.  The library caches the
50*ed093b41SRobert Mustacchi  * values of these files.  When we perorm updates, we ensure that cached copies
51*ed093b41SRobert Mustacchi  * are refreshed or updated as part of this.
527c478bd9Sstevel@tonic-gate  */
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate /*
557c478bd9Sstevel@tonic-gate  * Utility function to return a pointer to the structure of cached information
567c478bd9Sstevel@tonic-gate  * about an lwp in the core file, given its lwpid.
577c478bd9Sstevel@tonic-gate  */
587c478bd9Sstevel@tonic-gate static lwp_info_t *
getlwpcore(struct ps_prochandle * P,lwpid_t lwpid)597c478bd9Sstevel@tonic-gate getlwpcore(struct ps_prochandle *P, lwpid_t lwpid)
607c478bd9Sstevel@tonic-gate {
612a12f85aSJeremy Jones 	core_info_t *core = P->data;
6250d4d24eSRobert Mustacchi 	lwp_info_t *lwp;
637c478bd9Sstevel@tonic-gate 
6450d4d24eSRobert Mustacchi 	for (lwp = list_head(&core->core_lwp_head); lwp != NULL;
6550d4d24eSRobert Mustacchi 	    lwp = list_next(&core->core_lwp_head, lwp)) {
667c478bd9Sstevel@tonic-gate 		if (lwp->lwp_id == lwpid)
677c478bd9Sstevel@tonic-gate 			return (lwp);
687c478bd9Sstevel@tonic-gate 	}
697c478bd9Sstevel@tonic-gate 
70*ed093b41SRobert Mustacchi 	errno = ENOENT;
717c478bd9Sstevel@tonic-gate 	return (NULL);
727c478bd9Sstevel@tonic-gate }
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /*
757c478bd9Sstevel@tonic-gate  * Utility function to open and read the contents of a per-lwp /proc file.
76*ed093b41SRobert Mustacchi  * This function is used to slurp in lwpstatus, lwpname, lwpsinfo, spymaster,
77*ed093b41SRobert Mustacchi  * and others.
787c478bd9Sstevel@tonic-gate  */
797c478bd9Sstevel@tonic-gate static int
getlwpfile(struct ps_prochandle * P,lwpid_t lwpid,const char * fbase,void * rp,size_t n)807c478bd9Sstevel@tonic-gate getlwpfile(struct ps_prochandle *P, lwpid_t lwpid,
817c478bd9Sstevel@tonic-gate     const char *fbase, void *rp, size_t n)
827c478bd9Sstevel@tonic-gate {
839acbbeafSnn 	char fname[PATH_MAX];
847c478bd9Sstevel@tonic-gate 	int fd;
857c478bd9Sstevel@tonic-gate 
869acbbeafSnn 	(void) snprintf(fname, sizeof (fname), "%s/%d/lwp/%d/%s",
879acbbeafSnn 	    procfs_path, (int)P->status.pr_pid, (int)lwpid, fbase);
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	if ((fd = open(fname, O_RDONLY)) >= 0) {
907c478bd9Sstevel@tonic-gate 		if (read(fd, rp, n) > 0) {
917c478bd9Sstevel@tonic-gate 			(void) close(fd);
927c478bd9Sstevel@tonic-gate 			return (0);
937c478bd9Sstevel@tonic-gate 		}
94*ed093b41SRobert Mustacchi 
95*ed093b41SRobert Mustacchi 		int e = errno;
96*ed093b41SRobert Mustacchi 		(void) close(fd);
97*ed093b41SRobert Mustacchi 		errno = e;
98*ed093b41SRobert Mustacchi 	}
99*ed093b41SRobert Mustacchi 	return (-1);
100*ed093b41SRobert Mustacchi }
101*ed093b41SRobert Mustacchi 
102*ed093b41SRobert Mustacchi /*
103*ed093b41SRobert Mustacchi  * This is a variant of getlwpfile that has three different semantics:
104*ed093b41SRobert Mustacchi  *
105*ed093b41SRobert Mustacchi  *  o It will stat the file to determine the size and allocate that for the
106*ed093b41SRobert Mustacchi  *    caller.
107*ed093b41SRobert Mustacchi  *  o If the stat size is zero (e.g. traditional xregs behavior when
108*ed093b41SRobert Mustacchi  *    unsupported) then it will return the libproc ENODATA error.
109*ed093b41SRobert Mustacchi  *  o It is an error if not all the data is read.
110*ed093b41SRobert Mustacchi  *
111*ed093b41SRobert Mustacchi  * Currently this is just used by xregs.
112*ed093b41SRobert Mustacchi  */
113*ed093b41SRobert Mustacchi static int
getlwpfile_alloc(struct ps_prochandle * P,lwpid_t lwpid,const char * fbase,void ** datap,size_t * sizep)114*ed093b41SRobert Mustacchi getlwpfile_alloc(struct ps_prochandle *P, lwpid_t lwpid, const char *fbase,
115*ed093b41SRobert Mustacchi     void **datap, size_t *sizep)
116*ed093b41SRobert Mustacchi {
117*ed093b41SRobert Mustacchi 	char fname[PATH_MAX];
118*ed093b41SRobert Mustacchi 	int fd;
119*ed093b41SRobert Mustacchi 
120*ed093b41SRobert Mustacchi 	(void) snprintf(fname, sizeof (fname), "%s/%d/lwp/%d/%s",
121*ed093b41SRobert Mustacchi 	    procfs_path, (int)P->status.pr_pid, (int)lwpid, fbase);
122*ed093b41SRobert Mustacchi 
123*ed093b41SRobert Mustacchi 	if ((fd = open(fname, O_RDONLY)) >= 0) {
124*ed093b41SRobert Mustacchi 		int e;
125*ed093b41SRobert Mustacchi 		struct stat st;
126*ed093b41SRobert Mustacchi 
127*ed093b41SRobert Mustacchi 		if (fstat(fd, &st) == 0) {
128*ed093b41SRobert Mustacchi 			prxregset_t *prx;
129*ed093b41SRobert Mustacchi 
130*ed093b41SRobert Mustacchi 			if (st.st_size == 0) {
131*ed093b41SRobert Mustacchi 				errno = ENODATA;
132*ed093b41SRobert Mustacchi 				goto clean;
133*ed093b41SRobert Mustacchi 			}
134*ed093b41SRobert Mustacchi 
135*ed093b41SRobert Mustacchi 			prx = malloc(st.st_size);
136*ed093b41SRobert Mustacchi 			if (prx == NULL) {
137*ed093b41SRobert Mustacchi 				goto clean;
138*ed093b41SRobert Mustacchi 			}
139*ed093b41SRobert Mustacchi 
140*ed093b41SRobert Mustacchi 			if (read(fd, prx, st.st_size) == st.st_size) {
141*ed093b41SRobert Mustacchi 				(void) close(fd);
142*ed093b41SRobert Mustacchi 				*datap = prx;
143*ed093b41SRobert Mustacchi 				*sizep = st.st_size;
144*ed093b41SRobert Mustacchi 				return (0);
145*ed093b41SRobert Mustacchi 			}
146*ed093b41SRobert Mustacchi 
147*ed093b41SRobert Mustacchi 			free(prx);
148*ed093b41SRobert Mustacchi 		}
149*ed093b41SRobert Mustacchi clean:
150*ed093b41SRobert Mustacchi 		e = errno;
1517c478bd9Sstevel@tonic-gate 		(void) close(fd);
152*ed093b41SRobert Mustacchi 		errno = e;
1537c478bd9Sstevel@tonic-gate 	}
154*ed093b41SRobert Mustacchi 
1557c478bd9Sstevel@tonic-gate 	return (-1);
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate /*
1597c478bd9Sstevel@tonic-gate  * Get the lwpstatus_t for an lwp from either the live process or our
1607c478bd9Sstevel@tonic-gate  * cached information from the core file.  This is used to get the
1617c478bd9Sstevel@tonic-gate  * general-purpose registers or floating point registers.
1627c478bd9Sstevel@tonic-gate  */
1637c478bd9Sstevel@tonic-gate int
getlwpstatus(struct ps_prochandle * P,lwpid_t lwpid,lwpstatus_t * lps)1647c478bd9Sstevel@tonic-gate getlwpstatus(struct ps_prochandle *P, lwpid_t lwpid, lwpstatus_t *lps)
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate 	lwp_info_t *lwp;
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	/*
1697c478bd9Sstevel@tonic-gate 	 * For both live processes and cores, our job is easy if the lwpid
1707c478bd9Sstevel@tonic-gate 	 * matches that of the representative lwp:
1717c478bd9Sstevel@tonic-gate 	 */
1727c478bd9Sstevel@tonic-gate 	if (P->status.pr_lwp.pr_lwpid == lwpid) {
1737c478bd9Sstevel@tonic-gate 		(void) memcpy(lps, &P->status.pr_lwp, sizeof (lwpstatus_t));
1747c478bd9Sstevel@tonic-gate 		return (0);
1757c478bd9Sstevel@tonic-gate 	}
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	/*
1787c478bd9Sstevel@tonic-gate 	 * If this is a live process, then just read the information out
1797c478bd9Sstevel@tonic-gate 	 * of the per-lwp status file:
1807c478bd9Sstevel@tonic-gate 	 */
1817c478bd9Sstevel@tonic-gate 	if (P->state != PS_DEAD) {
1827c478bd9Sstevel@tonic-gate 		return (getlwpfile(P, lwpid, "lwpstatus",
1837c478bd9Sstevel@tonic-gate 		    lps, sizeof (lwpstatus_t)));
1847c478bd9Sstevel@tonic-gate 	}
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	/*
1877c478bd9Sstevel@tonic-gate 	 * If this is a core file, we need to iterate through our list of
1887c478bd9Sstevel@tonic-gate 	 * cached lwp information and then copy out the status.
1897c478bd9Sstevel@tonic-gate 	 */
1902a12f85aSJeremy Jones 	if (P->data != NULL && (lwp = getlwpcore(P, lwpid)) != NULL) {
1917c478bd9Sstevel@tonic-gate 		(void) memcpy(lps, &lwp->lwp_status, sizeof (lwpstatus_t));
1927c478bd9Sstevel@tonic-gate 		return (0);
1937c478bd9Sstevel@tonic-gate 	}
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	return (-1);
1967c478bd9Sstevel@tonic-gate }
1977c478bd9Sstevel@tonic-gate 
198*ed093b41SRobert Mustacchi /*
199*ed093b41SRobert Mustacchi  * libproc caches information about the registers for representative LWPs and
200*ed093b41SRobert Mustacchi  * threads which we have the thread handle for. When we do a write to certain
201*ed093b41SRobert Mustacchi  * files, we need to refresh state and take care of both the process and the
202*ed093b41SRobert Mustacchi  * representative LWP's info. Because the xregs may or may not mutate the state
203*ed093b41SRobert Mustacchi  * of the other regsiters, we just always do a refresh of the entire cached
204*ed093b41SRobert Mustacchi  * psinfo.
205*ed093b41SRobert Mustacchi  */
206*ed093b41SRobert Mustacchi static void
refresh_status(struct ps_prochandle * P,lwpid_t lwpid,struct ps_lwphandle * L,long cmd,const void * rp,size_t n)207*ed093b41SRobert Mustacchi refresh_status(struct ps_prochandle *P, lwpid_t lwpid, struct ps_lwphandle *L,
208*ed093b41SRobert Mustacchi     long cmd, const void *rp, size_t n)
209*ed093b41SRobert Mustacchi {
210*ed093b41SRobert Mustacchi 	if (P->status.pr_lwp.pr_lwpid == lwpid) {
211*ed093b41SRobert Mustacchi 		if (cmd == PCSREG)
212*ed093b41SRobert Mustacchi 			(void) memcpy(P->status.pr_lwp.pr_reg, rp, n);
213*ed093b41SRobert Mustacchi 		else if (cmd == PCSFPREG)
214*ed093b41SRobert Mustacchi 			(void) memcpy(&P->status.pr_lwp.pr_fpreg, rp, n);
215*ed093b41SRobert Mustacchi 		else if (cmd == PCSXREG)
216*ed093b41SRobert Mustacchi 			(void) Pstopstatus(P, PCNULL, 0);
217*ed093b41SRobert Mustacchi 	}
218*ed093b41SRobert Mustacchi 
219*ed093b41SRobert Mustacchi 	if (L != NULL) {
220*ed093b41SRobert Mustacchi 		if (cmd == PCSREG)
221*ed093b41SRobert Mustacchi 			(void) memcpy(&L->lwp_status.pr_reg, rp, n);
222*ed093b41SRobert Mustacchi 		else if (cmd == PCSFPREG)
223*ed093b41SRobert Mustacchi 			(void) memcpy(&L->lwp_status.pr_fpreg, rp, n);
224*ed093b41SRobert Mustacchi 		else if (cmd == PCSXREG)
225*ed093b41SRobert Mustacchi 			(void) Lstopstatus(L, PCNULL, 0);
226*ed093b41SRobert Mustacchi 	}
227*ed093b41SRobert Mustacchi }
228*ed093b41SRobert Mustacchi 
2297c478bd9Sstevel@tonic-gate /*
2307c478bd9Sstevel@tonic-gate  * Utility function to modify lwp registers.  This is done using either the
231*ed093b41SRobert Mustacchi  * process control file or per-lwp control file as necessary.  This assumes that
232*ed093b41SRobert Mustacchi  * we have a process-level hold on things, which may not always be true.
2337c478bd9Sstevel@tonic-gate  */
2347c478bd9Sstevel@tonic-gate static int
setlwpregs_proc(struct ps_prochandle * P,lwpid_t lwpid,long cmd,const void * rp,size_t n)235*ed093b41SRobert Mustacchi setlwpregs_proc(struct ps_prochandle *P, lwpid_t lwpid, long cmd,
2367c478bd9Sstevel@tonic-gate     const void *rp, size_t n)
2377c478bd9Sstevel@tonic-gate {
2387c478bd9Sstevel@tonic-gate 	iovec_t iov[2];
2399acbbeafSnn 	char fname[PATH_MAX];
240*ed093b41SRobert Mustacchi 	struct ps_lwphandle *L;
241*ed093b41SRobert Mustacchi 	int fd = -1;
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	if (P->state != PS_STOP) {
2447c478bd9Sstevel@tonic-gate 		errno = EBUSY;
2457c478bd9Sstevel@tonic-gate 		return (-1);
2467c478bd9Sstevel@tonic-gate 	}
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	iov[0].iov_base = (caddr_t)&cmd;
2497c478bd9Sstevel@tonic-gate 	iov[0].iov_len = sizeof (long);
2507c478bd9Sstevel@tonic-gate 	iov[1].iov_base = (caddr_t)rp;
2517c478bd9Sstevel@tonic-gate 	iov[1].iov_len = n;
2527c478bd9Sstevel@tonic-gate 
253*ed093b41SRobert Mustacchi 	/*
254*ed093b41SRobert Mustacchi 	 * If we have an lwp handle for this thread, then make sure that we use
255*ed093b41SRobert Mustacchi 	 * that to update the state so cached information is updated.  We sync
256*ed093b41SRobert Mustacchi 	 * the thread ahead of the process.
257*ed093b41SRobert Mustacchi 	 */
258*ed093b41SRobert Mustacchi 	if ((L = Lfind(P, lwpid)) != NULL) {
259*ed093b41SRobert Mustacchi 		Lsync(L);
260*ed093b41SRobert Mustacchi 		fd = L->lwp_ctlfd;
261*ed093b41SRobert Mustacchi 	}
262*ed093b41SRobert Mustacchi 
2637c478bd9Sstevel@tonic-gate 	/*
2647c478bd9Sstevel@tonic-gate 	 * Writing the process control file writes the representative lwp.
2657c478bd9Sstevel@tonic-gate 	 * Psync before we write to make sure we are consistent with the
2667c478bd9Sstevel@tonic-gate 	 * primary interfaces.  Similarly, make sure to update P->status
267*ed093b41SRobert Mustacchi 	 * afterward if we are modifying one of its register sets.  On some
268*ed093b41SRobert Mustacchi 	 * platforms the xregs cover the base integer or floating point
269*ed093b41SRobert Mustacchi 	 * registers.  As a result, always refresh the representative LWP's
270*ed093b41SRobert Mustacchi 	 * status.
2717c478bd9Sstevel@tonic-gate 	 */
2727c478bd9Sstevel@tonic-gate 	if (P->status.pr_lwp.pr_lwpid == lwpid) {
2737c478bd9Sstevel@tonic-gate 		Psync(P);
274*ed093b41SRobert Mustacchi 		fd = P->ctlfd;
275*ed093b41SRobert Mustacchi 	}
2767c478bd9Sstevel@tonic-gate 
277*ed093b41SRobert Mustacchi 	if (fd > -1) {
278*ed093b41SRobert Mustacchi 		if (writev(fd, iov, 2) == -1)
2797c478bd9Sstevel@tonic-gate 			return (-1);
280*ed093b41SRobert Mustacchi 		refresh_status(P, lwpid, L, cmd, rp, n);
2817c478bd9Sstevel@tonic-gate 		return (0);
2827c478bd9Sstevel@tonic-gate 	}
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	/*
2857c478bd9Sstevel@tonic-gate 	 * If the lwp we want is not the representative lwp, we need to
2867c478bd9Sstevel@tonic-gate 	 * open the ctl file for that specific lwp.
2877c478bd9Sstevel@tonic-gate 	 */
2889acbbeafSnn 	(void) snprintf(fname, sizeof (fname), "%s/%d/lwp/%d/lwpctl",
2899acbbeafSnn 	    procfs_path, (int)P->status.pr_pid, (int)lwpid);
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	if ((fd = open(fname, O_WRONLY)) >= 0) {
2927c478bd9Sstevel@tonic-gate 		if (writev(fd, iov, 2) > 0) {
2937c478bd9Sstevel@tonic-gate 			(void) close(fd);
2947c478bd9Sstevel@tonic-gate 			return (0);
2957c478bd9Sstevel@tonic-gate 		}
296*ed093b41SRobert Mustacchi 		int e = errno;
2977c478bd9Sstevel@tonic-gate 		(void) close(fd);
298*ed093b41SRobert Mustacchi 		errno = e;
2997c478bd9Sstevel@tonic-gate 	}
3007c478bd9Sstevel@tonic-gate 	return (-1);
3017c478bd9Sstevel@tonic-gate }
3027c478bd9Sstevel@tonic-gate 
303*ed093b41SRobert Mustacchi /*
304*ed093b41SRobert Mustacchi  * This is a variant of the above that only assumes we have a hold on the thread
305*ed093b41SRobert Mustacchi  * as opposed to a process.
306*ed093b41SRobert Mustacchi  */
307*ed093b41SRobert Mustacchi static int
setlwpregs_lwp(struct ps_lwphandle * L,long cmd,const void * rp,size_t n)308*ed093b41SRobert Mustacchi setlwpregs_lwp(struct ps_lwphandle *L, long cmd, const void *rp, size_t n)
309*ed093b41SRobert Mustacchi {
310*ed093b41SRobert Mustacchi 	iovec_t iov[2];
311*ed093b41SRobert Mustacchi 
312*ed093b41SRobert Mustacchi 	if (L->lwp_state != PS_STOP) {
313*ed093b41SRobert Mustacchi 		errno = EBUSY;
314*ed093b41SRobert Mustacchi 		return (-1);
315*ed093b41SRobert Mustacchi 	}
316*ed093b41SRobert Mustacchi 
317*ed093b41SRobert Mustacchi 	iov[0].iov_base = (caddr_t)&cmd;
318*ed093b41SRobert Mustacchi 	iov[0].iov_len = sizeof (long);
319*ed093b41SRobert Mustacchi 	iov[1].iov_base = (caddr_t)rp;
320*ed093b41SRobert Mustacchi 	iov[1].iov_len = n;
321*ed093b41SRobert Mustacchi 
322*ed093b41SRobert Mustacchi 	Lsync(L);
323*ed093b41SRobert Mustacchi 	if (writev(L->lwp_ctlfd, iov, 2) == -1)
324*ed093b41SRobert Mustacchi 		return (-1);
325*ed093b41SRobert Mustacchi 	refresh_status(L->lwp_proc, L->lwp_id, L, cmd, rp, n);
326*ed093b41SRobert Mustacchi 
327*ed093b41SRobert Mustacchi 	return (0);
328*ed093b41SRobert Mustacchi }
329*ed093b41SRobert Mustacchi 
3307c478bd9Sstevel@tonic-gate int
Plwp_getregs(struct ps_prochandle * P,lwpid_t lwpid,prgregset_t gregs)3317c478bd9Sstevel@tonic-gate Plwp_getregs(struct ps_prochandle *P, lwpid_t lwpid, prgregset_t gregs)
3327c478bd9Sstevel@tonic-gate {
3337c478bd9Sstevel@tonic-gate 	lwpstatus_t lps;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	if (getlwpstatus(P, lwpid, &lps) == -1)
3367c478bd9Sstevel@tonic-gate 		return (-1);
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	(void) memcpy(gregs, lps.pr_reg, sizeof (prgregset_t));
3397c478bd9Sstevel@tonic-gate 	return (0);
3407c478bd9Sstevel@tonic-gate }
3417c478bd9Sstevel@tonic-gate 
342*ed093b41SRobert Mustacchi int
Lgetregs(struct ps_lwphandle * L,prgregset_t * gregs)343*ed093b41SRobert Mustacchi Lgetregs(struct ps_lwphandle *L, prgregset_t *gregs)
344*ed093b41SRobert Mustacchi {
345*ed093b41SRobert Mustacchi 	(void) memcpy(gregs, L->lwp_status.pr_reg, sizeof (prgregset_t));
346*ed093b41SRobert Mustacchi 	return (0);
347*ed093b41SRobert Mustacchi }
348*ed093b41SRobert Mustacchi 
3497c478bd9Sstevel@tonic-gate int
Plwp_setregs(struct ps_prochandle * P,lwpid_t lwpid,const prgregset_t gregs)3507c478bd9Sstevel@tonic-gate Plwp_setregs(struct ps_prochandle *P, lwpid_t lwpid, const prgregset_t gregs)
3517c478bd9Sstevel@tonic-gate {
352*ed093b41SRobert Mustacchi 	return (setlwpregs_proc(P, lwpid, PCSREG, gregs, sizeof (prgregset_t)));
353*ed093b41SRobert Mustacchi }
354*ed093b41SRobert Mustacchi 
355*ed093b41SRobert Mustacchi int
Lsetregs(struct ps_lwphandle * L,const prgregset_t * gregs)356*ed093b41SRobert Mustacchi Lsetregs(struct ps_lwphandle *L, const prgregset_t *gregs)
357*ed093b41SRobert Mustacchi {
358*ed093b41SRobert Mustacchi 	return (setlwpregs_lwp(L, PCSREG, gregs, sizeof (prgregset_t)));
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate int
Plwp_getfpregs(struct ps_prochandle * P,lwpid_t lwpid,prfpregset_t * fpregs)3627c478bd9Sstevel@tonic-gate Plwp_getfpregs(struct ps_prochandle *P, lwpid_t lwpid, prfpregset_t *fpregs)
3637c478bd9Sstevel@tonic-gate {
3647c478bd9Sstevel@tonic-gate 	lwpstatus_t lps;
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	if (getlwpstatus(P, lwpid, &lps) == -1)
3677c478bd9Sstevel@tonic-gate 		return (-1);
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	(void) memcpy(fpregs, &lps.pr_fpreg, sizeof (prfpregset_t));
3707c478bd9Sstevel@tonic-gate 	return (0);
3717c478bd9Sstevel@tonic-gate }
3727c478bd9Sstevel@tonic-gate 
373*ed093b41SRobert Mustacchi int
Lgetfpregs(struct ps_lwphandle * L,prfpregset_t * fpregs)374*ed093b41SRobert Mustacchi Lgetfpregs(struct ps_lwphandle *L, prfpregset_t *fpregs)
375*ed093b41SRobert Mustacchi {
376*ed093b41SRobert Mustacchi 	(void) memcpy(fpregs, &L->lwp_status.pr_fpreg, sizeof (prfpregset_t));
377*ed093b41SRobert Mustacchi 	return (0);
378*ed093b41SRobert Mustacchi }
379*ed093b41SRobert Mustacchi 
380*ed093b41SRobert Mustacchi int
Plwp_setfpregs(struct ps_prochandle * P,lwpid_t lwpid,const prfpregset_t * fpregs)381*ed093b41SRobert Mustacchi Plwp_setfpregs(struct ps_prochandle *P, lwpid_t lwpid,
3827c478bd9Sstevel@tonic-gate     const prfpregset_t *fpregs)
3837c478bd9Sstevel@tonic-gate {
384*ed093b41SRobert Mustacchi 	return (setlwpregs_proc(P, lwpid, PCSFPREG, fpregs,
385*ed093b41SRobert Mustacchi 	    sizeof (prfpregset_t)));
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate int
Lsetfpregs(struct ps_lwphandle * L,const prfpregset_t * fpregs)389*ed093b41SRobert Mustacchi Lsetfpregs(struct ps_lwphandle *L, const prfpregset_t *fpregs)
390*ed093b41SRobert Mustacchi {
391*ed093b41SRobert Mustacchi 	return (setlwpregs_lwp(L, PCSFPREG, fpregs, sizeof (prfpregset_t)));
392*ed093b41SRobert Mustacchi }
393*ed093b41SRobert Mustacchi 
394*ed093b41SRobert Mustacchi /*
395*ed093b41SRobert Mustacchi  * The reason that this is structured to take both the size and the process
396*ed093b41SRobert Mustacchi  * handle is so that way we have enough information to tie this back to its
397*ed093b41SRobert Mustacchi  * underlying source and we can eventually use umem with this.
398*ed093b41SRobert Mustacchi  */
399*ed093b41SRobert Mustacchi void
Plwp_freexregs(struct ps_prochandle * P __unused,prxregset_t * prx,size_t size __unused)400*ed093b41SRobert Mustacchi Plwp_freexregs(struct ps_prochandle *P __unused, prxregset_t *prx,
401*ed093b41SRobert Mustacchi     size_t size __unused)
402*ed093b41SRobert Mustacchi {
403*ed093b41SRobert Mustacchi 	free(prx);
404*ed093b41SRobert Mustacchi }
405*ed093b41SRobert Mustacchi 
406*ed093b41SRobert Mustacchi /*
407*ed093b41SRobert Mustacchi  * Get a given thread's lwp registers. If this is a core file, we read it from
408*ed093b41SRobert Mustacchi  * the cache. If this is a live process, we always read it from the underlying
409*ed093b41SRobert Mustacchi  * file system because we do not currently cache xregs in libproc. sizep is the
410*ed093b41SRobert Mustacchi  * resulting size of data we've allocated and for a live process is filled in
411*ed093b41SRobert Mustacchi  * based on the /proc stat(2) information.
412*ed093b41SRobert Mustacchi  */
413*ed093b41SRobert Mustacchi int
Plwp_getxregs(struct ps_prochandle * P,lwpid_t lwpid,prxregset_t ** xregs,size_t * sizep)414*ed093b41SRobert Mustacchi Plwp_getxregs(struct ps_prochandle *P, lwpid_t lwpid, prxregset_t **xregs,
415*ed093b41SRobert Mustacchi     size_t *sizep)
4167c478bd9Sstevel@tonic-gate {
4177c478bd9Sstevel@tonic-gate 	lwp_info_t *lwp;
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
4207c478bd9Sstevel@tonic-gate 		errno = ENODATA;
4217c478bd9Sstevel@tonic-gate 		return (-1);
4227c478bd9Sstevel@tonic-gate 	}
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	if (P->state != PS_DEAD) {
4257c478bd9Sstevel@tonic-gate 		if (P->state != PS_STOP) {
4267c478bd9Sstevel@tonic-gate 			errno = EBUSY;
4277c478bd9Sstevel@tonic-gate 			return (-1);
4287c478bd9Sstevel@tonic-gate 		}
4297c478bd9Sstevel@tonic-gate 
430*ed093b41SRobert Mustacchi 		return (getlwpfile_alloc(P, lwpid, "xregs",
431*ed093b41SRobert Mustacchi 		    (void **)xregs, sizep));
432*ed093b41SRobert Mustacchi 	}
433*ed093b41SRobert Mustacchi 
434*ed093b41SRobert Mustacchi 	if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_xregs != NULL &&
435*ed093b41SRobert Mustacchi 	    lwp->lwp_xregsize > 0) {
436*ed093b41SRobert Mustacchi 		*xregs = malloc(lwp->lwp_xregsize);
437*ed093b41SRobert Mustacchi 		if (*xregs == NULL)
438*ed093b41SRobert Mustacchi 			return (-1);
439*ed093b41SRobert Mustacchi 		(void) memcpy(*xregs, lwp->lwp_xregs, lwp->lwp_xregsize);
440*ed093b41SRobert Mustacchi 		*sizep = lwp->lwp_xregsize;
441*ed093b41SRobert Mustacchi 		return (0);
442*ed093b41SRobert Mustacchi 	}
443*ed093b41SRobert Mustacchi 
444*ed093b41SRobert Mustacchi 	if (lwp != NULL)
445*ed093b41SRobert Mustacchi 		errno = ENODATA;
446*ed093b41SRobert Mustacchi 	return (-1);
447*ed093b41SRobert Mustacchi }
448*ed093b41SRobert Mustacchi 
449*ed093b41SRobert Mustacchi int
Lgetxregs(struct ps_lwphandle * L,prxregset_t ** xregs,size_t * sizep)450*ed093b41SRobert Mustacchi Lgetxregs(struct ps_lwphandle *L, prxregset_t **xregs, size_t *sizep)
451*ed093b41SRobert Mustacchi {
452*ed093b41SRobert Mustacchi 	lwp_info_t *lwp;
453*ed093b41SRobert Mustacchi 
454*ed093b41SRobert Mustacchi 	if (L->lwp_state != PS_DEAD) {
455*ed093b41SRobert Mustacchi 		if (L->lwp_state != PS_STOP) {
456*ed093b41SRobert Mustacchi 			errno = EBUSY;
457*ed093b41SRobert Mustacchi 			return (-1);
458*ed093b41SRobert Mustacchi 		}
459*ed093b41SRobert Mustacchi 		return (getlwpfile_alloc(L->lwp_proc, L->lwp_id, "xregs",
460*ed093b41SRobert Mustacchi 		    (void **)xregs, sizep));
4617c478bd9Sstevel@tonic-gate 	}
4627c478bd9Sstevel@tonic-gate 
463*ed093b41SRobert Mustacchi 	if ((lwp = getlwpcore(L->lwp_proc, L->lwp_id)) != NULL &&
464*ed093b41SRobert Mustacchi 	    lwp->lwp_xregs != NULL && lwp->lwp_xregsize > 0) {
465*ed093b41SRobert Mustacchi 		*xregs = malloc(lwp->lwp_xregsize);
466*ed093b41SRobert Mustacchi 		if (*xregs == NULL)
467*ed093b41SRobert Mustacchi 			return (-1);
468*ed093b41SRobert Mustacchi 		(void) memcpy(*xregs, lwp->lwp_xregs, lwp->lwp_xregsize);
469*ed093b41SRobert Mustacchi 		*sizep = lwp->lwp_xregsize;
4707c478bd9Sstevel@tonic-gate 		return (0);
4717c478bd9Sstevel@tonic-gate 	}
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	if (lwp != NULL)
4747c478bd9Sstevel@tonic-gate 		errno = ENODATA;
4757c478bd9Sstevel@tonic-gate 	return (-1);
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate int
Plwp_setxregs(struct ps_prochandle * P,lwpid_t lwpid,const prxregset_t * xregs,size_t len)479*ed093b41SRobert Mustacchi Plwp_setxregs(struct ps_prochandle *P, lwpid_t lwpid, const prxregset_t *xregs,
480*ed093b41SRobert Mustacchi     size_t len)
4817c478bd9Sstevel@tonic-gate {
482*ed093b41SRobert Mustacchi 	return (setlwpregs_proc(P, lwpid, PCSXREG, xregs, len));
4837c478bd9Sstevel@tonic-gate }
4847c478bd9Sstevel@tonic-gate 
485*ed093b41SRobert Mustacchi int
Lsetxregs(struct ps_lwphandle * L,const prxregset_t * xregs,size_t len)486*ed093b41SRobert Mustacchi Lsetxregs(struct ps_lwphandle *L, const prxregset_t *xregs, size_t len)
487*ed093b41SRobert Mustacchi {
488*ed093b41SRobert Mustacchi 	return (setlwpregs_lwp(L, PCSXREG, xregs, len));
489*ed093b41SRobert Mustacchi }
490*ed093b41SRobert Mustacchi 
491*ed093b41SRobert Mustacchi #if defined(sparc) || defined(__sparc)
4927c478bd9Sstevel@tonic-gate int
Plwp_getgwindows(struct ps_prochandle * P,lwpid_t lwpid,gwindows_t * gwins)4937c478bd9Sstevel@tonic-gate Plwp_getgwindows(struct ps_prochandle *P, lwpid_t lwpid, gwindows_t *gwins)
4947c478bd9Sstevel@tonic-gate {
4957c478bd9Sstevel@tonic-gate 	lwp_info_t *lwp;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
4987c478bd9Sstevel@tonic-gate 		errno = ENODATA;
4997c478bd9Sstevel@tonic-gate 		return (-1);
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	if (P->state != PS_DEAD) {
5037c478bd9Sstevel@tonic-gate 		if (P->state != PS_STOP) {
5047c478bd9Sstevel@tonic-gate 			errno = EBUSY;
5057c478bd9Sstevel@tonic-gate 			return (-1);
5067c478bd9Sstevel@tonic-gate 		}
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 		return (getlwpfile(P, lwpid, "gwindows",
5097c478bd9Sstevel@tonic-gate 		    gwins, sizeof (gwindows_t)));
5107c478bd9Sstevel@tonic-gate 	}
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_gwins != NULL) {
5137c478bd9Sstevel@tonic-gate 		*gwins = *lwp->lwp_gwins;
5147c478bd9Sstevel@tonic-gate 		return (0);
5157c478bd9Sstevel@tonic-gate 	}
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	if (lwp != NULL)
5187c478bd9Sstevel@tonic-gate 		errno = ENODATA;
5197c478bd9Sstevel@tonic-gate 	return (-1);
5207c478bd9Sstevel@tonic-gate }
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate #if defined(__sparcv9)
5237c478bd9Sstevel@tonic-gate int
Plwp_getasrs(struct ps_prochandle * P,lwpid_t lwpid,asrset_t asrs)5247c478bd9Sstevel@tonic-gate Plwp_getasrs(struct ps_prochandle *P, lwpid_t lwpid, asrset_t asrs)
5257c478bd9Sstevel@tonic-gate {
5267c478bd9Sstevel@tonic-gate 	lwp_info_t *lwp;
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
5297c478bd9Sstevel@tonic-gate 		errno = ENODATA;
5307c478bd9Sstevel@tonic-gate 		return (-1);
5317c478bd9Sstevel@tonic-gate 	}
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	if (P->state != PS_DEAD) {
5347c478bd9Sstevel@tonic-gate 		if (P->state != PS_STOP) {
5357c478bd9Sstevel@tonic-gate 			errno = EBUSY;
5367c478bd9Sstevel@tonic-gate 			return (-1);
5377c478bd9Sstevel@tonic-gate 		}
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 		return (getlwpfile(P, lwpid, "asrs", asrs, sizeof (asrset_t)));
5407c478bd9Sstevel@tonic-gate 	}
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_asrs != NULL) {
5437c478bd9Sstevel@tonic-gate 		(void) memcpy(asrs, lwp->lwp_asrs, sizeof (asrset_t));
5447c478bd9Sstevel@tonic-gate 		return (0);
5457c478bd9Sstevel@tonic-gate 	}
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	if (lwp != NULL)
5487c478bd9Sstevel@tonic-gate 		errno = ENODATA;
5497c478bd9Sstevel@tonic-gate 	return (-1);
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate int
Plwp_setasrs(struct ps_prochandle * P,lwpid_t lwpid,const asrset_t asrs)5547c478bd9Sstevel@tonic-gate Plwp_setasrs(struct ps_prochandle *P, lwpid_t lwpid, const asrset_t asrs)
5557c478bd9Sstevel@tonic-gate {
556*ed093b41SRobert Mustacchi 	return (setlwpregs_proc(P, lwpid, PCSASRS, asrs, sizeof (asrset_t)));
5577c478bd9Sstevel@tonic-gate }
5587c478bd9Sstevel@tonic-gate #endif	/* __sparcv9 */
5597c478bd9Sstevel@tonic-gate #endif	/* __sparc */
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate int
Plwp_getpsinfo(struct ps_prochandle * P,lwpid_t lwpid,lwpsinfo_t * lps)5627c478bd9Sstevel@tonic-gate Plwp_getpsinfo(struct ps_prochandle *P, lwpid_t lwpid, lwpsinfo_t *lps)
5637c478bd9Sstevel@tonic-gate {
5647c478bd9Sstevel@tonic-gate 	lwp_info_t *lwp;
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
5677c478bd9Sstevel@tonic-gate 		errno = ENODATA;
5687c478bd9Sstevel@tonic-gate 		return (-1);
5697c478bd9Sstevel@tonic-gate 	}
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	if (P->state != PS_DEAD) {
5727c478bd9Sstevel@tonic-gate 		return (getlwpfile(P, lwpid, "lwpsinfo",
5737c478bd9Sstevel@tonic-gate 		    lps, sizeof (lwpsinfo_t)));
5747c478bd9Sstevel@tonic-gate 	}
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	if ((lwp = getlwpcore(P, lwpid)) != NULL) {
5777c478bd9Sstevel@tonic-gate 		(void) memcpy(lps, &lwp->lwp_psinfo, sizeof (lwpsinfo_t));
5787c478bd9Sstevel@tonic-gate 		return (0);
5797c478bd9Sstevel@tonic-gate 	}
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	return (-1);
5827c478bd9Sstevel@tonic-gate }
5837c478bd9Sstevel@tonic-gate 
584ab618543SJohn Levon int
Plwp_getname(struct ps_prochandle * P,lwpid_t lwpid,char * buf,size_t bufsize)585ab618543SJohn Levon Plwp_getname(struct ps_prochandle *P, lwpid_t lwpid,
586ab618543SJohn Levon     char *buf, size_t bufsize)
587ab618543SJohn Levon {
588ab618543SJohn Levon 	char lwpname[THREAD_NAME_MAX];
589ab618543SJohn Levon 	char *from = NULL;
590ab618543SJohn Levon 	lwp_info_t *lwp;
591ab618543SJohn Levon 
592ab618543SJohn Levon 	if (P->state == PS_IDLE) {
593ab618543SJohn Levon 		errno = ENODATA;
594ab618543SJohn Levon 		return (-1);
595ab618543SJohn Levon 	}
596ab618543SJohn Levon 
597ab618543SJohn Levon 	if (P->state != PS_DEAD) {
598ab618543SJohn Levon 		if (getlwpfile(P, lwpid, "lwpname",
599ab618543SJohn Levon 		    lwpname, sizeof (lwpname)) != 0)
600ab618543SJohn Levon 			return (-1);
601ab618543SJohn Levon 		from = lwpname;
602ab618543SJohn Levon 	} else {
603ab618543SJohn Levon 		if ((lwp = getlwpcore(P, lwpid)) == NULL)
604ab618543SJohn Levon 			return (-1);
605ab618543SJohn Levon 		from = lwp->lwp_name;
606ab618543SJohn Levon 	}
607ab618543SJohn Levon 
608ab618543SJohn Levon 	if (strlcpy(buf, from, bufsize) >= bufsize) {
609ab618543SJohn Levon 		errno = ENAMETOOLONG;
610ab618543SJohn Levon 		return (-1);
611ab618543SJohn Levon 	}
612ab618543SJohn Levon 
613ab618543SJohn Levon 	return (0);
614ab618543SJohn Levon }
615ab618543SJohn Levon 
616f971a346SBryan Cantrill int
Plwp_getspymaster(struct ps_prochandle * P,lwpid_t lwpid,psinfo_t * ps)617f971a346SBryan Cantrill Plwp_getspymaster(struct ps_prochandle *P, lwpid_t lwpid, psinfo_t *ps)
618f971a346SBryan Cantrill {
619f971a346SBryan Cantrill 	lwpstatus_t lps;
620f971a346SBryan Cantrill 
621f971a346SBryan Cantrill 	if (P->state == PS_IDLE) {
622f971a346SBryan Cantrill 		errno = ENODATA;
623f971a346SBryan Cantrill 		return (-1);
624f971a346SBryan Cantrill 	}
625f971a346SBryan Cantrill 
626f971a346SBryan Cantrill 	if (getlwpstatus(P, lwpid, &lps) != 0)
627f971a346SBryan Cantrill 		return (-1);
628f971a346SBryan Cantrill 
629f971a346SBryan Cantrill 	if (!(lps.pr_flags & PR_AGENT)) {
630f971a346SBryan Cantrill 		errno = EINVAL;
631f971a346SBryan Cantrill 		return (-1);
632f971a346SBryan Cantrill 	}
633f971a346SBryan Cantrill 
634f971a346SBryan Cantrill 	if (P->state != PS_DEAD) {
635f971a346SBryan Cantrill 		return (getlwpfile(P, lwpid, "spymaster",
636f971a346SBryan Cantrill 		    ps, sizeof (psinfo_t)));
637f971a346SBryan Cantrill 	}
638f971a346SBryan Cantrill 
639f971a346SBryan Cantrill 	if (P->spymaster.pr_nlwp != 0) {
640f971a346SBryan Cantrill 		(void) memcpy(ps, &P->spymaster, sizeof (psinfo_t));
641f971a346SBryan Cantrill 		return (0);
642f971a346SBryan Cantrill 	}
643f971a346SBryan Cantrill 
644f971a346SBryan Cantrill 	errno = ENODATA;
645f971a346SBryan Cantrill 
646f971a346SBryan Cantrill 	return (-1);
647f971a346SBryan Cantrill }
648f971a346SBryan Cantrill 
6497c478bd9Sstevel@tonic-gate int
Plwp_stack(struct ps_prochandle * P,lwpid_t lwpid,stack_t * stkp)6507c478bd9Sstevel@tonic-gate Plwp_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp)
6517c478bd9Sstevel@tonic-gate {
6527c478bd9Sstevel@tonic-gate 	uintptr_t addr;
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
6557c478bd9Sstevel@tonic-gate 		errno = ENODATA;
6567c478bd9Sstevel@tonic-gate 		return (-1);
6577c478bd9Sstevel@tonic-gate 	}
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 	if (P->state != PS_DEAD) {
6607c478bd9Sstevel@tonic-gate 		lwpstatus_t ls;
6617c478bd9Sstevel@tonic-gate 		if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0)
6627c478bd9Sstevel@tonic-gate 			return (-1);
6637c478bd9Sstevel@tonic-gate 		addr = ls.pr_ustack;
6647c478bd9Sstevel@tonic-gate 	} else {
6657c478bd9Sstevel@tonic-gate 		lwp_info_t *lwp;
6667c478bd9Sstevel@tonic-gate 		if ((lwp = getlwpcore(P, lwpid)) == NULL)
6677c478bd9Sstevel@tonic-gate 			return (-1);
6687c478bd9Sstevel@tonic-gate 		addr = lwp->lwp_status.pr_ustack;
6697c478bd9Sstevel@tonic-gate 	}
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
6737c478bd9Sstevel@tonic-gate 		if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp))
6747c478bd9Sstevel@tonic-gate 			return (-1);
6757c478bd9Sstevel@tonic-gate #ifdef _LP64
6767c478bd9Sstevel@tonic-gate 	} else {
6777c478bd9Sstevel@tonic-gate 		stack32_t stk32;
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 		if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32))
6807c478bd9Sstevel@tonic-gate 			return (-1);
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 		stack_32_to_n(&stk32, stkp);
6837c478bd9Sstevel@tonic-gate #endif
6847c478bd9Sstevel@tonic-gate 	}
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 	return (0);
6877c478bd9Sstevel@tonic-gate }
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate int
Plwp_main_stack(struct ps_prochandle * P,lwpid_t lwpid,stack_t * stkp)6907c478bd9Sstevel@tonic-gate Plwp_main_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp)
6917c478bd9Sstevel@tonic-gate {
6927c478bd9Sstevel@tonic-gate 	uintptr_t addr;
6937c478bd9Sstevel@tonic-gate 	lwpstatus_t ls;
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
6967c478bd9Sstevel@tonic-gate 		errno = ENODATA;
6977c478bd9Sstevel@tonic-gate 		return (-1);
6987c478bd9Sstevel@tonic-gate 	}
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	if (P->state != PS_DEAD) {
7017c478bd9Sstevel@tonic-gate 		if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0)
7027c478bd9Sstevel@tonic-gate 			return (-1);
7037c478bd9Sstevel@tonic-gate 	} else {
7047c478bd9Sstevel@tonic-gate 		lwp_info_t *lwp;
7057c478bd9Sstevel@tonic-gate 		if ((lwp = getlwpcore(P, lwpid)) == NULL)
7067c478bd9Sstevel@tonic-gate 			return (-1);
7077c478bd9Sstevel@tonic-gate 		ls = lwp->lwp_status;
7087c478bd9Sstevel@tonic-gate 	}
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	addr = ls.pr_ustack;
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 	/*
7137c478bd9Sstevel@tonic-gate 	 * Read out the current stack; if the SS_ONSTACK flag is set then
7147c478bd9Sstevel@tonic-gate 	 * this LWP is operating on the alternate signal stack. We can
7157c478bd9Sstevel@tonic-gate 	 * recover the original stack from pr_oldcontext.
7167c478bd9Sstevel@tonic-gate 	 */
7177c478bd9Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
7187c478bd9Sstevel@tonic-gate 		if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp))
7197c478bd9Sstevel@tonic-gate 			return (-1);
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 		if (stkp->ss_flags & SS_ONSTACK)
7227c478bd9Sstevel@tonic-gate 			goto on_altstack;
7237c478bd9Sstevel@tonic-gate #ifdef _LP64
7247c478bd9Sstevel@tonic-gate 	} else {
7257c478bd9Sstevel@tonic-gate 		stack32_t stk32;
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 		if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32))
7287c478bd9Sstevel@tonic-gate 			return (-1);
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 		if (stk32.ss_flags & SS_ONSTACK)
7317c478bd9Sstevel@tonic-gate 			goto on_altstack;
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 		stack_32_to_n(&stk32, stkp);
7347c478bd9Sstevel@tonic-gate #endif
7357c478bd9Sstevel@tonic-gate 	}
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	return (0);
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate on_altstack:
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
7427c478bd9Sstevel@tonic-gate 		ucontext_t *ctxp = (void *)ls.pr_oldcontext;
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 		if (Pread(P, stkp, sizeof (*stkp),
7457c478bd9Sstevel@tonic-gate 		    (uintptr_t)&ctxp->uc_stack) != sizeof (*stkp))
7467c478bd9Sstevel@tonic-gate 			return (-1);
7477c478bd9Sstevel@tonic-gate #ifdef _LP64
7487c478bd9Sstevel@tonic-gate 	} else {
7497c478bd9Sstevel@tonic-gate 		ucontext32_t *ctxp = (void *)ls.pr_oldcontext;
7507c478bd9Sstevel@tonic-gate 		stack32_t stk32;
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 		if (Pread(P, &stk32, sizeof (stk32),
7537c478bd9Sstevel@tonic-gate 		    (uintptr_t)&ctxp->uc_stack) != sizeof (stk32))
7547c478bd9Sstevel@tonic-gate 			return (-1);
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 		stack_32_to_n(&stk32, stkp);
7577c478bd9Sstevel@tonic-gate #endif
7587c478bd9Sstevel@tonic-gate 	}
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 	return (0);
7617c478bd9Sstevel@tonic-gate }
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate int
Plwp_alt_stack(struct ps_prochandle * P,lwpid_t lwpid,stack_t * stkp)7647c478bd9Sstevel@tonic-gate Plwp_alt_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp)
7657c478bd9Sstevel@tonic-gate {
7667c478bd9Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
7677c478bd9Sstevel@tonic-gate 		errno = ENODATA;
7687c478bd9Sstevel@tonic-gate 		return (-1);
7697c478bd9Sstevel@tonic-gate 	}
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	if (P->state != PS_DEAD) {
7727c478bd9Sstevel@tonic-gate 		lwpstatus_t ls;
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 		if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0)
7757c478bd9Sstevel@tonic-gate 			return (-1);
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 		if (ls.pr_altstack.ss_flags & SS_DISABLE) {
7787c478bd9Sstevel@tonic-gate 			errno = ENODATA;
7797c478bd9Sstevel@tonic-gate 			return (-1);
7807c478bd9Sstevel@tonic-gate 		}
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 		*stkp = ls.pr_altstack;
7837c478bd9Sstevel@tonic-gate 	} else {
7847c478bd9Sstevel@tonic-gate 		lwp_info_t *lwp;
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 		if ((lwp = getlwpcore(P, lwpid)) == NULL)
7877c478bd9Sstevel@tonic-gate 			return (-1);
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 		if (lwp->lwp_status.pr_altstack.ss_flags & SS_DISABLE) {
7907c478bd9Sstevel@tonic-gate 			errno = ENODATA;
7917c478bd9Sstevel@tonic-gate 			return (-1);
7927c478bd9Sstevel@tonic-gate 		}
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 		*stkp = lwp->lwp_status.pr_altstack;
7957c478bd9Sstevel@tonic-gate 	}
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	return (0);
7987c478bd9Sstevel@tonic-gate }
799