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