xref: /illumos-gate/usr/src/lib/libproc/common/Plwpregs.c (revision 9164a50bf932130cbb5097a16f6986873ce0e6e5)
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 *
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 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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