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