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 /*
  23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  *
  26  * Portions Copyright 2007 Chad Mynhier
  27  * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
  28  * Copyright (c) 2013 by Delphix. All rights reserved.
  29  * Copyright 2015, Joyent, Inc.
  30  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  31  * Copyright 2021 Oxide Computer Company
  32  */
  33 
  34 #include <assert.h>
  35 #include <stdio.h>
  36 #include <stdlib.h>
  37 #include <unistd.h>
  38 #include <ctype.h>
  39 #include <fcntl.h>
  40 #include <string.h>
  41 #include <strings.h>
  42 #include <memory.h>
  43 #include <errno.h>
  44 #include <dirent.h>
  45 #include <limits.h>
  46 #include <signal.h>
  47 #include <atomic.h>
  48 #include <zone.h>
  49 #include <sys/types.h>
  50 #include <sys/uio.h>
  51 #include <sys/stat.h>
 
 
3138                 return (core->core_content);
3139         if (P->state == PS_IDLE)
3140                 return (CC_CONTENT_TEXT | CC_CONTENT_DATA | CC_CONTENT_CTF);
3141 
3142         return (CC_CONTENT_ALL);
3143 }
3144 
3145 /*
3146  * =================================================================
3147  * The remainder of the functions in this file are for the
3148  * control of individual LWPs in the controlled process.
3149  * =================================================================
3150  */
3151 
3152 /*
3153  * Find an entry in the process hash table for the specified lwpid.
3154  * The entry will either point to an existing struct ps_lwphandle
3155  * or it will point to an empty slot for a new struct ps_lwphandle.
3156  */
3157 static struct ps_lwphandle **
3158 Lfind(struct ps_prochandle *P, lwpid_t lwpid)
3159 {
3160         struct ps_lwphandle **Lp;
3161         struct ps_lwphandle *L;
3162 
3163         for (Lp = &P->hashtab[lwpid % (HASHSIZE - 1)];
3164             (L = *Lp) != NULL; Lp = &L->lwp_hash)
3165                 if (L->lwp_id == lwpid)
3166                         break;
3167         return (Lp);
3168 }
3169 
3170 /*
3171  * Grab an LWP contained within the controlled process.
3172  * Return an opaque pointer to its LWP control structure.
3173  *      perr: pointer to error return code.
3174  */
3175 struct ps_lwphandle *
3176 Lgrab(struct ps_prochandle *P, lwpid_t lwpid, int *perr)
3177 {
3178         struct ps_lwphandle **Lp;
3179         struct ps_lwphandle *L;
3180         int fd;
3181         char procname[PATH_MAX];
3182         char *fname;
3183         int rc = 0;
3184 
3185         (void) mutex_lock(&P->proc_lock);
3186 
3187         if (P->state == PS_UNDEAD || P->state == PS_IDLE)
3188                 rc = G_NOPROC;
3189         else if (P->hashtab == NULL &&
3190             (P->hashtab = calloc(HASHSIZE, sizeof (struct ps_lwphandle *)))
3191             == NULL)
3192                 rc = G_STRANGE;
3193         else if (*(Lp = Lfind(P, lwpid)) != NULL)
3194                 rc = G_BUSY;
3195         else if ((L = malloc(sizeof (struct ps_lwphandle))) == NULL)
3196                 rc = G_STRANGE;
3197         if (rc) {
3198                 *perr = rc;
3199                 (void) mutex_unlock(&P->proc_lock);
3200                 return (NULL);
3201         }
3202 
3203         (void) memset(L, 0, sizeof (*L));
3204         L->lwp_ctlfd = -1;
3205         L->lwp_statfd = -1;
3206         L->lwp_proc = P;
3207         L->lwp_id = lwpid;
3208         *Lp = L;        /* insert into the hash table */
3209 
3210         if (P->state == PS_DEAD) {   /* core file */
3211                 if (getlwpstatus(P, lwpid, &L->lwp_status) == -1) {
3212                         rc = G_NOPROC;
3213                         goto err;
 
3315 
3316         return (str);
3317 }
3318 
3319 /*
3320  * Free an LWP control structure.
3321  */
3322 void
3323 Lfree(struct ps_lwphandle *L)
3324 {
3325         struct ps_prochandle *P = L->lwp_proc;
3326 
3327         (void) mutex_lock(&P->proc_lock);
3328         Lfree_internal(P, L);
3329         (void) mutex_unlock(&P->proc_lock);
3330 }
3331 
3332 static void
3333 Lfree_internal(struct ps_prochandle *P, struct ps_lwphandle *L)
3334 {
3335         *Lfind(P, L->lwp_id) = L->lwp_hash;       /* delete from hash table */
3336         if (L->lwp_ctlfd >= 0)
3337                 (void) close(L->lwp_ctlfd);
3338         if (L->lwp_statfd >= 0)
3339                 (void) close(L->lwp_statfd);
3340 
3341         /* clear out the structure as a precaution against reuse */
3342         (void) memset(L, 0, sizeof (*L));
3343         L->lwp_ctlfd = -1;
3344         L->lwp_statfd = -1;
3345 
3346         free(L);
3347 }
3348 
3349 /*
3350  * Return the state of the process, one of the PS_* values.
3351  */
3352 int
3353 Lstate(struct ps_lwphandle *L)
3354 {
3355         return (L->lwp_state);
 
3421         }
3422         if (L->lwp_flags & SETREGS) {
3423                 cmd[1] = PCSREG;
3424                 iov[n].iov_base = (caddr_t)&cmd[1];
3425                 iov[n++].iov_len = sizeof (long);
3426                 iov[n].iov_base = (caddr_t)&L->lwp_status.pr_reg[0];
3427                 iov[n++].iov_len = sizeof (L->lwp_status.pr_reg);
3428         }
3429 
3430         if (n == 0 || writev(ctlfd, iov, n) < 0)
3431                 return;         /* nothing to do or write failed */
3432 
3433         L->lwp_flags &= ~(SETHOLD|SETREGS);
3434 }
3435 
3436 /*
3437  * Wait for the specified LWP to stop or terminate.
3438  * Or, just get the current status (PCNULL).
3439  * Or, direct it to stop and get the current status (PCDSTOP).
3440  */
3441 static int
3442 Lstopstatus(struct ps_lwphandle *L,
3443     long request,               /* PCNULL, PCDSTOP, PCSTOP, PCWSTOP */
3444     uint_t msec)                /* if non-zero, timeout in milliseconds */
3445 {
3446         int ctlfd = L->lwp_ctlfd;
3447         long ctl[3];
3448         ssize_t rc;
3449         int err;
3450 
3451         switch (L->lwp_state) {
3452         case PS_RUN:
3453                 break;
3454         case PS_STOP:
3455                 if (request != PCNULL && request != PCDSTOP)
3456                         return (0);
3457                 break;
3458         case PS_LOST:
3459                 if (request != PCNULL) {
3460                         errno = EAGAIN;
3461                         return (-1);
 
 | 
 
 
  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 /*
  23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  *
  26  * Portions Copyright 2007 Chad Mynhier
  27  * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
  28  * Copyright (c) 2013 by Delphix. All rights reserved.
  29  * Copyright 2015, Joyent, Inc.
  30  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  31  * Copyright 2023 Oxide Computer Company
  32  */
  33 
  34 #include <assert.h>
  35 #include <stdio.h>
  36 #include <stdlib.h>
  37 #include <unistd.h>
  38 #include <ctype.h>
  39 #include <fcntl.h>
  40 #include <string.h>
  41 #include <strings.h>
  42 #include <memory.h>
  43 #include <errno.h>
  44 #include <dirent.h>
  45 #include <limits.h>
  46 #include <signal.h>
  47 #include <atomic.h>
  48 #include <zone.h>
  49 #include <sys/types.h>
  50 #include <sys/uio.h>
  51 #include <sys/stat.h>
 
 
3138                 return (core->core_content);
3139         if (P->state == PS_IDLE)
3140                 return (CC_CONTENT_TEXT | CC_CONTENT_DATA | CC_CONTENT_CTF);
3141 
3142         return (CC_CONTENT_ALL);
3143 }
3144 
3145 /*
3146  * =================================================================
3147  * The remainder of the functions in this file are for the
3148  * control of individual LWPs in the controlled process.
3149  * =================================================================
3150  */
3151 
3152 /*
3153  * Find an entry in the process hash table for the specified lwpid.
3154  * The entry will either point to an existing struct ps_lwphandle
3155  * or it will point to an empty slot for a new struct ps_lwphandle.
3156  */
3157 static struct ps_lwphandle **
3158 Lfind_slot(struct ps_prochandle *P, lwpid_t lwpid)
3159 {
3160         struct ps_lwphandle **Lp;
3161         struct ps_lwphandle *L;
3162 
3163         for (Lp = &P->hashtab[lwpid % (HASHSIZE - 1)];
3164             (L = *Lp) != NULL; Lp = &L->lwp_hash)
3165                 if (L->lwp_id == lwpid)
3166                         break;
3167         return (Lp);
3168 }
3169 
3170 /*
3171  * A wrapper around Lfind_slot() that is suitable for the rest of the internal
3172  * consumers who don't care about a slot, merely existence.
3173  */
3174 struct ps_lwphandle *
3175 Lfind(struct ps_prochandle *P, lwpid_t lwpid)
3176 {
3177         if (P->hashtab == NULL) {
3178                 return (NULL);
3179         }
3180 
3181         return (*Lfind_slot(P, lwpid));
3182 }
3183 
3184 /*
3185  * Grab an LWP contained within the controlled process.
3186  * Return an opaque pointer to its LWP control structure.
3187  *      perr: pointer to error return code.
3188  */
3189 struct ps_lwphandle *
3190 Lgrab(struct ps_prochandle *P, lwpid_t lwpid, int *perr)
3191 {
3192         struct ps_lwphandle **Lp;
3193         struct ps_lwphandle *L;
3194         int fd;
3195         char procname[PATH_MAX];
3196         char *fname;
3197         int rc = 0;
3198 
3199         (void) mutex_lock(&P->proc_lock);
3200 
3201         if (P->state == PS_UNDEAD || P->state == PS_IDLE)
3202                 rc = G_NOPROC;
3203         else if (P->hashtab == NULL &&
3204             (P->hashtab = calloc(HASHSIZE, sizeof (struct ps_lwphandle *)))
3205             == NULL)
3206                 rc = G_STRANGE;
3207         else if (*(Lp = Lfind_slot(P, lwpid)) != NULL)
3208                 rc = G_BUSY;
3209         else if ((L = malloc(sizeof (struct ps_lwphandle))) == NULL)
3210                 rc = G_STRANGE;
3211         if (rc) {
3212                 *perr = rc;
3213                 (void) mutex_unlock(&P->proc_lock);
3214                 return (NULL);
3215         }
3216 
3217         (void) memset(L, 0, sizeof (*L));
3218         L->lwp_ctlfd = -1;
3219         L->lwp_statfd = -1;
3220         L->lwp_proc = P;
3221         L->lwp_id = lwpid;
3222         *Lp = L;        /* insert into the hash table */
3223 
3224         if (P->state == PS_DEAD) {   /* core file */
3225                 if (getlwpstatus(P, lwpid, &L->lwp_status) == -1) {
3226                         rc = G_NOPROC;
3227                         goto err;
 
3329 
3330         return (str);
3331 }
3332 
3333 /*
3334  * Free an LWP control structure.
3335  */
3336 void
3337 Lfree(struct ps_lwphandle *L)
3338 {
3339         struct ps_prochandle *P = L->lwp_proc;
3340 
3341         (void) mutex_lock(&P->proc_lock);
3342         Lfree_internal(P, L);
3343         (void) mutex_unlock(&P->proc_lock);
3344 }
3345 
3346 static void
3347 Lfree_internal(struct ps_prochandle *P, struct ps_lwphandle *L)
3348 {
3349         *Lfind_slot(P, L->lwp_id) = L->lwp_hash; /* delete from hash table */
3350         if (L->lwp_ctlfd >= 0)
3351                 (void) close(L->lwp_ctlfd);
3352         if (L->lwp_statfd >= 0)
3353                 (void) close(L->lwp_statfd);
3354 
3355         /* clear out the structure as a precaution against reuse */
3356         (void) memset(L, 0, sizeof (*L));
3357         L->lwp_ctlfd = -1;
3358         L->lwp_statfd = -1;
3359 
3360         free(L);
3361 }
3362 
3363 /*
3364  * Return the state of the process, one of the PS_* values.
3365  */
3366 int
3367 Lstate(struct ps_lwphandle *L)
3368 {
3369         return (L->lwp_state);
 
3435         }
3436         if (L->lwp_flags & SETREGS) {
3437                 cmd[1] = PCSREG;
3438                 iov[n].iov_base = (caddr_t)&cmd[1];
3439                 iov[n++].iov_len = sizeof (long);
3440                 iov[n].iov_base = (caddr_t)&L->lwp_status.pr_reg[0];
3441                 iov[n++].iov_len = sizeof (L->lwp_status.pr_reg);
3442         }
3443 
3444         if (n == 0 || writev(ctlfd, iov, n) < 0)
3445                 return;         /* nothing to do or write failed */
3446 
3447         L->lwp_flags &= ~(SETHOLD|SETREGS);
3448 }
3449 
3450 /*
3451  * Wait for the specified LWP to stop or terminate.
3452  * Or, just get the current status (PCNULL).
3453  * Or, direct it to stop and get the current status (PCDSTOP).
3454  */
3455 int
3456 Lstopstatus(struct ps_lwphandle *L,
3457     long request,               /* PCNULL, PCDSTOP, PCSTOP, PCWSTOP */
3458     uint_t msec)                /* if non-zero, timeout in milliseconds */
3459 {
3460         int ctlfd = L->lwp_ctlfd;
3461         long ctl[3];
3462         ssize_t rc;
3463         int err;
3464 
3465         switch (L->lwp_state) {
3466         case PS_RUN:
3467                 break;
3468         case PS_STOP:
3469                 if (request != PCNULL && request != PCDSTOP)
3470                         return (0);
3471                 break;
3472         case PS_LOST:
3473                 if (request != PCNULL) {
3474                         errno = EAGAIN;
3475                         return (-1);
 
 |