1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <stdio.h>
30*0Sstevel@tonic-gate #include <stdlib.h>
31*0Sstevel@tonic-gate #include <unistd.h>
32*0Sstevel@tonic-gate #include <ctype.h>
33*0Sstevel@tonic-gate #include <fcntl.h>
34*0Sstevel@tonic-gate #include <string.h>
35*0Sstevel@tonic-gate #include <memory.h>
36*0Sstevel@tonic-gate #include <errno.h>
37*0Sstevel@tonic-gate #include <dirent.h>
38*0Sstevel@tonic-gate #include <limits.h>
39*0Sstevel@tonic-gate #include <signal.h>
40*0Sstevel@tonic-gate #include <sys/types.h>
41*0Sstevel@tonic-gate #include <sys/uio.h>
42*0Sstevel@tonic-gate #include <sys/stat.h>
43*0Sstevel@tonic-gate #include <sys/resource.h>
44*0Sstevel@tonic-gate #include <sys/param.h>
45*0Sstevel@tonic-gate #include <sys/stack.h>
46*0Sstevel@tonic-gate #include <sys/fault.h>
47*0Sstevel@tonic-gate #include <sys/syscall.h>
48*0Sstevel@tonic-gate #include <sys/sysmacros.h>
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate #include "libproc.h"
51*0Sstevel@tonic-gate #include "Pcontrol.h"
52*0Sstevel@tonic-gate #include "Putil.h"
53*0Sstevel@tonic-gate #include "P32ton.h"
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate int	_libproc_debug;		/* set non-zero to enable debugging printfs */
56*0Sstevel@tonic-gate sigset_t blockable_sigs;	/* signals to block when we need to be safe */
57*0Sstevel@tonic-gate static	int	minfd;	/* minimum file descriptor returned by dupfd(fd, 0) */
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate /*
60*0Sstevel@tonic-gate  * Function prototypes for static routines in this module.
61*0Sstevel@tonic-gate  */
62*0Sstevel@tonic-gate static	void	deadcheck(struct ps_prochandle *);
63*0Sstevel@tonic-gate static	void	restore_tracing_flags(struct ps_prochandle *);
64*0Sstevel@tonic-gate static	void	Lfree_internal(struct ps_prochandle *, struct ps_lwphandle *);
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate /*
67*0Sstevel@tonic-gate  * Read/write interface for live processes: just pread/pwrite the
68*0Sstevel@tonic-gate  * /proc/<pid>/as file:
69*0Sstevel@tonic-gate  */
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate static ssize_t
72*0Sstevel@tonic-gate Pread_live(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr)
73*0Sstevel@tonic-gate {
74*0Sstevel@tonic-gate 	return (pread(P->asfd, buf, n, (off_t)addr));
75*0Sstevel@tonic-gate }
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate static ssize_t
78*0Sstevel@tonic-gate Pwrite_live(struct ps_prochandle *P, const void *buf, size_t n, uintptr_t addr)
79*0Sstevel@tonic-gate {
80*0Sstevel@tonic-gate 	return (pwrite(P->asfd, buf, n, (off_t)addr));
81*0Sstevel@tonic-gate }
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate static const ps_rwops_t P_live_ops = { Pread_live, Pwrite_live };
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate /*
86*0Sstevel@tonic-gate  * This is the library's .init handler.
87*0Sstevel@tonic-gate  */
88*0Sstevel@tonic-gate #pragma init(_libproc_init)
89*0Sstevel@tonic-gate void
90*0Sstevel@tonic-gate _libproc_init(void)
91*0Sstevel@tonic-gate {
92*0Sstevel@tonic-gate 	_libproc_debug = getenv("LIBPROC_DEBUG") != NULL;
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate 	(void) sigfillset(&blockable_sigs);
95*0Sstevel@tonic-gate 	(void) sigdelset(&blockable_sigs, SIGKILL);
96*0Sstevel@tonic-gate 	(void) sigdelset(&blockable_sigs, SIGSTOP);
97*0Sstevel@tonic-gate }
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate /*
100*0Sstevel@tonic-gate  * Call set_minfd() once before calling dupfd() several times.
101*0Sstevel@tonic-gate  * We assume that the application will not reduce its current file
102*0Sstevel@tonic-gate  * descriptor limit lower than 512 once it has set at least that value.
103*0Sstevel@tonic-gate  */
104*0Sstevel@tonic-gate int
105*0Sstevel@tonic-gate set_minfd(void)
106*0Sstevel@tonic-gate {
107*0Sstevel@tonic-gate 	static mutex_t minfd_lock = DEFAULTMUTEX;
108*0Sstevel@tonic-gate 	struct rlimit rlim;
109*0Sstevel@tonic-gate 	int fd;
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 	if ((fd = minfd) < 256) {
112*0Sstevel@tonic-gate 		(void) mutex_lock(&minfd_lock);
113*0Sstevel@tonic-gate 		if ((fd = minfd) < 256) {
114*0Sstevel@tonic-gate 			if (getrlimit(RLIMIT_NOFILE, &rlim) != 0)
115*0Sstevel@tonic-gate 				rlim.rlim_cur = rlim.rlim_max = 0;
116*0Sstevel@tonic-gate 			if (rlim.rlim_cur >= 512)
117*0Sstevel@tonic-gate 				fd = 256;
118*0Sstevel@tonic-gate 			else if ((fd = rlim.rlim_cur / 2) < 3)
119*0Sstevel@tonic-gate 				fd = 3;
120*0Sstevel@tonic-gate 			minfd = fd;
121*0Sstevel@tonic-gate 		}
122*0Sstevel@tonic-gate 		(void) mutex_unlock(&minfd_lock);
123*0Sstevel@tonic-gate 	}
124*0Sstevel@tonic-gate 	return (fd);
125*0Sstevel@tonic-gate }
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate int
128*0Sstevel@tonic-gate dupfd(int fd, int dfd)
129*0Sstevel@tonic-gate {
130*0Sstevel@tonic-gate 	int mfd;
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate 	/*
133*0Sstevel@tonic-gate 	 * Make fd be greater than 255 (the 32-bit stdio limit),
134*0Sstevel@tonic-gate 	 * or at least make it greater than 2 so that the
135*0Sstevel@tonic-gate 	 * program will work when spawned by init(1m).
136*0Sstevel@tonic-gate 	 * Also, if dfd is non-zero, dup the fd to be dfd.
137*0Sstevel@tonic-gate 	 */
138*0Sstevel@tonic-gate 	if ((mfd = minfd) == 0)
139*0Sstevel@tonic-gate 		mfd = set_minfd();
140*0Sstevel@tonic-gate 	if (dfd > 0 || (0 <= fd && fd < mfd)) {
141*0Sstevel@tonic-gate 		if (dfd <= 0)
142*0Sstevel@tonic-gate 			dfd = mfd;
143*0Sstevel@tonic-gate 		dfd = fcntl(fd, F_DUPFD, dfd);
144*0Sstevel@tonic-gate 		(void) close(fd);
145*0Sstevel@tonic-gate 		fd = dfd;
146*0Sstevel@tonic-gate 	}
147*0Sstevel@tonic-gate 	/*
148*0Sstevel@tonic-gate 	 * Mark it close-on-exec so any created process doesn't inherit it.
149*0Sstevel@tonic-gate 	 */
150*0Sstevel@tonic-gate 	if (fd >= 0)
151*0Sstevel@tonic-gate 		(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
152*0Sstevel@tonic-gate 	return (fd);
153*0Sstevel@tonic-gate }
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate /*
156*0Sstevel@tonic-gate  * Create a new controlled process.
157*0Sstevel@tonic-gate  * Leave it stopped on successful exit from exec() or execve().
158*0Sstevel@tonic-gate  * Return an opaque pointer to its process control structure.
159*0Sstevel@tonic-gate  * Return NULL if process cannot be created (fork()/exec() not successful).
160*0Sstevel@tonic-gate  */
161*0Sstevel@tonic-gate struct ps_prochandle *
162*0Sstevel@tonic-gate Pxcreate(const char *file,	/* executable file name */
163*0Sstevel@tonic-gate 	char *const *argv,	/* argument vector */
164*0Sstevel@tonic-gate 	char *const *envp,	/* environment */
165*0Sstevel@tonic-gate 	int *perr,	/* pointer to error return code */
166*0Sstevel@tonic-gate 	char *path,	/* if non-null, holds exec path name on return */
167*0Sstevel@tonic-gate 	size_t len)	/* size of the path buffer */
168*0Sstevel@tonic-gate {
169*0Sstevel@tonic-gate 	char execpath[PATH_MAX];
170*0Sstevel@tonic-gate 	char procname[100];
171*0Sstevel@tonic-gate 	struct ps_prochandle *P;
172*0Sstevel@tonic-gate 	pid_t pid;
173*0Sstevel@tonic-gate 	int fd;
174*0Sstevel@tonic-gate 	char *fname;
175*0Sstevel@tonic-gate 	int rc;
176*0Sstevel@tonic-gate 	int lasterrno = 0;
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate 	if (len == 0)	/* zero length, no path */
179*0Sstevel@tonic-gate 		path = NULL;
180*0Sstevel@tonic-gate 	if (path != NULL)
181*0Sstevel@tonic-gate 		*path = '\0';
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate 	if ((P = malloc(sizeof (struct ps_prochandle))) == NULL) {
184*0Sstevel@tonic-gate 		*perr = C_STRANGE;
185*0Sstevel@tonic-gate 		return (NULL);
186*0Sstevel@tonic-gate 	}
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 	if ((pid = fork1()) == -1) {
189*0Sstevel@tonic-gate 		free(P);
190*0Sstevel@tonic-gate 		*perr = C_FORK;
191*0Sstevel@tonic-gate 		return (NULL);
192*0Sstevel@tonic-gate 	}
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 	if (pid == 0) {			/* child process */
195*0Sstevel@tonic-gate 		id_t id;
196*0Sstevel@tonic-gate 		extern char **environ;
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate 		/*
199*0Sstevel@tonic-gate 		 * If running setuid or setgid, reset credentials to normal.
200*0Sstevel@tonic-gate 		 */
201*0Sstevel@tonic-gate 		if ((id = getgid()) != getegid())
202*0Sstevel@tonic-gate 			(void) setgid(id);
203*0Sstevel@tonic-gate 		if ((id = getuid()) != geteuid())
204*0Sstevel@tonic-gate 			(void) setuid(id);
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 		Pcreate_callback(P);	/* execute callback (see below) */
207*0Sstevel@tonic-gate 		(void) pause();		/* wait for PRSABORT from parent */
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 		/*
210*0Sstevel@tonic-gate 		 * This is ugly.  There is no execvep() function that takes a
211*0Sstevel@tonic-gate 		 * path and an environment.  We cheat here by replacing the
212*0Sstevel@tonic-gate 		 * global 'environ' variable right before we call this.
213*0Sstevel@tonic-gate 		 */
214*0Sstevel@tonic-gate 		if (envp)
215*0Sstevel@tonic-gate 			environ = (char **)envp;
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 		(void) execvp(file, argv);  /* execute the program */
218*0Sstevel@tonic-gate 		_exit(127);
219*0Sstevel@tonic-gate 	}
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	/*
222*0Sstevel@tonic-gate 	 * Initialize the process structure.
223*0Sstevel@tonic-gate 	 */
224*0Sstevel@tonic-gate 	(void) memset(P, 0, sizeof (*P));
225*0Sstevel@tonic-gate 	(void) mutex_init(&P->proc_lock, USYNC_THREAD, NULL);
226*0Sstevel@tonic-gate 	P->flags |= CREATED;
227*0Sstevel@tonic-gate 	P->state = PS_RUN;
228*0Sstevel@tonic-gate 	P->pid = pid;
229*0Sstevel@tonic-gate 	P->asfd = -1;
230*0Sstevel@tonic-gate 	P->ctlfd = -1;
231*0Sstevel@tonic-gate 	P->statfd = -1;
232*0Sstevel@tonic-gate 	P->agentctlfd = -1;
233*0Sstevel@tonic-gate 	P->agentstatfd = -1;
234*0Sstevel@tonic-gate 	P->ops = &P_live_ops;
235*0Sstevel@tonic-gate 	Pinitsym(P);
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate 	/*
238*0Sstevel@tonic-gate 	 * Open the /proc/pid files.
239*0Sstevel@tonic-gate 	 */
240*0Sstevel@tonic-gate 	(void) sprintf(procname, "/proc/%d/", (int)pid);
241*0Sstevel@tonic-gate 	fname = procname + strlen(procname);
242*0Sstevel@tonic-gate 	(void) set_minfd();
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate 	/*
245*0Sstevel@tonic-gate 	 * Exclusive write open advises others not to interfere.
246*0Sstevel@tonic-gate 	 * There is no reason for any of these open()s to fail.
247*0Sstevel@tonic-gate 	 */
248*0Sstevel@tonic-gate 	(void) strcpy(fname, "as");
249*0Sstevel@tonic-gate 	if ((fd = open(procname, (O_RDWR|O_EXCL))) < 0 ||
250*0Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
251*0Sstevel@tonic-gate 		dprintf("Pcreate: failed to open %s: %s\n",
252*0Sstevel@tonic-gate 		    procname, strerror(errno));
253*0Sstevel@tonic-gate 		rc = C_STRANGE;
254*0Sstevel@tonic-gate 		goto bad;
255*0Sstevel@tonic-gate 	}
256*0Sstevel@tonic-gate 	P->asfd = fd;
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 	(void) strcpy(fname, "status");
259*0Sstevel@tonic-gate 	if ((fd = open(procname, O_RDONLY)) < 0 ||
260*0Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
261*0Sstevel@tonic-gate 		dprintf("Pcreate: failed to open %s: %s\n",
262*0Sstevel@tonic-gate 		    procname, strerror(errno));
263*0Sstevel@tonic-gate 		rc = C_STRANGE;
264*0Sstevel@tonic-gate 		goto bad;
265*0Sstevel@tonic-gate 	}
266*0Sstevel@tonic-gate 	P->statfd = fd;
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate 	(void) strcpy(fname, "ctl");
269*0Sstevel@tonic-gate 	if ((fd = open(procname, O_WRONLY)) < 0 ||
270*0Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
271*0Sstevel@tonic-gate 		dprintf("Pcreate: failed to open %s: %s\n",
272*0Sstevel@tonic-gate 		    procname, strerror(errno));
273*0Sstevel@tonic-gate 		rc = C_STRANGE;
274*0Sstevel@tonic-gate 		goto bad;
275*0Sstevel@tonic-gate 	}
276*0Sstevel@tonic-gate 	P->ctlfd = fd;
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	(void) Pstop(P, 0);	/* stop the controlled process */
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate 	/*
281*0Sstevel@tonic-gate 	 * Wait for process to sleep in pause().
282*0Sstevel@tonic-gate 	 * If the process has already called pause(), then it should be
283*0Sstevel@tonic-gate 	 * stopped (PR_REQUESTED) while asleep in pause and we are done.
284*0Sstevel@tonic-gate 	 * Else we set up to catch entry/exit to pause() and set the process
285*0Sstevel@tonic-gate 	 * running again, expecting it to stop when it reaches pause().
286*0Sstevel@tonic-gate 	 * There is no reason for this to fail other than an interrupt.
287*0Sstevel@tonic-gate 	 */
288*0Sstevel@tonic-gate 	(void) Psysentry(P, SYS_pause, 1);
289*0Sstevel@tonic-gate 	(void) Psysexit(P, SYS_pause, 1);
290*0Sstevel@tonic-gate 	for (;;) {
291*0Sstevel@tonic-gate 		if (P->state == PS_STOP &&
292*0Sstevel@tonic-gate 		    P->status.pr_lwp.pr_syscall == SYS_pause &&
293*0Sstevel@tonic-gate 		    (P->status.pr_lwp.pr_why == PR_REQUESTED ||
294*0Sstevel@tonic-gate 		    P->status.pr_lwp.pr_why == PR_SYSENTRY ||
295*0Sstevel@tonic-gate 		    P->status.pr_lwp.pr_why == PR_SYSEXIT))
296*0Sstevel@tonic-gate 			break;
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 		if (P->state != PS_STOP ||	/* interrupt or process died */
299*0Sstevel@tonic-gate 		    Psetrun(P, 0, 0) != 0) {	/* can't restart */
300*0Sstevel@tonic-gate 			if (errno == EINTR || errno == ERESTART)
301*0Sstevel@tonic-gate 				rc = C_INTR;
302*0Sstevel@tonic-gate 			else {
303*0Sstevel@tonic-gate 				dprintf("Pcreate: Psetrun failed: %s\n",
304*0Sstevel@tonic-gate 				    strerror(errno));
305*0Sstevel@tonic-gate 				rc = C_STRANGE;
306*0Sstevel@tonic-gate 			}
307*0Sstevel@tonic-gate 			goto bad;
308*0Sstevel@tonic-gate 		}
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate 		(void) Pwait(P, 0);
311*0Sstevel@tonic-gate 	}
312*0Sstevel@tonic-gate 	(void) Psysentry(P, SYS_pause, 0);
313*0Sstevel@tonic-gate 	(void) Psysexit(P, SYS_pause, 0);
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate 	/*
316*0Sstevel@tonic-gate 	 * Kick the process off the pause() and catch
317*0Sstevel@tonic-gate 	 * it again on entry to exec() or exit().
318*0Sstevel@tonic-gate 	 */
319*0Sstevel@tonic-gate 	(void) Psysentry(P, SYS_exit, 1);
320*0Sstevel@tonic-gate 	(void) Psysentry(P, SYS_exec, 1);
321*0Sstevel@tonic-gate 	(void) Psysentry(P, SYS_execve, 1);
322*0Sstevel@tonic-gate 	if (Psetrun(P, 0, PRSABORT) == -1) {
323*0Sstevel@tonic-gate 		dprintf("Pcreate: Psetrun failed: %s\n", strerror(errno));
324*0Sstevel@tonic-gate 		rc = C_STRANGE;
325*0Sstevel@tonic-gate 		goto bad;
326*0Sstevel@tonic-gate 	}
327*0Sstevel@tonic-gate 	(void) Pwait(P, 0);
328*0Sstevel@tonic-gate 	if (P->state != PS_STOP) {
329*0Sstevel@tonic-gate 		dprintf("Pcreate: Pwait failed: %s\n", strerror(errno));
330*0Sstevel@tonic-gate 		rc = C_STRANGE;
331*0Sstevel@tonic-gate 		goto bad;
332*0Sstevel@tonic-gate 	}
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate 	/*
335*0Sstevel@tonic-gate 	 * Move the process through instances of failed exec()s
336*0Sstevel@tonic-gate 	 * to reach the point of stopped on successful exec().
337*0Sstevel@tonic-gate 	 */
338*0Sstevel@tonic-gate 	(void) Psysexit(P, SYS_exec, TRUE);
339*0Sstevel@tonic-gate 	(void) Psysexit(P, SYS_execve, TRUE);
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 	while (P->state == PS_STOP &&
342*0Sstevel@tonic-gate 	    P->status.pr_lwp.pr_why == PR_SYSENTRY &&
343*0Sstevel@tonic-gate 	    (P->status.pr_lwp.pr_what == SYS_execve ||
344*0Sstevel@tonic-gate 	    P->status.pr_lwp.pr_what == SYS_exec)) {
345*0Sstevel@tonic-gate 		/*
346*0Sstevel@tonic-gate 		 * Fetch the exec path name now, before we complete
347*0Sstevel@tonic-gate 		 * the exec().  We may lose the process and be unable
348*0Sstevel@tonic-gate 		 * to get the information later.
349*0Sstevel@tonic-gate 		 */
350*0Sstevel@tonic-gate 		(void) Pread_string(P, execpath, sizeof (execpath),
351*0Sstevel@tonic-gate 			(off_t)P->status.pr_lwp.pr_sysarg[0]);
352*0Sstevel@tonic-gate 		if (path != NULL)
353*0Sstevel@tonic-gate 			(void) strncpy(path, execpath, len);
354*0Sstevel@tonic-gate 		/*
355*0Sstevel@tonic-gate 		 * Set the process running and wait for
356*0Sstevel@tonic-gate 		 * it to stop on exit from the exec().
357*0Sstevel@tonic-gate 		 */
358*0Sstevel@tonic-gate 		(void) Psetrun(P, 0, 0);
359*0Sstevel@tonic-gate 		(void) Pwait(P, 0);
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate 		if (P->state == PS_LOST &&		/* we lost control */
362*0Sstevel@tonic-gate 		    Preopen(P) != 0) {		/* and we can't get it back */
363*0Sstevel@tonic-gate 			rc = C_PERM;
364*0Sstevel@tonic-gate 			goto bad;
365*0Sstevel@tonic-gate 		}
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 		/*
368*0Sstevel@tonic-gate 		 * If the exec() failed, continue the loop, expecting
369*0Sstevel@tonic-gate 		 * there to be more attempts to exec(), based on PATH.
370*0Sstevel@tonic-gate 		 */
371*0Sstevel@tonic-gate 		if (P->state == PS_STOP &&
372*0Sstevel@tonic-gate 		    P->status.pr_lwp.pr_why == PR_SYSEXIT &&
373*0Sstevel@tonic-gate 		    (P->status.pr_lwp.pr_what == SYS_execve ||
374*0Sstevel@tonic-gate 		    P->status.pr_lwp.pr_what == SYS_exec) &&
375*0Sstevel@tonic-gate 		    (lasterrno = P->status.pr_lwp.pr_errno) != 0) {
376*0Sstevel@tonic-gate 			/*
377*0Sstevel@tonic-gate 			 * The exec() failed.  Set the process running and
378*0Sstevel@tonic-gate 			 * wait for it to stop on entry to the next exec().
379*0Sstevel@tonic-gate 			 */
380*0Sstevel@tonic-gate 			(void) Psetrun(P, 0, 0);
381*0Sstevel@tonic-gate 			(void) Pwait(P, 0);
382*0Sstevel@tonic-gate 
383*0Sstevel@tonic-gate 			continue;
384*0Sstevel@tonic-gate 		}
385*0Sstevel@tonic-gate 		break;
386*0Sstevel@tonic-gate 	}
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 	if (P->state == PS_STOP &&
389*0Sstevel@tonic-gate 	    P->status.pr_lwp.pr_why == PR_SYSEXIT &&
390*0Sstevel@tonic-gate 	    (P->status.pr_lwp.pr_what == SYS_execve ||
391*0Sstevel@tonic-gate 	    P->status.pr_lwp.pr_what == SYS_exec) &&
392*0Sstevel@tonic-gate 	    P->status.pr_lwp.pr_errno == 0) {
393*0Sstevel@tonic-gate 		/*
394*0Sstevel@tonic-gate 		 * The process is stopped on successful exec() or execve().
395*0Sstevel@tonic-gate 		 * Turn off all tracing flags and return success.
396*0Sstevel@tonic-gate 		 */
397*0Sstevel@tonic-gate 		restore_tracing_flags(P);
398*0Sstevel@tonic-gate #ifndef _LP64
399*0Sstevel@tonic-gate 		/* We must be a 64-bit process to deal with a 64-bit process */
400*0Sstevel@tonic-gate 		if (P->status.pr_dmodel == PR_MODEL_LP64) {
401*0Sstevel@tonic-gate 			rc = C_LP64;
402*0Sstevel@tonic-gate 			goto bad;
403*0Sstevel@tonic-gate 		}
404*0Sstevel@tonic-gate #endif
405*0Sstevel@tonic-gate 		/*
406*0Sstevel@tonic-gate 		 * Set run-on-last-close so the controlled process
407*0Sstevel@tonic-gate 		 * runs even if we die on a signal.
408*0Sstevel@tonic-gate 		 */
409*0Sstevel@tonic-gate 		(void) Psetflags(P, PR_RLC);
410*0Sstevel@tonic-gate 		*perr = 0;
411*0Sstevel@tonic-gate 		return (P);
412*0Sstevel@tonic-gate 	}
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 	rc = lasterrno == ENOENT ? C_NOENT : C_NOEXEC;
415*0Sstevel@tonic-gate 
416*0Sstevel@tonic-gate bad:
417*0Sstevel@tonic-gate 	(void) kill(pid, SIGKILL);
418*0Sstevel@tonic-gate 	if (path != NULL && rc != C_PERM && rc != C_LP64)
419*0Sstevel@tonic-gate 		*path = '\0';
420*0Sstevel@tonic-gate 	Pfree(P);
421*0Sstevel@tonic-gate 	*perr = rc;
422*0Sstevel@tonic-gate 	return (NULL);
423*0Sstevel@tonic-gate }
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate struct ps_prochandle *
426*0Sstevel@tonic-gate Pcreate(
427*0Sstevel@tonic-gate 	const char *file,	/* executable file name */
428*0Sstevel@tonic-gate 	char *const *argv,	/* argument vector */
429*0Sstevel@tonic-gate 	int *perr,	/* pointer to error return code */
430*0Sstevel@tonic-gate 	char *path,	/* if non-null, holds exec path name on return */
431*0Sstevel@tonic-gate 	size_t len)	/* size of the path buffer */
432*0Sstevel@tonic-gate {
433*0Sstevel@tonic-gate 	return (Pxcreate(file, argv, NULL, perr, path, len));
434*0Sstevel@tonic-gate }
435*0Sstevel@tonic-gate 
436*0Sstevel@tonic-gate /*
437*0Sstevel@tonic-gate  * Return a printable string corresponding to a Pcreate() error return.
438*0Sstevel@tonic-gate  */
439*0Sstevel@tonic-gate const char *
440*0Sstevel@tonic-gate Pcreate_error(int error)
441*0Sstevel@tonic-gate {
442*0Sstevel@tonic-gate 	const char *str;
443*0Sstevel@tonic-gate 
444*0Sstevel@tonic-gate 	switch (error) {
445*0Sstevel@tonic-gate 	case C_FORK:
446*0Sstevel@tonic-gate 		str = "cannot fork";
447*0Sstevel@tonic-gate 		break;
448*0Sstevel@tonic-gate 	case C_PERM:
449*0Sstevel@tonic-gate 		str = "file is set-id or unreadable";
450*0Sstevel@tonic-gate 		break;
451*0Sstevel@tonic-gate 	case C_NOEXEC:
452*0Sstevel@tonic-gate 		str = "cannot execute file";
453*0Sstevel@tonic-gate 		break;
454*0Sstevel@tonic-gate 	case C_INTR:
455*0Sstevel@tonic-gate 		str = "operation interrupted";
456*0Sstevel@tonic-gate 		break;
457*0Sstevel@tonic-gate 	case C_LP64:
458*0Sstevel@tonic-gate 		str = "program is _LP64, self is not";
459*0Sstevel@tonic-gate 		break;
460*0Sstevel@tonic-gate 	case C_STRANGE:
461*0Sstevel@tonic-gate 		str = "unanticipated system error";
462*0Sstevel@tonic-gate 		break;
463*0Sstevel@tonic-gate 	case C_NOENT:
464*0Sstevel@tonic-gate 		str = "cannot find executable file";
465*0Sstevel@tonic-gate 		break;
466*0Sstevel@tonic-gate 	default:
467*0Sstevel@tonic-gate 		str = "unknown error";
468*0Sstevel@tonic-gate 		break;
469*0Sstevel@tonic-gate 	}
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate 	return (str);
472*0Sstevel@tonic-gate }
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate /*
475*0Sstevel@tonic-gate  * Callback to execute in each child process created with Pcreate() after fork
476*0Sstevel@tonic-gate  * but before it execs the new process image.  By default, we do nothing, but
477*0Sstevel@tonic-gate  * by calling this function we allow the client program to define its own
478*0Sstevel@tonic-gate  * version of the function which will interpose on our empty default.  This
479*0Sstevel@tonic-gate  * may be useful for clients that need to modify signal dispositions, terminal
480*0Sstevel@tonic-gate  * attributes, or process group and session properties for each new victim.
481*0Sstevel@tonic-gate  */
482*0Sstevel@tonic-gate /*ARGSUSED*/
483*0Sstevel@tonic-gate void
484*0Sstevel@tonic-gate Pcreate_callback(struct ps_prochandle *P)
485*0Sstevel@tonic-gate {
486*0Sstevel@tonic-gate 	/* nothing to do here */
487*0Sstevel@tonic-gate }
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate /*
490*0Sstevel@tonic-gate  * Grab an existing process.
491*0Sstevel@tonic-gate  * Return an opaque pointer to its process control structure.
492*0Sstevel@tonic-gate  *
493*0Sstevel@tonic-gate  * pid:		UNIX process ID.
494*0Sstevel@tonic-gate  * flags:
495*0Sstevel@tonic-gate  *	PGRAB_RETAIN	Retain tracing flags (default clears all tracing flags).
496*0Sstevel@tonic-gate  *	PGRAB_FORCE	Grab regardless of whether process is already traced.
497*0Sstevel@tonic-gate  *	PGRAB_RDONLY	Open the address space file O_RDONLY instead of O_RDWR,
498*0Sstevel@tonic-gate  *                      and do not open the process control file.
499*0Sstevel@tonic-gate  *	PGRAB_NOSTOP	Open the process but do not force it to stop.
500*0Sstevel@tonic-gate  * perr:	pointer to error return code.
501*0Sstevel@tonic-gate  */
502*0Sstevel@tonic-gate struct ps_prochandle *
503*0Sstevel@tonic-gate Pgrab(pid_t pid, int flags, int *perr)
504*0Sstevel@tonic-gate {
505*0Sstevel@tonic-gate 	struct ps_prochandle *P;
506*0Sstevel@tonic-gate 	int fd, omode;
507*0Sstevel@tonic-gate 	char procname[100];
508*0Sstevel@tonic-gate 	char *fname;
509*0Sstevel@tonic-gate 	int rc = 0;
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 	/*
512*0Sstevel@tonic-gate 	 * PGRAB_RDONLY means that we do not open the /proc/<pid>/control file,
513*0Sstevel@tonic-gate 	 * and so it implies RETAIN and NOSTOP since both require control.
514*0Sstevel@tonic-gate 	 */
515*0Sstevel@tonic-gate 	if (flags & PGRAB_RDONLY)
516*0Sstevel@tonic-gate 		flags |= PGRAB_RETAIN | PGRAB_NOSTOP;
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 	if ((P = malloc(sizeof (struct ps_prochandle))) == NULL) {
519*0Sstevel@tonic-gate 		*perr = G_STRANGE;
520*0Sstevel@tonic-gate 		return (NULL);
521*0Sstevel@tonic-gate 	}
522*0Sstevel@tonic-gate 
523*0Sstevel@tonic-gate 	P->asfd = -1;
524*0Sstevel@tonic-gate 	P->ctlfd = -1;
525*0Sstevel@tonic-gate 	P->statfd = -1;
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate again:	/* Come back here if we lose it in the Window of Vulnerability */
528*0Sstevel@tonic-gate 	if (P->ctlfd >= 0)
529*0Sstevel@tonic-gate 		(void) close(P->ctlfd);
530*0Sstevel@tonic-gate 	if (P->asfd >= 0)
531*0Sstevel@tonic-gate 		(void) close(P->asfd);
532*0Sstevel@tonic-gate 	if (P->statfd >= 0)
533*0Sstevel@tonic-gate 		(void) close(P->statfd);
534*0Sstevel@tonic-gate 	(void) memset(P, 0, sizeof (*P));
535*0Sstevel@tonic-gate 	(void) mutex_init(&P->proc_lock, USYNC_THREAD, NULL);
536*0Sstevel@tonic-gate 	P->ctlfd = -1;
537*0Sstevel@tonic-gate 	P->asfd = -1;
538*0Sstevel@tonic-gate 	P->statfd = -1;
539*0Sstevel@tonic-gate 	P->agentctlfd = -1;
540*0Sstevel@tonic-gate 	P->agentstatfd = -1;
541*0Sstevel@tonic-gate 	P->ops = &P_live_ops;
542*0Sstevel@tonic-gate 	Pinitsym(P);
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate 	/*
545*0Sstevel@tonic-gate 	 * Open the /proc/pid files
546*0Sstevel@tonic-gate 	 */
547*0Sstevel@tonic-gate 	(void) sprintf(procname, "/proc/%d/", (int)pid);
548*0Sstevel@tonic-gate 	fname = procname + strlen(procname);
549*0Sstevel@tonic-gate 	(void) set_minfd();
550*0Sstevel@tonic-gate 
551*0Sstevel@tonic-gate 	/*
552*0Sstevel@tonic-gate 	 * Request exclusive open to avoid grabbing someone else's
553*0Sstevel@tonic-gate 	 * process and to prevent others from interfering afterwards.
554*0Sstevel@tonic-gate 	 * If this fails and the 'PGRAB_FORCE' flag is set, attempt to
555*0Sstevel@tonic-gate 	 * open non-exclusively.
556*0Sstevel@tonic-gate 	 */
557*0Sstevel@tonic-gate 	(void) strcpy(fname, "as");
558*0Sstevel@tonic-gate 	omode = (flags & PGRAB_RDONLY) ? O_RDONLY : O_RDWR;
559*0Sstevel@tonic-gate 
560*0Sstevel@tonic-gate 	if (((fd = open(procname, omode | O_EXCL)) < 0 &&
561*0Sstevel@tonic-gate 	    (fd = ((flags & PGRAB_FORCE)? open(procname, omode) : -1)) < 0) ||
562*0Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
563*0Sstevel@tonic-gate 		switch (errno) {
564*0Sstevel@tonic-gate 		case ENOENT:
565*0Sstevel@tonic-gate 			rc = G_NOPROC;
566*0Sstevel@tonic-gate 			break;
567*0Sstevel@tonic-gate 		case EACCES:
568*0Sstevel@tonic-gate 		case EPERM:
569*0Sstevel@tonic-gate 			rc = G_PERM;
570*0Sstevel@tonic-gate 			break;
571*0Sstevel@tonic-gate 		case EBUSY:
572*0Sstevel@tonic-gate 			if (!(flags & PGRAB_FORCE) || geteuid() != 0) {
573*0Sstevel@tonic-gate 				rc = G_BUSY;
574*0Sstevel@tonic-gate 				break;
575*0Sstevel@tonic-gate 			}
576*0Sstevel@tonic-gate 			/* FALLTHROUGH */
577*0Sstevel@tonic-gate 		default:
578*0Sstevel@tonic-gate 			dprintf("Pgrab: failed to open %s: %s\n",
579*0Sstevel@tonic-gate 			    procname, strerror(errno));
580*0Sstevel@tonic-gate 			rc = G_STRANGE;
581*0Sstevel@tonic-gate 			break;
582*0Sstevel@tonic-gate 		}
583*0Sstevel@tonic-gate 		goto err;
584*0Sstevel@tonic-gate 	}
585*0Sstevel@tonic-gate 	P->asfd = fd;
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate 	(void) strcpy(fname, "status");
588*0Sstevel@tonic-gate 	if ((fd = open(procname, O_RDONLY)) < 0 ||
589*0Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
590*0Sstevel@tonic-gate 		switch (errno) {
591*0Sstevel@tonic-gate 		case ENOENT:
592*0Sstevel@tonic-gate 			rc = G_NOPROC;
593*0Sstevel@tonic-gate 			break;
594*0Sstevel@tonic-gate 		default:
595*0Sstevel@tonic-gate 			dprintf("Pgrab: failed to open %s: %s\n",
596*0Sstevel@tonic-gate 			    procname, strerror(errno));
597*0Sstevel@tonic-gate 			rc = G_STRANGE;
598*0Sstevel@tonic-gate 			break;
599*0Sstevel@tonic-gate 		}
600*0Sstevel@tonic-gate 		goto err;
601*0Sstevel@tonic-gate 	}
602*0Sstevel@tonic-gate 	P->statfd = fd;
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 	if (!(flags & PGRAB_RDONLY)) {
605*0Sstevel@tonic-gate 		(void) strcpy(fname, "ctl");
606*0Sstevel@tonic-gate 		if ((fd = open(procname, O_WRONLY)) < 0 ||
607*0Sstevel@tonic-gate 		    (fd = dupfd(fd, 0)) < 0) {
608*0Sstevel@tonic-gate 			switch (errno) {
609*0Sstevel@tonic-gate 			case ENOENT:
610*0Sstevel@tonic-gate 				rc = G_NOPROC;
611*0Sstevel@tonic-gate 				break;
612*0Sstevel@tonic-gate 			default:
613*0Sstevel@tonic-gate 				dprintf("Pgrab: failed to open %s: %s\n",
614*0Sstevel@tonic-gate 				    procname, strerror(errno));
615*0Sstevel@tonic-gate 				rc = G_STRANGE;
616*0Sstevel@tonic-gate 				break;
617*0Sstevel@tonic-gate 			}
618*0Sstevel@tonic-gate 			goto err;
619*0Sstevel@tonic-gate 		}
620*0Sstevel@tonic-gate 		P->ctlfd = fd;
621*0Sstevel@tonic-gate 	}
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate 	P->state = PS_RUN;
624*0Sstevel@tonic-gate 	P->pid = pid;
625*0Sstevel@tonic-gate 
626*0Sstevel@tonic-gate 	/*
627*0Sstevel@tonic-gate 	 * We are now in the Window of Vulnerability (WoV).  The process may
628*0Sstevel@tonic-gate 	 * exec() a setuid/setgid or unreadable object file between the open()
629*0Sstevel@tonic-gate 	 * and the PCSTOP.  We will get EAGAIN in this case and must start over.
630*0Sstevel@tonic-gate 	 * As Pstopstatus will trigger the first read() from a /proc file,
631*0Sstevel@tonic-gate 	 * we also need to handle EOVERFLOW here when 32-bit as an indicator
632*0Sstevel@tonic-gate 	 * that this process is 64-bit.  Finally, if the process has become
633*0Sstevel@tonic-gate 	 * a zombie (PS_UNDEAD) while we were trying to grab it, just remain
634*0Sstevel@tonic-gate 	 * silent about this and pretend there was no process.
635*0Sstevel@tonic-gate 	 */
636*0Sstevel@tonic-gate 	if (Pstopstatus(P, PCNULL, 0) != 0) {
637*0Sstevel@tonic-gate #ifndef _LP64
638*0Sstevel@tonic-gate 		if (errno == EOVERFLOW) {
639*0Sstevel@tonic-gate 			rc = G_LP64;
640*0Sstevel@tonic-gate 			goto err;
641*0Sstevel@tonic-gate 		}
642*0Sstevel@tonic-gate #endif
643*0Sstevel@tonic-gate 		if (P->state == PS_LOST) {	/* WoV */
644*0Sstevel@tonic-gate 			(void) mutex_destroy(&P->proc_lock);
645*0Sstevel@tonic-gate 			goto again;
646*0Sstevel@tonic-gate 		}
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate 		if (P->state == PS_UNDEAD)
649*0Sstevel@tonic-gate 			rc = G_NOPROC;
650*0Sstevel@tonic-gate 		else
651*0Sstevel@tonic-gate 			rc = G_STRANGE;
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 		goto err;
654*0Sstevel@tonic-gate 	}
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 	/*
657*0Sstevel@tonic-gate 	 * If the process is a system process, we can't control it even as root
658*0Sstevel@tonic-gate 	 */
659*0Sstevel@tonic-gate 	if (P->status.pr_flags & PR_ISSYS) {
660*0Sstevel@tonic-gate 		rc = G_SYS;
661*0Sstevel@tonic-gate 		goto err;
662*0Sstevel@tonic-gate 	}
663*0Sstevel@tonic-gate #ifndef _LP64
664*0Sstevel@tonic-gate 	/*
665*0Sstevel@tonic-gate 	 * We must be a 64-bit process to deal with a 64-bit process
666*0Sstevel@tonic-gate 	 */
667*0Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_LP64) {
668*0Sstevel@tonic-gate 		rc = G_LP64;
669*0Sstevel@tonic-gate 		goto err;
670*0Sstevel@tonic-gate 	}
671*0Sstevel@tonic-gate #endif
672*0Sstevel@tonic-gate 
673*0Sstevel@tonic-gate 	/*
674*0Sstevel@tonic-gate 	 * Remember the status for use by Prelease().
675*0Sstevel@tonic-gate 	 */
676*0Sstevel@tonic-gate 	P->orig_status = P->status;	/* structure copy */
677*0Sstevel@tonic-gate 
678*0Sstevel@tonic-gate 	/*
679*0Sstevel@tonic-gate 	 * Before stopping the process, make sure we are not grabbing ourselves.
680*0Sstevel@tonic-gate 	 * If we are, make sure we are doing it PGRAB_RDONLY.
681*0Sstevel@tonic-gate 	 */
682*0Sstevel@tonic-gate 	if (pid == getpid()) {
683*0Sstevel@tonic-gate 		/*
684*0Sstevel@tonic-gate 		 * Verify that the process is really ourself:
685*0Sstevel@tonic-gate 		 * Set a magic number, read it through the
686*0Sstevel@tonic-gate 		 * /proc file and see if the results match.
687*0Sstevel@tonic-gate 		 */
688*0Sstevel@tonic-gate 		uint32_t magic1 = 0;
689*0Sstevel@tonic-gate 		uint32_t magic2 = 2;
690*0Sstevel@tonic-gate 
691*0Sstevel@tonic-gate 		errno = 0;
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate 		if (Pread(P, &magic2, sizeof (magic2), (uintptr_t)&magic1)
694*0Sstevel@tonic-gate 		    == sizeof (magic2) &&
695*0Sstevel@tonic-gate 		    magic2 == 0 &&
696*0Sstevel@tonic-gate 		    (magic1 = 0xfeedbeef) &&
697*0Sstevel@tonic-gate 		    Pread(P, &magic2, sizeof (magic2), (uintptr_t)&magic1)
698*0Sstevel@tonic-gate 		    == sizeof (magic2) &&
699*0Sstevel@tonic-gate 		    magic2 == 0xfeedbeef &&
700*0Sstevel@tonic-gate 		    !(flags & PGRAB_RDONLY)) {
701*0Sstevel@tonic-gate 			rc = G_SELF;
702*0Sstevel@tonic-gate 			goto err;
703*0Sstevel@tonic-gate 		}
704*0Sstevel@tonic-gate 	}
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate 	/*
707*0Sstevel@tonic-gate 	 * If the process is already stopped or has been directed
708*0Sstevel@tonic-gate 	 * to stop via /proc, do not set run-on-last-close.
709*0Sstevel@tonic-gate 	 */
710*0Sstevel@tonic-gate 	if (!(P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)) &&
711*0Sstevel@tonic-gate 	    !(flags & PGRAB_RDONLY)) {
712*0Sstevel@tonic-gate 		/*
713*0Sstevel@tonic-gate 		 * Mark the process run-on-last-close so
714*0Sstevel@tonic-gate 		 * it runs even if we die from SIGKILL.
715*0Sstevel@tonic-gate 		 */
716*0Sstevel@tonic-gate 		if (Psetflags(P, PR_RLC) != 0) {
717*0Sstevel@tonic-gate 			if (errno == EAGAIN) {	/* WoV */
718*0Sstevel@tonic-gate 				(void) mutex_destroy(&P->proc_lock);
719*0Sstevel@tonic-gate 				goto again;
720*0Sstevel@tonic-gate 			}
721*0Sstevel@tonic-gate 			if (errno == ENOENT)	/* No complaint about zombies */
722*0Sstevel@tonic-gate 				rc = G_ZOMB;
723*0Sstevel@tonic-gate 			else {
724*0Sstevel@tonic-gate 				dprintf("Pgrab: failed to set RLC\n");
725*0Sstevel@tonic-gate 				rc = G_STRANGE;
726*0Sstevel@tonic-gate 			}
727*0Sstevel@tonic-gate 			goto err;
728*0Sstevel@tonic-gate 		}
729*0Sstevel@tonic-gate 	}
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate 	/*
732*0Sstevel@tonic-gate 	 * If a stop directive is pending and the process has not yet stopped,
733*0Sstevel@tonic-gate 	 * then synchronously wait for the stop directive to take effect.
734*0Sstevel@tonic-gate 	 * Limit the time spent waiting for the process to stop by iterating
735*0Sstevel@tonic-gate 	 * at most 10 times. The time-out of 20 ms corresponds to the time
736*0Sstevel@tonic-gate 	 * between sending the stop directive and the process actually stopped
737*0Sstevel@tonic-gate 	 * as measured by DTrace on a slow, busy system. If the process doesn't
738*0Sstevel@tonic-gate 	 * stop voluntarily, clear the PR_DSTOP flag so that the code below
739*0Sstevel@tonic-gate 	 * forces the process to stop.
740*0Sstevel@tonic-gate 	 */
741*0Sstevel@tonic-gate 	if (!(flags & PGRAB_RDONLY)) {
742*0Sstevel@tonic-gate 		int niter = 0;
743*0Sstevel@tonic-gate 		while ((P->status.pr_lwp.pr_flags & (PR_STOPPED|PR_DSTOP)) ==
744*0Sstevel@tonic-gate 		    PR_DSTOP && niter < 10 &&
745*0Sstevel@tonic-gate 		    Pstopstatus(P, PCTWSTOP, 20) != 0) {
746*0Sstevel@tonic-gate 			niter++;
747*0Sstevel@tonic-gate 			if (flags & PGRAB_NOSTOP)
748*0Sstevel@tonic-gate 				break;
749*0Sstevel@tonic-gate 		}
750*0Sstevel@tonic-gate 		if (niter == 10 && !(flags & PGRAB_NOSTOP)) {
751*0Sstevel@tonic-gate 			/* Try it harder down below */
752*0Sstevel@tonic-gate 			P->status.pr_lwp.pr_flags &= ~PR_DSTOP;
753*0Sstevel@tonic-gate 		}
754*0Sstevel@tonic-gate 	}
755*0Sstevel@tonic-gate 
756*0Sstevel@tonic-gate 	/*
757*0Sstevel@tonic-gate 	 * If the process is not already stopped or directed to stop
758*0Sstevel@tonic-gate 	 * and PGRAB_NOSTOP was not specified, stop the process now.
759*0Sstevel@tonic-gate 	 */
760*0Sstevel@tonic-gate 	if (!(P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)) &&
761*0Sstevel@tonic-gate 	    !(flags & PGRAB_NOSTOP)) {
762*0Sstevel@tonic-gate 		/*
763*0Sstevel@tonic-gate 		 * Stop the process, get its status and signal/syscall masks.
764*0Sstevel@tonic-gate 		 */
765*0Sstevel@tonic-gate 		if (((P->status.pr_lwp.pr_flags & PR_STOPPED) &&
766*0Sstevel@tonic-gate 		    Pstopstatus(P, PCDSTOP, 0) != 0) ||
767*0Sstevel@tonic-gate 		    Pstopstatus(P, PCSTOP, 2000) != 0) {
768*0Sstevel@tonic-gate #ifndef _LP64
769*0Sstevel@tonic-gate 			if (errno == EOVERFLOW) {
770*0Sstevel@tonic-gate 				rc = G_LP64;
771*0Sstevel@tonic-gate 				goto err;
772*0Sstevel@tonic-gate 			}
773*0Sstevel@tonic-gate #endif
774*0Sstevel@tonic-gate 			if (P->state == PS_LOST) {	/* WoV */
775*0Sstevel@tonic-gate 				(void) mutex_destroy(&P->proc_lock);
776*0Sstevel@tonic-gate 				goto again;
777*0Sstevel@tonic-gate 			}
778*0Sstevel@tonic-gate 			if ((errno != EINTR && errno != ERESTART) ||
779*0Sstevel@tonic-gate 			    (P->state != PS_STOP &&
780*0Sstevel@tonic-gate 			    !(P->status.pr_flags & PR_DSTOP))) {
781*0Sstevel@tonic-gate 				if (P->state != PS_RUN && errno != ENOENT) {
782*0Sstevel@tonic-gate 					dprintf("Pgrab: failed to PCSTOP\n");
783*0Sstevel@tonic-gate 					rc = G_STRANGE;
784*0Sstevel@tonic-gate 				} else {
785*0Sstevel@tonic-gate 					rc = G_ZOMB;
786*0Sstevel@tonic-gate 				}
787*0Sstevel@tonic-gate 				goto err;
788*0Sstevel@tonic-gate 			}
789*0Sstevel@tonic-gate 		}
790*0Sstevel@tonic-gate 
791*0Sstevel@tonic-gate 		/*
792*0Sstevel@tonic-gate 		 * Process should now either be stopped via /proc or there
793*0Sstevel@tonic-gate 		 * should be an outstanding stop directive.
794*0Sstevel@tonic-gate 		 */
795*0Sstevel@tonic-gate 		if (!(P->status.pr_flags & (PR_ISTOP|PR_DSTOP))) {
796*0Sstevel@tonic-gate 			dprintf("Pgrab: process is not stopped\n");
797*0Sstevel@tonic-gate 			rc = G_STRANGE;
798*0Sstevel@tonic-gate 			goto err;
799*0Sstevel@tonic-gate 		}
800*0Sstevel@tonic-gate #ifndef _LP64
801*0Sstevel@tonic-gate 		/*
802*0Sstevel@tonic-gate 		 * Test this again now because the 32-bit victim process may
803*0Sstevel@tonic-gate 		 * have exec'd a 64-bit process in the meantime.
804*0Sstevel@tonic-gate 		 */
805*0Sstevel@tonic-gate 		if (P->status.pr_dmodel == PR_MODEL_LP64) {
806*0Sstevel@tonic-gate 			rc = G_LP64;
807*0Sstevel@tonic-gate 			goto err;
808*0Sstevel@tonic-gate 		}
809*0Sstevel@tonic-gate #endif
810*0Sstevel@tonic-gate 	}
811*0Sstevel@tonic-gate 
812*0Sstevel@tonic-gate 	/*
813*0Sstevel@tonic-gate 	 * Cancel all tracing flags unless the PGRAB_RETAIN flag is set.
814*0Sstevel@tonic-gate 	 */
815*0Sstevel@tonic-gate 	if (!(flags & PGRAB_RETAIN)) {
816*0Sstevel@tonic-gate 		(void) Psysentry(P, 0, FALSE);
817*0Sstevel@tonic-gate 		(void) Psysexit(P, 0, FALSE);
818*0Sstevel@tonic-gate 		(void) Psignal(P, 0, FALSE);
819*0Sstevel@tonic-gate 		(void) Pfault(P, 0, FALSE);
820*0Sstevel@tonic-gate 		Psync(P);
821*0Sstevel@tonic-gate 	}
822*0Sstevel@tonic-gate 
823*0Sstevel@tonic-gate 	*perr = 0;
824*0Sstevel@tonic-gate 	return (P);
825*0Sstevel@tonic-gate 
826*0Sstevel@tonic-gate err:
827*0Sstevel@tonic-gate 	Pfree(P);
828*0Sstevel@tonic-gate 	*perr = rc;
829*0Sstevel@tonic-gate 	return (NULL);
830*0Sstevel@tonic-gate }
831*0Sstevel@tonic-gate 
832*0Sstevel@tonic-gate /*
833*0Sstevel@tonic-gate  * Return a printable string corresponding to a Pgrab() error return.
834*0Sstevel@tonic-gate  */
835*0Sstevel@tonic-gate const char *
836*0Sstevel@tonic-gate Pgrab_error(int error)
837*0Sstevel@tonic-gate {
838*0Sstevel@tonic-gate 	const char *str;
839*0Sstevel@tonic-gate 
840*0Sstevel@tonic-gate 	switch (error) {
841*0Sstevel@tonic-gate 	case G_NOPROC:
842*0Sstevel@tonic-gate 		str = "no such process";
843*0Sstevel@tonic-gate 		break;
844*0Sstevel@tonic-gate 	case G_NOCORE:
845*0Sstevel@tonic-gate 		str = "no such core file";
846*0Sstevel@tonic-gate 		break;
847*0Sstevel@tonic-gate 	case G_NOPROCORCORE:
848*0Sstevel@tonic-gate 		str = "no such process or core file";
849*0Sstevel@tonic-gate 		break;
850*0Sstevel@tonic-gate 	case G_NOEXEC:
851*0Sstevel@tonic-gate 		str = "cannot find executable file";
852*0Sstevel@tonic-gate 		break;
853*0Sstevel@tonic-gate 	case G_ZOMB:
854*0Sstevel@tonic-gate 		str = "zombie process";
855*0Sstevel@tonic-gate 		break;
856*0Sstevel@tonic-gate 	case G_PERM:
857*0Sstevel@tonic-gate 		str = "permission denied";
858*0Sstevel@tonic-gate 		break;
859*0Sstevel@tonic-gate 	case G_BUSY:
860*0Sstevel@tonic-gate 		str = "process is traced";
861*0Sstevel@tonic-gate 		break;
862*0Sstevel@tonic-gate 	case G_SYS:
863*0Sstevel@tonic-gate 		str = "system process";
864*0Sstevel@tonic-gate 		break;
865*0Sstevel@tonic-gate 	case G_SELF:
866*0Sstevel@tonic-gate 		str = "attempt to grab self";
867*0Sstevel@tonic-gate 		break;
868*0Sstevel@tonic-gate 	case G_INTR:
869*0Sstevel@tonic-gate 		str = "operation interrupted";
870*0Sstevel@tonic-gate 		break;
871*0Sstevel@tonic-gate 	case G_LP64:
872*0Sstevel@tonic-gate 		str = "program is _LP64, self is not";
873*0Sstevel@tonic-gate 		break;
874*0Sstevel@tonic-gate 	case G_FORMAT:
875*0Sstevel@tonic-gate 		str = "file is not an ELF core file";
876*0Sstevel@tonic-gate 		break;
877*0Sstevel@tonic-gate 	case G_ELF:
878*0Sstevel@tonic-gate 		str = "libelf error";
879*0Sstevel@tonic-gate 		break;
880*0Sstevel@tonic-gate 	case G_NOTE:
881*0Sstevel@tonic-gate 		str = "core file is corrupt or missing required data";
882*0Sstevel@tonic-gate 		break;
883*0Sstevel@tonic-gate 	case G_STRANGE:
884*0Sstevel@tonic-gate 		str = "unanticipated system error";
885*0Sstevel@tonic-gate 		break;
886*0Sstevel@tonic-gate 	case G_ISAINVAL:
887*0Sstevel@tonic-gate 		str = "wrong ELF machine type";
888*0Sstevel@tonic-gate 		break;
889*0Sstevel@tonic-gate 	case G_BADLWPS:
890*0Sstevel@tonic-gate 		str = "bad lwp specification";
891*0Sstevel@tonic-gate 		break;
892*0Sstevel@tonic-gate 	default:
893*0Sstevel@tonic-gate 		str = "unknown error";
894*0Sstevel@tonic-gate 		break;
895*0Sstevel@tonic-gate 	}
896*0Sstevel@tonic-gate 
897*0Sstevel@tonic-gate 	return (str);
898*0Sstevel@tonic-gate }
899*0Sstevel@tonic-gate 
900*0Sstevel@tonic-gate /*
901*0Sstevel@tonic-gate  * Free a process control structure.
902*0Sstevel@tonic-gate  * Close the file descriptors but don't do the Prelease logic.
903*0Sstevel@tonic-gate  */
904*0Sstevel@tonic-gate void
905*0Sstevel@tonic-gate Pfree(struct ps_prochandle *P)
906*0Sstevel@tonic-gate {
907*0Sstevel@tonic-gate 	uint_t i;
908*0Sstevel@tonic-gate 
909*0Sstevel@tonic-gate 	if (P->core != NULL) {
910*0Sstevel@tonic-gate 		extern void __priv_free_info(void *);
911*0Sstevel@tonic-gate 		lwp_info_t *nlwp, *lwp = list_next(&P->core->core_lwp_head);
912*0Sstevel@tonic-gate 
913*0Sstevel@tonic-gate 		for (i = 0; i < P->core->core_nlwp; i++, lwp = nlwp) {
914*0Sstevel@tonic-gate 			nlwp = list_next(lwp);
915*0Sstevel@tonic-gate #ifdef __sparc
916*0Sstevel@tonic-gate 			if (lwp->lwp_gwins != NULL)
917*0Sstevel@tonic-gate 				free(lwp->lwp_gwins);
918*0Sstevel@tonic-gate 			if (lwp->lwp_xregs != NULL)
919*0Sstevel@tonic-gate 				free(lwp->lwp_xregs);
920*0Sstevel@tonic-gate 			if (lwp->lwp_asrs != NULL)
921*0Sstevel@tonic-gate 				free(lwp->lwp_asrs);
922*0Sstevel@tonic-gate #endif
923*0Sstevel@tonic-gate 			free(lwp);
924*0Sstevel@tonic-gate 		}
925*0Sstevel@tonic-gate 
926*0Sstevel@tonic-gate 		if (P->core->core_platform != NULL)
927*0Sstevel@tonic-gate 			free(P->core->core_platform);
928*0Sstevel@tonic-gate 		if (P->core->core_uts != NULL)
929*0Sstevel@tonic-gate 			free(P->core->core_uts);
930*0Sstevel@tonic-gate 		if (P->core->core_cred != NULL)
931*0Sstevel@tonic-gate 			free(P->core->core_cred);
932*0Sstevel@tonic-gate 		if (P->core->core_priv != NULL)
933*0Sstevel@tonic-gate 			free(P->core->core_priv);
934*0Sstevel@tonic-gate 		if (P->core->core_privinfo != NULL)
935*0Sstevel@tonic-gate 			__priv_free_info(P->core->core_privinfo);
936*0Sstevel@tonic-gate 		if (P->core->core_ppii != NULL)
937*0Sstevel@tonic-gate 			free(P->core->core_ppii);
938*0Sstevel@tonic-gate 		if (P->core->core_zonename != NULL)
939*0Sstevel@tonic-gate 			free(P->core->core_zonename);
940*0Sstevel@tonic-gate #if defined(__i386) || defined(__amd64)
941*0Sstevel@tonic-gate 		if (P->core->core_ldt != NULL)
942*0Sstevel@tonic-gate 			free(P->core->core_ldt);
943*0Sstevel@tonic-gate #endif
944*0Sstevel@tonic-gate 
945*0Sstevel@tonic-gate 		free(P->core);
946*0Sstevel@tonic-gate 	}
947*0Sstevel@tonic-gate 
948*0Sstevel@tonic-gate 	if (P->ucaddrs != NULL) {
949*0Sstevel@tonic-gate 		free(P->ucaddrs);
950*0Sstevel@tonic-gate 		P->ucaddrs = NULL;
951*0Sstevel@tonic-gate 		P->ucnelems = 0;
952*0Sstevel@tonic-gate 	}
953*0Sstevel@tonic-gate 
954*0Sstevel@tonic-gate 	(void) mutex_lock(&P->proc_lock);
955*0Sstevel@tonic-gate 	if (P->hashtab != NULL) {
956*0Sstevel@tonic-gate 		struct ps_lwphandle *L;
957*0Sstevel@tonic-gate 		for (i = 0; i < HASHSIZE; i++) {
958*0Sstevel@tonic-gate 			while ((L = P->hashtab[i]) != NULL)
959*0Sstevel@tonic-gate 				Lfree_internal(P, L);
960*0Sstevel@tonic-gate 		}
961*0Sstevel@tonic-gate 		free(P->hashtab);
962*0Sstevel@tonic-gate 	}
963*0Sstevel@tonic-gate 	(void) mutex_unlock(&P->proc_lock);
964*0Sstevel@tonic-gate 	(void) mutex_destroy(&P->proc_lock);
965*0Sstevel@tonic-gate 
966*0Sstevel@tonic-gate 	if (P->agentctlfd >= 0)
967*0Sstevel@tonic-gate 		(void) close(P->agentctlfd);
968*0Sstevel@tonic-gate 	if (P->agentstatfd >= 0)
969*0Sstevel@tonic-gate 		(void) close(P->agentstatfd);
970*0Sstevel@tonic-gate 	if (P->ctlfd >= 0)
971*0Sstevel@tonic-gate 		(void) close(P->ctlfd);
972*0Sstevel@tonic-gate 	if (P->asfd >= 0)
973*0Sstevel@tonic-gate 		(void) close(P->asfd);
974*0Sstevel@tonic-gate 	if (P->statfd >= 0)
975*0Sstevel@tonic-gate 		(void) close(P->statfd);
976*0Sstevel@tonic-gate 	Preset_maps(P);
977*0Sstevel@tonic-gate 
978*0Sstevel@tonic-gate 	/* clear out the structure as a precaution against reuse */
979*0Sstevel@tonic-gate 	(void) memset(P, 0, sizeof (*P));
980*0Sstevel@tonic-gate 	P->ctlfd = -1;
981*0Sstevel@tonic-gate 	P->asfd = -1;
982*0Sstevel@tonic-gate 	P->statfd = -1;
983*0Sstevel@tonic-gate 	P->agentctlfd = -1;
984*0Sstevel@tonic-gate 	P->agentstatfd = -1;
985*0Sstevel@tonic-gate 
986*0Sstevel@tonic-gate 	free(P);
987*0Sstevel@tonic-gate }
988*0Sstevel@tonic-gate 
989*0Sstevel@tonic-gate /*
990*0Sstevel@tonic-gate  * Return the state of the process, one of the PS_* values.
991*0Sstevel@tonic-gate  */
992*0Sstevel@tonic-gate int
993*0Sstevel@tonic-gate Pstate(struct ps_prochandle *P)
994*0Sstevel@tonic-gate {
995*0Sstevel@tonic-gate 	return (P->state);
996*0Sstevel@tonic-gate }
997*0Sstevel@tonic-gate 
998*0Sstevel@tonic-gate /*
999*0Sstevel@tonic-gate  * Return the open address space file descriptor for the process.
1000*0Sstevel@tonic-gate  * Clients must not close this file descriptor, not use it
1001*0Sstevel@tonic-gate  * after the process is freed.
1002*0Sstevel@tonic-gate  */
1003*0Sstevel@tonic-gate int
1004*0Sstevel@tonic-gate Pasfd(struct ps_prochandle *P)
1005*0Sstevel@tonic-gate {
1006*0Sstevel@tonic-gate 	return (P->asfd);
1007*0Sstevel@tonic-gate }
1008*0Sstevel@tonic-gate 
1009*0Sstevel@tonic-gate /*
1010*0Sstevel@tonic-gate  * Return the open control file descriptor for the process.
1011*0Sstevel@tonic-gate  * Clients must not close this file descriptor, not use it
1012*0Sstevel@tonic-gate  * after the process is freed.
1013*0Sstevel@tonic-gate  */
1014*0Sstevel@tonic-gate int
1015*0Sstevel@tonic-gate Pctlfd(struct ps_prochandle *P)
1016*0Sstevel@tonic-gate {
1017*0Sstevel@tonic-gate 	return (P->ctlfd);
1018*0Sstevel@tonic-gate }
1019*0Sstevel@tonic-gate 
1020*0Sstevel@tonic-gate /*
1021*0Sstevel@tonic-gate  * Return a pointer to the process psinfo structure.
1022*0Sstevel@tonic-gate  * Clients should not hold on to this pointer indefinitely.
1023*0Sstevel@tonic-gate  * It will become invalid on Prelease().
1024*0Sstevel@tonic-gate  */
1025*0Sstevel@tonic-gate const psinfo_t *
1026*0Sstevel@tonic-gate Ppsinfo(struct ps_prochandle *P)
1027*0Sstevel@tonic-gate {
1028*0Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
1029*0Sstevel@tonic-gate 		errno = ENODATA;
1030*0Sstevel@tonic-gate 		return (NULL);
1031*0Sstevel@tonic-gate 	}
1032*0Sstevel@tonic-gate 
1033*0Sstevel@tonic-gate 	if (P->state != PS_DEAD && proc_get_psinfo(P->pid, &P->psinfo) == -1)
1034*0Sstevel@tonic-gate 		return (NULL);
1035*0Sstevel@tonic-gate 
1036*0Sstevel@tonic-gate 	return (&P->psinfo);
1037*0Sstevel@tonic-gate }
1038*0Sstevel@tonic-gate 
1039*0Sstevel@tonic-gate /*
1040*0Sstevel@tonic-gate  * Return a pointer to the process status structure.
1041*0Sstevel@tonic-gate  * Clients should not hold on to this pointer indefinitely.
1042*0Sstevel@tonic-gate  * It will become invalid on Prelease().
1043*0Sstevel@tonic-gate  */
1044*0Sstevel@tonic-gate const pstatus_t *
1045*0Sstevel@tonic-gate Pstatus(struct ps_prochandle *P)
1046*0Sstevel@tonic-gate {
1047*0Sstevel@tonic-gate 	return (&P->status);
1048*0Sstevel@tonic-gate }
1049*0Sstevel@tonic-gate 
1050*0Sstevel@tonic-gate /*
1051*0Sstevel@tonic-gate  * Fill in a pointer to a process credentials structure.  The ngroups parameter
1052*0Sstevel@tonic-gate  * is the number of supplementary group entries allocated in the caller's cred
1053*0Sstevel@tonic-gate  * structure.  It should equal zero or one unless extra space has been
1054*0Sstevel@tonic-gate  * allocated for the group list by the caller.
1055*0Sstevel@tonic-gate  */
1056*0Sstevel@tonic-gate int
1057*0Sstevel@tonic-gate Pcred(struct ps_prochandle *P, prcred_t *pcrp, int ngroups)
1058*0Sstevel@tonic-gate {
1059*0Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
1060*0Sstevel@tonic-gate 		errno = ENODATA;
1061*0Sstevel@tonic-gate 		return (-1);
1062*0Sstevel@tonic-gate 	}
1063*0Sstevel@tonic-gate 
1064*0Sstevel@tonic-gate 	if (P->state != PS_DEAD)
1065*0Sstevel@tonic-gate 		return (proc_get_cred(P->pid, pcrp, ngroups));
1066*0Sstevel@tonic-gate 
1067*0Sstevel@tonic-gate 	if (P->core->core_cred != NULL) {
1068*0Sstevel@tonic-gate 		/*
1069*0Sstevel@tonic-gate 		 * Avoid returning more supplementary group data than the
1070*0Sstevel@tonic-gate 		 * caller has allocated in their buffer.  We expect them to
1071*0Sstevel@tonic-gate 		 * check pr_ngroups afterward and potentially call us again.
1072*0Sstevel@tonic-gate 		 */
1073*0Sstevel@tonic-gate 		ngroups = MIN(ngroups, P->core->core_cred->pr_ngroups);
1074*0Sstevel@tonic-gate 
1075*0Sstevel@tonic-gate 		(void) memcpy(pcrp, P->core->core_cred,
1076*0Sstevel@tonic-gate 		    sizeof (prcred_t) + (ngroups - 1) * sizeof (gid_t));
1077*0Sstevel@tonic-gate 
1078*0Sstevel@tonic-gate 		return (0);
1079*0Sstevel@tonic-gate 	}
1080*0Sstevel@tonic-gate 
1081*0Sstevel@tonic-gate 	errno = ENODATA;
1082*0Sstevel@tonic-gate 	return (-1);
1083*0Sstevel@tonic-gate }
1084*0Sstevel@tonic-gate 
1085*0Sstevel@tonic-gate #if defined(__i386) || defined(__amd64)
1086*0Sstevel@tonic-gate /*
1087*0Sstevel@tonic-gate  * Fill in a pointer to a process LDT structure.
1088*0Sstevel@tonic-gate  * The caller provides a buffer of size 'nldt * sizeof (struct ssd)';
1089*0Sstevel@tonic-gate  * If pldt == NULL or nldt == 0, we return the number of existing LDT entries.
1090*0Sstevel@tonic-gate  * Otherwise we return the actual number of LDT entries fetched (<= nldt).
1091*0Sstevel@tonic-gate  */
1092*0Sstevel@tonic-gate int
1093*0Sstevel@tonic-gate Pldt(struct ps_prochandle *P, struct ssd *pldt, int nldt)
1094*0Sstevel@tonic-gate {
1095*0Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
1096*0Sstevel@tonic-gate 		errno = ENODATA;
1097*0Sstevel@tonic-gate 		return (-1);
1098*0Sstevel@tonic-gate 	}
1099*0Sstevel@tonic-gate 
1100*0Sstevel@tonic-gate 	if (P->state != PS_DEAD)
1101*0Sstevel@tonic-gate 		return (proc_get_ldt(P->pid, pldt, nldt));
1102*0Sstevel@tonic-gate 
1103*0Sstevel@tonic-gate 	if (pldt == NULL || nldt == 0)
1104*0Sstevel@tonic-gate 		return (P->core->core_nldt);
1105*0Sstevel@tonic-gate 
1106*0Sstevel@tonic-gate 	if (P->core->core_ldt != NULL) {
1107*0Sstevel@tonic-gate 		nldt = MIN(nldt, P->core->core_nldt);
1108*0Sstevel@tonic-gate 
1109*0Sstevel@tonic-gate 		(void) memcpy(pldt, P->core->core_ldt,
1110*0Sstevel@tonic-gate 		    nldt * sizeof (struct ssd));
1111*0Sstevel@tonic-gate 
1112*0Sstevel@tonic-gate 		return (nldt);
1113*0Sstevel@tonic-gate 	}
1114*0Sstevel@tonic-gate 
1115*0Sstevel@tonic-gate 	errno = ENODATA;
1116*0Sstevel@tonic-gate 	return (-1);
1117*0Sstevel@tonic-gate }
1118*0Sstevel@tonic-gate #endif	/* __i386 */
1119*0Sstevel@tonic-gate 
1120*0Sstevel@tonic-gate /*
1121*0Sstevel@tonic-gate  * Fill in a pointer to a process privilege structure.
1122*0Sstevel@tonic-gate  */
1123*0Sstevel@tonic-gate ssize_t
1124*0Sstevel@tonic-gate Ppriv(struct ps_prochandle *P, prpriv_t *pprv, size_t size)
1125*0Sstevel@tonic-gate {
1126*0Sstevel@tonic-gate 	if (P->state != PS_DEAD) {
1127*0Sstevel@tonic-gate 		prpriv_t *pp = proc_get_priv(P->pid);
1128*0Sstevel@tonic-gate 		if (pp != NULL) {
1129*0Sstevel@tonic-gate 			size = MIN(size, PRIV_PRPRIV_SIZE(pp));
1130*0Sstevel@tonic-gate 			(void) memcpy(pprv, pp, size);
1131*0Sstevel@tonic-gate 			free(pp);
1132*0Sstevel@tonic-gate 			return (size);
1133*0Sstevel@tonic-gate 		}
1134*0Sstevel@tonic-gate 		return (-1);
1135*0Sstevel@tonic-gate 	}
1136*0Sstevel@tonic-gate 
1137*0Sstevel@tonic-gate 	if (P->core->core_priv != NULL) {
1138*0Sstevel@tonic-gate 		size = MIN(P->core->core_priv_size, size);
1139*0Sstevel@tonic-gate 		(void) memcpy(pprv, P->core->core_priv, size);
1140*0Sstevel@tonic-gate 		return (size);
1141*0Sstevel@tonic-gate 	}
1142*0Sstevel@tonic-gate 	errno = ENODATA;
1143*0Sstevel@tonic-gate 	return (-1);
1144*0Sstevel@tonic-gate }
1145*0Sstevel@tonic-gate 
1146*0Sstevel@tonic-gate int
1147*0Sstevel@tonic-gate Psetpriv(struct ps_prochandle *P, prpriv_t *pprv)
1148*0Sstevel@tonic-gate {
1149*0Sstevel@tonic-gate 	int rc;
1150*0Sstevel@tonic-gate 	long *ctl;
1151*0Sstevel@tonic-gate 	size_t sz;
1152*0Sstevel@tonic-gate 
1153*0Sstevel@tonic-gate 	if (P->state == PS_DEAD) {
1154*0Sstevel@tonic-gate 		errno = EBADF;
1155*0Sstevel@tonic-gate 		return (-1);
1156*0Sstevel@tonic-gate 	}
1157*0Sstevel@tonic-gate 
1158*0Sstevel@tonic-gate 	sz = PRIV_PRPRIV_SIZE(pprv) + sizeof (long);
1159*0Sstevel@tonic-gate 
1160*0Sstevel@tonic-gate 	sz = ((sz - 1) / sizeof (long) + 1) * sizeof (long);
1161*0Sstevel@tonic-gate 
1162*0Sstevel@tonic-gate 	ctl = malloc(sz);
1163*0Sstevel@tonic-gate 	if (ctl == NULL)
1164*0Sstevel@tonic-gate 		return (-1);
1165*0Sstevel@tonic-gate 
1166*0Sstevel@tonic-gate 	ctl[0] = PCSPRIV;
1167*0Sstevel@tonic-gate 
1168*0Sstevel@tonic-gate 	(void) memcpy(&ctl[1], pprv, PRIV_PRPRIV_SIZE(pprv));
1169*0Sstevel@tonic-gate 
1170*0Sstevel@tonic-gate 	if (write(P->ctlfd, ctl, sz) != sz)
1171*0Sstevel@tonic-gate 		rc = -1;
1172*0Sstevel@tonic-gate 	else
1173*0Sstevel@tonic-gate 		rc = 0;
1174*0Sstevel@tonic-gate 
1175*0Sstevel@tonic-gate 	free(ctl);
1176*0Sstevel@tonic-gate 
1177*0Sstevel@tonic-gate 	return (rc);
1178*0Sstevel@tonic-gate }
1179*0Sstevel@tonic-gate 
1180*0Sstevel@tonic-gate void *
1181*0Sstevel@tonic-gate Pprivinfo(struct ps_prochandle *P)
1182*0Sstevel@tonic-gate {
1183*0Sstevel@tonic-gate 	/* Use default from libc */
1184*0Sstevel@tonic-gate 	if (P->state != PS_DEAD)
1185*0Sstevel@tonic-gate 		return (NULL);
1186*0Sstevel@tonic-gate 
1187*0Sstevel@tonic-gate 	return (P->core->core_privinfo);
1188*0Sstevel@tonic-gate }
1189*0Sstevel@tonic-gate 
1190*0Sstevel@tonic-gate /*
1191*0Sstevel@tonic-gate  * Ensure that all cached state is written to the process.
1192*0Sstevel@tonic-gate  * The cached state is the LWP's signal mask and registers
1193*0Sstevel@tonic-gate  * and the process's tracing flags.
1194*0Sstevel@tonic-gate  */
1195*0Sstevel@tonic-gate void
1196*0Sstevel@tonic-gate Psync(struct ps_prochandle *P)
1197*0Sstevel@tonic-gate {
1198*0Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
1199*0Sstevel@tonic-gate 	long cmd[6];
1200*0Sstevel@tonic-gate 	iovec_t iov[12];
1201*0Sstevel@tonic-gate 	int n = 0;
1202*0Sstevel@tonic-gate 
1203*0Sstevel@tonic-gate 	if (P->flags & SETHOLD) {
1204*0Sstevel@tonic-gate 		cmd[0] = PCSHOLD;
1205*0Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[0];
1206*0Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
1207*0Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&P->status.pr_lwp.pr_lwphold;
1208*0Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (P->status.pr_lwp.pr_lwphold);
1209*0Sstevel@tonic-gate 	}
1210*0Sstevel@tonic-gate 	if (P->flags & SETREGS) {
1211*0Sstevel@tonic-gate 		cmd[1] = PCSREG;
1212*0Sstevel@tonic-gate #ifdef __i386
1213*0Sstevel@tonic-gate 		/* XX64 we should probably restore REG_GS after this */
1214*0Sstevel@tonic-gate 		if (ctlfd == P->agentctlfd)
1215*0Sstevel@tonic-gate 			P->status.pr_lwp.pr_reg[GS] = 0;
1216*0Sstevel@tonic-gate #elif defined(__amd64)
1217*0Sstevel@tonic-gate 		/* XX64 */
1218*0Sstevel@tonic-gate #endif
1219*0Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[1];
1220*0Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
1221*0Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&P->status.pr_lwp.pr_reg[0];
1222*0Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (P->status.pr_lwp.pr_reg);
1223*0Sstevel@tonic-gate 	}
1224*0Sstevel@tonic-gate 	if (P->flags & SETSIG) {
1225*0Sstevel@tonic-gate 		cmd[2] = PCSTRACE;
1226*0Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[2];
1227*0Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
1228*0Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&P->status.pr_sigtrace;
1229*0Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (P->status.pr_sigtrace);
1230*0Sstevel@tonic-gate 	}
1231*0Sstevel@tonic-gate 	if (P->flags & SETFAULT) {
1232*0Sstevel@tonic-gate 		cmd[3] = PCSFAULT;
1233*0Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[3];
1234*0Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
1235*0Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&P->status.pr_flttrace;
1236*0Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (P->status.pr_flttrace);
1237*0Sstevel@tonic-gate 	}
1238*0Sstevel@tonic-gate 	if (P->flags & SETENTRY) {
1239*0Sstevel@tonic-gate 		cmd[4] = PCSENTRY;
1240*0Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[4];
1241*0Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
1242*0Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&P->status.pr_sysentry;
1243*0Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (P->status.pr_sysentry);
1244*0Sstevel@tonic-gate 	}
1245*0Sstevel@tonic-gate 	if (P->flags & SETEXIT) {
1246*0Sstevel@tonic-gate 		cmd[5] = PCSEXIT;
1247*0Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[5];
1248*0Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
1249*0Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&P->status.pr_sysexit;
1250*0Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (P->status.pr_sysexit);
1251*0Sstevel@tonic-gate 	}
1252*0Sstevel@tonic-gate 
1253*0Sstevel@tonic-gate 	if (n == 0 || writev(ctlfd, iov, n) < 0)
1254*0Sstevel@tonic-gate 		return;		/* nothing to do or write failed */
1255*0Sstevel@tonic-gate 
1256*0Sstevel@tonic-gate 	P->flags &= ~(SETSIG|SETFAULT|SETENTRY|SETEXIT|SETHOLD|SETREGS);
1257*0Sstevel@tonic-gate }
1258*0Sstevel@tonic-gate 
1259*0Sstevel@tonic-gate /*
1260*0Sstevel@tonic-gate  * Reopen the /proc file (after PS_LOST).
1261*0Sstevel@tonic-gate  */
1262*0Sstevel@tonic-gate int
1263*0Sstevel@tonic-gate Preopen(struct ps_prochandle *P)
1264*0Sstevel@tonic-gate {
1265*0Sstevel@tonic-gate 	int fd;
1266*0Sstevel@tonic-gate 	char procname[100];
1267*0Sstevel@tonic-gate 	char *fname;
1268*0Sstevel@tonic-gate 
1269*0Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_IDLE)
1270*0Sstevel@tonic-gate 		return (0);
1271*0Sstevel@tonic-gate 
1272*0Sstevel@tonic-gate 	if (P->agentcnt > 0) {
1273*0Sstevel@tonic-gate 		P->agentcnt = 1;
1274*0Sstevel@tonic-gate 		Pdestroy_agent(P);
1275*0Sstevel@tonic-gate 	}
1276*0Sstevel@tonic-gate 
1277*0Sstevel@tonic-gate 	(void) sprintf(procname, "/proc/%d/", (int)P->pid);
1278*0Sstevel@tonic-gate 	fname = procname + strlen(procname);
1279*0Sstevel@tonic-gate 
1280*0Sstevel@tonic-gate 	(void) strcpy(fname, "as");
1281*0Sstevel@tonic-gate 	if ((fd = open(procname, O_RDWR)) < 0 ||
1282*0Sstevel@tonic-gate 	    close(P->asfd) < 0 ||
1283*0Sstevel@tonic-gate 	    (fd = dupfd(fd, P->asfd)) != P->asfd) {
1284*0Sstevel@tonic-gate 		dprintf("Preopen: failed to open %s: %s\n",
1285*0Sstevel@tonic-gate 		    procname, strerror(errno));
1286*0Sstevel@tonic-gate 		if (fd >= 0)
1287*0Sstevel@tonic-gate 			(void) close(fd);
1288*0Sstevel@tonic-gate 		return (-1);
1289*0Sstevel@tonic-gate 	}
1290*0Sstevel@tonic-gate 	P->asfd = fd;
1291*0Sstevel@tonic-gate 
1292*0Sstevel@tonic-gate 	(void) strcpy(fname, "status");
1293*0Sstevel@tonic-gate 	if ((fd = open(procname, O_RDONLY)) < 0 ||
1294*0Sstevel@tonic-gate 	    close(P->statfd) < 0 ||
1295*0Sstevel@tonic-gate 	    (fd = dupfd(fd, P->statfd)) != P->statfd) {
1296*0Sstevel@tonic-gate 		dprintf("Preopen: failed to open %s: %s\n",
1297*0Sstevel@tonic-gate 		    procname, strerror(errno));
1298*0Sstevel@tonic-gate 		if (fd >= 0)
1299*0Sstevel@tonic-gate 			(void) close(fd);
1300*0Sstevel@tonic-gate 		return (-1);
1301*0Sstevel@tonic-gate 	}
1302*0Sstevel@tonic-gate 	P->statfd = fd;
1303*0Sstevel@tonic-gate 
1304*0Sstevel@tonic-gate 	(void) strcpy(fname, "ctl");
1305*0Sstevel@tonic-gate 	if ((fd = open(procname, O_WRONLY)) < 0 ||
1306*0Sstevel@tonic-gate 	    close(P->ctlfd) < 0 ||
1307*0Sstevel@tonic-gate 	    (fd = dupfd(fd, P->ctlfd)) != P->ctlfd) {
1308*0Sstevel@tonic-gate 		dprintf("Preopen: failed to open %s: %s\n",
1309*0Sstevel@tonic-gate 		    procname, strerror(errno));
1310*0Sstevel@tonic-gate 		if (fd >= 0)
1311*0Sstevel@tonic-gate 			(void) close(fd);
1312*0Sstevel@tonic-gate 		return (-1);
1313*0Sstevel@tonic-gate 	}
1314*0Sstevel@tonic-gate 	P->ctlfd = fd;
1315*0Sstevel@tonic-gate 
1316*0Sstevel@tonic-gate 	/*
1317*0Sstevel@tonic-gate 	 * Set the state to PS_RUN and wait for the process to stop so that
1318*0Sstevel@tonic-gate 	 * we re-read the status from the new P->statfd.  If this fails, Pwait
1319*0Sstevel@tonic-gate 	 * will reset the state to PS_LOST and we fail the reopen.  Before
1320*0Sstevel@tonic-gate 	 * returning, we also forge a bit of P->status to allow the debugger to
1321*0Sstevel@tonic-gate 	 * see that we are PS_LOST following a successful exec.
1322*0Sstevel@tonic-gate 	 */
1323*0Sstevel@tonic-gate 	P->state = PS_RUN;
1324*0Sstevel@tonic-gate 	if (Pwait(P, 0) == -1) {
1325*0Sstevel@tonic-gate #ifdef _ILP32
1326*0Sstevel@tonic-gate 		if (errno == EOVERFLOW)
1327*0Sstevel@tonic-gate 			P->status.pr_dmodel = PR_MODEL_LP64;
1328*0Sstevel@tonic-gate #endif
1329*0Sstevel@tonic-gate 		P->status.pr_lwp.pr_why = PR_SYSEXIT;
1330*0Sstevel@tonic-gate 		P->status.pr_lwp.pr_what = SYS_execve;
1331*0Sstevel@tonic-gate 		P->status.pr_lwp.pr_errno = 0;
1332*0Sstevel@tonic-gate 		return (-1);
1333*0Sstevel@tonic-gate 	}
1334*0Sstevel@tonic-gate 
1335*0Sstevel@tonic-gate 	/*
1336*0Sstevel@tonic-gate 	 * The process should be stopped on exec (REQUESTED)
1337*0Sstevel@tonic-gate 	 * or else should be stopped on exit from exec() (SYSEXIT)
1338*0Sstevel@tonic-gate 	 */
1339*0Sstevel@tonic-gate 	if (P->state == PS_STOP &&
1340*0Sstevel@tonic-gate 	    (P->status.pr_lwp.pr_why == PR_REQUESTED ||
1341*0Sstevel@tonic-gate 	    (P->status.pr_lwp.pr_why == PR_SYSEXIT &&
1342*0Sstevel@tonic-gate 	    (P->status.pr_lwp.pr_what == SYS_exec ||
1343*0Sstevel@tonic-gate 	    P->status.pr_lwp.pr_what == SYS_execve)))) {
1344*0Sstevel@tonic-gate 		/* fake up stop-on-exit-from-execve */
1345*0Sstevel@tonic-gate 		if (P->status.pr_lwp.pr_why == PR_REQUESTED) {
1346*0Sstevel@tonic-gate 			P->status.pr_lwp.pr_why = PR_SYSEXIT;
1347*0Sstevel@tonic-gate 			P->status.pr_lwp.pr_what = SYS_execve;
1348*0Sstevel@tonic-gate 			P->status.pr_lwp.pr_errno = 0;
1349*0Sstevel@tonic-gate 		}
1350*0Sstevel@tonic-gate 	} else {
1351*0Sstevel@tonic-gate 		dprintf("Preopen: expected REQUESTED or "
1352*0Sstevel@tonic-gate 		    "SYSEXIT(SYS_execve) stop\n");
1353*0Sstevel@tonic-gate 	}
1354*0Sstevel@tonic-gate 
1355*0Sstevel@tonic-gate 	return (0);
1356*0Sstevel@tonic-gate }
1357*0Sstevel@tonic-gate 
1358*0Sstevel@tonic-gate /*
1359*0Sstevel@tonic-gate  * Define all settable flags other than the microstate accounting flags.
1360*0Sstevel@tonic-gate  */
1361*0Sstevel@tonic-gate #define	ALL_SETTABLE_FLAGS (PR_FORK|PR_RLC|PR_KLC|PR_ASYNC|PR_BPTADJ|PR_PTRACE)
1362*0Sstevel@tonic-gate 
1363*0Sstevel@tonic-gate /*
1364*0Sstevel@tonic-gate  * Restore /proc tracing flags to their original values
1365*0Sstevel@tonic-gate  * in preparation for releasing the process.
1366*0Sstevel@tonic-gate  * Also called by Pcreate() to clear all tracing flags.
1367*0Sstevel@tonic-gate  */
1368*0Sstevel@tonic-gate static void
1369*0Sstevel@tonic-gate restore_tracing_flags(struct ps_prochandle *P)
1370*0Sstevel@tonic-gate {
1371*0Sstevel@tonic-gate 	long flags;
1372*0Sstevel@tonic-gate 	long cmd[4];
1373*0Sstevel@tonic-gate 	iovec_t iov[8];
1374*0Sstevel@tonic-gate 
1375*0Sstevel@tonic-gate 	if (P->flags & CREATED) {
1376*0Sstevel@tonic-gate 		/* we created this process; clear all tracing flags */
1377*0Sstevel@tonic-gate 		premptyset(&P->status.pr_sigtrace);
1378*0Sstevel@tonic-gate 		premptyset(&P->status.pr_flttrace);
1379*0Sstevel@tonic-gate 		premptyset(&P->status.pr_sysentry);
1380*0Sstevel@tonic-gate 		premptyset(&P->status.pr_sysexit);
1381*0Sstevel@tonic-gate 		if ((P->status.pr_flags & ALL_SETTABLE_FLAGS) != 0)
1382*0Sstevel@tonic-gate 			(void) Punsetflags(P, ALL_SETTABLE_FLAGS);
1383*0Sstevel@tonic-gate 	} else {
1384*0Sstevel@tonic-gate 		/* we grabbed the process; restore its tracing flags */
1385*0Sstevel@tonic-gate 		P->status.pr_sigtrace = P->orig_status.pr_sigtrace;
1386*0Sstevel@tonic-gate 		P->status.pr_flttrace = P->orig_status.pr_flttrace;
1387*0Sstevel@tonic-gate 		P->status.pr_sysentry = P->orig_status.pr_sysentry;
1388*0Sstevel@tonic-gate 		P->status.pr_sysexit  = P->orig_status.pr_sysexit;
1389*0Sstevel@tonic-gate 		if ((P->status.pr_flags & ALL_SETTABLE_FLAGS) !=
1390*0Sstevel@tonic-gate 		    (flags = (P->orig_status.pr_flags & ALL_SETTABLE_FLAGS))) {
1391*0Sstevel@tonic-gate 			(void) Punsetflags(P, ALL_SETTABLE_FLAGS);
1392*0Sstevel@tonic-gate 			if (flags)
1393*0Sstevel@tonic-gate 				(void) Psetflags(P, flags);
1394*0Sstevel@tonic-gate 		}
1395*0Sstevel@tonic-gate 	}
1396*0Sstevel@tonic-gate 
1397*0Sstevel@tonic-gate 	cmd[0] = PCSTRACE;
1398*0Sstevel@tonic-gate 	iov[0].iov_base = (caddr_t)&cmd[0];
1399*0Sstevel@tonic-gate 	iov[0].iov_len = sizeof (long);
1400*0Sstevel@tonic-gate 	iov[1].iov_base = (caddr_t)&P->status.pr_sigtrace;
1401*0Sstevel@tonic-gate 	iov[1].iov_len = sizeof (P->status.pr_sigtrace);
1402*0Sstevel@tonic-gate 
1403*0Sstevel@tonic-gate 	cmd[1] = PCSFAULT;
1404*0Sstevel@tonic-gate 	iov[2].iov_base = (caddr_t)&cmd[1];
1405*0Sstevel@tonic-gate 	iov[2].iov_len = sizeof (long);
1406*0Sstevel@tonic-gate 	iov[3].iov_base = (caddr_t)&P->status.pr_flttrace;
1407*0Sstevel@tonic-gate 	iov[3].iov_len = sizeof (P->status.pr_flttrace);
1408*0Sstevel@tonic-gate 
1409*0Sstevel@tonic-gate 	cmd[2] = PCSENTRY;
1410*0Sstevel@tonic-gate 	iov[4].iov_base = (caddr_t)&cmd[2];
1411*0Sstevel@tonic-gate 	iov[4].iov_len = sizeof (long);
1412*0Sstevel@tonic-gate 	iov[5].iov_base = (caddr_t)&P->status.pr_sysentry;
1413*0Sstevel@tonic-gate 	iov[5].iov_len = sizeof (P->status.pr_sysentry);
1414*0Sstevel@tonic-gate 
1415*0Sstevel@tonic-gate 	cmd[3] = PCSEXIT;
1416*0Sstevel@tonic-gate 	iov[6].iov_base = (caddr_t)&cmd[3];
1417*0Sstevel@tonic-gate 	iov[6].iov_len = sizeof (long);
1418*0Sstevel@tonic-gate 	iov[7].iov_base = (caddr_t)&P->status.pr_sysexit;
1419*0Sstevel@tonic-gate 	iov[7].iov_len = sizeof (P->status.pr_sysexit);
1420*0Sstevel@tonic-gate 
1421*0Sstevel@tonic-gate 	(void) writev(P->ctlfd, iov, 8);
1422*0Sstevel@tonic-gate 
1423*0Sstevel@tonic-gate 	P->flags &= ~(SETSIG|SETFAULT|SETENTRY|SETEXIT);
1424*0Sstevel@tonic-gate }
1425*0Sstevel@tonic-gate 
1426*0Sstevel@tonic-gate /*
1427*0Sstevel@tonic-gate  * Release the process.  Frees the process control structure.
1428*0Sstevel@tonic-gate  * flags:
1429*0Sstevel@tonic-gate  *	PRELEASE_CLEAR	Clear all tracing flags.
1430*0Sstevel@tonic-gate  *	PRELEASE_RETAIN	Retain current tracing flags.
1431*0Sstevel@tonic-gate  *	PRELEASE_HANG	Leave the process stopped and abandoned.
1432*0Sstevel@tonic-gate  *	PRELEASE_KILL	Terminate the process with SIGKILL.
1433*0Sstevel@tonic-gate  */
1434*0Sstevel@tonic-gate void
1435*0Sstevel@tonic-gate Prelease(struct ps_prochandle *P, int flags)
1436*0Sstevel@tonic-gate {
1437*0Sstevel@tonic-gate 	if (P->state == PS_DEAD) {
1438*0Sstevel@tonic-gate 		dprintf("Prelease: releasing handle %p PS_DEAD of pid %d\n",
1439*0Sstevel@tonic-gate 		    (void *)P, (int)P->pid);
1440*0Sstevel@tonic-gate 		Pfree(P);
1441*0Sstevel@tonic-gate 		return;
1442*0Sstevel@tonic-gate 	}
1443*0Sstevel@tonic-gate 
1444*0Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
1445*0Sstevel@tonic-gate 		file_info_t *fptr = list_next(&P->file_head);
1446*0Sstevel@tonic-gate 		dprintf("Prelease: releasing handle %p PS_IDLE of file %s\n",
1447*0Sstevel@tonic-gate 		    (void *)P, fptr->file_pname);
1448*0Sstevel@tonic-gate 		Pfree(P);
1449*0Sstevel@tonic-gate 		return;
1450*0Sstevel@tonic-gate 	}
1451*0Sstevel@tonic-gate 
1452*0Sstevel@tonic-gate 	dprintf("Prelease: releasing handle %p pid %d\n",
1453*0Sstevel@tonic-gate 	    (void *)P, (int)P->pid);
1454*0Sstevel@tonic-gate 
1455*0Sstevel@tonic-gate 	if (P->ctlfd == -1) {
1456*0Sstevel@tonic-gate 		Pfree(P);
1457*0Sstevel@tonic-gate 		return;
1458*0Sstevel@tonic-gate 	}
1459*0Sstevel@tonic-gate 
1460*0Sstevel@tonic-gate 	if (P->agentcnt > 0) {
1461*0Sstevel@tonic-gate 		P->agentcnt = 1;
1462*0Sstevel@tonic-gate 		Pdestroy_agent(P);
1463*0Sstevel@tonic-gate 	}
1464*0Sstevel@tonic-gate 
1465*0Sstevel@tonic-gate 	/*
1466*0Sstevel@tonic-gate 	 * Attempt to stop the process.
1467*0Sstevel@tonic-gate 	 */
1468*0Sstevel@tonic-gate 	P->state = PS_RUN;
1469*0Sstevel@tonic-gate 	(void) Pstop(P, 1000);
1470*0Sstevel@tonic-gate 
1471*0Sstevel@tonic-gate 	if (flags & PRELEASE_KILL) {
1472*0Sstevel@tonic-gate 		if (P->state == PS_STOP)
1473*0Sstevel@tonic-gate 			(void) Psetrun(P, SIGKILL, 0);
1474*0Sstevel@tonic-gate 		(void) kill(P->pid, SIGKILL);
1475*0Sstevel@tonic-gate 		Pfree(P);
1476*0Sstevel@tonic-gate 		return;
1477*0Sstevel@tonic-gate 	}
1478*0Sstevel@tonic-gate 
1479*0Sstevel@tonic-gate 	/*
1480*0Sstevel@tonic-gate 	 * If we lost control, all we can do now is close the files.
1481*0Sstevel@tonic-gate 	 * In this case, the last close sets the process running.
1482*0Sstevel@tonic-gate 	 */
1483*0Sstevel@tonic-gate 	if (P->state != PS_STOP &&
1484*0Sstevel@tonic-gate 	    (P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)) == 0) {
1485*0Sstevel@tonic-gate 		Pfree(P);
1486*0Sstevel@tonic-gate 		return;
1487*0Sstevel@tonic-gate 	}
1488*0Sstevel@tonic-gate 
1489*0Sstevel@tonic-gate 	/*
1490*0Sstevel@tonic-gate 	 * We didn't lose control; we do more.
1491*0Sstevel@tonic-gate 	 */
1492*0Sstevel@tonic-gate 	Psync(P);
1493*0Sstevel@tonic-gate 
1494*0Sstevel@tonic-gate 	if (flags & PRELEASE_CLEAR)
1495*0Sstevel@tonic-gate 		P->flags |= CREATED;
1496*0Sstevel@tonic-gate 
1497*0Sstevel@tonic-gate 	if (!(flags & PRELEASE_RETAIN))
1498*0Sstevel@tonic-gate 		restore_tracing_flags(P);
1499*0Sstevel@tonic-gate 
1500*0Sstevel@tonic-gate 	if (flags & PRELEASE_HANG) {
1501*0Sstevel@tonic-gate 		/* Leave the process stopped and abandoned */
1502*0Sstevel@tonic-gate 		(void) Punsetflags(P, PR_RLC|PR_KLC);
1503*0Sstevel@tonic-gate 		Pfree(P);
1504*0Sstevel@tonic-gate 		return;
1505*0Sstevel@tonic-gate 	}
1506*0Sstevel@tonic-gate 
1507*0Sstevel@tonic-gate 	/*
1508*0Sstevel@tonic-gate 	 * Set the process running if we created it or if it was
1509*0Sstevel@tonic-gate 	 * not originally stopped or directed to stop via /proc
1510*0Sstevel@tonic-gate 	 * or if we were given the PRELEASE_CLEAR flag.
1511*0Sstevel@tonic-gate 	 */
1512*0Sstevel@tonic-gate 	if ((P->flags & CREATED) ||
1513*0Sstevel@tonic-gate 	    (P->orig_status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)) == 0) {
1514*0Sstevel@tonic-gate 		(void) Psetflags(P, PR_RLC);
1515*0Sstevel@tonic-gate 		/*
1516*0Sstevel@tonic-gate 		 * We do this repeatedly because the process may have
1517*0Sstevel@tonic-gate 		 * more than one LWP stopped on an event of interest.
1518*0Sstevel@tonic-gate 		 * This makes sure all of them are set running.
1519*0Sstevel@tonic-gate 		 */
1520*0Sstevel@tonic-gate 		do {
1521*0Sstevel@tonic-gate 			if (Psetrun(P, 0, 0) == -1 && errno == EBUSY)
1522*0Sstevel@tonic-gate 				break; /* Agent LWP may be stuck */
1523*0Sstevel@tonic-gate 		} while (Pstopstatus(P, PCNULL, 0) == 0 &&
1524*0Sstevel@tonic-gate 		    P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP));
1525*0Sstevel@tonic-gate 
1526*0Sstevel@tonic-gate 		if (P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP))
1527*0Sstevel@tonic-gate 			dprintf("Prelease: failed to set process running\n");
1528*0Sstevel@tonic-gate 	}
1529*0Sstevel@tonic-gate 
1530*0Sstevel@tonic-gate 	Pfree(P);
1531*0Sstevel@tonic-gate }
1532*0Sstevel@tonic-gate 
1533*0Sstevel@tonic-gate /* debugging */
1534*0Sstevel@tonic-gate void
1535*0Sstevel@tonic-gate prldump(const char *caller, lwpstatus_t *lsp)
1536*0Sstevel@tonic-gate {
1537*0Sstevel@tonic-gate 	char name[32];
1538*0Sstevel@tonic-gate 	uint32_t bits;
1539*0Sstevel@tonic-gate 
1540*0Sstevel@tonic-gate 	switch (lsp->pr_why) {
1541*0Sstevel@tonic-gate 	case PR_REQUESTED:
1542*0Sstevel@tonic-gate 		dprintf("%s: REQUESTED\n", caller);
1543*0Sstevel@tonic-gate 		break;
1544*0Sstevel@tonic-gate 	case PR_SIGNALLED:
1545*0Sstevel@tonic-gate 		dprintf("%s: SIGNALLED %s\n", caller,
1546*0Sstevel@tonic-gate 			proc_signame(lsp->pr_what, name, sizeof (name)));
1547*0Sstevel@tonic-gate 		break;
1548*0Sstevel@tonic-gate 	case PR_FAULTED:
1549*0Sstevel@tonic-gate 		dprintf("%s: FAULTED %s\n", caller,
1550*0Sstevel@tonic-gate 			proc_fltname(lsp->pr_what, name, sizeof (name)));
1551*0Sstevel@tonic-gate 		break;
1552*0Sstevel@tonic-gate 	case PR_SYSENTRY:
1553*0Sstevel@tonic-gate 		dprintf("%s: SYSENTRY %s\n", caller,
1554*0Sstevel@tonic-gate 			proc_sysname(lsp->pr_what, name, sizeof (name)));
1555*0Sstevel@tonic-gate 		break;
1556*0Sstevel@tonic-gate 	case PR_SYSEXIT:
1557*0Sstevel@tonic-gate 		dprintf("%s: SYSEXIT %s\n", caller,
1558*0Sstevel@tonic-gate 			proc_sysname(lsp->pr_what, name, sizeof (name)));
1559*0Sstevel@tonic-gate 		break;
1560*0Sstevel@tonic-gate 	case PR_JOBCONTROL:
1561*0Sstevel@tonic-gate 		dprintf("%s: JOBCONTROL %s\n", caller,
1562*0Sstevel@tonic-gate 			proc_signame(lsp->pr_what, name, sizeof (name)));
1563*0Sstevel@tonic-gate 		break;
1564*0Sstevel@tonic-gate 	case PR_SUSPENDED:
1565*0Sstevel@tonic-gate 		dprintf("%s: SUSPENDED\n", caller);
1566*0Sstevel@tonic-gate 		break;
1567*0Sstevel@tonic-gate 	default:
1568*0Sstevel@tonic-gate 		dprintf("%s: Unknown\n", caller);
1569*0Sstevel@tonic-gate 		break;
1570*0Sstevel@tonic-gate 	}
1571*0Sstevel@tonic-gate 
1572*0Sstevel@tonic-gate 	if (lsp->pr_cursig)
1573*0Sstevel@tonic-gate 		dprintf("%s: p_cursig  = %d\n", caller, lsp->pr_cursig);
1574*0Sstevel@tonic-gate 
1575*0Sstevel@tonic-gate 	bits = *((uint32_t *)&lsp->pr_lwppend);
1576*0Sstevel@tonic-gate 	if (bits)
1577*0Sstevel@tonic-gate 		dprintf("%s: pr_lwppend = 0x%.8X\n", caller, bits);
1578*0Sstevel@tonic-gate }
1579*0Sstevel@tonic-gate 
1580*0Sstevel@tonic-gate /* debugging */
1581*0Sstevel@tonic-gate static void
1582*0Sstevel@tonic-gate prdump(struct ps_prochandle *P)
1583*0Sstevel@tonic-gate {
1584*0Sstevel@tonic-gate 	uint32_t bits;
1585*0Sstevel@tonic-gate 
1586*0Sstevel@tonic-gate 	prldump("Pstopstatus", &P->status.pr_lwp);
1587*0Sstevel@tonic-gate 
1588*0Sstevel@tonic-gate 	bits = *((uint32_t *)&P->status.pr_sigpend);
1589*0Sstevel@tonic-gate 	if (bits)
1590*0Sstevel@tonic-gate 		dprintf("Pstopstatus: pr_sigpend = 0x%.8X\n", bits);
1591*0Sstevel@tonic-gate }
1592*0Sstevel@tonic-gate 
1593*0Sstevel@tonic-gate /*
1594*0Sstevel@tonic-gate  * Wait for the specified process to stop or terminate.
1595*0Sstevel@tonic-gate  * Or, just get the current status (PCNULL).
1596*0Sstevel@tonic-gate  * Or, direct it to stop and get the current status (PCDSTOP).
1597*0Sstevel@tonic-gate  * If the agent LWP exists, do these things to the agent,
1598*0Sstevel@tonic-gate  * else do these things to the process as a whole.
1599*0Sstevel@tonic-gate  */
1600*0Sstevel@tonic-gate int
1601*0Sstevel@tonic-gate Pstopstatus(struct ps_prochandle *P,
1602*0Sstevel@tonic-gate 	long request,		/* PCNULL, PCDSTOP, PCSTOP, PCWSTOP */
1603*0Sstevel@tonic-gate 	uint_t msec)		/* if non-zero, timeout in milliseconds */
1604*0Sstevel@tonic-gate {
1605*0Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
1606*0Sstevel@tonic-gate 	long ctl[3];
1607*0Sstevel@tonic-gate 	ssize_t rc;
1608*0Sstevel@tonic-gate 	int err;
1609*0Sstevel@tonic-gate 	int old_state = P->state;
1610*0Sstevel@tonic-gate 
1611*0Sstevel@tonic-gate 	switch (P->state) {
1612*0Sstevel@tonic-gate 	case PS_RUN:
1613*0Sstevel@tonic-gate 		break;
1614*0Sstevel@tonic-gate 	case PS_STOP:
1615*0Sstevel@tonic-gate 		if (request != PCNULL && request != PCDSTOP)
1616*0Sstevel@tonic-gate 			return (0);
1617*0Sstevel@tonic-gate 		break;
1618*0Sstevel@tonic-gate 	case PS_LOST:
1619*0Sstevel@tonic-gate 		if (request != PCNULL) {
1620*0Sstevel@tonic-gate 			errno = EAGAIN;
1621*0Sstevel@tonic-gate 			return (-1);
1622*0Sstevel@tonic-gate 		}
1623*0Sstevel@tonic-gate 		break;
1624*0Sstevel@tonic-gate 	case PS_UNDEAD:
1625*0Sstevel@tonic-gate 	case PS_DEAD:
1626*0Sstevel@tonic-gate 	case PS_IDLE:
1627*0Sstevel@tonic-gate 		if (request != PCNULL) {
1628*0Sstevel@tonic-gate 			errno = ENOENT;
1629*0Sstevel@tonic-gate 			return (-1);
1630*0Sstevel@tonic-gate 		}
1631*0Sstevel@tonic-gate 		break;
1632*0Sstevel@tonic-gate 	default:	/* corrupted state */
1633*0Sstevel@tonic-gate 		dprintf("Pstopstatus: corrupted state: %d\n", P->state);
1634*0Sstevel@tonic-gate 		errno = EINVAL;
1635*0Sstevel@tonic-gate 		return (-1);
1636*0Sstevel@tonic-gate 	}
1637*0Sstevel@tonic-gate 
1638*0Sstevel@tonic-gate 	ctl[0] = PCDSTOP;
1639*0Sstevel@tonic-gate 	ctl[1] = PCTWSTOP;
1640*0Sstevel@tonic-gate 	ctl[2] = (long)msec;
1641*0Sstevel@tonic-gate 	rc = 0;
1642*0Sstevel@tonic-gate 	switch (request) {
1643*0Sstevel@tonic-gate 	case PCSTOP:
1644*0Sstevel@tonic-gate 		rc = write(ctlfd, &ctl[0], 3*sizeof (long));
1645*0Sstevel@tonic-gate 		break;
1646*0Sstevel@tonic-gate 	case PCWSTOP:
1647*0Sstevel@tonic-gate 		rc = write(ctlfd, &ctl[1], 2*sizeof (long));
1648*0Sstevel@tonic-gate 		break;
1649*0Sstevel@tonic-gate 	case PCDSTOP:
1650*0Sstevel@tonic-gate 		rc = write(ctlfd, &ctl[0], 1*sizeof (long));
1651*0Sstevel@tonic-gate 		break;
1652*0Sstevel@tonic-gate 	case PCNULL:
1653*0Sstevel@tonic-gate 		if (P->state == PS_DEAD || P->state == PS_IDLE)
1654*0Sstevel@tonic-gate 			return (0);
1655*0Sstevel@tonic-gate 		break;
1656*0Sstevel@tonic-gate 	default:	/* programming error */
1657*0Sstevel@tonic-gate 		errno = EINVAL;
1658*0Sstevel@tonic-gate 		return (-1);
1659*0Sstevel@tonic-gate 	}
1660*0Sstevel@tonic-gate 	err = (rc < 0)? errno : 0;
1661*0Sstevel@tonic-gate 	Psync(P);
1662*0Sstevel@tonic-gate 
1663*0Sstevel@tonic-gate 	if (P->agentstatfd < 0) {
1664*0Sstevel@tonic-gate 		if (pread(P->statfd, &P->status,
1665*0Sstevel@tonic-gate 		    sizeof (P->status), (off_t)0) < 0)
1666*0Sstevel@tonic-gate 			err = errno;
1667*0Sstevel@tonic-gate 	} else {
1668*0Sstevel@tonic-gate 		if (pread(P->agentstatfd, &P->status.pr_lwp,
1669*0Sstevel@tonic-gate 		    sizeof (P->status.pr_lwp), (off_t)0) < 0)
1670*0Sstevel@tonic-gate 			err = errno;
1671*0Sstevel@tonic-gate 		P->status.pr_flags = P->status.pr_lwp.pr_flags;
1672*0Sstevel@tonic-gate 	}
1673*0Sstevel@tonic-gate 
1674*0Sstevel@tonic-gate 	if (err) {
1675*0Sstevel@tonic-gate 		switch (err) {
1676*0Sstevel@tonic-gate 		case EINTR:		/* user typed ctl-C */
1677*0Sstevel@tonic-gate 		case ERESTART:
1678*0Sstevel@tonic-gate 			dprintf("Pstopstatus: EINTR\n");
1679*0Sstevel@tonic-gate 			break;
1680*0Sstevel@tonic-gate 		case EAGAIN:		/* we lost control of the the process */
1681*0Sstevel@tonic-gate 		case EOVERFLOW:
1682*0Sstevel@tonic-gate 			dprintf("Pstopstatus: PS_LOST, errno=%d\n", err);
1683*0Sstevel@tonic-gate 			P->state = PS_LOST;
1684*0Sstevel@tonic-gate 			break;
1685*0Sstevel@tonic-gate 		default:		/* check for dead process */
1686*0Sstevel@tonic-gate 			if (_libproc_debug) {
1687*0Sstevel@tonic-gate 				const char *errstr;
1688*0Sstevel@tonic-gate 
1689*0Sstevel@tonic-gate 				switch (request) {
1690*0Sstevel@tonic-gate 				case PCNULL:
1691*0Sstevel@tonic-gate 					errstr = "Pstopstatus PCNULL"; break;
1692*0Sstevel@tonic-gate 				case PCSTOP:
1693*0Sstevel@tonic-gate 					errstr = "Pstopstatus PCSTOP"; break;
1694*0Sstevel@tonic-gate 				case PCDSTOP:
1695*0Sstevel@tonic-gate 					errstr = "Pstopstatus PCDSTOP"; break;
1696*0Sstevel@tonic-gate 				case PCWSTOP:
1697*0Sstevel@tonic-gate 					errstr = "Pstopstatus PCWSTOP"; break;
1698*0Sstevel@tonic-gate 				default:
1699*0Sstevel@tonic-gate 					errstr = "Pstopstatus PC???"; break;
1700*0Sstevel@tonic-gate 				}
1701*0Sstevel@tonic-gate 				dprintf("%s: %s\n", errstr, strerror(err));
1702*0Sstevel@tonic-gate 			}
1703*0Sstevel@tonic-gate 			deadcheck(P);
1704*0Sstevel@tonic-gate 			break;
1705*0Sstevel@tonic-gate 		}
1706*0Sstevel@tonic-gate 		if (err != EINTR && err != ERESTART) {
1707*0Sstevel@tonic-gate 			errno = err;
1708*0Sstevel@tonic-gate 			return (-1);
1709*0Sstevel@tonic-gate 		}
1710*0Sstevel@tonic-gate 	}
1711*0Sstevel@tonic-gate 
1712*0Sstevel@tonic-gate 	if (!(P->status.pr_flags & PR_STOPPED)) {
1713*0Sstevel@tonic-gate 		P->state = PS_RUN;
1714*0Sstevel@tonic-gate 		if (request == PCNULL || request == PCDSTOP || msec != 0)
1715*0Sstevel@tonic-gate 			return (0);
1716*0Sstevel@tonic-gate 		dprintf("Pstopstatus: process is not stopped\n");
1717*0Sstevel@tonic-gate 		errno = EPROTO;
1718*0Sstevel@tonic-gate 		return (-1);
1719*0Sstevel@tonic-gate 	}
1720*0Sstevel@tonic-gate 
1721*0Sstevel@tonic-gate 	P->state = PS_STOP;
1722*0Sstevel@tonic-gate 
1723*0Sstevel@tonic-gate 	if (_libproc_debug)	/* debugging */
1724*0Sstevel@tonic-gate 		prdump(P);
1725*0Sstevel@tonic-gate 
1726*0Sstevel@tonic-gate 	/*
1727*0Sstevel@tonic-gate 	 * If the process was already stopped coming into Pstopstatus(),
1728*0Sstevel@tonic-gate 	 * then don't use its PC to set P->sysaddr since it may have been
1729*0Sstevel@tonic-gate 	 * changed since the time the process originally stopped.
1730*0Sstevel@tonic-gate 	 */
1731*0Sstevel@tonic-gate 	if (old_state == PS_STOP)
1732*0Sstevel@tonic-gate 		return (0);
1733*0Sstevel@tonic-gate 
1734*0Sstevel@tonic-gate 	switch (P->status.pr_lwp.pr_why) {
1735*0Sstevel@tonic-gate 	case PR_SYSENTRY:
1736*0Sstevel@tonic-gate 	case PR_SYSEXIT:
1737*0Sstevel@tonic-gate 		if (Pissyscall_prev(P, P->status.pr_lwp.pr_reg[R_PC],
1738*0Sstevel@tonic-gate 		    &P->sysaddr) == 0)
1739*0Sstevel@tonic-gate 			P->sysaddr = P->status.pr_lwp.pr_reg[R_PC];
1740*0Sstevel@tonic-gate 		break;
1741*0Sstevel@tonic-gate 	case PR_REQUESTED:
1742*0Sstevel@tonic-gate 	case PR_SIGNALLED:
1743*0Sstevel@tonic-gate 	case PR_FAULTED:
1744*0Sstevel@tonic-gate 	case PR_JOBCONTROL:
1745*0Sstevel@tonic-gate 	case PR_SUSPENDED:
1746*0Sstevel@tonic-gate 		break;
1747*0Sstevel@tonic-gate 	default:
1748*0Sstevel@tonic-gate 		errno = EPROTO;
1749*0Sstevel@tonic-gate 		return (-1);
1750*0Sstevel@tonic-gate 	}
1751*0Sstevel@tonic-gate 
1752*0Sstevel@tonic-gate 	return (0);
1753*0Sstevel@tonic-gate }
1754*0Sstevel@tonic-gate 
1755*0Sstevel@tonic-gate /*
1756*0Sstevel@tonic-gate  * Wait for the process to stop for any reason.
1757*0Sstevel@tonic-gate  */
1758*0Sstevel@tonic-gate int
1759*0Sstevel@tonic-gate Pwait(struct ps_prochandle *P, uint_t msec)
1760*0Sstevel@tonic-gate {
1761*0Sstevel@tonic-gate 	return (Pstopstatus(P, PCWSTOP, msec));
1762*0Sstevel@tonic-gate }
1763*0Sstevel@tonic-gate 
1764*0Sstevel@tonic-gate /*
1765*0Sstevel@tonic-gate  * Direct the process to stop; wait for it to stop.
1766*0Sstevel@tonic-gate  */
1767*0Sstevel@tonic-gate int
1768*0Sstevel@tonic-gate Pstop(struct ps_prochandle *P, uint_t msec)
1769*0Sstevel@tonic-gate {
1770*0Sstevel@tonic-gate 	return (Pstopstatus(P, PCSTOP, msec));
1771*0Sstevel@tonic-gate }
1772*0Sstevel@tonic-gate 
1773*0Sstevel@tonic-gate /*
1774*0Sstevel@tonic-gate  * Direct the process to stop; don't wait.
1775*0Sstevel@tonic-gate  */
1776*0Sstevel@tonic-gate int
1777*0Sstevel@tonic-gate Pdstop(struct ps_prochandle *P)
1778*0Sstevel@tonic-gate {
1779*0Sstevel@tonic-gate 	return (Pstopstatus(P, PCDSTOP, 0));
1780*0Sstevel@tonic-gate }
1781*0Sstevel@tonic-gate 
1782*0Sstevel@tonic-gate static void
1783*0Sstevel@tonic-gate deadcheck(struct ps_prochandle *P)
1784*0Sstevel@tonic-gate {
1785*0Sstevel@tonic-gate 	int fd;
1786*0Sstevel@tonic-gate 	void *buf;
1787*0Sstevel@tonic-gate 	size_t size;
1788*0Sstevel@tonic-gate 
1789*0Sstevel@tonic-gate 	if (P->statfd < 0)
1790*0Sstevel@tonic-gate 		P->state = PS_UNDEAD;
1791*0Sstevel@tonic-gate 	else {
1792*0Sstevel@tonic-gate 		if (P->agentstatfd < 0) {
1793*0Sstevel@tonic-gate 			fd = P->statfd;
1794*0Sstevel@tonic-gate 			buf = &P->status;
1795*0Sstevel@tonic-gate 			size = sizeof (P->status);
1796*0Sstevel@tonic-gate 		} else {
1797*0Sstevel@tonic-gate 			fd = P->agentstatfd;
1798*0Sstevel@tonic-gate 			buf = &P->status.pr_lwp;
1799*0Sstevel@tonic-gate 			size = sizeof (P->status.pr_lwp);
1800*0Sstevel@tonic-gate 		}
1801*0Sstevel@tonic-gate 		while (pread(fd, buf, size, (off_t)0) != size) {
1802*0Sstevel@tonic-gate 			switch (errno) {
1803*0Sstevel@tonic-gate 			default:
1804*0Sstevel@tonic-gate 				P->state = PS_UNDEAD;
1805*0Sstevel@tonic-gate 				break;
1806*0Sstevel@tonic-gate 			case EINTR:
1807*0Sstevel@tonic-gate 			case ERESTART:
1808*0Sstevel@tonic-gate 				continue;
1809*0Sstevel@tonic-gate 			case EAGAIN:
1810*0Sstevel@tonic-gate 				P->state = PS_LOST;
1811*0Sstevel@tonic-gate 				break;
1812*0Sstevel@tonic-gate 			}
1813*0Sstevel@tonic-gate 			break;
1814*0Sstevel@tonic-gate 		}
1815*0Sstevel@tonic-gate 		P->status.pr_flags = P->status.pr_lwp.pr_flags;
1816*0Sstevel@tonic-gate 	}
1817*0Sstevel@tonic-gate }
1818*0Sstevel@tonic-gate 
1819*0Sstevel@tonic-gate /*
1820*0Sstevel@tonic-gate  * Get the value of one register from stopped process.
1821*0Sstevel@tonic-gate  */
1822*0Sstevel@tonic-gate int
1823*0Sstevel@tonic-gate Pgetareg(struct ps_prochandle *P, int regno, prgreg_t *preg)
1824*0Sstevel@tonic-gate {
1825*0Sstevel@tonic-gate 	if (regno < 0 || regno >= NPRGREG) {
1826*0Sstevel@tonic-gate 		errno = EINVAL;
1827*0Sstevel@tonic-gate 		return (-1);
1828*0Sstevel@tonic-gate 	}
1829*0Sstevel@tonic-gate 
1830*0Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
1831*0Sstevel@tonic-gate 		errno = ENODATA;
1832*0Sstevel@tonic-gate 		return (-1);
1833*0Sstevel@tonic-gate 	}
1834*0Sstevel@tonic-gate 
1835*0Sstevel@tonic-gate 	if (P->state != PS_STOP && P->state != PS_DEAD) {
1836*0Sstevel@tonic-gate 		errno = EBUSY;
1837*0Sstevel@tonic-gate 		return (-1);
1838*0Sstevel@tonic-gate 	}
1839*0Sstevel@tonic-gate 
1840*0Sstevel@tonic-gate 	*preg = P->status.pr_lwp.pr_reg[regno];
1841*0Sstevel@tonic-gate 	return (0);
1842*0Sstevel@tonic-gate }
1843*0Sstevel@tonic-gate 
1844*0Sstevel@tonic-gate /*
1845*0Sstevel@tonic-gate  * Put value of one register into stopped process.
1846*0Sstevel@tonic-gate  */
1847*0Sstevel@tonic-gate int
1848*0Sstevel@tonic-gate Pputareg(struct ps_prochandle *P, int regno, prgreg_t reg)
1849*0Sstevel@tonic-gate {
1850*0Sstevel@tonic-gate 	if (regno < 0 || regno >= NPRGREG) {
1851*0Sstevel@tonic-gate 		errno = EINVAL;
1852*0Sstevel@tonic-gate 		return (-1);
1853*0Sstevel@tonic-gate 	}
1854*0Sstevel@tonic-gate 
1855*0Sstevel@tonic-gate 	if (P->state != PS_STOP) {
1856*0Sstevel@tonic-gate 		errno = EBUSY;
1857*0Sstevel@tonic-gate 		return (-1);
1858*0Sstevel@tonic-gate 	}
1859*0Sstevel@tonic-gate 
1860*0Sstevel@tonic-gate 	P->status.pr_lwp.pr_reg[regno] = reg;
1861*0Sstevel@tonic-gate 	P->flags |= SETREGS;	/* set registers before continuing */
1862*0Sstevel@tonic-gate 	return (0);
1863*0Sstevel@tonic-gate }
1864*0Sstevel@tonic-gate 
1865*0Sstevel@tonic-gate int
1866*0Sstevel@tonic-gate Psetrun(struct ps_prochandle *P,
1867*0Sstevel@tonic-gate 	int sig,	/* signal to pass to process */
1868*0Sstevel@tonic-gate 	int flags)	/* PRSTEP|PRSABORT|PRSTOP|PRCSIG|PRCFAULT */
1869*0Sstevel@tonic-gate {
1870*0Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0) ? P->agentctlfd : P->ctlfd;
1871*0Sstevel@tonic-gate 	int sbits = (PR_DSTOP | PR_ISTOP | PR_ASLEEP);
1872*0Sstevel@tonic-gate 
1873*0Sstevel@tonic-gate 	long ctl[1 +					/* PCCFAULT	*/
1874*0Sstevel@tonic-gate 		1 + sizeof (siginfo_t)/sizeof (long) +	/* PCSSIG/PCCSIG */
1875*0Sstevel@tonic-gate 		2 ];					/* PCRUN	*/
1876*0Sstevel@tonic-gate 
1877*0Sstevel@tonic-gate 	long *ctlp = ctl;
1878*0Sstevel@tonic-gate 	size_t size;
1879*0Sstevel@tonic-gate 
1880*0Sstevel@tonic-gate 	if (P->state != PS_STOP && (P->status.pr_lwp.pr_flags & sbits) == 0) {
1881*0Sstevel@tonic-gate 		errno = EBUSY;
1882*0Sstevel@tonic-gate 		return (-1);
1883*0Sstevel@tonic-gate 	}
1884*0Sstevel@tonic-gate 
1885*0Sstevel@tonic-gate 	Psync(P);	/* flush tracing flags and registers */
1886*0Sstevel@tonic-gate 
1887*0Sstevel@tonic-gate 	if (flags & PRCFAULT) {		/* clear current fault */
1888*0Sstevel@tonic-gate 		*ctlp++ = PCCFAULT;
1889*0Sstevel@tonic-gate 		flags &= ~PRCFAULT;
1890*0Sstevel@tonic-gate 	}
1891*0Sstevel@tonic-gate 
1892*0Sstevel@tonic-gate 	if (flags & PRCSIG) {		/* clear current signal */
1893*0Sstevel@tonic-gate 		*ctlp++ = PCCSIG;
1894*0Sstevel@tonic-gate 		flags &= ~PRCSIG;
1895*0Sstevel@tonic-gate 	} else if (sig && sig != P->status.pr_lwp.pr_cursig) {
1896*0Sstevel@tonic-gate 		/* make current signal */
1897*0Sstevel@tonic-gate 		siginfo_t *infop;
1898*0Sstevel@tonic-gate 
1899*0Sstevel@tonic-gate 		*ctlp++ = PCSSIG;
1900*0Sstevel@tonic-gate 		infop = (siginfo_t *)ctlp;
1901*0Sstevel@tonic-gate 		(void) memset(infop, 0, sizeof (*infop));
1902*0Sstevel@tonic-gate 		infop->si_signo = sig;
1903*0Sstevel@tonic-gate 		ctlp += sizeof (siginfo_t) / sizeof (long);
1904*0Sstevel@tonic-gate 	}
1905*0Sstevel@tonic-gate 
1906*0Sstevel@tonic-gate 	*ctlp++ = PCRUN;
1907*0Sstevel@tonic-gate 	*ctlp++ = flags;
1908*0Sstevel@tonic-gate 	size = (char *)ctlp - (char *)ctl;
1909*0Sstevel@tonic-gate 
1910*0Sstevel@tonic-gate 	P->info_valid = 0;	/* will need to update map and file info */
1911*0Sstevel@tonic-gate 
1912*0Sstevel@tonic-gate 	/*
1913*0Sstevel@tonic-gate 	 * If we've cached ucontext-list information while we were stopped,
1914*0Sstevel@tonic-gate 	 * free it now.
1915*0Sstevel@tonic-gate 	 */
1916*0Sstevel@tonic-gate 	if (P->ucaddrs != NULL) {
1917*0Sstevel@tonic-gate 		free(P->ucaddrs);
1918*0Sstevel@tonic-gate 		P->ucaddrs = NULL;
1919*0Sstevel@tonic-gate 		P->ucnelems = 0;
1920*0Sstevel@tonic-gate 	}
1921*0Sstevel@tonic-gate 
1922*0Sstevel@tonic-gate 	if (write(ctlfd, ctl, size) != size) {
1923*0Sstevel@tonic-gate 		/* If it is dead or lost, return the real status, not PS_RUN */
1924*0Sstevel@tonic-gate 		if (errno == ENOENT || errno == EAGAIN) {
1925*0Sstevel@tonic-gate 			(void) Pstopstatus(P, PCNULL, 0);
1926*0Sstevel@tonic-gate 			return (0);
1927*0Sstevel@tonic-gate 		}
1928*0Sstevel@tonic-gate 		/* If it is not in a jobcontrol stop, issue an error message */
1929*0Sstevel@tonic-gate 		if (errno != EBUSY ||
1930*0Sstevel@tonic-gate 		    P->status.pr_lwp.pr_why != PR_JOBCONTROL) {
1931*0Sstevel@tonic-gate 			dprintf("Psetrun: %s\n", strerror(errno));
1932*0Sstevel@tonic-gate 			return (-1);
1933*0Sstevel@tonic-gate 		}
1934*0Sstevel@tonic-gate 		/* Otherwise pretend that the job-stopped process is running */
1935*0Sstevel@tonic-gate 	}
1936*0Sstevel@tonic-gate 
1937*0Sstevel@tonic-gate 	P->state = PS_RUN;
1938*0Sstevel@tonic-gate 	return (0);
1939*0Sstevel@tonic-gate }
1940*0Sstevel@tonic-gate 
1941*0Sstevel@tonic-gate ssize_t
1942*0Sstevel@tonic-gate Pread(struct ps_prochandle *P,
1943*0Sstevel@tonic-gate 	void *buf,		/* caller's buffer */
1944*0Sstevel@tonic-gate 	size_t nbyte,		/* number of bytes to read */
1945*0Sstevel@tonic-gate 	uintptr_t address)	/* address in process */
1946*0Sstevel@tonic-gate {
1947*0Sstevel@tonic-gate 	return (P->ops->p_pread(P, buf, nbyte, address));
1948*0Sstevel@tonic-gate }
1949*0Sstevel@tonic-gate 
1950*0Sstevel@tonic-gate ssize_t
1951*0Sstevel@tonic-gate Pread_string(struct ps_prochandle *P,
1952*0Sstevel@tonic-gate 	char *buf, 		/* caller's buffer */
1953*0Sstevel@tonic-gate 	size_t size,		/* upper limit on bytes to read */
1954*0Sstevel@tonic-gate 	uintptr_t addr)		/* address in process */
1955*0Sstevel@tonic-gate {
1956*0Sstevel@tonic-gate 	enum { STRSZ = 40 };
1957*0Sstevel@tonic-gate 	char string[STRSZ + 1];
1958*0Sstevel@tonic-gate 	ssize_t leng = 0;
1959*0Sstevel@tonic-gate 	int nbyte;
1960*0Sstevel@tonic-gate 
1961*0Sstevel@tonic-gate 	if (size < 2) {
1962*0Sstevel@tonic-gate 		errno = EINVAL;
1963*0Sstevel@tonic-gate 		return (-1);
1964*0Sstevel@tonic-gate 	}
1965*0Sstevel@tonic-gate 
1966*0Sstevel@tonic-gate 	size--;			/* ensure trailing null fits in buffer */
1967*0Sstevel@tonic-gate 
1968*0Sstevel@tonic-gate 	*buf = '\0';
1969*0Sstevel@tonic-gate 	string[STRSZ] = '\0';
1970*0Sstevel@tonic-gate 
1971*0Sstevel@tonic-gate 	for (nbyte = STRSZ; nbyte == STRSZ && leng < size; addr += STRSZ) {
1972*0Sstevel@tonic-gate 		if ((nbyte = P->ops->p_pread(P, string, STRSZ, addr)) <= 0) {
1973*0Sstevel@tonic-gate 			buf[leng] = '\0';
1974*0Sstevel@tonic-gate 			return (leng ? leng : -1);
1975*0Sstevel@tonic-gate 		}
1976*0Sstevel@tonic-gate 		if ((nbyte = strlen(string)) > 0) {
1977*0Sstevel@tonic-gate 			if (leng + nbyte > size)
1978*0Sstevel@tonic-gate 				nbyte = size - leng;
1979*0Sstevel@tonic-gate 			(void) strncpy(buf + leng, string, nbyte);
1980*0Sstevel@tonic-gate 			leng += nbyte;
1981*0Sstevel@tonic-gate 		}
1982*0Sstevel@tonic-gate 	}
1983*0Sstevel@tonic-gate 	buf[leng] = '\0';
1984*0Sstevel@tonic-gate 	return (leng);
1985*0Sstevel@tonic-gate }
1986*0Sstevel@tonic-gate 
1987*0Sstevel@tonic-gate ssize_t
1988*0Sstevel@tonic-gate Pwrite(struct ps_prochandle *P,
1989*0Sstevel@tonic-gate 	const void *buf,	/* caller's buffer */
1990*0Sstevel@tonic-gate 	size_t nbyte,		/* number of bytes to write */
1991*0Sstevel@tonic-gate 	uintptr_t address)	/* address in process */
1992*0Sstevel@tonic-gate {
1993*0Sstevel@tonic-gate 	return (P->ops->p_pwrite(P, buf, nbyte, address));
1994*0Sstevel@tonic-gate }
1995*0Sstevel@tonic-gate 
1996*0Sstevel@tonic-gate int
1997*0Sstevel@tonic-gate Pclearsig(struct ps_prochandle *P)
1998*0Sstevel@tonic-gate {
1999*0Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
2000*0Sstevel@tonic-gate 	long ctl = PCCSIG;
2001*0Sstevel@tonic-gate 
2002*0Sstevel@tonic-gate 	if (write(ctlfd, &ctl, sizeof (ctl)) != sizeof (ctl))
2003*0Sstevel@tonic-gate 		return (-1);
2004*0Sstevel@tonic-gate 	P->status.pr_lwp.pr_cursig = 0;
2005*0Sstevel@tonic-gate 	return (0);
2006*0Sstevel@tonic-gate }
2007*0Sstevel@tonic-gate 
2008*0Sstevel@tonic-gate int
2009*0Sstevel@tonic-gate Pclearfault(struct ps_prochandle *P)
2010*0Sstevel@tonic-gate {
2011*0Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
2012*0Sstevel@tonic-gate 	long ctl = PCCFAULT;
2013*0Sstevel@tonic-gate 
2014*0Sstevel@tonic-gate 	if (write(ctlfd, &ctl, sizeof (ctl)) != sizeof (ctl))
2015*0Sstevel@tonic-gate 		return (-1);
2016*0Sstevel@tonic-gate 	return (0);
2017*0Sstevel@tonic-gate }
2018*0Sstevel@tonic-gate 
2019*0Sstevel@tonic-gate /*
2020*0Sstevel@tonic-gate  * Set a breakpoint trap, return original instruction.
2021*0Sstevel@tonic-gate  */
2022*0Sstevel@tonic-gate int
2023*0Sstevel@tonic-gate Psetbkpt(struct ps_prochandle *P, uintptr_t address, ulong_t *saved)
2024*0Sstevel@tonic-gate {
2025*0Sstevel@tonic-gate 	long ctl[1 + sizeof (priovec_t) / sizeof (long) +	/* PCREAD */
2026*0Sstevel@tonic-gate 		1 + sizeof (priovec_t) / sizeof (long)];	/* PCWRITE */
2027*0Sstevel@tonic-gate 	long *ctlp = ctl;
2028*0Sstevel@tonic-gate 	size_t size;
2029*0Sstevel@tonic-gate 	priovec_t *iovp;
2030*0Sstevel@tonic-gate 	instr_t bpt = BPT;
2031*0Sstevel@tonic-gate 	instr_t old;
2032*0Sstevel@tonic-gate 
2033*0Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
2034*0Sstevel@tonic-gate 	    P->state == PS_IDLE) {
2035*0Sstevel@tonic-gate 		errno = ENOENT;
2036*0Sstevel@tonic-gate 		return (-1);
2037*0Sstevel@tonic-gate 	}
2038*0Sstevel@tonic-gate 
2039*0Sstevel@tonic-gate 	/* fetch the old instruction */
2040*0Sstevel@tonic-gate 	*ctlp++ = PCREAD;
2041*0Sstevel@tonic-gate 	iovp = (priovec_t *)ctlp;
2042*0Sstevel@tonic-gate 	iovp->pio_base = &old;
2043*0Sstevel@tonic-gate 	iovp->pio_len = sizeof (old);
2044*0Sstevel@tonic-gate 	iovp->pio_offset = address;
2045*0Sstevel@tonic-gate 	ctlp += sizeof (priovec_t) / sizeof (long);
2046*0Sstevel@tonic-gate 
2047*0Sstevel@tonic-gate 	/* write the BPT instruction */
2048*0Sstevel@tonic-gate 	*ctlp++ = PCWRITE;
2049*0Sstevel@tonic-gate 	iovp = (priovec_t *)ctlp;
2050*0Sstevel@tonic-gate 	iovp->pio_base = &bpt;
2051*0Sstevel@tonic-gate 	iovp->pio_len = sizeof (bpt);
2052*0Sstevel@tonic-gate 	iovp->pio_offset = address;
2053*0Sstevel@tonic-gate 	ctlp += sizeof (priovec_t) / sizeof (long);
2054*0Sstevel@tonic-gate 
2055*0Sstevel@tonic-gate 	size = (char *)ctlp - (char *)ctl;
2056*0Sstevel@tonic-gate 	if (write(P->ctlfd, ctl, size) != size)
2057*0Sstevel@tonic-gate 		return (-1);
2058*0Sstevel@tonic-gate 
2059*0Sstevel@tonic-gate 	/*
2060*0Sstevel@tonic-gate 	 * Fail if there was already a breakpoint there from another debugger
2061*0Sstevel@tonic-gate 	 * or DTrace's user-level tracing on x86.
2062*0Sstevel@tonic-gate 	 */
2063*0Sstevel@tonic-gate 	if (old == BPT)
2064*0Sstevel@tonic-gate 		return (EBUSY);
2065*0Sstevel@tonic-gate 
2066*0Sstevel@tonic-gate 	*saved = (ulong_t)old;
2067*0Sstevel@tonic-gate 	return (0);
2068*0Sstevel@tonic-gate }
2069*0Sstevel@tonic-gate 
2070*0Sstevel@tonic-gate /*
2071*0Sstevel@tonic-gate  * Restore original instruction where a breakpoint was set.
2072*0Sstevel@tonic-gate  */
2073*0Sstevel@tonic-gate int
2074*0Sstevel@tonic-gate Pdelbkpt(struct ps_prochandle *P, uintptr_t address, ulong_t saved)
2075*0Sstevel@tonic-gate {
2076*0Sstevel@tonic-gate 	instr_t old = (instr_t)saved;
2077*0Sstevel@tonic-gate 	instr_t cur;
2078*0Sstevel@tonic-gate 
2079*0Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
2080*0Sstevel@tonic-gate 	    P->state == PS_IDLE) {
2081*0Sstevel@tonic-gate 		errno = ENOENT;
2082*0Sstevel@tonic-gate 		return (-1);
2083*0Sstevel@tonic-gate 	}
2084*0Sstevel@tonic-gate 
2085*0Sstevel@tonic-gate 	/*
2086*0Sstevel@tonic-gate 	 * If the breakpoint instruction we had placed has been overwritten
2087*0Sstevel@tonic-gate 	 * with a new instruction, then don't try to replace it with the
2088*0Sstevel@tonic-gate 	 * old instruction. Doing do can cause problems with self-modifying
2089*0Sstevel@tonic-gate 	 * code -- PLTs for example. If the Pread() fails, we assume that we
2090*0Sstevel@tonic-gate 	 * should proceed though most likely the Pwrite() will also fail.
2091*0Sstevel@tonic-gate 	 */
2092*0Sstevel@tonic-gate 	if (Pread(P, &cur, sizeof (cur), address) == sizeof (cur) &&
2093*0Sstevel@tonic-gate 	    cur != BPT)
2094*0Sstevel@tonic-gate 		return (0);
2095*0Sstevel@tonic-gate 
2096*0Sstevel@tonic-gate 	if (Pwrite(P, &old, sizeof (old), address) != sizeof (old))
2097*0Sstevel@tonic-gate 		return (-1);
2098*0Sstevel@tonic-gate 
2099*0Sstevel@tonic-gate 	return (0);
2100*0Sstevel@tonic-gate }
2101*0Sstevel@tonic-gate 
2102*0Sstevel@tonic-gate /*
2103*0Sstevel@tonic-gate  * Common code for Pxecbkpt() and Lxecbkpt().
2104*0Sstevel@tonic-gate  * Develop the array of requests that will do the job, then
2105*0Sstevel@tonic-gate  * write them to the specified control file descriptor.
2106*0Sstevel@tonic-gate  * Return the non-zero errno if the write fails.
2107*0Sstevel@tonic-gate  */
2108*0Sstevel@tonic-gate static int
2109*0Sstevel@tonic-gate execute_bkpt(
2110*0Sstevel@tonic-gate 	int ctlfd,		/* process or LWP control file descriptor */
2111*0Sstevel@tonic-gate 	const fltset_t *faultset,	/* current set of traced faults */
2112*0Sstevel@tonic-gate 	const sigset_t *sigmask,	/* current signal mask */
2113*0Sstevel@tonic-gate 	uintptr_t address,		/* address of breakpint */
2114*0Sstevel@tonic-gate 	ulong_t saved)			/* the saved instruction */
2115*0Sstevel@tonic-gate {
2116*0Sstevel@tonic-gate 	long ctl[
2117*0Sstevel@tonic-gate 		1 + sizeof (sigset_t) / sizeof (long) +		/* PCSHOLD */
2118*0Sstevel@tonic-gate 		1 + sizeof (fltset_t) / sizeof (long) +		/* PCSFAULT */
2119*0Sstevel@tonic-gate 		1 + sizeof (priovec_t) / sizeof (long) +	/* PCWRITE */
2120*0Sstevel@tonic-gate 		2 +						/* PCRUN */
2121*0Sstevel@tonic-gate 		1 +						/* PCWSTOP */
2122*0Sstevel@tonic-gate 		1 +						/* PCCFAULT */
2123*0Sstevel@tonic-gate 		1 + sizeof (priovec_t) / sizeof (long) +	/* PCWRITE */
2124*0Sstevel@tonic-gate 		1 + sizeof (fltset_t) / sizeof (long) +		/* PCSFAULT */
2125*0Sstevel@tonic-gate 		1 + sizeof (sigset_t) / sizeof (long)];		/* PCSHOLD */
2126*0Sstevel@tonic-gate 	long *ctlp = ctl;
2127*0Sstevel@tonic-gate 	sigset_t unblock;
2128*0Sstevel@tonic-gate 	size_t size;
2129*0Sstevel@tonic-gate 	ssize_t ssize;
2130*0Sstevel@tonic-gate 	priovec_t *iovp;
2131*0Sstevel@tonic-gate 	sigset_t *holdp;
2132*0Sstevel@tonic-gate 	fltset_t *faultp;
2133*0Sstevel@tonic-gate 	instr_t old = (instr_t)saved;
2134*0Sstevel@tonic-gate 	instr_t bpt = BPT;
2135*0Sstevel@tonic-gate 	int error = 0;
2136*0Sstevel@tonic-gate 
2137*0Sstevel@tonic-gate 	/* block our signals for the duration */
2138*0Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &blockable_sigs, &unblock);
2139*0Sstevel@tonic-gate 
2140*0Sstevel@tonic-gate 	/* hold posted signals */
2141*0Sstevel@tonic-gate 	*ctlp++ = PCSHOLD;
2142*0Sstevel@tonic-gate 	holdp = (sigset_t *)ctlp;
2143*0Sstevel@tonic-gate 	prfillset(holdp);
2144*0Sstevel@tonic-gate 	prdelset(holdp, SIGKILL);
2145*0Sstevel@tonic-gate 	prdelset(holdp, SIGSTOP);
2146*0Sstevel@tonic-gate 	ctlp += sizeof (sigset_t) / sizeof (long);
2147*0Sstevel@tonic-gate 
2148*0Sstevel@tonic-gate 	/* force tracing of FLTTRACE */
2149*0Sstevel@tonic-gate 	if (!(prismember(faultset, FLTTRACE))) {
2150*0Sstevel@tonic-gate 		*ctlp++ = PCSFAULT;
2151*0Sstevel@tonic-gate 		faultp = (fltset_t *)ctlp;
2152*0Sstevel@tonic-gate 		*faultp = *faultset;
2153*0Sstevel@tonic-gate 		praddset(faultp, FLTTRACE);
2154*0Sstevel@tonic-gate 		ctlp += sizeof (fltset_t) / sizeof (long);
2155*0Sstevel@tonic-gate 	}
2156*0Sstevel@tonic-gate 
2157*0Sstevel@tonic-gate 	/* restore the old instruction */
2158*0Sstevel@tonic-gate 	*ctlp++ = PCWRITE;
2159*0Sstevel@tonic-gate 	iovp = (priovec_t *)ctlp;
2160*0Sstevel@tonic-gate 	iovp->pio_base = &old;
2161*0Sstevel@tonic-gate 	iovp->pio_len = sizeof (old);
2162*0Sstevel@tonic-gate 	iovp->pio_offset = address;
2163*0Sstevel@tonic-gate 	ctlp += sizeof (priovec_t) / sizeof (long);
2164*0Sstevel@tonic-gate 
2165*0Sstevel@tonic-gate 	/* clear current signal and fault; set running w/ single-step */
2166*0Sstevel@tonic-gate 	*ctlp++ = PCRUN;
2167*0Sstevel@tonic-gate 	*ctlp++ = PRCSIG | PRCFAULT | PRSTEP;
2168*0Sstevel@tonic-gate 
2169*0Sstevel@tonic-gate 	/* wait for stop, cancel the fault */
2170*0Sstevel@tonic-gate 	*ctlp++ = PCWSTOP;
2171*0Sstevel@tonic-gate 	*ctlp++ = PCCFAULT;
2172*0Sstevel@tonic-gate 
2173*0Sstevel@tonic-gate 	/* restore the breakpoint trap */
2174*0Sstevel@tonic-gate 	*ctlp++ = PCWRITE;
2175*0Sstevel@tonic-gate 	iovp = (priovec_t *)ctlp;
2176*0Sstevel@tonic-gate 	iovp->pio_base = &bpt;
2177*0Sstevel@tonic-gate 	iovp->pio_len = sizeof (bpt);
2178*0Sstevel@tonic-gate 	iovp->pio_offset = address;
2179*0Sstevel@tonic-gate 	ctlp += sizeof (priovec_t) / sizeof (long);
2180*0Sstevel@tonic-gate 
2181*0Sstevel@tonic-gate 	/* restore fault tracing set */
2182*0Sstevel@tonic-gate 	if (!(prismember(faultset, FLTTRACE))) {
2183*0Sstevel@tonic-gate 		*ctlp++ = PCSFAULT;
2184*0Sstevel@tonic-gate 		*(fltset_t *)ctlp = *faultset;
2185*0Sstevel@tonic-gate 		ctlp += sizeof (fltset_t) / sizeof (long);
2186*0Sstevel@tonic-gate 	}
2187*0Sstevel@tonic-gate 
2188*0Sstevel@tonic-gate 	/* restore the hold mask */
2189*0Sstevel@tonic-gate 	*ctlp++ = PCSHOLD;
2190*0Sstevel@tonic-gate 	*(sigset_t *)ctlp = *sigmask;
2191*0Sstevel@tonic-gate 	ctlp += sizeof (sigset_t) / sizeof (long);
2192*0Sstevel@tonic-gate 
2193*0Sstevel@tonic-gate 	size = (char *)ctlp - (char *)ctl;
2194*0Sstevel@tonic-gate 	if ((ssize = write(ctlfd, ctl, size)) != size)
2195*0Sstevel@tonic-gate 		error = (ssize == -1)? errno : EINTR;
2196*0Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &unblock, NULL);
2197*0Sstevel@tonic-gate 	return (error);
2198*0Sstevel@tonic-gate }
2199*0Sstevel@tonic-gate 
2200*0Sstevel@tonic-gate /*
2201*0Sstevel@tonic-gate  * Step over a breakpoint, i.e., execute the instruction that
2202*0Sstevel@tonic-gate  * really belongs at the breakpoint location (the current %pc)
2203*0Sstevel@tonic-gate  * and leave the process stopped at the next instruction.
2204*0Sstevel@tonic-gate  */
2205*0Sstevel@tonic-gate int
2206*0Sstevel@tonic-gate Pxecbkpt(struct ps_prochandle *P, ulong_t saved)
2207*0Sstevel@tonic-gate {
2208*0Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
2209*0Sstevel@tonic-gate 	int rv, error;
2210*0Sstevel@tonic-gate 
2211*0Sstevel@tonic-gate 	if (P->state != PS_STOP) {
2212*0Sstevel@tonic-gate 		errno = EBUSY;
2213*0Sstevel@tonic-gate 		return (-1);
2214*0Sstevel@tonic-gate 	}
2215*0Sstevel@tonic-gate 
2216*0Sstevel@tonic-gate 	Psync(P);
2217*0Sstevel@tonic-gate 
2218*0Sstevel@tonic-gate 	error = execute_bkpt(ctlfd,
2219*0Sstevel@tonic-gate 		&P->status.pr_flttrace, &P->status.pr_lwp.pr_lwphold,
2220*0Sstevel@tonic-gate 		P->status.pr_lwp.pr_reg[R_PC], saved);
2221*0Sstevel@tonic-gate 	rv = Pstopstatus(P, PCNULL, 0);
2222*0Sstevel@tonic-gate 
2223*0Sstevel@tonic-gate 	if (error != 0) {
2224*0Sstevel@tonic-gate 		if (P->status.pr_lwp.pr_why == PR_JOBCONTROL &&
2225*0Sstevel@tonic-gate 		    error == EBUSY) {	/* jobcontrol stop -- back off */
2226*0Sstevel@tonic-gate 			P->state = PS_RUN;
2227*0Sstevel@tonic-gate 			return (0);
2228*0Sstevel@tonic-gate 		}
2229*0Sstevel@tonic-gate 		if (error == ENOENT)
2230*0Sstevel@tonic-gate 			return (0);
2231*0Sstevel@tonic-gate 		errno = error;
2232*0Sstevel@tonic-gate 		return (-1);
2233*0Sstevel@tonic-gate 	}
2234*0Sstevel@tonic-gate 
2235*0Sstevel@tonic-gate 	return (rv);
2236*0Sstevel@tonic-gate }
2237*0Sstevel@tonic-gate 
2238*0Sstevel@tonic-gate /*
2239*0Sstevel@tonic-gate  * Install the watchpoint described by wp.
2240*0Sstevel@tonic-gate  */
2241*0Sstevel@tonic-gate int
2242*0Sstevel@tonic-gate Psetwapt(struct ps_prochandle *P, const prwatch_t *wp)
2243*0Sstevel@tonic-gate {
2244*0Sstevel@tonic-gate 	long ctl[1 + sizeof (prwatch_t) / sizeof (long)];
2245*0Sstevel@tonic-gate 	prwatch_t *cwp = (prwatch_t *)&ctl[1];
2246*0Sstevel@tonic-gate 
2247*0Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
2248*0Sstevel@tonic-gate 	    P->state == PS_IDLE) {
2249*0Sstevel@tonic-gate 		errno = ENOENT;
2250*0Sstevel@tonic-gate 		return (-1);
2251*0Sstevel@tonic-gate 	}
2252*0Sstevel@tonic-gate 
2253*0Sstevel@tonic-gate 	ctl[0] = PCWATCH;
2254*0Sstevel@tonic-gate 	cwp->pr_vaddr = wp->pr_vaddr;
2255*0Sstevel@tonic-gate 	cwp->pr_size = wp->pr_size;
2256*0Sstevel@tonic-gate 	cwp->pr_wflags = wp->pr_wflags;
2257*0Sstevel@tonic-gate 
2258*0Sstevel@tonic-gate 	if (write(P->ctlfd, ctl, sizeof (ctl)) != sizeof (ctl))
2259*0Sstevel@tonic-gate 		return (-1);
2260*0Sstevel@tonic-gate 
2261*0Sstevel@tonic-gate 	return (0);
2262*0Sstevel@tonic-gate }
2263*0Sstevel@tonic-gate 
2264*0Sstevel@tonic-gate /*
2265*0Sstevel@tonic-gate  * Remove the watchpoint described by wp.
2266*0Sstevel@tonic-gate  */
2267*0Sstevel@tonic-gate int
2268*0Sstevel@tonic-gate Pdelwapt(struct ps_prochandle *P, const prwatch_t *wp)
2269*0Sstevel@tonic-gate {
2270*0Sstevel@tonic-gate 	long ctl[1 + sizeof (prwatch_t) / sizeof (long)];
2271*0Sstevel@tonic-gate 	prwatch_t *cwp = (prwatch_t *)&ctl[1];
2272*0Sstevel@tonic-gate 
2273*0Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
2274*0Sstevel@tonic-gate 	    P->state == PS_IDLE) {
2275*0Sstevel@tonic-gate 		errno = ENOENT;
2276*0Sstevel@tonic-gate 		return (-1);
2277*0Sstevel@tonic-gate 	}
2278*0Sstevel@tonic-gate 
2279*0Sstevel@tonic-gate 	ctl[0] = PCWATCH;
2280*0Sstevel@tonic-gate 	cwp->pr_vaddr = wp->pr_vaddr;
2281*0Sstevel@tonic-gate 	cwp->pr_size = wp->pr_size;
2282*0Sstevel@tonic-gate 	cwp->pr_wflags = 0;
2283*0Sstevel@tonic-gate 
2284*0Sstevel@tonic-gate 	if (write(P->ctlfd, ctl, sizeof (ctl)) != sizeof (ctl))
2285*0Sstevel@tonic-gate 		return (-1);
2286*0Sstevel@tonic-gate 
2287*0Sstevel@tonic-gate 	return (0);
2288*0Sstevel@tonic-gate }
2289*0Sstevel@tonic-gate 
2290*0Sstevel@tonic-gate /*
2291*0Sstevel@tonic-gate  * Common code for Pxecwapt() and Lxecwapt().  Develop the array of requests
2292*0Sstevel@tonic-gate  * that will do the job, then write them to the specified control file
2293*0Sstevel@tonic-gate  * descriptor.  Return the non-zero errno if the write fails.
2294*0Sstevel@tonic-gate  */
2295*0Sstevel@tonic-gate static int
2296*0Sstevel@tonic-gate execute_wapt(
2297*0Sstevel@tonic-gate 	int ctlfd,		/* process or LWP control file descriptor */
2298*0Sstevel@tonic-gate 	const fltset_t *faultset,	/* current set of traced faults */
2299*0Sstevel@tonic-gate 	const sigset_t *sigmask,	/* current signal mask */
2300*0Sstevel@tonic-gate 	const prwatch_t *wp)		/* watchpoint descriptor */
2301*0Sstevel@tonic-gate {
2302*0Sstevel@tonic-gate 	long ctl[
2303*0Sstevel@tonic-gate 	    1 + sizeof (sigset_t) / sizeof (long) +		/* PCSHOLD */
2304*0Sstevel@tonic-gate 	    1 + sizeof (fltset_t) / sizeof (long) +		/* PCSFAULT */
2305*0Sstevel@tonic-gate 	    1 + sizeof (prwatch_t) / sizeof (long) +		/* PCWATCH */
2306*0Sstevel@tonic-gate 	    2 +							/* PCRUN */
2307*0Sstevel@tonic-gate 	    1 +							/* PCWSTOP */
2308*0Sstevel@tonic-gate 	    1 +							/* PCCFAULT */
2309*0Sstevel@tonic-gate 	    1 + sizeof (prwatch_t) / sizeof (long) +		/* PCWATCH */
2310*0Sstevel@tonic-gate 	    1 + sizeof (fltset_t) / sizeof (long) +		/* PCSFAULT */
2311*0Sstevel@tonic-gate 	    1 + sizeof (sigset_t) / sizeof (long)];		/* PCSHOLD */
2312*0Sstevel@tonic-gate 
2313*0Sstevel@tonic-gate 	long *ctlp = ctl;
2314*0Sstevel@tonic-gate 	int error = 0;
2315*0Sstevel@tonic-gate 
2316*0Sstevel@tonic-gate 	sigset_t unblock;
2317*0Sstevel@tonic-gate 	sigset_t *holdp;
2318*0Sstevel@tonic-gate 	fltset_t *faultp;
2319*0Sstevel@tonic-gate 	prwatch_t *prw;
2320*0Sstevel@tonic-gate 	ssize_t ssize;
2321*0Sstevel@tonic-gate 	size_t size;
2322*0Sstevel@tonic-gate 
2323*0Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &blockable_sigs, &unblock);
2324*0Sstevel@tonic-gate 
2325*0Sstevel@tonic-gate 	/*
2326*0Sstevel@tonic-gate 	 * Hold all posted signals in the victim process prior to stepping.
2327*0Sstevel@tonic-gate 	 */
2328*0Sstevel@tonic-gate 	*ctlp++ = PCSHOLD;
2329*0Sstevel@tonic-gate 	holdp = (sigset_t *)ctlp;
2330*0Sstevel@tonic-gate 	prfillset(holdp);
2331*0Sstevel@tonic-gate 	prdelset(holdp, SIGKILL);
2332*0Sstevel@tonic-gate 	prdelset(holdp, SIGSTOP);
2333*0Sstevel@tonic-gate 	ctlp += sizeof (sigset_t) / sizeof (long);
2334*0Sstevel@tonic-gate 
2335*0Sstevel@tonic-gate 	/*
2336*0Sstevel@tonic-gate 	 * Force tracing of FLTTRACE since we need to single step.
2337*0Sstevel@tonic-gate 	 */
2338*0Sstevel@tonic-gate 	if (!(prismember(faultset, FLTTRACE))) {
2339*0Sstevel@tonic-gate 		*ctlp++ = PCSFAULT;
2340*0Sstevel@tonic-gate 		faultp = (fltset_t *)ctlp;
2341*0Sstevel@tonic-gate 		*faultp = *faultset;
2342*0Sstevel@tonic-gate 		praddset(faultp, FLTTRACE);
2343*0Sstevel@tonic-gate 		ctlp += sizeof (fltset_t) / sizeof (long);
2344*0Sstevel@tonic-gate 	}
2345*0Sstevel@tonic-gate 
2346*0Sstevel@tonic-gate 	/*
2347*0Sstevel@tonic-gate 	 * Clear only the current watchpoint by setting pr_wflags to zero.
2348*0Sstevel@tonic-gate 	 */
2349*0Sstevel@tonic-gate 	*ctlp++ = PCWATCH;
2350*0Sstevel@tonic-gate 	prw = (prwatch_t *)ctlp;
2351*0Sstevel@tonic-gate 	prw->pr_vaddr = wp->pr_vaddr;
2352*0Sstevel@tonic-gate 	prw->pr_size = wp->pr_size;
2353*0Sstevel@tonic-gate 	prw->pr_wflags = 0;
2354*0Sstevel@tonic-gate 	ctlp += sizeof (prwatch_t) / sizeof (long);
2355*0Sstevel@tonic-gate 
2356*0Sstevel@tonic-gate 	/*
2357*0Sstevel@tonic-gate 	 * Clear the current signal and fault; set running with single-step.
2358*0Sstevel@tonic-gate 	 * Then wait for the victim to stop and cancel the FLTTRACE.
2359*0Sstevel@tonic-gate 	 */
2360*0Sstevel@tonic-gate 	*ctlp++ = PCRUN;
2361*0Sstevel@tonic-gate 	*ctlp++ = PRCSIG | PRCFAULT | PRSTEP;
2362*0Sstevel@tonic-gate 	*ctlp++ = PCWSTOP;
2363*0Sstevel@tonic-gate 	*ctlp++ = PCCFAULT;
2364*0Sstevel@tonic-gate 
2365*0Sstevel@tonic-gate 	/*
2366*0Sstevel@tonic-gate 	 * Restore the current watchpoint.
2367*0Sstevel@tonic-gate 	 */
2368*0Sstevel@tonic-gate 	*ctlp++ = PCWATCH;
2369*0Sstevel@tonic-gate 	(void) memcpy(ctlp, wp, sizeof (prwatch_t));
2370*0Sstevel@tonic-gate 	ctlp += sizeof (prwatch_t) / sizeof (long);
2371*0Sstevel@tonic-gate 
2372*0Sstevel@tonic-gate 	/*
2373*0Sstevel@tonic-gate 	 * Restore fault tracing set if we modified it.
2374*0Sstevel@tonic-gate 	 */
2375*0Sstevel@tonic-gate 	if (!(prismember(faultset, FLTTRACE))) {
2376*0Sstevel@tonic-gate 		*ctlp++ = PCSFAULT;
2377*0Sstevel@tonic-gate 		*(fltset_t *)ctlp = *faultset;
2378*0Sstevel@tonic-gate 		ctlp += sizeof (fltset_t) / sizeof (long);
2379*0Sstevel@tonic-gate 	}
2380*0Sstevel@tonic-gate 
2381*0Sstevel@tonic-gate 	/*
2382*0Sstevel@tonic-gate 	 * Restore the hold mask to the current hold mask (i.e. the one
2383*0Sstevel@tonic-gate 	 * before we executed any of the previous operations).
2384*0Sstevel@tonic-gate 	 */
2385*0Sstevel@tonic-gate 	*ctlp++ = PCSHOLD;
2386*0Sstevel@tonic-gate 	*(sigset_t *)ctlp = *sigmask;
2387*0Sstevel@tonic-gate 	ctlp += sizeof (sigset_t) / sizeof (long);
2388*0Sstevel@tonic-gate 
2389*0Sstevel@tonic-gate 	size = (char *)ctlp - (char *)ctl;
2390*0Sstevel@tonic-gate 	if ((ssize = write(ctlfd, ctl, size)) != size)
2391*0Sstevel@tonic-gate 		error = (ssize == -1)? errno : EINTR;
2392*0Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &unblock, NULL);
2393*0Sstevel@tonic-gate 	return (error);
2394*0Sstevel@tonic-gate }
2395*0Sstevel@tonic-gate 
2396*0Sstevel@tonic-gate /*
2397*0Sstevel@tonic-gate  * Step over a watchpoint, i.e., execute the instruction that was stopped by
2398*0Sstevel@tonic-gate  * the watchpoint, and then leave the LWP stopped at the next instruction.
2399*0Sstevel@tonic-gate  */
2400*0Sstevel@tonic-gate int
2401*0Sstevel@tonic-gate Pxecwapt(struct ps_prochandle *P, const prwatch_t *wp)
2402*0Sstevel@tonic-gate {
2403*0Sstevel@tonic-gate 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
2404*0Sstevel@tonic-gate 	int rv, error;
2405*0Sstevel@tonic-gate 
2406*0Sstevel@tonic-gate 	if (P->state != PS_STOP) {
2407*0Sstevel@tonic-gate 		errno = EBUSY;
2408*0Sstevel@tonic-gate 		return (-1);
2409*0Sstevel@tonic-gate 	}
2410*0Sstevel@tonic-gate 
2411*0Sstevel@tonic-gate 	Psync(P);
2412*0Sstevel@tonic-gate 	error = execute_wapt(ctlfd,
2413*0Sstevel@tonic-gate 		&P->status.pr_flttrace, &P->status.pr_lwp.pr_lwphold, wp);
2414*0Sstevel@tonic-gate 	rv = Pstopstatus(P, PCNULL, 0);
2415*0Sstevel@tonic-gate 
2416*0Sstevel@tonic-gate 	if (error != 0) {
2417*0Sstevel@tonic-gate 		if (P->status.pr_lwp.pr_why == PR_JOBCONTROL &&
2418*0Sstevel@tonic-gate 		    error == EBUSY) {	/* jobcontrol stop -- back off */
2419*0Sstevel@tonic-gate 			P->state = PS_RUN;
2420*0Sstevel@tonic-gate 			return (0);
2421*0Sstevel@tonic-gate 		}
2422*0Sstevel@tonic-gate 		if (error == ENOENT)
2423*0Sstevel@tonic-gate 			return (0);
2424*0Sstevel@tonic-gate 		errno = error;
2425*0Sstevel@tonic-gate 		return (-1);
2426*0Sstevel@tonic-gate 	}
2427*0Sstevel@tonic-gate 
2428*0Sstevel@tonic-gate 	return (rv);
2429*0Sstevel@tonic-gate }
2430*0Sstevel@tonic-gate 
2431*0Sstevel@tonic-gate int
2432*0Sstevel@tonic-gate Psetflags(struct ps_prochandle *P, long flags)
2433*0Sstevel@tonic-gate {
2434*0Sstevel@tonic-gate 	int rc;
2435*0Sstevel@tonic-gate 	long ctl[2];
2436*0Sstevel@tonic-gate 
2437*0Sstevel@tonic-gate 	ctl[0] = PCSET;
2438*0Sstevel@tonic-gate 	ctl[1] = flags;
2439*0Sstevel@tonic-gate 
2440*0Sstevel@tonic-gate 	if (write(P->ctlfd, ctl, 2*sizeof (long)) != 2*sizeof (long)) {
2441*0Sstevel@tonic-gate 		rc = -1;
2442*0Sstevel@tonic-gate 	} else {
2443*0Sstevel@tonic-gate 		P->status.pr_flags |= flags;
2444*0Sstevel@tonic-gate 		P->status.pr_lwp.pr_flags |= flags;
2445*0Sstevel@tonic-gate 		rc = 0;
2446*0Sstevel@tonic-gate 	}
2447*0Sstevel@tonic-gate 
2448*0Sstevel@tonic-gate 	return (rc);
2449*0Sstevel@tonic-gate }
2450*0Sstevel@tonic-gate 
2451*0Sstevel@tonic-gate int
2452*0Sstevel@tonic-gate Punsetflags(struct ps_prochandle *P, long flags)
2453*0Sstevel@tonic-gate {
2454*0Sstevel@tonic-gate 	int rc;
2455*0Sstevel@tonic-gate 	long ctl[2];
2456*0Sstevel@tonic-gate 
2457*0Sstevel@tonic-gate 	ctl[0] = PCUNSET;
2458*0Sstevel@tonic-gate 	ctl[1] = flags;
2459*0Sstevel@tonic-gate 
2460*0Sstevel@tonic-gate 	if (write(P->ctlfd, ctl, 2*sizeof (long)) != 2*sizeof (long)) {
2461*0Sstevel@tonic-gate 		rc = -1;
2462*0Sstevel@tonic-gate 	} else {
2463*0Sstevel@tonic-gate 		P->status.pr_flags &= ~flags;
2464*0Sstevel@tonic-gate 		P->status.pr_lwp.pr_flags &= ~flags;
2465*0Sstevel@tonic-gate 		rc = 0;
2466*0Sstevel@tonic-gate 	}
2467*0Sstevel@tonic-gate 
2468*0Sstevel@tonic-gate 	return (rc);
2469*0Sstevel@tonic-gate }
2470*0Sstevel@tonic-gate 
2471*0Sstevel@tonic-gate /*
2472*0Sstevel@tonic-gate  * Common function to allow clients to manipulate the action to be taken
2473*0Sstevel@tonic-gate  * on receipt of a signal, receipt of machine fault, entry to a system call,
2474*0Sstevel@tonic-gate  * or exit from a system call.  We make use of our private prset_* functions
2475*0Sstevel@tonic-gate  * in order to make this code be common.  The 'which' parameter identifies
2476*0Sstevel@tonic-gate  * the code for the event of interest (0 means change the entire set), and
2477*0Sstevel@tonic-gate  * the 'stop' parameter is a boolean indicating whether the process should
2478*0Sstevel@tonic-gate  * stop when the event of interest occurs.  The previous value is returned
2479*0Sstevel@tonic-gate  * to the caller; -1 is returned if an error occurred.
2480*0Sstevel@tonic-gate  */
2481*0Sstevel@tonic-gate static int
2482*0Sstevel@tonic-gate Psetaction(struct ps_prochandle *P, void *sp, size_t size,
2483*0Sstevel@tonic-gate     uint_t flag, int max, int which, int stop)
2484*0Sstevel@tonic-gate {
2485*0Sstevel@tonic-gate 	int oldval;
2486*0Sstevel@tonic-gate 
2487*0Sstevel@tonic-gate 	if (which < 0 || which > max) {
2488*0Sstevel@tonic-gate 		errno = EINVAL;
2489*0Sstevel@tonic-gate 		return (-1);
2490*0Sstevel@tonic-gate 	}
2491*0Sstevel@tonic-gate 
2492*0Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
2493*0Sstevel@tonic-gate 	    P->state == PS_IDLE) {
2494*0Sstevel@tonic-gate 		errno = ENOENT;
2495*0Sstevel@tonic-gate 		return (-1);
2496*0Sstevel@tonic-gate 	}
2497*0Sstevel@tonic-gate 
2498*0Sstevel@tonic-gate 	oldval = prset_ismember(sp, size, which) ? TRUE : FALSE;
2499*0Sstevel@tonic-gate 
2500*0Sstevel@tonic-gate 	if (stop) {
2501*0Sstevel@tonic-gate 		if (which == 0) {
2502*0Sstevel@tonic-gate 			prset_fill(sp, size);
2503*0Sstevel@tonic-gate 			P->flags |= flag;
2504*0Sstevel@tonic-gate 		} else if (!oldval) {
2505*0Sstevel@tonic-gate 			prset_add(sp, size, which);
2506*0Sstevel@tonic-gate 			P->flags |= flag;
2507*0Sstevel@tonic-gate 		}
2508*0Sstevel@tonic-gate 	} else {
2509*0Sstevel@tonic-gate 		if (which == 0) {
2510*0Sstevel@tonic-gate 			prset_empty(sp, size);
2511*0Sstevel@tonic-gate 			P->flags |= flag;
2512*0Sstevel@tonic-gate 		} else if (oldval) {
2513*0Sstevel@tonic-gate 			prset_del(sp, size, which);
2514*0Sstevel@tonic-gate 			P->flags |= flag;
2515*0Sstevel@tonic-gate 		}
2516*0Sstevel@tonic-gate 	}
2517*0Sstevel@tonic-gate 
2518*0Sstevel@tonic-gate 	if (P->state == PS_RUN)
2519*0Sstevel@tonic-gate 		Psync(P);
2520*0Sstevel@tonic-gate 
2521*0Sstevel@tonic-gate 	return (oldval);
2522*0Sstevel@tonic-gate }
2523*0Sstevel@tonic-gate 
2524*0Sstevel@tonic-gate /*
2525*0Sstevel@tonic-gate  * Set action on specified signal.
2526*0Sstevel@tonic-gate  */
2527*0Sstevel@tonic-gate int
2528*0Sstevel@tonic-gate Psignal(struct ps_prochandle *P, int which, int stop)
2529*0Sstevel@tonic-gate {
2530*0Sstevel@tonic-gate 	int oldval;
2531*0Sstevel@tonic-gate 
2532*0Sstevel@tonic-gate 	if (which == SIGKILL && stop != 0) {
2533*0Sstevel@tonic-gate 		errno = EINVAL;
2534*0Sstevel@tonic-gate 		return (-1);
2535*0Sstevel@tonic-gate 	}
2536*0Sstevel@tonic-gate 
2537*0Sstevel@tonic-gate 	oldval = Psetaction(P, &P->status.pr_sigtrace, sizeof (sigset_t),
2538*0Sstevel@tonic-gate 	    SETSIG, PRMAXSIG, which, stop);
2539*0Sstevel@tonic-gate 
2540*0Sstevel@tonic-gate 	if (oldval != -1 && which == 0 && stop != 0)
2541*0Sstevel@tonic-gate 		prdelset(&P->status.pr_sigtrace, SIGKILL);
2542*0Sstevel@tonic-gate 
2543*0Sstevel@tonic-gate 	return (oldval);
2544*0Sstevel@tonic-gate }
2545*0Sstevel@tonic-gate 
2546*0Sstevel@tonic-gate /*
2547*0Sstevel@tonic-gate  * Set all signal tracing flags.
2548*0Sstevel@tonic-gate  */
2549*0Sstevel@tonic-gate void
2550*0Sstevel@tonic-gate Psetsignal(struct ps_prochandle *P, const sigset_t *set)
2551*0Sstevel@tonic-gate {
2552*0Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
2553*0Sstevel@tonic-gate 	    P->state == PS_IDLE)
2554*0Sstevel@tonic-gate 		return;
2555*0Sstevel@tonic-gate 
2556*0Sstevel@tonic-gate 	P->status.pr_sigtrace = *set;
2557*0Sstevel@tonic-gate 	P->flags |= SETSIG;
2558*0Sstevel@tonic-gate 
2559*0Sstevel@tonic-gate 	if (P->state == PS_RUN)
2560*0Sstevel@tonic-gate 		Psync(P);
2561*0Sstevel@tonic-gate }
2562*0Sstevel@tonic-gate 
2563*0Sstevel@tonic-gate /*
2564*0Sstevel@tonic-gate  * Set action on specified fault.
2565*0Sstevel@tonic-gate  */
2566*0Sstevel@tonic-gate int
2567*0Sstevel@tonic-gate Pfault(struct ps_prochandle *P, int which, int stop)
2568*0Sstevel@tonic-gate {
2569*0Sstevel@tonic-gate 	return (Psetaction(P, &P->status.pr_flttrace, sizeof (fltset_t),
2570*0Sstevel@tonic-gate 	    SETFAULT, PRMAXFAULT, which, stop));
2571*0Sstevel@tonic-gate }
2572*0Sstevel@tonic-gate 
2573*0Sstevel@tonic-gate /*
2574*0Sstevel@tonic-gate  * Set all machine fault tracing flags.
2575*0Sstevel@tonic-gate  */
2576*0Sstevel@tonic-gate void
2577*0Sstevel@tonic-gate Psetfault(struct ps_prochandle *P, const fltset_t *set)
2578*0Sstevel@tonic-gate {
2579*0Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
2580*0Sstevel@tonic-gate 	    P->state == PS_IDLE)
2581*0Sstevel@tonic-gate 		return;
2582*0Sstevel@tonic-gate 
2583*0Sstevel@tonic-gate 	P->status.pr_flttrace = *set;
2584*0Sstevel@tonic-gate 	P->flags |= SETFAULT;
2585*0Sstevel@tonic-gate 
2586*0Sstevel@tonic-gate 	if (P->state == PS_RUN)
2587*0Sstevel@tonic-gate 		Psync(P);
2588*0Sstevel@tonic-gate }
2589*0Sstevel@tonic-gate 
2590*0Sstevel@tonic-gate /*
2591*0Sstevel@tonic-gate  * Set action on specified system call entry.
2592*0Sstevel@tonic-gate  */
2593*0Sstevel@tonic-gate int
2594*0Sstevel@tonic-gate Psysentry(struct ps_prochandle *P, int which, int stop)
2595*0Sstevel@tonic-gate {
2596*0Sstevel@tonic-gate 	return (Psetaction(P, &P->status.pr_sysentry, sizeof (sysset_t),
2597*0Sstevel@tonic-gate 	    SETENTRY, PRMAXSYS, which, stop));
2598*0Sstevel@tonic-gate }
2599*0Sstevel@tonic-gate 
2600*0Sstevel@tonic-gate /*
2601*0Sstevel@tonic-gate  * Set all system call entry tracing flags.
2602*0Sstevel@tonic-gate  */
2603*0Sstevel@tonic-gate void
2604*0Sstevel@tonic-gate Psetsysentry(struct ps_prochandle *P, const sysset_t *set)
2605*0Sstevel@tonic-gate {
2606*0Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
2607*0Sstevel@tonic-gate 	    P->state == PS_IDLE)
2608*0Sstevel@tonic-gate 		return;
2609*0Sstevel@tonic-gate 
2610*0Sstevel@tonic-gate 	P->status.pr_sysentry = *set;
2611*0Sstevel@tonic-gate 	P->flags |= SETENTRY;
2612*0Sstevel@tonic-gate 
2613*0Sstevel@tonic-gate 	if (P->state == PS_RUN)
2614*0Sstevel@tonic-gate 		Psync(P);
2615*0Sstevel@tonic-gate }
2616*0Sstevel@tonic-gate 
2617*0Sstevel@tonic-gate /*
2618*0Sstevel@tonic-gate  * Set action on specified system call exit.
2619*0Sstevel@tonic-gate  */
2620*0Sstevel@tonic-gate int
2621*0Sstevel@tonic-gate Psysexit(struct ps_prochandle *P, int which, int stop)
2622*0Sstevel@tonic-gate {
2623*0Sstevel@tonic-gate 	return (Psetaction(P, &P->status.pr_sysexit, sizeof (sysset_t),
2624*0Sstevel@tonic-gate 	    SETEXIT, PRMAXSYS, which, stop));
2625*0Sstevel@tonic-gate }
2626*0Sstevel@tonic-gate 
2627*0Sstevel@tonic-gate /*
2628*0Sstevel@tonic-gate  * Set all system call exit tracing flags.
2629*0Sstevel@tonic-gate  */
2630*0Sstevel@tonic-gate void
2631*0Sstevel@tonic-gate Psetsysexit(struct ps_prochandle *P, const sysset_t *set)
2632*0Sstevel@tonic-gate {
2633*0Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
2634*0Sstevel@tonic-gate 	    P->state == PS_IDLE)
2635*0Sstevel@tonic-gate 		return;
2636*0Sstevel@tonic-gate 
2637*0Sstevel@tonic-gate 	P->status.pr_sysexit = *set;
2638*0Sstevel@tonic-gate 	P->flags |= SETEXIT;
2639*0Sstevel@tonic-gate 
2640*0Sstevel@tonic-gate 	if (P->state == PS_RUN)
2641*0Sstevel@tonic-gate 		Psync(P);
2642*0Sstevel@tonic-gate }
2643*0Sstevel@tonic-gate 
2644*0Sstevel@tonic-gate /*
2645*0Sstevel@tonic-gate  * Utility function to read the contents of a file that contains a
2646*0Sstevel@tonic-gate  * prheader_t at the start (/proc/pid/lstatus or /proc/pid/lpsinfo).
2647*0Sstevel@tonic-gate  * Returns a malloc()d buffer or NULL on failure.
2648*0Sstevel@tonic-gate  */
2649*0Sstevel@tonic-gate static prheader_t *
2650*0Sstevel@tonic-gate read_lfile(struct ps_prochandle *P, const char *lname)
2651*0Sstevel@tonic-gate {
2652*0Sstevel@tonic-gate 	prheader_t *Lhp;
2653*0Sstevel@tonic-gate 	char lpath[64];
2654*0Sstevel@tonic-gate 	struct stat64 statb;
2655*0Sstevel@tonic-gate 	int fd;
2656*0Sstevel@tonic-gate 	size_t size;
2657*0Sstevel@tonic-gate 	ssize_t rval;
2658*0Sstevel@tonic-gate 
2659*0Sstevel@tonic-gate 	(void) snprintf(lpath, sizeof (lpath), "/proc/%d/%s",
2660*0Sstevel@tonic-gate 	    (int)P->status.pr_pid, lname);
2661*0Sstevel@tonic-gate 	if ((fd = open(lpath, O_RDONLY)) < 0 || fstat64(fd, &statb) != 0) {
2662*0Sstevel@tonic-gate 		if (fd >= 0)
2663*0Sstevel@tonic-gate 			(void) close(fd);
2664*0Sstevel@tonic-gate 		return (NULL);
2665*0Sstevel@tonic-gate 	}
2666*0Sstevel@tonic-gate 
2667*0Sstevel@tonic-gate 	/*
2668*0Sstevel@tonic-gate 	 * 'size' is just the initial guess at the buffer size.
2669*0Sstevel@tonic-gate 	 * It will have to grow if the number of lwps increases
2670*0Sstevel@tonic-gate 	 * while we are looking at the process.
2671*0Sstevel@tonic-gate 	 * 'size' must be larger than the actual file size.
2672*0Sstevel@tonic-gate 	 */
2673*0Sstevel@tonic-gate 	size = statb.st_size + 32;
2674*0Sstevel@tonic-gate 
2675*0Sstevel@tonic-gate 	for (;;) {
2676*0Sstevel@tonic-gate 		if ((Lhp = malloc(size)) == NULL)
2677*0Sstevel@tonic-gate 			break;
2678*0Sstevel@tonic-gate 		if ((rval = pread(fd, Lhp, size, 0)) < 0 ||
2679*0Sstevel@tonic-gate 		    rval <= sizeof (prheader_t)) {
2680*0Sstevel@tonic-gate 			free(Lhp);
2681*0Sstevel@tonic-gate 			Lhp = NULL;
2682*0Sstevel@tonic-gate 			break;
2683*0Sstevel@tonic-gate 		}
2684*0Sstevel@tonic-gate 		if (rval < size)
2685*0Sstevel@tonic-gate 			break;
2686*0Sstevel@tonic-gate 		/* need a bigger buffer */
2687*0Sstevel@tonic-gate 		free(Lhp);
2688*0Sstevel@tonic-gate 		size *= 2;
2689*0Sstevel@tonic-gate 	}
2690*0Sstevel@tonic-gate 
2691*0Sstevel@tonic-gate 	(void) close(fd);
2692*0Sstevel@tonic-gate 	return (Lhp);
2693*0Sstevel@tonic-gate }
2694*0Sstevel@tonic-gate 
2695*0Sstevel@tonic-gate /*
2696*0Sstevel@tonic-gate  * LWP iteration interface.
2697*0Sstevel@tonic-gate  */
2698*0Sstevel@tonic-gate int
2699*0Sstevel@tonic-gate Plwp_iter(struct ps_prochandle *P, proc_lwp_f *func, void *cd)
2700*0Sstevel@tonic-gate {
2701*0Sstevel@tonic-gate 	prheader_t *Lhp;
2702*0Sstevel@tonic-gate 	lwpstatus_t *Lsp;
2703*0Sstevel@tonic-gate 	long nlwp;
2704*0Sstevel@tonic-gate 	int rv;
2705*0Sstevel@tonic-gate 
2706*0Sstevel@tonic-gate 	switch (P->state) {
2707*0Sstevel@tonic-gate 	case PS_RUN:
2708*0Sstevel@tonic-gate 		(void) Pstopstatus(P, PCNULL, 0);
2709*0Sstevel@tonic-gate 		break;
2710*0Sstevel@tonic-gate 
2711*0Sstevel@tonic-gate 	case PS_STOP:
2712*0Sstevel@tonic-gate 		Psync(P);
2713*0Sstevel@tonic-gate 		break;
2714*0Sstevel@tonic-gate 
2715*0Sstevel@tonic-gate 	case PS_IDLE:
2716*0Sstevel@tonic-gate 		errno = ENODATA;
2717*0Sstevel@tonic-gate 		return (-1);
2718*0Sstevel@tonic-gate 	}
2719*0Sstevel@tonic-gate 
2720*0Sstevel@tonic-gate 	/*
2721*0Sstevel@tonic-gate 	 * For either live processes or cores, the single LWP case is easy:
2722*0Sstevel@tonic-gate 	 * the pstatus_t contains the lwpstatus_t for the only LWP.
2723*0Sstevel@tonic-gate 	 */
2724*0Sstevel@tonic-gate 	if (P->status.pr_nlwp <= 1)
2725*0Sstevel@tonic-gate 		return (func(cd, &P->status.pr_lwp));
2726*0Sstevel@tonic-gate 
2727*0Sstevel@tonic-gate 	/*
2728*0Sstevel@tonic-gate 	 * For the core file multi-LWP case, we just iterate through the
2729*0Sstevel@tonic-gate 	 * list of LWP structs we read in from the core file.
2730*0Sstevel@tonic-gate 	 */
2731*0Sstevel@tonic-gate 	if (P->state == PS_DEAD) {
2732*0Sstevel@tonic-gate 		lwp_info_t *lwp = list_prev(&P->core->core_lwp_head);
2733*0Sstevel@tonic-gate 		uint_t i;
2734*0Sstevel@tonic-gate 
2735*0Sstevel@tonic-gate 		for (i = 0; i < P->core->core_nlwp; i++, lwp = list_prev(lwp)) {
2736*0Sstevel@tonic-gate 			if (lwp->lwp_psinfo.pr_sname != 'Z' &&
2737*0Sstevel@tonic-gate 			    (rv = func(cd, &lwp->lwp_status)) != 0)
2738*0Sstevel@tonic-gate 				break;
2739*0Sstevel@tonic-gate 		}
2740*0Sstevel@tonic-gate 
2741*0Sstevel@tonic-gate 		return (rv);
2742*0Sstevel@tonic-gate 	}
2743*0Sstevel@tonic-gate 
2744*0Sstevel@tonic-gate 	/*
2745*0Sstevel@tonic-gate 	 * For the live process multi-LWP case, we have to work a little
2746*0Sstevel@tonic-gate 	 * harder: the /proc/pid/lstatus file has the array of LWP structs.
2747*0Sstevel@tonic-gate 	 */
2748*0Sstevel@tonic-gate 	if ((Lhp = read_lfile(P, "lstatus")) == NULL)
2749*0Sstevel@tonic-gate 		return (-1);
2750*0Sstevel@tonic-gate 
2751*0Sstevel@tonic-gate 	for (nlwp = Lhp->pr_nent, Lsp = (lwpstatus_t *)(uintptr_t)(Lhp + 1);
2752*0Sstevel@tonic-gate 	    nlwp > 0;
2753*0Sstevel@tonic-gate 	    nlwp--, Lsp = (lwpstatus_t *)((uintptr_t)Lsp + Lhp->pr_entsize)) {
2754*0Sstevel@tonic-gate 		if ((rv = func(cd, Lsp)) != 0)
2755*0Sstevel@tonic-gate 			break;
2756*0Sstevel@tonic-gate 	}
2757*0Sstevel@tonic-gate 
2758*0Sstevel@tonic-gate 	free(Lhp);
2759*0Sstevel@tonic-gate 	return (rv);
2760*0Sstevel@tonic-gate }
2761*0Sstevel@tonic-gate 
2762*0Sstevel@tonic-gate /*
2763*0Sstevel@tonic-gate  * Extended LWP iteration interface.
2764*0Sstevel@tonic-gate  * Iterate over all LWPs, active and zombie.
2765*0Sstevel@tonic-gate  */
2766*0Sstevel@tonic-gate int
2767*0Sstevel@tonic-gate Plwp_iter_all(struct ps_prochandle *P, proc_lwp_all_f *func, void *cd)
2768*0Sstevel@tonic-gate {
2769*0Sstevel@tonic-gate 	prheader_t *Lhp = NULL;
2770*0Sstevel@tonic-gate 	lwpstatus_t *Lsp;
2771*0Sstevel@tonic-gate 	lwpstatus_t *sp;
2772*0Sstevel@tonic-gate 	prheader_t *Lphp = NULL;
2773*0Sstevel@tonic-gate 	lwpsinfo_t *Lpsp;
2774*0Sstevel@tonic-gate 	long nstat;
2775*0Sstevel@tonic-gate 	long ninfo;
2776*0Sstevel@tonic-gate 	int rv;
2777*0Sstevel@tonic-gate 
2778*0Sstevel@tonic-gate retry:
2779*0Sstevel@tonic-gate 	if (Lhp != NULL)
2780*0Sstevel@tonic-gate 		free(Lhp);
2781*0Sstevel@tonic-gate 	if (Lphp != NULL)
2782*0Sstevel@tonic-gate 		free(Lphp);
2783*0Sstevel@tonic-gate 	if (P->state == PS_RUN)
2784*0Sstevel@tonic-gate 		(void) Pstopstatus(P, PCNULL, 0);
2785*0Sstevel@tonic-gate 	(void) Ppsinfo(P);
2786*0Sstevel@tonic-gate 
2787*0Sstevel@tonic-gate 	if (P->state == PS_STOP)
2788*0Sstevel@tonic-gate 		Psync(P);
2789*0Sstevel@tonic-gate 
2790*0Sstevel@tonic-gate 	/*
2791*0Sstevel@tonic-gate 	 * For either live processes or cores, the single LWP case is easy:
2792*0Sstevel@tonic-gate 	 * the pstatus_t contains the lwpstatus_t for the only LWP and
2793*0Sstevel@tonic-gate 	 * the psinfo_t contains the lwpsinfo_t for the only LWP.
2794*0Sstevel@tonic-gate 	 */
2795*0Sstevel@tonic-gate 	if (P->status.pr_nlwp + P->status.pr_nzomb <= 1)
2796*0Sstevel@tonic-gate 		return (func(cd, &P->status.pr_lwp, &P->psinfo.pr_lwp));
2797*0Sstevel@tonic-gate 
2798*0Sstevel@tonic-gate 	/*
2799*0Sstevel@tonic-gate 	 * For the core file multi-LWP case, we just iterate through the
2800*0Sstevel@tonic-gate 	 * list of LWP structs we read in from the core file.
2801*0Sstevel@tonic-gate 	 */
2802*0Sstevel@tonic-gate 	if (P->state == PS_DEAD) {
2803*0Sstevel@tonic-gate 		lwp_info_t *lwp = list_prev(&P->core->core_lwp_head);
2804*0Sstevel@tonic-gate 		uint_t i;
2805*0Sstevel@tonic-gate 
2806*0Sstevel@tonic-gate 		for (i = 0; i < P->core->core_nlwp; i++, lwp = list_prev(lwp)) {
2807*0Sstevel@tonic-gate 			sp = (lwp->lwp_psinfo.pr_sname == 'Z')? NULL :
2808*0Sstevel@tonic-gate 				&lwp->lwp_status;
2809*0Sstevel@tonic-gate 			if ((rv = func(cd, sp, &lwp->lwp_psinfo)) != 0)
2810*0Sstevel@tonic-gate 				break;
2811*0Sstevel@tonic-gate 		}
2812*0Sstevel@tonic-gate 
2813*0Sstevel@tonic-gate 		return (rv);
2814*0Sstevel@tonic-gate 	}
2815*0Sstevel@tonic-gate 
2816*0Sstevel@tonic-gate 	/*
2817*0Sstevel@tonic-gate 	 * For the live process multi-LWP case, we have to work a little
2818*0Sstevel@tonic-gate 	 * harder: the /proc/pid/lstatus file has the array of lwpstatus_t's
2819*0Sstevel@tonic-gate 	 * and the /proc/pid/lpsinfo file has the array of lwpsinfo_t's.
2820*0Sstevel@tonic-gate 	 */
2821*0Sstevel@tonic-gate 	if ((Lhp = read_lfile(P, "lstatus")) == NULL)
2822*0Sstevel@tonic-gate 		return (-1);
2823*0Sstevel@tonic-gate 	if ((Lphp = read_lfile(P, "lpsinfo")) == NULL) {
2824*0Sstevel@tonic-gate 		free(Lhp);
2825*0Sstevel@tonic-gate 		return (-1);
2826*0Sstevel@tonic-gate 	}
2827*0Sstevel@tonic-gate 
2828*0Sstevel@tonic-gate 	/*
2829*0Sstevel@tonic-gate 	 * If we are looking at a running process, or one we do not control,
2830*0Sstevel@tonic-gate 	 * the active and zombie lwps in the process may have changed since
2831*0Sstevel@tonic-gate 	 * we read the process status structure.  If so, just start over.
2832*0Sstevel@tonic-gate 	 */
2833*0Sstevel@tonic-gate 	if (Lhp->pr_nent != P->status.pr_nlwp ||
2834*0Sstevel@tonic-gate 	    Lphp->pr_nent != P->status.pr_nlwp + P->status.pr_nzomb)
2835*0Sstevel@tonic-gate 		goto retry;
2836*0Sstevel@tonic-gate 
2837*0Sstevel@tonic-gate 	/*
2838*0Sstevel@tonic-gate 	 * To be perfectly safe, prescan the two arrays, checking consistency.
2839*0Sstevel@tonic-gate 	 * We rely on /proc giving us lwpstatus_t's and lwpsinfo_t's in the
2840*0Sstevel@tonic-gate 	 * same order (the lwp directory order) in their respective files.
2841*0Sstevel@tonic-gate 	 * We also rely on there being (possibly) more lwpsinfo_t's than
2842*0Sstevel@tonic-gate 	 * lwpstatus_t's (the extra lwpsinfo_t's are for zombie lwps).
2843*0Sstevel@tonic-gate 	 */
2844*0Sstevel@tonic-gate 	Lsp = (lwpstatus_t *)(uintptr_t)(Lhp + 1);
2845*0Sstevel@tonic-gate 	Lpsp = (lwpsinfo_t *)(uintptr_t)(Lphp + 1);
2846*0Sstevel@tonic-gate 	nstat = Lhp->pr_nent;
2847*0Sstevel@tonic-gate 	for (ninfo = Lphp->pr_nent; ninfo != 0; ninfo--) {
2848*0Sstevel@tonic-gate 		if (Lpsp->pr_sname != 'Z') {
2849*0Sstevel@tonic-gate 			/*
2850*0Sstevel@tonic-gate 			 * Not a zombie lwp; check for matching lwpids.
2851*0Sstevel@tonic-gate 			 */
2852*0Sstevel@tonic-gate 			if (nstat == 0 || Lsp->pr_lwpid != Lpsp->pr_lwpid)
2853*0Sstevel@tonic-gate 				goto retry;
2854*0Sstevel@tonic-gate 			Lsp = (lwpstatus_t *)((uintptr_t)Lsp + Lhp->pr_entsize);
2855*0Sstevel@tonic-gate 			nstat--;
2856*0Sstevel@tonic-gate 		}
2857*0Sstevel@tonic-gate 		Lpsp = (lwpsinfo_t *)((uintptr_t)Lpsp + Lphp->pr_entsize);
2858*0Sstevel@tonic-gate 	}
2859*0Sstevel@tonic-gate 	if (nstat != 0)
2860*0Sstevel@tonic-gate 		goto retry;
2861*0Sstevel@tonic-gate 
2862*0Sstevel@tonic-gate 	/*
2863*0Sstevel@tonic-gate 	 * Rescan, this time for real.
2864*0Sstevel@tonic-gate 	 */
2865*0Sstevel@tonic-gate 	Lsp = (lwpstatus_t *)(uintptr_t)(Lhp + 1);
2866*0Sstevel@tonic-gate 	Lpsp = (lwpsinfo_t *)(uintptr_t)(Lphp + 1);
2867*0Sstevel@tonic-gate 	for (ninfo = Lphp->pr_nent; ninfo != 0; ninfo--) {
2868*0Sstevel@tonic-gate 		if (Lpsp->pr_sname != 'Z') {
2869*0Sstevel@tonic-gate 			sp = Lsp;
2870*0Sstevel@tonic-gate 			Lsp = (lwpstatus_t *)((uintptr_t)Lsp + Lhp->pr_entsize);
2871*0Sstevel@tonic-gate 		} else {
2872*0Sstevel@tonic-gate 			sp = NULL;
2873*0Sstevel@tonic-gate 		}
2874*0Sstevel@tonic-gate 		if ((rv = func(cd, sp, Lpsp)) != 0)
2875*0Sstevel@tonic-gate 			break;
2876*0Sstevel@tonic-gate 		Lpsp = (lwpsinfo_t *)((uintptr_t)Lpsp + Lphp->pr_entsize);
2877*0Sstevel@tonic-gate 	}
2878*0Sstevel@tonic-gate 
2879*0Sstevel@tonic-gate 	free(Lhp);
2880*0Sstevel@tonic-gate 	free(Lphp);
2881*0Sstevel@tonic-gate 	return (rv);
2882*0Sstevel@tonic-gate }
2883*0Sstevel@tonic-gate 
2884*0Sstevel@tonic-gate core_content_t
2885*0Sstevel@tonic-gate Pcontent(struct ps_prochandle *P)
2886*0Sstevel@tonic-gate {
2887*0Sstevel@tonic-gate 	if (P->state == PS_DEAD)
2888*0Sstevel@tonic-gate 		return (P->core->core_content);
2889*0Sstevel@tonic-gate 	if (P->state == PS_IDLE)
2890*0Sstevel@tonic-gate 		return (CC_CONTENT_TEXT | CC_CONTENT_DATA | CC_CONTENT_CTF);
2891*0Sstevel@tonic-gate 
2892*0Sstevel@tonic-gate 	return (CC_CONTENT_ALL);
2893*0Sstevel@tonic-gate }
2894*0Sstevel@tonic-gate 
2895*0Sstevel@tonic-gate /*
2896*0Sstevel@tonic-gate  * =================================================================
2897*0Sstevel@tonic-gate  * The remainder of the functions in this file are for the
2898*0Sstevel@tonic-gate  * control of individual LWPs in the controlled process.
2899*0Sstevel@tonic-gate  * =================================================================
2900*0Sstevel@tonic-gate  */
2901*0Sstevel@tonic-gate 
2902*0Sstevel@tonic-gate /*
2903*0Sstevel@tonic-gate  * Find an entry in the process hash table for the specified lwpid.
2904*0Sstevel@tonic-gate  * The entry will either point to an existing struct ps_lwphandle
2905*0Sstevel@tonic-gate  * or it will point to an empty slot for a new struct ps_lwphandle.
2906*0Sstevel@tonic-gate  */
2907*0Sstevel@tonic-gate static struct ps_lwphandle **
2908*0Sstevel@tonic-gate Lfind(struct ps_prochandle *P, lwpid_t lwpid)
2909*0Sstevel@tonic-gate {
2910*0Sstevel@tonic-gate 	struct ps_lwphandle **Lp;
2911*0Sstevel@tonic-gate 	struct ps_lwphandle *L;
2912*0Sstevel@tonic-gate 
2913*0Sstevel@tonic-gate 	for (Lp = &P->hashtab[lwpid % (HASHSIZE - 1)];
2914*0Sstevel@tonic-gate 	    (L = *Lp) != NULL; Lp = &L->lwp_hash)
2915*0Sstevel@tonic-gate 		if (L->lwp_id == lwpid)
2916*0Sstevel@tonic-gate 			break;
2917*0Sstevel@tonic-gate 	return (Lp);
2918*0Sstevel@tonic-gate }
2919*0Sstevel@tonic-gate 
2920*0Sstevel@tonic-gate /*
2921*0Sstevel@tonic-gate  * Grab an LWP contained within the controlled process.
2922*0Sstevel@tonic-gate  * Return an opaque pointer to its LWP control structure.
2923*0Sstevel@tonic-gate  *	perr: pointer to error return code.
2924*0Sstevel@tonic-gate  */
2925*0Sstevel@tonic-gate struct ps_lwphandle *
2926*0Sstevel@tonic-gate Lgrab(struct ps_prochandle *P, lwpid_t lwpid, int *perr)
2927*0Sstevel@tonic-gate {
2928*0Sstevel@tonic-gate 	struct ps_lwphandle **Lp;
2929*0Sstevel@tonic-gate 	struct ps_lwphandle *L;
2930*0Sstevel@tonic-gate 	int fd;
2931*0Sstevel@tonic-gate 	char procname[100];
2932*0Sstevel@tonic-gate 	char *fname;
2933*0Sstevel@tonic-gate 	int rc = 0;
2934*0Sstevel@tonic-gate 
2935*0Sstevel@tonic-gate 	(void) mutex_lock(&P->proc_lock);
2936*0Sstevel@tonic-gate 
2937*0Sstevel@tonic-gate 	if (P->state == PS_UNDEAD || P->state == PS_IDLE)
2938*0Sstevel@tonic-gate 		rc = G_NOPROC;
2939*0Sstevel@tonic-gate 	else if (P->hashtab == NULL &&
2940*0Sstevel@tonic-gate 	    (P->hashtab = calloc(HASHSIZE, sizeof (struct ps_lwphandle *)))
2941*0Sstevel@tonic-gate 	    == NULL)
2942*0Sstevel@tonic-gate 		rc = G_STRANGE;
2943*0Sstevel@tonic-gate 	else if (*(Lp = Lfind(P, lwpid)) != NULL)
2944*0Sstevel@tonic-gate 		rc = G_BUSY;
2945*0Sstevel@tonic-gate 	else if ((L = malloc(sizeof (struct ps_lwphandle))) == NULL)
2946*0Sstevel@tonic-gate 		rc = G_STRANGE;
2947*0Sstevel@tonic-gate 	if (rc) {
2948*0Sstevel@tonic-gate 		*perr = rc;
2949*0Sstevel@tonic-gate 		(void) mutex_unlock(&P->proc_lock);
2950*0Sstevel@tonic-gate 		return (NULL);
2951*0Sstevel@tonic-gate 	}
2952*0Sstevel@tonic-gate 
2953*0Sstevel@tonic-gate 	(void) memset(L, 0, sizeof (*L));
2954*0Sstevel@tonic-gate 	L->lwp_ctlfd = -1;
2955*0Sstevel@tonic-gate 	L->lwp_statfd = -1;
2956*0Sstevel@tonic-gate 	L->lwp_proc = P;
2957*0Sstevel@tonic-gate 	L->lwp_id = lwpid;
2958*0Sstevel@tonic-gate 	*Lp = L;	/* insert into the hash table */
2959*0Sstevel@tonic-gate 
2960*0Sstevel@tonic-gate 	if (P->state == PS_DEAD) {	/* core file */
2961*0Sstevel@tonic-gate 		if (getlwpstatus(P, lwpid, &L->lwp_status) == -1) {
2962*0Sstevel@tonic-gate 			rc = G_NOPROC;
2963*0Sstevel@tonic-gate 			goto err;
2964*0Sstevel@tonic-gate 		}
2965*0Sstevel@tonic-gate 		L->lwp_state = PS_DEAD;
2966*0Sstevel@tonic-gate 		*perr = 0;
2967*0Sstevel@tonic-gate 		(void) mutex_unlock(&P->proc_lock);
2968*0Sstevel@tonic-gate 		return (L);
2969*0Sstevel@tonic-gate 	}
2970*0Sstevel@tonic-gate 
2971*0Sstevel@tonic-gate 	/*
2972*0Sstevel@tonic-gate 	 * Open the /proc/<pid>/lwp/<lwpid> files
2973*0Sstevel@tonic-gate 	 */
2974*0Sstevel@tonic-gate 	(void) sprintf(procname, "/proc/%d/lwp/%d/", (int)P->pid, (int)lwpid);
2975*0Sstevel@tonic-gate 	fname = procname + strlen(procname);
2976*0Sstevel@tonic-gate 	(void) set_minfd();
2977*0Sstevel@tonic-gate 
2978*0Sstevel@tonic-gate 	(void) strcpy(fname, "lwpstatus");
2979*0Sstevel@tonic-gate 	if ((fd = open(procname, O_RDONLY)) < 0 ||
2980*0Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
2981*0Sstevel@tonic-gate 		switch (errno) {
2982*0Sstevel@tonic-gate 		case ENOENT:
2983*0Sstevel@tonic-gate 			rc = G_NOPROC;
2984*0Sstevel@tonic-gate 			break;
2985*0Sstevel@tonic-gate 		default:
2986*0Sstevel@tonic-gate 			dprintf("Lgrab: failed to open %s: %s\n",
2987*0Sstevel@tonic-gate 			    procname, strerror(errno));
2988*0Sstevel@tonic-gate 			rc = G_STRANGE;
2989*0Sstevel@tonic-gate 			break;
2990*0Sstevel@tonic-gate 		}
2991*0Sstevel@tonic-gate 		goto err;
2992*0Sstevel@tonic-gate 	}
2993*0Sstevel@tonic-gate 	L->lwp_statfd = fd;
2994*0Sstevel@tonic-gate 
2995*0Sstevel@tonic-gate 	if (pread(fd, &L->lwp_status, sizeof (L->lwp_status), (off_t)0) < 0) {
2996*0Sstevel@tonic-gate 		switch (errno) {
2997*0Sstevel@tonic-gate 		case ENOENT:
2998*0Sstevel@tonic-gate 			rc = G_NOPROC;
2999*0Sstevel@tonic-gate 			break;
3000*0Sstevel@tonic-gate 		default:
3001*0Sstevel@tonic-gate 			dprintf("Lgrab: failed to read %s: %s\n",
3002*0Sstevel@tonic-gate 			    procname, strerror(errno));
3003*0Sstevel@tonic-gate 			rc = G_STRANGE;
3004*0Sstevel@tonic-gate 			break;
3005*0Sstevel@tonic-gate 		}
3006*0Sstevel@tonic-gate 		goto err;
3007*0Sstevel@tonic-gate 	}
3008*0Sstevel@tonic-gate 
3009*0Sstevel@tonic-gate 	(void) strcpy(fname, "lwpctl");
3010*0Sstevel@tonic-gate 	if ((fd = open(procname, O_WRONLY)) < 0 ||
3011*0Sstevel@tonic-gate 	    (fd = dupfd(fd, 0)) < 0) {
3012*0Sstevel@tonic-gate 		switch (errno) {
3013*0Sstevel@tonic-gate 		case ENOENT:
3014*0Sstevel@tonic-gate 			rc = G_NOPROC;
3015*0Sstevel@tonic-gate 			break;
3016*0Sstevel@tonic-gate 		default:
3017*0Sstevel@tonic-gate 			dprintf("Lgrab: failed to open %s: %s\n",
3018*0Sstevel@tonic-gate 			    procname, strerror(errno));
3019*0Sstevel@tonic-gate 			rc = G_STRANGE;
3020*0Sstevel@tonic-gate 			break;
3021*0Sstevel@tonic-gate 		}
3022*0Sstevel@tonic-gate 		goto err;
3023*0Sstevel@tonic-gate 	}
3024*0Sstevel@tonic-gate 	L->lwp_ctlfd = fd;
3025*0Sstevel@tonic-gate 
3026*0Sstevel@tonic-gate 	L->lwp_state =
3027*0Sstevel@tonic-gate 		((L->lwp_status.pr_flags & (PR_STOPPED|PR_ISTOP))
3028*0Sstevel@tonic-gate 		== (PR_STOPPED|PR_ISTOP))?
3029*0Sstevel@tonic-gate 		PS_STOP : PS_RUN;
3030*0Sstevel@tonic-gate 
3031*0Sstevel@tonic-gate 	*perr = 0;
3032*0Sstevel@tonic-gate 	(void) mutex_unlock(&P->proc_lock);
3033*0Sstevel@tonic-gate 	return (L);
3034*0Sstevel@tonic-gate 
3035*0Sstevel@tonic-gate err:
3036*0Sstevel@tonic-gate 	Lfree_internal(P, L);
3037*0Sstevel@tonic-gate 	*perr = rc;
3038*0Sstevel@tonic-gate 	(void) mutex_unlock(&P->proc_lock);
3039*0Sstevel@tonic-gate 	return (NULL);
3040*0Sstevel@tonic-gate }
3041*0Sstevel@tonic-gate 
3042*0Sstevel@tonic-gate /*
3043*0Sstevel@tonic-gate  * Return a printable string corresponding to an Lgrab() error return.
3044*0Sstevel@tonic-gate  */
3045*0Sstevel@tonic-gate const char *
3046*0Sstevel@tonic-gate Lgrab_error(int error)
3047*0Sstevel@tonic-gate {
3048*0Sstevel@tonic-gate 	const char *str;
3049*0Sstevel@tonic-gate 
3050*0Sstevel@tonic-gate 	switch (error) {
3051*0Sstevel@tonic-gate 	case G_NOPROC:
3052*0Sstevel@tonic-gate 		str = "no such LWP";
3053*0Sstevel@tonic-gate 		break;
3054*0Sstevel@tonic-gate 	case G_BUSY:
3055*0Sstevel@tonic-gate 		str = "LWP already grabbed";
3056*0Sstevel@tonic-gate 		break;
3057*0Sstevel@tonic-gate 	case G_STRANGE:
3058*0Sstevel@tonic-gate 		str = "unanticipated system error";
3059*0Sstevel@tonic-gate 		break;
3060*0Sstevel@tonic-gate 	default:
3061*0Sstevel@tonic-gate 		str = "unknown error";
3062*0Sstevel@tonic-gate 		break;
3063*0Sstevel@tonic-gate 	}
3064*0Sstevel@tonic-gate 
3065*0Sstevel@tonic-gate 	return (str);
3066*0Sstevel@tonic-gate }
3067*0Sstevel@tonic-gate 
3068*0Sstevel@tonic-gate /*
3069*0Sstevel@tonic-gate  * Free an LWP control structure.
3070*0Sstevel@tonic-gate  */
3071*0Sstevel@tonic-gate void
3072*0Sstevel@tonic-gate Lfree(struct ps_lwphandle *L)
3073*0Sstevel@tonic-gate {
3074*0Sstevel@tonic-gate 	struct ps_prochandle *P = L->lwp_proc;
3075*0Sstevel@tonic-gate 
3076*0Sstevel@tonic-gate 	(void) mutex_lock(&P->proc_lock);
3077*0Sstevel@tonic-gate 	Lfree_internal(P, L);
3078*0Sstevel@tonic-gate 	(void) mutex_unlock(&P->proc_lock);
3079*0Sstevel@tonic-gate }
3080*0Sstevel@tonic-gate 
3081*0Sstevel@tonic-gate static void
3082*0Sstevel@tonic-gate Lfree_internal(struct ps_prochandle *P, struct ps_lwphandle *L)
3083*0Sstevel@tonic-gate {
3084*0Sstevel@tonic-gate 	*Lfind(P, L->lwp_id) = L->lwp_hash;	/* delete from hash table */
3085*0Sstevel@tonic-gate 	if (L->lwp_ctlfd >= 0)
3086*0Sstevel@tonic-gate 		(void) close(L->lwp_ctlfd);
3087*0Sstevel@tonic-gate 	if (L->lwp_statfd >= 0)
3088*0Sstevel@tonic-gate 		(void) close(L->lwp_statfd);
3089*0Sstevel@tonic-gate 
3090*0Sstevel@tonic-gate 	/* clear out the structure as a precaution against reuse */
3091*0Sstevel@tonic-gate 	(void) memset(L, 0, sizeof (*L));
3092*0Sstevel@tonic-gate 	L->lwp_ctlfd = -1;
3093*0Sstevel@tonic-gate 	L->lwp_statfd = -1;
3094*0Sstevel@tonic-gate 
3095*0Sstevel@tonic-gate 	free(L);
3096*0Sstevel@tonic-gate }
3097*0Sstevel@tonic-gate 
3098*0Sstevel@tonic-gate /*
3099*0Sstevel@tonic-gate  * Return the state of the process, one of the PS_* values.
3100*0Sstevel@tonic-gate  */
3101*0Sstevel@tonic-gate int
3102*0Sstevel@tonic-gate Lstate(struct ps_lwphandle *L)
3103*0Sstevel@tonic-gate {
3104*0Sstevel@tonic-gate 	return (L->lwp_state);
3105*0Sstevel@tonic-gate }
3106*0Sstevel@tonic-gate 
3107*0Sstevel@tonic-gate /*
3108*0Sstevel@tonic-gate  * Return the open control file descriptor for the LWP.
3109*0Sstevel@tonic-gate  * Clients must not close this file descriptor, nor use it
3110*0Sstevel@tonic-gate  * after the LWP is freed.
3111*0Sstevel@tonic-gate  */
3112*0Sstevel@tonic-gate int
3113*0Sstevel@tonic-gate Lctlfd(struct ps_lwphandle *L)
3114*0Sstevel@tonic-gate {
3115*0Sstevel@tonic-gate 	return (L->lwp_ctlfd);
3116*0Sstevel@tonic-gate }
3117*0Sstevel@tonic-gate 
3118*0Sstevel@tonic-gate /*
3119*0Sstevel@tonic-gate  * Return a pointer to the LWP lwpsinfo structure.
3120*0Sstevel@tonic-gate  * Clients should not hold on to this pointer indefinitely.
3121*0Sstevel@tonic-gate  * It will become invalid on Lfree().
3122*0Sstevel@tonic-gate  */
3123*0Sstevel@tonic-gate const lwpsinfo_t *
3124*0Sstevel@tonic-gate Lpsinfo(struct ps_lwphandle *L)
3125*0Sstevel@tonic-gate {
3126*0Sstevel@tonic-gate 	if (Plwp_getpsinfo(L->lwp_proc, L->lwp_id, &L->lwp_psinfo) == -1)
3127*0Sstevel@tonic-gate 		return (NULL);
3128*0Sstevel@tonic-gate 
3129*0Sstevel@tonic-gate 	return (&L->lwp_psinfo);
3130*0Sstevel@tonic-gate }
3131*0Sstevel@tonic-gate 
3132*0Sstevel@tonic-gate /*
3133*0Sstevel@tonic-gate  * Return a pointer to the LWP status structure.
3134*0Sstevel@tonic-gate  * Clients should not hold on to this pointer indefinitely.
3135*0Sstevel@tonic-gate  * It will become invalid on Lfree().
3136*0Sstevel@tonic-gate  */
3137*0Sstevel@tonic-gate const lwpstatus_t *
3138*0Sstevel@tonic-gate Lstatus(struct ps_lwphandle *L)
3139*0Sstevel@tonic-gate {
3140*0Sstevel@tonic-gate 	return (&L->lwp_status);
3141*0Sstevel@tonic-gate }
3142*0Sstevel@tonic-gate 
3143*0Sstevel@tonic-gate /*
3144*0Sstevel@tonic-gate  * Given an LWP handle, return the process handle.
3145*0Sstevel@tonic-gate  */
3146*0Sstevel@tonic-gate struct ps_prochandle *
3147*0Sstevel@tonic-gate Lprochandle(struct ps_lwphandle *L)
3148*0Sstevel@tonic-gate {
3149*0Sstevel@tonic-gate 	return (L->lwp_proc);
3150*0Sstevel@tonic-gate }
3151*0Sstevel@tonic-gate 
3152*0Sstevel@tonic-gate /*
3153*0Sstevel@tonic-gate  * Ensure that all cached state is written to the LWP.
3154*0Sstevel@tonic-gate  * The cached state is the LWP's signal mask and registers.
3155*0Sstevel@tonic-gate  */
3156*0Sstevel@tonic-gate void
3157*0Sstevel@tonic-gate Lsync(struct ps_lwphandle *L)
3158*0Sstevel@tonic-gate {
3159*0Sstevel@tonic-gate 	int ctlfd = L->lwp_ctlfd;
3160*0Sstevel@tonic-gate 	long cmd[2];
3161*0Sstevel@tonic-gate 	iovec_t iov[4];
3162*0Sstevel@tonic-gate 	int n = 0;
3163*0Sstevel@tonic-gate 
3164*0Sstevel@tonic-gate 	if (L->lwp_flags & SETHOLD) {
3165*0Sstevel@tonic-gate 		cmd[0] = PCSHOLD;
3166*0Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[0];
3167*0Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
3168*0Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&L->lwp_status.pr_lwphold;
3169*0Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (L->lwp_status.pr_lwphold);
3170*0Sstevel@tonic-gate 	}
3171*0Sstevel@tonic-gate 	if (L->lwp_flags & SETREGS) {
3172*0Sstevel@tonic-gate 		cmd[1] = PCSREG;
3173*0Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&cmd[1];
3174*0Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (long);
3175*0Sstevel@tonic-gate 		iov[n].iov_base = (caddr_t)&L->lwp_status.pr_reg[0];
3176*0Sstevel@tonic-gate 		iov[n++].iov_len = sizeof (L->lwp_status.pr_reg);
3177*0Sstevel@tonic-gate 	}
3178*0Sstevel@tonic-gate 
3179*0Sstevel@tonic-gate 	if (n == 0 || writev(ctlfd, iov, n) < 0)
3180*0Sstevel@tonic-gate 		return;		/* nothing to do or write failed */
3181*0Sstevel@tonic-gate 
3182*0Sstevel@tonic-gate 	L->lwp_flags &= ~(SETHOLD|SETREGS);
3183*0Sstevel@tonic-gate }
3184*0Sstevel@tonic-gate 
3185*0Sstevel@tonic-gate /*
3186*0Sstevel@tonic-gate  * Wait for the specified LWP to stop or terminate.
3187*0Sstevel@tonic-gate  * Or, just get the current status (PCNULL).
3188*0Sstevel@tonic-gate  * Or, direct it to stop and get the current status (PCDSTOP).
3189*0Sstevel@tonic-gate  */
3190*0Sstevel@tonic-gate static int
3191*0Sstevel@tonic-gate Lstopstatus(struct ps_lwphandle *L,
3192*0Sstevel@tonic-gate 	long request,		/* PCNULL, PCDSTOP, PCSTOP, PCWSTOP */
3193*0Sstevel@tonic-gate 	uint_t msec)		/* if non-zero, timeout in milliseconds */
3194*0Sstevel@tonic-gate {
3195*0Sstevel@tonic-gate 	int ctlfd = L->lwp_ctlfd;
3196*0Sstevel@tonic-gate 	long ctl[3];
3197*0Sstevel@tonic-gate 	ssize_t rc;
3198*0Sstevel@tonic-gate 	int err;
3199*0Sstevel@tonic-gate 
3200*0Sstevel@tonic-gate 	switch (L->lwp_state) {
3201*0Sstevel@tonic-gate 	case PS_RUN:
3202*0Sstevel@tonic-gate 		break;
3203*0Sstevel@tonic-gate 	case PS_STOP:
3204*0Sstevel@tonic-gate 		if (request != PCNULL && request != PCDSTOP)
3205*0Sstevel@tonic-gate 			return (0);
3206*0Sstevel@tonic-gate 		break;
3207*0Sstevel@tonic-gate 	case PS_LOST:
3208*0Sstevel@tonic-gate 		if (request != PCNULL) {
3209*0Sstevel@tonic-gate 			errno = EAGAIN;
3210*0Sstevel@tonic-gate 			return (-1);
3211*0Sstevel@tonic-gate 		}
3212*0Sstevel@tonic-gate 		break;
3213*0Sstevel@tonic-gate 	case PS_UNDEAD:
3214*0Sstevel@tonic-gate 	case PS_DEAD:
3215*0Sstevel@tonic-gate 		if (request != PCNULL) {
3216*0Sstevel@tonic-gate 			errno = ENOENT;
3217*0Sstevel@tonic-gate 			return (-1);
3218*0Sstevel@tonic-gate 		}
3219*0Sstevel@tonic-gate 		break;
3220*0Sstevel@tonic-gate 	default:	/* corrupted state */
3221*0Sstevel@tonic-gate 		dprintf("Lstopstatus: corrupted state: %d\n", L->lwp_state);
3222*0Sstevel@tonic-gate 		errno = EINVAL;
3223*0Sstevel@tonic-gate 		return (-1);
3224*0Sstevel@tonic-gate 	}
3225*0Sstevel@tonic-gate 
3226*0Sstevel@tonic-gate 	ctl[0] = PCDSTOP;
3227*0Sstevel@tonic-gate 	ctl[1] = PCTWSTOP;
3228*0Sstevel@tonic-gate 	ctl[2] = (long)msec;
3229*0Sstevel@tonic-gate 	rc = 0;
3230*0Sstevel@tonic-gate 	switch (request) {
3231*0Sstevel@tonic-gate 	case PCSTOP:
3232*0Sstevel@tonic-gate 		rc = write(ctlfd, &ctl[0], 3*sizeof (long));
3233*0Sstevel@tonic-gate 		break;
3234*0Sstevel@tonic-gate 	case PCWSTOP:
3235*0Sstevel@tonic-gate 		rc = write(ctlfd, &ctl[1], 2*sizeof (long));
3236*0Sstevel@tonic-gate 		break;
3237*0Sstevel@tonic-gate 	case PCDSTOP:
3238*0Sstevel@tonic-gate 		rc = write(ctlfd, &ctl[0], 1*sizeof (long));
3239*0Sstevel@tonic-gate 		break;
3240*0Sstevel@tonic-gate 	case PCNULL:
3241*0Sstevel@tonic-gate 		if (L->lwp_state == PS_DEAD)
3242*0Sstevel@tonic-gate 			return (0); /* Nothing else to do for cores */
3243*0Sstevel@tonic-gate 		break;
3244*0Sstevel@tonic-gate 	default:	/* programming error */
3245*0Sstevel@tonic-gate 		errno = EINVAL;
3246*0Sstevel@tonic-gate 		return (-1);
3247*0Sstevel@tonic-gate 	}
3248*0Sstevel@tonic-gate 	err = (rc < 0)? errno : 0;
3249*0Sstevel@tonic-gate 	Lsync(L);
3250*0Sstevel@tonic-gate 
3251*0Sstevel@tonic-gate 	if (pread(L->lwp_statfd, &L->lwp_status,
3252*0Sstevel@tonic-gate 	    sizeof (L->lwp_status), (off_t)0) < 0)
3253*0Sstevel@tonic-gate 		err = errno;
3254*0Sstevel@tonic-gate 
3255*0Sstevel@tonic-gate 	if (err) {
3256*0Sstevel@tonic-gate 		switch (err) {
3257*0Sstevel@tonic-gate 		case EINTR:		/* user typed ctl-C */
3258*0Sstevel@tonic-gate 		case ERESTART:
3259*0Sstevel@tonic-gate 			dprintf("Lstopstatus: EINTR\n");
3260*0Sstevel@tonic-gate 			break;
3261*0Sstevel@tonic-gate 		case EAGAIN:		/* we lost control of the the process */
3262*0Sstevel@tonic-gate 			dprintf("Lstopstatus: EAGAIN\n");
3263*0Sstevel@tonic-gate 			L->lwp_state = PS_LOST;
3264*0Sstevel@tonic-gate 			errno = err;
3265*0Sstevel@tonic-gate 			return (-1);
3266*0Sstevel@tonic-gate 		default:
3267*0Sstevel@tonic-gate 			if (_libproc_debug) {
3268*0Sstevel@tonic-gate 				const char *errstr;
3269*0Sstevel@tonic-gate 
3270*0Sstevel@tonic-gate 				switch (request) {
3271*0Sstevel@tonic-gate 				case PCNULL:
3272*0Sstevel@tonic-gate 					errstr = "Lstopstatus PCNULL"; break;
3273*0Sstevel@tonic-gate 				case PCSTOP:
3274*0Sstevel@tonic-gate 					errstr = "Lstopstatus PCSTOP"; break;
3275*0Sstevel@tonic-gate 				case PCDSTOP:
3276*0Sstevel@tonic-gate 					errstr = "Lstopstatus PCDSTOP"; break;
3277*0Sstevel@tonic-gate 				case PCWSTOP:
3278*0Sstevel@tonic-gate 					errstr = "Lstopstatus PCWSTOP"; break;
3279*0Sstevel@tonic-gate 				default:
3280*0Sstevel@tonic-gate 					errstr = "Lstopstatus PC???"; break;
3281*0Sstevel@tonic-gate 				}
3282*0Sstevel@tonic-gate 				dprintf("%s: %s\n", errstr, strerror(err));
3283*0Sstevel@tonic-gate 			}
3284*0Sstevel@tonic-gate 			L->lwp_state = PS_UNDEAD;
3285*0Sstevel@tonic-gate 			errno = err;
3286*0Sstevel@tonic-gate 			return (-1);
3287*0Sstevel@tonic-gate 		}
3288*0Sstevel@tonic-gate 	}
3289*0Sstevel@tonic-gate 
3290*0Sstevel@tonic-gate 	if ((L->lwp_status.pr_flags & (PR_STOPPED|PR_ISTOP))
3291*0Sstevel@tonic-gate 	    != (PR_STOPPED|PR_ISTOP)) {
3292*0Sstevel@tonic-gate 		L->lwp_state = PS_RUN;
3293*0Sstevel@tonic-gate 		if (request == PCNULL || request == PCDSTOP || msec != 0)
3294*0Sstevel@tonic-gate 			return (0);
3295*0Sstevel@tonic-gate 		dprintf("Lstopstatus: LWP is not stopped\n");
3296*0Sstevel@tonic-gate 		errno = EPROTO;
3297*0Sstevel@tonic-gate 		return (-1);
3298*0Sstevel@tonic-gate 	}
3299*0Sstevel@tonic-gate 
3300*0Sstevel@tonic-gate 	L->lwp_state = PS_STOP;
3301*0Sstevel@tonic-gate 
3302*0Sstevel@tonic-gate 	if (_libproc_debug)	/* debugging */
3303*0Sstevel@tonic-gate 		prldump("Lstopstatus", &L->lwp_status);
3304*0Sstevel@tonic-gate 
3305*0Sstevel@tonic-gate 	switch (L->lwp_status.pr_why) {
3306*0Sstevel@tonic-gate 	case PR_SYSENTRY:
3307*0Sstevel@tonic-gate 	case PR_SYSEXIT:
3308*0Sstevel@tonic-gate 	case PR_REQUESTED:
3309*0Sstevel@tonic-gate 	case PR_SIGNALLED:
3310*0Sstevel@tonic-gate 	case PR_FAULTED:
3311*0Sstevel@tonic-gate 	case PR_JOBCONTROL:
3312*0Sstevel@tonic-gate 	case PR_SUSPENDED:
3313*0Sstevel@tonic-gate 		break;
3314*0Sstevel@tonic-gate 	default:
3315*0Sstevel@tonic-gate 		errno = EPROTO;
3316*0Sstevel@tonic-gate 		return (-1);
3317*0Sstevel@tonic-gate 	}
3318*0Sstevel@tonic-gate 
3319*0Sstevel@tonic-gate 	return (0);
3320*0Sstevel@tonic-gate }
3321*0Sstevel@tonic-gate 
3322*0Sstevel@tonic-gate /*
3323*0Sstevel@tonic-gate  * Wait for the LWP to stop for any reason.
3324*0Sstevel@tonic-gate  */
3325*0Sstevel@tonic-gate int
3326*0Sstevel@tonic-gate Lwait(struct ps_lwphandle *L, uint_t msec)
3327*0Sstevel@tonic-gate {
3328*0Sstevel@tonic-gate 	return (Lstopstatus(L, PCWSTOP, msec));
3329*0Sstevel@tonic-gate }
3330*0Sstevel@tonic-gate 
3331*0Sstevel@tonic-gate /*
3332*0Sstevel@tonic-gate  * Direct the LWP to stop; wait for it to stop.
3333*0Sstevel@tonic-gate  */
3334*0Sstevel@tonic-gate int
3335*0Sstevel@tonic-gate Lstop(struct ps_lwphandle *L, uint_t msec)
3336*0Sstevel@tonic-gate {
3337*0Sstevel@tonic-gate 	return (Lstopstatus(L, PCSTOP, msec));
3338*0Sstevel@tonic-gate }
3339*0Sstevel@tonic-gate 
3340*0Sstevel@tonic-gate /*
3341*0Sstevel@tonic-gate  * Direct the LWP to stop; don't wait.
3342*0Sstevel@tonic-gate  */
3343*0Sstevel@tonic-gate int
3344*0Sstevel@tonic-gate Ldstop(struct ps_lwphandle *L)
3345*0Sstevel@tonic-gate {
3346*0Sstevel@tonic-gate 	return (Lstopstatus(L, PCDSTOP, 0));
3347*0Sstevel@tonic-gate }
3348*0Sstevel@tonic-gate 
3349*0Sstevel@tonic-gate /*
3350*0Sstevel@tonic-gate  * Get the value of one register from stopped LWP.
3351*0Sstevel@tonic-gate  */
3352*0Sstevel@tonic-gate int
3353*0Sstevel@tonic-gate Lgetareg(struct ps_lwphandle *L, int regno, prgreg_t *preg)
3354*0Sstevel@tonic-gate {
3355*0Sstevel@tonic-gate 	if (regno < 0 || regno >= NPRGREG) {
3356*0Sstevel@tonic-gate 		errno = EINVAL;
3357*0Sstevel@tonic-gate 		return (-1);
3358*0Sstevel@tonic-gate 	}
3359*0Sstevel@tonic-gate 
3360*0Sstevel@tonic-gate 	if (L->lwp_state != PS_STOP) {
3361*0Sstevel@tonic-gate 		errno = EBUSY;
3362*0Sstevel@tonic-gate 		return (-1);
3363*0Sstevel@tonic-gate 	}
3364*0Sstevel@tonic-gate 
3365*0Sstevel@tonic-gate 	*preg = L->lwp_status.pr_reg[regno];
3366*0Sstevel@tonic-gate 	return (0);
3367*0Sstevel@tonic-gate }
3368*0Sstevel@tonic-gate 
3369*0Sstevel@tonic-gate /*
3370*0Sstevel@tonic-gate  * Put value of one register into stopped LWP.
3371*0Sstevel@tonic-gate  */
3372*0Sstevel@tonic-gate int
3373*0Sstevel@tonic-gate Lputareg(struct ps_lwphandle *L, int regno, prgreg_t reg)
3374*0Sstevel@tonic-gate {
3375*0Sstevel@tonic-gate 	if (regno < 0 || regno >= NPRGREG) {
3376*0Sstevel@tonic-gate 		errno = EINVAL;
3377*0Sstevel@tonic-gate 		return (-1);
3378*0Sstevel@tonic-gate 	}
3379*0Sstevel@tonic-gate 
3380*0Sstevel@tonic-gate 	if (L->lwp_state != PS_STOP) {
3381*0Sstevel@tonic-gate 		errno = EBUSY;
3382*0Sstevel@tonic-gate 		return (-1);
3383*0Sstevel@tonic-gate 	}
3384*0Sstevel@tonic-gate 
3385*0Sstevel@tonic-gate 	L->lwp_status.pr_reg[regno] = reg;
3386*0Sstevel@tonic-gate 	L->lwp_flags |= SETREGS;	/* set registers before continuing */
3387*0Sstevel@tonic-gate 	return (0);
3388*0Sstevel@tonic-gate }
3389*0Sstevel@tonic-gate 
3390*0Sstevel@tonic-gate int
3391*0Sstevel@tonic-gate Lsetrun(struct ps_lwphandle *L,
3392*0Sstevel@tonic-gate 	int sig,	/* signal to pass to LWP */
3393*0Sstevel@tonic-gate 	int flags)	/* PRSTEP|PRSABORT|PRSTOP|PRCSIG|PRCFAULT */
3394*0Sstevel@tonic-gate {
3395*0Sstevel@tonic-gate 	int ctlfd = L->lwp_ctlfd;
3396*0Sstevel@tonic-gate 	int sbits = (PR_DSTOP | PR_ISTOP | PR_ASLEEP);
3397*0Sstevel@tonic-gate 
3398*0Sstevel@tonic-gate 	long ctl[1 +					/* PCCFAULT	*/
3399*0Sstevel@tonic-gate 		1 + sizeof (siginfo_t)/sizeof (long) +	/* PCSSIG/PCCSIG */
3400*0Sstevel@tonic-gate 		2 ];					/* PCRUN	*/
3401*0Sstevel@tonic-gate 
3402*0Sstevel@tonic-gate 	long *ctlp = ctl;
3403*0Sstevel@tonic-gate 	size_t size;
3404*0Sstevel@tonic-gate 
3405*0Sstevel@tonic-gate 	if (L->lwp_state != PS_STOP &&
3406*0Sstevel@tonic-gate 	    (L->lwp_status.pr_flags & sbits) == 0) {
3407*0Sstevel@tonic-gate 		errno = EBUSY;
3408*0Sstevel@tonic-gate 		return (-1);
3409*0Sstevel@tonic-gate 	}
3410*0Sstevel@tonic-gate 
3411*0Sstevel@tonic-gate 	Lsync(L);	/* flush registers */
3412*0Sstevel@tonic-gate 
3413*0Sstevel@tonic-gate 	if (flags & PRCFAULT) {		/* clear current fault */
3414*0Sstevel@tonic-gate 		*ctlp++ = PCCFAULT;
3415*0Sstevel@tonic-gate 		flags &= ~PRCFAULT;
3416*0Sstevel@tonic-gate 	}
3417*0Sstevel@tonic-gate 
3418*0Sstevel@tonic-gate 	if (flags & PRCSIG) {		/* clear current signal */
3419*0Sstevel@tonic-gate 		*ctlp++ = PCCSIG;
3420*0Sstevel@tonic-gate 		flags &= ~PRCSIG;
3421*0Sstevel@tonic-gate 	} else if (sig && sig != L->lwp_status.pr_cursig) {
3422*0Sstevel@tonic-gate 		/* make current signal */
3423*0Sstevel@tonic-gate 		siginfo_t *infop;
3424*0Sstevel@tonic-gate 
3425*0Sstevel@tonic-gate 		*ctlp++ = PCSSIG;
3426*0Sstevel@tonic-gate 		infop = (siginfo_t *)ctlp;
3427*0Sstevel@tonic-gate 		(void) memset(infop, 0, sizeof (*infop));
3428*0Sstevel@tonic-gate 		infop->si_signo = sig;
3429*0Sstevel@tonic-gate 		ctlp += sizeof (siginfo_t) / sizeof (long);
3430*0Sstevel@tonic-gate 	}
3431*0Sstevel@tonic-gate 
3432*0Sstevel@tonic-gate 	*ctlp++ = PCRUN;
3433*0Sstevel@tonic-gate 	*ctlp++ = flags;
3434*0Sstevel@tonic-gate 	size = (char *)ctlp - (char *)ctl;
3435*0Sstevel@tonic-gate 
3436*0Sstevel@tonic-gate 	L->lwp_proc->info_valid = 0; /* will need to update map and file info */
3437*0Sstevel@tonic-gate 	L->lwp_proc->state = PS_RUN;
3438*0Sstevel@tonic-gate 	L->lwp_state = PS_RUN;
3439*0Sstevel@tonic-gate 
3440*0Sstevel@tonic-gate 	if (write(ctlfd, ctl, size) != size) {
3441*0Sstevel@tonic-gate 		/* Pretend that a job-stopped LWP is running */
3442*0Sstevel@tonic-gate 		if (errno != EBUSY || L->lwp_status.pr_why != PR_JOBCONTROL)
3443*0Sstevel@tonic-gate 			return (Lstopstatus(L, PCNULL, 0));
3444*0Sstevel@tonic-gate 	}
3445*0Sstevel@tonic-gate 
3446*0Sstevel@tonic-gate 	return (0);
3447*0Sstevel@tonic-gate }
3448*0Sstevel@tonic-gate 
3449*0Sstevel@tonic-gate int
3450*0Sstevel@tonic-gate Lclearsig(struct ps_lwphandle *L)
3451*0Sstevel@tonic-gate {
3452*0Sstevel@tonic-gate 	int ctlfd = L->lwp_ctlfd;
3453*0Sstevel@tonic-gate 	long ctl = PCCSIG;
3454*0Sstevel@tonic-gate 
3455*0Sstevel@tonic-gate 	if (write(ctlfd, &ctl, sizeof (ctl)) != sizeof (ctl))
3456*0Sstevel@tonic-gate 		return (-1);
3457*0Sstevel@tonic-gate 	L->lwp_status.pr_cursig = 0;
3458*0Sstevel@tonic-gate 	return (0);
3459*0Sstevel@tonic-gate }
3460*0Sstevel@tonic-gate 
3461*0Sstevel@tonic-gate int
3462*0Sstevel@tonic-gate Lclearfault(struct ps_lwphandle *L)
3463*0Sstevel@tonic-gate {
3464*0Sstevel@tonic-gate 	int ctlfd = L->lwp_ctlfd;
3465*0Sstevel@tonic-gate 	long ctl = PCCFAULT;
3466*0Sstevel@tonic-gate 
3467*0Sstevel@tonic-gate 	if (write(ctlfd, &ctl, sizeof (ctl)) != sizeof (ctl))
3468*0Sstevel@tonic-gate 		return (-1);
3469*0Sstevel@tonic-gate 	return (0);
3470*0Sstevel@tonic-gate }
3471*0Sstevel@tonic-gate 
3472*0Sstevel@tonic-gate /*
3473*0Sstevel@tonic-gate  * Step over a breakpoint, i.e., execute the instruction that
3474*0Sstevel@tonic-gate  * really belongs at the breakpoint location (the current %pc)
3475*0Sstevel@tonic-gate  * and leave the LWP stopped at the next instruction.
3476*0Sstevel@tonic-gate  */
3477*0Sstevel@tonic-gate int
3478*0Sstevel@tonic-gate Lxecbkpt(struct ps_lwphandle *L, ulong_t saved)
3479*0Sstevel@tonic-gate {
3480*0Sstevel@tonic-gate 	struct ps_prochandle *P = L->lwp_proc;
3481*0Sstevel@tonic-gate 	int rv, error;
3482*0Sstevel@tonic-gate 
3483*0Sstevel@tonic-gate 	if (L->lwp_state != PS_STOP) {
3484*0Sstevel@tonic-gate 		errno = EBUSY;
3485*0Sstevel@tonic-gate 		return (-1);
3486*0Sstevel@tonic-gate 	}
3487*0Sstevel@tonic-gate 
3488*0Sstevel@tonic-gate 	Lsync(L);
3489*0Sstevel@tonic-gate 	error = execute_bkpt(L->lwp_ctlfd,
3490*0Sstevel@tonic-gate 		&P->status.pr_flttrace, &L->lwp_status.pr_lwphold,
3491*0Sstevel@tonic-gate 		L->lwp_status.pr_reg[R_PC], saved);
3492*0Sstevel@tonic-gate 	rv = Lstopstatus(L, PCNULL, 0);
3493*0Sstevel@tonic-gate 
3494*0Sstevel@tonic-gate 	if (error != 0) {
3495*0Sstevel@tonic-gate 		if (L->lwp_status.pr_why == PR_JOBCONTROL &&
3496*0Sstevel@tonic-gate 		    error == EBUSY) {	/* jobcontrol stop -- back off */
3497*0Sstevel@tonic-gate 			L->lwp_state = PS_RUN;
3498*0Sstevel@tonic-gate 			return (0);
3499*0Sstevel@tonic-gate 		}
3500*0Sstevel@tonic-gate 		if (error == ENOENT)
3501*0Sstevel@tonic-gate 			return (0);
3502*0Sstevel@tonic-gate 		errno = error;
3503*0Sstevel@tonic-gate 		return (-1);
3504*0Sstevel@tonic-gate 	}
3505*0Sstevel@tonic-gate 
3506*0Sstevel@tonic-gate 	return (rv);
3507*0Sstevel@tonic-gate }
3508*0Sstevel@tonic-gate 
3509*0Sstevel@tonic-gate /*
3510*0Sstevel@tonic-gate  * Step over a watchpoint, i.e., execute the instruction that was stopped by
3511*0Sstevel@tonic-gate  * the watchpoint, and then leave the LWP stopped at the next instruction.
3512*0Sstevel@tonic-gate  */
3513*0Sstevel@tonic-gate int
3514*0Sstevel@tonic-gate Lxecwapt(struct ps_lwphandle *L, const prwatch_t *wp)
3515*0Sstevel@tonic-gate {
3516*0Sstevel@tonic-gate 	struct ps_prochandle *P = L->lwp_proc;
3517*0Sstevel@tonic-gate 	int rv, error;
3518*0Sstevel@tonic-gate 
3519*0Sstevel@tonic-gate 	if (L->lwp_state != PS_STOP) {
3520*0Sstevel@tonic-gate 		errno = EBUSY;
3521*0Sstevel@tonic-gate 		return (-1);
3522*0Sstevel@tonic-gate 	}
3523*0Sstevel@tonic-gate 
3524*0Sstevel@tonic-gate 	Lsync(L);
3525*0Sstevel@tonic-gate 	error = execute_wapt(L->lwp_ctlfd,
3526*0Sstevel@tonic-gate 		&P->status.pr_flttrace, &L->lwp_status.pr_lwphold, wp);
3527*0Sstevel@tonic-gate 	rv = Lstopstatus(L, PCNULL, 0);
3528*0Sstevel@tonic-gate 
3529*0Sstevel@tonic-gate 	if (error != 0) {
3530*0Sstevel@tonic-gate 		if (L->lwp_status.pr_why == PR_JOBCONTROL &&
3531*0Sstevel@tonic-gate 		    error == EBUSY) {	/* jobcontrol stop -- back off */
3532*0Sstevel@tonic-gate 			L->lwp_state = PS_RUN;
3533*0Sstevel@tonic-gate 			return (0);
3534*0Sstevel@tonic-gate 		}
3535*0Sstevel@tonic-gate 		if (error == ENOENT)
3536*0Sstevel@tonic-gate 			return (0);
3537*0Sstevel@tonic-gate 		errno = error;
3538*0Sstevel@tonic-gate 		return (-1);
3539*0Sstevel@tonic-gate 	}
3540*0Sstevel@tonic-gate 
3541*0Sstevel@tonic-gate 	return (rv);
3542*0Sstevel@tonic-gate }
3543*0Sstevel@tonic-gate 
3544*0Sstevel@tonic-gate int
3545*0Sstevel@tonic-gate Lstack(struct ps_lwphandle *L, stack_t *stkp)
3546*0Sstevel@tonic-gate {
3547*0Sstevel@tonic-gate 	struct ps_prochandle *P = L->lwp_proc;
3548*0Sstevel@tonic-gate 	uintptr_t addr = L->lwp_status.pr_ustack;
3549*0Sstevel@tonic-gate 
3550*0Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
3551*0Sstevel@tonic-gate 		if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp))
3552*0Sstevel@tonic-gate 			return (-1);
3553*0Sstevel@tonic-gate #ifdef _LP64
3554*0Sstevel@tonic-gate 	} else {
3555*0Sstevel@tonic-gate 		stack32_t stk32;
3556*0Sstevel@tonic-gate 
3557*0Sstevel@tonic-gate 		if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32))
3558*0Sstevel@tonic-gate 			return (-1);
3559*0Sstevel@tonic-gate 
3560*0Sstevel@tonic-gate 		stack_32_to_n(&stk32, stkp);
3561*0Sstevel@tonic-gate #endif
3562*0Sstevel@tonic-gate 	}
3563*0Sstevel@tonic-gate 
3564*0Sstevel@tonic-gate 	return (0);
3565*0Sstevel@tonic-gate }
3566*0Sstevel@tonic-gate 
3567*0Sstevel@tonic-gate int
3568*0Sstevel@tonic-gate Lmain_stack(struct ps_lwphandle *L, stack_t *stkp)
3569*0Sstevel@tonic-gate {
3570*0Sstevel@tonic-gate 	struct ps_prochandle *P = L->lwp_proc;
3571*0Sstevel@tonic-gate 
3572*0Sstevel@tonic-gate 	if (Lstack(L, stkp) != 0)
3573*0Sstevel@tonic-gate 		return (-1);
3574*0Sstevel@tonic-gate 
3575*0Sstevel@tonic-gate 	/*
3576*0Sstevel@tonic-gate 	 * If the SS_ONSTACK flag is set then this LWP is operating on the
3577*0Sstevel@tonic-gate 	 * alternate signal stack. We can recover the original stack from
3578*0Sstevel@tonic-gate 	 * pr_oldcontext.
3579*0Sstevel@tonic-gate 	 */
3580*0Sstevel@tonic-gate 	if (!(stkp->ss_flags & SS_ONSTACK))
3581*0Sstevel@tonic-gate 		return (0);
3582*0Sstevel@tonic-gate 
3583*0Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
3584*0Sstevel@tonic-gate 		ucontext_t *ctxp = (void *)L->lwp_status.pr_oldcontext;
3585*0Sstevel@tonic-gate 
3586*0Sstevel@tonic-gate 		if (Pread(P, stkp, sizeof (*stkp),
3587*0Sstevel@tonic-gate 		    (uintptr_t)&ctxp->uc_stack) != sizeof (*stkp))
3588*0Sstevel@tonic-gate 			return (-1);
3589*0Sstevel@tonic-gate #ifdef _LP64
3590*0Sstevel@tonic-gate 	} else {
3591*0Sstevel@tonic-gate 		ucontext32_t *ctxp = (void *)L->lwp_status.pr_oldcontext;
3592*0Sstevel@tonic-gate 		stack32_t stk32;
3593*0Sstevel@tonic-gate 
3594*0Sstevel@tonic-gate 		if (Pread(P, &stk32, sizeof (stk32),
3595*0Sstevel@tonic-gate 		    (uintptr_t)&ctxp->uc_stack) != sizeof (stk32))
3596*0Sstevel@tonic-gate 			return (-1);
3597*0Sstevel@tonic-gate 
3598*0Sstevel@tonic-gate 		stack_32_to_n(&stk32, stkp);
3599*0Sstevel@tonic-gate #endif
3600*0Sstevel@tonic-gate 	}
3601*0Sstevel@tonic-gate 
3602*0Sstevel@tonic-gate 	return (0);
3603*0Sstevel@tonic-gate }
3604*0Sstevel@tonic-gate 
3605*0Sstevel@tonic-gate int
3606*0Sstevel@tonic-gate Lalt_stack(struct ps_lwphandle *L, stack_t *stkp)
3607*0Sstevel@tonic-gate {
3608*0Sstevel@tonic-gate 	if (L->lwp_status.pr_altstack.ss_flags & SS_DISABLE) {
3609*0Sstevel@tonic-gate 		errno = ENODATA;
3610*0Sstevel@tonic-gate 		return (-1);
3611*0Sstevel@tonic-gate 	}
3612*0Sstevel@tonic-gate 
3613*0Sstevel@tonic-gate 	*stkp = L->lwp_status.pr_altstack;
3614*0Sstevel@tonic-gate 
3615*0Sstevel@tonic-gate 	return (0);
3616*0Sstevel@tonic-gate }
3617*0Sstevel@tonic-gate 
3618*0Sstevel@tonic-gate /*
3619*0Sstevel@tonic-gate  * Add a mapping to the given proc handle.  Resizes the array as appropriate and
3620*0Sstevel@tonic-gate  * manages reference counts on the given file_info_t.
3621*0Sstevel@tonic-gate  *
3622*0Sstevel@tonic-gate  * The 'map_relocate' member is used to tell Psort_mappings() that the
3623*0Sstevel@tonic-gate  * associated file_map pointer needs to be relocated after the mappings have
3624*0Sstevel@tonic-gate  * been sorted.  It is only set for the first mapping, and has no meaning
3625*0Sstevel@tonic-gate  * outside these two functions.
3626*0Sstevel@tonic-gate  */
3627*0Sstevel@tonic-gate int
3628*0Sstevel@tonic-gate Padd_mapping(struct ps_prochandle *P, off64_t off, file_info_t *fp,
3629*0Sstevel@tonic-gate     prmap_t *pmap)
3630*0Sstevel@tonic-gate {
3631*0Sstevel@tonic-gate 	map_info_t *mp;
3632*0Sstevel@tonic-gate 
3633*0Sstevel@tonic-gate 	if (P->map_count == P->map_alloc) {
3634*0Sstevel@tonic-gate 		size_t next = P->map_alloc ? P->map_alloc * 2 : 16;
3635*0Sstevel@tonic-gate 
3636*0Sstevel@tonic-gate 		if ((P->mappings = realloc(P->mappings,
3637*0Sstevel@tonic-gate 		    next * sizeof (map_info_t))) == NULL)
3638*0Sstevel@tonic-gate 			return (-1);
3639*0Sstevel@tonic-gate 
3640*0Sstevel@tonic-gate 		P->map_alloc = next;
3641*0Sstevel@tonic-gate 	}
3642*0Sstevel@tonic-gate 
3643*0Sstevel@tonic-gate 	mp = &P->mappings[P->map_count++];
3644*0Sstevel@tonic-gate 
3645*0Sstevel@tonic-gate 	mp->map_offset = off;
3646*0Sstevel@tonic-gate 	mp->map_pmap = *pmap;
3647*0Sstevel@tonic-gate 	mp->map_relocate = 0;
3648*0Sstevel@tonic-gate 	if ((mp->map_file = fp) != NULL) {
3649*0Sstevel@tonic-gate 		if (fp->file_map == NULL) {
3650*0Sstevel@tonic-gate 			fp->file_map = mp;
3651*0Sstevel@tonic-gate 			mp->map_relocate = 1;
3652*0Sstevel@tonic-gate 		}
3653*0Sstevel@tonic-gate 		fp->file_ref++;
3654*0Sstevel@tonic-gate 	}
3655*0Sstevel@tonic-gate 
3656*0Sstevel@tonic-gate 	return (0);
3657*0Sstevel@tonic-gate }
3658*0Sstevel@tonic-gate 
3659*0Sstevel@tonic-gate static int
3660*0Sstevel@tonic-gate map_sort(const void *a, const void *b)
3661*0Sstevel@tonic-gate {
3662*0Sstevel@tonic-gate 	const map_info_t *ap = a, *bp = b;
3663*0Sstevel@tonic-gate 
3664*0Sstevel@tonic-gate 	if (ap->map_pmap.pr_vaddr < bp->map_pmap.pr_vaddr)
3665*0Sstevel@tonic-gate 		return (-1);
3666*0Sstevel@tonic-gate 	else if (ap->map_pmap.pr_vaddr > bp->map_pmap.pr_vaddr)
3667*0Sstevel@tonic-gate 		return (1);
3668*0Sstevel@tonic-gate 	else
3669*0Sstevel@tonic-gate 		return (0);
3670*0Sstevel@tonic-gate }
3671*0Sstevel@tonic-gate 
3672*0Sstevel@tonic-gate /*
3673*0Sstevel@tonic-gate  * Sort the current set of mappings.  Should be called during target
3674*0Sstevel@tonic-gate  * initialization after all calls to Padd_mapping() have been made.
3675*0Sstevel@tonic-gate  */
3676*0Sstevel@tonic-gate void
3677*0Sstevel@tonic-gate Psort_mappings(struct ps_prochandle *P)
3678*0Sstevel@tonic-gate {
3679*0Sstevel@tonic-gate 	int i;
3680*0Sstevel@tonic-gate 	map_info_t *mp;
3681*0Sstevel@tonic-gate 
3682*0Sstevel@tonic-gate 	qsort(P->mappings, P->map_count, sizeof (map_info_t), map_sort);
3683*0Sstevel@tonic-gate 
3684*0Sstevel@tonic-gate 	/*
3685*0Sstevel@tonic-gate 	 * Update all the file_map pointers to refer to the new locations.
3686*0Sstevel@tonic-gate 	 */
3687*0Sstevel@tonic-gate 	for (i = 0; i < P->map_count; i++) {
3688*0Sstevel@tonic-gate 		mp = &P->mappings[i];
3689*0Sstevel@tonic-gate 		if (mp->map_relocate)
3690*0Sstevel@tonic-gate 			mp->map_file->file_map = mp;
3691*0Sstevel@tonic-gate 		mp->map_relocate = 0;
3692*0Sstevel@tonic-gate 	}
3693*0Sstevel@tonic-gate }
3694