xref: /onnv-gate/usr/src/lib/libproc/common/Pcontrol.c (revision 11798:1e7f1f154004)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52712Snn35248  * Common Development and Distribution License (the "License").
62712Snn35248  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211222Smws 
220Sstevel@tonic-gate /*
23*11798SRoger.Faulkner@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
255272Sjhaslam  *
265272Sjhaslam  * Portions Copyright 2007 Chad Mynhier
270Sstevel@tonic-gate  */
280Sstevel@tonic-gate 
2910201SEdward.Pilatowicz@Sun.COM #include <assert.h>
300Sstevel@tonic-gate #include <stdio.h>
310Sstevel@tonic-gate #include <stdlib.h>
320Sstevel@tonic-gate #include <unistd.h>
330Sstevel@tonic-gate #include <ctype.h>
340Sstevel@tonic-gate #include <fcntl.h>
350Sstevel@tonic-gate #include <string.h>
362712Snn35248 #include <strings.h>
370Sstevel@tonic-gate #include <memory.h>
380Sstevel@tonic-gate #include <errno.h>
390Sstevel@tonic-gate #include <dirent.h>
400Sstevel@tonic-gate #include <limits.h>
410Sstevel@tonic-gate #include <signal.h>
423864Sraf #include <atomic.h>
430Sstevel@tonic-gate #include <sys/types.h>
440Sstevel@tonic-gate #include <sys/uio.h>
450Sstevel@tonic-gate #include <sys/stat.h>
460Sstevel@tonic-gate #include <sys/resource.h>
470Sstevel@tonic-gate #include <sys/param.h>
480Sstevel@tonic-gate #include <sys/stack.h>
490Sstevel@tonic-gate #include <sys/fault.h>
500Sstevel@tonic-gate #include <sys/syscall.h>
510Sstevel@tonic-gate #include <sys/sysmacros.h>
520Sstevel@tonic-gate 
530Sstevel@tonic-gate #include "libproc.h"
540Sstevel@tonic-gate #include "Pcontrol.h"
550Sstevel@tonic-gate #include "Putil.h"
560Sstevel@tonic-gate #include "P32ton.h"
570Sstevel@tonic-gate 
580Sstevel@tonic-gate int	_libproc_debug;		/* set non-zero to enable debugging printfs */
594753Srh87107 int	_libproc_no_qsort;	/* set non-zero to inhibit sorting */
604753Srh87107 				/* of symbol tables */
6110201SEdward.Pilatowicz@Sun.COM int	_libproc_incore_elf;	/* only use in-core elf data */
624753Srh87107 
630Sstevel@tonic-gate sigset_t blockable_sigs;	/* signals to block when we need to be safe */
640Sstevel@tonic-gate static	int	minfd;	/* minimum file descriptor returned by dupfd(fd, 0) */
652712Snn35248 char	procfs_path[PATH_MAX] = "/proc";
660Sstevel@tonic-gate 
670Sstevel@tonic-gate /*
680Sstevel@tonic-gate  * Function prototypes for static routines in this module.
690Sstevel@tonic-gate  */
700Sstevel@tonic-gate static	void	deadcheck(struct ps_prochandle *);
710Sstevel@tonic-gate static	void	restore_tracing_flags(struct ps_prochandle *);
720Sstevel@tonic-gate static	void	Lfree_internal(struct ps_prochandle *, struct ps_lwphandle *);
730Sstevel@tonic-gate 
740Sstevel@tonic-gate /*
750Sstevel@tonic-gate  * Read/write interface for live processes: just pread/pwrite the
760Sstevel@tonic-gate  * /proc/<pid>/as file:
770Sstevel@tonic-gate  */
780Sstevel@tonic-gate 
790Sstevel@tonic-gate static ssize_t
Pread_live(struct ps_prochandle * P,void * buf,size_t n,uintptr_t addr)800Sstevel@tonic-gate Pread_live(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr)
810Sstevel@tonic-gate {
820Sstevel@tonic-gate 	return (pread(P->asfd, buf, n, (off_t)addr));
830Sstevel@tonic-gate }
840Sstevel@tonic-gate 
850Sstevel@tonic-gate static ssize_t
Pwrite_live(struct ps_prochandle * P,const void * buf,size_t n,uintptr_t addr)860Sstevel@tonic-gate Pwrite_live(struct ps_prochandle *P, const void *buf, size_t n, uintptr_t addr)
870Sstevel@tonic-gate {
880Sstevel@tonic-gate 	return (pwrite(P->asfd, buf, n, (off_t)addr));
890Sstevel@tonic-gate }
900Sstevel@tonic-gate 
910Sstevel@tonic-gate static const ps_rwops_t P_live_ops = { Pread_live, Pwrite_live };
920Sstevel@tonic-gate 
930Sstevel@tonic-gate /*
940Sstevel@tonic-gate  * This is the library's .init handler.
950Sstevel@tonic-gate  */
960Sstevel@tonic-gate #pragma init(_libproc_init)
970Sstevel@tonic-gate void
_libproc_init(void)980Sstevel@tonic-gate _libproc_init(void)
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate 	_libproc_debug = getenv("LIBPROC_DEBUG") != NULL;
1014753Srh87107 	_libproc_no_qsort = getenv("LIBPROC_NO_QSORT") != NULL;
10210201SEdward.Pilatowicz@Sun.COM 	_libproc_incore_elf = getenv("LIBPROC_INCORE_ELF") != NULL;
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 	(void) sigfillset(&blockable_sigs);
1050Sstevel@tonic-gate 	(void) sigdelset(&blockable_sigs, SIGKILL);
1060Sstevel@tonic-gate 	(void) sigdelset(&blockable_sigs, SIGSTOP);
1070Sstevel@tonic-gate }
1080Sstevel@tonic-gate 
1092712Snn35248 void
Pset_procfs_path(const char * path)1102712Snn35248 Pset_procfs_path(const char *path)
1112712Snn35248 {
1122712Snn35248 	(void) snprintf(procfs_path, sizeof (procfs_path), "%s", path);
1132712Snn35248 }
1142712Snn35248 
1150Sstevel@tonic-gate /*
1160Sstevel@tonic-gate  * Call set_minfd() once before calling dupfd() several times.
1170Sstevel@tonic-gate  * We assume that the application will not reduce its current file
1180Sstevel@tonic-gate  * descriptor limit lower than 512 once it has set at least that value.
1190Sstevel@tonic-gate  */
1200Sstevel@tonic-gate int
set_minfd(void)1210Sstevel@tonic-gate set_minfd(void)
1220Sstevel@tonic-gate {
1230Sstevel@tonic-gate 	static mutex_t minfd_lock = DEFAULTMUTEX;
1240Sstevel@tonic-gate 	struct rlimit rlim;
1250Sstevel@tonic-gate 	int fd;
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	if ((fd = minfd) < 256) {
1280Sstevel@tonic-gate 		(void) mutex_lock(&minfd_lock);
1290Sstevel@tonic-gate 		if ((fd = minfd) < 256) {
1300Sstevel@tonic-gate 			if (getrlimit(RLIMIT_NOFILE, &rlim) != 0)
1310Sstevel@tonic-gate 				rlim.rlim_cur = rlim.rlim_max = 0;
1320Sstevel@tonic-gate 			if (rlim.rlim_cur >= 512)
1330Sstevel@tonic-gate 				fd = 256;
1340Sstevel@tonic-gate 			else if ((fd = rlim.rlim_cur / 2) < 3)
1350Sstevel@tonic-gate 				fd = 3;
1363864Sraf 			membar_producer();
1370Sstevel@tonic-gate 			minfd = fd;
1380Sstevel@tonic-gate 		}
1390Sstevel@tonic-gate 		(void) mutex_unlock(&minfd_lock);
1400Sstevel@tonic-gate 	}
1410Sstevel@tonic-gate 	return (fd);
1420Sstevel@tonic-gate }
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate int
dupfd(int fd,int dfd)1450Sstevel@tonic-gate dupfd(int fd, int dfd)
1460Sstevel@tonic-gate {
1470Sstevel@tonic-gate 	int mfd;
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	/*
1500Sstevel@tonic-gate 	 * Make fd be greater than 255 (the 32-bit stdio limit),
1510Sstevel@tonic-gate 	 * or at least make it greater than 2 so that the
1520Sstevel@tonic-gate 	 * program will work when spawned by init(1m).
1530Sstevel@tonic-gate 	 * Also, if dfd is non-zero, dup the fd to be dfd.
1540Sstevel@tonic-gate 	 */
1550Sstevel@tonic-gate 	if ((mfd = minfd) == 0)
1560Sstevel@tonic-gate 		mfd = set_minfd();
1570Sstevel@tonic-gate 	if (dfd > 0 || (0 <= fd && fd < mfd)) {
1580Sstevel@tonic-gate 		if (dfd <= 0)
1590Sstevel@tonic-gate 			dfd = mfd;
1600Sstevel@tonic-gate 		dfd = fcntl(fd, F_DUPFD, dfd);
1610Sstevel@tonic-gate 		(void) close(fd);
1620Sstevel@tonic-gate 		fd = dfd;
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate 	/*
1650Sstevel@tonic-gate 	 * Mark it close-on-exec so any created process doesn't inherit it.
1660Sstevel@tonic-gate 	 */
1670Sstevel@tonic-gate 	if (fd >= 0)
1680Sstevel@tonic-gate 		(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
1690Sstevel@tonic-gate 	return (fd);
1700Sstevel@tonic-gate }
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate /*
1730Sstevel@tonic-gate  * Create a new controlled process.
1740Sstevel@tonic-gate  * Leave it stopped on successful exit from exec() or execve().
1750Sstevel@tonic-gate  * Return an opaque pointer to its process control structure.
1760Sstevel@tonic-gate  * Return NULL if process cannot be created (fork()/exec() not successful).
1770Sstevel@tonic-gate  */
1780Sstevel@tonic-gate struct ps_prochandle *
Pxcreate(const char * file,char * const * argv,char * const * envp,int * perr,char * path,size_t len)1790Sstevel@tonic-gate Pxcreate(const char *file,	/* executable file name */
1800Sstevel@tonic-gate 	char *const *argv,	/* argument vector */
1810Sstevel@tonic-gate 	char *const *envp,	/* environment */
1820Sstevel@tonic-gate 	int *perr,	/* pointer to error return code */
1830Sstevel@tonic-gate 	char *path,	/* if non-null, holds exec path name on return */
1840Sstevel@tonic-gate 	size_t len)	/* size of the path buffer */
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate 	char execpath[PATH_MAX];
1872712Snn35248 	char procname[PATH_MAX];
1880Sstevel@tonic-gate 	struct ps_prochandle *P;
1890Sstevel@tonic-gate 	pid_t pid;
1900Sstevel@tonic-gate 	int fd;
1910Sstevel@tonic-gate 	char *fname;
1920Sstevel@tonic-gate 	int rc;
1930Sstevel@tonic-gate 	int lasterrno = 0;
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	if (len == 0)	/* zero length, no path */
1960Sstevel@tonic-gate 		path = NULL;
1970Sstevel@tonic-gate 	if (path != NULL)
1980Sstevel@tonic-gate 		*path = '\0';
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	if ((P = malloc(sizeof (struct ps_prochandle))) == NULL) {
2010Sstevel@tonic-gate 		*perr = C_STRANGE;
2020Sstevel@tonic-gate 		return (NULL);
2030Sstevel@tonic-gate 	}
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	if ((pid = fork1()) == -1) {
2060Sstevel@tonic-gate 		free(P);
2070Sstevel@tonic-gate 		*perr = C_FORK;
2080Sstevel@tonic-gate 		return (NULL);
2090Sstevel@tonic-gate 	}
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	if (pid == 0) {			/* child process */
2120Sstevel@tonic-gate 		id_t id;
2130Sstevel@tonic-gate 		extern char **environ;
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 		/*
2160Sstevel@tonic-gate 		 * If running setuid or setgid, reset credentials to normal.
2170Sstevel@tonic-gate 		 */
2180Sstevel@tonic-gate 		if ((id = getgid()) != getegid())
2190Sstevel@tonic-gate 			(void) setgid(id);
2200Sstevel@tonic-gate 		if ((id = getuid()) != geteuid())
2210Sstevel@tonic-gate 			(void) setuid(id);
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 		Pcreate_callback(P);	/* execute callback (see below) */
2240Sstevel@tonic-gate 		(void) pause();		/* wait for PRSABORT from parent */
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 		/*
2270Sstevel@tonic-gate 		 * This is ugly.  There is no execvep() function that takes a
2280Sstevel@tonic-gate 		 * path and an environment.  We cheat here by replacing the
2290Sstevel@tonic-gate 		 * global 'environ' variable right before we call this.
2300Sstevel@tonic-gate 		 */
2310Sstevel@tonic-gate 		if (envp)
2320Sstevel@tonic-gate 			environ = (char **)envp;
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 		(void) execvp(file, argv);  /* execute the program */
2350Sstevel@tonic-gate 		_exit(127);
2360Sstevel@tonic-gate 	}
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	/*
2390Sstevel@tonic-gate 	 * Initialize the process structure.
2400Sstevel@tonic-gate 	 */
2410Sstevel@tonic-gate 	(void) memset(P, 0, sizeof (*P));
2420Sstevel@tonic-gate 	(void) mutex_init(&P->proc_lock, USYNC_THREAD, NULL);
2430Sstevel@tonic-gate 	P->flags |= CREATED;
2440Sstevel@tonic-gate 	P->state = PS_RUN;
2450Sstevel@tonic-gate 	P->pid = pid;
2460Sstevel@tonic-gate 	P->asfd = -1;
2470Sstevel@tonic-gate 	P->ctlfd = -1;
2480Sstevel@tonic-gate 	P->statfd = -1;
2490Sstevel@tonic-gate 	P->agentctlfd = -1;
2500Sstevel@tonic-gate 	P->agentstatfd = -1;
2510Sstevel@tonic-gate 	P->ops = &P_live_ops;
2520Sstevel@tonic-gate 	Pinitsym(P);
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 	/*
2550Sstevel@tonic-gate 	 * Open the /proc/pid files.
2560Sstevel@tonic-gate 	 */
2572712Snn35248 	(void) snprintf(procname, sizeof (procname), "%s/%d/",
2582712Snn35248 	    procfs_path, (int)pid);
2590Sstevel@tonic-gate 	fname = procname + strlen(procname);
2600Sstevel@tonic-gate 	(void) set_minfd();
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	/*
2630Sstevel@tonic-gate 	 * Exclusive write open advises others not to interfere.
2640Sstevel@tonic-gate 	 * There is no reason for any of these open()s to fail.
2650Sstevel@tonic-gate 	 */
2660Sstevel@tonic-gate 	(void) strcpy(fname, "as");
2670Sstevel@tonic-gate 	if ((fd = open(procname, (O_RDWR|O_EXCL))) < 0 ||
2680Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
2690Sstevel@tonic-gate 		dprintf("Pcreate: failed to open %s: %s\n",
2700Sstevel@tonic-gate 		    procname, strerror(errno));
2710Sstevel@tonic-gate 		rc = C_STRANGE;
2720Sstevel@tonic-gate 		goto bad;
2730Sstevel@tonic-gate 	}
2740Sstevel@tonic-gate 	P->asfd = fd;
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	(void) strcpy(fname, "status");
2770Sstevel@tonic-gate 	if ((fd = open(procname, O_RDONLY)) < 0 ||
2780Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
2790Sstevel@tonic-gate 		dprintf("Pcreate: failed to open %s: %s\n",
2800Sstevel@tonic-gate 		    procname, strerror(errno));
2810Sstevel@tonic-gate 		rc = C_STRANGE;
2820Sstevel@tonic-gate 		goto bad;
2830Sstevel@tonic-gate 	}
2840Sstevel@tonic-gate 	P->statfd = fd;
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	(void) strcpy(fname, "ctl");
2870Sstevel@tonic-gate 	if ((fd = open(procname, O_WRONLY)) < 0 ||
2880Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
2890Sstevel@tonic-gate 		dprintf("Pcreate: failed to open %s: %s\n",
2900Sstevel@tonic-gate 		    procname, strerror(errno));
2910Sstevel@tonic-gate 		rc = C_STRANGE;
2920Sstevel@tonic-gate 		goto bad;
2930Sstevel@tonic-gate 	}
2940Sstevel@tonic-gate 	P->ctlfd = fd;
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	(void) Pstop(P, 0);	/* stop the controlled process */
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	/*
2990Sstevel@tonic-gate 	 * Wait for process to sleep in pause().
3000Sstevel@tonic-gate 	 * If the process has already called pause(), then it should be
3010Sstevel@tonic-gate 	 * stopped (PR_REQUESTED) while asleep in pause and we are done.
3020Sstevel@tonic-gate 	 * Else we set up to catch entry/exit to pause() and set the process
3030Sstevel@tonic-gate 	 * running again, expecting it to stop when it reaches pause().
3040Sstevel@tonic-gate 	 * There is no reason for this to fail other than an interrupt.
3050Sstevel@tonic-gate 	 */
3060Sstevel@tonic-gate 	(void) Psysentry(P, SYS_pause, 1);
3070Sstevel@tonic-gate 	(void) Psysexit(P, SYS_pause, 1);
3080Sstevel@tonic-gate 	for (;;) {
3090Sstevel@tonic-gate 		if (P->state == PS_STOP &&
3100Sstevel@tonic-gate 		    P->status.pr_lwp.pr_syscall == SYS_pause &&
3110Sstevel@tonic-gate 		    (P->status.pr_lwp.pr_why == PR_REQUESTED ||
3120Sstevel@tonic-gate 		    P->status.pr_lwp.pr_why == PR_SYSENTRY ||
3130Sstevel@tonic-gate 		    P->status.pr_lwp.pr_why == PR_SYSEXIT))
3140Sstevel@tonic-gate 			break;
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 		if (P->state != PS_STOP ||	/* interrupt or process died */
3170Sstevel@tonic-gate 		    Psetrun(P, 0, 0) != 0) {	/* can't restart */
3180Sstevel@tonic-gate 			if (errno == EINTR || errno == ERESTART)
3190Sstevel@tonic-gate 				rc = C_INTR;
3200Sstevel@tonic-gate 			else {
3210Sstevel@tonic-gate 				dprintf("Pcreate: Psetrun failed: %s\n",
3220Sstevel@tonic-gate 				    strerror(errno));
3230Sstevel@tonic-gate 				rc = C_STRANGE;
3240Sstevel@tonic-gate 			}
3250Sstevel@tonic-gate 			goto bad;
3260Sstevel@tonic-gate 		}
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 		(void) Pwait(P, 0);
3290Sstevel@tonic-gate 	}
3300Sstevel@tonic-gate 	(void) Psysentry(P, SYS_pause, 0);
3310Sstevel@tonic-gate 	(void) Psysexit(P, SYS_pause, 0);
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	/*
3340Sstevel@tonic-gate 	 * Kick the process off the pause() and catch
3350Sstevel@tonic-gate 	 * it again on entry to exec() or exit().
3360Sstevel@tonic-gate 	 */
3370Sstevel@tonic-gate 	(void) Psysentry(P, SYS_exit, 1);
3380Sstevel@tonic-gate 	(void) Psysentry(P, SYS_execve, 1);
3390Sstevel@tonic-gate 	if (Psetrun(P, 0, PRSABORT) == -1) {
3400Sstevel@tonic-gate 		dprintf("Pcreate: Psetrun failed: %s\n", strerror(errno));
3410Sstevel@tonic-gate 		rc = C_STRANGE;
3420Sstevel@tonic-gate 		goto bad;
3430Sstevel@tonic-gate 	}
3440Sstevel@tonic-gate 	(void) Pwait(P, 0);
3450Sstevel@tonic-gate 	if (P->state != PS_STOP) {
3460Sstevel@tonic-gate 		dprintf("Pcreate: Pwait failed: %s\n", strerror(errno));
3470Sstevel@tonic-gate 		rc = C_STRANGE;
3480Sstevel@tonic-gate 		goto bad;
3490Sstevel@tonic-gate 	}
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	/*
3520Sstevel@tonic-gate 	 * Move the process through instances of failed exec()s
3530Sstevel@tonic-gate 	 * to reach the point of stopped on successful exec().
3540Sstevel@tonic-gate 	 */
3550Sstevel@tonic-gate 	(void) Psysexit(P, SYS_execve, TRUE);
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	while (P->state == PS_STOP &&
3580Sstevel@tonic-gate 	    P->status.pr_lwp.pr_why == PR_SYSENTRY &&
359*11798SRoger.Faulkner@Sun.COM 	    P->status.pr_lwp.pr_what == SYS_execve) {
3600Sstevel@tonic-gate 		/*
3610Sstevel@tonic-gate 		 * Fetch the exec path name now, before we complete
3620Sstevel@tonic-gate 		 * the exec().  We may lose the process and be unable
3630Sstevel@tonic-gate 		 * to get the information later.
3640Sstevel@tonic-gate 		 */
3650Sstevel@tonic-gate 		(void) Pread_string(P, execpath, sizeof (execpath),
3664753Srh87107 		    (off_t)P->status.pr_lwp.pr_sysarg[0]);
3670Sstevel@tonic-gate 		if (path != NULL)
3680Sstevel@tonic-gate 			(void) strncpy(path, execpath, len);
3690Sstevel@tonic-gate 		/*
3700Sstevel@tonic-gate 		 * Set the process running and wait for
3710Sstevel@tonic-gate 		 * it to stop on exit from the exec().
3720Sstevel@tonic-gate 		 */
3730Sstevel@tonic-gate 		(void) Psetrun(P, 0, 0);
3740Sstevel@tonic-gate 		(void) Pwait(P, 0);
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 		if (P->state == PS_LOST &&		/* we lost control */
3770Sstevel@tonic-gate 		    Preopen(P) != 0) {		/* and we can't get it back */
3780Sstevel@tonic-gate 			rc = C_PERM;
3790Sstevel@tonic-gate 			goto bad;
3800Sstevel@tonic-gate 		}
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 		/*
3830Sstevel@tonic-gate 		 * If the exec() failed, continue the loop, expecting
3840Sstevel@tonic-gate 		 * there to be more attempts to exec(), based on PATH.
3850Sstevel@tonic-gate 		 */
3860Sstevel@tonic-gate 		if (P->state == PS_STOP &&
3870Sstevel@tonic-gate 		    P->status.pr_lwp.pr_why == PR_SYSEXIT &&
388*11798SRoger.Faulkner@Sun.COM 		    P->status.pr_lwp.pr_what == SYS_execve &&
3890Sstevel@tonic-gate 		    (lasterrno = P->status.pr_lwp.pr_errno) != 0) {
3900Sstevel@tonic-gate 			/*
3910Sstevel@tonic-gate 			 * The exec() failed.  Set the process running and
3920Sstevel@tonic-gate 			 * wait for it to stop on entry to the next exec().
3930Sstevel@tonic-gate 			 */
3940Sstevel@tonic-gate 			(void) Psetrun(P, 0, 0);
3950Sstevel@tonic-gate 			(void) Pwait(P, 0);
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 			continue;
3980Sstevel@tonic-gate 		}
3990Sstevel@tonic-gate 		break;
4000Sstevel@tonic-gate 	}
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	if (P->state == PS_STOP &&
4030Sstevel@tonic-gate 	    P->status.pr_lwp.pr_why == PR_SYSEXIT &&
404*11798SRoger.Faulkner@Sun.COM 	    P->status.pr_lwp.pr_what == SYS_execve &&
4050Sstevel@tonic-gate 	    P->status.pr_lwp.pr_errno == 0) {
4060Sstevel@tonic-gate 		/*
4070Sstevel@tonic-gate 		 * The process is stopped on successful exec() or execve().
4080Sstevel@tonic-gate 		 * Turn off all tracing flags and return success.
4090Sstevel@tonic-gate 		 */
4100Sstevel@tonic-gate 		restore_tracing_flags(P);
4110Sstevel@tonic-gate #ifndef _LP64
4120Sstevel@tonic-gate 		/* We must be a 64-bit process to deal with a 64-bit process */
4130Sstevel@tonic-gate 		if (P->status.pr_dmodel == PR_MODEL_LP64) {
4140Sstevel@tonic-gate 			rc = C_LP64;
4150Sstevel@tonic-gate 			goto bad;
4160Sstevel@tonic-gate 		}
4170Sstevel@tonic-gate #endif
4180Sstevel@tonic-gate 		/*
4190Sstevel@tonic-gate 		 * Set run-on-last-close so the controlled process
4200Sstevel@tonic-gate 		 * runs even if we die on a signal.
4210Sstevel@tonic-gate 		 */
4220Sstevel@tonic-gate 		(void) Psetflags(P, PR_RLC);
4230Sstevel@tonic-gate 		*perr = 0;
4240Sstevel@tonic-gate 		return (P);
4250Sstevel@tonic-gate 	}
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	rc = lasterrno == ENOENT ? C_NOENT : C_NOEXEC;
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate bad:
4300Sstevel@tonic-gate 	(void) kill(pid, SIGKILL);
4310Sstevel@tonic-gate 	if (path != NULL && rc != C_PERM && rc != C_LP64)
4320Sstevel@tonic-gate 		*path = '\0';
4330Sstevel@tonic-gate 	Pfree(P);
4340Sstevel@tonic-gate 	*perr = rc;
4350Sstevel@tonic-gate 	return (NULL);
4360Sstevel@tonic-gate }
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate struct ps_prochandle *
Pcreate(const char * file,char * const * argv,int * perr,char * path,size_t len)4390Sstevel@tonic-gate Pcreate(
4400Sstevel@tonic-gate 	const char *file,	/* executable file name */
4410Sstevel@tonic-gate 	char *const *argv,	/* argument vector */
4420Sstevel@tonic-gate 	int *perr,	/* pointer to error return code */
4430Sstevel@tonic-gate 	char *path,	/* if non-null, holds exec path name on return */
4440Sstevel@tonic-gate 	size_t len)	/* size of the path buffer */
4450Sstevel@tonic-gate {
4460Sstevel@tonic-gate 	return (Pxcreate(file, argv, NULL, perr, path, len));
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate /*
4500Sstevel@tonic-gate  * Return a printable string corresponding to a Pcreate() error return.
4510Sstevel@tonic-gate  */
4520Sstevel@tonic-gate const char *
Pcreate_error(int error)4530Sstevel@tonic-gate Pcreate_error(int error)
4540Sstevel@tonic-gate {
4550Sstevel@tonic-gate 	const char *str;
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	switch (error) {
4580Sstevel@tonic-gate 	case C_FORK:
4590Sstevel@tonic-gate 		str = "cannot fork";
4600Sstevel@tonic-gate 		break;
4610Sstevel@tonic-gate 	case C_PERM:
4620Sstevel@tonic-gate 		str = "file is set-id or unreadable";
4630Sstevel@tonic-gate 		break;
4640Sstevel@tonic-gate 	case C_NOEXEC:
4650Sstevel@tonic-gate 		str = "cannot execute file";
4660Sstevel@tonic-gate 		break;
4670Sstevel@tonic-gate 	case C_INTR:
4680Sstevel@tonic-gate 		str = "operation interrupted";
4690Sstevel@tonic-gate 		break;
4700Sstevel@tonic-gate 	case C_LP64:
4710Sstevel@tonic-gate 		str = "program is _LP64, self is not";
4720Sstevel@tonic-gate 		break;
4730Sstevel@tonic-gate 	case C_STRANGE:
4740Sstevel@tonic-gate 		str = "unanticipated system error";
4750Sstevel@tonic-gate 		break;
4760Sstevel@tonic-gate 	case C_NOENT:
4770Sstevel@tonic-gate 		str = "cannot find executable file";
4780Sstevel@tonic-gate 		break;
4790Sstevel@tonic-gate 	default:
4800Sstevel@tonic-gate 		str = "unknown error";
4810Sstevel@tonic-gate 		break;
4820Sstevel@tonic-gate 	}
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	return (str);
4850Sstevel@tonic-gate }
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate /*
4880Sstevel@tonic-gate  * Callback to execute in each child process created with Pcreate() after fork
4890Sstevel@tonic-gate  * but before it execs the new process image.  By default, we do nothing, but
4900Sstevel@tonic-gate  * by calling this function we allow the client program to define its own
4910Sstevel@tonic-gate  * version of the function which will interpose on our empty default.  This
4920Sstevel@tonic-gate  * may be useful for clients that need to modify signal dispositions, terminal
4930Sstevel@tonic-gate  * attributes, or process group and session properties for each new victim.
4940Sstevel@tonic-gate  */
4950Sstevel@tonic-gate /*ARGSUSED*/
4960Sstevel@tonic-gate void
Pcreate_callback(struct ps_prochandle * P)4970Sstevel@tonic-gate Pcreate_callback(struct ps_prochandle *P)
4980Sstevel@tonic-gate {
4990Sstevel@tonic-gate 	/* nothing to do here */
5000Sstevel@tonic-gate }
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate /*
5030Sstevel@tonic-gate  * Grab an existing process.
5040Sstevel@tonic-gate  * Return an opaque pointer to its process control structure.
5050Sstevel@tonic-gate  *
5060Sstevel@tonic-gate  * pid:		UNIX process ID.
5070Sstevel@tonic-gate  * flags:
5080Sstevel@tonic-gate  *	PGRAB_RETAIN	Retain tracing flags (default clears all tracing flags).
5090Sstevel@tonic-gate  *	PGRAB_FORCE	Grab regardless of whether process is already traced.
5100Sstevel@tonic-gate  *	PGRAB_RDONLY	Open the address space file O_RDONLY instead of O_RDWR,
5110Sstevel@tonic-gate  *                      and do not open the process control file.
5120Sstevel@tonic-gate  *	PGRAB_NOSTOP	Open the process but do not force it to stop.
5130Sstevel@tonic-gate  * perr:	pointer to error return code.
5140Sstevel@tonic-gate  */
5150Sstevel@tonic-gate struct ps_prochandle *
Pgrab(pid_t pid,int flags,int * perr)5160Sstevel@tonic-gate Pgrab(pid_t pid, int flags, int *perr)
5170Sstevel@tonic-gate {
5180Sstevel@tonic-gate 	struct ps_prochandle *P;
5190Sstevel@tonic-gate 	int fd, omode;
5202712Snn35248 	char procname[PATH_MAX];
5210Sstevel@tonic-gate 	char *fname;
5220Sstevel@tonic-gate 	int rc = 0;
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	/*
5250Sstevel@tonic-gate 	 * PGRAB_RDONLY means that we do not open the /proc/<pid>/control file,
5260Sstevel@tonic-gate 	 * and so it implies RETAIN and NOSTOP since both require control.
5270Sstevel@tonic-gate 	 */
5280Sstevel@tonic-gate 	if (flags & PGRAB_RDONLY)
5290Sstevel@tonic-gate 		flags |= PGRAB_RETAIN | PGRAB_NOSTOP;
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 	if ((P = malloc(sizeof (struct ps_prochandle))) == NULL) {
5320Sstevel@tonic-gate 		*perr = G_STRANGE;
5330Sstevel@tonic-gate 		return (NULL);
5340Sstevel@tonic-gate 	}
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	P->asfd = -1;
5370Sstevel@tonic-gate 	P->ctlfd = -1;
5380Sstevel@tonic-gate 	P->statfd = -1;
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate again:	/* Come back here if we lose it in the Window of Vulnerability */
5410Sstevel@tonic-gate 	if (P->ctlfd >= 0)
5420Sstevel@tonic-gate 		(void) close(P->ctlfd);
5430Sstevel@tonic-gate 	if (P->asfd >= 0)
5440Sstevel@tonic-gate 		(void) close(P->asfd);
5450Sstevel@tonic-gate 	if (P->statfd >= 0)
5460Sstevel@tonic-gate 		(void) close(P->statfd);
5470Sstevel@tonic-gate 	(void) memset(P, 0, sizeof (*P));
5480Sstevel@tonic-gate 	(void) mutex_init(&P->proc_lock, USYNC_THREAD, NULL);
5490Sstevel@tonic-gate 	P->ctlfd = -1;
5500Sstevel@tonic-gate 	P->asfd = -1;
5510Sstevel@tonic-gate 	P->statfd = -1;
5520Sstevel@tonic-gate 	P->agentctlfd = -1;
5530Sstevel@tonic-gate 	P->agentstatfd = -1;
5540Sstevel@tonic-gate 	P->ops = &P_live_ops;
5550Sstevel@tonic-gate 	Pinitsym(P);
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	/*
5580Sstevel@tonic-gate 	 * Open the /proc/pid files
5590Sstevel@tonic-gate 	 */
5602712Snn35248 	(void) snprintf(procname, sizeof (procname), "%s/%d/",
5612712Snn35248 	    procfs_path, (int)pid);
5620Sstevel@tonic-gate 	fname = procname + strlen(procname);
5630Sstevel@tonic-gate 	(void) set_minfd();
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	/*
5660Sstevel@tonic-gate 	 * Request exclusive open to avoid grabbing someone else's
5670Sstevel@tonic-gate 	 * process and to prevent others from interfering afterwards.
5680Sstevel@tonic-gate 	 * If this fails and the 'PGRAB_FORCE' flag is set, attempt to
5690Sstevel@tonic-gate 	 * open non-exclusively.
5700Sstevel@tonic-gate 	 */
5710Sstevel@tonic-gate 	(void) strcpy(fname, "as");
5720Sstevel@tonic-gate 	omode = (flags & PGRAB_RDONLY) ? O_RDONLY : O_RDWR;
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	if (((fd = open(procname, omode | O_EXCL)) < 0 &&
5750Sstevel@tonic-gate 	    (fd = ((flags & PGRAB_FORCE)? open(procname, omode) : -1)) < 0) ||
5760Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
5770Sstevel@tonic-gate 		switch (errno) {
5780Sstevel@tonic-gate 		case ENOENT:
5790Sstevel@tonic-gate 			rc = G_NOPROC;
5800Sstevel@tonic-gate 			break;
5810Sstevel@tonic-gate 		case EACCES:
5820Sstevel@tonic-gate 		case EPERM:
5830Sstevel@tonic-gate 			rc = G_PERM;
5840Sstevel@tonic-gate 			break;
5855272Sjhaslam 		case EMFILE:
5865272Sjhaslam 			rc = G_NOFD;
5875272Sjhaslam 			break;
5880Sstevel@tonic-gate 		case EBUSY:
5890Sstevel@tonic-gate 			if (!(flags & PGRAB_FORCE) || geteuid() != 0) {
5900Sstevel@tonic-gate 				rc = G_BUSY;
5910Sstevel@tonic-gate 				break;
5920Sstevel@tonic-gate 			}
5930Sstevel@tonic-gate 			/* FALLTHROUGH */
5940Sstevel@tonic-gate 		default:
5950Sstevel@tonic-gate 			dprintf("Pgrab: failed to open %s: %s\n",
5960Sstevel@tonic-gate 			    procname, strerror(errno));
5970Sstevel@tonic-gate 			rc = G_STRANGE;
5980Sstevel@tonic-gate 			break;
5990Sstevel@tonic-gate 		}
6000Sstevel@tonic-gate 		goto err;
6010Sstevel@tonic-gate 	}
6020Sstevel@tonic-gate 	P->asfd = fd;
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	(void) strcpy(fname, "status");
6050Sstevel@tonic-gate 	if ((fd = open(procname, O_RDONLY)) < 0 ||
6060Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
6070Sstevel@tonic-gate 		switch (errno) {
6080Sstevel@tonic-gate 		case ENOENT:
6090Sstevel@tonic-gate 			rc = G_NOPROC;
6100Sstevel@tonic-gate 			break;
6115272Sjhaslam 		case EMFILE:
6125272Sjhaslam 			rc = G_NOFD;
6135272Sjhaslam 			break;
6140Sstevel@tonic-gate 		default:
6150Sstevel@tonic-gate 			dprintf("Pgrab: failed to open %s: %s\n",
6160Sstevel@tonic-gate 			    procname, strerror(errno));
6170Sstevel@tonic-gate 			rc = G_STRANGE;
6180Sstevel@tonic-gate 			break;
6190Sstevel@tonic-gate 		}
6200Sstevel@tonic-gate 		goto err;
6210Sstevel@tonic-gate 	}
6220Sstevel@tonic-gate 	P->statfd = fd;
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	if (!(flags & PGRAB_RDONLY)) {
6250Sstevel@tonic-gate 		(void) strcpy(fname, "ctl");
6260Sstevel@tonic-gate 		if ((fd = open(procname, O_WRONLY)) < 0 ||
6270Sstevel@tonic-gate 		    (fd = dupfd(fd, 0)) < 0) {
6280Sstevel@tonic-gate 			switch (errno) {
6290Sstevel@tonic-gate 			case ENOENT:
6300Sstevel@tonic-gate 				rc = G_NOPROC;
6310Sstevel@tonic-gate 				break;
6325272Sjhaslam 			case EMFILE:
6335272Sjhaslam 				rc = G_NOFD;
6345272Sjhaslam 				break;
6350Sstevel@tonic-gate 			default:
6360Sstevel@tonic-gate 				dprintf("Pgrab: failed to open %s: %s\n",
6370Sstevel@tonic-gate 				    procname, strerror(errno));
6380Sstevel@tonic-gate 				rc = G_STRANGE;
6390Sstevel@tonic-gate 				break;
6400Sstevel@tonic-gate 			}
6410Sstevel@tonic-gate 			goto err;
6420Sstevel@tonic-gate 		}
6430Sstevel@tonic-gate 		P->ctlfd = fd;
6440Sstevel@tonic-gate 	}
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	P->state = PS_RUN;
6470Sstevel@tonic-gate 	P->pid = pid;
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	/*
6500Sstevel@tonic-gate 	 * We are now in the Window of Vulnerability (WoV).  The process may
6510Sstevel@tonic-gate 	 * exec() a setuid/setgid or unreadable object file between the open()
6520Sstevel@tonic-gate 	 * and the PCSTOP.  We will get EAGAIN in this case and must start over.
6530Sstevel@tonic-gate 	 * As Pstopstatus will trigger the first read() from a /proc file,
6540Sstevel@tonic-gate 	 * we also need to handle EOVERFLOW here when 32-bit as an indicator
6550Sstevel@tonic-gate 	 * that this process is 64-bit.  Finally, if the process has become
6560Sstevel@tonic-gate 	 * a zombie (PS_UNDEAD) while we were trying to grab it, just remain
6570Sstevel@tonic-gate 	 * silent about this and pretend there was no process.
6580Sstevel@tonic-gate 	 */
6590Sstevel@tonic-gate 	if (Pstopstatus(P, PCNULL, 0) != 0) {
6600Sstevel@tonic-gate #ifndef _LP64
6610Sstevel@tonic-gate 		if (errno == EOVERFLOW) {
6620Sstevel@tonic-gate 			rc = G_LP64;
6630Sstevel@tonic-gate 			goto err;
6640Sstevel@tonic-gate 		}
6650Sstevel@tonic-gate #endif
6660Sstevel@tonic-gate 		if (P->state == PS_LOST) {	/* WoV */
6670Sstevel@tonic-gate 			(void) mutex_destroy(&P->proc_lock);
6680Sstevel@tonic-gate 			goto again;
6690Sstevel@tonic-gate 		}
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 		if (P->state == PS_UNDEAD)
6720Sstevel@tonic-gate 			rc = G_NOPROC;
6730Sstevel@tonic-gate 		else
6740Sstevel@tonic-gate 			rc = G_STRANGE;
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 		goto err;
6770Sstevel@tonic-gate 	}
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 	/*
6800Sstevel@tonic-gate 	 * If the process is a system process, we can't control it even as root
6810Sstevel@tonic-gate 	 */
6820Sstevel@tonic-gate 	if (P->status.pr_flags & PR_ISSYS) {
6830Sstevel@tonic-gate 		rc = G_SYS;
6840Sstevel@tonic-gate 		goto err;
6850Sstevel@tonic-gate 	}
6860Sstevel@tonic-gate #ifndef _LP64
6870Sstevel@tonic-gate 	/*
6880Sstevel@tonic-gate 	 * We must be a 64-bit process to deal with a 64-bit process
6890Sstevel@tonic-gate 	 */
6900Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_LP64) {
6910Sstevel@tonic-gate 		rc = G_LP64;
6920Sstevel@tonic-gate 		goto err;
6930Sstevel@tonic-gate 	}
6940Sstevel@tonic-gate #endif
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	/*
6970Sstevel@tonic-gate 	 * Remember the status for use by Prelease().
6980Sstevel@tonic-gate 	 */
6990Sstevel@tonic-gate 	P->orig_status = P->status;	/* structure copy */
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	/*
7020Sstevel@tonic-gate 	 * Before stopping the process, make sure we are not grabbing ourselves.
7030Sstevel@tonic-gate 	 * If we are, make sure we are doing it PGRAB_RDONLY.
7040Sstevel@tonic-gate 	 */
7050Sstevel@tonic-gate 	if (pid == getpid()) {
7060Sstevel@tonic-gate 		/*
7070Sstevel@tonic-gate 		 * Verify that the process is really ourself:
7080Sstevel@tonic-gate 		 * Set a magic number, read it through the
7090Sstevel@tonic-gate 		 * /proc file and see if the results match.
7100Sstevel@tonic-gate 		 */
7110Sstevel@tonic-gate 		uint32_t magic1 = 0;
7120Sstevel@tonic-gate 		uint32_t magic2 = 2;
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 		errno = 0;
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 		if (Pread(P, &magic2, sizeof (magic2), (uintptr_t)&magic1)
7170Sstevel@tonic-gate 		    == sizeof (magic2) &&
7180Sstevel@tonic-gate 		    magic2 == 0 &&
7190Sstevel@tonic-gate 		    (magic1 = 0xfeedbeef) &&
7200Sstevel@tonic-gate 		    Pread(P, &magic2, sizeof (magic2), (uintptr_t)&magic1)
7210Sstevel@tonic-gate 		    == sizeof (magic2) &&
7220Sstevel@tonic-gate 		    magic2 == 0xfeedbeef &&
7230Sstevel@tonic-gate 		    !(flags & PGRAB_RDONLY)) {
7240Sstevel@tonic-gate 			rc = G_SELF;
7250Sstevel@tonic-gate 			goto err;
7260Sstevel@tonic-gate 		}
7270Sstevel@tonic-gate 	}
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	/*
7300Sstevel@tonic-gate 	 * If the process is already stopped or has been directed
7310Sstevel@tonic-gate 	 * to stop via /proc, do not set run-on-last-close.
7320Sstevel@tonic-gate 	 */
7330Sstevel@tonic-gate 	if (!(P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)) &&
7340Sstevel@tonic-gate 	    !(flags & PGRAB_RDONLY)) {
7350Sstevel@tonic-gate 		/*
7360Sstevel@tonic-gate 		 * Mark the process run-on-last-close so
7370Sstevel@tonic-gate 		 * it runs even if we die from SIGKILL.
7380Sstevel@tonic-gate 		 */
7390Sstevel@tonic-gate 		if (Psetflags(P, PR_RLC) != 0) {
7400Sstevel@tonic-gate 			if (errno == EAGAIN) {	/* WoV */
7410Sstevel@tonic-gate 				(void) mutex_destroy(&P->proc_lock);
7420Sstevel@tonic-gate 				goto again;
7430Sstevel@tonic-gate 			}
7440Sstevel@tonic-gate 			if (errno == ENOENT)	/* No complaint about zombies */
7450Sstevel@tonic-gate 				rc = G_ZOMB;
7460Sstevel@tonic-gate 			else {
7470Sstevel@tonic-gate 				dprintf("Pgrab: failed to set RLC\n");
7480Sstevel@tonic-gate 				rc = G_STRANGE;
7490Sstevel@tonic-gate 			}
7500Sstevel@tonic-gate 			goto err;
7510Sstevel@tonic-gate 		}
7520Sstevel@tonic-gate 	}
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate 	/*
7550Sstevel@tonic-gate 	 * If a stop directive is pending and the process has not yet stopped,
7560Sstevel@tonic-gate 	 * then synchronously wait for the stop directive to take effect.
7570Sstevel@tonic-gate 	 * Limit the time spent waiting for the process to stop by iterating
7580Sstevel@tonic-gate 	 * at most 10 times. The time-out of 20 ms corresponds to the time
7590Sstevel@tonic-gate 	 * between sending the stop directive and the process actually stopped
7600Sstevel@tonic-gate 	 * as measured by DTrace on a slow, busy system. If the process doesn't
7610Sstevel@tonic-gate 	 * stop voluntarily, clear the PR_DSTOP flag so that the code below
7620Sstevel@tonic-gate 	 * forces the process to stop.
7630Sstevel@tonic-gate 	 */
7640Sstevel@tonic-gate 	if (!(flags & PGRAB_RDONLY)) {
7650Sstevel@tonic-gate 		int niter = 0;
7660Sstevel@tonic-gate 		while ((P->status.pr_lwp.pr_flags & (PR_STOPPED|PR_DSTOP)) ==
7670Sstevel@tonic-gate 		    PR_DSTOP && niter < 10 &&
7680Sstevel@tonic-gate 		    Pstopstatus(P, PCTWSTOP, 20) != 0) {
7690Sstevel@tonic-gate 			niter++;
7700Sstevel@tonic-gate 			if (flags & PGRAB_NOSTOP)
7710Sstevel@tonic-gate 				break;
7720Sstevel@tonic-gate 		}
7730Sstevel@tonic-gate 		if (niter == 10 && !(flags & PGRAB_NOSTOP)) {
7740Sstevel@tonic-gate 			/* Try it harder down below */
7750Sstevel@tonic-gate 			P->status.pr_lwp.pr_flags &= ~PR_DSTOP;
7760Sstevel@tonic-gate 		}
7770Sstevel@tonic-gate 	}
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 	/*
7800Sstevel@tonic-gate 	 * If the process is not already stopped or directed to stop
7810Sstevel@tonic-gate 	 * and PGRAB_NOSTOP was not specified, stop the process now.
7820Sstevel@tonic-gate 	 */
7830Sstevel@tonic-gate 	if (!(P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)) &&
7840Sstevel@tonic-gate 	    !(flags & PGRAB_NOSTOP)) {
7850Sstevel@tonic-gate 		/*
7860Sstevel@tonic-gate 		 * Stop the process, get its status and signal/syscall masks.
7870Sstevel@tonic-gate 		 */
7880Sstevel@tonic-gate 		if (((P->status.pr_lwp.pr_flags & PR_STOPPED) &&
7890Sstevel@tonic-gate 		    Pstopstatus(P, PCDSTOP, 0) != 0) ||
7900Sstevel@tonic-gate 		    Pstopstatus(P, PCSTOP, 2000) != 0) {
7910Sstevel@tonic-gate #ifndef _LP64
7920Sstevel@tonic-gate 			if (errno == EOVERFLOW) {
7930Sstevel@tonic-gate 				rc = G_LP64;
7940Sstevel@tonic-gate 				goto err;
7950Sstevel@tonic-gate 			}
7960Sstevel@tonic-gate #endif
7970Sstevel@tonic-gate 			if (P->state == PS_LOST) {	/* WoV */
7980Sstevel@tonic-gate 				(void) mutex_destroy(&P->proc_lock);
7990Sstevel@tonic-gate 				goto again;
8000Sstevel@tonic-gate 			}
8010Sstevel@tonic-gate 			if ((errno != EINTR && errno != ERESTART) ||
8020Sstevel@tonic-gate 			    (P->state != PS_STOP &&
8030Sstevel@tonic-gate 			    !(P->status.pr_flags & PR_DSTOP))) {
8040Sstevel@tonic-gate 				if (P->state != PS_RUN && errno != ENOENT) {
8050Sstevel@tonic-gate 					dprintf("Pgrab: failed to PCSTOP\n");
8060Sstevel@tonic-gate 					rc = G_STRANGE;
8070Sstevel@tonic-gate 				} else {
8080Sstevel@tonic-gate 					rc = G_ZOMB;
8090Sstevel@tonic-gate 				}
8100Sstevel@tonic-gate 				goto err;
8110Sstevel@tonic-gate 			}
8120Sstevel@tonic-gate 		}
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 		/*
8150Sstevel@tonic-gate 		 * Process should now either be stopped via /proc or there
8160Sstevel@tonic-gate 		 * should be an outstanding stop directive.
8170Sstevel@tonic-gate 		 */
8180Sstevel@tonic-gate 		if (!(P->status.pr_flags & (PR_ISTOP|PR_DSTOP))) {
8190Sstevel@tonic-gate 			dprintf("Pgrab: process is not stopped\n");
8200Sstevel@tonic-gate 			rc = G_STRANGE;
8210Sstevel@tonic-gate 			goto err;
8220Sstevel@tonic-gate 		}
8230Sstevel@tonic-gate #ifndef _LP64
8240Sstevel@tonic-gate 		/*
8250Sstevel@tonic-gate 		 * Test this again now because the 32-bit victim process may
8260Sstevel@tonic-gate 		 * have exec'd a 64-bit process in the meantime.
8270Sstevel@tonic-gate 		 */
8280Sstevel@tonic-gate 		if (P->status.pr_dmodel == PR_MODEL_LP64) {
8290Sstevel@tonic-gate 			rc = G_LP64;
8300Sstevel@tonic-gate 			goto err;
8310Sstevel@tonic-gate 		}
8320Sstevel@tonic-gate #endif
8330Sstevel@tonic-gate 	}
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	/*
8360Sstevel@tonic-gate 	 * Cancel all tracing flags unless the PGRAB_RETAIN flag is set.
8370Sstevel@tonic-gate 	 */
8380Sstevel@tonic-gate 	if (!(flags & PGRAB_RETAIN)) {
8390Sstevel@tonic-gate 		(void) Psysentry(P, 0, FALSE);
8400Sstevel@tonic-gate 		(void) Psysexit(P, 0, FALSE);
8410Sstevel@tonic-gate 		(void) Psignal(P, 0, FALSE);
8420Sstevel@tonic-gate 		(void) Pfault(P, 0, FALSE);
8430Sstevel@tonic-gate 		Psync(P);
8440Sstevel@tonic-gate 	}
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 	*perr = 0;
8470Sstevel@tonic-gate 	return (P);
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate err:
8500Sstevel@tonic-gate 	Pfree(P);
8510Sstevel@tonic-gate 	*perr = rc;
8520Sstevel@tonic-gate 	return (NULL);
8530Sstevel@tonic-gate }
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate /*
8560Sstevel@tonic-gate  * Return a printable string corresponding to a Pgrab() error return.
8570Sstevel@tonic-gate  */
8580Sstevel@tonic-gate const char *
Pgrab_error(int error)8590Sstevel@tonic-gate Pgrab_error(int error)
8600Sstevel@tonic-gate {
8610Sstevel@tonic-gate 	const char *str;
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 	switch (error) {
8640Sstevel@tonic-gate 	case G_NOPROC:
8650Sstevel@tonic-gate 		str = "no such process";
8660Sstevel@tonic-gate 		break;
8670Sstevel@tonic-gate 	case G_NOCORE:
8680Sstevel@tonic-gate 		str = "no such core file";
8690Sstevel@tonic-gate 		break;
8700Sstevel@tonic-gate 	case G_NOPROCORCORE:
8710Sstevel@tonic-gate 		str = "no such process or core file";
8720Sstevel@tonic-gate 		break;
8730Sstevel@tonic-gate 	case G_NOEXEC:
8740Sstevel@tonic-gate 		str = "cannot find executable file";
8750Sstevel@tonic-gate 		break;
8760Sstevel@tonic-gate 	case G_ZOMB:
8770Sstevel@tonic-gate 		str = "zombie process";
8780Sstevel@tonic-gate 		break;
8790Sstevel@tonic-gate 	case G_PERM:
8800Sstevel@tonic-gate 		str = "permission denied";
8810Sstevel@tonic-gate 		break;
8820Sstevel@tonic-gate 	case G_BUSY:
8830Sstevel@tonic-gate 		str = "process is traced";
8840Sstevel@tonic-gate 		break;
8850Sstevel@tonic-gate 	case G_SYS:
8860Sstevel@tonic-gate 		str = "system process";
8870Sstevel@tonic-gate 		break;
8880Sstevel@tonic-gate 	case G_SELF:
8890Sstevel@tonic-gate 		str = "attempt to grab self";
8900Sstevel@tonic-gate 		break;
8910Sstevel@tonic-gate 	case G_INTR:
8920Sstevel@tonic-gate 		str = "operation interrupted";
8930Sstevel@tonic-gate 		break;
8940Sstevel@tonic-gate 	case G_LP64:
8950Sstevel@tonic-gate 		str = "program is _LP64, self is not";
8960Sstevel@tonic-gate 		break;
8970Sstevel@tonic-gate 	case G_FORMAT:
8980Sstevel@tonic-gate 		str = "file is not an ELF core file";
8990Sstevel@tonic-gate 		break;
9000Sstevel@tonic-gate 	case G_ELF:
9010Sstevel@tonic-gate 		str = "libelf error";
9020Sstevel@tonic-gate 		break;
9030Sstevel@tonic-gate 	case G_NOTE:
9040Sstevel@tonic-gate 		str = "core file is corrupt or missing required data";
9050Sstevel@tonic-gate 		break;
9060Sstevel@tonic-gate 	case G_STRANGE:
9070Sstevel@tonic-gate 		str = "unanticipated system error";
9080Sstevel@tonic-gate 		break;
9090Sstevel@tonic-gate 	case G_ISAINVAL:
9100Sstevel@tonic-gate 		str = "wrong ELF machine type";
9110Sstevel@tonic-gate 		break;
9120Sstevel@tonic-gate 	case G_BADLWPS:
9130Sstevel@tonic-gate 		str = "bad lwp specification";
9140Sstevel@tonic-gate 		break;
9155272Sjhaslam 	case G_NOFD:
9165272Sjhaslam 		str = "too many open files";
9175272Sjhaslam 		break;
9180Sstevel@tonic-gate 	default:
9190Sstevel@tonic-gate 		str = "unknown error";
9200Sstevel@tonic-gate 		break;
9210Sstevel@tonic-gate 	}
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 	return (str);
9240Sstevel@tonic-gate }
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate /*
9270Sstevel@tonic-gate  * Free a process control structure.
9280Sstevel@tonic-gate  * Close the file descriptors but don't do the Prelease logic.
9290Sstevel@tonic-gate  */
9300Sstevel@tonic-gate void
Pfree(struct ps_prochandle * P)9310Sstevel@tonic-gate Pfree(struct ps_prochandle *P)
9320Sstevel@tonic-gate {
9330Sstevel@tonic-gate 	uint_t i;
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	if (P->core != NULL) {
9360Sstevel@tonic-gate 		extern void __priv_free_info(void *);
9370Sstevel@tonic-gate 		lwp_info_t *nlwp, *lwp = list_next(&P->core->core_lwp_head);
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 		for (i = 0; i < P->core->core_nlwp; i++, lwp = nlwp) {
9400Sstevel@tonic-gate 			nlwp = list_next(lwp);
9410Sstevel@tonic-gate #ifdef __sparc
9420Sstevel@tonic-gate 			if (lwp->lwp_gwins != NULL)
9430Sstevel@tonic-gate 				free(lwp->lwp_gwins);
9440Sstevel@tonic-gate 			if (lwp->lwp_xregs != NULL)
9450Sstevel@tonic-gate 				free(lwp->lwp_xregs);
9460Sstevel@tonic-gate 			if (lwp->lwp_asrs != NULL)
9470Sstevel@tonic-gate 				free(lwp->lwp_asrs);
9480Sstevel@tonic-gate #endif
9490Sstevel@tonic-gate 			free(lwp);
9500Sstevel@tonic-gate 		}
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate 		if (P->core->core_platform != NULL)
9530Sstevel@tonic-gate 			free(P->core->core_platform);
9540Sstevel@tonic-gate 		if (P->core->core_uts != NULL)
9550Sstevel@tonic-gate 			free(P->core->core_uts);
9560Sstevel@tonic-gate 		if (P->core->core_cred != NULL)
9570Sstevel@tonic-gate 			free(P->core->core_cred);
9580Sstevel@tonic-gate 		if (P->core->core_priv != NULL)
9590Sstevel@tonic-gate 			free(P->core->core_priv);
9600Sstevel@tonic-gate 		if (P->core->core_privinfo != NULL)
9610Sstevel@tonic-gate 			__priv_free_info(P->core->core_privinfo);
9620Sstevel@tonic-gate 		if (P->core->core_ppii != NULL)
9630Sstevel@tonic-gate 			free(P->core->core_ppii);
9640Sstevel@tonic-gate 		if (P->core->core_zonename != NULL)
9650Sstevel@tonic-gate 			free(P->core->core_zonename);
9660Sstevel@tonic-gate #if defined(__i386) || defined(__amd64)
9670Sstevel@tonic-gate 		if (P->core->core_ldt != NULL)
9680Sstevel@tonic-gate 			free(P->core->core_ldt);
9690Sstevel@tonic-gate #endif
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 		free(P->core);
9720Sstevel@tonic-gate 	}
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate 	if (P->ucaddrs != NULL) {
9750Sstevel@tonic-gate 		free(P->ucaddrs);
9760Sstevel@tonic-gate 		P->ucaddrs = NULL;
9770Sstevel@tonic-gate 		P->ucnelems = 0;
9780Sstevel@tonic-gate 	}
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	(void) mutex_lock(&P->proc_lock);
9810Sstevel@tonic-gate 	if (P->hashtab != NULL) {
9820Sstevel@tonic-gate 		struct ps_lwphandle *L;
9830Sstevel@tonic-gate 		for (i = 0; i < HASHSIZE; i++) {
9840Sstevel@tonic-gate 			while ((L = P->hashtab[i]) != NULL)
9850Sstevel@tonic-gate 				Lfree_internal(P, L);
9860Sstevel@tonic-gate 		}
9870Sstevel@tonic-gate 		free(P->hashtab);
9880Sstevel@tonic-gate 	}
9890Sstevel@tonic-gate 	(void) mutex_unlock(&P->proc_lock);
9900Sstevel@tonic-gate 	(void) mutex_destroy(&P->proc_lock);
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 	if (P->agentctlfd >= 0)
9930Sstevel@tonic-gate 		(void) close(P->agentctlfd);
9940Sstevel@tonic-gate 	if (P->agentstatfd >= 0)
9950Sstevel@tonic-gate 		(void) close(P->agentstatfd);
9960Sstevel@tonic-gate 	if (P->ctlfd >= 0)
9970Sstevel@tonic-gate 		(void) close(P->ctlfd);
9980Sstevel@tonic-gate 	if (P->asfd >= 0)
9990Sstevel@tonic-gate 		(void) close(P->asfd);
10000Sstevel@tonic-gate 	if (P->statfd >= 0)
10010Sstevel@tonic-gate 		(void) close(P->statfd);
10020Sstevel@tonic-gate 	Preset_maps(P);
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	/* clear out the structure as a precaution against reuse */
10050Sstevel@tonic-gate 	(void) memset(P, 0, sizeof (*P));
10060Sstevel@tonic-gate 	P->ctlfd = -1;
10070Sstevel@tonic-gate 	P->asfd = -1;
10080Sstevel@tonic-gate 	P->statfd = -1;
10090Sstevel@tonic-gate 	P->agentctlfd = -1;
10100Sstevel@tonic-gate 	P->agentstatfd = -1;
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 	free(P);
10130Sstevel@tonic-gate }
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate /*
10160Sstevel@tonic-gate  * Return the state of the process, one of the PS_* values.
10170Sstevel@tonic-gate  */
10180Sstevel@tonic-gate int
Pstate(struct ps_prochandle * P)10190Sstevel@tonic-gate Pstate(struct ps_prochandle *P)
10200Sstevel@tonic-gate {
10210Sstevel@tonic-gate 	return (P->state);
10220Sstevel@tonic-gate }
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate /*
10250Sstevel@tonic-gate  * Return the open address space file descriptor for the process.
10260Sstevel@tonic-gate  * Clients must not close this file descriptor, not use it
10270Sstevel@tonic-gate  * after the process is freed.
10280Sstevel@tonic-gate  */
10290Sstevel@tonic-gate int
Pasfd(struct ps_prochandle * P)10300Sstevel@tonic-gate Pasfd(struct ps_prochandle *P)
10310Sstevel@tonic-gate {
10320Sstevel@tonic-gate 	return (P->asfd);
10330Sstevel@tonic-gate }
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate /*
10360Sstevel@tonic-gate  * Return the open control file descriptor for the process.
10370Sstevel@tonic-gate  * Clients must not close this file descriptor, not use it
10380Sstevel@tonic-gate  * after the process is freed.
10390Sstevel@tonic-gate  */
10400Sstevel@tonic-gate int
Pctlfd(struct ps_prochandle * P)10410Sstevel@tonic-gate Pctlfd(struct ps_prochandle *P)
10420Sstevel@tonic-gate {
10430Sstevel@tonic-gate 	return (P->ctlfd);
10440Sstevel@tonic-gate }
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate /*
10470Sstevel@tonic-gate  * Return a pointer to the process psinfo structure.
10480Sstevel@tonic-gate  * Clients should not hold on to this pointer indefinitely.
10490Sstevel@tonic-gate  * It will become invalid on Prelease().
10500Sstevel@tonic-gate  */
10510Sstevel@tonic-gate const psinfo_t *
Ppsinfo(struct ps_prochandle * P)10520Sstevel@tonic-gate Ppsinfo(struct ps_prochandle *P)
10530Sstevel@tonic-gate {
10540Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
10550Sstevel@tonic-gate 		errno = ENODATA;
10560Sstevel@tonic-gate 		return (NULL);
10570Sstevel@tonic-gate 	}
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 	if (P->state != PS_DEAD && proc_get_psinfo(P->pid, &P->psinfo) == -1)
10600Sstevel@tonic-gate 		return (NULL);
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 	return (&P->psinfo);
10630Sstevel@tonic-gate }
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate /*
10660Sstevel@tonic-gate  * Return a pointer to the process status structure.
10670Sstevel@tonic-gate  * Clients should not hold on to this pointer indefinitely.
10680Sstevel@tonic-gate  * It will become invalid on Prelease().
10690Sstevel@tonic-gate  */
10700Sstevel@tonic-gate const pstatus_t *
Pstatus(struct ps_prochandle * P)10710Sstevel@tonic-gate Pstatus(struct ps_prochandle *P)
10720Sstevel@tonic-gate {
10730Sstevel@tonic-gate 	return (&P->status);
10740Sstevel@tonic-gate }
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate /*
10770Sstevel@tonic-gate  * Fill in a pointer to a process credentials structure.  The ngroups parameter
10780Sstevel@tonic-gate  * is the number of supplementary group entries allocated in the caller's cred
10790Sstevel@tonic-gate  * structure.  It should equal zero or one unless extra space has been
10800Sstevel@tonic-gate  * allocated for the group list by the caller.
10810Sstevel@tonic-gate  */
10820Sstevel@tonic-gate int
Pcred(struct ps_prochandle * P,prcred_t * pcrp,int ngroups)10830Sstevel@tonic-gate Pcred(struct ps_prochandle *P, prcred_t *pcrp, int ngroups)
10840Sstevel@tonic-gate {
10850Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
10860Sstevel@tonic-gate 		errno = ENODATA;
10870Sstevel@tonic-gate 		return (-1);
10880Sstevel@tonic-gate 	}
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	if (P->state != PS_DEAD)
10910Sstevel@tonic-gate 		return (proc_get_cred(P->pid, pcrp, ngroups));
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate 	if (P->core->core_cred != NULL) {
10940Sstevel@tonic-gate 		/*
10950Sstevel@tonic-gate 		 * Avoid returning more supplementary group data than the
10960Sstevel@tonic-gate 		 * caller has allocated in their buffer.  We expect them to
10970Sstevel@tonic-gate 		 * check pr_ngroups afterward and potentially call us again.
10980Sstevel@tonic-gate 		 */
10990Sstevel@tonic-gate 		ngroups = MIN(ngroups, P->core->core_cred->pr_ngroups);
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 		(void) memcpy(pcrp, P->core->core_cred,
11020Sstevel@tonic-gate 		    sizeof (prcred_t) + (ngroups - 1) * sizeof (gid_t));
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 		return (0);
11050Sstevel@tonic-gate 	}
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 	errno = ENODATA;
11080Sstevel@tonic-gate 	return (-1);
11090Sstevel@tonic-gate }
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate #if defined(__i386) || defined(__amd64)
11120Sstevel@tonic-gate /*
11130Sstevel@tonic-gate  * Fill in a pointer to a process LDT structure.
11140Sstevel@tonic-gate  * The caller provides a buffer of size 'nldt * sizeof (struct ssd)';
11150Sstevel@tonic-gate  * If pldt == NULL or nldt == 0, we return the number of existing LDT entries.
11160Sstevel@tonic-gate  * Otherwise we return the actual number of LDT entries fetched (<= nldt).
11170Sstevel@tonic-gate  */
11180Sstevel@tonic-gate int
Pldt(struct ps_prochandle * P,struct ssd * pldt,int nldt)11190Sstevel@tonic-gate Pldt(struct ps_prochandle *P, struct ssd *pldt, int nldt)
11200Sstevel@tonic-gate {
11210Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
11220Sstevel@tonic-gate 		errno = ENODATA;
11230Sstevel@tonic-gate 		return (-1);
11240Sstevel@tonic-gate 	}
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	if (P->state != PS_DEAD)
11270Sstevel@tonic-gate 		return (proc_get_ldt(P->pid, pldt, nldt));
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate 	if (pldt == NULL || nldt == 0)
11300Sstevel@tonic-gate 		return (P->core->core_nldt);
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	if (P->core->core_ldt != NULL) {
11330Sstevel@tonic-gate 		nldt = MIN(nldt, P->core->core_nldt);
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate 		(void) memcpy(pldt, P->core->core_ldt,
11360Sstevel@tonic-gate 		    nldt * sizeof (struct ssd));
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate 		return (nldt);
11390Sstevel@tonic-gate 	}
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 	errno = ENODATA;
11420Sstevel@tonic-gate 	return (-1);
11430Sstevel@tonic-gate }
11440Sstevel@tonic-gate #endif	/* __i386 */
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate /*
11470Sstevel@tonic-gate  * Fill in a pointer to a process privilege structure.
11480Sstevel@tonic-gate  */
11490Sstevel@tonic-gate ssize_t
Ppriv(struct ps_prochandle * P,prpriv_t * pprv,size_t size)11500Sstevel@tonic-gate Ppriv(struct ps_prochandle *P, prpriv_t *pprv, size_t size)
11510Sstevel@tonic-gate {
11520Sstevel@tonic-gate 	if (P->state != PS_DEAD) {
11530Sstevel@tonic-gate 		prpriv_t *pp = proc_get_priv(P->pid);
11540Sstevel@tonic-gate 		if (pp != NULL) {
11550Sstevel@tonic-gate 			size = MIN(size, PRIV_PRPRIV_SIZE(pp));
11560Sstevel@tonic-gate 			(void) memcpy(pprv, pp, size);
11570Sstevel@tonic-gate 			free(pp);
11580Sstevel@tonic-gate 			return (size);
11590Sstevel@tonic-gate 		}
11600Sstevel@tonic-gate 		return (-1);
11610Sstevel@tonic-gate 	}
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate 	if (P->core->core_priv != NULL) {
11640Sstevel@tonic-gate 		size = MIN(P->core->core_priv_size, size);
11650Sstevel@tonic-gate 		(void) memcpy(pprv, P->core->core_priv, size);
11660Sstevel@tonic-gate 		return (size);
11670Sstevel@tonic-gate 	}
11680Sstevel@tonic-gate 	errno = ENODATA;
11690Sstevel@tonic-gate 	return (-1);
11700Sstevel@tonic-gate }
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate int
Psetpriv(struct ps_prochandle * P,prpriv_t * pprv)11730Sstevel@tonic-gate Psetpriv(struct ps_prochandle *P, prpriv_t *pprv)
11740Sstevel@tonic-gate {
11750Sstevel@tonic-gate 	int rc;
11760Sstevel@tonic-gate 	long *ctl;
11770Sstevel@tonic-gate 	size_t sz;
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	if (P->state == PS_DEAD) {
11800Sstevel@tonic-gate 		errno = EBADF;
11810Sstevel@tonic-gate 		return (-1);
11820Sstevel@tonic-gate 	}
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate 	sz = PRIV_PRPRIV_SIZE(pprv) + sizeof (long);
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 	sz = ((sz - 1) / sizeof (long) + 1) * sizeof (long);
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate 	ctl = malloc(sz);
11890Sstevel@tonic-gate 	if (ctl == NULL)
11900Sstevel@tonic-gate 		return (-1);
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 	ctl[0] = PCSPRIV;
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 	(void) memcpy(&ctl[1], pprv, PRIV_PRPRIV_SIZE(pprv));
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate 	if (write(P->ctlfd, ctl, sz) != sz)
11970Sstevel@tonic-gate 		rc = -1;
11980Sstevel@tonic-gate 	else
11990Sstevel@tonic-gate 		rc = 0;
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate 	free(ctl);
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 	return (rc);
12040Sstevel@tonic-gate }
12050Sstevel@tonic-gate 
12060Sstevel@tonic-gate void *
Pprivinfo(struct ps_prochandle * P)12070Sstevel@tonic-gate Pprivinfo(struct ps_prochandle *P)
12080Sstevel@tonic-gate {
12090Sstevel@tonic-gate 	/* Use default from libc */
12100Sstevel@tonic-gate 	if (P->state != PS_DEAD)
12110Sstevel@tonic-gate 		return (NULL);
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate 	return (P->core->core_privinfo);
12140Sstevel@tonic-gate }
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate /*
12170Sstevel@tonic-gate  * Ensure that all cached state is written to the process.
12180Sstevel@tonic-gate  * The cached state is the LWP's signal mask and registers
12190Sstevel@tonic-gate  * and the process's tracing flags.
12200Sstevel@tonic-gate  */
12210Sstevel@tonic-gate void
Psync(struct ps_prochandle * P)12220Sstevel@tonic-gate Psync(struct ps_prochandle *P)
12230Sstevel@tonic-gate {
12240Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
12250Sstevel@tonic-gate 	long cmd[6];
12260Sstevel@tonic-gate 	iovec_t iov[12];
12270Sstevel@tonic-gate 	int n = 0;
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 	if (P->flags & SETHOLD) {
12300Sstevel@tonic-gate 		cmd[0] = PCSHOLD;
12310Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[0];
12320Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
12330Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&P->status.pr_lwp.pr_lwphold;
12340Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (P->status.pr_lwp.pr_lwphold);
12350Sstevel@tonic-gate 	}
12360Sstevel@tonic-gate 	if (P->flags & SETREGS) {
12370Sstevel@tonic-gate 		cmd[1] = PCSREG;
12380Sstevel@tonic-gate #ifdef __i386
12390Sstevel@tonic-gate 		/* XX64 we should probably restore REG_GS after this */
12400Sstevel@tonic-gate 		if (ctlfd == P->agentctlfd)
12410Sstevel@tonic-gate 			P->status.pr_lwp.pr_reg[GS] = 0;
12420Sstevel@tonic-gate #elif defined(__amd64)
12430Sstevel@tonic-gate 		/* XX64 */
12440Sstevel@tonic-gate #endif
12450Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[1];
12460Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
12470Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&P->status.pr_lwp.pr_reg[0];
12480Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (P->status.pr_lwp.pr_reg);
12490Sstevel@tonic-gate 	}
12500Sstevel@tonic-gate 	if (P->flags & SETSIG) {
12510Sstevel@tonic-gate 		cmd[2] = PCSTRACE;
12520Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[2];
12530Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
12540Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&P->status.pr_sigtrace;
12550Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (P->status.pr_sigtrace);
12560Sstevel@tonic-gate 	}
12570Sstevel@tonic-gate 	if (P->flags & SETFAULT) {
12580Sstevel@tonic-gate 		cmd[3] = PCSFAULT;
12590Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[3];
12600Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
12610Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&P->status.pr_flttrace;
12620Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (P->status.pr_flttrace);
12630Sstevel@tonic-gate 	}
12640Sstevel@tonic-gate 	if (P->flags & SETENTRY) {
12650Sstevel@tonic-gate 		cmd[4] = PCSENTRY;
12660Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[4];
12670Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
12680Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&P->status.pr_sysentry;
12690Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (P->status.pr_sysentry);
12700Sstevel@tonic-gate 	}
12710Sstevel@tonic-gate 	if (P->flags & SETEXIT) {
12720Sstevel@tonic-gate 		cmd[5] = PCSEXIT;
12730Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[5];
12740Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
12750Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&P->status.pr_sysexit;
12760Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (P->status.pr_sysexit);
12770Sstevel@tonic-gate 	}
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 	if (n == 0 || writev(ctlfd, iov, n) < 0)
12800Sstevel@tonic-gate 		return;		/* nothing to do or write failed */
12810Sstevel@tonic-gate 
12820Sstevel@tonic-gate 	P->flags &= ~(SETSIG|SETFAULT|SETENTRY|SETEXIT|SETHOLD|SETREGS);
12830Sstevel@tonic-gate }
12840Sstevel@tonic-gate 
12850Sstevel@tonic-gate /*
12860Sstevel@tonic-gate  * Reopen the /proc file (after PS_LOST).
12870Sstevel@tonic-gate  */
12880Sstevel@tonic-gate int
Preopen(struct ps_prochandle * P)12890Sstevel@tonic-gate Preopen(struct ps_prochandle *P)
12900Sstevel@tonic-gate {
12910Sstevel@tonic-gate 	int fd;
12922712Snn35248 	char procname[PATH_MAX];
12930Sstevel@tonic-gate 	char *fname;
12940Sstevel@tonic-gate 
12950Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_IDLE)
12960Sstevel@tonic-gate 		return (0);
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate 	if (P->agentcnt > 0) {
12990Sstevel@tonic-gate 		P->agentcnt = 1;
13000Sstevel@tonic-gate 		Pdestroy_agent(P);
13010Sstevel@tonic-gate 	}
13020Sstevel@tonic-gate 
13032712Snn35248 	(void) snprintf(procname, sizeof (procname), "%s/%d/",
13042712Snn35248 	    procfs_path, (int)P->pid);
13050Sstevel@tonic-gate 	fname = procname + strlen(procname);
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 	(void) strcpy(fname, "as");
13080Sstevel@tonic-gate 	if ((fd = open(procname, O_RDWR)) < 0 ||
13090Sstevel@tonic-gate 	    close(P->asfd) < 0 ||
13100Sstevel@tonic-gate 	    (fd = dupfd(fd, P->asfd)) != P->asfd) {
13110Sstevel@tonic-gate 		dprintf("Preopen: failed to open %s: %s\n",
13120Sstevel@tonic-gate 		    procname, strerror(errno));
13130Sstevel@tonic-gate 		if (fd >= 0)
13140Sstevel@tonic-gate 			(void) close(fd);
13150Sstevel@tonic-gate 		return (-1);
13160Sstevel@tonic-gate 	}
13170Sstevel@tonic-gate 	P->asfd = fd;
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate 	(void) strcpy(fname, "status");
13200Sstevel@tonic-gate 	if ((fd = open(procname, O_RDONLY)) < 0 ||
13210Sstevel@tonic-gate 	    close(P->statfd) < 0 ||
13220Sstevel@tonic-gate 	    (fd = dupfd(fd, P->statfd)) != P->statfd) {
13230Sstevel@tonic-gate 		dprintf("Preopen: failed to open %s: %s\n",
13240Sstevel@tonic-gate 		    procname, strerror(errno));
13250Sstevel@tonic-gate 		if (fd >= 0)
13260Sstevel@tonic-gate 			(void) close(fd);
13270Sstevel@tonic-gate 		return (-1);
13280Sstevel@tonic-gate 	}
13290Sstevel@tonic-gate 	P->statfd = fd;
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 	(void) strcpy(fname, "ctl");
13320Sstevel@tonic-gate 	if ((fd = open(procname, O_WRONLY)) < 0 ||
13330Sstevel@tonic-gate 	    close(P->ctlfd) < 0 ||
13340Sstevel@tonic-gate 	    (fd = dupfd(fd, P->ctlfd)) != P->ctlfd) {
13350Sstevel@tonic-gate 		dprintf("Preopen: failed to open %s: %s\n",
13360Sstevel@tonic-gate 		    procname, strerror(errno));
13370Sstevel@tonic-gate 		if (fd >= 0)
13380Sstevel@tonic-gate 			(void) close(fd);
13390Sstevel@tonic-gate 		return (-1);
13400Sstevel@tonic-gate 	}
13410Sstevel@tonic-gate 	P->ctlfd = fd;
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 	/*
13440Sstevel@tonic-gate 	 * Set the state to PS_RUN and wait for the process to stop so that
13450Sstevel@tonic-gate 	 * we re-read the status from the new P->statfd.  If this fails, Pwait
13460Sstevel@tonic-gate 	 * will reset the state to PS_LOST and we fail the reopen.  Before
13470Sstevel@tonic-gate 	 * returning, we also forge a bit of P->status to allow the debugger to
13480Sstevel@tonic-gate 	 * see that we are PS_LOST following a successful exec.
13490Sstevel@tonic-gate 	 */
13500Sstevel@tonic-gate 	P->state = PS_RUN;
13510Sstevel@tonic-gate 	if (Pwait(P, 0) == -1) {
13520Sstevel@tonic-gate #ifdef _ILP32
13530Sstevel@tonic-gate 		if (errno == EOVERFLOW)
13540Sstevel@tonic-gate 			P->status.pr_dmodel = PR_MODEL_LP64;
13550Sstevel@tonic-gate #endif
13560Sstevel@tonic-gate 		P->status.pr_lwp.pr_why = PR_SYSEXIT;
13570Sstevel@tonic-gate 		P->status.pr_lwp.pr_what = SYS_execve;
13580Sstevel@tonic-gate 		P->status.pr_lwp.pr_errno = 0;
13590Sstevel@tonic-gate 		return (-1);
13600Sstevel@tonic-gate 	}
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 	/*
13630Sstevel@tonic-gate 	 * The process should be stopped on exec (REQUESTED)
13640Sstevel@tonic-gate 	 * or else should be stopped on exit from exec() (SYSEXIT)
13650Sstevel@tonic-gate 	 */
13660Sstevel@tonic-gate 	if (P->state == PS_STOP &&
13670Sstevel@tonic-gate 	    (P->status.pr_lwp.pr_why == PR_REQUESTED ||
13680Sstevel@tonic-gate 	    (P->status.pr_lwp.pr_why == PR_SYSEXIT &&
1369*11798SRoger.Faulkner@Sun.COM 	    P->status.pr_lwp.pr_what == SYS_execve))) {
13700Sstevel@tonic-gate 		/* fake up stop-on-exit-from-execve */
13710Sstevel@tonic-gate 		if (P->status.pr_lwp.pr_why == PR_REQUESTED) {
13720Sstevel@tonic-gate 			P->status.pr_lwp.pr_why = PR_SYSEXIT;
13730Sstevel@tonic-gate 			P->status.pr_lwp.pr_what = SYS_execve;
13740Sstevel@tonic-gate 			P->status.pr_lwp.pr_errno = 0;
13750Sstevel@tonic-gate 		}
13760Sstevel@tonic-gate 	} else {
13770Sstevel@tonic-gate 		dprintf("Preopen: expected REQUESTED or "
13780Sstevel@tonic-gate 		    "SYSEXIT(SYS_execve) stop\n");
13790Sstevel@tonic-gate 	}
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate 	return (0);
13820Sstevel@tonic-gate }
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate /*
13850Sstevel@tonic-gate  * Define all settable flags other than the microstate accounting flags.
13860Sstevel@tonic-gate  */
13870Sstevel@tonic-gate #define	ALL_SETTABLE_FLAGS (PR_FORK|PR_RLC|PR_KLC|PR_ASYNC|PR_BPTADJ|PR_PTRACE)
13880Sstevel@tonic-gate 
13890Sstevel@tonic-gate /*
13900Sstevel@tonic-gate  * Restore /proc tracing flags to their original values
13910Sstevel@tonic-gate  * in preparation for releasing the process.
13920Sstevel@tonic-gate  * Also called by Pcreate() to clear all tracing flags.
13930Sstevel@tonic-gate  */
13940Sstevel@tonic-gate static void
restore_tracing_flags(struct ps_prochandle * P)13950Sstevel@tonic-gate restore_tracing_flags(struct ps_prochandle *P)
13960Sstevel@tonic-gate {
13970Sstevel@tonic-gate 	long flags;
13980Sstevel@tonic-gate 	long cmd[4];
13990Sstevel@tonic-gate 	iovec_t iov[8];
14000Sstevel@tonic-gate 
14010Sstevel@tonic-gate 	if (P->flags & CREATED) {
14020Sstevel@tonic-gate 		/* we created this process; clear all tracing flags */
14030Sstevel@tonic-gate 		premptyset(&P->status.pr_sigtrace);
14040Sstevel@tonic-gate 		premptyset(&P->status.pr_flttrace);
14050Sstevel@tonic-gate 		premptyset(&P->status.pr_sysentry);
14060Sstevel@tonic-gate 		premptyset(&P->status.pr_sysexit);
14070Sstevel@tonic-gate 		if ((P->status.pr_flags & ALL_SETTABLE_FLAGS) != 0)
14080Sstevel@tonic-gate 			(void) Punsetflags(P, ALL_SETTABLE_FLAGS);
14090Sstevel@tonic-gate 	} else {
14100Sstevel@tonic-gate 		/* we grabbed the process; restore its tracing flags */
14110Sstevel@tonic-gate 		P->status.pr_sigtrace = P->orig_status.pr_sigtrace;
14120Sstevel@tonic-gate 		P->status.pr_flttrace = P->orig_status.pr_flttrace;
14130Sstevel@tonic-gate 		P->status.pr_sysentry = P->orig_status.pr_sysentry;
14140Sstevel@tonic-gate 		P->status.pr_sysexit  = P->orig_status.pr_sysexit;
14150Sstevel@tonic-gate 		if ((P->status.pr_flags & ALL_SETTABLE_FLAGS) !=
14160Sstevel@tonic-gate 		    (flags = (P->orig_status.pr_flags & ALL_SETTABLE_FLAGS))) {
14170Sstevel@tonic-gate 			(void) Punsetflags(P, ALL_SETTABLE_FLAGS);
14180Sstevel@tonic-gate 			if (flags)
14190Sstevel@tonic-gate 				(void) Psetflags(P, flags);
14200Sstevel@tonic-gate 		}
14210Sstevel@tonic-gate 	}
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 	cmd[0] = PCSTRACE;
14240Sstevel@tonic-gate 	iov[0].iov_base = (caddr_t)&cmd[0];
14250Sstevel@tonic-gate 	iov[0].iov_len = sizeof (long);
14260Sstevel@tonic-gate 	iov[1].iov_base = (caddr_t)&P->status.pr_sigtrace;
14270Sstevel@tonic-gate 	iov[1].iov_len = sizeof (P->status.pr_sigtrace);
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate 	cmd[1] = PCSFAULT;
14300Sstevel@tonic-gate 	iov[2].iov_base = (caddr_t)&cmd[1];
14310Sstevel@tonic-gate 	iov[2].iov_len = sizeof (long);
14320Sstevel@tonic-gate 	iov[3].iov_base = (caddr_t)&P->status.pr_flttrace;
14330Sstevel@tonic-gate 	iov[3].iov_len = sizeof (P->status.pr_flttrace);
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 	cmd[2] = PCSENTRY;
14360Sstevel@tonic-gate 	iov[4].iov_base = (caddr_t)&cmd[2];
14370Sstevel@tonic-gate 	iov[4].iov_len = sizeof (long);
14380Sstevel@tonic-gate 	iov[5].iov_base = (caddr_t)&P->status.pr_sysentry;
14390Sstevel@tonic-gate 	iov[5].iov_len = sizeof (P->status.pr_sysentry);
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 	cmd[3] = PCSEXIT;
14420Sstevel@tonic-gate 	iov[6].iov_base = (caddr_t)&cmd[3];
14430Sstevel@tonic-gate 	iov[6].iov_len = sizeof (long);
14440Sstevel@tonic-gate 	iov[7].iov_base = (caddr_t)&P->status.pr_sysexit;
14450Sstevel@tonic-gate 	iov[7].iov_len = sizeof (P->status.pr_sysexit);
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 	(void) writev(P->ctlfd, iov, 8);
14480Sstevel@tonic-gate 
14490Sstevel@tonic-gate 	P->flags &= ~(SETSIG|SETFAULT|SETENTRY|SETEXIT);
14500Sstevel@tonic-gate }
14510Sstevel@tonic-gate 
14520Sstevel@tonic-gate /*
14530Sstevel@tonic-gate  * Release the process.  Frees the process control structure.
14540Sstevel@tonic-gate  * flags:
14550Sstevel@tonic-gate  *	PRELEASE_CLEAR	Clear all tracing flags.
14560Sstevel@tonic-gate  *	PRELEASE_RETAIN	Retain current tracing flags.
14570Sstevel@tonic-gate  *	PRELEASE_HANG	Leave the process stopped and abandoned.
14580Sstevel@tonic-gate  *	PRELEASE_KILL	Terminate the process with SIGKILL.
14590Sstevel@tonic-gate  */
14600Sstevel@tonic-gate void
Prelease(struct ps_prochandle * P,int flags)14610Sstevel@tonic-gate Prelease(struct ps_prochandle *P, int flags)
14620Sstevel@tonic-gate {
14630Sstevel@tonic-gate 	if (P->state == PS_DEAD) {
14640Sstevel@tonic-gate 		dprintf("Prelease: releasing handle %p PS_DEAD of pid %d\n",
14650Sstevel@tonic-gate 		    (void *)P, (int)P->pid);
14660Sstevel@tonic-gate 		Pfree(P);
14670Sstevel@tonic-gate 		return;
14680Sstevel@tonic-gate 	}
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
14710Sstevel@tonic-gate 		file_info_t *fptr = list_next(&P->file_head);
14720Sstevel@tonic-gate 		dprintf("Prelease: releasing handle %p PS_IDLE of file %s\n",
14730Sstevel@tonic-gate 		    (void *)P, fptr->file_pname);
14740Sstevel@tonic-gate 		Pfree(P);
14750Sstevel@tonic-gate 		return;
14760Sstevel@tonic-gate 	}
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate 	dprintf("Prelease: releasing handle %p pid %d\n",
14790Sstevel@tonic-gate 	    (void *)P, (int)P->pid);
14800Sstevel@tonic-gate 
14810Sstevel@tonic-gate 	if (P->ctlfd == -1) {
14820Sstevel@tonic-gate 		Pfree(P);
14830Sstevel@tonic-gate 		return;
14840Sstevel@tonic-gate 	}
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 	if (P->agentcnt > 0) {
14870Sstevel@tonic-gate 		P->agentcnt = 1;
14880Sstevel@tonic-gate 		Pdestroy_agent(P);
14890Sstevel@tonic-gate 	}
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 	/*
14920Sstevel@tonic-gate 	 * Attempt to stop the process.
14930Sstevel@tonic-gate 	 */
14940Sstevel@tonic-gate 	P->state = PS_RUN;
14950Sstevel@tonic-gate 	(void) Pstop(P, 1000);
14960Sstevel@tonic-gate 
14970Sstevel@tonic-gate 	if (flags & PRELEASE_KILL) {
14980Sstevel@tonic-gate 		if (P->state == PS_STOP)
14990Sstevel@tonic-gate 			(void) Psetrun(P, SIGKILL, 0);
15000Sstevel@tonic-gate 		(void) kill(P->pid, SIGKILL);
15010Sstevel@tonic-gate 		Pfree(P);
15020Sstevel@tonic-gate 		return;
15030Sstevel@tonic-gate 	}
15040Sstevel@tonic-gate 
15050Sstevel@tonic-gate 	/*
15060Sstevel@tonic-gate 	 * If we lost control, all we can do now is close the files.
15070Sstevel@tonic-gate 	 * In this case, the last close sets the process running.
15080Sstevel@tonic-gate 	 */
15090Sstevel@tonic-gate 	if (P->state != PS_STOP &&
15100Sstevel@tonic-gate 	    (P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)) == 0) {
15110Sstevel@tonic-gate 		Pfree(P);
15120Sstevel@tonic-gate 		return;
15130Sstevel@tonic-gate 	}
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate 	/*
15160Sstevel@tonic-gate 	 * We didn't lose control; we do more.
15170Sstevel@tonic-gate 	 */
15180Sstevel@tonic-gate 	Psync(P);
15190Sstevel@tonic-gate 
15200Sstevel@tonic-gate 	if (flags & PRELEASE_CLEAR)
15210Sstevel@tonic-gate 		P->flags |= CREATED;
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate 	if (!(flags & PRELEASE_RETAIN))
15240Sstevel@tonic-gate 		restore_tracing_flags(P);
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 	if (flags & PRELEASE_HANG) {
15270Sstevel@tonic-gate 		/* Leave the process stopped and abandoned */
15280Sstevel@tonic-gate 		(void) Punsetflags(P, PR_RLC|PR_KLC);
15290Sstevel@tonic-gate 		Pfree(P);
15300Sstevel@tonic-gate 		return;
15310Sstevel@tonic-gate 	}
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 	/*
15340Sstevel@tonic-gate 	 * Set the process running if we created it or if it was
15350Sstevel@tonic-gate 	 * not originally stopped or directed to stop via /proc
15360Sstevel@tonic-gate 	 * or if we were given the PRELEASE_CLEAR flag.
15370Sstevel@tonic-gate 	 */
15380Sstevel@tonic-gate 	if ((P->flags & CREATED) ||
15390Sstevel@tonic-gate 	    (P->orig_status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)) == 0) {
15400Sstevel@tonic-gate 		(void) Psetflags(P, PR_RLC);
15410Sstevel@tonic-gate 		/*
15420Sstevel@tonic-gate 		 * We do this repeatedly because the process may have
15430Sstevel@tonic-gate 		 * more than one LWP stopped on an event of interest.
15440Sstevel@tonic-gate 		 * This makes sure all of them are set running.
15450Sstevel@tonic-gate 		 */
15460Sstevel@tonic-gate 		do {
15470Sstevel@tonic-gate 			if (Psetrun(P, 0, 0) == -1 && errno == EBUSY)
15480Sstevel@tonic-gate 				break; /* Agent LWP may be stuck */
15490Sstevel@tonic-gate 		} while (Pstopstatus(P, PCNULL, 0) == 0 &&
15500Sstevel@tonic-gate 		    P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP));
15510Sstevel@tonic-gate 
15520Sstevel@tonic-gate 		if (P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP))
15530Sstevel@tonic-gate 			dprintf("Prelease: failed to set process running\n");
15540Sstevel@tonic-gate 	}
15550Sstevel@tonic-gate 
15560Sstevel@tonic-gate 	Pfree(P);
15570Sstevel@tonic-gate }
15580Sstevel@tonic-gate 
15590Sstevel@tonic-gate /* debugging */
15600Sstevel@tonic-gate void
prldump(const char * caller,lwpstatus_t * lsp)15610Sstevel@tonic-gate prldump(const char *caller, lwpstatus_t *lsp)
15620Sstevel@tonic-gate {
15630Sstevel@tonic-gate 	char name[32];
15640Sstevel@tonic-gate 	uint32_t bits;
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate 	switch (lsp->pr_why) {
15670Sstevel@tonic-gate 	case PR_REQUESTED:
15680Sstevel@tonic-gate 		dprintf("%s: REQUESTED\n", caller);
15690Sstevel@tonic-gate 		break;
15700Sstevel@tonic-gate 	case PR_SIGNALLED:
15710Sstevel@tonic-gate 		dprintf("%s: SIGNALLED %s\n", caller,
15724753Srh87107 		    proc_signame(lsp->pr_what, name, sizeof (name)));
15730Sstevel@tonic-gate 		break;
15740Sstevel@tonic-gate 	case PR_FAULTED:
15750Sstevel@tonic-gate 		dprintf("%s: FAULTED %s\n", caller,
15764753Srh87107 		    proc_fltname(lsp->pr_what, name, sizeof (name)));
15770Sstevel@tonic-gate 		break;
15780Sstevel@tonic-gate 	case PR_SYSENTRY:
15790Sstevel@tonic-gate 		dprintf("%s: SYSENTRY %s\n", caller,
15804753Srh87107 		    proc_sysname(lsp->pr_what, name, sizeof (name)));
15810Sstevel@tonic-gate 		break;
15820Sstevel@tonic-gate 	case PR_SYSEXIT:
15830Sstevel@tonic-gate 		dprintf("%s: SYSEXIT %s\n", caller,
15844753Srh87107 		    proc_sysname(lsp->pr_what, name, sizeof (name)));
15850Sstevel@tonic-gate 		break;
15860Sstevel@tonic-gate 	case PR_JOBCONTROL:
15870Sstevel@tonic-gate 		dprintf("%s: JOBCONTROL %s\n", caller,
15884753Srh87107 		    proc_signame(lsp->pr_what, name, sizeof (name)));
15890Sstevel@tonic-gate 		break;
15900Sstevel@tonic-gate 	case PR_SUSPENDED:
15910Sstevel@tonic-gate 		dprintf("%s: SUSPENDED\n", caller);
15920Sstevel@tonic-gate 		break;
15930Sstevel@tonic-gate 	default:
15940Sstevel@tonic-gate 		dprintf("%s: Unknown\n", caller);
15950Sstevel@tonic-gate 		break;
15960Sstevel@tonic-gate 	}
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate 	if (lsp->pr_cursig)
15990Sstevel@tonic-gate 		dprintf("%s: p_cursig  = %d\n", caller, lsp->pr_cursig);
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate 	bits = *((uint32_t *)&lsp->pr_lwppend);
16020Sstevel@tonic-gate 	if (bits)
16030Sstevel@tonic-gate 		dprintf("%s: pr_lwppend = 0x%.8X\n", caller, bits);
16040Sstevel@tonic-gate }
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate /* debugging */
16070Sstevel@tonic-gate static void
prdump(struct ps_prochandle * P)16080Sstevel@tonic-gate prdump(struct ps_prochandle *P)
16090Sstevel@tonic-gate {
16100Sstevel@tonic-gate 	uint32_t bits;
16110Sstevel@tonic-gate 
16120Sstevel@tonic-gate 	prldump("Pstopstatus", &P->status.pr_lwp);
16130Sstevel@tonic-gate 
16140Sstevel@tonic-gate 	bits = *((uint32_t *)&P->status.pr_sigpend);
16150Sstevel@tonic-gate 	if (bits)
16160Sstevel@tonic-gate 		dprintf("Pstopstatus: pr_sigpend = 0x%.8X\n", bits);
16170Sstevel@tonic-gate }
16180Sstevel@tonic-gate 
16190Sstevel@tonic-gate /*
16200Sstevel@tonic-gate  * Wait for the specified process to stop or terminate.
16210Sstevel@tonic-gate  * Or, just get the current status (PCNULL).
16220Sstevel@tonic-gate  * Or, direct it to stop and get the current status (PCDSTOP).
16230Sstevel@tonic-gate  * If the agent LWP exists, do these things to the agent,
16240Sstevel@tonic-gate  * else do these things to the process as a whole.
16250Sstevel@tonic-gate  */
16260Sstevel@tonic-gate int
Pstopstatus(struct ps_prochandle * P,long request,uint_t msec)16270Sstevel@tonic-gate Pstopstatus(struct ps_prochandle *P,
16280Sstevel@tonic-gate 	long request,		/* PCNULL, PCDSTOP, PCSTOP, PCWSTOP */
16290Sstevel@tonic-gate 	uint_t msec)		/* if non-zero, timeout in milliseconds */
16300Sstevel@tonic-gate {
16310Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
16320Sstevel@tonic-gate 	long ctl[3];
16330Sstevel@tonic-gate 	ssize_t rc;
16340Sstevel@tonic-gate 	int err;
16350Sstevel@tonic-gate 	int old_state = P->state;
16360Sstevel@tonic-gate 
16370Sstevel@tonic-gate 	switch (P->state) {
16380Sstevel@tonic-gate 	case PS_RUN:
16390Sstevel@tonic-gate 		break;
16400Sstevel@tonic-gate 	case PS_STOP:
16410Sstevel@tonic-gate 		if (request != PCNULL && request != PCDSTOP)
16420Sstevel@tonic-gate 			return (0);
16430Sstevel@tonic-gate 		break;
16440Sstevel@tonic-gate 	case PS_LOST:
16450Sstevel@tonic-gate 		if (request != PCNULL) {
16460Sstevel@tonic-gate 			errno = EAGAIN;
16470Sstevel@tonic-gate 			return (-1);
16480Sstevel@tonic-gate 		}
16490Sstevel@tonic-gate 		break;
16500Sstevel@tonic-gate 	case PS_UNDEAD:
16510Sstevel@tonic-gate 	case PS_DEAD:
16520Sstevel@tonic-gate 	case PS_IDLE:
16530Sstevel@tonic-gate 		if (request != PCNULL) {
16540Sstevel@tonic-gate 			errno = ENOENT;
16550Sstevel@tonic-gate 			return (-1);
16560Sstevel@tonic-gate 		}
16570Sstevel@tonic-gate 		break;
16580Sstevel@tonic-gate 	default:	/* corrupted state */
16590Sstevel@tonic-gate 		dprintf("Pstopstatus: corrupted state: %d\n", P->state);
16600Sstevel@tonic-gate 		errno = EINVAL;
16610Sstevel@tonic-gate 		return (-1);
16620Sstevel@tonic-gate 	}
16630Sstevel@tonic-gate 
16640Sstevel@tonic-gate 	ctl[0] = PCDSTOP;
16650Sstevel@tonic-gate 	ctl[1] = PCTWSTOP;
16660Sstevel@tonic-gate 	ctl[2] = (long)msec;
16670Sstevel@tonic-gate 	rc = 0;
16680Sstevel@tonic-gate 	switch (request) {
16690Sstevel@tonic-gate 	case PCSTOP:
16700Sstevel@tonic-gate 		rc = write(ctlfd, &ctl[0], 3*sizeof (long));
16710Sstevel@tonic-gate 		break;
16720Sstevel@tonic-gate 	case PCWSTOP:
16730Sstevel@tonic-gate 		rc = write(ctlfd, &ctl[1], 2*sizeof (long));
16740Sstevel@tonic-gate 		break;
16750Sstevel@tonic-gate 	case PCDSTOP:
16760Sstevel@tonic-gate 		rc = write(ctlfd, &ctl[0], 1*sizeof (long));
16770Sstevel@tonic-gate 		break;
16780Sstevel@tonic-gate 	case PCNULL:
16790Sstevel@tonic-gate 		if (P->state == PS_DEAD || P->state == PS_IDLE)
16800Sstevel@tonic-gate 			return (0);
16810Sstevel@tonic-gate 		break;
16820Sstevel@tonic-gate 	default:	/* programming error */
16830Sstevel@tonic-gate 		errno = EINVAL;
16840Sstevel@tonic-gate 		return (-1);
16850Sstevel@tonic-gate 	}
16860Sstevel@tonic-gate 	err = (rc < 0)? errno : 0;
16870Sstevel@tonic-gate 	Psync(P);
16880Sstevel@tonic-gate 
16890Sstevel@tonic-gate 	if (P->agentstatfd < 0) {
16900Sstevel@tonic-gate 		if (pread(P->statfd, &P->status,
16910Sstevel@tonic-gate 		    sizeof (P->status), (off_t)0) < 0)
16920Sstevel@tonic-gate 			err = errno;
16930Sstevel@tonic-gate 	} else {
16940Sstevel@tonic-gate 		if (pread(P->agentstatfd, &P->status.pr_lwp,
16950Sstevel@tonic-gate 		    sizeof (P->status.pr_lwp), (off_t)0) < 0)
16960Sstevel@tonic-gate 			err = errno;
16970Sstevel@tonic-gate 		P->status.pr_flags = P->status.pr_lwp.pr_flags;
16980Sstevel@tonic-gate 	}
16990Sstevel@tonic-gate 
17000Sstevel@tonic-gate 	if (err) {
17010Sstevel@tonic-gate 		switch (err) {
17020Sstevel@tonic-gate 		case EINTR:		/* user typed ctl-C */
17030Sstevel@tonic-gate 		case ERESTART:
17040Sstevel@tonic-gate 			dprintf("Pstopstatus: EINTR\n");
17050Sstevel@tonic-gate 			break;
17060Sstevel@tonic-gate 		case EAGAIN:		/* we lost control of the the process */
17070Sstevel@tonic-gate 		case EOVERFLOW:
17080Sstevel@tonic-gate 			dprintf("Pstopstatus: PS_LOST, errno=%d\n", err);
17090Sstevel@tonic-gate 			P->state = PS_LOST;
17100Sstevel@tonic-gate 			break;
17110Sstevel@tonic-gate 		default:		/* check for dead process */
17120Sstevel@tonic-gate 			if (_libproc_debug) {
17130Sstevel@tonic-gate 				const char *errstr;
17140Sstevel@tonic-gate 
17150Sstevel@tonic-gate 				switch (request) {
17160Sstevel@tonic-gate 				case PCNULL:
17170Sstevel@tonic-gate 					errstr = "Pstopstatus PCNULL"; break;
17180Sstevel@tonic-gate 				case PCSTOP:
17190Sstevel@tonic-gate 					errstr = "Pstopstatus PCSTOP"; break;
17200Sstevel@tonic-gate 				case PCDSTOP:
17210Sstevel@tonic-gate 					errstr = "Pstopstatus PCDSTOP"; break;
17220Sstevel@tonic-gate 				case PCWSTOP:
17230Sstevel@tonic-gate 					errstr = "Pstopstatus PCWSTOP"; break;
17240Sstevel@tonic-gate 				default:
17250Sstevel@tonic-gate 					errstr = "Pstopstatus PC???"; break;
17260Sstevel@tonic-gate 				}
17270Sstevel@tonic-gate 				dprintf("%s: %s\n", errstr, strerror(err));
17280Sstevel@tonic-gate 			}
17290Sstevel@tonic-gate 			deadcheck(P);
17300Sstevel@tonic-gate 			break;
17310Sstevel@tonic-gate 		}
17320Sstevel@tonic-gate 		if (err != EINTR && err != ERESTART) {
17330Sstevel@tonic-gate 			errno = err;
17340Sstevel@tonic-gate 			return (-1);
17350Sstevel@tonic-gate 		}
17360Sstevel@tonic-gate 	}
17370Sstevel@tonic-gate 
17380Sstevel@tonic-gate 	if (!(P->status.pr_flags & PR_STOPPED)) {
17390Sstevel@tonic-gate 		P->state = PS_RUN;
17400Sstevel@tonic-gate 		if (request == PCNULL || request == PCDSTOP || msec != 0)
17410Sstevel@tonic-gate 			return (0);
17420Sstevel@tonic-gate 		dprintf("Pstopstatus: process is not stopped\n");
17430Sstevel@tonic-gate 		errno = EPROTO;
17440Sstevel@tonic-gate 		return (-1);
17450Sstevel@tonic-gate 	}
17460Sstevel@tonic-gate 
17470Sstevel@tonic-gate 	P->state = PS_STOP;
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 	if (_libproc_debug)	/* debugging */
17500Sstevel@tonic-gate 		prdump(P);
17510Sstevel@tonic-gate 
17520Sstevel@tonic-gate 	/*
17530Sstevel@tonic-gate 	 * If the process was already stopped coming into Pstopstatus(),
17540Sstevel@tonic-gate 	 * then don't use its PC to set P->sysaddr since it may have been
17550Sstevel@tonic-gate 	 * changed since the time the process originally stopped.
17560Sstevel@tonic-gate 	 */
17570Sstevel@tonic-gate 	if (old_state == PS_STOP)
17580Sstevel@tonic-gate 		return (0);
17590Sstevel@tonic-gate 
17600Sstevel@tonic-gate 	switch (P->status.pr_lwp.pr_why) {
17610Sstevel@tonic-gate 	case PR_SYSENTRY:
17620Sstevel@tonic-gate 	case PR_SYSEXIT:
17630Sstevel@tonic-gate 		if (Pissyscall_prev(P, P->status.pr_lwp.pr_reg[R_PC],
17640Sstevel@tonic-gate 		    &P->sysaddr) == 0)
17650Sstevel@tonic-gate 			P->sysaddr = P->status.pr_lwp.pr_reg[R_PC];
17660Sstevel@tonic-gate 		break;
17670Sstevel@tonic-gate 	case PR_REQUESTED:
17680Sstevel@tonic-gate 	case PR_SIGNALLED:
17690Sstevel@tonic-gate 	case PR_FAULTED:
17700Sstevel@tonic-gate 	case PR_JOBCONTROL:
17710Sstevel@tonic-gate 	case PR_SUSPENDED:
17720Sstevel@tonic-gate 		break;
17730Sstevel@tonic-gate 	default:
17740Sstevel@tonic-gate 		errno = EPROTO;
17750Sstevel@tonic-gate 		return (-1);
17760Sstevel@tonic-gate 	}
17770Sstevel@tonic-gate 
17780Sstevel@tonic-gate 	return (0);
17790Sstevel@tonic-gate }
17800Sstevel@tonic-gate 
17810Sstevel@tonic-gate /*
17820Sstevel@tonic-gate  * Wait for the process to stop for any reason.
17830Sstevel@tonic-gate  */
17840Sstevel@tonic-gate int
Pwait(struct ps_prochandle * P,uint_t msec)17850Sstevel@tonic-gate Pwait(struct ps_prochandle *P, uint_t msec)
17860Sstevel@tonic-gate {
17870Sstevel@tonic-gate 	return (Pstopstatus(P, PCWSTOP, msec));
17880Sstevel@tonic-gate }
17890Sstevel@tonic-gate 
17900Sstevel@tonic-gate /*
17910Sstevel@tonic-gate  * Direct the process to stop; wait for it to stop.
17920Sstevel@tonic-gate  */
17930Sstevel@tonic-gate int
Pstop(struct ps_prochandle * P,uint_t msec)17940Sstevel@tonic-gate Pstop(struct ps_prochandle *P, uint_t msec)
17950Sstevel@tonic-gate {
17960Sstevel@tonic-gate 	return (Pstopstatus(P, PCSTOP, msec));
17970Sstevel@tonic-gate }
17980Sstevel@tonic-gate 
17990Sstevel@tonic-gate /*
18000Sstevel@tonic-gate  * Direct the process to stop; don't wait.
18010Sstevel@tonic-gate  */
18020Sstevel@tonic-gate int
Pdstop(struct ps_prochandle * P)18030Sstevel@tonic-gate Pdstop(struct ps_prochandle *P)
18040Sstevel@tonic-gate {
18050Sstevel@tonic-gate 	return (Pstopstatus(P, PCDSTOP, 0));
18060Sstevel@tonic-gate }
18070Sstevel@tonic-gate 
18080Sstevel@tonic-gate static void
deadcheck(struct ps_prochandle * P)18090Sstevel@tonic-gate deadcheck(struct ps_prochandle *P)
18100Sstevel@tonic-gate {
18110Sstevel@tonic-gate 	int fd;
18120Sstevel@tonic-gate 	void *buf;
18130Sstevel@tonic-gate 	size_t size;
18140Sstevel@tonic-gate 
18150Sstevel@tonic-gate 	if (P->statfd < 0)
18160Sstevel@tonic-gate 		P->state = PS_UNDEAD;
18170Sstevel@tonic-gate 	else {
18180Sstevel@tonic-gate 		if (P->agentstatfd < 0) {
18190Sstevel@tonic-gate 			fd = P->statfd;
18200Sstevel@tonic-gate 			buf = &P->status;
18210Sstevel@tonic-gate 			size = sizeof (P->status);
18220Sstevel@tonic-gate 		} else {
18230Sstevel@tonic-gate 			fd = P->agentstatfd;
18240Sstevel@tonic-gate 			buf = &P->status.pr_lwp;
18250Sstevel@tonic-gate 			size = sizeof (P->status.pr_lwp);
18260Sstevel@tonic-gate 		}
18270Sstevel@tonic-gate 		while (pread(fd, buf, size, (off_t)0) != size) {
18280Sstevel@tonic-gate 			switch (errno) {
18290Sstevel@tonic-gate 			default:
18300Sstevel@tonic-gate 				P->state = PS_UNDEAD;
18310Sstevel@tonic-gate 				break;
18320Sstevel@tonic-gate 			case EINTR:
18330Sstevel@tonic-gate 			case ERESTART:
18340Sstevel@tonic-gate 				continue;
18350Sstevel@tonic-gate 			case EAGAIN:
18360Sstevel@tonic-gate 				P->state = PS_LOST;
18370Sstevel@tonic-gate 				break;
18380Sstevel@tonic-gate 			}
18390Sstevel@tonic-gate 			break;
18400Sstevel@tonic-gate 		}
18410Sstevel@tonic-gate 		P->status.pr_flags = P->status.pr_lwp.pr_flags;
18420Sstevel@tonic-gate 	}
18430Sstevel@tonic-gate }
18440Sstevel@tonic-gate 
18450Sstevel@tonic-gate /*
18460Sstevel@tonic-gate  * Get the value of one register from stopped process.
18470Sstevel@tonic-gate  */
18480Sstevel@tonic-gate int
Pgetareg(struct ps_prochandle * P,int regno,prgreg_t * preg)18490Sstevel@tonic-gate Pgetareg(struct ps_prochandle *P, int regno, prgreg_t *preg)
18500Sstevel@tonic-gate {
18510Sstevel@tonic-gate 	if (regno < 0 || regno >= NPRGREG) {
18520Sstevel@tonic-gate 		errno = EINVAL;
18530Sstevel@tonic-gate 		return (-1);
18540Sstevel@tonic-gate 	}
18550Sstevel@tonic-gate 
18560Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
18570Sstevel@tonic-gate 		errno = ENODATA;
18580Sstevel@tonic-gate 		return (-1);
18590Sstevel@tonic-gate 	}
18600Sstevel@tonic-gate 
18610Sstevel@tonic-gate 	if (P->state != PS_STOP && P->state != PS_DEAD) {
18620Sstevel@tonic-gate 		errno = EBUSY;
18630Sstevel@tonic-gate 		return (-1);
18640Sstevel@tonic-gate 	}
18650Sstevel@tonic-gate 
18660Sstevel@tonic-gate 	*preg = P->status.pr_lwp.pr_reg[regno];
18670Sstevel@tonic-gate 	return (0);
18680Sstevel@tonic-gate }
18690Sstevel@tonic-gate 
18700Sstevel@tonic-gate /*
18710Sstevel@tonic-gate  * Put value of one register into stopped process.
18720Sstevel@tonic-gate  */
18730Sstevel@tonic-gate int
Pputareg(struct ps_prochandle * P,int regno,prgreg_t reg)18740Sstevel@tonic-gate Pputareg(struct ps_prochandle *P, int regno, prgreg_t reg)
18750Sstevel@tonic-gate {
18760Sstevel@tonic-gate 	if (regno < 0 || regno >= NPRGREG) {
18770Sstevel@tonic-gate 		errno = EINVAL;
18780Sstevel@tonic-gate 		return (-1);
18790Sstevel@tonic-gate 	}
18800Sstevel@tonic-gate 
18810Sstevel@tonic-gate 	if (P->state != PS_STOP) {
18820Sstevel@tonic-gate 		errno = EBUSY;
18830Sstevel@tonic-gate 		return (-1);
18840Sstevel@tonic-gate 	}
18850Sstevel@tonic-gate 
18860Sstevel@tonic-gate 	P->status.pr_lwp.pr_reg[regno] = reg;
18870Sstevel@tonic-gate 	P->flags |= SETREGS;	/* set registers before continuing */
18880Sstevel@tonic-gate 	return (0);
18890Sstevel@tonic-gate }
18900Sstevel@tonic-gate 
18910Sstevel@tonic-gate int
Psetrun(struct ps_prochandle * P,int sig,int flags)18920Sstevel@tonic-gate Psetrun(struct ps_prochandle *P,
18930Sstevel@tonic-gate 	int sig,	/* signal to pass to process */
18940Sstevel@tonic-gate 	int flags)	/* PRSTEP|PRSABORT|PRSTOP|PRCSIG|PRCFAULT */
18950Sstevel@tonic-gate {
18960Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0) ? P->agentctlfd : P->ctlfd;
18970Sstevel@tonic-gate 	int sbits = (PR_DSTOP | PR_ISTOP | PR_ASLEEP);
18980Sstevel@tonic-gate 
18990Sstevel@tonic-gate 	long ctl[1 +					/* PCCFAULT	*/
19004753Srh87107 	    1 + sizeof (siginfo_t)/sizeof (long) +	/* PCSSIG/PCCSIG */
19014753Srh87107 	    2 ];					/* PCRUN	*/
19020Sstevel@tonic-gate 
19030Sstevel@tonic-gate 	long *ctlp = ctl;
19040Sstevel@tonic-gate 	size_t size;
19050Sstevel@tonic-gate 
19060Sstevel@tonic-gate 	if (P->state != PS_STOP && (P->status.pr_lwp.pr_flags & sbits) == 0) {
19070Sstevel@tonic-gate 		errno = EBUSY;
19080Sstevel@tonic-gate 		return (-1);
19090Sstevel@tonic-gate 	}
19100Sstevel@tonic-gate 
19110Sstevel@tonic-gate 	Psync(P);	/* flush tracing flags and registers */
19120Sstevel@tonic-gate 
19130Sstevel@tonic-gate 	if (flags & PRCFAULT) {		/* clear current fault */
19140Sstevel@tonic-gate 		*ctlp++ = PCCFAULT;
19150Sstevel@tonic-gate 		flags &= ~PRCFAULT;
19160Sstevel@tonic-gate 	}
19170Sstevel@tonic-gate 
19180Sstevel@tonic-gate 	if (flags & PRCSIG) {		/* clear current signal */
19190Sstevel@tonic-gate 		*ctlp++ = PCCSIG;
19200Sstevel@tonic-gate 		flags &= ~PRCSIG;
19210Sstevel@tonic-gate 	} else if (sig && sig != P->status.pr_lwp.pr_cursig) {
19220Sstevel@tonic-gate 		/* make current signal */
19230Sstevel@tonic-gate 		siginfo_t *infop;
19240Sstevel@tonic-gate 
19250Sstevel@tonic-gate 		*ctlp++ = PCSSIG;
19260Sstevel@tonic-gate 		infop = (siginfo_t *)ctlp;
19270Sstevel@tonic-gate 		(void) memset(infop, 0, sizeof (*infop));
19280Sstevel@tonic-gate 		infop->si_signo = sig;
19290Sstevel@tonic-gate 		ctlp += sizeof (siginfo_t) / sizeof (long);
19300Sstevel@tonic-gate 	}
19310Sstevel@tonic-gate 
19320Sstevel@tonic-gate 	*ctlp++ = PCRUN;
19330Sstevel@tonic-gate 	*ctlp++ = flags;
19340Sstevel@tonic-gate 	size = (char *)ctlp - (char *)ctl;
19350Sstevel@tonic-gate 
19360Sstevel@tonic-gate 	P->info_valid = 0;	/* will need to update map and file info */
19370Sstevel@tonic-gate 
19380Sstevel@tonic-gate 	/*
19390Sstevel@tonic-gate 	 * If we've cached ucontext-list information while we were stopped,
19400Sstevel@tonic-gate 	 * free it now.
19410Sstevel@tonic-gate 	 */
19420Sstevel@tonic-gate 	if (P->ucaddrs != NULL) {
19430Sstevel@tonic-gate 		free(P->ucaddrs);
19440Sstevel@tonic-gate 		P->ucaddrs = NULL;
19450Sstevel@tonic-gate 		P->ucnelems = 0;
19460Sstevel@tonic-gate 	}
19470Sstevel@tonic-gate 
19480Sstevel@tonic-gate 	if (write(ctlfd, ctl, size) != size) {
19490Sstevel@tonic-gate 		/* If it is dead or lost, return the real status, not PS_RUN */
19500Sstevel@tonic-gate 		if (errno == ENOENT || errno == EAGAIN) {
19510Sstevel@tonic-gate 			(void) Pstopstatus(P, PCNULL, 0);
19520Sstevel@tonic-gate 			return (0);
19530Sstevel@tonic-gate 		}
19540Sstevel@tonic-gate 		/* If it is not in a jobcontrol stop, issue an error message */
19550Sstevel@tonic-gate 		if (errno != EBUSY ||
19560Sstevel@tonic-gate 		    P->status.pr_lwp.pr_why != PR_JOBCONTROL) {
19570Sstevel@tonic-gate 			dprintf("Psetrun: %s\n", strerror(errno));
19580Sstevel@tonic-gate 			return (-1);
19590Sstevel@tonic-gate 		}
19600Sstevel@tonic-gate 		/* Otherwise pretend that the job-stopped process is running */
19610Sstevel@tonic-gate 	}
19620Sstevel@tonic-gate 
19630Sstevel@tonic-gate 	P->state = PS_RUN;
19640Sstevel@tonic-gate 	return (0);
19650Sstevel@tonic-gate }
19660Sstevel@tonic-gate 
19670Sstevel@tonic-gate ssize_t
Pread(struct ps_prochandle * P,void * buf,size_t nbyte,uintptr_t address)19680Sstevel@tonic-gate Pread(struct ps_prochandle *P,
19690Sstevel@tonic-gate 	void *buf,		/* caller's buffer */
19700Sstevel@tonic-gate 	size_t nbyte,		/* number of bytes to read */
19710Sstevel@tonic-gate 	uintptr_t address)	/* address in process */
19720Sstevel@tonic-gate {
19730Sstevel@tonic-gate 	return (P->ops->p_pread(P, buf, nbyte, address));
19740Sstevel@tonic-gate }
19750Sstevel@tonic-gate 
19760Sstevel@tonic-gate ssize_t
Pread_string(struct ps_prochandle * P,char * buf,size_t size,uintptr_t addr)19770Sstevel@tonic-gate Pread_string(struct ps_prochandle *P,
19780Sstevel@tonic-gate 	char *buf, 		/* caller's buffer */
19790Sstevel@tonic-gate 	size_t size,		/* upper limit on bytes to read */
19800Sstevel@tonic-gate 	uintptr_t addr)		/* address in process */
19810Sstevel@tonic-gate {
19820Sstevel@tonic-gate 	enum { STRSZ = 40 };
19830Sstevel@tonic-gate 	char string[STRSZ + 1];
19840Sstevel@tonic-gate 	ssize_t leng = 0;
19850Sstevel@tonic-gate 	int nbyte;
19860Sstevel@tonic-gate 
19870Sstevel@tonic-gate 	if (size < 2) {
19880Sstevel@tonic-gate 		errno = EINVAL;
19890Sstevel@tonic-gate 		return (-1);
19900Sstevel@tonic-gate 	}
19910Sstevel@tonic-gate 
19920Sstevel@tonic-gate 	size--;			/* ensure trailing null fits in buffer */
19930Sstevel@tonic-gate 
19940Sstevel@tonic-gate 	*buf = '\0';
19950Sstevel@tonic-gate 	string[STRSZ] = '\0';
19960Sstevel@tonic-gate 
19970Sstevel@tonic-gate 	for (nbyte = STRSZ; nbyte == STRSZ && leng < size; addr += STRSZ) {
19980Sstevel@tonic-gate 		if ((nbyte = P->ops->p_pread(P, string, STRSZ, addr)) <= 0) {
19990Sstevel@tonic-gate 			buf[leng] = '\0';
20000Sstevel@tonic-gate 			return (leng ? leng : -1);
20010Sstevel@tonic-gate 		}
20020Sstevel@tonic-gate 		if ((nbyte = strlen(string)) > 0) {
20030Sstevel@tonic-gate 			if (leng + nbyte > size)
20040Sstevel@tonic-gate 				nbyte = size - leng;
20050Sstevel@tonic-gate 			(void) strncpy(buf + leng, string, nbyte);
20060Sstevel@tonic-gate 			leng += nbyte;
20070Sstevel@tonic-gate 		}
20080Sstevel@tonic-gate 	}
20090Sstevel@tonic-gate 	buf[leng] = '\0';
20100Sstevel@tonic-gate 	return (leng);
20110Sstevel@tonic-gate }
20120Sstevel@tonic-gate 
20130Sstevel@tonic-gate ssize_t
Pwrite(struct ps_prochandle * P,const void * buf,size_t nbyte,uintptr_t address)20140Sstevel@tonic-gate Pwrite(struct ps_prochandle *P,
20150Sstevel@tonic-gate 	const void *buf,	/* caller's buffer */
20160Sstevel@tonic-gate 	size_t nbyte,		/* number of bytes to write */
20170Sstevel@tonic-gate 	uintptr_t address)	/* address in process */
20180Sstevel@tonic-gate {
20190Sstevel@tonic-gate 	return (P->ops->p_pwrite(P, buf, nbyte, address));
20200Sstevel@tonic-gate }
20210Sstevel@tonic-gate 
20220Sstevel@tonic-gate int
Pclearsig(struct ps_prochandle * P)20230Sstevel@tonic-gate Pclearsig(struct ps_prochandle *P)
20240Sstevel@tonic-gate {
20250Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
20260Sstevel@tonic-gate 	long ctl = PCCSIG;
20270Sstevel@tonic-gate 
20280Sstevel@tonic-gate 	if (write(ctlfd, &ctl, sizeof (ctl)) != sizeof (ctl))
20290Sstevel@tonic-gate 		return (-1);
20300Sstevel@tonic-gate 	P->status.pr_lwp.pr_cursig = 0;
20310Sstevel@tonic-gate 	return (0);
20320Sstevel@tonic-gate }
20330Sstevel@tonic-gate 
20340Sstevel@tonic-gate int
Pclearfault(struct ps_prochandle * P)20350Sstevel@tonic-gate Pclearfault(struct ps_prochandle *P)
20360Sstevel@tonic-gate {
20370Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
20380Sstevel@tonic-gate 	long ctl = PCCFAULT;
20390Sstevel@tonic-gate 
20400Sstevel@tonic-gate 	if (write(ctlfd, &ctl, sizeof (ctl)) != sizeof (ctl))
20410Sstevel@tonic-gate 		return (-1);
20420Sstevel@tonic-gate 	return (0);
20430Sstevel@tonic-gate }
20440Sstevel@tonic-gate 
20450Sstevel@tonic-gate /*
20460Sstevel@tonic-gate  * Set a breakpoint trap, return original instruction.
20470Sstevel@tonic-gate  */
20480Sstevel@tonic-gate int
Psetbkpt(struct ps_prochandle * P,uintptr_t address,ulong_t * saved)20490Sstevel@tonic-gate Psetbkpt(struct ps_prochandle *P, uintptr_t address, ulong_t *saved)
20500Sstevel@tonic-gate {
20510Sstevel@tonic-gate 	long ctl[1 + sizeof (priovec_t) / sizeof (long) +	/* PCREAD */
20524753Srh87107 	    1 + sizeof (priovec_t) / sizeof (long)];	/* PCWRITE */
20530Sstevel@tonic-gate 	long *ctlp = ctl;
20540Sstevel@tonic-gate 	size_t size;
20550Sstevel@tonic-gate 	priovec_t *iovp;
20560Sstevel@tonic-gate 	instr_t bpt = BPT;
20570Sstevel@tonic-gate 	instr_t old;
20580Sstevel@tonic-gate 
20590Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
20600Sstevel@tonic-gate 	    P->state == PS_IDLE) {
20610Sstevel@tonic-gate 		errno = ENOENT;
20620Sstevel@tonic-gate 		return (-1);
20630Sstevel@tonic-gate 	}
20640Sstevel@tonic-gate 
20650Sstevel@tonic-gate 	/* fetch the old instruction */
20660Sstevel@tonic-gate 	*ctlp++ = PCREAD;
20670Sstevel@tonic-gate 	iovp = (priovec_t *)ctlp;
20680Sstevel@tonic-gate 	iovp->pio_base = &old;
20690Sstevel@tonic-gate 	iovp->pio_len = sizeof (old);
20700Sstevel@tonic-gate 	iovp->pio_offset = address;
20710Sstevel@tonic-gate 	ctlp += sizeof (priovec_t) / sizeof (long);
20720Sstevel@tonic-gate 
20730Sstevel@tonic-gate 	/* write the BPT instruction */
20740Sstevel@tonic-gate 	*ctlp++ = PCWRITE;
20750Sstevel@tonic-gate 	iovp = (priovec_t *)ctlp;
20760Sstevel@tonic-gate 	iovp->pio_base = &bpt;
20770Sstevel@tonic-gate 	iovp->pio_len = sizeof (bpt);
20780Sstevel@tonic-gate 	iovp->pio_offset = address;
20790Sstevel@tonic-gate 	ctlp += sizeof (priovec_t) / sizeof (long);
20800Sstevel@tonic-gate 
20810Sstevel@tonic-gate 	size = (char *)ctlp - (char *)ctl;
20820Sstevel@tonic-gate 	if (write(P->ctlfd, ctl, size) != size)
20830Sstevel@tonic-gate 		return (-1);
20840Sstevel@tonic-gate 
20850Sstevel@tonic-gate 	/*
20860Sstevel@tonic-gate 	 * Fail if there was already a breakpoint there from another debugger
20870Sstevel@tonic-gate 	 * or DTrace's user-level tracing on x86.
20880Sstevel@tonic-gate 	 */
20891222Smws 	if (old == BPT) {
20901222Smws 		errno = EBUSY;
20911222Smws 		return (-1);
20921222Smws 	}
20930Sstevel@tonic-gate 
20940Sstevel@tonic-gate 	*saved = (ulong_t)old;
20950Sstevel@tonic-gate 	return (0);
20960Sstevel@tonic-gate }
20970Sstevel@tonic-gate 
20980Sstevel@tonic-gate /*
20990Sstevel@tonic-gate  * Restore original instruction where a breakpoint was set.
21000Sstevel@tonic-gate  */
21010Sstevel@tonic-gate int
Pdelbkpt(struct ps_prochandle * P,uintptr_t address,ulong_t saved)21020Sstevel@tonic-gate Pdelbkpt(struct ps_prochandle *P, uintptr_t address, ulong_t saved)
21030Sstevel@tonic-gate {
21040Sstevel@tonic-gate 	instr_t old = (instr_t)saved;
21050Sstevel@tonic-gate 	instr_t cur;
21060Sstevel@tonic-gate 
21070Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
21080Sstevel@tonic-gate 	    P->state == PS_IDLE) {
21090Sstevel@tonic-gate 		errno = ENOENT;
21100Sstevel@tonic-gate 		return (-1);
21110Sstevel@tonic-gate 	}
21120Sstevel@tonic-gate 
21130Sstevel@tonic-gate 	/*
21140Sstevel@tonic-gate 	 * If the breakpoint instruction we had placed has been overwritten
21150Sstevel@tonic-gate 	 * with a new instruction, then don't try to replace it with the
21160Sstevel@tonic-gate 	 * old instruction. Doing do can cause problems with self-modifying
21170Sstevel@tonic-gate 	 * code -- PLTs for example. If the Pread() fails, we assume that we
21180Sstevel@tonic-gate 	 * should proceed though most likely the Pwrite() will also fail.
21190Sstevel@tonic-gate 	 */
21200Sstevel@tonic-gate 	if (Pread(P, &cur, sizeof (cur), address) == sizeof (cur) &&
21210Sstevel@tonic-gate 	    cur != BPT)
21220Sstevel@tonic-gate 		return (0);
21230Sstevel@tonic-gate 
21240Sstevel@tonic-gate 	if (Pwrite(P, &old, sizeof (old), address) != sizeof (old))
21250Sstevel@tonic-gate 		return (-1);
21260Sstevel@tonic-gate 
21270Sstevel@tonic-gate 	return (0);
21280Sstevel@tonic-gate }
21290Sstevel@tonic-gate 
21300Sstevel@tonic-gate /*
21310Sstevel@tonic-gate  * Common code for Pxecbkpt() and Lxecbkpt().
21320Sstevel@tonic-gate  * Develop the array of requests that will do the job, then
21330Sstevel@tonic-gate  * write them to the specified control file descriptor.
21340Sstevel@tonic-gate  * Return the non-zero errno if the write fails.
21350Sstevel@tonic-gate  */
21360Sstevel@tonic-gate static int
execute_bkpt(int ctlfd,const fltset_t * faultset,const sigset_t * sigmask,uintptr_t address,ulong_t saved)21370Sstevel@tonic-gate execute_bkpt(
21380Sstevel@tonic-gate 	int ctlfd,		/* process or LWP control file descriptor */
21390Sstevel@tonic-gate 	const fltset_t *faultset,	/* current set of traced faults */
21400Sstevel@tonic-gate 	const sigset_t *sigmask,	/* current signal mask */
21410Sstevel@tonic-gate 	uintptr_t address,		/* address of breakpint */
21420Sstevel@tonic-gate 	ulong_t saved)			/* the saved instruction */
21430Sstevel@tonic-gate {
21440Sstevel@tonic-gate 	long ctl[
21454753Srh87107 	    1 + sizeof (sigset_t) / sizeof (long) +		/* PCSHOLD */
21464753Srh87107 	    1 + sizeof (fltset_t) / sizeof (long) +		/* PCSFAULT */
21474753Srh87107 	    1 + sizeof (priovec_t) / sizeof (long) +		/* PCWRITE */
21484753Srh87107 	    2 +							/* PCRUN */
21494753Srh87107 	    1 +							/* PCWSTOP */
21504753Srh87107 	    1 +							/* PCCFAULT */
21514753Srh87107 	    1 + sizeof (priovec_t) / sizeof (long) +		/* PCWRITE */
21524753Srh87107 	    1 + sizeof (fltset_t) / sizeof (long) +		/* PCSFAULT */
21534753Srh87107 	    1 + sizeof (sigset_t) / sizeof (long)];		/* PCSHOLD */
21540Sstevel@tonic-gate 	long *ctlp = ctl;
21550Sstevel@tonic-gate 	sigset_t unblock;
21560Sstevel@tonic-gate 	size_t size;
21570Sstevel@tonic-gate 	ssize_t ssize;
21580Sstevel@tonic-gate 	priovec_t *iovp;
21590Sstevel@tonic-gate 	sigset_t *holdp;
21600Sstevel@tonic-gate 	fltset_t *faultp;
21610Sstevel@tonic-gate 	instr_t old = (instr_t)saved;
21620Sstevel@tonic-gate 	instr_t bpt = BPT;
21630Sstevel@tonic-gate 	int error = 0;
21640Sstevel@tonic-gate 
21650Sstevel@tonic-gate 	/* block our signals for the duration */
21660Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &blockable_sigs, &unblock);
21670Sstevel@tonic-gate 
21680Sstevel@tonic-gate 	/* hold posted signals */
21690Sstevel@tonic-gate 	*ctlp++ = PCSHOLD;
21700Sstevel@tonic-gate 	holdp = (sigset_t *)ctlp;
21710Sstevel@tonic-gate 	prfillset(holdp);
21720Sstevel@tonic-gate 	prdelset(holdp, SIGKILL);
21730Sstevel@tonic-gate 	prdelset(holdp, SIGSTOP);
21740Sstevel@tonic-gate 	ctlp += sizeof (sigset_t) / sizeof (long);
21750Sstevel@tonic-gate 
21760Sstevel@tonic-gate 	/* force tracing of FLTTRACE */
21770Sstevel@tonic-gate 	if (!(prismember(faultset, FLTTRACE))) {
21780Sstevel@tonic-gate 		*ctlp++ = PCSFAULT;
21790Sstevel@tonic-gate 		faultp = (fltset_t *)ctlp;
21800Sstevel@tonic-gate 		*faultp = *faultset;
21810Sstevel@tonic-gate 		praddset(faultp, FLTTRACE);
21820Sstevel@tonic-gate 		ctlp += sizeof (fltset_t) / sizeof (long);
21830Sstevel@tonic-gate 	}
21840Sstevel@tonic-gate 
21850Sstevel@tonic-gate 	/* restore the old instruction */
21860Sstevel@tonic-gate 	*ctlp++ = PCWRITE;
21870Sstevel@tonic-gate 	iovp = (priovec_t *)ctlp;
21880Sstevel@tonic-gate 	iovp->pio_base = &old;
21890Sstevel@tonic-gate 	iovp->pio_len = sizeof (old);
21900Sstevel@tonic-gate 	iovp->pio_offset = address;
21910Sstevel@tonic-gate 	ctlp += sizeof (priovec_t) / sizeof (long);
21920Sstevel@tonic-gate 
21930Sstevel@tonic-gate 	/* clear current signal and fault; set running w/ single-step */
21940Sstevel@tonic-gate 	*ctlp++ = PCRUN;
21950Sstevel@tonic-gate 	*ctlp++ = PRCSIG | PRCFAULT | PRSTEP;
21960Sstevel@tonic-gate 
21970Sstevel@tonic-gate 	/* wait for stop, cancel the fault */
21980Sstevel@tonic-gate 	*ctlp++ = PCWSTOP;
21990Sstevel@tonic-gate 	*ctlp++ = PCCFAULT;
22000Sstevel@tonic-gate 
22010Sstevel@tonic-gate 	/* restore the breakpoint trap */
22020Sstevel@tonic-gate 	*ctlp++ = PCWRITE;
22030Sstevel@tonic-gate 	iovp = (priovec_t *)ctlp;
22040Sstevel@tonic-gate 	iovp->pio_base = &bpt;
22050Sstevel@tonic-gate 	iovp->pio_len = sizeof (bpt);
22060Sstevel@tonic-gate 	iovp->pio_offset = address;
22070Sstevel@tonic-gate 	ctlp += sizeof (priovec_t) / sizeof (long);
22080Sstevel@tonic-gate 
22090Sstevel@tonic-gate 	/* restore fault tracing set */
22100Sstevel@tonic-gate 	if (!(prismember(faultset, FLTTRACE))) {
22110Sstevel@tonic-gate 		*ctlp++ = PCSFAULT;
22120Sstevel@tonic-gate 		*(fltset_t *)ctlp = *faultset;
22130Sstevel@tonic-gate 		ctlp += sizeof (fltset_t) / sizeof (long);
22140Sstevel@tonic-gate 	}
22150Sstevel@tonic-gate 
22160Sstevel@tonic-gate 	/* restore the hold mask */
22170Sstevel@tonic-gate 	*ctlp++ = PCSHOLD;
22180Sstevel@tonic-gate 	*(sigset_t *)ctlp = *sigmask;
22190Sstevel@tonic-gate 	ctlp += sizeof (sigset_t) / sizeof (long);
22200Sstevel@tonic-gate 
22210Sstevel@tonic-gate 	size = (char *)ctlp - (char *)ctl;
22220Sstevel@tonic-gate 	if ((ssize = write(ctlfd, ctl, size)) != size)
22230Sstevel@tonic-gate 		error = (ssize == -1)? errno : EINTR;
22240Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &unblock, NULL);
22250Sstevel@tonic-gate 	return (error);
22260Sstevel@tonic-gate }
22270Sstevel@tonic-gate 
22280Sstevel@tonic-gate /*
22290Sstevel@tonic-gate  * Step over a breakpoint, i.e., execute the instruction that
22300Sstevel@tonic-gate  * really belongs at the breakpoint location (the current %pc)
22310Sstevel@tonic-gate  * and leave the process stopped at the next instruction.
22320Sstevel@tonic-gate  */
22330Sstevel@tonic-gate int
Pxecbkpt(struct ps_prochandle * P,ulong_t saved)22340Sstevel@tonic-gate Pxecbkpt(struct ps_prochandle *P, ulong_t saved)
22350Sstevel@tonic-gate {
22360Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
22370Sstevel@tonic-gate 	int rv, error;
22380Sstevel@tonic-gate 
22390Sstevel@tonic-gate 	if (P->state != PS_STOP) {
22400Sstevel@tonic-gate 		errno = EBUSY;
22410Sstevel@tonic-gate 		return (-1);
22420Sstevel@tonic-gate 	}
22430Sstevel@tonic-gate 
22440Sstevel@tonic-gate 	Psync(P);
22450Sstevel@tonic-gate 
22460Sstevel@tonic-gate 	error = execute_bkpt(ctlfd,
22474753Srh87107 	    &P->status.pr_flttrace, &P->status.pr_lwp.pr_lwphold,
22484753Srh87107 	    P->status.pr_lwp.pr_reg[R_PC], saved);
22490Sstevel@tonic-gate 	rv = Pstopstatus(P, PCNULL, 0);
22500Sstevel@tonic-gate 
22510Sstevel@tonic-gate 	if (error != 0) {
22520Sstevel@tonic-gate 		if (P->status.pr_lwp.pr_why == PR_JOBCONTROL &&
22530Sstevel@tonic-gate 		    error == EBUSY) {	/* jobcontrol stop -- back off */
22540Sstevel@tonic-gate 			P->state = PS_RUN;
22550Sstevel@tonic-gate 			return (0);
22560Sstevel@tonic-gate 		}
22570Sstevel@tonic-gate 		if (error == ENOENT)
22580Sstevel@tonic-gate 			return (0);
22590Sstevel@tonic-gate 		errno = error;
22600Sstevel@tonic-gate 		return (-1);
22610Sstevel@tonic-gate 	}
22620Sstevel@tonic-gate 
22630Sstevel@tonic-gate 	return (rv);
22640Sstevel@tonic-gate }
22650Sstevel@tonic-gate 
22660Sstevel@tonic-gate /*
22670Sstevel@tonic-gate  * Install the watchpoint described by wp.
22680Sstevel@tonic-gate  */
22690Sstevel@tonic-gate int
Psetwapt(struct ps_prochandle * P,const prwatch_t * wp)22700Sstevel@tonic-gate Psetwapt(struct ps_prochandle *P, const prwatch_t *wp)
22710Sstevel@tonic-gate {
22720Sstevel@tonic-gate 	long ctl[1 + sizeof (prwatch_t) / sizeof (long)];
22730Sstevel@tonic-gate 	prwatch_t *cwp = (prwatch_t *)&ctl[1];
22740Sstevel@tonic-gate 
22750Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
22760Sstevel@tonic-gate 	    P->state == PS_IDLE) {
22770Sstevel@tonic-gate 		errno = ENOENT;
22780Sstevel@tonic-gate 		return (-1);
22790Sstevel@tonic-gate 	}
22800Sstevel@tonic-gate 
22810Sstevel@tonic-gate 	ctl[0] = PCWATCH;
22820Sstevel@tonic-gate 	cwp->pr_vaddr = wp->pr_vaddr;
22830Sstevel@tonic-gate 	cwp->pr_size = wp->pr_size;
22840Sstevel@tonic-gate 	cwp->pr_wflags = wp->pr_wflags;
22850Sstevel@tonic-gate 
22860Sstevel@tonic-gate 	if (write(P->ctlfd, ctl, sizeof (ctl)) != sizeof (ctl))
22870Sstevel@tonic-gate 		return (-1);
22880Sstevel@tonic-gate 
22890Sstevel@tonic-gate 	return (0);
22900Sstevel@tonic-gate }
22910Sstevel@tonic-gate 
22920Sstevel@tonic-gate /*
22930Sstevel@tonic-gate  * Remove the watchpoint described by wp.
22940Sstevel@tonic-gate  */
22950Sstevel@tonic-gate int
Pdelwapt(struct ps_prochandle * P,const prwatch_t * wp)22960Sstevel@tonic-gate Pdelwapt(struct ps_prochandle *P, const prwatch_t *wp)
22970Sstevel@tonic-gate {
22980Sstevel@tonic-gate 	long ctl[1 + sizeof (prwatch_t) / sizeof (long)];
22990Sstevel@tonic-gate 	prwatch_t *cwp = (prwatch_t *)&ctl[1];
23000Sstevel@tonic-gate 
23010Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
23020Sstevel@tonic-gate 	    P->state == PS_IDLE) {
23030Sstevel@tonic-gate 		errno = ENOENT;
23040Sstevel@tonic-gate 		return (-1);
23050Sstevel@tonic-gate 	}
23060Sstevel@tonic-gate 
23070Sstevel@tonic-gate 	ctl[0] = PCWATCH;
23080Sstevel@tonic-gate 	cwp->pr_vaddr = wp->pr_vaddr;
23090Sstevel@tonic-gate 	cwp->pr_size = wp->pr_size;
23100Sstevel@tonic-gate 	cwp->pr_wflags = 0;
23110Sstevel@tonic-gate 
23120Sstevel@tonic-gate 	if (write(P->ctlfd, ctl, sizeof (ctl)) != sizeof (ctl))
23130Sstevel@tonic-gate 		return (-1);
23140Sstevel@tonic-gate 
23150Sstevel@tonic-gate 	return (0);
23160Sstevel@tonic-gate }
23170Sstevel@tonic-gate 
23180Sstevel@tonic-gate /*
23190Sstevel@tonic-gate  * Common code for Pxecwapt() and Lxecwapt().  Develop the array of requests
23200Sstevel@tonic-gate  * that will do the job, then write them to the specified control file
23210Sstevel@tonic-gate  * descriptor.  Return the non-zero errno if the write fails.
23220Sstevel@tonic-gate  */
23230Sstevel@tonic-gate static int
execute_wapt(int ctlfd,const fltset_t * faultset,const sigset_t * sigmask,const prwatch_t * wp)23240Sstevel@tonic-gate execute_wapt(
23250Sstevel@tonic-gate 	int ctlfd,		/* process or LWP control file descriptor */
23260Sstevel@tonic-gate 	const fltset_t *faultset,	/* current set of traced faults */
23270Sstevel@tonic-gate 	const sigset_t *sigmask,	/* current signal mask */
23280Sstevel@tonic-gate 	const prwatch_t *wp)		/* watchpoint descriptor */
23290Sstevel@tonic-gate {
23300Sstevel@tonic-gate 	long ctl[
23310Sstevel@tonic-gate 	    1 + sizeof (sigset_t) / sizeof (long) +		/* PCSHOLD */
23320Sstevel@tonic-gate 	    1 + sizeof (fltset_t) / sizeof (long) +		/* PCSFAULT */
23330Sstevel@tonic-gate 	    1 + sizeof (prwatch_t) / sizeof (long) +		/* PCWATCH */
23340Sstevel@tonic-gate 	    2 +							/* PCRUN */
23350Sstevel@tonic-gate 	    1 +							/* PCWSTOP */
23360Sstevel@tonic-gate 	    1 +							/* PCCFAULT */
23370Sstevel@tonic-gate 	    1 + sizeof (prwatch_t) / sizeof (long) +		/* PCWATCH */
23380Sstevel@tonic-gate 	    1 + sizeof (fltset_t) / sizeof (long) +		/* PCSFAULT */
23390Sstevel@tonic-gate 	    1 + sizeof (sigset_t) / sizeof (long)];		/* PCSHOLD */
23400Sstevel@tonic-gate 
23410Sstevel@tonic-gate 	long *ctlp = ctl;
23420Sstevel@tonic-gate 	int error = 0;
23430Sstevel@tonic-gate 
23440Sstevel@tonic-gate 	sigset_t unblock;
23450Sstevel@tonic-gate 	sigset_t *holdp;
23460Sstevel@tonic-gate 	fltset_t *faultp;
23470Sstevel@tonic-gate 	prwatch_t *prw;
23480Sstevel@tonic-gate 	ssize_t ssize;
23490Sstevel@tonic-gate 	size_t size;
23500Sstevel@tonic-gate 
23510Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &blockable_sigs, &unblock);
23520Sstevel@tonic-gate 
23530Sstevel@tonic-gate 	/*
23540Sstevel@tonic-gate 	 * Hold all posted signals in the victim process prior to stepping.
23550Sstevel@tonic-gate 	 */
23560Sstevel@tonic-gate 	*ctlp++ = PCSHOLD;
23570Sstevel@tonic-gate 	holdp = (sigset_t *)ctlp;
23580Sstevel@tonic-gate 	prfillset(holdp);
23590Sstevel@tonic-gate 	prdelset(holdp, SIGKILL);
23600Sstevel@tonic-gate 	prdelset(holdp, SIGSTOP);
23610Sstevel@tonic-gate 	ctlp += sizeof (sigset_t) / sizeof (long);
23620Sstevel@tonic-gate 
23630Sstevel@tonic-gate 	/*
23640Sstevel@tonic-gate 	 * Force tracing of FLTTRACE since we need to single step.
23650Sstevel@tonic-gate 	 */
23660Sstevel@tonic-gate 	if (!(prismember(faultset, FLTTRACE))) {
23670Sstevel@tonic-gate 		*ctlp++ = PCSFAULT;
23680Sstevel@tonic-gate 		faultp = (fltset_t *)ctlp;
23690Sstevel@tonic-gate 		*faultp = *faultset;
23700Sstevel@tonic-gate 		praddset(faultp, FLTTRACE);
23710Sstevel@tonic-gate 		ctlp += sizeof (fltset_t) / sizeof (long);
23720Sstevel@tonic-gate 	}
23730Sstevel@tonic-gate 
23740Sstevel@tonic-gate 	/*
23750Sstevel@tonic-gate 	 * Clear only the current watchpoint by setting pr_wflags to zero.
23760Sstevel@tonic-gate 	 */
23770Sstevel@tonic-gate 	*ctlp++ = PCWATCH;
23780Sstevel@tonic-gate 	prw = (prwatch_t *)ctlp;
23790Sstevel@tonic-gate 	prw->pr_vaddr = wp->pr_vaddr;
23800Sstevel@tonic-gate 	prw->pr_size = wp->pr_size;
23810Sstevel@tonic-gate 	prw->pr_wflags = 0;
23820Sstevel@tonic-gate 	ctlp += sizeof (prwatch_t) / sizeof (long);
23830Sstevel@tonic-gate 
23840Sstevel@tonic-gate 	/*
23850Sstevel@tonic-gate 	 * Clear the current signal and fault; set running with single-step.
23860Sstevel@tonic-gate 	 * Then wait for the victim to stop and cancel the FLTTRACE.
23870Sstevel@tonic-gate 	 */
23880Sstevel@tonic-gate 	*ctlp++ = PCRUN;
23890Sstevel@tonic-gate 	*ctlp++ = PRCSIG | PRCFAULT | PRSTEP;
23900Sstevel@tonic-gate 	*ctlp++ = PCWSTOP;
23910Sstevel@tonic-gate 	*ctlp++ = PCCFAULT;
23920Sstevel@tonic-gate 
23930Sstevel@tonic-gate 	/*
23940Sstevel@tonic-gate 	 * Restore the current watchpoint.
23950Sstevel@tonic-gate 	 */
23960Sstevel@tonic-gate 	*ctlp++ = PCWATCH;
23970Sstevel@tonic-gate 	(void) memcpy(ctlp, wp, sizeof (prwatch_t));
23980Sstevel@tonic-gate 	ctlp += sizeof (prwatch_t) / sizeof (long);
23990Sstevel@tonic-gate 
24000Sstevel@tonic-gate 	/*
24010Sstevel@tonic-gate 	 * Restore fault tracing set if we modified it.
24020Sstevel@tonic-gate 	 */
24030Sstevel@tonic-gate 	if (!(prismember(faultset, FLTTRACE))) {
24040Sstevel@tonic-gate 		*ctlp++ = PCSFAULT;
24050Sstevel@tonic-gate 		*(fltset_t *)ctlp = *faultset;
24060Sstevel@tonic-gate 		ctlp += sizeof (fltset_t) / sizeof (long);
24070Sstevel@tonic-gate 	}
24080Sstevel@tonic-gate 
24090Sstevel@tonic-gate 	/*
24100Sstevel@tonic-gate 	 * Restore the hold mask to the current hold mask (i.e. the one
24110Sstevel@tonic-gate 	 * before we executed any of the previous operations).
24120Sstevel@tonic-gate 	 */
24130Sstevel@tonic-gate 	*ctlp++ = PCSHOLD;
24140Sstevel@tonic-gate 	*(sigset_t *)ctlp = *sigmask;
24150Sstevel@tonic-gate 	ctlp += sizeof (sigset_t) / sizeof (long);
24160Sstevel@tonic-gate 
24170Sstevel@tonic-gate 	size = (char *)ctlp - (char *)ctl;
24180Sstevel@tonic-gate 	if ((ssize = write(ctlfd, ctl, size)) != size)
24190Sstevel@tonic-gate 		error = (ssize == -1)? errno : EINTR;
24200Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &unblock, NULL);
24210Sstevel@tonic-gate 	return (error);
24220Sstevel@tonic-gate }
24230Sstevel@tonic-gate 
24240Sstevel@tonic-gate /*
24250Sstevel@tonic-gate  * Step over a watchpoint, i.e., execute the instruction that was stopped by
24260Sstevel@tonic-gate  * the watchpoint, and then leave the LWP stopped at the next instruction.
24270Sstevel@tonic-gate  */
24280Sstevel@tonic-gate int
Pxecwapt(struct ps_prochandle * P,const prwatch_t * wp)24290Sstevel@tonic-gate Pxecwapt(struct ps_prochandle *P, const prwatch_t *wp)
24300Sstevel@tonic-gate {
24310Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
24320Sstevel@tonic-gate 	int rv, error;
24330Sstevel@tonic-gate 
24340Sstevel@tonic-gate 	if (P->state != PS_STOP) {
24350Sstevel@tonic-gate 		errno = EBUSY;
24360Sstevel@tonic-gate 		return (-1);
24370Sstevel@tonic-gate 	}
24380Sstevel@tonic-gate 
24390Sstevel@tonic-gate 	Psync(P);
24400Sstevel@tonic-gate 	error = execute_wapt(ctlfd,
24414753Srh87107 	    &P->status.pr_flttrace, &P->status.pr_lwp.pr_lwphold, wp);
24420Sstevel@tonic-gate 	rv = Pstopstatus(P, PCNULL, 0);
24430Sstevel@tonic-gate 
24440Sstevel@tonic-gate 	if (error != 0) {
24450Sstevel@tonic-gate 		if (P->status.pr_lwp.pr_why == PR_JOBCONTROL &&
24460Sstevel@tonic-gate 		    error == EBUSY) {	/* jobcontrol stop -- back off */
24470Sstevel@tonic-gate 			P->state = PS_RUN;
24480Sstevel@tonic-gate 			return (0);
24490Sstevel@tonic-gate 		}
24500Sstevel@tonic-gate 		if (error == ENOENT)
24510Sstevel@tonic-gate 			return (0);
24520Sstevel@tonic-gate 		errno = error;
24530Sstevel@tonic-gate 		return (-1);
24540Sstevel@tonic-gate 	}
24550Sstevel@tonic-gate 
24560Sstevel@tonic-gate 	return (rv);
24570Sstevel@tonic-gate }
24580Sstevel@tonic-gate 
24590Sstevel@tonic-gate int
Psetflags(struct ps_prochandle * P,long flags)24600Sstevel@tonic-gate Psetflags(struct ps_prochandle *P, long flags)
24610Sstevel@tonic-gate {
24620Sstevel@tonic-gate 	int rc;
24630Sstevel@tonic-gate 	long ctl[2];
24640Sstevel@tonic-gate 
24650Sstevel@tonic-gate 	ctl[0] = PCSET;
24660Sstevel@tonic-gate 	ctl[1] = flags;
24670Sstevel@tonic-gate 
24680Sstevel@tonic-gate 	if (write(P->ctlfd, ctl, 2*sizeof (long)) != 2*sizeof (long)) {
24690Sstevel@tonic-gate 		rc = -1;
24700Sstevel@tonic-gate 	} else {
24710Sstevel@tonic-gate 		P->status.pr_flags |= flags;
24720Sstevel@tonic-gate 		P->status.pr_lwp.pr_flags |= flags;
24730Sstevel@tonic-gate 		rc = 0;
24740Sstevel@tonic-gate 	}
24750Sstevel@tonic-gate 
24760Sstevel@tonic-gate 	return (rc);
24770Sstevel@tonic-gate }
24780Sstevel@tonic-gate 
24790Sstevel@tonic-gate int
Punsetflags(struct ps_prochandle * P,long flags)24800Sstevel@tonic-gate Punsetflags(struct ps_prochandle *P, long flags)
24810Sstevel@tonic-gate {
24820Sstevel@tonic-gate 	int rc;
24830Sstevel@tonic-gate 	long ctl[2];
24840Sstevel@tonic-gate 
24850Sstevel@tonic-gate 	ctl[0] = PCUNSET;
24860Sstevel@tonic-gate 	ctl[1] = flags;
24870Sstevel@tonic-gate 
24880Sstevel@tonic-gate 	if (write(P->ctlfd, ctl, 2*sizeof (long)) != 2*sizeof (long)) {
24890Sstevel@tonic-gate 		rc = -1;
24900Sstevel@tonic-gate 	} else {
24910Sstevel@tonic-gate 		P->status.pr_flags &= ~flags;
24920Sstevel@tonic-gate 		P->status.pr_lwp.pr_flags &= ~flags;
24930Sstevel@tonic-gate 		rc = 0;
24940Sstevel@tonic-gate 	}
24950Sstevel@tonic-gate 
24960Sstevel@tonic-gate 	return (rc);
24970Sstevel@tonic-gate }
24980Sstevel@tonic-gate 
24990Sstevel@tonic-gate /*
25000Sstevel@tonic-gate  * Common function to allow clients to manipulate the action to be taken
25010Sstevel@tonic-gate  * on receipt of a signal, receipt of machine fault, entry to a system call,
25020Sstevel@tonic-gate  * or exit from a system call.  We make use of our private prset_* functions
25030Sstevel@tonic-gate  * in order to make this code be common.  The 'which' parameter identifies
25040Sstevel@tonic-gate  * the code for the event of interest (0 means change the entire set), and
25050Sstevel@tonic-gate  * the 'stop' parameter is a boolean indicating whether the process should
25060Sstevel@tonic-gate  * stop when the event of interest occurs.  The previous value is returned
25070Sstevel@tonic-gate  * to the caller; -1 is returned if an error occurred.
25080Sstevel@tonic-gate  */
25090Sstevel@tonic-gate static int
Psetaction(struct ps_prochandle * P,void * sp,size_t size,uint_t flag,int max,int which,int stop)25100Sstevel@tonic-gate Psetaction(struct ps_prochandle *P, void *sp, size_t size,
25110Sstevel@tonic-gate     uint_t flag, int max, int which, int stop)
25120Sstevel@tonic-gate {
25130Sstevel@tonic-gate 	int oldval;
25140Sstevel@tonic-gate 
25150Sstevel@tonic-gate 	if (which < 0 || which > max) {
25160Sstevel@tonic-gate 		errno = EINVAL;
25170Sstevel@tonic-gate 		return (-1);
25180Sstevel@tonic-gate 	}
25190Sstevel@tonic-gate 
25200Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
25210Sstevel@tonic-gate 	    P->state == PS_IDLE) {
25220Sstevel@tonic-gate 		errno = ENOENT;
25230Sstevel@tonic-gate 		return (-1);
25240Sstevel@tonic-gate 	}
25250Sstevel@tonic-gate 
25260Sstevel@tonic-gate 	oldval = prset_ismember(sp, size, which) ? TRUE : FALSE;
25270Sstevel@tonic-gate 
25280Sstevel@tonic-gate 	if (stop) {
25290Sstevel@tonic-gate 		if (which == 0) {
25300Sstevel@tonic-gate 			prset_fill(sp, size);
25310Sstevel@tonic-gate 			P->flags |= flag;
25320Sstevel@tonic-gate 		} else if (!oldval) {
25330Sstevel@tonic-gate 			prset_add(sp, size, which);
25340Sstevel@tonic-gate 			P->flags |= flag;
25350Sstevel@tonic-gate 		}
25360Sstevel@tonic-gate 	} else {
25370Sstevel@tonic-gate 		if (which == 0) {
25380Sstevel@tonic-gate 			prset_empty(sp, size);
25390Sstevel@tonic-gate 			P->flags |= flag;
25400Sstevel@tonic-gate 		} else if (oldval) {
25410Sstevel@tonic-gate 			prset_del(sp, size, which);
25420Sstevel@tonic-gate 			P->flags |= flag;
25430Sstevel@tonic-gate 		}
25440Sstevel@tonic-gate 	}
25450Sstevel@tonic-gate 
25460Sstevel@tonic-gate 	if (P->state == PS_RUN)
25470Sstevel@tonic-gate 		Psync(P);
25480Sstevel@tonic-gate 
25490Sstevel@tonic-gate 	return (oldval);
25500Sstevel@tonic-gate }
25510Sstevel@tonic-gate 
25520Sstevel@tonic-gate /*
25530Sstevel@tonic-gate  * Set action on specified signal.
25540Sstevel@tonic-gate  */
25550Sstevel@tonic-gate int
Psignal(struct ps_prochandle * P,int which,int stop)25560Sstevel@tonic-gate Psignal(struct ps_prochandle *P, int which, int stop)
25570Sstevel@tonic-gate {
25580Sstevel@tonic-gate 	int oldval;
25590Sstevel@tonic-gate 
25600Sstevel@tonic-gate 	if (which == SIGKILL && stop != 0) {
25610Sstevel@tonic-gate 		errno = EINVAL;
25620Sstevel@tonic-gate 		return (-1);
25630Sstevel@tonic-gate 	}
25640Sstevel@tonic-gate 
25650Sstevel@tonic-gate 	oldval = Psetaction(P, &P->status.pr_sigtrace, sizeof (sigset_t),
25660Sstevel@tonic-gate 	    SETSIG, PRMAXSIG, which, stop);
25670Sstevel@tonic-gate 
25680Sstevel@tonic-gate 	if (oldval != -1 && which == 0 && stop != 0)
25690Sstevel@tonic-gate 		prdelset(&P->status.pr_sigtrace, SIGKILL);
25700Sstevel@tonic-gate 
25710Sstevel@tonic-gate 	return (oldval);
25720Sstevel@tonic-gate }
25730Sstevel@tonic-gate 
25740Sstevel@tonic-gate /*
25750Sstevel@tonic-gate  * Set all signal tracing flags.
25760Sstevel@tonic-gate  */
25770Sstevel@tonic-gate void
Psetsignal(struct ps_prochandle * P,const sigset_t * set)25780Sstevel@tonic-gate Psetsignal(struct ps_prochandle *P, const sigset_t *set)
25790Sstevel@tonic-gate {
25800Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
25810Sstevel@tonic-gate 	    P->state == PS_IDLE)
25820Sstevel@tonic-gate 		return;
25830Sstevel@tonic-gate 
25840Sstevel@tonic-gate 	P->status.pr_sigtrace = *set;
25850Sstevel@tonic-gate 	P->flags |= SETSIG;
25860Sstevel@tonic-gate 
25870Sstevel@tonic-gate 	if (P->state == PS_RUN)
25880Sstevel@tonic-gate 		Psync(P);
25890Sstevel@tonic-gate }
25900Sstevel@tonic-gate 
25910Sstevel@tonic-gate /*
25920Sstevel@tonic-gate  * Set action on specified fault.
25930Sstevel@tonic-gate  */
25940Sstevel@tonic-gate int
Pfault(struct ps_prochandle * P,int which,int stop)25950Sstevel@tonic-gate Pfault(struct ps_prochandle *P, int which, int stop)
25960Sstevel@tonic-gate {
25970Sstevel@tonic-gate 	return (Psetaction(P, &P->status.pr_flttrace, sizeof (fltset_t),
25980Sstevel@tonic-gate 	    SETFAULT, PRMAXFAULT, which, stop));
25990Sstevel@tonic-gate }
26000Sstevel@tonic-gate 
26010Sstevel@tonic-gate /*
26020Sstevel@tonic-gate  * Set all machine fault tracing flags.
26030Sstevel@tonic-gate  */
26040Sstevel@tonic-gate void
Psetfault(struct ps_prochandle * P,const fltset_t * set)26050Sstevel@tonic-gate Psetfault(struct ps_prochandle *P, const fltset_t *set)
26060Sstevel@tonic-gate {
26070Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
26080Sstevel@tonic-gate 	    P->state == PS_IDLE)
26090Sstevel@tonic-gate 		return;
26100Sstevel@tonic-gate 
26110Sstevel@tonic-gate 	P->status.pr_flttrace = *set;
26120Sstevel@tonic-gate 	P->flags |= SETFAULT;
26130Sstevel@tonic-gate 
26140Sstevel@tonic-gate 	if (P->state == PS_RUN)
26150Sstevel@tonic-gate 		Psync(P);
26160Sstevel@tonic-gate }
26170Sstevel@tonic-gate 
26180Sstevel@tonic-gate /*
26190Sstevel@tonic-gate  * Set action on specified system call entry.
26200Sstevel@tonic-gate  */
26210Sstevel@tonic-gate int
Psysentry(struct ps_prochandle * P,int which,int stop)26220Sstevel@tonic-gate Psysentry(struct ps_prochandle *P, int which, int stop)
26230Sstevel@tonic-gate {
26240Sstevel@tonic-gate 	return (Psetaction(P, &P->status.pr_sysentry, sizeof (sysset_t),
26250Sstevel@tonic-gate 	    SETENTRY, PRMAXSYS, which, stop));
26260Sstevel@tonic-gate }
26270Sstevel@tonic-gate 
26280Sstevel@tonic-gate /*
26290Sstevel@tonic-gate  * Set all system call entry tracing flags.
26300Sstevel@tonic-gate  */
26310Sstevel@tonic-gate void
Psetsysentry(struct ps_prochandle * P,const sysset_t * set)26320Sstevel@tonic-gate Psetsysentry(struct ps_prochandle *P, const sysset_t *set)
26330Sstevel@tonic-gate {
26340Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
26350Sstevel@tonic-gate 	    P->state == PS_IDLE)
26360Sstevel@tonic-gate 		return;
26370Sstevel@tonic-gate 
26380Sstevel@tonic-gate 	P->status.pr_sysentry = *set;
26390Sstevel@tonic-gate 	P->flags |= SETENTRY;
26400Sstevel@tonic-gate 
26410Sstevel@tonic-gate 	if (P->state == PS_RUN)
26420Sstevel@tonic-gate 		Psync(P);
26430Sstevel@tonic-gate }
26440Sstevel@tonic-gate 
26450Sstevel@tonic-gate /*
26460Sstevel@tonic-gate  * Set action on specified system call exit.
26470Sstevel@tonic-gate  */
26480Sstevel@tonic-gate int
Psysexit(struct ps_prochandle * P,int which,int stop)26490Sstevel@tonic-gate Psysexit(struct ps_prochandle *P, int which, int stop)
26500Sstevel@tonic-gate {
26510Sstevel@tonic-gate 	return (Psetaction(P, &P->status.pr_sysexit, sizeof (sysset_t),
26520Sstevel@tonic-gate 	    SETEXIT, PRMAXSYS, which, stop));
26530Sstevel@tonic-gate }
26540Sstevel@tonic-gate 
26550Sstevel@tonic-gate /*
26560Sstevel@tonic-gate  * Set all system call exit tracing flags.
26570Sstevel@tonic-gate  */
26580Sstevel@tonic-gate void
Psetsysexit(struct ps_prochandle * P,const sysset_t * set)26590Sstevel@tonic-gate Psetsysexit(struct ps_prochandle *P, const sysset_t *set)
26600Sstevel@tonic-gate {
26610Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
26620Sstevel@tonic-gate 	    P->state == PS_IDLE)
26630Sstevel@tonic-gate 		return;
26640Sstevel@tonic-gate 
26650Sstevel@tonic-gate 	P->status.pr_sysexit = *set;
26660Sstevel@tonic-gate 	P->flags |= SETEXIT;
26670Sstevel@tonic-gate 
26680Sstevel@tonic-gate 	if (P->state == PS_RUN)
26690Sstevel@tonic-gate 		Psync(P);
26700Sstevel@tonic-gate }
26710Sstevel@tonic-gate 
26720Sstevel@tonic-gate /*
26730Sstevel@tonic-gate  * Utility function to read the contents of a file that contains a
26740Sstevel@tonic-gate  * prheader_t at the start (/proc/pid/lstatus or /proc/pid/lpsinfo).
26750Sstevel@tonic-gate  * Returns a malloc()d buffer or NULL on failure.
26760Sstevel@tonic-gate  */
26770Sstevel@tonic-gate static prheader_t *
read_lfile(struct ps_prochandle * P,const char * lname)26780Sstevel@tonic-gate read_lfile(struct ps_prochandle *P, const char *lname)
26790Sstevel@tonic-gate {
26800Sstevel@tonic-gate 	prheader_t *Lhp;
26812712Snn35248 	char lpath[PATH_MAX];
26820Sstevel@tonic-gate 	struct stat64 statb;
26830Sstevel@tonic-gate 	int fd;
26840Sstevel@tonic-gate 	size_t size;
26850Sstevel@tonic-gate 	ssize_t rval;
26860Sstevel@tonic-gate 
26872712Snn35248 	(void) snprintf(lpath, sizeof (lpath), "%s/%d/%s", procfs_path,
26880Sstevel@tonic-gate 	    (int)P->status.pr_pid, lname);
26890Sstevel@tonic-gate 	if ((fd = open(lpath, O_RDONLY)) < 0 || fstat64(fd, &statb) != 0) {
26900Sstevel@tonic-gate 		if (fd >= 0)
26910Sstevel@tonic-gate 			(void) close(fd);
26920Sstevel@tonic-gate 		return (NULL);
26930Sstevel@tonic-gate 	}
26940Sstevel@tonic-gate 
26950Sstevel@tonic-gate 	/*
26960Sstevel@tonic-gate 	 * 'size' is just the initial guess at the buffer size.
26970Sstevel@tonic-gate 	 * It will have to grow if the number of lwps increases
26980Sstevel@tonic-gate 	 * while we are looking at the process.
26990Sstevel@tonic-gate 	 * 'size' must be larger than the actual file size.
27000Sstevel@tonic-gate 	 */
27010Sstevel@tonic-gate 	size = statb.st_size + 32;
27020Sstevel@tonic-gate 
27030Sstevel@tonic-gate 	for (;;) {
27040Sstevel@tonic-gate 		if ((Lhp = malloc(size)) == NULL)
27050Sstevel@tonic-gate 			break;
27060Sstevel@tonic-gate 		if ((rval = pread(fd, Lhp, size, 0)) < 0 ||
27070Sstevel@tonic-gate 		    rval <= sizeof (prheader_t)) {
27080Sstevel@tonic-gate 			free(Lhp);
27090Sstevel@tonic-gate 			Lhp = NULL;
27100Sstevel@tonic-gate 			break;
27110Sstevel@tonic-gate 		}
27120Sstevel@tonic-gate 		if (rval < size)
27130Sstevel@tonic-gate 			break;
27140Sstevel@tonic-gate 		/* need a bigger buffer */
27150Sstevel@tonic-gate 		free(Lhp);
27160Sstevel@tonic-gate 		size *= 2;
27170Sstevel@tonic-gate 	}
27180Sstevel@tonic-gate 
27190Sstevel@tonic-gate 	(void) close(fd);
27200Sstevel@tonic-gate 	return (Lhp);
27210Sstevel@tonic-gate }
27220Sstevel@tonic-gate 
27230Sstevel@tonic-gate /*
27240Sstevel@tonic-gate  * LWP iteration interface.
27250Sstevel@tonic-gate  */
27260Sstevel@tonic-gate int
Plwp_iter(struct ps_prochandle * P,proc_lwp_f * func,void * cd)27270Sstevel@tonic-gate Plwp_iter(struct ps_prochandle *P, proc_lwp_f *func, void *cd)
27280Sstevel@tonic-gate {
27290Sstevel@tonic-gate 	prheader_t *Lhp;
27300Sstevel@tonic-gate 	lwpstatus_t *Lsp;
27310Sstevel@tonic-gate 	long nlwp;
27320Sstevel@tonic-gate 	int rv;
27330Sstevel@tonic-gate 
27340Sstevel@tonic-gate 	switch (P->state) {
27350Sstevel@tonic-gate 	case PS_RUN:
27360Sstevel@tonic-gate 		(void) Pstopstatus(P, PCNULL, 0);
27370Sstevel@tonic-gate 		break;
27380Sstevel@tonic-gate 
27390Sstevel@tonic-gate 	case PS_STOP:
27400Sstevel@tonic-gate 		Psync(P);
27410Sstevel@tonic-gate 		break;
27420Sstevel@tonic-gate 
27430Sstevel@tonic-gate 	case PS_IDLE:
27440Sstevel@tonic-gate 		errno = ENODATA;
27450Sstevel@tonic-gate 		return (-1);
27460Sstevel@tonic-gate 	}
27470Sstevel@tonic-gate 
27480Sstevel@tonic-gate 	/*
27490Sstevel@tonic-gate 	 * For either live processes or cores, the single LWP case is easy:
27500Sstevel@tonic-gate 	 * the pstatus_t contains the lwpstatus_t for the only LWP.
27510Sstevel@tonic-gate 	 */
27520Sstevel@tonic-gate 	if (P->status.pr_nlwp <= 1)
27530Sstevel@tonic-gate 		return (func(cd, &P->status.pr_lwp));
27540Sstevel@tonic-gate 
27550Sstevel@tonic-gate 	/*
27560Sstevel@tonic-gate 	 * For the core file multi-LWP case, we just iterate through the
27570Sstevel@tonic-gate 	 * list of LWP structs we read in from the core file.
27580Sstevel@tonic-gate 	 */
27590Sstevel@tonic-gate 	if (P->state == PS_DEAD) {
27600Sstevel@tonic-gate 		lwp_info_t *lwp = list_prev(&P->core->core_lwp_head);
27610Sstevel@tonic-gate 		uint_t i;
27620Sstevel@tonic-gate 
27630Sstevel@tonic-gate 		for (i = 0; i < P->core->core_nlwp; i++, lwp = list_prev(lwp)) {
27640Sstevel@tonic-gate 			if (lwp->lwp_psinfo.pr_sname != 'Z' &&
27650Sstevel@tonic-gate 			    (rv = func(cd, &lwp->lwp_status)) != 0)
27660Sstevel@tonic-gate 				break;
27670Sstevel@tonic-gate 		}
27680Sstevel@tonic-gate 
27690Sstevel@tonic-gate 		return (rv);
27700Sstevel@tonic-gate 	}
27710Sstevel@tonic-gate 
27720Sstevel@tonic-gate 	/*
27730Sstevel@tonic-gate 	 * For the live process multi-LWP case, we have to work a little
27740Sstevel@tonic-gate 	 * harder: the /proc/pid/lstatus file has the array of LWP structs.
27750Sstevel@tonic-gate 	 */
27760Sstevel@tonic-gate 	if ((Lhp = read_lfile(P, "lstatus")) == NULL)
27770Sstevel@tonic-gate 		return (-1);
27780Sstevel@tonic-gate 
27790Sstevel@tonic-gate 	for (nlwp = Lhp->pr_nent, Lsp = (lwpstatus_t *)(uintptr_t)(Lhp + 1);
27800Sstevel@tonic-gate 	    nlwp > 0;
27810Sstevel@tonic-gate 	    nlwp--, Lsp = (lwpstatus_t *)((uintptr_t)Lsp + Lhp->pr_entsize)) {
27820Sstevel@tonic-gate 		if ((rv = func(cd, Lsp)) != 0)
27830Sstevel@tonic-gate 			break;
27840Sstevel@tonic-gate 	}
27850Sstevel@tonic-gate 
27860Sstevel@tonic-gate 	free(Lhp);
27870Sstevel@tonic-gate 	return (rv);
27880Sstevel@tonic-gate }
27890Sstevel@tonic-gate 
27900Sstevel@tonic-gate /*
27910Sstevel@tonic-gate  * Extended LWP iteration interface.
27920Sstevel@tonic-gate  * Iterate over all LWPs, active and zombie.
27930Sstevel@tonic-gate  */
27940Sstevel@tonic-gate int
Plwp_iter_all(struct ps_prochandle * P,proc_lwp_all_f * func,void * cd)27950Sstevel@tonic-gate Plwp_iter_all(struct ps_prochandle *P, proc_lwp_all_f *func, void *cd)
27960Sstevel@tonic-gate {
27970Sstevel@tonic-gate 	prheader_t *Lhp = NULL;
27980Sstevel@tonic-gate 	lwpstatus_t *Lsp;
27990Sstevel@tonic-gate 	lwpstatus_t *sp;
28000Sstevel@tonic-gate 	prheader_t *Lphp = NULL;
28010Sstevel@tonic-gate 	lwpsinfo_t *Lpsp;
28020Sstevel@tonic-gate 	long nstat;
28030Sstevel@tonic-gate 	long ninfo;
28040Sstevel@tonic-gate 	int rv;
28050Sstevel@tonic-gate 
28060Sstevel@tonic-gate retry:
28070Sstevel@tonic-gate 	if (Lhp != NULL)
28080Sstevel@tonic-gate 		free(Lhp);
28090Sstevel@tonic-gate 	if (Lphp != NULL)
28100Sstevel@tonic-gate 		free(Lphp);
28110Sstevel@tonic-gate 	if (P->state == PS_RUN)
28120Sstevel@tonic-gate 		(void) Pstopstatus(P, PCNULL, 0);
28130Sstevel@tonic-gate 	(void) Ppsinfo(P);
28140Sstevel@tonic-gate 
28150Sstevel@tonic-gate 	if (P->state == PS_STOP)
28160Sstevel@tonic-gate 		Psync(P);
28170Sstevel@tonic-gate 
28180Sstevel@tonic-gate 	/*
28190Sstevel@tonic-gate 	 * For either live processes or cores, the single LWP case is easy:
28200Sstevel@tonic-gate 	 * the pstatus_t contains the lwpstatus_t for the only LWP and
28210Sstevel@tonic-gate 	 * the psinfo_t contains the lwpsinfo_t for the only LWP.
28220Sstevel@tonic-gate 	 */
28230Sstevel@tonic-gate 	if (P->status.pr_nlwp + P->status.pr_nzomb <= 1)
28240Sstevel@tonic-gate 		return (func(cd, &P->status.pr_lwp, &P->psinfo.pr_lwp));
28250Sstevel@tonic-gate 
28260Sstevel@tonic-gate 	/*
28270Sstevel@tonic-gate 	 * For the core file multi-LWP case, we just iterate through the
28280Sstevel@tonic-gate 	 * list of LWP structs we read in from the core file.
28290Sstevel@tonic-gate 	 */
28300Sstevel@tonic-gate 	if (P->state == PS_DEAD) {
28310Sstevel@tonic-gate 		lwp_info_t *lwp = list_prev(&P->core->core_lwp_head);
28320Sstevel@tonic-gate 		uint_t i;
28330Sstevel@tonic-gate 
28340Sstevel@tonic-gate 		for (i = 0; i < P->core->core_nlwp; i++, lwp = list_prev(lwp)) {
28350Sstevel@tonic-gate 			sp = (lwp->lwp_psinfo.pr_sname == 'Z')? NULL :
28364753Srh87107 			    &lwp->lwp_status;
28370Sstevel@tonic-gate 			if ((rv = func(cd, sp, &lwp->lwp_psinfo)) != 0)
28380Sstevel@tonic-gate 				break;
28390Sstevel@tonic-gate 		}
28400Sstevel@tonic-gate 
28410Sstevel@tonic-gate 		return (rv);
28420Sstevel@tonic-gate 	}
28430Sstevel@tonic-gate 
28440Sstevel@tonic-gate 	/*
28450Sstevel@tonic-gate 	 * For the live process multi-LWP case, we have to work a little
28460Sstevel@tonic-gate 	 * harder: the /proc/pid/lstatus file has the array of lwpstatus_t's
28470Sstevel@tonic-gate 	 * and the /proc/pid/lpsinfo file has the array of lwpsinfo_t's.
28480Sstevel@tonic-gate 	 */
28490Sstevel@tonic-gate 	if ((Lhp = read_lfile(P, "lstatus")) == NULL)
28500Sstevel@tonic-gate 		return (-1);
28510Sstevel@tonic-gate 	if ((Lphp = read_lfile(P, "lpsinfo")) == NULL) {
28520Sstevel@tonic-gate 		free(Lhp);
28530Sstevel@tonic-gate 		return (-1);
28540Sstevel@tonic-gate 	}
28550Sstevel@tonic-gate 
28560Sstevel@tonic-gate 	/*
28570Sstevel@tonic-gate 	 * If we are looking at a running process, or one we do not control,
28580Sstevel@tonic-gate 	 * the active and zombie lwps in the process may have changed since
28590Sstevel@tonic-gate 	 * we read the process status structure.  If so, just start over.
28600Sstevel@tonic-gate 	 */
28610Sstevel@tonic-gate 	if (Lhp->pr_nent != P->status.pr_nlwp ||
28620Sstevel@tonic-gate 	    Lphp->pr_nent != P->status.pr_nlwp + P->status.pr_nzomb)
28630Sstevel@tonic-gate 		goto retry;
28640Sstevel@tonic-gate 
28650Sstevel@tonic-gate 	/*
28660Sstevel@tonic-gate 	 * To be perfectly safe, prescan the two arrays, checking consistency.
28670Sstevel@tonic-gate 	 * We rely on /proc giving us lwpstatus_t's and lwpsinfo_t's in the
28680Sstevel@tonic-gate 	 * same order (the lwp directory order) in their respective files.
28690Sstevel@tonic-gate 	 * We also rely on there being (possibly) more lwpsinfo_t's than
28700Sstevel@tonic-gate 	 * lwpstatus_t's (the extra lwpsinfo_t's are for zombie lwps).
28710Sstevel@tonic-gate 	 */
28720Sstevel@tonic-gate 	Lsp = (lwpstatus_t *)(uintptr_t)(Lhp + 1);
28730Sstevel@tonic-gate 	Lpsp = (lwpsinfo_t *)(uintptr_t)(Lphp + 1);
28740Sstevel@tonic-gate 	nstat = Lhp->pr_nent;
28750Sstevel@tonic-gate 	for (ninfo = Lphp->pr_nent; ninfo != 0; ninfo--) {
28760Sstevel@tonic-gate 		if (Lpsp->pr_sname != 'Z') {
28770Sstevel@tonic-gate 			/*
28780Sstevel@tonic-gate 			 * Not a zombie lwp; check for matching lwpids.
28790Sstevel@tonic-gate 			 */
28800Sstevel@tonic-gate 			if (nstat == 0 || Lsp->pr_lwpid != Lpsp->pr_lwpid)
28810Sstevel@tonic-gate 				goto retry;
28820Sstevel@tonic-gate 			Lsp = (lwpstatus_t *)((uintptr_t)Lsp + Lhp->pr_entsize);
28830Sstevel@tonic-gate 			nstat--;
28840Sstevel@tonic-gate 		}
28850Sstevel@tonic-gate 		Lpsp = (lwpsinfo_t *)((uintptr_t)Lpsp + Lphp->pr_entsize);
28860Sstevel@tonic-gate 	}
28870Sstevel@tonic-gate 	if (nstat != 0)
28880Sstevel@tonic-gate 		goto retry;
28890Sstevel@tonic-gate 
28900Sstevel@tonic-gate 	/*
28910Sstevel@tonic-gate 	 * Rescan, this time for real.
28920Sstevel@tonic-gate 	 */
28930Sstevel@tonic-gate 	Lsp = (lwpstatus_t *)(uintptr_t)(Lhp + 1);
28940Sstevel@tonic-gate 	Lpsp = (lwpsinfo_t *)(uintptr_t)(Lphp + 1);
28950Sstevel@tonic-gate 	for (ninfo = Lphp->pr_nent; ninfo != 0; ninfo--) {
28960Sstevel@tonic-gate 		if (Lpsp->pr_sname != 'Z') {
28970Sstevel@tonic-gate 			sp = Lsp;
28980Sstevel@tonic-gate 			Lsp = (lwpstatus_t *)((uintptr_t)Lsp + Lhp->pr_entsize);
28990Sstevel@tonic-gate 		} else {
29000Sstevel@tonic-gate 			sp = NULL;
29010Sstevel@tonic-gate 		}
29020Sstevel@tonic-gate 		if ((rv = func(cd, sp, Lpsp)) != 0)
29030Sstevel@tonic-gate 			break;
29040Sstevel@tonic-gate 		Lpsp = (lwpsinfo_t *)((uintptr_t)Lpsp + Lphp->pr_entsize);
29050Sstevel@tonic-gate 	}
29060Sstevel@tonic-gate 
29070Sstevel@tonic-gate 	free(Lhp);
29080Sstevel@tonic-gate 	free(Lphp);
29090Sstevel@tonic-gate 	return (rv);
29100Sstevel@tonic-gate }
29110Sstevel@tonic-gate 
29120Sstevel@tonic-gate core_content_t
Pcontent(struct ps_prochandle * P)29130Sstevel@tonic-gate Pcontent(struct ps_prochandle *P)
29140Sstevel@tonic-gate {
29150Sstevel@tonic-gate 	if (P->state == PS_DEAD)
29160Sstevel@tonic-gate 		return (P->core->core_content);
29170Sstevel@tonic-gate 	if (P->state == PS_IDLE)
29180Sstevel@tonic-gate 		return (CC_CONTENT_TEXT | CC_CONTENT_DATA | CC_CONTENT_CTF);
29190Sstevel@tonic-gate 
29200Sstevel@tonic-gate 	return (CC_CONTENT_ALL);
29210Sstevel@tonic-gate }
29220Sstevel@tonic-gate 
29230Sstevel@tonic-gate /*
29240Sstevel@tonic-gate  * =================================================================
29250Sstevel@tonic-gate  * The remainder of the functions in this file are for the
29260Sstevel@tonic-gate  * control of individual LWPs in the controlled process.
29270Sstevel@tonic-gate  * =================================================================
29280Sstevel@tonic-gate  */
29290Sstevel@tonic-gate 
29300Sstevel@tonic-gate /*
29310Sstevel@tonic-gate  * Find an entry in the process hash table for the specified lwpid.
29320Sstevel@tonic-gate  * The entry will either point to an existing struct ps_lwphandle
29330Sstevel@tonic-gate  * or it will point to an empty slot for a new struct ps_lwphandle.
29340Sstevel@tonic-gate  */
29350Sstevel@tonic-gate static struct ps_lwphandle **
Lfind(struct ps_prochandle * P,lwpid_t lwpid)29360Sstevel@tonic-gate Lfind(struct ps_prochandle *P, lwpid_t lwpid)
29370Sstevel@tonic-gate {
29380Sstevel@tonic-gate 	struct ps_lwphandle **Lp;
29390Sstevel@tonic-gate 	struct ps_lwphandle *L;
29400Sstevel@tonic-gate 
29410Sstevel@tonic-gate 	for (Lp = &P->hashtab[lwpid % (HASHSIZE - 1)];
29420Sstevel@tonic-gate 	    (L = *Lp) != NULL; Lp = &L->lwp_hash)
29430Sstevel@tonic-gate 		if (L->lwp_id == lwpid)
29440Sstevel@tonic-gate 			break;
29450Sstevel@tonic-gate 	return (Lp);
29460Sstevel@tonic-gate }
29470Sstevel@tonic-gate 
29480Sstevel@tonic-gate /*
29490Sstevel@tonic-gate  * Grab an LWP contained within the controlled process.
29500Sstevel@tonic-gate  * Return an opaque pointer to its LWP control structure.
29510Sstevel@tonic-gate  *	perr: pointer to error return code.
29520Sstevel@tonic-gate  */
29530Sstevel@tonic-gate struct ps_lwphandle *
Lgrab(struct ps_prochandle * P,lwpid_t lwpid,int * perr)29540Sstevel@tonic-gate Lgrab(struct ps_prochandle *P, lwpid_t lwpid, int *perr)
29550Sstevel@tonic-gate {
29560Sstevel@tonic-gate 	struct ps_lwphandle **Lp;
29570Sstevel@tonic-gate 	struct ps_lwphandle *L;
29580Sstevel@tonic-gate 	int fd;
29592712Snn35248 	char procname[PATH_MAX];
29600Sstevel@tonic-gate 	char *fname;
29610Sstevel@tonic-gate 	int rc = 0;
29620Sstevel@tonic-gate 
29630Sstevel@tonic-gate 	(void) mutex_lock(&P->proc_lock);
29640Sstevel@tonic-gate 
29650Sstevel@tonic-gate 	if (P->state == PS_UNDEAD || P->state == PS_IDLE)
29660Sstevel@tonic-gate 		rc = G_NOPROC;
29670Sstevel@tonic-gate 	else if (P->hashtab == NULL &&
29680Sstevel@tonic-gate 	    (P->hashtab = calloc(HASHSIZE, sizeof (struct ps_lwphandle *)))
29690Sstevel@tonic-gate 	    == NULL)
29700Sstevel@tonic-gate 		rc = G_STRANGE;
29710Sstevel@tonic-gate 	else if (*(Lp = Lfind(P, lwpid)) != NULL)
29720Sstevel@tonic-gate 		rc = G_BUSY;
29730Sstevel@tonic-gate 	else if ((L = malloc(sizeof (struct ps_lwphandle))) == NULL)
29740Sstevel@tonic-gate 		rc = G_STRANGE;
29750Sstevel@tonic-gate 	if (rc) {
29760Sstevel@tonic-gate 		*perr = rc;
29770Sstevel@tonic-gate 		(void) mutex_unlock(&P->proc_lock);
29780Sstevel@tonic-gate 		return (NULL);
29790Sstevel@tonic-gate 	}
29800Sstevel@tonic-gate 
29810Sstevel@tonic-gate 	(void) memset(L, 0, sizeof (*L));
29820Sstevel@tonic-gate 	L->lwp_ctlfd = -1;
29830Sstevel@tonic-gate 	L->lwp_statfd = -1;
29840Sstevel@tonic-gate 	L->lwp_proc = P;
29850Sstevel@tonic-gate 	L->lwp_id = lwpid;
29860Sstevel@tonic-gate 	*Lp = L;	/* insert into the hash table */
29870Sstevel@tonic-gate 
29880Sstevel@tonic-gate 	if (P->state == PS_DEAD) {	/* core file */
29890Sstevel@tonic-gate 		if (getlwpstatus(P, lwpid, &L->lwp_status) == -1) {
29900Sstevel@tonic-gate 			rc = G_NOPROC;
29910Sstevel@tonic-gate 			goto err;
29920Sstevel@tonic-gate 		}
29930Sstevel@tonic-gate 		L->lwp_state = PS_DEAD;
29940Sstevel@tonic-gate 		*perr = 0;
29950Sstevel@tonic-gate 		(void) mutex_unlock(&P->proc_lock);
29960Sstevel@tonic-gate 		return (L);
29970Sstevel@tonic-gate 	}
29980Sstevel@tonic-gate 
29990Sstevel@tonic-gate 	/*
30000Sstevel@tonic-gate 	 * Open the /proc/<pid>/lwp/<lwpid> files
30010Sstevel@tonic-gate 	 */
30022712Snn35248 	(void) snprintf(procname, sizeof (procname), "%s/%d/lwp/%d/",
30032712Snn35248 	    procfs_path, (int)P->pid, (int)lwpid);
30040Sstevel@tonic-gate 	fname = procname + strlen(procname);
30050Sstevel@tonic-gate 	(void) set_minfd();
30060Sstevel@tonic-gate 
30070Sstevel@tonic-gate 	(void) strcpy(fname, "lwpstatus");
30080Sstevel@tonic-gate 	if ((fd = open(procname, O_RDONLY)) < 0 ||
30090Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
30100Sstevel@tonic-gate 		switch (errno) {
30110Sstevel@tonic-gate 		case ENOENT:
30120Sstevel@tonic-gate 			rc = G_NOPROC;
30130Sstevel@tonic-gate 			break;
30140Sstevel@tonic-gate 		default:
30150Sstevel@tonic-gate 			dprintf("Lgrab: failed to open %s: %s\n",
30160Sstevel@tonic-gate 			    procname, strerror(errno));
30170Sstevel@tonic-gate 			rc = G_STRANGE;
30180Sstevel@tonic-gate 			break;
30190Sstevel@tonic-gate 		}
30200Sstevel@tonic-gate 		goto err;
30210Sstevel@tonic-gate 	}
30220Sstevel@tonic-gate 	L->lwp_statfd = fd;
30230Sstevel@tonic-gate 
30240Sstevel@tonic-gate 	if (pread(fd, &L->lwp_status, sizeof (L->lwp_status), (off_t)0) < 0) {
30250Sstevel@tonic-gate 		switch (errno) {
30260Sstevel@tonic-gate 		case ENOENT:
30270Sstevel@tonic-gate 			rc = G_NOPROC;
30280Sstevel@tonic-gate 			break;
30290Sstevel@tonic-gate 		default:
30300Sstevel@tonic-gate 			dprintf("Lgrab: failed to read %s: %s\n",
30310Sstevel@tonic-gate 			    procname, strerror(errno));
30320Sstevel@tonic-gate 			rc = G_STRANGE;
30330Sstevel@tonic-gate 			break;
30340Sstevel@tonic-gate 		}
30350Sstevel@tonic-gate 		goto err;
30360Sstevel@tonic-gate 	}
30370Sstevel@tonic-gate 
30380Sstevel@tonic-gate 	(void) strcpy(fname, "lwpctl");
30390Sstevel@tonic-gate 	if ((fd = open(procname, O_WRONLY)) < 0 ||
30400Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
30410Sstevel@tonic-gate 		switch (errno) {
30420Sstevel@tonic-gate 		case ENOENT:
30430Sstevel@tonic-gate 			rc = G_NOPROC;
30440Sstevel@tonic-gate 			break;
30450Sstevel@tonic-gate 		default:
30460Sstevel@tonic-gate 			dprintf("Lgrab: failed to open %s: %s\n",
30470Sstevel@tonic-gate 			    procname, strerror(errno));
30480Sstevel@tonic-gate 			rc = G_STRANGE;
30490Sstevel@tonic-gate 			break;
30500Sstevel@tonic-gate 		}
30510Sstevel@tonic-gate 		goto err;
30520Sstevel@tonic-gate 	}
30530Sstevel@tonic-gate 	L->lwp_ctlfd = fd;
30540Sstevel@tonic-gate 
30550Sstevel@tonic-gate 	L->lwp_state =
30564753Srh87107 	    ((L->lwp_status.pr_flags & (PR_STOPPED|PR_ISTOP))
30574753Srh87107 	    == (PR_STOPPED|PR_ISTOP))?
30584753Srh87107 	    PS_STOP : PS_RUN;
30590Sstevel@tonic-gate 
30600Sstevel@tonic-gate 	*perr = 0;
30610Sstevel@tonic-gate 	(void) mutex_unlock(&P->proc_lock);
30620Sstevel@tonic-gate 	return (L);
30630Sstevel@tonic-gate 
30640Sstevel@tonic-gate err:
30650Sstevel@tonic-gate 	Lfree_internal(P, L);
30660Sstevel@tonic-gate 	*perr = rc;
30670Sstevel@tonic-gate 	(void) mutex_unlock(&P->proc_lock);
30680Sstevel@tonic-gate 	return (NULL);
30690Sstevel@tonic-gate }
30700Sstevel@tonic-gate 
30710Sstevel@tonic-gate /*
30720Sstevel@tonic-gate  * Return a printable string corresponding to an Lgrab() error return.
30730Sstevel@tonic-gate  */
30740Sstevel@tonic-gate const char *
Lgrab_error(int error)30750Sstevel@tonic-gate Lgrab_error(int error)
30760Sstevel@tonic-gate {
30770Sstevel@tonic-gate 	const char *str;
30780Sstevel@tonic-gate 
30790Sstevel@tonic-gate 	switch (error) {
30800Sstevel@tonic-gate 	case G_NOPROC:
30810Sstevel@tonic-gate 		str = "no such LWP";
30820Sstevel@tonic-gate 		break;
30830Sstevel@tonic-gate 	case G_BUSY:
30840Sstevel@tonic-gate 		str = "LWP already grabbed";
30850Sstevel@tonic-gate 		break;
30860Sstevel@tonic-gate 	case G_STRANGE:
30870Sstevel@tonic-gate 		str = "unanticipated system error";
30880Sstevel@tonic-gate 		break;
30890Sstevel@tonic-gate 	default:
30900Sstevel@tonic-gate 		str = "unknown error";
30910Sstevel@tonic-gate 		break;
30920Sstevel@tonic-gate 	}
30930Sstevel@tonic-gate 
30940Sstevel@tonic-gate 	return (str);
30950Sstevel@tonic-gate }
30960Sstevel@tonic-gate 
30970Sstevel@tonic-gate /*
30980Sstevel@tonic-gate  * Free an LWP control structure.
30990Sstevel@tonic-gate  */
31000Sstevel@tonic-gate void
Lfree(struct ps_lwphandle * L)31010Sstevel@tonic-gate Lfree(struct ps_lwphandle *L)
31020Sstevel@tonic-gate {
31030Sstevel@tonic-gate 	struct ps_prochandle *P = L->lwp_proc;
31040Sstevel@tonic-gate 
31050Sstevel@tonic-gate 	(void) mutex_lock(&P->proc_lock);
31060Sstevel@tonic-gate 	Lfree_internal(P, L);
31070Sstevel@tonic-gate 	(void) mutex_unlock(&P->proc_lock);
31080Sstevel@tonic-gate }
31090Sstevel@tonic-gate 
31100Sstevel@tonic-gate static void
Lfree_internal(struct ps_prochandle * P,struct ps_lwphandle * L)31110Sstevel@tonic-gate Lfree_internal(struct ps_prochandle *P, struct ps_lwphandle *L)
31120Sstevel@tonic-gate {
31130Sstevel@tonic-gate 	*Lfind(P, L->lwp_id) = L->lwp_hash;	/* delete from hash table */
31140Sstevel@tonic-gate 	if (L->lwp_ctlfd >= 0)
31150Sstevel@tonic-gate 		(void) close(L->lwp_ctlfd);
31160Sstevel@tonic-gate 	if (L->lwp_statfd >= 0)
31170Sstevel@tonic-gate 		(void) close(L->lwp_statfd);
31180Sstevel@tonic-gate 
31190Sstevel@tonic-gate 	/* clear out the structure as a precaution against reuse */
31200Sstevel@tonic-gate 	(void) memset(L, 0, sizeof (*L));
31210Sstevel@tonic-gate 	L->lwp_ctlfd = -1;
31220Sstevel@tonic-gate 	L->lwp_statfd = -1;
31230Sstevel@tonic-gate 
31240Sstevel@tonic-gate 	free(L);
31250Sstevel@tonic-gate }
31260Sstevel@tonic-gate 
31270Sstevel@tonic-gate /*
31280Sstevel@tonic-gate  * Return the state of the process, one of the PS_* values.
31290Sstevel@tonic-gate  */
31300Sstevel@tonic-gate int
Lstate(struct ps_lwphandle * L)31310Sstevel@tonic-gate Lstate(struct ps_lwphandle *L)
31320Sstevel@tonic-gate {
31330Sstevel@tonic-gate 	return (L->lwp_state);
31340Sstevel@tonic-gate }
31350Sstevel@tonic-gate 
31360Sstevel@tonic-gate /*
31370Sstevel@tonic-gate  * Return the open control file descriptor for the LWP.
31380Sstevel@tonic-gate  * Clients must not close this file descriptor, nor use it
31390Sstevel@tonic-gate  * after the LWP is freed.
31400Sstevel@tonic-gate  */
31410Sstevel@tonic-gate int
Lctlfd(struct ps_lwphandle * L)31420Sstevel@tonic-gate Lctlfd(struct ps_lwphandle *L)
31430Sstevel@tonic-gate {
31440Sstevel@tonic-gate 	return (L->lwp_ctlfd);
31450Sstevel@tonic-gate }
31460Sstevel@tonic-gate 
31470Sstevel@tonic-gate /*
31480Sstevel@tonic-gate  * Return a pointer to the LWP lwpsinfo structure.
31490Sstevel@tonic-gate  * Clients should not hold on to this pointer indefinitely.
31500Sstevel@tonic-gate  * It will become invalid on Lfree().
31510Sstevel@tonic-gate  */
31520Sstevel@tonic-gate const lwpsinfo_t *
Lpsinfo(struct ps_lwphandle * L)31530Sstevel@tonic-gate Lpsinfo(struct ps_lwphandle *L)
31540Sstevel@tonic-gate {
31550Sstevel@tonic-gate 	if (Plwp_getpsinfo(L->lwp_proc, L->lwp_id, &L->lwp_psinfo) == -1)
31560Sstevel@tonic-gate 		return (NULL);
31570Sstevel@tonic-gate 
31580Sstevel@tonic-gate 	return (&L->lwp_psinfo);
31590Sstevel@tonic-gate }
31600Sstevel@tonic-gate 
31610Sstevel@tonic-gate /*
31620Sstevel@tonic-gate  * Return a pointer to the LWP status structure.
31630Sstevel@tonic-gate  * Clients should not hold on to this pointer indefinitely.
31640Sstevel@tonic-gate  * It will become invalid on Lfree().
31650Sstevel@tonic-gate  */
31660Sstevel@tonic-gate const lwpstatus_t *
Lstatus(struct ps_lwphandle * L)31670Sstevel@tonic-gate Lstatus(struct ps_lwphandle *L)
31680Sstevel@tonic-gate {
31690Sstevel@tonic-gate 	return (&L->lwp_status);
31700Sstevel@tonic-gate }
31710Sstevel@tonic-gate 
31720Sstevel@tonic-gate /*
31730Sstevel@tonic-gate  * Given an LWP handle, return the process handle.
31740Sstevel@tonic-gate  */
31750Sstevel@tonic-gate struct ps_prochandle *
Lprochandle(struct ps_lwphandle * L)31760Sstevel@tonic-gate Lprochandle(struct ps_lwphandle *L)
31770Sstevel@tonic-gate {
31780Sstevel@tonic-gate 	return (L->lwp_proc);
31790Sstevel@tonic-gate }
31800Sstevel@tonic-gate 
31810Sstevel@tonic-gate /*
31820Sstevel@tonic-gate  * Ensure that all cached state is written to the LWP.
31830Sstevel@tonic-gate  * The cached state is the LWP's signal mask and registers.
31840Sstevel@tonic-gate  */
31850Sstevel@tonic-gate void
Lsync(struct ps_lwphandle * L)31860Sstevel@tonic-gate Lsync(struct ps_lwphandle *L)
31870Sstevel@tonic-gate {
31880Sstevel@tonic-gate 	int ctlfd = L->lwp_ctlfd;
31890Sstevel@tonic-gate 	long cmd[2];
31900Sstevel@tonic-gate 	iovec_t iov[4];
31910Sstevel@tonic-gate 	int n = 0;
31920Sstevel@tonic-gate 
31930Sstevel@tonic-gate 	if (L->lwp_flags & SETHOLD) {
31940Sstevel@tonic-gate 		cmd[0] = PCSHOLD;
31950Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[0];
31960Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
31970Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&L->lwp_status.pr_lwphold;
31980Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (L->lwp_status.pr_lwphold);
31990Sstevel@tonic-gate 	}
32000Sstevel@tonic-gate 	if (L->lwp_flags & SETREGS) {
32010Sstevel@tonic-gate 		cmd[1] = PCSREG;
32020Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[1];
32030Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
32040Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&L->lwp_status.pr_reg[0];
32050Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (L->lwp_status.pr_reg);
32060Sstevel@tonic-gate 	}
32070Sstevel@tonic-gate 
32080Sstevel@tonic-gate 	if (n == 0 || writev(ctlfd, iov, n) < 0)
32090Sstevel@tonic-gate 		return;		/* nothing to do or write failed */
32100Sstevel@tonic-gate 
32110Sstevel@tonic-gate 	L->lwp_flags &= ~(SETHOLD|SETREGS);
32120Sstevel@tonic-gate }
32130Sstevel@tonic-gate 
32140Sstevel@tonic-gate /*
32150Sstevel@tonic-gate  * Wait for the specified LWP to stop or terminate.
32160Sstevel@tonic-gate  * Or, just get the current status (PCNULL).
32170Sstevel@tonic-gate  * Or, direct it to stop and get the current status (PCDSTOP).
32180Sstevel@tonic-gate  */
32190Sstevel@tonic-gate static int
Lstopstatus(struct ps_lwphandle * L,long request,uint_t msec)32200Sstevel@tonic-gate Lstopstatus(struct ps_lwphandle *L,
32210Sstevel@tonic-gate 	long request,		/* PCNULL, PCDSTOP, PCSTOP, PCWSTOP */
32220Sstevel@tonic-gate 	uint_t msec)		/* if non-zero, timeout in milliseconds */
32230Sstevel@tonic-gate {
32240Sstevel@tonic-gate 	int ctlfd = L->lwp_ctlfd;
32250Sstevel@tonic-gate 	long ctl[3];
32260Sstevel@tonic-gate 	ssize_t rc;
32270Sstevel@tonic-gate 	int err;
32280Sstevel@tonic-gate 
32290Sstevel@tonic-gate 	switch (L->lwp_state) {
32300Sstevel@tonic-gate 	case PS_RUN:
32310Sstevel@tonic-gate 		break;
32320Sstevel@tonic-gate 	case PS_STOP:
32330Sstevel@tonic-gate 		if (request != PCNULL && request != PCDSTOP)
32340Sstevel@tonic-gate 			return (0);
32350Sstevel@tonic-gate 		break;
32360Sstevel@tonic-gate 	case PS_LOST:
32370Sstevel@tonic-gate 		if (request != PCNULL) {
32380Sstevel@tonic-gate 			errno = EAGAIN;
32390Sstevel@tonic-gate 			return (-1);
32400Sstevel@tonic-gate 		}
32410Sstevel@tonic-gate 		break;
32420Sstevel@tonic-gate 	case PS_UNDEAD:
32430Sstevel@tonic-gate 	case PS_DEAD:
32440Sstevel@tonic-gate 		if (request != PCNULL) {
32450Sstevel@tonic-gate 			errno = ENOENT;
32460Sstevel@tonic-gate 			return (-1);
32470Sstevel@tonic-gate 		}
32480Sstevel@tonic-gate 		break;
32490Sstevel@tonic-gate 	default:	/* corrupted state */
32500Sstevel@tonic-gate 		dprintf("Lstopstatus: corrupted state: %d\n", L->lwp_state);
32510Sstevel@tonic-gate 		errno = EINVAL;
32520Sstevel@tonic-gate 		return (-1);
32530Sstevel@tonic-gate 	}
32540Sstevel@tonic-gate 
32550Sstevel@tonic-gate 	ctl[0] = PCDSTOP;
32560Sstevel@tonic-gate 	ctl[1] = PCTWSTOP;
32570Sstevel@tonic-gate 	ctl[2] = (long)msec;
32580Sstevel@tonic-gate 	rc = 0;
32590Sstevel@tonic-gate 	switch (request) {
32600Sstevel@tonic-gate 	case PCSTOP:
32610Sstevel@tonic-gate 		rc = write(ctlfd, &ctl[0], 3*sizeof (long));
32620Sstevel@tonic-gate 		break;
32630Sstevel@tonic-gate 	case PCWSTOP:
32640Sstevel@tonic-gate 		rc = write(ctlfd, &ctl[1], 2*sizeof (long));
32650Sstevel@tonic-gate 		break;
32660Sstevel@tonic-gate 	case PCDSTOP:
32670Sstevel@tonic-gate 		rc = write(ctlfd, &ctl[0], 1*sizeof (long));
32680Sstevel@tonic-gate 		break;
32690Sstevel@tonic-gate 	case PCNULL:
32700Sstevel@tonic-gate 		if (L->lwp_state == PS_DEAD)
32710Sstevel@tonic-gate 			return (0); /* Nothing else to do for cores */
32720Sstevel@tonic-gate 		break;
32730Sstevel@tonic-gate 	default:	/* programming error */
32740Sstevel@tonic-gate 		errno = EINVAL;
32750Sstevel@tonic-gate 		return (-1);
32760Sstevel@tonic-gate 	}
32770Sstevel@tonic-gate 	err = (rc < 0)? errno : 0;
32780Sstevel@tonic-gate 	Lsync(L);
32790Sstevel@tonic-gate 
32800Sstevel@tonic-gate 	if (pread(L->lwp_statfd, &L->lwp_status,
32810Sstevel@tonic-gate 	    sizeof (L->lwp_status), (off_t)0) < 0)
32820Sstevel@tonic-gate 		err = errno;
32830Sstevel@tonic-gate 
32840Sstevel@tonic-gate 	if (err) {
32850Sstevel@tonic-gate 		switch (err) {
32860Sstevel@tonic-gate 		case EINTR:		/* user typed ctl-C */
32870Sstevel@tonic-gate 		case ERESTART:
32880Sstevel@tonic-gate 			dprintf("Lstopstatus: EINTR\n");
32890Sstevel@tonic-gate 			break;
32900Sstevel@tonic-gate 		case EAGAIN:		/* we lost control of the the process */
32910Sstevel@tonic-gate 			dprintf("Lstopstatus: EAGAIN\n");
32920Sstevel@tonic-gate 			L->lwp_state = PS_LOST;
32930Sstevel@tonic-gate 			errno = err;
32940Sstevel@tonic-gate 			return (-1);
32950Sstevel@tonic-gate 		default:
32960Sstevel@tonic-gate 			if (_libproc_debug) {
32970Sstevel@tonic-gate 				const char *errstr;
32980Sstevel@tonic-gate 
32990Sstevel@tonic-gate 				switch (request) {
33000Sstevel@tonic-gate 				case PCNULL:
33010Sstevel@tonic-gate 					errstr = "Lstopstatus PCNULL"; break;
33020Sstevel@tonic-gate 				case PCSTOP:
33030Sstevel@tonic-gate 					errstr = "Lstopstatus PCSTOP"; break;
33040Sstevel@tonic-gate 				case PCDSTOP:
33050Sstevel@tonic-gate 					errstr = "Lstopstatus PCDSTOP"; break;
33060Sstevel@tonic-gate 				case PCWSTOP:
33070Sstevel@tonic-gate 					errstr = "Lstopstatus PCWSTOP"; break;
33080Sstevel@tonic-gate 				default:
33090Sstevel@tonic-gate 					errstr = "Lstopstatus PC???"; break;
33100Sstevel@tonic-gate 				}
33110Sstevel@tonic-gate 				dprintf("%s: %s\n", errstr, strerror(err));
33120Sstevel@tonic-gate 			}
33130Sstevel@tonic-gate 			L->lwp_state = PS_UNDEAD;
33140Sstevel@tonic-gate 			errno = err;
33150Sstevel@tonic-gate 			return (-1);
33160Sstevel@tonic-gate 		}
33170Sstevel@tonic-gate 	}
33180Sstevel@tonic-gate 
33190Sstevel@tonic-gate 	if ((L->lwp_status.pr_flags & (PR_STOPPED|PR_ISTOP))
33200Sstevel@tonic-gate 	    != (PR_STOPPED|PR_ISTOP)) {
33210Sstevel@tonic-gate 		L->lwp_state = PS_RUN;
33220Sstevel@tonic-gate 		if (request == PCNULL || request == PCDSTOP || msec != 0)
33230Sstevel@tonic-gate 			return (0);
33240Sstevel@tonic-gate 		dprintf("Lstopstatus: LWP is not stopped\n");
33250Sstevel@tonic-gate 		errno = EPROTO;
33260Sstevel@tonic-gate 		return (-1);
33270Sstevel@tonic-gate 	}
33280Sstevel@tonic-gate 
33290Sstevel@tonic-gate 	L->lwp_state = PS_STOP;
33300Sstevel@tonic-gate 
33310Sstevel@tonic-gate 	if (_libproc_debug)	/* debugging */
33320Sstevel@tonic-gate 		prldump("Lstopstatus", &L->lwp_status);
33330Sstevel@tonic-gate 
33340Sstevel@tonic-gate 	switch (L->lwp_status.pr_why) {
33350Sstevel@tonic-gate 	case PR_SYSENTRY:
33360Sstevel@tonic-gate 	case PR_SYSEXIT:
33370Sstevel@tonic-gate 	case PR_REQUESTED:
33380Sstevel@tonic-gate 	case PR_SIGNALLED:
33390Sstevel@tonic-gate 	case PR_FAULTED:
33400Sstevel@tonic-gate 	case PR_JOBCONTROL:
33410Sstevel@tonic-gate 	case PR_SUSPENDED:
33420Sstevel@tonic-gate 		break;
33430Sstevel@tonic-gate 	default:
33440Sstevel@tonic-gate 		errno = EPROTO;
33450Sstevel@tonic-gate 		return (-1);
33460Sstevel@tonic-gate 	}
33470Sstevel@tonic-gate 
33480Sstevel@tonic-gate 	return (0);
33490Sstevel@tonic-gate }
33500Sstevel@tonic-gate 
33510Sstevel@tonic-gate /*
33520Sstevel@tonic-gate  * Wait for the LWP to stop for any reason.
33530Sstevel@tonic-gate  */
33540Sstevel@tonic-gate int
Lwait(struct ps_lwphandle * L,uint_t msec)33550Sstevel@tonic-gate Lwait(struct ps_lwphandle *L, uint_t msec)
33560Sstevel@tonic-gate {
33570Sstevel@tonic-gate 	return (Lstopstatus(L, PCWSTOP, msec));
33580Sstevel@tonic-gate }
33590Sstevel@tonic-gate 
33600Sstevel@tonic-gate /*
33610Sstevel@tonic-gate  * Direct the LWP to stop; wait for it to stop.
33620Sstevel@tonic-gate  */
33630Sstevel@tonic-gate int
Lstop(struct ps_lwphandle * L,uint_t msec)33640Sstevel@tonic-gate Lstop(struct ps_lwphandle *L, uint_t msec)
33650Sstevel@tonic-gate {
33660Sstevel@tonic-gate 	return (Lstopstatus(L, PCSTOP, msec));
33670Sstevel@tonic-gate }
33680Sstevel@tonic-gate 
33690Sstevel@tonic-gate /*
33700Sstevel@tonic-gate  * Direct the LWP to stop; don't wait.
33710Sstevel@tonic-gate  */
33720Sstevel@tonic-gate int
Ldstop(struct ps_lwphandle * L)33730Sstevel@tonic-gate Ldstop(struct ps_lwphandle *L)
33740Sstevel@tonic-gate {
33750Sstevel@tonic-gate 	return (Lstopstatus(L, PCDSTOP, 0));
33760Sstevel@tonic-gate }
33770Sstevel@tonic-gate 
33780Sstevel@tonic-gate /*
33790Sstevel@tonic-gate  * Get the value of one register from stopped LWP.
33800Sstevel@tonic-gate  */
33810Sstevel@tonic-gate int
Lgetareg(struct ps_lwphandle * L,int regno,prgreg_t * preg)33820Sstevel@tonic-gate Lgetareg(struct ps_lwphandle *L, int regno, prgreg_t *preg)
33830Sstevel@tonic-gate {
33840Sstevel@tonic-gate 	if (regno < 0 || regno >= NPRGREG) {
33850Sstevel@tonic-gate 		errno = EINVAL;
33860Sstevel@tonic-gate 		return (-1);
33870Sstevel@tonic-gate 	}
33880Sstevel@tonic-gate 
33890Sstevel@tonic-gate 	if (L->lwp_state != PS_STOP) {
33900Sstevel@tonic-gate 		errno = EBUSY;
33910Sstevel@tonic-gate 		return (-1);
33920Sstevel@tonic-gate 	}
33930Sstevel@tonic-gate 
33940Sstevel@tonic-gate 	*preg = L->lwp_status.pr_reg[regno];
33950Sstevel@tonic-gate 	return (0);
33960Sstevel@tonic-gate }
33970Sstevel@tonic-gate 
33980Sstevel@tonic-gate /*
33990Sstevel@tonic-gate  * Put value of one register into stopped LWP.
34000Sstevel@tonic-gate  */
34010Sstevel@tonic-gate int
Lputareg(struct ps_lwphandle * L,int regno,prgreg_t reg)34020Sstevel@tonic-gate Lputareg(struct ps_lwphandle *L, int regno, prgreg_t reg)
34030Sstevel@tonic-gate {
34040Sstevel@tonic-gate 	if (regno < 0 || regno >= NPRGREG) {
34050Sstevel@tonic-gate 		errno = EINVAL;
34060Sstevel@tonic-gate 		return (-1);
34070Sstevel@tonic-gate 	}
34080Sstevel@tonic-gate 
34090Sstevel@tonic-gate 	if (L->lwp_state != PS_STOP) {
34100Sstevel@tonic-gate 		errno = EBUSY;
34110Sstevel@tonic-gate 		return (-1);
34120Sstevel@tonic-gate 	}
34130Sstevel@tonic-gate 
34140Sstevel@tonic-gate 	L->lwp_status.pr_reg[regno] = reg;
34150Sstevel@tonic-gate 	L->lwp_flags |= SETREGS;	/* set registers before continuing */
34160Sstevel@tonic-gate 	return (0);
34170Sstevel@tonic-gate }
34180Sstevel@tonic-gate 
34190Sstevel@tonic-gate int
Lsetrun(struct ps_lwphandle * L,int sig,int flags)34200Sstevel@tonic-gate Lsetrun(struct ps_lwphandle *L,
34210Sstevel@tonic-gate 	int sig,	/* signal to pass to LWP */
34220Sstevel@tonic-gate 	int flags)	/* PRSTEP|PRSABORT|PRSTOP|PRCSIG|PRCFAULT */
34230Sstevel@tonic-gate {
34240Sstevel@tonic-gate 	int ctlfd = L->lwp_ctlfd;
34250Sstevel@tonic-gate 	int sbits = (PR_DSTOP | PR_ISTOP | PR_ASLEEP);
34260Sstevel@tonic-gate 
34270Sstevel@tonic-gate 	long ctl[1 +					/* PCCFAULT	*/
34284753Srh87107 	    1 + sizeof (siginfo_t)/sizeof (long) +	/* PCSSIG/PCCSIG */
34294753Srh87107 	    2 ];					/* PCRUN	*/
34300Sstevel@tonic-gate 
34310Sstevel@tonic-gate 	long *ctlp = ctl;
34320Sstevel@tonic-gate 	size_t size;
34330Sstevel@tonic-gate 
34340Sstevel@tonic-gate 	if (L->lwp_state != PS_STOP &&
34350Sstevel@tonic-gate 	    (L->lwp_status.pr_flags & sbits) == 0) {
34360Sstevel@tonic-gate 		errno = EBUSY;
34370Sstevel@tonic-gate 		return (-1);
34380Sstevel@tonic-gate 	}
34390Sstevel@tonic-gate 
34400Sstevel@tonic-gate 	Lsync(L);	/* flush registers */
34410Sstevel@tonic-gate 
34420Sstevel@tonic-gate 	if (flags & PRCFAULT) {		/* clear current fault */
34430Sstevel@tonic-gate 		*ctlp++ = PCCFAULT;
34440Sstevel@tonic-gate 		flags &= ~PRCFAULT;
34450Sstevel@tonic-gate 	}
34460Sstevel@tonic-gate 
34470Sstevel@tonic-gate 	if (flags & PRCSIG) {		/* clear current signal */
34480Sstevel@tonic-gate 		*ctlp++ = PCCSIG;
34490Sstevel@tonic-gate 		flags &= ~PRCSIG;
34500Sstevel@tonic-gate 	} else if (sig && sig != L->lwp_status.pr_cursig) {
34510Sstevel@tonic-gate 		/* make current signal */
34520Sstevel@tonic-gate 		siginfo_t *infop;
34530Sstevel@tonic-gate 
34540Sstevel@tonic-gate 		*ctlp++ = PCSSIG;
34550Sstevel@tonic-gate 		infop = (siginfo_t *)ctlp;
34560Sstevel@tonic-gate 		(void) memset(infop, 0, sizeof (*infop));
34570Sstevel@tonic-gate 		infop->si_signo = sig;
34580Sstevel@tonic-gate 		ctlp += sizeof (siginfo_t) / sizeof (long);
34590Sstevel@tonic-gate 	}
34600Sstevel@tonic-gate 
34610Sstevel@tonic-gate 	*ctlp++ = PCRUN;
34620Sstevel@tonic-gate 	*ctlp++ = flags;
34630Sstevel@tonic-gate 	size = (char *)ctlp - (char *)ctl;
34640Sstevel@tonic-gate 
34650Sstevel@tonic-gate 	L->lwp_proc->info_valid = 0; /* will need to update map and file info */
34660Sstevel@tonic-gate 	L->lwp_proc->state = PS_RUN;
34670Sstevel@tonic-gate 	L->lwp_state = PS_RUN;
34680Sstevel@tonic-gate 
34690Sstevel@tonic-gate 	if (write(ctlfd, ctl, size) != size) {
34700Sstevel@tonic-gate 		/* Pretend that a job-stopped LWP is running */
34710Sstevel@tonic-gate 		if (errno != EBUSY || L->lwp_status.pr_why != PR_JOBCONTROL)
34720Sstevel@tonic-gate 			return (Lstopstatus(L, PCNULL, 0));
34730Sstevel@tonic-gate 	}
34740Sstevel@tonic-gate 
34750Sstevel@tonic-gate 	return (0);
34760Sstevel@tonic-gate }
34770Sstevel@tonic-gate 
34780Sstevel@tonic-gate int
Lclearsig(struct ps_lwphandle * L)34790Sstevel@tonic-gate Lclearsig(struct ps_lwphandle *L)
34800Sstevel@tonic-gate {
34810Sstevel@tonic-gate 	int ctlfd = L->lwp_ctlfd;
34820Sstevel@tonic-gate 	long ctl = PCCSIG;
34830Sstevel@tonic-gate 
34840Sstevel@tonic-gate 	if (write(ctlfd, &ctl, sizeof (ctl)) != sizeof (ctl))
34850Sstevel@tonic-gate 		return (-1);
34860Sstevel@tonic-gate 	L->lwp_status.pr_cursig = 0;
34870Sstevel@tonic-gate 	return (0);
34880Sstevel@tonic-gate }
34890Sstevel@tonic-gate 
34900Sstevel@tonic-gate int
Lclearfault(struct ps_lwphandle * L)34910Sstevel@tonic-gate Lclearfault(struct ps_lwphandle *L)
34920Sstevel@tonic-gate {
34930Sstevel@tonic-gate 	int ctlfd = L->lwp_ctlfd;
34940Sstevel@tonic-gate 	long ctl = PCCFAULT;
34950Sstevel@tonic-gate 
34960Sstevel@tonic-gate 	if (write(ctlfd, &ctl, sizeof (ctl)) != sizeof (ctl))
34970Sstevel@tonic-gate 		return (-1);
34980Sstevel@tonic-gate 	return (0);
34990Sstevel@tonic-gate }
35000Sstevel@tonic-gate 
35010Sstevel@tonic-gate /*
35020Sstevel@tonic-gate  * Step over a breakpoint, i.e., execute the instruction that
35030Sstevel@tonic-gate  * really belongs at the breakpoint location (the current %pc)
35040Sstevel@tonic-gate  * and leave the LWP stopped at the next instruction.
35050Sstevel@tonic-gate  */
35060Sstevel@tonic-gate int
Lxecbkpt(struct ps_lwphandle * L,ulong_t saved)35070Sstevel@tonic-gate Lxecbkpt(struct ps_lwphandle *L, ulong_t saved)
35080Sstevel@tonic-gate {
35090Sstevel@tonic-gate 	struct ps_prochandle *P = L->lwp_proc;
35100Sstevel@tonic-gate 	int rv, error;
35110Sstevel@tonic-gate 
35120Sstevel@tonic-gate 	if (L->lwp_state != PS_STOP) {
35130Sstevel@tonic-gate 		errno = EBUSY;
35140Sstevel@tonic-gate 		return (-1);
35150Sstevel@tonic-gate 	}
35160Sstevel@tonic-gate 
35170Sstevel@tonic-gate 	Lsync(L);
35180Sstevel@tonic-gate 	error = execute_bkpt(L->lwp_ctlfd,
35194753Srh87107 	    &P->status.pr_flttrace, &L->lwp_status.pr_lwphold,
35204753Srh87107 	    L->lwp_status.pr_reg[R_PC], saved);
35210Sstevel@tonic-gate 	rv = Lstopstatus(L, PCNULL, 0);
35220Sstevel@tonic-gate 
35230Sstevel@tonic-gate 	if (error != 0) {
35240Sstevel@tonic-gate 		if (L->lwp_status.pr_why == PR_JOBCONTROL &&
35250Sstevel@tonic-gate 		    error == EBUSY) {	/* jobcontrol stop -- back off */
35260Sstevel@tonic-gate 			L->lwp_state = PS_RUN;
35270Sstevel@tonic-gate 			return (0);
35280Sstevel@tonic-gate 		}
35290Sstevel@tonic-gate 		if (error == ENOENT)
35300Sstevel@tonic-gate 			return (0);
35310Sstevel@tonic-gate 		errno = error;
35320Sstevel@tonic-gate 		return (-1);
35330Sstevel@tonic-gate 	}
35340Sstevel@tonic-gate 
35350Sstevel@tonic-gate 	return (rv);
35360Sstevel@tonic-gate }
35370Sstevel@tonic-gate 
35380Sstevel@tonic-gate /*
35390Sstevel@tonic-gate  * Step over a watchpoint, i.e., execute the instruction that was stopped by
35400Sstevel@tonic-gate  * the watchpoint, and then leave the LWP stopped at the next instruction.
35410Sstevel@tonic-gate  */
35420Sstevel@tonic-gate int
Lxecwapt(struct ps_lwphandle * L,const prwatch_t * wp)35430Sstevel@tonic-gate Lxecwapt(struct ps_lwphandle *L, const prwatch_t *wp)
35440Sstevel@tonic-gate {
35450Sstevel@tonic-gate 	struct ps_prochandle *P = L->lwp_proc;
35460Sstevel@tonic-gate 	int rv, error;
35470Sstevel@tonic-gate 
35480Sstevel@tonic-gate 	if (L->lwp_state != PS_STOP) {
35490Sstevel@tonic-gate 		errno = EBUSY;
35500Sstevel@tonic-gate 		return (-1);
35510Sstevel@tonic-gate 	}
35520Sstevel@tonic-gate 
35530Sstevel@tonic-gate 	Lsync(L);
35540Sstevel@tonic-gate 	error = execute_wapt(L->lwp_ctlfd,
35554753Srh87107 	    &P->status.pr_flttrace, &L->lwp_status.pr_lwphold, wp);
35560Sstevel@tonic-gate 	rv = Lstopstatus(L, PCNULL, 0);
35570Sstevel@tonic-gate 
35580Sstevel@tonic-gate 	if (error != 0) {
35590Sstevel@tonic-gate 		if (L->lwp_status.pr_why == PR_JOBCONTROL &&
35600Sstevel@tonic-gate 		    error == EBUSY) {	/* jobcontrol stop -- back off */
35610Sstevel@tonic-gate 			L->lwp_state = PS_RUN;
35620Sstevel@tonic-gate 			return (0);
35630Sstevel@tonic-gate 		}
35640Sstevel@tonic-gate 		if (error == ENOENT)
35650Sstevel@tonic-gate 			return (0);
35660Sstevel@tonic-gate 		errno = error;
35670Sstevel@tonic-gate 		return (-1);
35680Sstevel@tonic-gate 	}
35690Sstevel@tonic-gate 
35700Sstevel@tonic-gate 	return (rv);
35710Sstevel@tonic-gate }
35720Sstevel@tonic-gate 
35730Sstevel@tonic-gate int
Lstack(struct ps_lwphandle * L,stack_t * stkp)35740Sstevel@tonic-gate Lstack(struct ps_lwphandle *L, stack_t *stkp)
35750Sstevel@tonic-gate {
35760Sstevel@tonic-gate 	struct ps_prochandle *P = L->lwp_proc;
35770Sstevel@tonic-gate 	uintptr_t addr = L->lwp_status.pr_ustack;
35780Sstevel@tonic-gate 
35790Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
35800Sstevel@tonic-gate 		if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp))
35810Sstevel@tonic-gate 			return (-1);
35820Sstevel@tonic-gate #ifdef _LP64
35830Sstevel@tonic-gate 	} else {
35840Sstevel@tonic-gate 		stack32_t stk32;
35850Sstevel@tonic-gate 
35860Sstevel@tonic-gate 		if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32))
35870Sstevel@tonic-gate 			return (-1);
35880Sstevel@tonic-gate 
35890Sstevel@tonic-gate 		stack_32_to_n(&stk32, stkp);
35900Sstevel@tonic-gate #endif
35910Sstevel@tonic-gate 	}
35920Sstevel@tonic-gate 
35930Sstevel@tonic-gate 	return (0);
35940Sstevel@tonic-gate }
35950Sstevel@tonic-gate 
35960Sstevel@tonic-gate int
Lmain_stack(struct ps_lwphandle * L,stack_t * stkp)35970Sstevel@tonic-gate Lmain_stack(struct ps_lwphandle *L, stack_t *stkp)
35980Sstevel@tonic-gate {
35990Sstevel@tonic-gate 	struct ps_prochandle *P = L->lwp_proc;
36000Sstevel@tonic-gate 
36010Sstevel@tonic-gate 	if (Lstack(L, stkp) != 0)
36020Sstevel@tonic-gate 		return (-1);
36030Sstevel@tonic-gate 
36040Sstevel@tonic-gate 	/*
36050Sstevel@tonic-gate 	 * If the SS_ONSTACK flag is set then this LWP is operating on the
36060Sstevel@tonic-gate 	 * alternate signal stack. We can recover the original stack from
36070Sstevel@tonic-gate 	 * pr_oldcontext.
36080Sstevel@tonic-gate 	 */
36090Sstevel@tonic-gate 	if (!(stkp->ss_flags & SS_ONSTACK))
36100Sstevel@tonic-gate 		return (0);
36110Sstevel@tonic-gate 
36120Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
36130Sstevel@tonic-gate 		ucontext_t *ctxp = (void *)L->lwp_status.pr_oldcontext;
36140Sstevel@tonic-gate 
36150Sstevel@tonic-gate 		if (Pread(P, stkp, sizeof (*stkp),
36160Sstevel@tonic-gate 		    (uintptr_t)&ctxp->uc_stack) != sizeof (*stkp))
36170Sstevel@tonic-gate 			return (-1);
36180Sstevel@tonic-gate #ifdef _LP64
36190Sstevel@tonic-gate 	} else {
36200Sstevel@tonic-gate 		ucontext32_t *ctxp = (void *)L->lwp_status.pr_oldcontext;
36210Sstevel@tonic-gate 		stack32_t stk32;
36220Sstevel@tonic-gate 
36230Sstevel@tonic-gate 		if (Pread(P, &stk32, sizeof (stk32),
36240Sstevel@tonic-gate 		    (uintptr_t)&ctxp->uc_stack) != sizeof (stk32))
36250Sstevel@tonic-gate 			return (-1);
36260Sstevel@tonic-gate 
36270Sstevel@tonic-gate 		stack_32_to_n(&stk32, stkp);
36280Sstevel@tonic-gate #endif
36290Sstevel@tonic-gate 	}
36300Sstevel@tonic-gate 
36310Sstevel@tonic-gate 	return (0);
36320Sstevel@tonic-gate }
36330Sstevel@tonic-gate 
36340Sstevel@tonic-gate int
Lalt_stack(struct ps_lwphandle * L,stack_t * stkp)36350Sstevel@tonic-gate Lalt_stack(struct ps_lwphandle *L, stack_t *stkp)
36360Sstevel@tonic-gate {
36370Sstevel@tonic-gate 	if (L->lwp_status.pr_altstack.ss_flags & SS_DISABLE) {
36380Sstevel@tonic-gate 		errno = ENODATA;
36390Sstevel@tonic-gate 		return (-1);
36400Sstevel@tonic-gate 	}
36410Sstevel@tonic-gate 
36420Sstevel@tonic-gate 	*stkp = L->lwp_status.pr_altstack;
36430Sstevel@tonic-gate 
36440Sstevel@tonic-gate 	return (0);
36450Sstevel@tonic-gate }
36460Sstevel@tonic-gate 
36470Sstevel@tonic-gate /*
36480Sstevel@tonic-gate  * Add a mapping to the given proc handle.  Resizes the array as appropriate and
36490Sstevel@tonic-gate  * manages reference counts on the given file_info_t.
36500Sstevel@tonic-gate  *
36510Sstevel@tonic-gate  * The 'map_relocate' member is used to tell Psort_mappings() that the
36520Sstevel@tonic-gate  * associated file_map pointer needs to be relocated after the mappings have
36530Sstevel@tonic-gate  * been sorted.  It is only set for the first mapping, and has no meaning
36540Sstevel@tonic-gate  * outside these two functions.
36550Sstevel@tonic-gate  */
36560Sstevel@tonic-gate int
Padd_mapping(struct ps_prochandle * P,off64_t off,file_info_t * fp,prmap_t * pmap)36570Sstevel@tonic-gate Padd_mapping(struct ps_prochandle *P, off64_t off, file_info_t *fp,
36580Sstevel@tonic-gate     prmap_t *pmap)
36590Sstevel@tonic-gate {
36600Sstevel@tonic-gate 	map_info_t *mp;
36610Sstevel@tonic-gate 
36620Sstevel@tonic-gate 	if (P->map_count == P->map_alloc) {
36630Sstevel@tonic-gate 		size_t next = P->map_alloc ? P->map_alloc * 2 : 16;
36640Sstevel@tonic-gate 
36650Sstevel@tonic-gate 		if ((P->mappings = realloc(P->mappings,
36660Sstevel@tonic-gate 		    next * sizeof (map_info_t))) == NULL)
36670Sstevel@tonic-gate 			return (-1);
36680Sstevel@tonic-gate 
36690Sstevel@tonic-gate 		P->map_alloc = next;
36700Sstevel@tonic-gate 	}
36710Sstevel@tonic-gate 
36720Sstevel@tonic-gate 	mp = &P->mappings[P->map_count++];
36730Sstevel@tonic-gate 
36740Sstevel@tonic-gate 	mp->map_offset = off;
36750Sstevel@tonic-gate 	mp->map_pmap = *pmap;
36760Sstevel@tonic-gate 	mp->map_relocate = 0;
36770Sstevel@tonic-gate 	if ((mp->map_file = fp) != NULL) {
36780Sstevel@tonic-gate 		if (fp->file_map == NULL) {
36790Sstevel@tonic-gate 			fp->file_map = mp;
36800Sstevel@tonic-gate 			mp->map_relocate = 1;
36810Sstevel@tonic-gate 		}
36820Sstevel@tonic-gate 		fp->file_ref++;
36830Sstevel@tonic-gate 	}
36840Sstevel@tonic-gate 
36850Sstevel@tonic-gate 	return (0);
36860Sstevel@tonic-gate }
36870Sstevel@tonic-gate 
36880Sstevel@tonic-gate static int
map_sort(const void * a,const void * b)36890Sstevel@tonic-gate map_sort(const void *a, const void *b)
36900Sstevel@tonic-gate {
36910Sstevel@tonic-gate 	const map_info_t *ap = a, *bp = b;
36920Sstevel@tonic-gate 
36930Sstevel@tonic-gate 	if (ap->map_pmap.pr_vaddr < bp->map_pmap.pr_vaddr)
36940Sstevel@tonic-gate 		return (-1);
36950Sstevel@tonic-gate 	else if (ap->map_pmap.pr_vaddr > bp->map_pmap.pr_vaddr)
36960Sstevel@tonic-gate 		return (1);
36970Sstevel@tonic-gate 	else
36980Sstevel@tonic-gate 		return (0);
36990Sstevel@tonic-gate }
37000Sstevel@tonic-gate 
37010Sstevel@tonic-gate /*
37020Sstevel@tonic-gate  * Sort the current set of mappings.  Should be called during target
37030Sstevel@tonic-gate  * initialization after all calls to Padd_mapping() have been made.
37040Sstevel@tonic-gate  */
37050Sstevel@tonic-gate void
Psort_mappings(struct ps_prochandle * P)37060Sstevel@tonic-gate Psort_mappings(struct ps_prochandle *P)
37070Sstevel@tonic-gate {
37080Sstevel@tonic-gate 	int i;
37090Sstevel@tonic-gate 	map_info_t *mp;
37100Sstevel@tonic-gate 
37110Sstevel@tonic-gate 	qsort(P->mappings, P->map_count, sizeof (map_info_t), map_sort);
37120Sstevel@tonic-gate 
37130Sstevel@tonic-gate 	/*
37140Sstevel@tonic-gate 	 * Update all the file_map pointers to refer to the new locations.
37150Sstevel@tonic-gate 	 */
37160Sstevel@tonic-gate 	for (i = 0; i < P->map_count; i++) {
37170Sstevel@tonic-gate 		mp = &P->mappings[i];
37180Sstevel@tonic-gate 		if (mp->map_relocate)
37190Sstevel@tonic-gate 			mp->map_file->file_map = mp;
37200Sstevel@tonic-gate 		mp->map_relocate = 0;
37210Sstevel@tonic-gate 	}
37220Sstevel@tonic-gate }
3723