xref: /illumos-gate/usr/src/lib/libproc/common/Plwpregs.c (revision ed093b41a93e8563e6e1e5dae0768dda2a7bcc27)
1  /*
2   * CDDL HEADER START
3   *
4   * The contents of this file are subject to the terms of the
5   * Common Development and Distribution License (the "License").
6   * You may not use this file except in compliance with the License.
7   *
8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
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 *
getlwpcore(struct ps_prochandle * P,lwpid_t lwpid)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
getlwpfile(struct ps_prochandle * P,lwpid_t lwpid,const char * fbase,void * rp,size_t n)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
getlwpfile_alloc(struct ps_prochandle * P,lwpid_t lwpid,const char * fbase,void ** datap,size_t * sizep)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
getlwpstatus(struct ps_prochandle * P,lwpid_t lwpid,lwpstatus_t * lps)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
refresh_status(struct ps_prochandle * P,lwpid_t lwpid,struct ps_lwphandle * L,long cmd,const void * rp,size_t n)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
setlwpregs_proc(struct ps_prochandle * P,lwpid_t lwpid,long cmd,const void * rp,size_t n)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 cover the base integer or floating point
269  	 * registers.  As a result, always refresh the representative LWP's
270  	 * status.
271  	 */
272  	if (P->status.pr_lwp.pr_lwpid == lwpid) {
273  		Psync(P);
274  		fd = P->ctlfd;
275  	}
276  
277  	if (fd > -1) {
278  		if (writev(fd, iov, 2) == -1)
279  			return (-1);
280  		refresh_status(P, lwpid, L, cmd, rp, n);
281  		return (0);
282  	}
283  
284  	/*
285  	 * If the lwp we want is not the representative lwp, we need to
286  	 * open the ctl file for that specific lwp.
287  	 */
288  	(void) snprintf(fname, sizeof (fname), "%s/%d/lwp/%d/lwpctl",
289  	    procfs_path, (int)P->status.pr_pid, (int)lwpid);
290  
291  	if ((fd = open(fname, O_WRONLY)) >= 0) {
292  		if (writev(fd, iov, 2) > 0) {
293  			(void) close(fd);
294  			return (0);
295  		}
296  		int e = errno;
297  		(void) close(fd);
298  		errno = e;
299  	}
300  	return (-1);
301  }
302  
303  /*
304   * This is a variant of the above that only assumes we have a hold on the thread
305   * as opposed to a process.
306   */
307  static int
setlwpregs_lwp(struct ps_lwphandle * L,long cmd,const void * rp,size_t n)308  setlwpregs_lwp(struct ps_lwphandle *L, long cmd, const void *rp, size_t n)
309  {
310  	iovec_t iov[2];
311  
312  	if (L->lwp_state != PS_STOP) {
313  		errno = EBUSY;
314  		return (-1);
315  	}
316  
317  	iov[0].iov_base = (caddr_t)&cmd;
318  	iov[0].iov_len = sizeof (long);
319  	iov[1].iov_base = (caddr_t)rp;
320  	iov[1].iov_len = n;
321  
322  	Lsync(L);
323  	if (writev(L->lwp_ctlfd, iov, 2) == -1)
324  		return (-1);
325  	refresh_status(L->lwp_proc, L->lwp_id, L, cmd, rp, n);
326  
327  	return (0);
328  }
329  
330  int
Plwp_getregs(struct ps_prochandle * P,lwpid_t lwpid,prgregset_t gregs)331  Plwp_getregs(struct ps_prochandle *P, lwpid_t lwpid, prgregset_t gregs)
332  {
333  	lwpstatus_t lps;
334  
335  	if (getlwpstatus(P, lwpid, &lps) == -1)
336  		return (-1);
337  
338  	(void) memcpy(gregs, lps.pr_reg, sizeof (prgregset_t));
339  	return (0);
340  }
341  
342  int
Lgetregs(struct ps_lwphandle * L,prgregset_t * gregs)343  Lgetregs(struct ps_lwphandle *L, prgregset_t *gregs)
344  {
345  	(void) memcpy(gregs, L->lwp_status.pr_reg, sizeof (prgregset_t));
346  	return (0);
347  }
348  
349  int
Plwp_setregs(struct ps_prochandle * P,lwpid_t lwpid,const prgregset_t gregs)350  Plwp_setregs(struct ps_prochandle *P, lwpid_t lwpid, const prgregset_t gregs)
351  {
352  	return (setlwpregs_proc(P, lwpid, PCSREG, gregs, sizeof (prgregset_t)));
353  }
354  
355  int
Lsetregs(struct ps_lwphandle * L,const prgregset_t * gregs)356  Lsetregs(struct ps_lwphandle *L, const prgregset_t *gregs)
357  {
358  	return (setlwpregs_lwp(L, PCSREG, gregs, sizeof (prgregset_t)));
359  }
360  
361  int
Plwp_getfpregs(struct ps_prochandle * P,lwpid_t lwpid,prfpregset_t * fpregs)362  Plwp_getfpregs(struct ps_prochandle *P, lwpid_t lwpid, prfpregset_t *fpregs)
363  {
364  	lwpstatus_t lps;
365  
366  	if (getlwpstatus(P, lwpid, &lps) == -1)
367  		return (-1);
368  
369  	(void) memcpy(fpregs, &lps.pr_fpreg, sizeof (prfpregset_t));
370  	return (0);
371  }
372  
373  int
Lgetfpregs(struct ps_lwphandle * L,prfpregset_t * fpregs)374  Lgetfpregs(struct ps_lwphandle *L, prfpregset_t *fpregs)
375  {
376  	(void) memcpy(fpregs, &L->lwp_status.pr_fpreg, sizeof (prfpregset_t));
377  	return (0);
378  }
379  
380  int
Plwp_setfpregs(struct ps_prochandle * P,lwpid_t lwpid,const prfpregset_t * fpregs)381  Plwp_setfpregs(struct ps_prochandle *P, lwpid_t lwpid,
382      const prfpregset_t *fpregs)
383  {
384  	return (setlwpregs_proc(P, lwpid, PCSFPREG, fpregs,
385  	    sizeof (prfpregset_t)));
386  }
387  
388  int
Lsetfpregs(struct ps_lwphandle * L,const prfpregset_t * fpregs)389  Lsetfpregs(struct ps_lwphandle *L, const prfpregset_t *fpregs)
390  {
391  	return (setlwpregs_lwp(L, PCSFPREG, fpregs, sizeof (prfpregset_t)));
392  }
393  
394  /*
395   * The reason that this is structured to take both the size and the process
396   * handle is so that way we have enough information to tie this back to its
397   * underlying source and we can eventually use umem with this.
398   */
399  void
Plwp_freexregs(struct ps_prochandle * P __unused,prxregset_t * prx,size_t size __unused)400  Plwp_freexregs(struct ps_prochandle *P __unused, prxregset_t *prx,
401      size_t size __unused)
402  {
403  	free(prx);
404  }
405  
406  /*
407   * Get a given thread's lwp registers. If this is a core file, we read it from
408   * the cache. If this is a live process, we always read it from the underlying
409   * file system because we do not currently cache xregs in libproc. sizep is the
410   * resulting size of data we've allocated and for a live process is filled in
411   * based on the /proc stat(2) information.
412   */
413  int
Plwp_getxregs(struct ps_prochandle * P,lwpid_t lwpid,prxregset_t ** xregs,size_t * sizep)414  Plwp_getxregs(struct ps_prochandle *P, lwpid_t lwpid, prxregset_t **xregs,
415      size_t *sizep)
416  {
417  	lwp_info_t *lwp;
418  
419  	if (P->state == PS_IDLE) {
420  		errno = ENODATA;
421  		return (-1);
422  	}
423  
424  	if (P->state != PS_DEAD) {
425  		if (P->state != PS_STOP) {
426  			errno = EBUSY;
427  			return (-1);
428  		}
429  
430  		return (getlwpfile_alloc(P, lwpid, "xregs",
431  		    (void **)xregs, sizep));
432  	}
433  
434  	if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_xregs != NULL &&
435  	    lwp->lwp_xregsize > 0) {
436  		*xregs = malloc(lwp->lwp_xregsize);
437  		if (*xregs == NULL)
438  			return (-1);
439  		(void) memcpy(*xregs, lwp->lwp_xregs, lwp->lwp_xregsize);
440  		*sizep = lwp->lwp_xregsize;
441  		return (0);
442  	}
443  
444  	if (lwp != NULL)
445  		errno = ENODATA;
446  	return (-1);
447  }
448  
449  int
Lgetxregs(struct ps_lwphandle * L,prxregset_t ** xregs,size_t * sizep)450  Lgetxregs(struct ps_lwphandle *L, prxregset_t **xregs, size_t *sizep)
451  {
452  	lwp_info_t *lwp;
453  
454  	if (L->lwp_state != PS_DEAD) {
455  		if (L->lwp_state != PS_STOP) {
456  			errno = EBUSY;
457  			return (-1);
458  		}
459  		return (getlwpfile_alloc(L->lwp_proc, L->lwp_id, "xregs",
460  		    (void **)xregs, sizep));
461  	}
462  
463  	if ((lwp = getlwpcore(L->lwp_proc, L->lwp_id)) != NULL &&
464  	    lwp->lwp_xregs != NULL && lwp->lwp_xregsize > 0) {
465  		*xregs = malloc(lwp->lwp_xregsize);
466  		if (*xregs == NULL)
467  			return (-1);
468  		(void) memcpy(*xregs, lwp->lwp_xregs, lwp->lwp_xregsize);
469  		*sizep = lwp->lwp_xregsize;
470  		return (0);
471  	}
472  
473  	if (lwp != NULL)
474  		errno = ENODATA;
475  	return (-1);
476  }
477  
478  int
Plwp_setxregs(struct ps_prochandle * P,lwpid_t lwpid,const prxregset_t * xregs,size_t len)479  Plwp_setxregs(struct ps_prochandle *P, lwpid_t lwpid, const prxregset_t *xregs,
480      size_t len)
481  {
482  	return (setlwpregs_proc(P, lwpid, PCSXREG, xregs, len));
483  }
484  
485  int
Lsetxregs(struct ps_lwphandle * L,const prxregset_t * xregs,size_t len)486  Lsetxregs(struct ps_lwphandle *L, const prxregset_t *xregs, size_t len)
487  {
488  	return (setlwpregs_lwp(L, PCSXREG, xregs, len));
489  }
490  
491  #if defined(sparc) || defined(__sparc)
492  int
Plwp_getgwindows(struct ps_prochandle * P,lwpid_t lwpid,gwindows_t * gwins)493  Plwp_getgwindows(struct ps_prochandle *P, lwpid_t lwpid, gwindows_t *gwins)
494  {
495  	lwp_info_t *lwp;
496  
497  	if (P->state == PS_IDLE) {
498  		errno = ENODATA;
499  		return (-1);
500  	}
501  
502  	if (P->state != PS_DEAD) {
503  		if (P->state != PS_STOP) {
504  			errno = EBUSY;
505  			return (-1);
506  		}
507  
508  		return (getlwpfile(P, lwpid, "gwindows",
509  		    gwins, sizeof (gwindows_t)));
510  	}
511  
512  	if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_gwins != NULL) {
513  		*gwins = *lwp->lwp_gwins;
514  		return (0);
515  	}
516  
517  	if (lwp != NULL)
518  		errno = ENODATA;
519  	return (-1);
520  }
521  
522  #if defined(__sparcv9)
523  int
Plwp_getasrs(struct ps_prochandle * P,lwpid_t lwpid,asrset_t asrs)524  Plwp_getasrs(struct ps_prochandle *P, lwpid_t lwpid, asrset_t asrs)
525  {
526  	lwp_info_t *lwp;
527  
528  	if (P->state == PS_IDLE) {
529  		errno = ENODATA;
530  		return (-1);
531  	}
532  
533  	if (P->state != PS_DEAD) {
534  		if (P->state != PS_STOP) {
535  			errno = EBUSY;
536  			return (-1);
537  		}
538  
539  		return (getlwpfile(P, lwpid, "asrs", asrs, sizeof (asrset_t)));
540  	}
541  
542  	if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_asrs != NULL) {
543  		(void) memcpy(asrs, lwp->lwp_asrs, sizeof (asrset_t));
544  		return (0);
545  	}
546  
547  	if (lwp != NULL)
548  		errno = ENODATA;
549  	return (-1);
550  
551  }
552  
553  int
Plwp_setasrs(struct ps_prochandle * P,lwpid_t lwpid,const asrset_t asrs)554  Plwp_setasrs(struct ps_prochandle *P, lwpid_t lwpid, const asrset_t asrs)
555  {
556  	return (setlwpregs_proc(P, lwpid, PCSASRS, asrs, sizeof (asrset_t)));
557  }
558  #endif	/* __sparcv9 */
559  #endif	/* __sparc */
560  
561  int
Plwp_getpsinfo(struct ps_prochandle * P,lwpid_t lwpid,lwpsinfo_t * lps)562  Plwp_getpsinfo(struct ps_prochandle *P, lwpid_t lwpid, lwpsinfo_t *lps)
563  {
564  	lwp_info_t *lwp;
565  
566  	if (P->state == PS_IDLE) {
567  		errno = ENODATA;
568  		return (-1);
569  	}
570  
571  	if (P->state != PS_DEAD) {
572  		return (getlwpfile(P, lwpid, "lwpsinfo",
573  		    lps, sizeof (lwpsinfo_t)));
574  	}
575  
576  	if ((lwp = getlwpcore(P, lwpid)) != NULL) {
577  		(void) memcpy(lps, &lwp->lwp_psinfo, sizeof (lwpsinfo_t));
578  		return (0);
579  	}
580  
581  	return (-1);
582  }
583  
584  int
Plwp_getname(struct ps_prochandle * P,lwpid_t lwpid,char * buf,size_t bufsize)585  Plwp_getname(struct ps_prochandle *P, lwpid_t lwpid,
586      char *buf, size_t bufsize)
587  {
588  	char lwpname[THREAD_NAME_MAX];
589  	char *from = NULL;
590  	lwp_info_t *lwp;
591  
592  	if (P->state == PS_IDLE) {
593  		errno = ENODATA;
594  		return (-1);
595  	}
596  
597  	if (P->state != PS_DEAD) {
598  		if (getlwpfile(P, lwpid, "lwpname",
599  		    lwpname, sizeof (lwpname)) != 0)
600  			return (-1);
601  		from = lwpname;
602  	} else {
603  		if ((lwp = getlwpcore(P, lwpid)) == NULL)
604  			return (-1);
605  		from = lwp->lwp_name;
606  	}
607  
608  	if (strlcpy(buf, from, bufsize) >= bufsize) {
609  		errno = ENAMETOOLONG;
610  		return (-1);
611  	}
612  
613  	return (0);
614  }
615  
616  int
Plwp_getspymaster(struct ps_prochandle * P,lwpid_t lwpid,psinfo_t * ps)617  Plwp_getspymaster(struct ps_prochandle *P, lwpid_t lwpid, psinfo_t *ps)
618  {
619  	lwpstatus_t lps;
620  
621  	if (P->state == PS_IDLE) {
622  		errno = ENODATA;
623  		return (-1);
624  	}
625  
626  	if (getlwpstatus(P, lwpid, &lps) != 0)
627  		return (-1);
628  
629  	if (!(lps.pr_flags & PR_AGENT)) {
630  		errno = EINVAL;
631  		return (-1);
632  	}
633  
634  	if (P->state != PS_DEAD) {
635  		return (getlwpfile(P, lwpid, "spymaster",
636  		    ps, sizeof (psinfo_t)));
637  	}
638  
639  	if (P->spymaster.pr_nlwp != 0) {
640  		(void) memcpy(ps, &P->spymaster, sizeof (psinfo_t));
641  		return (0);
642  	}
643  
644  	errno = ENODATA;
645  
646  	return (-1);
647  }
648  
649  int
Plwp_stack(struct ps_prochandle * P,lwpid_t lwpid,stack_t * stkp)650  Plwp_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp)
651  {
652  	uintptr_t addr;
653  
654  	if (P->state == PS_IDLE) {
655  		errno = ENODATA;
656  		return (-1);
657  	}
658  
659  	if (P->state != PS_DEAD) {
660  		lwpstatus_t ls;
661  		if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0)
662  			return (-1);
663  		addr = ls.pr_ustack;
664  	} else {
665  		lwp_info_t *lwp;
666  		if ((lwp = getlwpcore(P, lwpid)) == NULL)
667  			return (-1);
668  		addr = lwp->lwp_status.pr_ustack;
669  	}
670  
671  
672  	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
673  		if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp))
674  			return (-1);
675  #ifdef _LP64
676  	} else {
677  		stack32_t stk32;
678  
679  		if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32))
680  			return (-1);
681  
682  		stack_32_to_n(&stk32, stkp);
683  #endif
684  	}
685  
686  	return (0);
687  }
688  
689  int
Plwp_main_stack(struct ps_prochandle * P,lwpid_t lwpid,stack_t * stkp)690  Plwp_main_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp)
691  {
692  	uintptr_t addr;
693  	lwpstatus_t ls;
694  
695  	if (P->state == PS_IDLE) {
696  		errno = ENODATA;
697  		return (-1);
698  	}
699  
700  	if (P->state != PS_DEAD) {
701  		if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0)
702  			return (-1);
703  	} else {
704  		lwp_info_t *lwp;
705  		if ((lwp = getlwpcore(P, lwpid)) == NULL)
706  			return (-1);
707  		ls = lwp->lwp_status;
708  	}
709  
710  	addr = ls.pr_ustack;
711  
712  	/*
713  	 * Read out the current stack; if the SS_ONSTACK flag is set then
714  	 * this LWP is operating on the alternate signal stack. We can
715  	 * recover the original stack from pr_oldcontext.
716  	 */
717  	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
718  		if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp))
719  			return (-1);
720  
721  		if (stkp->ss_flags & SS_ONSTACK)
722  			goto on_altstack;
723  #ifdef _LP64
724  	} else {
725  		stack32_t stk32;
726  
727  		if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32))
728  			return (-1);
729  
730  		if (stk32.ss_flags & SS_ONSTACK)
731  			goto on_altstack;
732  
733  		stack_32_to_n(&stk32, stkp);
734  #endif
735  	}
736  
737  	return (0);
738  
739  on_altstack:
740  
741  	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
742  		ucontext_t *ctxp = (void *)ls.pr_oldcontext;
743  
744  		if (Pread(P, stkp, sizeof (*stkp),
745  		    (uintptr_t)&ctxp->uc_stack) != sizeof (*stkp))
746  			return (-1);
747  #ifdef _LP64
748  	} else {
749  		ucontext32_t *ctxp = (void *)ls.pr_oldcontext;
750  		stack32_t stk32;
751  
752  		if (Pread(P, &stk32, sizeof (stk32),
753  		    (uintptr_t)&ctxp->uc_stack) != sizeof (stk32))
754  			return (-1);
755  
756  		stack_32_to_n(&stk32, stkp);
757  #endif
758  	}
759  
760  	return (0);
761  }
762  
763  int
Plwp_alt_stack(struct ps_prochandle * P,lwpid_t lwpid,stack_t * stkp)764  Plwp_alt_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp)
765  {
766  	if (P->state == PS_IDLE) {
767  		errno = ENODATA;
768  		return (-1);
769  	}
770  
771  	if (P->state != PS_DEAD) {
772  		lwpstatus_t ls;
773  
774  		if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0)
775  			return (-1);
776  
777  		if (ls.pr_altstack.ss_flags & SS_DISABLE) {
778  			errno = ENODATA;
779  			return (-1);
780  		}
781  
782  		*stkp = ls.pr_altstack;
783  	} else {
784  		lwp_info_t *lwp;
785  
786  		if ((lwp = getlwpcore(P, lwpid)) == NULL)
787  			return (-1);
788  
789  		if (lwp->lwp_status.pr_altstack.ss_flags & SS_DISABLE) {
790  			errno = ENODATA;
791  			return (-1);
792  		}
793  
794  		*stkp = lwp->lwp_status.pr_altstack;
795  	}
796  
797  	return (0);
798  }
799