17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
59acbbeafSnn  * Common Development and Distribution License (the "License").
69acbbeafSnn  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21e4586ebfSmws 
227c478bd9Sstevel@tonic-gate /*
238fd04b83SRoger A. Faulkner  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25cd11e192Sjhaslam  *
26cd11e192Sjhaslam  * Portions Copyright 2007 Chad Mynhier
2734bdffbfSGarrett D'Amore  * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
282a12f85aSJeremy Jones  * Copyright (c) 2013 by Delphix. All rights reserved.
2943051d27SRobert Mustacchi  * Copyright 2015, Joyent, Inc.
30a02120c4SAndy Fiddaman  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
31*ed093b41SRobert Mustacchi  * Copyright 2023 Oxide Computer Company
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
34d9452f23SEdward Pilatowicz #include <assert.h>
357c478bd9Sstevel@tonic-gate #include <stdio.h>
367c478bd9Sstevel@tonic-gate #include <stdlib.h>
377c478bd9Sstevel@tonic-gate #include <unistd.h>
387c478bd9Sstevel@tonic-gate #include <ctype.h>
397c478bd9Sstevel@tonic-gate #include <fcntl.h>
407c478bd9Sstevel@tonic-gate #include <string.h>
419acbbeafSnn #include <strings.h>
427c478bd9Sstevel@tonic-gate #include <memory.h>
437c478bd9Sstevel@tonic-gate #include <errno.h>
447c478bd9Sstevel@tonic-gate #include <dirent.h>
457c478bd9Sstevel@tonic-gate #include <limits.h>
467c478bd9Sstevel@tonic-gate #include <signal.h>
47cb620785Sraf #include <atomic.h>
482a12f85aSJeremy Jones #include <zone.h>
497c478bd9Sstevel@tonic-gate #include <sys/types.h>
507c478bd9Sstevel@tonic-gate #include <sys/uio.h>
517c478bd9Sstevel@tonic-gate #include <sys/stat.h>
527c478bd9Sstevel@tonic-gate #include <sys/resource.h>
537c478bd9Sstevel@tonic-gate #include <sys/param.h>
547c478bd9Sstevel@tonic-gate #include <sys/stack.h>
557c478bd9Sstevel@tonic-gate #include <sys/fault.h>
567c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
577c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
582a12f85aSJeremy Jones #include <sys/systeminfo.h>
59d2a70789SRichard Lowe #include <sys/secflags.h>
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #include "libproc.h"
627c478bd9Sstevel@tonic-gate #include "Pcontrol.h"
637c478bd9Sstevel@tonic-gate #include "Putil.h"
647c478bd9Sstevel@tonic-gate #include "P32ton.h"
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate int	_libproc_debug;		/* set non-zero to enable debugging printfs */
67d7755b5aSrh int	_libproc_no_qsort;	/* set non-zero to inhibit sorting */
68d7755b5aSrh 				/* of symbol tables */
69d9452f23SEdward Pilatowicz int	_libproc_incore_elf;	/* only use in-core elf data */
70d7755b5aSrh 
717c478bd9Sstevel@tonic-gate sigset_t blockable_sigs;	/* signals to block when we need to be safe */
727c478bd9Sstevel@tonic-gate static	int	minfd;	/* minimum file descriptor returned by dupfd(fd, 0) */
739acbbeafSnn char	procfs_path[PATH_MAX] = "/proc";
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate /*
767c478bd9Sstevel@tonic-gate  * Function prototypes for static routines in this module.
777c478bd9Sstevel@tonic-gate  */
787c478bd9Sstevel@tonic-gate static	void	deadcheck(struct ps_prochandle *);
797c478bd9Sstevel@tonic-gate static	void	restore_tracing_flags(struct ps_prochandle *);
807c478bd9Sstevel@tonic-gate static	void	Lfree_internal(struct ps_prochandle *, struct ps_lwphandle *);
812a12f85aSJeremy Jones static  prheader_t *read_lfile(struct ps_prochandle *, const char *);
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /*
842a12f85aSJeremy Jones  * Ops vector functions for live processes.
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate 
872a12f85aSJeremy Jones /*ARGSUSED*/
887c478bd9Sstevel@tonic-gate static ssize_t
Pread_live(struct ps_prochandle * P,void * buf,size_t n,uintptr_t addr,void * data)892a12f85aSJeremy Jones Pread_live(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr,
902a12f85aSJeremy Jones     void *data)
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate 	return (pread(P->asfd, buf, n, (off_t)addr));
937c478bd9Sstevel@tonic-gate }
947c478bd9Sstevel@tonic-gate 
952a12f85aSJeremy Jones /*ARGSUSED*/
967c478bd9Sstevel@tonic-gate static ssize_t
Pwrite_live(struct ps_prochandle * P,const void * buf,size_t n,uintptr_t addr,void * data)972a12f85aSJeremy Jones Pwrite_live(struct ps_prochandle *P, const void *buf, size_t n, uintptr_t addr,
982a12f85aSJeremy Jones     void *data)
997c478bd9Sstevel@tonic-gate {
1007c478bd9Sstevel@tonic-gate 	return (pwrite(P->asfd, buf, n, (off_t)addr));
1017c478bd9Sstevel@tonic-gate }
1027c478bd9Sstevel@tonic-gate 
1032a12f85aSJeremy Jones /*ARGSUSED*/
1042a12f85aSJeremy Jones static int
Pread_maps_live(struct ps_prochandle * P,prmap_t ** Pmapp,ssize_t * nmapp,void * data)1052a12f85aSJeremy Jones Pread_maps_live(struct ps_prochandle *P, prmap_t **Pmapp, ssize_t *nmapp,
1062a12f85aSJeremy Jones     void *data)
1072a12f85aSJeremy Jones {
1082a12f85aSJeremy Jones 	char mapfile[PATH_MAX];
1092a12f85aSJeremy Jones 	int mapfd;
1102a12f85aSJeremy Jones 	struct stat statb;
1112a12f85aSJeremy Jones 	ssize_t nmap;
1122a12f85aSJeremy Jones 	prmap_t *Pmap = NULL;
1132a12f85aSJeremy Jones 
1142a12f85aSJeremy Jones 	(void) snprintf(mapfile, sizeof (mapfile), "%s/%d/map",
1152a12f85aSJeremy Jones 	    procfs_path, (int)P->pid);
1162a12f85aSJeremy Jones 	if ((mapfd = open(mapfile, O_RDONLY)) < 0 ||
1172a12f85aSJeremy Jones 	    fstat(mapfd, &statb) != 0 ||
1182a12f85aSJeremy Jones 	    statb.st_size < sizeof (prmap_t) ||
1192a12f85aSJeremy Jones 	    (Pmap = malloc(statb.st_size)) == NULL ||
1202a12f85aSJeremy Jones 	    (nmap = pread(mapfd, Pmap, statb.st_size, 0L)) <= 0 ||
1212a12f85aSJeremy Jones 	    (nmap /= sizeof (prmap_t)) == 0) {
1222a12f85aSJeremy Jones 		if (Pmap != NULL)
1232a12f85aSJeremy Jones 			free(Pmap);
1242a12f85aSJeremy Jones 		if (mapfd >= 0)
1252a12f85aSJeremy Jones 			(void) close(mapfd);
1262a12f85aSJeremy Jones 		Preset_maps(P); /* utter failure; destroy tables */
1272a12f85aSJeremy Jones 		return (-1);
1282a12f85aSJeremy Jones 	}
1292a12f85aSJeremy Jones 	(void) close(mapfd);
1302a12f85aSJeremy Jones 
1312a12f85aSJeremy Jones 	*Pmapp = Pmap;
1322a12f85aSJeremy Jones 	*nmapp = nmap;
1332a12f85aSJeremy Jones 
1342a12f85aSJeremy Jones 	return (0);
1352a12f85aSJeremy Jones }
1362a12f85aSJeremy Jones 
1372a12f85aSJeremy Jones /*ARGSUSED*/
1382a12f85aSJeremy Jones static void
Pread_aux_live(struct ps_prochandle * P,auxv_t ** auxvp,int * nauxp,void * data)1392a12f85aSJeremy Jones Pread_aux_live(struct ps_prochandle *P, auxv_t **auxvp, int *nauxp, void *data)
1402a12f85aSJeremy Jones {
1412a12f85aSJeremy Jones 	char auxfile[64];
1422a12f85aSJeremy Jones 	int fd;
1432a12f85aSJeremy Jones 	struct stat statb;
1442a12f85aSJeremy Jones 	auxv_t *auxv;
1452a12f85aSJeremy Jones 	ssize_t naux;
1462a12f85aSJeremy Jones 
1472a12f85aSJeremy Jones 	(void) snprintf(auxfile, sizeof (auxfile), "%s/%d/auxv",
1482a12f85aSJeremy Jones 	    procfs_path, (int)P->pid);
1492a12f85aSJeremy Jones 	if ((fd = open(auxfile, O_RDONLY)) < 0) {
1502a12f85aSJeremy Jones 		dprintf("%s: failed to open %s: %s\n",
1512a12f85aSJeremy Jones 		    __func__, auxfile, strerror(errno));
1522a12f85aSJeremy Jones 		return;
1532a12f85aSJeremy Jones 	}
1542a12f85aSJeremy Jones 
1552a12f85aSJeremy Jones 	if (fstat(fd, &statb) == 0 &&
1562a12f85aSJeremy Jones 	    statb.st_size >= sizeof (auxv_t) &&
1572a12f85aSJeremy Jones 	    (auxv = malloc(statb.st_size + sizeof (auxv_t))) != NULL) {
1582a12f85aSJeremy Jones 		if ((naux = read(fd, auxv, statb.st_size)) < 0 ||
1592a12f85aSJeremy Jones 		    (naux /= sizeof (auxv_t)) < 1) {
1602a12f85aSJeremy Jones 			dprintf("%s: read failed: %s\n",
1612a12f85aSJeremy Jones 			    __func__, strerror(errno));
1622a12f85aSJeremy Jones 			free(auxv);
1632a12f85aSJeremy Jones 		} else {
1642a12f85aSJeremy Jones 			auxv[naux].a_type = AT_NULL;
1652a12f85aSJeremy Jones 			auxv[naux].a_un.a_val = 0L;
1662a12f85aSJeremy Jones 
1672a12f85aSJeremy Jones 			*auxvp = auxv;
1682a12f85aSJeremy Jones 			*nauxp = (int)naux;
1692a12f85aSJeremy Jones 		}
1702a12f85aSJeremy Jones 	}
1712a12f85aSJeremy Jones 
1722a12f85aSJeremy Jones 	(void) close(fd);
1732a12f85aSJeremy Jones }
1742a12f85aSJeremy Jones 
1752a12f85aSJeremy Jones /*ARGSUSED*/
1762a12f85aSJeremy Jones static int
Pcred_live(struct ps_prochandle * P,prcred_t * pcrp,int ngroups,void * data)1772a12f85aSJeremy Jones Pcred_live(struct ps_prochandle *P, prcred_t *pcrp, int ngroups, void *data)
1782a12f85aSJeremy Jones {
1792a12f85aSJeremy Jones 	return (proc_get_cred(P->pid, pcrp, ngroups));
1802a12f85aSJeremy Jones }
1812a12f85aSJeremy Jones 
182d2a70789SRichard Lowe /* ARGSUSED */
183d2a70789SRichard Lowe static int
Psecflags_live(struct ps_prochandle * P,prsecflags_t ** psf,void * data)184d2a70789SRichard Lowe Psecflags_live(struct ps_prochandle *P, prsecflags_t **psf, void *data)
185d2a70789SRichard Lowe {
186d2a70789SRichard Lowe 	return (proc_get_secflags(P->pid, psf));
187d2a70789SRichard Lowe }
188d2a70789SRichard Lowe 
1892a12f85aSJeremy Jones /*ARGSUSED*/
1902a12f85aSJeremy Jones static int
Ppriv_live(struct ps_prochandle * P,prpriv_t ** pprv,void * data)1912a12f85aSJeremy Jones Ppriv_live(struct ps_prochandle *P, prpriv_t **pprv, void *data)
1922a12f85aSJeremy Jones {
1932a12f85aSJeremy Jones 	prpriv_t *pp;
1942a12f85aSJeremy Jones 
1952a12f85aSJeremy Jones 	pp = proc_get_priv(P->pid);
1962a12f85aSJeremy Jones 	if (pp == NULL) {
1972a12f85aSJeremy Jones 		return (-1);
1982a12f85aSJeremy Jones 	}
1992a12f85aSJeremy Jones 
2002a12f85aSJeremy Jones 	*pprv = pp;
2012a12f85aSJeremy Jones 	return (0);
2022a12f85aSJeremy Jones }
2032a12f85aSJeremy Jones 
2042a12f85aSJeremy Jones /*ARGSUSED*/
2052a12f85aSJeremy Jones static const psinfo_t *
Ppsinfo_live(struct ps_prochandle * P,psinfo_t * psinfo,void * data)2062a12f85aSJeremy Jones Ppsinfo_live(struct ps_prochandle *P, psinfo_t *psinfo, void *data)
2072a12f85aSJeremy Jones {
2082a12f85aSJeremy Jones 	if (proc_get_psinfo(P->pid, psinfo) == -1)
2092a12f85aSJeremy Jones 		return (NULL);
2102a12f85aSJeremy Jones 
2112a12f85aSJeremy Jones 	return (psinfo);
2122a12f85aSJeremy Jones }
2132a12f85aSJeremy Jones 
2142a12f85aSJeremy Jones /*ARGSUSED*/
2152a12f85aSJeremy Jones static prheader_t *
Plstatus_live(struct ps_prochandle * P,void * data)2162a12f85aSJeremy Jones Plstatus_live(struct ps_prochandle *P, void *data)
2172a12f85aSJeremy Jones {
2182a12f85aSJeremy Jones 	return (read_lfile(P, "lstatus"));
2192a12f85aSJeremy Jones }
2202a12f85aSJeremy Jones 
2212a12f85aSJeremy Jones /*ARGSUSED*/
2222a12f85aSJeremy Jones static prheader_t *
Plpsinfo_live(struct ps_prochandle * P,void * data)2232a12f85aSJeremy Jones Plpsinfo_live(struct ps_prochandle *P, void *data)
2242a12f85aSJeremy Jones {
2252a12f85aSJeremy Jones 	return (read_lfile(P, "lpsinfo"));
2262a12f85aSJeremy Jones }
2272a12f85aSJeremy Jones 
2282a12f85aSJeremy Jones /*ARGSUSED*/
2292a12f85aSJeremy Jones static char *
Pplatform_live(struct ps_prochandle * P,char * s,size_t n,void * data)2302a12f85aSJeremy Jones Pplatform_live(struct ps_prochandle *P, char *s, size_t n, void *data)
2312a12f85aSJeremy Jones {
2322a12f85aSJeremy Jones 	if (sysinfo(SI_PLATFORM, s, n) == -1)
2332a12f85aSJeremy Jones 		return (NULL);
2342a12f85aSJeremy Jones 	return (s);
2352a12f85aSJeremy Jones }
2362a12f85aSJeremy Jones 
2372a12f85aSJeremy Jones /*ARGSUSED*/
2382a12f85aSJeremy Jones static int
Puname_live(struct ps_prochandle * P,struct utsname * u,void * data)2392a12f85aSJeremy Jones Puname_live(struct ps_prochandle *P, struct utsname *u, void *data)
2402a12f85aSJeremy Jones {
2412a12f85aSJeremy Jones 	return (uname(u));
2422a12f85aSJeremy Jones }
2432a12f85aSJeremy Jones 
2442a12f85aSJeremy Jones /*ARGSUSED*/
2452a12f85aSJeremy Jones static char *
Pzonename_live(struct ps_prochandle * P,char * s,size_t n,void * data)2462a12f85aSJeremy Jones Pzonename_live(struct ps_prochandle *P, char *s, size_t n, void *data)
2472a12f85aSJeremy Jones {
2482a12f85aSJeremy Jones 	if (getzonenamebyid(P->status.pr_zoneid, s, n) < 0)
2492a12f85aSJeremy Jones 		return (NULL);
2502a12f85aSJeremy Jones 	s[n - 1] = '\0';
2512a12f85aSJeremy Jones 	return (s);
2522a12f85aSJeremy Jones }
2532a12f85aSJeremy Jones 
2542a12f85aSJeremy Jones /*
2552a12f85aSJeremy Jones  * Callback function for Pfindexec().  We return a match if we can stat the
2562a12f85aSJeremy Jones  * suggested pathname and confirm its device and inode number match our
2572a12f85aSJeremy Jones  * previous information about the /proc/<pid>/object/a.out file.
2582a12f85aSJeremy Jones  */
2592a12f85aSJeremy Jones static int
stat_exec(const char * path,void * arg)2602a12f85aSJeremy Jones stat_exec(const char *path, void *arg)
2612a12f85aSJeremy Jones {
2622a12f85aSJeremy Jones 	struct stat64 *stp = arg;
2632a12f85aSJeremy Jones 	struct stat64 st;
2642a12f85aSJeremy Jones 
2652a12f85aSJeremy Jones 	return (stat64(path, &st) == 0 && S_ISREG(st.st_mode) &&
2662a12f85aSJeremy Jones 	    stp->st_dev == st.st_dev && stp->st_ino == st.st_ino);
2672a12f85aSJeremy Jones }
2682a12f85aSJeremy Jones 
2692a12f85aSJeremy Jones /*ARGSUSED*/
2702a12f85aSJeremy Jones static char *
Pexecname_live(struct ps_prochandle * P,char * buf,size_t buflen,void * data)2712a12f85aSJeremy Jones Pexecname_live(struct ps_prochandle *P, char *buf, size_t buflen, void *data)
2722a12f85aSJeremy Jones {
2732a12f85aSJeremy Jones 	char exec_name[PATH_MAX];
2742a12f85aSJeremy Jones 	char cwd[PATH_MAX];
2752a12f85aSJeremy Jones 	char proc_cwd[64];
2762a12f85aSJeremy Jones 	struct stat64 st;
2772a12f85aSJeremy Jones 	int ret;
2782a12f85aSJeremy Jones 
2792a12f85aSJeremy Jones 	/*
2802a12f85aSJeremy Jones 	 * Try to get the path information first.
2812a12f85aSJeremy Jones 	 */
2822a12f85aSJeremy Jones 	(void) snprintf(exec_name, sizeof (exec_name),
2832a12f85aSJeremy Jones 	    "%s/%d/path/a.out", procfs_path, (int)P->pid);
2842a12f85aSJeremy Jones 	if ((ret = readlink(exec_name, buf, buflen - 1)) > 0) {
2852a12f85aSJeremy Jones 		buf[ret] = '\0';
2862a12f85aSJeremy Jones 		(void) Pfindobj(P, buf, buf, buflen);
2872a12f85aSJeremy Jones 		return (buf);
2882a12f85aSJeremy Jones 	}
2892a12f85aSJeremy Jones 
2902a12f85aSJeremy Jones 	/*
2912a12f85aSJeremy Jones 	 * Stat the executable file so we can compare Pfindexec's
2922a12f85aSJeremy Jones 	 * suggestions to the actual device and inode number.
2932a12f85aSJeremy Jones 	 */
2942a12f85aSJeremy Jones 	(void) snprintf(exec_name, sizeof (exec_name),
2952a12f85aSJeremy Jones 	    "%s/%d/object/a.out", procfs_path, (int)P->pid);
2962a12f85aSJeremy Jones 
2972a12f85aSJeremy Jones 	if (stat64(exec_name, &st) != 0 || !S_ISREG(st.st_mode))
2982a12f85aSJeremy Jones 		return (NULL);
2992a12f85aSJeremy Jones 
3002a12f85aSJeremy Jones 	/*
3012a12f85aSJeremy Jones 	 * Attempt to figure out the current working directory of the
3022a12f85aSJeremy Jones 	 * target process.  This only works if the target process has
3032a12f85aSJeremy Jones 	 * not changed its current directory since it was exec'd.
3042a12f85aSJeremy Jones 	 */
3052a12f85aSJeremy Jones 	(void) snprintf(proc_cwd, sizeof (proc_cwd),
3062a12f85aSJeremy Jones 	    "%s/%d/path/cwd", procfs_path, (int)P->pid);
3072a12f85aSJeremy Jones 
3082a12f85aSJeremy Jones 	if ((ret = readlink(proc_cwd, cwd, PATH_MAX - 1)) > 0)
3092a12f85aSJeremy Jones 		cwd[ret] = '\0';
3102a12f85aSJeremy Jones 
3112a12f85aSJeremy Jones 	(void) Pfindexec(P, ret > 0 ? cwd : NULL, stat_exec, &st);
3122a12f85aSJeremy Jones 
3132a12f85aSJeremy Jones 	return (NULL);
3142a12f85aSJeremy Jones }
3152a12f85aSJeremy Jones 
3162a12f85aSJeremy Jones #if defined(__i386) || defined(__amd64)
3172a12f85aSJeremy Jones /*ARGSUSED*/
3182a12f85aSJeremy Jones static int
Pldt_live(struct ps_prochandle * P,struct ssd * pldt,int nldt,void * data)3192a12f85aSJeremy Jones Pldt_live(struct ps_prochandle *P, struct ssd *pldt, int nldt, void *data)
3202a12f85aSJeremy Jones {
3212a12f85aSJeremy Jones 	return (proc_get_ldt(P->pid, pldt, nldt));
3222a12f85aSJeremy Jones }
3232a12f85aSJeremy Jones #endif
3242a12f85aSJeremy Jones 
3252a12f85aSJeremy Jones static const ps_ops_t P_live_ops = {
3262a12f85aSJeremy Jones 	.pop_pread	= Pread_live,
3272a12f85aSJeremy Jones 	.pop_pwrite	= Pwrite_live,
3282a12f85aSJeremy Jones 	.pop_read_maps	= Pread_maps_live,
3292a12f85aSJeremy Jones 	.pop_read_aux	= Pread_aux_live,
3302a12f85aSJeremy Jones 	.pop_cred	= Pcred_live,
3312a12f85aSJeremy Jones 	.pop_priv	= Ppriv_live,
3322a12f85aSJeremy Jones 	.pop_psinfo	= Ppsinfo_live,
3332a12f85aSJeremy Jones 	.pop_lstatus	= Plstatus_live,
3342a12f85aSJeremy Jones 	.pop_lpsinfo	= Plpsinfo_live,
3352a12f85aSJeremy Jones 	.pop_platform	= Pplatform_live,
3362a12f85aSJeremy Jones 	.pop_uname	= Puname_live,
3372a12f85aSJeremy Jones 	.pop_zonename	= Pzonename_live,
3382a12f85aSJeremy Jones 	.pop_execname	= Pexecname_live,
339d2a70789SRichard Lowe 	.pop_secflags	= Psecflags_live,
3402a12f85aSJeremy Jones #if defined(__i386) || defined(__amd64)
3412a12f85aSJeremy Jones 	.pop_ldt	= Pldt_live
3422a12f85aSJeremy Jones #endif
3432a12f85aSJeremy Jones };
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate /*
3467c478bd9Sstevel@tonic-gate  * This is the library's .init handler.
3477c478bd9Sstevel@tonic-gate  */
3487c478bd9Sstevel@tonic-gate #pragma init(_libproc_init)
3497c478bd9Sstevel@tonic-gate void
_libproc_init(void)3507c478bd9Sstevel@tonic-gate _libproc_init(void)
3517c478bd9Sstevel@tonic-gate {
3527c478bd9Sstevel@tonic-gate 	_libproc_debug = getenv("LIBPROC_DEBUG") != NULL;
353d7755b5aSrh 	_libproc_no_qsort = getenv("LIBPROC_NO_QSORT") != NULL;
354d9452f23SEdward Pilatowicz 	_libproc_incore_elf = getenv("LIBPROC_INCORE_ELF") != NULL;
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	(void) sigfillset(&blockable_sigs);
3577c478bd9Sstevel@tonic-gate 	(void) sigdelset(&blockable_sigs, SIGKILL);
3587c478bd9Sstevel@tonic-gate 	(void) sigdelset(&blockable_sigs, SIGSTOP);
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate 
3619acbbeafSnn void
Pset_procfs_path(const char * path)3629acbbeafSnn Pset_procfs_path(const char *path)
3639acbbeafSnn {
3649acbbeafSnn 	(void) snprintf(procfs_path, sizeof (procfs_path), "%s", path);
3659acbbeafSnn }
3669acbbeafSnn 
3677c478bd9Sstevel@tonic-gate /*
3687c478bd9Sstevel@tonic-gate  * Call set_minfd() once before calling dupfd() several times.
3697c478bd9Sstevel@tonic-gate  * We assume that the application will not reduce its current file
3707c478bd9Sstevel@tonic-gate  * descriptor limit lower than 512 once it has set at least that value.
3717c478bd9Sstevel@tonic-gate  */
3727c478bd9Sstevel@tonic-gate int
set_minfd(void)3737c478bd9Sstevel@tonic-gate set_minfd(void)
3747c478bd9Sstevel@tonic-gate {
3757c478bd9Sstevel@tonic-gate 	static mutex_t minfd_lock = DEFAULTMUTEX;
3767c478bd9Sstevel@tonic-gate 	struct rlimit rlim;
3777c478bd9Sstevel@tonic-gate 	int fd;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	if ((fd = minfd) < 256) {
3807c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&minfd_lock);
3817c478bd9Sstevel@tonic-gate 		if ((fd = minfd) < 256) {
3827c478bd9Sstevel@tonic-gate 			if (getrlimit(RLIMIT_NOFILE, &rlim) != 0)
3837c478bd9Sstevel@tonic-gate 				rlim.rlim_cur = rlim.rlim_max = 0;
3847c478bd9Sstevel@tonic-gate 			if (rlim.rlim_cur >= 512)
3857c478bd9Sstevel@tonic-gate 				fd = 256;
3867c478bd9Sstevel@tonic-gate 			else if ((fd = rlim.rlim_cur / 2) < 3)
3877c478bd9Sstevel@tonic-gate 				fd = 3;
388cb620785Sraf 			membar_producer();
3897c478bd9Sstevel@tonic-gate 			minfd = fd;
3907c478bd9Sstevel@tonic-gate 		}
3917c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&minfd_lock);
3927c478bd9Sstevel@tonic-gate 	}
3937c478bd9Sstevel@tonic-gate 	return (fd);
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate int
dupfd(int fd,int dfd)3977c478bd9Sstevel@tonic-gate dupfd(int fd, int dfd)
3987c478bd9Sstevel@tonic-gate {
3997c478bd9Sstevel@tonic-gate 	int mfd;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	/*
4027c478bd9Sstevel@tonic-gate 	 * Make fd be greater than 255 (the 32-bit stdio limit),
4037c478bd9Sstevel@tonic-gate 	 * or at least make it greater than 2 so that the
404bbf21555SRichard Lowe 	 * program will work when spawned by init(8).
4057c478bd9Sstevel@tonic-gate 	 * Also, if dfd is non-zero, dup the fd to be dfd.
4067c478bd9Sstevel@tonic-gate 	 */
4077c478bd9Sstevel@tonic-gate 	if ((mfd = minfd) == 0)
4087c478bd9Sstevel@tonic-gate 		mfd = set_minfd();
4097c478bd9Sstevel@tonic-gate 	if (dfd > 0 || (0 <= fd && fd < mfd)) {
4107c478bd9Sstevel@tonic-gate 		if (dfd <= 0)
4117c478bd9Sstevel@tonic-gate 			dfd = mfd;
4127c478bd9Sstevel@tonic-gate 		dfd = fcntl(fd, F_DUPFD, dfd);
4137c478bd9Sstevel@tonic-gate 		(void) close(fd);
4147c478bd9Sstevel@tonic-gate 		fd = dfd;
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate 	/*
4177c478bd9Sstevel@tonic-gate 	 * Mark it close-on-exec so any created process doesn't inherit it.
4187c478bd9Sstevel@tonic-gate 	 */
4197c478bd9Sstevel@tonic-gate 	if (fd >= 0)
4207c478bd9Sstevel@tonic-gate 		(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
4217c478bd9Sstevel@tonic-gate 	return (fd);
4227c478bd9Sstevel@tonic-gate }
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate /*
4257c478bd9Sstevel@tonic-gate  * Create a new controlled process.
4267c478bd9Sstevel@tonic-gate  * Leave it stopped on successful exit from exec() or execve().
4277c478bd9Sstevel@tonic-gate  * Return an opaque pointer to its process control structure.
4287c478bd9Sstevel@tonic-gate  * Return NULL if process cannot be created (fork()/exec() not successful).
4297c478bd9Sstevel@tonic-gate  */
4307c478bd9Sstevel@tonic-gate struct ps_prochandle *
Pxcreate(const char * file,char * const * argv,char * const * envp,int * perr,char * path,size_t len)4317c478bd9Sstevel@tonic-gate Pxcreate(const char *file,	/* executable file name */
432d2a70789SRichard Lowe     char *const *argv,		/* argument vector */
433d2a70789SRichard Lowe     char *const *envp,		/* environment */
434d2a70789SRichard Lowe     int *perr,			/* pointer to error return code */
435d2a70789SRichard Lowe     char *path,		/* if non-null, holds exec path name on return */
436d2a70789SRichard Lowe     size_t len)			/* size of the path buffer */
4377c478bd9Sstevel@tonic-gate {
4387c478bd9Sstevel@tonic-gate 	char execpath[PATH_MAX];
4399acbbeafSnn 	char procname[PATH_MAX];
4407c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P;
4417c478bd9Sstevel@tonic-gate 	pid_t pid;
4427c478bd9Sstevel@tonic-gate 	int fd;
4437c478bd9Sstevel@tonic-gate 	char *fname;
4447c478bd9Sstevel@tonic-gate 	int rc;
4457c478bd9Sstevel@tonic-gate 	int lasterrno = 0;
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	if (len == 0)	/* zero length, no path */
4487c478bd9Sstevel@tonic-gate 		path = NULL;
4497c478bd9Sstevel@tonic-gate 	if (path != NULL)
4507c478bd9Sstevel@tonic-gate 		*path = '\0';
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	if ((P = malloc(sizeof (struct ps_prochandle))) == NULL) {
4537c478bd9Sstevel@tonic-gate 		*perr = C_STRANGE;
4547c478bd9Sstevel@tonic-gate 		return (NULL);
4557c478bd9Sstevel@tonic-gate 	}
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	if ((pid = fork1()) == -1) {
4587c478bd9Sstevel@tonic-gate 		free(P);
4597c478bd9Sstevel@tonic-gate 		*perr = C_FORK;
4607c478bd9Sstevel@tonic-gate 		return (NULL);
4617c478bd9Sstevel@tonic-gate 	}
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	if (pid == 0) {			/* child process */
4647c478bd9Sstevel@tonic-gate 		id_t id;
4657c478bd9Sstevel@tonic-gate 		extern char **environ;
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 		/*
4687c478bd9Sstevel@tonic-gate 		 * If running setuid or setgid, reset credentials to normal.
4697c478bd9Sstevel@tonic-gate 		 */
4707c478bd9Sstevel@tonic-gate 		if ((id = getgid()) != getegid())
4717c478bd9Sstevel@tonic-gate 			(void) setgid(id);
4727c478bd9Sstevel@tonic-gate 		if ((id = getuid()) != geteuid())
4737c478bd9Sstevel@tonic-gate 			(void) setuid(id);
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 		Pcreate_callback(P);	/* execute callback (see below) */
4767c478bd9Sstevel@tonic-gate 		(void) pause();		/* wait for PRSABORT from parent */
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 		/*
4797c478bd9Sstevel@tonic-gate 		 * This is ugly.  There is no execvep() function that takes a
4807c478bd9Sstevel@tonic-gate 		 * path and an environment.  We cheat here by replacing the
4817c478bd9Sstevel@tonic-gate 		 * global 'environ' variable right before we call this.
4827c478bd9Sstevel@tonic-gate 		 */
4837c478bd9Sstevel@tonic-gate 		if (envp)
4847c478bd9Sstevel@tonic-gate 			environ = (char **)envp;
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 		(void) execvp(file, argv);  /* execute the program */
4877c478bd9Sstevel@tonic-gate 		_exit(127);
4887c478bd9Sstevel@tonic-gate 	}
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	/*
4917c478bd9Sstevel@tonic-gate 	 * Initialize the process structure.
4927c478bd9Sstevel@tonic-gate 	 */
4937c478bd9Sstevel@tonic-gate 	(void) memset(P, 0, sizeof (*P));
4947c478bd9Sstevel@tonic-gate 	(void) mutex_init(&P->proc_lock, USYNC_THREAD, NULL);
4957c478bd9Sstevel@tonic-gate 	P->flags |= CREATED;
4967c478bd9Sstevel@tonic-gate 	P->state = PS_RUN;
4977c478bd9Sstevel@tonic-gate 	P->pid = pid;
4987c478bd9Sstevel@tonic-gate 	P->asfd = -1;
4997c478bd9Sstevel@tonic-gate 	P->ctlfd = -1;
5007c478bd9Sstevel@tonic-gate 	P->statfd = -1;
5017c478bd9Sstevel@tonic-gate 	P->agentctlfd = -1;
5027c478bd9Sstevel@tonic-gate 	P->agentstatfd = -1;
5032a12f85aSJeremy Jones 	Pinit_ops(&P->ops, &P_live_ops);
5047c478bd9Sstevel@tonic-gate 	Pinitsym(P);
50550d4d24eSRobert Mustacchi 	Pinitfd(P);
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	/*
5087c478bd9Sstevel@tonic-gate 	 * Open the /proc/pid files.
5097c478bd9Sstevel@tonic-gate 	 */
5109acbbeafSnn 	(void) snprintf(procname, sizeof (procname), "%s/%d/",
5119acbbeafSnn 	    procfs_path, (int)pid);
5127c478bd9Sstevel@tonic-gate 	fname = procname + strlen(procname);
5137c478bd9Sstevel@tonic-gate 	(void) set_minfd();
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	/*
5167c478bd9Sstevel@tonic-gate 	 * Exclusive write open advises others not to interfere.
5177c478bd9Sstevel@tonic-gate 	 * There is no reason for any of these open()s to fail.
5187c478bd9Sstevel@tonic-gate 	 */
5197c478bd9Sstevel@tonic-gate 	(void) strcpy(fname, "as");
5207c478bd9Sstevel@tonic-gate 	if ((fd = open(procname, (O_RDWR|O_EXCL))) < 0 ||
5217c478bd9Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
5227c478bd9Sstevel@tonic-gate 		dprintf("Pcreate: failed to open %s: %s\n",
5237c478bd9Sstevel@tonic-gate 		    procname, strerror(errno));
5247c478bd9Sstevel@tonic-gate 		rc = C_STRANGE;
5257c478bd9Sstevel@tonic-gate 		goto bad;
5267c478bd9Sstevel@tonic-gate 	}
5277c478bd9Sstevel@tonic-gate 	P->asfd = fd;
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	(void) strcpy(fname, "status");
5307c478bd9Sstevel@tonic-gate 	if ((fd = open(procname, O_RDONLY)) < 0 ||
5317c478bd9Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
5327c478bd9Sstevel@tonic-gate 		dprintf("Pcreate: failed to open %s: %s\n",
5337c478bd9Sstevel@tonic-gate 		    procname, strerror(errno));
5347c478bd9Sstevel@tonic-gate 		rc = C_STRANGE;
5357c478bd9Sstevel@tonic-gate 		goto bad;
5367c478bd9Sstevel@tonic-gate 	}
5377c478bd9Sstevel@tonic-gate 	P->statfd = fd;
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	(void) strcpy(fname, "ctl");
5407c478bd9Sstevel@tonic-gate 	if ((fd = open(procname, O_WRONLY)) < 0 ||
5417c478bd9Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
5427c478bd9Sstevel@tonic-gate 		dprintf("Pcreate: failed to open %s: %s\n",
5437c478bd9Sstevel@tonic-gate 		    procname, strerror(errno));
5447c478bd9Sstevel@tonic-gate 		rc = C_STRANGE;
5457c478bd9Sstevel@tonic-gate 		goto bad;
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 	P->ctlfd = fd;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	(void) Pstop(P, 0);	/* stop the controlled process */
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	/*
5527c478bd9Sstevel@tonic-gate 	 * Wait for process to sleep in pause().
5537c478bd9Sstevel@tonic-gate 	 * If the process has already called pause(), then it should be
5547c478bd9Sstevel@tonic-gate 	 * stopped (PR_REQUESTED) while asleep in pause and we are done.
5557c478bd9Sstevel@tonic-gate 	 * Else we set up to catch entry/exit to pause() and set the process
5567c478bd9Sstevel@tonic-gate 	 * running again, expecting it to stop when it reaches pause().
5577c478bd9Sstevel@tonic-gate 	 * There is no reason for this to fail other than an interrupt.
5587c478bd9Sstevel@tonic-gate 	 */
5597c478bd9Sstevel@tonic-gate 	(void) Psysentry(P, SYS_pause, 1);
5607c478bd9Sstevel@tonic-gate 	(void) Psysexit(P, SYS_pause, 1);
5617c478bd9Sstevel@tonic-gate 	for (;;) {
5627c478bd9Sstevel@tonic-gate 		if (P->state == PS_STOP &&
5637c478bd9Sstevel@tonic-gate 		    P->status.pr_lwp.pr_syscall == SYS_pause &&
5647c478bd9Sstevel@tonic-gate 		    (P->status.pr_lwp.pr_why == PR_REQUESTED ||
5657c478bd9Sstevel@tonic-gate 		    P->status.pr_lwp.pr_why == PR_SYSENTRY ||
5667c478bd9Sstevel@tonic-gate 		    P->status.pr_lwp.pr_why == PR_SYSEXIT))
5677c478bd9Sstevel@tonic-gate 			break;
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 		if (P->state != PS_STOP ||	/* interrupt or process died */
5707c478bd9Sstevel@tonic-gate 		    Psetrun(P, 0, 0) != 0) {	/* can't restart */
5717c478bd9Sstevel@tonic-gate 			if (errno == EINTR || errno == ERESTART)
5727c478bd9Sstevel@tonic-gate 				rc = C_INTR;
5737c478bd9Sstevel@tonic-gate 			else {
5747c478bd9Sstevel@tonic-gate 				dprintf("Pcreate: Psetrun failed: %s\n",
5757c478bd9Sstevel@tonic-gate 				    strerror(errno));
5767c478bd9Sstevel@tonic-gate 				rc = C_STRANGE;
5777c478bd9Sstevel@tonic-gate 			}
5787c478bd9Sstevel@tonic-gate 			goto bad;
5797c478bd9Sstevel@tonic-gate 		}
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 		(void) Pwait(P, 0);
5827c478bd9Sstevel@tonic-gate 	}
5837c478bd9Sstevel@tonic-gate 	(void) Psysentry(P, SYS_pause, 0);
5847c478bd9Sstevel@tonic-gate 	(void) Psysexit(P, SYS_pause, 0);
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	/*
5877c478bd9Sstevel@tonic-gate 	 * Kick the process off the pause() and catch
5887c478bd9Sstevel@tonic-gate 	 * it again on entry to exec() or exit().
5897c478bd9Sstevel@tonic-gate 	 */
5907c478bd9Sstevel@tonic-gate 	(void) Psysentry(P, SYS_exit, 1);
5917c478bd9Sstevel@tonic-gate 	(void) Psysentry(P, SYS_execve, 1);
5927c478bd9Sstevel@tonic-gate 	if (Psetrun(P, 0, PRSABORT) == -1) {
5937c478bd9Sstevel@tonic-gate 		dprintf("Pcreate: Psetrun failed: %s\n", strerror(errno));
5947c478bd9Sstevel@tonic-gate 		rc = C_STRANGE;
5957c478bd9Sstevel@tonic-gate 		goto bad;
5967c478bd9Sstevel@tonic-gate 	}
5977c478bd9Sstevel@tonic-gate 	(void) Pwait(P, 0);
5987c478bd9Sstevel@tonic-gate 	if (P->state != PS_STOP) {
5997c478bd9Sstevel@tonic-gate 		dprintf("Pcreate: Pwait failed: %s\n", strerror(errno));
6007c478bd9Sstevel@tonic-gate 		rc = C_STRANGE;
6017c478bd9Sstevel@tonic-gate 		goto bad;
6027c478bd9Sstevel@tonic-gate 	}
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	/*
6057c478bd9Sstevel@tonic-gate 	 * Move the process through instances of failed exec()s
6067c478bd9Sstevel@tonic-gate 	 * to reach the point of stopped on successful exec().
6077c478bd9Sstevel@tonic-gate 	 */
6087c478bd9Sstevel@tonic-gate 	(void) Psysexit(P, SYS_execve, TRUE);
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	while (P->state == PS_STOP &&
6117c478bd9Sstevel@tonic-gate 	    P->status.pr_lwp.pr_why == PR_SYSENTRY &&
6128fd04b83SRoger A. Faulkner 	    P->status.pr_lwp.pr_what == SYS_execve) {
6137c478bd9Sstevel@tonic-gate 		/*
6147c478bd9Sstevel@tonic-gate 		 * Fetch the exec path name now, before we complete
6157c478bd9Sstevel@tonic-gate 		 * the exec().  We may lose the process and be unable
6167c478bd9Sstevel@tonic-gate 		 * to get the information later.
6177c478bd9Sstevel@tonic-gate 		 */
6187c478bd9Sstevel@tonic-gate 		(void) Pread_string(P, execpath, sizeof (execpath),
619d7755b5aSrh 		    (off_t)P->status.pr_lwp.pr_sysarg[0]);
6207c478bd9Sstevel@tonic-gate 		if (path != NULL)
6217c478bd9Sstevel@tonic-gate 			(void) strncpy(path, execpath, len);
6227c478bd9Sstevel@tonic-gate 		/*
6237c478bd9Sstevel@tonic-gate 		 * Set the process running and wait for
6247c478bd9Sstevel@tonic-gate 		 * it to stop on exit from the exec().
6257c478bd9Sstevel@tonic-gate 		 */
6267c478bd9Sstevel@tonic-gate 		(void) Psetrun(P, 0, 0);
6277c478bd9Sstevel@tonic-gate 		(void) Pwait(P, 0);
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 		if (P->state == PS_LOST &&		/* we lost control */
6307c478bd9Sstevel@tonic-gate 		    Preopen(P) != 0) {		/* and we can't get it back */
6317c478bd9Sstevel@tonic-gate 			rc = C_PERM;
6327c478bd9Sstevel@tonic-gate 			goto bad;
6337c478bd9Sstevel@tonic-gate 		}
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 		/*
6367c478bd9Sstevel@tonic-gate 		 * If the exec() failed, continue the loop, expecting
6377c478bd9Sstevel@tonic-gate 		 * there to be more attempts to exec(), based on PATH.
6387c478bd9Sstevel@tonic-gate 		 */
6397c478bd9Sstevel@tonic-gate 		if (P->state == PS_STOP &&
6407c478bd9Sstevel@tonic-gate 		    P->status.pr_lwp.pr_why == PR_SYSEXIT &&
6418fd04b83SRoger A. Faulkner 		    P->status.pr_lwp.pr_what == SYS_execve &&
6427c478bd9Sstevel@tonic-gate 		    (lasterrno = P->status.pr_lwp.pr_errno) != 0) {
6437c478bd9Sstevel@tonic-gate 			/*
6447c478bd9Sstevel@tonic-gate 			 * The exec() failed.  Set the process running and
6457c478bd9Sstevel@tonic-gate 			 * wait for it to stop on entry to the next exec().
6467c478bd9Sstevel@tonic-gate 			 */
6477c478bd9Sstevel@tonic-gate 			(void) Psetrun(P, 0, 0);
6487c478bd9Sstevel@tonic-gate 			(void) Pwait(P, 0);
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 			continue;
6517c478bd9Sstevel@tonic-gate 		}
6527c478bd9Sstevel@tonic-gate 		break;
6537c478bd9Sstevel@tonic-gate 	}
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	if (P->state == PS_STOP &&
6567c478bd9Sstevel@tonic-gate 	    P->status.pr_lwp.pr_why == PR_SYSEXIT &&
6578fd04b83SRoger A. Faulkner 	    P->status.pr_lwp.pr_what == SYS_execve &&
6587c478bd9Sstevel@tonic-gate 	    P->status.pr_lwp.pr_errno == 0) {
6597c478bd9Sstevel@tonic-gate 		/*
6607c478bd9Sstevel@tonic-gate 		 * The process is stopped on successful exec() or execve().
6617c478bd9Sstevel@tonic-gate 		 * Turn off all tracing flags and return success.
6627c478bd9Sstevel@tonic-gate 		 */
6637c478bd9Sstevel@tonic-gate 		restore_tracing_flags(P);
6647c478bd9Sstevel@tonic-gate #ifndef _LP64
6657c478bd9Sstevel@tonic-gate 		/* We must be a 64-bit process to deal with a 64-bit process */
6667c478bd9Sstevel@tonic-gate 		if (P->status.pr_dmodel == PR_MODEL_LP64) {
6677c478bd9Sstevel@tonic-gate 			rc = C_LP64;
6687c478bd9Sstevel@tonic-gate 			goto bad;
6697c478bd9Sstevel@tonic-gate 		}
6707c478bd9Sstevel@tonic-gate #endif
6717c478bd9Sstevel@tonic-gate 		/*
6727c478bd9Sstevel@tonic-gate 		 * Set run-on-last-close so the controlled process
6737c478bd9Sstevel@tonic-gate 		 * runs even if we die on a signal.
6747c478bd9Sstevel@tonic-gate 		 */
6757c478bd9Sstevel@tonic-gate 		(void) Psetflags(P, PR_RLC);
6767c478bd9Sstevel@tonic-gate 		*perr = 0;
6777c478bd9Sstevel@tonic-gate 		return (P);
6787c478bd9Sstevel@tonic-gate 	}
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	rc = lasterrno == ENOENT ? C_NOENT : C_NOEXEC;
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate bad:
6837c478bd9Sstevel@tonic-gate 	(void) kill(pid, SIGKILL);
6847c478bd9Sstevel@tonic-gate 	if (path != NULL && rc != C_PERM && rc != C_LP64)
6857c478bd9Sstevel@tonic-gate 		*path = '\0';
6867c478bd9Sstevel@tonic-gate 	Pfree(P);
6877c478bd9Sstevel@tonic-gate 	*perr = rc;
6887c478bd9Sstevel@tonic-gate 	return (NULL);
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate struct ps_prochandle *
Pcreate(const char * file,char * const * argv,int * perr,char * path,size_t len)6927c478bd9Sstevel@tonic-gate Pcreate(
6937c478bd9Sstevel@tonic-gate 	const char *file,	/* executable file name */
6947c478bd9Sstevel@tonic-gate 	char *const *argv,	/* argument vector */
6957c478bd9Sstevel@tonic-gate 	int *perr,	/* pointer to error return code */
6967c478bd9Sstevel@tonic-gate 	char *path,	/* if non-null, holds exec path name on return */
6977c478bd9Sstevel@tonic-gate 	size_t len)	/* size of the path buffer */
6987c478bd9Sstevel@tonic-gate {
6997c478bd9Sstevel@tonic-gate 	return (Pxcreate(file, argv, NULL, perr, path, len));
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate /*
7037c478bd9Sstevel@tonic-gate  * Return a printable string corresponding to a Pcreate() error return.
7047c478bd9Sstevel@tonic-gate  */
7057c478bd9Sstevel@tonic-gate const char *
Pcreate_error(int error)7067c478bd9Sstevel@tonic-gate Pcreate_error(int error)
7077c478bd9Sstevel@tonic-gate {
7087c478bd9Sstevel@tonic-gate 	const char *str;
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	switch (error) {
7117c478bd9Sstevel@tonic-gate 	case C_FORK:
7127c478bd9Sstevel@tonic-gate 		str = "cannot fork";
7137c478bd9Sstevel@tonic-gate 		break;
7147c478bd9Sstevel@tonic-gate 	case C_PERM:
7157c478bd9Sstevel@tonic-gate 		str = "file is set-id or unreadable";
7167c478bd9Sstevel@tonic-gate 		break;
7177c478bd9Sstevel@tonic-gate 	case C_NOEXEC:
7187c478bd9Sstevel@tonic-gate 		str = "cannot execute file";
7197c478bd9Sstevel@tonic-gate 		break;
7207c478bd9Sstevel@tonic-gate 	case C_INTR:
7217c478bd9Sstevel@tonic-gate 		str = "operation interrupted";
7227c478bd9Sstevel@tonic-gate 		break;
7237c478bd9Sstevel@tonic-gate 	case C_LP64:
7247c478bd9Sstevel@tonic-gate 		str = "program is _LP64, self is not";
7257c478bd9Sstevel@tonic-gate 		break;
7267c478bd9Sstevel@tonic-gate 	case C_STRANGE:
7277c478bd9Sstevel@tonic-gate 		str = "unanticipated system error";
7287c478bd9Sstevel@tonic-gate 		break;
7297c478bd9Sstevel@tonic-gate 	case C_NOENT:
7307c478bd9Sstevel@tonic-gate 		str = "cannot find executable file";
7317c478bd9Sstevel@tonic-gate 		break;
7327c478bd9Sstevel@tonic-gate 	default:
7337c478bd9Sstevel@tonic-gate 		str = "unknown error";
7347c478bd9Sstevel@tonic-gate 		break;
7357c478bd9Sstevel@tonic-gate 	}
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	return (str);
7387c478bd9Sstevel@tonic-gate }
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate /*
7417c478bd9Sstevel@tonic-gate  * Callback to execute in each child process created with Pcreate() after fork
7427c478bd9Sstevel@tonic-gate  * but before it execs the new process image.  By default, we do nothing, but
7437c478bd9Sstevel@tonic-gate  * by calling this function we allow the client program to define its own
7447c478bd9Sstevel@tonic-gate  * version of the function which will interpose on our empty default.  This
7457c478bd9Sstevel@tonic-gate  * may be useful for clients that need to modify signal dispositions, terminal
7467c478bd9Sstevel@tonic-gate  * attributes, or process group and session properties for each new victim.
7477c478bd9Sstevel@tonic-gate  */
7487c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7497c478bd9Sstevel@tonic-gate void
Pcreate_callback(struct ps_prochandle * P)7507c478bd9Sstevel@tonic-gate Pcreate_callback(struct ps_prochandle *P)
7517c478bd9Sstevel@tonic-gate {
7527c478bd9Sstevel@tonic-gate 	/* nothing to do here */
7537c478bd9Sstevel@tonic-gate }
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate /*
7567c478bd9Sstevel@tonic-gate  * Grab an existing process.
7577c478bd9Sstevel@tonic-gate  * Return an opaque pointer to its process control structure.
7587c478bd9Sstevel@tonic-gate  *
7597c478bd9Sstevel@tonic-gate  * pid:		UNIX process ID.
7607c478bd9Sstevel@tonic-gate  * flags:
7617c478bd9Sstevel@tonic-gate  *	PGRAB_RETAIN	Retain tracing flags (default clears all tracing flags).
7627c478bd9Sstevel@tonic-gate  *	PGRAB_FORCE	Grab regardless of whether process is already traced.
7637c478bd9Sstevel@tonic-gate  *	PGRAB_RDONLY	Open the address space file O_RDONLY instead of O_RDWR,
7647c478bd9Sstevel@tonic-gate  *                      and do not open the process control file.
7657c478bd9Sstevel@tonic-gate  *	PGRAB_NOSTOP	Open the process but do not force it to stop.
7667c478bd9Sstevel@tonic-gate  * perr:	pointer to error return code.
7677c478bd9Sstevel@tonic-gate  */
7687c478bd9Sstevel@tonic-gate struct ps_prochandle *
Pgrab(pid_t pid,int flags,int * perr)7697c478bd9Sstevel@tonic-gate Pgrab(pid_t pid, int flags, int *perr)
7707c478bd9Sstevel@tonic-gate {
7717c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P;
7727c478bd9Sstevel@tonic-gate 	int fd, omode;
7739acbbeafSnn 	char procname[PATH_MAX];
7747c478bd9Sstevel@tonic-gate 	char *fname;
7757c478bd9Sstevel@tonic-gate 	int rc = 0;
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 	/*
7787c478bd9Sstevel@tonic-gate 	 * PGRAB_RDONLY means that we do not open the /proc/<pid>/control file,
7797c478bd9Sstevel@tonic-gate 	 * and so it implies RETAIN and NOSTOP since both require control.
7807c478bd9Sstevel@tonic-gate 	 */
7817c478bd9Sstevel@tonic-gate 	if (flags & PGRAB_RDONLY)
7827c478bd9Sstevel@tonic-gate 		flags |= PGRAB_RETAIN | PGRAB_NOSTOP;
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 	if ((P = malloc(sizeof (struct ps_prochandle))) == NULL) {
7857c478bd9Sstevel@tonic-gate 		*perr = G_STRANGE;
7867c478bd9Sstevel@tonic-gate 		return (NULL);
7877c478bd9Sstevel@tonic-gate 	}
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 	P->asfd = -1;
7907c478bd9Sstevel@tonic-gate 	P->ctlfd = -1;
7917c478bd9Sstevel@tonic-gate 	P->statfd = -1;
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate again:	/* Come back here if we lose it in the Window of Vulnerability */
7947c478bd9Sstevel@tonic-gate 	if (P->ctlfd >= 0)
7957c478bd9Sstevel@tonic-gate 		(void) close(P->ctlfd);
7967c478bd9Sstevel@tonic-gate 	if (P->asfd >= 0)
7977c478bd9Sstevel@tonic-gate 		(void) close(P->asfd);
7987c478bd9Sstevel@tonic-gate 	if (P->statfd >= 0)
7997c478bd9Sstevel@tonic-gate 		(void) close(P->statfd);
8007c478bd9Sstevel@tonic-gate 	(void) memset(P, 0, sizeof (*P));
8017c478bd9Sstevel@tonic-gate 	(void) mutex_init(&P->proc_lock, USYNC_THREAD, NULL);
8027c478bd9Sstevel@tonic-gate 	P->ctlfd = -1;
8037c478bd9Sstevel@tonic-gate 	P->asfd = -1;
8047c478bd9Sstevel@tonic-gate 	P->statfd = -1;
8057c478bd9Sstevel@tonic-gate 	P->agentctlfd = -1;
8067c478bd9Sstevel@tonic-gate 	P->agentstatfd = -1;
8072a12f85aSJeremy Jones 	Pinit_ops(&P->ops, &P_live_ops);
8087c478bd9Sstevel@tonic-gate 	Pinitsym(P);
80950d4d24eSRobert Mustacchi 	Pinitfd(P);
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	/*
8127c478bd9Sstevel@tonic-gate 	 * Open the /proc/pid files
8137c478bd9Sstevel@tonic-gate 	 */
8149acbbeafSnn 	(void) snprintf(procname, sizeof (procname), "%s/%d/",
8159acbbeafSnn 	    procfs_path, (int)pid);
8167c478bd9Sstevel@tonic-gate 	fname = procname + strlen(procname);
8177c478bd9Sstevel@tonic-gate 	(void) set_minfd();
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 	/*
8207c478bd9Sstevel@tonic-gate 	 * Request exclusive open to avoid grabbing someone else's
8217c478bd9Sstevel@tonic-gate 	 * process and to prevent others from interfering afterwards.
8227c478bd9Sstevel@tonic-gate 	 * If this fails and the 'PGRAB_FORCE' flag is set, attempt to
8237c478bd9Sstevel@tonic-gate 	 * open non-exclusively.
8247c478bd9Sstevel@tonic-gate 	 */
8257c478bd9Sstevel@tonic-gate 	(void) strcpy(fname, "as");
8267c478bd9Sstevel@tonic-gate 	omode = (flags & PGRAB_RDONLY) ? O_RDONLY : O_RDWR;
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 	if (((fd = open(procname, omode | O_EXCL)) < 0 &&
8297c478bd9Sstevel@tonic-gate 	    (fd = ((flags & PGRAB_FORCE)? open(procname, omode) : -1)) < 0) ||
8307c478bd9Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
8317c478bd9Sstevel@tonic-gate 		switch (errno) {
8327c478bd9Sstevel@tonic-gate 		case ENOENT:
8337c478bd9Sstevel@tonic-gate 			rc = G_NOPROC;
8347c478bd9Sstevel@tonic-gate 			break;
8357c478bd9Sstevel@tonic-gate 		case EACCES:
8367c478bd9Sstevel@tonic-gate 		case EPERM:
8377c478bd9Sstevel@tonic-gate 			rc = G_PERM;
8387c478bd9Sstevel@tonic-gate 			break;
839cd11e192Sjhaslam 		case EMFILE:
840cd11e192Sjhaslam 			rc = G_NOFD;
841cd11e192Sjhaslam 			break;
8427c478bd9Sstevel@tonic-gate 		case EBUSY:
8437c478bd9Sstevel@tonic-gate 			if (!(flags & PGRAB_FORCE) || geteuid() != 0) {
8447c478bd9Sstevel@tonic-gate 				rc = G_BUSY;
8457c478bd9Sstevel@tonic-gate 				break;
8467c478bd9Sstevel@tonic-gate 			}
8477c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
8487c478bd9Sstevel@tonic-gate 		default:
8497c478bd9Sstevel@tonic-gate 			dprintf("Pgrab: failed to open %s: %s\n",
8507c478bd9Sstevel@tonic-gate 			    procname, strerror(errno));
8517c478bd9Sstevel@tonic-gate 			rc = G_STRANGE;
8527c478bd9Sstevel@tonic-gate 			break;
8537c478bd9Sstevel@tonic-gate 		}
8547c478bd9Sstevel@tonic-gate 		goto err;
8557c478bd9Sstevel@tonic-gate 	}
8567c478bd9Sstevel@tonic-gate 	P->asfd = fd;
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 	(void) strcpy(fname, "status");
8597c478bd9Sstevel@tonic-gate 	if ((fd = open(procname, O_RDONLY)) < 0 ||
8607c478bd9Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
8617c478bd9Sstevel@tonic-gate 		switch (errno) {
8627c478bd9Sstevel@tonic-gate 		case ENOENT:
8637c478bd9Sstevel@tonic-gate 			rc = G_NOPROC;
8647c478bd9Sstevel@tonic-gate 			break;
865cd11e192Sjhaslam 		case EMFILE:
866cd11e192Sjhaslam 			rc = G_NOFD;
867cd11e192Sjhaslam 			break;
8687c478bd9Sstevel@tonic-gate 		default:
8697c478bd9Sstevel@tonic-gate 			dprintf("Pgrab: failed to open %s: %s\n",
8707c478bd9Sstevel@tonic-gate 			    procname, strerror(errno));
8717c478bd9Sstevel@tonic-gate 			rc = G_STRANGE;
8727c478bd9Sstevel@tonic-gate 			break;
8737c478bd9Sstevel@tonic-gate 		}
8747c478bd9Sstevel@tonic-gate 		goto err;
8757c478bd9Sstevel@tonic-gate 	}
8767c478bd9Sstevel@tonic-gate 	P->statfd = fd;
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	if (!(flags & PGRAB_RDONLY)) {
8797c478bd9Sstevel@tonic-gate 		(void) strcpy(fname, "ctl");
8807c478bd9Sstevel@tonic-gate 		if ((fd = open(procname, O_WRONLY)) < 0 ||
8817c478bd9Sstevel@tonic-gate 		    (fd = dupfd(fd, 0)) < 0) {
8827c478bd9Sstevel@tonic-gate 			switch (errno) {
8837c478bd9Sstevel@tonic-gate 			case ENOENT:
8847c478bd9Sstevel@tonic-gate 				rc = G_NOPROC;
8857c478bd9Sstevel@tonic-gate 				break;
886cd11e192Sjhaslam 			case EMFILE:
887cd11e192Sjhaslam 				rc = G_NOFD;
888cd11e192Sjhaslam 				break;
8897c478bd9Sstevel@tonic-gate 			default:
8907c478bd9Sstevel@tonic-gate 				dprintf("Pgrab: failed to open %s: %s\n",
8917c478bd9Sstevel@tonic-gate 				    procname, strerror(errno));
8927c478bd9Sstevel@tonic-gate 				rc = G_STRANGE;
8937c478bd9Sstevel@tonic-gate 				break;
8947c478bd9Sstevel@tonic-gate 			}
8957c478bd9Sstevel@tonic-gate 			goto err;
8967c478bd9Sstevel@tonic-gate 		}
8977c478bd9Sstevel@tonic-gate 		P->ctlfd = fd;
8987c478bd9Sstevel@tonic-gate 	}
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	P->state = PS_RUN;
9017c478bd9Sstevel@tonic-gate 	P->pid = pid;
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	/*
9047c478bd9Sstevel@tonic-gate 	 * We are now in the Window of Vulnerability (WoV).  The process may
9057c478bd9Sstevel@tonic-gate 	 * exec() a setuid/setgid or unreadable object file between the open()
9067c478bd9Sstevel@tonic-gate 	 * and the PCSTOP.  We will get EAGAIN in this case and must start over.
9077c478bd9Sstevel@tonic-gate 	 * As Pstopstatus will trigger the first read() from a /proc file,
9087c478bd9Sstevel@tonic-gate 	 * we also need to handle EOVERFLOW here when 32-bit as an indicator
9097c478bd9Sstevel@tonic-gate 	 * that this process is 64-bit.  Finally, if the process has become
9107c478bd9Sstevel@tonic-gate 	 * a zombie (PS_UNDEAD) while we were trying to grab it, just remain
9117c478bd9Sstevel@tonic-gate 	 * silent about this and pretend there was no process.
9127c478bd9Sstevel@tonic-gate 	 */
9137c478bd9Sstevel@tonic-gate 	if (Pstopstatus(P, PCNULL, 0) != 0) {
9147c478bd9Sstevel@tonic-gate #ifndef _LP64
9157c478bd9Sstevel@tonic-gate 		if (errno == EOVERFLOW) {
9167c478bd9Sstevel@tonic-gate 			rc = G_LP64;
9177c478bd9Sstevel@tonic-gate 			goto err;
9187c478bd9Sstevel@tonic-gate 		}
9197c478bd9Sstevel@tonic-gate #endif
9207c478bd9Sstevel@tonic-gate 		if (P->state == PS_LOST) {	/* WoV */
9217c478bd9Sstevel@tonic-gate 			(void) mutex_destroy(&P->proc_lock);
9227c478bd9Sstevel@tonic-gate 			goto again;
9237c478bd9Sstevel@tonic-gate 		}
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 		if (P->state == PS_UNDEAD)
9267c478bd9Sstevel@tonic-gate 			rc = G_NOPROC;
9277c478bd9Sstevel@tonic-gate 		else
9287c478bd9Sstevel@tonic-gate 			rc = G_STRANGE;
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 		goto err;
9317c478bd9Sstevel@tonic-gate 	}
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	/*
9347c478bd9Sstevel@tonic-gate 	 * If the process is a system process, we can't control it even as root
9357c478bd9Sstevel@tonic-gate 	 */
9367c478bd9Sstevel@tonic-gate 	if (P->status.pr_flags & PR_ISSYS) {
9377c478bd9Sstevel@tonic-gate 		rc = G_SYS;
9387c478bd9Sstevel@tonic-gate 		goto err;
9397c478bd9Sstevel@tonic-gate 	}
9407c478bd9Sstevel@tonic-gate #ifndef _LP64
9417c478bd9Sstevel@tonic-gate 	/*
9427c478bd9Sstevel@tonic-gate 	 * We must be a 64-bit process to deal with a 64-bit process
9437c478bd9Sstevel@tonic-gate 	 */
9447c478bd9Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_LP64) {
9457c478bd9Sstevel@tonic-gate 		rc = G_LP64;
9467c478bd9Sstevel@tonic-gate 		goto err;
9477c478bd9Sstevel@tonic-gate 	}
9487c478bd9Sstevel@tonic-gate #endif
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	/*
9517c478bd9Sstevel@tonic-gate 	 * Remember the status for use by Prelease().
9527c478bd9Sstevel@tonic-gate 	 */
9537c478bd9Sstevel@tonic-gate 	P->orig_status = P->status;	/* structure copy */
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	/*
9567c478bd9Sstevel@tonic-gate 	 * Before stopping the process, make sure we are not grabbing ourselves.
9577c478bd9Sstevel@tonic-gate 	 * If we are, make sure we are doing it PGRAB_RDONLY.
9587c478bd9Sstevel@tonic-gate 	 */
9597c478bd9Sstevel@tonic-gate 	if (pid == getpid()) {
9607c478bd9Sstevel@tonic-gate 		/*
9617c478bd9Sstevel@tonic-gate 		 * Verify that the process is really ourself:
9627c478bd9Sstevel@tonic-gate 		 * Set a magic number, read it through the
9637c478bd9Sstevel@tonic-gate 		 * /proc file and see if the results match.
9647c478bd9Sstevel@tonic-gate 		 */
9657c478bd9Sstevel@tonic-gate 		uint32_t magic1 = 0;
9667c478bd9Sstevel@tonic-gate 		uint32_t magic2 = 2;
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 		errno = 0;
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 		if (Pread(P, &magic2, sizeof (magic2), (uintptr_t)&magic1)
9717c478bd9Sstevel@tonic-gate 		    == sizeof (magic2) &&
9727c478bd9Sstevel@tonic-gate 		    magic2 == 0 &&
9737c478bd9Sstevel@tonic-gate 		    (magic1 = 0xfeedbeef) &&
9747c478bd9Sstevel@tonic-gate 		    Pread(P, &magic2, sizeof (magic2), (uintptr_t)&magic1)
9757c478bd9Sstevel@tonic-gate 		    == sizeof (magic2) &&
9767c478bd9Sstevel@tonic-gate 		    magic2 == 0xfeedbeef &&
9777c478bd9Sstevel@tonic-gate 		    !(flags & PGRAB_RDONLY)) {
9787c478bd9Sstevel@tonic-gate 			rc = G_SELF;
9797c478bd9Sstevel@tonic-gate 			goto err;
9807c478bd9Sstevel@tonic-gate 		}
9817c478bd9Sstevel@tonic-gate 	}
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 	/*
9847c478bd9Sstevel@tonic-gate 	 * If the process is already stopped or has been directed
9857c478bd9Sstevel@tonic-gate 	 * to stop via /proc, do not set run-on-last-close.
9867c478bd9Sstevel@tonic-gate 	 */
9877c478bd9Sstevel@tonic-gate 	if (!(P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)) &&
9887c478bd9Sstevel@tonic-gate 	    !(flags & PGRAB_RDONLY)) {
9897c478bd9Sstevel@tonic-gate 		/*
9907c478bd9Sstevel@tonic-gate 		 * Mark the process run-on-last-close so
9917c478bd9Sstevel@tonic-gate 		 * it runs even if we die from SIGKILL.
9927c478bd9Sstevel@tonic-gate 		 */
9937c478bd9Sstevel@tonic-gate 		if (Psetflags(P, PR_RLC) != 0) {
9947c478bd9Sstevel@tonic-gate 			if (errno == EAGAIN) {	/* WoV */
9957c478bd9Sstevel@tonic-gate 				(void) mutex_destroy(&P->proc_lock);
9967c478bd9Sstevel@tonic-gate 				goto again;
9977c478bd9Sstevel@tonic-gate 			}
9987c478bd9Sstevel@tonic-gate 			if (errno == ENOENT)	/* No complaint about zombies */
9997c478bd9Sstevel@tonic-gate 				rc = G_ZOMB;
10007c478bd9Sstevel@tonic-gate 			else {
10017c478bd9Sstevel@tonic-gate 				dprintf("Pgrab: failed to set RLC\n");
10027c478bd9Sstevel@tonic-gate 				rc = G_STRANGE;
10037c478bd9Sstevel@tonic-gate 			}
10047c478bd9Sstevel@tonic-gate 			goto err;
10057c478bd9Sstevel@tonic-gate 		}
10067c478bd9Sstevel@tonic-gate 	}
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 	/*
10097c478bd9Sstevel@tonic-gate 	 * If a stop directive is pending and the process has not yet stopped,
10107c478bd9Sstevel@tonic-gate 	 * then synchronously wait for the stop directive to take effect.
10117c478bd9Sstevel@tonic-gate 	 * Limit the time spent waiting for the process to stop by iterating
10127c478bd9Sstevel@tonic-gate 	 * at most 10 times. The time-out of 20 ms corresponds to the time
10137c478bd9Sstevel@tonic-gate 	 * between sending the stop directive and the process actually stopped
10147c478bd9Sstevel@tonic-gate 	 * as measured by DTrace on a slow, busy system. If the process doesn't
10157c478bd9Sstevel@tonic-gate 	 * stop voluntarily, clear the PR_DSTOP flag so that the code below
10167c478bd9Sstevel@tonic-gate 	 * forces the process to stop.
10177c478bd9Sstevel@tonic-gate 	 */
10187c478bd9Sstevel@tonic-gate 	if (!(flags & PGRAB_RDONLY)) {
10197c478bd9Sstevel@tonic-gate 		int niter = 0;
10207c478bd9Sstevel@tonic-gate 		while ((P->status.pr_lwp.pr_flags & (PR_STOPPED|PR_DSTOP)) ==
10217c478bd9Sstevel@tonic-gate 		    PR_DSTOP && niter < 10 &&
10227c478bd9Sstevel@tonic-gate 		    Pstopstatus(P, PCTWSTOP, 20) != 0) {
10237c478bd9Sstevel@tonic-gate 			niter++;
10247c478bd9Sstevel@tonic-gate 			if (flags & PGRAB_NOSTOP)
10257c478bd9Sstevel@tonic-gate 				break;
10267c478bd9Sstevel@tonic-gate 		}
10277c478bd9Sstevel@tonic-gate 		if (niter == 10 && !(flags & PGRAB_NOSTOP)) {
10287c478bd9Sstevel@tonic-gate 			/* Try it harder down below */
10297c478bd9Sstevel@tonic-gate 			P->status.pr_lwp.pr_flags &= ~PR_DSTOP;
10307c478bd9Sstevel@tonic-gate 		}
10317c478bd9Sstevel@tonic-gate 	}
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	/*
10347c478bd9Sstevel@tonic-gate 	 * If the process is not already stopped or directed to stop
10357c478bd9Sstevel@tonic-gate 	 * and PGRAB_NOSTOP was not specified, stop the process now.
10367c478bd9Sstevel@tonic-gate 	 */
10377c478bd9Sstevel@tonic-gate 	if (!(P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)) &&
10387c478bd9Sstevel@tonic-gate 	    !(flags & PGRAB_NOSTOP)) {
10397c478bd9Sstevel@tonic-gate 		/*
10407c478bd9Sstevel@tonic-gate 		 * Stop the process, get its status and signal/syscall masks.
10417c478bd9Sstevel@tonic-gate 		 */
10427c478bd9Sstevel@tonic-gate 		if (((P->status.pr_lwp.pr_flags & PR_STOPPED) &&
10437c478bd9Sstevel@tonic-gate 		    Pstopstatus(P, PCDSTOP, 0) != 0) ||
10447c478bd9Sstevel@tonic-gate 		    Pstopstatus(P, PCSTOP, 2000) != 0) {
10457c478bd9Sstevel@tonic-gate #ifndef _LP64
10467c478bd9Sstevel@tonic-gate 			if (errno == EOVERFLOW) {
10477c478bd9Sstevel@tonic-gate 				rc = G_LP64;
10487c478bd9Sstevel@tonic-gate 				goto err;
10497c478bd9Sstevel@tonic-gate 			}
10507c478bd9Sstevel@tonic-gate #endif
10517c478bd9Sstevel@tonic-gate 			if (P->state == PS_LOST) {	/* WoV */
10527c478bd9Sstevel@tonic-gate 				(void) mutex_destroy(&P->proc_lock);
10537c478bd9Sstevel@tonic-gate 				goto again;
10547c478bd9Sstevel@tonic-gate 			}
10557c478bd9Sstevel@tonic-gate 			if ((errno != EINTR && errno != ERESTART) ||
10567c478bd9Sstevel@tonic-gate 			    (P->state != PS_STOP &&
10577c478bd9Sstevel@tonic-gate 			    !(P->status.pr_flags & PR_DSTOP))) {
10587c478bd9Sstevel@tonic-gate 				if (P->state != PS_RUN && errno != ENOENT) {
10597c478bd9Sstevel@tonic-gate 					dprintf("Pgrab: failed to PCSTOP\n");
10607c478bd9Sstevel@tonic-gate 					rc = G_STRANGE;
10617c478bd9Sstevel@tonic-gate 				} else {
10627c478bd9Sstevel@tonic-gate 					rc = G_ZOMB;
10637c478bd9Sstevel@tonic-gate 				}
10647c478bd9Sstevel@tonic-gate 				goto err;
10657c478bd9Sstevel@tonic-gate 			}
10667c478bd9Sstevel@tonic-gate 		}
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 		/*
10697c478bd9Sstevel@tonic-gate 		 * Process should now either be stopped via /proc or there
10707c478bd9Sstevel@tonic-gate 		 * should be an outstanding stop directive.
10717c478bd9Sstevel@tonic-gate 		 */
10727c478bd9Sstevel@tonic-gate 		if (!(P->status.pr_flags & (PR_ISTOP|PR_DSTOP))) {
10737c478bd9Sstevel@tonic-gate 			dprintf("Pgrab: process is not stopped\n");
10747c478bd9Sstevel@tonic-gate 			rc = G_STRANGE;
10757c478bd9Sstevel@tonic-gate 			goto err;
10767c478bd9Sstevel@tonic-gate 		}
10777c478bd9Sstevel@tonic-gate #ifndef _LP64
10787c478bd9Sstevel@tonic-gate 		/*
10797c478bd9Sstevel@tonic-gate 		 * Test this again now because the 32-bit victim process may
10807c478bd9Sstevel@tonic-gate 		 * have exec'd a 64-bit process in the meantime.
10817c478bd9Sstevel@tonic-gate 		 */
10827c478bd9Sstevel@tonic-gate 		if (P->status.pr_dmodel == PR_MODEL_LP64) {
10837c478bd9Sstevel@tonic-gate 			rc = G_LP64;
10847c478bd9Sstevel@tonic-gate 			goto err;
10857c478bd9Sstevel@tonic-gate 		}
10867c478bd9Sstevel@tonic-gate #endif
10877c478bd9Sstevel@tonic-gate 	}
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 	/*
10907c478bd9Sstevel@tonic-gate 	 * Cancel all tracing flags unless the PGRAB_RETAIN flag is set.
10917c478bd9Sstevel@tonic-gate 	 */
10927c478bd9Sstevel@tonic-gate 	if (!(flags & PGRAB_RETAIN)) {
10937c478bd9Sstevel@tonic-gate 		(void) Psysentry(P, 0, FALSE);
10947c478bd9Sstevel@tonic-gate 		(void) Psysexit(P, 0, FALSE);
10957c478bd9Sstevel@tonic-gate 		(void) Psignal(P, 0, FALSE);
10967c478bd9Sstevel@tonic-gate 		(void) Pfault(P, 0, FALSE);
10977c478bd9Sstevel@tonic-gate 		Psync(P);
10987c478bd9Sstevel@tonic-gate 	}
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	*perr = 0;
11017c478bd9Sstevel@tonic-gate 	return (P);
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate err:
11047c478bd9Sstevel@tonic-gate 	Pfree(P);
11057c478bd9Sstevel@tonic-gate 	*perr = rc;
11067c478bd9Sstevel@tonic-gate 	return (NULL);
11077c478bd9Sstevel@tonic-gate }
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate /*
11107c478bd9Sstevel@tonic-gate  * Return a printable string corresponding to a Pgrab() error return.
11117c478bd9Sstevel@tonic-gate  */
11127c478bd9Sstevel@tonic-gate const char *
Pgrab_error(int error)11137c478bd9Sstevel@tonic-gate Pgrab_error(int error)
11147c478bd9Sstevel@tonic-gate {
11157c478bd9Sstevel@tonic-gate 	const char *str;
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 	switch (error) {
11187c478bd9Sstevel@tonic-gate 	case G_NOPROC:
11197c478bd9Sstevel@tonic-gate 		str = "no such process";
11207c478bd9Sstevel@tonic-gate 		break;
11217c478bd9Sstevel@tonic-gate 	case G_NOCORE:
11227c478bd9Sstevel@tonic-gate 		str = "no such core file";
11237c478bd9Sstevel@tonic-gate 		break;
11247c478bd9Sstevel@tonic-gate 	case G_NOPROCORCORE:
11257c478bd9Sstevel@tonic-gate 		str = "no such process or core file";
11267c478bd9Sstevel@tonic-gate 		break;
11277c478bd9Sstevel@tonic-gate 	case G_NOEXEC:
11287c478bd9Sstevel@tonic-gate 		str = "cannot find executable file";
11297c478bd9Sstevel@tonic-gate 		break;
11307c478bd9Sstevel@tonic-gate 	case G_ZOMB:
11317c478bd9Sstevel@tonic-gate 		str = "zombie process";
11327c478bd9Sstevel@tonic-gate 		break;
11337c478bd9Sstevel@tonic-gate 	case G_PERM:
11347c478bd9Sstevel@tonic-gate 		str = "permission denied";
11357c478bd9Sstevel@tonic-gate 		break;
11367c478bd9Sstevel@tonic-gate 	case G_BUSY:
11377c478bd9Sstevel@tonic-gate 		str = "process is traced";
11387c478bd9Sstevel@tonic-gate 		break;
11397c478bd9Sstevel@tonic-gate 	case G_SYS:
11407c478bd9Sstevel@tonic-gate 		str = "system process";
11417c478bd9Sstevel@tonic-gate 		break;
11427c478bd9Sstevel@tonic-gate 	case G_SELF:
11437c478bd9Sstevel@tonic-gate 		str = "attempt to grab self";
11447c478bd9Sstevel@tonic-gate 		break;
11457c478bd9Sstevel@tonic-gate 	case G_INTR:
11467c478bd9Sstevel@tonic-gate 		str = "operation interrupted";
11477c478bd9Sstevel@tonic-gate 		break;
11487c478bd9Sstevel@tonic-gate 	case G_LP64:
11497c478bd9Sstevel@tonic-gate 		str = "program is _LP64, self is not";
11507c478bd9Sstevel@tonic-gate 		break;
11517c478bd9Sstevel@tonic-gate 	case G_FORMAT:
11527c478bd9Sstevel@tonic-gate 		str = "file is not an ELF core file";
11537c478bd9Sstevel@tonic-gate 		break;
11547c478bd9Sstevel@tonic-gate 	case G_ELF:
11557c478bd9Sstevel@tonic-gate 		str = "libelf error";
11567c478bd9Sstevel@tonic-gate 		break;
11577c478bd9Sstevel@tonic-gate 	case G_NOTE:
11587c478bd9Sstevel@tonic-gate 		str = "core file is corrupt or missing required data";
11597c478bd9Sstevel@tonic-gate 		break;
11607c478bd9Sstevel@tonic-gate 	case G_STRANGE:
11617c478bd9Sstevel@tonic-gate 		str = "unanticipated system error";
11627c478bd9Sstevel@tonic-gate 		break;
11637c478bd9Sstevel@tonic-gate 	case G_ISAINVAL:
11647c478bd9Sstevel@tonic-gate 		str = "wrong ELF machine type";
11657c478bd9Sstevel@tonic-gate 		break;
11667c478bd9Sstevel@tonic-gate 	case G_BADLWPS:
11677c478bd9Sstevel@tonic-gate 		str = "bad lwp specification";
11687c478bd9Sstevel@tonic-gate 		break;
1169cd11e192Sjhaslam 	case G_NOFD:
1170cd11e192Sjhaslam 		str = "too many open files";
1171cd11e192Sjhaslam 		break;
11727c478bd9Sstevel@tonic-gate 	default:
11737c478bd9Sstevel@tonic-gate 		str = "unknown error";
11747c478bd9Sstevel@tonic-gate 		break;
11757c478bd9Sstevel@tonic-gate 	}
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 	return (str);
11787c478bd9Sstevel@tonic-gate }
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate /*
11817c478bd9Sstevel@tonic-gate  * Free a process control structure.
11827c478bd9Sstevel@tonic-gate  * Close the file descriptors but don't do the Prelease logic.
11837c478bd9Sstevel@tonic-gate  */
11847c478bd9Sstevel@tonic-gate void
Pfree(struct ps_prochandle * P)11857c478bd9Sstevel@tonic-gate Pfree(struct ps_prochandle *P)
11867c478bd9Sstevel@tonic-gate {
11877c478bd9Sstevel@tonic-gate 	uint_t i;
118850d4d24eSRobert Mustacchi 	fd_info_t *fip;
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 	if (P->ucaddrs != NULL) {
11917c478bd9Sstevel@tonic-gate 		free(P->ucaddrs);
11927c478bd9Sstevel@tonic-gate 		P->ucaddrs = NULL;
11937c478bd9Sstevel@tonic-gate 		P->ucnelems = 0;
11947c478bd9Sstevel@tonic-gate 	}
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&P->proc_lock);
11977c478bd9Sstevel@tonic-gate 	if (P->hashtab != NULL) {
11987c478bd9Sstevel@tonic-gate 		struct ps_lwphandle *L;
11997c478bd9Sstevel@tonic-gate 		for (i = 0; i < HASHSIZE; i++) {
12007c478bd9Sstevel@tonic-gate 			while ((L = P->hashtab[i]) != NULL)
12017c478bd9Sstevel@tonic-gate 				Lfree_internal(P, L);
12027c478bd9Sstevel@tonic-gate 		}
12037c478bd9Sstevel@tonic-gate 		free(P->hashtab);
12047c478bd9Sstevel@tonic-gate 	}
120534bdffbfSGarrett D'Amore 
120650d4d24eSRobert Mustacchi 	while ((fip = list_remove_head(&P->fd_head)) != NULL) {
1207a02120c4SAndy Fiddaman 		proc_fdinfo_free(fip->fd_info);
120834bdffbfSGarrett D'Amore 		free(fip);
120934bdffbfSGarrett D'Amore 	}
12107c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&P->proc_lock);
12117c478bd9Sstevel@tonic-gate 	(void) mutex_destroy(&P->proc_lock);
12127c478bd9Sstevel@tonic-gate 
1213998cfd7bSRobert Mustacchi 	free(P->zoneroot);
1214998cfd7bSRobert Mustacchi 
12157c478bd9Sstevel@tonic-gate 	if (P->agentctlfd >= 0)
12167c478bd9Sstevel@tonic-gate 		(void) close(P->agentctlfd);
12177c478bd9Sstevel@tonic-gate 	if (P->agentstatfd >= 0)
12187c478bd9Sstevel@tonic-gate 		(void) close(P->agentstatfd);
12197c478bd9Sstevel@tonic-gate 	if (P->ctlfd >= 0)
12207c478bd9Sstevel@tonic-gate 		(void) close(P->ctlfd);
12217c478bd9Sstevel@tonic-gate 	if (P->asfd >= 0)
12227c478bd9Sstevel@tonic-gate 		(void) close(P->asfd);
12237c478bd9Sstevel@tonic-gate 	if (P->statfd >= 0)
12247c478bd9Sstevel@tonic-gate 		(void) close(P->statfd);
12257c478bd9Sstevel@tonic-gate 	Preset_maps(P);
12262a12f85aSJeremy Jones 	P->ops.pop_fini(P, P->data);
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate 	/* clear out the structure as a precaution against reuse */
12297c478bd9Sstevel@tonic-gate 	(void) memset(P, 0, sizeof (*P));
12307c478bd9Sstevel@tonic-gate 	P->ctlfd = -1;
12317c478bd9Sstevel@tonic-gate 	P->asfd = -1;
12327c478bd9Sstevel@tonic-gate 	P->statfd = -1;
12337c478bd9Sstevel@tonic-gate 	P->agentctlfd = -1;
12347c478bd9Sstevel@tonic-gate 	P->agentstatfd = -1;
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 	free(P);
12377c478bd9Sstevel@tonic-gate }
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate /*
12407c478bd9Sstevel@tonic-gate  * Return the state of the process, one of the PS_* values.
12417c478bd9Sstevel@tonic-gate  */
12427c478bd9Sstevel@tonic-gate int
Pstate(struct ps_prochandle * P)12437c478bd9Sstevel@tonic-gate Pstate(struct ps_prochandle *P)
12447c478bd9Sstevel@tonic-gate {
12457c478bd9Sstevel@tonic-gate 	return (P->state);
12467c478bd9Sstevel@tonic-gate }
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate /*
12497c478bd9Sstevel@tonic-gate  * Return the open address space file descriptor for the process.
12507c478bd9Sstevel@tonic-gate  * Clients must not close this file descriptor, not use it
12517c478bd9Sstevel@tonic-gate  * after the process is freed.
12527c478bd9Sstevel@tonic-gate  */
12537c478bd9Sstevel@tonic-gate int
Pasfd(struct ps_prochandle * P)12547c478bd9Sstevel@tonic-gate Pasfd(struct ps_prochandle *P)
12557c478bd9Sstevel@tonic-gate {
12567c478bd9Sstevel@tonic-gate 	return (P->asfd);
12577c478bd9Sstevel@tonic-gate }
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate /*
12607c478bd9Sstevel@tonic-gate  * Return the open control file descriptor for the process.
12617c478bd9Sstevel@tonic-gate  * Clients must not close this file descriptor, not use it
12627c478bd9Sstevel@tonic-gate  * after the process is freed.
12637c478bd9Sstevel@tonic-gate  */
12647c478bd9Sstevel@tonic-gate int
Pctlfd(struct ps_prochandle * P)12657c478bd9Sstevel@tonic-gate Pctlfd(struct ps_prochandle *P)
12667c478bd9Sstevel@tonic-gate {
12677c478bd9Sstevel@tonic-gate 	return (P->ctlfd);
12687c478bd9Sstevel@tonic-gate }
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate /*
12717c478bd9Sstevel@tonic-gate  * Return a pointer to the process psinfo structure.
12727c478bd9Sstevel@tonic-gate  * Clients should not hold on to this pointer indefinitely.
12737c478bd9Sstevel@tonic-gate  * It will become invalid on Prelease().
12747c478bd9Sstevel@tonic-gate  */
12757c478bd9Sstevel@tonic-gate const psinfo_t *
Ppsinfo(struct ps_prochandle * P)12767c478bd9Sstevel@tonic-gate Ppsinfo(struct ps_prochandle *P)
12777c478bd9Sstevel@tonic-gate {
12782a12f85aSJeremy Jones 	return (P->ops.pop_psinfo(P, &P->psinfo, P->data));
12797c478bd9Sstevel@tonic-gate }
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate /*
12827c478bd9Sstevel@tonic-gate  * Return a pointer to the process status structure.
12837c478bd9Sstevel@tonic-gate  * Clients should not hold on to this pointer indefinitely.
12847c478bd9Sstevel@tonic-gate  * It will become invalid on Prelease().
12857c478bd9Sstevel@tonic-gate  */
12867c478bd9Sstevel@tonic-gate const pstatus_t *
Pstatus(struct ps_prochandle * P)12877c478bd9Sstevel@tonic-gate Pstatus(struct ps_prochandle *P)
12887c478bd9Sstevel@tonic-gate {
12897c478bd9Sstevel@tonic-gate 	return (&P->status);
12907c478bd9Sstevel@tonic-gate }
12917c478bd9Sstevel@tonic-gate 
12922a12f85aSJeremy Jones static void
Pread_status(struct ps_prochandle * P)12932a12f85aSJeremy Jones Pread_status(struct ps_prochandle *P)
12942a12f85aSJeremy Jones {
12952a12f85aSJeremy Jones 	P->ops.pop_status(P, &P->status, P->data);
12962a12f85aSJeremy Jones }
12972a12f85aSJeremy Jones 
12987c478bd9Sstevel@tonic-gate /*
12997c478bd9Sstevel@tonic-gate  * Fill in a pointer to a process credentials structure.  The ngroups parameter
13007c478bd9Sstevel@tonic-gate  * is the number of supplementary group entries allocated in the caller's cred
13017c478bd9Sstevel@tonic-gate  * structure.  It should equal zero or one unless extra space has been
13027c478bd9Sstevel@tonic-gate  * allocated for the group list by the caller.
13037c478bd9Sstevel@tonic-gate  */
13047c478bd9Sstevel@tonic-gate int
Pcred(struct ps_prochandle * P,prcred_t * pcrp,int ngroups)13057c478bd9Sstevel@tonic-gate Pcred(struct ps_prochandle *P, prcred_t *pcrp, int ngroups)
13067c478bd9Sstevel@tonic-gate {
13072a12f85aSJeremy Jones 	return (P->ops.pop_cred(P, pcrp, ngroups, P->data));
13082a12f85aSJeremy Jones }
13097c478bd9Sstevel@tonic-gate 
1310d2a70789SRichard Lowe /* Return an allocated prsecflags_t */
1311d2a70789SRichard Lowe int
Psecflags(struct ps_prochandle * P,prsecflags_t ** psf)1312d2a70789SRichard Lowe Psecflags(struct ps_prochandle *P, prsecflags_t **psf)
1313d2a70789SRichard Lowe {
1314d2a70789SRichard Lowe 	int ret;
1315d2a70789SRichard Lowe 
1316d2a70789SRichard Lowe 	if ((ret = P->ops.pop_secflags(P, psf, P->data)) == 0) {
1317d2a70789SRichard Lowe 		if ((*psf)->pr_version != PRSECFLAGS_VERSION_1) {
1318350ffdd5SRobert Mustacchi 			free(*psf);
1319350ffdd5SRobert Mustacchi 			*psf = NULL;
1320d2a70789SRichard Lowe 			errno = EINVAL;
1321d2a70789SRichard Lowe 			return (-1);
1322d2a70789SRichard Lowe 		}
1323d2a70789SRichard Lowe 	}
1324d2a70789SRichard Lowe 
1325d2a70789SRichard Lowe 	return (ret);
1326d2a70789SRichard Lowe }
1327d2a70789SRichard Lowe 
1328d2a70789SRichard Lowe void
Psecflags_free(prsecflags_t * psf)1329d2a70789SRichard Lowe Psecflags_free(prsecflags_t *psf)
1330d2a70789SRichard Lowe {
1331d2a70789SRichard Lowe 	free(psf);
1332d2a70789SRichard Lowe }
1333d2a70789SRichard Lowe 
13342a12f85aSJeremy Jones static prheader_t *
Plstatus(struct ps_prochandle * P)13352a12f85aSJeremy Jones Plstatus(struct ps_prochandle *P)
13362a12f85aSJeremy Jones {
13372a12f85aSJeremy Jones 	return (P->ops.pop_lstatus(P, P->data));
13382a12f85aSJeremy Jones }
13397c478bd9Sstevel@tonic-gate 
13402a12f85aSJeremy Jones static prheader_t *
Plpsinfo(struct ps_prochandle * P)13412a12f85aSJeremy Jones Plpsinfo(struct ps_prochandle *P)
13422a12f85aSJeremy Jones {
13432a12f85aSJeremy Jones 	return (P->ops.pop_lpsinfo(P, P->data));
13447c478bd9Sstevel@tonic-gate }
13457c478bd9Sstevel@tonic-gate 
13462a12f85aSJeremy Jones 
13477c478bd9Sstevel@tonic-gate #if defined(__i386) || defined(__amd64)
13487c478bd9Sstevel@tonic-gate /*
13497c478bd9Sstevel@tonic-gate  * Fill in a pointer to a process LDT structure.
13507c478bd9Sstevel@tonic-gate  * The caller provides a buffer of size 'nldt * sizeof (struct ssd)';
13517c478bd9Sstevel@tonic-gate  * If pldt == NULL or nldt == 0, we return the number of existing LDT entries.
13527c478bd9Sstevel@tonic-gate  * Otherwise we return the actual number of LDT entries fetched (<= nldt).
13537c478bd9Sstevel@tonic-gate  */
13547c478bd9Sstevel@tonic-gate int
Pldt(struct ps_prochandle * P,struct ssd * pldt,int nldt)13557c478bd9Sstevel@tonic-gate Pldt(struct ps_prochandle *P, struct ssd *pldt, int nldt)
13567c478bd9Sstevel@tonic-gate {
13572a12f85aSJeremy Jones 	return (P->ops.pop_ldt(P, pldt, nldt, P->data));
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate }
13607c478bd9Sstevel@tonic-gate #endif	/* __i386 */
13617c478bd9Sstevel@tonic-gate 
136243051d27SRobert Mustacchi /* ARGSUSED */
136343051d27SRobert Mustacchi void
Ppriv_free(struct ps_prochandle * P,prpriv_t * prv)136443051d27SRobert Mustacchi Ppriv_free(struct ps_prochandle *P, prpriv_t *prv)
136543051d27SRobert Mustacchi {
136643051d27SRobert Mustacchi 	free(prv);
136743051d27SRobert Mustacchi }
136843051d27SRobert Mustacchi 
13697c478bd9Sstevel@tonic-gate /*
13702a12f85aSJeremy Jones  * Return a malloced process privilege structure in *pprv.
13717c478bd9Sstevel@tonic-gate  */
13722a12f85aSJeremy Jones int
Ppriv(struct ps_prochandle * P,prpriv_t ** pprv)13732a12f85aSJeremy Jones Ppriv(struct ps_prochandle *P, prpriv_t **pprv)
13742a12f85aSJeremy Jones {
13752a12f85aSJeremy Jones 	return (P->ops.pop_priv(P, pprv, P->data));
13767c478bd9Sstevel@tonic-gate }
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate int
Psetpriv(struct ps_prochandle * P,prpriv_t * pprv)13797c478bd9Sstevel@tonic-gate Psetpriv(struct ps_prochandle *P, prpriv_t *pprv)
13807c478bd9Sstevel@tonic-gate {
13817c478bd9Sstevel@tonic-gate 	int rc;
13827c478bd9Sstevel@tonic-gate 	long *ctl;
13837c478bd9Sstevel@tonic-gate 	size_t sz;
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 	if (P->state == PS_DEAD) {
13867c478bd9Sstevel@tonic-gate 		errno = EBADF;
13877c478bd9Sstevel@tonic-gate 		return (-1);
13887c478bd9Sstevel@tonic-gate 	}
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 	sz = PRIV_PRPRIV_SIZE(pprv) + sizeof (long);
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 	sz = ((sz - 1) / sizeof (long) + 1) * sizeof (long);
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate 	ctl = malloc(sz);
13957c478bd9Sstevel@tonic-gate 	if (ctl == NULL)
13967c478bd9Sstevel@tonic-gate 		return (-1);
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 	ctl[0] = PCSPRIV;
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate 	(void) memcpy(&ctl[1], pprv, PRIV_PRPRIV_SIZE(pprv));
14017c478bd9Sstevel@tonic-gate 
14027c478bd9Sstevel@tonic-gate 	if (write(P->ctlfd, ctl, sz) != sz)
14037c478bd9Sstevel@tonic-gate 		rc = -1;
14047c478bd9Sstevel@tonic-gate 	else
14057c478bd9Sstevel@tonic-gate 		rc = 0;
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 	free(ctl);
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate 	return (rc);
14107c478bd9Sstevel@tonic-gate }
14117c478bd9Sstevel@tonic-gate 
14127c478bd9Sstevel@tonic-gate void *
Pprivinfo(struct ps_prochandle * P)14137c478bd9Sstevel@tonic-gate Pprivinfo(struct ps_prochandle *P)
14147c478bd9Sstevel@tonic-gate {
14152a12f85aSJeremy Jones 	core_info_t *core = P->data;
14162a12f85aSJeremy Jones 
14177c478bd9Sstevel@tonic-gate 	/* Use default from libc */
14187c478bd9Sstevel@tonic-gate 	if (P->state != PS_DEAD)
14197c478bd9Sstevel@tonic-gate 		return (NULL);
14207c478bd9Sstevel@tonic-gate 
14212a12f85aSJeremy Jones 	return (core->core_privinfo);
14227c478bd9Sstevel@tonic-gate }
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate /*
14257c478bd9Sstevel@tonic-gate  * Ensure that all cached state is written to the process.
14267c478bd9Sstevel@tonic-gate  * The cached state is the LWP's signal mask and registers
14277c478bd9Sstevel@tonic-gate  * and the process's tracing flags.
14287c478bd9Sstevel@tonic-gate  */
14297c478bd9Sstevel@tonic-gate void
Psync(struct ps_prochandle * P)14307c478bd9Sstevel@tonic-gate Psync(struct ps_prochandle *P)
14317c478bd9Sstevel@tonic-gate {
14327c478bd9Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
14337c478bd9Sstevel@tonic-gate 	long cmd[6];
14347c478bd9Sstevel@tonic-gate 	iovec_t iov[12];
14357c478bd9Sstevel@tonic-gate 	int n = 0;
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 	if (P->flags & SETHOLD) {
14387c478bd9Sstevel@tonic-gate 		cmd[0] = PCSHOLD;
14397c478bd9Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[0];
14407c478bd9Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
14417c478bd9Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&P->status.pr_lwp.pr_lwphold;
14427c478bd9Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (P->status.pr_lwp.pr_lwphold);
14437c478bd9Sstevel@tonic-gate 	}
14447c478bd9Sstevel@tonic-gate 	if (P->flags & SETREGS) {
14457c478bd9Sstevel@tonic-gate 		cmd[1] = PCSREG;
14467c478bd9Sstevel@tonic-gate #ifdef __i386
14477c478bd9Sstevel@tonic-gate 		/* XX64 we should probably restore REG_GS after this */
14487c478bd9Sstevel@tonic-gate 		if (ctlfd == P->agentctlfd)
14497c478bd9Sstevel@tonic-gate 			P->status.pr_lwp.pr_reg[GS] = 0;
14507c478bd9Sstevel@tonic-gate #elif defined(__amd64)
14517c478bd9Sstevel@tonic-gate 		/* XX64 */
14527c478bd9Sstevel@tonic-gate #endif
14537c478bd9Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[1];
14547c478bd9Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
14557c478bd9Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&P->status.pr_lwp.pr_reg[0];
14567c478bd9Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (P->status.pr_lwp.pr_reg);
14577c478bd9Sstevel@tonic-gate 	}
14587c478bd9Sstevel@tonic-gate 	if (P->flags & SETSIG) {
14597c478bd9Sstevel@tonic-gate 		cmd[2] = PCSTRACE;
14607c478bd9Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[2];
14617c478bd9Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
14627c478bd9Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&P->status.pr_sigtrace;
14637c478bd9Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (P->status.pr_sigtrace);
14647c478bd9Sstevel@tonic-gate 	}
14657c478bd9Sstevel@tonic-gate 	if (P->flags & SETFAULT) {
14667c478bd9Sstevel@tonic-gate 		cmd[3] = PCSFAULT;
14677c478bd9Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[3];
14687c478bd9Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
14697c478bd9Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&P->status.pr_flttrace;
14707c478bd9Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (P->status.pr_flttrace);
14717c478bd9Sstevel@tonic-gate 	}
14727c478bd9Sstevel@tonic-gate 	if (P->flags & SETENTRY) {
14737c478bd9Sstevel@tonic-gate 		cmd[4] = PCSENTRY;
14747c478bd9Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[4];
14757c478bd9Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
14767c478bd9Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&P->status.pr_sysentry;
14777c478bd9Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (P->status.pr_sysentry);
14787c478bd9Sstevel@tonic-gate 	}
14797c478bd9Sstevel@tonic-gate 	if (P->flags & SETEXIT) {
14807c478bd9Sstevel@tonic-gate 		cmd[5] = PCSEXIT;
14817c478bd9Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[5];
14827c478bd9Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
14837c478bd9Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&P->status.pr_sysexit;
14847c478bd9Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (P->status.pr_sysexit);
14857c478bd9Sstevel@tonic-gate 	}
14867c478bd9Sstevel@tonic-gate 
14877c478bd9Sstevel@tonic-gate 	if (n == 0 || writev(ctlfd, iov, n) < 0)
14887c478bd9Sstevel@tonic-gate 		return;		/* nothing to do or write failed */
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate 	P->flags &= ~(SETSIG|SETFAULT|SETENTRY|SETEXIT|SETHOLD|SETREGS);
14917c478bd9Sstevel@tonic-gate }
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate /*
14947c478bd9Sstevel@tonic-gate  * Reopen the /proc file (after PS_LOST).
14957c478bd9Sstevel@tonic-gate  */
14967c478bd9Sstevel@tonic-gate int
Preopen(struct ps_prochandle * P)14977c478bd9Sstevel@tonic-gate Preopen(struct ps_prochandle *P)
14987c478bd9Sstevel@tonic-gate {
14997c478bd9Sstevel@tonic-gate 	int fd;
15009acbbeafSnn 	char procname[PATH_MAX];
15017c478bd9Sstevel@tonic-gate 	char *fname;
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_IDLE)
15047c478bd9Sstevel@tonic-gate 		return (0);
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate 	if (P->agentcnt > 0) {
15077c478bd9Sstevel@tonic-gate 		P->agentcnt = 1;
15087c478bd9Sstevel@tonic-gate 		Pdestroy_agent(P);
15097c478bd9Sstevel@tonic-gate 	}
15107c478bd9Sstevel@tonic-gate 
15119acbbeafSnn 	(void) snprintf(procname, sizeof (procname), "%s/%d/",
15129acbbeafSnn 	    procfs_path, (int)P->pid);
15137c478bd9Sstevel@tonic-gate 	fname = procname + strlen(procname);
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 	(void) strcpy(fname, "as");
15167c478bd9Sstevel@tonic-gate 	if ((fd = open(procname, O_RDWR)) < 0 ||
15177c478bd9Sstevel@tonic-gate 	    close(P->asfd) < 0 ||
15187c478bd9Sstevel@tonic-gate 	    (fd = dupfd(fd, P->asfd)) != P->asfd) {
15197c478bd9Sstevel@tonic-gate 		dprintf("Preopen: failed to open %s: %s\n",
15207c478bd9Sstevel@tonic-gate 		    procname, strerror(errno));
15217c478bd9Sstevel@tonic-gate 		if (fd >= 0)
15227c478bd9Sstevel@tonic-gate 			(void) close(fd);
15237c478bd9Sstevel@tonic-gate 		return (-1);
15247c478bd9Sstevel@tonic-gate 	}
15257c478bd9Sstevel@tonic-gate 	P->asfd = fd;
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate 	(void) strcpy(fname, "status");
15287c478bd9Sstevel@tonic-gate 	if ((fd = open(procname, O_RDONLY)) < 0 ||
15297c478bd9Sstevel@tonic-gate 	    close(P->statfd) < 0 ||
15307c478bd9Sstevel@tonic-gate 	    (fd = dupfd(fd, P->statfd)) != P->statfd) {
15317c478bd9Sstevel@tonic-gate 		dprintf("Preopen: failed to open %s: %s\n",
15327c478bd9Sstevel@tonic-gate 		    procname, strerror(errno));
15337c478bd9Sstevel@tonic-gate 		if (fd >= 0)
15347c478bd9Sstevel@tonic-gate 			(void) close(fd);
15357c478bd9Sstevel@tonic-gate 		return (-1);
15367c478bd9Sstevel@tonic-gate 	}
15377c478bd9Sstevel@tonic-gate 	P->statfd = fd;
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 	(void) strcpy(fname, "ctl");
15407c478bd9Sstevel@tonic-gate 	if ((fd = open(procname, O_WRONLY)) < 0 ||
15417c478bd9Sstevel@tonic-gate 	    close(P->ctlfd) < 0 ||
15427c478bd9Sstevel@tonic-gate 	    (fd = dupfd(fd, P->ctlfd)) != P->ctlfd) {
15437c478bd9Sstevel@tonic-gate 		dprintf("Preopen: failed to open %s: %s\n",
15447c478bd9Sstevel@tonic-gate 		    procname, strerror(errno));
15457c478bd9Sstevel@tonic-gate 		if (fd >= 0)
15467c478bd9Sstevel@tonic-gate 			(void) close(fd);
15477c478bd9Sstevel@tonic-gate 		return (-1);
15487c478bd9Sstevel@tonic-gate 	}
15497c478bd9Sstevel@tonic-gate 	P->ctlfd = fd;
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate 	/*
15527c478bd9Sstevel@tonic-gate 	 * Set the state to PS_RUN and wait for the process to stop so that
15537c478bd9Sstevel@tonic-gate 	 * we re-read the status from the new P->statfd.  If this fails, Pwait
15547c478bd9Sstevel@tonic-gate 	 * will reset the state to PS_LOST and we fail the reopen.  Before
15557c478bd9Sstevel@tonic-gate 	 * returning, we also forge a bit of P->status to allow the debugger to
15567c478bd9Sstevel@tonic-gate 	 * see that we are PS_LOST following a successful exec.
15577c478bd9Sstevel@tonic-gate 	 */
15587c478bd9Sstevel@tonic-gate 	P->state = PS_RUN;
15597c478bd9Sstevel@tonic-gate 	if (Pwait(P, 0) == -1) {
15607c478bd9Sstevel@tonic-gate #ifdef _ILP32
15617c478bd9Sstevel@tonic-gate 		if (errno == EOVERFLOW)
15627c478bd9Sstevel@tonic-gate 			P->status.pr_dmodel = PR_MODEL_LP64;
15637c478bd9Sstevel@tonic-gate #endif
15647c478bd9Sstevel@tonic-gate 		P->status.pr_lwp.pr_why = PR_SYSEXIT;
15657c478bd9Sstevel@tonic-gate 		P->status.pr_lwp.pr_what = SYS_execve;
15667c478bd9Sstevel@tonic-gate 		P->status.pr_lwp.pr_errno = 0;
15677c478bd9Sstevel@tonic-gate 		return (-1);
15687c478bd9Sstevel@tonic-gate 	}
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 	/*
15717c478bd9Sstevel@tonic-gate 	 * The process should be stopped on exec (REQUESTED)
15727c478bd9Sstevel@tonic-gate 	 * or else should be stopped on exit from exec() (SYSEXIT)
15737c478bd9Sstevel@tonic-gate 	 */
15747c478bd9Sstevel@tonic-gate 	if (P->state == PS_STOP &&
15757c478bd9Sstevel@tonic-gate 	    (P->status.pr_lwp.pr_why == PR_REQUESTED ||
15767c478bd9Sstevel@tonic-gate 	    (P->status.pr_lwp.pr_why == PR_SYSEXIT &&
15778fd04b83SRoger A. Faulkner 	    P->status.pr_lwp.pr_what == SYS_execve))) {
15787c478bd9Sstevel@tonic-gate 		/* fake up stop-on-exit-from-execve */
15797c478bd9Sstevel@tonic-gate 		if (P->status.pr_lwp.pr_why == PR_REQUESTED) {
15807c478bd9Sstevel@tonic-gate 			P->status.pr_lwp.pr_why = PR_SYSEXIT;
15817c478bd9Sstevel@tonic-gate 			P->status.pr_lwp.pr_what = SYS_execve;
15827c478bd9Sstevel@tonic-gate 			P->status.pr_lwp.pr_errno = 0;
15837c478bd9Sstevel@tonic-gate 		}
15847c478bd9Sstevel@tonic-gate 	} else {
15857c478bd9Sstevel@tonic-gate 		dprintf("Preopen: expected REQUESTED or "
15867c478bd9Sstevel@tonic-gate 		    "SYSEXIT(SYS_execve) stop\n");
15877c478bd9Sstevel@tonic-gate 	}
15887c478bd9Sstevel@tonic-gate 
15897c478bd9Sstevel@tonic-gate 	return (0);
15907c478bd9Sstevel@tonic-gate }
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate /*
15937c478bd9Sstevel@tonic-gate  * Define all settable flags other than the microstate accounting flags.
15947c478bd9Sstevel@tonic-gate  */
15957c478bd9Sstevel@tonic-gate #define	ALL_SETTABLE_FLAGS (PR_FORK|PR_RLC|PR_KLC|PR_ASYNC|PR_BPTADJ|PR_PTRACE)
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate /*
15987c478bd9Sstevel@tonic-gate  * Restore /proc tracing flags to their original values
15997c478bd9Sstevel@tonic-gate  * in preparation for releasing the process.
16007c478bd9Sstevel@tonic-gate  * Also called by Pcreate() to clear all tracing flags.
16017c478bd9Sstevel@tonic-gate  */
16027c478bd9Sstevel@tonic-gate static void
restore_tracing_flags(struct ps_prochandle * P)16037c478bd9Sstevel@tonic-gate restore_tracing_flags(struct ps_prochandle *P)
16047c478bd9Sstevel@tonic-gate {
16057c478bd9Sstevel@tonic-gate 	long flags;
16067c478bd9Sstevel@tonic-gate 	long cmd[4];
16077c478bd9Sstevel@tonic-gate 	iovec_t iov[8];
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 	if (P->flags & CREATED) {
16107c478bd9Sstevel@tonic-gate 		/* we created this process; clear all tracing flags */
16117c478bd9Sstevel@tonic-gate 		premptyset(&P->status.pr_sigtrace);
16127c478bd9Sstevel@tonic-gate 		premptyset(&P->status.pr_flttrace);
16137c478bd9Sstevel@tonic-gate 		premptyset(&P->status.pr_sysentry);
16147c478bd9Sstevel@tonic-gate 		premptyset(&P->status.pr_sysexit);
16157c478bd9Sstevel@tonic-gate 		if ((P->status.pr_flags & ALL_SETTABLE_FLAGS) != 0)
16167c478bd9Sstevel@tonic-gate 			(void) Punsetflags(P, ALL_SETTABLE_FLAGS);
16177c478bd9Sstevel@tonic-gate 	} else {
16187c478bd9Sstevel@tonic-gate 		/* we grabbed the process; restore its tracing flags */
16197c478bd9Sstevel@tonic-gate 		P->status.pr_sigtrace = P->orig_status.pr_sigtrace;
16207c478bd9Sstevel@tonic-gate 		P->status.pr_flttrace = P->orig_status.pr_flttrace;
16217c478bd9Sstevel@tonic-gate 		P->status.pr_sysentry = P->orig_status.pr_sysentry;
16227c478bd9Sstevel@tonic-gate 		P->status.pr_sysexit  = P->orig_status.pr_sysexit;
16237c478bd9Sstevel@tonic-gate 		if ((P->status.pr_flags & ALL_SETTABLE_FLAGS) !=
16247c478bd9Sstevel@tonic-gate 		    (flags = (P->orig_status.pr_flags & ALL_SETTABLE_FLAGS))) {
16257c478bd9Sstevel@tonic-gate 			(void) Punsetflags(P, ALL_SETTABLE_FLAGS);
16267c478bd9Sstevel@tonic-gate 			if (flags)
16277c478bd9Sstevel@tonic-gate 				(void) Psetflags(P, flags);
16287c478bd9Sstevel@tonic-gate 		}
16297c478bd9Sstevel@tonic-gate 	}
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 	cmd[0] = PCSTRACE;
16327c478bd9Sstevel@tonic-gate 	iov[0].iov_base = (caddr_t)&cmd[0];
16337c478bd9Sstevel@tonic-gate 	iov[0].iov_len = sizeof (long);
16347c478bd9Sstevel@tonic-gate 	iov[1].iov_base = (caddr_t)&P->status.pr_sigtrace;
16357c478bd9Sstevel@tonic-gate 	iov[1].iov_len = sizeof (P->status.pr_sigtrace);
16367c478bd9Sstevel@tonic-gate 
16377c478bd9Sstevel@tonic-gate 	cmd[1] = PCSFAULT;
16387c478bd9Sstevel@tonic-gate 	iov[2].iov_base = (caddr_t)&cmd[1];
16397c478bd9Sstevel@tonic-gate 	iov[2].iov_len = sizeof (long);
16407c478bd9Sstevel@tonic-gate 	iov[3].iov_base = (caddr_t)&P->status.pr_flttrace;
16417c478bd9Sstevel@tonic-gate 	iov[3].iov_len = sizeof (P->status.pr_flttrace);
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 	cmd[2] = PCSENTRY;
16447c478bd9Sstevel@tonic-gate 	iov[4].iov_base = (caddr_t)&cmd[2];
16457c478bd9Sstevel@tonic-gate 	iov[4].iov_len = sizeof (long);
16467c478bd9Sstevel@tonic-gate 	iov[5].iov_base = (caddr_t)&P->status.pr_sysentry;
16477c478bd9Sstevel@tonic-gate 	iov[5].iov_len = sizeof (P->status.pr_sysentry);
16487c478bd9Sstevel@tonic-gate 
16497c478bd9Sstevel@tonic-gate 	cmd[3] = PCSEXIT;
16507c478bd9Sstevel@tonic-gate 	iov[6].iov_base = (caddr_t)&cmd[3];
16517c478bd9Sstevel@tonic-gate 	iov[6].iov_len = sizeof (long);
16527c478bd9Sstevel@tonic-gate 	iov[7].iov_base = (caddr_t)&P->status.pr_sysexit;
16537c478bd9Sstevel@tonic-gate 	iov[7].iov_len = sizeof (P->status.pr_sysexit);
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 	(void) writev(P->ctlfd, iov, 8);
16567c478bd9Sstevel@tonic-gate 
16577c478bd9Sstevel@tonic-gate 	P->flags &= ~(SETSIG|SETFAULT|SETENTRY|SETEXIT);
16587c478bd9Sstevel@tonic-gate }
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate /*
16617c478bd9Sstevel@tonic-gate  * Release the process.  Frees the process control structure.
16627c478bd9Sstevel@tonic-gate  * flags:
16637c478bd9Sstevel@tonic-gate  *	PRELEASE_CLEAR	Clear all tracing flags.
16647c478bd9Sstevel@tonic-gate  *	PRELEASE_RETAIN	Retain current tracing flags.
16657c478bd9Sstevel@tonic-gate  *	PRELEASE_HANG	Leave the process stopped and abandoned.
16667c478bd9Sstevel@tonic-gate  *	PRELEASE_KILL	Terminate the process with SIGKILL.
16677c478bd9Sstevel@tonic-gate  */
16687c478bd9Sstevel@tonic-gate void
Prelease(struct ps_prochandle * P,int flags)16697c478bd9Sstevel@tonic-gate Prelease(struct ps_prochandle *P, int flags)
16707c478bd9Sstevel@tonic-gate {
16717c478bd9Sstevel@tonic-gate 	if (P->state == PS_DEAD) {
16727c478bd9Sstevel@tonic-gate 		dprintf("Prelease: releasing handle %p PS_DEAD of pid %d\n",
16737c478bd9Sstevel@tonic-gate 		    (void *)P, (int)P->pid);
16747c478bd9Sstevel@tonic-gate 		Pfree(P);
16757c478bd9Sstevel@tonic-gate 		return;
16767c478bd9Sstevel@tonic-gate 	}
16777c478bd9Sstevel@tonic-gate 
16787c478bd9Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
167950d4d24eSRobert Mustacchi 		file_info_t *fptr = list_head(&P->file_head);
16807c478bd9Sstevel@tonic-gate 		dprintf("Prelease: releasing handle %p PS_IDLE of file %s\n",
16817c478bd9Sstevel@tonic-gate 		    (void *)P, fptr->file_pname);
16827c478bd9Sstevel@tonic-gate 		Pfree(P);
16837c478bd9Sstevel@tonic-gate 		return;
16847c478bd9Sstevel@tonic-gate 	}
16857c478bd9Sstevel@tonic-gate 
16867c478bd9Sstevel@tonic-gate 	dprintf("Prelease: releasing handle %p pid %d\n",
16877c478bd9Sstevel@tonic-gate 	    (void *)P, (int)P->pid);
16887c478bd9Sstevel@tonic-gate 
16897c478bd9Sstevel@tonic-gate 	if (P->ctlfd == -1) {
16907c478bd9Sstevel@tonic-gate 		Pfree(P);
16917c478bd9Sstevel@tonic-gate 		return;
16927c478bd9Sstevel@tonic-gate 	}
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 	if (P->agentcnt > 0) {
16957c478bd9Sstevel@tonic-gate 		P->agentcnt = 1;
16967c478bd9Sstevel@tonic-gate 		Pdestroy_agent(P);
16977c478bd9Sstevel@tonic-gate 	}
16987c478bd9Sstevel@tonic-gate 
16997c478bd9Sstevel@tonic-gate 	/*
17007c478bd9Sstevel@tonic-gate 	 * Attempt to stop the process.
17017c478bd9Sstevel@tonic-gate 	 */
17027c478bd9Sstevel@tonic-gate 	P->state = PS_RUN;
17037c478bd9Sstevel@tonic-gate 	(void) Pstop(P, 1000);
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 	if (flags & PRELEASE_KILL) {
17067c478bd9Sstevel@tonic-gate 		if (P->state == PS_STOP)
17077c478bd9Sstevel@tonic-gate 			(void) Psetrun(P, SIGKILL, 0);
17087c478bd9Sstevel@tonic-gate 		(void) kill(P->pid, SIGKILL);
17097c478bd9Sstevel@tonic-gate 		Pfree(P);
17107c478bd9Sstevel@tonic-gate 		return;
17117c478bd9Sstevel@tonic-gate 	}
17127c478bd9Sstevel@tonic-gate 
17137c478bd9Sstevel@tonic-gate 	/*
17147c478bd9Sstevel@tonic-gate 	 * If we lost control, all we can do now is close the files.
17157c478bd9Sstevel@tonic-gate 	 * In this case, the last close sets the process running.
17167c478bd9Sstevel@tonic-gate 	 */
17177c478bd9Sstevel@tonic-gate 	if (P->state != PS_STOP &&
17187c478bd9Sstevel@tonic-gate 	    (P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)) == 0) {
17197c478bd9Sstevel@tonic-gate 		Pfree(P);
17207c478bd9Sstevel@tonic-gate 		return;
17217c478bd9Sstevel@tonic-gate 	}
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate 	/*
17247c478bd9Sstevel@tonic-gate 	 * We didn't lose control; we do more.
17257c478bd9Sstevel@tonic-gate 	 */
17267c478bd9Sstevel@tonic-gate 	Psync(P);
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 	if (flags & PRELEASE_CLEAR)
17297c478bd9Sstevel@tonic-gate 		P->flags |= CREATED;
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate 	if (!(flags & PRELEASE_RETAIN))
17327c478bd9Sstevel@tonic-gate 		restore_tracing_flags(P);
17337c478bd9Sstevel@tonic-gate 
17347c478bd9Sstevel@tonic-gate 	if (flags & PRELEASE_HANG) {
17357c478bd9Sstevel@tonic-gate 		/* Leave the process stopped and abandoned */
17367c478bd9Sstevel@tonic-gate 		(void) Punsetflags(P, PR_RLC|PR_KLC);
17377c478bd9Sstevel@tonic-gate 		Pfree(P);
17387c478bd9Sstevel@tonic-gate 		return;
17397c478bd9Sstevel@tonic-gate 	}
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate 	/*
17427c478bd9Sstevel@tonic-gate 	 * Set the process running if we created it or if it was
17437c478bd9Sstevel@tonic-gate 	 * not originally stopped or directed to stop via /proc
17447c478bd9Sstevel@tonic-gate 	 * or if we were given the PRELEASE_CLEAR flag.
17457c478bd9Sstevel@tonic-gate 	 */
17467c478bd9Sstevel@tonic-gate 	if ((P->flags & CREATED) ||
17477c478bd9Sstevel@tonic-gate 	    (P->orig_status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)) == 0) {
17487c478bd9Sstevel@tonic-gate 		(void) Psetflags(P, PR_RLC);
17497c478bd9Sstevel@tonic-gate 		/*
17507c478bd9Sstevel@tonic-gate 		 * We do this repeatedly because the process may have
17517c478bd9Sstevel@tonic-gate 		 * more than one LWP stopped on an event of interest.
17527c478bd9Sstevel@tonic-gate 		 * This makes sure all of them are set running.
17537c478bd9Sstevel@tonic-gate 		 */
17547c478bd9Sstevel@tonic-gate 		do {
17557c478bd9Sstevel@tonic-gate 			if (Psetrun(P, 0, 0) == -1 && errno == EBUSY)
17567c478bd9Sstevel@tonic-gate 				break; /* Agent LWP may be stuck */
17577c478bd9Sstevel@tonic-gate 		} while (Pstopstatus(P, PCNULL, 0) == 0 &&
17587c478bd9Sstevel@tonic-gate 		    P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP));
17597c478bd9Sstevel@tonic-gate 
17607c478bd9Sstevel@tonic-gate 		if (P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP))
17617c478bd9Sstevel@tonic-gate 			dprintf("Prelease: failed to set process running\n");
17627c478bd9Sstevel@tonic-gate 	}
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate 	Pfree(P);
17657c478bd9Sstevel@tonic-gate }
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate /* debugging */
17687c478bd9Sstevel@tonic-gate void
prldump(const char * caller,lwpstatus_t * lsp)17697c478bd9Sstevel@tonic-gate prldump(const char *caller, lwpstatus_t *lsp)
17707c478bd9Sstevel@tonic-gate {
17717c478bd9Sstevel@tonic-gate 	char name[32];
17727c478bd9Sstevel@tonic-gate 	uint32_t bits;
17737c478bd9Sstevel@tonic-gate 
17747c478bd9Sstevel@tonic-gate 	switch (lsp->pr_why) {
17757c478bd9Sstevel@tonic-gate 	case PR_REQUESTED:
17767c478bd9Sstevel@tonic-gate 		dprintf("%s: REQUESTED\n", caller);
17777c478bd9Sstevel@tonic-gate 		break;
17787c478bd9Sstevel@tonic-gate 	case PR_SIGNALLED:
17797c478bd9Sstevel@tonic-gate 		dprintf("%s: SIGNALLED %s\n", caller,
1780d7755b5aSrh 		    proc_signame(lsp->pr_what, name, sizeof (name)));
17817c478bd9Sstevel@tonic-gate 		break;
17827c478bd9Sstevel@tonic-gate 	case PR_FAULTED:
17837c478bd9Sstevel@tonic-gate 		dprintf("%s: FAULTED %s\n", caller,
1784d7755b5aSrh 		    proc_fltname(lsp->pr_what, name, sizeof (name)));
17857c478bd9Sstevel@tonic-gate 		break;
17867c478bd9Sstevel@tonic-gate 	case PR_SYSENTRY:
17877c478bd9Sstevel@tonic-gate 		dprintf("%s: SYSENTRY %s\n", caller,
1788d7755b5aSrh 		    proc_sysname(lsp->pr_what, name, sizeof (name)));
17897c478bd9Sstevel@tonic-gate 		break;
17907c478bd9Sstevel@tonic-gate 	case PR_SYSEXIT:
17917c478bd9Sstevel@tonic-gate 		dprintf("%s: SYSEXIT %s\n", caller,
1792d7755b5aSrh 		    proc_sysname(lsp->pr_what, name, sizeof (name)));
17937c478bd9Sstevel@tonic-gate 		break;
17947c478bd9Sstevel@tonic-gate 	case PR_JOBCONTROL:
17957c478bd9Sstevel@tonic-gate 		dprintf("%s: JOBCONTROL %s\n", caller,
1796d7755b5aSrh 		    proc_signame(lsp->pr_what, name, sizeof (name)));
17977c478bd9Sstevel@tonic-gate 		break;
17987c478bd9Sstevel@tonic-gate 	case PR_SUSPENDED:
17997c478bd9Sstevel@tonic-gate 		dprintf("%s: SUSPENDED\n", caller);
18007c478bd9Sstevel@tonic-gate 		break;
18017c478bd9Sstevel@tonic-gate 	default:
18027c478bd9Sstevel@tonic-gate 		dprintf("%s: Unknown\n", caller);
18037c478bd9Sstevel@tonic-gate 		break;
18047c478bd9Sstevel@tonic-gate 	}
18057c478bd9Sstevel@tonic-gate 
18067c478bd9Sstevel@tonic-gate 	if (lsp->pr_cursig)
18077c478bd9Sstevel@tonic-gate 		dprintf("%s: p_cursig  = %d\n", caller, lsp->pr_cursig);
18087c478bd9Sstevel@tonic-gate 
18097c478bd9Sstevel@tonic-gate 	bits = *((uint32_t *)&lsp->pr_lwppend);
18107c478bd9Sstevel@tonic-gate 	if (bits)
18117c478bd9Sstevel@tonic-gate 		dprintf("%s: pr_lwppend = 0x%.8X\n", caller, bits);
18127c478bd9Sstevel@tonic-gate }
18137c478bd9Sstevel@tonic-gate 
18147c478bd9Sstevel@tonic-gate /* debugging */
18157c478bd9Sstevel@tonic-gate static void
prdump(struct ps_prochandle * P)18167c478bd9Sstevel@tonic-gate prdump(struct ps_prochandle *P)
18177c478bd9Sstevel@tonic-gate {
18187c478bd9Sstevel@tonic-gate 	uint32_t bits;
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate 	prldump("Pstopstatus", &P->status.pr_lwp);
18217c478bd9Sstevel@tonic-gate 
18227c478bd9Sstevel@tonic-gate 	bits = *((uint32_t *)&P->status.pr_sigpend);
18237c478bd9Sstevel@tonic-gate 	if (bits)
18247c478bd9Sstevel@tonic-gate 		dprintf("Pstopstatus: pr_sigpend = 0x%.8X\n", bits);
18257c478bd9Sstevel@tonic-gate }
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate /*
18287c478bd9Sstevel@tonic-gate  * Wait for the specified process to stop or terminate.
18297c478bd9Sstevel@tonic-gate  * Or, just get the current status (PCNULL).
18307c478bd9Sstevel@tonic-gate  * Or, direct it to stop and get the current status (PCDSTOP).
18317c478bd9Sstevel@tonic-gate  * If the agent LWP exists, do these things to the agent,
18327c478bd9Sstevel@tonic-gate  * else do these things to the process as a whole.
18337c478bd9Sstevel@tonic-gate  */
18347c478bd9Sstevel@tonic-gate int
Pstopstatus(struct ps_prochandle * P,long request,uint_t msec)18357c478bd9Sstevel@tonic-gate Pstopstatus(struct ps_prochandle *P,
1836d2a70789SRichard Lowe     long request,		/* PCNULL, PCDSTOP, PCSTOP, PCWSTOP */
1837d2a70789SRichard Lowe     uint_t msec)		/* if non-zero, timeout in milliseconds */
18387c478bd9Sstevel@tonic-gate {
18397c478bd9Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
18407c478bd9Sstevel@tonic-gate 	long ctl[3];
18417c478bd9Sstevel@tonic-gate 	ssize_t rc;
18427c478bd9Sstevel@tonic-gate 	int err;
18437c478bd9Sstevel@tonic-gate 	int old_state = P->state;
18447c478bd9Sstevel@tonic-gate 
18457c478bd9Sstevel@tonic-gate 	switch (P->state) {
18467c478bd9Sstevel@tonic-gate 	case PS_RUN:
18477c478bd9Sstevel@tonic-gate 		break;
18487c478bd9Sstevel@tonic-gate 	case PS_STOP:
18497c478bd9Sstevel@tonic-gate 		if (request != PCNULL && request != PCDSTOP)
18507c478bd9Sstevel@tonic-gate 			return (0);
18517c478bd9Sstevel@tonic-gate 		break;
18527c478bd9Sstevel@tonic-gate 	case PS_LOST:
18537c478bd9Sstevel@tonic-gate 		if (request != PCNULL) {
18547c478bd9Sstevel@tonic-gate 			errno = EAGAIN;
18557c478bd9Sstevel@tonic-gate 			return (-1);
18567c478bd9Sstevel@tonic-gate 		}
18577c478bd9Sstevel@tonic-gate 		break;
18587c478bd9Sstevel@tonic-gate 	case PS_UNDEAD:
18597c478bd9Sstevel@tonic-gate 	case PS_DEAD:
18607c478bd9Sstevel@tonic-gate 	case PS_IDLE:
18617c478bd9Sstevel@tonic-gate 		if (request != PCNULL) {
18627c478bd9Sstevel@tonic-gate 			errno = ENOENT;
18637c478bd9Sstevel@tonic-gate 			return (-1);
18647c478bd9Sstevel@tonic-gate 		}
18657c478bd9Sstevel@tonic-gate 		break;
18667c478bd9Sstevel@tonic-gate 	default:	/* corrupted state */
18677c478bd9Sstevel@tonic-gate 		dprintf("Pstopstatus: corrupted state: %d\n", P->state);
18687c478bd9Sstevel@tonic-gate 		errno = EINVAL;
18697c478bd9Sstevel@tonic-gate 		return (-1);
18707c478bd9Sstevel@tonic-gate 	}
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate 	ctl[0] = PCDSTOP;
18737c478bd9Sstevel@tonic-gate 	ctl[1] = PCTWSTOP;
18747c478bd9Sstevel@tonic-gate 	ctl[2] = (long)msec;
18757c478bd9Sstevel@tonic-gate 	rc = 0;
18767c478bd9Sstevel@tonic-gate 	switch (request) {
18777c478bd9Sstevel@tonic-gate 	case PCSTOP:
18787c478bd9Sstevel@tonic-gate 		rc = write(ctlfd, &ctl[0], 3*sizeof (long));
18797c478bd9Sstevel@tonic-gate 		break;
18807c478bd9Sstevel@tonic-gate 	case PCWSTOP:
18817c478bd9Sstevel@tonic-gate 		rc = write(ctlfd, &ctl[1], 2*sizeof (long));
18827c478bd9Sstevel@tonic-gate 		break;
18837c478bd9Sstevel@tonic-gate 	case PCDSTOP:
18847c478bd9Sstevel@tonic-gate 		rc = write(ctlfd, &ctl[0], 1*sizeof (long));
18857c478bd9Sstevel@tonic-gate 		break;
18867c478bd9Sstevel@tonic-gate 	case PCNULL:
18877c478bd9Sstevel@tonic-gate 		if (P->state == PS_DEAD || P->state == PS_IDLE)
18887c478bd9Sstevel@tonic-gate 			return (0);
18897c478bd9Sstevel@tonic-gate 		break;
18907c478bd9Sstevel@tonic-gate 	default:	/* programming error */
18917c478bd9Sstevel@tonic-gate 		errno = EINVAL;
18927c478bd9Sstevel@tonic-gate 		return (-1);
18937c478bd9Sstevel@tonic-gate 	}
18947c478bd9Sstevel@tonic-gate 	err = (rc < 0)? errno : 0;
18957c478bd9Sstevel@tonic-gate 	Psync(P);
18967c478bd9Sstevel@tonic-gate 
18977c478bd9Sstevel@tonic-gate 	if (P->agentstatfd < 0) {
18987c478bd9Sstevel@tonic-gate 		if (pread(P->statfd, &P->status,
18997c478bd9Sstevel@tonic-gate 		    sizeof (P->status), (off_t)0) < 0)
19007c478bd9Sstevel@tonic-gate 			err = errno;
19017c478bd9Sstevel@tonic-gate 	} else {
19027c478bd9Sstevel@tonic-gate 		if (pread(P->agentstatfd, &P->status.pr_lwp,
19037c478bd9Sstevel@tonic-gate 		    sizeof (P->status.pr_lwp), (off_t)0) < 0)
19047c478bd9Sstevel@tonic-gate 			err = errno;
19057c478bd9Sstevel@tonic-gate 		P->status.pr_flags = P->status.pr_lwp.pr_flags;
19067c478bd9Sstevel@tonic-gate 	}
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 	if (err) {
19097c478bd9Sstevel@tonic-gate 		switch (err) {
19107c478bd9Sstevel@tonic-gate 		case EINTR:		/* user typed ctl-C */
19117c478bd9Sstevel@tonic-gate 		case ERESTART:
19127c478bd9Sstevel@tonic-gate 			dprintf("Pstopstatus: EINTR\n");
19137c478bd9Sstevel@tonic-gate 			break;
19147c478bd9Sstevel@tonic-gate 		case EAGAIN:		/* we lost control of the the process */
19157c478bd9Sstevel@tonic-gate 		case EOVERFLOW:
19167c478bd9Sstevel@tonic-gate 			dprintf("Pstopstatus: PS_LOST, errno=%d\n", err);
19177c478bd9Sstevel@tonic-gate 			P->state = PS_LOST;
19187c478bd9Sstevel@tonic-gate 			break;
19197c478bd9Sstevel@tonic-gate 		default:		/* check for dead process */
19207c478bd9Sstevel@tonic-gate 			if (_libproc_debug) {
19217c478bd9Sstevel@tonic-gate 				const char *errstr;
19227c478bd9Sstevel@tonic-gate 
19237c478bd9Sstevel@tonic-gate 				switch (request) {
19247c478bd9Sstevel@tonic-gate 				case PCNULL:
19257c478bd9Sstevel@tonic-gate 					errstr = "Pstopstatus PCNULL"; break;
19267c478bd9Sstevel@tonic-gate 				case PCSTOP:
19277c478bd9Sstevel@tonic-gate 					errstr = "Pstopstatus PCSTOP"; break;
19287c478bd9Sstevel@tonic-gate 				case PCDSTOP:
19297c478bd9Sstevel@tonic-gate 					errstr = "Pstopstatus PCDSTOP"; break;
19307c478bd9Sstevel@tonic-gate 				case PCWSTOP:
19317c478bd9Sstevel@tonic-gate 					errstr = "Pstopstatus PCWSTOP"; break;
19327c478bd9Sstevel@tonic-gate 				default:
19337c478bd9Sstevel@tonic-gate 					errstr = "Pstopstatus PC???"; break;
19347c478bd9Sstevel@tonic-gate 				}
19357c478bd9Sstevel@tonic-gate 				dprintf("%s: %s\n", errstr, strerror(err));
19367c478bd9Sstevel@tonic-gate 			}
19377c478bd9Sstevel@tonic-gate 			deadcheck(P);
19387c478bd9Sstevel@tonic-gate 			break;
19397c478bd9Sstevel@tonic-gate 		}
19407c478bd9Sstevel@tonic-gate 		if (err != EINTR && err != ERESTART) {
19417c478bd9Sstevel@tonic-gate 			errno = err;
19427c478bd9Sstevel@tonic-gate 			return (-1);
19437c478bd9Sstevel@tonic-gate 		}
19447c478bd9Sstevel@tonic-gate 	}
19457c478bd9Sstevel@tonic-gate 
19467c478bd9Sstevel@tonic-gate 	if (!(P->status.pr_flags & PR_STOPPED)) {
19477c478bd9Sstevel@tonic-gate 		P->state = PS_RUN;
19487c478bd9Sstevel@tonic-gate 		if (request == PCNULL || request == PCDSTOP || msec != 0)
19497c478bd9Sstevel@tonic-gate 			return (0);
19507c478bd9Sstevel@tonic-gate 		dprintf("Pstopstatus: process is not stopped\n");
19517c478bd9Sstevel@tonic-gate 		errno = EPROTO;
19527c478bd9Sstevel@tonic-gate 		return (-1);
19537c478bd9Sstevel@tonic-gate 	}
19547c478bd9Sstevel@tonic-gate 
19557c478bd9Sstevel@tonic-gate 	P->state = PS_STOP;
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate 	if (_libproc_debug)	/* debugging */
19587c478bd9Sstevel@tonic-gate 		prdump(P);
19597c478bd9Sstevel@tonic-gate 
19607c478bd9Sstevel@tonic-gate 	/*
19617c478bd9Sstevel@tonic-gate 	 * If the process was already stopped coming into Pstopstatus(),
19627c478bd9Sstevel@tonic-gate 	 * then don't use its PC to set P->sysaddr since it may have been
19637c478bd9Sstevel@tonic-gate 	 * changed since the time the process originally stopped.
19647c478bd9Sstevel@tonic-gate 	 */
19657c478bd9Sstevel@tonic-gate 	if (old_state == PS_STOP)
19667c478bd9Sstevel@tonic-gate 		return (0);
19677c478bd9Sstevel@tonic-gate 
19687c478bd9Sstevel@tonic-gate 	switch (P->status.pr_lwp.pr_why) {
19697c478bd9Sstevel@tonic-gate 	case PR_SYSENTRY:
19707c478bd9Sstevel@tonic-gate 	case PR_SYSEXIT:
19717c478bd9Sstevel@tonic-gate 		if (Pissyscall_prev(P, P->status.pr_lwp.pr_reg[R_PC],
19727c478bd9Sstevel@tonic-gate 		    &P->sysaddr) == 0)
19737c478bd9Sstevel@tonic-gate 			P->sysaddr = P->status.pr_lwp.pr_reg[R_PC];
19747c478bd9Sstevel@tonic-gate 		break;
19757c478bd9Sstevel@tonic-gate 	case PR_REQUESTED:
19767c478bd9Sstevel@tonic-gate 	case PR_SIGNALLED:
19777c478bd9Sstevel@tonic-gate 	case PR_FAULTED:
19787c478bd9Sstevel@tonic-gate 	case PR_JOBCONTROL:
19797c478bd9Sstevel@tonic-gate 	case PR_SUSPENDED:
19807c478bd9Sstevel@tonic-gate 		break;
19817c478bd9Sstevel@tonic-gate 	default:
19827c478bd9Sstevel@tonic-gate 		errno = EPROTO;
19837c478bd9Sstevel@tonic-gate 		return (-1);
19847c478bd9Sstevel@tonic-gate 	}
19857c478bd9Sstevel@tonic-gate 
19867c478bd9Sstevel@tonic-gate 	return (0);
19877c478bd9Sstevel@tonic-gate }
19887c478bd9Sstevel@tonic-gate 
19897c478bd9Sstevel@tonic-gate /*
19907c478bd9Sstevel@tonic-gate  * Wait for the process to stop for any reason.
19917c478bd9Sstevel@tonic-gate  */
19927c478bd9Sstevel@tonic-gate int
Pwait(struct ps_prochandle * P,uint_t msec)19937c478bd9Sstevel@tonic-gate Pwait(struct ps_prochandle *P, uint_t msec)
19947c478bd9Sstevel@tonic-gate {
19957c478bd9Sstevel@tonic-gate 	return (Pstopstatus(P, PCWSTOP, msec));
19967c478bd9Sstevel@tonic-gate }
19977c478bd9Sstevel@tonic-gate 
19987c478bd9Sstevel@tonic-gate /*
19997c478bd9Sstevel@tonic-gate  * Direct the process to stop; wait for it to stop.
20007c478bd9Sstevel@tonic-gate  */
20017c478bd9Sstevel@tonic-gate int
Pstop(struct ps_prochandle * P,uint_t msec)20027c478bd9Sstevel@tonic-gate Pstop(struct ps_prochandle *P, uint_t msec)
20037c478bd9Sstevel@tonic-gate {
20047c478bd9Sstevel@tonic-gate 	return (Pstopstatus(P, PCSTOP, msec));
20057c478bd9Sstevel@tonic-gate }
20067c478bd9Sstevel@tonic-gate 
20077c478bd9Sstevel@tonic-gate /*
20087c478bd9Sstevel@tonic-gate  * Direct the process to stop; don't wait.
20097c478bd9Sstevel@tonic-gate  */
20107c478bd9Sstevel@tonic-gate int
Pdstop(struct ps_prochandle * P)20117c478bd9Sstevel@tonic-gate Pdstop(struct ps_prochandle *P)
20127c478bd9Sstevel@tonic-gate {
20137c478bd9Sstevel@tonic-gate 	return (Pstopstatus(P, PCDSTOP, 0));
20147c478bd9Sstevel@tonic-gate }
20157c478bd9Sstevel@tonic-gate 
20167c478bd9Sstevel@tonic-gate static void
deadcheck(struct ps_prochandle * P)20177c478bd9Sstevel@tonic-gate deadcheck(struct ps_prochandle *P)
20187c478bd9Sstevel@tonic-gate {
20197c478bd9Sstevel@tonic-gate 	int fd;
20207c478bd9Sstevel@tonic-gate 	void *buf;
20217c478bd9Sstevel@tonic-gate 	size_t size;
20227c478bd9Sstevel@tonic-gate 
20237c478bd9Sstevel@tonic-gate 	if (P->statfd < 0)
20247c478bd9Sstevel@tonic-gate 		P->state = PS_UNDEAD;
20257c478bd9Sstevel@tonic-gate 	else {
20267c478bd9Sstevel@tonic-gate 		if (P->agentstatfd < 0) {
20277c478bd9Sstevel@tonic-gate 			fd = P->statfd;
20287c478bd9Sstevel@tonic-gate 			buf = &P->status;
20297c478bd9Sstevel@tonic-gate 			size = sizeof (P->status);
20307c478bd9Sstevel@tonic-gate 		} else {
20317c478bd9Sstevel@tonic-gate 			fd = P->agentstatfd;
20327c478bd9Sstevel@tonic-gate 			buf = &P->status.pr_lwp;
20337c478bd9Sstevel@tonic-gate 			size = sizeof (P->status.pr_lwp);
20347c478bd9Sstevel@tonic-gate 		}
20357c478bd9Sstevel@tonic-gate 		while (pread(fd, buf, size, (off_t)0) != size) {
20367c478bd9Sstevel@tonic-gate 			switch (errno) {
20377c478bd9Sstevel@tonic-gate 			default:
20387c478bd9Sstevel@tonic-gate 				P->state = PS_UNDEAD;
20397c478bd9Sstevel@tonic-gate 				break;
20407c478bd9Sstevel@tonic-gate 			case EINTR:
20417c478bd9Sstevel@tonic-gate 			case ERESTART:
20427c478bd9Sstevel@tonic-gate 				continue;
20437c478bd9Sstevel@tonic-gate 			case EAGAIN:
20447c478bd9Sstevel@tonic-gate 				P->state = PS_LOST;
20457c478bd9Sstevel@tonic-gate 				break;
20467c478bd9Sstevel@tonic-gate 			}
20477c478bd9Sstevel@tonic-gate 			break;
20487c478bd9Sstevel@tonic-gate 		}
20497c478bd9Sstevel@tonic-gate 		P->status.pr_flags = P->status.pr_lwp.pr_flags;
20507c478bd9Sstevel@tonic-gate 	}
20517c478bd9Sstevel@tonic-gate }
20527c478bd9Sstevel@tonic-gate 
20537c478bd9Sstevel@tonic-gate /*
20547c478bd9Sstevel@tonic-gate  * Get the value of one register from stopped process.
20557c478bd9Sstevel@tonic-gate  */
20567c478bd9Sstevel@tonic-gate int
Pgetareg(struct ps_prochandle * P,int regno,prgreg_t * preg)20577c478bd9Sstevel@tonic-gate Pgetareg(struct ps_prochandle *P, int regno, prgreg_t *preg)
20587c478bd9Sstevel@tonic-gate {
20597c478bd9Sstevel@tonic-gate 	if (regno < 0 || regno >= NPRGREG) {
20607c478bd9Sstevel@tonic-gate 		errno = EINVAL;
20617c478bd9Sstevel@tonic-gate 		return (-1);
20627c478bd9Sstevel@tonic-gate 	}
20637c478bd9Sstevel@tonic-gate 
20647c478bd9Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
20657c478bd9Sstevel@tonic-gate 		errno = ENODATA;
20667c478bd9Sstevel@tonic-gate 		return (-1);
20677c478bd9Sstevel@tonic-gate 	}
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 	if (P->state != PS_STOP && P->state != PS_DEAD) {
20707c478bd9Sstevel@tonic-gate 		errno = EBUSY;
20717c478bd9Sstevel@tonic-gate 		return (-1);
20727c478bd9Sstevel@tonic-gate 	}
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate 	*preg = P->status.pr_lwp.pr_reg[regno];
20757c478bd9Sstevel@tonic-gate 	return (0);
20767c478bd9Sstevel@tonic-gate }
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate /*
20797c478bd9Sstevel@tonic-gate  * Put value of one register into stopped process.
20807c478bd9Sstevel@tonic-gate  */
20817c478bd9Sstevel@tonic-gate int
Pputareg(struct ps_prochandle * P,int regno,prgreg_t reg)20827c478bd9Sstevel@tonic-gate Pputareg(struct ps_prochandle *P, int regno, prgreg_t reg)
20837c478bd9Sstevel@tonic-gate {
20847c478bd9Sstevel@tonic-gate 	if (regno < 0 || regno >= NPRGREG) {
20857c478bd9Sstevel@tonic-gate 		errno = EINVAL;
20867c478bd9Sstevel@tonic-gate 		return (-1);
20877c478bd9Sstevel@tonic-gate 	}
20887c478bd9Sstevel@tonic-gate 
20897c478bd9Sstevel@tonic-gate 	if (P->state != PS_STOP) {
20907c478bd9Sstevel@tonic-gate 		errno = EBUSY;
20917c478bd9Sstevel@tonic-gate 		return (-1);
20927c478bd9Sstevel@tonic-gate 	}
20937c478bd9Sstevel@tonic-gate 
20947c478bd9Sstevel@tonic-gate 	P->status.pr_lwp.pr_reg[regno] = reg;
20957c478bd9Sstevel@tonic-gate 	P->flags |= SETREGS;	/* set registers before continuing */
20967c478bd9Sstevel@tonic-gate 	return (0);
20977c478bd9Sstevel@tonic-gate }
20987c478bd9Sstevel@tonic-gate 
20997c478bd9Sstevel@tonic-gate int
Psetrun(struct ps_prochandle * P,int sig,int flags)21007c478bd9Sstevel@tonic-gate Psetrun(struct ps_prochandle *P,
2101d2a70789SRichard Lowe     int sig,	/* signal to pass to process */
2102d2a70789SRichard Lowe     int flags)	/* PRSTEP|PRSABORT|PRSTOP|PRCSIG|PRCFAULT */
21037c478bd9Sstevel@tonic-gate {
21047c478bd9Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0) ? P->agentctlfd : P->ctlfd;
21057c478bd9Sstevel@tonic-gate 	int sbits = (PR_DSTOP | PR_ISTOP | PR_ASLEEP);
21067c478bd9Sstevel@tonic-gate 
21077c478bd9Sstevel@tonic-gate 	long ctl[1 +					/* PCCFAULT	*/
2108d7755b5aSrh 	    1 + sizeof (siginfo_t)/sizeof (long) +	/* PCSSIG/PCCSIG */
2109d7755b5aSrh 	    2 ];					/* PCRUN	*/
21107c478bd9Sstevel@tonic-gate 
21117c478bd9Sstevel@tonic-gate 	long *ctlp = ctl;
21127c478bd9Sstevel@tonic-gate 	size_t size;
21137c478bd9Sstevel@tonic-gate 
21147c478bd9Sstevel@tonic-gate 	if (P->state != PS_STOP && (P->status.pr_lwp.pr_flags & sbits) == 0) {
21157c478bd9Sstevel@tonic-gate 		errno = EBUSY;
21167c478bd9Sstevel@tonic-gate 		return (-1);
21177c478bd9Sstevel@tonic-gate 	}
21187c478bd9Sstevel@tonic-gate 
21197c478bd9Sstevel@tonic-gate 	Psync(P);	/* flush tracing flags and registers */
21207c478bd9Sstevel@tonic-gate 
21217c478bd9Sstevel@tonic-gate 	if (flags & PRCFAULT) {		/* clear current fault */
21227c478bd9Sstevel@tonic-gate 		*ctlp++ = PCCFAULT;
21237c478bd9Sstevel@tonic-gate 		flags &= ~PRCFAULT;
21247c478bd9Sstevel@tonic-gate 	}
21257c478bd9Sstevel@tonic-gate 
21267c478bd9Sstevel@tonic-gate 	if (flags & PRCSIG) {		/* clear current signal */
21277c478bd9Sstevel@tonic-gate 		*ctlp++ = PCCSIG;
21287c478bd9Sstevel@tonic-gate 		flags &= ~PRCSIG;
21297c478bd9Sstevel@tonic-gate 	} else if (sig && sig != P->status.pr_lwp.pr_cursig) {
21307c478bd9Sstevel@tonic-gate 		/* make current signal */
21317c478bd9Sstevel@tonic-gate 		siginfo_t *infop;
21327c478bd9Sstevel@tonic-gate 
21337c478bd9Sstevel@tonic-gate 		*ctlp++ = PCSSIG;
21347c478bd9Sstevel@tonic-gate 		infop = (siginfo_t *)ctlp;
21357c478bd9Sstevel@tonic-gate 		(void) memset(infop, 0, sizeof (*infop));
21367c478bd9Sstevel@tonic-gate 		infop->si_signo = sig;
21377c478bd9Sstevel@tonic-gate 		ctlp += sizeof (siginfo_t) / sizeof (long);
21387c478bd9Sstevel@tonic-gate 	}
21397c478bd9Sstevel@tonic-gate 
21407c478bd9Sstevel@tonic-gate 	*ctlp++ = PCRUN;
21417c478bd9Sstevel@tonic-gate 	*ctlp++ = flags;
21427c478bd9Sstevel@tonic-gate 	size = (char *)ctlp - (char *)ctl;
21437c478bd9Sstevel@tonic-gate 
21447c478bd9Sstevel@tonic-gate 	P->info_valid = 0;	/* will need to update map and file info */
21457c478bd9Sstevel@tonic-gate 
21467c478bd9Sstevel@tonic-gate 	/*
21477c478bd9Sstevel@tonic-gate 	 * If we've cached ucontext-list information while we were stopped,
21487c478bd9Sstevel@tonic-gate 	 * free it now.
21497c478bd9Sstevel@tonic-gate 	 */
21507c478bd9Sstevel@tonic-gate 	if (P->ucaddrs != NULL) {
21517c478bd9Sstevel@tonic-gate 		free(P->ucaddrs);
21527c478bd9Sstevel@tonic-gate 		P->ucaddrs = NULL;
21537c478bd9Sstevel@tonic-gate 		P->ucnelems = 0;
21547c478bd9Sstevel@tonic-gate 	}
21557c478bd9Sstevel@tonic-gate 
21567c478bd9Sstevel@tonic-gate 	if (write(ctlfd, ctl, size) != size) {
21577c478bd9Sstevel@tonic-gate 		/* If it is dead or lost, return the real status, not PS_RUN */
21587c478bd9Sstevel@tonic-gate 		if (errno == ENOENT || errno == EAGAIN) {
21597c478bd9Sstevel@tonic-gate 			(void) Pstopstatus(P, PCNULL, 0);
21607c478bd9Sstevel@tonic-gate 			return (0);
21617c478bd9Sstevel@tonic-gate 		}
21627c478bd9Sstevel@tonic-gate 		/* If it is not in a jobcontrol stop, issue an error message */
21637c478bd9Sstevel@tonic-gate 		if (errno != EBUSY ||
21647c478bd9Sstevel@tonic-gate 		    P->status.pr_lwp.pr_why != PR_JOBCONTROL) {
21657c478bd9Sstevel@tonic-gate 			dprintf("Psetrun: %s\n", strerror(errno));
21667c478bd9Sstevel@tonic-gate 			return (-1);
21677c478bd9Sstevel@tonic-gate 		}
21687c478bd9Sstevel@tonic-gate 		/* Otherwise pretend that the job-stopped process is running */
21697c478bd9Sstevel@tonic-gate 	}
21707c478bd9Sstevel@tonic-gate 
21717c478bd9Sstevel@tonic-gate 	P->state = PS_RUN;
21727c478bd9Sstevel@tonic-gate 	return (0);
21737c478bd9Sstevel@tonic-gate }
21747c478bd9Sstevel@tonic-gate 
21757c478bd9Sstevel@tonic-gate ssize_t
Pread(struct ps_prochandle * P,void * buf,size_t nbyte,uintptr_t address)21767c478bd9Sstevel@tonic-gate Pread(struct ps_prochandle *P,
2177d2a70789SRichard Lowe     void *buf,		/* caller's buffer */
2178d2a70789SRichard Lowe     size_t nbyte,	/* number of bytes to read */
2179d2a70789SRichard Lowe     uintptr_t address)	/* address in process */
21807c478bd9Sstevel@tonic-gate {
21812a12f85aSJeremy Jones 	return (P->ops.pop_pread(P, buf, nbyte, address, P->data));
21827c478bd9Sstevel@tonic-gate }
21837c478bd9Sstevel@tonic-gate 
21847c478bd9Sstevel@tonic-gate ssize_t
Pread_string(struct ps_prochandle * P,char * buf,size_t size,uintptr_t addr)21857c478bd9Sstevel@tonic-gate Pread_string(struct ps_prochandle *P,
2186d2a70789SRichard Lowe     char *buf,			/* caller's buffer */
2187d2a70789SRichard Lowe     size_t size,		/* upper limit on bytes to read */
2188d2a70789SRichard Lowe     uintptr_t addr)		/* address in process */
21897c478bd9Sstevel@tonic-gate {
21907c478bd9Sstevel@tonic-gate 	enum { STRSZ = 40 };
21917c478bd9Sstevel@tonic-gate 	char string[STRSZ + 1];
21927c478bd9Sstevel@tonic-gate 	ssize_t leng = 0;
21937c478bd9Sstevel@tonic-gate 	int nbyte;
21947c478bd9Sstevel@tonic-gate 
21957c478bd9Sstevel@tonic-gate 	if (size < 2) {
21967c478bd9Sstevel@tonic-gate 		errno = EINVAL;
21977c478bd9Sstevel@tonic-gate 		return (-1);
21987c478bd9Sstevel@tonic-gate 	}
21997c478bd9Sstevel@tonic-gate 
22007c478bd9Sstevel@tonic-gate 	size--;			/* ensure trailing null fits in buffer */
22017c478bd9Sstevel@tonic-gate 
22027c478bd9Sstevel@tonic-gate 	*buf = '\0';
22037c478bd9Sstevel@tonic-gate 	string[STRSZ] = '\0';
22047c478bd9Sstevel@tonic-gate 
22057c478bd9Sstevel@tonic-gate 	for (nbyte = STRSZ; nbyte == STRSZ && leng < size; addr += STRSZ) {
22062a12f85aSJeremy Jones 		if ((nbyte = P->ops.pop_pread(P, string, STRSZ, addr,
22072a12f85aSJeremy Jones 		    P->data)) <= 0) {
22087c478bd9Sstevel@tonic-gate 			buf[leng] = '\0';
22097c478bd9Sstevel@tonic-gate 			return (leng ? leng : -1);
22107c478bd9Sstevel@tonic-gate 		}
22117c478bd9Sstevel@tonic-gate 		if ((nbyte = strlen(string)) > 0) {
22127c478bd9Sstevel@tonic-gate 			if (leng + nbyte > size)
22137c478bd9Sstevel@tonic-gate 				nbyte = size - leng;
22147c478bd9Sstevel@tonic-gate 			(void) strncpy(buf + leng, string, nbyte);
22157c478bd9Sstevel@tonic-gate 			leng += nbyte;
22167c478bd9Sstevel@tonic-gate 		}
22177c478bd9Sstevel@tonic-gate 	}
22187c478bd9Sstevel@tonic-gate 	buf[leng] = '\0';
22197c478bd9Sstevel@tonic-gate 	return (leng);
22207c478bd9Sstevel@tonic-gate }
22217c478bd9Sstevel@tonic-gate 
22227c478bd9Sstevel@tonic-gate ssize_t
Pwrite(struct ps_prochandle * P,const void * buf,size_t nbyte,uintptr_t address)22237c478bd9Sstevel@tonic-gate Pwrite(struct ps_prochandle *P,
2224d2a70789SRichard Lowe     const void *buf,	/* caller's buffer */
2225d2a70789SRichard Lowe     size_t nbyte,	/* number of bytes to write */
2226d2a70789SRichard Lowe     uintptr_t address)	/* address in process */
22277c478bd9Sstevel@tonic-gate {
22282a12f85aSJeremy Jones 	return (P->ops.pop_pwrite(P, buf, nbyte, address, P->data));
22297c478bd9Sstevel@tonic-gate }
22307c478bd9Sstevel@tonic-gate 
22317c478bd9Sstevel@tonic-gate int
Pclearsig(struct ps_prochandle * P)22327c478bd9Sstevel@tonic-gate Pclearsig(struct ps_prochandle *P)
22337c478bd9Sstevel@tonic-gate {
22347c478bd9Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
22357c478bd9Sstevel@tonic-gate 	long ctl = PCCSIG;
22367c478bd9Sstevel@tonic-gate 
22377c478bd9Sstevel@tonic-gate 	if (write(ctlfd, &ctl, sizeof (ctl)) != sizeof (ctl))
22387c478bd9Sstevel@tonic-gate 		return (-1);
22397c478bd9Sstevel@tonic-gate 	P->status.pr_lwp.pr_cursig = 0;
22407c478bd9Sstevel@tonic-gate 	return (0);
22417c478bd9Sstevel@tonic-gate }
22427c478bd9Sstevel@tonic-gate 
22437c478bd9Sstevel@tonic-gate int
Pclearfault(struct ps_prochandle * P)22447c478bd9Sstevel@tonic-gate Pclearfault(struct ps_prochandle *P)
22457c478bd9Sstevel@tonic-gate {
22467c478bd9Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
22477c478bd9Sstevel@tonic-gate 	long ctl = PCCFAULT;
22487c478bd9Sstevel@tonic-gate 
22497c478bd9Sstevel@tonic-gate 	if (write(ctlfd, &ctl, sizeof (ctl)) != sizeof (ctl))
22507c478bd9Sstevel@tonic-gate 		return (-1);
22517c478bd9Sstevel@tonic-gate 	return (0);
22527c478bd9Sstevel@tonic-gate }
22537c478bd9Sstevel@tonic-gate 
22547c478bd9Sstevel@tonic-gate /*
22557c478bd9Sstevel@tonic-gate  * Set a breakpoint trap, return original instruction.
22567c478bd9Sstevel@tonic-gate  */
22577c478bd9Sstevel@tonic-gate int
Psetbkpt(struct ps_prochandle * P,uintptr_t address,ulong_t * saved)22587c478bd9Sstevel@tonic-gate Psetbkpt(struct ps_prochandle *P, uintptr_t address, ulong_t *saved)
22597c478bd9Sstevel@tonic-gate {
22607c478bd9Sstevel@tonic-gate 	long ctl[1 + sizeof (priovec_t) / sizeof (long) +	/* PCREAD */
2261d7755b5aSrh 	    1 + sizeof (priovec_t) / sizeof (long)];	/* PCWRITE */
22627c478bd9Sstevel@tonic-gate 	long *ctlp = ctl;
22637c478bd9Sstevel@tonic-gate 	size_t size;
22647c478bd9Sstevel@tonic-gate 	priovec_t *iovp;
22657c478bd9Sstevel@tonic-gate 	instr_t bpt = BPT;
22667c478bd9Sstevel@tonic-gate 	instr_t old;
22677c478bd9Sstevel@tonic-gate 
22687c478bd9Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
22697c478bd9Sstevel@tonic-gate 	    P->state == PS_IDLE) {
22707c478bd9Sstevel@tonic-gate 		errno = ENOENT;
22717c478bd9Sstevel@tonic-gate 		return (-1);
22727c478bd9Sstevel@tonic-gate 	}
22737c478bd9Sstevel@tonic-gate 
22747c478bd9Sstevel@tonic-gate 	/* fetch the old instruction */
22757c478bd9Sstevel@tonic-gate 	*ctlp++ = PCREAD;
22767c478bd9Sstevel@tonic-gate 	iovp = (priovec_t *)ctlp;
22777c478bd9Sstevel@tonic-gate 	iovp->pio_base = &old;
22787c478bd9Sstevel@tonic-gate 	iovp->pio_len = sizeof (old);
22797c478bd9Sstevel@tonic-gate 	iovp->pio_offset = address;
22807c478bd9Sstevel@tonic-gate 	ctlp += sizeof (priovec_t) / sizeof (long);
22817c478bd9Sstevel@tonic-gate 
22827c478bd9Sstevel@tonic-gate 	/* write the BPT instruction */
22837c478bd9Sstevel@tonic-gate 	*ctlp++ = PCWRITE;
22847c478bd9Sstevel@tonic-gate 	iovp = (priovec_t *)ctlp;
22857c478bd9Sstevel@tonic-gate 	iovp->pio_base = &bpt;
22867c478bd9Sstevel@tonic-gate 	iovp->pio_len = sizeof (bpt);
22877c478bd9Sstevel@tonic-gate 	iovp->pio_offset = address;
22887c478bd9Sstevel@tonic-gate 	ctlp += sizeof (priovec_t) / sizeof (long);
22897c478bd9Sstevel@tonic-gate 
22907c478bd9Sstevel@tonic-gate 	size = (char *)ctlp - (char *)ctl;
22917c478bd9Sstevel@tonic-gate 	if (write(P->ctlfd, ctl, size) != size)
22927c478bd9Sstevel@tonic-gate 		return (-1);
22937c478bd9Sstevel@tonic-gate 
22947c478bd9Sstevel@tonic-gate 	/*
22957c478bd9Sstevel@tonic-gate 	 * Fail if there was already a breakpoint there from another debugger
22967c478bd9Sstevel@tonic-gate 	 * or DTrace's user-level tracing on x86.
22977c478bd9Sstevel@tonic-gate 	 */
2298e4586ebfSmws 	if (old == BPT) {
2299e4586ebfSmws 		errno = EBUSY;
2300e4586ebfSmws 		return (-1);
2301e4586ebfSmws 	}
23027c478bd9Sstevel@tonic-gate 
23037c478bd9Sstevel@tonic-gate 	*saved = (ulong_t)old;
23047c478bd9Sstevel@tonic-gate 	return (0);
23057c478bd9Sstevel@tonic-gate }
23067c478bd9Sstevel@tonic-gate 
23077c478bd9Sstevel@tonic-gate /*
23087c478bd9Sstevel@tonic-gate  * Restore original instruction where a breakpoint was set.
23097c478bd9Sstevel@tonic-gate  */
23107c478bd9Sstevel@tonic-gate int
Pdelbkpt(struct ps_prochandle * P,uintptr_t address,ulong_t saved)23117c478bd9Sstevel@tonic-gate Pdelbkpt(struct ps_prochandle *P, uintptr_t address, ulong_t saved)
23127c478bd9Sstevel@tonic-gate {
23137c478bd9Sstevel@tonic-gate 	instr_t old = (instr_t)saved;
23147c478bd9Sstevel@tonic-gate 	instr_t cur;
23157c478bd9Sstevel@tonic-gate 
23167c478bd9Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
23177c478bd9Sstevel@tonic-gate 	    P->state == PS_IDLE) {
23187c478bd9Sstevel@tonic-gate 		errno = ENOENT;
23197c478bd9Sstevel@tonic-gate 		return (-1);
23207c478bd9Sstevel@tonic-gate 	}
23217c478bd9Sstevel@tonic-gate 
23227c478bd9Sstevel@tonic-gate 	/*
23237c478bd9Sstevel@tonic-gate 	 * If the breakpoint instruction we had placed has been overwritten
23247c478bd9Sstevel@tonic-gate 	 * with a new instruction, then don't try to replace it with the
23257c478bd9Sstevel@tonic-gate 	 * old instruction. Doing do can cause problems with self-modifying
23267c478bd9Sstevel@tonic-gate 	 * code -- PLTs for example. If the Pread() fails, we assume that we
23277c478bd9Sstevel@tonic-gate 	 * should proceed though most likely the Pwrite() will also fail.
23287c478bd9Sstevel@tonic-gate 	 */
23297c478bd9Sstevel@tonic-gate 	if (Pread(P, &cur, sizeof (cur), address) == sizeof (cur) &&
23307c478bd9Sstevel@tonic-gate 	    cur != BPT)
23317c478bd9Sstevel@tonic-gate 		return (0);
23327c478bd9Sstevel@tonic-gate 
23337c478bd9Sstevel@tonic-gate 	if (Pwrite(P, &old, sizeof (old), address) != sizeof (old))
23347c478bd9Sstevel@tonic-gate 		return (-1);
23357c478bd9Sstevel@tonic-gate 
23367c478bd9Sstevel@tonic-gate 	return (0);
23377c478bd9Sstevel@tonic-gate }
23387c478bd9Sstevel@tonic-gate 
23397c478bd9Sstevel@tonic-gate /*
23407c478bd9Sstevel@tonic-gate  * Common code for Pxecbkpt() and Lxecbkpt().
23417c478bd9Sstevel@tonic-gate  * Develop the array of requests that will do the job, then
23427c478bd9Sstevel@tonic-gate  * write them to the specified control file descriptor.
23437c478bd9Sstevel@tonic-gate  * Return the non-zero errno if the write fails.
23447c478bd9Sstevel@tonic-gate  */
23457c478bd9Sstevel@tonic-gate static int
execute_bkpt(int ctlfd,const fltset_t * faultset,const sigset_t * sigmask,uintptr_t address,ulong_t saved)23467c478bd9Sstevel@tonic-gate execute_bkpt(
23477c478bd9Sstevel@tonic-gate 	int ctlfd,		/* process or LWP control file descriptor */
23487c478bd9Sstevel@tonic-gate 	const fltset_t *faultset,	/* current set of traced faults */
23497c478bd9Sstevel@tonic-gate 	const sigset_t *sigmask,	/* current signal mask */
23507c478bd9Sstevel@tonic-gate 	uintptr_t address,		/* address of breakpint */
23517c478bd9Sstevel@tonic-gate 	ulong_t saved)			/* the saved instruction */
23527c478bd9Sstevel@tonic-gate {
23537c478bd9Sstevel@tonic-gate 	long ctl[
2354d7755b5aSrh 	    1 + sizeof (sigset_t) / sizeof (long) +		/* PCSHOLD */
2355d7755b5aSrh 	    1 + sizeof (fltset_t) / sizeof (long) +		/* PCSFAULT */
2356d7755b5aSrh 	    1 + sizeof (priovec_t) / sizeof (long) +		/* PCWRITE */
2357d7755b5aSrh 	    2 +							/* PCRUN */
2358d7755b5aSrh 	    1 +							/* PCWSTOP */
2359d7755b5aSrh 	    1 +							/* PCCFAULT */
2360d7755b5aSrh 	    1 + sizeof (priovec_t) / sizeof (long) +		/* PCWRITE */
2361d7755b5aSrh 	    1 + sizeof (fltset_t) / sizeof (long) +		/* PCSFAULT */
2362d7755b5aSrh 	    1 + sizeof (sigset_t) / sizeof (long)];		/* PCSHOLD */
23637c478bd9Sstevel@tonic-gate 	long *ctlp = ctl;
23647c478bd9Sstevel@tonic-gate 	sigset_t unblock;
23657c478bd9Sstevel@tonic-gate 	size_t size;
23667c478bd9Sstevel@tonic-gate 	ssize_t ssize;
23677c478bd9Sstevel@tonic-gate 	priovec_t *iovp;
23687c478bd9Sstevel@tonic-gate 	sigset_t *holdp;
23697c478bd9Sstevel@tonic-gate 	fltset_t *faultp;
23707c478bd9Sstevel@tonic-gate 	instr_t old = (instr_t)saved;
23717c478bd9Sstevel@tonic-gate 	instr_t bpt = BPT;
23727c478bd9Sstevel@tonic-gate 	int error = 0;
23737c478bd9Sstevel@tonic-gate 
23747c478bd9Sstevel@tonic-gate 	/* block our signals for the duration */
23757c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &blockable_sigs, &unblock);
23767c478bd9Sstevel@tonic-gate 
23777c478bd9Sstevel@tonic-gate 	/* hold posted signals */
23787c478bd9Sstevel@tonic-gate 	*ctlp++ = PCSHOLD;
23797c478bd9Sstevel@tonic-gate 	holdp = (sigset_t *)ctlp;
23807c478bd9Sstevel@tonic-gate 	prfillset(holdp);
23817c478bd9Sstevel@tonic-gate 	prdelset(holdp, SIGKILL);
23827c478bd9Sstevel@tonic-gate 	prdelset(holdp, SIGSTOP);
23837c478bd9Sstevel@tonic-gate 	ctlp += sizeof (sigset_t) / sizeof (long);
23847c478bd9Sstevel@tonic-gate 
23857c478bd9Sstevel@tonic-gate 	/* force tracing of FLTTRACE */
23867c478bd9Sstevel@tonic-gate 	if (!(prismember(faultset, FLTTRACE))) {
23877c478bd9Sstevel@tonic-gate 		*ctlp++ = PCSFAULT;
23887c478bd9Sstevel@tonic-gate 		faultp = (fltset_t *)ctlp;
23897c478bd9Sstevel@tonic-gate 		*faultp = *faultset;
23907c478bd9Sstevel@tonic-gate 		praddset(faultp, FLTTRACE);
23917c478bd9Sstevel@tonic-gate 		ctlp += sizeof (fltset_t) / sizeof (long);
23927c478bd9Sstevel@tonic-gate 	}
23937c478bd9Sstevel@tonic-gate 
23947c478bd9Sstevel@tonic-gate 	/* restore the old instruction */
23957c478bd9Sstevel@tonic-gate 	*ctlp++ = PCWRITE;
23967c478bd9Sstevel@tonic-gate 	iovp = (priovec_t *)ctlp;
23977c478bd9Sstevel@tonic-gate 	iovp->pio_base = &old;
23987c478bd9Sstevel@tonic-gate 	iovp->pio_len = sizeof (old);
23997c478bd9Sstevel@tonic-gate 	iovp->pio_offset = address;
24007c478bd9Sstevel@tonic-gate 	ctlp += sizeof (priovec_t) / sizeof (long);
24017c478bd9Sstevel@tonic-gate 
24027c478bd9Sstevel@tonic-gate 	/* clear current signal and fault; set running w/ single-step */
24037c478bd9Sstevel@tonic-gate 	*ctlp++ = PCRUN;
24047c478bd9Sstevel@tonic-gate 	*ctlp++ = PRCSIG | PRCFAULT | PRSTEP;
24057c478bd9Sstevel@tonic-gate 
24067c478bd9Sstevel@tonic-gate 	/* wait for stop, cancel the fault */
24077c478bd9Sstevel@tonic-gate 	*ctlp++ = PCWSTOP;
24087c478bd9Sstevel@tonic-gate 	*ctlp++ = PCCFAULT;
24097c478bd9Sstevel@tonic-gate 
24107c478bd9Sstevel@tonic-gate 	/* restore the breakpoint trap */
24117c478bd9Sstevel@tonic-gate 	*ctlp++ = PCWRITE;
24127c478bd9Sstevel@tonic-gate 	iovp = (priovec_t *)ctlp;
24137c478bd9Sstevel@tonic-gate 	iovp->pio_base = &bpt;
24147c478bd9Sstevel@tonic-gate 	iovp->pio_len = sizeof (bpt);
24157c478bd9Sstevel@tonic-gate 	iovp->pio_offset = address;
24167c478bd9Sstevel@tonic-gate 	ctlp += sizeof (priovec_t) / sizeof (long);
24177c478bd9Sstevel@tonic-gate 
24187c478bd9Sstevel@tonic-gate 	/* restore fault tracing set */
24197c478bd9Sstevel@tonic-gate 	if (!(prismember(faultset, FLTTRACE))) {
24207c478bd9Sstevel@tonic-gate 		*ctlp++ = PCSFAULT;
24217c478bd9Sstevel@tonic-gate 		*(fltset_t *)ctlp = *faultset;
24227c478bd9Sstevel@tonic-gate 		ctlp += sizeof (fltset_t) / sizeof (long);
24237c478bd9Sstevel@tonic-gate 	}
24247c478bd9Sstevel@tonic-gate 
24257c478bd9Sstevel@tonic-gate 	/* restore the hold mask */
24267c478bd9Sstevel@tonic-gate 	*ctlp++ = PCSHOLD;
24277c478bd9Sstevel@tonic-gate 	*(sigset_t *)ctlp = *sigmask;
24287c478bd9Sstevel@tonic-gate 	ctlp += sizeof (sigset_t) / sizeof (long);
24297c478bd9Sstevel@tonic-gate 
24307c478bd9Sstevel@tonic-gate 	size = (char *)ctlp - (char *)ctl;
24317c478bd9Sstevel@tonic-gate 	if ((ssize = write(ctlfd, ctl, size)) != size)
24327c478bd9Sstevel@tonic-gate 		error = (ssize == -1)? errno : EINTR;
24337c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &unblock, NULL);
24347c478bd9Sstevel@tonic-gate 	return (error);
24357c478bd9Sstevel@tonic-gate }
24367c478bd9Sstevel@tonic-gate 
24377c478bd9Sstevel@tonic-gate /*
24387c478bd9Sstevel@tonic-gate  * Step over a breakpoint, i.e., execute the instruction that
24397c478bd9Sstevel@tonic-gate  * really belongs at the breakpoint location (the current %pc)
24407c478bd9Sstevel@tonic-gate  * and leave the process stopped at the next instruction.
24417c478bd9Sstevel@tonic-gate  */
24427c478bd9Sstevel@tonic-gate int
Pxecbkpt(struct ps_prochandle * P,ulong_t saved)24437c478bd9Sstevel@tonic-gate Pxecbkpt(struct ps_prochandle *P, ulong_t saved)
24447c478bd9Sstevel@tonic-gate {
24457c478bd9Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
24467c478bd9Sstevel@tonic-gate 	int rv, error;
24477c478bd9Sstevel@tonic-gate 
24487c478bd9Sstevel@tonic-gate 	if (P->state != PS_STOP) {
24497c478bd9Sstevel@tonic-gate 		errno = EBUSY;
24507c478bd9Sstevel@tonic-gate 		return (-1);
24517c478bd9Sstevel@tonic-gate 	}
24527c478bd9Sstevel@tonic-gate 
24537c478bd9Sstevel@tonic-gate 	Psync(P);
24547c478bd9Sstevel@tonic-gate 
24557c478bd9Sstevel@tonic-gate 	error = execute_bkpt(ctlfd,
2456d7755b5aSrh 	    &P->status.pr_flttrace, &P->status.pr_lwp.pr_lwphold,
2457d7755b5aSrh 	    P->status.pr_lwp.pr_reg[R_PC], saved);
24587c478bd9Sstevel@tonic-gate 	rv = Pstopstatus(P, PCNULL, 0);
24597c478bd9Sstevel@tonic-gate 
24607c478bd9Sstevel@tonic-gate 	if (error != 0) {
24617c478bd9Sstevel@tonic-gate 		if (P->status.pr_lwp.pr_why == PR_JOBCONTROL &&
24627c478bd9Sstevel@tonic-gate 		    error == EBUSY) {	/* jobcontrol stop -- back off */
24637c478bd9Sstevel@tonic-gate 			P->state = PS_RUN;
24647c478bd9Sstevel@tonic-gate 			return (0);
24657c478bd9Sstevel@tonic-gate 		}
24667c478bd9Sstevel@tonic-gate 		if (error == ENOENT)
24677c478bd9Sstevel@tonic-gate 			return (0);
24687c478bd9Sstevel@tonic-gate 		errno = error;
24697c478bd9Sstevel@tonic-gate 		return (-1);
24707c478bd9Sstevel@tonic-gate 	}
24717c478bd9Sstevel@tonic-gate 
24727c478bd9Sstevel@tonic-gate 	return (rv);
24737c478bd9Sstevel@tonic-gate }
24747c478bd9Sstevel@tonic-gate 
24757c478bd9Sstevel@tonic-gate /*
24767c478bd9Sstevel@tonic-gate  * Install the watchpoint described by wp.
24777c478bd9Sstevel@tonic-gate  */
24787c478bd9Sstevel@tonic-gate int
Psetwapt(struct ps_prochandle * P,const prwatch_t * wp)24797c478bd9Sstevel@tonic-gate Psetwapt(struct ps_prochandle *P, const prwatch_t *wp)
24807c478bd9Sstevel@tonic-gate {
24817c478bd9Sstevel@tonic-gate 	long ctl[1 + sizeof (prwatch_t) / sizeof (long)];
24827c478bd9Sstevel@tonic-gate 	prwatch_t *cwp = (prwatch_t *)&ctl[1];
24837c478bd9Sstevel@tonic-gate 
24847c478bd9Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
24857c478bd9Sstevel@tonic-gate 	    P->state == PS_IDLE) {
24867c478bd9Sstevel@tonic-gate 		errno = ENOENT;
24877c478bd9Sstevel@tonic-gate 		return (-1);
24887c478bd9Sstevel@tonic-gate 	}
24897c478bd9Sstevel@tonic-gate 
24907c478bd9Sstevel@tonic-gate 	ctl[0] = PCWATCH;
24917c478bd9Sstevel@tonic-gate 	cwp->pr_vaddr = wp->pr_vaddr;
24927c478bd9Sstevel@tonic-gate 	cwp->pr_size = wp->pr_size;
24937c478bd9Sstevel@tonic-gate 	cwp->pr_wflags = wp->pr_wflags;
24947c478bd9Sstevel@tonic-gate 
24957c478bd9Sstevel@tonic-gate 	if (write(P->ctlfd, ctl, sizeof (ctl)) != sizeof (ctl))
24967c478bd9Sstevel@tonic-gate 		return (-1);
24977c478bd9Sstevel@tonic-gate 
24987c478bd9Sstevel@tonic-gate 	return (0);
24997c478bd9Sstevel@tonic-gate }
25007c478bd9Sstevel@tonic-gate 
25017c478bd9Sstevel@tonic-gate /*
25027c478bd9Sstevel@tonic-gate  * Remove the watchpoint described by wp.
25037c478bd9Sstevel@tonic-gate  */
25047c478bd9Sstevel@tonic-gate int
Pdelwapt(struct ps_prochandle * P,const prwatch_t * wp)25057c478bd9Sstevel@tonic-gate Pdelwapt(struct ps_prochandle *P, const prwatch_t *wp)
25067c478bd9Sstevel@tonic-gate {
25077c478bd9Sstevel@tonic-gate 	long ctl[1 + sizeof (prwatch_t) / sizeof (long)];
25087c478bd9Sstevel@tonic-gate 	prwatch_t *cwp = (prwatch_t *)&ctl[1];
25097c478bd9Sstevel@tonic-gate 
25107c478bd9Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
25117c478bd9Sstevel@tonic-gate 	    P->state == PS_IDLE) {
25127c478bd9Sstevel@tonic-gate 		errno = ENOENT;
25137c478bd9Sstevel@tonic-gate 		return (-1);
25147c478bd9Sstevel@tonic-gate 	}
25157c478bd9Sstevel@tonic-gate 
25167c478bd9Sstevel@tonic-gate 	ctl[0] = PCWATCH;
25177c478bd9Sstevel@tonic-gate 	cwp->pr_vaddr = wp->pr_vaddr;
25187c478bd9Sstevel@tonic-gate 	cwp->pr_size = wp->pr_size;
25197c478bd9Sstevel@tonic-gate 	cwp->pr_wflags = 0;
25207c478bd9Sstevel@tonic-gate 
25217c478bd9Sstevel@tonic-gate 	if (write(P->ctlfd, ctl, sizeof (ctl)) != sizeof (ctl))
25227c478bd9Sstevel@tonic-gate 		return (-1);
25237c478bd9Sstevel@tonic-gate 
25247c478bd9Sstevel@tonic-gate 	return (0);
25257c478bd9Sstevel@tonic-gate }
25267c478bd9Sstevel@tonic-gate 
25277c478bd9Sstevel@tonic-gate /*
25287c478bd9Sstevel@tonic-gate  * Common code for Pxecwapt() and Lxecwapt().  Develop the array of requests
25297c478bd9Sstevel@tonic-gate  * that will do the job, then write them to the specified control file
25307c478bd9Sstevel@tonic-gate  * descriptor.  Return the non-zero errno if the write fails.
25317c478bd9Sstevel@tonic-gate  */
25327c478bd9Sstevel@tonic-gate static int
execute_wapt(int ctlfd,const fltset_t * faultset,const sigset_t * sigmask,const prwatch_t * wp)25337c478bd9Sstevel@tonic-gate execute_wapt(
25347c478bd9Sstevel@tonic-gate 	int ctlfd,		/* process or LWP control file descriptor */
25357c478bd9Sstevel@tonic-gate 	const fltset_t *faultset,	/* current set of traced faults */
25367c478bd9Sstevel@tonic-gate 	const sigset_t *sigmask,	/* current signal mask */
25377c478bd9Sstevel@tonic-gate 	const prwatch_t *wp)		/* watchpoint descriptor */
25387c478bd9Sstevel@tonic-gate {
25397c478bd9Sstevel@tonic-gate 	long ctl[
25407c478bd9Sstevel@tonic-gate 	    1 + sizeof (sigset_t) / sizeof (long) +		/* PCSHOLD */
25417c478bd9Sstevel@tonic-gate 	    1 + sizeof (fltset_t) / sizeof (long) +		/* PCSFAULT */
25427c478bd9Sstevel@tonic-gate 	    1 + sizeof (prwatch_t) / sizeof (long) +		/* PCWATCH */
25437c478bd9Sstevel@tonic-gate 	    2 +							/* PCRUN */
25447c478bd9Sstevel@tonic-gate 	    1 +							/* PCWSTOP */
25457c478bd9Sstevel@tonic-gate 	    1 +							/* PCCFAULT */
25467c478bd9Sstevel@tonic-gate 	    1 + sizeof (prwatch_t) / sizeof (long) +		/* PCWATCH */
25477c478bd9Sstevel@tonic-gate 	    1 + sizeof (fltset_t) / sizeof (long) +		/* PCSFAULT */
25487c478bd9Sstevel@tonic-gate 	    1 + sizeof (sigset_t) / sizeof (long)];		/* PCSHOLD */
25497c478bd9Sstevel@tonic-gate 
25507c478bd9Sstevel@tonic-gate 	long *ctlp = ctl;
25517c478bd9Sstevel@tonic-gate 	int error = 0;
25527c478bd9Sstevel@tonic-gate 
25537c478bd9Sstevel@tonic-gate 	sigset_t unblock;
25547c478bd9Sstevel@tonic-gate 	sigset_t *holdp;
25557c478bd9Sstevel@tonic-gate 	fltset_t *faultp;
25567c478bd9Sstevel@tonic-gate 	prwatch_t *prw;
25577c478bd9Sstevel@tonic-gate 	ssize_t ssize;
25587c478bd9Sstevel@tonic-gate 	size_t size;
25597c478bd9Sstevel@tonic-gate 
25607c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &blockable_sigs, &unblock);
25617c478bd9Sstevel@tonic-gate 
25627c478bd9Sstevel@tonic-gate 	/*
25637c478bd9Sstevel@tonic-gate 	 * Hold all posted signals in the victim process prior to stepping.
25647c478bd9Sstevel@tonic-gate 	 */
25657c478bd9Sstevel@tonic-gate 	*ctlp++ = PCSHOLD;
25667c478bd9Sstevel@tonic-gate 	holdp = (sigset_t *)ctlp;
25677c478bd9Sstevel@tonic-gate 	prfillset(holdp);
25687c478bd9Sstevel@tonic-gate 	prdelset(holdp, SIGKILL);
25697c478bd9Sstevel@tonic-gate 	prdelset(holdp, SIGSTOP);
25707c478bd9Sstevel@tonic-gate 	ctlp += sizeof (sigset_t) / sizeof (long);
25717c478bd9Sstevel@tonic-gate 
25727c478bd9Sstevel@tonic-gate 	/*
25737c478bd9Sstevel@tonic-gate 	 * Force tracing of FLTTRACE since we need to single step.
25747c478bd9Sstevel@tonic-gate 	 */
25757c478bd9Sstevel@tonic-gate 	if (!(prismember(faultset, FLTTRACE))) {
25767c478bd9Sstevel@tonic-gate 		*ctlp++ = PCSFAULT;
25777c478bd9Sstevel@tonic-gate 		faultp = (fltset_t *)ctlp;
25787c478bd9Sstevel@tonic-gate 		*faultp = *faultset;
25797c478bd9Sstevel@tonic-gate 		praddset(faultp, FLTTRACE);
25807c478bd9Sstevel@tonic-gate 		ctlp += sizeof (fltset_t) / sizeof (long);
25817c478bd9Sstevel@tonic-gate 	}
25827c478bd9Sstevel@tonic-gate 
25837c478bd9Sstevel@tonic-gate 	/*
25847c478bd9Sstevel@tonic-gate 	 * Clear only the current watchpoint by setting pr_wflags to zero.
25857c478bd9Sstevel@tonic-gate 	 */
25867c478bd9Sstevel@tonic-gate 	*ctlp++ = PCWATCH;
25877c478bd9Sstevel@tonic-gate 	prw = (prwatch_t *)ctlp;
25887c478bd9Sstevel@tonic-gate 	prw->pr_vaddr = wp->pr_vaddr;
25897c478bd9Sstevel@tonic-gate 	prw->pr_size = wp->pr_size;
25907c478bd9Sstevel@tonic-gate 	prw->pr_wflags = 0;
25917c478bd9Sstevel@tonic-gate 	ctlp += sizeof (prwatch_t) / sizeof (long);
25927c478bd9Sstevel@tonic-gate 
25937c478bd9Sstevel@tonic-gate 	/*
25947c478bd9Sstevel@tonic-gate 	 * Clear the current signal and fault; set running with single-step.
25957c478bd9Sstevel@tonic-gate 	 * Then wait for the victim to stop and cancel the FLTTRACE.
25967c478bd9Sstevel@tonic-gate 	 */
25977c478bd9Sstevel@tonic-gate 	*ctlp++ = PCRUN;
25987c478bd9Sstevel@tonic-gate 	*ctlp++ = PRCSIG | PRCFAULT | PRSTEP;
25997c478bd9Sstevel@tonic-gate 	*ctlp++ = PCWSTOP;
26007c478bd9Sstevel@tonic-gate 	*ctlp++ = PCCFAULT;
26017c478bd9Sstevel@tonic-gate 
26027c478bd9Sstevel@tonic-gate 	/*
26037c478bd9Sstevel@tonic-gate 	 * Restore the current watchpoint.
26047c478bd9Sstevel@tonic-gate 	 */
26057c478bd9Sstevel@tonic-gate 	*ctlp++ = PCWATCH;
26067c478bd9Sstevel@tonic-gate 	(void) memcpy(ctlp, wp, sizeof (prwatch_t));
26077c478bd9Sstevel@tonic-gate 	ctlp += sizeof (prwatch_t) / sizeof (long);
26087c478bd9Sstevel@tonic-gate 
26097c478bd9Sstevel@tonic-gate 	/*
26107c478bd9Sstevel@tonic-gate 	 * Restore fault tracing set if we modified it.
26117c478bd9Sstevel@tonic-gate 	 */
26127c478bd9Sstevel@tonic-gate 	if (!(prismember(faultset, FLTTRACE))) {
26137c478bd9Sstevel@tonic-gate 		*ctlp++ = PCSFAULT;
26147c478bd9Sstevel@tonic-gate 		*(fltset_t *)ctlp = *faultset;
26157c478bd9Sstevel@tonic-gate 		ctlp += sizeof (fltset_t) / sizeof (long);
26167c478bd9Sstevel@tonic-gate 	}
26177c478bd9Sstevel@tonic-gate 
26187c478bd9Sstevel@tonic-gate 	/*
26197c478bd9Sstevel@tonic-gate 	 * Restore the hold mask to the current hold mask (i.e. the one
26207c478bd9Sstevel@tonic-gate 	 * before we executed any of the previous operations).
26217c478bd9Sstevel@tonic-gate 	 */
26227c478bd9Sstevel@tonic-gate 	*ctlp++ = PCSHOLD;
26237c478bd9Sstevel@tonic-gate 	*(sigset_t *)ctlp = *sigmask;
26247c478bd9Sstevel@tonic-gate 	ctlp += sizeof (sigset_t) / sizeof (long);
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate 	size = (char *)ctlp - (char *)ctl;
26277c478bd9Sstevel@tonic-gate 	if ((ssize = write(ctlfd, ctl, size)) != size)
26287c478bd9Sstevel@tonic-gate 		error = (ssize == -1)? errno : EINTR;
26297c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &unblock, NULL);
26307c478bd9Sstevel@tonic-gate 	return (error);
26317c478bd9Sstevel@tonic-gate }
26327c478bd9Sstevel@tonic-gate 
26337c478bd9Sstevel@tonic-gate /*
26347c478bd9Sstevel@tonic-gate  * Step over a watchpoint, i.e., execute the instruction that was stopped by
26357c478bd9Sstevel@tonic-gate  * the watchpoint, and then leave the LWP stopped at the next instruction.
26367c478bd9Sstevel@tonic-gate  */
26377c478bd9Sstevel@tonic-gate int
Pxecwapt(struct ps_prochandle * P,const prwatch_t * wp)26387c478bd9Sstevel@tonic-gate Pxecwapt(struct ps_prochandle *P, const prwatch_t *wp)
26397c478bd9Sstevel@tonic-gate {
26407c478bd9Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
26417c478bd9Sstevel@tonic-gate 	int rv, error;
26427c478bd9Sstevel@tonic-gate 
26437c478bd9Sstevel@tonic-gate 	if (P->state != PS_STOP) {
26447c478bd9Sstevel@tonic-gate 		errno = EBUSY;
26457c478bd9Sstevel@tonic-gate 		return (-1);
26467c478bd9Sstevel@tonic-gate 	}
26477c478bd9Sstevel@tonic-gate 
26487c478bd9Sstevel@tonic-gate 	Psync(P);
26497c478bd9Sstevel@tonic-gate 	error = execute_wapt(ctlfd,
2650d7755b5aSrh 	    &P->status.pr_flttrace, &P->status.pr_lwp.pr_lwphold, wp);
26517c478bd9Sstevel@tonic-gate 	rv = Pstopstatus(P, PCNULL, 0);
26527c478bd9Sstevel@tonic-gate 
26537c478bd9Sstevel@tonic-gate 	if (error != 0) {
26547c478bd9Sstevel@tonic-gate 		if (P->status.pr_lwp.pr_why == PR_JOBCONTROL &&
26557c478bd9Sstevel@tonic-gate 		    error == EBUSY) {	/* jobcontrol stop -- back off */
26567c478bd9Sstevel@tonic-gate 			P->state = PS_RUN;
26577c478bd9Sstevel@tonic-gate 			return (0);
26587c478bd9Sstevel@tonic-gate 		}
26597c478bd9Sstevel@tonic-gate 		if (error == ENOENT)
26607c478bd9Sstevel@tonic-gate 			return (0);
26617c478bd9Sstevel@tonic-gate 		errno = error;
26627c478bd9Sstevel@tonic-gate 		return (-1);
26637c478bd9Sstevel@tonic-gate 	}
26647c478bd9Sstevel@tonic-gate 
26657c478bd9Sstevel@tonic-gate 	return (rv);
26667c478bd9Sstevel@tonic-gate }
26677c478bd9Sstevel@tonic-gate 
26687c478bd9Sstevel@tonic-gate int
Psetflags(struct ps_prochandle * P,long flags)26697c478bd9Sstevel@tonic-gate Psetflags(struct ps_prochandle *P, long flags)
26707c478bd9Sstevel@tonic-gate {
26717c478bd9Sstevel@tonic-gate 	int rc;
26727c478bd9Sstevel@tonic-gate 	long ctl[2];
26737c478bd9Sstevel@tonic-gate 
26747c478bd9Sstevel@tonic-gate 	ctl[0] = PCSET;
26757c478bd9Sstevel@tonic-gate 	ctl[1] = flags;
26767c478bd9Sstevel@tonic-gate 
26777c478bd9Sstevel@tonic-gate 	if (write(P->ctlfd, ctl, 2*sizeof (long)) != 2*sizeof (long)) {
26787c478bd9Sstevel@tonic-gate 		rc = -1;
26797c478bd9Sstevel@tonic-gate 	} else {
26807c478bd9Sstevel@tonic-gate 		P->status.pr_flags |= flags;
26817c478bd9Sstevel@tonic-gate 		P->status.pr_lwp.pr_flags |= flags;
26827c478bd9Sstevel@tonic-gate 		rc = 0;
26837c478bd9Sstevel@tonic-gate 	}
26847c478bd9Sstevel@tonic-gate 
26857c478bd9Sstevel@tonic-gate 	return (rc);
26867c478bd9Sstevel@tonic-gate }
26877c478bd9Sstevel@tonic-gate 
26887c478bd9Sstevel@tonic-gate int
Punsetflags(struct ps_prochandle * P,long flags)26897c478bd9Sstevel@tonic-gate Punsetflags(struct ps_prochandle *P, long flags)
26907c478bd9Sstevel@tonic-gate {
26917c478bd9Sstevel@tonic-gate 	int rc;
26927c478bd9Sstevel@tonic-gate 	long ctl[2];
26937c478bd9Sstevel@tonic-gate 
26947c478bd9Sstevel@tonic-gate 	ctl[0] = PCUNSET;
26957c478bd9Sstevel@tonic-gate 	ctl[1] = flags;
26967c478bd9Sstevel@tonic-gate 
26977c478bd9Sstevel@tonic-gate 	if (write(P->ctlfd, ctl, 2*sizeof (long)) != 2*sizeof (long)) {
26987c478bd9Sstevel@tonic-gate 		rc = -1;
26997c478bd9Sstevel@tonic-gate 	} else {
27007c478bd9Sstevel@tonic-gate 		P->status.pr_flags &= ~flags;
27017c478bd9Sstevel@tonic-gate 		P->status.pr_lwp.pr_flags &= ~flags;
27027c478bd9Sstevel@tonic-gate 		rc = 0;
27037c478bd9Sstevel@tonic-gate 	}
27047c478bd9Sstevel@tonic-gate 
27057c478bd9Sstevel@tonic-gate 	return (rc);
27067c478bd9Sstevel@tonic-gate }
27077c478bd9Sstevel@tonic-gate 
27087c478bd9Sstevel@tonic-gate /*
27097c478bd9Sstevel@tonic-gate  * Common function to allow clients to manipulate the action to be taken
27107c478bd9Sstevel@tonic-gate  * on receipt of a signal, receipt of machine fault, entry to a system call,
27117c478bd9Sstevel@tonic-gate  * or exit from a system call.  We make use of our private prset_* functions
27127c478bd9Sstevel@tonic-gate  * in order to make this code be common.  The 'which' parameter identifies
27137c478bd9Sstevel@tonic-gate  * the code for the event of interest (0 means change the entire set), and
27147c478bd9Sstevel@tonic-gate  * the 'stop' parameter is a boolean indicating whether the process should
27157c478bd9Sstevel@tonic-gate  * stop when the event of interest occurs.  The previous value is returned
27167c478bd9Sstevel@tonic-gate  * to the caller; -1 is returned if an error occurred.
27177c478bd9Sstevel@tonic-gate  */
27187c478bd9Sstevel@tonic-gate static int
Psetaction(struct ps_prochandle * P,void * sp,size_t size,uint_t flag,int max,int which,int stop)27197c478bd9Sstevel@tonic-gate Psetaction(struct ps_prochandle *P, void *sp, size_t size,
27207c478bd9Sstevel@tonic-gate     uint_t flag, int max, int which, int stop)
27217c478bd9Sstevel@tonic-gate {
27227c478bd9Sstevel@tonic-gate 	int oldval;
27237c478bd9Sstevel@tonic-gate 
27247c478bd9Sstevel@tonic-gate 	if (which < 0 || which > max) {
27257c478bd9Sstevel@tonic-gate 		errno = EINVAL;
27267c478bd9Sstevel@tonic-gate 		return (-1);
27277c478bd9Sstevel@tonic-gate 	}
27287c478bd9Sstevel@tonic-gate 
27297c478bd9Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
27307c478bd9Sstevel@tonic-gate 	    P->state == PS_IDLE) {
27317c478bd9Sstevel@tonic-gate 		errno = ENOENT;
27327c478bd9Sstevel@tonic-gate 		return (-1);
27337c478bd9Sstevel@tonic-gate 	}
27347c478bd9Sstevel@tonic-gate 
27357c478bd9Sstevel@tonic-gate 	oldval = prset_ismember(sp, size, which) ? TRUE : FALSE;
27367c478bd9Sstevel@tonic-gate 
27377c478bd9Sstevel@tonic-gate 	if (stop) {
27387c478bd9Sstevel@tonic-gate 		if (which == 0) {
27397c478bd9Sstevel@tonic-gate 			prset_fill(sp, size);
27407c478bd9Sstevel@tonic-gate 			P->flags |= flag;
27417c478bd9Sstevel@tonic-gate 		} else if (!oldval) {
27427c478bd9Sstevel@tonic-gate 			prset_add(sp, size, which);
27437c478bd9Sstevel@tonic-gate 			P->flags |= flag;
27447c478bd9Sstevel@tonic-gate 		}
27457c478bd9Sstevel@tonic-gate 	} else {
27467c478bd9Sstevel@tonic-gate 		if (which == 0) {
27477c478bd9Sstevel@tonic-gate 			prset_empty(sp, size);
27487c478bd9Sstevel@tonic-gate 			P->flags |= flag;
27497c478bd9Sstevel@tonic-gate 		} else if (oldval) {
27507c478bd9Sstevel@tonic-gate 			prset_del(sp, size, which);
27517c478bd9Sstevel@tonic-gate 			P->flags |= flag;
27527c478bd9Sstevel@tonic-gate 		}
27537c478bd9Sstevel@tonic-gate 	}
27547c478bd9Sstevel@tonic-gate 
27557c478bd9Sstevel@tonic-gate 	if (P->state == PS_RUN)
27567c478bd9Sstevel@tonic-gate 		Psync(P);
27577c478bd9Sstevel@tonic-gate 
27587c478bd9Sstevel@tonic-gate 	return (oldval);
27597c478bd9Sstevel@tonic-gate }
27607c478bd9Sstevel@tonic-gate 
27617c478bd9Sstevel@tonic-gate /*
27627c478bd9Sstevel@tonic-gate  * Set action on specified signal.
27637c478bd9Sstevel@tonic-gate  */
27647c478bd9Sstevel@tonic-gate int
Psignal(struct ps_prochandle * P,int which,int stop)27657c478bd9Sstevel@tonic-gate Psignal(struct ps_prochandle *P, int which, int stop)
27667c478bd9Sstevel@tonic-gate {
27677c478bd9Sstevel@tonic-gate 	int oldval;
27687c478bd9Sstevel@tonic-gate 
27697c478bd9Sstevel@tonic-gate 	if (which == SIGKILL && stop != 0) {
27707c478bd9Sstevel@tonic-gate 		errno = EINVAL;
27717c478bd9Sstevel@tonic-gate 		return (-1);
27727c478bd9Sstevel@tonic-gate 	}
27737c478bd9Sstevel@tonic-gate 
27747c478bd9Sstevel@tonic-gate 	oldval = Psetaction(P, &P->status.pr_sigtrace, sizeof (sigset_t),
27757c478bd9Sstevel@tonic-gate 	    SETSIG, PRMAXSIG, which, stop);
27767c478bd9Sstevel@tonic-gate 
27777c478bd9Sstevel@tonic-gate 	if (oldval != -1 && which == 0 && stop != 0)
27787c478bd9Sstevel@tonic-gate 		prdelset(&P->status.pr_sigtrace, SIGKILL);
27797c478bd9Sstevel@tonic-gate 
27807c478bd9Sstevel@tonic-gate 	return (oldval);
27817c478bd9Sstevel@tonic-gate }
27827c478bd9Sstevel@tonic-gate 
27837c478bd9Sstevel@tonic-gate /*
27847c478bd9Sstevel@tonic-gate  * Set all signal tracing flags.
27857c478bd9Sstevel@tonic-gate  */
27867c478bd9Sstevel@tonic-gate void
Psetsignal(struct ps_prochandle * P,const sigset_t * set)27877c478bd9Sstevel@tonic-gate Psetsignal(struct ps_prochandle *P, const sigset_t *set)
27887c478bd9Sstevel@tonic-gate {
27897c478bd9Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
27907c478bd9Sstevel@tonic-gate 	    P->state == PS_IDLE)
27917c478bd9Sstevel@tonic-gate 		return;
27927c478bd9Sstevel@tonic-gate 
27937c478bd9Sstevel@tonic-gate 	P->status.pr_sigtrace = *set;
27947c478bd9Sstevel@tonic-gate 	P->flags |= SETSIG;
27957c478bd9Sstevel@tonic-gate 
27967c478bd9Sstevel@tonic-gate 	if (P->state == PS_RUN)
27977c478bd9Sstevel@tonic-gate 		Psync(P);
27987c478bd9Sstevel@tonic-gate }
27997c478bd9Sstevel@tonic-gate 
28007c478bd9Sstevel@tonic-gate /*
28017c478bd9Sstevel@tonic-gate  * Set action on specified fault.
28027c478bd9Sstevel@tonic-gate  */
28037c478bd9Sstevel@tonic-gate int
Pfault(struct ps_prochandle * P,int which,int stop)28047c478bd9Sstevel@tonic-gate Pfault(struct ps_prochandle *P, int which, int stop)
28057c478bd9Sstevel@tonic-gate {
28067c478bd9Sstevel@tonic-gate 	return (Psetaction(P, &P->status.pr_flttrace, sizeof (fltset_t),
28077c478bd9Sstevel@tonic-gate 	    SETFAULT, PRMAXFAULT, which, stop));
28087c478bd9Sstevel@tonic-gate }
28097c478bd9Sstevel@tonic-gate 
28107c478bd9Sstevel@tonic-gate /*
28117c478bd9Sstevel@tonic-gate  * Set all machine fault tracing flags.
28127c478bd9Sstevel@tonic-gate  */
28137c478bd9Sstevel@tonic-gate void
Psetfault(struct ps_prochandle * P,const fltset_t * set)28147c478bd9Sstevel@tonic-gate Psetfault(struct ps_prochandle *P, const fltset_t *set)
28157c478bd9Sstevel@tonic-gate {
28167c478bd9Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
28177c478bd9Sstevel@tonic-gate 	    P->state == PS_IDLE)
28187c478bd9Sstevel@tonic-gate 		return;
28197c478bd9Sstevel@tonic-gate 
28207c478bd9Sstevel@tonic-gate 	P->status.pr_flttrace = *set;
28217c478bd9Sstevel@tonic-gate 	P->flags |= SETFAULT;
28227c478bd9Sstevel@tonic-gate 
28237c478bd9Sstevel@tonic-gate 	if (P->state == PS_RUN)
28247c478bd9Sstevel@tonic-gate 		Psync(P);
28257c478bd9Sstevel@tonic-gate }
28267c478bd9Sstevel@tonic-gate 
28277c478bd9Sstevel@tonic-gate /*
28287c478bd9Sstevel@tonic-gate  * Set action on specified system call entry.
28297c478bd9Sstevel@tonic-gate  */
28307c478bd9Sstevel@tonic-gate int
Psysentry(struct ps_prochandle * P,int which,int stop)28317c478bd9Sstevel@tonic-gate Psysentry(struct ps_prochandle *P, int which, int stop)
28327c478bd9Sstevel@tonic-gate {
28337c478bd9Sstevel@tonic-gate 	return (Psetaction(P, &P->status.pr_sysentry, sizeof (sysset_t),
28347c478bd9Sstevel@tonic-gate 	    SETENTRY, PRMAXSYS, which, stop));
28357c478bd9Sstevel@tonic-gate }
28367c478bd9Sstevel@tonic-gate 
28377c478bd9Sstevel@tonic-gate /*
28387c478bd9Sstevel@tonic-gate  * Set all system call entry tracing flags.
28397c478bd9Sstevel@tonic-gate  */
28407c478bd9Sstevel@tonic-gate void
Psetsysentry(struct ps_prochandle * P,const sysset_t * set)28417c478bd9Sstevel@tonic-gate Psetsysentry(struct ps_prochandle *P, const sysset_t *set)
28427c478bd9Sstevel@tonic-gate {
28437c478bd9Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
28447c478bd9Sstevel@tonic-gate 	    P->state == PS_IDLE)
28457c478bd9Sstevel@tonic-gate 		return;
28467c478bd9Sstevel@tonic-gate 
28477c478bd9Sstevel@tonic-gate 	P->status.pr_sysentry = *set;
28487c478bd9Sstevel@tonic-gate 	P->flags |= SETENTRY;
28497c478bd9Sstevel@tonic-gate 
28507c478bd9Sstevel@tonic-gate 	if (P->state == PS_RUN)
28517c478bd9Sstevel@tonic-gate 		Psync(P);
28527c478bd9Sstevel@tonic-gate }
28537c478bd9Sstevel@tonic-gate 
28547c478bd9Sstevel@tonic-gate /*
28557c478bd9Sstevel@tonic-gate  * Set action on specified system call exit.
28567c478bd9Sstevel@tonic-gate  */
28577c478bd9Sstevel@tonic-gate int
Psysexit(struct ps_prochandle * P,int which,int stop)28587c478bd9Sstevel@tonic-gate Psysexit(struct ps_prochandle *P, int which, int stop)
28597c478bd9Sstevel@tonic-gate {
28607c478bd9Sstevel@tonic-gate 	return (Psetaction(P, &P->status.pr_sysexit, sizeof (sysset_t),
28617c478bd9Sstevel@tonic-gate 	    SETEXIT, PRMAXSYS, which, stop));
28627c478bd9Sstevel@tonic-gate }
28637c478bd9Sstevel@tonic-gate 
28647c478bd9Sstevel@tonic-gate /*
28657c478bd9Sstevel@tonic-gate  * Set all system call exit tracing flags.
28667c478bd9Sstevel@tonic-gate  */
28677c478bd9Sstevel@tonic-gate void
Psetsysexit(struct ps_prochandle * P,const sysset_t * set)28687c478bd9Sstevel@tonic-gate Psetsysexit(struct ps_prochandle *P, const sysset_t *set)
28697c478bd9Sstevel@tonic-gate {
28707c478bd9Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
28717c478bd9Sstevel@tonic-gate 	    P->state == PS_IDLE)
28727c478bd9Sstevel@tonic-gate 		return;
28737c478bd9Sstevel@tonic-gate 
28747c478bd9Sstevel@tonic-gate 	P->status.pr_sysexit = *set;
28757c478bd9Sstevel@tonic-gate 	P->flags |= SETEXIT;
28767c478bd9Sstevel@tonic-gate 
28777c478bd9Sstevel@tonic-gate 	if (P->state == PS_RUN)
28787c478bd9Sstevel@tonic-gate 		Psync(P);
28797c478bd9Sstevel@tonic-gate }
28807c478bd9Sstevel@tonic-gate 
28817c478bd9Sstevel@tonic-gate /*
28827c478bd9Sstevel@tonic-gate  * Utility function to read the contents of a file that contains a
28837c478bd9Sstevel@tonic-gate  * prheader_t at the start (/proc/pid/lstatus or /proc/pid/lpsinfo).
28847c478bd9Sstevel@tonic-gate  * Returns a malloc()d buffer or NULL on failure.
28857c478bd9Sstevel@tonic-gate  */
28867c478bd9Sstevel@tonic-gate static prheader_t *
read_lfile(struct ps_prochandle * P,const char * lname)28877c478bd9Sstevel@tonic-gate read_lfile(struct ps_prochandle *P, const char *lname)
28887c478bd9Sstevel@tonic-gate {
28897c478bd9Sstevel@tonic-gate 	prheader_t *Lhp;
28909acbbeafSnn 	char lpath[PATH_MAX];
28917c478bd9Sstevel@tonic-gate 	struct stat64 statb;
28927c478bd9Sstevel@tonic-gate 	int fd;
28937c478bd9Sstevel@tonic-gate 	size_t size;
28947c478bd9Sstevel@tonic-gate 	ssize_t rval;
28957c478bd9Sstevel@tonic-gate 
28969acbbeafSnn 	(void) snprintf(lpath, sizeof (lpath), "%s/%d/%s", procfs_path,
28977c478bd9Sstevel@tonic-gate 	    (int)P->status.pr_pid, lname);
28987c478bd9Sstevel@tonic-gate 	if ((fd = open(lpath, O_RDONLY)) < 0 || fstat64(fd, &statb) != 0) {
28997c478bd9Sstevel@tonic-gate 		if (fd >= 0)
29007c478bd9Sstevel@tonic-gate 			(void) close(fd);
29017c478bd9Sstevel@tonic-gate 		return (NULL);
29027c478bd9Sstevel@tonic-gate 	}
29037c478bd9Sstevel@tonic-gate 
29047c478bd9Sstevel@tonic-gate 	/*
29057c478bd9Sstevel@tonic-gate 	 * 'size' is just the initial guess at the buffer size.
29067c478bd9Sstevel@tonic-gate 	 * It will have to grow if the number of lwps increases
29077c478bd9Sstevel@tonic-gate 	 * while we are looking at the process.
29087c478bd9Sstevel@tonic-gate 	 * 'size' must be larger than the actual file size.
29097c478bd9Sstevel@tonic-gate 	 */
29107c478bd9Sstevel@tonic-gate 	size = statb.st_size + 32;
29117c478bd9Sstevel@tonic-gate 
29127c478bd9Sstevel@tonic-gate 	for (;;) {
29137c478bd9Sstevel@tonic-gate 		if ((Lhp = malloc(size)) == NULL)
29147c478bd9Sstevel@tonic-gate 			break;
29157c478bd9Sstevel@tonic-gate 		if ((rval = pread(fd, Lhp, size, 0)) < 0 ||
29167c478bd9Sstevel@tonic-gate 		    rval <= sizeof (prheader_t)) {
29177c478bd9Sstevel@tonic-gate 			free(Lhp);
29187c478bd9Sstevel@tonic-gate 			Lhp = NULL;
29197c478bd9Sstevel@tonic-gate 			break;
29207c478bd9Sstevel@tonic-gate 		}
29217c478bd9Sstevel@tonic-gate 		if (rval < size)
29227c478bd9Sstevel@tonic-gate 			break;
29237c478bd9Sstevel@tonic-gate 		/* need a bigger buffer */
29247c478bd9Sstevel@tonic-gate 		free(Lhp);
29257c478bd9Sstevel@tonic-gate 		size *= 2;
29267c478bd9Sstevel@tonic-gate 	}
29277c478bd9Sstevel@tonic-gate 
29287c478bd9Sstevel@tonic-gate 	(void) close(fd);
29297c478bd9Sstevel@tonic-gate 	return (Lhp);
29307c478bd9Sstevel@tonic-gate }
29317c478bd9Sstevel@tonic-gate 
29327c478bd9Sstevel@tonic-gate /*
29337c478bd9Sstevel@tonic-gate  * LWP iteration interface.
29347c478bd9Sstevel@tonic-gate  */
29357c478bd9Sstevel@tonic-gate int
Plwp_iter(struct ps_prochandle * P,proc_lwp_f * func,void * cd)29367c478bd9Sstevel@tonic-gate Plwp_iter(struct ps_prochandle *P, proc_lwp_f *func, void *cd)
29377c478bd9Sstevel@tonic-gate {
29387c478bd9Sstevel@tonic-gate 	prheader_t *Lhp;
29397c478bd9Sstevel@tonic-gate 	lwpstatus_t *Lsp;
29407c478bd9Sstevel@tonic-gate 	long nlwp;
29417c478bd9Sstevel@tonic-gate 	int rv;
29427c478bd9Sstevel@tonic-gate 
29437c478bd9Sstevel@tonic-gate 	switch (P->state) {
29447c478bd9Sstevel@tonic-gate 	case PS_RUN:
29457c478bd9Sstevel@tonic-gate 		(void) Pstopstatus(P, PCNULL, 0);
29467c478bd9Sstevel@tonic-gate 		break;
29477c478bd9Sstevel@tonic-gate 
29487c478bd9Sstevel@tonic-gate 	case PS_STOP:
29497c478bd9Sstevel@tonic-gate 		Psync(P);
29507c478bd9Sstevel@tonic-gate 		break;
29517c478bd9Sstevel@tonic-gate 
29527c478bd9Sstevel@tonic-gate 	case PS_IDLE:
29537c478bd9Sstevel@tonic-gate 		errno = ENODATA;
29547c478bd9Sstevel@tonic-gate 		return (-1);
29557c478bd9Sstevel@tonic-gate 	}
29567c478bd9Sstevel@tonic-gate 
29577c478bd9Sstevel@tonic-gate 	/*
29587c478bd9Sstevel@tonic-gate 	 * For either live processes or cores, the single LWP case is easy:
29597c478bd9Sstevel@tonic-gate 	 * the pstatus_t contains the lwpstatus_t for the only LWP.
29607c478bd9Sstevel@tonic-gate 	 */
29617c478bd9Sstevel@tonic-gate 	if (P->status.pr_nlwp <= 1)
29627c478bd9Sstevel@tonic-gate 		return (func(cd, &P->status.pr_lwp));
29637c478bd9Sstevel@tonic-gate 
29647c478bd9Sstevel@tonic-gate 	/*
29657c478bd9Sstevel@tonic-gate 	 * For the core file multi-LWP case, we just iterate through the
29667c478bd9Sstevel@tonic-gate 	 * list of LWP structs we read in from the core file.
29677c478bd9Sstevel@tonic-gate 	 */
29687c478bd9Sstevel@tonic-gate 	if (P->state == PS_DEAD) {
29692a12f85aSJeremy Jones 		core_info_t *core = P->data;
297050d4d24eSRobert Mustacchi 		lwp_info_t *lwp;
29717c478bd9Sstevel@tonic-gate 
297250d4d24eSRobert Mustacchi 		for (lwp = list_tail(&core->core_lwp_head); lwp != NULL;
297350d4d24eSRobert Mustacchi 		    lwp = list_prev(&core->core_lwp_head, lwp)) {
29747c478bd9Sstevel@tonic-gate 			if (lwp->lwp_psinfo.pr_sname != 'Z' &&
29757c478bd9Sstevel@tonic-gate 			    (rv = func(cd, &lwp->lwp_status)) != 0)
29767c478bd9Sstevel@tonic-gate 				break;
29777c478bd9Sstevel@tonic-gate 		}
29787c478bd9Sstevel@tonic-gate 
29797c478bd9Sstevel@tonic-gate 		return (rv);
29807c478bd9Sstevel@tonic-gate 	}
29817c478bd9Sstevel@tonic-gate 
29827c478bd9Sstevel@tonic-gate 	/*
29837c478bd9Sstevel@tonic-gate 	 * For the live process multi-LWP case, we have to work a little
29847c478bd9Sstevel@tonic-gate 	 * harder: the /proc/pid/lstatus file has the array of LWP structs.
29857c478bd9Sstevel@tonic-gate 	 */
29862a12f85aSJeremy Jones 	if ((Lhp = Plstatus(P)) == NULL)
29877c478bd9Sstevel@tonic-gate 		return (-1);
29887c478bd9Sstevel@tonic-gate 
29897c478bd9Sstevel@tonic-gate 	for (nlwp = Lhp->pr_nent, Lsp = (lwpstatus_t *)(uintptr_t)(Lhp + 1);
29907c478bd9Sstevel@tonic-gate 	    nlwp > 0;
29917c478bd9Sstevel@tonic-gate 	    nlwp--, Lsp = (lwpstatus_t *)((uintptr_t)Lsp + Lhp->pr_entsize)) {
29927c478bd9Sstevel@tonic-gate 		if ((rv = func(cd, Lsp)) != 0)
29937c478bd9Sstevel@tonic-gate 			break;
29947c478bd9Sstevel@tonic-gate 	}
29957c478bd9Sstevel@tonic-gate 
29967c478bd9Sstevel@tonic-gate 	free(Lhp);
29977c478bd9Sstevel@tonic-gate 	return (rv);
29987c478bd9Sstevel@tonic-gate }
29997c478bd9Sstevel@tonic-gate 
30007c478bd9Sstevel@tonic-gate /*
30017c478bd9Sstevel@tonic-gate  * Extended LWP iteration interface.
30027c478bd9Sstevel@tonic-gate  * Iterate over all LWPs, active and zombie.
30037c478bd9Sstevel@tonic-gate  */
30047c478bd9Sstevel@tonic-gate int
Plwp_iter_all(struct ps_prochandle * P,proc_lwp_all_f * func,void * cd)30057c478bd9Sstevel@tonic-gate Plwp_iter_all(struct ps_prochandle *P, proc_lwp_all_f *func, void *cd)
30067c478bd9Sstevel@tonic-gate {
30077c478bd9Sstevel@tonic-gate 	prheader_t *Lhp = NULL;
30087c478bd9Sstevel@tonic-gate 	lwpstatus_t *Lsp;
30097c478bd9Sstevel@tonic-gate 	lwpstatus_t *sp;
30107c478bd9Sstevel@tonic-gate 	prheader_t *Lphp = NULL;
30117c478bd9Sstevel@tonic-gate 	lwpsinfo_t *Lpsp;
30127c478bd9Sstevel@tonic-gate 	long nstat;
30137c478bd9Sstevel@tonic-gate 	long ninfo;
30147c478bd9Sstevel@tonic-gate 	int rv;
30157c478bd9Sstevel@tonic-gate 
30167c478bd9Sstevel@tonic-gate retry:
30177c478bd9Sstevel@tonic-gate 	if (Lhp != NULL)
30187c478bd9Sstevel@tonic-gate 		free(Lhp);
30197c478bd9Sstevel@tonic-gate 	if (Lphp != NULL)
30207c478bd9Sstevel@tonic-gate 		free(Lphp);
30217c478bd9Sstevel@tonic-gate 	if (P->state == PS_RUN)
30227c478bd9Sstevel@tonic-gate 		(void) Pstopstatus(P, PCNULL, 0);
30237c478bd9Sstevel@tonic-gate 	(void) Ppsinfo(P);
30247c478bd9Sstevel@tonic-gate 
30257c478bd9Sstevel@tonic-gate 	if (P->state == PS_STOP)
30267c478bd9Sstevel@tonic-gate 		Psync(P);
30277c478bd9Sstevel@tonic-gate 
30287c478bd9Sstevel@tonic-gate 	/*
30297c478bd9Sstevel@tonic-gate 	 * For either live processes or cores, the single LWP case is easy:
30307c478bd9Sstevel@tonic-gate 	 * the pstatus_t contains the lwpstatus_t for the only LWP and
30317c478bd9Sstevel@tonic-gate 	 * the psinfo_t contains the lwpsinfo_t for the only LWP.
30327c478bd9Sstevel@tonic-gate 	 */
30337c478bd9Sstevel@tonic-gate 	if (P->status.pr_nlwp + P->status.pr_nzomb <= 1)
30347c478bd9Sstevel@tonic-gate 		return (func(cd, &P->status.pr_lwp, &P->psinfo.pr_lwp));
30357c478bd9Sstevel@tonic-gate 
30367c478bd9Sstevel@tonic-gate 	/*
30377c478bd9Sstevel@tonic-gate 	 * For the core file multi-LWP case, we just iterate through the
30387c478bd9Sstevel@tonic-gate 	 * list of LWP structs we read in from the core file.
30397c478bd9Sstevel@tonic-gate 	 */
30407c478bd9Sstevel@tonic-gate 	if (P->state == PS_DEAD) {
30412a12f85aSJeremy Jones 		core_info_t *core = P->data;
304250d4d24eSRobert Mustacchi 		lwp_info_t *lwp;
30437c478bd9Sstevel@tonic-gate 
304450d4d24eSRobert Mustacchi 		for (lwp = list_tail(&core->core_lwp_head); lwp != NULL;
304550d4d24eSRobert Mustacchi 		    lwp = list_prev(&core->core_lwp_head, lwp)) {
30467c478bd9Sstevel@tonic-gate 			sp = (lwp->lwp_psinfo.pr_sname == 'Z')? NULL :
3047d7755b5aSrh 			    &lwp->lwp_status;
30487c478bd9Sstevel@tonic-gate 			if ((rv = func(cd, sp, &lwp->lwp_psinfo)) != 0)
30497c478bd9Sstevel@tonic-gate 				break;
30507c478bd9Sstevel@tonic-gate 		}
30517c478bd9Sstevel@tonic-gate 
30527c478bd9Sstevel@tonic-gate 		return (rv);
30537c478bd9Sstevel@tonic-gate 	}
30547c478bd9Sstevel@tonic-gate 
30557c478bd9Sstevel@tonic-gate 	/*
30562a12f85aSJeremy Jones 	 * For all other cases retrieve the array of lwpstatus_t's and
30572a12f85aSJeremy Jones 	 * lwpsinfo_t's.
30587c478bd9Sstevel@tonic-gate 	 */
30592a12f85aSJeremy Jones 	if ((Lhp = Plstatus(P)) == NULL)
30607c478bd9Sstevel@tonic-gate 		return (-1);
30612a12f85aSJeremy Jones 	if ((Lphp = Plpsinfo(P)) == NULL) {
30627c478bd9Sstevel@tonic-gate 		free(Lhp);
30637c478bd9Sstevel@tonic-gate 		return (-1);
30647c478bd9Sstevel@tonic-gate 	}
30657c478bd9Sstevel@tonic-gate 
30667c478bd9Sstevel@tonic-gate 	/*
30677c478bd9Sstevel@tonic-gate 	 * If we are looking at a running process, or one we do not control,
30687c478bd9Sstevel@tonic-gate 	 * the active and zombie lwps in the process may have changed since
30697c478bd9Sstevel@tonic-gate 	 * we read the process status structure.  If so, just start over.
30707c478bd9Sstevel@tonic-gate 	 */
30717c478bd9Sstevel@tonic-gate 	if (Lhp->pr_nent != P->status.pr_nlwp ||
30727c478bd9Sstevel@tonic-gate 	    Lphp->pr_nent != P->status.pr_nlwp + P->status.pr_nzomb)
30737c478bd9Sstevel@tonic-gate 		goto retry;
30747c478bd9Sstevel@tonic-gate 
30757c478bd9Sstevel@tonic-gate 	/*
30767c478bd9Sstevel@tonic-gate 	 * To be perfectly safe, prescan the two arrays, checking consistency.
30777c478bd9Sstevel@tonic-gate 	 * We rely on /proc giving us lwpstatus_t's and lwpsinfo_t's in the
30787c478bd9Sstevel@tonic-gate 	 * same order (the lwp directory order) in their respective files.
30797c478bd9Sstevel@tonic-gate 	 * We also rely on there being (possibly) more lwpsinfo_t's than
30807c478bd9Sstevel@tonic-gate 	 * lwpstatus_t's (the extra lwpsinfo_t's are for zombie lwps).
30817c478bd9Sstevel@tonic-gate 	 */
30827c478bd9Sstevel@tonic-gate 	Lsp = (lwpstatus_t *)(uintptr_t)(Lhp + 1);
30837c478bd9Sstevel@tonic-gate 	Lpsp = (lwpsinfo_t *)(uintptr_t)(Lphp + 1);
30847c478bd9Sstevel@tonic-gate 	nstat = Lhp->pr_nent;
30857c478bd9Sstevel@tonic-gate 	for (ninfo = Lphp->pr_nent; ninfo != 0; ninfo--) {
30867c478bd9Sstevel@tonic-gate 		if (Lpsp->pr_sname != 'Z') {
30877c478bd9Sstevel@tonic-gate 			/*
30887c478bd9Sstevel@tonic-gate 			 * Not a zombie lwp; check for matching lwpids.
30897c478bd9Sstevel@tonic-gate 			 */
30907c478bd9Sstevel@tonic-gate 			if (nstat == 0 || Lsp->pr_lwpid != Lpsp->pr_lwpid)
30917c478bd9Sstevel@tonic-gate 				goto retry;
30927c478bd9Sstevel@tonic-gate 			Lsp = (lwpstatus_t *)((uintptr_t)Lsp + Lhp->pr_entsize);
30937c478bd9Sstevel@tonic-gate 			nstat--;
30947c478bd9Sstevel@tonic-gate 		}
30957c478bd9Sstevel@tonic-gate 		Lpsp = (lwpsinfo_t *)((uintptr_t)Lpsp + Lphp->pr_entsize);
30967c478bd9Sstevel@tonic-gate 	}
30977c478bd9Sstevel@tonic-gate 	if (nstat != 0)
30987c478bd9Sstevel@tonic-gate 		goto retry;
30997c478bd9Sstevel@tonic-gate 
31007c478bd9Sstevel@tonic-gate 	/*
31017c478bd9Sstevel@tonic-gate 	 * Rescan, this time for real.
31027c478bd9Sstevel@tonic-gate 	 */
31037c478bd9Sstevel@tonic-gate 	Lsp = (lwpstatus_t *)(uintptr_t)(Lhp + 1);
31047c478bd9Sstevel@tonic-gate 	Lpsp = (lwpsinfo_t *)(uintptr_t)(Lphp + 1);
31057c478bd9Sstevel@tonic-gate 	for (ninfo = Lphp->pr_nent; ninfo != 0; ninfo--) {
31067c478bd9Sstevel@tonic-gate 		if (Lpsp->pr_sname != 'Z') {
31077c478bd9Sstevel@tonic-gate 			sp = Lsp;
31087c478bd9Sstevel@tonic-gate 			Lsp = (lwpstatus_t *)((uintptr_t)Lsp + Lhp->pr_entsize);
31097c478bd9Sstevel@tonic-gate 		} else {
31107c478bd9Sstevel@tonic-gate 			sp = NULL;
31117c478bd9Sstevel@tonic-gate 		}
31127c478bd9Sstevel@tonic-gate 		if ((rv = func(cd, sp, Lpsp)) != 0)
31137c478bd9Sstevel@tonic-gate 			break;
31147c478bd9Sstevel@tonic-gate 		Lpsp = (lwpsinfo_t *)((uintptr_t)Lpsp + Lphp->pr_entsize);
31157c478bd9Sstevel@tonic-gate 	}
31167c478bd9Sstevel@tonic-gate 
31177c478bd9Sstevel@tonic-gate 	free(Lhp);
31187c478bd9Sstevel@tonic-gate 	free(Lphp);
31197c478bd9Sstevel@tonic-gate 	return (rv);
31207c478bd9Sstevel@tonic-gate }
31217c478bd9Sstevel@tonic-gate 
31227c478bd9Sstevel@tonic-gate core_content_t
Pcontent(struct ps_prochandle * P)31237c478bd9Sstevel@tonic-gate Pcontent(struct ps_prochandle *P)
31247c478bd9Sstevel@tonic-gate {
31252a12f85aSJeremy Jones 	core_info_t *core = P->data;
31262a12f85aSJeremy Jones 
31277c478bd9Sstevel@tonic-gate 	if (P->state == PS_DEAD)
31282a12f85aSJeremy Jones 		return (core->core_content);
31297c478bd9Sstevel@tonic-gate 	if (P->state == PS_IDLE)
31307c478bd9Sstevel@tonic-gate 		return (CC_CONTENT_TEXT | CC_CONTENT_DATA | CC_CONTENT_CTF);
31317c478bd9Sstevel@tonic-gate 
31327c478bd9Sstevel@tonic-gate 	return (CC_CONTENT_ALL);
31337c478bd9Sstevel@tonic-gate }
31347c478bd9Sstevel@tonic-gate 
31357c478bd9Sstevel@tonic-gate /*
31367c478bd9Sstevel@tonic-gate  * =================================================================
31377c478bd9Sstevel@tonic-gate  * The remainder of the functions in this file are for the
31387c478bd9Sstevel@tonic-gate  * control of individual LWPs in the controlled process.
31397c478bd9Sstevel@tonic-gate  * =================================================================
31407c478bd9Sstevel@tonic-gate  */
31417c478bd9Sstevel@tonic-gate 
31427c478bd9Sstevel@tonic-gate /*
31437c478bd9Sstevel@tonic-gate  * Find an entry in the process hash table for the specified lwpid.
31447c478bd9Sstevel@tonic-gate  * The entry will either point to an existing struct ps_lwphandle
31457c478bd9Sstevel@tonic-gate  * or it will point to an empty slot for a new struct ps_lwphandle.
31467c478bd9Sstevel@tonic-gate  */
31477c478bd9Sstevel@tonic-gate static struct ps_lwphandle **
Lfind_slot(struct ps_prochandle * P,lwpid_t lwpid)3148*ed093b41SRobert Mustacchi Lfind_slot(struct ps_prochandle *P, lwpid_t lwpid)
31497c478bd9Sstevel@tonic-gate {
31507c478bd9Sstevel@tonic-gate 	struct ps_lwphandle **Lp;
31517c478bd9Sstevel@tonic-gate 	struct ps_lwphandle *L;
31527c478bd9Sstevel@tonic-gate 
31537c478bd9Sstevel@tonic-gate 	for (Lp = &P->hashtab[lwpid % (HASHSIZE - 1)];
31547c478bd9Sstevel@tonic-gate 	    (L = *Lp) != NULL; Lp = &L->lwp_hash)
31557c478bd9Sstevel@tonic-gate 		if (L->lwp_id == lwpid)
31567c478bd9Sstevel@tonic-gate 			break;
31577c478bd9Sstevel@tonic-gate 	return (Lp);
31587c478bd9Sstevel@tonic-gate }
31597c478bd9Sstevel@tonic-gate 
3160*ed093b41SRobert Mustacchi /*
3161*ed093b41SRobert Mustacchi  * A wrapper around Lfind_slot() that is suitable for the rest of the internal
3162*ed093b41SRobert Mustacchi  * consumers who don't care about a slot, merely existence.
3163*ed093b41SRobert Mustacchi  */
3164*ed093b41SRobert Mustacchi struct ps_lwphandle *
Lfind(struct ps_prochandle * P,lwpid_t lwpid)3165*ed093b41SRobert Mustacchi Lfind(struct ps_prochandle *P, lwpid_t lwpid)
3166*ed093b41SRobert Mustacchi {
3167*ed093b41SRobert Mustacchi 	if (P->hashtab == NULL) {
3168*ed093b41SRobert Mustacchi 		return (NULL);
3169*ed093b41SRobert Mustacchi 	}
3170*ed093b41SRobert Mustacchi 
3171*ed093b41SRobert Mustacchi 	return (*Lfind_slot(P, lwpid));
3172*ed093b41SRobert Mustacchi }
3173*ed093b41SRobert Mustacchi 
31747c478bd9Sstevel@tonic-gate /*
31757c478bd9Sstevel@tonic-gate  * Grab an LWP contained within the controlled process.
31767c478bd9Sstevel@tonic-gate  * Return an opaque pointer to its LWP control structure.
31777c478bd9Sstevel@tonic-gate  *	perr: pointer to error return code.
31787c478bd9Sstevel@tonic-gate  */
31797c478bd9Sstevel@tonic-gate struct ps_lwphandle *
Lgrab(struct ps_prochandle * P,lwpid_t lwpid,int * perr)31807c478bd9Sstevel@tonic-gate Lgrab(struct ps_prochandle *P, lwpid_t lwpid, int *perr)
31817c478bd9Sstevel@tonic-gate {
31827c478bd9Sstevel@tonic-gate 	struct ps_lwphandle **Lp;
31837c478bd9Sstevel@tonic-gate 	struct ps_lwphandle *L;
31847c478bd9Sstevel@tonic-gate 	int fd;
31859acbbeafSnn 	char procname[PATH_MAX];
31867c478bd9Sstevel@tonic-gate 	char *fname;
31877c478bd9Sstevel@tonic-gate 	int rc = 0;
31887c478bd9Sstevel@tonic-gate 
31897c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&P->proc_lock);
31907c478bd9Sstevel@tonic-gate 
31917c478bd9Sstevel@tonic-gate 	if (P->state == PS_UNDEAD || P->state == PS_IDLE)
31927c478bd9Sstevel@tonic-gate 		rc = G_NOPROC;
31937c478bd9Sstevel@tonic-gate 	else if (P->hashtab == NULL &&
31947c478bd9Sstevel@tonic-gate 	    (P->hashtab = calloc(HASHSIZE, sizeof (struct ps_lwphandle *)))
31957c478bd9Sstevel@tonic-gate 	    == NULL)
31967c478bd9Sstevel@tonic-gate 		rc = G_STRANGE;
3197*ed093b41SRobert Mustacchi 	else if (*(Lp = Lfind_slot(P, lwpid)) != NULL)
31987c478bd9Sstevel@tonic-gate 		rc = G_BUSY;
31997c478bd9Sstevel@tonic-gate 	else if ((L = malloc(sizeof (struct ps_lwphandle))) == NULL)
32007c478bd9Sstevel@tonic-gate 		rc = G_STRANGE;
32017c478bd9Sstevel@tonic-gate 	if (rc) {
32027c478bd9Sstevel@tonic-gate 		*perr = rc;
32037c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&P->proc_lock);
32047c478bd9Sstevel@tonic-gate 		return (NULL);
32057c478bd9Sstevel@tonic-gate 	}
32067c478bd9Sstevel@tonic-gate 
32077c478bd9Sstevel@tonic-gate 	(void) memset(L, 0, sizeof (*L));
32087c478bd9Sstevel@tonic-gate 	L->lwp_ctlfd = -1;
32097c478bd9Sstevel@tonic-gate 	L->lwp_statfd = -1;
32107c478bd9Sstevel@tonic-gate 	L->lwp_proc = P;
32117c478bd9Sstevel@tonic-gate 	L->lwp_id = lwpid;
32127c478bd9Sstevel@tonic-gate 	*Lp = L;	/* insert into the hash table */
32137c478bd9Sstevel@tonic-gate 
32147c478bd9Sstevel@tonic-gate 	if (P->state == PS_DEAD) {	/* core file */
32157c478bd9Sstevel@tonic-gate 		if (getlwpstatus(P, lwpid, &L->lwp_status) == -1) {
32167c478bd9Sstevel@tonic-gate 			rc = G_NOPROC;
32177c478bd9Sstevel@tonic-gate 			goto err;
32187c478bd9Sstevel@tonic-gate 		}
32197c478bd9Sstevel@tonic-gate 		L->lwp_state = PS_DEAD;
32207c478bd9Sstevel@tonic-gate 		*perr = 0;
32217c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&P->proc_lock);
32227c478bd9Sstevel@tonic-gate 		return (L);
32237c478bd9Sstevel@tonic-gate 	}
32247c478bd9Sstevel@tonic-gate 
32257c478bd9Sstevel@tonic-gate 	/*
32267c478bd9Sstevel@tonic-gate 	 * Open the /proc/<pid>/lwp/<lwpid> files
32277c478bd9Sstevel@tonic-gate 	 */
32289acbbeafSnn 	(void) snprintf(procname, sizeof (procname), "%s/%d/lwp/%d/",
32299acbbeafSnn 	    procfs_path, (int)P->pid, (int)lwpid);
32307c478bd9Sstevel@tonic-gate 	fname = procname + strlen(procname);
32317c478bd9Sstevel@tonic-gate 	(void) set_minfd();
32327c478bd9Sstevel@tonic-gate 
32337c478bd9Sstevel@tonic-gate 	(void) strcpy(fname, "lwpstatus");
32347c478bd9Sstevel@tonic-gate 	if ((fd = open(procname, O_RDONLY)) < 0 ||
32357c478bd9Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
32367c478bd9Sstevel@tonic-gate 		switch (errno) {
32377c478bd9Sstevel@tonic-gate 		case ENOENT:
32387c478bd9Sstevel@tonic-gate 			rc = G_NOPROC;
32397c478bd9Sstevel@tonic-gate 			break;
32407c478bd9Sstevel@tonic-gate 		default:
32417c478bd9Sstevel@tonic-gate 			dprintf("Lgrab: failed to open %s: %s\n",
32427c478bd9Sstevel@tonic-gate 			    procname, strerror(errno));
32437c478bd9Sstevel@tonic-gate 			rc = G_STRANGE;
32447c478bd9Sstevel@tonic-gate 			break;
32457c478bd9Sstevel@tonic-gate 		}
32467c478bd9Sstevel@tonic-gate 		goto err;
32477c478bd9Sstevel@tonic-gate 	}
32487c478bd9Sstevel@tonic-gate 	L->lwp_statfd = fd;
32497c478bd9Sstevel@tonic-gate 
32507c478bd9Sstevel@tonic-gate 	if (pread(fd, &L->lwp_status, sizeof (L->lwp_status), (off_t)0) < 0) {
32517c478bd9Sstevel@tonic-gate 		switch (errno) {
32527c478bd9Sstevel@tonic-gate 		case ENOENT:
32537c478bd9Sstevel@tonic-gate 			rc = G_NOPROC;
32547c478bd9Sstevel@tonic-gate 			break;
32557c478bd9Sstevel@tonic-gate 		default:
32567c478bd9Sstevel@tonic-gate 			dprintf("Lgrab: failed to read %s: %s\n",
32577c478bd9Sstevel@tonic-gate 			    procname, strerror(errno));
32587c478bd9Sstevel@tonic-gate 			rc = G_STRANGE;
32597c478bd9Sstevel@tonic-gate 			break;
32607c478bd9Sstevel@tonic-gate 		}
32617c478bd9Sstevel@tonic-gate 		goto err;
32627c478bd9Sstevel@tonic-gate 	}
32637c478bd9Sstevel@tonic-gate 
32647c478bd9Sstevel@tonic-gate 	(void) strcpy(fname, "lwpctl");
32657c478bd9Sstevel@tonic-gate 	if ((fd = open(procname, O_WRONLY)) < 0 ||
32667c478bd9Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
32677c478bd9Sstevel@tonic-gate 		switch (errno) {
32687c478bd9Sstevel@tonic-gate 		case ENOENT:
32697c478bd9Sstevel@tonic-gate 			rc = G_NOPROC;
32707c478bd9Sstevel@tonic-gate 			break;
32717c478bd9Sstevel@tonic-gate 		default:
32727c478bd9Sstevel@tonic-gate 			dprintf("Lgrab: failed to open %s: %s\n",
32737c478bd9Sstevel@tonic-gate 			    procname, strerror(errno));
32747c478bd9Sstevel@tonic-gate 			rc = G_STRANGE;
32757c478bd9Sstevel@tonic-gate 			break;
32767c478bd9Sstevel@tonic-gate 		}
32777c478bd9Sstevel@tonic-gate 		goto err;
32787c478bd9Sstevel@tonic-gate 	}
32797c478bd9Sstevel@tonic-gate 	L->lwp_ctlfd = fd;
32807c478bd9Sstevel@tonic-gate 
32817c478bd9Sstevel@tonic-gate 	L->lwp_state =
3282d7755b5aSrh 	    ((L->lwp_status.pr_flags & (PR_STOPPED|PR_ISTOP))
3283d7755b5aSrh 	    == (PR_STOPPED|PR_ISTOP))?
3284d7755b5aSrh 	    PS_STOP : PS_RUN;
32857c478bd9Sstevel@tonic-gate 
32867c478bd9Sstevel@tonic-gate 	*perr = 0;
32877c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&P->proc_lock);
32887c478bd9Sstevel@tonic-gate 	return (L);
32897c478bd9Sstevel@tonic-gate 
32907c478bd9Sstevel@tonic-gate err:
32917c478bd9Sstevel@tonic-gate 	Lfree_internal(P, L);
32927c478bd9Sstevel@tonic-gate 	*perr = rc;
32937c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&P->proc_lock);
32947c478bd9Sstevel@tonic-gate 	return (NULL);
32957c478bd9Sstevel@tonic-gate }
32967c478bd9Sstevel@tonic-gate 
32977c478bd9Sstevel@tonic-gate /*
32987c478bd9Sstevel@tonic-gate  * Return a printable string corresponding to an Lgrab() error return.
32997c478bd9Sstevel@tonic-gate  */
33007c478bd9Sstevel@tonic-gate const char *
Lgrab_error(int error)33017c478bd9Sstevel@tonic-gate Lgrab_error(int error)
33027c478bd9Sstevel@tonic-gate {
33037c478bd9Sstevel@tonic-gate 	const char *str;
33047c478bd9Sstevel@tonic-gate 
33057c478bd9Sstevel@tonic-gate 	switch (error) {
33067c478bd9Sstevel@tonic-gate 	case G_NOPROC:
33077c478bd9Sstevel@tonic-gate 		str = "no such LWP";
33087c478bd9Sstevel@tonic-gate 		break;
33097c478bd9Sstevel@tonic-gate 	case G_BUSY:
33107c478bd9Sstevel@tonic-gate 		str = "LWP already grabbed";
33117c478bd9Sstevel@tonic-gate 		break;
33127c478bd9Sstevel@tonic-gate 	case G_STRANGE:
33137c478bd9Sstevel@tonic-gate 		str = "unanticipated system error";
33147c478bd9Sstevel@tonic-gate 		break;
33157c478bd9Sstevel@tonic-gate 	default:
33167c478bd9Sstevel@tonic-gate 		str = "unknown error";
33177c478bd9Sstevel@tonic-gate 		break;
33187c478bd9Sstevel@tonic-gate 	}
33197c478bd9Sstevel@tonic-gate 
33207c478bd9Sstevel@tonic-gate 	return (str);
33217c478bd9Sstevel@tonic-gate }
33227c478bd9Sstevel@tonic-gate 
33237c478bd9Sstevel@tonic-gate /*
33247c478bd9Sstevel@tonic-gate  * Free an LWP control structure.
33257c478bd9Sstevel@tonic-gate  */
33267c478bd9Sstevel@tonic-gate void
Lfree(struct ps_lwphandle * L)33277c478bd9Sstevel@tonic-gate Lfree(struct ps_lwphandle *L)
33287c478bd9Sstevel@tonic-gate {
33297c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = L->lwp_proc;
33307c478bd9Sstevel@tonic-gate 
33317c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&P->proc_lock);
33327c478bd9Sstevel@tonic-gate 	Lfree_internal(P, L);
33337c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&P->proc_lock);
33347c478bd9Sstevel@tonic-gate }
33357c478bd9Sstevel@tonic-gate 
33367c478bd9Sstevel@tonic-gate static void
Lfree_internal(struct ps_prochandle * P,struct ps_lwphandle * L)33377c478bd9Sstevel@tonic-gate Lfree_internal(struct ps_prochandle *P, struct ps_lwphandle *L)
33387c478bd9Sstevel@tonic-gate {
3339*ed093b41SRobert Mustacchi 	*Lfind_slot(P, L->lwp_id) = L->lwp_hash; /* delete from hash table */
33407c478bd9Sstevel@tonic-gate 	if (L->lwp_ctlfd >= 0)
33417c478bd9Sstevel@tonic-gate 		(void) close(L->lwp_ctlfd);
33427c478bd9Sstevel@tonic-gate 	if (L->lwp_statfd >= 0)
33437c478bd9Sstevel@tonic-gate 		(void) close(L->lwp_statfd);
33447c478bd9Sstevel@tonic-gate 
33457c478bd9Sstevel@tonic-gate 	/* clear out the structure as a precaution against reuse */
33467c478bd9Sstevel@tonic-gate 	(void) memset(L, 0, sizeof (*L));
33477c478bd9Sstevel@tonic-gate 	L->lwp_ctlfd = -1;
33487c478bd9Sstevel@tonic-gate 	L->lwp_statfd = -1;
33497c478bd9Sstevel@tonic-gate 
33507c478bd9Sstevel@tonic-gate 	free(L);
33517c478bd9Sstevel@tonic-gate }
33527c478bd9Sstevel@tonic-gate 
33537c478bd9Sstevel@tonic-gate /*
33547c478bd9Sstevel@tonic-gate  * Return the state of the process, one of the PS_* values.
33557c478bd9Sstevel@tonic-gate  */
33567c478bd9Sstevel@tonic-gate int
Lstate(struct ps_lwphandle * L)33577c478bd9Sstevel@tonic-gate Lstate(struct ps_lwphandle *L)
33587c478bd9Sstevel@tonic-gate {
33597c478bd9Sstevel@tonic-gate 	return (L->lwp_state);
33607c478bd9Sstevel@tonic-gate }
33617c478bd9Sstevel@tonic-gate 
33627c478bd9Sstevel@tonic-gate /*
33637c478bd9Sstevel@tonic-gate  * Return the open control file descriptor for the LWP.
33647c478bd9Sstevel@tonic-gate  * Clients must not close this file descriptor, nor use it
33657c478bd9Sstevel@tonic-gate  * after the LWP is freed.
33667c478bd9Sstevel@tonic-gate  */
33677c478bd9Sstevel@tonic-gate int
Lctlfd(struct ps_lwphandle * L)33687c478bd9Sstevel@tonic-gate Lctlfd(struct ps_lwphandle *L)
33697c478bd9Sstevel@tonic-gate {
33707c478bd9Sstevel@tonic-gate 	return (L->lwp_ctlfd);
33717c478bd9Sstevel@tonic-gate }
33727c478bd9Sstevel@tonic-gate 
33737c478bd9Sstevel@tonic-gate /*
33747c478bd9Sstevel@tonic-gate  * Return a pointer to the LWP lwpsinfo structure.
33757c478bd9Sstevel@tonic-gate  * Clients should not hold on to this pointer indefinitely.
33767c478bd9Sstevel@tonic-gate  * It will become invalid on Lfree().
33777c478bd9Sstevel@tonic-gate  */
33787c478bd9Sstevel@tonic-gate const lwpsinfo_t *
Lpsinfo(struct ps_lwphandle * L)33797c478bd9Sstevel@tonic-gate Lpsinfo(struct ps_lwphandle *L)
33807c478bd9Sstevel@tonic-gate {
33817c478bd9Sstevel@tonic-gate 	if (Plwp_getpsinfo(L->lwp_proc, L->lwp_id, &L->lwp_psinfo) == -1)
33827c478bd9Sstevel@tonic-gate 		return (NULL);
33837c478bd9Sstevel@tonic-gate 
33847c478bd9Sstevel@tonic-gate 	return (&L->lwp_psinfo);
33857c478bd9Sstevel@tonic-gate }
33867c478bd9Sstevel@tonic-gate 
33877c478bd9Sstevel@tonic-gate /*
33887c478bd9Sstevel@tonic-gate  * Return a pointer to the LWP status structure.
33897c478bd9Sstevel@tonic-gate  * Clients should not hold on to this pointer indefinitely.
33907c478bd9Sstevel@tonic-gate  * It will become invalid on Lfree().
33917c478bd9Sstevel@tonic-gate  */
33927c478bd9Sstevel@tonic-gate const lwpstatus_t *
Lstatus(struct ps_lwphandle * L)33937c478bd9Sstevel@tonic-gate Lstatus(struct ps_lwphandle *L)
33947c478bd9Sstevel@tonic-gate {
33957c478bd9Sstevel@tonic-gate 	return (&L->lwp_status);
33967c478bd9Sstevel@tonic-gate }
33977c478bd9Sstevel@tonic-gate 
33987c478bd9Sstevel@tonic-gate /*
33997c478bd9Sstevel@tonic-gate  * Given an LWP handle, return the process handle.
34007c478bd9Sstevel@tonic-gate  */
34017c478bd9Sstevel@tonic-gate struct ps_prochandle *
Lprochandle(struct ps_lwphandle * L)34027c478bd9Sstevel@tonic-gate Lprochandle(struct ps_lwphandle *L)
34037c478bd9Sstevel@tonic-gate {
34047c478bd9Sstevel@tonic-gate 	return (L->lwp_proc);
34057c478bd9Sstevel@tonic-gate }
34067c478bd9Sstevel@tonic-gate 
34077c478bd9Sstevel@tonic-gate /*
34087c478bd9Sstevel@tonic-gate  * Ensure that all cached state is written to the LWP.
34097c478bd9Sstevel@tonic-gate  * The cached state is the LWP's signal mask and registers.
34107c478bd9Sstevel@tonic-gate  */
34117c478bd9Sstevel@tonic-gate void
Lsync(struct ps_lwphandle * L)34127c478bd9Sstevel@tonic-gate Lsync(struct ps_lwphandle *L)
34137c478bd9Sstevel@tonic-gate {
34147c478bd9Sstevel@tonic-gate 	int ctlfd = L->lwp_ctlfd;
34157c478bd9Sstevel@tonic-gate 	long cmd[2];
34167c478bd9Sstevel@tonic-gate 	iovec_t iov[4];
34177c478bd9Sstevel@tonic-gate 	int n = 0;
34187c478bd9Sstevel@tonic-gate 
34197c478bd9Sstevel@tonic-gate 	if (L->lwp_flags & SETHOLD) {
34207c478bd9Sstevel@tonic-gate 		cmd[0] = PCSHOLD;
34217c478bd9Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[0];
34227c478bd9Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
34237c478bd9Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&L->lwp_status.pr_lwphold;
34247c478bd9Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (L->lwp_status.pr_lwphold);
34257c478bd9Sstevel@tonic-gate 	}
34267c478bd9Sstevel@tonic-gate 	if (L->lwp_flags & SETREGS) {
34277c478bd9Sstevel@tonic-gate 		cmd[1] = PCSREG;
34287c478bd9Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[1];
34297c478bd9Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
34307c478bd9Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&L->lwp_status.pr_reg[0];
34317c478bd9Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (L->lwp_status.pr_reg);
34327c478bd9Sstevel@tonic-gate 	}
34337c478bd9Sstevel@tonic-gate 
34347c478bd9Sstevel@tonic-gate 	if (n == 0 || writev(ctlfd, iov, n) < 0)
34357c478bd9Sstevel@tonic-gate 		return;		/* nothing to do or write failed */
34367c478bd9Sstevel@tonic-gate 
34377c478bd9Sstevel@tonic-gate 	L->lwp_flags &= ~(SETHOLD|SETREGS);
34387c478bd9Sstevel@tonic-gate }
34397c478bd9Sstevel@tonic-gate 
34407c478bd9Sstevel@tonic-gate /*
34417c478bd9Sstevel@tonic-gate  * Wait for the specified LWP to stop or terminate.
34427c478bd9Sstevel@tonic-gate  * Or, just get the current status (PCNULL).
34437c478bd9Sstevel@tonic-gate  * Or, direct it to stop and get the current status (PCDSTOP).
34447c478bd9Sstevel@tonic-gate  */
3445*ed093b41SRobert Mustacchi int
Lstopstatus(struct ps_lwphandle * L,long request,uint_t msec)34467c478bd9Sstevel@tonic-gate Lstopstatus(struct ps_lwphandle *L,
3447d2a70789SRichard Lowe     long request,		/* PCNULL, PCDSTOP, PCSTOP, PCWSTOP */
3448d2a70789SRichard Lowe     uint_t msec)		/* if non-zero, timeout in milliseconds */
34497c478bd9Sstevel@tonic-gate {
34507c478bd9Sstevel@tonic-gate 	int ctlfd = L->lwp_ctlfd;
34517c478bd9Sstevel@tonic-gate 	long ctl[3];
34527c478bd9Sstevel@tonic-gate 	ssize_t rc;
34537c478bd9Sstevel@tonic-gate 	int err;
34547c478bd9Sstevel@tonic-gate 
34557c478bd9Sstevel@tonic-gate 	switch (L->lwp_state) {
34567c478bd9Sstevel@tonic-gate 	case PS_RUN:
34577c478bd9Sstevel@tonic-gate 		break;
34587c478bd9Sstevel@tonic-gate 	case PS_STOP:
34597c478bd9Sstevel@tonic-gate 		if (request != PCNULL && request != PCDSTOP)
34607c478bd9Sstevel@tonic-gate 			return (0);
34617c478bd9Sstevel@tonic-gate 		break;
34627c478bd9Sstevel@tonic-gate 	case PS_LOST:
34637c478bd9Sstevel@tonic-gate 		if (request != PCNULL) {
34647c478bd9Sstevel@tonic-gate 			errno = EAGAIN;
34657c478bd9Sstevel@tonic-gate 			return (-1);
34667c478bd9Sstevel@tonic-gate 		}
34677c478bd9Sstevel@tonic-gate 		break;
34687c478bd9Sstevel@tonic-gate 	case PS_UNDEAD:
34697c478bd9Sstevel@tonic-gate 	case PS_DEAD:
34707c478bd9Sstevel@tonic-gate 		if (request != PCNULL) {
34717c478bd9Sstevel@tonic-gate 			errno = ENOENT;
34727c478bd9Sstevel@tonic-gate 			return (-1);
34737c478bd9Sstevel@tonic-gate 		}
34747c478bd9Sstevel@tonic-gate 		break;
34757c478bd9Sstevel@tonic-gate 	default:	/* corrupted state */
34767c478bd9Sstevel@tonic-gate 		dprintf("Lstopstatus: corrupted state: %d\n", L->lwp_state);
34777c478bd9Sstevel@tonic-gate 		errno = EINVAL;
34787c478bd9Sstevel@tonic-gate 		return (-1);
34797c478bd9Sstevel@tonic-gate 	}
34807c478bd9Sstevel@tonic-gate 
34817c478bd9Sstevel@tonic-gate 	ctl[0] = PCDSTOP;
34827c478bd9Sstevel@tonic-gate 	ctl[1] = PCTWSTOP;
34837c478bd9Sstevel@tonic-gate 	ctl[2] = (long)msec;
34847c478bd9Sstevel@tonic-gate 	rc = 0;
34857c478bd9Sstevel@tonic-gate 	switch (request) {
34867c478bd9Sstevel@tonic-gate 	case PCSTOP:
34877c478bd9Sstevel@tonic-gate 		rc = write(ctlfd, &ctl[0], 3*sizeof (long));
34887c478bd9Sstevel@tonic-gate 		break;
34897c478bd9Sstevel@tonic-gate 	case PCWSTOP:
34907c478bd9Sstevel@tonic-gate 		rc = write(ctlfd, &ctl[1], 2*sizeof (long));
34917c478bd9Sstevel@tonic-gate 		break;
34927c478bd9Sstevel@tonic-gate 	case PCDSTOP:
34937c478bd9Sstevel@tonic-gate 		rc = write(ctlfd, &ctl[0], 1*sizeof (long));
34947c478bd9Sstevel@tonic-gate 		break;
34957c478bd9Sstevel@tonic-gate 	case PCNULL:
34967c478bd9Sstevel@tonic-gate 		if (L->lwp_state == PS_DEAD)
34977c478bd9Sstevel@tonic-gate 			return (0); /* Nothing else to do for cores */
34987c478bd9Sstevel@tonic-gate 		break;
34997c478bd9Sstevel@tonic-gate 	default:	/* programming error */
35007c478bd9Sstevel@tonic-gate 		errno = EINVAL;
35017c478bd9Sstevel@tonic-gate 		return (-1);
35027c478bd9Sstevel@tonic-gate 	}
35037c478bd9Sstevel@tonic-gate 	err = (rc < 0)? errno : 0;
35047c478bd9Sstevel@tonic-gate 	Lsync(L);
35057c478bd9Sstevel@tonic-gate 
35067c478bd9Sstevel@tonic-gate 	if (pread(L->lwp_statfd, &L->lwp_status,
35077c478bd9Sstevel@tonic-gate 	    sizeof (L->lwp_status), (off_t)0) < 0)
35087c478bd9Sstevel@tonic-gate 		err = errno;
35097c478bd9Sstevel@tonic-gate 
35107c478bd9Sstevel@tonic-gate 	if (err) {
35117c478bd9Sstevel@tonic-gate 		switch (err) {
35127c478bd9Sstevel@tonic-gate 		case EINTR:		/* user typed ctl-C */
35137c478bd9Sstevel@tonic-gate 		case ERESTART:
35147c478bd9Sstevel@tonic-gate 			dprintf("Lstopstatus: EINTR\n");
35157c478bd9Sstevel@tonic-gate 			break;
35167c478bd9Sstevel@tonic-gate 		case EAGAIN:		/* we lost control of the the process */
35177c478bd9Sstevel@tonic-gate 			dprintf("Lstopstatus: EAGAIN\n");
35187c478bd9Sstevel@tonic-gate 			L->lwp_state = PS_LOST;
35197c478bd9Sstevel@tonic-gate 			errno = err;
35207c478bd9Sstevel@tonic-gate 			return (-1);
35217c478bd9Sstevel@tonic-gate 		default:
35227c478bd9Sstevel@tonic-gate 			if (_libproc_debug) {
35237c478bd9Sstevel@tonic-gate 				const char *errstr;
35247c478bd9Sstevel@tonic-gate 
35257c478bd9Sstevel@tonic-gate 				switch (request) {
35267c478bd9Sstevel@tonic-gate 				case PCNULL:
35277c478bd9Sstevel@tonic-gate 					errstr = "Lstopstatus PCNULL"; break;
35287c478bd9Sstevel@tonic-gate 				case PCSTOP:
35297c478bd9Sstevel@tonic-gate 					errstr = "Lstopstatus PCSTOP"; break;
35307c478bd9Sstevel@tonic-gate 				case PCDSTOP:
35317c478bd9Sstevel@tonic-gate 					errstr = "Lstopstatus PCDSTOP"; break;
35327c478bd9Sstevel@tonic-gate 				case PCWSTOP:
35337c478bd9Sstevel@tonic-gate 					errstr = "Lstopstatus PCWSTOP"; break;
35347c478bd9Sstevel@tonic-gate 				default:
35357c478bd9Sstevel@tonic-gate 					errstr = "Lstopstatus PC???"; break;
35367c478bd9Sstevel@tonic-gate 				}
35377c478bd9Sstevel@tonic-gate 				dprintf("%s: %s\n", errstr, strerror(err));
35387c478bd9Sstevel@tonic-gate 			}
35397c478bd9Sstevel@tonic-gate 			L->lwp_state = PS_UNDEAD;
35407c478bd9Sstevel@tonic-gate 			errno = err;
35417c478bd9Sstevel@tonic-gate 			return (-1);
35427c478bd9Sstevel@tonic-gate 		}
35437c478bd9Sstevel@tonic-gate 	}
35447c478bd9Sstevel@tonic-gate 
35457c478bd9Sstevel@tonic-gate 	if ((L->lwp_status.pr_flags & (PR_STOPPED|PR_ISTOP))
35467c478bd9Sstevel@tonic-gate 	    != (PR_STOPPED|PR_ISTOP)) {
35477c478bd9Sstevel@tonic-gate 		L->lwp_state = PS_RUN;
35487c478bd9Sstevel@tonic-gate 		if (request == PCNULL || request == PCDSTOP || msec != 0)
35497c478bd9Sstevel@tonic-gate 			return (0);
35507c478bd9Sstevel@tonic-gate 		dprintf("Lstopstatus: LWP is not stopped\n");
35517c478bd9Sstevel@tonic-gate 		errno = EPROTO;
35527c478bd9Sstevel@tonic-gate 		return (-1);
35537c478bd9Sstevel@tonic-gate 	}
35547c478bd9Sstevel@tonic-gate 
35557c478bd9Sstevel@tonic-gate 	L->lwp_state = PS_STOP;
35567c478bd9Sstevel@tonic-gate 
35577c478bd9Sstevel@tonic-gate 	if (_libproc_debug)	/* debugging */
35587c478bd9Sstevel@tonic-gate 		prldump("Lstopstatus", &L->lwp_status);
35597c478bd9Sstevel@tonic-gate 
35607c478bd9Sstevel@tonic-gate 	switch (L->lwp_status.pr_why) {
35617c478bd9Sstevel@tonic-gate 	case PR_SYSENTRY:
35627c478bd9Sstevel@tonic-gate 	case PR_SYSEXIT:
35637c478bd9Sstevel@tonic-gate 	case PR_REQUESTED:
35647c478bd9Sstevel@tonic-gate 	case PR_SIGNALLED:
35657c478bd9Sstevel@tonic-gate 	case PR_FAULTED:
35667c478bd9Sstevel@tonic-gate 	case PR_JOBCONTROL:
35677c478bd9Sstevel@tonic-gate 	case PR_SUSPENDED:
35687c478bd9Sstevel@tonic-gate 		break;
35697c478bd9Sstevel@tonic-gate 	default:
35707c478bd9Sstevel@tonic-gate 		errno = EPROTO;
35717c478bd9Sstevel@tonic-gate 		return (-1);
35727c478bd9Sstevel@tonic-gate 	}
35737c478bd9Sstevel@tonic-gate 
35747c478bd9Sstevel@tonic-gate 	return (0);
35757c478bd9Sstevel@tonic-gate }
35767c478bd9Sstevel@tonic-gate 
35777c478bd9Sstevel@tonic-gate /*
35787c478bd9Sstevel@tonic-gate  * Wait for the LWP to stop for any reason.
35797c478bd9Sstevel@tonic-gate  */
35807c478bd9Sstevel@tonic-gate int
Lwait(struct ps_lwphandle * L,uint_t msec)35817c478bd9Sstevel@tonic-gate Lwait(struct ps_lwphandle *L, uint_t msec)
35827c478bd9Sstevel@tonic-gate {
35837c478bd9Sstevel@tonic-gate 	return (Lstopstatus(L, PCWSTOP, msec));
35847c478bd9Sstevel@tonic-gate }
35857c478bd9Sstevel@tonic-gate 
35867c478bd9Sstevel@tonic-gate /*
35877c478bd9Sstevel@tonic-gate  * Direct the LWP to stop; wait for it to stop.
35887c478bd9Sstevel@tonic-gate  */
35897c478bd9Sstevel@tonic-gate int
Lstop(struct ps_lwphandle * L,uint_t msec)35907c478bd9Sstevel@tonic-gate Lstop(struct ps_lwphandle *L, uint_t msec)
35917c478bd9Sstevel@tonic-gate {
35927c478bd9Sstevel@tonic-gate 	return (Lstopstatus(L, PCSTOP, msec));
35937c478bd9Sstevel@tonic-gate }
35947c478bd9Sstevel@tonic-gate 
35957c478bd9Sstevel@tonic-gate /*
35967c478bd9Sstevel@tonic-gate  * Direct the LWP to stop; don't wait.
35977c478bd9Sstevel@tonic-gate  */
35987c478bd9Sstevel@tonic-gate int
Ldstop(struct ps_lwphandle * L)35997c478bd9Sstevel@tonic-gate Ldstop(struct ps_lwphandle *L)
36007c478bd9Sstevel@tonic-gate {
36017c478bd9Sstevel@tonic-gate 	return (Lstopstatus(L, PCDSTOP, 0));
36027c478bd9Sstevel@tonic-gate }
36037c478bd9Sstevel@tonic-gate 
36047c478bd9Sstevel@tonic-gate /*
36057c478bd9Sstevel@tonic-gate  * Get the value of one register from stopped LWP.
36067c478bd9Sstevel@tonic-gate  */
36077c478bd9Sstevel@tonic-gate int
Lgetareg(struct ps_lwphandle * L,int regno,prgreg_t * preg)36087c478bd9Sstevel@tonic-gate Lgetareg(struct ps_lwphandle *L, int regno, prgreg_t *preg)
36097c478bd9Sstevel@tonic-gate {
36107c478bd9Sstevel@tonic-gate 	if (regno < 0 || regno >= NPRGREG) {
36117c478bd9Sstevel@tonic-gate 		errno = EINVAL;
36127c478bd9Sstevel@tonic-gate 		return (-1);
36137c478bd9Sstevel@tonic-gate 	}
36147c478bd9Sstevel@tonic-gate 
36157c478bd9Sstevel@tonic-gate 	if (L->lwp_state != PS_STOP) {
36167c478bd9Sstevel@tonic-gate 		errno = EBUSY;
36177c478bd9Sstevel@tonic-gate 		return (-1);
36187c478bd9Sstevel@tonic-gate 	}
36197c478bd9Sstevel@tonic-gate 
36207c478bd9Sstevel@tonic-gate 	*preg = L->lwp_status.pr_reg[regno];
36217c478bd9Sstevel@tonic-gate 	return (0);
36227c478bd9Sstevel@tonic-gate }
36237c478bd9Sstevel@tonic-gate 
36247c478bd9Sstevel@tonic-gate /*
36257c478bd9Sstevel@tonic-gate  * Put value of one register into stopped LWP.
36267c478bd9Sstevel@tonic-gate  */
36277c478bd9Sstevel@tonic-gate int
Lputareg(struct ps_lwphandle * L,int regno,prgreg_t reg)36287c478bd9Sstevel@tonic-gate Lputareg(struct ps_lwphandle *L, int regno, prgreg_t reg)
36297c478bd9Sstevel@tonic-gate {
36307c478bd9Sstevel@tonic-gate 	if (regno < 0 || regno >= NPRGREG) {
36317c478bd9Sstevel@tonic-gate 		errno = EINVAL;
36327c478bd9Sstevel@tonic-gate 		return (-1);
36337c478bd9Sstevel@tonic-gate 	}
36347c478bd9Sstevel@tonic-gate 
36357c478bd9Sstevel@tonic-gate 	if (L->lwp_state != PS_STOP) {
36367c478bd9Sstevel@tonic-gate 		errno = EBUSY;
36377c478bd9Sstevel@tonic-gate 		return (-1);
36387c478bd9Sstevel@tonic-gate 	}
36397c478bd9Sstevel@tonic-gate 
36407c478bd9Sstevel@tonic-gate 	L->lwp_status.pr_reg[regno] = reg;
36417c478bd9Sstevel@tonic-gate 	L->lwp_flags |= SETREGS;	/* set registers before continuing */
36427c478bd9Sstevel@tonic-gate 	return (0);
36437c478bd9Sstevel@tonic-gate }
36447c478bd9Sstevel@tonic-gate 
36457c478bd9Sstevel@tonic-gate int
Lsetrun(struct ps_lwphandle * L,int sig,int flags)36467c478bd9Sstevel@tonic-gate Lsetrun(struct ps_lwphandle *L,
3647d2a70789SRichard Lowe     int sig,	/* signal to pass to LWP */
3648d2a70789SRichard Lowe     int flags)	/* PRSTEP|PRSABORT|PRSTOP|PRCSIG|PRCFAULT */
36497c478bd9Sstevel@tonic-gate {
36507c478bd9Sstevel@tonic-gate 	int ctlfd = L->lwp_ctlfd;
36517c478bd9Sstevel@tonic-gate 	int sbits = (PR_DSTOP | PR_ISTOP | PR_ASLEEP);
36527c478bd9Sstevel@tonic-gate 
36537c478bd9Sstevel@tonic-gate 	long ctl[1 +					/* PCCFAULT	*/
3654d7755b5aSrh 	    1 + sizeof (siginfo_t)/sizeof (long) +	/* PCSSIG/PCCSIG */
3655d7755b5aSrh 	    2 ];					/* PCRUN	*/
36567c478bd9Sstevel@tonic-gate 
36577c478bd9Sstevel@tonic-gate 	long *ctlp = ctl;
36587c478bd9Sstevel@tonic-gate 	size_t size;
36597c478bd9Sstevel@tonic-gate 
36607c478bd9Sstevel@tonic-gate 	if (L->lwp_state != PS_STOP &&
36617c478bd9Sstevel@tonic-gate 	    (L->lwp_status.pr_flags & sbits) == 0) {
36627c478bd9Sstevel@tonic-gate 		errno = EBUSY;
36637c478bd9Sstevel@tonic-gate 		return (-1);
36647c478bd9Sstevel@tonic-gate 	}
36657c478bd9Sstevel@tonic-gate 
36667c478bd9Sstevel@tonic-gate 	Lsync(L);	/* flush registers */
36677c478bd9Sstevel@tonic-gate 
36687c478bd9Sstevel@tonic-gate 	if (flags & PRCFAULT) {		/* clear current fault */
36697c478bd9Sstevel@tonic-gate 		*ctlp++ = PCCFAULT;
36707c478bd9Sstevel@tonic-gate 		flags &= ~PRCFAULT;
36717c478bd9Sstevel@tonic-gate 	}
36727c478bd9Sstevel@tonic-gate 
36737c478bd9Sstevel@tonic-gate 	if (flags & PRCSIG) {		/* clear current signal */
36747c478bd9Sstevel@tonic-gate 		*ctlp++ = PCCSIG;
36757c478bd9Sstevel@tonic-gate 		flags &= ~PRCSIG;
36767c478bd9Sstevel@tonic-gate 	} else if (sig && sig != L->lwp_status.pr_cursig) {
36777c478bd9Sstevel@tonic-gate 		/* make current signal */
36787c478bd9Sstevel@tonic-gate 		siginfo_t *infop;
36797c478bd9Sstevel@tonic-gate 
36807c478bd9Sstevel@tonic-gate 		*ctlp++ = PCSSIG;
36817c478bd9Sstevel@tonic-gate 		infop = (siginfo_t *)ctlp;
36827c478bd9Sstevel@tonic-gate 		(void) memset(infop, 0, sizeof (*infop));
36837c478bd9Sstevel@tonic-gate 		infop->si_signo = sig;
36847c478bd9Sstevel@tonic-gate 		ctlp += sizeof (siginfo_t) / sizeof (long);
36857c478bd9Sstevel@tonic-gate 	}
36867c478bd9Sstevel@tonic-gate 
36877c478bd9Sstevel@tonic-gate 	*ctlp++ = PCRUN;
36887c478bd9Sstevel@tonic-gate 	*ctlp++ = flags;
36897c478bd9Sstevel@tonic-gate 	size = (char *)ctlp - (char *)ctl;
36907c478bd9Sstevel@tonic-gate 
36917c478bd9Sstevel@tonic-gate 	L->lwp_proc->info_valid = 0; /* will need to update map and file info */
36927c478bd9Sstevel@tonic-gate 	L->lwp_proc->state = PS_RUN;
36937c478bd9Sstevel@tonic-gate 	L->lwp_state = PS_RUN;
36947c478bd9Sstevel@tonic-gate 
36957c478bd9Sstevel@tonic-gate 	if (write(ctlfd, ctl, size) != size) {
36967c478bd9Sstevel@tonic-gate 		/* Pretend that a job-stopped LWP is running */
36977c478bd9Sstevel@tonic-gate 		if (errno != EBUSY || L->lwp_status.pr_why != PR_JOBCONTROL)
36987c478bd9Sstevel@tonic-gate 			return (Lstopstatus(L, PCNULL, 0));
36997c478bd9Sstevel@tonic-gate 	}
37007c478bd9Sstevel@tonic-gate 
37017c478bd9Sstevel@tonic-gate 	return (0);
37027c478bd9Sstevel@tonic-gate }
37037c478bd9Sstevel@tonic-gate 
37047c478bd9Sstevel@tonic-gate int
Lclearsig(struct ps_lwphandle * L)37057c478bd9Sstevel@tonic-gate Lclearsig(struct ps_lwphandle *L)
37067c478bd9Sstevel@tonic-gate {
37077c478bd9Sstevel@tonic-gate 	int ctlfd = L->lwp_ctlfd;
37087c478bd9Sstevel@tonic-gate 	long ctl = PCCSIG;
37097c478bd9Sstevel@tonic-gate 
37107c478bd9Sstevel@tonic-gate 	if (write(ctlfd, &ctl, sizeof (ctl)) != sizeof (ctl))
37117c478bd9Sstevel@tonic-gate 		return (-1);
37127c478bd9Sstevel@tonic-gate 	L->lwp_status.pr_cursig = 0;
37137c478bd9Sstevel@tonic-gate 	return (0);
37147c478bd9Sstevel@tonic-gate }
37157c478bd9Sstevel@tonic-gate 
37167c478bd9Sstevel@tonic-gate int
Lclearfault(struct ps_lwphandle * L)37177c478bd9Sstevel@tonic-gate Lclearfault(struct ps_lwphandle *L)
37187c478bd9Sstevel@tonic-gate {
37197c478bd9Sstevel@tonic-gate 	int ctlfd = L->lwp_ctlfd;
37207c478bd9Sstevel@tonic-gate 	long ctl = PCCFAULT;
37217c478bd9Sstevel@tonic-gate 
37227c478bd9Sstevel@tonic-gate 	if (write(ctlfd, &ctl, sizeof (ctl)) != sizeof (ctl))
37237c478bd9Sstevel@tonic-gate 		return (-1);
37247c478bd9Sstevel@tonic-gate 	return (0);
37257c478bd9Sstevel@tonic-gate }
37267c478bd9Sstevel@tonic-gate 
37277c478bd9Sstevel@tonic-gate /*
37287c478bd9Sstevel@tonic-gate  * Step over a breakpoint, i.e., execute the instruction that
37297c478bd9Sstevel@tonic-gate  * really belongs at the breakpoint location (the current %pc)
37307c478bd9Sstevel@tonic-gate  * and leave the LWP stopped at the next instruction.
37317c478bd9Sstevel@tonic-gate  */
37327c478bd9Sstevel@tonic-gate int
Lxecbkpt(struct ps_lwphandle * L,ulong_t saved)37337c478bd9Sstevel@tonic-gate Lxecbkpt(struct ps_lwphandle *L, ulong_t saved)
37347c478bd9Sstevel@tonic-gate {
37357c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = L->lwp_proc;
37367c478bd9Sstevel@tonic-gate 	int rv, error;
37377c478bd9Sstevel@tonic-gate 
37387c478bd9Sstevel@tonic-gate 	if (L->lwp_state != PS_STOP) {
37397c478bd9Sstevel@tonic-gate 		errno = EBUSY;
37407c478bd9Sstevel@tonic-gate 		return (-1);
37417c478bd9Sstevel@tonic-gate 	}
37427c478bd9Sstevel@tonic-gate 
37437c478bd9Sstevel@tonic-gate 	Lsync(L);
37447c478bd9Sstevel@tonic-gate 	error = execute_bkpt(L->lwp_ctlfd,
3745d7755b5aSrh 	    &P->status.pr_flttrace, &L->lwp_status.pr_lwphold,
3746d7755b5aSrh 	    L->lwp_status.pr_reg[R_PC], saved);
37477c478bd9Sstevel@tonic-gate 	rv = Lstopstatus(L, PCNULL, 0);
37487c478bd9Sstevel@tonic-gate 
37497c478bd9Sstevel@tonic-gate 	if (error != 0) {
37507c478bd9Sstevel@tonic-gate 		if (L->lwp_status.pr_why == PR_JOBCONTROL &&
37517c478bd9Sstevel@tonic-gate 		    error == EBUSY) {	/* jobcontrol stop -- back off */
37527c478bd9Sstevel@tonic-gate 			L->lwp_state = PS_RUN;
37537c478bd9Sstevel@tonic-gate 			return (0);
37547c478bd9Sstevel@tonic-gate 		}
37557c478bd9Sstevel@tonic-gate 		if (error == ENOENT)
37567c478bd9Sstevel@tonic-gate 			return (0);
37577c478bd9Sstevel@tonic-gate 		errno = error;
37587c478bd9Sstevel@tonic-gate 		return (-1);
37597c478bd9Sstevel@tonic-gate 	}
37607c478bd9Sstevel@tonic-gate 
37617c478bd9Sstevel@tonic-gate 	return (rv);
37627c478bd9Sstevel@tonic-gate }
37637c478bd9Sstevel@tonic-gate 
37647c478bd9Sstevel@tonic-gate /*
37657c478bd9Sstevel@tonic-gate  * Step over a watchpoint, i.e., execute the instruction that was stopped by
37667c478bd9Sstevel@tonic-gate  * the watchpoint, and then leave the LWP stopped at the next instruction.
37677c478bd9Sstevel@tonic-gate  */
37687c478bd9Sstevel@tonic-gate int
Lxecwapt(struct ps_lwphandle * L,const prwatch_t * wp)37697c478bd9Sstevel@tonic-gate Lxecwapt(struct ps_lwphandle *L, const prwatch_t *wp)
37707c478bd9Sstevel@tonic-gate {
37717c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = L->lwp_proc;
37727c478bd9Sstevel@tonic-gate 	int rv, error;
37737c478bd9Sstevel@tonic-gate 
37747c478bd9Sstevel@tonic-gate 	if (L->lwp_state != PS_STOP) {
37757c478bd9Sstevel@tonic-gate 		errno = EBUSY;
37767c478bd9Sstevel@tonic-gate 		return (-1);
37777c478bd9Sstevel@tonic-gate 	}
37787c478bd9Sstevel@tonic-gate 
37797c478bd9Sstevel@tonic-gate 	Lsync(L);
37807c478bd9Sstevel@tonic-gate 	error = execute_wapt(L->lwp_ctlfd,
3781d7755b5aSrh 	    &P->status.pr_flttrace, &L->lwp_status.pr_lwphold, wp);
37827c478bd9Sstevel@tonic-gate 	rv = Lstopstatus(L, PCNULL, 0);
37837c478bd9Sstevel@tonic-gate 
37847c478bd9Sstevel@tonic-gate 	if (error != 0) {
37857c478bd9Sstevel@tonic-gate 		if (L->lwp_status.pr_why == PR_JOBCONTROL &&
37867c478bd9Sstevel@tonic-gate 		    error == EBUSY) {	/* jobcontrol stop -- back off */
37877c478bd9Sstevel@tonic-gate 			L->lwp_state = PS_RUN;
37887c478bd9Sstevel@tonic-gate 			return (0);
37897c478bd9Sstevel@tonic-gate 		}
37907c478bd9Sstevel@tonic-gate 		if (error == ENOENT)
37917c478bd9Sstevel@tonic-gate 			return (0);
37927c478bd9Sstevel@tonic-gate 		errno = error;
37937c478bd9Sstevel@tonic-gate 		return (-1);
37947c478bd9Sstevel@tonic-gate 	}
37957c478bd9Sstevel@tonic-gate 
37967c478bd9Sstevel@tonic-gate 	return (rv);
37977c478bd9Sstevel@tonic-gate }
37987c478bd9Sstevel@tonic-gate 
37997c478bd9Sstevel@tonic-gate int
Lstack(struct ps_lwphandle * L,stack_t * stkp)38007c478bd9Sstevel@tonic-gate Lstack(struct ps_lwphandle *L, stack_t *stkp)
38017c478bd9Sstevel@tonic-gate {
38027c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = L->lwp_proc;
38037c478bd9Sstevel@tonic-gate 	uintptr_t addr = L->lwp_status.pr_ustack;
38047c478bd9Sstevel@tonic-gate 
38057c478bd9Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
38067c478bd9Sstevel@tonic-gate 		if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp))
38077c478bd9Sstevel@tonic-gate 			return (-1);
38087c478bd9Sstevel@tonic-gate #ifdef _LP64
38097c478bd9Sstevel@tonic-gate 	} else {
38107c478bd9Sstevel@tonic-gate 		stack32_t stk32;
38117c478bd9Sstevel@tonic-gate 
38127c478bd9Sstevel@tonic-gate 		if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32))
38137c478bd9Sstevel@tonic-gate 			return (-1);
38147c478bd9Sstevel@tonic-gate 
38157c478bd9Sstevel@tonic-gate 		stack_32_to_n(&stk32, stkp);
38167c478bd9Sstevel@tonic-gate #endif
38177c478bd9Sstevel@tonic-gate 	}
38187c478bd9Sstevel@tonic-gate 
38197c478bd9Sstevel@tonic-gate 	return (0);
38207c478bd9Sstevel@tonic-gate }
38217c478bd9Sstevel@tonic-gate 
38227c478bd9Sstevel@tonic-gate int
Lmain_stack(struct ps_lwphandle * L,stack_t * stkp)38237c478bd9Sstevel@tonic-gate Lmain_stack(struct ps_lwphandle *L, stack_t *stkp)
38247c478bd9Sstevel@tonic-gate {
38257c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = L->lwp_proc;
38267c478bd9Sstevel@tonic-gate 
38277c478bd9Sstevel@tonic-gate 	if (Lstack(L, stkp) != 0)
38287c478bd9Sstevel@tonic-gate 		return (-1);
38297c478bd9Sstevel@tonic-gate 
38307c478bd9Sstevel@tonic-gate 	/*
38317c478bd9Sstevel@tonic-gate 	 * If the SS_ONSTACK flag is set then this LWP is operating on the
38327c478bd9Sstevel@tonic-gate 	 * alternate signal stack. We can recover the original stack from
38337c478bd9Sstevel@tonic-gate 	 * pr_oldcontext.
38347c478bd9Sstevel@tonic-gate 	 */
38357c478bd9Sstevel@tonic-gate 	if (!(stkp->ss_flags & SS_ONSTACK))
38367c478bd9Sstevel@tonic-gate 		return (0);
38377c478bd9Sstevel@tonic-gate 
38387c478bd9Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
38397c478bd9Sstevel@tonic-gate 		ucontext_t *ctxp = (void *)L->lwp_status.pr_oldcontext;
38407c478bd9Sstevel@tonic-gate 
38417c478bd9Sstevel@tonic-gate 		if (Pread(P, stkp, sizeof (*stkp),
38427c478bd9Sstevel@tonic-gate 		    (uintptr_t)&ctxp->uc_stack) != sizeof (*stkp))
38437c478bd9Sstevel@tonic-gate 			return (-1);
38447c478bd9Sstevel@tonic-gate #ifdef _LP64
38457c478bd9Sstevel@tonic-gate 	} else {
38467c478bd9Sstevel@tonic-gate 		ucontext32_t *ctxp = (void *)L->lwp_status.pr_oldcontext;
38477c478bd9Sstevel@tonic-gate 		stack32_t stk32;
38487c478bd9Sstevel@tonic-gate 
38497c478bd9Sstevel@tonic-gate 		if (Pread(P, &stk32, sizeof (stk32),
38507c478bd9Sstevel@tonic-gate 		    (uintptr_t)&ctxp->uc_stack) != sizeof (stk32))
38517c478bd9Sstevel@tonic-gate 			return (-1);
38527c478bd9Sstevel@tonic-gate 
38537c478bd9Sstevel@tonic-gate 		stack_32_to_n(&stk32, stkp);
38547c478bd9Sstevel@tonic-gate #endif
38557c478bd9Sstevel@tonic-gate 	}
38567c478bd9Sstevel@tonic-gate 
38577c478bd9Sstevel@tonic-gate 	return (0);
38587c478bd9Sstevel@tonic-gate }
38597c478bd9Sstevel@tonic-gate 
38607c478bd9Sstevel@tonic-gate int
Lalt_stack(struct ps_lwphandle * L,stack_t * stkp)38617c478bd9Sstevel@tonic-gate Lalt_stack(struct ps_lwphandle *L, stack_t *stkp)
38627c478bd9Sstevel@tonic-gate {
38637c478bd9Sstevel@tonic-gate 	if (L->lwp_status.pr_altstack.ss_flags & SS_DISABLE) {
38647c478bd9Sstevel@tonic-gate 		errno = ENODATA;
38657c478bd9Sstevel@tonic-gate 		return (-1);
38667c478bd9Sstevel@tonic-gate 	}
38677c478bd9Sstevel@tonic-gate 
38687c478bd9Sstevel@tonic-gate 	*stkp = L->lwp_status.pr_altstack;
38697c478bd9Sstevel@tonic-gate 
38707c478bd9Sstevel@tonic-gate 	return (0);
38717c478bd9Sstevel@tonic-gate }
38727c478bd9Sstevel@tonic-gate 
38737c478bd9Sstevel@tonic-gate /*
38747c478bd9Sstevel@tonic-gate  * Add a mapping to the given proc handle.  Resizes the array as appropriate and
38757c478bd9Sstevel@tonic-gate  * manages reference counts on the given file_info_t.
38767c478bd9Sstevel@tonic-gate  *
38777c478bd9Sstevel@tonic-gate  * The 'map_relocate' member is used to tell Psort_mappings() that the
38787c478bd9Sstevel@tonic-gate  * associated file_map pointer needs to be relocated after the mappings have
38797c478bd9Sstevel@tonic-gate  * been sorted.  It is only set for the first mapping, and has no meaning
38807c478bd9Sstevel@tonic-gate  * outside these two functions.
38817c478bd9Sstevel@tonic-gate  */
38827c478bd9Sstevel@tonic-gate int
Padd_mapping(struct ps_prochandle * P,off64_t off,file_info_t * fp,prmap_t * pmap)38837c478bd9Sstevel@tonic-gate Padd_mapping(struct ps_prochandle *P, off64_t off, file_info_t *fp,
38847c478bd9Sstevel@tonic-gate     prmap_t *pmap)
38857c478bd9Sstevel@tonic-gate {
38867c478bd9Sstevel@tonic-gate 	map_info_t *mp;
38877c478bd9Sstevel@tonic-gate 
38887c478bd9Sstevel@tonic-gate 	if (P->map_count == P->map_alloc) {
38897c478bd9Sstevel@tonic-gate 		size_t next = P->map_alloc ? P->map_alloc * 2 : 16;
38907c478bd9Sstevel@tonic-gate 
38917c478bd9Sstevel@tonic-gate 		if ((P->mappings = realloc(P->mappings,
38927c478bd9Sstevel@tonic-gate 		    next * sizeof (map_info_t))) == NULL)
38937c478bd9Sstevel@tonic-gate 			return (-1);
38947c478bd9Sstevel@tonic-gate 
38957c478bd9Sstevel@tonic-gate 		P->map_alloc = next;
38967c478bd9Sstevel@tonic-gate 	}
38977c478bd9Sstevel@tonic-gate 
38987c478bd9Sstevel@tonic-gate 	mp = &P->mappings[P->map_count++];
38997c478bd9Sstevel@tonic-gate 
39007c478bd9Sstevel@tonic-gate 	mp->map_offset = off;
39017c478bd9Sstevel@tonic-gate 	mp->map_pmap = *pmap;
39027c478bd9Sstevel@tonic-gate 	mp->map_relocate = 0;
39037c478bd9Sstevel@tonic-gate 	if ((mp->map_file = fp) != NULL) {
39047c478bd9Sstevel@tonic-gate 		if (fp->file_map == NULL) {
39057c478bd9Sstevel@tonic-gate 			fp->file_map = mp;
39067c478bd9Sstevel@tonic-gate 			mp->map_relocate = 1;
39077c478bd9Sstevel@tonic-gate 		}
39087c478bd9Sstevel@tonic-gate 		fp->file_ref++;
39097c478bd9Sstevel@tonic-gate 	}
39107c478bd9Sstevel@tonic-gate 
39117c478bd9Sstevel@tonic-gate 	return (0);
39127c478bd9Sstevel@tonic-gate }
39137c478bd9Sstevel@tonic-gate 
39147c478bd9Sstevel@tonic-gate static int
map_sort(const void * a,const void * b)39157c478bd9Sstevel@tonic-gate map_sort(const void *a, const void *b)
39167c478bd9Sstevel@tonic-gate {
39177c478bd9Sstevel@tonic-gate 	const map_info_t *ap = a, *bp = b;
39187c478bd9Sstevel@tonic-gate 
39197c478bd9Sstevel@tonic-gate 	if (ap->map_pmap.pr_vaddr < bp->map_pmap.pr_vaddr)
39207c478bd9Sstevel@tonic-gate 		return (-1);
39217c478bd9Sstevel@tonic-gate 	else if (ap->map_pmap.pr_vaddr > bp->map_pmap.pr_vaddr)
39227c478bd9Sstevel@tonic-gate 		return (1);
39237c478bd9Sstevel@tonic-gate 	else
39247c478bd9Sstevel@tonic-gate 		return (0);
39257c478bd9Sstevel@tonic-gate }
39267c478bd9Sstevel@tonic-gate 
39277c478bd9Sstevel@tonic-gate /*
39287c478bd9Sstevel@tonic-gate  * Sort the current set of mappings.  Should be called during target
39297c478bd9Sstevel@tonic-gate  * initialization after all calls to Padd_mapping() have been made.
39307c478bd9Sstevel@tonic-gate  */
39317c478bd9Sstevel@tonic-gate void
Psort_mappings(struct ps_prochandle * P)39327c478bd9Sstevel@tonic-gate Psort_mappings(struct ps_prochandle *P)
39337c478bd9Sstevel@tonic-gate {
39347c478bd9Sstevel@tonic-gate 	int i;
39357c478bd9Sstevel@tonic-gate 	map_info_t *mp;
39367c478bd9Sstevel@tonic-gate 
39377c478bd9Sstevel@tonic-gate 	qsort(P->mappings, P->map_count, sizeof (map_info_t), map_sort);
39387c478bd9Sstevel@tonic-gate 
39397c478bd9Sstevel@tonic-gate 	/*
39407c478bd9Sstevel@tonic-gate 	 * Update all the file_map pointers to refer to the new locations.
39417c478bd9Sstevel@tonic-gate 	 */
39427c478bd9Sstevel@tonic-gate 	for (i = 0; i < P->map_count; i++) {
39437c478bd9Sstevel@tonic-gate 		mp = &P->mappings[i];
39447c478bd9Sstevel@tonic-gate 		if (mp->map_relocate)
39457c478bd9Sstevel@tonic-gate 			mp->map_file->file_map = mp;
39467c478bd9Sstevel@tonic-gate 		mp->map_relocate = 0;
39477c478bd9Sstevel@tonic-gate 	}
39487c478bd9Sstevel@tonic-gate }
39492a12f85aSJeremy Jones 
39502a12f85aSJeremy Jones struct ps_prochandle *
Pgrab_ops(pid_t pid,void * data,const ps_ops_t * ops,int flags)39512a12f85aSJeremy Jones Pgrab_ops(pid_t pid, void *data, const ps_ops_t *ops, int flags)
39522a12f85aSJeremy Jones {
39532a12f85aSJeremy Jones 	struct ps_prochandle *P;
39542a12f85aSJeremy Jones 
39552a12f85aSJeremy Jones 	if ((P = calloc(1, sizeof (*P))) == NULL) {
39562a12f85aSJeremy Jones 		return (NULL);
39572a12f85aSJeremy Jones 	}
39582a12f85aSJeremy Jones 
39592a12f85aSJeremy Jones 	Pinit_ops(&P->ops, ops);
39602a12f85aSJeremy Jones 	(void) mutex_init(&P->proc_lock, USYNC_THREAD, NULL);
39612a12f85aSJeremy Jones 	P->pid = pid;
39622a12f85aSJeremy Jones 	P->state = PS_STOP;
39632a12f85aSJeremy Jones 	P->asfd = -1;
39642a12f85aSJeremy Jones 	P->ctlfd = -1;
39652a12f85aSJeremy Jones 	P->statfd = -1;
39662a12f85aSJeremy Jones 	P->agentctlfd = -1;
39672a12f85aSJeremy Jones 	P->agentstatfd = -1;
39682a12f85aSJeremy Jones 	Pinitsym(P);
396950d4d24eSRobert Mustacchi 	Pinitfd(P);
39702a12f85aSJeremy Jones 	P->data = data;
39712a12f85aSJeremy Jones 	Pread_status(P);
39722a12f85aSJeremy Jones 
39732a12f85aSJeremy Jones 	if (flags & PGRAB_INCORE) {
39742a12f85aSJeremy Jones 		P->flags |= INCORE;
39752a12f85aSJeremy Jones 	}
39762a12f85aSJeremy Jones 
39772a12f85aSJeremy Jones 	return (P);
39782a12f85aSJeremy Jones }
3979