xref: /onnv-gate/usr/src/uts/common/fs/proc/prsubr.c (revision 3235:9af05252020c)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52299Ssudheer  * Common Development and Distribution License (the "License").
62299Ssudheer  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21390Sraf 
220Sstevel@tonic-gate /*
232299Ssudheer  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
280Sstevel@tonic-gate /*	  All Rights Reserved  	*/
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <sys/types.h>
330Sstevel@tonic-gate #include <sys/t_lock.h>
340Sstevel@tonic-gate #include <sys/param.h>
350Sstevel@tonic-gate #include <sys/cmn_err.h>
360Sstevel@tonic-gate #include <sys/cred.h>
370Sstevel@tonic-gate #include <sys/priv.h>
380Sstevel@tonic-gate #include <sys/debug.h>
390Sstevel@tonic-gate #include <sys/errno.h>
400Sstevel@tonic-gate #include <sys/inline.h>
410Sstevel@tonic-gate #include <sys/kmem.h>
420Sstevel@tonic-gate #include <sys/mman.h>
430Sstevel@tonic-gate #include <sys/proc.h>
440Sstevel@tonic-gate #include <sys/sobject.h>
450Sstevel@tonic-gate #include <sys/sysmacros.h>
460Sstevel@tonic-gate #include <sys/systm.h>
470Sstevel@tonic-gate #include <sys/uio.h>
480Sstevel@tonic-gate #include <sys/var.h>
490Sstevel@tonic-gate #include <sys/vfs.h>
500Sstevel@tonic-gate #include <sys/vnode.h>
510Sstevel@tonic-gate #include <sys/session.h>
520Sstevel@tonic-gate #include <sys/pcb.h>
530Sstevel@tonic-gate #include <sys/signal.h>
540Sstevel@tonic-gate #include <sys/user.h>
550Sstevel@tonic-gate #include <sys/disp.h>
560Sstevel@tonic-gate #include <sys/class.h>
570Sstevel@tonic-gate #include <sys/ts.h>
580Sstevel@tonic-gate #include <sys/bitmap.h>
590Sstevel@tonic-gate #include <sys/poll.h>
600Sstevel@tonic-gate #include <sys/shm_impl.h>
610Sstevel@tonic-gate #include <sys/fault.h>
620Sstevel@tonic-gate #include <sys/syscall.h>
630Sstevel@tonic-gate #include <sys/procfs.h>
640Sstevel@tonic-gate #include <sys/processor.h>
650Sstevel@tonic-gate #include <sys/cpuvar.h>
660Sstevel@tonic-gate #include <sys/copyops.h>
670Sstevel@tonic-gate #include <sys/time.h>
680Sstevel@tonic-gate #include <sys/msacct.h>
690Sstevel@tonic-gate #include <vm/as.h>
700Sstevel@tonic-gate #include <vm/rm.h>
710Sstevel@tonic-gate #include <vm/seg.h>
720Sstevel@tonic-gate #include <vm/seg_vn.h>
730Sstevel@tonic-gate #include <vm/seg_dev.h>
740Sstevel@tonic-gate #include <vm/seg_spt.h>
750Sstevel@tonic-gate #include <vm/page.h>
760Sstevel@tonic-gate #include <sys/vmparam.h>
770Sstevel@tonic-gate #include <sys/swap.h>
780Sstevel@tonic-gate #include <fs/proc/prdata.h>
790Sstevel@tonic-gate #include <sys/task.h>
800Sstevel@tonic-gate #include <sys/project.h>
810Sstevel@tonic-gate #include <sys/contract_impl.h>
820Sstevel@tonic-gate #include <sys/contract/process.h>
830Sstevel@tonic-gate #include <sys/contract/process_impl.h>
840Sstevel@tonic-gate #include <sys/schedctl.h>
850Sstevel@tonic-gate #include <sys/pool.h>
860Sstevel@tonic-gate #include <sys/zone.h>
870Sstevel@tonic-gate #include <sys/atomic.h>
882789Sfrankho #include <sys/sdt.h>
890Sstevel@tonic-gate 
900Sstevel@tonic-gate #define	MAX_ITERS_SPIN	5
910Sstevel@tonic-gate 
920Sstevel@tonic-gate typedef struct prpagev {
930Sstevel@tonic-gate 	uint_t *pg_protv;	/* vector of page permissions */
940Sstevel@tonic-gate 	char *pg_incore;	/* vector of incore flags */
950Sstevel@tonic-gate 	size_t pg_npages;	/* number of pages in protv and incore */
960Sstevel@tonic-gate 	ulong_t pg_pnbase;	/* pn within segment of first protv element */
970Sstevel@tonic-gate } prpagev_t;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate size_t pagev_lim = 256 * 1024;	/* limit on number of pages in prpagev_t */
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate extern struct seg_ops segdev_ops;	/* needs a header file */
1020Sstevel@tonic-gate extern struct seg_ops segspt_shmops;	/* needs a header file */
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate static	int	set_watched_page(proc_t *, caddr_t, caddr_t, ulong_t, ulong_t);
1050Sstevel@tonic-gate static	void	clear_watched_page(proc_t *, caddr_t, caddr_t, ulong_t);
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate /*
1080Sstevel@tonic-gate  * Choose an lwp from the complete set of lwps for the process.
1090Sstevel@tonic-gate  * This is called for any operation applied to the process
1100Sstevel@tonic-gate  * file descriptor that requires an lwp to operate upon.
1110Sstevel@tonic-gate  *
1120Sstevel@tonic-gate  * Returns a pointer to the thread for the selected LWP,
1130Sstevel@tonic-gate  * and with the dispatcher lock held for the thread.
1140Sstevel@tonic-gate  *
1150Sstevel@tonic-gate  * The algorithm for choosing an lwp is critical for /proc semantics;
1160Sstevel@tonic-gate  * don't touch this code unless you know all of the implications.
1170Sstevel@tonic-gate  */
1180Sstevel@tonic-gate kthread_t *
1190Sstevel@tonic-gate prchoose(proc_t *p)
1200Sstevel@tonic-gate {
1210Sstevel@tonic-gate 	kthread_t *t;
1220Sstevel@tonic-gate 	kthread_t *t_onproc = NULL;	/* running on processor */
1230Sstevel@tonic-gate 	kthread_t *t_run = NULL;	/* runnable, on disp queue */
1240Sstevel@tonic-gate 	kthread_t *t_sleep = NULL;	/* sleeping */
1250Sstevel@tonic-gate 	kthread_t *t_hold = NULL;	/* sleeping, performing hold */
1260Sstevel@tonic-gate 	kthread_t *t_susp = NULL;	/* suspended stop */
1270Sstevel@tonic-gate 	kthread_t *t_jstop = NULL;	/* jobcontrol stop, w/o directed stop */
1280Sstevel@tonic-gate 	kthread_t *t_jdstop = NULL;	/* jobcontrol stop with directed stop */
1290Sstevel@tonic-gate 	kthread_t *t_req = NULL;	/* requested stop */
1300Sstevel@tonic-gate 	kthread_t *t_istop = NULL;	/* event-of-interest stop */
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	/*
1350Sstevel@tonic-gate 	 * If the agent lwp exists, it takes precedence over all others.
1360Sstevel@tonic-gate 	 */
1370Sstevel@tonic-gate 	if ((t = p->p_agenttp) != NULL) {
1380Sstevel@tonic-gate 		thread_lock(t);
1390Sstevel@tonic-gate 		return (t);
1400Sstevel@tonic-gate 	}
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	if ((t = p->p_tlist) == NULL)	/* start at the head of the list */
1430Sstevel@tonic-gate 		return (t);
1440Sstevel@tonic-gate 	do {		/* for eacn lwp in the process */
1450Sstevel@tonic-gate 		if (VSTOPPED(t)) {	/* virtually stopped */
1460Sstevel@tonic-gate 			if (t_req == NULL)
1470Sstevel@tonic-gate 				t_req = t;
1480Sstevel@tonic-gate 			continue;
1490Sstevel@tonic-gate 		}
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 		thread_lock(t);		/* make sure thread is in good state */
1520Sstevel@tonic-gate 		switch (t->t_state) {
1530Sstevel@tonic-gate 		default:
1540Sstevel@tonic-gate 			panic("prchoose: bad thread state %d, thread 0x%p",
1550Sstevel@tonic-gate 			    t->t_state, (void *)t);
1560Sstevel@tonic-gate 			/*NOTREACHED*/
1570Sstevel@tonic-gate 		case TS_SLEEP:
1580Sstevel@tonic-gate 			/* this is filthy */
1590Sstevel@tonic-gate 			if (t->t_wchan == (caddr_t)&p->p_holdlwps &&
1600Sstevel@tonic-gate 			    t->t_wchan0 == NULL) {
1610Sstevel@tonic-gate 				if (t_hold == NULL)
1620Sstevel@tonic-gate 					t_hold = t;
1630Sstevel@tonic-gate 			} else {
1640Sstevel@tonic-gate 				if (t_sleep == NULL)
1650Sstevel@tonic-gate 					t_sleep = t;
1660Sstevel@tonic-gate 			}
1670Sstevel@tonic-gate 			break;
1680Sstevel@tonic-gate 		case TS_RUN:
1690Sstevel@tonic-gate 			if (t_run == NULL)
1700Sstevel@tonic-gate 				t_run = t;
1710Sstevel@tonic-gate 			break;
1720Sstevel@tonic-gate 		case TS_ONPROC:
1730Sstevel@tonic-gate 			if (t_onproc == NULL)
1740Sstevel@tonic-gate 				t_onproc = t;
1750Sstevel@tonic-gate 			break;
1760Sstevel@tonic-gate 		case TS_ZOMB:		/* last possible choice */
1770Sstevel@tonic-gate 			break;
1780Sstevel@tonic-gate 		case TS_STOPPED:
1790Sstevel@tonic-gate 			switch (t->t_whystop) {
1800Sstevel@tonic-gate 			case PR_SUSPENDED:
1810Sstevel@tonic-gate 				if (t_susp == NULL)
1820Sstevel@tonic-gate 					t_susp = t;
1830Sstevel@tonic-gate 				break;
1840Sstevel@tonic-gate 			case PR_JOBCONTROL:
1850Sstevel@tonic-gate 				if (t->t_proc_flag & TP_PRSTOP) {
1860Sstevel@tonic-gate 					if (t_jdstop == NULL)
1870Sstevel@tonic-gate 						t_jdstop = t;
1880Sstevel@tonic-gate 				} else {
1890Sstevel@tonic-gate 					if (t_jstop == NULL)
1900Sstevel@tonic-gate 						t_jstop = t;
1910Sstevel@tonic-gate 				}
1920Sstevel@tonic-gate 				break;
1930Sstevel@tonic-gate 			case PR_REQUESTED:
1940Sstevel@tonic-gate 				if (t_req == NULL)
1950Sstevel@tonic-gate 					t_req = t;
1960Sstevel@tonic-gate 				break;
1970Sstevel@tonic-gate 			case PR_SYSENTRY:
1980Sstevel@tonic-gate 			case PR_SYSEXIT:
1990Sstevel@tonic-gate 			case PR_SIGNALLED:
2000Sstevel@tonic-gate 			case PR_FAULTED:
2010Sstevel@tonic-gate 				/*
2020Sstevel@tonic-gate 				 * Make an lwp calling exit() be the
2030Sstevel@tonic-gate 				 * last lwp seen in the process.
2040Sstevel@tonic-gate 				 */
2050Sstevel@tonic-gate 				if (t_istop == NULL ||
2060Sstevel@tonic-gate 				    (t_istop->t_whystop == PR_SYSENTRY &&
2070Sstevel@tonic-gate 				    t_istop->t_whatstop == SYS_exit))
2080Sstevel@tonic-gate 					t_istop = t;
2090Sstevel@tonic-gate 				break;
2100Sstevel@tonic-gate 			case PR_CHECKPOINT:	/* can't happen? */
2110Sstevel@tonic-gate 				break;
2120Sstevel@tonic-gate 			default:
2130Sstevel@tonic-gate 				panic("prchoose: bad t_whystop %d, thread 0x%p",
2140Sstevel@tonic-gate 				    t->t_whystop, (void *)t);
2150Sstevel@tonic-gate 				/*NOTREACHED*/
2160Sstevel@tonic-gate 			}
2170Sstevel@tonic-gate 			break;
2180Sstevel@tonic-gate 		}
2190Sstevel@tonic-gate 		thread_unlock(t);
2200Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 	if (t_onproc)
2230Sstevel@tonic-gate 		t = t_onproc;
2240Sstevel@tonic-gate 	else if (t_run)
2250Sstevel@tonic-gate 		t = t_run;
2260Sstevel@tonic-gate 	else if (t_sleep)
2270Sstevel@tonic-gate 		t = t_sleep;
2280Sstevel@tonic-gate 	else if (t_jstop)
2290Sstevel@tonic-gate 		t = t_jstop;
2300Sstevel@tonic-gate 	else if (t_jdstop)
2310Sstevel@tonic-gate 		t = t_jdstop;
2320Sstevel@tonic-gate 	else if (t_istop)
2330Sstevel@tonic-gate 		t = t_istop;
2340Sstevel@tonic-gate 	else if (t_req)
2350Sstevel@tonic-gate 		t = t_req;
2360Sstevel@tonic-gate 	else if (t_hold)
2370Sstevel@tonic-gate 		t = t_hold;
2380Sstevel@tonic-gate 	else if (t_susp)
2390Sstevel@tonic-gate 		t = t_susp;
2400Sstevel@tonic-gate 	else			/* TS_ZOMB */
2410Sstevel@tonic-gate 		t = p->p_tlist;
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	if (t != NULL)
2440Sstevel@tonic-gate 		thread_lock(t);
2450Sstevel@tonic-gate 	return (t);
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate /*
2490Sstevel@tonic-gate  * Wakeup anyone sleeping on the /proc vnode for the process/lwp to stop.
2500Sstevel@tonic-gate  * Also call pollwakeup() if any lwps are waiting in poll() for POLLPRI
2510Sstevel@tonic-gate  * on the /proc file descriptor.  Called from stop() when a traced
2520Sstevel@tonic-gate  * process stops on an event of interest.  Also called from exit()
2530Sstevel@tonic-gate  * and prinvalidate() to indicate POLLHUP and POLLERR respectively.
2540Sstevel@tonic-gate  */
2550Sstevel@tonic-gate void
2560Sstevel@tonic-gate prnotify(struct vnode *vp)
2570Sstevel@tonic-gate {
2580Sstevel@tonic-gate 	prcommon_t *pcp = VTOP(vp)->pr_common;
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	mutex_enter(&pcp->prc_mutex);
2610Sstevel@tonic-gate 	cv_broadcast(&pcp->prc_wait);
2620Sstevel@tonic-gate 	mutex_exit(&pcp->prc_mutex);
2630Sstevel@tonic-gate 	if (pcp->prc_flags & PRC_POLL) {
2640Sstevel@tonic-gate 		/*
2650Sstevel@tonic-gate 		 * We call pollwakeup() with POLLHUP to ensure that
2660Sstevel@tonic-gate 		 * the pollers are awakened even if they are polling
2670Sstevel@tonic-gate 		 * for nothing (i.e., waiting for the process to exit).
2680Sstevel@tonic-gate 		 * This enables the use of the PRC_POLL flag for optimization
2690Sstevel@tonic-gate 		 * (we can turn off PRC_POLL only if we know no pollers remain).
2700Sstevel@tonic-gate 		 */
2710Sstevel@tonic-gate 		pcp->prc_flags &= ~PRC_POLL;
2720Sstevel@tonic-gate 		pollwakeup(&pcp->prc_pollhead, POLLHUP);
2730Sstevel@tonic-gate 	}
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate /* called immediately below, in prfree() */
2770Sstevel@tonic-gate static void
2780Sstevel@tonic-gate prfreenotify(vnode_t *vp)
2790Sstevel@tonic-gate {
2800Sstevel@tonic-gate 	prnode_t *pnp;
2810Sstevel@tonic-gate 	prcommon_t *pcp;
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	while (vp != NULL) {
2840Sstevel@tonic-gate 		pnp = VTOP(vp);
2850Sstevel@tonic-gate 		pcp = pnp->pr_common;
2860Sstevel@tonic-gate 		ASSERT(pcp->prc_thread == NULL);
2870Sstevel@tonic-gate 		pcp->prc_proc = NULL;
2880Sstevel@tonic-gate 		/*
2890Sstevel@tonic-gate 		 * We can't call prnotify() here because we are holding
2900Sstevel@tonic-gate 		 * pidlock.  We assert that there is no need to.
2910Sstevel@tonic-gate 		 */
2920Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
2930Sstevel@tonic-gate 		cv_broadcast(&pcp->prc_wait);
2940Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
2950Sstevel@tonic-gate 		ASSERT(!(pcp->prc_flags & PRC_POLL));
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 		vp = pnp->pr_next;
2980Sstevel@tonic-gate 		pnp->pr_next = NULL;
2990Sstevel@tonic-gate 	}
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate /*
3030Sstevel@tonic-gate  * Called from a hook in freeproc() when a traced process is removed
3040Sstevel@tonic-gate  * from the process table.  The proc-table pointers of all associated
3050Sstevel@tonic-gate  * /proc vnodes are cleared to indicate that the process has gone away.
3060Sstevel@tonic-gate  */
3070Sstevel@tonic-gate void
3080Sstevel@tonic-gate prfree(proc_t *p)
3090Sstevel@tonic-gate {
3100Sstevel@tonic-gate 	uint_t slot = p->p_slot;
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock));
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	/*
3150Sstevel@tonic-gate 	 * Block the process against /proc so it can be freed.
3160Sstevel@tonic-gate 	 * It cannot be freed while locked by some controlling process.
3170Sstevel@tonic-gate 	 * Lock ordering:
3180Sstevel@tonic-gate 	 *	pidlock -> pr_pidlock -> p->p_lock -> pcp->prc_mutex
3190Sstevel@tonic-gate 	 */
3200Sstevel@tonic-gate 	mutex_enter(&pr_pidlock);	/* protects pcp->prc_proc */
3210Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
3220Sstevel@tonic-gate 	while (p->p_proc_flag & P_PR_LOCK) {
3230Sstevel@tonic-gate 		mutex_exit(&pr_pidlock);
3240Sstevel@tonic-gate 		cv_wait(&pr_pid_cv[slot], &p->p_lock);
3250Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
3260Sstevel@tonic-gate 		mutex_enter(&pr_pidlock);
3270Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
3280Sstevel@tonic-gate 	}
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	ASSERT(p->p_tlist == NULL);
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	prfreenotify(p->p_plist);
3330Sstevel@tonic-gate 	p->p_plist = NULL;
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	prfreenotify(p->p_trace);
3360Sstevel@tonic-gate 	p->p_trace = NULL;
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	/*
3390Sstevel@tonic-gate 	 * We broadcast to wake up everyone waiting for this process.
3400Sstevel@tonic-gate 	 * No one can reach this process from this point on.
3410Sstevel@tonic-gate 	 */
3420Sstevel@tonic-gate 	cv_broadcast(&pr_pid_cv[slot]);
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
3450Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate /*
3490Sstevel@tonic-gate  * Called from a hook in exit() when a traced process is becoming a zombie.
3500Sstevel@tonic-gate  */
3510Sstevel@tonic-gate void
3520Sstevel@tonic-gate prexit(proc_t *p)
3530Sstevel@tonic-gate {
3540Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 	if (pr_watch_active(p)) {
3570Sstevel@tonic-gate 		pr_free_watchpoints(p);
3580Sstevel@tonic-gate 		watch_disable(curthread);
3590Sstevel@tonic-gate 	}
3600Sstevel@tonic-gate 	/* pr_free_watched_pages() is called in exit(), after dropping p_lock */
3610Sstevel@tonic-gate 	if (p->p_trace) {
3620Sstevel@tonic-gate 		VTOP(p->p_trace)->pr_common->prc_flags |= PRC_DESTROY;
3630Sstevel@tonic-gate 		prnotify(p->p_trace);
3640Sstevel@tonic-gate 	}
3650Sstevel@tonic-gate 	cv_broadcast(&pr_pid_cv[p->p_slot]);	/* pauselwps() */
3660Sstevel@tonic-gate }
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate /*
3690Sstevel@tonic-gate  * Called when a thread calls lwp_exit().
3700Sstevel@tonic-gate  */
3710Sstevel@tonic-gate void
3720Sstevel@tonic-gate prlwpexit(kthread_t *t)
3730Sstevel@tonic-gate {
3740Sstevel@tonic-gate 	vnode_t *vp;
3750Sstevel@tonic-gate 	prnode_t *pnp;
3760Sstevel@tonic-gate 	prcommon_t *pcp;
3770Sstevel@tonic-gate 	proc_t *p = ttoproc(t);
3780Sstevel@tonic-gate 	lwpent_t *lep = p->p_lwpdir[t->t_dslot].ld_entry;
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	ASSERT(t == curthread);
3810Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	/*
3840Sstevel@tonic-gate 	 * The process must be blocked against /proc to do this safely.
3850Sstevel@tonic-gate 	 * The lwp must not disappear while the process is marked P_PR_LOCK.
3860Sstevel@tonic-gate 	 * It is the caller's responsibility to have called prbarrier(p).
3870Sstevel@tonic-gate 	 */
3880Sstevel@tonic-gate 	ASSERT(!(p->p_proc_flag & P_PR_LOCK));
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	for (vp = p->p_plist; vp != NULL; vp = pnp->pr_next) {
3910Sstevel@tonic-gate 		pnp = VTOP(vp);
3920Sstevel@tonic-gate 		pcp = pnp->pr_common;
3930Sstevel@tonic-gate 		if (pcp->prc_thread == t) {
3940Sstevel@tonic-gate 			pcp->prc_thread = NULL;
3950Sstevel@tonic-gate 			pcp->prc_flags |= PRC_DESTROY;
3960Sstevel@tonic-gate 		}
3970Sstevel@tonic-gate 	}
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	for (vp = lep->le_trace; vp != NULL; vp = pnp->pr_next) {
4000Sstevel@tonic-gate 		pnp = VTOP(vp);
4010Sstevel@tonic-gate 		pcp = pnp->pr_common;
4020Sstevel@tonic-gate 		pcp->prc_thread = NULL;
4030Sstevel@tonic-gate 		pcp->prc_flags |= PRC_DESTROY;
4040Sstevel@tonic-gate 		prnotify(vp);
4050Sstevel@tonic-gate 	}
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	if (p->p_trace)
4080Sstevel@tonic-gate 		prnotify(p->p_trace);
4090Sstevel@tonic-gate }
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate /*
4120Sstevel@tonic-gate  * Called when a zombie thread is joined or when a
4130Sstevel@tonic-gate  * detached lwp exits.  Called from lwp_hash_out().
4140Sstevel@tonic-gate  */
4150Sstevel@tonic-gate void
4160Sstevel@tonic-gate prlwpfree(proc_t *p, lwpent_t *lep)
4170Sstevel@tonic-gate {
4180Sstevel@tonic-gate 	vnode_t *vp;
4190Sstevel@tonic-gate 	prnode_t *pnp;
4200Sstevel@tonic-gate 	prcommon_t *pcp;
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 	/*
4250Sstevel@tonic-gate 	 * The process must be blocked against /proc to do this safely.
4260Sstevel@tonic-gate 	 * The lwp must not disappear while the process is marked P_PR_LOCK.
4270Sstevel@tonic-gate 	 * It is the caller's responsibility to have called prbarrier(p).
4280Sstevel@tonic-gate 	 */
4290Sstevel@tonic-gate 	ASSERT(!(p->p_proc_flag & P_PR_LOCK));
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	vp = lep->le_trace;
4320Sstevel@tonic-gate 	lep->le_trace = NULL;
4330Sstevel@tonic-gate 	while (vp) {
4340Sstevel@tonic-gate 		prnotify(vp);
4350Sstevel@tonic-gate 		pnp = VTOP(vp);
4360Sstevel@tonic-gate 		pcp = pnp->pr_common;
4370Sstevel@tonic-gate 		ASSERT(pcp->prc_thread == NULL &&
4380Sstevel@tonic-gate 		    (pcp->prc_flags & PRC_DESTROY));
4390Sstevel@tonic-gate 		pcp->prc_tslot = -1;
4400Sstevel@tonic-gate 		vp = pnp->pr_next;
4410Sstevel@tonic-gate 		pnp->pr_next = NULL;
4420Sstevel@tonic-gate 	}
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	if (p->p_trace)
4450Sstevel@tonic-gate 		prnotify(p->p_trace);
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate /*
4490Sstevel@tonic-gate  * Called from a hook in exec() when a thread starts exec().
4500Sstevel@tonic-gate  */
4510Sstevel@tonic-gate void
4520Sstevel@tonic-gate prexecstart(void)
4530Sstevel@tonic-gate {
4540Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
4550Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	/*
4580Sstevel@tonic-gate 	 * The P_PR_EXEC flag blocks /proc operations for
4590Sstevel@tonic-gate 	 * the duration of the exec().
4600Sstevel@tonic-gate 	 * We can't start exec() while the process is
4610Sstevel@tonic-gate 	 * locked by /proc, so we call prbarrier().
4620Sstevel@tonic-gate 	 * lwp_nostop keeps the process from being stopped
4630Sstevel@tonic-gate 	 * via job control for the duration of the exec().
4640Sstevel@tonic-gate 	 */
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
4670Sstevel@tonic-gate 	prbarrier(p);
4680Sstevel@tonic-gate 	lwp->lwp_nostop++;
4690Sstevel@tonic-gate 	p->p_proc_flag |= P_PR_EXEC;
4700Sstevel@tonic-gate }
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate /*
4730Sstevel@tonic-gate  * Called from a hook in exec() when a thread finishes exec().
4740Sstevel@tonic-gate  * The thread may or may not have succeeded.  Some other thread
4750Sstevel@tonic-gate  * may have beat it to the punch.
4760Sstevel@tonic-gate  */
4770Sstevel@tonic-gate void
4780Sstevel@tonic-gate prexecend(void)
4790Sstevel@tonic-gate {
4800Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
4810Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
4820Sstevel@tonic-gate 	vnode_t *vp;
4830Sstevel@tonic-gate 	prnode_t *pnp;
4840Sstevel@tonic-gate 	prcommon_t *pcp;
4850Sstevel@tonic-gate 	model_t model = p->p_model;
4860Sstevel@tonic-gate 	id_t tid = curthread->t_tid;
4870Sstevel@tonic-gate 	int tslot = curthread->t_dslot;
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	lwp->lwp_nostop--;
4920Sstevel@tonic-gate 	if (p->p_flag & SEXITLWPS) {
4930Sstevel@tonic-gate 		/*
4940Sstevel@tonic-gate 		 * We are on our way to exiting because some
4950Sstevel@tonic-gate 		 * other thread beat us in the race to exec().
4960Sstevel@tonic-gate 		 * Don't clear the P_PR_EXEC flag in this case.
4970Sstevel@tonic-gate 		 */
4980Sstevel@tonic-gate 		return;
4990Sstevel@tonic-gate 	}
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	/*
5020Sstevel@tonic-gate 	 * Wake up anyone waiting in /proc for the process to complete exec().
5030Sstevel@tonic-gate 	 */
5040Sstevel@tonic-gate 	p->p_proc_flag &= ~P_PR_EXEC;
5050Sstevel@tonic-gate 	if ((vp = p->p_trace) != NULL) {
5060Sstevel@tonic-gate 		pcp = VTOP(vp)->pr_common;
5070Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
5080Sstevel@tonic-gate 		cv_broadcast(&pcp->prc_wait);
5090Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
5100Sstevel@tonic-gate 		for (; vp != NULL; vp = pnp->pr_next) {
5110Sstevel@tonic-gate 			pnp = VTOP(vp);
5120Sstevel@tonic-gate 			pnp->pr_common->prc_datamodel = model;
5130Sstevel@tonic-gate 		}
5140Sstevel@tonic-gate 	}
5150Sstevel@tonic-gate 	if ((vp = p->p_lwpdir[tslot].ld_entry->le_trace) != NULL) {
5160Sstevel@tonic-gate 		/*
5170Sstevel@tonic-gate 		 * We dealt with the process common above.
5180Sstevel@tonic-gate 		 */
5190Sstevel@tonic-gate 		ASSERT(p->p_trace != NULL);
5200Sstevel@tonic-gate 		pcp = VTOP(vp)->pr_common;
5210Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
5220Sstevel@tonic-gate 		cv_broadcast(&pcp->prc_wait);
5230Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
5240Sstevel@tonic-gate 		for (; vp != NULL; vp = pnp->pr_next) {
5250Sstevel@tonic-gate 			pnp = VTOP(vp);
5260Sstevel@tonic-gate 			pcp = pnp->pr_common;
5270Sstevel@tonic-gate 			pcp->prc_datamodel = model;
5280Sstevel@tonic-gate 			pcp->prc_tid = tid;
5290Sstevel@tonic-gate 			pcp->prc_tslot = tslot;
5300Sstevel@tonic-gate 		}
5310Sstevel@tonic-gate 	}
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate /*
5350Sstevel@tonic-gate  * Called from a hook in relvm() just before freeing the address space.
5360Sstevel@tonic-gate  * We free all the watched areas now.
5370Sstevel@tonic-gate  */
5380Sstevel@tonic-gate void
5390Sstevel@tonic-gate prrelvm(void)
5400Sstevel@tonic-gate {
5410Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
5440Sstevel@tonic-gate 	prbarrier(p);	/* block all other /proc operations */
5450Sstevel@tonic-gate 	if (pr_watch_active(p)) {
5460Sstevel@tonic-gate 		pr_free_watchpoints(p);
5470Sstevel@tonic-gate 		watch_disable(curthread);
5480Sstevel@tonic-gate 	}
5490Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
5500Sstevel@tonic-gate 	pr_free_watched_pages(p);
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate /*
5540Sstevel@tonic-gate  * Called from hooks in exec-related code when a traced process
5550Sstevel@tonic-gate  * attempts to exec(2) a setuid/setgid program or an unreadable
5560Sstevel@tonic-gate  * file.  Rather than fail the exec we invalidate the associated
5570Sstevel@tonic-gate  * /proc vnodes so that subsequent attempts to use them will fail.
5580Sstevel@tonic-gate  *
5590Sstevel@tonic-gate  * All /proc vnodes, except directory vnodes, are retained on a linked
5600Sstevel@tonic-gate  * list (rooted at p_plist in the process structure) until last close.
5610Sstevel@tonic-gate  *
5620Sstevel@tonic-gate  * A controlling process must re-open the /proc files in order to
5630Sstevel@tonic-gate  * regain control.
5640Sstevel@tonic-gate  */
5650Sstevel@tonic-gate void
5660Sstevel@tonic-gate prinvalidate(struct user *up)
5670Sstevel@tonic-gate {
5680Sstevel@tonic-gate 	kthread_t *t = curthread;
5690Sstevel@tonic-gate 	proc_t *p = ttoproc(t);
5700Sstevel@tonic-gate 	vnode_t *vp;
5710Sstevel@tonic-gate 	prnode_t *pnp;
5720Sstevel@tonic-gate 	int writers = 0;
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
5750Sstevel@tonic-gate 	prbarrier(p);	/* block all other /proc operations */
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	/*
5780Sstevel@tonic-gate 	 * At this moment, there can be only one lwp in the process.
5790Sstevel@tonic-gate 	 */
5800Sstevel@tonic-gate 	ASSERT(p->p_lwpcnt == 1 && p->p_zombcnt == 0);
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	/*
5830Sstevel@tonic-gate 	 * Invalidate any currently active /proc vnodes.
5840Sstevel@tonic-gate 	 */
5850Sstevel@tonic-gate 	for (vp = p->p_plist; vp != NULL; vp = pnp->pr_next) {
5860Sstevel@tonic-gate 		pnp = VTOP(vp);
5870Sstevel@tonic-gate 		switch (pnp->pr_type) {
5880Sstevel@tonic-gate 		case PR_PSINFO:		/* these files can read by anyone */
5890Sstevel@tonic-gate 		case PR_LPSINFO:
5900Sstevel@tonic-gate 		case PR_LWPSINFO:
5910Sstevel@tonic-gate 		case PR_LWPDIR:
5920Sstevel@tonic-gate 		case PR_LWPIDDIR:
5930Sstevel@tonic-gate 		case PR_USAGE:
5940Sstevel@tonic-gate 		case PR_LUSAGE:
5950Sstevel@tonic-gate 		case PR_LWPUSAGE:
5960Sstevel@tonic-gate 			break;
5970Sstevel@tonic-gate 		default:
5980Sstevel@tonic-gate 			pnp->pr_flags |= PR_INVAL;
5990Sstevel@tonic-gate 			break;
6000Sstevel@tonic-gate 		}
6010Sstevel@tonic-gate 	}
6020Sstevel@tonic-gate 	/*
6030Sstevel@tonic-gate 	 * Wake up anyone waiting for the process or lwp.
6040Sstevel@tonic-gate 	 * p->p_trace is guaranteed to be non-NULL if there
6050Sstevel@tonic-gate 	 * are any open /proc files for this process.
6060Sstevel@tonic-gate 	 */
6070Sstevel@tonic-gate 	if ((vp = p->p_trace) != NULL) {
6080Sstevel@tonic-gate 		prcommon_t *pcp = VTOP(vp)->pr_pcommon;
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 		prnotify(vp);
6110Sstevel@tonic-gate 		/*
6120Sstevel@tonic-gate 		 * Are there any writers?
6130Sstevel@tonic-gate 		 */
6140Sstevel@tonic-gate 		if ((writers = pcp->prc_writers) != 0) {
6150Sstevel@tonic-gate 			/*
6160Sstevel@tonic-gate 			 * Clear the exclusive open flag (old /proc interface).
6170Sstevel@tonic-gate 			 * Set prc_selfopens equal to prc_writers so that
6180Sstevel@tonic-gate 			 * the next O_EXCL|O_WRITE open will succeed
6190Sstevel@tonic-gate 			 * even with existing (though invalid) writers.
6200Sstevel@tonic-gate 			 * prclose() must decrement prc_selfopens when
6210Sstevel@tonic-gate 			 * the invalid files are closed.
6220Sstevel@tonic-gate 			 */
6230Sstevel@tonic-gate 			pcp->prc_flags &= ~PRC_EXCL;
6240Sstevel@tonic-gate 			ASSERT(pcp->prc_selfopens <= writers);
6250Sstevel@tonic-gate 			pcp->prc_selfopens = writers;
6260Sstevel@tonic-gate 		}
6270Sstevel@tonic-gate 	}
6280Sstevel@tonic-gate 	vp = p->p_lwpdir[t->t_dslot].ld_entry->le_trace;
6290Sstevel@tonic-gate 	while (vp != NULL) {
6300Sstevel@tonic-gate 		/*
6310Sstevel@tonic-gate 		 * We should not invalidate the lwpiddir vnodes,
6320Sstevel@tonic-gate 		 * but the necessities of maintaining the old
6330Sstevel@tonic-gate 		 * ioctl()-based version of /proc require it.
6340Sstevel@tonic-gate 		 */
6350Sstevel@tonic-gate 		pnp = VTOP(vp);
6360Sstevel@tonic-gate 		pnp->pr_flags |= PR_INVAL;
6370Sstevel@tonic-gate 		prnotify(vp);
6380Sstevel@tonic-gate 		vp = pnp->pr_next;
6390Sstevel@tonic-gate 	}
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	/*
6420Sstevel@tonic-gate 	 * If any tracing flags are in effect and any vnodes are open for
6430Sstevel@tonic-gate 	 * writing then set the requested-stop and run-on-last-close flags.
6440Sstevel@tonic-gate 	 * Otherwise, clear all tracing flags.
6450Sstevel@tonic-gate 	 */
6460Sstevel@tonic-gate 	t->t_proc_flag &= ~TP_PAUSE;
6470Sstevel@tonic-gate 	if ((p->p_proc_flag & P_PR_TRACE) && writers) {
6480Sstevel@tonic-gate 		t->t_proc_flag |= TP_PRSTOP;
6490Sstevel@tonic-gate 		aston(t);		/* so ISSIG will see the flag */
6500Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_RUNLCL;
6510Sstevel@tonic-gate 	} else {
6520Sstevel@tonic-gate 		premptyset(&up->u_entrymask);		/* syscalls */
6530Sstevel@tonic-gate 		premptyset(&up->u_exitmask);
6540Sstevel@tonic-gate 		up->u_systrap = 0;
6550Sstevel@tonic-gate 		premptyset(&p->p_sigmask);		/* signals */
6560Sstevel@tonic-gate 		premptyset(&p->p_fltmask);		/* faults */
6570Sstevel@tonic-gate 		t->t_proc_flag &= ~(TP_PRSTOP|TP_PRVSTOP|TP_STOPPING);
6580Sstevel@tonic-gate 		p->p_proc_flag &= ~(P_PR_RUNLCL|P_PR_KILLCL|P_PR_TRACE);
6590Sstevel@tonic-gate 		prnostep(ttolwp(t));
6600Sstevel@tonic-gate 	}
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
6630Sstevel@tonic-gate }
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate /*
6660Sstevel@tonic-gate  * Acquire the controlled process's p_lock and mark it P_PR_LOCK.
6670Sstevel@tonic-gate  * Return with pr_pidlock held in all cases.
6680Sstevel@tonic-gate  * Return with p_lock held if the the process still exists.
6690Sstevel@tonic-gate  * Return value is the process pointer if the process still exists, else NULL.
6700Sstevel@tonic-gate  * If we lock the process, give ourself kernel priority to avoid deadlocks;
6710Sstevel@tonic-gate  * this is undone in prunlock().
6720Sstevel@tonic-gate  */
6730Sstevel@tonic-gate proc_t *
6740Sstevel@tonic-gate pr_p_lock(prnode_t *pnp)
6750Sstevel@tonic-gate {
6760Sstevel@tonic-gate 	proc_t *p;
6770Sstevel@tonic-gate 	prcommon_t *pcp;
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 	mutex_enter(&pr_pidlock);
6800Sstevel@tonic-gate 	if ((pcp = pnp->pr_pcommon) == NULL || (p = pcp->prc_proc) == NULL)
6810Sstevel@tonic-gate 		return (NULL);
6820Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
6830Sstevel@tonic-gate 	while (p->p_proc_flag & P_PR_LOCK) {
6840Sstevel@tonic-gate 		/*
6850Sstevel@tonic-gate 		 * This cv/mutex pair is persistent even if
6860Sstevel@tonic-gate 		 * the process disappears while we sleep.
6870Sstevel@tonic-gate 		 */
6880Sstevel@tonic-gate 		kcondvar_t *cv = &pr_pid_cv[p->p_slot];
6890Sstevel@tonic-gate 		kmutex_t *mp = &p->p_lock;
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 		mutex_exit(&pr_pidlock);
6920Sstevel@tonic-gate 		cv_wait(cv, mp);
6930Sstevel@tonic-gate 		mutex_exit(mp);
6940Sstevel@tonic-gate 		mutex_enter(&pr_pidlock);
6950Sstevel@tonic-gate 		if (pcp->prc_proc == NULL)
6960Sstevel@tonic-gate 			return (NULL);
6970Sstevel@tonic-gate 		ASSERT(p == pcp->prc_proc);
6980Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
6990Sstevel@tonic-gate 	}
7000Sstevel@tonic-gate 	p->p_proc_flag |= P_PR_LOCK;
7010Sstevel@tonic-gate 	THREAD_KPRI_REQUEST();
7020Sstevel@tonic-gate 	return (p);
7030Sstevel@tonic-gate }
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate /*
7060Sstevel@tonic-gate  * Lock the target process by setting P_PR_LOCK and grabbing p->p_lock.
7070Sstevel@tonic-gate  * This prevents any lwp of the process from disappearing and
7080Sstevel@tonic-gate  * blocks most operations that a process can perform on itself.
7090Sstevel@tonic-gate  * Returns 0 on success, a non-zero error number on failure.
7100Sstevel@tonic-gate  *
7110Sstevel@tonic-gate  * 'zdisp' is ZYES or ZNO to indicate whether prlock() should succeed when
7120Sstevel@tonic-gate  * the subject process is a zombie (ZYES) or fail for zombies (ZNO).
7130Sstevel@tonic-gate  *
7140Sstevel@tonic-gate  * error returns:
7150Sstevel@tonic-gate  *	ENOENT: process or lwp has disappeared or process is exiting
7160Sstevel@tonic-gate  *		(or has become a zombie and zdisp == ZNO).
7170Sstevel@tonic-gate  *	EAGAIN: procfs vnode has become invalid.
7180Sstevel@tonic-gate  *	EINTR:  signal arrived while waiting for exec to complete.
7190Sstevel@tonic-gate  */
7200Sstevel@tonic-gate int
7210Sstevel@tonic-gate prlock(prnode_t *pnp, int zdisp)
7220Sstevel@tonic-gate {
7230Sstevel@tonic-gate 	prcommon_t *pcp;
7240Sstevel@tonic-gate 	proc_t *p;
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate again:
7270Sstevel@tonic-gate 	pcp = pnp->pr_common;
7280Sstevel@tonic-gate 	p = pr_p_lock(pnp);
7290Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	/*
7320Sstevel@tonic-gate 	 * Return ENOENT immediately if there is no process.
7330Sstevel@tonic-gate 	 */
7340Sstevel@tonic-gate 	if (p == NULL)
7350Sstevel@tonic-gate 		return (ENOENT);
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	ASSERT(p == pcp->prc_proc && p->p_stat != 0 && p->p_stat != SIDL);
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 	/*
7400Sstevel@tonic-gate 	 * Return ENOENT if process entered zombie state or is exiting
7410Sstevel@tonic-gate 	 * and the 'zdisp' flag is set to ZNO indicating not to lock zombies.
7420Sstevel@tonic-gate 	 */
7430Sstevel@tonic-gate 	if (zdisp == ZNO &&
744390Sraf 	    ((pcp->prc_flags & PRC_DESTROY) || (p->p_flag & SEXITING))) {
7450Sstevel@tonic-gate 		prunlock(pnp);
7460Sstevel@tonic-gate 		return (ENOENT);
7470Sstevel@tonic-gate 	}
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	/*
7500Sstevel@tonic-gate 	 * If lwp-specific, check to see if lwp has disappeared.
7510Sstevel@tonic-gate 	 */
7520Sstevel@tonic-gate 	if (pcp->prc_flags & PRC_LWP) {
7530Sstevel@tonic-gate 		if ((zdisp == ZNO && (pcp->prc_flags & PRC_DESTROY)) ||
7540Sstevel@tonic-gate 		    pcp->prc_tslot == -1) {
7550Sstevel@tonic-gate 			prunlock(pnp);
7560Sstevel@tonic-gate 			return (ENOENT);
7570Sstevel@tonic-gate 		}
7580Sstevel@tonic-gate 	}
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 	/*
7610Sstevel@tonic-gate 	 * Return EAGAIN if we have encountered a security violation.
7620Sstevel@tonic-gate 	 * (The process exec'd a set-id or unreadable executable file.)
7630Sstevel@tonic-gate 	 */
7640Sstevel@tonic-gate 	if (pnp->pr_flags & PR_INVAL) {
7650Sstevel@tonic-gate 		prunlock(pnp);
7660Sstevel@tonic-gate 		return (EAGAIN);
7670Sstevel@tonic-gate 	}
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 	/*
7700Sstevel@tonic-gate 	 * If process is undergoing an exec(), wait for
7710Sstevel@tonic-gate 	 * completion and then start all over again.
7720Sstevel@tonic-gate 	 */
7730Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_EXEC) {
7740Sstevel@tonic-gate 		pcp = pnp->pr_pcommon;	/* Put on the correct sleep queue */
7750Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
7760Sstevel@tonic-gate 		prunlock(pnp);
7770Sstevel@tonic-gate 		if (!cv_wait_sig(&pcp->prc_wait, &pcp->prc_mutex)) {
7780Sstevel@tonic-gate 			mutex_exit(&pcp->prc_mutex);
7790Sstevel@tonic-gate 			return (EINTR);
7800Sstevel@tonic-gate 		}
7810Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
7820Sstevel@tonic-gate 		goto again;
7830Sstevel@tonic-gate 	}
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 	/*
7860Sstevel@tonic-gate 	 * We return holding p->p_lock.
7870Sstevel@tonic-gate 	 */
7880Sstevel@tonic-gate 	return (0);
7890Sstevel@tonic-gate }
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate /*
7920Sstevel@tonic-gate  * Undo prlock() and pr_p_lock().
7930Sstevel@tonic-gate  * p->p_lock is still held; pr_pidlock is no longer held.
7940Sstevel@tonic-gate  *
7950Sstevel@tonic-gate  * prunmark() drops the P_PR_LOCK flag and wakes up another thread,
7960Sstevel@tonic-gate  * if any, waiting for the flag to be dropped; it retains p->p_lock.
7970Sstevel@tonic-gate  *
7980Sstevel@tonic-gate  * prunlock() calls prunmark() and then drops p->p_lock.
7990Sstevel@tonic-gate  */
8000Sstevel@tonic-gate void
8010Sstevel@tonic-gate prunmark(proc_t *p)
8020Sstevel@tonic-gate {
8030Sstevel@tonic-gate 	ASSERT(p->p_proc_flag & P_PR_LOCK);
8040Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 	cv_signal(&pr_pid_cv[p->p_slot]);
8070Sstevel@tonic-gate 	p->p_proc_flag &= ~P_PR_LOCK;
8080Sstevel@tonic-gate 	THREAD_KPRI_RELEASE();
8090Sstevel@tonic-gate }
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate void
8120Sstevel@tonic-gate prunlock(prnode_t *pnp)
8130Sstevel@tonic-gate {
814658Sraf 	prcommon_t *pcp = pnp->pr_common;
815658Sraf 	proc_t *p = pcp->prc_proc;
816658Sraf 
817658Sraf 	/*
818658Sraf 	 * If we (or someone) gave it a SIGKILL, and it is not
819658Sraf 	 * already a zombie, set it running unconditionally.
820658Sraf 	 */
821658Sraf 	if ((p->p_flag & SKILLED) &&
822658Sraf 	    !(p->p_flag & SEXITING) &&
823658Sraf 	    !(pcp->prc_flags & PRC_DESTROY) &&
824658Sraf 	    !((pcp->prc_flags & PRC_LWP) && pcp->prc_tslot == -1))
825658Sraf 		(void) pr_setrun(pnp, 0);
8260Sstevel@tonic-gate 	prunmark(p);
8270Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
8280Sstevel@tonic-gate }
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate /*
8310Sstevel@tonic-gate  * Called while holding p->p_lock to delay until the process is unlocked.
8320Sstevel@tonic-gate  * We enter holding p->p_lock; p->p_lock is dropped and reacquired.
8330Sstevel@tonic-gate  * The process cannot become locked again until p->p_lock is dropped.
8340Sstevel@tonic-gate  */
8350Sstevel@tonic-gate void
8360Sstevel@tonic-gate prbarrier(proc_t *p)
8370Sstevel@tonic-gate {
8380Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_LOCK) {
8410Sstevel@tonic-gate 		/* The process is locked; delay until not locked */
8420Sstevel@tonic-gate 		uint_t slot = p->p_slot;
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 		while (p->p_proc_flag & P_PR_LOCK)
8450Sstevel@tonic-gate 			cv_wait(&pr_pid_cv[slot], &p->p_lock);
8460Sstevel@tonic-gate 		cv_signal(&pr_pid_cv[slot]);
8470Sstevel@tonic-gate 	}
8480Sstevel@tonic-gate }
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate /*
8510Sstevel@tonic-gate  * Return process/lwp status.
8520Sstevel@tonic-gate  * The u-block is mapped in by this routine and unmapped at the end.
8530Sstevel@tonic-gate  */
8540Sstevel@tonic-gate void
8550Sstevel@tonic-gate prgetstatus(proc_t *p, pstatus_t *sp, zone_t *zp)
8560Sstevel@tonic-gate {
8570Sstevel@tonic-gate 	kthread_t *t;
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	t = prchoose(p);	/* returns locked thread */
8620Sstevel@tonic-gate 	ASSERT(t != NULL);
8630Sstevel@tonic-gate 	thread_unlock(t);
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 	/* just bzero the process part, prgetlwpstatus() does the rest */
8660Sstevel@tonic-gate 	bzero(sp, sizeof (pstatus_t) - sizeof (lwpstatus_t));
8670Sstevel@tonic-gate 	sp->pr_nlwp = p->p_lwpcnt;
8680Sstevel@tonic-gate 	sp->pr_nzomb = p->p_zombcnt;
8690Sstevel@tonic-gate 	prassignset(&sp->pr_sigpend, &p->p_sig);
8700Sstevel@tonic-gate 	sp->pr_brkbase = (uintptr_t)p->p_brkbase;
8710Sstevel@tonic-gate 	sp->pr_brksize = p->p_brksize;
8720Sstevel@tonic-gate 	sp->pr_stkbase = (uintptr_t)prgetstackbase(p);
8730Sstevel@tonic-gate 	sp->pr_stksize = p->p_stksize;
8740Sstevel@tonic-gate 	sp->pr_pid = p->p_pid;
8750Sstevel@tonic-gate 	if (curproc->p_zone->zone_id != GLOBAL_ZONEID &&
8760Sstevel@tonic-gate 	    (p->p_flag & SZONETOP)) {
8770Sstevel@tonic-gate 		ASSERT(p->p_zone->zone_id != GLOBAL_ZONEID);
8780Sstevel@tonic-gate 		/*
8790Sstevel@tonic-gate 		 * Inside local zones, fake zsched's pid as parent pids for
8800Sstevel@tonic-gate 		 * processes which reference processes outside of the zone.
8810Sstevel@tonic-gate 		 */
8820Sstevel@tonic-gate 		sp->pr_ppid = curproc->p_zone->zone_zsched->p_pid;
8830Sstevel@tonic-gate 	} else {
8840Sstevel@tonic-gate 		sp->pr_ppid = p->p_ppid;
8850Sstevel@tonic-gate 	}
8860Sstevel@tonic-gate 	sp->pr_pgid  = p->p_pgrp;
8870Sstevel@tonic-gate 	sp->pr_sid   = p->p_sessp->s_sid;
8880Sstevel@tonic-gate 	sp->pr_taskid = p->p_task->tk_tkid;
8890Sstevel@tonic-gate 	sp->pr_projid = p->p_task->tk_proj->kpj_id;
8900Sstevel@tonic-gate 	sp->pr_zoneid = p->p_zone->zone_id;
8910Sstevel@tonic-gate 	hrt2ts(mstate_aggr_state(p, LMS_USER), &sp->pr_utime);
8920Sstevel@tonic-gate 	hrt2ts(mstate_aggr_state(p, LMS_SYSTEM), &sp->pr_stime);
8930Sstevel@tonic-gate 	TICK_TO_TIMESTRUC(p->p_cutime, &sp->pr_cutime);
8940Sstevel@tonic-gate 	TICK_TO_TIMESTRUC(p->p_cstime, &sp->pr_cstime);
8950Sstevel@tonic-gate 	prassignset(&sp->pr_sigtrace, &p->p_sigmask);
8960Sstevel@tonic-gate 	prassignset(&sp->pr_flttrace, &p->p_fltmask);
8970Sstevel@tonic-gate 	prassignset(&sp->pr_sysentry, &PTOU(p)->u_entrymask);
8980Sstevel@tonic-gate 	prassignset(&sp->pr_sysexit, &PTOU(p)->u_exitmask);
8990Sstevel@tonic-gate 	switch (p->p_model) {
9000Sstevel@tonic-gate 	case DATAMODEL_ILP32:
9010Sstevel@tonic-gate 		sp->pr_dmodel = PR_MODEL_ILP32;
9020Sstevel@tonic-gate 		break;
9030Sstevel@tonic-gate 	case DATAMODEL_LP64:
9040Sstevel@tonic-gate 		sp->pr_dmodel = PR_MODEL_LP64;
9050Sstevel@tonic-gate 		break;
9060Sstevel@tonic-gate 	}
9070Sstevel@tonic-gate 	if (p->p_agenttp)
9080Sstevel@tonic-gate 		sp->pr_agentid = p->p_agenttp->t_tid;
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 	/* get the chosen lwp's status */
9110Sstevel@tonic-gate 	prgetlwpstatus(t, &sp->pr_lwp, zp);
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	/* replicate the flags */
9140Sstevel@tonic-gate 	sp->pr_flags = sp->pr_lwp.pr_flags;
9150Sstevel@tonic-gate }
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
9180Sstevel@tonic-gate void
9190Sstevel@tonic-gate prgetlwpstatus32(kthread_t *t, lwpstatus32_t *sp, zone_t *zp)
9200Sstevel@tonic-gate {
9210Sstevel@tonic-gate 	proc_t *p = ttoproc(t);
9220Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
9230Sstevel@tonic-gate 	struct mstate *ms = &lwp->lwp_mstate;
9240Sstevel@tonic-gate 	hrtime_t usr, sys;
9250Sstevel@tonic-gate 	int flags;
9260Sstevel@tonic-gate 	ulong_t instr;
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 	bzero(sp, sizeof (*sp));
9310Sstevel@tonic-gate 	flags = 0L;
9320Sstevel@tonic-gate 	if (t->t_state == TS_STOPPED) {
9330Sstevel@tonic-gate 		flags |= PR_STOPPED;
9340Sstevel@tonic-gate 		if ((t->t_schedflag & TS_PSTART) == 0)
9350Sstevel@tonic-gate 			flags |= PR_ISTOP;
9360Sstevel@tonic-gate 	} else if (VSTOPPED(t)) {
9370Sstevel@tonic-gate 		flags |= PR_STOPPED|PR_ISTOP;
9380Sstevel@tonic-gate 	}
9390Sstevel@tonic-gate 	if (!(flags & PR_ISTOP) && (t->t_proc_flag & TP_PRSTOP))
9400Sstevel@tonic-gate 		flags |= PR_DSTOP;
9410Sstevel@tonic-gate 	if (lwp->lwp_asleep)
9420Sstevel@tonic-gate 		flags |= PR_ASLEEP;
9430Sstevel@tonic-gate 	if (t == p->p_agenttp)
9440Sstevel@tonic-gate 		flags |= PR_AGENT;
9450Sstevel@tonic-gate 	if (!(t->t_proc_flag & TP_TWAIT))
9460Sstevel@tonic-gate 		flags |= PR_DETACH;
9470Sstevel@tonic-gate 	if (t->t_proc_flag & TP_DAEMON)
9480Sstevel@tonic-gate 		flags |= PR_DAEMON;
9490Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_FORK)
9500Sstevel@tonic-gate 		flags |= PR_FORK;
9510Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_RUNLCL)
9520Sstevel@tonic-gate 		flags |= PR_RLC;
9530Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_KILLCL)
9540Sstevel@tonic-gate 		flags |= PR_KLC;
9550Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_ASYNC)
9560Sstevel@tonic-gate 		flags |= PR_ASYNC;
9570Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_BPTADJ)
9580Sstevel@tonic-gate 		flags |= PR_BPTADJ;
9590Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_PTRACE)
9600Sstevel@tonic-gate 		flags |= PR_PTRACE;
9610Sstevel@tonic-gate 	if (p->p_flag & SMSACCT)
9620Sstevel@tonic-gate 		flags |= PR_MSACCT;
9630Sstevel@tonic-gate 	if (p->p_flag & SMSFORK)
9640Sstevel@tonic-gate 		flags |= PR_MSFORK;
9650Sstevel@tonic-gate 	if (p->p_flag & SVFWAIT)
9660Sstevel@tonic-gate 		flags |= PR_VFORKP;
9670Sstevel@tonic-gate 	sp->pr_flags = flags;
9680Sstevel@tonic-gate 	if (VSTOPPED(t)) {
9690Sstevel@tonic-gate 		sp->pr_why   = PR_REQUESTED;
9700Sstevel@tonic-gate 		sp->pr_what  = 0;
9710Sstevel@tonic-gate 	} else {
9720Sstevel@tonic-gate 		sp->pr_why   = t->t_whystop;
9730Sstevel@tonic-gate 		sp->pr_what  = t->t_whatstop;
9740Sstevel@tonic-gate 	}
9750Sstevel@tonic-gate 	sp->pr_lwpid = t->t_tid;
9760Sstevel@tonic-gate 	sp->pr_cursig  = lwp->lwp_cursig;
9770Sstevel@tonic-gate 	prassignset(&sp->pr_lwppend, &t->t_sig);
9780Sstevel@tonic-gate 	schedctl_finish_sigblock(t);
9790Sstevel@tonic-gate 	prassignset(&sp->pr_lwphold, &t->t_hold);
9800Sstevel@tonic-gate 	if (t->t_whystop == PR_FAULTED) {
9810Sstevel@tonic-gate 		siginfo_kto32(&lwp->lwp_siginfo, &sp->pr_info);
9820Sstevel@tonic-gate 		if (t->t_whatstop == FLTPAGE)
9830Sstevel@tonic-gate 			sp->pr_info.si_addr =
9840Sstevel@tonic-gate 			    (caddr32_t)(uintptr_t)lwp->lwp_siginfo.si_addr;
9850Sstevel@tonic-gate 	} else if (lwp->lwp_curinfo)
9860Sstevel@tonic-gate 		siginfo_kto32(&lwp->lwp_curinfo->sq_info, &sp->pr_info);
9870Sstevel@tonic-gate 	if (SI_FROMUSER(&lwp->lwp_siginfo) && zp->zone_id != GLOBAL_ZONEID &&
9880Sstevel@tonic-gate 	    sp->pr_info.si_zoneid != zp->zone_id) {
9890Sstevel@tonic-gate 		sp->pr_info.si_pid = zp->zone_zsched->p_pid;
9900Sstevel@tonic-gate 		sp->pr_info.si_uid = 0;
9910Sstevel@tonic-gate 		sp->pr_info.si_ctid = -1;
9920Sstevel@tonic-gate 		sp->pr_info.si_zoneid = zp->zone_id;
9930Sstevel@tonic-gate 	}
9940Sstevel@tonic-gate 	sp->pr_altstack.ss_sp =
9950Sstevel@tonic-gate 	    (caddr32_t)(uintptr_t)lwp->lwp_sigaltstack.ss_sp;
9960Sstevel@tonic-gate 	sp->pr_altstack.ss_size = (size32_t)lwp->lwp_sigaltstack.ss_size;
9970Sstevel@tonic-gate 	sp->pr_altstack.ss_flags = (int32_t)lwp->lwp_sigaltstack.ss_flags;
9980Sstevel@tonic-gate 	prgetaction32(p, PTOU(p), lwp->lwp_cursig, &sp->pr_action);
9990Sstevel@tonic-gate 	sp->pr_oldcontext = (caddr32_t)lwp->lwp_oldcontext;
10000Sstevel@tonic-gate 	sp->pr_ustack = (caddr32_t)lwp->lwp_ustack;
10010Sstevel@tonic-gate 	(void) strncpy(sp->pr_clname, sclass[t->t_cid].cl_name,
10020Sstevel@tonic-gate 		sizeof (sp->pr_clname) - 1);
10030Sstevel@tonic-gate 	if (flags & PR_STOPPED)
10040Sstevel@tonic-gate 		hrt2ts32(t->t_stoptime, &sp->pr_tstamp);
10050Sstevel@tonic-gate 	usr = ms->ms_acct[LMS_USER];
10060Sstevel@tonic-gate 	sys = ms->ms_acct[LMS_SYSTEM] + ms->ms_acct[LMS_TRAP];
10070Sstevel@tonic-gate 	scalehrtime(&usr);
10080Sstevel@tonic-gate 	scalehrtime(&sys);
10090Sstevel@tonic-gate 	hrt2ts32(usr, &sp->pr_utime);
10100Sstevel@tonic-gate 	hrt2ts32(sys, &sp->pr_stime);
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 	/*
10130Sstevel@tonic-gate 	 * Fetch the current instruction, if not a system process.
10140Sstevel@tonic-gate 	 * We don't attempt this unless the lwp is stopped.
10150Sstevel@tonic-gate 	 */
10160Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
10170Sstevel@tonic-gate 		sp->pr_flags |= (PR_ISSYS|PR_PCINVAL);
10180Sstevel@tonic-gate 	else if (!(flags & PR_STOPPED))
10190Sstevel@tonic-gate 		sp->pr_flags |= PR_PCINVAL;
10200Sstevel@tonic-gate 	else if (!prfetchinstr(lwp, &instr))
10210Sstevel@tonic-gate 		sp->pr_flags |= PR_PCINVAL;
10220Sstevel@tonic-gate 	else
10230Sstevel@tonic-gate 		sp->pr_instr = (uint32_t)instr;
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 	/*
10260Sstevel@tonic-gate 	 * Drop p_lock while touching the lwp's stack.
10270Sstevel@tonic-gate 	 */
10280Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
10290Sstevel@tonic-gate 	if (prisstep(lwp))
10300Sstevel@tonic-gate 		sp->pr_flags |= PR_STEP;
10310Sstevel@tonic-gate 	if ((flags & (PR_STOPPED|PR_ASLEEP)) && t->t_sysnum) {
10320Sstevel@tonic-gate 		int i;
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 		sp->pr_syscall = get_syscall32_args(lwp,
10350Sstevel@tonic-gate 			(int *)sp->pr_sysarg, &i);
10360Sstevel@tonic-gate 		sp->pr_nsysarg = (ushort_t)i;
10370Sstevel@tonic-gate 	}
10380Sstevel@tonic-gate 	if ((flags & PR_STOPPED) || t == curthread)
10390Sstevel@tonic-gate 		prgetprregs32(lwp, sp->pr_reg);
10400Sstevel@tonic-gate 	if ((t->t_state == TS_STOPPED && t->t_whystop == PR_SYSEXIT) ||
10410Sstevel@tonic-gate 	    (flags & PR_VFORKP)) {
10420Sstevel@tonic-gate 		long r1, r2;
10430Sstevel@tonic-gate 		user_t *up;
10440Sstevel@tonic-gate 		auxv_t *auxp;
10450Sstevel@tonic-gate 		int i;
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 		sp->pr_errno = prgetrvals(lwp, &r1, &r2);
10480Sstevel@tonic-gate 		if (sp->pr_errno == 0) {
10490Sstevel@tonic-gate 			sp->pr_rval1 = (int32_t)r1;
10500Sstevel@tonic-gate 			sp->pr_rval2 = (int32_t)r2;
10510Sstevel@tonic-gate 			sp->pr_errpriv = PRIV_NONE;
10520Sstevel@tonic-gate 		} else
10530Sstevel@tonic-gate 			sp->pr_errpriv = lwp->lwp_badpriv;
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 		if (t->t_sysnum == SYS_exec || t->t_sysnum == SYS_execve) {
10560Sstevel@tonic-gate 			up = PTOU(p);
10570Sstevel@tonic-gate 			sp->pr_sysarg[0] = 0;
10580Sstevel@tonic-gate 			sp->pr_sysarg[1] = (caddr32_t)up->u_argv;
10590Sstevel@tonic-gate 			sp->pr_sysarg[2] = (caddr32_t)up->u_envp;
10600Sstevel@tonic-gate 			for (i = 0, auxp = up->u_auxv;
10610Sstevel@tonic-gate 			    i < sizeof (up->u_auxv) / sizeof (up->u_auxv[0]);
10620Sstevel@tonic-gate 			    i++, auxp++) {
10630Sstevel@tonic-gate 				if (auxp->a_type == AT_SUN_EXECNAME) {
10640Sstevel@tonic-gate 					sp->pr_sysarg[0] =
10650Sstevel@tonic-gate 					(caddr32_t)(uintptr_t)auxp->a_un.a_ptr;
10660Sstevel@tonic-gate 					break;
10670Sstevel@tonic-gate 				}
10680Sstevel@tonic-gate 			}
10690Sstevel@tonic-gate 		}
10700Sstevel@tonic-gate 	}
10710Sstevel@tonic-gate 	if (prhasfp())
10720Sstevel@tonic-gate 		prgetprfpregs32(lwp, &sp->pr_fpreg);
10730Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
10740Sstevel@tonic-gate }
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate void
10770Sstevel@tonic-gate prgetstatus32(proc_t *p, pstatus32_t *sp, zone_t *zp)
10780Sstevel@tonic-gate {
10790Sstevel@tonic-gate 	kthread_t *t;
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 	t = prchoose(p);	/* returns locked thread */
10840Sstevel@tonic-gate 	ASSERT(t != NULL);
10850Sstevel@tonic-gate 	thread_unlock(t);
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 	/* just bzero the process part, prgetlwpstatus32() does the rest */
10880Sstevel@tonic-gate 	bzero(sp, sizeof (pstatus32_t) - sizeof (lwpstatus32_t));
10890Sstevel@tonic-gate 	sp->pr_nlwp = p->p_lwpcnt;
10900Sstevel@tonic-gate 	sp->pr_nzomb = p->p_zombcnt;
10910Sstevel@tonic-gate 	prassignset(&sp->pr_sigpend, &p->p_sig);
10920Sstevel@tonic-gate 	sp->pr_brkbase = (uint32_t)(uintptr_t)p->p_brkbase;
10930Sstevel@tonic-gate 	sp->pr_brksize = (uint32_t)p->p_brksize;
10940Sstevel@tonic-gate 	sp->pr_stkbase = (uint32_t)(uintptr_t)prgetstackbase(p);
10950Sstevel@tonic-gate 	sp->pr_stksize = (uint32_t)p->p_stksize;
10960Sstevel@tonic-gate 	sp->pr_pid   = p->p_pid;
10970Sstevel@tonic-gate 	if (curproc->p_zone->zone_id != GLOBAL_ZONEID &&
10980Sstevel@tonic-gate 	    (p->p_flag & SZONETOP)) {
10990Sstevel@tonic-gate 		ASSERT(p->p_zone->zone_id != GLOBAL_ZONEID);
11000Sstevel@tonic-gate 		/*
11010Sstevel@tonic-gate 		 * Inside local zones, fake zsched's pid as parent pids for
11020Sstevel@tonic-gate 		 * processes which reference processes outside of the zone.
11030Sstevel@tonic-gate 		 */
11040Sstevel@tonic-gate 		sp->pr_ppid = curproc->p_zone->zone_zsched->p_pid;
11050Sstevel@tonic-gate 	} else {
11060Sstevel@tonic-gate 		sp->pr_ppid = p->p_ppid;
11070Sstevel@tonic-gate 	}
11080Sstevel@tonic-gate 	sp->pr_pgid  = p->p_pgrp;
11090Sstevel@tonic-gate 	sp->pr_sid   = p->p_sessp->s_sid;
11100Sstevel@tonic-gate 	sp->pr_taskid = p->p_task->tk_tkid;
11110Sstevel@tonic-gate 	sp->pr_projid = p->p_task->tk_proj->kpj_id;
11120Sstevel@tonic-gate 	sp->pr_zoneid = p->p_zone->zone_id;
11130Sstevel@tonic-gate 	hrt2ts32(mstate_aggr_state(p, LMS_USER), &sp->pr_utime);
11140Sstevel@tonic-gate 	hrt2ts32(mstate_aggr_state(p, LMS_SYSTEM), &sp->pr_stime);
11150Sstevel@tonic-gate 	TICK_TO_TIMESTRUC32(p->p_cutime, &sp->pr_cutime);
11160Sstevel@tonic-gate 	TICK_TO_TIMESTRUC32(p->p_cstime, &sp->pr_cstime);
11170Sstevel@tonic-gate 	prassignset(&sp->pr_sigtrace, &p->p_sigmask);
11180Sstevel@tonic-gate 	prassignset(&sp->pr_flttrace, &p->p_fltmask);
11190Sstevel@tonic-gate 	prassignset(&sp->pr_sysentry, &PTOU(p)->u_entrymask);
11200Sstevel@tonic-gate 	prassignset(&sp->pr_sysexit, &PTOU(p)->u_exitmask);
11210Sstevel@tonic-gate 	switch (p->p_model) {
11220Sstevel@tonic-gate 	case DATAMODEL_ILP32:
11230Sstevel@tonic-gate 		sp->pr_dmodel = PR_MODEL_ILP32;
11240Sstevel@tonic-gate 		break;
11250Sstevel@tonic-gate 	case DATAMODEL_LP64:
11260Sstevel@tonic-gate 		sp->pr_dmodel = PR_MODEL_LP64;
11270Sstevel@tonic-gate 		break;
11280Sstevel@tonic-gate 	}
11290Sstevel@tonic-gate 	if (p->p_agenttp)
11300Sstevel@tonic-gate 		sp->pr_agentid = p->p_agenttp->t_tid;
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	/* get the chosen lwp's status */
11330Sstevel@tonic-gate 	prgetlwpstatus32(t, &sp->pr_lwp, zp);
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate 	/* replicate the flags */
11360Sstevel@tonic-gate 	sp->pr_flags = sp->pr_lwp.pr_flags;
11370Sstevel@tonic-gate }
11380Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate /*
11410Sstevel@tonic-gate  * Return lwp status.
11420Sstevel@tonic-gate  */
11430Sstevel@tonic-gate void
11440Sstevel@tonic-gate prgetlwpstatus(kthread_t *t, lwpstatus_t *sp, zone_t *zp)
11450Sstevel@tonic-gate {
11460Sstevel@tonic-gate 	proc_t *p = ttoproc(t);
11470Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
11480Sstevel@tonic-gate 	struct mstate *ms = &lwp->lwp_mstate;
11490Sstevel@tonic-gate 	hrtime_t usr, sys;
11500Sstevel@tonic-gate 	int flags;
11510Sstevel@tonic-gate 	ulong_t instr;
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 	bzero(sp, sizeof (*sp));
11560Sstevel@tonic-gate 	flags = 0L;
11570Sstevel@tonic-gate 	if (t->t_state == TS_STOPPED) {
11580Sstevel@tonic-gate 		flags |= PR_STOPPED;
11590Sstevel@tonic-gate 		if ((t->t_schedflag & TS_PSTART) == 0)
11600Sstevel@tonic-gate 			flags |= PR_ISTOP;
11610Sstevel@tonic-gate 	} else if (VSTOPPED(t)) {
11620Sstevel@tonic-gate 		flags |= PR_STOPPED|PR_ISTOP;
11630Sstevel@tonic-gate 	}
11640Sstevel@tonic-gate 	if (!(flags & PR_ISTOP) && (t->t_proc_flag & TP_PRSTOP))
11650Sstevel@tonic-gate 		flags |= PR_DSTOP;
11660Sstevel@tonic-gate 	if (lwp->lwp_asleep)
11670Sstevel@tonic-gate 		flags |= PR_ASLEEP;
11680Sstevel@tonic-gate 	if (t == p->p_agenttp)
11690Sstevel@tonic-gate 		flags |= PR_AGENT;
11700Sstevel@tonic-gate 	if (!(t->t_proc_flag & TP_TWAIT))
11710Sstevel@tonic-gate 		flags |= PR_DETACH;
11720Sstevel@tonic-gate 	if (t->t_proc_flag & TP_DAEMON)
11730Sstevel@tonic-gate 		flags |= PR_DAEMON;
11740Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_FORK)
11750Sstevel@tonic-gate 		flags |= PR_FORK;
11760Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_RUNLCL)
11770Sstevel@tonic-gate 		flags |= PR_RLC;
11780Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_KILLCL)
11790Sstevel@tonic-gate 		flags |= PR_KLC;
11800Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_ASYNC)
11810Sstevel@tonic-gate 		flags |= PR_ASYNC;
11820Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_BPTADJ)
11830Sstevel@tonic-gate 		flags |= PR_BPTADJ;
11840Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_PTRACE)
11850Sstevel@tonic-gate 		flags |= PR_PTRACE;
11860Sstevel@tonic-gate 	if (p->p_flag & SMSACCT)
11870Sstevel@tonic-gate 		flags |= PR_MSACCT;
11880Sstevel@tonic-gate 	if (p->p_flag & SMSFORK)
11890Sstevel@tonic-gate 		flags |= PR_MSFORK;
11900Sstevel@tonic-gate 	if (p->p_flag & SVFWAIT)
11910Sstevel@tonic-gate 		flags |= PR_VFORKP;
11920Sstevel@tonic-gate 	if (p->p_pgidp->pid_pgorphaned)
11930Sstevel@tonic-gate 		flags |= PR_ORPHAN;
1194*3235Sraf 	if (p->p_pidflag & CLDNOSIGCHLD)
1195*3235Sraf 		flags |= PR_NOSIGCHLD;
1196*3235Sraf 	if (p->p_pidflag & CLDWAITPID)
1197*3235Sraf 		flags |= PR_WAITPID;
11980Sstevel@tonic-gate 	sp->pr_flags = flags;
11990Sstevel@tonic-gate 	if (VSTOPPED(t)) {
12000Sstevel@tonic-gate 		sp->pr_why   = PR_REQUESTED;
12010Sstevel@tonic-gate 		sp->pr_what  = 0;
12020Sstevel@tonic-gate 	} else {
12030Sstevel@tonic-gate 		sp->pr_why   = t->t_whystop;
12040Sstevel@tonic-gate 		sp->pr_what  = t->t_whatstop;
12050Sstevel@tonic-gate 	}
12060Sstevel@tonic-gate 	sp->pr_lwpid = t->t_tid;
12070Sstevel@tonic-gate 	sp->pr_cursig  = lwp->lwp_cursig;
12080Sstevel@tonic-gate 	prassignset(&sp->pr_lwppend, &t->t_sig);
12090Sstevel@tonic-gate 	schedctl_finish_sigblock(t);
12100Sstevel@tonic-gate 	prassignset(&sp->pr_lwphold, &t->t_hold);
12110Sstevel@tonic-gate 	if (t->t_whystop == PR_FAULTED)
12120Sstevel@tonic-gate 		bcopy(&lwp->lwp_siginfo,
12130Sstevel@tonic-gate 		    &sp->pr_info, sizeof (k_siginfo_t));
12140Sstevel@tonic-gate 	else if (lwp->lwp_curinfo)
12150Sstevel@tonic-gate 		bcopy(&lwp->lwp_curinfo->sq_info,
12160Sstevel@tonic-gate 		    &sp->pr_info, sizeof (k_siginfo_t));
12170Sstevel@tonic-gate 	if (SI_FROMUSER(&lwp->lwp_siginfo) && zp->zone_id != GLOBAL_ZONEID &&
12180Sstevel@tonic-gate 	    sp->pr_info.si_zoneid != zp->zone_id) {
12190Sstevel@tonic-gate 		sp->pr_info.si_pid = zp->zone_zsched->p_pid;
12200Sstevel@tonic-gate 		sp->pr_info.si_uid = 0;
12210Sstevel@tonic-gate 		sp->pr_info.si_ctid = -1;
12220Sstevel@tonic-gate 		sp->pr_info.si_zoneid = zp->zone_id;
12230Sstevel@tonic-gate 	}
12240Sstevel@tonic-gate 	sp->pr_altstack = lwp->lwp_sigaltstack;
12250Sstevel@tonic-gate 	prgetaction(p, PTOU(p), lwp->lwp_cursig, &sp->pr_action);
12260Sstevel@tonic-gate 	sp->pr_oldcontext = (uintptr_t)lwp->lwp_oldcontext;
12270Sstevel@tonic-gate 	sp->pr_ustack = lwp->lwp_ustack;
12280Sstevel@tonic-gate 	(void) strncpy(sp->pr_clname, sclass[t->t_cid].cl_name,
12290Sstevel@tonic-gate 		sizeof (sp->pr_clname) - 1);
12300Sstevel@tonic-gate 	if (flags & PR_STOPPED)
12310Sstevel@tonic-gate 		hrt2ts(t->t_stoptime, &sp->pr_tstamp);
12320Sstevel@tonic-gate 	usr = ms->ms_acct[LMS_USER];
12330Sstevel@tonic-gate 	sys = ms->ms_acct[LMS_SYSTEM] + ms->ms_acct[LMS_TRAP];
12340Sstevel@tonic-gate 	scalehrtime(&usr);
12350Sstevel@tonic-gate 	scalehrtime(&sys);
12360Sstevel@tonic-gate 	hrt2ts(usr, &sp->pr_utime);
12370Sstevel@tonic-gate 	hrt2ts(sys, &sp->pr_stime);
12380Sstevel@tonic-gate 
12390Sstevel@tonic-gate 	/*
12400Sstevel@tonic-gate 	 * Fetch the current instruction, if not a system process.
12410Sstevel@tonic-gate 	 * We don't attempt this unless the lwp is stopped.
12420Sstevel@tonic-gate 	 */
12430Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
12440Sstevel@tonic-gate 		sp->pr_flags |= (PR_ISSYS|PR_PCINVAL);
12450Sstevel@tonic-gate 	else if (!(flags & PR_STOPPED))
12460Sstevel@tonic-gate 		sp->pr_flags |= PR_PCINVAL;
12470Sstevel@tonic-gate 	else if (!prfetchinstr(lwp, &instr))
12480Sstevel@tonic-gate 		sp->pr_flags |= PR_PCINVAL;
12490Sstevel@tonic-gate 	else
12500Sstevel@tonic-gate 		sp->pr_instr = instr;
12510Sstevel@tonic-gate 
12520Sstevel@tonic-gate 	/*
12530Sstevel@tonic-gate 	 * Drop p_lock while touching the lwp's stack.
12540Sstevel@tonic-gate 	 */
12550Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
12560Sstevel@tonic-gate 	if (prisstep(lwp))
12570Sstevel@tonic-gate 		sp->pr_flags |= PR_STEP;
12580Sstevel@tonic-gate 	if ((flags & (PR_STOPPED|PR_ASLEEP)) && t->t_sysnum) {
12590Sstevel@tonic-gate 		int i;
12600Sstevel@tonic-gate 
12610Sstevel@tonic-gate 		sp->pr_syscall = get_syscall_args(lwp,
12620Sstevel@tonic-gate 			(long *)sp->pr_sysarg, &i);
12630Sstevel@tonic-gate 		sp->pr_nsysarg = (ushort_t)i;
12640Sstevel@tonic-gate 	}
12650Sstevel@tonic-gate 	if ((flags & PR_STOPPED) || t == curthread)
12660Sstevel@tonic-gate 		prgetprregs(lwp, sp->pr_reg);
12670Sstevel@tonic-gate 	if ((t->t_state == TS_STOPPED && t->t_whystop == PR_SYSEXIT) ||
12680Sstevel@tonic-gate 	    (flags & PR_VFORKP)) {
12690Sstevel@tonic-gate 		user_t *up;
12700Sstevel@tonic-gate 		auxv_t *auxp;
12710Sstevel@tonic-gate 		int i;
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate 		sp->pr_errno = prgetrvals(lwp, &sp->pr_rval1, &sp->pr_rval2);
12740Sstevel@tonic-gate 		if (sp->pr_errno == 0)
12750Sstevel@tonic-gate 			sp->pr_errpriv = PRIV_NONE;
12760Sstevel@tonic-gate 		else
12770Sstevel@tonic-gate 			sp->pr_errpriv = lwp->lwp_badpriv;
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 		if (t->t_sysnum == SYS_exec || t->t_sysnum == SYS_execve) {
12800Sstevel@tonic-gate 			up = PTOU(p);
12810Sstevel@tonic-gate 			sp->pr_sysarg[0] = 0;
12820Sstevel@tonic-gate 			sp->pr_sysarg[1] = (uintptr_t)up->u_argv;
12830Sstevel@tonic-gate 			sp->pr_sysarg[2] = (uintptr_t)up->u_envp;
12840Sstevel@tonic-gate 			for (i = 0, auxp = up->u_auxv;
12850Sstevel@tonic-gate 			    i < sizeof (up->u_auxv) / sizeof (up->u_auxv[0]);
12860Sstevel@tonic-gate 			    i++, auxp++) {
12870Sstevel@tonic-gate 				if (auxp->a_type == AT_SUN_EXECNAME) {
12880Sstevel@tonic-gate 					sp->pr_sysarg[0] =
12890Sstevel@tonic-gate 						(uintptr_t)auxp->a_un.a_ptr;
12900Sstevel@tonic-gate 					break;
12910Sstevel@tonic-gate 				}
12920Sstevel@tonic-gate 			}
12930Sstevel@tonic-gate 		}
12940Sstevel@tonic-gate 	}
12950Sstevel@tonic-gate 	if (prhasfp())
12960Sstevel@tonic-gate 		prgetprfpregs(lwp, &sp->pr_fpreg);
12970Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
12980Sstevel@tonic-gate }
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate /*
13010Sstevel@tonic-gate  * Get the sigaction structure for the specified signal.  The u-block
13020Sstevel@tonic-gate  * must already have been mapped in by the caller.
13030Sstevel@tonic-gate  */
13040Sstevel@tonic-gate void
13050Sstevel@tonic-gate prgetaction(proc_t *p, user_t *up, uint_t sig, struct sigaction *sp)
13060Sstevel@tonic-gate {
13070Sstevel@tonic-gate 	bzero(sp, sizeof (*sp));
13080Sstevel@tonic-gate 
13090Sstevel@tonic-gate 	if (sig != 0 && (unsigned)sig < NSIG) {
13100Sstevel@tonic-gate 		sp->sa_handler = up->u_signal[sig-1];
13110Sstevel@tonic-gate 		prassignset(&sp->sa_mask, &up->u_sigmask[sig-1]);
13120Sstevel@tonic-gate 		if (sigismember(&up->u_sigonstack, sig))
13130Sstevel@tonic-gate 			sp->sa_flags |= SA_ONSTACK;
13140Sstevel@tonic-gate 		if (sigismember(&up->u_sigresethand, sig))
13150Sstevel@tonic-gate 			sp->sa_flags |= SA_RESETHAND;
13160Sstevel@tonic-gate 		if (sigismember(&up->u_sigrestart, sig))
13170Sstevel@tonic-gate 			sp->sa_flags |= SA_RESTART;
13180Sstevel@tonic-gate 		if (sigismember(&p->p_siginfo, sig))
13190Sstevel@tonic-gate 			sp->sa_flags |= SA_SIGINFO;
13200Sstevel@tonic-gate 		if (sigismember(&up->u_signodefer, sig))
13210Sstevel@tonic-gate 			sp->sa_flags |= SA_NODEFER;
13220Sstevel@tonic-gate 		if (sig == SIGCLD) {
13230Sstevel@tonic-gate 			if (p->p_flag & SNOWAIT)
13240Sstevel@tonic-gate 				sp->sa_flags |= SA_NOCLDWAIT;
13250Sstevel@tonic-gate 			if ((p->p_flag & SJCTL) == 0)
13260Sstevel@tonic-gate 				sp->sa_flags |= SA_NOCLDSTOP;
13270Sstevel@tonic-gate 		}
13280Sstevel@tonic-gate 	}
13290Sstevel@tonic-gate }
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
13320Sstevel@tonic-gate void
13330Sstevel@tonic-gate prgetaction32(proc_t *p, user_t *up, uint_t sig, struct sigaction32 *sp)
13340Sstevel@tonic-gate {
13350Sstevel@tonic-gate 	bzero(sp, sizeof (*sp));
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 	if (sig != 0 && (unsigned)sig < NSIG) {
13380Sstevel@tonic-gate 		sp->sa_handler = (caddr32_t)(uintptr_t)up->u_signal[sig-1];
13390Sstevel@tonic-gate 		prassignset(&sp->sa_mask, &up->u_sigmask[sig-1]);
13400Sstevel@tonic-gate 		if (sigismember(&up->u_sigonstack, sig))
13410Sstevel@tonic-gate 			sp->sa_flags |= SA_ONSTACK;
13420Sstevel@tonic-gate 		if (sigismember(&up->u_sigresethand, sig))
13430Sstevel@tonic-gate 			sp->sa_flags |= SA_RESETHAND;
13440Sstevel@tonic-gate 		if (sigismember(&up->u_sigrestart, sig))
13450Sstevel@tonic-gate 			sp->sa_flags |= SA_RESTART;
13460Sstevel@tonic-gate 		if (sigismember(&p->p_siginfo, sig))
13470Sstevel@tonic-gate 			sp->sa_flags |= SA_SIGINFO;
13480Sstevel@tonic-gate 		if (sigismember(&up->u_signodefer, sig))
13490Sstevel@tonic-gate 			sp->sa_flags |= SA_NODEFER;
13500Sstevel@tonic-gate 		if (sig == SIGCLD) {
13510Sstevel@tonic-gate 			if (p->p_flag & SNOWAIT)
13520Sstevel@tonic-gate 				sp->sa_flags |= SA_NOCLDWAIT;
13530Sstevel@tonic-gate 			if ((p->p_flag & SJCTL) == 0)
13540Sstevel@tonic-gate 				sp->sa_flags |= SA_NOCLDSTOP;
13550Sstevel@tonic-gate 		}
13560Sstevel@tonic-gate 	}
13570Sstevel@tonic-gate }
13580Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate /*
13610Sstevel@tonic-gate  * Count the number of segments in this process's address space.
13620Sstevel@tonic-gate  */
13630Sstevel@tonic-gate int
13640Sstevel@tonic-gate prnsegs(struct as *as, int reserved)
13650Sstevel@tonic-gate {
13660Sstevel@tonic-gate 	int n = 0;
13670Sstevel@tonic-gate 	struct seg *seg;
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 	ASSERT(as != &kas && AS_WRITE_HELD(as, &as->a_lock));
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 	for (seg = AS_SEGFIRST(as); seg != NULL; seg = AS_SEGNEXT(as, seg)) {
13720Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, reserved);
13730Sstevel@tonic-gate 		caddr_t saddr, naddr;
13740Sstevel@tonic-gate 		void *tmp = NULL;
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
13770Sstevel@tonic-gate 			(void) pr_getprot(seg, reserved, &tmp,
13780Sstevel@tonic-gate 			    &saddr, &naddr, eaddr);
13790Sstevel@tonic-gate 			if (saddr != naddr)
13800Sstevel@tonic-gate 				n++;
13810Sstevel@tonic-gate 		}
13820Sstevel@tonic-gate 
13830Sstevel@tonic-gate 		ASSERT(tmp == NULL);
13840Sstevel@tonic-gate 	}
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 	return (n);
13870Sstevel@tonic-gate }
13880Sstevel@tonic-gate 
13890Sstevel@tonic-gate /*
13900Sstevel@tonic-gate  * Convert uint32_t to decimal string w/o leading zeros.
13910Sstevel@tonic-gate  * Add trailing null characters if 'len' is greater than string length.
13920Sstevel@tonic-gate  * Return the string length.
13930Sstevel@tonic-gate  */
13940Sstevel@tonic-gate int
13950Sstevel@tonic-gate pr_u32tos(uint32_t n, char *s, int len)
13960Sstevel@tonic-gate {
13970Sstevel@tonic-gate 	char cbuf[11];		/* 32-bit unsigned integer fits in 10 digits */
13980Sstevel@tonic-gate 	char *cp = cbuf;
13990Sstevel@tonic-gate 	char *end = s + len;
14000Sstevel@tonic-gate 
14010Sstevel@tonic-gate 	do {
14020Sstevel@tonic-gate 		*cp++ = (char)(n % 10 + '0');
14030Sstevel@tonic-gate 		n /= 10;
14040Sstevel@tonic-gate 	} while (n);
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate 	len = (int)(cp - cbuf);
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 	do {
14090Sstevel@tonic-gate 		*s++ = *--cp;
14100Sstevel@tonic-gate 	} while (cp > cbuf);
14110Sstevel@tonic-gate 
14120Sstevel@tonic-gate 	while (s < end)		/* optional pad */
14130Sstevel@tonic-gate 		*s++ = '\0';
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate 	return (len);
14160Sstevel@tonic-gate }
14170Sstevel@tonic-gate 
14180Sstevel@tonic-gate /*
14190Sstevel@tonic-gate  * Convert uint64_t to decimal string w/o leading zeros.
14200Sstevel@tonic-gate  * Return the string length.
14210Sstevel@tonic-gate  */
14220Sstevel@tonic-gate static int
14230Sstevel@tonic-gate pr_u64tos(uint64_t n, char *s)
14240Sstevel@tonic-gate {
14250Sstevel@tonic-gate 	char cbuf[21];		/* 64-bit unsigned integer fits in 20 digits */
14260Sstevel@tonic-gate 	char *cp = cbuf;
14270Sstevel@tonic-gate 	int len;
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate 	do {
14300Sstevel@tonic-gate 		*cp++ = (char)(n % 10 + '0');
14310Sstevel@tonic-gate 		n /= 10;
14320Sstevel@tonic-gate 	} while (n);
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate 	len = (int)(cp - cbuf);
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate 	do {
14370Sstevel@tonic-gate 		*s++ = *--cp;
14380Sstevel@tonic-gate 	} while (cp > cbuf);
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate 	return (len);
14410Sstevel@tonic-gate }
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate void
14440Sstevel@tonic-gate pr_object_name(char *name, vnode_t *vp, struct vattr *vattr)
14450Sstevel@tonic-gate {
14460Sstevel@tonic-gate 	char *s = name;
14470Sstevel@tonic-gate 	struct vfs *vfsp;
14480Sstevel@tonic-gate 	struct vfssw *vfsswp;
14490Sstevel@tonic-gate 
14500Sstevel@tonic-gate 	if ((vfsp = vp->v_vfsp) != NULL &&
14510Sstevel@tonic-gate 	    ((vfsswp = vfssw + vfsp->vfs_fstype), vfsswp->vsw_name) &&
14520Sstevel@tonic-gate 	    *vfsswp->vsw_name) {
14530Sstevel@tonic-gate 		(void) strcpy(s, vfsswp->vsw_name);
14540Sstevel@tonic-gate 		s += strlen(s);
14550Sstevel@tonic-gate 		*s++ = '.';
14560Sstevel@tonic-gate 	}
14570Sstevel@tonic-gate 	s += pr_u32tos(getmajor(vattr->va_fsid), s, 0);
14580Sstevel@tonic-gate 	*s++ = '.';
14590Sstevel@tonic-gate 	s += pr_u32tos(getminor(vattr->va_fsid), s, 0);
14600Sstevel@tonic-gate 	*s++ = '.';
14610Sstevel@tonic-gate 	s += pr_u64tos(vattr->va_nodeid, s);
14620Sstevel@tonic-gate 	*s++ = '\0';
14630Sstevel@tonic-gate }
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate struct seg *
14660Sstevel@tonic-gate break_seg(proc_t *p)
14670Sstevel@tonic-gate {
14680Sstevel@tonic-gate 	caddr_t addr = p->p_brkbase;
14690Sstevel@tonic-gate 	struct seg *seg;
14700Sstevel@tonic-gate 	struct vnode *vp;
14710Sstevel@tonic-gate 
14720Sstevel@tonic-gate 	if (p->p_brksize != 0)
14730Sstevel@tonic-gate 		addr += p->p_brksize - 1;
14740Sstevel@tonic-gate 	seg = as_segat(p->p_as, addr);
14750Sstevel@tonic-gate 	if (seg != NULL && seg->s_ops == &segvn_ops &&
14760Sstevel@tonic-gate 	    (SEGOP_GETVP(seg, seg->s_base, &vp) != 0 || vp == NULL))
14770Sstevel@tonic-gate 		return (seg);
14780Sstevel@tonic-gate 	return (NULL);
14790Sstevel@tonic-gate }
14800Sstevel@tonic-gate 
14810Sstevel@tonic-gate /*
14822789Sfrankho  * Implementation of service functions to handle procfs generic chained
14832789Sfrankho  * copyout buffers.
14842789Sfrankho  */
14852789Sfrankho typedef struct pr_iobuf_list {
14862789Sfrankho 	list_node_t	piol_link;	/* buffer linkage */
14872789Sfrankho 	size_t		piol_size;	/* total size (header + data) */
14882789Sfrankho 	size_t		piol_usedsize;	/* amount to copy out from this buf */
14892789Sfrankho } piol_t;
14902789Sfrankho 
14912789Sfrankho #define	MAPSIZE	(64 * 1024)
14922789Sfrankho #define	PIOL_DATABUF(iol)	((void *)(&(iol)[1]))
14932789Sfrankho 
14942789Sfrankho void
14952789Sfrankho pr_iol_initlist(list_t *iolhead, size_t itemsize, int n)
14962789Sfrankho {
14972789Sfrankho 	piol_t	*iol;
14982789Sfrankho 	size_t	initial_size = MIN(1, n) * itemsize;
14992789Sfrankho 
15002789Sfrankho 	list_create(iolhead, sizeof (piol_t), offsetof(piol_t, piol_link));
15012789Sfrankho 
15022789Sfrankho 	ASSERT(list_head(iolhead) == NULL);
15032789Sfrankho 	ASSERT(itemsize < MAPSIZE - sizeof (*iol));
15042789Sfrankho 	ASSERT(initial_size > 0);
15052789Sfrankho 
15062789Sfrankho 	/*
15072789Sfrankho 	 * Someone creating chained copyout buffers may ask for less than
15082789Sfrankho 	 * MAPSIZE if the amount of data to be buffered is known to be
15092789Sfrankho 	 * smaller than that.
15102789Sfrankho 	 * But in order to prevent involuntary self-denial of service,
15112789Sfrankho 	 * the requested input size is clamped at MAPSIZE.
15122789Sfrankho 	 */
15132789Sfrankho 	initial_size = MIN(MAPSIZE, initial_size + sizeof (*iol));
15142789Sfrankho 	iol = kmem_alloc(initial_size, KM_SLEEP);
15152789Sfrankho 	list_insert_head(iolhead, iol);
15162789Sfrankho 	iol->piol_usedsize = 0;
15172789Sfrankho 	iol->piol_size = initial_size;
15182789Sfrankho }
15192789Sfrankho 
15202789Sfrankho void *
15212789Sfrankho pr_iol_newbuf(list_t *iolhead, size_t itemsize)
15222789Sfrankho {
15232789Sfrankho 	piol_t	*iol;
15242789Sfrankho 	char	*new;
15252789Sfrankho 
15262789Sfrankho 	ASSERT(itemsize < MAPSIZE - sizeof (*iol));
15272789Sfrankho 	ASSERT(list_head(iolhead) != NULL);
15282789Sfrankho 
15292789Sfrankho 	iol = (piol_t *)list_tail(iolhead);
15302789Sfrankho 
15312789Sfrankho 	if (iol->piol_size <
15322789Sfrankho 	    iol->piol_usedsize + sizeof (*iol) + itemsize) {
15332789Sfrankho 		/*
15342789Sfrankho 		 * Out of space in the current buffer. Allocate more.
15352789Sfrankho 		 */
15362789Sfrankho 		piol_t *newiol;
15372789Sfrankho 
15382789Sfrankho 		newiol = kmem_alloc(MAPSIZE, KM_SLEEP);
15392789Sfrankho 		newiol->piol_size = MAPSIZE;
15402789Sfrankho 		newiol->piol_usedsize = 0;
15412789Sfrankho 
15422789Sfrankho 		list_insert_after(iolhead, iol, newiol);
15432789Sfrankho 		iol = list_next(iolhead, iol);
15442789Sfrankho 		ASSERT(iol == newiol);
15452789Sfrankho 	}
15462789Sfrankho 	new = (char *)PIOL_DATABUF(iol) + iol->piol_usedsize;
15472789Sfrankho 	iol->piol_usedsize += itemsize;
15482789Sfrankho 	bzero(new, itemsize);
15492789Sfrankho 	return (new);
15502789Sfrankho }
15512789Sfrankho 
15522789Sfrankho int
15532789Sfrankho pr_iol_copyout_and_free(list_t *iolhead, caddr_t *tgt, int errin)
15542789Sfrankho {
15552789Sfrankho 	int error = errin;
15562789Sfrankho 	piol_t	*iol;
15572789Sfrankho 
15582789Sfrankho 	while ((iol = list_head(iolhead)) != NULL) {
15592789Sfrankho 		list_remove(iolhead, iol);
15602789Sfrankho 		if (!error) {
15612789Sfrankho 			if (copyout(PIOL_DATABUF(iol), *tgt,
15622789Sfrankho 			    iol->piol_usedsize))
15632789Sfrankho 				error = EFAULT;
15642789Sfrankho 			*tgt += iol->piol_usedsize;
15652789Sfrankho 		}
15662789Sfrankho 		kmem_free(iol, iol->piol_size);
15672789Sfrankho 	}
15682789Sfrankho 	list_destroy(iolhead);
15692789Sfrankho 
15702789Sfrankho 	return (error);
15712789Sfrankho }
15722789Sfrankho 
15732789Sfrankho int
15742789Sfrankho pr_iol_uiomove_and_free(list_t *iolhead, uio_t *uiop, int errin)
15752789Sfrankho {
15762789Sfrankho 	offset_t	off = uiop->uio_offset;
15772789Sfrankho 	char		*base;
15782789Sfrankho 	size_t		size;
15792789Sfrankho 	piol_t		*iol;
15802789Sfrankho 	int		error = errin;
15812789Sfrankho 
15822789Sfrankho 	while ((iol = list_head(iolhead)) != NULL) {
15832789Sfrankho 		list_remove(iolhead, iol);
15842789Sfrankho 		base = PIOL_DATABUF(iol);
15852789Sfrankho 		size = iol->piol_usedsize;
15862789Sfrankho 		if (off <= size && error == 0 && uiop->uio_resid > 0)
15872789Sfrankho 			error = uiomove(base + off, size - off,
15882789Sfrankho 			    UIO_READ, uiop);
15892789Sfrankho 		off = MAX(0, off - (offset_t)size);
15902789Sfrankho 		kmem_free(iol, iol->piol_size);
15912789Sfrankho 	}
15922789Sfrankho 	list_destroy(iolhead);
15932789Sfrankho 
15942789Sfrankho 	return (error);
15952789Sfrankho }
15962789Sfrankho 
15972789Sfrankho /*
15980Sstevel@tonic-gate  * Return an array of structures with memory map information.
15990Sstevel@tonic-gate  * We allocate here; the caller must deallocate.
16000Sstevel@tonic-gate  */
16010Sstevel@tonic-gate int
16022789Sfrankho prgetmap(proc_t *p, int reserved, list_t *iolhead)
16030Sstevel@tonic-gate {
16040Sstevel@tonic-gate 	struct as *as = p->p_as;
16050Sstevel@tonic-gate 	prmap_t *mp;
16060Sstevel@tonic-gate 	struct seg *seg;
16070Sstevel@tonic-gate 	struct seg *brkseg, *stkseg;
16080Sstevel@tonic-gate 	struct vnode *vp;
16090Sstevel@tonic-gate 	struct vattr vattr;
16100Sstevel@tonic-gate 	uint_t prot;
16110Sstevel@tonic-gate 
16120Sstevel@tonic-gate 	ASSERT(as != &kas && AS_WRITE_HELD(as, &as->a_lock));
16130Sstevel@tonic-gate 
16142789Sfrankho 	/*
16152789Sfrankho 	 * Request an initial buffer size that doesn't waste memory
16162789Sfrankho 	 * if the address space has only a small number of segments.
16172789Sfrankho 	 */
16182789Sfrankho 	pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
16190Sstevel@tonic-gate 
16200Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL)
16210Sstevel@tonic-gate 		return (0);
16220Sstevel@tonic-gate 
16230Sstevel@tonic-gate 	brkseg = break_seg(p);
16240Sstevel@tonic-gate 	stkseg = as_segat(as, prgetstackbase(p));
16250Sstevel@tonic-gate 
16260Sstevel@tonic-gate 	do {
16270Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, reserved);
16280Sstevel@tonic-gate 		caddr_t saddr, naddr;
16290Sstevel@tonic-gate 		void *tmp = NULL;
16300Sstevel@tonic-gate 
16310Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
16320Sstevel@tonic-gate 			prot = pr_getprot(seg, reserved, &tmp,
16330Sstevel@tonic-gate 			    &saddr, &naddr, eaddr);
16340Sstevel@tonic-gate 			if (saddr == naddr)
16350Sstevel@tonic-gate 				continue;
16362789Sfrankho 
16372789Sfrankho 			mp = pr_iol_newbuf(iolhead, sizeof (*mp));
16382789Sfrankho 
16390Sstevel@tonic-gate 			mp->pr_vaddr = (uintptr_t)saddr;
16400Sstevel@tonic-gate 			mp->pr_size = naddr - saddr;
16410Sstevel@tonic-gate 			mp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
16420Sstevel@tonic-gate 			mp->pr_mflags = 0;
16430Sstevel@tonic-gate 			if (prot & PROT_READ)
16440Sstevel@tonic-gate 				mp->pr_mflags |= MA_READ;
16450Sstevel@tonic-gate 			if (prot & PROT_WRITE)
16460Sstevel@tonic-gate 				mp->pr_mflags |= MA_WRITE;
16470Sstevel@tonic-gate 			if (prot & PROT_EXEC)
16480Sstevel@tonic-gate 				mp->pr_mflags |= MA_EXEC;
16490Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_SHARED)
16500Sstevel@tonic-gate 				mp->pr_mflags |= MA_SHARED;
16510Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_NORESERVE)
16520Sstevel@tonic-gate 				mp->pr_mflags |= MA_NORESERVE;
16530Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops ||
16540Sstevel@tonic-gate 			    (seg->s_ops == &segvn_ops &&
16550Sstevel@tonic-gate 			    (SEGOP_GETVP(seg, saddr, &vp) != 0 || vp == NULL)))
16560Sstevel@tonic-gate 				mp->pr_mflags |= MA_ANON;
16570Sstevel@tonic-gate 			if (seg == brkseg)
16580Sstevel@tonic-gate 				mp->pr_mflags |= MA_BREAK;
16590Sstevel@tonic-gate 			else if (seg == stkseg) {
16600Sstevel@tonic-gate 				mp->pr_mflags |= MA_STACK;
16610Sstevel@tonic-gate 				if (reserved) {
16620Sstevel@tonic-gate 					size_t maxstack =
16630Sstevel@tonic-gate 					    ((size_t)p->p_stk_ctl +
16640Sstevel@tonic-gate 					    PAGEOFFSET) & PAGEMASK;
16650Sstevel@tonic-gate 					mp->pr_vaddr =
16660Sstevel@tonic-gate 					    (uintptr_t)prgetstackbase(p) +
16670Sstevel@tonic-gate 					    p->p_stksize - maxstack;
16680Sstevel@tonic-gate 					mp->pr_size = (uintptr_t)naddr -
16690Sstevel@tonic-gate 					    mp->pr_vaddr;
16700Sstevel@tonic-gate 				}
16710Sstevel@tonic-gate 			}
16720Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops)
16730Sstevel@tonic-gate 				mp->pr_mflags |= MA_ISM | MA_SHM;
16740Sstevel@tonic-gate 			mp->pr_pagesize = PAGESIZE;
16750Sstevel@tonic-gate 
16760Sstevel@tonic-gate 			/*
16770Sstevel@tonic-gate 			 * Manufacture a filename for the "object" directory.
16780Sstevel@tonic-gate 			 */
16790Sstevel@tonic-gate 			vattr.va_mask = AT_FSID|AT_NODEID;
16800Sstevel@tonic-gate 			if (seg->s_ops == &segvn_ops &&
16810Sstevel@tonic-gate 			    SEGOP_GETVP(seg, saddr, &vp) == 0 &&
16820Sstevel@tonic-gate 			    vp != NULL && vp->v_type == VREG &&
16830Sstevel@tonic-gate 			    VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
16840Sstevel@tonic-gate 				if (vp == p->p_exec)
16850Sstevel@tonic-gate 					(void) strcpy(mp->pr_mapname, "a.out");
16860Sstevel@tonic-gate 				else
16870Sstevel@tonic-gate 					pr_object_name(mp->pr_mapname,
16880Sstevel@tonic-gate 						vp, &vattr);
16890Sstevel@tonic-gate 			}
16900Sstevel@tonic-gate 
16910Sstevel@tonic-gate 			/*
16920Sstevel@tonic-gate 			 * Get the SysV shared memory id, if any.
16930Sstevel@tonic-gate 			 */
16940Sstevel@tonic-gate 			if ((mp->pr_mflags & MA_SHARED) && p->p_segacct &&
16950Sstevel@tonic-gate 			    (mp->pr_shmid = shmgetid(p, seg->s_base)) !=
16960Sstevel@tonic-gate 			    SHMID_NONE) {
16970Sstevel@tonic-gate 				if (mp->pr_shmid == SHMID_FREE)
16980Sstevel@tonic-gate 					mp->pr_shmid = -1;
16990Sstevel@tonic-gate 
17000Sstevel@tonic-gate 				mp->pr_mflags |= MA_SHM;
17010Sstevel@tonic-gate 			} else {
17020Sstevel@tonic-gate 				mp->pr_shmid = -1;
17030Sstevel@tonic-gate 			}
17040Sstevel@tonic-gate 		}
17050Sstevel@tonic-gate 		ASSERT(tmp == NULL);
17060Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
17070Sstevel@tonic-gate 
17082789Sfrankho 	return (0);
17090Sstevel@tonic-gate }
17100Sstevel@tonic-gate 
17110Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
17120Sstevel@tonic-gate int
17132789Sfrankho prgetmap32(proc_t *p, int reserved, list_t *iolhead)
17140Sstevel@tonic-gate {
17150Sstevel@tonic-gate 	struct as *as = p->p_as;
17160Sstevel@tonic-gate 	prmap32_t *mp;
17170Sstevel@tonic-gate 	struct seg *seg;
17180Sstevel@tonic-gate 	struct seg *brkseg, *stkseg;
17190Sstevel@tonic-gate 	struct vnode *vp;
17200Sstevel@tonic-gate 	struct vattr vattr;
17210Sstevel@tonic-gate 	uint_t prot;
17220Sstevel@tonic-gate 
17230Sstevel@tonic-gate 	ASSERT(as != &kas && AS_WRITE_HELD(as, &as->a_lock));
17240Sstevel@tonic-gate 
17252789Sfrankho 	/*
17262789Sfrankho 	 * Request an initial buffer size that doesn't waste memory
17272789Sfrankho 	 * if the address space has only a small number of segments.
17282789Sfrankho 	 */
17292789Sfrankho 	pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL)
17320Sstevel@tonic-gate 		return (0);
17330Sstevel@tonic-gate 
17340Sstevel@tonic-gate 	brkseg = break_seg(p);
17350Sstevel@tonic-gate 	stkseg = as_segat(as, prgetstackbase(p));
17360Sstevel@tonic-gate 
17370Sstevel@tonic-gate 	do {
17380Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, reserved);
17390Sstevel@tonic-gate 		caddr_t saddr, naddr;
17400Sstevel@tonic-gate 		void *tmp = NULL;
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
17430Sstevel@tonic-gate 			prot = pr_getprot(seg, reserved, &tmp,
17440Sstevel@tonic-gate 			    &saddr, &naddr, eaddr);
17450Sstevel@tonic-gate 			if (saddr == naddr)
17460Sstevel@tonic-gate 				continue;
17472789Sfrankho 
17482789Sfrankho 			mp = pr_iol_newbuf(iolhead, sizeof (*mp));
17492789Sfrankho 
17500Sstevel@tonic-gate 			mp->pr_vaddr = (caddr32_t)(uintptr_t)saddr;
17510Sstevel@tonic-gate 			mp->pr_size = (size32_t)(naddr - saddr);
17520Sstevel@tonic-gate 			mp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
17530Sstevel@tonic-gate 			mp->pr_mflags = 0;
17540Sstevel@tonic-gate 			if (prot & PROT_READ)
17550Sstevel@tonic-gate 				mp->pr_mflags |= MA_READ;
17560Sstevel@tonic-gate 			if (prot & PROT_WRITE)
17570Sstevel@tonic-gate 				mp->pr_mflags |= MA_WRITE;
17580Sstevel@tonic-gate 			if (prot & PROT_EXEC)
17590Sstevel@tonic-gate 				mp->pr_mflags |= MA_EXEC;
17600Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_SHARED)
17610Sstevel@tonic-gate 				mp->pr_mflags |= MA_SHARED;
17620Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_NORESERVE)
17630Sstevel@tonic-gate 				mp->pr_mflags |= MA_NORESERVE;
17640Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops ||
17650Sstevel@tonic-gate 			    (seg->s_ops == &segvn_ops &&
17660Sstevel@tonic-gate 			    (SEGOP_GETVP(seg, saddr, &vp) != 0 || vp == NULL)))
17670Sstevel@tonic-gate 				mp->pr_mflags |= MA_ANON;
17680Sstevel@tonic-gate 			if (seg == brkseg)
17690Sstevel@tonic-gate 				mp->pr_mflags |= MA_BREAK;
17700Sstevel@tonic-gate 			else if (seg == stkseg) {
17710Sstevel@tonic-gate 				mp->pr_mflags |= MA_STACK;
17720Sstevel@tonic-gate 				if (reserved) {
17730Sstevel@tonic-gate 					size_t maxstack =
17740Sstevel@tonic-gate 					    ((size_t)p->p_stk_ctl +
17750Sstevel@tonic-gate 					    PAGEOFFSET) & PAGEMASK;
17760Sstevel@tonic-gate 					uintptr_t vaddr =
17770Sstevel@tonic-gate 					    (uintptr_t)prgetstackbase(p) +
17780Sstevel@tonic-gate 					    p->p_stksize - maxstack;
17790Sstevel@tonic-gate 					mp->pr_vaddr = (caddr32_t)vaddr;
17800Sstevel@tonic-gate 					mp->pr_size = (size32_t)
17810Sstevel@tonic-gate 					    ((uintptr_t)naddr - vaddr);
17820Sstevel@tonic-gate 				}
17830Sstevel@tonic-gate 			}
17840Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops)
17850Sstevel@tonic-gate 				mp->pr_mflags |= MA_ISM | MA_SHM;
17860Sstevel@tonic-gate 			mp->pr_pagesize = PAGESIZE;
17870Sstevel@tonic-gate 
17880Sstevel@tonic-gate 			/*
17890Sstevel@tonic-gate 			 * Manufacture a filename for the "object" directory.
17900Sstevel@tonic-gate 			 */
17910Sstevel@tonic-gate 			vattr.va_mask = AT_FSID|AT_NODEID;
17920Sstevel@tonic-gate 			if (seg->s_ops == &segvn_ops &&
17930Sstevel@tonic-gate 			    SEGOP_GETVP(seg, saddr, &vp) == 0 &&
17940Sstevel@tonic-gate 			    vp != NULL && vp->v_type == VREG &&
17950Sstevel@tonic-gate 			    VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
17960Sstevel@tonic-gate 				if (vp == p->p_exec)
17970Sstevel@tonic-gate 					(void) strcpy(mp->pr_mapname, "a.out");
17980Sstevel@tonic-gate 				else
17990Sstevel@tonic-gate 					pr_object_name(mp->pr_mapname,
18000Sstevel@tonic-gate 						vp, &vattr);
18010Sstevel@tonic-gate 			}
18020Sstevel@tonic-gate 
18030Sstevel@tonic-gate 			/*
18040Sstevel@tonic-gate 			 * Get the SysV shared memory id, if any.
18050Sstevel@tonic-gate 			 */
18060Sstevel@tonic-gate 			if ((mp->pr_mflags & MA_SHARED) && p->p_segacct &&
18070Sstevel@tonic-gate 			    (mp->pr_shmid = shmgetid(p, seg->s_base)) !=
18080Sstevel@tonic-gate 			    SHMID_NONE) {
18090Sstevel@tonic-gate 				if (mp->pr_shmid == SHMID_FREE)
18100Sstevel@tonic-gate 					mp->pr_shmid = -1;
18110Sstevel@tonic-gate 
18120Sstevel@tonic-gate 				mp->pr_mflags |= MA_SHM;
18130Sstevel@tonic-gate 			} else {
18140Sstevel@tonic-gate 				mp->pr_shmid = -1;
18150Sstevel@tonic-gate 			}
18160Sstevel@tonic-gate 		}
18170Sstevel@tonic-gate 		ASSERT(tmp == NULL);
18180Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
18190Sstevel@tonic-gate 
18202789Sfrankho 	return (0);
18210Sstevel@tonic-gate }
18220Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
18230Sstevel@tonic-gate 
18240Sstevel@tonic-gate /*
18250Sstevel@tonic-gate  * Return the size of the /proc page data file.
18260Sstevel@tonic-gate  */
18270Sstevel@tonic-gate size_t
18280Sstevel@tonic-gate prpdsize(struct as *as)
18290Sstevel@tonic-gate {
18300Sstevel@tonic-gate 	struct seg *seg;
18310Sstevel@tonic-gate 	size_t size;
18320Sstevel@tonic-gate 
18330Sstevel@tonic-gate 	ASSERT(as != &kas && AS_WRITE_HELD(as, &as->a_lock));
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL)
18360Sstevel@tonic-gate 		return (0);
18370Sstevel@tonic-gate 
18380Sstevel@tonic-gate 	size = sizeof (prpageheader_t);
18390Sstevel@tonic-gate 	do {
18400Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
18410Sstevel@tonic-gate 		caddr_t saddr, naddr;
18420Sstevel@tonic-gate 		void *tmp = NULL;
18430Sstevel@tonic-gate 		size_t npage;
18440Sstevel@tonic-gate 
18450Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
18460Sstevel@tonic-gate 			(void) pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
18470Sstevel@tonic-gate 			if ((npage = (naddr - saddr) / PAGESIZE) != 0)
18480Sstevel@tonic-gate 				size += sizeof (prasmap_t) + round8(npage);
18490Sstevel@tonic-gate 		}
18500Sstevel@tonic-gate 		ASSERT(tmp == NULL);
18510Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
18520Sstevel@tonic-gate 
18530Sstevel@tonic-gate 	return (size);
18540Sstevel@tonic-gate }
18550Sstevel@tonic-gate 
18560Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
18570Sstevel@tonic-gate size_t
18580Sstevel@tonic-gate prpdsize32(struct as *as)
18590Sstevel@tonic-gate {
18600Sstevel@tonic-gate 	struct seg *seg;
18610Sstevel@tonic-gate 	size_t size;
18620Sstevel@tonic-gate 
18630Sstevel@tonic-gate 	ASSERT(as != &kas && AS_WRITE_HELD(as, &as->a_lock));
18640Sstevel@tonic-gate 
18650Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL)
18660Sstevel@tonic-gate 		return (0);
18670Sstevel@tonic-gate 
18680Sstevel@tonic-gate 	size = sizeof (prpageheader32_t);
18690Sstevel@tonic-gate 	do {
18700Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
18710Sstevel@tonic-gate 		caddr_t saddr, naddr;
18720Sstevel@tonic-gate 		void *tmp = NULL;
18730Sstevel@tonic-gate 		size_t npage;
18740Sstevel@tonic-gate 
18750Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
18760Sstevel@tonic-gate 			(void) pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
18770Sstevel@tonic-gate 			if ((npage = (naddr - saddr) / PAGESIZE) != 0)
18780Sstevel@tonic-gate 				size += sizeof (prasmap32_t) + round8(npage);
18790Sstevel@tonic-gate 		}
18800Sstevel@tonic-gate 		ASSERT(tmp == NULL);
18810Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
18820Sstevel@tonic-gate 
18830Sstevel@tonic-gate 	return (size);
18840Sstevel@tonic-gate }
18850Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate /*
18880Sstevel@tonic-gate  * Read page data information.
18890Sstevel@tonic-gate  */
18900Sstevel@tonic-gate int
18910Sstevel@tonic-gate prpdread(proc_t *p, uint_t hatid, struct uio *uiop)
18920Sstevel@tonic-gate {
18930Sstevel@tonic-gate 	struct as *as = p->p_as;
18940Sstevel@tonic-gate 	caddr_t buf;
18950Sstevel@tonic-gate 	size_t size;
18960Sstevel@tonic-gate 	prpageheader_t *php;
18970Sstevel@tonic-gate 	prasmap_t *pmp;
18980Sstevel@tonic-gate 	struct seg *seg;
18990Sstevel@tonic-gate 	int error;
19000Sstevel@tonic-gate 
19010Sstevel@tonic-gate again:
19020Sstevel@tonic-gate 	AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
19030Sstevel@tonic-gate 
19040Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL) {
19050Sstevel@tonic-gate 		AS_LOCK_EXIT(as, &as->a_lock);
19060Sstevel@tonic-gate 		return (0);
19070Sstevel@tonic-gate 	}
19080Sstevel@tonic-gate 	size = prpdsize(as);
19090Sstevel@tonic-gate 	if (uiop->uio_resid < size) {
19100Sstevel@tonic-gate 		AS_LOCK_EXIT(as, &as->a_lock);
19110Sstevel@tonic-gate 		return (E2BIG);
19120Sstevel@tonic-gate 	}
19130Sstevel@tonic-gate 
19140Sstevel@tonic-gate 	buf = kmem_zalloc(size, KM_SLEEP);
19150Sstevel@tonic-gate 	php = (prpageheader_t *)buf;
19160Sstevel@tonic-gate 	pmp = (prasmap_t *)(buf + sizeof (prpageheader_t));
19170Sstevel@tonic-gate 
19180Sstevel@tonic-gate 	hrt2ts(gethrtime(), &php->pr_tstamp);
19190Sstevel@tonic-gate 	php->pr_nmap = 0;
19200Sstevel@tonic-gate 	php->pr_npage = 0;
19210Sstevel@tonic-gate 	do {
19220Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
19230Sstevel@tonic-gate 		caddr_t saddr, naddr;
19240Sstevel@tonic-gate 		void *tmp = NULL;
19250Sstevel@tonic-gate 
19260Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
19270Sstevel@tonic-gate 			struct vnode *vp;
19280Sstevel@tonic-gate 			struct vattr vattr;
19290Sstevel@tonic-gate 			size_t len;
19300Sstevel@tonic-gate 			size_t npage;
19310Sstevel@tonic-gate 			uint_t prot;
19320Sstevel@tonic-gate 			uintptr_t next;
19330Sstevel@tonic-gate 
19340Sstevel@tonic-gate 			prot = pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
19350Sstevel@tonic-gate 			if ((len = (size_t)(naddr - saddr)) == 0)
19360Sstevel@tonic-gate 				continue;
19370Sstevel@tonic-gate 			npage = len / PAGESIZE;
19380Sstevel@tonic-gate 			next = (uintptr_t)(pmp + 1) + round8(npage);
19390Sstevel@tonic-gate 			/*
19400Sstevel@tonic-gate 			 * It's possible that the address space can change
19410Sstevel@tonic-gate 			 * subtlely even though we're holding as->a_lock
19420Sstevel@tonic-gate 			 * due to the nondeterminism of page_exists() in
19430Sstevel@tonic-gate 			 * the presence of asychronously flushed pages or
19440Sstevel@tonic-gate 			 * mapped files whose sizes are changing.
19450Sstevel@tonic-gate 			 * page_exists() may be called indirectly from
19460Sstevel@tonic-gate 			 * pr_getprot() by a SEGOP_INCORE() routine.
19470Sstevel@tonic-gate 			 * If this happens we need to make sure we don't
19480Sstevel@tonic-gate 			 * overrun the buffer whose size we computed based
19490Sstevel@tonic-gate 			 * on the initial iteration through the segments.
19500Sstevel@tonic-gate 			 * Once we've detected an overflow, we need to clean
19510Sstevel@tonic-gate 			 * up the temporary memory allocated in pr_getprot()
19520Sstevel@tonic-gate 			 * and retry. If there's a pending signal, we return
19530Sstevel@tonic-gate 			 * EINTR so that this thread can be dislodged if
19540Sstevel@tonic-gate 			 * a latent bug causes us to spin indefinitely.
19550Sstevel@tonic-gate 			 */
19560Sstevel@tonic-gate 			if (next > (uintptr_t)buf + size) {
19570Sstevel@tonic-gate 				pr_getprot_done(&tmp);
19580Sstevel@tonic-gate 				AS_LOCK_EXIT(as, &as->a_lock);
19590Sstevel@tonic-gate 
19600Sstevel@tonic-gate 				kmem_free(buf, size);
19610Sstevel@tonic-gate 
19620Sstevel@tonic-gate 				if (ISSIG(curthread, JUSTLOOKING))
19630Sstevel@tonic-gate 					return (EINTR);
19640Sstevel@tonic-gate 
19650Sstevel@tonic-gate 				goto again;
19660Sstevel@tonic-gate 			}
19670Sstevel@tonic-gate 
19680Sstevel@tonic-gate 			php->pr_nmap++;
19690Sstevel@tonic-gate 			php->pr_npage += npage;
19700Sstevel@tonic-gate 			pmp->pr_vaddr = (uintptr_t)saddr;
19710Sstevel@tonic-gate 			pmp->pr_npage = npage;
19720Sstevel@tonic-gate 			pmp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
19730Sstevel@tonic-gate 			pmp->pr_mflags = 0;
19740Sstevel@tonic-gate 			if (prot & PROT_READ)
19750Sstevel@tonic-gate 				pmp->pr_mflags |= MA_READ;
19760Sstevel@tonic-gate 			if (prot & PROT_WRITE)
19770Sstevel@tonic-gate 				pmp->pr_mflags |= MA_WRITE;
19780Sstevel@tonic-gate 			if (prot & PROT_EXEC)
19790Sstevel@tonic-gate 				pmp->pr_mflags |= MA_EXEC;
19800Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_SHARED)
19810Sstevel@tonic-gate 				pmp->pr_mflags |= MA_SHARED;
19820Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_NORESERVE)
19830Sstevel@tonic-gate 				pmp->pr_mflags |= MA_NORESERVE;
19840Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops ||
19850Sstevel@tonic-gate 			    (seg->s_ops == &segvn_ops &&
19860Sstevel@tonic-gate 			    (SEGOP_GETVP(seg, saddr, &vp) != 0 || vp == NULL)))
19870Sstevel@tonic-gate 				pmp->pr_mflags |= MA_ANON;
19880Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops)
19890Sstevel@tonic-gate 				pmp->pr_mflags |= MA_ISM | MA_SHM;
19900Sstevel@tonic-gate 			pmp->pr_pagesize = PAGESIZE;
19910Sstevel@tonic-gate 			/*
19920Sstevel@tonic-gate 			 * Manufacture a filename for the "object" directory.
19930Sstevel@tonic-gate 			 */
19940Sstevel@tonic-gate 			vattr.va_mask = AT_FSID|AT_NODEID;
19950Sstevel@tonic-gate 			if (seg->s_ops == &segvn_ops &&
19960Sstevel@tonic-gate 			    SEGOP_GETVP(seg, saddr, &vp) == 0 &&
19970Sstevel@tonic-gate 			    vp != NULL && vp->v_type == VREG &&
19980Sstevel@tonic-gate 			    VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
19990Sstevel@tonic-gate 				if (vp == p->p_exec)
20000Sstevel@tonic-gate 					(void) strcpy(pmp->pr_mapname, "a.out");
20010Sstevel@tonic-gate 				else
20020Sstevel@tonic-gate 					pr_object_name(pmp->pr_mapname,
20030Sstevel@tonic-gate 						vp, &vattr);
20040Sstevel@tonic-gate 			}
20050Sstevel@tonic-gate 
20060Sstevel@tonic-gate 			/*
20070Sstevel@tonic-gate 			 * Get the SysV shared memory id, if any.
20080Sstevel@tonic-gate 			 */
20090Sstevel@tonic-gate 			if ((pmp->pr_mflags & MA_SHARED) && p->p_segacct &&
20100Sstevel@tonic-gate 			    (pmp->pr_shmid = shmgetid(p, seg->s_base)) !=
20110Sstevel@tonic-gate 			    SHMID_NONE) {
20120Sstevel@tonic-gate 				if (pmp->pr_shmid == SHMID_FREE)
20130Sstevel@tonic-gate 					pmp->pr_shmid = -1;
20140Sstevel@tonic-gate 
20150Sstevel@tonic-gate 				pmp->pr_mflags |= MA_SHM;
20160Sstevel@tonic-gate 			} else {
20170Sstevel@tonic-gate 				pmp->pr_shmid = -1;
20180Sstevel@tonic-gate 			}
20190Sstevel@tonic-gate 
20200Sstevel@tonic-gate 			hat_getstat(as, saddr, len, hatid,
20210Sstevel@tonic-gate 			    (char *)(pmp + 1), HAT_SYNC_ZERORM);
20220Sstevel@tonic-gate 			pmp = (prasmap_t *)next;
20230Sstevel@tonic-gate 		}
20240Sstevel@tonic-gate 		ASSERT(tmp == NULL);
20250Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
20260Sstevel@tonic-gate 
20270Sstevel@tonic-gate 	AS_LOCK_EXIT(as, &as->a_lock);
20280Sstevel@tonic-gate 
20290Sstevel@tonic-gate 	ASSERT((uintptr_t)pmp <= (uintptr_t)buf + size);
20300Sstevel@tonic-gate 	error = uiomove(buf, (caddr_t)pmp - buf, UIO_READ, uiop);
20310Sstevel@tonic-gate 	kmem_free(buf, size);
20320Sstevel@tonic-gate 
20330Sstevel@tonic-gate 	return (error);
20340Sstevel@tonic-gate }
20350Sstevel@tonic-gate 
20360Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
20370Sstevel@tonic-gate int
20380Sstevel@tonic-gate prpdread32(proc_t *p, uint_t hatid, struct uio *uiop)
20390Sstevel@tonic-gate {
20400Sstevel@tonic-gate 	struct as *as = p->p_as;
20410Sstevel@tonic-gate 	caddr_t buf;
20420Sstevel@tonic-gate 	size_t size;
20430Sstevel@tonic-gate 	prpageheader32_t *php;
20440Sstevel@tonic-gate 	prasmap32_t *pmp;
20450Sstevel@tonic-gate 	struct seg *seg;
20460Sstevel@tonic-gate 	int error;
20470Sstevel@tonic-gate 
20480Sstevel@tonic-gate again:
20490Sstevel@tonic-gate 	AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
20500Sstevel@tonic-gate 
20510Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL) {
20520Sstevel@tonic-gate 		AS_LOCK_EXIT(as, &as->a_lock);
20530Sstevel@tonic-gate 		return (0);
20540Sstevel@tonic-gate 	}
20550Sstevel@tonic-gate 	size = prpdsize32(as);
20560Sstevel@tonic-gate 	if (uiop->uio_resid < size) {
20570Sstevel@tonic-gate 		AS_LOCK_EXIT(as, &as->a_lock);
20580Sstevel@tonic-gate 		return (E2BIG);
20590Sstevel@tonic-gate 	}
20600Sstevel@tonic-gate 
20610Sstevel@tonic-gate 	buf = kmem_zalloc(size, KM_SLEEP);
20620Sstevel@tonic-gate 	php = (prpageheader32_t *)buf;
20630Sstevel@tonic-gate 	pmp = (prasmap32_t *)(buf + sizeof (prpageheader32_t));
20640Sstevel@tonic-gate 
20650Sstevel@tonic-gate 	hrt2ts32(gethrtime(), &php->pr_tstamp);
20660Sstevel@tonic-gate 	php->pr_nmap = 0;
20670Sstevel@tonic-gate 	php->pr_npage = 0;
20680Sstevel@tonic-gate 	do {
20690Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
20700Sstevel@tonic-gate 		caddr_t saddr, naddr;
20710Sstevel@tonic-gate 		void *tmp = NULL;
20720Sstevel@tonic-gate 
20730Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
20740Sstevel@tonic-gate 			struct vnode *vp;
20750Sstevel@tonic-gate 			struct vattr vattr;
20760Sstevel@tonic-gate 			size_t len;
20770Sstevel@tonic-gate 			size_t npage;
20780Sstevel@tonic-gate 			uint_t prot;
20790Sstevel@tonic-gate 			uintptr_t next;
20800Sstevel@tonic-gate 
20810Sstevel@tonic-gate 			prot = pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
20820Sstevel@tonic-gate 			if ((len = (size_t)(naddr - saddr)) == 0)
20830Sstevel@tonic-gate 				continue;
20840Sstevel@tonic-gate 			npage = len / PAGESIZE;
20850Sstevel@tonic-gate 			next = (uintptr_t)(pmp + 1) + round8(npage);
20860Sstevel@tonic-gate 			/*
20870Sstevel@tonic-gate 			 * It's possible that the address space can change
20880Sstevel@tonic-gate 			 * subtlely even though we're holding as->a_lock
20890Sstevel@tonic-gate 			 * due to the nondeterminism of page_exists() in
20900Sstevel@tonic-gate 			 * the presence of asychronously flushed pages or
20910Sstevel@tonic-gate 			 * mapped files whose sizes are changing.
20920Sstevel@tonic-gate 			 * page_exists() may be called indirectly from
20930Sstevel@tonic-gate 			 * pr_getprot() by a SEGOP_INCORE() routine.
20940Sstevel@tonic-gate 			 * If this happens we need to make sure we don't
20950Sstevel@tonic-gate 			 * overrun the buffer whose size we computed based
20960Sstevel@tonic-gate 			 * on the initial iteration through the segments.
20970Sstevel@tonic-gate 			 * Once we've detected an overflow, we need to clean
20980Sstevel@tonic-gate 			 * up the temporary memory allocated in pr_getprot()
20990Sstevel@tonic-gate 			 * and retry. If there's a pending signal, we return
21000Sstevel@tonic-gate 			 * EINTR so that this thread can be dislodged if
21010Sstevel@tonic-gate 			 * a latent bug causes us to spin indefinitely.
21020Sstevel@tonic-gate 			 */
21030Sstevel@tonic-gate 			if (next > (uintptr_t)buf + size) {
21040Sstevel@tonic-gate 				pr_getprot_done(&tmp);
21050Sstevel@tonic-gate 				AS_LOCK_EXIT(as, &as->a_lock);
21060Sstevel@tonic-gate 
21070Sstevel@tonic-gate 				kmem_free(buf, size);
21080Sstevel@tonic-gate 
21090Sstevel@tonic-gate 				if (ISSIG(curthread, JUSTLOOKING))
21100Sstevel@tonic-gate 					return (EINTR);
21110Sstevel@tonic-gate 
21120Sstevel@tonic-gate 				goto again;
21130Sstevel@tonic-gate 			}
21140Sstevel@tonic-gate 
21150Sstevel@tonic-gate 			php->pr_nmap++;
21160Sstevel@tonic-gate 			php->pr_npage += npage;
21170Sstevel@tonic-gate 			pmp->pr_vaddr = (caddr32_t)(uintptr_t)saddr;
21180Sstevel@tonic-gate 			pmp->pr_npage = (size32_t)npage;
21190Sstevel@tonic-gate 			pmp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
21200Sstevel@tonic-gate 			pmp->pr_mflags = 0;
21210Sstevel@tonic-gate 			if (prot & PROT_READ)
21220Sstevel@tonic-gate 				pmp->pr_mflags |= MA_READ;
21230Sstevel@tonic-gate 			if (prot & PROT_WRITE)
21240Sstevel@tonic-gate 				pmp->pr_mflags |= MA_WRITE;
21250Sstevel@tonic-gate 			if (prot & PROT_EXEC)
21260Sstevel@tonic-gate 				pmp->pr_mflags |= MA_EXEC;
21270Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_SHARED)
21280Sstevel@tonic-gate 				pmp->pr_mflags |= MA_SHARED;
21290Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_NORESERVE)
21300Sstevel@tonic-gate 				pmp->pr_mflags |= MA_NORESERVE;
21310Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops ||
21320Sstevel@tonic-gate 			    (seg->s_ops == &segvn_ops &&
21330Sstevel@tonic-gate 			    (SEGOP_GETVP(seg, saddr, &vp) != 0 || vp == NULL)))
21340Sstevel@tonic-gate 				pmp->pr_mflags |= MA_ANON;
21350Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops)
21360Sstevel@tonic-gate 				pmp->pr_mflags |= MA_ISM | MA_SHM;
21370Sstevel@tonic-gate 			pmp->pr_pagesize = PAGESIZE;
21380Sstevel@tonic-gate 			/*
21390Sstevel@tonic-gate 			 * Manufacture a filename for the "object" directory.
21400Sstevel@tonic-gate 			 */
21410Sstevel@tonic-gate 			vattr.va_mask = AT_FSID|AT_NODEID;
21420Sstevel@tonic-gate 			if (seg->s_ops == &segvn_ops &&
21430Sstevel@tonic-gate 			    SEGOP_GETVP(seg, saddr, &vp) == 0 &&
21440Sstevel@tonic-gate 			    vp != NULL && vp->v_type == VREG &&
21450Sstevel@tonic-gate 			    VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
21460Sstevel@tonic-gate 				if (vp == p->p_exec)
21470Sstevel@tonic-gate 					(void) strcpy(pmp->pr_mapname, "a.out");
21480Sstevel@tonic-gate 				else
21490Sstevel@tonic-gate 					pr_object_name(pmp->pr_mapname,
21500Sstevel@tonic-gate 						vp, &vattr);
21510Sstevel@tonic-gate 			}
21520Sstevel@tonic-gate 
21530Sstevel@tonic-gate 			/*
21540Sstevel@tonic-gate 			 * Get the SysV shared memory id, if any.
21550Sstevel@tonic-gate 			 */
21560Sstevel@tonic-gate 			if ((pmp->pr_mflags & MA_SHARED) && p->p_segacct &&
21570Sstevel@tonic-gate 			    (pmp->pr_shmid = shmgetid(p, seg->s_base)) !=
21580Sstevel@tonic-gate 			    SHMID_NONE) {
21590Sstevel@tonic-gate 				if (pmp->pr_shmid == SHMID_FREE)
21600Sstevel@tonic-gate 					pmp->pr_shmid = -1;
21610Sstevel@tonic-gate 
21620Sstevel@tonic-gate 				pmp->pr_mflags |= MA_SHM;
21630Sstevel@tonic-gate 			} else {
21640Sstevel@tonic-gate 				pmp->pr_shmid = -1;
21650Sstevel@tonic-gate 			}
21660Sstevel@tonic-gate 
21670Sstevel@tonic-gate 			hat_getstat(as, saddr, len, hatid,
21680Sstevel@tonic-gate 			    (char *)(pmp + 1), HAT_SYNC_ZERORM);
21690Sstevel@tonic-gate 			pmp = (prasmap32_t *)next;
21700Sstevel@tonic-gate 		}
21710Sstevel@tonic-gate 		ASSERT(tmp == NULL);
21720Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
21730Sstevel@tonic-gate 
21740Sstevel@tonic-gate 	AS_LOCK_EXIT(as, &as->a_lock);
21750Sstevel@tonic-gate 
21760Sstevel@tonic-gate 	ASSERT((uintptr_t)pmp <= (uintptr_t)buf + size);
21770Sstevel@tonic-gate 	error = uiomove(buf, (caddr_t)pmp - buf, UIO_READ, uiop);
21780Sstevel@tonic-gate 	kmem_free(buf, size);
21790Sstevel@tonic-gate 
21800Sstevel@tonic-gate 	return (error);
21810Sstevel@tonic-gate }
21820Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
21830Sstevel@tonic-gate 
21840Sstevel@tonic-gate ushort_t
21850Sstevel@tonic-gate prgetpctcpu(uint64_t pct)
21860Sstevel@tonic-gate {
21870Sstevel@tonic-gate 	/*
21880Sstevel@tonic-gate 	 * The value returned will be relevant in the zone of the examiner,
21890Sstevel@tonic-gate 	 * which may not be the same as the zone which performed the procfs
21900Sstevel@tonic-gate 	 * mount.
21910Sstevel@tonic-gate 	 */
21920Sstevel@tonic-gate 	int nonline = zone_ncpus_online_get(curproc->p_zone);
21930Sstevel@tonic-gate 
21940Sstevel@tonic-gate 	/*
21950Sstevel@tonic-gate 	 * Prorate over online cpus so we don't exceed 100%
21960Sstevel@tonic-gate 	 */
21970Sstevel@tonic-gate 	if (nonline > 1)
21980Sstevel@tonic-gate 		pct /= nonline;
21990Sstevel@tonic-gate 	pct >>= 16;		/* convert to 16-bit scaled integer */
22000Sstevel@tonic-gate 	if (pct > 0x8000)	/* might happen, due to rounding */
22010Sstevel@tonic-gate 		pct = 0x8000;
22020Sstevel@tonic-gate 	return ((ushort_t)pct);
22030Sstevel@tonic-gate }
22040Sstevel@tonic-gate 
22050Sstevel@tonic-gate /*
22060Sstevel@tonic-gate  * Return information used by ps(1).
22070Sstevel@tonic-gate  */
22080Sstevel@tonic-gate void
22090Sstevel@tonic-gate prgetpsinfo(proc_t *p, psinfo_t *psp)
22100Sstevel@tonic-gate {
22110Sstevel@tonic-gate 	kthread_t *t;
22120Sstevel@tonic-gate 	struct cred *cred;
22130Sstevel@tonic-gate 	hrtime_t hrutime, hrstime;
22140Sstevel@tonic-gate 
22150Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
22160Sstevel@tonic-gate 
22170Sstevel@tonic-gate 	if ((t = prchoose(p)) == NULL)	/* returns locked thread */
22180Sstevel@tonic-gate 		bzero(psp, sizeof (*psp));
22190Sstevel@tonic-gate 	else {
22200Sstevel@tonic-gate 		thread_unlock(t);
22210Sstevel@tonic-gate 		bzero(psp, sizeof (*psp) - sizeof (psp->pr_lwp));
22220Sstevel@tonic-gate 	}
22230Sstevel@tonic-gate 
22240Sstevel@tonic-gate 	/*
22250Sstevel@tonic-gate 	 * only export SSYS and SMSACCT; everything else is off-limits to
22260Sstevel@tonic-gate 	 * userland apps.
22270Sstevel@tonic-gate 	 */
22280Sstevel@tonic-gate 	psp->pr_flag = p->p_flag & (SSYS | SMSACCT);
22290Sstevel@tonic-gate 	psp->pr_nlwp = p->p_lwpcnt;
22300Sstevel@tonic-gate 	psp->pr_nzomb = p->p_zombcnt;
22310Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
22320Sstevel@tonic-gate 	cred = p->p_cred;
22330Sstevel@tonic-gate 	psp->pr_uid = crgetruid(cred);
22340Sstevel@tonic-gate 	psp->pr_euid = crgetuid(cred);
22350Sstevel@tonic-gate 	psp->pr_gid = crgetrgid(cred);
22360Sstevel@tonic-gate 	psp->pr_egid = crgetgid(cred);
22370Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
22380Sstevel@tonic-gate 	psp->pr_pid = p->p_pid;
22390Sstevel@tonic-gate 	if (curproc->p_zone->zone_id != GLOBAL_ZONEID &&
22400Sstevel@tonic-gate 	    (p->p_flag & SZONETOP)) {
22410Sstevel@tonic-gate 		ASSERT(p->p_zone->zone_id != GLOBAL_ZONEID);
22420Sstevel@tonic-gate 		/*
22430Sstevel@tonic-gate 		 * Inside local zones, fake zsched's pid as parent pids for
22440Sstevel@tonic-gate 		 * processes which reference processes outside of the zone.
22450Sstevel@tonic-gate 		 */
22460Sstevel@tonic-gate 		psp->pr_ppid = curproc->p_zone->zone_zsched->p_pid;
22470Sstevel@tonic-gate 	} else {
22480Sstevel@tonic-gate 		psp->pr_ppid = p->p_ppid;
22490Sstevel@tonic-gate 	}
22500Sstevel@tonic-gate 	psp->pr_pgid = p->p_pgrp;
22510Sstevel@tonic-gate 	psp->pr_sid = p->p_sessp->s_sid;
22520Sstevel@tonic-gate 	psp->pr_taskid = p->p_task->tk_tkid;
22530Sstevel@tonic-gate 	psp->pr_projid = p->p_task->tk_proj->kpj_id;
22540Sstevel@tonic-gate 	psp->pr_poolid = p->p_pool->pool_id;
22550Sstevel@tonic-gate 	psp->pr_zoneid = p->p_zone->zone_id;
22560Sstevel@tonic-gate 	if ((psp->pr_contract = PRCTID(p)) == 0)
22570Sstevel@tonic-gate 		psp->pr_contract = -1;
22580Sstevel@tonic-gate 	psp->pr_addr = (uintptr_t)prgetpsaddr(p);
22590Sstevel@tonic-gate 	switch (p->p_model) {
22600Sstevel@tonic-gate 	case DATAMODEL_ILP32:
22610Sstevel@tonic-gate 		psp->pr_dmodel = PR_MODEL_ILP32;
22620Sstevel@tonic-gate 		break;
22630Sstevel@tonic-gate 	case DATAMODEL_LP64:
22640Sstevel@tonic-gate 		psp->pr_dmodel = PR_MODEL_LP64;
22650Sstevel@tonic-gate 		break;
22660Sstevel@tonic-gate 	}
22670Sstevel@tonic-gate 	hrutime = mstate_aggr_state(p, LMS_USER);
22680Sstevel@tonic-gate 	hrstime = mstate_aggr_state(p, LMS_SYSTEM);
22690Sstevel@tonic-gate 	hrt2ts((hrutime + hrstime), &psp->pr_time);
22700Sstevel@tonic-gate 	TICK_TO_TIMESTRUC(p->p_cutime + p->p_cstime, &psp->pr_ctime);
22710Sstevel@tonic-gate 
22720Sstevel@tonic-gate 	if (t == NULL) {
22730Sstevel@tonic-gate 		int wcode = p->p_wcode;		/* must be atomic read */
22740Sstevel@tonic-gate 
22750Sstevel@tonic-gate 		if (wcode)
22760Sstevel@tonic-gate 			psp->pr_wstat = wstat(wcode, p->p_wdata);
22770Sstevel@tonic-gate 		psp->pr_ttydev = PRNODEV;
22780Sstevel@tonic-gate 		psp->pr_lwp.pr_state = SZOMB;
22790Sstevel@tonic-gate 		psp->pr_lwp.pr_sname = 'Z';
22800Sstevel@tonic-gate 		psp->pr_lwp.pr_bindpro = PBIND_NONE;
22810Sstevel@tonic-gate 		psp->pr_lwp.pr_bindpset = PS_NONE;
22820Sstevel@tonic-gate 	} else {
22830Sstevel@tonic-gate 		user_t *up = PTOU(p);
22840Sstevel@tonic-gate 		struct as *as;
22850Sstevel@tonic-gate 		dev_t d;
22860Sstevel@tonic-gate 		extern dev_t rwsconsdev, rconsdev, uconsdev;
22870Sstevel@tonic-gate 
22880Sstevel@tonic-gate 		d = cttydev(p);
22890Sstevel@tonic-gate 		/*
22900Sstevel@tonic-gate 		 * If the controlling terminal is the real
22910Sstevel@tonic-gate 		 * or workstation console device, map to what the
22920Sstevel@tonic-gate 		 * user thinks is the console device.
22930Sstevel@tonic-gate 		 */
22940Sstevel@tonic-gate 		if (d == rwsconsdev || d == rconsdev)
22950Sstevel@tonic-gate 			d = uconsdev;
22960Sstevel@tonic-gate 		psp->pr_ttydev = (d == NODEV) ? PRNODEV : d;
22970Sstevel@tonic-gate 		psp->pr_start = up->u_start;
22980Sstevel@tonic-gate 		bcopy(up->u_comm, psp->pr_fname,
22990Sstevel@tonic-gate 		    MIN(sizeof (up->u_comm), sizeof (psp->pr_fname)-1));
23000Sstevel@tonic-gate 		bcopy(up->u_psargs, psp->pr_psargs,
23010Sstevel@tonic-gate 		    MIN(PRARGSZ-1, PSARGSZ));
23020Sstevel@tonic-gate 		psp->pr_argc = up->u_argc;
23030Sstevel@tonic-gate 		psp->pr_argv = up->u_argv;
23040Sstevel@tonic-gate 		psp->pr_envp = up->u_envp;
23050Sstevel@tonic-gate 
23060Sstevel@tonic-gate 		/* get the chosen lwp's lwpsinfo */
23070Sstevel@tonic-gate 		prgetlwpsinfo(t, &psp->pr_lwp);
23080Sstevel@tonic-gate 
23090Sstevel@tonic-gate 		/* compute %cpu for the process */
23100Sstevel@tonic-gate 		if (p->p_lwpcnt == 1)
23110Sstevel@tonic-gate 			psp->pr_pctcpu = psp->pr_lwp.pr_pctcpu;
23120Sstevel@tonic-gate 		else {
23130Sstevel@tonic-gate 			uint64_t pct = 0;
23140Sstevel@tonic-gate 			hrtime_t cur_time = gethrtime_unscaled();
23150Sstevel@tonic-gate 
23160Sstevel@tonic-gate 			t = p->p_tlist;
23170Sstevel@tonic-gate 			do {
23180Sstevel@tonic-gate 				pct += cpu_update_pct(t, cur_time);
23190Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
23200Sstevel@tonic-gate 
23210Sstevel@tonic-gate 			psp->pr_pctcpu = prgetpctcpu(pct);
23220Sstevel@tonic-gate 		}
23230Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
23240Sstevel@tonic-gate 			psp->pr_size = 0;
23250Sstevel@tonic-gate 			psp->pr_rssize = 0;
23260Sstevel@tonic-gate 		} else {
23270Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
23280Sstevel@tonic-gate 			AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
23290Sstevel@tonic-gate 			psp->pr_size = btopr(rm_assize(as)) * (PAGESIZE / 1024);
23300Sstevel@tonic-gate 			psp->pr_rssize = rm_asrss(as) * (PAGESIZE / 1024);
23310Sstevel@tonic-gate 			psp->pr_pctmem = rm_pctmemory(as);
23320Sstevel@tonic-gate 			AS_LOCK_EXIT(as, &as->a_lock);
23330Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
23340Sstevel@tonic-gate 		}
23350Sstevel@tonic-gate 	}
23360Sstevel@tonic-gate }
23370Sstevel@tonic-gate 
23380Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
23390Sstevel@tonic-gate void
23400Sstevel@tonic-gate prgetpsinfo32(proc_t *p, psinfo32_t *psp)
23410Sstevel@tonic-gate {
23420Sstevel@tonic-gate 	kthread_t *t;
23430Sstevel@tonic-gate 	struct cred *cred;
23440Sstevel@tonic-gate 	hrtime_t hrutime, hrstime;
23450Sstevel@tonic-gate 
23460Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
23470Sstevel@tonic-gate 
23480Sstevel@tonic-gate 	if ((t = prchoose(p)) == NULL)	/* returns locked thread */
23490Sstevel@tonic-gate 		bzero(psp, sizeof (*psp));
23500Sstevel@tonic-gate 	else {
23510Sstevel@tonic-gate 		thread_unlock(t);
23520Sstevel@tonic-gate 		bzero(psp, sizeof (*psp) - sizeof (psp->pr_lwp));
23530Sstevel@tonic-gate 	}
23540Sstevel@tonic-gate 
23550Sstevel@tonic-gate 	/*
23560Sstevel@tonic-gate 	 * only export SSYS and SMSACCT; everything else is off-limits to
23570Sstevel@tonic-gate 	 * userland apps.
23580Sstevel@tonic-gate 	 */
23590Sstevel@tonic-gate 	psp->pr_flag = p->p_flag & (SSYS | SMSACCT);
23600Sstevel@tonic-gate 	psp->pr_nlwp = p->p_lwpcnt;
23610Sstevel@tonic-gate 	psp->pr_nzomb = p->p_zombcnt;
23620Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
23630Sstevel@tonic-gate 	cred = p->p_cred;
23640Sstevel@tonic-gate 	psp->pr_uid = crgetruid(cred);
23650Sstevel@tonic-gate 	psp->pr_euid = crgetuid(cred);
23660Sstevel@tonic-gate 	psp->pr_gid = crgetrgid(cred);
23670Sstevel@tonic-gate 	psp->pr_egid = crgetgid(cred);
23680Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
23690Sstevel@tonic-gate 	psp->pr_pid = p->p_pid;
23700Sstevel@tonic-gate 	if (curproc->p_zone->zone_id != GLOBAL_ZONEID &&
23710Sstevel@tonic-gate 	    (p->p_flag & SZONETOP)) {
23720Sstevel@tonic-gate 		ASSERT(p->p_zone->zone_id != GLOBAL_ZONEID);
23730Sstevel@tonic-gate 		/*
23740Sstevel@tonic-gate 		 * Inside local zones, fake zsched's pid as parent pids for
23750Sstevel@tonic-gate 		 * processes which reference processes outside of the zone.
23760Sstevel@tonic-gate 		 */
23770Sstevel@tonic-gate 		psp->pr_ppid = curproc->p_zone->zone_zsched->p_pid;
23780Sstevel@tonic-gate 	} else {
23790Sstevel@tonic-gate 		psp->pr_ppid = p->p_ppid;
23800Sstevel@tonic-gate 	}
23810Sstevel@tonic-gate 	psp->pr_pgid = p->p_pgrp;
23820Sstevel@tonic-gate 	psp->pr_sid = p->p_sessp->s_sid;
23830Sstevel@tonic-gate 	psp->pr_taskid = p->p_task->tk_tkid;
23840Sstevel@tonic-gate 	psp->pr_projid = p->p_task->tk_proj->kpj_id;
23850Sstevel@tonic-gate 	psp->pr_poolid = p->p_pool->pool_id;
23860Sstevel@tonic-gate 	psp->pr_zoneid = p->p_zone->zone_id;
23870Sstevel@tonic-gate 	if ((psp->pr_contract = PRCTID(p)) == 0)
23880Sstevel@tonic-gate 		psp->pr_contract = -1;
23890Sstevel@tonic-gate 	psp->pr_addr = 0;	/* cannot represent 64-bit addr in 32 bits */
23900Sstevel@tonic-gate 	switch (p->p_model) {
23910Sstevel@tonic-gate 	case DATAMODEL_ILP32:
23920Sstevel@tonic-gate 		psp->pr_dmodel = PR_MODEL_ILP32;
23930Sstevel@tonic-gate 		break;
23940Sstevel@tonic-gate 	case DATAMODEL_LP64:
23950Sstevel@tonic-gate 		psp->pr_dmodel = PR_MODEL_LP64;
23960Sstevel@tonic-gate 		break;
23970Sstevel@tonic-gate 	}
23980Sstevel@tonic-gate 	hrutime = mstate_aggr_state(p, LMS_USER);
23990Sstevel@tonic-gate 	hrstime = mstate_aggr_state(p, LMS_SYSTEM);
24000Sstevel@tonic-gate 	hrt2ts32(hrutime + hrstime, &psp->pr_time);
24010Sstevel@tonic-gate 	TICK_TO_TIMESTRUC32(p->p_cutime + p->p_cstime, &psp->pr_ctime);
24020Sstevel@tonic-gate 
24030Sstevel@tonic-gate 	if (t == NULL) {
24040Sstevel@tonic-gate 		extern int wstat(int, int);	/* needs a header file */
24050Sstevel@tonic-gate 		int wcode = p->p_wcode;		/* must be atomic read */
24060Sstevel@tonic-gate 
24070Sstevel@tonic-gate 		if (wcode)
24080Sstevel@tonic-gate 			psp->pr_wstat = wstat(wcode, p->p_wdata);
24090Sstevel@tonic-gate 		psp->pr_ttydev = PRNODEV32;
24100Sstevel@tonic-gate 		psp->pr_lwp.pr_state = SZOMB;
24110Sstevel@tonic-gate 		psp->pr_lwp.pr_sname = 'Z';
24120Sstevel@tonic-gate 	} else {
24130Sstevel@tonic-gate 		user_t *up = PTOU(p);
24140Sstevel@tonic-gate 		struct as *as;
24150Sstevel@tonic-gate 		dev_t d;
24160Sstevel@tonic-gate 		extern dev_t rwsconsdev, rconsdev, uconsdev;
24170Sstevel@tonic-gate 
24180Sstevel@tonic-gate 		d = cttydev(p);
24190Sstevel@tonic-gate 		/*
24200Sstevel@tonic-gate 		 * If the controlling terminal is the real
24210Sstevel@tonic-gate 		 * or workstation console device, map to what the
24220Sstevel@tonic-gate 		 * user thinks is the console device.
24230Sstevel@tonic-gate 		 */
24240Sstevel@tonic-gate 		if (d == rwsconsdev || d == rconsdev)
24250Sstevel@tonic-gate 			d = uconsdev;
24260Sstevel@tonic-gate 		(void) cmpldev(&psp->pr_ttydev, d);
24270Sstevel@tonic-gate 		TIMESPEC_TO_TIMESPEC32(&psp->pr_start, &up->u_start);
24280Sstevel@tonic-gate 		bcopy(up->u_comm, psp->pr_fname,
24290Sstevel@tonic-gate 		    MIN(sizeof (up->u_comm), sizeof (psp->pr_fname)-1));
24300Sstevel@tonic-gate 		bcopy(up->u_psargs, psp->pr_psargs,
24310Sstevel@tonic-gate 		    MIN(PRARGSZ-1, PSARGSZ));
24320Sstevel@tonic-gate 		psp->pr_argc = up->u_argc;
24330Sstevel@tonic-gate 		psp->pr_argv = (caddr32_t)up->u_argv;
24340Sstevel@tonic-gate 		psp->pr_envp = (caddr32_t)up->u_envp;
24350Sstevel@tonic-gate 
24360Sstevel@tonic-gate 		/* get the chosen lwp's lwpsinfo */
24370Sstevel@tonic-gate 		prgetlwpsinfo32(t, &psp->pr_lwp);
24380Sstevel@tonic-gate 
24390Sstevel@tonic-gate 		/* compute %cpu for the process */
24400Sstevel@tonic-gate 		if (p->p_lwpcnt == 1)
24410Sstevel@tonic-gate 			psp->pr_pctcpu = psp->pr_lwp.pr_pctcpu;
24420Sstevel@tonic-gate 		else {
24430Sstevel@tonic-gate 			uint64_t pct = 0;
24440Sstevel@tonic-gate 			hrtime_t cur_time;
24450Sstevel@tonic-gate 
24460Sstevel@tonic-gate 			t = p->p_tlist;
24470Sstevel@tonic-gate 			cur_time = gethrtime_unscaled();
24480Sstevel@tonic-gate 			do {
24490Sstevel@tonic-gate 				pct += cpu_update_pct(t, cur_time);
24500Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
24510Sstevel@tonic-gate 
24520Sstevel@tonic-gate 			psp->pr_pctcpu = prgetpctcpu(pct);
24530Sstevel@tonic-gate 		}
24540Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
24550Sstevel@tonic-gate 			psp->pr_size = 0;
24560Sstevel@tonic-gate 			psp->pr_rssize = 0;
24570Sstevel@tonic-gate 		} else {
24580Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
24590Sstevel@tonic-gate 			AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
24600Sstevel@tonic-gate 			psp->pr_size = (size32_t)
24610Sstevel@tonic-gate 				(btopr(rm_assize(as)) * (PAGESIZE / 1024));
24620Sstevel@tonic-gate 			psp->pr_rssize = (size32_t)
24630Sstevel@tonic-gate 				(rm_asrss(as) * (PAGESIZE / 1024));
24640Sstevel@tonic-gate 			psp->pr_pctmem = rm_pctmemory(as);
24650Sstevel@tonic-gate 			AS_LOCK_EXIT(as, &as->a_lock);
24660Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
24670Sstevel@tonic-gate 		}
24680Sstevel@tonic-gate 	}
24690Sstevel@tonic-gate 
24700Sstevel@tonic-gate 	/*
24710Sstevel@tonic-gate 	 * If we are looking at an LP64 process, zero out
24720Sstevel@tonic-gate 	 * the fields that cannot be represented in ILP32.
24730Sstevel@tonic-gate 	 */
24740Sstevel@tonic-gate 	if (p->p_model != DATAMODEL_ILP32) {
24750Sstevel@tonic-gate 		psp->pr_size = 0;
24760Sstevel@tonic-gate 		psp->pr_rssize = 0;
24770Sstevel@tonic-gate 		psp->pr_argv = 0;
24780Sstevel@tonic-gate 		psp->pr_envp = 0;
24790Sstevel@tonic-gate 	}
24800Sstevel@tonic-gate }
24810Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
24820Sstevel@tonic-gate 
24830Sstevel@tonic-gate void
24840Sstevel@tonic-gate prgetlwpsinfo(kthread_t *t, lwpsinfo_t *psp)
24850Sstevel@tonic-gate {
24860Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
24870Sstevel@tonic-gate 	sobj_ops_t *sobj;
24880Sstevel@tonic-gate 	char c, state;
24890Sstevel@tonic-gate 	uint64_t pct;
24900Sstevel@tonic-gate 	int retval, niceval;
24910Sstevel@tonic-gate 	hrtime_t hrutime, hrstime;
24920Sstevel@tonic-gate 
24930Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
24940Sstevel@tonic-gate 
24950Sstevel@tonic-gate 	bzero(psp, sizeof (*psp));
24960Sstevel@tonic-gate 
24970Sstevel@tonic-gate 	psp->pr_flag = 0;	/* lwpsinfo_t.pr_flag is deprecated */
24980Sstevel@tonic-gate 	psp->pr_lwpid = t->t_tid;
24990Sstevel@tonic-gate 	psp->pr_addr = (uintptr_t)t;
25000Sstevel@tonic-gate 	psp->pr_wchan = (uintptr_t)t->t_wchan;
25010Sstevel@tonic-gate 
25020Sstevel@tonic-gate 	/* map the thread state enum into a process state enum */
25030Sstevel@tonic-gate 	state = VSTOPPED(t) ? TS_STOPPED : t->t_state;
25040Sstevel@tonic-gate 	switch (state) {
25050Sstevel@tonic-gate 	case TS_SLEEP:		state = SSLEEP;		c = 'S';	break;
25060Sstevel@tonic-gate 	case TS_RUN:		state = SRUN;		c = 'R';	break;
25070Sstevel@tonic-gate 	case TS_ONPROC:		state = SONPROC;	c = 'O';	break;
25080Sstevel@tonic-gate 	case TS_ZOMB:		state = SZOMB;		c = 'Z';	break;
25090Sstevel@tonic-gate 	case TS_STOPPED:	state = SSTOP;		c = 'T';	break;
25100Sstevel@tonic-gate 	default:		state = 0;		c = '?';	break;
25110Sstevel@tonic-gate 	}
25120Sstevel@tonic-gate 	psp->pr_state = state;
25130Sstevel@tonic-gate 	psp->pr_sname = c;
25140Sstevel@tonic-gate 	if ((sobj = t->t_sobj_ops) != NULL)
25150Sstevel@tonic-gate 		psp->pr_stype = SOBJ_TYPE(sobj);
25160Sstevel@tonic-gate 	retval = CL_DONICE(t, NULL, 0, &niceval);
25170Sstevel@tonic-gate 	if (retval == 0) {
25180Sstevel@tonic-gate 		psp->pr_oldpri = v.v_maxsyspri - t->t_pri;
25190Sstevel@tonic-gate 		psp->pr_nice = niceval + NZERO;
25200Sstevel@tonic-gate 	}
25210Sstevel@tonic-gate 	psp->pr_syscall = t->t_sysnum;
25220Sstevel@tonic-gate 	psp->pr_pri = t->t_pri;
25230Sstevel@tonic-gate 	psp->pr_start.tv_sec = t->t_start;
25240Sstevel@tonic-gate 	psp->pr_start.tv_nsec = 0L;
25250Sstevel@tonic-gate 	hrutime = lwp->lwp_mstate.ms_acct[LMS_USER];
25260Sstevel@tonic-gate 	scalehrtime(&hrutime);
25270Sstevel@tonic-gate 	hrstime = lwp->lwp_mstate.ms_acct[LMS_SYSTEM] +
25280Sstevel@tonic-gate 	    lwp->lwp_mstate.ms_acct[LMS_TRAP];
25290Sstevel@tonic-gate 	scalehrtime(&hrstime);
25300Sstevel@tonic-gate 	hrt2ts(hrutime + hrstime, &psp->pr_time);
25310Sstevel@tonic-gate 	/* compute %cpu for the lwp */
25320Sstevel@tonic-gate 	pct = cpu_update_pct(t, gethrtime_unscaled());
25330Sstevel@tonic-gate 	psp->pr_pctcpu = prgetpctcpu(pct);
25340Sstevel@tonic-gate 	psp->pr_cpu = (psp->pr_pctcpu*100 + 0x6000) >> 15;	/* [0..99] */
25350Sstevel@tonic-gate 	if (psp->pr_cpu > 99)
25360Sstevel@tonic-gate 		psp->pr_cpu = 99;
25370Sstevel@tonic-gate 
25380Sstevel@tonic-gate 	(void) strncpy(psp->pr_clname, sclass[t->t_cid].cl_name,
25390Sstevel@tonic-gate 		sizeof (psp->pr_clname) - 1);
25400Sstevel@tonic-gate 	bzero(psp->pr_name, sizeof (psp->pr_name));	/* XXX ??? */
25410Sstevel@tonic-gate 	psp->pr_onpro = t->t_cpu->cpu_id;
25420Sstevel@tonic-gate 	psp->pr_bindpro = t->t_bind_cpu;
25430Sstevel@tonic-gate 	psp->pr_bindpset = t->t_bind_pset;
25442685Sakolb 	psp->pr_lgrp = t->t_lpl->lpl_lgrpid;
25450Sstevel@tonic-gate }
25460Sstevel@tonic-gate 
25470Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
25480Sstevel@tonic-gate void
25490Sstevel@tonic-gate prgetlwpsinfo32(kthread_t *t, lwpsinfo32_t *psp)
25500Sstevel@tonic-gate {
25510Sstevel@tonic-gate 	proc_t *p = ttoproc(t);
25520Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
25530Sstevel@tonic-gate 	sobj_ops_t *sobj;
25540Sstevel@tonic-gate 	char c, state;
25550Sstevel@tonic-gate 	uint64_t pct;
25560Sstevel@tonic-gate 	int retval, niceval;
25570Sstevel@tonic-gate 	hrtime_t hrutime, hrstime;
25580Sstevel@tonic-gate 
25590Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
25600Sstevel@tonic-gate 
25610Sstevel@tonic-gate 	bzero(psp, sizeof (*psp));
25620Sstevel@tonic-gate 
25630Sstevel@tonic-gate 	psp->pr_flag = 0;	/* lwpsinfo_t.pr_flag is deprecated */
25640Sstevel@tonic-gate 	psp->pr_lwpid = t->t_tid;
25650Sstevel@tonic-gate 	psp->pr_addr = 0;	/* cannot represent 64-bit addr in 32 bits */
25660Sstevel@tonic-gate 	psp->pr_wchan = 0;	/* cannot represent 64-bit addr in 32 bits */
25670Sstevel@tonic-gate 
25680Sstevel@tonic-gate 	/* map the thread state enum into a process state enum */
25690Sstevel@tonic-gate 	state = VSTOPPED(t) ? TS_STOPPED : t->t_state;
25700Sstevel@tonic-gate 	switch (state) {
25710Sstevel@tonic-gate 	case TS_SLEEP:		state = SSLEEP;		c = 'S';	break;
25720Sstevel@tonic-gate 	case TS_RUN:		state = SRUN;		c = 'R';	break;
25730Sstevel@tonic-gate 	case TS_ONPROC:		state = SONPROC;	c = 'O';	break;
25740Sstevel@tonic-gate 	case TS_ZOMB:		state = SZOMB;		c = 'Z';	break;
25750Sstevel@tonic-gate 	case TS_STOPPED:	state = SSTOP;		c = 'T';	break;
25760Sstevel@tonic-gate 	default:		state = 0;		c = '?';	break;
25770Sstevel@tonic-gate 	}
25780Sstevel@tonic-gate 	psp->pr_state = state;
25790Sstevel@tonic-gate 	psp->pr_sname = c;
25800Sstevel@tonic-gate 	if ((sobj = t->t_sobj_ops) != NULL)
25810Sstevel@tonic-gate 		psp->pr_stype = SOBJ_TYPE(sobj);
25820Sstevel@tonic-gate 	retval = CL_DONICE(t, NULL, 0, &niceval);
25830Sstevel@tonic-gate 	if (retval == 0) {
25840Sstevel@tonic-gate 		psp->pr_oldpri = v.v_maxsyspri - t->t_pri;
25850Sstevel@tonic-gate 		psp->pr_nice = niceval + NZERO;
25860Sstevel@tonic-gate 	} else {
25870Sstevel@tonic-gate 		psp->pr_oldpri = 0;
25880Sstevel@tonic-gate 		psp->pr_nice = 0;
25890Sstevel@tonic-gate 	}
25900Sstevel@tonic-gate 	psp->pr_syscall = t->t_sysnum;
25910Sstevel@tonic-gate 	psp->pr_pri = t->t_pri;
25920Sstevel@tonic-gate 	psp->pr_start.tv_sec = (time32_t)t->t_start;
25930Sstevel@tonic-gate 	psp->pr_start.tv_nsec = 0L;
25940Sstevel@tonic-gate 	hrutime = lwp->lwp_mstate.ms_acct[LMS_USER];
25950Sstevel@tonic-gate 	scalehrtime(&hrutime);
25960Sstevel@tonic-gate 	hrstime = lwp->lwp_mstate.ms_acct[LMS_SYSTEM] +
25970Sstevel@tonic-gate 	    lwp->lwp_mstate.ms_acct[LMS_TRAP];
25980Sstevel@tonic-gate 	scalehrtime(&hrstime);
25990Sstevel@tonic-gate 	hrt2ts32(hrutime + hrstime, &psp->pr_time);
26000Sstevel@tonic-gate 	/* compute %cpu for the lwp */
26010Sstevel@tonic-gate 	pct = cpu_update_pct(t, gethrtime_unscaled());
26020Sstevel@tonic-gate 	psp->pr_pctcpu = prgetpctcpu(pct);
26030Sstevel@tonic-gate 	psp->pr_cpu = (psp->pr_pctcpu*100 + 0x6000) >> 15;	/* [0..99] */
26040Sstevel@tonic-gate 	if (psp->pr_cpu > 99)
26050Sstevel@tonic-gate 		psp->pr_cpu = 99;
26060Sstevel@tonic-gate 
26070Sstevel@tonic-gate 	(void) strncpy(psp->pr_clname, sclass[t->t_cid].cl_name,
26080Sstevel@tonic-gate 		sizeof (psp->pr_clname) - 1);
26090Sstevel@tonic-gate 	bzero(psp->pr_name, sizeof (psp->pr_name));	/* XXX ??? */
26100Sstevel@tonic-gate 	psp->pr_onpro = t->t_cpu->cpu_id;
26110Sstevel@tonic-gate 	psp->pr_bindpro = t->t_bind_cpu;
26120Sstevel@tonic-gate 	psp->pr_bindpset = t->t_bind_pset;
26132685Sakolb 	psp->pr_lgrp = t->t_lpl->lpl_lgrpid;
26140Sstevel@tonic-gate }
26150Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
26160Sstevel@tonic-gate 
26170Sstevel@tonic-gate /*
26180Sstevel@tonic-gate  * This used to get called when microstate accounting was disabled but
26190Sstevel@tonic-gate  * microstate information was requested.  Since Microstate accounting is on
26200Sstevel@tonic-gate  * regardless of the proc flags, this simply makes it appear to procfs that
26210Sstevel@tonic-gate  * microstate accounting is on.  This is relatively meaningless since you
26220Sstevel@tonic-gate  * can't turn it off, but this is here for the sake of appearances.
26230Sstevel@tonic-gate  */
26240Sstevel@tonic-gate 
26250Sstevel@tonic-gate /*ARGSUSED*/
26260Sstevel@tonic-gate void
26270Sstevel@tonic-gate estimate_msacct(kthread_t *t, hrtime_t curtime)
26280Sstevel@tonic-gate {
26290Sstevel@tonic-gate 	proc_t *p;
26300Sstevel@tonic-gate 
26310Sstevel@tonic-gate 	if (t == NULL)
26320Sstevel@tonic-gate 		return;
26330Sstevel@tonic-gate 
26340Sstevel@tonic-gate 	p = ttoproc(t);
26350Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
26360Sstevel@tonic-gate 
26370Sstevel@tonic-gate 	/*
26380Sstevel@tonic-gate 	 * A system process (p0) could be referenced if the thread is
26390Sstevel@tonic-gate 	 * in the process of exiting.  Don't turn on microstate accounting
26400Sstevel@tonic-gate 	 * in that case.
26410Sstevel@tonic-gate 	 */
26420Sstevel@tonic-gate 	if (p->p_flag & SSYS)
26430Sstevel@tonic-gate 		return;
26440Sstevel@tonic-gate 
26450Sstevel@tonic-gate 	/*
26460Sstevel@tonic-gate 	 * Loop through all the LWPs (kernel threads) in the process.
26470Sstevel@tonic-gate 	 */
26480Sstevel@tonic-gate 	t = p->p_tlist;
26490Sstevel@tonic-gate 	do {
26500Sstevel@tonic-gate 		t->t_proc_flag |= TP_MSACCT;
26510Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
26520Sstevel@tonic-gate 
26530Sstevel@tonic-gate 	p->p_flag |= SMSACCT;			/* set process-wide MSACCT */
26540Sstevel@tonic-gate }
26550Sstevel@tonic-gate 
26560Sstevel@tonic-gate /*
26570Sstevel@tonic-gate  * It's not really possible to disable microstate accounting anymore.
26580Sstevel@tonic-gate  * However, this routine simply turns off the ms accounting flags in a process
26590Sstevel@tonic-gate  * This way procfs can still pretend to turn microstate accounting on and
26600Sstevel@tonic-gate  * off for a process, but it actually doesn't do anything.  This is
26610Sstevel@tonic-gate  * a neutered form of preemptive idiot-proofing.
26620Sstevel@tonic-gate  */
26630Sstevel@tonic-gate void
26640Sstevel@tonic-gate disable_msacct(proc_t *p)
26650Sstevel@tonic-gate {
26660Sstevel@tonic-gate 	kthread_t *t;
26670Sstevel@tonic-gate 
26680Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
26690Sstevel@tonic-gate 
26700Sstevel@tonic-gate 	p->p_flag &= ~SMSACCT;		/* clear process-wide MSACCT */
26710Sstevel@tonic-gate 	/*
26720Sstevel@tonic-gate 	 * Loop through all the LWPs (kernel threads) in the process.
26730Sstevel@tonic-gate 	 */
26740Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL) {
26750Sstevel@tonic-gate 		do {
26760Sstevel@tonic-gate 			/* clear per-thread flag */
26770Sstevel@tonic-gate 			t->t_proc_flag &= ~TP_MSACCT;
26780Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
26790Sstevel@tonic-gate 	}
26800Sstevel@tonic-gate }
26810Sstevel@tonic-gate 
26820Sstevel@tonic-gate /*
26830Sstevel@tonic-gate  * Return resource usage information.
26840Sstevel@tonic-gate  */
26850Sstevel@tonic-gate void
26860Sstevel@tonic-gate prgetusage(kthread_t *t, prhusage_t *pup)
26870Sstevel@tonic-gate {
26880Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
26890Sstevel@tonic-gate 	hrtime_t *mstimep;
26900Sstevel@tonic-gate 	struct mstate *ms = &lwp->lwp_mstate;
26910Sstevel@tonic-gate 	int state;
26920Sstevel@tonic-gate 	int i;
26930Sstevel@tonic-gate 	hrtime_t curtime;
26940Sstevel@tonic-gate 	hrtime_t waitrq;
26950Sstevel@tonic-gate 	hrtime_t tmp1;
26960Sstevel@tonic-gate 
26970Sstevel@tonic-gate 	curtime = gethrtime_unscaled();
26980Sstevel@tonic-gate 
26990Sstevel@tonic-gate 	pup->pr_lwpid	= t->t_tid;
27000Sstevel@tonic-gate 	pup->pr_count	= 1;
27010Sstevel@tonic-gate 	pup->pr_create	= ms->ms_start;
27020Sstevel@tonic-gate 	pup->pr_term    = ms->ms_term;
27030Sstevel@tonic-gate 	scalehrtime(&pup->pr_create);
27040Sstevel@tonic-gate 	scalehrtime(&pup->pr_term);
27050Sstevel@tonic-gate 	if (ms->ms_term == 0) {
27060Sstevel@tonic-gate 		pup->pr_rtime = curtime - ms->ms_start;
27070Sstevel@tonic-gate 		scalehrtime(&pup->pr_rtime);
27080Sstevel@tonic-gate 	} else {
27090Sstevel@tonic-gate 		pup->pr_rtime = ms->ms_term - ms->ms_start;
27100Sstevel@tonic-gate 		scalehrtime(&pup->pr_rtime);
27110Sstevel@tonic-gate 	}
27120Sstevel@tonic-gate 
27130Sstevel@tonic-gate 
27140Sstevel@tonic-gate 	pup->pr_utime    = ms->ms_acct[LMS_USER];
27150Sstevel@tonic-gate 	pup->pr_stime    = ms->ms_acct[LMS_SYSTEM];
27160Sstevel@tonic-gate 	pup->pr_ttime    = ms->ms_acct[LMS_TRAP];
27170Sstevel@tonic-gate 	pup->pr_tftime   = ms->ms_acct[LMS_TFAULT];
27180Sstevel@tonic-gate 	pup->pr_dftime   = ms->ms_acct[LMS_DFAULT];
27190Sstevel@tonic-gate 	pup->pr_kftime   = ms->ms_acct[LMS_KFAULT];
27200Sstevel@tonic-gate 	pup->pr_ltime    = ms->ms_acct[LMS_USER_LOCK];
27210Sstevel@tonic-gate 	pup->pr_slptime  = ms->ms_acct[LMS_SLEEP];
27220Sstevel@tonic-gate 	pup->pr_wtime    = ms->ms_acct[LMS_WAIT_CPU];
27230Sstevel@tonic-gate 	pup->pr_stoptime = ms->ms_acct[LMS_STOPPED];
27240Sstevel@tonic-gate 
27250Sstevel@tonic-gate 	prscaleusage(pup);
27260Sstevel@tonic-gate 
27270Sstevel@tonic-gate 	/*
27280Sstevel@tonic-gate 	 * Adjust for time waiting in the dispatcher queue.
27290Sstevel@tonic-gate 	 */
27300Sstevel@tonic-gate 	waitrq = t->t_waitrq;	/* hopefully atomic */
27310Sstevel@tonic-gate 	if (waitrq != 0) {
27320Sstevel@tonic-gate 		tmp1 = curtime - waitrq;
27330Sstevel@tonic-gate 		scalehrtime(&tmp1);
27340Sstevel@tonic-gate 		pup->pr_wtime += tmp1;
27350Sstevel@tonic-gate 		curtime = waitrq;
27360Sstevel@tonic-gate 	}
27370Sstevel@tonic-gate 
27380Sstevel@tonic-gate 	/*
27390Sstevel@tonic-gate 	 * Adjust for time spent in current microstate.
27400Sstevel@tonic-gate 	 */
27410Sstevel@tonic-gate 	if (ms->ms_state_start > curtime) {
27420Sstevel@tonic-gate 		curtime = gethrtime_unscaled();
27430Sstevel@tonic-gate 	}
27440Sstevel@tonic-gate 
27450Sstevel@tonic-gate 	i = 0;
27460Sstevel@tonic-gate 	do {
27470Sstevel@tonic-gate 		switch (state = t->t_mstate) {
27480Sstevel@tonic-gate 		case LMS_SLEEP:
27490Sstevel@tonic-gate 			/*
27500Sstevel@tonic-gate 			 * Update the timer for the current sleep state.
27510Sstevel@tonic-gate 			 */
27520Sstevel@tonic-gate 			switch (state = ms->ms_prev) {
27530Sstevel@tonic-gate 			case LMS_TFAULT:
27540Sstevel@tonic-gate 			case LMS_DFAULT:
27550Sstevel@tonic-gate 			case LMS_KFAULT:
27560Sstevel@tonic-gate 			case LMS_USER_LOCK:
27570Sstevel@tonic-gate 				break;
27580Sstevel@tonic-gate 			default:
27590Sstevel@tonic-gate 				state = LMS_SLEEP;
27600Sstevel@tonic-gate 				break;
27610Sstevel@tonic-gate 			}
27620Sstevel@tonic-gate 			break;
27630Sstevel@tonic-gate 		case LMS_TFAULT:
27640Sstevel@tonic-gate 		case LMS_DFAULT:
27650Sstevel@tonic-gate 		case LMS_KFAULT:
27660Sstevel@tonic-gate 		case LMS_USER_LOCK:
27670Sstevel@tonic-gate 			state = LMS_SYSTEM;
27680Sstevel@tonic-gate 			break;
27690Sstevel@tonic-gate 		}
27700Sstevel@tonic-gate 		switch (state) {
27710Sstevel@tonic-gate 		case LMS_USER:		mstimep = &pup->pr_utime;	break;
27720Sstevel@tonic-gate 		case LMS_SYSTEM:	mstimep = &pup->pr_stime;	break;
27730Sstevel@tonic-gate 		case LMS_TRAP:		mstimep = &pup->pr_ttime;	break;
27740Sstevel@tonic-gate 		case LMS_TFAULT:	mstimep = &pup->pr_tftime;	break;
27750Sstevel@tonic-gate 		case LMS_DFAULT:	mstimep = &pup->pr_dftime;	break;
27760Sstevel@tonic-gate 		case LMS_KFAULT:	mstimep = &pup->pr_kftime;	break;
27770Sstevel@tonic-gate 		case LMS_USER_LOCK:	mstimep = &pup->pr_ltime;	break;
27780Sstevel@tonic-gate 		case LMS_SLEEP:		mstimep = &pup->pr_slptime;	break;
27790Sstevel@tonic-gate 		case LMS_WAIT_CPU:	mstimep = &pup->pr_wtime;	break;
27800Sstevel@tonic-gate 		case LMS_STOPPED:	mstimep = &pup->pr_stoptime;	break;
27810Sstevel@tonic-gate 		default:		panic("prgetusage: unknown microstate");
27820Sstevel@tonic-gate 		}
27830Sstevel@tonic-gate 		tmp1 = curtime - ms->ms_state_start;
27842299Ssudheer 		if (tmp1 < 0) {
27850Sstevel@tonic-gate 			curtime = gethrtime_unscaled();
27860Sstevel@tonic-gate 			i++;
27870Sstevel@tonic-gate 			continue;
27880Sstevel@tonic-gate 		}
27890Sstevel@tonic-gate 		scalehrtime(&tmp1);
27902299Ssudheer 	} while (tmp1 < 0 && i < MAX_ITERS_SPIN);
27910Sstevel@tonic-gate 
27920Sstevel@tonic-gate 	*mstimep += tmp1;
27930Sstevel@tonic-gate 
27940Sstevel@tonic-gate 	/* update pup timestamp */
27950Sstevel@tonic-gate 	pup->pr_tstamp = curtime;
27960Sstevel@tonic-gate 	scalehrtime(&pup->pr_tstamp);
27970Sstevel@tonic-gate 
27980Sstevel@tonic-gate 	/*
27990Sstevel@tonic-gate 	 * Resource usage counters.
28000Sstevel@tonic-gate 	 */
28010Sstevel@tonic-gate 	pup->pr_minf  = lwp->lwp_ru.minflt;
28020Sstevel@tonic-gate 	pup->pr_majf  = lwp->lwp_ru.majflt;
28030Sstevel@tonic-gate 	pup->pr_nswap = lwp->lwp_ru.nswap;
28040Sstevel@tonic-gate 	pup->pr_inblk = lwp->lwp_ru.inblock;
28050Sstevel@tonic-gate 	pup->pr_oublk = lwp->lwp_ru.oublock;
28060Sstevel@tonic-gate 	pup->pr_msnd  = lwp->lwp_ru.msgsnd;
28070Sstevel@tonic-gate 	pup->pr_mrcv  = lwp->lwp_ru.msgrcv;
28080Sstevel@tonic-gate 	pup->pr_sigs  = lwp->lwp_ru.nsignals;
28090Sstevel@tonic-gate 	pup->pr_vctx  = lwp->lwp_ru.nvcsw;
28100Sstevel@tonic-gate 	pup->pr_ictx  = lwp->lwp_ru.nivcsw;
28110Sstevel@tonic-gate 	pup->pr_sysc  = lwp->lwp_ru.sysc;
28120Sstevel@tonic-gate 	pup->pr_ioch  = lwp->lwp_ru.ioch;
28130Sstevel@tonic-gate }
28140Sstevel@tonic-gate 
28150Sstevel@tonic-gate /*
28160Sstevel@tonic-gate  * Convert ms_acct stats from unscaled high-res time to nanoseconds
28170Sstevel@tonic-gate  */
28180Sstevel@tonic-gate void
28190Sstevel@tonic-gate prscaleusage(prhusage_t *usg)
28200Sstevel@tonic-gate {
28210Sstevel@tonic-gate 	scalehrtime(&usg->pr_utime);
28220Sstevel@tonic-gate 	scalehrtime(&usg->pr_stime);
28230Sstevel@tonic-gate 	scalehrtime(&usg->pr_ttime);
28240Sstevel@tonic-gate 	scalehrtime(&usg->pr_tftime);
28250Sstevel@tonic-gate 	scalehrtime(&usg->pr_dftime);
28260Sstevel@tonic-gate 	scalehrtime(&usg->pr_kftime);
28270Sstevel@tonic-gate 	scalehrtime(&usg->pr_ltime);
28280Sstevel@tonic-gate 	scalehrtime(&usg->pr_slptime);
28290Sstevel@tonic-gate 	scalehrtime(&usg->pr_wtime);
28300Sstevel@tonic-gate 	scalehrtime(&usg->pr_stoptime);
28310Sstevel@tonic-gate }
28320Sstevel@tonic-gate 
28330Sstevel@tonic-gate 
28340Sstevel@tonic-gate /*
28350Sstevel@tonic-gate  * Sum resource usage information.
28360Sstevel@tonic-gate  */
28370Sstevel@tonic-gate void
28380Sstevel@tonic-gate praddusage(kthread_t *t, prhusage_t *pup)
28390Sstevel@tonic-gate {
28400Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
28410Sstevel@tonic-gate 	hrtime_t *mstimep;
28420Sstevel@tonic-gate 	struct mstate *ms = &lwp->lwp_mstate;
28430Sstevel@tonic-gate 	int state;
28440Sstevel@tonic-gate 	int i;
28450Sstevel@tonic-gate 	hrtime_t curtime;
28460Sstevel@tonic-gate 	hrtime_t waitrq;
28470Sstevel@tonic-gate 	hrtime_t tmp;
28480Sstevel@tonic-gate 	prhusage_t conv;
28490Sstevel@tonic-gate 
28500Sstevel@tonic-gate 	curtime = gethrtime_unscaled();
28510Sstevel@tonic-gate 
28520Sstevel@tonic-gate 	if (ms->ms_term == 0) {
28530Sstevel@tonic-gate 		tmp = curtime - ms->ms_start;
28540Sstevel@tonic-gate 		scalehrtime(&tmp);
28550Sstevel@tonic-gate 		pup->pr_rtime += tmp;
28560Sstevel@tonic-gate 	} else {
28570Sstevel@tonic-gate 		tmp = ms->ms_term - ms->ms_start;
28580Sstevel@tonic-gate 		scalehrtime(&tmp);
28590Sstevel@tonic-gate 		pup->pr_rtime += tmp;
28600Sstevel@tonic-gate 	}
28610Sstevel@tonic-gate 
28620Sstevel@tonic-gate 	conv.pr_utime = ms->ms_acct[LMS_USER];
28630Sstevel@tonic-gate 	conv.pr_stime = ms->ms_acct[LMS_SYSTEM];
28640Sstevel@tonic-gate 	conv.pr_ttime = ms->ms_acct[LMS_TRAP];
28650Sstevel@tonic-gate 	conv.pr_tftime = ms->ms_acct[LMS_TFAULT];
28660Sstevel@tonic-gate 	conv.pr_dftime = ms->ms_acct[LMS_DFAULT];
28670Sstevel@tonic-gate 	conv.pr_kftime = ms->ms_acct[LMS_KFAULT];
28680Sstevel@tonic-gate 	conv.pr_ltime = ms->ms_acct[LMS_USER_LOCK];
28690Sstevel@tonic-gate 	conv.pr_slptime = ms->ms_acct[LMS_SLEEP];
28700Sstevel@tonic-gate 	conv.pr_wtime = ms->ms_acct[LMS_WAIT_CPU];
28710Sstevel@tonic-gate 	conv.pr_stoptime = ms->ms_acct[LMS_STOPPED];
28720Sstevel@tonic-gate 
28730Sstevel@tonic-gate 	prscaleusage(&conv);
28740Sstevel@tonic-gate 
28750Sstevel@tonic-gate 	pup->pr_utime	+= conv.pr_utime;
28760Sstevel@tonic-gate 	pup->pr_stime	+= conv.pr_stime;
28770Sstevel@tonic-gate 	pup->pr_ttime	+= conv.pr_ttime;
28780Sstevel@tonic-gate 	pup->pr_tftime	+= conv.pr_tftime;
28790Sstevel@tonic-gate 	pup->pr_dftime	+= conv.pr_dftime;
28800Sstevel@tonic-gate 	pup->pr_kftime	+= conv.pr_kftime;
28810Sstevel@tonic-gate 	pup->pr_ltime	+= conv.pr_ltime;
28820Sstevel@tonic-gate 	pup->pr_slptime	+= conv.pr_slptime;
28830Sstevel@tonic-gate 	pup->pr_wtime	+= conv.pr_wtime;
28840Sstevel@tonic-gate 	pup->pr_stoptime += conv.pr_stoptime;
28850Sstevel@tonic-gate 
28860Sstevel@tonic-gate 	/*
28870Sstevel@tonic-gate 	 * Adjust for time waiting in the dispatcher queue.
28880Sstevel@tonic-gate 	 */
28890Sstevel@tonic-gate 	waitrq = t->t_waitrq;	/* hopefully atomic */
28900Sstevel@tonic-gate 	if (waitrq != 0) {
28910Sstevel@tonic-gate 		tmp = curtime - waitrq;
28920Sstevel@tonic-gate 		scalehrtime(&tmp);
28930Sstevel@tonic-gate 		pup->pr_wtime += tmp;
28940Sstevel@tonic-gate 		curtime = waitrq;
28950Sstevel@tonic-gate 	}
28960Sstevel@tonic-gate 
28970Sstevel@tonic-gate 	/*
28980Sstevel@tonic-gate 	 * Adjust for time spent in current microstate.
28990Sstevel@tonic-gate 	 */
29000Sstevel@tonic-gate 	if (ms->ms_state_start > curtime) {
29010Sstevel@tonic-gate 		curtime = gethrtime_unscaled();
29020Sstevel@tonic-gate 	}
29030Sstevel@tonic-gate 
29040Sstevel@tonic-gate 	i = 0;
29050Sstevel@tonic-gate 	do {
29060Sstevel@tonic-gate 		switch (state = t->t_mstate) {
29070Sstevel@tonic-gate 		case LMS_SLEEP:
29080Sstevel@tonic-gate 			/*
29090Sstevel@tonic-gate 			 * Update the timer for the current sleep state.
29100Sstevel@tonic-gate 			 */
29110Sstevel@tonic-gate 			switch (state = ms->ms_prev) {
29120Sstevel@tonic-gate 			case LMS_TFAULT:
29130Sstevel@tonic-gate 			case LMS_DFAULT:
29140Sstevel@tonic-gate 			case LMS_KFAULT:
29150Sstevel@tonic-gate 			case LMS_USER_LOCK:
29160Sstevel@tonic-gate 				break;
29170Sstevel@tonic-gate 			default:
29180Sstevel@tonic-gate 				state = LMS_SLEEP;
29190Sstevel@tonic-gate 				break;
29200Sstevel@tonic-gate 			}
29210Sstevel@tonic-gate 			break;
29220Sstevel@tonic-gate 		case LMS_TFAULT:
29230Sstevel@tonic-gate 		case LMS_DFAULT:
29240Sstevel@tonic-gate 		case LMS_KFAULT:
29250Sstevel@tonic-gate 		case LMS_USER_LOCK:
29260Sstevel@tonic-gate 			state = LMS_SYSTEM;
29270Sstevel@tonic-gate 			break;
29280Sstevel@tonic-gate 		}
29290Sstevel@tonic-gate 		switch (state) {
29300Sstevel@tonic-gate 		case LMS_USER:		mstimep = &pup->pr_utime;	break;
29310Sstevel@tonic-gate 		case LMS_SYSTEM:	mstimep = &pup->pr_stime;	break;
29320Sstevel@tonic-gate 		case LMS_TRAP:		mstimep = &pup->pr_ttime;	break;
29330Sstevel@tonic-gate 		case LMS_TFAULT:	mstimep = &pup->pr_tftime;	break;
29340Sstevel@tonic-gate 		case LMS_DFAULT:	mstimep = &pup->pr_dftime;	break;
29350Sstevel@tonic-gate 		case LMS_KFAULT:	mstimep = &pup->pr_kftime;	break;
29360Sstevel@tonic-gate 		case LMS_USER_LOCK:	mstimep = &pup->pr_ltime;	break;
29370Sstevel@tonic-gate 		case LMS_SLEEP:		mstimep = &pup->pr_slptime;	break;
29380Sstevel@tonic-gate 		case LMS_WAIT_CPU:	mstimep = &pup->pr_wtime;	break;
29390Sstevel@tonic-gate 		case LMS_STOPPED:	mstimep = &pup->pr_stoptime;	break;
29400Sstevel@tonic-gate 		default:		panic("praddusage: unknown microstate");
29410Sstevel@tonic-gate 		}
29420Sstevel@tonic-gate 		tmp = curtime - ms->ms_state_start;
29432299Ssudheer 		if (tmp < 0) {
29440Sstevel@tonic-gate 			curtime = gethrtime_unscaled();
29450Sstevel@tonic-gate 			i++;
29460Sstevel@tonic-gate 			continue;
29470Sstevel@tonic-gate 		}
29480Sstevel@tonic-gate 		scalehrtime(&tmp);
29492299Ssudheer 	} while (tmp < 0 && i < MAX_ITERS_SPIN);
29500Sstevel@tonic-gate 
29510Sstevel@tonic-gate 	*mstimep += tmp;
29520Sstevel@tonic-gate 
29530Sstevel@tonic-gate 	/* update pup timestamp */
29540Sstevel@tonic-gate 	pup->pr_tstamp = curtime;
29550Sstevel@tonic-gate 	scalehrtime(&pup->pr_tstamp);
29560Sstevel@tonic-gate 
29570Sstevel@tonic-gate 	/*
29580Sstevel@tonic-gate 	 * Resource usage counters.
29590Sstevel@tonic-gate 	 */
29600Sstevel@tonic-gate 	pup->pr_minf  += lwp->lwp_ru.minflt;
29610Sstevel@tonic-gate 	pup->pr_majf  += lwp->lwp_ru.majflt;
29620Sstevel@tonic-gate 	pup->pr_nswap += lwp->lwp_ru.nswap;
29630Sstevel@tonic-gate 	pup->pr_inblk += lwp->lwp_ru.inblock;
29640Sstevel@tonic-gate 	pup->pr_oublk += lwp->lwp_ru.oublock;
29650Sstevel@tonic-gate 	pup->pr_msnd  += lwp->lwp_ru.msgsnd;
29660Sstevel@tonic-gate 	pup->pr_mrcv  += lwp->lwp_ru.msgrcv;
29670Sstevel@tonic-gate 	pup->pr_sigs  += lwp->lwp_ru.nsignals;
29680Sstevel@tonic-gate 	pup->pr_vctx  += lwp->lwp_ru.nvcsw;
29690Sstevel@tonic-gate 	pup->pr_ictx  += lwp->lwp_ru.nivcsw;
29700Sstevel@tonic-gate 	pup->pr_sysc  += lwp->lwp_ru.sysc;
29710Sstevel@tonic-gate 	pup->pr_ioch  += lwp->lwp_ru.ioch;
29720Sstevel@tonic-gate }
29730Sstevel@tonic-gate 
29740Sstevel@tonic-gate /*
29750Sstevel@tonic-gate  * Convert a prhusage_t to a prusage_t.
29760Sstevel@tonic-gate  * This means convert each hrtime_t to a timestruc_t
29770Sstevel@tonic-gate  * and copy the count fields uint64_t => ulong_t.
29780Sstevel@tonic-gate  */
29790Sstevel@tonic-gate void
29800Sstevel@tonic-gate prcvtusage(prhusage_t *pup, prusage_t *upup)
29810Sstevel@tonic-gate {
29820Sstevel@tonic-gate 	uint64_t *ullp;
29830Sstevel@tonic-gate 	ulong_t *ulp;
29840Sstevel@tonic-gate 	int i;
29850Sstevel@tonic-gate 
29860Sstevel@tonic-gate 	upup->pr_lwpid = pup->pr_lwpid;
29870Sstevel@tonic-gate 	upup->pr_count = pup->pr_count;
29880Sstevel@tonic-gate 
29890Sstevel@tonic-gate 	hrt2ts(pup->pr_tstamp,	&upup->pr_tstamp);
29900Sstevel@tonic-gate 	hrt2ts(pup->pr_create,	&upup->pr_create);
29910Sstevel@tonic-gate 	hrt2ts(pup->pr_term,	&upup->pr_term);
29920Sstevel@tonic-gate 	hrt2ts(pup->pr_rtime,	&upup->pr_rtime);
29930Sstevel@tonic-gate 	hrt2ts(pup->pr_utime,	&upup->pr_utime);
29940Sstevel@tonic-gate 	hrt2ts(pup->pr_stime,	&upup->pr_stime);
29950Sstevel@tonic-gate 	hrt2ts(pup->pr_ttime,	&upup->pr_ttime);
29960Sstevel@tonic-gate 	hrt2ts(pup->pr_tftime,	&upup->pr_tftime);
29970Sstevel@tonic-gate 	hrt2ts(pup->pr_dftime,	&upup->pr_dftime);
29980Sstevel@tonic-gate 	hrt2ts(pup->pr_kftime,	&upup->pr_kftime);
29990Sstevel@tonic-gate 	hrt2ts(pup->pr_ltime,	&upup->pr_ltime);
30000Sstevel@tonic-gate 	hrt2ts(pup->pr_slptime,	&upup->pr_slptime);
30010Sstevel@tonic-gate 	hrt2ts(pup->pr_wtime,	&upup->pr_wtime);
30020Sstevel@tonic-gate 	hrt2ts(pup->pr_stoptime, &upup->pr_stoptime);
30030Sstevel@tonic-gate 	bzero(upup->filltime, sizeof (upup->filltime));
30040Sstevel@tonic-gate 
30050Sstevel@tonic-gate 	ullp = &pup->pr_minf;
30060Sstevel@tonic-gate 	ulp = &upup->pr_minf;
30070Sstevel@tonic-gate 	for (i = 0; i < 22; i++)
30080Sstevel@tonic-gate 		*ulp++ = (ulong_t)*ullp++;
30090Sstevel@tonic-gate }
30100Sstevel@tonic-gate 
30110Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
30120Sstevel@tonic-gate void
30130Sstevel@tonic-gate prcvtusage32(prhusage_t *pup, prusage32_t *upup)
30140Sstevel@tonic-gate {
30150Sstevel@tonic-gate 	uint64_t *ullp;
30160Sstevel@tonic-gate 	uint32_t *ulp;
30170Sstevel@tonic-gate 	int i;
30180Sstevel@tonic-gate 
30190Sstevel@tonic-gate 	upup->pr_lwpid = pup->pr_lwpid;
30200Sstevel@tonic-gate 	upup->pr_count = pup->pr_count;
30210Sstevel@tonic-gate 
30220Sstevel@tonic-gate 	hrt2ts32(pup->pr_tstamp,	&upup->pr_tstamp);
30230Sstevel@tonic-gate 	hrt2ts32(pup->pr_create,	&upup->pr_create);
30240Sstevel@tonic-gate 	hrt2ts32(pup->pr_term,		&upup->pr_term);
30250Sstevel@tonic-gate 	hrt2ts32(pup->pr_rtime,		&upup->pr_rtime);
30260Sstevel@tonic-gate 	hrt2ts32(pup->pr_utime,		&upup->pr_utime);
30270Sstevel@tonic-gate 	hrt2ts32(pup->pr_stime,		&upup->pr_stime);
30280Sstevel@tonic-gate 	hrt2ts32(pup->pr_ttime,		&upup->pr_ttime);
30290Sstevel@tonic-gate 	hrt2ts32(pup->pr_tftime,	&upup->pr_tftime);
30300Sstevel@tonic-gate 	hrt2ts32(pup->pr_dftime,	&upup->pr_dftime);
30310Sstevel@tonic-gate 	hrt2ts32(pup->pr_kftime,	&upup->pr_kftime);
30320Sstevel@tonic-gate 	hrt2ts32(pup->pr_ltime,		&upup->pr_ltime);
30330Sstevel@tonic-gate 	hrt2ts32(pup->pr_slptime,	&upup->pr_slptime);
30340Sstevel@tonic-gate 	hrt2ts32(pup->pr_wtime,		&upup->pr_wtime);
30350Sstevel@tonic-gate 	hrt2ts32(pup->pr_stoptime,	&upup->pr_stoptime);
30360Sstevel@tonic-gate 	bzero(upup->filltime, sizeof (upup->filltime));
30370Sstevel@tonic-gate 
30380Sstevel@tonic-gate 	ullp = &pup->pr_minf;
30390Sstevel@tonic-gate 	ulp = &upup->pr_minf;
30400Sstevel@tonic-gate 	for (i = 0; i < 22; i++)
30410Sstevel@tonic-gate 		*ulp++ = (uint32_t)*ullp++;
30420Sstevel@tonic-gate }
30430Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
30440Sstevel@tonic-gate 
30450Sstevel@tonic-gate /*
30460Sstevel@tonic-gate  * Determine whether a set is empty.
30470Sstevel@tonic-gate  */
30480Sstevel@tonic-gate int
30490Sstevel@tonic-gate setisempty(uint32_t *sp, uint_t n)
30500Sstevel@tonic-gate {
30510Sstevel@tonic-gate 	while (n--)
30520Sstevel@tonic-gate 		if (*sp++)
30530Sstevel@tonic-gate 			return (0);
30540Sstevel@tonic-gate 	return (1);
30550Sstevel@tonic-gate }
30560Sstevel@tonic-gate 
30570Sstevel@tonic-gate /*
30580Sstevel@tonic-gate  * Utility routine for establishing a watched area in the process.
30590Sstevel@tonic-gate  * Keep the list of watched areas sorted by virtual address.
30600Sstevel@tonic-gate  */
30610Sstevel@tonic-gate int
30620Sstevel@tonic-gate set_watched_area(proc_t *p, struct watched_area *pwa)
30630Sstevel@tonic-gate {
30640Sstevel@tonic-gate 	caddr_t vaddr = pwa->wa_vaddr;
30650Sstevel@tonic-gate 	caddr_t eaddr = pwa->wa_eaddr;
30660Sstevel@tonic-gate 	ulong_t flags = pwa->wa_flags;
30670Sstevel@tonic-gate 	struct watched_area *target;
30680Sstevel@tonic-gate 	avl_index_t where;
30690Sstevel@tonic-gate 	int error = 0;
30700Sstevel@tonic-gate 
30710Sstevel@tonic-gate 	/* we must not be holding p->p_lock, but the process must be locked */
30720Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&p->p_lock));
30730Sstevel@tonic-gate 	ASSERT(p->p_proc_flag & P_PR_LOCK);
30740Sstevel@tonic-gate 
30750Sstevel@tonic-gate 	/*
30760Sstevel@tonic-gate 	 * If this is our first watchpoint, enable watchpoints for the process.
30770Sstevel@tonic-gate 	 */
30780Sstevel@tonic-gate 	if (!pr_watch_active(p)) {
30790Sstevel@tonic-gate 		kthread_t *t;
30800Sstevel@tonic-gate 
30810Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
30820Sstevel@tonic-gate 		if ((t = p->p_tlist) != NULL) {
30830Sstevel@tonic-gate 			do {
30840Sstevel@tonic-gate 				watch_enable(t);
30850Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
30860Sstevel@tonic-gate 		}
30870Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
30880Sstevel@tonic-gate 	}
30890Sstevel@tonic-gate 
30900Sstevel@tonic-gate 	target = pr_find_watched_area(p, pwa, &where);
30910Sstevel@tonic-gate 	if (target != NULL) {
30920Sstevel@tonic-gate 		/*
30930Sstevel@tonic-gate 		 * We discovered an existing, overlapping watched area.
30940Sstevel@tonic-gate 		 * Allow it only if it is an exact match.
30950Sstevel@tonic-gate 		 */
30960Sstevel@tonic-gate 		if (target->wa_vaddr != vaddr ||
30970Sstevel@tonic-gate 		    target->wa_eaddr != eaddr)
30980Sstevel@tonic-gate 			error = EINVAL;
30990Sstevel@tonic-gate 		else if (target->wa_flags != flags) {
31000Sstevel@tonic-gate 			error = set_watched_page(p, vaddr, eaddr,
31010Sstevel@tonic-gate 			    flags, target->wa_flags);
31020Sstevel@tonic-gate 			target->wa_flags = flags;
31030Sstevel@tonic-gate 		}
31040Sstevel@tonic-gate 		kmem_free(pwa, sizeof (struct watched_area));
31050Sstevel@tonic-gate 	} else {
31060Sstevel@tonic-gate 		avl_insert(&p->p_warea, pwa, where);
31070Sstevel@tonic-gate 		error = set_watched_page(p, vaddr, eaddr, flags, 0);
31080Sstevel@tonic-gate 	}
31090Sstevel@tonic-gate 
31100Sstevel@tonic-gate 	return (error);
31110Sstevel@tonic-gate }
31120Sstevel@tonic-gate 
31130Sstevel@tonic-gate /*
31140Sstevel@tonic-gate  * Utility routine for clearing a watched area in the process.
31150Sstevel@tonic-gate  * Must be an exact match of the virtual address.
31160Sstevel@tonic-gate  * size and flags don't matter.
31170Sstevel@tonic-gate  */
31180Sstevel@tonic-gate int
31190Sstevel@tonic-gate clear_watched_area(proc_t *p, struct watched_area *pwa)
31200Sstevel@tonic-gate {
31210Sstevel@tonic-gate 	struct watched_area *found;
31220Sstevel@tonic-gate 
31230Sstevel@tonic-gate 	/* we must not be holding p->p_lock, but the process must be locked */
31240Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&p->p_lock));
31250Sstevel@tonic-gate 	ASSERT(p->p_proc_flag & P_PR_LOCK);
31260Sstevel@tonic-gate 
31270Sstevel@tonic-gate 
31280Sstevel@tonic-gate 	if (!pr_watch_active(p)) {
31290Sstevel@tonic-gate 		kmem_free(pwa, sizeof (struct watched_area));
31300Sstevel@tonic-gate 		return (0);
31310Sstevel@tonic-gate 	}
31320Sstevel@tonic-gate 
31330Sstevel@tonic-gate 	/*
31340Sstevel@tonic-gate 	 * Look for a matching address in the watched areas.  If a match is
31350Sstevel@tonic-gate 	 * found, clear the old watched area and adjust the watched page(s).  It
31360Sstevel@tonic-gate 	 * is not an error if there is no match.
31370Sstevel@tonic-gate 	 */
31380Sstevel@tonic-gate 	if ((found = pr_find_watched_area(p, pwa, NULL)) != NULL &&
31390Sstevel@tonic-gate 	    found->wa_vaddr == pwa->wa_vaddr) {
31400Sstevel@tonic-gate 		clear_watched_page(p, found->wa_vaddr, found->wa_eaddr,
31410Sstevel@tonic-gate 		    found->wa_flags);
31420Sstevel@tonic-gate 		avl_remove(&p->p_warea, found);
31430Sstevel@tonic-gate 		kmem_free(found, sizeof (struct watched_area));
31440Sstevel@tonic-gate 	}
31450Sstevel@tonic-gate 
31460Sstevel@tonic-gate 	kmem_free(pwa, sizeof (struct watched_area));
31470Sstevel@tonic-gate 
31480Sstevel@tonic-gate 	/*
31490Sstevel@tonic-gate 	 * If we removed the last watched area from the process, disable
31500Sstevel@tonic-gate 	 * watchpoints.
31510Sstevel@tonic-gate 	 */
31520Sstevel@tonic-gate 	if (!pr_watch_active(p)) {
31530Sstevel@tonic-gate 		kthread_t *t;
31540Sstevel@tonic-gate 
31550Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
31560Sstevel@tonic-gate 		if ((t = p->p_tlist) != NULL) {
31570Sstevel@tonic-gate 			do {
31580Sstevel@tonic-gate 				watch_disable(t);
31590Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
31600Sstevel@tonic-gate 		}
31610Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
31620Sstevel@tonic-gate 	}
31630Sstevel@tonic-gate 
31640Sstevel@tonic-gate 	return (0);
31650Sstevel@tonic-gate }
31660Sstevel@tonic-gate 
31670Sstevel@tonic-gate /*
31680Sstevel@tonic-gate  * Frees all the watched_area structures
31690Sstevel@tonic-gate  */
31700Sstevel@tonic-gate void
31710Sstevel@tonic-gate pr_free_watchpoints(proc_t *p)
31720Sstevel@tonic-gate {
31730Sstevel@tonic-gate 	struct watched_area *delp;
31740Sstevel@tonic-gate 	void *cookie;
31750Sstevel@tonic-gate 
31760Sstevel@tonic-gate 	cookie = NULL;
31770Sstevel@tonic-gate 	while ((delp = avl_destroy_nodes(&p->p_warea, &cookie)) != NULL)
31780Sstevel@tonic-gate 		kmem_free(delp, sizeof (struct watched_area));
31790Sstevel@tonic-gate 
31800Sstevel@tonic-gate 	avl_destroy(&p->p_warea);
31810Sstevel@tonic-gate }
31820Sstevel@tonic-gate 
31830Sstevel@tonic-gate /*
31840Sstevel@tonic-gate  * This one is called by the traced process to unwatch all the
31850Sstevel@tonic-gate  * pages while deallocating the list of watched_page structs.
31860Sstevel@tonic-gate  */
31870Sstevel@tonic-gate void
31880Sstevel@tonic-gate pr_free_watched_pages(proc_t *p)
31890Sstevel@tonic-gate {
31900Sstevel@tonic-gate 	struct as *as = p->p_as;
31910Sstevel@tonic-gate 	struct watched_page *pwp;
31920Sstevel@tonic-gate 	uint_t prot;
31930Sstevel@tonic-gate 	int    retrycnt, err;
31940Sstevel@tonic-gate 	void *cookie;
31950Sstevel@tonic-gate 
31960Sstevel@tonic-gate 	if (as == NULL || avl_numnodes(&as->a_wpage) == 0)
31970Sstevel@tonic-gate 		return;
31980Sstevel@tonic-gate 
31990Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&curproc->p_lock));
32000Sstevel@tonic-gate 	AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
32010Sstevel@tonic-gate 
32020Sstevel@tonic-gate 	pwp = avl_first(&as->a_wpage);
32030Sstevel@tonic-gate 
32040Sstevel@tonic-gate 	cookie = NULL;
32050Sstevel@tonic-gate 	while ((pwp = avl_destroy_nodes(&as->a_wpage, &cookie)) != NULL) {
32060Sstevel@tonic-gate 		retrycnt = 0;
32070Sstevel@tonic-gate 		if ((prot = pwp->wp_oprot) != 0) {
32080Sstevel@tonic-gate 			caddr_t addr = pwp->wp_vaddr;
32090Sstevel@tonic-gate 			struct seg *seg;
32100Sstevel@tonic-gate 		retry:
32110Sstevel@tonic-gate 
32120Sstevel@tonic-gate 			if ((pwp->wp_prot != prot ||
32130Sstevel@tonic-gate 			    (pwp->wp_flags & WP_NOWATCH)) &&
32140Sstevel@tonic-gate 			    (seg = as_segat(as, addr)) != NULL) {
32150Sstevel@tonic-gate 				err = SEGOP_SETPROT(seg, addr, PAGESIZE, prot);
32160Sstevel@tonic-gate 				if (err == IE_RETRY) {
32170Sstevel@tonic-gate 					ASSERT(retrycnt == 0);
32180Sstevel@tonic-gate 					retrycnt++;
32190Sstevel@tonic-gate 					goto retry;
32200Sstevel@tonic-gate 				}
32210Sstevel@tonic-gate 			}
32220Sstevel@tonic-gate 		}
32230Sstevel@tonic-gate 		kmem_free(pwp, sizeof (struct watched_page));
32240Sstevel@tonic-gate 	}
32250Sstevel@tonic-gate 
32260Sstevel@tonic-gate 	avl_destroy(&as->a_wpage);
32270Sstevel@tonic-gate 	p->p_wprot = NULL;
32280Sstevel@tonic-gate 
32290Sstevel@tonic-gate 	AS_LOCK_EXIT(as, &as->a_lock);
32300Sstevel@tonic-gate }
32310Sstevel@tonic-gate 
32320Sstevel@tonic-gate /*
32330Sstevel@tonic-gate  * Insert a watched area into the list of watched pages.
32340Sstevel@tonic-gate  * If oflags is zero then we are adding a new watched area.
32350Sstevel@tonic-gate  * Otherwise we are changing the flags of an existing watched area.
32360Sstevel@tonic-gate  */
32370Sstevel@tonic-gate static int
32380Sstevel@tonic-gate set_watched_page(proc_t *p, caddr_t vaddr, caddr_t eaddr,
32390Sstevel@tonic-gate 	ulong_t flags, ulong_t oflags)
32400Sstevel@tonic-gate {
32410Sstevel@tonic-gate 	struct as *as = p->p_as;
32420Sstevel@tonic-gate 	avl_tree_t *pwp_tree;
32430Sstevel@tonic-gate 	struct watched_page *pwp, *newpwp;
32440Sstevel@tonic-gate 	struct watched_page tpw;
32450Sstevel@tonic-gate 	avl_index_t where;
32460Sstevel@tonic-gate 	struct seg *seg;
32470Sstevel@tonic-gate 	uint_t prot;
32480Sstevel@tonic-gate 	caddr_t addr;
32490Sstevel@tonic-gate 
32500Sstevel@tonic-gate 	/*
32510Sstevel@tonic-gate 	 * We need to pre-allocate a list of structures before we grab the
32520Sstevel@tonic-gate 	 * address space lock to avoid calling kmem_alloc(KM_SLEEP) with locks
32530Sstevel@tonic-gate 	 * held.
32540Sstevel@tonic-gate 	 */
32550Sstevel@tonic-gate 	newpwp = NULL;
32560Sstevel@tonic-gate 	for (addr = (caddr_t)((uintptr_t)vaddr & (uintptr_t)PAGEMASK);
32570Sstevel@tonic-gate 	    addr < eaddr; addr += PAGESIZE) {
32580Sstevel@tonic-gate 		pwp = kmem_zalloc(sizeof (struct watched_page), KM_SLEEP);
32590Sstevel@tonic-gate 		pwp->wp_list = newpwp;
32600Sstevel@tonic-gate 		newpwp = pwp;
32610Sstevel@tonic-gate 	}
32620Sstevel@tonic-gate 
32630Sstevel@tonic-gate 	AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
32640Sstevel@tonic-gate 
32650Sstevel@tonic-gate 	/*
32660Sstevel@tonic-gate 	 * Search for an existing watched page to contain the watched area.
32670Sstevel@tonic-gate 	 * If none is found, grab a new one from the available list
32680Sstevel@tonic-gate 	 * and insert it in the active list, keeping the list sorted
32690Sstevel@tonic-gate 	 * by user-level virtual address.
32700Sstevel@tonic-gate 	 */
32710Sstevel@tonic-gate 	if (p->p_flag & SVFWAIT)
32720Sstevel@tonic-gate 		pwp_tree = &p->p_wpage;
32730Sstevel@tonic-gate 	else
32740Sstevel@tonic-gate 		pwp_tree = &as->a_wpage;
32750Sstevel@tonic-gate 
32760Sstevel@tonic-gate again:
32770Sstevel@tonic-gate 	if (avl_numnodes(pwp_tree) > prnwatch) {
32780Sstevel@tonic-gate 		AS_LOCK_EXIT(as, &as->a_lock);
32790Sstevel@tonic-gate 		while (newpwp != NULL) {
32800Sstevel@tonic-gate 			pwp = newpwp->wp_list;
32810Sstevel@tonic-gate 			kmem_free(newpwp, sizeof (struct watched_page));
32820Sstevel@tonic-gate 			newpwp = pwp;
32830Sstevel@tonic-gate 		}
32840Sstevel@tonic-gate 		return (E2BIG);
32850Sstevel@tonic-gate 	}
32860Sstevel@tonic-gate 
32870Sstevel@tonic-gate 	tpw.wp_vaddr = (caddr_t)((uintptr_t)vaddr & (uintptr_t)PAGEMASK);
32880Sstevel@tonic-gate 	if ((pwp = avl_find(pwp_tree, &tpw, &where)) == NULL) {
32890Sstevel@tonic-gate 		pwp = newpwp;
32900Sstevel@tonic-gate 		newpwp = newpwp->wp_list;
32910Sstevel@tonic-gate 		pwp->wp_list = NULL;
32920Sstevel@tonic-gate 		pwp->wp_vaddr = (caddr_t)((uintptr_t)vaddr &
32930Sstevel@tonic-gate 		    (uintptr_t)PAGEMASK);
32940Sstevel@tonic-gate 		avl_insert(pwp_tree, pwp, where);
32950Sstevel@tonic-gate 	}
32960Sstevel@tonic-gate 
32970Sstevel@tonic-gate 	ASSERT(vaddr >= pwp->wp_vaddr && vaddr < pwp->wp_vaddr + PAGESIZE);
32980Sstevel@tonic-gate 
32990Sstevel@tonic-gate 	if (oflags & WA_READ)
33000Sstevel@tonic-gate 		pwp->wp_read--;
33010Sstevel@tonic-gate 	if (oflags & WA_WRITE)
33020Sstevel@tonic-gate 		pwp->wp_write--;
33030Sstevel@tonic-gate 	if (oflags & WA_EXEC)
33040Sstevel@tonic-gate 		pwp->wp_exec--;
33050Sstevel@tonic-gate 
33060Sstevel@tonic-gate 	ASSERT(pwp->wp_read >= 0);
33070Sstevel@tonic-gate 	ASSERT(pwp->wp_write >= 0);
33080Sstevel@tonic-gate 	ASSERT(pwp->wp_exec >= 0);
33090Sstevel@tonic-gate 
33100Sstevel@tonic-gate 	if (flags & WA_READ)
33110Sstevel@tonic-gate 		pwp->wp_read++;
33120Sstevel@tonic-gate 	if (flags & WA_WRITE)
33130Sstevel@tonic-gate 		pwp->wp_write++;
33140Sstevel@tonic-gate 	if (flags & WA_EXEC)
33150Sstevel@tonic-gate 		pwp->wp_exec++;
33160Sstevel@tonic-gate 
33170Sstevel@tonic-gate 	if (!(p->p_flag & SVFWAIT)) {
33180Sstevel@tonic-gate 		vaddr = pwp->wp_vaddr;
33190Sstevel@tonic-gate 		if (pwp->wp_oprot == 0 &&
33200Sstevel@tonic-gate 		    (seg = as_segat(as, vaddr)) != NULL) {
33210Sstevel@tonic-gate 			SEGOP_GETPROT(seg, vaddr, 0, &prot);
33220Sstevel@tonic-gate 			pwp->wp_oprot = (uchar_t)prot;
33230Sstevel@tonic-gate 			pwp->wp_prot = (uchar_t)prot;
33240Sstevel@tonic-gate 		}
33250Sstevel@tonic-gate 		if (pwp->wp_oprot != 0) {
33260Sstevel@tonic-gate 			prot = pwp->wp_oprot;
33270Sstevel@tonic-gate 			if (pwp->wp_read)
33280Sstevel@tonic-gate 				prot &= ~(PROT_READ|PROT_WRITE|PROT_EXEC);
33290Sstevel@tonic-gate 			if (pwp->wp_write)
33300Sstevel@tonic-gate 				prot &= ~PROT_WRITE;
33310Sstevel@tonic-gate 			if (pwp->wp_exec)
33320Sstevel@tonic-gate 				prot &= ~(PROT_READ|PROT_WRITE|PROT_EXEC);
33330Sstevel@tonic-gate 			if (!(pwp->wp_flags & WP_NOWATCH) &&
33340Sstevel@tonic-gate 			    pwp->wp_prot != prot &&
33350Sstevel@tonic-gate 			    (pwp->wp_flags & WP_SETPROT) == 0) {
33360Sstevel@tonic-gate 				pwp->wp_flags |= WP_SETPROT;
33370Sstevel@tonic-gate 				pwp->wp_list = p->p_wprot;
33380Sstevel@tonic-gate 				p->p_wprot = pwp;
33390Sstevel@tonic-gate 			}
33400Sstevel@tonic-gate 			pwp->wp_prot = (uchar_t)prot;
33410Sstevel@tonic-gate 		}
33420Sstevel@tonic-gate 	}
33430Sstevel@tonic-gate 
33440Sstevel@tonic-gate 	/*
33450Sstevel@tonic-gate 	 * If the watched area extends into the next page then do
33460Sstevel@tonic-gate 	 * it over again with the virtual address of the next page.
33470Sstevel@tonic-gate 	 */
33480Sstevel@tonic-gate 	if ((vaddr = pwp->wp_vaddr + PAGESIZE) < eaddr)
33490Sstevel@tonic-gate 		goto again;
33500Sstevel@tonic-gate 
33510Sstevel@tonic-gate 	AS_LOCK_EXIT(as, &as->a_lock);
33520Sstevel@tonic-gate 
33530Sstevel@tonic-gate 	/*
33540Sstevel@tonic-gate 	 * Free any pages we may have over-allocated
33550Sstevel@tonic-gate 	 */
33560Sstevel@tonic-gate 	while (newpwp != NULL) {
33570Sstevel@tonic-gate 		pwp = newpwp->wp_list;
33580Sstevel@tonic-gate 		kmem_free(newpwp, sizeof (struct watched_page));
33590Sstevel@tonic-gate 		newpwp = pwp;
33600Sstevel@tonic-gate 	}
33610Sstevel@tonic-gate 
33620Sstevel@tonic-gate 	return (0);
33630Sstevel@tonic-gate }
33640Sstevel@tonic-gate 
33650Sstevel@tonic-gate /*
33660Sstevel@tonic-gate  * Remove a watched area from the list of watched pages.
33670Sstevel@tonic-gate  * A watched area may extend over more than one page.
33680Sstevel@tonic-gate  */
33690Sstevel@tonic-gate static void
33700Sstevel@tonic-gate clear_watched_page(proc_t *p, caddr_t vaddr, caddr_t eaddr, ulong_t flags)
33710Sstevel@tonic-gate {
33720Sstevel@tonic-gate 	struct as *as = p->p_as;
33730Sstevel@tonic-gate 	struct watched_page *pwp;
33740Sstevel@tonic-gate 	struct watched_page tpw;
33750Sstevel@tonic-gate 	avl_tree_t *tree;
33760Sstevel@tonic-gate 	avl_index_t where;
33770Sstevel@tonic-gate 
33780Sstevel@tonic-gate 	AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
33790Sstevel@tonic-gate 
33800Sstevel@tonic-gate 	if (p->p_flag & SVFWAIT)
33810Sstevel@tonic-gate 		tree = &p->p_wpage;
33820Sstevel@tonic-gate 	else
33830Sstevel@tonic-gate 		tree = &as->a_wpage;
33840Sstevel@tonic-gate 
33850Sstevel@tonic-gate 	tpw.wp_vaddr = vaddr =
33860Sstevel@tonic-gate 	    (caddr_t)((uintptr_t)vaddr & (uintptr_t)PAGEMASK);
33870Sstevel@tonic-gate 	pwp = avl_find(tree, &tpw, &where);
33880Sstevel@tonic-gate 	if (pwp == NULL)
33890Sstevel@tonic-gate 		pwp = avl_nearest(tree, where, AVL_AFTER);
33900Sstevel@tonic-gate 
33910Sstevel@tonic-gate 	while (pwp != NULL && pwp->wp_vaddr < eaddr) {
33920Sstevel@tonic-gate 		ASSERT(vaddr <=  pwp->wp_vaddr);
33930Sstevel@tonic-gate 
33940Sstevel@tonic-gate 		if (flags & WA_READ)
33950Sstevel@tonic-gate 			pwp->wp_read--;
33960Sstevel@tonic-gate 		if (flags & WA_WRITE)
33970Sstevel@tonic-gate 			pwp->wp_write--;
33980Sstevel@tonic-gate 		if (flags & WA_EXEC)
33990Sstevel@tonic-gate 			pwp->wp_exec--;
34000Sstevel@tonic-gate 
34010Sstevel@tonic-gate 		if (pwp->wp_read + pwp->wp_write + pwp->wp_exec != 0) {
34020Sstevel@tonic-gate 			/*
34030Sstevel@tonic-gate 			 * Reset the hat layer's protections on this page.
34040Sstevel@tonic-gate 			 */
34050Sstevel@tonic-gate 			if (pwp->wp_oprot != 0) {
34060Sstevel@tonic-gate 				uint_t prot = pwp->wp_oprot;
34070Sstevel@tonic-gate 
34080Sstevel@tonic-gate 				if (pwp->wp_read)
34090Sstevel@tonic-gate 					prot &=
34100Sstevel@tonic-gate 					    ~(PROT_READ|PROT_WRITE|PROT_EXEC);
34110Sstevel@tonic-gate 				if (pwp->wp_write)
34120Sstevel@tonic-gate 					prot &= ~PROT_WRITE;
34130Sstevel@tonic-gate 				if (pwp->wp_exec)
34140Sstevel@tonic-gate 					prot &=
34150Sstevel@tonic-gate 					    ~(PROT_READ|PROT_WRITE|PROT_EXEC);
34160Sstevel@tonic-gate 				if (!(pwp->wp_flags & WP_NOWATCH) &&
34170Sstevel@tonic-gate 				    pwp->wp_prot != prot &&
34180Sstevel@tonic-gate 				    (pwp->wp_flags & WP_SETPROT) == 0) {
34190Sstevel@tonic-gate 					pwp->wp_flags |= WP_SETPROT;
34200Sstevel@tonic-gate 					pwp->wp_list = p->p_wprot;
34210Sstevel@tonic-gate 					p->p_wprot = pwp;
34220Sstevel@tonic-gate 				}
34230Sstevel@tonic-gate 				pwp->wp_prot = (uchar_t)prot;
34240Sstevel@tonic-gate 			}
34250Sstevel@tonic-gate 		} else {
34260Sstevel@tonic-gate 			/*
34270Sstevel@tonic-gate 			 * No watched areas remain in this page.
34280Sstevel@tonic-gate 			 * Reset everything to normal.
34290Sstevel@tonic-gate 			 */
34300Sstevel@tonic-gate 			if (pwp->wp_oprot != 0) {
34310Sstevel@tonic-gate 				pwp->wp_prot = pwp->wp_oprot;
34320Sstevel@tonic-gate 				if ((pwp->wp_flags & WP_SETPROT) == 0) {
34330Sstevel@tonic-gate 					pwp->wp_flags |= WP_SETPROT;
34340Sstevel@tonic-gate 					pwp->wp_list = p->p_wprot;
34350Sstevel@tonic-gate 					p->p_wprot = pwp;
34360Sstevel@tonic-gate 				}
34370Sstevel@tonic-gate 			}
34380Sstevel@tonic-gate 		}
34390Sstevel@tonic-gate 
34400Sstevel@tonic-gate 		pwp = AVL_NEXT(tree, pwp);
34410Sstevel@tonic-gate 	}
34420Sstevel@tonic-gate 
34430Sstevel@tonic-gate 	AS_LOCK_EXIT(as, &as->a_lock);
34440Sstevel@tonic-gate }
34450Sstevel@tonic-gate 
34460Sstevel@tonic-gate /*
34470Sstevel@tonic-gate  * Return the original protections for the specified page.
34480Sstevel@tonic-gate  */
34490Sstevel@tonic-gate static void
34500Sstevel@tonic-gate getwatchprot(struct as *as, caddr_t addr, uint_t *prot)
34510Sstevel@tonic-gate {
34520Sstevel@tonic-gate 	struct watched_page *pwp;
34530Sstevel@tonic-gate 	struct watched_page tpw;
34540Sstevel@tonic-gate 
34550Sstevel@tonic-gate 	ASSERT(AS_LOCK_HELD(as, &as->a_lock));
34560Sstevel@tonic-gate 
34570Sstevel@tonic-gate 	tpw.wp_vaddr = (caddr_t)((uintptr_t)addr & (uintptr_t)PAGEMASK);
34580Sstevel@tonic-gate 	if ((pwp = avl_find(&as->a_wpage, &tpw, NULL)) != NULL)
34590Sstevel@tonic-gate 		*prot = pwp->wp_oprot;
34600Sstevel@tonic-gate }
34610Sstevel@tonic-gate 
34620Sstevel@tonic-gate static prpagev_t *
34630Sstevel@tonic-gate pr_pagev_create(struct seg *seg, int check_noreserve)
34640Sstevel@tonic-gate {
34650Sstevel@tonic-gate 	prpagev_t *pagev = kmem_alloc(sizeof (prpagev_t), KM_SLEEP);
34660Sstevel@tonic-gate 	size_t total_pages = seg_pages(seg);
34670Sstevel@tonic-gate 
34680Sstevel@tonic-gate 	/*
34690Sstevel@tonic-gate 	 * Limit the size of our vectors to pagev_lim pages at a time.  We need
34700Sstevel@tonic-gate 	 * 4 or 5 bytes of storage per page, so this means we limit ourself
34710Sstevel@tonic-gate 	 * to about a megabyte of kernel heap by default.
34720Sstevel@tonic-gate 	 */
34730Sstevel@tonic-gate 	pagev->pg_npages = MIN(total_pages, pagev_lim);
34740Sstevel@tonic-gate 	pagev->pg_pnbase = 0;
34750Sstevel@tonic-gate 
34760Sstevel@tonic-gate 	pagev->pg_protv =
34770Sstevel@tonic-gate 	    kmem_alloc(pagev->pg_npages * sizeof (uint_t), KM_SLEEP);
34780Sstevel@tonic-gate 
34790Sstevel@tonic-gate 	if (check_noreserve)
34800Sstevel@tonic-gate 		pagev->pg_incore =
34810Sstevel@tonic-gate 		    kmem_alloc(pagev->pg_npages * sizeof (char), KM_SLEEP);
34820Sstevel@tonic-gate 	else
34830Sstevel@tonic-gate 		pagev->pg_incore = NULL;
34840Sstevel@tonic-gate 
34850Sstevel@tonic-gate 	return (pagev);
34860Sstevel@tonic-gate }
34870Sstevel@tonic-gate 
34880Sstevel@tonic-gate static void
34890Sstevel@tonic-gate pr_pagev_destroy(prpagev_t *pagev)
34900Sstevel@tonic-gate {
34910Sstevel@tonic-gate 	if (pagev->pg_incore != NULL)
34920Sstevel@tonic-gate 		kmem_free(pagev->pg_incore, pagev->pg_npages * sizeof (char));
34930Sstevel@tonic-gate 
34940Sstevel@tonic-gate 	kmem_free(pagev->pg_protv, pagev->pg_npages * sizeof (uint_t));
34950Sstevel@tonic-gate 	kmem_free(pagev, sizeof (prpagev_t));
34960Sstevel@tonic-gate }
34970Sstevel@tonic-gate 
34980Sstevel@tonic-gate static caddr_t
34990Sstevel@tonic-gate pr_pagev_fill(prpagev_t *pagev, struct seg *seg, caddr_t addr, caddr_t eaddr)
35000Sstevel@tonic-gate {
35010Sstevel@tonic-gate 	ulong_t lastpg = seg_page(seg, eaddr - 1);
35020Sstevel@tonic-gate 	ulong_t pn, pnlim;
35030Sstevel@tonic-gate 	caddr_t saddr;
35040Sstevel@tonic-gate 	size_t len;
35050Sstevel@tonic-gate 
35060Sstevel@tonic-gate 	ASSERT(addr >= seg->s_base && addr <= eaddr);
35070Sstevel@tonic-gate 
35080Sstevel@tonic-gate 	if (addr == eaddr)
35090Sstevel@tonic-gate 		return (eaddr);
35100Sstevel@tonic-gate 
35110Sstevel@tonic-gate refill:
35120Sstevel@tonic-gate 	ASSERT(addr < eaddr);
35130Sstevel@tonic-gate 	pagev->pg_pnbase = seg_page(seg, addr);
35140Sstevel@tonic-gate 	pnlim = pagev->pg_pnbase + pagev->pg_npages;
35150Sstevel@tonic-gate 	saddr = addr;
35160Sstevel@tonic-gate 
35170Sstevel@tonic-gate 	if (lastpg < pnlim)
35180Sstevel@tonic-gate 		len = (size_t)(eaddr - addr);
35190Sstevel@tonic-gate 	else
35200Sstevel@tonic-gate 		len = pagev->pg_npages * PAGESIZE;
35210Sstevel@tonic-gate 
35220Sstevel@tonic-gate 	if (pagev->pg_incore != NULL) {
35230Sstevel@tonic-gate 		/*
35240Sstevel@tonic-gate 		 * INCORE cleverly has different semantics than GETPROT:
35250Sstevel@tonic-gate 		 * it returns info on pages up to but NOT including addr + len.
35260Sstevel@tonic-gate 		 */
35270Sstevel@tonic-gate 		SEGOP_INCORE(seg, addr, len, pagev->pg_incore);
35280Sstevel@tonic-gate 		pn = pagev->pg_pnbase;
35290Sstevel@tonic-gate 
35300Sstevel@tonic-gate 		do {
35310Sstevel@tonic-gate 			/*
35320Sstevel@tonic-gate 			 * Guilty knowledge here:  We know that segvn_incore
35330Sstevel@tonic-gate 			 * returns more than just the low-order bit that
35340Sstevel@tonic-gate 			 * indicates the page is actually in memory.  If any
35350Sstevel@tonic-gate 			 * bits are set, then the page has backing store.
35360Sstevel@tonic-gate 			 */
35370Sstevel@tonic-gate 			if (pagev->pg_incore[pn++ - pagev->pg_pnbase])
35380Sstevel@tonic-gate 				goto out;
35390Sstevel@tonic-gate 
35400Sstevel@tonic-gate 		} while ((addr += PAGESIZE) < eaddr && pn < pnlim);
35410Sstevel@tonic-gate 
35420Sstevel@tonic-gate 		/*
35430Sstevel@tonic-gate 		 * If we examined all the pages in the vector but we're not
35440Sstevel@tonic-gate 		 * at the end of the segment, take another lap.
35450Sstevel@tonic-gate 		 */
35460Sstevel@tonic-gate 		if (addr < eaddr)
35470Sstevel@tonic-gate 			goto refill;
35480Sstevel@tonic-gate 	}
35490Sstevel@tonic-gate 
35500Sstevel@tonic-gate 	/*
35510Sstevel@tonic-gate 	 * Need to take len - 1 because addr + len is the address of the
35520Sstevel@tonic-gate 	 * first byte of the page just past the end of what we want.
35530Sstevel@tonic-gate 	 */
35540Sstevel@tonic-gate out:
35550Sstevel@tonic-gate 	SEGOP_GETPROT(seg, saddr, len - 1, pagev->pg_protv);
35560Sstevel@tonic-gate 	return (addr);
35570Sstevel@tonic-gate }
35580Sstevel@tonic-gate 
35590Sstevel@tonic-gate static caddr_t
35600Sstevel@tonic-gate pr_pagev_nextprot(prpagev_t *pagev, struct seg *seg,
35610Sstevel@tonic-gate     caddr_t *saddrp, caddr_t eaddr, uint_t *protp)
35620Sstevel@tonic-gate {
35630Sstevel@tonic-gate 	/*
35640Sstevel@tonic-gate 	 * Our starting address is either the specified address, or the base
35650Sstevel@tonic-gate 	 * address from the start of the pagev.  If the latter is greater,
35660Sstevel@tonic-gate 	 * this means a previous call to pr_pagev_fill has already scanned
35670Sstevel@tonic-gate 	 * further than the end of the previous mapping.
35680Sstevel@tonic-gate 	 */
35690Sstevel@tonic-gate 	caddr_t base = seg->s_base + pagev->pg_pnbase * PAGESIZE;
35700Sstevel@tonic-gate 	caddr_t addr = MAX(*saddrp, base);
35710Sstevel@tonic-gate 	ulong_t pn = seg_page(seg, addr);
35720Sstevel@tonic-gate 	uint_t prot, nprot;
35730Sstevel@tonic-gate 
35740Sstevel@tonic-gate 	/*
35750Sstevel@tonic-gate 	 * If we're dealing with noreserve pages, then advance addr to
35760Sstevel@tonic-gate 	 * the address of the next page which has backing store.
35770Sstevel@tonic-gate 	 */
35780Sstevel@tonic-gate 	if (pagev->pg_incore != NULL) {
35790Sstevel@tonic-gate 		while (pagev->pg_incore[pn - pagev->pg_pnbase] == 0) {
35800Sstevel@tonic-gate 			if ((addr += PAGESIZE) == eaddr) {
35810Sstevel@tonic-gate 				*saddrp = addr;
35820Sstevel@tonic-gate 				prot = 0;
35830Sstevel@tonic-gate 				goto out;
35840Sstevel@tonic-gate 			}
35850Sstevel@tonic-gate 			if (++pn == pagev->pg_pnbase + pagev->pg_npages) {
35860Sstevel@tonic-gate 				addr = pr_pagev_fill(pagev, seg, addr, eaddr);
35870Sstevel@tonic-gate 				if (addr == eaddr) {
35880Sstevel@tonic-gate 					*saddrp = addr;
35890Sstevel@tonic-gate 					prot = 0;
35900Sstevel@tonic-gate 					goto out;
35910Sstevel@tonic-gate 				}
35920Sstevel@tonic-gate 				pn = seg_page(seg, addr);
35930Sstevel@tonic-gate 			}
35940Sstevel@tonic-gate 		}
35950Sstevel@tonic-gate 	}
35960Sstevel@tonic-gate 
35970Sstevel@tonic-gate 	/*
35980Sstevel@tonic-gate 	 * Get the protections on the page corresponding to addr.
35990Sstevel@tonic-gate 	 */
36000Sstevel@tonic-gate 	pn = seg_page(seg, addr);
36010Sstevel@tonic-gate 	ASSERT(pn >= pagev->pg_pnbase);
36020Sstevel@tonic-gate 	ASSERT(pn < (pagev->pg_pnbase + pagev->pg_npages));
36030Sstevel@tonic-gate 
36040Sstevel@tonic-gate 	prot = pagev->pg_protv[pn - pagev->pg_pnbase];
36050Sstevel@tonic-gate 	getwatchprot(seg->s_as, addr, &prot);
36060Sstevel@tonic-gate 	*saddrp = addr;
36070Sstevel@tonic-gate 
36080Sstevel@tonic-gate 	/*
36090Sstevel@tonic-gate 	 * Now loop until we find a backed page with different protections
36100Sstevel@tonic-gate 	 * or we reach the end of this segment.
36110Sstevel@tonic-gate 	 */
36120Sstevel@tonic-gate 	while ((addr += PAGESIZE) < eaddr) {
36130Sstevel@tonic-gate 		/*
36140Sstevel@tonic-gate 		 * If pn has advanced to the page number following what we
36150Sstevel@tonic-gate 		 * have information on, refill the page vector and reset
36160Sstevel@tonic-gate 		 * addr and pn.  If pr_pagev_fill does not return the
36170Sstevel@tonic-gate 		 * address of the next page, we have a discontiguity and
36180Sstevel@tonic-gate 		 * thus have reached the end of the current mapping.
36190Sstevel@tonic-gate 		 */
36200Sstevel@tonic-gate 		if (++pn == pagev->pg_pnbase + pagev->pg_npages) {
36210Sstevel@tonic-gate 			caddr_t naddr = pr_pagev_fill(pagev, seg, addr, eaddr);
36220Sstevel@tonic-gate 			if (naddr != addr)
36230Sstevel@tonic-gate 				goto out;
36240Sstevel@tonic-gate 			pn = seg_page(seg, addr);
36250Sstevel@tonic-gate 		}
36260Sstevel@tonic-gate 
36270Sstevel@tonic-gate 		/*
36280Sstevel@tonic-gate 		 * The previous page's protections are in prot, and it has
36290Sstevel@tonic-gate 		 * backing.  If this page is MAP_NORESERVE and has no backing,
36300Sstevel@tonic-gate 		 * then end this mapping and return the previous protections.
36310Sstevel@tonic-gate 		 */
36320Sstevel@tonic-gate 		if (pagev->pg_incore != NULL &&
36330Sstevel@tonic-gate 		    pagev->pg_incore[pn - pagev->pg_pnbase] == 0)
36340Sstevel@tonic-gate 			break;
36350Sstevel@tonic-gate 
36360Sstevel@tonic-gate 		/*
36370Sstevel@tonic-gate 		 * Otherwise end the mapping if this page's protections (nprot)
36380Sstevel@tonic-gate 		 * are different than those in the previous page (prot).
36390Sstevel@tonic-gate 		 */
36400Sstevel@tonic-gate 		nprot = pagev->pg_protv[pn - pagev->pg_pnbase];
36410Sstevel@tonic-gate 		getwatchprot(seg->s_as, addr, &nprot);
36420Sstevel@tonic-gate 
36430Sstevel@tonic-gate 		if (nprot != prot)
36440Sstevel@tonic-gate 			break;
36450Sstevel@tonic-gate 	}
36460Sstevel@tonic-gate 
36470Sstevel@tonic-gate out:
36480Sstevel@tonic-gate 	*protp = prot;
36490Sstevel@tonic-gate 	return (addr);
36500Sstevel@tonic-gate }
36510Sstevel@tonic-gate 
36520Sstevel@tonic-gate size_t
36530Sstevel@tonic-gate pr_getsegsize(struct seg *seg, int reserved)
36540Sstevel@tonic-gate {
36550Sstevel@tonic-gate 	size_t size = seg->s_size;
36560Sstevel@tonic-gate 
36570Sstevel@tonic-gate 	/*
36580Sstevel@tonic-gate 	 * If we're interested in the reserved space, return the size of the
36590Sstevel@tonic-gate 	 * segment itself.  Everything else in this function is a special case
36600Sstevel@tonic-gate 	 * to determine the actual underlying size of various segment types.
36610Sstevel@tonic-gate 	 */
36620Sstevel@tonic-gate 	if (reserved)
36630Sstevel@tonic-gate 		return (size);
36640Sstevel@tonic-gate 
36650Sstevel@tonic-gate 	/*
36660Sstevel@tonic-gate 	 * If this is a segvn mapping of a regular file, return the smaller
36670Sstevel@tonic-gate 	 * of the segment size and the remaining size of the file beyond
36680Sstevel@tonic-gate 	 * the file offset corresponding to seg->s_base.
36690Sstevel@tonic-gate 	 */
36700Sstevel@tonic-gate 	if (seg->s_ops == &segvn_ops) {
36710Sstevel@tonic-gate 		vattr_t vattr;
36720Sstevel@tonic-gate 		vnode_t *vp;
36730Sstevel@tonic-gate 
36740Sstevel@tonic-gate 		vattr.va_mask = AT_SIZE;
36750Sstevel@tonic-gate 
36760Sstevel@tonic-gate 		if (SEGOP_GETVP(seg, seg->s_base, &vp) == 0 &&
36770Sstevel@tonic-gate 		    vp != NULL && vp->v_type == VREG &&
36780Sstevel@tonic-gate 		    VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
36790Sstevel@tonic-gate 
36800Sstevel@tonic-gate 			u_offset_t fsize = vattr.va_size;
36810Sstevel@tonic-gate 			u_offset_t offset = SEGOP_GETOFFSET(seg, seg->s_base);
36820Sstevel@tonic-gate 
36830Sstevel@tonic-gate 			if (fsize < offset)
36840Sstevel@tonic-gate 				fsize = 0;
36850Sstevel@tonic-gate 			else
36860Sstevel@tonic-gate 				fsize -= offset;
36870Sstevel@tonic-gate 
36880Sstevel@tonic-gate 			fsize = roundup(fsize, (u_offset_t)PAGESIZE);
36890Sstevel@tonic-gate 
36900Sstevel@tonic-gate 			if (fsize < (u_offset_t)size)
36910Sstevel@tonic-gate 				size = (size_t)fsize;
36920Sstevel@tonic-gate 		}
36930Sstevel@tonic-gate 
36940Sstevel@tonic-gate 		return (size);
36950Sstevel@tonic-gate 	}
36960Sstevel@tonic-gate 
36970Sstevel@tonic-gate 	/*
36980Sstevel@tonic-gate 	 * If this is an ISM shared segment, don't include pages that are
36990Sstevel@tonic-gate 	 * beyond the real size of the spt segment that backs it.
37000Sstevel@tonic-gate 	 */
37010Sstevel@tonic-gate 	if (seg->s_ops == &segspt_shmops)
37020Sstevel@tonic-gate 		return (MIN(spt_realsize(seg), size));
37030Sstevel@tonic-gate 
37040Sstevel@tonic-gate 	/*
37050Sstevel@tonic-gate 	 * If this is segment is a mapping from /dev/null, then this is a
37060Sstevel@tonic-gate 	 * reservation of virtual address space and has no actual size.
37070Sstevel@tonic-gate 	 * Such segments are backed by segdev and have type set to neither
37080Sstevel@tonic-gate 	 * MAP_SHARED nor MAP_PRIVATE.
37090Sstevel@tonic-gate 	 */
37100Sstevel@tonic-gate 	if (seg->s_ops == &segdev_ops &&
37110Sstevel@tonic-gate 	    ((SEGOP_GETTYPE(seg, seg->s_base) &
37120Sstevel@tonic-gate 		(MAP_SHARED | MAP_PRIVATE)) == 0))
37130Sstevel@tonic-gate 		return (0);
37140Sstevel@tonic-gate 
37150Sstevel@tonic-gate 	/*
37160Sstevel@tonic-gate 	 * If this segment doesn't match one of the special types we handle,
37170Sstevel@tonic-gate 	 * just return the size of the segment itself.
37180Sstevel@tonic-gate 	 */
37190Sstevel@tonic-gate 	return (size);
37200Sstevel@tonic-gate }
37210Sstevel@tonic-gate 
37220Sstevel@tonic-gate uint_t
37230Sstevel@tonic-gate pr_getprot(struct seg *seg, int reserved, void **tmp,
37240Sstevel@tonic-gate 	caddr_t *saddrp, caddr_t *naddrp, caddr_t eaddr)
37250Sstevel@tonic-gate {
37260Sstevel@tonic-gate 	struct as *as = seg->s_as;
37270Sstevel@tonic-gate 
37280Sstevel@tonic-gate 	caddr_t saddr = *saddrp;
37290Sstevel@tonic-gate 	caddr_t naddr;
37300Sstevel@tonic-gate 
37310Sstevel@tonic-gate 	int check_noreserve;
37320Sstevel@tonic-gate 	uint_t prot;
37330Sstevel@tonic-gate 
37340Sstevel@tonic-gate 	union {
37350Sstevel@tonic-gate 		struct segvn_data *svd;
37360Sstevel@tonic-gate 		struct segdev_data *sdp;
37370Sstevel@tonic-gate 		void *data;
37380Sstevel@tonic-gate 	} s;
37390Sstevel@tonic-gate 
37400Sstevel@tonic-gate 	s.data = seg->s_data;
37410Sstevel@tonic-gate 
37420Sstevel@tonic-gate 	ASSERT(AS_WRITE_HELD(as, &as->a_lock));
37430Sstevel@tonic-gate 	ASSERT(saddr >= seg->s_base && saddr < eaddr);
37440Sstevel@tonic-gate 	ASSERT(eaddr <= seg->s_base + seg->s_size);
37450Sstevel@tonic-gate 
37460Sstevel@tonic-gate 	/*
37470Sstevel@tonic-gate 	 * Don't include MAP_NORESERVE pages in the address range
37480Sstevel@tonic-gate 	 * unless their mappings have actually materialized.
37490Sstevel@tonic-gate 	 * We cheat by knowing that segvn is the only segment
37500Sstevel@tonic-gate 	 * driver that supports MAP_NORESERVE.
37510Sstevel@tonic-gate 	 */
37520Sstevel@tonic-gate 	check_noreserve =
37530Sstevel@tonic-gate 	    (!reserved && seg->s_ops == &segvn_ops && s.svd != NULL &&
37540Sstevel@tonic-gate 	    (s.svd->vp == NULL || s.svd->vp->v_type != VREG) &&
37550Sstevel@tonic-gate 	    (s.svd->flags & MAP_NORESERVE));
37560Sstevel@tonic-gate 
37570Sstevel@tonic-gate 	/*
37580Sstevel@tonic-gate 	 * Examine every page only as a last resort.  We use guilty knowledge
37590Sstevel@tonic-gate 	 * of segvn and segdev to avoid this: if there are no per-page
37600Sstevel@tonic-gate 	 * protections present in the segment and we don't care about
37610Sstevel@tonic-gate 	 * MAP_NORESERVE, then s_data->prot is the prot for the whole segment.
37620Sstevel@tonic-gate 	 */
37630Sstevel@tonic-gate 	if (!check_noreserve && saddr == seg->s_base &&
37640Sstevel@tonic-gate 	    seg->s_ops == &segvn_ops && s.svd != NULL && s.svd->pageprot == 0) {
37650Sstevel@tonic-gate 		prot = s.svd->prot;
37660Sstevel@tonic-gate 		getwatchprot(as, saddr, &prot);
37670Sstevel@tonic-gate 		naddr = eaddr;
37680Sstevel@tonic-gate 
37690Sstevel@tonic-gate 	} else if (saddr == seg->s_base && seg->s_ops == &segdev_ops &&
37700Sstevel@tonic-gate 	    s.sdp != NULL && s.sdp->pageprot == 0) {
37710Sstevel@tonic-gate 		prot = s.sdp->prot;
37720Sstevel@tonic-gate 		getwatchprot(as, saddr, &prot);
37730Sstevel@tonic-gate 		naddr = eaddr;
37740Sstevel@tonic-gate 
37750Sstevel@tonic-gate 	} else {
37760Sstevel@tonic-gate 		prpagev_t *pagev;
37770Sstevel@tonic-gate 
37780Sstevel@tonic-gate 		/*
37790Sstevel@tonic-gate 		 * If addr is sitting at the start of the segment, then
37800Sstevel@tonic-gate 		 * create a page vector to store protection and incore
37810Sstevel@tonic-gate 		 * information for pages in the segment, and fill it.
37820Sstevel@tonic-gate 		 * Otherwise, we expect *tmp to address the prpagev_t
37830Sstevel@tonic-gate 		 * allocated by a previous call to this function.
37840Sstevel@tonic-gate 		 */
37850Sstevel@tonic-gate 		if (saddr == seg->s_base) {
37860Sstevel@tonic-gate 			pagev = pr_pagev_create(seg, check_noreserve);
37870Sstevel@tonic-gate 			saddr = pr_pagev_fill(pagev, seg, saddr, eaddr);
37880Sstevel@tonic-gate 
37890Sstevel@tonic-gate 			ASSERT(*tmp == NULL);
37900Sstevel@tonic-gate 			*tmp = pagev;
37910Sstevel@tonic-gate 
37920Sstevel@tonic-gate 			ASSERT(saddr <= eaddr);
37930Sstevel@tonic-gate 			*saddrp = saddr;
37940Sstevel@tonic-gate 
37950Sstevel@tonic-gate 			if (saddr == eaddr) {
37960Sstevel@tonic-gate 				naddr = saddr;
37970Sstevel@tonic-gate 				prot = 0;
37980Sstevel@tonic-gate 				goto out;
37990Sstevel@tonic-gate 			}
38000Sstevel@tonic-gate 
38010Sstevel@tonic-gate 		} else {
38020Sstevel@tonic-gate 			ASSERT(*tmp != NULL);
38030Sstevel@tonic-gate 			pagev = (prpagev_t *)*tmp;
38040Sstevel@tonic-gate 		}
38050Sstevel@tonic-gate 
38060Sstevel@tonic-gate 		naddr = pr_pagev_nextprot(pagev, seg, saddrp, eaddr, &prot);
38070Sstevel@tonic-gate 		ASSERT(naddr <= eaddr);
38080Sstevel@tonic-gate 	}
38090Sstevel@tonic-gate 
38100Sstevel@tonic-gate out:
38110Sstevel@tonic-gate 	if (naddr == eaddr)
38120Sstevel@tonic-gate 		pr_getprot_done(tmp);
38130Sstevel@tonic-gate 	*naddrp = naddr;
38140Sstevel@tonic-gate 	return (prot);
38150Sstevel@tonic-gate }
38160Sstevel@tonic-gate 
38170Sstevel@tonic-gate void
38180Sstevel@tonic-gate pr_getprot_done(void **tmp)
38190Sstevel@tonic-gate {
38200Sstevel@tonic-gate 	if (*tmp != NULL) {
38210Sstevel@tonic-gate 		pr_pagev_destroy((prpagev_t *)*tmp);
38220Sstevel@tonic-gate 		*tmp = NULL;
38230Sstevel@tonic-gate 	}
38240Sstevel@tonic-gate }
38250Sstevel@tonic-gate 
38260Sstevel@tonic-gate /*
38270Sstevel@tonic-gate  * Return true iff the vnode is a /proc file from the object directory.
38280Sstevel@tonic-gate  */
38290Sstevel@tonic-gate int
38300Sstevel@tonic-gate pr_isobject(vnode_t *vp)
38310Sstevel@tonic-gate {
38320Sstevel@tonic-gate 	return (vn_matchops(vp, prvnodeops) && VTOP(vp)->pr_type == PR_OBJECT);
38330Sstevel@tonic-gate }
38340Sstevel@tonic-gate 
38350Sstevel@tonic-gate /*
38360Sstevel@tonic-gate  * Return true iff the vnode is a /proc file opened by the process itself.
38370Sstevel@tonic-gate  */
38380Sstevel@tonic-gate int
38390Sstevel@tonic-gate pr_isself(vnode_t *vp)
38400Sstevel@tonic-gate {
38410Sstevel@tonic-gate 	/*
38420Sstevel@tonic-gate 	 * XXX: To retain binary compatibility with the old
38430Sstevel@tonic-gate 	 * ioctl()-based version of /proc, we exempt self-opens
38440Sstevel@tonic-gate 	 * of /proc/<pid> from being marked close-on-exec.
38450Sstevel@tonic-gate 	 */
38460Sstevel@tonic-gate 	return (vn_matchops(vp, prvnodeops) &&
38470Sstevel@tonic-gate 	    (VTOP(vp)->pr_flags & PR_ISSELF) &&
38480Sstevel@tonic-gate 	    VTOP(vp)->pr_type != PR_PIDDIR);
38490Sstevel@tonic-gate }
38500Sstevel@tonic-gate 
38510Sstevel@tonic-gate static ssize_t
38520Sstevel@tonic-gate pr_getpagesize(struct seg *seg, caddr_t saddr, caddr_t *naddrp, caddr_t eaddr)
38530Sstevel@tonic-gate {
38540Sstevel@tonic-gate 	ssize_t pagesize, hatsize;
38550Sstevel@tonic-gate 
38560Sstevel@tonic-gate 	ASSERT(AS_WRITE_HELD(seg->s_as, &seg->s_as->a_lock));
38570Sstevel@tonic-gate 	ASSERT(IS_P2ALIGNED(saddr, PAGESIZE));
38580Sstevel@tonic-gate 	ASSERT(IS_P2ALIGNED(eaddr, PAGESIZE));
38590Sstevel@tonic-gate 	ASSERT(saddr < eaddr);
38600Sstevel@tonic-gate 
38610Sstevel@tonic-gate 	pagesize = hatsize = hat_getpagesize(seg->s_as->a_hat, saddr);
38620Sstevel@tonic-gate 	ASSERT(pagesize == -1 || IS_P2ALIGNED(pagesize, pagesize));
38630Sstevel@tonic-gate 	ASSERT(pagesize != 0);
38640Sstevel@tonic-gate 
38650Sstevel@tonic-gate 	if (pagesize == -1)
38660Sstevel@tonic-gate 		pagesize = PAGESIZE;
38670Sstevel@tonic-gate 
38680Sstevel@tonic-gate 	saddr += P2NPHASE((uintptr_t)saddr, pagesize);
38690Sstevel@tonic-gate 
38700Sstevel@tonic-gate 	while (saddr < eaddr) {
38710Sstevel@tonic-gate 		if (hatsize != hat_getpagesize(seg->s_as->a_hat, saddr))
38720Sstevel@tonic-gate 			break;
38730Sstevel@tonic-gate 		ASSERT(IS_P2ALIGNED(saddr, pagesize));
38740Sstevel@tonic-gate 		saddr += pagesize;
38750Sstevel@tonic-gate 	}
38760Sstevel@tonic-gate 
38770Sstevel@tonic-gate 	*naddrp = ((saddr < eaddr) ? saddr : eaddr);
38780Sstevel@tonic-gate 	return (hatsize);
38790Sstevel@tonic-gate }
38800Sstevel@tonic-gate 
38810Sstevel@tonic-gate /*
38820Sstevel@tonic-gate  * Return an array of structures with extended memory map information.
38830Sstevel@tonic-gate  * We allocate here; the caller must deallocate.
38840Sstevel@tonic-gate  */
38850Sstevel@tonic-gate int
38862789Sfrankho prgetxmap(proc_t *p, list_t *iolhead)
38870Sstevel@tonic-gate {
38880Sstevel@tonic-gate 	struct as *as = p->p_as;
38890Sstevel@tonic-gate 	prxmap_t *mp;
38900Sstevel@tonic-gate 	struct seg *seg;
38910Sstevel@tonic-gate 	struct seg *brkseg, *stkseg;
38920Sstevel@tonic-gate 	struct vnode *vp;
38930Sstevel@tonic-gate 	struct vattr vattr;
38940Sstevel@tonic-gate 	uint_t prot;
38950Sstevel@tonic-gate 
38960Sstevel@tonic-gate 	ASSERT(as != &kas && AS_WRITE_HELD(as, &as->a_lock));
38970Sstevel@tonic-gate 
38982789Sfrankho 	/*
38992789Sfrankho 	 * Request an initial buffer size that doesn't waste memory
39002789Sfrankho 	 * if the address space has only a small number of segments.
39012789Sfrankho 	 */
39022789Sfrankho 	pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
39030Sstevel@tonic-gate 
39040Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL)
39050Sstevel@tonic-gate 		return (0);
39060Sstevel@tonic-gate 
39070Sstevel@tonic-gate 	brkseg = break_seg(p);
39080Sstevel@tonic-gate 	stkseg = as_segat(as, prgetstackbase(p));
39090Sstevel@tonic-gate 
39100Sstevel@tonic-gate 	do {
39110Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
39120Sstevel@tonic-gate 		caddr_t saddr, naddr, baddr;
39130Sstevel@tonic-gate 		void *tmp = NULL;
39140Sstevel@tonic-gate 		ssize_t psz;
39150Sstevel@tonic-gate 		char *parr;
39160Sstevel@tonic-gate 		uint64_t npages;
39170Sstevel@tonic-gate 		uint64_t pagenum;
39180Sstevel@tonic-gate 
39190Sstevel@tonic-gate 		/*
39200Sstevel@tonic-gate 		 * Segment loop part one: iterate from the base of the segment
39210Sstevel@tonic-gate 		 * to its end, pausing at each address boundary (baddr) between
39220Sstevel@tonic-gate 		 * ranges that have different virtual memory protections.
39230Sstevel@tonic-gate 		 */
39240Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = baddr) {
39250Sstevel@tonic-gate 			prot = pr_getprot(seg, 0, &tmp, &saddr, &baddr, eaddr);
39260Sstevel@tonic-gate 			ASSERT(baddr >= saddr && baddr <= eaddr);
39270Sstevel@tonic-gate 
39280Sstevel@tonic-gate 			/*
39290Sstevel@tonic-gate 			 * Segment loop part two: iterate from the current
39300Sstevel@tonic-gate 			 * position to the end of the protection boundary,
39310Sstevel@tonic-gate 			 * pausing at each address boundary (naddr) between
39320Sstevel@tonic-gate 			 * ranges that have different underlying page sizes.
39330Sstevel@tonic-gate 			 */
39340Sstevel@tonic-gate 			for (; saddr < baddr; saddr = naddr) {
39350Sstevel@tonic-gate 				psz = pr_getpagesize(seg, saddr, &naddr, baddr);
39360Sstevel@tonic-gate 				ASSERT(naddr >= saddr && naddr <= baddr);
39370Sstevel@tonic-gate 
39382789Sfrankho 				mp = pr_iol_newbuf(iolhead, sizeof (*mp));
39392789Sfrankho 
39400Sstevel@tonic-gate 				mp->pr_vaddr = (uintptr_t)saddr;
39410Sstevel@tonic-gate 				mp->pr_size = naddr - saddr;
39420Sstevel@tonic-gate 				mp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
39430Sstevel@tonic-gate 				mp->pr_mflags = 0;
39440Sstevel@tonic-gate 				if (prot & PROT_READ)
39450Sstevel@tonic-gate 					mp->pr_mflags |= MA_READ;
39460Sstevel@tonic-gate 				if (prot & PROT_WRITE)
39470Sstevel@tonic-gate 					mp->pr_mflags |= MA_WRITE;
39480Sstevel@tonic-gate 				if (prot & PROT_EXEC)
39490Sstevel@tonic-gate 					mp->pr_mflags |= MA_EXEC;
39500Sstevel@tonic-gate 				if (SEGOP_GETTYPE(seg, saddr) & MAP_SHARED)
39510Sstevel@tonic-gate 					mp->pr_mflags |= MA_SHARED;
39520Sstevel@tonic-gate 				if (SEGOP_GETTYPE(seg, saddr) & MAP_NORESERVE)
39530Sstevel@tonic-gate 					mp->pr_mflags |= MA_NORESERVE;
39540Sstevel@tonic-gate 				if (seg->s_ops == &segspt_shmops ||
39550Sstevel@tonic-gate 				    (seg->s_ops == &segvn_ops &&
39560Sstevel@tonic-gate 				    (SEGOP_GETVP(seg, saddr, &vp) != 0 ||
39570Sstevel@tonic-gate 				    vp == NULL)))
39580Sstevel@tonic-gate 					mp->pr_mflags |= MA_ANON;
39590Sstevel@tonic-gate 				if (seg == brkseg)
39600Sstevel@tonic-gate 					mp->pr_mflags |= MA_BREAK;
39610Sstevel@tonic-gate 				else if (seg == stkseg)
39620Sstevel@tonic-gate 					mp->pr_mflags |= MA_STACK;
39630Sstevel@tonic-gate 				if (seg->s_ops == &segspt_shmops)
39640Sstevel@tonic-gate 					mp->pr_mflags |= MA_ISM | MA_SHM;
39650Sstevel@tonic-gate 
39660Sstevel@tonic-gate 				mp->pr_pagesize = PAGESIZE;
39670Sstevel@tonic-gate 				if (psz == -1) {
39680Sstevel@tonic-gate 					mp->pr_hatpagesize = 0;
39690Sstevel@tonic-gate 				} else {
39700Sstevel@tonic-gate 					mp->pr_hatpagesize = psz;
39710Sstevel@tonic-gate 				}
39720Sstevel@tonic-gate 
39730Sstevel@tonic-gate 				/*
39740Sstevel@tonic-gate 				 * Manufacture a filename for the "object" dir.
39750Sstevel@tonic-gate 				 */
39760Sstevel@tonic-gate 				mp->pr_dev = PRNODEV;
39770Sstevel@tonic-gate 				vattr.va_mask = AT_FSID|AT_NODEID;
39780Sstevel@tonic-gate 				if (seg->s_ops == &segvn_ops &&
39790Sstevel@tonic-gate 				    SEGOP_GETVP(seg, saddr, &vp) == 0 &&
39800Sstevel@tonic-gate 				    vp != NULL && vp->v_type == VREG &&
39810Sstevel@tonic-gate 				    VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
39820Sstevel@tonic-gate 					mp->pr_dev = vattr.va_fsid;
39830Sstevel@tonic-gate 					mp->pr_ino = vattr.va_nodeid;
39840Sstevel@tonic-gate 					if (vp == p->p_exec)
39850Sstevel@tonic-gate 						(void) strcpy(mp->pr_mapname,
39860Sstevel@tonic-gate 						    "a.out");
39870Sstevel@tonic-gate 					else
39880Sstevel@tonic-gate 						pr_object_name(mp->pr_mapname,
39890Sstevel@tonic-gate 						    vp, &vattr);
39900Sstevel@tonic-gate 				}
39910Sstevel@tonic-gate 
39920Sstevel@tonic-gate 				/*
39930Sstevel@tonic-gate 				 * Get the SysV shared memory id, if any.
39940Sstevel@tonic-gate 				 */
39950Sstevel@tonic-gate 				if ((mp->pr_mflags & MA_SHARED) &&
39960Sstevel@tonic-gate 				    p->p_segacct && (mp->pr_shmid = shmgetid(p,
39970Sstevel@tonic-gate 				    seg->s_base)) != SHMID_NONE) {
39980Sstevel@tonic-gate 					if (mp->pr_shmid == SHMID_FREE)
39990Sstevel@tonic-gate 						mp->pr_shmid = -1;
40000Sstevel@tonic-gate 
40010Sstevel@tonic-gate 					mp->pr_mflags |= MA_SHM;
40020Sstevel@tonic-gate 				} else {
40030Sstevel@tonic-gate 					mp->pr_shmid = -1;
40040Sstevel@tonic-gate 				}
40050Sstevel@tonic-gate 
40060Sstevel@tonic-gate 				npages = ((uintptr_t)(naddr - saddr)) >>
40070Sstevel@tonic-gate 				    PAGESHIFT;
40080Sstevel@tonic-gate 				parr = kmem_zalloc(npages, KM_SLEEP);
40090Sstevel@tonic-gate 
40100Sstevel@tonic-gate 				SEGOP_INCORE(seg, saddr, naddr - saddr, parr);
40110Sstevel@tonic-gate 
40120Sstevel@tonic-gate 				for (pagenum = 0; pagenum < npages; pagenum++) {
40130Sstevel@tonic-gate 					if (parr[pagenum] & SEG_PAGE_INCORE)
40140Sstevel@tonic-gate 						mp->pr_rss++;
40150Sstevel@tonic-gate 					if (parr[pagenum] & SEG_PAGE_ANON)
40160Sstevel@tonic-gate 						mp->pr_anon++;
40170Sstevel@tonic-gate 					if (parr[pagenum] & SEG_PAGE_LOCKED)
40180Sstevel@tonic-gate 						mp->pr_locked++;
40190Sstevel@tonic-gate 				}
40200Sstevel@tonic-gate 				kmem_free(parr, npages);
40210Sstevel@tonic-gate 			}
40220Sstevel@tonic-gate 		}
40230Sstevel@tonic-gate 		ASSERT(tmp == NULL);
40240Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
40250Sstevel@tonic-gate 
40262789Sfrankho 	return (0);
40270Sstevel@tonic-gate }
40280Sstevel@tonic-gate 
40290Sstevel@tonic-gate /*
40300Sstevel@tonic-gate  * Return the process's credentials.  We don't need a 32-bit equivalent of
40310Sstevel@tonic-gate  * this function because prcred_t and prcred32_t are actually the same.
40320Sstevel@tonic-gate  */
40330Sstevel@tonic-gate void
40340Sstevel@tonic-gate prgetcred(proc_t *p, prcred_t *pcrp)
40350Sstevel@tonic-gate {
40360Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
40370Sstevel@tonic-gate 	cred2prcred(p->p_cred, pcrp);
40380Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
40390Sstevel@tonic-gate }
40400Sstevel@tonic-gate 
40410Sstevel@tonic-gate /*
40420Sstevel@tonic-gate  * Compute actual size of the prpriv_t structure.
40430Sstevel@tonic-gate  */
40440Sstevel@tonic-gate 
40450Sstevel@tonic-gate size_t
40460Sstevel@tonic-gate prgetprivsize(void)
40470Sstevel@tonic-gate {
40480Sstevel@tonic-gate 	return (priv_prgetprivsize(NULL));
40490Sstevel@tonic-gate }
40500Sstevel@tonic-gate 
40510Sstevel@tonic-gate /*
40520Sstevel@tonic-gate  * Return the process's privileges.  We don't need a 32-bit equivalent of
40530Sstevel@tonic-gate  * this function because prpriv_t and prpriv32_t are actually the same.
40540Sstevel@tonic-gate  */
40550Sstevel@tonic-gate void
40560Sstevel@tonic-gate prgetpriv(proc_t *p, prpriv_t *pprp)
40570Sstevel@tonic-gate {
40580Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
40590Sstevel@tonic-gate 	cred2prpriv(p->p_cred, pprp);
40600Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
40610Sstevel@tonic-gate }
40620Sstevel@tonic-gate 
40630Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
40640Sstevel@tonic-gate /*
40650Sstevel@tonic-gate  * Return an array of structures with HAT memory map information.
40660Sstevel@tonic-gate  * We allocate here; the caller must deallocate.
40670Sstevel@tonic-gate  */
40680Sstevel@tonic-gate int
40692789Sfrankho prgetxmap32(proc_t *p, list_t *iolhead)
40700Sstevel@tonic-gate {
40710Sstevel@tonic-gate 	struct as *as = p->p_as;
40720Sstevel@tonic-gate 	prxmap32_t *mp;
40730Sstevel@tonic-gate 	struct seg *seg;
40740Sstevel@tonic-gate 	struct seg *brkseg, *stkseg;
40750Sstevel@tonic-gate 	struct vnode *vp;
40760Sstevel@tonic-gate 	struct vattr vattr;
40770Sstevel@tonic-gate 	uint_t prot;
40780Sstevel@tonic-gate 
40790Sstevel@tonic-gate 	ASSERT(as != &kas && AS_WRITE_HELD(as, &as->a_lock));
40800Sstevel@tonic-gate 
40812789Sfrankho 	/*
40822789Sfrankho 	 * Request an initial buffer size that doesn't waste memory
40832789Sfrankho 	 * if the address space has only a small number of segments.
40842789Sfrankho 	 */
40852789Sfrankho 	pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
40860Sstevel@tonic-gate 
40870Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL)
40880Sstevel@tonic-gate 		return (0);
40890Sstevel@tonic-gate 
40900Sstevel@tonic-gate 	brkseg = break_seg(p);
40910Sstevel@tonic-gate 	stkseg = as_segat(as, prgetstackbase(p));
40920Sstevel@tonic-gate 
40930Sstevel@tonic-gate 	do {
40940Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
40950Sstevel@tonic-gate 		caddr_t saddr, naddr, baddr;
40960Sstevel@tonic-gate 		void *tmp = NULL;
40970Sstevel@tonic-gate 		ssize_t psz;
40980Sstevel@tonic-gate 		char *parr;
40990Sstevel@tonic-gate 		uint64_t npages;
41000Sstevel@tonic-gate 		uint64_t pagenum;
41010Sstevel@tonic-gate 
41020Sstevel@tonic-gate 		/*
41030Sstevel@tonic-gate 		 * Segment loop part one: iterate from the base of the segment
41040Sstevel@tonic-gate 		 * to its end, pausing at each address boundary (baddr) between
41050Sstevel@tonic-gate 		 * ranges that have different virtual memory protections.
41060Sstevel@tonic-gate 		 */
41070Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = baddr) {
41080Sstevel@tonic-gate 			prot = pr_getprot(seg, 0, &tmp, &saddr, &baddr, eaddr);
41090Sstevel@tonic-gate 			ASSERT(baddr >= saddr && baddr <= eaddr);
41100Sstevel@tonic-gate 
41110Sstevel@tonic-gate 			/*
41120Sstevel@tonic-gate 			 * Segment loop part two: iterate from the current
41130Sstevel@tonic-gate 			 * position to the end of the protection boundary,
41140Sstevel@tonic-gate 			 * pausing at each address boundary (naddr) between
41150Sstevel@tonic-gate 			 * ranges that have different underlying page sizes.
41160Sstevel@tonic-gate 			 */
41170Sstevel@tonic-gate 			for (; saddr < baddr; saddr = naddr) {
41180Sstevel@tonic-gate 				psz = pr_getpagesize(seg, saddr, &naddr, baddr);
41190Sstevel@tonic-gate 				ASSERT(naddr >= saddr && naddr <= baddr);
41200Sstevel@tonic-gate 
41212789Sfrankho 				mp = pr_iol_newbuf(iolhead, sizeof (*mp));
41222789Sfrankho 
41230Sstevel@tonic-gate 				mp->pr_vaddr = (caddr32_t)(uintptr_t)saddr;
41240Sstevel@tonic-gate 				mp->pr_size = (size32_t)(naddr - saddr);
41250Sstevel@tonic-gate 				mp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
41260Sstevel@tonic-gate 				mp->pr_mflags = 0;
41270Sstevel@tonic-gate 				if (prot & PROT_READ)
41280Sstevel@tonic-gate 					mp->pr_mflags |= MA_READ;
41290Sstevel@tonic-gate 				if (prot & PROT_WRITE)
41300Sstevel@tonic-gate 					mp->pr_mflags |= MA_WRITE;
41310Sstevel@tonic-gate 				if (prot & PROT_EXEC)
41320Sstevel@tonic-gate 					mp->pr_mflags |= MA_EXEC;
41330Sstevel@tonic-gate 				if (SEGOP_GETTYPE(seg, saddr) & MAP_SHARED)
41340Sstevel@tonic-gate 					mp->pr_mflags |= MA_SHARED;
41350Sstevel@tonic-gate 				if (SEGOP_GETTYPE(seg, saddr) & MAP_NORESERVE)
41360Sstevel@tonic-gate 					mp->pr_mflags |= MA_NORESERVE;
41370Sstevel@tonic-gate 				if (seg->s_ops == &segspt_shmops ||
41380Sstevel@tonic-gate 				    (seg->s_ops == &segvn_ops &&
41390Sstevel@tonic-gate 				    (SEGOP_GETVP(seg, saddr, &vp) != 0 ||
41400Sstevel@tonic-gate 				    vp == NULL)))
41410Sstevel@tonic-gate 					mp->pr_mflags |= MA_ANON;
41420Sstevel@tonic-gate 				if (seg == brkseg)
41430Sstevel@tonic-gate 					mp->pr_mflags |= MA_BREAK;
41440Sstevel@tonic-gate 				else if (seg == stkseg)
41450Sstevel@tonic-gate 					mp->pr_mflags |= MA_STACK;
41460Sstevel@tonic-gate 				if (seg->s_ops == &segspt_shmops)
41470Sstevel@tonic-gate 					mp->pr_mflags |= MA_ISM | MA_SHM;
41480Sstevel@tonic-gate 
41490Sstevel@tonic-gate 				mp->pr_pagesize = PAGESIZE;
41500Sstevel@tonic-gate 				if (psz == -1) {
41510Sstevel@tonic-gate 					mp->pr_hatpagesize = 0;
41520Sstevel@tonic-gate 				} else {
41530Sstevel@tonic-gate 					mp->pr_hatpagesize = psz;
41540Sstevel@tonic-gate 				}
41550Sstevel@tonic-gate 
41560Sstevel@tonic-gate 				/*
41570Sstevel@tonic-gate 				 * Manufacture a filename for the "object" dir.
41580Sstevel@tonic-gate 				 */
41590Sstevel@tonic-gate 				mp->pr_dev = PRNODEV32;
41600Sstevel@tonic-gate 				vattr.va_mask = AT_FSID|AT_NODEID;
41610Sstevel@tonic-gate 				if (seg->s_ops == &segvn_ops &&
41620Sstevel@tonic-gate 				    SEGOP_GETVP(seg, saddr, &vp) == 0 &&
41630Sstevel@tonic-gate 				    vp != NULL && vp->v_type == VREG &&
41640Sstevel@tonic-gate 				    VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
41650Sstevel@tonic-gate 					(void) cmpldev(&mp->pr_dev,
41660Sstevel@tonic-gate 					    vattr.va_fsid);
41670Sstevel@tonic-gate 					mp->pr_ino = vattr.va_nodeid;
41680Sstevel@tonic-gate 					if (vp == p->p_exec)
41690Sstevel@tonic-gate 						(void) strcpy(mp->pr_mapname,
41700Sstevel@tonic-gate 						    "a.out");
41710Sstevel@tonic-gate 					else
41720Sstevel@tonic-gate 						pr_object_name(mp->pr_mapname,
41730Sstevel@tonic-gate 						    vp, &vattr);
41740Sstevel@tonic-gate 				}
41750Sstevel@tonic-gate 
41760Sstevel@tonic-gate 				/*
41770Sstevel@tonic-gate 				 * Get the SysV shared memory id, if any.
41780Sstevel@tonic-gate 				 */
41790Sstevel@tonic-gate 				if ((mp->pr_mflags & MA_SHARED) &&
41800Sstevel@tonic-gate 				    p->p_segacct && (mp->pr_shmid = shmgetid(p,
41810Sstevel@tonic-gate 				    seg->s_base)) != SHMID_NONE) {
41820Sstevel@tonic-gate 					if (mp->pr_shmid == SHMID_FREE)
41830Sstevel@tonic-gate 						mp->pr_shmid = -1;
41840Sstevel@tonic-gate 
41850Sstevel@tonic-gate 					mp->pr_mflags |= MA_SHM;
41860Sstevel@tonic-gate 				} else {
41870Sstevel@tonic-gate 					mp->pr_shmid = -1;
41880Sstevel@tonic-gate 				}
41890Sstevel@tonic-gate 
41900Sstevel@tonic-gate 				npages = ((uintptr_t)(naddr - saddr)) >>
41910Sstevel@tonic-gate 				    PAGESHIFT;
41920Sstevel@tonic-gate 				parr = kmem_zalloc(npages, KM_SLEEP);
41930Sstevel@tonic-gate 
41940Sstevel@tonic-gate 				SEGOP_INCORE(seg, saddr, naddr - saddr, parr);
41950Sstevel@tonic-gate 
41960Sstevel@tonic-gate 				for (pagenum = 0; pagenum < npages; pagenum++) {
41970Sstevel@tonic-gate 					if (parr[pagenum] & SEG_PAGE_INCORE)
41980Sstevel@tonic-gate 						mp->pr_rss++;
41990Sstevel@tonic-gate 					if (parr[pagenum] & SEG_PAGE_ANON)
42000Sstevel@tonic-gate 						mp->pr_anon++;
42010Sstevel@tonic-gate 					if (parr[pagenum] & SEG_PAGE_LOCKED)
42020Sstevel@tonic-gate 						mp->pr_locked++;
42030Sstevel@tonic-gate 				}
42040Sstevel@tonic-gate 				kmem_free(parr, npages);
42050Sstevel@tonic-gate 			}
42060Sstevel@tonic-gate 		}
42070Sstevel@tonic-gate 		ASSERT(tmp == NULL);
42080Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
42090Sstevel@tonic-gate 
42102789Sfrankho 	return (0);
42110Sstevel@tonic-gate }
42120Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
4213