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