xref: /titanic_51/usr/src/uts/common/fs/proc/prsubr.c (revision 2c164fafa089aa352e513b095e1ecd0abd29c61f)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
58ace1d31Ssudheer  * Common Development and Distribution License (the "License").
68ace1d31Ssudheer  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2197eda132Sraf 
227c478bd9Sstevel@tonic-gate /*
23872650ccSGangadhar Mylapuram  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24f971a346SBryan Cantrill  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
287c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
327c478bd9Sstevel@tonic-gate #include <sys/param.h>
337c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
347c478bd9Sstevel@tonic-gate #include <sys/cred.h>
357c478bd9Sstevel@tonic-gate #include <sys/priv.h>
367c478bd9Sstevel@tonic-gate #include <sys/debug.h>
377c478bd9Sstevel@tonic-gate #include <sys/errno.h>
387c478bd9Sstevel@tonic-gate #include <sys/inline.h>
397c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
407c478bd9Sstevel@tonic-gate #include <sys/mman.h>
417c478bd9Sstevel@tonic-gate #include <sys/proc.h>
42eb9dbf0cSRoger A. Faulkner #include <sys/brand.h>
437c478bd9Sstevel@tonic-gate #include <sys/sobject.h>
447c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
457c478bd9Sstevel@tonic-gate #include <sys/systm.h>
467c478bd9Sstevel@tonic-gate #include <sys/uio.h>
477c478bd9Sstevel@tonic-gate #include <sys/var.h>
487c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
497c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
507c478bd9Sstevel@tonic-gate #include <sys/session.h>
517c478bd9Sstevel@tonic-gate #include <sys/pcb.h>
527c478bd9Sstevel@tonic-gate #include <sys/signal.h>
537c478bd9Sstevel@tonic-gate #include <sys/user.h>
547c478bd9Sstevel@tonic-gate #include <sys/disp.h>
557c478bd9Sstevel@tonic-gate #include <sys/class.h>
567c478bd9Sstevel@tonic-gate #include <sys/ts.h>
577c478bd9Sstevel@tonic-gate #include <sys/bitmap.h>
587c478bd9Sstevel@tonic-gate #include <sys/poll.h>
597c478bd9Sstevel@tonic-gate #include <sys/shm_impl.h>
607c478bd9Sstevel@tonic-gate #include <sys/fault.h>
617c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
627c478bd9Sstevel@tonic-gate #include <sys/procfs.h>
637c478bd9Sstevel@tonic-gate #include <sys/processor.h>
647c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
657c478bd9Sstevel@tonic-gate #include <sys/copyops.h>
667c478bd9Sstevel@tonic-gate #include <sys/time.h>
677c478bd9Sstevel@tonic-gate #include <sys/msacct.h>
687c478bd9Sstevel@tonic-gate #include <vm/as.h>
697c478bd9Sstevel@tonic-gate #include <vm/rm.h>
707c478bd9Sstevel@tonic-gate #include <vm/seg.h>
717c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h>
727c478bd9Sstevel@tonic-gate #include <vm/seg_dev.h>
737c478bd9Sstevel@tonic-gate #include <vm/seg_spt.h>
747c478bd9Sstevel@tonic-gate #include <vm/page.h>
757c478bd9Sstevel@tonic-gate #include <sys/vmparam.h>
767c478bd9Sstevel@tonic-gate #include <sys/swap.h>
777c478bd9Sstevel@tonic-gate #include <fs/proc/prdata.h>
787c478bd9Sstevel@tonic-gate #include <sys/task.h>
797c478bd9Sstevel@tonic-gate #include <sys/project.h>
807c478bd9Sstevel@tonic-gate #include <sys/contract_impl.h>
817c478bd9Sstevel@tonic-gate #include <sys/contract/process.h>
827c478bd9Sstevel@tonic-gate #include <sys/contract/process_impl.h>
837c478bd9Sstevel@tonic-gate #include <sys/schedctl.h>
847c478bd9Sstevel@tonic-gate #include <sys/pool.h>
857c478bd9Sstevel@tonic-gate #include <sys/zone.h>
867c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
87870619e9Sfrankho #include <sys/sdt.h>
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate #define	MAX_ITERS_SPIN	5
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate typedef struct prpagev {
927c478bd9Sstevel@tonic-gate 	uint_t *pg_protv;	/* vector of page permissions */
937c478bd9Sstevel@tonic-gate 	char *pg_incore;	/* vector of incore flags */
947c478bd9Sstevel@tonic-gate 	size_t pg_npages;	/* number of pages in protv and incore */
957c478bd9Sstevel@tonic-gate 	ulong_t pg_pnbase;	/* pn within segment of first protv element */
967c478bd9Sstevel@tonic-gate } prpagev_t;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate size_t pagev_lim = 256 * 1024;	/* limit on number of pages in prpagev_t */
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate extern struct seg_ops segdev_ops;	/* needs a header file */
1017c478bd9Sstevel@tonic-gate extern struct seg_ops segspt_shmops;	/* needs a header file */
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate static	int	set_watched_page(proc_t *, caddr_t, caddr_t, ulong_t, ulong_t);
1047c478bd9Sstevel@tonic-gate static	void	clear_watched_page(proc_t *, caddr_t, caddr_t, ulong_t);
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate /*
1077c478bd9Sstevel@tonic-gate  * Choose an lwp from the complete set of lwps for the process.
1087c478bd9Sstevel@tonic-gate  * This is called for any operation applied to the process
1097c478bd9Sstevel@tonic-gate  * file descriptor that requires an lwp to operate upon.
1107c478bd9Sstevel@tonic-gate  *
1117c478bd9Sstevel@tonic-gate  * Returns a pointer to the thread for the selected LWP,
1127c478bd9Sstevel@tonic-gate  * and with the dispatcher lock held for the thread.
1137c478bd9Sstevel@tonic-gate  *
1147c478bd9Sstevel@tonic-gate  * The algorithm for choosing an lwp is critical for /proc semantics;
1157c478bd9Sstevel@tonic-gate  * don't touch this code unless you know all of the implications.
1167c478bd9Sstevel@tonic-gate  */
1177c478bd9Sstevel@tonic-gate kthread_t *
1187c478bd9Sstevel@tonic-gate prchoose(proc_t *p)
1197c478bd9Sstevel@tonic-gate {
1207c478bd9Sstevel@tonic-gate 	kthread_t *t;
1217c478bd9Sstevel@tonic-gate 	kthread_t *t_onproc = NULL;	/* running on processor */
1227c478bd9Sstevel@tonic-gate 	kthread_t *t_run = NULL;	/* runnable, on disp queue */
1237c478bd9Sstevel@tonic-gate 	kthread_t *t_sleep = NULL;	/* sleeping */
1247c478bd9Sstevel@tonic-gate 	kthread_t *t_hold = NULL;	/* sleeping, performing hold */
1257c478bd9Sstevel@tonic-gate 	kthread_t *t_susp = NULL;	/* suspended stop */
1267c478bd9Sstevel@tonic-gate 	kthread_t *t_jstop = NULL;	/* jobcontrol stop, w/o directed stop */
1277c478bd9Sstevel@tonic-gate 	kthread_t *t_jdstop = NULL;	/* jobcontrol stop with directed stop */
1287c478bd9Sstevel@tonic-gate 	kthread_t *t_req = NULL;	/* requested stop */
1297c478bd9Sstevel@tonic-gate 	kthread_t *t_istop = NULL;	/* event-of-interest stop */
1301959771bSJonathan Haslam 	kthread_t *t_dtrace = NULL;	/* DTrace stop */
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	/*
1357c478bd9Sstevel@tonic-gate 	 * If the agent lwp exists, it takes precedence over all others.
1367c478bd9Sstevel@tonic-gate 	 */
1377c478bd9Sstevel@tonic-gate 	if ((t = p->p_agenttp) != NULL) {
1387c478bd9Sstevel@tonic-gate 		thread_lock(t);
1397c478bd9Sstevel@tonic-gate 		return (t);
1407c478bd9Sstevel@tonic-gate 	}
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	if ((t = p->p_tlist) == NULL)	/* start at the head of the list */
1437c478bd9Sstevel@tonic-gate 		return (t);
1447c478bd9Sstevel@tonic-gate 	do {		/* for eacn lwp in the process */
1457c478bd9Sstevel@tonic-gate 		if (VSTOPPED(t)) {	/* virtually stopped */
1467c478bd9Sstevel@tonic-gate 			if (t_req == NULL)
1477c478bd9Sstevel@tonic-gate 				t_req = t;
1487c478bd9Sstevel@tonic-gate 			continue;
1497c478bd9Sstevel@tonic-gate 		}
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 		thread_lock(t);		/* make sure thread is in good state */
1527c478bd9Sstevel@tonic-gate 		switch (t->t_state) {
1537c478bd9Sstevel@tonic-gate 		default:
1547c478bd9Sstevel@tonic-gate 			panic("prchoose: bad thread state %d, thread 0x%p",
1557c478bd9Sstevel@tonic-gate 			    t->t_state, (void *)t);
1567c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1577c478bd9Sstevel@tonic-gate 		case TS_SLEEP:
1587c478bd9Sstevel@tonic-gate 			/* this is filthy */
1597c478bd9Sstevel@tonic-gate 			if (t->t_wchan == (caddr_t)&p->p_holdlwps &&
1607c478bd9Sstevel@tonic-gate 			    t->t_wchan0 == NULL) {
1617c478bd9Sstevel@tonic-gate 				if (t_hold == NULL)
1627c478bd9Sstevel@tonic-gate 					t_hold = t;
1637c478bd9Sstevel@tonic-gate 			} else {
1647c478bd9Sstevel@tonic-gate 				if (t_sleep == NULL)
1657c478bd9Sstevel@tonic-gate 					t_sleep = t;
1667c478bd9Sstevel@tonic-gate 			}
1677c478bd9Sstevel@tonic-gate 			break;
1687c478bd9Sstevel@tonic-gate 		case TS_RUN:
169c97ad5cdSakolb 		case TS_WAIT:
1707c478bd9Sstevel@tonic-gate 			if (t_run == NULL)
1717c478bd9Sstevel@tonic-gate 				t_run = t;
1727c478bd9Sstevel@tonic-gate 			break;
1737c478bd9Sstevel@tonic-gate 		case TS_ONPROC:
1747c478bd9Sstevel@tonic-gate 			if (t_onproc == NULL)
1757c478bd9Sstevel@tonic-gate 				t_onproc = t;
1767c478bd9Sstevel@tonic-gate 			break;
1777c478bd9Sstevel@tonic-gate 		case TS_ZOMB:		/* last possible choice */
1787c478bd9Sstevel@tonic-gate 			break;
1797c478bd9Sstevel@tonic-gate 		case TS_STOPPED:
1807c478bd9Sstevel@tonic-gate 			switch (t->t_whystop) {
1817c478bd9Sstevel@tonic-gate 			case PR_SUSPENDED:
1827c478bd9Sstevel@tonic-gate 				if (t_susp == NULL)
1837c478bd9Sstevel@tonic-gate 					t_susp = t;
1847c478bd9Sstevel@tonic-gate 				break;
1857c478bd9Sstevel@tonic-gate 			case PR_JOBCONTROL:
1867c478bd9Sstevel@tonic-gate 				if (t->t_proc_flag & TP_PRSTOP) {
1877c478bd9Sstevel@tonic-gate 					if (t_jdstop == NULL)
1887c478bd9Sstevel@tonic-gate 						t_jdstop = t;
1897c478bd9Sstevel@tonic-gate 				} else {
1907c478bd9Sstevel@tonic-gate 					if (t_jstop == NULL)
1917c478bd9Sstevel@tonic-gate 						t_jstop = t;
1927c478bd9Sstevel@tonic-gate 				}
1937c478bd9Sstevel@tonic-gate 				break;
1947c478bd9Sstevel@tonic-gate 			case PR_REQUESTED:
1951959771bSJonathan Haslam 				if (t->t_dtrace_stop && t_dtrace == NULL)
1961959771bSJonathan Haslam 					t_dtrace = t;
1971959771bSJonathan Haslam 				else if (t_req == NULL)
1987c478bd9Sstevel@tonic-gate 					t_req = t;
1997c478bd9Sstevel@tonic-gate 				break;
2007c478bd9Sstevel@tonic-gate 			case PR_SYSENTRY:
2017c478bd9Sstevel@tonic-gate 			case PR_SYSEXIT:
2027c478bd9Sstevel@tonic-gate 			case PR_SIGNALLED:
2037c478bd9Sstevel@tonic-gate 			case PR_FAULTED:
2047c478bd9Sstevel@tonic-gate 				/*
2057c478bd9Sstevel@tonic-gate 				 * Make an lwp calling exit() be the
2067c478bd9Sstevel@tonic-gate 				 * last lwp seen in the process.
2077c478bd9Sstevel@tonic-gate 				 */
2087c478bd9Sstevel@tonic-gate 				if (t_istop == NULL ||
2097c478bd9Sstevel@tonic-gate 				    (t_istop->t_whystop == PR_SYSENTRY &&
2107c478bd9Sstevel@tonic-gate 				    t_istop->t_whatstop == SYS_exit))
2117c478bd9Sstevel@tonic-gate 					t_istop = t;
2127c478bd9Sstevel@tonic-gate 				break;
2137c478bd9Sstevel@tonic-gate 			case PR_CHECKPOINT:	/* can't happen? */
2147c478bd9Sstevel@tonic-gate 				break;
2157c478bd9Sstevel@tonic-gate 			default:
2167c478bd9Sstevel@tonic-gate 				panic("prchoose: bad t_whystop %d, thread 0x%p",
2177c478bd9Sstevel@tonic-gate 				    t->t_whystop, (void *)t);
2187c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
2197c478bd9Sstevel@tonic-gate 			}
2207c478bd9Sstevel@tonic-gate 			break;
2217c478bd9Sstevel@tonic-gate 		}
2227c478bd9Sstevel@tonic-gate 		thread_unlock(t);
2237c478bd9Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	if (t_onproc)
2267c478bd9Sstevel@tonic-gate 		t = t_onproc;
2277c478bd9Sstevel@tonic-gate 	else if (t_run)
2287c478bd9Sstevel@tonic-gate 		t = t_run;
2297c478bd9Sstevel@tonic-gate 	else if (t_sleep)
2307c478bd9Sstevel@tonic-gate 		t = t_sleep;
2317c478bd9Sstevel@tonic-gate 	else if (t_jstop)
2327c478bd9Sstevel@tonic-gate 		t = t_jstop;
2337c478bd9Sstevel@tonic-gate 	else if (t_jdstop)
2347c478bd9Sstevel@tonic-gate 		t = t_jdstop;
2357c478bd9Sstevel@tonic-gate 	else if (t_istop)
2367c478bd9Sstevel@tonic-gate 		t = t_istop;
2371959771bSJonathan Haslam 	else if (t_dtrace)
2381959771bSJonathan Haslam 		t = t_dtrace;
2397c478bd9Sstevel@tonic-gate 	else if (t_req)
2407c478bd9Sstevel@tonic-gate 		t = t_req;
2417c478bd9Sstevel@tonic-gate 	else if (t_hold)
2427c478bd9Sstevel@tonic-gate 		t = t_hold;
2437c478bd9Sstevel@tonic-gate 	else if (t_susp)
2447c478bd9Sstevel@tonic-gate 		t = t_susp;
2457c478bd9Sstevel@tonic-gate 	else			/* TS_ZOMB */
2467c478bd9Sstevel@tonic-gate 		t = p->p_tlist;
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	if (t != NULL)
2497c478bd9Sstevel@tonic-gate 		thread_lock(t);
2507c478bd9Sstevel@tonic-gate 	return (t);
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate /*
2547c478bd9Sstevel@tonic-gate  * Wakeup anyone sleeping on the /proc vnode for the process/lwp to stop.
2557c478bd9Sstevel@tonic-gate  * Also call pollwakeup() if any lwps are waiting in poll() for POLLPRI
2567c478bd9Sstevel@tonic-gate  * on the /proc file descriptor.  Called from stop() when a traced
2577c478bd9Sstevel@tonic-gate  * process stops on an event of interest.  Also called from exit()
2587c478bd9Sstevel@tonic-gate  * and prinvalidate() to indicate POLLHUP and POLLERR respectively.
2597c478bd9Sstevel@tonic-gate  */
2607c478bd9Sstevel@tonic-gate void
2617c478bd9Sstevel@tonic-gate prnotify(struct vnode *vp)
2627c478bd9Sstevel@tonic-gate {
2637c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = VTOP(vp)->pr_common;
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	mutex_enter(&pcp->prc_mutex);
2667c478bd9Sstevel@tonic-gate 	cv_broadcast(&pcp->prc_wait);
2677c478bd9Sstevel@tonic-gate 	mutex_exit(&pcp->prc_mutex);
2687c478bd9Sstevel@tonic-gate 	if (pcp->prc_flags & PRC_POLL) {
2697c478bd9Sstevel@tonic-gate 		/*
2707c478bd9Sstevel@tonic-gate 		 * We call pollwakeup() with POLLHUP to ensure that
2717c478bd9Sstevel@tonic-gate 		 * the pollers are awakened even if they are polling
2727c478bd9Sstevel@tonic-gate 		 * for nothing (i.e., waiting for the process to exit).
2737c478bd9Sstevel@tonic-gate 		 * This enables the use of the PRC_POLL flag for optimization
2747c478bd9Sstevel@tonic-gate 		 * (we can turn off PRC_POLL only if we know no pollers remain).
2757c478bd9Sstevel@tonic-gate 		 */
2767c478bd9Sstevel@tonic-gate 		pcp->prc_flags &= ~PRC_POLL;
2777c478bd9Sstevel@tonic-gate 		pollwakeup(&pcp->prc_pollhead, POLLHUP);
2787c478bd9Sstevel@tonic-gate 	}
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate /* called immediately below, in prfree() */
2827c478bd9Sstevel@tonic-gate static void
2837c478bd9Sstevel@tonic-gate prfreenotify(vnode_t *vp)
2847c478bd9Sstevel@tonic-gate {
2857c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
2867c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	while (vp != NULL) {
2897c478bd9Sstevel@tonic-gate 		pnp = VTOP(vp);
2907c478bd9Sstevel@tonic-gate 		pcp = pnp->pr_common;
2917c478bd9Sstevel@tonic-gate 		ASSERT(pcp->prc_thread == NULL);
2927c478bd9Sstevel@tonic-gate 		pcp->prc_proc = NULL;
2937c478bd9Sstevel@tonic-gate 		/*
2947c478bd9Sstevel@tonic-gate 		 * We can't call prnotify() here because we are holding
2957c478bd9Sstevel@tonic-gate 		 * pidlock.  We assert that there is no need to.
2967c478bd9Sstevel@tonic-gate 		 */
2977c478bd9Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
2987c478bd9Sstevel@tonic-gate 		cv_broadcast(&pcp->prc_wait);
2997c478bd9Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
3007c478bd9Sstevel@tonic-gate 		ASSERT(!(pcp->prc_flags & PRC_POLL));
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 		vp = pnp->pr_next;
3037c478bd9Sstevel@tonic-gate 		pnp->pr_next = NULL;
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate }
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate /*
3087c478bd9Sstevel@tonic-gate  * Called from a hook in freeproc() when a traced process is removed
3097c478bd9Sstevel@tonic-gate  * from the process table.  The proc-table pointers of all associated
3107c478bd9Sstevel@tonic-gate  * /proc vnodes are cleared to indicate that the process has gone away.
3117c478bd9Sstevel@tonic-gate  */
3127c478bd9Sstevel@tonic-gate void
3137c478bd9Sstevel@tonic-gate prfree(proc_t *p)
3147c478bd9Sstevel@tonic-gate {
3157c478bd9Sstevel@tonic-gate 	uint_t slot = p->p_slot;
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock));
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	/*
3207c478bd9Sstevel@tonic-gate 	 * Block the process against /proc so it can be freed.
3217c478bd9Sstevel@tonic-gate 	 * It cannot be freed while locked by some controlling process.
3227c478bd9Sstevel@tonic-gate 	 * Lock ordering:
3237c478bd9Sstevel@tonic-gate 	 *	pidlock -> pr_pidlock -> p->p_lock -> pcp->prc_mutex
3247c478bd9Sstevel@tonic-gate 	 */
3257c478bd9Sstevel@tonic-gate 	mutex_enter(&pr_pidlock);	/* protects pcp->prc_proc */
3267c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
3277c478bd9Sstevel@tonic-gate 	while (p->p_proc_flag & P_PR_LOCK) {
3287c478bd9Sstevel@tonic-gate 		mutex_exit(&pr_pidlock);
3297c478bd9Sstevel@tonic-gate 		cv_wait(&pr_pid_cv[slot], &p->p_lock);
3307c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
3317c478bd9Sstevel@tonic-gate 		mutex_enter(&pr_pidlock);
3327c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
3337c478bd9Sstevel@tonic-gate 	}
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	ASSERT(p->p_tlist == NULL);
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	prfreenotify(p->p_plist);
3387c478bd9Sstevel@tonic-gate 	p->p_plist = NULL;
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	prfreenotify(p->p_trace);
3417c478bd9Sstevel@tonic-gate 	p->p_trace = NULL;
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	/*
3447c478bd9Sstevel@tonic-gate 	 * We broadcast to wake up everyone waiting for this process.
3457c478bd9Sstevel@tonic-gate 	 * No one can reach this process from this point on.
3467c478bd9Sstevel@tonic-gate 	 */
3477c478bd9Sstevel@tonic-gate 	cv_broadcast(&pr_pid_cv[slot]);
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
3507c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate /*
3547c478bd9Sstevel@tonic-gate  * Called from a hook in exit() when a traced process is becoming a zombie.
3557c478bd9Sstevel@tonic-gate  */
3567c478bd9Sstevel@tonic-gate void
3577c478bd9Sstevel@tonic-gate prexit(proc_t *p)
3587c478bd9Sstevel@tonic-gate {
3597c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	if (pr_watch_active(p)) {
3627c478bd9Sstevel@tonic-gate 		pr_free_watchpoints(p);
3637c478bd9Sstevel@tonic-gate 		watch_disable(curthread);
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 	/* pr_free_watched_pages() is called in exit(), after dropping p_lock */
3667c478bd9Sstevel@tonic-gate 	if (p->p_trace) {
3677c478bd9Sstevel@tonic-gate 		VTOP(p->p_trace)->pr_common->prc_flags |= PRC_DESTROY;
3687c478bd9Sstevel@tonic-gate 		prnotify(p->p_trace);
3697c478bd9Sstevel@tonic-gate 	}
3707c478bd9Sstevel@tonic-gate 	cv_broadcast(&pr_pid_cv[p->p_slot]);	/* pauselwps() */
3717c478bd9Sstevel@tonic-gate }
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate /*
3747c478bd9Sstevel@tonic-gate  * Called when a thread calls lwp_exit().
3757c478bd9Sstevel@tonic-gate  */
3767c478bd9Sstevel@tonic-gate void
3777c478bd9Sstevel@tonic-gate prlwpexit(kthread_t *t)
3787c478bd9Sstevel@tonic-gate {
3797c478bd9Sstevel@tonic-gate 	vnode_t *vp;
3807c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
3817c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
3827c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(t);
3837c478bd9Sstevel@tonic-gate 	lwpent_t *lep = p->p_lwpdir[t->t_dslot].ld_entry;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	ASSERT(t == curthread);
3867c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	/*
3897c478bd9Sstevel@tonic-gate 	 * The process must be blocked against /proc to do this safely.
3907c478bd9Sstevel@tonic-gate 	 * The lwp must not disappear while the process is marked P_PR_LOCK.
3917c478bd9Sstevel@tonic-gate 	 * It is the caller's responsibility to have called prbarrier(p).
3927c478bd9Sstevel@tonic-gate 	 */
3937c478bd9Sstevel@tonic-gate 	ASSERT(!(p->p_proc_flag & P_PR_LOCK));
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	for (vp = p->p_plist; vp != NULL; vp = pnp->pr_next) {
3967c478bd9Sstevel@tonic-gate 		pnp = VTOP(vp);
3977c478bd9Sstevel@tonic-gate 		pcp = pnp->pr_common;
3987c478bd9Sstevel@tonic-gate 		if (pcp->prc_thread == t) {
3997c478bd9Sstevel@tonic-gate 			pcp->prc_thread = NULL;
4007c478bd9Sstevel@tonic-gate 			pcp->prc_flags |= PRC_DESTROY;
4017c478bd9Sstevel@tonic-gate 		}
4027c478bd9Sstevel@tonic-gate 	}
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	for (vp = lep->le_trace; vp != NULL; vp = pnp->pr_next) {
4057c478bd9Sstevel@tonic-gate 		pnp = VTOP(vp);
4067c478bd9Sstevel@tonic-gate 		pcp = pnp->pr_common;
4077c478bd9Sstevel@tonic-gate 		pcp->prc_thread = NULL;
4087c478bd9Sstevel@tonic-gate 		pcp->prc_flags |= PRC_DESTROY;
4097c478bd9Sstevel@tonic-gate 		prnotify(vp);
4107c478bd9Sstevel@tonic-gate 	}
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	if (p->p_trace)
4137c478bd9Sstevel@tonic-gate 		prnotify(p->p_trace);
4147c478bd9Sstevel@tonic-gate }
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate /*
4177c478bd9Sstevel@tonic-gate  * Called when a zombie thread is joined or when a
4187c478bd9Sstevel@tonic-gate  * detached lwp exits.  Called from lwp_hash_out().
4197c478bd9Sstevel@tonic-gate  */
4207c478bd9Sstevel@tonic-gate void
4217c478bd9Sstevel@tonic-gate prlwpfree(proc_t *p, lwpent_t *lep)
4227c478bd9Sstevel@tonic-gate {
4237c478bd9Sstevel@tonic-gate 	vnode_t *vp;
4247c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
4257c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	/*
4307c478bd9Sstevel@tonic-gate 	 * The process must be blocked against /proc to do this safely.
4317c478bd9Sstevel@tonic-gate 	 * The lwp must not disappear while the process is marked P_PR_LOCK.
4327c478bd9Sstevel@tonic-gate 	 * It is the caller's responsibility to have called prbarrier(p).
4337c478bd9Sstevel@tonic-gate 	 */
4347c478bd9Sstevel@tonic-gate 	ASSERT(!(p->p_proc_flag & P_PR_LOCK));
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	vp = lep->le_trace;
4377c478bd9Sstevel@tonic-gate 	lep->le_trace = NULL;
4387c478bd9Sstevel@tonic-gate 	while (vp) {
4397c478bd9Sstevel@tonic-gate 		prnotify(vp);
4407c478bd9Sstevel@tonic-gate 		pnp = VTOP(vp);
4417c478bd9Sstevel@tonic-gate 		pcp = pnp->pr_common;
4427c478bd9Sstevel@tonic-gate 		ASSERT(pcp->prc_thread == NULL &&
4437c478bd9Sstevel@tonic-gate 		    (pcp->prc_flags & PRC_DESTROY));
4447c478bd9Sstevel@tonic-gate 		pcp->prc_tslot = -1;
4457c478bd9Sstevel@tonic-gate 		vp = pnp->pr_next;
4467c478bd9Sstevel@tonic-gate 		pnp->pr_next = NULL;
4477c478bd9Sstevel@tonic-gate 	}
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	if (p->p_trace)
4507c478bd9Sstevel@tonic-gate 		prnotify(p->p_trace);
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate /*
4547c478bd9Sstevel@tonic-gate  * Called from a hook in exec() when a thread starts exec().
4557c478bd9Sstevel@tonic-gate  */
4567c478bd9Sstevel@tonic-gate void
4577c478bd9Sstevel@tonic-gate prexecstart(void)
4587c478bd9Sstevel@tonic-gate {
4597c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
4607c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	/*
4637c478bd9Sstevel@tonic-gate 	 * The P_PR_EXEC flag blocks /proc operations for
4647c478bd9Sstevel@tonic-gate 	 * the duration of the exec().
4657c478bd9Sstevel@tonic-gate 	 * We can't start exec() while the process is
4667c478bd9Sstevel@tonic-gate 	 * locked by /proc, so we call prbarrier().
4677c478bd9Sstevel@tonic-gate 	 * lwp_nostop keeps the process from being stopped
4687c478bd9Sstevel@tonic-gate 	 * via job control for the duration of the exec().
4697c478bd9Sstevel@tonic-gate 	 */
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
4727c478bd9Sstevel@tonic-gate 	prbarrier(p);
4737c478bd9Sstevel@tonic-gate 	lwp->lwp_nostop++;
4747c478bd9Sstevel@tonic-gate 	p->p_proc_flag |= P_PR_EXEC;
4757c478bd9Sstevel@tonic-gate }
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate /*
4787c478bd9Sstevel@tonic-gate  * Called from a hook in exec() when a thread finishes exec().
4797c478bd9Sstevel@tonic-gate  * The thread may or may not have succeeded.  Some other thread
4807c478bd9Sstevel@tonic-gate  * may have beat it to the punch.
4817c478bd9Sstevel@tonic-gate  */
4827c478bd9Sstevel@tonic-gate void
4837c478bd9Sstevel@tonic-gate prexecend(void)
4847c478bd9Sstevel@tonic-gate {
4857c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
4867c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
4877c478bd9Sstevel@tonic-gate 	vnode_t *vp;
4887c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
4897c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
4907c478bd9Sstevel@tonic-gate 	model_t model = p->p_model;
4917c478bd9Sstevel@tonic-gate 	id_t tid = curthread->t_tid;
4927c478bd9Sstevel@tonic-gate 	int tslot = curthread->t_dslot;
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	lwp->lwp_nostop--;
4977c478bd9Sstevel@tonic-gate 	if (p->p_flag & SEXITLWPS) {
4987c478bd9Sstevel@tonic-gate 		/*
4997c478bd9Sstevel@tonic-gate 		 * We are on our way to exiting because some
5007c478bd9Sstevel@tonic-gate 		 * other thread beat us in the race to exec().
5017c478bd9Sstevel@tonic-gate 		 * Don't clear the P_PR_EXEC flag in this case.
5027c478bd9Sstevel@tonic-gate 		 */
5037c478bd9Sstevel@tonic-gate 		return;
5047c478bd9Sstevel@tonic-gate 	}
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	/*
5077c478bd9Sstevel@tonic-gate 	 * Wake up anyone waiting in /proc for the process to complete exec().
5087c478bd9Sstevel@tonic-gate 	 */
5097c478bd9Sstevel@tonic-gate 	p->p_proc_flag &= ~P_PR_EXEC;
5107c478bd9Sstevel@tonic-gate 	if ((vp = p->p_trace) != NULL) {
5117c478bd9Sstevel@tonic-gate 		pcp = VTOP(vp)->pr_common;
5127c478bd9Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
5137c478bd9Sstevel@tonic-gate 		cv_broadcast(&pcp->prc_wait);
5147c478bd9Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
5157c478bd9Sstevel@tonic-gate 		for (; vp != NULL; vp = pnp->pr_next) {
5167c478bd9Sstevel@tonic-gate 			pnp = VTOP(vp);
5177c478bd9Sstevel@tonic-gate 			pnp->pr_common->prc_datamodel = model;
5187c478bd9Sstevel@tonic-gate 		}
5197c478bd9Sstevel@tonic-gate 	}
5207c478bd9Sstevel@tonic-gate 	if ((vp = p->p_lwpdir[tslot].ld_entry->le_trace) != NULL) {
5217c478bd9Sstevel@tonic-gate 		/*
5227c478bd9Sstevel@tonic-gate 		 * We dealt with the process common above.
5237c478bd9Sstevel@tonic-gate 		 */
5247c478bd9Sstevel@tonic-gate 		ASSERT(p->p_trace != NULL);
5257c478bd9Sstevel@tonic-gate 		pcp = VTOP(vp)->pr_common;
5267c478bd9Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
5277c478bd9Sstevel@tonic-gate 		cv_broadcast(&pcp->prc_wait);
5287c478bd9Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
5297c478bd9Sstevel@tonic-gate 		for (; vp != NULL; vp = pnp->pr_next) {
5307c478bd9Sstevel@tonic-gate 			pnp = VTOP(vp);
5317c478bd9Sstevel@tonic-gate 			pcp = pnp->pr_common;
5327c478bd9Sstevel@tonic-gate 			pcp->prc_datamodel = model;
5337c478bd9Sstevel@tonic-gate 			pcp->prc_tid = tid;
5347c478bd9Sstevel@tonic-gate 			pcp->prc_tslot = tslot;
5357c478bd9Sstevel@tonic-gate 		}
5367c478bd9Sstevel@tonic-gate 	}
5377c478bd9Sstevel@tonic-gate }
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate /*
5407c478bd9Sstevel@tonic-gate  * Called from a hook in relvm() just before freeing the address space.
5417c478bd9Sstevel@tonic-gate  * We free all the watched areas now.
5427c478bd9Sstevel@tonic-gate  */
5437c478bd9Sstevel@tonic-gate void
5447c478bd9Sstevel@tonic-gate prrelvm(void)
5457c478bd9Sstevel@tonic-gate {
5467c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
5497c478bd9Sstevel@tonic-gate 	prbarrier(p);	/* block all other /proc operations */
5507c478bd9Sstevel@tonic-gate 	if (pr_watch_active(p)) {
5517c478bd9Sstevel@tonic-gate 		pr_free_watchpoints(p);
5527c478bd9Sstevel@tonic-gate 		watch_disable(curthread);
5537c478bd9Sstevel@tonic-gate 	}
5547c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
5557c478bd9Sstevel@tonic-gate 	pr_free_watched_pages(p);
5567c478bd9Sstevel@tonic-gate }
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate /*
5597c478bd9Sstevel@tonic-gate  * Called from hooks in exec-related code when a traced process
5607c478bd9Sstevel@tonic-gate  * attempts to exec(2) a setuid/setgid program or an unreadable
5617c478bd9Sstevel@tonic-gate  * file.  Rather than fail the exec we invalidate the associated
5627c478bd9Sstevel@tonic-gate  * /proc vnodes so that subsequent attempts to use them will fail.
5637c478bd9Sstevel@tonic-gate  *
5647c478bd9Sstevel@tonic-gate  * All /proc vnodes, except directory vnodes, are retained on a linked
5657c478bd9Sstevel@tonic-gate  * list (rooted at p_plist in the process structure) until last close.
5667c478bd9Sstevel@tonic-gate  *
5677c478bd9Sstevel@tonic-gate  * A controlling process must re-open the /proc files in order to
5687c478bd9Sstevel@tonic-gate  * regain control.
5697c478bd9Sstevel@tonic-gate  */
5707c478bd9Sstevel@tonic-gate void
5717c478bd9Sstevel@tonic-gate prinvalidate(struct user *up)
5727c478bd9Sstevel@tonic-gate {
5737c478bd9Sstevel@tonic-gate 	kthread_t *t = curthread;
5747c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(t);
5757c478bd9Sstevel@tonic-gate 	vnode_t *vp;
5767c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
5777c478bd9Sstevel@tonic-gate 	int writers = 0;
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
5807c478bd9Sstevel@tonic-gate 	prbarrier(p);	/* block all other /proc operations */
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	/*
5837c478bd9Sstevel@tonic-gate 	 * At this moment, there can be only one lwp in the process.
5847c478bd9Sstevel@tonic-gate 	 */
5857c478bd9Sstevel@tonic-gate 	ASSERT(p->p_lwpcnt == 1 && p->p_zombcnt == 0);
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	/*
5887c478bd9Sstevel@tonic-gate 	 * Invalidate any currently active /proc vnodes.
5897c478bd9Sstevel@tonic-gate 	 */
5907c478bd9Sstevel@tonic-gate 	for (vp = p->p_plist; vp != NULL; vp = pnp->pr_next) {
5917c478bd9Sstevel@tonic-gate 		pnp = VTOP(vp);
5927c478bd9Sstevel@tonic-gate 		switch (pnp->pr_type) {
5937c478bd9Sstevel@tonic-gate 		case PR_PSINFO:		/* these files can read by anyone */
5947c478bd9Sstevel@tonic-gate 		case PR_LPSINFO:
5957c478bd9Sstevel@tonic-gate 		case PR_LWPSINFO:
5967c478bd9Sstevel@tonic-gate 		case PR_LWPDIR:
5977c478bd9Sstevel@tonic-gate 		case PR_LWPIDDIR:
5987c478bd9Sstevel@tonic-gate 		case PR_USAGE:
5997c478bd9Sstevel@tonic-gate 		case PR_LUSAGE:
6007c478bd9Sstevel@tonic-gate 		case PR_LWPUSAGE:
6017c478bd9Sstevel@tonic-gate 			break;
6027c478bd9Sstevel@tonic-gate 		default:
6037c478bd9Sstevel@tonic-gate 			pnp->pr_flags |= PR_INVAL;
6047c478bd9Sstevel@tonic-gate 			break;
6057c478bd9Sstevel@tonic-gate 		}
6067c478bd9Sstevel@tonic-gate 	}
6077c478bd9Sstevel@tonic-gate 	/*
6087c478bd9Sstevel@tonic-gate 	 * Wake up anyone waiting for the process or lwp.
6097c478bd9Sstevel@tonic-gate 	 * p->p_trace is guaranteed to be non-NULL if there
6107c478bd9Sstevel@tonic-gate 	 * are any open /proc files for this process.
6117c478bd9Sstevel@tonic-gate 	 */
6127c478bd9Sstevel@tonic-gate 	if ((vp = p->p_trace) != NULL) {
6137c478bd9Sstevel@tonic-gate 		prcommon_t *pcp = VTOP(vp)->pr_pcommon;
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 		prnotify(vp);
6167c478bd9Sstevel@tonic-gate 		/*
6177c478bd9Sstevel@tonic-gate 		 * Are there any writers?
6187c478bd9Sstevel@tonic-gate 		 */
6197c478bd9Sstevel@tonic-gate 		if ((writers = pcp->prc_writers) != 0) {
6207c478bd9Sstevel@tonic-gate 			/*
6217c478bd9Sstevel@tonic-gate 			 * Clear the exclusive open flag (old /proc interface).
6227c478bd9Sstevel@tonic-gate 			 * Set prc_selfopens equal to prc_writers so that
6237c478bd9Sstevel@tonic-gate 			 * the next O_EXCL|O_WRITE open will succeed
6247c478bd9Sstevel@tonic-gate 			 * even with existing (though invalid) writers.
6257c478bd9Sstevel@tonic-gate 			 * prclose() must decrement prc_selfopens when
6267c478bd9Sstevel@tonic-gate 			 * the invalid files are closed.
6277c478bd9Sstevel@tonic-gate 			 */
6287c478bd9Sstevel@tonic-gate 			pcp->prc_flags &= ~PRC_EXCL;
6297c478bd9Sstevel@tonic-gate 			ASSERT(pcp->prc_selfopens <= writers);
6307c478bd9Sstevel@tonic-gate 			pcp->prc_selfopens = writers;
6317c478bd9Sstevel@tonic-gate 		}
6327c478bd9Sstevel@tonic-gate 	}
6337c478bd9Sstevel@tonic-gate 	vp = p->p_lwpdir[t->t_dslot].ld_entry->le_trace;
6347c478bd9Sstevel@tonic-gate 	while (vp != NULL) {
6357c478bd9Sstevel@tonic-gate 		/*
6367c478bd9Sstevel@tonic-gate 		 * We should not invalidate the lwpiddir vnodes,
6377c478bd9Sstevel@tonic-gate 		 * but the necessities of maintaining the old
6387c478bd9Sstevel@tonic-gate 		 * ioctl()-based version of /proc require it.
6397c478bd9Sstevel@tonic-gate 		 */
6407c478bd9Sstevel@tonic-gate 		pnp = VTOP(vp);
6417c478bd9Sstevel@tonic-gate 		pnp->pr_flags |= PR_INVAL;
6427c478bd9Sstevel@tonic-gate 		prnotify(vp);
6437c478bd9Sstevel@tonic-gate 		vp = pnp->pr_next;
6447c478bd9Sstevel@tonic-gate 	}
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	/*
6477c478bd9Sstevel@tonic-gate 	 * If any tracing flags are in effect and any vnodes are open for
6487c478bd9Sstevel@tonic-gate 	 * writing then set the requested-stop and run-on-last-close flags.
6497c478bd9Sstevel@tonic-gate 	 * Otherwise, clear all tracing flags.
6507c478bd9Sstevel@tonic-gate 	 */
6517c478bd9Sstevel@tonic-gate 	t->t_proc_flag &= ~TP_PAUSE;
6527c478bd9Sstevel@tonic-gate 	if ((p->p_proc_flag & P_PR_TRACE) && writers) {
6537c478bd9Sstevel@tonic-gate 		t->t_proc_flag |= TP_PRSTOP;
6547c478bd9Sstevel@tonic-gate 		aston(t);		/* so ISSIG will see the flag */
6557c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_RUNLCL;
6567c478bd9Sstevel@tonic-gate 	} else {
6577c478bd9Sstevel@tonic-gate 		premptyset(&up->u_entrymask);		/* syscalls */
6587c478bd9Sstevel@tonic-gate 		premptyset(&up->u_exitmask);
6597c478bd9Sstevel@tonic-gate 		up->u_systrap = 0;
6607c478bd9Sstevel@tonic-gate 		premptyset(&p->p_sigmask);		/* signals */
6617c478bd9Sstevel@tonic-gate 		premptyset(&p->p_fltmask);		/* faults */
6627c478bd9Sstevel@tonic-gate 		t->t_proc_flag &= ~(TP_PRSTOP|TP_PRVSTOP|TP_STOPPING);
6637c478bd9Sstevel@tonic-gate 		p->p_proc_flag &= ~(P_PR_RUNLCL|P_PR_KILLCL|P_PR_TRACE);
6647c478bd9Sstevel@tonic-gate 		prnostep(ttolwp(t));
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
6687c478bd9Sstevel@tonic-gate }
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate /*
6717c478bd9Sstevel@tonic-gate  * Acquire the controlled process's p_lock and mark it P_PR_LOCK.
6727c478bd9Sstevel@tonic-gate  * Return with pr_pidlock held in all cases.
6737c478bd9Sstevel@tonic-gate  * Return with p_lock held if the the process still exists.
6747c478bd9Sstevel@tonic-gate  * Return value is the process pointer if the process still exists, else NULL.
6757c478bd9Sstevel@tonic-gate  * If we lock the process, give ourself kernel priority to avoid deadlocks;
6767c478bd9Sstevel@tonic-gate  * this is undone in prunlock().
6777c478bd9Sstevel@tonic-gate  */
6787c478bd9Sstevel@tonic-gate proc_t *
6797c478bd9Sstevel@tonic-gate pr_p_lock(prnode_t *pnp)
6807c478bd9Sstevel@tonic-gate {
6817c478bd9Sstevel@tonic-gate 	proc_t *p;
6827c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	mutex_enter(&pr_pidlock);
6857c478bd9Sstevel@tonic-gate 	if ((pcp = pnp->pr_pcommon) == NULL || (p = pcp->prc_proc) == NULL)
6867c478bd9Sstevel@tonic-gate 		return (NULL);
6877c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
6887c478bd9Sstevel@tonic-gate 	while (p->p_proc_flag & P_PR_LOCK) {
6897c478bd9Sstevel@tonic-gate 		/*
6907c478bd9Sstevel@tonic-gate 		 * This cv/mutex pair is persistent even if
6917c478bd9Sstevel@tonic-gate 		 * the process disappears while we sleep.
6927c478bd9Sstevel@tonic-gate 		 */
6937c478bd9Sstevel@tonic-gate 		kcondvar_t *cv = &pr_pid_cv[p->p_slot];
6947c478bd9Sstevel@tonic-gate 		kmutex_t *mp = &p->p_lock;
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 		mutex_exit(&pr_pidlock);
6977c478bd9Sstevel@tonic-gate 		cv_wait(cv, mp);
6987c478bd9Sstevel@tonic-gate 		mutex_exit(mp);
6997c478bd9Sstevel@tonic-gate 		mutex_enter(&pr_pidlock);
7007c478bd9Sstevel@tonic-gate 		if (pcp->prc_proc == NULL)
7017c478bd9Sstevel@tonic-gate 			return (NULL);
7027c478bd9Sstevel@tonic-gate 		ASSERT(p == pcp->prc_proc);
7037c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
7047c478bd9Sstevel@tonic-gate 	}
7057c478bd9Sstevel@tonic-gate 	p->p_proc_flag |= P_PR_LOCK;
7067c478bd9Sstevel@tonic-gate 	return (p);
7077c478bd9Sstevel@tonic-gate }
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate /*
7107c478bd9Sstevel@tonic-gate  * Lock the target process by setting P_PR_LOCK and grabbing p->p_lock.
7117c478bd9Sstevel@tonic-gate  * This prevents any lwp of the process from disappearing and
7127c478bd9Sstevel@tonic-gate  * blocks most operations that a process can perform on itself.
7137c478bd9Sstevel@tonic-gate  * Returns 0 on success, a non-zero error number on failure.
7147c478bd9Sstevel@tonic-gate  *
7157c478bd9Sstevel@tonic-gate  * 'zdisp' is ZYES or ZNO to indicate whether prlock() should succeed when
7167c478bd9Sstevel@tonic-gate  * the subject process is a zombie (ZYES) or fail for zombies (ZNO).
7177c478bd9Sstevel@tonic-gate  *
7187c478bd9Sstevel@tonic-gate  * error returns:
7197c478bd9Sstevel@tonic-gate  *	ENOENT: process or lwp has disappeared or process is exiting
7207c478bd9Sstevel@tonic-gate  *		(or has become a zombie and zdisp == ZNO).
7217c478bd9Sstevel@tonic-gate  *	EAGAIN: procfs vnode has become invalid.
7227c478bd9Sstevel@tonic-gate  *	EINTR:  signal arrived while waiting for exec to complete.
7237c478bd9Sstevel@tonic-gate  */
7247c478bd9Sstevel@tonic-gate int
7257c478bd9Sstevel@tonic-gate prlock(prnode_t *pnp, int zdisp)
7267c478bd9Sstevel@tonic-gate {
7277c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
7287c478bd9Sstevel@tonic-gate 	proc_t *p;
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate again:
7317c478bd9Sstevel@tonic-gate 	pcp = pnp->pr_common;
7327c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
7337c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	/*
7367c478bd9Sstevel@tonic-gate 	 * Return ENOENT immediately if there is no process.
7377c478bd9Sstevel@tonic-gate 	 */
7387c478bd9Sstevel@tonic-gate 	if (p == NULL)
7397c478bd9Sstevel@tonic-gate 		return (ENOENT);
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	ASSERT(p == pcp->prc_proc && p->p_stat != 0 && p->p_stat != SIDL);
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 	/*
7447c478bd9Sstevel@tonic-gate 	 * Return ENOENT if process entered zombie state or is exiting
7457c478bd9Sstevel@tonic-gate 	 * and the 'zdisp' flag is set to ZNO indicating not to lock zombies.
7467c478bd9Sstevel@tonic-gate 	 */
7477c478bd9Sstevel@tonic-gate 	if (zdisp == ZNO &&
74897eda132Sraf 	    ((pcp->prc_flags & PRC_DESTROY) || (p->p_flag & SEXITING))) {
7497c478bd9Sstevel@tonic-gate 		prunlock(pnp);
7507c478bd9Sstevel@tonic-gate 		return (ENOENT);
7517c478bd9Sstevel@tonic-gate 	}
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 	/*
7547c478bd9Sstevel@tonic-gate 	 * If lwp-specific, check to see if lwp has disappeared.
7557c478bd9Sstevel@tonic-gate 	 */
7567c478bd9Sstevel@tonic-gate 	if (pcp->prc_flags & PRC_LWP) {
7577c478bd9Sstevel@tonic-gate 		if ((zdisp == ZNO && (pcp->prc_flags & PRC_DESTROY)) ||
7587c478bd9Sstevel@tonic-gate 		    pcp->prc_tslot == -1) {
7597c478bd9Sstevel@tonic-gate 			prunlock(pnp);
7607c478bd9Sstevel@tonic-gate 			return (ENOENT);
7617c478bd9Sstevel@tonic-gate 		}
7627c478bd9Sstevel@tonic-gate 	}
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 	/*
7657c478bd9Sstevel@tonic-gate 	 * Return EAGAIN if we have encountered a security violation.
7667c478bd9Sstevel@tonic-gate 	 * (The process exec'd a set-id or unreadable executable file.)
7677c478bd9Sstevel@tonic-gate 	 */
7687c478bd9Sstevel@tonic-gate 	if (pnp->pr_flags & PR_INVAL) {
7697c478bd9Sstevel@tonic-gate 		prunlock(pnp);
7707c478bd9Sstevel@tonic-gate 		return (EAGAIN);
7717c478bd9Sstevel@tonic-gate 	}
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	/*
7747c478bd9Sstevel@tonic-gate 	 * If process is undergoing an exec(), wait for
7757c478bd9Sstevel@tonic-gate 	 * completion and then start all over again.
7767c478bd9Sstevel@tonic-gate 	 */
7777c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_EXEC) {
7787c478bd9Sstevel@tonic-gate 		pcp = pnp->pr_pcommon;	/* Put on the correct sleep queue */
7797c478bd9Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
7807c478bd9Sstevel@tonic-gate 		prunlock(pnp);
7817c478bd9Sstevel@tonic-gate 		if (!cv_wait_sig(&pcp->prc_wait, &pcp->prc_mutex)) {
7827c478bd9Sstevel@tonic-gate 			mutex_exit(&pcp->prc_mutex);
7837c478bd9Sstevel@tonic-gate 			return (EINTR);
7847c478bd9Sstevel@tonic-gate 		}
7857c478bd9Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
7867c478bd9Sstevel@tonic-gate 		goto again;
7877c478bd9Sstevel@tonic-gate 	}
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 	/*
7907c478bd9Sstevel@tonic-gate 	 * We return holding p->p_lock.
7917c478bd9Sstevel@tonic-gate 	 */
7927c478bd9Sstevel@tonic-gate 	return (0);
7937c478bd9Sstevel@tonic-gate }
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate /*
7967c478bd9Sstevel@tonic-gate  * Undo prlock() and pr_p_lock().
7977c478bd9Sstevel@tonic-gate  * p->p_lock is still held; pr_pidlock is no longer held.
7987c478bd9Sstevel@tonic-gate  *
7997c478bd9Sstevel@tonic-gate  * prunmark() drops the P_PR_LOCK flag and wakes up another thread,
8007c478bd9Sstevel@tonic-gate  * if any, waiting for the flag to be dropped; it retains p->p_lock.
8017c478bd9Sstevel@tonic-gate  *
8027c478bd9Sstevel@tonic-gate  * prunlock() calls prunmark() and then drops p->p_lock.
8037c478bd9Sstevel@tonic-gate  */
8047c478bd9Sstevel@tonic-gate void
8057c478bd9Sstevel@tonic-gate prunmark(proc_t *p)
8067c478bd9Sstevel@tonic-gate {
8077c478bd9Sstevel@tonic-gate 	ASSERT(p->p_proc_flag & P_PR_LOCK);
8087c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	cv_signal(&pr_pid_cv[p->p_slot]);
8117c478bd9Sstevel@tonic-gate 	p->p_proc_flag &= ~P_PR_LOCK;
8127c478bd9Sstevel@tonic-gate }
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate void
8157c478bd9Sstevel@tonic-gate prunlock(prnode_t *pnp)
8167c478bd9Sstevel@tonic-gate {
8177c1a8fa4Sraf 	prcommon_t *pcp = pnp->pr_common;
8187c1a8fa4Sraf 	proc_t *p = pcp->prc_proc;
8197c478bd9Sstevel@tonic-gate 
8207c1a8fa4Sraf 	/*
8217c1a8fa4Sraf 	 * If we (or someone) gave it a SIGKILL, and it is not
8227c1a8fa4Sraf 	 * already a zombie, set it running unconditionally.
8237c1a8fa4Sraf 	 */
8247c1a8fa4Sraf 	if ((p->p_flag & SKILLED) &&
8257c1a8fa4Sraf 	    !(p->p_flag & SEXITING) &&
8267c1a8fa4Sraf 	    !(pcp->prc_flags & PRC_DESTROY) &&
8277c1a8fa4Sraf 	    !((pcp->prc_flags & PRC_LWP) && pcp->prc_tslot == -1))
8287c1a8fa4Sraf 		(void) pr_setrun(pnp, 0);
8297c478bd9Sstevel@tonic-gate 	prunmark(p);
8307c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
8317c478bd9Sstevel@tonic-gate }
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate /*
8347c478bd9Sstevel@tonic-gate  * Called while holding p->p_lock to delay until the process is unlocked.
8357c478bd9Sstevel@tonic-gate  * We enter holding p->p_lock; p->p_lock is dropped and reacquired.
8367c478bd9Sstevel@tonic-gate  * The process cannot become locked again until p->p_lock is dropped.
8377c478bd9Sstevel@tonic-gate  */
8387c478bd9Sstevel@tonic-gate void
8397c478bd9Sstevel@tonic-gate prbarrier(proc_t *p)
8407c478bd9Sstevel@tonic-gate {
8417c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_LOCK) {
8447c478bd9Sstevel@tonic-gate 		/* The process is locked; delay until not locked */
8457c478bd9Sstevel@tonic-gate 		uint_t slot = p->p_slot;
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 		while (p->p_proc_flag & P_PR_LOCK)
8487c478bd9Sstevel@tonic-gate 			cv_wait(&pr_pid_cv[slot], &p->p_lock);
8497c478bd9Sstevel@tonic-gate 		cv_signal(&pr_pid_cv[slot]);
8507c478bd9Sstevel@tonic-gate 	}
8517c478bd9Sstevel@tonic-gate }
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate /*
8547c478bd9Sstevel@tonic-gate  * Return process/lwp status.
8557c478bd9Sstevel@tonic-gate  * The u-block is mapped in by this routine and unmapped at the end.
8567c478bd9Sstevel@tonic-gate  */
8577c478bd9Sstevel@tonic-gate void
8587c478bd9Sstevel@tonic-gate prgetstatus(proc_t *p, pstatus_t *sp, zone_t *zp)
8597c478bd9Sstevel@tonic-gate {
8607c478bd9Sstevel@tonic-gate 	kthread_t *t;
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	t = prchoose(p);	/* returns locked thread */
8657c478bd9Sstevel@tonic-gate 	ASSERT(t != NULL);
8667c478bd9Sstevel@tonic-gate 	thread_unlock(t);
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	/* just bzero the process part, prgetlwpstatus() does the rest */
8697c478bd9Sstevel@tonic-gate 	bzero(sp, sizeof (pstatus_t) - sizeof (lwpstatus_t));
8707c478bd9Sstevel@tonic-gate 	sp->pr_nlwp = p->p_lwpcnt;
8717c478bd9Sstevel@tonic-gate 	sp->pr_nzomb = p->p_zombcnt;
8727c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_sigpend, &p->p_sig);
8737c478bd9Sstevel@tonic-gate 	sp->pr_brkbase = (uintptr_t)p->p_brkbase;
8747c478bd9Sstevel@tonic-gate 	sp->pr_brksize = p->p_brksize;
8757c478bd9Sstevel@tonic-gate 	sp->pr_stkbase = (uintptr_t)prgetstackbase(p);
8767c478bd9Sstevel@tonic-gate 	sp->pr_stksize = p->p_stksize;
8777c478bd9Sstevel@tonic-gate 	sp->pr_pid = p->p_pid;
8787c478bd9Sstevel@tonic-gate 	if (curproc->p_zone->zone_id != GLOBAL_ZONEID &&
8797c478bd9Sstevel@tonic-gate 	    (p->p_flag & SZONETOP)) {
8807c478bd9Sstevel@tonic-gate 		ASSERT(p->p_zone->zone_id != GLOBAL_ZONEID);
8817c478bd9Sstevel@tonic-gate 		/*
8827c478bd9Sstevel@tonic-gate 		 * Inside local zones, fake zsched's pid as parent pids for
8837c478bd9Sstevel@tonic-gate 		 * processes which reference processes outside of the zone.
8847c478bd9Sstevel@tonic-gate 		 */
8857c478bd9Sstevel@tonic-gate 		sp->pr_ppid = curproc->p_zone->zone_zsched->p_pid;
8867c478bd9Sstevel@tonic-gate 	} else {
8877c478bd9Sstevel@tonic-gate 		sp->pr_ppid = p->p_ppid;
8887c478bd9Sstevel@tonic-gate 	}
8897c478bd9Sstevel@tonic-gate 	sp->pr_pgid  = p->p_pgrp;
8907c478bd9Sstevel@tonic-gate 	sp->pr_sid   = p->p_sessp->s_sid;
8917c478bd9Sstevel@tonic-gate 	sp->pr_taskid = p->p_task->tk_tkid;
8927c478bd9Sstevel@tonic-gate 	sp->pr_projid = p->p_task->tk_proj->kpj_id;
8937c478bd9Sstevel@tonic-gate 	sp->pr_zoneid = p->p_zone->zone_id;
8947c478bd9Sstevel@tonic-gate 	hrt2ts(mstate_aggr_state(p, LMS_USER), &sp->pr_utime);
8957c478bd9Sstevel@tonic-gate 	hrt2ts(mstate_aggr_state(p, LMS_SYSTEM), &sp->pr_stime);
8967c478bd9Sstevel@tonic-gate 	TICK_TO_TIMESTRUC(p->p_cutime, &sp->pr_cutime);
8977c478bd9Sstevel@tonic-gate 	TICK_TO_TIMESTRUC(p->p_cstime, &sp->pr_cstime);
8987c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_sigtrace, &p->p_sigmask);
8997c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_flttrace, &p->p_fltmask);
9007c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_sysentry, &PTOU(p)->u_entrymask);
9017c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_sysexit, &PTOU(p)->u_exitmask);
9027c478bd9Sstevel@tonic-gate 	switch (p->p_model) {
9037c478bd9Sstevel@tonic-gate 	case DATAMODEL_ILP32:
9047c478bd9Sstevel@tonic-gate 		sp->pr_dmodel = PR_MODEL_ILP32;
9057c478bd9Sstevel@tonic-gate 		break;
9067c478bd9Sstevel@tonic-gate 	case DATAMODEL_LP64:
9077c478bd9Sstevel@tonic-gate 		sp->pr_dmodel = PR_MODEL_LP64;
9087c478bd9Sstevel@tonic-gate 		break;
9097c478bd9Sstevel@tonic-gate 	}
9107c478bd9Sstevel@tonic-gate 	if (p->p_agenttp)
9117c478bd9Sstevel@tonic-gate 		sp->pr_agentid = p->p_agenttp->t_tid;
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 	/* get the chosen lwp's status */
9147c478bd9Sstevel@tonic-gate 	prgetlwpstatus(t, &sp->pr_lwp, zp);
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 	/* replicate the flags */
9177c478bd9Sstevel@tonic-gate 	sp->pr_flags = sp->pr_lwp.pr_flags;
9187c478bd9Sstevel@tonic-gate }
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
9217c478bd9Sstevel@tonic-gate void
9227c478bd9Sstevel@tonic-gate prgetlwpstatus32(kthread_t *t, lwpstatus32_t *sp, zone_t *zp)
9237c478bd9Sstevel@tonic-gate {
9247c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(t);
9257c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
9267c478bd9Sstevel@tonic-gate 	struct mstate *ms = &lwp->lwp_mstate;
9277c478bd9Sstevel@tonic-gate 	hrtime_t usr, sys;
9287c478bd9Sstevel@tonic-gate 	int flags;
9297c478bd9Sstevel@tonic-gate 	ulong_t instr;
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	bzero(sp, sizeof (*sp));
9347c478bd9Sstevel@tonic-gate 	flags = 0L;
9357c478bd9Sstevel@tonic-gate 	if (t->t_state == TS_STOPPED) {
9367c478bd9Sstevel@tonic-gate 		flags |= PR_STOPPED;
9377c478bd9Sstevel@tonic-gate 		if ((t->t_schedflag & TS_PSTART) == 0)
9387c478bd9Sstevel@tonic-gate 			flags |= PR_ISTOP;
9397c478bd9Sstevel@tonic-gate 	} else if (VSTOPPED(t)) {
9407c478bd9Sstevel@tonic-gate 		flags |= PR_STOPPED|PR_ISTOP;
9417c478bd9Sstevel@tonic-gate 	}
9427c478bd9Sstevel@tonic-gate 	if (!(flags & PR_ISTOP) && (t->t_proc_flag & TP_PRSTOP))
9437c478bd9Sstevel@tonic-gate 		flags |= PR_DSTOP;
9447c478bd9Sstevel@tonic-gate 	if (lwp->lwp_asleep)
9457c478bd9Sstevel@tonic-gate 		flags |= PR_ASLEEP;
9467c478bd9Sstevel@tonic-gate 	if (t == p->p_agenttp)
9477c478bd9Sstevel@tonic-gate 		flags |= PR_AGENT;
9487c478bd9Sstevel@tonic-gate 	if (!(t->t_proc_flag & TP_TWAIT))
9497c478bd9Sstevel@tonic-gate 		flags |= PR_DETACH;
9507c478bd9Sstevel@tonic-gate 	if (t->t_proc_flag & TP_DAEMON)
9517c478bd9Sstevel@tonic-gate 		flags |= PR_DAEMON;
9527c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_FORK)
9537c478bd9Sstevel@tonic-gate 		flags |= PR_FORK;
9547c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_RUNLCL)
9557c478bd9Sstevel@tonic-gate 		flags |= PR_RLC;
9567c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_KILLCL)
9577c478bd9Sstevel@tonic-gate 		flags |= PR_KLC;
9587c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_ASYNC)
9597c478bd9Sstevel@tonic-gate 		flags |= PR_ASYNC;
9607c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_BPTADJ)
9617c478bd9Sstevel@tonic-gate 		flags |= PR_BPTADJ;
9627c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_PTRACE)
9637c478bd9Sstevel@tonic-gate 		flags |= PR_PTRACE;
9647c478bd9Sstevel@tonic-gate 	if (p->p_flag & SMSACCT)
9657c478bd9Sstevel@tonic-gate 		flags |= PR_MSACCT;
9667c478bd9Sstevel@tonic-gate 	if (p->p_flag & SMSFORK)
9677c478bd9Sstevel@tonic-gate 		flags |= PR_MSFORK;
9687c478bd9Sstevel@tonic-gate 	if (p->p_flag & SVFWAIT)
9697c478bd9Sstevel@tonic-gate 		flags |= PR_VFORKP;
9707c478bd9Sstevel@tonic-gate 	sp->pr_flags = flags;
9717c478bd9Sstevel@tonic-gate 	if (VSTOPPED(t)) {
9727c478bd9Sstevel@tonic-gate 		sp->pr_why   = PR_REQUESTED;
9737c478bd9Sstevel@tonic-gate 		sp->pr_what  = 0;
9747c478bd9Sstevel@tonic-gate 	} else {
9757c478bd9Sstevel@tonic-gate 		sp->pr_why   = t->t_whystop;
9767c478bd9Sstevel@tonic-gate 		sp->pr_what  = t->t_whatstop;
9777c478bd9Sstevel@tonic-gate 	}
9787c478bd9Sstevel@tonic-gate 	sp->pr_lwpid = t->t_tid;
9797c478bd9Sstevel@tonic-gate 	sp->pr_cursig  = lwp->lwp_cursig;
9807c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_lwppend, &t->t_sig);
9817c478bd9Sstevel@tonic-gate 	schedctl_finish_sigblock(t);
9827c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_lwphold, &t->t_hold);
9837c478bd9Sstevel@tonic-gate 	if (t->t_whystop == PR_FAULTED) {
9847c478bd9Sstevel@tonic-gate 		siginfo_kto32(&lwp->lwp_siginfo, &sp->pr_info);
9857c478bd9Sstevel@tonic-gate 		if (t->t_whatstop == FLTPAGE)
9867c478bd9Sstevel@tonic-gate 			sp->pr_info.si_addr =
9877c478bd9Sstevel@tonic-gate 			    (caddr32_t)(uintptr_t)lwp->lwp_siginfo.si_addr;
9887c478bd9Sstevel@tonic-gate 	} else if (lwp->lwp_curinfo)
9897c478bd9Sstevel@tonic-gate 		siginfo_kto32(&lwp->lwp_curinfo->sq_info, &sp->pr_info);
9907c478bd9Sstevel@tonic-gate 	if (SI_FROMUSER(&lwp->lwp_siginfo) && zp->zone_id != GLOBAL_ZONEID &&
9917c478bd9Sstevel@tonic-gate 	    sp->pr_info.si_zoneid != zp->zone_id) {
9927c478bd9Sstevel@tonic-gate 		sp->pr_info.si_pid = zp->zone_zsched->p_pid;
9937c478bd9Sstevel@tonic-gate 		sp->pr_info.si_uid = 0;
9947c478bd9Sstevel@tonic-gate 		sp->pr_info.si_ctid = -1;
9957c478bd9Sstevel@tonic-gate 		sp->pr_info.si_zoneid = zp->zone_id;
9967c478bd9Sstevel@tonic-gate 	}
9977c478bd9Sstevel@tonic-gate 	sp->pr_altstack.ss_sp =
9987c478bd9Sstevel@tonic-gate 	    (caddr32_t)(uintptr_t)lwp->lwp_sigaltstack.ss_sp;
9997c478bd9Sstevel@tonic-gate 	sp->pr_altstack.ss_size = (size32_t)lwp->lwp_sigaltstack.ss_size;
10007c478bd9Sstevel@tonic-gate 	sp->pr_altstack.ss_flags = (int32_t)lwp->lwp_sigaltstack.ss_flags;
10017c478bd9Sstevel@tonic-gate 	prgetaction32(p, PTOU(p), lwp->lwp_cursig, &sp->pr_action);
10027c478bd9Sstevel@tonic-gate 	sp->pr_oldcontext = (caddr32_t)lwp->lwp_oldcontext;
10037c478bd9Sstevel@tonic-gate 	sp->pr_ustack = (caddr32_t)lwp->lwp_ustack;
10047c478bd9Sstevel@tonic-gate 	(void) strncpy(sp->pr_clname, sclass[t->t_cid].cl_name,
10057c478bd9Sstevel@tonic-gate 	    sizeof (sp->pr_clname) - 1);
10067c478bd9Sstevel@tonic-gate 	if (flags & PR_STOPPED)
10077c478bd9Sstevel@tonic-gate 		hrt2ts32(t->t_stoptime, &sp->pr_tstamp);
10087c478bd9Sstevel@tonic-gate 	usr = ms->ms_acct[LMS_USER];
10097c478bd9Sstevel@tonic-gate 	sys = ms->ms_acct[LMS_SYSTEM] + ms->ms_acct[LMS_TRAP];
10107c478bd9Sstevel@tonic-gate 	scalehrtime(&usr);
10117c478bd9Sstevel@tonic-gate 	scalehrtime(&sys);
10127c478bd9Sstevel@tonic-gate 	hrt2ts32(usr, &sp->pr_utime);
10137c478bd9Sstevel@tonic-gate 	hrt2ts32(sys, &sp->pr_stime);
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	/*
10167c478bd9Sstevel@tonic-gate 	 * Fetch the current instruction, if not a system process.
10177c478bd9Sstevel@tonic-gate 	 * We don't attempt this unless the lwp is stopped.
10187c478bd9Sstevel@tonic-gate 	 */
10197c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
10207c478bd9Sstevel@tonic-gate 		sp->pr_flags |= (PR_ISSYS|PR_PCINVAL);
10217c478bd9Sstevel@tonic-gate 	else if (!(flags & PR_STOPPED))
10227c478bd9Sstevel@tonic-gate 		sp->pr_flags |= PR_PCINVAL;
10237c478bd9Sstevel@tonic-gate 	else if (!prfetchinstr(lwp, &instr))
10247c478bd9Sstevel@tonic-gate 		sp->pr_flags |= PR_PCINVAL;
10257c478bd9Sstevel@tonic-gate 	else
10267c478bd9Sstevel@tonic-gate 		sp->pr_instr = (uint32_t)instr;
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 	/*
10297c478bd9Sstevel@tonic-gate 	 * Drop p_lock while touching the lwp's stack.
10307c478bd9Sstevel@tonic-gate 	 */
10317c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
10327c478bd9Sstevel@tonic-gate 	if (prisstep(lwp))
10337c478bd9Sstevel@tonic-gate 		sp->pr_flags |= PR_STEP;
10347c478bd9Sstevel@tonic-gate 	if ((flags & (PR_STOPPED|PR_ASLEEP)) && t->t_sysnum) {
10357c478bd9Sstevel@tonic-gate 		int i;
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 		sp->pr_syscall = get_syscall32_args(lwp,
10387c478bd9Sstevel@tonic-gate 		    (int *)sp->pr_sysarg, &i);
10397c478bd9Sstevel@tonic-gate 		sp->pr_nsysarg = (ushort_t)i;
10407c478bd9Sstevel@tonic-gate 	}
10417c478bd9Sstevel@tonic-gate 	if ((flags & PR_STOPPED) || t == curthread)
10427c478bd9Sstevel@tonic-gate 		prgetprregs32(lwp, sp->pr_reg);
10437c478bd9Sstevel@tonic-gate 	if ((t->t_state == TS_STOPPED && t->t_whystop == PR_SYSEXIT) ||
10447c478bd9Sstevel@tonic-gate 	    (flags & PR_VFORKP)) {
10457c478bd9Sstevel@tonic-gate 		long r1, r2;
10467c478bd9Sstevel@tonic-gate 		user_t *up;
10477c478bd9Sstevel@tonic-gate 		auxv_t *auxp;
10487c478bd9Sstevel@tonic-gate 		int i;
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate 		sp->pr_errno = prgetrvals(lwp, &r1, &r2);
10517c478bd9Sstevel@tonic-gate 		if (sp->pr_errno == 0) {
10527c478bd9Sstevel@tonic-gate 			sp->pr_rval1 = (int32_t)r1;
10537c478bd9Sstevel@tonic-gate 			sp->pr_rval2 = (int32_t)r2;
10547c478bd9Sstevel@tonic-gate 			sp->pr_errpriv = PRIV_NONE;
10557c478bd9Sstevel@tonic-gate 		} else
10567c478bd9Sstevel@tonic-gate 			sp->pr_errpriv = lwp->lwp_badpriv;
10577c478bd9Sstevel@tonic-gate 
10588fd04b83SRoger A. Faulkner 		if (t->t_sysnum == SYS_execve) {
10597c478bd9Sstevel@tonic-gate 			up = PTOU(p);
10607c478bd9Sstevel@tonic-gate 			sp->pr_sysarg[0] = 0;
10617c478bd9Sstevel@tonic-gate 			sp->pr_sysarg[1] = (caddr32_t)up->u_argv;
10627c478bd9Sstevel@tonic-gate 			sp->pr_sysarg[2] = (caddr32_t)up->u_envp;
10637c478bd9Sstevel@tonic-gate 			for (i = 0, auxp = up->u_auxv;
10647c478bd9Sstevel@tonic-gate 			    i < sizeof (up->u_auxv) / sizeof (up->u_auxv[0]);
10657c478bd9Sstevel@tonic-gate 			    i++, auxp++) {
10667c478bd9Sstevel@tonic-gate 				if (auxp->a_type == AT_SUN_EXECNAME) {
10677c478bd9Sstevel@tonic-gate 					sp->pr_sysarg[0] =
106825b463cdSethindra 					    (caddr32_t)
106925b463cdSethindra 					    (uintptr_t)auxp->a_un.a_ptr;
10707c478bd9Sstevel@tonic-gate 					break;
10717c478bd9Sstevel@tonic-gate 				}
10727c478bd9Sstevel@tonic-gate 			}
10737c478bd9Sstevel@tonic-gate 		}
10747c478bd9Sstevel@tonic-gate 	}
10757c478bd9Sstevel@tonic-gate 	if (prhasfp())
10767c478bd9Sstevel@tonic-gate 		prgetprfpregs32(lwp, &sp->pr_fpreg);
10777c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
10787c478bd9Sstevel@tonic-gate }
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate void
10817c478bd9Sstevel@tonic-gate prgetstatus32(proc_t *p, pstatus32_t *sp, zone_t *zp)
10827c478bd9Sstevel@tonic-gate {
10837c478bd9Sstevel@tonic-gate 	kthread_t *t;
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate 	t = prchoose(p);	/* returns locked thread */
10887c478bd9Sstevel@tonic-gate 	ASSERT(t != NULL);
10897c478bd9Sstevel@tonic-gate 	thread_unlock(t);
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	/* just bzero the process part, prgetlwpstatus32() does the rest */
10927c478bd9Sstevel@tonic-gate 	bzero(sp, sizeof (pstatus32_t) - sizeof (lwpstatus32_t));
10937c478bd9Sstevel@tonic-gate 	sp->pr_nlwp = p->p_lwpcnt;
10947c478bd9Sstevel@tonic-gate 	sp->pr_nzomb = p->p_zombcnt;
10957c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_sigpend, &p->p_sig);
10967c478bd9Sstevel@tonic-gate 	sp->pr_brkbase = (uint32_t)(uintptr_t)p->p_brkbase;
10977c478bd9Sstevel@tonic-gate 	sp->pr_brksize = (uint32_t)p->p_brksize;
10987c478bd9Sstevel@tonic-gate 	sp->pr_stkbase = (uint32_t)(uintptr_t)prgetstackbase(p);
10997c478bd9Sstevel@tonic-gate 	sp->pr_stksize = (uint32_t)p->p_stksize;
11007c478bd9Sstevel@tonic-gate 	sp->pr_pid   = p->p_pid;
11017c478bd9Sstevel@tonic-gate 	if (curproc->p_zone->zone_id != GLOBAL_ZONEID &&
11027c478bd9Sstevel@tonic-gate 	    (p->p_flag & SZONETOP)) {
11037c478bd9Sstevel@tonic-gate 		ASSERT(p->p_zone->zone_id != GLOBAL_ZONEID);
11047c478bd9Sstevel@tonic-gate 		/*
11057c478bd9Sstevel@tonic-gate 		 * Inside local zones, fake zsched's pid as parent pids for
11067c478bd9Sstevel@tonic-gate 		 * processes which reference processes outside of the zone.
11077c478bd9Sstevel@tonic-gate 		 */
11087c478bd9Sstevel@tonic-gate 		sp->pr_ppid = curproc->p_zone->zone_zsched->p_pid;
11097c478bd9Sstevel@tonic-gate 	} else {
11107c478bd9Sstevel@tonic-gate 		sp->pr_ppid = p->p_ppid;
11117c478bd9Sstevel@tonic-gate 	}
11127c478bd9Sstevel@tonic-gate 	sp->pr_pgid  = p->p_pgrp;
11137c478bd9Sstevel@tonic-gate 	sp->pr_sid   = p->p_sessp->s_sid;
11147c478bd9Sstevel@tonic-gate 	sp->pr_taskid = p->p_task->tk_tkid;
11157c478bd9Sstevel@tonic-gate 	sp->pr_projid = p->p_task->tk_proj->kpj_id;
11167c478bd9Sstevel@tonic-gate 	sp->pr_zoneid = p->p_zone->zone_id;
11177c478bd9Sstevel@tonic-gate 	hrt2ts32(mstate_aggr_state(p, LMS_USER), &sp->pr_utime);
11187c478bd9Sstevel@tonic-gate 	hrt2ts32(mstate_aggr_state(p, LMS_SYSTEM), &sp->pr_stime);
11197c478bd9Sstevel@tonic-gate 	TICK_TO_TIMESTRUC32(p->p_cutime, &sp->pr_cutime);
11207c478bd9Sstevel@tonic-gate 	TICK_TO_TIMESTRUC32(p->p_cstime, &sp->pr_cstime);
11217c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_sigtrace, &p->p_sigmask);
11227c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_flttrace, &p->p_fltmask);
11237c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_sysentry, &PTOU(p)->u_entrymask);
11247c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_sysexit, &PTOU(p)->u_exitmask);
11257c478bd9Sstevel@tonic-gate 	switch (p->p_model) {
11267c478bd9Sstevel@tonic-gate 	case DATAMODEL_ILP32:
11277c478bd9Sstevel@tonic-gate 		sp->pr_dmodel = PR_MODEL_ILP32;
11287c478bd9Sstevel@tonic-gate 		break;
11297c478bd9Sstevel@tonic-gate 	case DATAMODEL_LP64:
11307c478bd9Sstevel@tonic-gate 		sp->pr_dmodel = PR_MODEL_LP64;
11317c478bd9Sstevel@tonic-gate 		break;
11327c478bd9Sstevel@tonic-gate 	}
11337c478bd9Sstevel@tonic-gate 	if (p->p_agenttp)
11347c478bd9Sstevel@tonic-gate 		sp->pr_agentid = p->p_agenttp->t_tid;
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 	/* get the chosen lwp's status */
11377c478bd9Sstevel@tonic-gate 	prgetlwpstatus32(t, &sp->pr_lwp, zp);
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	/* replicate the flags */
11407c478bd9Sstevel@tonic-gate 	sp->pr_flags = sp->pr_lwp.pr_flags;
11417c478bd9Sstevel@tonic-gate }
11427c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate /*
11457c478bd9Sstevel@tonic-gate  * Return lwp status.
11467c478bd9Sstevel@tonic-gate  */
11477c478bd9Sstevel@tonic-gate void
11487c478bd9Sstevel@tonic-gate prgetlwpstatus(kthread_t *t, lwpstatus_t *sp, zone_t *zp)
11497c478bd9Sstevel@tonic-gate {
11507c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(t);
11517c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
11527c478bd9Sstevel@tonic-gate 	struct mstate *ms = &lwp->lwp_mstate;
11537c478bd9Sstevel@tonic-gate 	hrtime_t usr, sys;
11547c478bd9Sstevel@tonic-gate 	int flags;
11557c478bd9Sstevel@tonic-gate 	ulong_t instr;
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	bzero(sp, sizeof (*sp));
11607c478bd9Sstevel@tonic-gate 	flags = 0L;
11617c478bd9Sstevel@tonic-gate 	if (t->t_state == TS_STOPPED) {
11627c478bd9Sstevel@tonic-gate 		flags |= PR_STOPPED;
11637c478bd9Sstevel@tonic-gate 		if ((t->t_schedflag & TS_PSTART) == 0)
11647c478bd9Sstevel@tonic-gate 			flags |= PR_ISTOP;
11657c478bd9Sstevel@tonic-gate 	} else if (VSTOPPED(t)) {
11667c478bd9Sstevel@tonic-gate 		flags |= PR_STOPPED|PR_ISTOP;
11677c478bd9Sstevel@tonic-gate 	}
11687c478bd9Sstevel@tonic-gate 	if (!(flags & PR_ISTOP) && (t->t_proc_flag & TP_PRSTOP))
11697c478bd9Sstevel@tonic-gate 		flags |= PR_DSTOP;
11707c478bd9Sstevel@tonic-gate 	if (lwp->lwp_asleep)
11717c478bd9Sstevel@tonic-gate 		flags |= PR_ASLEEP;
11727c478bd9Sstevel@tonic-gate 	if (t == p->p_agenttp)
11737c478bd9Sstevel@tonic-gate 		flags |= PR_AGENT;
11747c478bd9Sstevel@tonic-gate 	if (!(t->t_proc_flag & TP_TWAIT))
11757c478bd9Sstevel@tonic-gate 		flags |= PR_DETACH;
11767c478bd9Sstevel@tonic-gate 	if (t->t_proc_flag & TP_DAEMON)
11777c478bd9Sstevel@tonic-gate 		flags |= PR_DAEMON;
11787c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_FORK)
11797c478bd9Sstevel@tonic-gate 		flags |= PR_FORK;
11807c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_RUNLCL)
11817c478bd9Sstevel@tonic-gate 		flags |= PR_RLC;
11827c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_KILLCL)
11837c478bd9Sstevel@tonic-gate 		flags |= PR_KLC;
11847c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_ASYNC)
11857c478bd9Sstevel@tonic-gate 		flags |= PR_ASYNC;
11867c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_BPTADJ)
11877c478bd9Sstevel@tonic-gate 		flags |= PR_BPTADJ;
11887c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_PTRACE)
11897c478bd9Sstevel@tonic-gate 		flags |= PR_PTRACE;
11907c478bd9Sstevel@tonic-gate 	if (p->p_flag & SMSACCT)
11917c478bd9Sstevel@tonic-gate 		flags |= PR_MSACCT;
11927c478bd9Sstevel@tonic-gate 	if (p->p_flag & SMSFORK)
11937c478bd9Sstevel@tonic-gate 		flags |= PR_MSFORK;
11947c478bd9Sstevel@tonic-gate 	if (p->p_flag & SVFWAIT)
11957c478bd9Sstevel@tonic-gate 		flags |= PR_VFORKP;
11967c478bd9Sstevel@tonic-gate 	if (p->p_pgidp->pid_pgorphaned)
11977c478bd9Sstevel@tonic-gate 		flags |= PR_ORPHAN;
1198657b1f3dSraf 	if (p->p_pidflag & CLDNOSIGCHLD)
1199657b1f3dSraf 		flags |= PR_NOSIGCHLD;
1200657b1f3dSraf 	if (p->p_pidflag & CLDWAITPID)
1201657b1f3dSraf 		flags |= PR_WAITPID;
12027c478bd9Sstevel@tonic-gate 	sp->pr_flags = flags;
12037c478bd9Sstevel@tonic-gate 	if (VSTOPPED(t)) {
12047c478bd9Sstevel@tonic-gate 		sp->pr_why   = PR_REQUESTED;
12057c478bd9Sstevel@tonic-gate 		sp->pr_what  = 0;
12067c478bd9Sstevel@tonic-gate 	} else {
12077c478bd9Sstevel@tonic-gate 		sp->pr_why   = t->t_whystop;
12087c478bd9Sstevel@tonic-gate 		sp->pr_what  = t->t_whatstop;
12097c478bd9Sstevel@tonic-gate 	}
12107c478bd9Sstevel@tonic-gate 	sp->pr_lwpid = t->t_tid;
12117c478bd9Sstevel@tonic-gate 	sp->pr_cursig  = lwp->lwp_cursig;
12127c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_lwppend, &t->t_sig);
12137c478bd9Sstevel@tonic-gate 	schedctl_finish_sigblock(t);
12147c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_lwphold, &t->t_hold);
12157c478bd9Sstevel@tonic-gate 	if (t->t_whystop == PR_FAULTED)
12167c478bd9Sstevel@tonic-gate 		bcopy(&lwp->lwp_siginfo,
12177c478bd9Sstevel@tonic-gate 		    &sp->pr_info, sizeof (k_siginfo_t));
12187c478bd9Sstevel@tonic-gate 	else if (lwp->lwp_curinfo)
12197c478bd9Sstevel@tonic-gate 		bcopy(&lwp->lwp_curinfo->sq_info,
12207c478bd9Sstevel@tonic-gate 		    &sp->pr_info, sizeof (k_siginfo_t));
12217c478bd9Sstevel@tonic-gate 	if (SI_FROMUSER(&lwp->lwp_siginfo) && zp->zone_id != GLOBAL_ZONEID &&
12227c478bd9Sstevel@tonic-gate 	    sp->pr_info.si_zoneid != zp->zone_id) {
12237c478bd9Sstevel@tonic-gate 		sp->pr_info.si_pid = zp->zone_zsched->p_pid;
12247c478bd9Sstevel@tonic-gate 		sp->pr_info.si_uid = 0;
12257c478bd9Sstevel@tonic-gate 		sp->pr_info.si_ctid = -1;
12267c478bd9Sstevel@tonic-gate 		sp->pr_info.si_zoneid = zp->zone_id;
12277c478bd9Sstevel@tonic-gate 	}
12287c478bd9Sstevel@tonic-gate 	sp->pr_altstack = lwp->lwp_sigaltstack;
12297c478bd9Sstevel@tonic-gate 	prgetaction(p, PTOU(p), lwp->lwp_cursig, &sp->pr_action);
12307c478bd9Sstevel@tonic-gate 	sp->pr_oldcontext = (uintptr_t)lwp->lwp_oldcontext;
12317c478bd9Sstevel@tonic-gate 	sp->pr_ustack = lwp->lwp_ustack;
12327c478bd9Sstevel@tonic-gate 	(void) strncpy(sp->pr_clname, sclass[t->t_cid].cl_name,
12337c478bd9Sstevel@tonic-gate 	    sizeof (sp->pr_clname) - 1);
12347c478bd9Sstevel@tonic-gate 	if (flags & PR_STOPPED)
12357c478bd9Sstevel@tonic-gate 		hrt2ts(t->t_stoptime, &sp->pr_tstamp);
12367c478bd9Sstevel@tonic-gate 	usr = ms->ms_acct[LMS_USER];
12377c478bd9Sstevel@tonic-gate 	sys = ms->ms_acct[LMS_SYSTEM] + ms->ms_acct[LMS_TRAP];
12387c478bd9Sstevel@tonic-gate 	scalehrtime(&usr);
12397c478bd9Sstevel@tonic-gate 	scalehrtime(&sys);
12407c478bd9Sstevel@tonic-gate 	hrt2ts(usr, &sp->pr_utime);
12417c478bd9Sstevel@tonic-gate 	hrt2ts(sys, &sp->pr_stime);
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 	/*
12447c478bd9Sstevel@tonic-gate 	 * Fetch the current instruction, if not a system process.
12457c478bd9Sstevel@tonic-gate 	 * We don't attempt this unless the lwp is stopped.
12467c478bd9Sstevel@tonic-gate 	 */
12477c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
12487c478bd9Sstevel@tonic-gate 		sp->pr_flags |= (PR_ISSYS|PR_PCINVAL);
12497c478bd9Sstevel@tonic-gate 	else if (!(flags & PR_STOPPED))
12507c478bd9Sstevel@tonic-gate 		sp->pr_flags |= PR_PCINVAL;
12517c478bd9Sstevel@tonic-gate 	else if (!prfetchinstr(lwp, &instr))
12527c478bd9Sstevel@tonic-gate 		sp->pr_flags |= PR_PCINVAL;
12537c478bd9Sstevel@tonic-gate 	else
12547c478bd9Sstevel@tonic-gate 		sp->pr_instr = instr;
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	/*
12577c478bd9Sstevel@tonic-gate 	 * Drop p_lock while touching the lwp's stack.
12587c478bd9Sstevel@tonic-gate 	 */
12597c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
12607c478bd9Sstevel@tonic-gate 	if (prisstep(lwp))
12617c478bd9Sstevel@tonic-gate 		sp->pr_flags |= PR_STEP;
12627c478bd9Sstevel@tonic-gate 	if ((flags & (PR_STOPPED|PR_ASLEEP)) && t->t_sysnum) {
12637c478bd9Sstevel@tonic-gate 		int i;
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate 		sp->pr_syscall = get_syscall_args(lwp,
12667c478bd9Sstevel@tonic-gate 		    (long *)sp->pr_sysarg, &i);
12677c478bd9Sstevel@tonic-gate 		sp->pr_nsysarg = (ushort_t)i;
12687c478bd9Sstevel@tonic-gate 	}
12697c478bd9Sstevel@tonic-gate 	if ((flags & PR_STOPPED) || t == curthread)
12707c478bd9Sstevel@tonic-gate 		prgetprregs(lwp, sp->pr_reg);
12717c478bd9Sstevel@tonic-gate 	if ((t->t_state == TS_STOPPED && t->t_whystop == PR_SYSEXIT) ||
12727c478bd9Sstevel@tonic-gate 	    (flags & PR_VFORKP)) {
12737c478bd9Sstevel@tonic-gate 		user_t *up;
12747c478bd9Sstevel@tonic-gate 		auxv_t *auxp;
12757c478bd9Sstevel@tonic-gate 		int i;
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate 		sp->pr_errno = prgetrvals(lwp, &sp->pr_rval1, &sp->pr_rval2);
12787c478bd9Sstevel@tonic-gate 		if (sp->pr_errno == 0)
12797c478bd9Sstevel@tonic-gate 			sp->pr_errpriv = PRIV_NONE;
12807c478bd9Sstevel@tonic-gate 		else
12817c478bd9Sstevel@tonic-gate 			sp->pr_errpriv = lwp->lwp_badpriv;
12827c478bd9Sstevel@tonic-gate 
12838fd04b83SRoger A. Faulkner 		if (t->t_sysnum == SYS_execve) {
12847c478bd9Sstevel@tonic-gate 			up = PTOU(p);
12857c478bd9Sstevel@tonic-gate 			sp->pr_sysarg[0] = 0;
12867c478bd9Sstevel@tonic-gate 			sp->pr_sysarg[1] = (uintptr_t)up->u_argv;
12877c478bd9Sstevel@tonic-gate 			sp->pr_sysarg[2] = (uintptr_t)up->u_envp;
12887c478bd9Sstevel@tonic-gate 			for (i = 0, auxp = up->u_auxv;
12897c478bd9Sstevel@tonic-gate 			    i < sizeof (up->u_auxv) / sizeof (up->u_auxv[0]);
12907c478bd9Sstevel@tonic-gate 			    i++, auxp++) {
12917c478bd9Sstevel@tonic-gate 				if (auxp->a_type == AT_SUN_EXECNAME) {
12927c478bd9Sstevel@tonic-gate 					sp->pr_sysarg[0] =
12937c478bd9Sstevel@tonic-gate 					    (uintptr_t)auxp->a_un.a_ptr;
12947c478bd9Sstevel@tonic-gate 					break;
12957c478bd9Sstevel@tonic-gate 				}
12967c478bd9Sstevel@tonic-gate 			}
12977c478bd9Sstevel@tonic-gate 		}
12987c478bd9Sstevel@tonic-gate 	}
12997c478bd9Sstevel@tonic-gate 	if (prhasfp())
13007c478bd9Sstevel@tonic-gate 		prgetprfpregs(lwp, &sp->pr_fpreg);
13017c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
13027c478bd9Sstevel@tonic-gate }
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate /*
13057c478bd9Sstevel@tonic-gate  * Get the sigaction structure for the specified signal.  The u-block
13067c478bd9Sstevel@tonic-gate  * must already have been mapped in by the caller.
13077c478bd9Sstevel@tonic-gate  */
13087c478bd9Sstevel@tonic-gate void
13097c478bd9Sstevel@tonic-gate prgetaction(proc_t *p, user_t *up, uint_t sig, struct sigaction *sp)
13107c478bd9Sstevel@tonic-gate {
1311eb9dbf0cSRoger A. Faulkner 	int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
1312eb9dbf0cSRoger A. Faulkner 
13137c478bd9Sstevel@tonic-gate 	bzero(sp, sizeof (*sp));
13147c478bd9Sstevel@tonic-gate 
1315eb9dbf0cSRoger A. Faulkner 	if (sig != 0 && (unsigned)sig < nsig) {
13167c478bd9Sstevel@tonic-gate 		sp->sa_handler = up->u_signal[sig-1];
13177c478bd9Sstevel@tonic-gate 		prassignset(&sp->sa_mask, &up->u_sigmask[sig-1]);
13187c478bd9Sstevel@tonic-gate 		if (sigismember(&up->u_sigonstack, sig))
13197c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_ONSTACK;
13207c478bd9Sstevel@tonic-gate 		if (sigismember(&up->u_sigresethand, sig))
13217c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_RESETHAND;
13227c478bd9Sstevel@tonic-gate 		if (sigismember(&up->u_sigrestart, sig))
13237c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_RESTART;
13247c478bd9Sstevel@tonic-gate 		if (sigismember(&p->p_siginfo, sig))
13257c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_SIGINFO;
13267c478bd9Sstevel@tonic-gate 		if (sigismember(&up->u_signodefer, sig))
13277c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_NODEFER;
13287c478bd9Sstevel@tonic-gate 		if (sig == SIGCLD) {
13297c478bd9Sstevel@tonic-gate 			if (p->p_flag & SNOWAIT)
13307c478bd9Sstevel@tonic-gate 				sp->sa_flags |= SA_NOCLDWAIT;
13317c478bd9Sstevel@tonic-gate 			if ((p->p_flag & SJCTL) == 0)
13327c478bd9Sstevel@tonic-gate 				sp->sa_flags |= SA_NOCLDSTOP;
13337c478bd9Sstevel@tonic-gate 		}
13347c478bd9Sstevel@tonic-gate 	}
13357c478bd9Sstevel@tonic-gate }
13367c478bd9Sstevel@tonic-gate 
13377c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
13387c478bd9Sstevel@tonic-gate void
13397c478bd9Sstevel@tonic-gate prgetaction32(proc_t *p, user_t *up, uint_t sig, struct sigaction32 *sp)
13407c478bd9Sstevel@tonic-gate {
1341eb9dbf0cSRoger A. Faulkner 	int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
1342eb9dbf0cSRoger A. Faulkner 
13437c478bd9Sstevel@tonic-gate 	bzero(sp, sizeof (*sp));
13447c478bd9Sstevel@tonic-gate 
1345eb9dbf0cSRoger A. Faulkner 	if (sig != 0 && (unsigned)sig < nsig) {
13467c478bd9Sstevel@tonic-gate 		sp->sa_handler = (caddr32_t)(uintptr_t)up->u_signal[sig-1];
13477c478bd9Sstevel@tonic-gate 		prassignset(&sp->sa_mask, &up->u_sigmask[sig-1]);
13487c478bd9Sstevel@tonic-gate 		if (sigismember(&up->u_sigonstack, sig))
13497c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_ONSTACK;
13507c478bd9Sstevel@tonic-gate 		if (sigismember(&up->u_sigresethand, sig))
13517c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_RESETHAND;
13527c478bd9Sstevel@tonic-gate 		if (sigismember(&up->u_sigrestart, sig))
13537c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_RESTART;
13547c478bd9Sstevel@tonic-gate 		if (sigismember(&p->p_siginfo, sig))
13557c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_SIGINFO;
13567c478bd9Sstevel@tonic-gate 		if (sigismember(&up->u_signodefer, sig))
13577c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_NODEFER;
13587c478bd9Sstevel@tonic-gate 		if (sig == SIGCLD) {
13597c478bd9Sstevel@tonic-gate 			if (p->p_flag & SNOWAIT)
13607c478bd9Sstevel@tonic-gate 				sp->sa_flags |= SA_NOCLDWAIT;
13617c478bd9Sstevel@tonic-gate 			if ((p->p_flag & SJCTL) == 0)
13627c478bd9Sstevel@tonic-gate 				sp->sa_flags |= SA_NOCLDSTOP;
13637c478bd9Sstevel@tonic-gate 		}
13647c478bd9Sstevel@tonic-gate 	}
13657c478bd9Sstevel@tonic-gate }
13667c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate /*
13697c478bd9Sstevel@tonic-gate  * Count the number of segments in this process's address space.
13707c478bd9Sstevel@tonic-gate  */
13717c478bd9Sstevel@tonic-gate int
13727c478bd9Sstevel@tonic-gate prnsegs(struct as *as, int reserved)
13737c478bd9Sstevel@tonic-gate {
13747c478bd9Sstevel@tonic-gate 	int n = 0;
13757c478bd9Sstevel@tonic-gate 	struct seg *seg;
13767c478bd9Sstevel@tonic-gate 
1377*dc32d872SJosef 'Jeff' Sipek 	ASSERT(as != &kas && AS_WRITE_HELD(as));
13787c478bd9Sstevel@tonic-gate 
13797c478bd9Sstevel@tonic-gate 	for (seg = AS_SEGFIRST(as); seg != NULL; seg = AS_SEGNEXT(as, seg)) {
13807c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, reserved);
13817c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr;
13827c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
13857c478bd9Sstevel@tonic-gate 			(void) pr_getprot(seg, reserved, &tmp,
13867c478bd9Sstevel@tonic-gate 			    &saddr, &naddr, eaddr);
13877c478bd9Sstevel@tonic-gate 			if (saddr != naddr)
13887c478bd9Sstevel@tonic-gate 				n++;
13897c478bd9Sstevel@tonic-gate 		}
13907c478bd9Sstevel@tonic-gate 
13917c478bd9Sstevel@tonic-gate 		ASSERT(tmp == NULL);
13927c478bd9Sstevel@tonic-gate 	}
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate 	return (n);
13957c478bd9Sstevel@tonic-gate }
13967c478bd9Sstevel@tonic-gate 
13977c478bd9Sstevel@tonic-gate /*
13987c478bd9Sstevel@tonic-gate  * Convert uint32_t to decimal string w/o leading zeros.
13997c478bd9Sstevel@tonic-gate  * Add trailing null characters if 'len' is greater than string length.
14007c478bd9Sstevel@tonic-gate  * Return the string length.
14017c478bd9Sstevel@tonic-gate  */
14027c478bd9Sstevel@tonic-gate int
14037c478bd9Sstevel@tonic-gate pr_u32tos(uint32_t n, char *s, int len)
14047c478bd9Sstevel@tonic-gate {
14057c478bd9Sstevel@tonic-gate 	char cbuf[11];		/* 32-bit unsigned integer fits in 10 digits */
14067c478bd9Sstevel@tonic-gate 	char *cp = cbuf;
14077c478bd9Sstevel@tonic-gate 	char *end = s + len;
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate 	do {
14107c478bd9Sstevel@tonic-gate 		*cp++ = (char)(n % 10 + '0');
14117c478bd9Sstevel@tonic-gate 		n /= 10;
14127c478bd9Sstevel@tonic-gate 	} while (n);
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 	len = (int)(cp - cbuf);
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 	do {
14177c478bd9Sstevel@tonic-gate 		*s++ = *--cp;
14187c478bd9Sstevel@tonic-gate 	} while (cp > cbuf);
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 	while (s < end)		/* optional pad */
14217c478bd9Sstevel@tonic-gate 		*s++ = '\0';
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 	return (len);
14247c478bd9Sstevel@tonic-gate }
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate /*
14277c478bd9Sstevel@tonic-gate  * Convert uint64_t to decimal string w/o leading zeros.
14287c478bd9Sstevel@tonic-gate  * Return the string length.
14297c478bd9Sstevel@tonic-gate  */
14307c478bd9Sstevel@tonic-gate static int
14317c478bd9Sstevel@tonic-gate pr_u64tos(uint64_t n, char *s)
14327c478bd9Sstevel@tonic-gate {
14337c478bd9Sstevel@tonic-gate 	char cbuf[21];		/* 64-bit unsigned integer fits in 20 digits */
14347c478bd9Sstevel@tonic-gate 	char *cp = cbuf;
14357c478bd9Sstevel@tonic-gate 	int len;
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 	do {
14387c478bd9Sstevel@tonic-gate 		*cp++ = (char)(n % 10 + '0');
14397c478bd9Sstevel@tonic-gate 		n /= 10;
14407c478bd9Sstevel@tonic-gate 	} while (n);
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 	len = (int)(cp - cbuf);
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 	do {
14457c478bd9Sstevel@tonic-gate 		*s++ = *--cp;
14467c478bd9Sstevel@tonic-gate 	} while (cp > cbuf);
14477c478bd9Sstevel@tonic-gate 
14487c478bd9Sstevel@tonic-gate 	return (len);
14497c478bd9Sstevel@tonic-gate }
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate void
14527c478bd9Sstevel@tonic-gate pr_object_name(char *name, vnode_t *vp, struct vattr *vattr)
14537c478bd9Sstevel@tonic-gate {
14547c478bd9Sstevel@tonic-gate 	char *s = name;
14557c478bd9Sstevel@tonic-gate 	struct vfs *vfsp;
14567c478bd9Sstevel@tonic-gate 	struct vfssw *vfsswp;
14577c478bd9Sstevel@tonic-gate 
14587c478bd9Sstevel@tonic-gate 	if ((vfsp = vp->v_vfsp) != NULL &&
14597c478bd9Sstevel@tonic-gate 	    ((vfsswp = vfssw + vfsp->vfs_fstype), vfsswp->vsw_name) &&
14607c478bd9Sstevel@tonic-gate 	    *vfsswp->vsw_name) {
14617c478bd9Sstevel@tonic-gate 		(void) strcpy(s, vfsswp->vsw_name);
14627c478bd9Sstevel@tonic-gate 		s += strlen(s);
14637c478bd9Sstevel@tonic-gate 		*s++ = '.';
14647c478bd9Sstevel@tonic-gate 	}
14657c478bd9Sstevel@tonic-gate 	s += pr_u32tos(getmajor(vattr->va_fsid), s, 0);
14667c478bd9Sstevel@tonic-gate 	*s++ = '.';
14677c478bd9Sstevel@tonic-gate 	s += pr_u32tos(getminor(vattr->va_fsid), s, 0);
14687c478bd9Sstevel@tonic-gate 	*s++ = '.';
14697c478bd9Sstevel@tonic-gate 	s += pr_u64tos(vattr->va_nodeid, s);
14707c478bd9Sstevel@tonic-gate 	*s++ = '\0';
14717c478bd9Sstevel@tonic-gate }
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate struct seg *
14747c478bd9Sstevel@tonic-gate break_seg(proc_t *p)
14757c478bd9Sstevel@tonic-gate {
14767c478bd9Sstevel@tonic-gate 	caddr_t addr = p->p_brkbase;
14777c478bd9Sstevel@tonic-gate 	struct seg *seg;
14787c478bd9Sstevel@tonic-gate 	struct vnode *vp;
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate 	if (p->p_brksize != 0)
14817c478bd9Sstevel@tonic-gate 		addr += p->p_brksize - 1;
14827c478bd9Sstevel@tonic-gate 	seg = as_segat(p->p_as, addr);
14837c478bd9Sstevel@tonic-gate 	if (seg != NULL && seg->s_ops == &segvn_ops &&
14847c478bd9Sstevel@tonic-gate 	    (SEGOP_GETVP(seg, seg->s_base, &vp) != 0 || vp == NULL))
14857c478bd9Sstevel@tonic-gate 		return (seg);
14867c478bd9Sstevel@tonic-gate 	return (NULL);
14877c478bd9Sstevel@tonic-gate }
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate /*
1490870619e9Sfrankho  * Implementation of service functions to handle procfs generic chained
1491870619e9Sfrankho  * copyout buffers.
1492870619e9Sfrankho  */
1493870619e9Sfrankho typedef struct pr_iobuf_list {
1494870619e9Sfrankho 	list_node_t	piol_link;	/* buffer linkage */
1495870619e9Sfrankho 	size_t		piol_size;	/* total size (header + data) */
1496870619e9Sfrankho 	size_t		piol_usedsize;	/* amount to copy out from this buf */
1497870619e9Sfrankho } piol_t;
1498870619e9Sfrankho 
1499870619e9Sfrankho #define	MAPSIZE	(64 * 1024)
1500870619e9Sfrankho #define	PIOL_DATABUF(iol)	((void *)(&(iol)[1]))
1501870619e9Sfrankho 
1502870619e9Sfrankho void
1503870619e9Sfrankho pr_iol_initlist(list_t *iolhead, size_t itemsize, int n)
1504870619e9Sfrankho {
1505870619e9Sfrankho 	piol_t	*iol;
1506870619e9Sfrankho 	size_t	initial_size = MIN(1, n) * itemsize;
1507870619e9Sfrankho 
1508870619e9Sfrankho 	list_create(iolhead, sizeof (piol_t), offsetof(piol_t, piol_link));
1509870619e9Sfrankho 
1510870619e9Sfrankho 	ASSERT(list_head(iolhead) == NULL);
1511870619e9Sfrankho 	ASSERT(itemsize < MAPSIZE - sizeof (*iol));
1512870619e9Sfrankho 	ASSERT(initial_size > 0);
1513870619e9Sfrankho 
1514870619e9Sfrankho 	/*
1515870619e9Sfrankho 	 * Someone creating chained copyout buffers may ask for less than
1516870619e9Sfrankho 	 * MAPSIZE if the amount of data to be buffered is known to be
1517870619e9Sfrankho 	 * smaller than that.
1518870619e9Sfrankho 	 * But in order to prevent involuntary self-denial of service,
1519870619e9Sfrankho 	 * the requested input size is clamped at MAPSIZE.
1520870619e9Sfrankho 	 */
1521870619e9Sfrankho 	initial_size = MIN(MAPSIZE, initial_size + sizeof (*iol));
1522870619e9Sfrankho 	iol = kmem_alloc(initial_size, KM_SLEEP);
1523870619e9Sfrankho 	list_insert_head(iolhead, iol);
1524870619e9Sfrankho 	iol->piol_usedsize = 0;
1525870619e9Sfrankho 	iol->piol_size = initial_size;
1526870619e9Sfrankho }
1527870619e9Sfrankho 
1528870619e9Sfrankho void *
1529870619e9Sfrankho pr_iol_newbuf(list_t *iolhead, size_t itemsize)
1530870619e9Sfrankho {
1531870619e9Sfrankho 	piol_t	*iol;
1532870619e9Sfrankho 	char	*new;
1533870619e9Sfrankho 
1534870619e9Sfrankho 	ASSERT(itemsize < MAPSIZE - sizeof (*iol));
1535870619e9Sfrankho 	ASSERT(list_head(iolhead) != NULL);
1536870619e9Sfrankho 
1537870619e9Sfrankho 	iol = (piol_t *)list_tail(iolhead);
1538870619e9Sfrankho 
1539870619e9Sfrankho 	if (iol->piol_size <
1540870619e9Sfrankho 	    iol->piol_usedsize + sizeof (*iol) + itemsize) {
1541870619e9Sfrankho 		/*
1542870619e9Sfrankho 		 * Out of space in the current buffer. Allocate more.
1543870619e9Sfrankho 		 */
1544870619e9Sfrankho 		piol_t *newiol;
1545870619e9Sfrankho 
1546870619e9Sfrankho 		newiol = kmem_alloc(MAPSIZE, KM_SLEEP);
1547870619e9Sfrankho 		newiol->piol_size = MAPSIZE;
1548870619e9Sfrankho 		newiol->piol_usedsize = 0;
1549870619e9Sfrankho 
1550870619e9Sfrankho 		list_insert_after(iolhead, iol, newiol);
1551870619e9Sfrankho 		iol = list_next(iolhead, iol);
1552870619e9Sfrankho 		ASSERT(iol == newiol);
1553870619e9Sfrankho 	}
1554870619e9Sfrankho 	new = (char *)PIOL_DATABUF(iol) + iol->piol_usedsize;
1555870619e9Sfrankho 	iol->piol_usedsize += itemsize;
1556870619e9Sfrankho 	bzero(new, itemsize);
1557870619e9Sfrankho 	return (new);
1558870619e9Sfrankho }
1559870619e9Sfrankho 
1560870619e9Sfrankho int
1561870619e9Sfrankho pr_iol_copyout_and_free(list_t *iolhead, caddr_t *tgt, int errin)
1562870619e9Sfrankho {
1563870619e9Sfrankho 	int error = errin;
1564870619e9Sfrankho 	piol_t	*iol;
1565870619e9Sfrankho 
1566870619e9Sfrankho 	while ((iol = list_head(iolhead)) != NULL) {
1567870619e9Sfrankho 		list_remove(iolhead, iol);
1568870619e9Sfrankho 		if (!error) {
1569870619e9Sfrankho 			if (copyout(PIOL_DATABUF(iol), *tgt,
1570870619e9Sfrankho 			    iol->piol_usedsize))
1571870619e9Sfrankho 				error = EFAULT;
1572870619e9Sfrankho 			*tgt += iol->piol_usedsize;
1573870619e9Sfrankho 		}
1574870619e9Sfrankho 		kmem_free(iol, iol->piol_size);
1575870619e9Sfrankho 	}
1576870619e9Sfrankho 	list_destroy(iolhead);
1577870619e9Sfrankho 
1578870619e9Sfrankho 	return (error);
1579870619e9Sfrankho }
1580870619e9Sfrankho 
1581870619e9Sfrankho int
1582870619e9Sfrankho pr_iol_uiomove_and_free(list_t *iolhead, uio_t *uiop, int errin)
1583870619e9Sfrankho {
1584870619e9Sfrankho 	offset_t	off = uiop->uio_offset;
1585870619e9Sfrankho 	char		*base;
1586870619e9Sfrankho 	size_t		size;
1587870619e9Sfrankho 	piol_t		*iol;
1588870619e9Sfrankho 	int		error = errin;
1589870619e9Sfrankho 
1590870619e9Sfrankho 	while ((iol = list_head(iolhead)) != NULL) {
1591870619e9Sfrankho 		list_remove(iolhead, iol);
1592870619e9Sfrankho 		base = PIOL_DATABUF(iol);
1593870619e9Sfrankho 		size = iol->piol_usedsize;
1594870619e9Sfrankho 		if (off <= size && error == 0 && uiop->uio_resid > 0)
1595870619e9Sfrankho 			error = uiomove(base + off, size - off,
1596870619e9Sfrankho 			    UIO_READ, uiop);
1597870619e9Sfrankho 		off = MAX(0, off - (offset_t)size);
1598870619e9Sfrankho 		kmem_free(iol, iol->piol_size);
1599870619e9Sfrankho 	}
1600870619e9Sfrankho 	list_destroy(iolhead);
1601870619e9Sfrankho 
1602870619e9Sfrankho 	return (error);
1603870619e9Sfrankho }
1604870619e9Sfrankho 
1605870619e9Sfrankho /*
16067c478bd9Sstevel@tonic-gate  * Return an array of structures with memory map information.
16077c478bd9Sstevel@tonic-gate  * We allocate here; the caller must deallocate.
16087c478bd9Sstevel@tonic-gate  */
16097c478bd9Sstevel@tonic-gate int
1610870619e9Sfrankho prgetmap(proc_t *p, int reserved, list_t *iolhead)
16117c478bd9Sstevel@tonic-gate {
16127c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
16137c478bd9Sstevel@tonic-gate 	prmap_t *mp;
16147c478bd9Sstevel@tonic-gate 	struct seg *seg;
16157c478bd9Sstevel@tonic-gate 	struct seg *brkseg, *stkseg;
16167c478bd9Sstevel@tonic-gate 	struct vnode *vp;
16177c478bd9Sstevel@tonic-gate 	struct vattr vattr;
16187c478bd9Sstevel@tonic-gate 	uint_t prot;
16197c478bd9Sstevel@tonic-gate 
1620*dc32d872SJosef 'Jeff' Sipek 	ASSERT(as != &kas && AS_WRITE_HELD(as));
16217c478bd9Sstevel@tonic-gate 
1622870619e9Sfrankho 	/*
1623870619e9Sfrankho 	 * Request an initial buffer size that doesn't waste memory
1624870619e9Sfrankho 	 * if the address space has only a small number of segments.
1625870619e9Sfrankho 	 */
1626870619e9Sfrankho 	pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL)
16297c478bd9Sstevel@tonic-gate 		return (0);
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 	brkseg = break_seg(p);
16327c478bd9Sstevel@tonic-gate 	stkseg = as_segat(as, prgetstackbase(p));
16337c478bd9Sstevel@tonic-gate 
16347c478bd9Sstevel@tonic-gate 	do {
16357c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, reserved);
16367c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr;
16377c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
16387c478bd9Sstevel@tonic-gate 
16397c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
16407c478bd9Sstevel@tonic-gate 			prot = pr_getprot(seg, reserved, &tmp,
16417c478bd9Sstevel@tonic-gate 			    &saddr, &naddr, eaddr);
16427c478bd9Sstevel@tonic-gate 			if (saddr == naddr)
16437c478bd9Sstevel@tonic-gate 				continue;
16447c478bd9Sstevel@tonic-gate 
1645870619e9Sfrankho 			mp = pr_iol_newbuf(iolhead, sizeof (*mp));
1646870619e9Sfrankho 
16477c478bd9Sstevel@tonic-gate 			mp->pr_vaddr = (uintptr_t)saddr;
16487c478bd9Sstevel@tonic-gate 			mp->pr_size = naddr - saddr;
16497c478bd9Sstevel@tonic-gate 			mp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
16507c478bd9Sstevel@tonic-gate 			mp->pr_mflags = 0;
16517c478bd9Sstevel@tonic-gate 			if (prot & PROT_READ)
16527c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_READ;
16537c478bd9Sstevel@tonic-gate 			if (prot & PROT_WRITE)
16547c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_WRITE;
16557c478bd9Sstevel@tonic-gate 			if (prot & PROT_EXEC)
16567c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_EXEC;
16577c478bd9Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_SHARED)
16587c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_SHARED;
16597c478bd9Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_NORESERVE)
16607c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_NORESERVE;
16617c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops ||
16627c478bd9Sstevel@tonic-gate 			    (seg->s_ops == &segvn_ops &&
16637c478bd9Sstevel@tonic-gate 			    (SEGOP_GETVP(seg, saddr, &vp) != 0 || vp == NULL)))
16647c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_ANON;
16657c478bd9Sstevel@tonic-gate 			if (seg == brkseg)
16667c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_BREAK;
16677c478bd9Sstevel@tonic-gate 			else if (seg == stkseg) {
16687c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_STACK;
16697c478bd9Sstevel@tonic-gate 				if (reserved) {
16707c478bd9Sstevel@tonic-gate 					size_t maxstack =
16717c478bd9Sstevel@tonic-gate 					    ((size_t)p->p_stk_ctl +
16727c478bd9Sstevel@tonic-gate 					    PAGEOFFSET) & PAGEMASK;
16737c478bd9Sstevel@tonic-gate 					mp->pr_vaddr =
16747c478bd9Sstevel@tonic-gate 					    (uintptr_t)prgetstackbase(p) +
16757c478bd9Sstevel@tonic-gate 					    p->p_stksize - maxstack;
16767c478bd9Sstevel@tonic-gate 					mp->pr_size = (uintptr_t)naddr -
16777c478bd9Sstevel@tonic-gate 					    mp->pr_vaddr;
16787c478bd9Sstevel@tonic-gate 				}
16797c478bd9Sstevel@tonic-gate 			}
16807c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops)
16817c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_ISM | MA_SHM;
16827c478bd9Sstevel@tonic-gate 			mp->pr_pagesize = PAGESIZE;
16837c478bd9Sstevel@tonic-gate 
16847c478bd9Sstevel@tonic-gate 			/*
16857c478bd9Sstevel@tonic-gate 			 * Manufacture a filename for the "object" directory.
16867c478bd9Sstevel@tonic-gate 			 */
16877c478bd9Sstevel@tonic-gate 			vattr.va_mask = AT_FSID|AT_NODEID;
16887c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segvn_ops &&
16897c478bd9Sstevel@tonic-gate 			    SEGOP_GETVP(seg, saddr, &vp) == 0 &&
16907c478bd9Sstevel@tonic-gate 			    vp != NULL && vp->v_type == VREG &&
1691da6c28aaSamw 			    VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
16927c478bd9Sstevel@tonic-gate 				if (vp == p->p_exec)
16937c478bd9Sstevel@tonic-gate 					(void) strcpy(mp->pr_mapname, "a.out");
16947c478bd9Sstevel@tonic-gate 				else
16957c478bd9Sstevel@tonic-gate 					pr_object_name(mp->pr_mapname,
16967c478bd9Sstevel@tonic-gate 					    vp, &vattr);
16977c478bd9Sstevel@tonic-gate 			}
16987c478bd9Sstevel@tonic-gate 
16997c478bd9Sstevel@tonic-gate 			/*
17007c478bd9Sstevel@tonic-gate 			 * Get the SysV shared memory id, if any.
17017c478bd9Sstevel@tonic-gate 			 */
17027c478bd9Sstevel@tonic-gate 			if ((mp->pr_mflags & MA_SHARED) && p->p_segacct &&
17037c478bd9Sstevel@tonic-gate 			    (mp->pr_shmid = shmgetid(p, seg->s_base)) !=
17047c478bd9Sstevel@tonic-gate 			    SHMID_NONE) {
17057c478bd9Sstevel@tonic-gate 				if (mp->pr_shmid == SHMID_FREE)
17067c478bd9Sstevel@tonic-gate 					mp->pr_shmid = -1;
17077c478bd9Sstevel@tonic-gate 
17087c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_SHM;
17097c478bd9Sstevel@tonic-gate 			} else {
17107c478bd9Sstevel@tonic-gate 				mp->pr_shmid = -1;
17117c478bd9Sstevel@tonic-gate 			}
17127c478bd9Sstevel@tonic-gate 		}
17137c478bd9Sstevel@tonic-gate 		ASSERT(tmp == NULL);
17147c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
17157c478bd9Sstevel@tonic-gate 
1716870619e9Sfrankho 	return (0);
17177c478bd9Sstevel@tonic-gate }
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
17207c478bd9Sstevel@tonic-gate int
1721870619e9Sfrankho prgetmap32(proc_t *p, int reserved, list_t *iolhead)
17227c478bd9Sstevel@tonic-gate {
17237c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
17247c478bd9Sstevel@tonic-gate 	prmap32_t *mp;
17257c478bd9Sstevel@tonic-gate 	struct seg *seg;
17267c478bd9Sstevel@tonic-gate 	struct seg *brkseg, *stkseg;
17277c478bd9Sstevel@tonic-gate 	struct vnode *vp;
17287c478bd9Sstevel@tonic-gate 	struct vattr vattr;
17297c478bd9Sstevel@tonic-gate 	uint_t prot;
17307c478bd9Sstevel@tonic-gate 
1731*dc32d872SJosef 'Jeff' Sipek 	ASSERT(as != &kas && AS_WRITE_HELD(as));
17327c478bd9Sstevel@tonic-gate 
1733870619e9Sfrankho 	/*
1734870619e9Sfrankho 	 * Request an initial buffer size that doesn't waste memory
1735870619e9Sfrankho 	 * if the address space has only a small number of segments.
1736870619e9Sfrankho 	 */
1737870619e9Sfrankho 	pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL)
17407c478bd9Sstevel@tonic-gate 		return (0);
17417c478bd9Sstevel@tonic-gate 
17427c478bd9Sstevel@tonic-gate 	brkseg = break_seg(p);
17437c478bd9Sstevel@tonic-gate 	stkseg = as_segat(as, prgetstackbase(p));
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate 	do {
17467c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, reserved);
17477c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr;
17487c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
17517c478bd9Sstevel@tonic-gate 			prot = pr_getprot(seg, reserved, &tmp,
17527c478bd9Sstevel@tonic-gate 			    &saddr, &naddr, eaddr);
17537c478bd9Sstevel@tonic-gate 			if (saddr == naddr)
17547c478bd9Sstevel@tonic-gate 				continue;
17557c478bd9Sstevel@tonic-gate 
1756870619e9Sfrankho 			mp = pr_iol_newbuf(iolhead, sizeof (*mp));
1757870619e9Sfrankho 
17587c478bd9Sstevel@tonic-gate 			mp->pr_vaddr = (caddr32_t)(uintptr_t)saddr;
17597c478bd9Sstevel@tonic-gate 			mp->pr_size = (size32_t)(naddr - saddr);
17607c478bd9Sstevel@tonic-gate 			mp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
17617c478bd9Sstevel@tonic-gate 			mp->pr_mflags = 0;
17627c478bd9Sstevel@tonic-gate 			if (prot & PROT_READ)
17637c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_READ;
17647c478bd9Sstevel@tonic-gate 			if (prot & PROT_WRITE)
17657c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_WRITE;
17667c478bd9Sstevel@tonic-gate 			if (prot & PROT_EXEC)
17677c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_EXEC;
17687c478bd9Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_SHARED)
17697c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_SHARED;
17707c478bd9Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_NORESERVE)
17717c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_NORESERVE;
17727c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops ||
17737c478bd9Sstevel@tonic-gate 			    (seg->s_ops == &segvn_ops &&
17747c478bd9Sstevel@tonic-gate 			    (SEGOP_GETVP(seg, saddr, &vp) != 0 || vp == NULL)))
17757c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_ANON;
17767c478bd9Sstevel@tonic-gate 			if (seg == brkseg)
17777c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_BREAK;
17787c478bd9Sstevel@tonic-gate 			else if (seg == stkseg) {
17797c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_STACK;
17807c478bd9Sstevel@tonic-gate 				if (reserved) {
17817c478bd9Sstevel@tonic-gate 					size_t maxstack =
17827c478bd9Sstevel@tonic-gate 					    ((size_t)p->p_stk_ctl +
17837c478bd9Sstevel@tonic-gate 					    PAGEOFFSET) & PAGEMASK;
17847c478bd9Sstevel@tonic-gate 					uintptr_t vaddr =
17857c478bd9Sstevel@tonic-gate 					    (uintptr_t)prgetstackbase(p) +
17867c478bd9Sstevel@tonic-gate 					    p->p_stksize - maxstack;
17877c478bd9Sstevel@tonic-gate 					mp->pr_vaddr = (caddr32_t)vaddr;
17887c478bd9Sstevel@tonic-gate 					mp->pr_size = (size32_t)
17897c478bd9Sstevel@tonic-gate 					    ((uintptr_t)naddr - vaddr);
17907c478bd9Sstevel@tonic-gate 				}
17917c478bd9Sstevel@tonic-gate 			}
17927c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops)
17937c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_ISM | MA_SHM;
17947c478bd9Sstevel@tonic-gate 			mp->pr_pagesize = PAGESIZE;
17957c478bd9Sstevel@tonic-gate 
17967c478bd9Sstevel@tonic-gate 			/*
17977c478bd9Sstevel@tonic-gate 			 * Manufacture a filename for the "object" directory.
17987c478bd9Sstevel@tonic-gate 			 */
17997c478bd9Sstevel@tonic-gate 			vattr.va_mask = AT_FSID|AT_NODEID;
18007c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segvn_ops &&
18017c478bd9Sstevel@tonic-gate 			    SEGOP_GETVP(seg, saddr, &vp) == 0 &&
18027c478bd9Sstevel@tonic-gate 			    vp != NULL && vp->v_type == VREG &&
1803da6c28aaSamw 			    VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
18047c478bd9Sstevel@tonic-gate 				if (vp == p->p_exec)
18057c478bd9Sstevel@tonic-gate 					(void) strcpy(mp->pr_mapname, "a.out");
18067c478bd9Sstevel@tonic-gate 				else
18077c478bd9Sstevel@tonic-gate 					pr_object_name(mp->pr_mapname,
18087c478bd9Sstevel@tonic-gate 					    vp, &vattr);
18097c478bd9Sstevel@tonic-gate 			}
18107c478bd9Sstevel@tonic-gate 
18117c478bd9Sstevel@tonic-gate 			/*
18127c478bd9Sstevel@tonic-gate 			 * Get the SysV shared memory id, if any.
18137c478bd9Sstevel@tonic-gate 			 */
18147c478bd9Sstevel@tonic-gate 			if ((mp->pr_mflags & MA_SHARED) && p->p_segacct &&
18157c478bd9Sstevel@tonic-gate 			    (mp->pr_shmid = shmgetid(p, seg->s_base)) !=
18167c478bd9Sstevel@tonic-gate 			    SHMID_NONE) {
18177c478bd9Sstevel@tonic-gate 				if (mp->pr_shmid == SHMID_FREE)
18187c478bd9Sstevel@tonic-gate 					mp->pr_shmid = -1;
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_SHM;
18217c478bd9Sstevel@tonic-gate 			} else {
18227c478bd9Sstevel@tonic-gate 				mp->pr_shmid = -1;
18237c478bd9Sstevel@tonic-gate 			}
18247c478bd9Sstevel@tonic-gate 		}
18257c478bd9Sstevel@tonic-gate 		ASSERT(tmp == NULL);
18267c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
18277c478bd9Sstevel@tonic-gate 
1828870619e9Sfrankho 	return (0);
18297c478bd9Sstevel@tonic-gate }
18307c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
18317c478bd9Sstevel@tonic-gate 
18327c478bd9Sstevel@tonic-gate /*
18337c478bd9Sstevel@tonic-gate  * Return the size of the /proc page data file.
18347c478bd9Sstevel@tonic-gate  */
18357c478bd9Sstevel@tonic-gate size_t
18367c478bd9Sstevel@tonic-gate prpdsize(struct as *as)
18377c478bd9Sstevel@tonic-gate {
18387c478bd9Sstevel@tonic-gate 	struct seg *seg;
18397c478bd9Sstevel@tonic-gate 	size_t size;
18407c478bd9Sstevel@tonic-gate 
1841*dc32d872SJosef 'Jeff' Sipek 	ASSERT(as != &kas && AS_WRITE_HELD(as));
18427c478bd9Sstevel@tonic-gate 
18437c478bd9Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL)
18447c478bd9Sstevel@tonic-gate 		return (0);
18457c478bd9Sstevel@tonic-gate 
18467c478bd9Sstevel@tonic-gate 	size = sizeof (prpageheader_t);
18477c478bd9Sstevel@tonic-gate 	do {
18487c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
18497c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr;
18507c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
18517c478bd9Sstevel@tonic-gate 		size_t npage;
18527c478bd9Sstevel@tonic-gate 
18537c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
18547c478bd9Sstevel@tonic-gate 			(void) pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
18557c478bd9Sstevel@tonic-gate 			if ((npage = (naddr - saddr) / PAGESIZE) != 0)
18567c478bd9Sstevel@tonic-gate 				size += sizeof (prasmap_t) + round8(npage);
18577c478bd9Sstevel@tonic-gate 		}
18587c478bd9Sstevel@tonic-gate 		ASSERT(tmp == NULL);
18597c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 	return (size);
18627c478bd9Sstevel@tonic-gate }
18637c478bd9Sstevel@tonic-gate 
18647c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
18657c478bd9Sstevel@tonic-gate size_t
18667c478bd9Sstevel@tonic-gate prpdsize32(struct as *as)
18677c478bd9Sstevel@tonic-gate {
18687c478bd9Sstevel@tonic-gate 	struct seg *seg;
18697c478bd9Sstevel@tonic-gate 	size_t size;
18707c478bd9Sstevel@tonic-gate 
1871*dc32d872SJosef 'Jeff' Sipek 	ASSERT(as != &kas && AS_WRITE_HELD(as));
18727c478bd9Sstevel@tonic-gate 
18737c478bd9Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL)
18747c478bd9Sstevel@tonic-gate 		return (0);
18757c478bd9Sstevel@tonic-gate 
18767c478bd9Sstevel@tonic-gate 	size = sizeof (prpageheader32_t);
18777c478bd9Sstevel@tonic-gate 	do {
18787c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
18797c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr;
18807c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
18817c478bd9Sstevel@tonic-gate 		size_t npage;
18827c478bd9Sstevel@tonic-gate 
18837c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
18847c478bd9Sstevel@tonic-gate 			(void) pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
18857c478bd9Sstevel@tonic-gate 			if ((npage = (naddr - saddr) / PAGESIZE) != 0)
18867c478bd9Sstevel@tonic-gate 				size += sizeof (prasmap32_t) + round8(npage);
18877c478bd9Sstevel@tonic-gate 		}
18887c478bd9Sstevel@tonic-gate 		ASSERT(tmp == NULL);
18897c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
18907c478bd9Sstevel@tonic-gate 
18917c478bd9Sstevel@tonic-gate 	return (size);
18927c478bd9Sstevel@tonic-gate }
18937c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate /*
18967c478bd9Sstevel@tonic-gate  * Read page data information.
18977c478bd9Sstevel@tonic-gate  */
18987c478bd9Sstevel@tonic-gate int
18997c478bd9Sstevel@tonic-gate prpdread(proc_t *p, uint_t hatid, struct uio *uiop)
19007c478bd9Sstevel@tonic-gate {
19017c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
19027c478bd9Sstevel@tonic-gate 	caddr_t buf;
19037c478bd9Sstevel@tonic-gate 	size_t size;
19047c478bd9Sstevel@tonic-gate 	prpageheader_t *php;
19057c478bd9Sstevel@tonic-gate 	prasmap_t *pmp;
19067c478bd9Sstevel@tonic-gate 	struct seg *seg;
19077c478bd9Sstevel@tonic-gate 	int error;
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate again:
1910*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_ENTER(as, RW_WRITER);
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL) {
1913*dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_EXIT(as);
19147c478bd9Sstevel@tonic-gate 		return (0);
19157c478bd9Sstevel@tonic-gate 	}
19167c478bd9Sstevel@tonic-gate 	size = prpdsize(as);
19177c478bd9Sstevel@tonic-gate 	if (uiop->uio_resid < size) {
1918*dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_EXIT(as);
19197c478bd9Sstevel@tonic-gate 		return (E2BIG);
19207c478bd9Sstevel@tonic-gate 	}
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate 	buf = kmem_zalloc(size, KM_SLEEP);
19237c478bd9Sstevel@tonic-gate 	php = (prpageheader_t *)buf;
19247c478bd9Sstevel@tonic-gate 	pmp = (prasmap_t *)(buf + sizeof (prpageheader_t));
19257c478bd9Sstevel@tonic-gate 
19267c478bd9Sstevel@tonic-gate 	hrt2ts(gethrtime(), &php->pr_tstamp);
19277c478bd9Sstevel@tonic-gate 	php->pr_nmap = 0;
19287c478bd9Sstevel@tonic-gate 	php->pr_npage = 0;
19297c478bd9Sstevel@tonic-gate 	do {
19307c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
19317c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr;
19327c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
19337c478bd9Sstevel@tonic-gate 
19347c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
19357c478bd9Sstevel@tonic-gate 			struct vnode *vp;
19367c478bd9Sstevel@tonic-gate 			struct vattr vattr;
19377c478bd9Sstevel@tonic-gate 			size_t len;
19387c478bd9Sstevel@tonic-gate 			size_t npage;
19397c478bd9Sstevel@tonic-gate 			uint_t prot;
19407c478bd9Sstevel@tonic-gate 			uintptr_t next;
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 			prot = pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
19437c478bd9Sstevel@tonic-gate 			if ((len = (size_t)(naddr - saddr)) == 0)
19447c478bd9Sstevel@tonic-gate 				continue;
19457c478bd9Sstevel@tonic-gate 			npage = len / PAGESIZE;
19467c478bd9Sstevel@tonic-gate 			next = (uintptr_t)(pmp + 1) + round8(npage);
19477c478bd9Sstevel@tonic-gate 			/*
19487c478bd9Sstevel@tonic-gate 			 * It's possible that the address space can change
19497c478bd9Sstevel@tonic-gate 			 * subtlely even though we're holding as->a_lock
19507c478bd9Sstevel@tonic-gate 			 * due to the nondeterminism of page_exists() in
19517c478bd9Sstevel@tonic-gate 			 * the presence of asychronously flushed pages or
19527c478bd9Sstevel@tonic-gate 			 * mapped files whose sizes are changing.
19537c478bd9Sstevel@tonic-gate 			 * page_exists() may be called indirectly from
19547c478bd9Sstevel@tonic-gate 			 * pr_getprot() by a SEGOP_INCORE() routine.
19557c478bd9Sstevel@tonic-gate 			 * If this happens we need to make sure we don't
19567c478bd9Sstevel@tonic-gate 			 * overrun the buffer whose size we computed based
19577c478bd9Sstevel@tonic-gate 			 * on the initial iteration through the segments.
19587c478bd9Sstevel@tonic-gate 			 * Once we've detected an overflow, we need to clean
19597c478bd9Sstevel@tonic-gate 			 * up the temporary memory allocated in pr_getprot()
19607c478bd9Sstevel@tonic-gate 			 * and retry. If there's a pending signal, we return
19617c478bd9Sstevel@tonic-gate 			 * EINTR so that this thread can be dislodged if
19627c478bd9Sstevel@tonic-gate 			 * a latent bug causes us to spin indefinitely.
19637c478bd9Sstevel@tonic-gate 			 */
19647c478bd9Sstevel@tonic-gate 			if (next > (uintptr_t)buf + size) {
19657c478bd9Sstevel@tonic-gate 				pr_getprot_done(&tmp);
1966*dc32d872SJosef 'Jeff' Sipek 				AS_LOCK_EXIT(as);
19677c478bd9Sstevel@tonic-gate 
19687c478bd9Sstevel@tonic-gate 				kmem_free(buf, size);
19697c478bd9Sstevel@tonic-gate 
19707c478bd9Sstevel@tonic-gate 				if (ISSIG(curthread, JUSTLOOKING))
19717c478bd9Sstevel@tonic-gate 					return (EINTR);
19727c478bd9Sstevel@tonic-gate 
19737c478bd9Sstevel@tonic-gate 				goto again;
19747c478bd9Sstevel@tonic-gate 			}
19757c478bd9Sstevel@tonic-gate 
19767c478bd9Sstevel@tonic-gate 			php->pr_nmap++;
19777c478bd9Sstevel@tonic-gate 			php->pr_npage += npage;
19787c478bd9Sstevel@tonic-gate 			pmp->pr_vaddr = (uintptr_t)saddr;
19797c478bd9Sstevel@tonic-gate 			pmp->pr_npage = npage;
19807c478bd9Sstevel@tonic-gate 			pmp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
19817c478bd9Sstevel@tonic-gate 			pmp->pr_mflags = 0;
19827c478bd9Sstevel@tonic-gate 			if (prot & PROT_READ)
19837c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_READ;
19847c478bd9Sstevel@tonic-gate 			if (prot & PROT_WRITE)
19857c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_WRITE;
19867c478bd9Sstevel@tonic-gate 			if (prot & PROT_EXEC)
19877c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_EXEC;
19887c478bd9Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_SHARED)
19897c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_SHARED;
19907c478bd9Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_NORESERVE)
19917c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_NORESERVE;
19927c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops ||
19937c478bd9Sstevel@tonic-gate 			    (seg->s_ops == &segvn_ops &&
19947c478bd9Sstevel@tonic-gate 			    (SEGOP_GETVP(seg, saddr, &vp) != 0 || vp == NULL)))
19957c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_ANON;
19967c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops)
19977c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_ISM | MA_SHM;
19987c478bd9Sstevel@tonic-gate 			pmp->pr_pagesize = PAGESIZE;
19997c478bd9Sstevel@tonic-gate 			/*
20007c478bd9Sstevel@tonic-gate 			 * Manufacture a filename for the "object" directory.
20017c478bd9Sstevel@tonic-gate 			 */
20027c478bd9Sstevel@tonic-gate 			vattr.va_mask = AT_FSID|AT_NODEID;
20037c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segvn_ops &&
20047c478bd9Sstevel@tonic-gate 			    SEGOP_GETVP(seg, saddr, &vp) == 0 &&
20057c478bd9Sstevel@tonic-gate 			    vp != NULL && vp->v_type == VREG &&
2006da6c28aaSamw 			    VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
20077c478bd9Sstevel@tonic-gate 				if (vp == p->p_exec)
20087c478bd9Sstevel@tonic-gate 					(void) strcpy(pmp->pr_mapname, "a.out");
20097c478bd9Sstevel@tonic-gate 				else
20107c478bd9Sstevel@tonic-gate 					pr_object_name(pmp->pr_mapname,
20117c478bd9Sstevel@tonic-gate 					    vp, &vattr);
20127c478bd9Sstevel@tonic-gate 			}
20137c478bd9Sstevel@tonic-gate 
20147c478bd9Sstevel@tonic-gate 			/*
20157c478bd9Sstevel@tonic-gate 			 * Get the SysV shared memory id, if any.
20167c478bd9Sstevel@tonic-gate 			 */
20177c478bd9Sstevel@tonic-gate 			if ((pmp->pr_mflags & MA_SHARED) && p->p_segacct &&
20187c478bd9Sstevel@tonic-gate 			    (pmp->pr_shmid = shmgetid(p, seg->s_base)) !=
20197c478bd9Sstevel@tonic-gate 			    SHMID_NONE) {
20207c478bd9Sstevel@tonic-gate 				if (pmp->pr_shmid == SHMID_FREE)
20217c478bd9Sstevel@tonic-gate 					pmp->pr_shmid = -1;
20227c478bd9Sstevel@tonic-gate 
20237c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_SHM;
20247c478bd9Sstevel@tonic-gate 			} else {
20257c478bd9Sstevel@tonic-gate 				pmp->pr_shmid = -1;
20267c478bd9Sstevel@tonic-gate 			}
20277c478bd9Sstevel@tonic-gate 
20287c478bd9Sstevel@tonic-gate 			hat_getstat(as, saddr, len, hatid,
20297c478bd9Sstevel@tonic-gate 			    (char *)(pmp + 1), HAT_SYNC_ZERORM);
20307c478bd9Sstevel@tonic-gate 			pmp = (prasmap_t *)next;
20317c478bd9Sstevel@tonic-gate 		}
20327c478bd9Sstevel@tonic-gate 		ASSERT(tmp == NULL);
20337c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
20347c478bd9Sstevel@tonic-gate 
2035*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
20367c478bd9Sstevel@tonic-gate 
20377c478bd9Sstevel@tonic-gate 	ASSERT((uintptr_t)pmp <= (uintptr_t)buf + size);
20387c478bd9Sstevel@tonic-gate 	error = uiomove(buf, (caddr_t)pmp - buf, UIO_READ, uiop);
20397c478bd9Sstevel@tonic-gate 	kmem_free(buf, size);
20407c478bd9Sstevel@tonic-gate 
20417c478bd9Sstevel@tonic-gate 	return (error);
20427c478bd9Sstevel@tonic-gate }
20437c478bd9Sstevel@tonic-gate 
20447c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
20457c478bd9Sstevel@tonic-gate int
20467c478bd9Sstevel@tonic-gate prpdread32(proc_t *p, uint_t hatid, struct uio *uiop)
20477c478bd9Sstevel@tonic-gate {
20487c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
20497c478bd9Sstevel@tonic-gate 	caddr_t buf;
20507c478bd9Sstevel@tonic-gate 	size_t size;
20517c478bd9Sstevel@tonic-gate 	prpageheader32_t *php;
20527c478bd9Sstevel@tonic-gate 	prasmap32_t *pmp;
20537c478bd9Sstevel@tonic-gate 	struct seg *seg;
20547c478bd9Sstevel@tonic-gate 	int error;
20557c478bd9Sstevel@tonic-gate 
20567c478bd9Sstevel@tonic-gate again:
2057*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_ENTER(as, RW_WRITER);
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL) {
2060*dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_EXIT(as);
20617c478bd9Sstevel@tonic-gate 		return (0);
20627c478bd9Sstevel@tonic-gate 	}
20637c478bd9Sstevel@tonic-gate 	size = prpdsize32(as);
20647c478bd9Sstevel@tonic-gate 	if (uiop->uio_resid < size) {
2065*dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_EXIT(as);
20667c478bd9Sstevel@tonic-gate 		return (E2BIG);
20677c478bd9Sstevel@tonic-gate 	}
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 	buf = kmem_zalloc(size, KM_SLEEP);
20707c478bd9Sstevel@tonic-gate 	php = (prpageheader32_t *)buf;
20717c478bd9Sstevel@tonic-gate 	pmp = (prasmap32_t *)(buf + sizeof (prpageheader32_t));
20727c478bd9Sstevel@tonic-gate 
20737c478bd9Sstevel@tonic-gate 	hrt2ts32(gethrtime(), &php->pr_tstamp);
20747c478bd9Sstevel@tonic-gate 	php->pr_nmap = 0;
20757c478bd9Sstevel@tonic-gate 	php->pr_npage = 0;
20767c478bd9Sstevel@tonic-gate 	do {
20777c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
20787c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr;
20797c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
20807c478bd9Sstevel@tonic-gate 
20817c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
20827c478bd9Sstevel@tonic-gate 			struct vnode *vp;
20837c478bd9Sstevel@tonic-gate 			struct vattr vattr;
20847c478bd9Sstevel@tonic-gate 			size_t len;
20857c478bd9Sstevel@tonic-gate 			size_t npage;
20867c478bd9Sstevel@tonic-gate 			uint_t prot;
20877c478bd9Sstevel@tonic-gate 			uintptr_t next;
20887c478bd9Sstevel@tonic-gate 
20897c478bd9Sstevel@tonic-gate 			prot = pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
20907c478bd9Sstevel@tonic-gate 			if ((len = (size_t)(naddr - saddr)) == 0)
20917c478bd9Sstevel@tonic-gate 				continue;
20927c478bd9Sstevel@tonic-gate 			npage = len / PAGESIZE;
20937c478bd9Sstevel@tonic-gate 			next = (uintptr_t)(pmp + 1) + round8(npage);
20947c478bd9Sstevel@tonic-gate 			/*
20957c478bd9Sstevel@tonic-gate 			 * It's possible that the address space can change
20967c478bd9Sstevel@tonic-gate 			 * subtlely even though we're holding as->a_lock
20977c478bd9Sstevel@tonic-gate 			 * due to the nondeterminism of page_exists() in
20987c478bd9Sstevel@tonic-gate 			 * the presence of asychronously flushed pages or
20997c478bd9Sstevel@tonic-gate 			 * mapped files whose sizes are changing.
21007c478bd9Sstevel@tonic-gate 			 * page_exists() may be called indirectly from
21017c478bd9Sstevel@tonic-gate 			 * pr_getprot() by a SEGOP_INCORE() routine.
21027c478bd9Sstevel@tonic-gate 			 * If this happens we need to make sure we don't
21037c478bd9Sstevel@tonic-gate 			 * overrun the buffer whose size we computed based
21047c478bd9Sstevel@tonic-gate 			 * on the initial iteration through the segments.
21057c478bd9Sstevel@tonic-gate 			 * Once we've detected an overflow, we need to clean
21067c478bd9Sstevel@tonic-gate 			 * up the temporary memory allocated in pr_getprot()
21077c478bd9Sstevel@tonic-gate 			 * and retry. If there's a pending signal, we return
21087c478bd9Sstevel@tonic-gate 			 * EINTR so that this thread can be dislodged if
21097c478bd9Sstevel@tonic-gate 			 * a latent bug causes us to spin indefinitely.
21107c478bd9Sstevel@tonic-gate 			 */
21117c478bd9Sstevel@tonic-gate 			if (next > (uintptr_t)buf + size) {
21127c478bd9Sstevel@tonic-gate 				pr_getprot_done(&tmp);
2113*dc32d872SJosef 'Jeff' Sipek 				AS_LOCK_EXIT(as);
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 				kmem_free(buf, size);
21167c478bd9Sstevel@tonic-gate 
21177c478bd9Sstevel@tonic-gate 				if (ISSIG(curthread, JUSTLOOKING))
21187c478bd9Sstevel@tonic-gate 					return (EINTR);
21197c478bd9Sstevel@tonic-gate 
21207c478bd9Sstevel@tonic-gate 				goto again;
21217c478bd9Sstevel@tonic-gate 			}
21227c478bd9Sstevel@tonic-gate 
21237c478bd9Sstevel@tonic-gate 			php->pr_nmap++;
21247c478bd9Sstevel@tonic-gate 			php->pr_npage += npage;
21257c478bd9Sstevel@tonic-gate 			pmp->pr_vaddr = (caddr32_t)(uintptr_t)saddr;
21267c478bd9Sstevel@tonic-gate 			pmp->pr_npage = (size32_t)npage;
21277c478bd9Sstevel@tonic-gate 			pmp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
21287c478bd9Sstevel@tonic-gate 			pmp->pr_mflags = 0;
21297c478bd9Sstevel@tonic-gate 			if (prot & PROT_READ)
21307c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_READ;
21317c478bd9Sstevel@tonic-gate 			if (prot & PROT_WRITE)
21327c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_WRITE;
21337c478bd9Sstevel@tonic-gate 			if (prot & PROT_EXEC)
21347c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_EXEC;
21357c478bd9Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_SHARED)
21367c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_SHARED;
21377c478bd9Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_NORESERVE)
21387c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_NORESERVE;
21397c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops ||
21407c478bd9Sstevel@tonic-gate 			    (seg->s_ops == &segvn_ops &&
21417c478bd9Sstevel@tonic-gate 			    (SEGOP_GETVP(seg, saddr, &vp) != 0 || vp == NULL)))
21427c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_ANON;
21437c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops)
21447c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_ISM | MA_SHM;
21457c478bd9Sstevel@tonic-gate 			pmp->pr_pagesize = PAGESIZE;
21467c478bd9Sstevel@tonic-gate 			/*
21477c478bd9Sstevel@tonic-gate 			 * Manufacture a filename for the "object" directory.
21487c478bd9Sstevel@tonic-gate 			 */
21497c478bd9Sstevel@tonic-gate 			vattr.va_mask = AT_FSID|AT_NODEID;
21507c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segvn_ops &&
21517c478bd9Sstevel@tonic-gate 			    SEGOP_GETVP(seg, saddr, &vp) == 0 &&
21527c478bd9Sstevel@tonic-gate 			    vp != NULL && vp->v_type == VREG &&
2153da6c28aaSamw 			    VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
21547c478bd9Sstevel@tonic-gate 				if (vp == p->p_exec)
21557c478bd9Sstevel@tonic-gate 					(void) strcpy(pmp->pr_mapname, "a.out");
21567c478bd9Sstevel@tonic-gate 				else
21577c478bd9Sstevel@tonic-gate 					pr_object_name(pmp->pr_mapname,
21587c478bd9Sstevel@tonic-gate 					    vp, &vattr);
21597c478bd9Sstevel@tonic-gate 			}
21607c478bd9Sstevel@tonic-gate 
21617c478bd9Sstevel@tonic-gate 			/*
21627c478bd9Sstevel@tonic-gate 			 * Get the SysV shared memory id, if any.
21637c478bd9Sstevel@tonic-gate 			 */
21647c478bd9Sstevel@tonic-gate 			if ((pmp->pr_mflags & MA_SHARED) && p->p_segacct &&
21657c478bd9Sstevel@tonic-gate 			    (pmp->pr_shmid = shmgetid(p, seg->s_base)) !=
21667c478bd9Sstevel@tonic-gate 			    SHMID_NONE) {
21677c478bd9Sstevel@tonic-gate 				if (pmp->pr_shmid == SHMID_FREE)
21687c478bd9Sstevel@tonic-gate 					pmp->pr_shmid = -1;
21697c478bd9Sstevel@tonic-gate 
21707c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_SHM;
21717c478bd9Sstevel@tonic-gate 			} else {
21727c478bd9Sstevel@tonic-gate 				pmp->pr_shmid = -1;
21737c478bd9Sstevel@tonic-gate 			}
21747c478bd9Sstevel@tonic-gate 
21757c478bd9Sstevel@tonic-gate 			hat_getstat(as, saddr, len, hatid,
21767c478bd9Sstevel@tonic-gate 			    (char *)(pmp + 1), HAT_SYNC_ZERORM);
21777c478bd9Sstevel@tonic-gate 			pmp = (prasmap32_t *)next;
21787c478bd9Sstevel@tonic-gate 		}
21797c478bd9Sstevel@tonic-gate 		ASSERT(tmp == NULL);
21807c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
21817c478bd9Sstevel@tonic-gate 
2182*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
21837c478bd9Sstevel@tonic-gate 
21847c478bd9Sstevel@tonic-gate 	ASSERT((uintptr_t)pmp <= (uintptr_t)buf + size);
21857c478bd9Sstevel@tonic-gate 	error = uiomove(buf, (caddr_t)pmp - buf, UIO_READ, uiop);
21867c478bd9Sstevel@tonic-gate 	kmem_free(buf, size);
21877c478bd9Sstevel@tonic-gate 
21887c478bd9Sstevel@tonic-gate 	return (error);
21897c478bd9Sstevel@tonic-gate }
21907c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
21917c478bd9Sstevel@tonic-gate 
21927c478bd9Sstevel@tonic-gate ushort_t
21937c478bd9Sstevel@tonic-gate prgetpctcpu(uint64_t pct)
21947c478bd9Sstevel@tonic-gate {
21957c478bd9Sstevel@tonic-gate 	/*
21967c478bd9Sstevel@tonic-gate 	 * The value returned will be relevant in the zone of the examiner,
21977c478bd9Sstevel@tonic-gate 	 * which may not be the same as the zone which performed the procfs
21987c478bd9Sstevel@tonic-gate 	 * mount.
21997c478bd9Sstevel@tonic-gate 	 */
22007c478bd9Sstevel@tonic-gate 	int nonline = zone_ncpus_online_get(curproc->p_zone);
22017c478bd9Sstevel@tonic-gate 
22027c478bd9Sstevel@tonic-gate 	/*
22037c478bd9Sstevel@tonic-gate 	 * Prorate over online cpus so we don't exceed 100%
22047c478bd9Sstevel@tonic-gate 	 */
22057c478bd9Sstevel@tonic-gate 	if (nonline > 1)
22067c478bd9Sstevel@tonic-gate 		pct /= nonline;
22077c478bd9Sstevel@tonic-gate 	pct >>= 16;		/* convert to 16-bit scaled integer */
22087c478bd9Sstevel@tonic-gate 	if (pct > 0x8000)	/* might happen, due to rounding */
22097c478bd9Sstevel@tonic-gate 		pct = 0x8000;
22107c478bd9Sstevel@tonic-gate 	return ((ushort_t)pct);
22117c478bd9Sstevel@tonic-gate }
22127c478bd9Sstevel@tonic-gate 
22137c478bd9Sstevel@tonic-gate /*
22147c478bd9Sstevel@tonic-gate  * Return information used by ps(1).
22157c478bd9Sstevel@tonic-gate  */
22167c478bd9Sstevel@tonic-gate void
22177c478bd9Sstevel@tonic-gate prgetpsinfo(proc_t *p, psinfo_t *psp)
22187c478bd9Sstevel@tonic-gate {
22197c478bd9Sstevel@tonic-gate 	kthread_t *t;
22207c478bd9Sstevel@tonic-gate 	struct cred *cred;
22217c478bd9Sstevel@tonic-gate 	hrtime_t hrutime, hrstime;
22227c478bd9Sstevel@tonic-gate 
22237c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
22247c478bd9Sstevel@tonic-gate 
22257c478bd9Sstevel@tonic-gate 	if ((t = prchoose(p)) == NULL)	/* returns locked thread */
22267c478bd9Sstevel@tonic-gate 		bzero(psp, sizeof (*psp));
22277c478bd9Sstevel@tonic-gate 	else {
22287c478bd9Sstevel@tonic-gate 		thread_unlock(t);
22297c478bd9Sstevel@tonic-gate 		bzero(psp, sizeof (*psp) - sizeof (psp->pr_lwp));
22307c478bd9Sstevel@tonic-gate 	}
22317c478bd9Sstevel@tonic-gate 
22327c478bd9Sstevel@tonic-gate 	/*
22337c478bd9Sstevel@tonic-gate 	 * only export SSYS and SMSACCT; everything else is off-limits to
22347c478bd9Sstevel@tonic-gate 	 * userland apps.
22357c478bd9Sstevel@tonic-gate 	 */
22367c478bd9Sstevel@tonic-gate 	psp->pr_flag = p->p_flag & (SSYS | SMSACCT);
22377c478bd9Sstevel@tonic-gate 	psp->pr_nlwp = p->p_lwpcnt;
22387c478bd9Sstevel@tonic-gate 	psp->pr_nzomb = p->p_zombcnt;
22397c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
22407c478bd9Sstevel@tonic-gate 	cred = p->p_cred;
22417c478bd9Sstevel@tonic-gate 	psp->pr_uid = crgetruid(cred);
22427c478bd9Sstevel@tonic-gate 	psp->pr_euid = crgetuid(cred);
22437c478bd9Sstevel@tonic-gate 	psp->pr_gid = crgetrgid(cred);
22447c478bd9Sstevel@tonic-gate 	psp->pr_egid = crgetgid(cred);
22457c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
22467c478bd9Sstevel@tonic-gate 	psp->pr_pid = p->p_pid;
22477c478bd9Sstevel@tonic-gate 	if (curproc->p_zone->zone_id != GLOBAL_ZONEID &&
22487c478bd9Sstevel@tonic-gate 	    (p->p_flag & SZONETOP)) {
22497c478bd9Sstevel@tonic-gate 		ASSERT(p->p_zone->zone_id != GLOBAL_ZONEID);
22507c478bd9Sstevel@tonic-gate 		/*
22517c478bd9Sstevel@tonic-gate 		 * Inside local zones, fake zsched's pid as parent pids for
22527c478bd9Sstevel@tonic-gate 		 * processes which reference processes outside of the zone.
22537c478bd9Sstevel@tonic-gate 		 */
22547c478bd9Sstevel@tonic-gate 		psp->pr_ppid = curproc->p_zone->zone_zsched->p_pid;
22557c478bd9Sstevel@tonic-gate 	} else {
22567c478bd9Sstevel@tonic-gate 		psp->pr_ppid = p->p_ppid;
22577c478bd9Sstevel@tonic-gate 	}
22587c478bd9Sstevel@tonic-gate 	psp->pr_pgid = p->p_pgrp;
22597c478bd9Sstevel@tonic-gate 	psp->pr_sid = p->p_sessp->s_sid;
22607c478bd9Sstevel@tonic-gate 	psp->pr_taskid = p->p_task->tk_tkid;
22617c478bd9Sstevel@tonic-gate 	psp->pr_projid = p->p_task->tk_proj->kpj_id;
22627c478bd9Sstevel@tonic-gate 	psp->pr_poolid = p->p_pool->pool_id;
22637c478bd9Sstevel@tonic-gate 	psp->pr_zoneid = p->p_zone->zone_id;
22647c478bd9Sstevel@tonic-gate 	if ((psp->pr_contract = PRCTID(p)) == 0)
22657c478bd9Sstevel@tonic-gate 		psp->pr_contract = -1;
22667c478bd9Sstevel@tonic-gate 	psp->pr_addr = (uintptr_t)prgetpsaddr(p);
22677c478bd9Sstevel@tonic-gate 	switch (p->p_model) {
22687c478bd9Sstevel@tonic-gate 	case DATAMODEL_ILP32:
22697c478bd9Sstevel@tonic-gate 		psp->pr_dmodel = PR_MODEL_ILP32;
22707c478bd9Sstevel@tonic-gate 		break;
22717c478bd9Sstevel@tonic-gate 	case DATAMODEL_LP64:
22727c478bd9Sstevel@tonic-gate 		psp->pr_dmodel = PR_MODEL_LP64;
22737c478bd9Sstevel@tonic-gate 		break;
22747c478bd9Sstevel@tonic-gate 	}
22757c478bd9Sstevel@tonic-gate 	hrutime = mstate_aggr_state(p, LMS_USER);
22767c478bd9Sstevel@tonic-gate 	hrstime = mstate_aggr_state(p, LMS_SYSTEM);
22777c478bd9Sstevel@tonic-gate 	hrt2ts((hrutime + hrstime), &psp->pr_time);
22787c478bd9Sstevel@tonic-gate 	TICK_TO_TIMESTRUC(p->p_cutime + p->p_cstime, &psp->pr_ctime);
22797c478bd9Sstevel@tonic-gate 
22807c478bd9Sstevel@tonic-gate 	if (t == NULL) {
22817c478bd9Sstevel@tonic-gate 		int wcode = p->p_wcode;		/* must be atomic read */
22827c478bd9Sstevel@tonic-gate 
22837c478bd9Sstevel@tonic-gate 		if (wcode)
22847c478bd9Sstevel@tonic-gate 			psp->pr_wstat = wstat(wcode, p->p_wdata);
22857c478bd9Sstevel@tonic-gate 		psp->pr_ttydev = PRNODEV;
22867c478bd9Sstevel@tonic-gate 		psp->pr_lwp.pr_state = SZOMB;
22877c478bd9Sstevel@tonic-gate 		psp->pr_lwp.pr_sname = 'Z';
22887c478bd9Sstevel@tonic-gate 		psp->pr_lwp.pr_bindpro = PBIND_NONE;
22897c478bd9Sstevel@tonic-gate 		psp->pr_lwp.pr_bindpset = PS_NONE;
22907c478bd9Sstevel@tonic-gate 	} else {
22917c478bd9Sstevel@tonic-gate 		user_t *up = PTOU(p);
22927c478bd9Sstevel@tonic-gate 		struct as *as;
22937c478bd9Sstevel@tonic-gate 		dev_t d;
22947c478bd9Sstevel@tonic-gate 		extern dev_t rwsconsdev, rconsdev, uconsdev;
22957c478bd9Sstevel@tonic-gate 
22967c478bd9Sstevel@tonic-gate 		d = cttydev(p);
22977c478bd9Sstevel@tonic-gate 		/*
22987c478bd9Sstevel@tonic-gate 		 * If the controlling terminal is the real
22997c478bd9Sstevel@tonic-gate 		 * or workstation console device, map to what the
230025b463cdSethindra 		 * user thinks is the console device. Handle case when
230125b463cdSethindra 		 * rwsconsdev or rconsdev is set to NODEV for Starfire.
23027c478bd9Sstevel@tonic-gate 		 */
230325b463cdSethindra 		if ((d == rwsconsdev || d == rconsdev) && d != NODEV)
23047c478bd9Sstevel@tonic-gate 			d = uconsdev;
23057c478bd9Sstevel@tonic-gate 		psp->pr_ttydev = (d == NODEV) ? PRNODEV : d;
23067c478bd9Sstevel@tonic-gate 		psp->pr_start = up->u_start;
23077c478bd9Sstevel@tonic-gate 		bcopy(up->u_comm, psp->pr_fname,
23087c478bd9Sstevel@tonic-gate 		    MIN(sizeof (up->u_comm), sizeof (psp->pr_fname)-1));
23097c478bd9Sstevel@tonic-gate 		bcopy(up->u_psargs, psp->pr_psargs,
23107c478bd9Sstevel@tonic-gate 		    MIN(PRARGSZ-1, PSARGSZ));
23117c478bd9Sstevel@tonic-gate 		psp->pr_argc = up->u_argc;
23127c478bd9Sstevel@tonic-gate 		psp->pr_argv = up->u_argv;
23137c478bd9Sstevel@tonic-gate 		psp->pr_envp = up->u_envp;
23147c478bd9Sstevel@tonic-gate 
23157c478bd9Sstevel@tonic-gate 		/* get the chosen lwp's lwpsinfo */
23167c478bd9Sstevel@tonic-gate 		prgetlwpsinfo(t, &psp->pr_lwp);
23177c478bd9Sstevel@tonic-gate 
23187c478bd9Sstevel@tonic-gate 		/* compute %cpu for the process */
23197c478bd9Sstevel@tonic-gate 		if (p->p_lwpcnt == 1)
23207c478bd9Sstevel@tonic-gate 			psp->pr_pctcpu = psp->pr_lwp.pr_pctcpu;
23217c478bd9Sstevel@tonic-gate 		else {
23227c478bd9Sstevel@tonic-gate 			uint64_t pct = 0;
23237c478bd9Sstevel@tonic-gate 			hrtime_t cur_time = gethrtime_unscaled();
23247c478bd9Sstevel@tonic-gate 
23257c478bd9Sstevel@tonic-gate 			t = p->p_tlist;
23267c478bd9Sstevel@tonic-gate 			do {
23277c478bd9Sstevel@tonic-gate 				pct += cpu_update_pct(t, cur_time);
23287c478bd9Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
23297c478bd9Sstevel@tonic-gate 
23307c478bd9Sstevel@tonic-gate 			psp->pr_pctcpu = prgetpctcpu(pct);
23317c478bd9Sstevel@tonic-gate 		}
23327c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
23337c478bd9Sstevel@tonic-gate 			psp->pr_size = 0;
23347c478bd9Sstevel@tonic-gate 			psp->pr_rssize = 0;
23357c478bd9Sstevel@tonic-gate 		} else {
23367c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
2337*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_READER);
233840688216SSudheer A 			psp->pr_size = btopr(as->a_resvsize) *
233940688216SSudheer A 			    (PAGESIZE / 1024);
23407c478bd9Sstevel@tonic-gate 			psp->pr_rssize = rm_asrss(as) * (PAGESIZE / 1024);
23417c478bd9Sstevel@tonic-gate 			psp->pr_pctmem = rm_pctmemory(as);
2342*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
23437c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
23447c478bd9Sstevel@tonic-gate 		}
23457c478bd9Sstevel@tonic-gate 	}
23467c478bd9Sstevel@tonic-gate }
23477c478bd9Sstevel@tonic-gate 
23487c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
23497c478bd9Sstevel@tonic-gate void
23507c478bd9Sstevel@tonic-gate prgetpsinfo32(proc_t *p, psinfo32_t *psp)
23517c478bd9Sstevel@tonic-gate {
23527c478bd9Sstevel@tonic-gate 	kthread_t *t;
23537c478bd9Sstevel@tonic-gate 	struct cred *cred;
23547c478bd9Sstevel@tonic-gate 	hrtime_t hrutime, hrstime;
23557c478bd9Sstevel@tonic-gate 
23567c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
23577c478bd9Sstevel@tonic-gate 
23587c478bd9Sstevel@tonic-gate 	if ((t = prchoose(p)) == NULL)	/* returns locked thread */
23597c478bd9Sstevel@tonic-gate 		bzero(psp, sizeof (*psp));
23607c478bd9Sstevel@tonic-gate 	else {
23617c478bd9Sstevel@tonic-gate 		thread_unlock(t);
23627c478bd9Sstevel@tonic-gate 		bzero(psp, sizeof (*psp) - sizeof (psp->pr_lwp));
23637c478bd9Sstevel@tonic-gate 	}
23647c478bd9Sstevel@tonic-gate 
23657c478bd9Sstevel@tonic-gate 	/*
23667c478bd9Sstevel@tonic-gate 	 * only export SSYS and SMSACCT; everything else is off-limits to
23677c478bd9Sstevel@tonic-gate 	 * userland apps.
23687c478bd9Sstevel@tonic-gate 	 */
23697c478bd9Sstevel@tonic-gate 	psp->pr_flag = p->p_flag & (SSYS | SMSACCT);
23707c478bd9Sstevel@tonic-gate 	psp->pr_nlwp = p->p_lwpcnt;
23717c478bd9Sstevel@tonic-gate 	psp->pr_nzomb = p->p_zombcnt;
23727c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
23737c478bd9Sstevel@tonic-gate 	cred = p->p_cred;
23747c478bd9Sstevel@tonic-gate 	psp->pr_uid = crgetruid(cred);
23757c478bd9Sstevel@tonic-gate 	psp->pr_euid = crgetuid(cred);
23767c478bd9Sstevel@tonic-gate 	psp->pr_gid = crgetrgid(cred);
23777c478bd9Sstevel@tonic-gate 	psp->pr_egid = crgetgid(cred);
23787c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
23797c478bd9Sstevel@tonic-gate 	psp->pr_pid = p->p_pid;
23807c478bd9Sstevel@tonic-gate 	if (curproc->p_zone->zone_id != GLOBAL_ZONEID &&
23817c478bd9Sstevel@tonic-gate 	    (p->p_flag & SZONETOP)) {
23827c478bd9Sstevel@tonic-gate 		ASSERT(p->p_zone->zone_id != GLOBAL_ZONEID);
23837c478bd9Sstevel@tonic-gate 		/*
23847c478bd9Sstevel@tonic-gate 		 * Inside local zones, fake zsched's pid as parent pids for
23857c478bd9Sstevel@tonic-gate 		 * processes which reference processes outside of the zone.
23867c478bd9Sstevel@tonic-gate 		 */
23877c478bd9Sstevel@tonic-gate 		psp->pr_ppid = curproc->p_zone->zone_zsched->p_pid;
23887c478bd9Sstevel@tonic-gate 	} else {
23897c478bd9Sstevel@tonic-gate 		psp->pr_ppid = p->p_ppid;
23907c478bd9Sstevel@tonic-gate 	}
23917c478bd9Sstevel@tonic-gate 	psp->pr_pgid = p->p_pgrp;
23927c478bd9Sstevel@tonic-gate 	psp->pr_sid = p->p_sessp->s_sid;
23937c478bd9Sstevel@tonic-gate 	psp->pr_taskid = p->p_task->tk_tkid;
23947c478bd9Sstevel@tonic-gate 	psp->pr_projid = p->p_task->tk_proj->kpj_id;
23957c478bd9Sstevel@tonic-gate 	psp->pr_poolid = p->p_pool->pool_id;
23967c478bd9Sstevel@tonic-gate 	psp->pr_zoneid = p->p_zone->zone_id;
23977c478bd9Sstevel@tonic-gate 	if ((psp->pr_contract = PRCTID(p)) == 0)
23987c478bd9Sstevel@tonic-gate 		psp->pr_contract = -1;
23997c478bd9Sstevel@tonic-gate 	psp->pr_addr = 0;	/* cannot represent 64-bit addr in 32 bits */
24007c478bd9Sstevel@tonic-gate 	switch (p->p_model) {
24017c478bd9Sstevel@tonic-gate 	case DATAMODEL_ILP32:
24027c478bd9Sstevel@tonic-gate 		psp->pr_dmodel = PR_MODEL_ILP32;
24037c478bd9Sstevel@tonic-gate 		break;
24047c478bd9Sstevel@tonic-gate 	case DATAMODEL_LP64:
24057c478bd9Sstevel@tonic-gate 		psp->pr_dmodel = PR_MODEL_LP64;
24067c478bd9Sstevel@tonic-gate 		break;
24077c478bd9Sstevel@tonic-gate 	}
24087c478bd9Sstevel@tonic-gate 	hrutime = mstate_aggr_state(p, LMS_USER);
24097c478bd9Sstevel@tonic-gate 	hrstime = mstate_aggr_state(p, LMS_SYSTEM);
24107c478bd9Sstevel@tonic-gate 	hrt2ts32(hrutime + hrstime, &psp->pr_time);
24117c478bd9Sstevel@tonic-gate 	TICK_TO_TIMESTRUC32(p->p_cutime + p->p_cstime, &psp->pr_ctime);
24127c478bd9Sstevel@tonic-gate 
24137c478bd9Sstevel@tonic-gate 	if (t == NULL) {
24147c478bd9Sstevel@tonic-gate 		extern int wstat(int, int);	/* needs a header file */
24157c478bd9Sstevel@tonic-gate 		int wcode = p->p_wcode;		/* must be atomic read */
24167c478bd9Sstevel@tonic-gate 
24177c478bd9Sstevel@tonic-gate 		if (wcode)
24187c478bd9Sstevel@tonic-gate 			psp->pr_wstat = wstat(wcode, p->p_wdata);
24197c478bd9Sstevel@tonic-gate 		psp->pr_ttydev = PRNODEV32;
24207c478bd9Sstevel@tonic-gate 		psp->pr_lwp.pr_state = SZOMB;
24217c478bd9Sstevel@tonic-gate 		psp->pr_lwp.pr_sname = 'Z';
24227c478bd9Sstevel@tonic-gate 	} else {
24237c478bd9Sstevel@tonic-gate 		user_t *up = PTOU(p);
24247c478bd9Sstevel@tonic-gate 		struct as *as;
24257c478bd9Sstevel@tonic-gate 		dev_t d;
24267c478bd9Sstevel@tonic-gate 		extern dev_t rwsconsdev, rconsdev, uconsdev;
24277c478bd9Sstevel@tonic-gate 
24287c478bd9Sstevel@tonic-gate 		d = cttydev(p);
24297c478bd9Sstevel@tonic-gate 		/*
24307c478bd9Sstevel@tonic-gate 		 * If the controlling terminal is the real
24317c478bd9Sstevel@tonic-gate 		 * or workstation console device, map to what the
243225b463cdSethindra 		 * user thinks is the console device. Handle case when
243325b463cdSethindra 		 * rwsconsdev or rconsdev is set to NODEV for Starfire.
24347c478bd9Sstevel@tonic-gate 		 */
243525b463cdSethindra 		if ((d == rwsconsdev || d == rconsdev) && d != NODEV)
24367c478bd9Sstevel@tonic-gate 			d = uconsdev;
24377c478bd9Sstevel@tonic-gate 		(void) cmpldev(&psp->pr_ttydev, d);
24387c478bd9Sstevel@tonic-gate 		TIMESPEC_TO_TIMESPEC32(&psp->pr_start, &up->u_start);
24397c478bd9Sstevel@tonic-gate 		bcopy(up->u_comm, psp->pr_fname,
24407c478bd9Sstevel@tonic-gate 		    MIN(sizeof (up->u_comm), sizeof (psp->pr_fname)-1));
24417c478bd9Sstevel@tonic-gate 		bcopy(up->u_psargs, psp->pr_psargs,
24427c478bd9Sstevel@tonic-gate 		    MIN(PRARGSZ-1, PSARGSZ));
24437c478bd9Sstevel@tonic-gate 		psp->pr_argc = up->u_argc;
24447c478bd9Sstevel@tonic-gate 		psp->pr_argv = (caddr32_t)up->u_argv;
24457c478bd9Sstevel@tonic-gate 		psp->pr_envp = (caddr32_t)up->u_envp;
24467c478bd9Sstevel@tonic-gate 
24477c478bd9Sstevel@tonic-gate 		/* get the chosen lwp's lwpsinfo */
24487c478bd9Sstevel@tonic-gate 		prgetlwpsinfo32(t, &psp->pr_lwp);
24497c478bd9Sstevel@tonic-gate 
24507c478bd9Sstevel@tonic-gate 		/* compute %cpu for the process */
24517c478bd9Sstevel@tonic-gate 		if (p->p_lwpcnt == 1)
24527c478bd9Sstevel@tonic-gate 			psp->pr_pctcpu = psp->pr_lwp.pr_pctcpu;
24537c478bd9Sstevel@tonic-gate 		else {
24547c478bd9Sstevel@tonic-gate 			uint64_t pct = 0;
24557c478bd9Sstevel@tonic-gate 			hrtime_t cur_time;
24567c478bd9Sstevel@tonic-gate 
24577c478bd9Sstevel@tonic-gate 			t = p->p_tlist;
24587c478bd9Sstevel@tonic-gate 			cur_time = gethrtime_unscaled();
24597c478bd9Sstevel@tonic-gate 			do {
24607c478bd9Sstevel@tonic-gate 				pct += cpu_update_pct(t, cur_time);
24617c478bd9Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
24627c478bd9Sstevel@tonic-gate 
24637c478bd9Sstevel@tonic-gate 			psp->pr_pctcpu = prgetpctcpu(pct);
24647c478bd9Sstevel@tonic-gate 		}
24657c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
24667c478bd9Sstevel@tonic-gate 			psp->pr_size = 0;
24677c478bd9Sstevel@tonic-gate 			psp->pr_rssize = 0;
24687c478bd9Sstevel@tonic-gate 		} else {
24697c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
2470*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_READER);
24717c478bd9Sstevel@tonic-gate 			psp->pr_size = (size32_t)
247240688216SSudheer A 			    (btopr(as->a_resvsize) * (PAGESIZE / 1024));
24737c478bd9Sstevel@tonic-gate 			psp->pr_rssize = (size32_t)
24747c478bd9Sstevel@tonic-gate 			    (rm_asrss(as) * (PAGESIZE / 1024));
24757c478bd9Sstevel@tonic-gate 			psp->pr_pctmem = rm_pctmemory(as);
2476*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
24777c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
24787c478bd9Sstevel@tonic-gate 		}
24797c478bd9Sstevel@tonic-gate 	}
24807c478bd9Sstevel@tonic-gate 
24817c478bd9Sstevel@tonic-gate 	/*
24827c478bd9Sstevel@tonic-gate 	 * If we are looking at an LP64 process, zero out
24837c478bd9Sstevel@tonic-gate 	 * the fields that cannot be represented in ILP32.
24847c478bd9Sstevel@tonic-gate 	 */
24857c478bd9Sstevel@tonic-gate 	if (p->p_model != DATAMODEL_ILP32) {
24867c478bd9Sstevel@tonic-gate 		psp->pr_size = 0;
24877c478bd9Sstevel@tonic-gate 		psp->pr_rssize = 0;
24887c478bd9Sstevel@tonic-gate 		psp->pr_argv = 0;
24897c478bd9Sstevel@tonic-gate 		psp->pr_envp = 0;
24907c478bd9Sstevel@tonic-gate 	}
24917c478bd9Sstevel@tonic-gate }
2492f971a346SBryan Cantrill 
24937c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
24947c478bd9Sstevel@tonic-gate 
24957c478bd9Sstevel@tonic-gate void
24967c478bd9Sstevel@tonic-gate prgetlwpsinfo(kthread_t *t, lwpsinfo_t *psp)
24977c478bd9Sstevel@tonic-gate {
24987c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
24997c478bd9Sstevel@tonic-gate 	sobj_ops_t *sobj;
25007c478bd9Sstevel@tonic-gate 	char c, state;
25017c478bd9Sstevel@tonic-gate 	uint64_t pct;
25027c478bd9Sstevel@tonic-gate 	int retval, niceval;
25037c478bd9Sstevel@tonic-gate 	hrtime_t hrutime, hrstime;
25047c478bd9Sstevel@tonic-gate 
25057c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
25067c478bd9Sstevel@tonic-gate 
25077c478bd9Sstevel@tonic-gate 	bzero(psp, sizeof (*psp));
25087c478bd9Sstevel@tonic-gate 
25097c478bd9Sstevel@tonic-gate 	psp->pr_flag = 0;	/* lwpsinfo_t.pr_flag is deprecated */
25107c478bd9Sstevel@tonic-gate 	psp->pr_lwpid = t->t_tid;
25117c478bd9Sstevel@tonic-gate 	psp->pr_addr = (uintptr_t)t;
25127c478bd9Sstevel@tonic-gate 	psp->pr_wchan = (uintptr_t)t->t_wchan;
25137c478bd9Sstevel@tonic-gate 
25147c478bd9Sstevel@tonic-gate 	/* map the thread state enum into a process state enum */
25157c478bd9Sstevel@tonic-gate 	state = VSTOPPED(t) ? TS_STOPPED : t->t_state;
25167c478bd9Sstevel@tonic-gate 	switch (state) {
25177c478bd9Sstevel@tonic-gate 	case TS_SLEEP:		state = SSLEEP;		c = 'S';	break;
25187c478bd9Sstevel@tonic-gate 	case TS_RUN:		state = SRUN;		c = 'R';	break;
25197c478bd9Sstevel@tonic-gate 	case TS_ONPROC:		state = SONPROC;	c = 'O';	break;
25207c478bd9Sstevel@tonic-gate 	case TS_ZOMB:		state = SZOMB;		c = 'Z';	break;
25217c478bd9Sstevel@tonic-gate 	case TS_STOPPED:	state = SSTOP;		c = 'T';	break;
2522c97ad5cdSakolb 	case TS_WAIT:		state = SWAIT;		c = 'W';	break;
25237c478bd9Sstevel@tonic-gate 	default:		state = 0;		c = '?';	break;
25247c478bd9Sstevel@tonic-gate 	}
25257c478bd9Sstevel@tonic-gate 	psp->pr_state = state;
25267c478bd9Sstevel@tonic-gate 	psp->pr_sname = c;
25277c478bd9Sstevel@tonic-gate 	if ((sobj = t->t_sobj_ops) != NULL)
25287c478bd9Sstevel@tonic-gate 		psp->pr_stype = SOBJ_TYPE(sobj);
25297c478bd9Sstevel@tonic-gate 	retval = CL_DONICE(t, NULL, 0, &niceval);
25307c478bd9Sstevel@tonic-gate 	if (retval == 0) {
25317c478bd9Sstevel@tonic-gate 		psp->pr_oldpri = v.v_maxsyspri - t->t_pri;
25327c478bd9Sstevel@tonic-gate 		psp->pr_nice = niceval + NZERO;
25337c478bd9Sstevel@tonic-gate 	}
25347c478bd9Sstevel@tonic-gate 	psp->pr_syscall = t->t_sysnum;
25357c478bd9Sstevel@tonic-gate 	psp->pr_pri = t->t_pri;
25367c478bd9Sstevel@tonic-gate 	psp->pr_start.tv_sec = t->t_start;
25377c478bd9Sstevel@tonic-gate 	psp->pr_start.tv_nsec = 0L;
25387c478bd9Sstevel@tonic-gate 	hrutime = lwp->lwp_mstate.ms_acct[LMS_USER];
25397c478bd9Sstevel@tonic-gate 	scalehrtime(&hrutime);
25407c478bd9Sstevel@tonic-gate 	hrstime = lwp->lwp_mstate.ms_acct[LMS_SYSTEM] +
25417c478bd9Sstevel@tonic-gate 	    lwp->lwp_mstate.ms_acct[LMS_TRAP];
25427c478bd9Sstevel@tonic-gate 	scalehrtime(&hrstime);
25437c478bd9Sstevel@tonic-gate 	hrt2ts(hrutime + hrstime, &psp->pr_time);
25447c478bd9Sstevel@tonic-gate 	/* compute %cpu for the lwp */
25457c478bd9Sstevel@tonic-gate 	pct = cpu_update_pct(t, gethrtime_unscaled());
25467c478bd9Sstevel@tonic-gate 	psp->pr_pctcpu = prgetpctcpu(pct);
25477c478bd9Sstevel@tonic-gate 	psp->pr_cpu = (psp->pr_pctcpu*100 + 0x6000) >> 15;	/* [0..99] */
25487c478bd9Sstevel@tonic-gate 	if (psp->pr_cpu > 99)
25497c478bd9Sstevel@tonic-gate 		psp->pr_cpu = 99;
25507c478bd9Sstevel@tonic-gate 
25517c478bd9Sstevel@tonic-gate 	(void) strncpy(psp->pr_clname, sclass[t->t_cid].cl_name,
25527c478bd9Sstevel@tonic-gate 	    sizeof (psp->pr_clname) - 1);
25537c478bd9Sstevel@tonic-gate 	bzero(psp->pr_name, sizeof (psp->pr_name));	/* XXX ??? */
25547c478bd9Sstevel@tonic-gate 	psp->pr_onpro = t->t_cpu->cpu_id;
25557c478bd9Sstevel@tonic-gate 	psp->pr_bindpro = t->t_bind_cpu;
25567c478bd9Sstevel@tonic-gate 	psp->pr_bindpset = t->t_bind_pset;
2557c6402783Sakolb 	psp->pr_lgrp = t->t_lpl->lpl_lgrpid;
25587c478bd9Sstevel@tonic-gate }
25597c478bd9Sstevel@tonic-gate 
25607c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
25617c478bd9Sstevel@tonic-gate void
25627c478bd9Sstevel@tonic-gate prgetlwpsinfo32(kthread_t *t, lwpsinfo32_t *psp)
25637c478bd9Sstevel@tonic-gate {
25647c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(t);
25657c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
25667c478bd9Sstevel@tonic-gate 	sobj_ops_t *sobj;
25677c478bd9Sstevel@tonic-gate 	char c, state;
25687c478bd9Sstevel@tonic-gate 	uint64_t pct;
25697c478bd9Sstevel@tonic-gate 	int retval, niceval;
25707c478bd9Sstevel@tonic-gate 	hrtime_t hrutime, hrstime;
25717c478bd9Sstevel@tonic-gate 
25727c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
25737c478bd9Sstevel@tonic-gate 
25747c478bd9Sstevel@tonic-gate 	bzero(psp, sizeof (*psp));
25757c478bd9Sstevel@tonic-gate 
25767c478bd9Sstevel@tonic-gate 	psp->pr_flag = 0;	/* lwpsinfo_t.pr_flag is deprecated */
25777c478bd9Sstevel@tonic-gate 	psp->pr_lwpid = t->t_tid;
25787c478bd9Sstevel@tonic-gate 	psp->pr_addr = 0;	/* cannot represent 64-bit addr in 32 bits */
25797c478bd9Sstevel@tonic-gate 	psp->pr_wchan = 0;	/* cannot represent 64-bit addr in 32 bits */
25807c478bd9Sstevel@tonic-gate 
25817c478bd9Sstevel@tonic-gate 	/* map the thread state enum into a process state enum */
25827c478bd9Sstevel@tonic-gate 	state = VSTOPPED(t) ? TS_STOPPED : t->t_state;
25837c478bd9Sstevel@tonic-gate 	switch (state) {
25847c478bd9Sstevel@tonic-gate 	case TS_SLEEP:		state = SSLEEP;		c = 'S';	break;
25857c478bd9Sstevel@tonic-gate 	case TS_RUN:		state = SRUN;		c = 'R';	break;
25867c478bd9Sstevel@tonic-gate 	case TS_ONPROC:		state = SONPROC;	c = 'O';	break;
25877c478bd9Sstevel@tonic-gate 	case TS_ZOMB:		state = SZOMB;		c = 'Z';	break;
25887c478bd9Sstevel@tonic-gate 	case TS_STOPPED:	state = SSTOP;		c = 'T';	break;
2589c97ad5cdSakolb 	case TS_WAIT:		state = SWAIT;		c = 'W';	break;
25907c478bd9Sstevel@tonic-gate 	default:		state = 0;		c = '?';	break;
25917c478bd9Sstevel@tonic-gate 	}
25927c478bd9Sstevel@tonic-gate 	psp->pr_state = state;
25937c478bd9Sstevel@tonic-gate 	psp->pr_sname = c;
25947c478bd9Sstevel@tonic-gate 	if ((sobj = t->t_sobj_ops) != NULL)
25957c478bd9Sstevel@tonic-gate 		psp->pr_stype = SOBJ_TYPE(sobj);
25967c478bd9Sstevel@tonic-gate 	retval = CL_DONICE(t, NULL, 0, &niceval);
25977c478bd9Sstevel@tonic-gate 	if (retval == 0) {
25987c478bd9Sstevel@tonic-gate 		psp->pr_oldpri = v.v_maxsyspri - t->t_pri;
25997c478bd9Sstevel@tonic-gate 		psp->pr_nice = niceval + NZERO;
26007c478bd9Sstevel@tonic-gate 	} else {
26017c478bd9Sstevel@tonic-gate 		psp->pr_oldpri = 0;
26027c478bd9Sstevel@tonic-gate 		psp->pr_nice = 0;
26037c478bd9Sstevel@tonic-gate 	}
26047c478bd9Sstevel@tonic-gate 	psp->pr_syscall = t->t_sysnum;
26057c478bd9Sstevel@tonic-gate 	psp->pr_pri = t->t_pri;
26067c478bd9Sstevel@tonic-gate 	psp->pr_start.tv_sec = (time32_t)t->t_start;
26077c478bd9Sstevel@tonic-gate 	psp->pr_start.tv_nsec = 0L;
26087c478bd9Sstevel@tonic-gate 	hrutime = lwp->lwp_mstate.ms_acct[LMS_USER];
26097c478bd9Sstevel@tonic-gate 	scalehrtime(&hrutime);
26107c478bd9Sstevel@tonic-gate 	hrstime = lwp->lwp_mstate.ms_acct[LMS_SYSTEM] +
26117c478bd9Sstevel@tonic-gate 	    lwp->lwp_mstate.ms_acct[LMS_TRAP];
26127c478bd9Sstevel@tonic-gate 	scalehrtime(&hrstime);
26137c478bd9Sstevel@tonic-gate 	hrt2ts32(hrutime + hrstime, &psp->pr_time);
26147c478bd9Sstevel@tonic-gate 	/* compute %cpu for the lwp */
26157c478bd9Sstevel@tonic-gate 	pct = cpu_update_pct(t, gethrtime_unscaled());
26167c478bd9Sstevel@tonic-gate 	psp->pr_pctcpu = prgetpctcpu(pct);
26177c478bd9Sstevel@tonic-gate 	psp->pr_cpu = (psp->pr_pctcpu*100 + 0x6000) >> 15;	/* [0..99] */
26187c478bd9Sstevel@tonic-gate 	if (psp->pr_cpu > 99)
26197c478bd9Sstevel@tonic-gate 		psp->pr_cpu = 99;
26207c478bd9Sstevel@tonic-gate 
26217c478bd9Sstevel@tonic-gate 	(void) strncpy(psp->pr_clname, sclass[t->t_cid].cl_name,
26227c478bd9Sstevel@tonic-gate 	    sizeof (psp->pr_clname) - 1);
26237c478bd9Sstevel@tonic-gate 	bzero(psp->pr_name, sizeof (psp->pr_name));	/* XXX ??? */
26247c478bd9Sstevel@tonic-gate 	psp->pr_onpro = t->t_cpu->cpu_id;
26257c478bd9Sstevel@tonic-gate 	psp->pr_bindpro = t->t_bind_cpu;
26267c478bd9Sstevel@tonic-gate 	psp->pr_bindpset = t->t_bind_pset;
2627c6402783Sakolb 	psp->pr_lgrp = t->t_lpl->lpl_lgrpid;
26287c478bd9Sstevel@tonic-gate }
26297c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
26307c478bd9Sstevel@tonic-gate 
2631f971a346SBryan Cantrill #ifdef _SYSCALL32_IMPL
2632f971a346SBryan Cantrill 
2633f971a346SBryan Cantrill #define	PR_COPY_FIELD(s, d, field)	 d->field = s->field
2634f971a346SBryan Cantrill 
2635f971a346SBryan Cantrill #define	PR_COPY_FIELD_ILP32(s, d, field)				\
2636f971a346SBryan Cantrill 	if (s->pr_dmodel == PR_MODEL_ILP32) {			\
2637f971a346SBryan Cantrill 		d->field = s->field;				\
2638f971a346SBryan Cantrill 	}
2639f971a346SBryan Cantrill 
2640f971a346SBryan Cantrill #define	PR_COPY_TIMESPEC(s, d, field)				\
2641f971a346SBryan Cantrill 	TIMESPEC_TO_TIMESPEC32(&d->field, &s->field);
2642f971a346SBryan Cantrill 
2643f971a346SBryan Cantrill #define	PR_COPY_BUF(s, d, field)	 			\
2644f971a346SBryan Cantrill 	bcopy(s->field, d->field, sizeof (d->field));
2645f971a346SBryan Cantrill 
2646f971a346SBryan Cantrill #define	PR_IGNORE_FIELD(s, d, field)
2647f971a346SBryan Cantrill 
2648f971a346SBryan Cantrill void
2649f971a346SBryan Cantrill lwpsinfo_kto32(const struct lwpsinfo *src, struct lwpsinfo32 *dest)
2650f971a346SBryan Cantrill {
2651f971a346SBryan Cantrill 	bzero(dest, sizeof (*dest));
2652f971a346SBryan Cantrill 
2653f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_flag);
2654f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_lwpid);
2655f971a346SBryan Cantrill 	PR_IGNORE_FIELD(src, dest, pr_addr);
2656f971a346SBryan Cantrill 	PR_IGNORE_FIELD(src, dest, pr_wchan);
2657f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_stype);
2658f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_state);
2659f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_sname);
2660f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_nice);
2661f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_syscall);
2662f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_oldpri);
2663f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_cpu);
2664f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_pri);
2665f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_pctcpu);
2666f971a346SBryan Cantrill 	PR_COPY_TIMESPEC(src, dest, pr_start);
2667f971a346SBryan Cantrill 	PR_COPY_BUF(src, dest, pr_clname);
2668f971a346SBryan Cantrill 	PR_COPY_BUF(src, dest, pr_name);
2669f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_onpro);
2670f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_bindpro);
2671f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_bindpset);
2672f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_lgrp);
2673f971a346SBryan Cantrill }
2674f971a346SBryan Cantrill 
2675f971a346SBryan Cantrill void
2676f971a346SBryan Cantrill psinfo_kto32(const struct psinfo *src, struct psinfo32 *dest)
2677f971a346SBryan Cantrill {
2678f971a346SBryan Cantrill 	bzero(dest, sizeof (*dest));
2679f971a346SBryan Cantrill 
2680f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_flag);
2681f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_nlwp);
2682f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_pid);
2683f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_ppid);
2684f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_pgid);
2685f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_sid);
2686f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_uid);
2687f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_euid);
2688f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_gid);
2689f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_egid);
2690f971a346SBryan Cantrill 	PR_IGNORE_FIELD(src, dest, pr_addr);
2691f971a346SBryan Cantrill 	PR_COPY_FIELD_ILP32(src, dest, pr_size);
2692f971a346SBryan Cantrill 	PR_COPY_FIELD_ILP32(src, dest, pr_rssize);
2693f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_ttydev);
2694f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_pctcpu);
2695f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_pctmem);
2696f971a346SBryan Cantrill 	PR_COPY_TIMESPEC(src, dest, pr_start);
2697f971a346SBryan Cantrill 	PR_COPY_TIMESPEC(src, dest, pr_time);
2698f971a346SBryan Cantrill 	PR_COPY_TIMESPEC(src, dest, pr_ctime);
2699f971a346SBryan Cantrill 	PR_COPY_BUF(src, dest, pr_fname);
2700f971a346SBryan Cantrill 	PR_COPY_BUF(src, dest, pr_psargs);
2701f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_wstat);
2702f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_argc);
2703f971a346SBryan Cantrill 	PR_COPY_FIELD_ILP32(src, dest, pr_argv);
2704f971a346SBryan Cantrill 	PR_COPY_FIELD_ILP32(src, dest, pr_envp);
2705f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_dmodel);
2706f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_taskid);
2707f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_projid);
2708f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_nzomb);
2709f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_poolid);
2710f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_contract);
2711f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_poolid);
2712f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_poolid);
2713f971a346SBryan Cantrill 
2714f971a346SBryan Cantrill 	lwpsinfo_kto32(&src->pr_lwp, &dest->pr_lwp);
2715f971a346SBryan Cantrill }
2716f971a346SBryan Cantrill 
2717f971a346SBryan Cantrill #undef	PR_COPY_FIELD
2718f971a346SBryan Cantrill #undef	PR_COPY_FIELD_ILP32
2719f971a346SBryan Cantrill #undef	PR_COPY_TIMESPEC
2720f971a346SBryan Cantrill #undef	PR_COPY_BUF
2721f971a346SBryan Cantrill #undef	PR_IGNORE_FIELD
2722f971a346SBryan Cantrill 
2723f971a346SBryan Cantrill #endif	/* _SYSCALL32_IMPL */
2724f971a346SBryan Cantrill 
27257c478bd9Sstevel@tonic-gate /*
27267c478bd9Sstevel@tonic-gate  * This used to get called when microstate accounting was disabled but
27277c478bd9Sstevel@tonic-gate  * microstate information was requested.  Since Microstate accounting is on
27287c478bd9Sstevel@tonic-gate  * regardless of the proc flags, this simply makes it appear to procfs that
27297c478bd9Sstevel@tonic-gate  * microstate accounting is on.  This is relatively meaningless since you
27307c478bd9Sstevel@tonic-gate  * can't turn it off, but this is here for the sake of appearances.
27317c478bd9Sstevel@tonic-gate  */
27327c478bd9Sstevel@tonic-gate 
27337c478bd9Sstevel@tonic-gate /*ARGSUSED*/
27347c478bd9Sstevel@tonic-gate void
27357c478bd9Sstevel@tonic-gate estimate_msacct(kthread_t *t, hrtime_t curtime)
27367c478bd9Sstevel@tonic-gate {
27377c478bd9Sstevel@tonic-gate 	proc_t *p;
27387c478bd9Sstevel@tonic-gate 
27397c478bd9Sstevel@tonic-gate 	if (t == NULL)
27407c478bd9Sstevel@tonic-gate 		return;
27417c478bd9Sstevel@tonic-gate 
27427c478bd9Sstevel@tonic-gate 	p = ttoproc(t);
27437c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
27447c478bd9Sstevel@tonic-gate 
27457c478bd9Sstevel@tonic-gate 	/*
27467c478bd9Sstevel@tonic-gate 	 * A system process (p0) could be referenced if the thread is
27477c478bd9Sstevel@tonic-gate 	 * in the process of exiting.  Don't turn on microstate accounting
27487c478bd9Sstevel@tonic-gate 	 * in that case.
27497c478bd9Sstevel@tonic-gate 	 */
27507c478bd9Sstevel@tonic-gate 	if (p->p_flag & SSYS)
27517c478bd9Sstevel@tonic-gate 		return;
27527c478bd9Sstevel@tonic-gate 
27537c478bd9Sstevel@tonic-gate 	/*
27547c478bd9Sstevel@tonic-gate 	 * Loop through all the LWPs (kernel threads) in the process.
27557c478bd9Sstevel@tonic-gate 	 */
27567c478bd9Sstevel@tonic-gate 	t = p->p_tlist;
27577c478bd9Sstevel@tonic-gate 	do {
27587c478bd9Sstevel@tonic-gate 		t->t_proc_flag |= TP_MSACCT;
27597c478bd9Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
27607c478bd9Sstevel@tonic-gate 
27617c478bd9Sstevel@tonic-gate 	p->p_flag |= SMSACCT;			/* set process-wide MSACCT */
27627c478bd9Sstevel@tonic-gate }
27637c478bd9Sstevel@tonic-gate 
27647c478bd9Sstevel@tonic-gate /*
27657c478bd9Sstevel@tonic-gate  * It's not really possible to disable microstate accounting anymore.
27667c478bd9Sstevel@tonic-gate  * However, this routine simply turns off the ms accounting flags in a process
27677c478bd9Sstevel@tonic-gate  * This way procfs can still pretend to turn microstate accounting on and
27687c478bd9Sstevel@tonic-gate  * off for a process, but it actually doesn't do anything.  This is
27697c478bd9Sstevel@tonic-gate  * a neutered form of preemptive idiot-proofing.
27707c478bd9Sstevel@tonic-gate  */
27717c478bd9Sstevel@tonic-gate void
27727c478bd9Sstevel@tonic-gate disable_msacct(proc_t *p)
27737c478bd9Sstevel@tonic-gate {
27747c478bd9Sstevel@tonic-gate 	kthread_t *t;
27757c478bd9Sstevel@tonic-gate 
27767c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
27777c478bd9Sstevel@tonic-gate 
27787c478bd9Sstevel@tonic-gate 	p->p_flag &= ~SMSACCT;		/* clear process-wide MSACCT */
27797c478bd9Sstevel@tonic-gate 	/*
27807c478bd9Sstevel@tonic-gate 	 * Loop through all the LWPs (kernel threads) in the process.
27817c478bd9Sstevel@tonic-gate 	 */
27827c478bd9Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL) {
27837c478bd9Sstevel@tonic-gate 		do {
27847c478bd9Sstevel@tonic-gate 			/* clear per-thread flag */
27857c478bd9Sstevel@tonic-gate 			t->t_proc_flag &= ~TP_MSACCT;
27867c478bd9Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
27877c478bd9Sstevel@tonic-gate 	}
27887c478bd9Sstevel@tonic-gate }
27897c478bd9Sstevel@tonic-gate 
27907c478bd9Sstevel@tonic-gate /*
27917c478bd9Sstevel@tonic-gate  * Return resource usage information.
27927c478bd9Sstevel@tonic-gate  */
27937c478bd9Sstevel@tonic-gate void
27947c478bd9Sstevel@tonic-gate prgetusage(kthread_t *t, prhusage_t *pup)
27957c478bd9Sstevel@tonic-gate {
27967c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
27977c478bd9Sstevel@tonic-gate 	hrtime_t *mstimep;
27987c478bd9Sstevel@tonic-gate 	struct mstate *ms = &lwp->lwp_mstate;
27997c478bd9Sstevel@tonic-gate 	int state;
28007c478bd9Sstevel@tonic-gate 	int i;
28017c478bd9Sstevel@tonic-gate 	hrtime_t curtime;
28027c478bd9Sstevel@tonic-gate 	hrtime_t waitrq;
28037c478bd9Sstevel@tonic-gate 	hrtime_t tmp1;
28047c478bd9Sstevel@tonic-gate 
28057c478bd9Sstevel@tonic-gate 	curtime = gethrtime_unscaled();
28067c478bd9Sstevel@tonic-gate 
28077c478bd9Sstevel@tonic-gate 	pup->pr_lwpid	= t->t_tid;
28087c478bd9Sstevel@tonic-gate 	pup->pr_count	= 1;
28097c478bd9Sstevel@tonic-gate 	pup->pr_create	= ms->ms_start;
28107c478bd9Sstevel@tonic-gate 	pup->pr_term    = ms->ms_term;
28117c478bd9Sstevel@tonic-gate 	scalehrtime(&pup->pr_create);
28127c478bd9Sstevel@tonic-gate 	scalehrtime(&pup->pr_term);
28137c478bd9Sstevel@tonic-gate 	if (ms->ms_term == 0) {
28147c478bd9Sstevel@tonic-gate 		pup->pr_rtime = curtime - ms->ms_start;
28157c478bd9Sstevel@tonic-gate 		scalehrtime(&pup->pr_rtime);
28167c478bd9Sstevel@tonic-gate 	} else {
28177c478bd9Sstevel@tonic-gate 		pup->pr_rtime = ms->ms_term - ms->ms_start;
28187c478bd9Sstevel@tonic-gate 		scalehrtime(&pup->pr_rtime);
28197c478bd9Sstevel@tonic-gate 	}
28207c478bd9Sstevel@tonic-gate 
28217c478bd9Sstevel@tonic-gate 
28227c478bd9Sstevel@tonic-gate 	pup->pr_utime    = ms->ms_acct[LMS_USER];
28237c478bd9Sstevel@tonic-gate 	pup->pr_stime    = ms->ms_acct[LMS_SYSTEM];
28247c478bd9Sstevel@tonic-gate 	pup->pr_ttime    = ms->ms_acct[LMS_TRAP];
28257c478bd9Sstevel@tonic-gate 	pup->pr_tftime   = ms->ms_acct[LMS_TFAULT];
28267c478bd9Sstevel@tonic-gate 	pup->pr_dftime   = ms->ms_acct[LMS_DFAULT];
28277c478bd9Sstevel@tonic-gate 	pup->pr_kftime   = ms->ms_acct[LMS_KFAULT];
28287c478bd9Sstevel@tonic-gate 	pup->pr_ltime    = ms->ms_acct[LMS_USER_LOCK];
28297c478bd9Sstevel@tonic-gate 	pup->pr_slptime  = ms->ms_acct[LMS_SLEEP];
28307c478bd9Sstevel@tonic-gate 	pup->pr_wtime    = ms->ms_acct[LMS_WAIT_CPU];
28317c478bd9Sstevel@tonic-gate 	pup->pr_stoptime = ms->ms_acct[LMS_STOPPED];
28327c478bd9Sstevel@tonic-gate 
28337c478bd9Sstevel@tonic-gate 	prscaleusage(pup);
28347c478bd9Sstevel@tonic-gate 
28357c478bd9Sstevel@tonic-gate 	/*
28367c478bd9Sstevel@tonic-gate 	 * Adjust for time waiting in the dispatcher queue.
28377c478bd9Sstevel@tonic-gate 	 */
28387c478bd9Sstevel@tonic-gate 	waitrq = t->t_waitrq;	/* hopefully atomic */
28397c478bd9Sstevel@tonic-gate 	if (waitrq != 0) {
2840872650ccSGangadhar Mylapuram 		if (waitrq > curtime) {
2841872650ccSGangadhar Mylapuram 			curtime = gethrtime_unscaled();
2842872650ccSGangadhar Mylapuram 		}
28437c478bd9Sstevel@tonic-gate 		tmp1 = curtime - waitrq;
28447c478bd9Sstevel@tonic-gate 		scalehrtime(&tmp1);
28457c478bd9Sstevel@tonic-gate 		pup->pr_wtime += tmp1;
28467c478bd9Sstevel@tonic-gate 		curtime = waitrq;
28477c478bd9Sstevel@tonic-gate 	}
28487c478bd9Sstevel@tonic-gate 
28497c478bd9Sstevel@tonic-gate 	/*
28507c478bd9Sstevel@tonic-gate 	 * Adjust for time spent in current microstate.
28517c478bd9Sstevel@tonic-gate 	 */
28527c478bd9Sstevel@tonic-gate 	if (ms->ms_state_start > curtime) {
28537c478bd9Sstevel@tonic-gate 		curtime = gethrtime_unscaled();
28547c478bd9Sstevel@tonic-gate 	}
28557c478bd9Sstevel@tonic-gate 
28567c478bd9Sstevel@tonic-gate 	i = 0;
28577c478bd9Sstevel@tonic-gate 	do {
28587c478bd9Sstevel@tonic-gate 		switch (state = t->t_mstate) {
28597c478bd9Sstevel@tonic-gate 		case LMS_SLEEP:
28607c478bd9Sstevel@tonic-gate 			/*
28617c478bd9Sstevel@tonic-gate 			 * Update the timer for the current sleep state.
28627c478bd9Sstevel@tonic-gate 			 */
28637c478bd9Sstevel@tonic-gate 			switch (state = ms->ms_prev) {
28647c478bd9Sstevel@tonic-gate 			case LMS_TFAULT:
28657c478bd9Sstevel@tonic-gate 			case LMS_DFAULT:
28667c478bd9Sstevel@tonic-gate 			case LMS_KFAULT:
28677c478bd9Sstevel@tonic-gate 			case LMS_USER_LOCK:
28687c478bd9Sstevel@tonic-gate 				break;
28697c478bd9Sstevel@tonic-gate 			default:
28707c478bd9Sstevel@tonic-gate 				state = LMS_SLEEP;
28717c478bd9Sstevel@tonic-gate 				break;
28727c478bd9Sstevel@tonic-gate 			}
28737c478bd9Sstevel@tonic-gate 			break;
28747c478bd9Sstevel@tonic-gate 		case LMS_TFAULT:
28757c478bd9Sstevel@tonic-gate 		case LMS_DFAULT:
28767c478bd9Sstevel@tonic-gate 		case LMS_KFAULT:
28777c478bd9Sstevel@tonic-gate 		case LMS_USER_LOCK:
28787c478bd9Sstevel@tonic-gate 			state = LMS_SYSTEM;
28797c478bd9Sstevel@tonic-gate 			break;
28807c478bd9Sstevel@tonic-gate 		}
28817c478bd9Sstevel@tonic-gate 		switch (state) {
28827c478bd9Sstevel@tonic-gate 		case LMS_USER:		mstimep = &pup->pr_utime;	break;
28837c478bd9Sstevel@tonic-gate 		case LMS_SYSTEM:	mstimep = &pup->pr_stime;	break;
28847c478bd9Sstevel@tonic-gate 		case LMS_TRAP:		mstimep = &pup->pr_ttime;	break;
28857c478bd9Sstevel@tonic-gate 		case LMS_TFAULT:	mstimep = &pup->pr_tftime;	break;
28867c478bd9Sstevel@tonic-gate 		case LMS_DFAULT:	mstimep = &pup->pr_dftime;	break;
28877c478bd9Sstevel@tonic-gate 		case LMS_KFAULT:	mstimep = &pup->pr_kftime;	break;
28887c478bd9Sstevel@tonic-gate 		case LMS_USER_LOCK:	mstimep = &pup->pr_ltime;	break;
28897c478bd9Sstevel@tonic-gate 		case LMS_SLEEP:		mstimep = &pup->pr_slptime;	break;
28907c478bd9Sstevel@tonic-gate 		case LMS_WAIT_CPU:	mstimep = &pup->pr_wtime;	break;
28917c478bd9Sstevel@tonic-gate 		case LMS_STOPPED:	mstimep = &pup->pr_stoptime;	break;
28927c478bd9Sstevel@tonic-gate 		default:		panic("prgetusage: unknown microstate");
28937c478bd9Sstevel@tonic-gate 		}
28947c478bd9Sstevel@tonic-gate 		tmp1 = curtime - ms->ms_state_start;
28958ace1d31Ssudheer 		if (tmp1 < 0) {
28967c478bd9Sstevel@tonic-gate 			curtime = gethrtime_unscaled();
28977c478bd9Sstevel@tonic-gate 			i++;
28987c478bd9Sstevel@tonic-gate 			continue;
28997c478bd9Sstevel@tonic-gate 		}
29007c478bd9Sstevel@tonic-gate 		scalehrtime(&tmp1);
29018ace1d31Ssudheer 	} while (tmp1 < 0 && i < MAX_ITERS_SPIN);
29027c478bd9Sstevel@tonic-gate 
29037c478bd9Sstevel@tonic-gate 	*mstimep += tmp1;
29047c478bd9Sstevel@tonic-gate 
29057c478bd9Sstevel@tonic-gate 	/* update pup timestamp */
29067c478bd9Sstevel@tonic-gate 	pup->pr_tstamp = curtime;
29077c478bd9Sstevel@tonic-gate 	scalehrtime(&pup->pr_tstamp);
29087c478bd9Sstevel@tonic-gate 
29097c478bd9Sstevel@tonic-gate 	/*
29107c478bd9Sstevel@tonic-gate 	 * Resource usage counters.
29117c478bd9Sstevel@tonic-gate 	 */
29127c478bd9Sstevel@tonic-gate 	pup->pr_minf  = lwp->lwp_ru.minflt;
29137c478bd9Sstevel@tonic-gate 	pup->pr_majf  = lwp->lwp_ru.majflt;
29147c478bd9Sstevel@tonic-gate 	pup->pr_nswap = lwp->lwp_ru.nswap;
29157c478bd9Sstevel@tonic-gate 	pup->pr_inblk = lwp->lwp_ru.inblock;
29167c478bd9Sstevel@tonic-gate 	pup->pr_oublk = lwp->lwp_ru.oublock;
29177c478bd9Sstevel@tonic-gate 	pup->pr_msnd  = lwp->lwp_ru.msgsnd;
29187c478bd9Sstevel@tonic-gate 	pup->pr_mrcv  = lwp->lwp_ru.msgrcv;
29197c478bd9Sstevel@tonic-gate 	pup->pr_sigs  = lwp->lwp_ru.nsignals;
29207c478bd9Sstevel@tonic-gate 	pup->pr_vctx  = lwp->lwp_ru.nvcsw;
29217c478bd9Sstevel@tonic-gate 	pup->pr_ictx  = lwp->lwp_ru.nivcsw;
29227c478bd9Sstevel@tonic-gate 	pup->pr_sysc  = lwp->lwp_ru.sysc;
29237c478bd9Sstevel@tonic-gate 	pup->pr_ioch  = lwp->lwp_ru.ioch;
29247c478bd9Sstevel@tonic-gate }
29257c478bd9Sstevel@tonic-gate 
29267c478bd9Sstevel@tonic-gate /*
29277c478bd9Sstevel@tonic-gate  * Convert ms_acct stats from unscaled high-res time to nanoseconds
29287c478bd9Sstevel@tonic-gate  */
29297c478bd9Sstevel@tonic-gate void
29307c478bd9Sstevel@tonic-gate prscaleusage(prhusage_t *usg)
29317c478bd9Sstevel@tonic-gate {
29327c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_utime);
29337c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_stime);
29347c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_ttime);
29357c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_tftime);
29367c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_dftime);
29377c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_kftime);
29387c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_ltime);
29397c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_slptime);
29407c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_wtime);
29417c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_stoptime);
29427c478bd9Sstevel@tonic-gate }
29437c478bd9Sstevel@tonic-gate 
29447c478bd9Sstevel@tonic-gate 
29457c478bd9Sstevel@tonic-gate /*
29467c478bd9Sstevel@tonic-gate  * Sum resource usage information.
29477c478bd9Sstevel@tonic-gate  */
29487c478bd9Sstevel@tonic-gate void
29497c478bd9Sstevel@tonic-gate praddusage(kthread_t *t, prhusage_t *pup)
29507c478bd9Sstevel@tonic-gate {
29517c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
29527c478bd9Sstevel@tonic-gate 	hrtime_t *mstimep;
29537c478bd9Sstevel@tonic-gate 	struct mstate *ms = &lwp->lwp_mstate;
29547c478bd9Sstevel@tonic-gate 	int state;
29557c478bd9Sstevel@tonic-gate 	int i;
29567c478bd9Sstevel@tonic-gate 	hrtime_t curtime;
29577c478bd9Sstevel@tonic-gate 	hrtime_t waitrq;
29587c478bd9Sstevel@tonic-gate 	hrtime_t tmp;
29597c478bd9Sstevel@tonic-gate 	prhusage_t conv;
29607c478bd9Sstevel@tonic-gate 
29617c478bd9Sstevel@tonic-gate 	curtime = gethrtime_unscaled();
29627c478bd9Sstevel@tonic-gate 
29637c478bd9Sstevel@tonic-gate 	if (ms->ms_term == 0) {
29647c478bd9Sstevel@tonic-gate 		tmp = curtime - ms->ms_start;
29657c478bd9Sstevel@tonic-gate 		scalehrtime(&tmp);
29667c478bd9Sstevel@tonic-gate 		pup->pr_rtime += tmp;
29677c478bd9Sstevel@tonic-gate 	} else {
29687c478bd9Sstevel@tonic-gate 		tmp = ms->ms_term - ms->ms_start;
29697c478bd9Sstevel@tonic-gate 		scalehrtime(&tmp);
29707c478bd9Sstevel@tonic-gate 		pup->pr_rtime += tmp;
29717c478bd9Sstevel@tonic-gate 	}
29727c478bd9Sstevel@tonic-gate 
29737c478bd9Sstevel@tonic-gate 	conv.pr_utime = ms->ms_acct[LMS_USER];
29747c478bd9Sstevel@tonic-gate 	conv.pr_stime = ms->ms_acct[LMS_SYSTEM];
29757c478bd9Sstevel@tonic-gate 	conv.pr_ttime = ms->ms_acct[LMS_TRAP];
29767c478bd9Sstevel@tonic-gate 	conv.pr_tftime = ms->ms_acct[LMS_TFAULT];
29777c478bd9Sstevel@tonic-gate 	conv.pr_dftime = ms->ms_acct[LMS_DFAULT];
29787c478bd9Sstevel@tonic-gate 	conv.pr_kftime = ms->ms_acct[LMS_KFAULT];
29797c478bd9Sstevel@tonic-gate 	conv.pr_ltime = ms->ms_acct[LMS_USER_LOCK];
29807c478bd9Sstevel@tonic-gate 	conv.pr_slptime = ms->ms_acct[LMS_SLEEP];
29817c478bd9Sstevel@tonic-gate 	conv.pr_wtime = ms->ms_acct[LMS_WAIT_CPU];
29827c478bd9Sstevel@tonic-gate 	conv.pr_stoptime = ms->ms_acct[LMS_STOPPED];
29837c478bd9Sstevel@tonic-gate 
29847c478bd9Sstevel@tonic-gate 	prscaleusage(&conv);
29857c478bd9Sstevel@tonic-gate 
29867c478bd9Sstevel@tonic-gate 	pup->pr_utime	+= conv.pr_utime;
29877c478bd9Sstevel@tonic-gate 	pup->pr_stime	+= conv.pr_stime;
29887c478bd9Sstevel@tonic-gate 	pup->pr_ttime	+= conv.pr_ttime;
29897c478bd9Sstevel@tonic-gate 	pup->pr_tftime	+= conv.pr_tftime;
29907c478bd9Sstevel@tonic-gate 	pup->pr_dftime	+= conv.pr_dftime;
29917c478bd9Sstevel@tonic-gate 	pup->pr_kftime	+= conv.pr_kftime;
29927c478bd9Sstevel@tonic-gate 	pup->pr_ltime	+= conv.pr_ltime;
29937c478bd9Sstevel@tonic-gate 	pup->pr_slptime	+= conv.pr_slptime;
29947c478bd9Sstevel@tonic-gate 	pup->pr_wtime	+= conv.pr_wtime;
29957c478bd9Sstevel@tonic-gate 	pup->pr_stoptime += conv.pr_stoptime;
29967c478bd9Sstevel@tonic-gate 
29977c478bd9Sstevel@tonic-gate 	/*
29987c478bd9Sstevel@tonic-gate 	 * Adjust for time waiting in the dispatcher queue.
29997c478bd9Sstevel@tonic-gate 	 */
30007c478bd9Sstevel@tonic-gate 	waitrq = t->t_waitrq;	/* hopefully atomic */
30017c478bd9Sstevel@tonic-gate 	if (waitrq != 0) {
3002872650ccSGangadhar Mylapuram 		if (waitrq > curtime) {
3003872650ccSGangadhar Mylapuram 			curtime = gethrtime_unscaled();
3004872650ccSGangadhar Mylapuram 		}
30057c478bd9Sstevel@tonic-gate 		tmp = curtime - waitrq;
30067c478bd9Sstevel@tonic-gate 		scalehrtime(&tmp);
30077c478bd9Sstevel@tonic-gate 		pup->pr_wtime += tmp;
30087c478bd9Sstevel@tonic-gate 		curtime = waitrq;
30097c478bd9Sstevel@tonic-gate 	}
30107c478bd9Sstevel@tonic-gate 
30117c478bd9Sstevel@tonic-gate 	/*
30127c478bd9Sstevel@tonic-gate 	 * Adjust for time spent in current microstate.
30137c478bd9Sstevel@tonic-gate 	 */
30147c478bd9Sstevel@tonic-gate 	if (ms->ms_state_start > curtime) {
30157c478bd9Sstevel@tonic-gate 		curtime = gethrtime_unscaled();
30167c478bd9Sstevel@tonic-gate 	}
30177c478bd9Sstevel@tonic-gate 
30187c478bd9Sstevel@tonic-gate 	i = 0;
30197c478bd9Sstevel@tonic-gate 	do {
30207c478bd9Sstevel@tonic-gate 		switch (state = t->t_mstate) {
30217c478bd9Sstevel@tonic-gate 		case LMS_SLEEP:
30227c478bd9Sstevel@tonic-gate 			/*
30237c478bd9Sstevel@tonic-gate 			 * Update the timer for the current sleep state.
30247c478bd9Sstevel@tonic-gate 			 */
30257c478bd9Sstevel@tonic-gate 			switch (state = ms->ms_prev) {
30267c478bd9Sstevel@tonic-gate 			case LMS_TFAULT:
30277c478bd9Sstevel@tonic-gate 			case LMS_DFAULT:
30287c478bd9Sstevel@tonic-gate 			case LMS_KFAULT:
30297c478bd9Sstevel@tonic-gate 			case LMS_USER_LOCK:
30307c478bd9Sstevel@tonic-gate 				break;
30317c478bd9Sstevel@tonic-gate 			default:
30327c478bd9Sstevel@tonic-gate 				state = LMS_SLEEP;
30337c478bd9Sstevel@tonic-gate 				break;
30347c478bd9Sstevel@tonic-gate 			}
30357c478bd9Sstevel@tonic-gate 			break;
30367c478bd9Sstevel@tonic-gate 		case LMS_TFAULT:
30377c478bd9Sstevel@tonic-gate 		case LMS_DFAULT:
30387c478bd9Sstevel@tonic-gate 		case LMS_KFAULT:
30397c478bd9Sstevel@tonic-gate 		case LMS_USER_LOCK:
30407c478bd9Sstevel@tonic-gate 			state = LMS_SYSTEM;
30417c478bd9Sstevel@tonic-gate 			break;
30427c478bd9Sstevel@tonic-gate 		}
30437c478bd9Sstevel@tonic-gate 		switch (state) {
30447c478bd9Sstevel@tonic-gate 		case LMS_USER:		mstimep = &pup->pr_utime;	break;
30457c478bd9Sstevel@tonic-gate 		case LMS_SYSTEM:	mstimep = &pup->pr_stime;	break;
30467c478bd9Sstevel@tonic-gate 		case LMS_TRAP:		mstimep = &pup->pr_ttime;	break;
30477c478bd9Sstevel@tonic-gate 		case LMS_TFAULT:	mstimep = &pup->pr_tftime;	break;
30487c478bd9Sstevel@tonic-gate 		case LMS_DFAULT:	mstimep = &pup->pr_dftime;	break;
30497c478bd9Sstevel@tonic-gate 		case LMS_KFAULT:	mstimep = &pup->pr_kftime;	break;
30507c478bd9Sstevel@tonic-gate 		case LMS_USER_LOCK:	mstimep = &pup->pr_ltime;	break;
30517c478bd9Sstevel@tonic-gate 		case LMS_SLEEP:		mstimep = &pup->pr_slptime;	break;
30527c478bd9Sstevel@tonic-gate 		case LMS_WAIT_CPU:	mstimep = &pup->pr_wtime;	break;
30537c478bd9Sstevel@tonic-gate 		case LMS_STOPPED:	mstimep = &pup->pr_stoptime;	break;
30547c478bd9Sstevel@tonic-gate 		default:		panic("praddusage: unknown microstate");
30557c478bd9Sstevel@tonic-gate 		}
30567c478bd9Sstevel@tonic-gate 		tmp = curtime - ms->ms_state_start;
30578ace1d31Ssudheer 		if (tmp < 0) {
30587c478bd9Sstevel@tonic-gate 			curtime = gethrtime_unscaled();
30597c478bd9Sstevel@tonic-gate 			i++;
30607c478bd9Sstevel@tonic-gate 			continue;
30617c478bd9Sstevel@tonic-gate 		}
30627c478bd9Sstevel@tonic-gate 		scalehrtime(&tmp);
30638ace1d31Ssudheer 	} while (tmp < 0 && i < MAX_ITERS_SPIN);
30647c478bd9Sstevel@tonic-gate 
30657c478bd9Sstevel@tonic-gate 	*mstimep += tmp;
30667c478bd9Sstevel@tonic-gate 
30677c478bd9Sstevel@tonic-gate 	/* update pup timestamp */
30687c478bd9Sstevel@tonic-gate 	pup->pr_tstamp = curtime;
30697c478bd9Sstevel@tonic-gate 	scalehrtime(&pup->pr_tstamp);
30707c478bd9Sstevel@tonic-gate 
30717c478bd9Sstevel@tonic-gate 	/*
30727c478bd9Sstevel@tonic-gate 	 * Resource usage counters.
30737c478bd9Sstevel@tonic-gate 	 */
30747c478bd9Sstevel@tonic-gate 	pup->pr_minf  += lwp->lwp_ru.minflt;
30757c478bd9Sstevel@tonic-gate 	pup->pr_majf  += lwp->lwp_ru.majflt;
30767c478bd9Sstevel@tonic-gate 	pup->pr_nswap += lwp->lwp_ru.nswap;
30777c478bd9Sstevel@tonic-gate 	pup->pr_inblk += lwp->lwp_ru.inblock;
30787c478bd9Sstevel@tonic-gate 	pup->pr_oublk += lwp->lwp_ru.oublock;
30797c478bd9Sstevel@tonic-gate 	pup->pr_msnd  += lwp->lwp_ru.msgsnd;
30807c478bd9Sstevel@tonic-gate 	pup->pr_mrcv  += lwp->lwp_ru.msgrcv;
30817c478bd9Sstevel@tonic-gate 	pup->pr_sigs  += lwp->lwp_ru.nsignals;
30827c478bd9Sstevel@tonic-gate 	pup->pr_vctx  += lwp->lwp_ru.nvcsw;
30837c478bd9Sstevel@tonic-gate 	pup->pr_ictx  += lwp->lwp_ru.nivcsw;
30847c478bd9Sstevel@tonic-gate 	pup->pr_sysc  += lwp->lwp_ru.sysc;
30857c478bd9Sstevel@tonic-gate 	pup->pr_ioch  += lwp->lwp_ru.ioch;
30867c478bd9Sstevel@tonic-gate }
30877c478bd9Sstevel@tonic-gate 
30887c478bd9Sstevel@tonic-gate /*
30897c478bd9Sstevel@tonic-gate  * Convert a prhusage_t to a prusage_t.
30907c478bd9Sstevel@tonic-gate  * This means convert each hrtime_t to a timestruc_t
30917c478bd9Sstevel@tonic-gate  * and copy the count fields uint64_t => ulong_t.
30927c478bd9Sstevel@tonic-gate  */
30937c478bd9Sstevel@tonic-gate void
30947c478bd9Sstevel@tonic-gate prcvtusage(prhusage_t *pup, prusage_t *upup)
30957c478bd9Sstevel@tonic-gate {
30967c478bd9Sstevel@tonic-gate 	uint64_t *ullp;
30977c478bd9Sstevel@tonic-gate 	ulong_t *ulp;
30987c478bd9Sstevel@tonic-gate 	int i;
30997c478bd9Sstevel@tonic-gate 
31007c478bd9Sstevel@tonic-gate 	upup->pr_lwpid = pup->pr_lwpid;
31017c478bd9Sstevel@tonic-gate 	upup->pr_count = pup->pr_count;
31027c478bd9Sstevel@tonic-gate 
31037c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_tstamp,	&upup->pr_tstamp);
31047c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_create,	&upup->pr_create);
31057c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_term,	&upup->pr_term);
31067c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_rtime,	&upup->pr_rtime);
31077c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_utime,	&upup->pr_utime);
31087c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_stime,	&upup->pr_stime);
31097c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_ttime,	&upup->pr_ttime);
31107c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_tftime,	&upup->pr_tftime);
31117c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_dftime,	&upup->pr_dftime);
31127c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_kftime,	&upup->pr_kftime);
31137c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_ltime,	&upup->pr_ltime);
31147c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_slptime,	&upup->pr_slptime);
31157c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_wtime,	&upup->pr_wtime);
31167c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_stoptime, &upup->pr_stoptime);
31177c478bd9Sstevel@tonic-gate 	bzero(upup->filltime, sizeof (upup->filltime));
31187c478bd9Sstevel@tonic-gate 
31197c478bd9Sstevel@tonic-gate 	ullp = &pup->pr_minf;
31207c478bd9Sstevel@tonic-gate 	ulp = &upup->pr_minf;
31217c478bd9Sstevel@tonic-gate 	for (i = 0; i < 22; i++)
31227c478bd9Sstevel@tonic-gate 		*ulp++ = (ulong_t)*ullp++;
31237c478bd9Sstevel@tonic-gate }
31247c478bd9Sstevel@tonic-gate 
31257c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
31267c478bd9Sstevel@tonic-gate void
31277c478bd9Sstevel@tonic-gate prcvtusage32(prhusage_t *pup, prusage32_t *upup)
31287c478bd9Sstevel@tonic-gate {
31297c478bd9Sstevel@tonic-gate 	uint64_t *ullp;
31307c478bd9Sstevel@tonic-gate 	uint32_t *ulp;
31317c478bd9Sstevel@tonic-gate 	int i;
31327c478bd9Sstevel@tonic-gate 
31337c478bd9Sstevel@tonic-gate 	upup->pr_lwpid = pup->pr_lwpid;
31347c478bd9Sstevel@tonic-gate 	upup->pr_count = pup->pr_count;
31357c478bd9Sstevel@tonic-gate 
31367c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_tstamp,	&upup->pr_tstamp);
31377c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_create,	&upup->pr_create);
31387c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_term,		&upup->pr_term);
31397c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_rtime,		&upup->pr_rtime);
31407c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_utime,		&upup->pr_utime);
31417c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_stime,		&upup->pr_stime);
31427c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_ttime,		&upup->pr_ttime);
31437c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_tftime,	&upup->pr_tftime);
31447c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_dftime,	&upup->pr_dftime);
31457c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_kftime,	&upup->pr_kftime);
31467c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_ltime,		&upup->pr_ltime);
31477c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_slptime,	&upup->pr_slptime);
31487c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_wtime,		&upup->pr_wtime);
31497c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_stoptime,	&upup->pr_stoptime);
31507c478bd9Sstevel@tonic-gate 	bzero(upup->filltime, sizeof (upup->filltime));
31517c478bd9Sstevel@tonic-gate 
31527c478bd9Sstevel@tonic-gate 	ullp = &pup->pr_minf;
31537c478bd9Sstevel@tonic-gate 	ulp = &upup->pr_minf;
31547c478bd9Sstevel@tonic-gate 	for (i = 0; i < 22; i++)
31557c478bd9Sstevel@tonic-gate 		*ulp++ = (uint32_t)*ullp++;
31567c478bd9Sstevel@tonic-gate }
31577c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
31587c478bd9Sstevel@tonic-gate 
31597c478bd9Sstevel@tonic-gate /*
31607c478bd9Sstevel@tonic-gate  * Determine whether a set is empty.
31617c478bd9Sstevel@tonic-gate  */
31627c478bd9Sstevel@tonic-gate int
31637c478bd9Sstevel@tonic-gate setisempty(uint32_t *sp, uint_t n)
31647c478bd9Sstevel@tonic-gate {
31657c478bd9Sstevel@tonic-gate 	while (n--)
31667c478bd9Sstevel@tonic-gate 		if (*sp++)
31677c478bd9Sstevel@tonic-gate 			return (0);
31687c478bd9Sstevel@tonic-gate 	return (1);
31697c478bd9Sstevel@tonic-gate }
31707c478bd9Sstevel@tonic-gate 
31717c478bd9Sstevel@tonic-gate /*
31727c478bd9Sstevel@tonic-gate  * Utility routine for establishing a watched area in the process.
31737c478bd9Sstevel@tonic-gate  * Keep the list of watched areas sorted by virtual address.
31747c478bd9Sstevel@tonic-gate  */
31757c478bd9Sstevel@tonic-gate int
31767c478bd9Sstevel@tonic-gate set_watched_area(proc_t *p, struct watched_area *pwa)
31777c478bd9Sstevel@tonic-gate {
31787c478bd9Sstevel@tonic-gate 	caddr_t vaddr = pwa->wa_vaddr;
31797c478bd9Sstevel@tonic-gate 	caddr_t eaddr = pwa->wa_eaddr;
31807c478bd9Sstevel@tonic-gate 	ulong_t flags = pwa->wa_flags;
31817c478bd9Sstevel@tonic-gate 	struct watched_area *target;
31827c478bd9Sstevel@tonic-gate 	avl_index_t where;
31837c478bd9Sstevel@tonic-gate 	int error = 0;
31847c478bd9Sstevel@tonic-gate 
31857c478bd9Sstevel@tonic-gate 	/* we must not be holding p->p_lock, but the process must be locked */
31867c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&p->p_lock));
31877c478bd9Sstevel@tonic-gate 	ASSERT(p->p_proc_flag & P_PR_LOCK);
31887c478bd9Sstevel@tonic-gate 
31897c478bd9Sstevel@tonic-gate 	/*
31907c478bd9Sstevel@tonic-gate 	 * If this is our first watchpoint, enable watchpoints for the process.
31917c478bd9Sstevel@tonic-gate 	 */
31927c478bd9Sstevel@tonic-gate 	if (!pr_watch_active(p)) {
31937c478bd9Sstevel@tonic-gate 		kthread_t *t;
31947c478bd9Sstevel@tonic-gate 
31957c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
31967c478bd9Sstevel@tonic-gate 		if ((t = p->p_tlist) != NULL) {
31977c478bd9Sstevel@tonic-gate 			do {
31987c478bd9Sstevel@tonic-gate 				watch_enable(t);
31997c478bd9Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
32007c478bd9Sstevel@tonic-gate 		}
32017c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
32027c478bd9Sstevel@tonic-gate 	}
32037c478bd9Sstevel@tonic-gate 
32047c478bd9Sstevel@tonic-gate 	target = pr_find_watched_area(p, pwa, &where);
32057c478bd9Sstevel@tonic-gate 	if (target != NULL) {
32067c478bd9Sstevel@tonic-gate 		/*
32077c478bd9Sstevel@tonic-gate 		 * We discovered an existing, overlapping watched area.
32087c478bd9Sstevel@tonic-gate 		 * Allow it only if it is an exact match.
32097c478bd9Sstevel@tonic-gate 		 */
32107c478bd9Sstevel@tonic-gate 		if (target->wa_vaddr != vaddr ||
32117c478bd9Sstevel@tonic-gate 		    target->wa_eaddr != eaddr)
32127c478bd9Sstevel@tonic-gate 			error = EINVAL;
32137c478bd9Sstevel@tonic-gate 		else if (target->wa_flags != flags) {
32147c478bd9Sstevel@tonic-gate 			error = set_watched_page(p, vaddr, eaddr,
32157c478bd9Sstevel@tonic-gate 			    flags, target->wa_flags);
32167c478bd9Sstevel@tonic-gate 			target->wa_flags = flags;
32177c478bd9Sstevel@tonic-gate 		}
32187c478bd9Sstevel@tonic-gate 		kmem_free(pwa, sizeof (struct watched_area));
32197c478bd9Sstevel@tonic-gate 	} else {
32207c478bd9Sstevel@tonic-gate 		avl_insert(&p->p_warea, pwa, where);
32217c478bd9Sstevel@tonic-gate 		error = set_watched_page(p, vaddr, eaddr, flags, 0);
32227c478bd9Sstevel@tonic-gate 	}
32237c478bd9Sstevel@tonic-gate 
32247c478bd9Sstevel@tonic-gate 	return (error);
32257c478bd9Sstevel@tonic-gate }
32267c478bd9Sstevel@tonic-gate 
32277c478bd9Sstevel@tonic-gate /*
32287c478bd9Sstevel@tonic-gate  * Utility routine for clearing a watched area in the process.
32297c478bd9Sstevel@tonic-gate  * Must be an exact match of the virtual address.
32307c478bd9Sstevel@tonic-gate  * size and flags don't matter.
32317c478bd9Sstevel@tonic-gate  */
32327c478bd9Sstevel@tonic-gate int
32337c478bd9Sstevel@tonic-gate clear_watched_area(proc_t *p, struct watched_area *pwa)
32347c478bd9Sstevel@tonic-gate {
32357c478bd9Sstevel@tonic-gate 	struct watched_area *found;
32367c478bd9Sstevel@tonic-gate 
32377c478bd9Sstevel@tonic-gate 	/* we must not be holding p->p_lock, but the process must be locked */
32387c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&p->p_lock));
32397c478bd9Sstevel@tonic-gate 	ASSERT(p->p_proc_flag & P_PR_LOCK);
32407c478bd9Sstevel@tonic-gate 
32417c478bd9Sstevel@tonic-gate 
32427c478bd9Sstevel@tonic-gate 	if (!pr_watch_active(p)) {
32437c478bd9Sstevel@tonic-gate 		kmem_free(pwa, sizeof (struct watched_area));
32447c478bd9Sstevel@tonic-gate 		return (0);
32457c478bd9Sstevel@tonic-gate 	}
32467c478bd9Sstevel@tonic-gate 
32477c478bd9Sstevel@tonic-gate 	/*
32487c478bd9Sstevel@tonic-gate 	 * Look for a matching address in the watched areas.  If a match is
32497c478bd9Sstevel@tonic-gate 	 * found, clear the old watched area and adjust the watched page(s).  It
32507c478bd9Sstevel@tonic-gate 	 * is not an error if there is no match.
32517c478bd9Sstevel@tonic-gate 	 */
32527c478bd9Sstevel@tonic-gate 	if ((found = pr_find_watched_area(p, pwa, NULL)) != NULL &&
32537c478bd9Sstevel@tonic-gate 	    found->wa_vaddr == pwa->wa_vaddr) {
32547c478bd9Sstevel@tonic-gate 		clear_watched_page(p, found->wa_vaddr, found->wa_eaddr,
32557c478bd9Sstevel@tonic-gate 		    found->wa_flags);
32567c478bd9Sstevel@tonic-gate 		avl_remove(&p->p_warea, found);
32577c478bd9Sstevel@tonic-gate 		kmem_free(found, sizeof (struct watched_area));
32587c478bd9Sstevel@tonic-gate 	}
32597c478bd9Sstevel@tonic-gate 
32607c478bd9Sstevel@tonic-gate 	kmem_free(pwa, sizeof (struct watched_area));
32617c478bd9Sstevel@tonic-gate 
32627c478bd9Sstevel@tonic-gate 	/*
32637c478bd9Sstevel@tonic-gate 	 * If we removed the last watched area from the process, disable
32647c478bd9Sstevel@tonic-gate 	 * watchpoints.
32657c478bd9Sstevel@tonic-gate 	 */
32667c478bd9Sstevel@tonic-gate 	if (!pr_watch_active(p)) {
32677c478bd9Sstevel@tonic-gate 		kthread_t *t;
32687c478bd9Sstevel@tonic-gate 
32697c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
32707c478bd9Sstevel@tonic-gate 		if ((t = p->p_tlist) != NULL) {
32717c478bd9Sstevel@tonic-gate 			do {
32727c478bd9Sstevel@tonic-gate 				watch_disable(t);
32737c478bd9Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
32747c478bd9Sstevel@tonic-gate 		}
32757c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
32767c478bd9Sstevel@tonic-gate 	}
32777c478bd9Sstevel@tonic-gate 
32787c478bd9Sstevel@tonic-gate 	return (0);
32797c478bd9Sstevel@tonic-gate }
32807c478bd9Sstevel@tonic-gate 
32817c478bd9Sstevel@tonic-gate /*
32827c478bd9Sstevel@tonic-gate  * Frees all the watched_area structures
32837c478bd9Sstevel@tonic-gate  */
32847c478bd9Sstevel@tonic-gate void
32857c478bd9Sstevel@tonic-gate pr_free_watchpoints(proc_t *p)
32867c478bd9Sstevel@tonic-gate {
32877c478bd9Sstevel@tonic-gate 	struct watched_area *delp;
32887c478bd9Sstevel@tonic-gate 	void *cookie;
32897c478bd9Sstevel@tonic-gate 
32907c478bd9Sstevel@tonic-gate 	cookie = NULL;
32917c478bd9Sstevel@tonic-gate 	while ((delp = avl_destroy_nodes(&p->p_warea, &cookie)) != NULL)
32927c478bd9Sstevel@tonic-gate 		kmem_free(delp, sizeof (struct watched_area));
32937c478bd9Sstevel@tonic-gate 
32947c478bd9Sstevel@tonic-gate 	avl_destroy(&p->p_warea);
32957c478bd9Sstevel@tonic-gate }
32967c478bd9Sstevel@tonic-gate 
32977c478bd9Sstevel@tonic-gate /*
32987c478bd9Sstevel@tonic-gate  * This one is called by the traced process to unwatch all the
32997c478bd9Sstevel@tonic-gate  * pages while deallocating the list of watched_page structs.
33007c478bd9Sstevel@tonic-gate  */
33017c478bd9Sstevel@tonic-gate void
33027c478bd9Sstevel@tonic-gate pr_free_watched_pages(proc_t *p)
33037c478bd9Sstevel@tonic-gate {
33047c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
33057c478bd9Sstevel@tonic-gate 	struct watched_page *pwp;
33067c478bd9Sstevel@tonic-gate 	uint_t prot;
33077c478bd9Sstevel@tonic-gate 	int    retrycnt, err;
33087c478bd9Sstevel@tonic-gate 	void *cookie;
33097c478bd9Sstevel@tonic-gate 
33107c478bd9Sstevel@tonic-gate 	if (as == NULL || avl_numnodes(&as->a_wpage) == 0)
33117c478bd9Sstevel@tonic-gate 		return;
33127c478bd9Sstevel@tonic-gate 
33137c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&curproc->p_lock));
3314*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_ENTER(as, RW_WRITER);
33157c478bd9Sstevel@tonic-gate 
33167c478bd9Sstevel@tonic-gate 	pwp = avl_first(&as->a_wpage);
33177c478bd9Sstevel@tonic-gate 
33187c478bd9Sstevel@tonic-gate 	cookie = NULL;
33197c478bd9Sstevel@tonic-gate 	while ((pwp = avl_destroy_nodes(&as->a_wpage, &cookie)) != NULL) {
33207c478bd9Sstevel@tonic-gate 		retrycnt = 0;
33217c478bd9Sstevel@tonic-gate 		if ((prot = pwp->wp_oprot) != 0) {
33227c478bd9Sstevel@tonic-gate 			caddr_t addr = pwp->wp_vaddr;
33237c478bd9Sstevel@tonic-gate 			struct seg *seg;
33247c478bd9Sstevel@tonic-gate 		retry:
33257c478bd9Sstevel@tonic-gate 
33267c478bd9Sstevel@tonic-gate 			if ((pwp->wp_prot != prot ||
33277c478bd9Sstevel@tonic-gate 			    (pwp->wp_flags & WP_NOWATCH)) &&
33287c478bd9Sstevel@tonic-gate 			    (seg = as_segat(as, addr)) != NULL) {
33297c478bd9Sstevel@tonic-gate 				err = SEGOP_SETPROT(seg, addr, PAGESIZE, prot);
33307c478bd9Sstevel@tonic-gate 				if (err == IE_RETRY) {
33317c478bd9Sstevel@tonic-gate 					ASSERT(retrycnt == 0);
33327c478bd9Sstevel@tonic-gate 					retrycnt++;
33337c478bd9Sstevel@tonic-gate 					goto retry;
33347c478bd9Sstevel@tonic-gate 				}
33357c478bd9Sstevel@tonic-gate 			}
33367c478bd9Sstevel@tonic-gate 		}
33377c478bd9Sstevel@tonic-gate 		kmem_free(pwp, sizeof (struct watched_page));
33387c478bd9Sstevel@tonic-gate 	}
33397c478bd9Sstevel@tonic-gate 
33407c478bd9Sstevel@tonic-gate 	avl_destroy(&as->a_wpage);
33417c478bd9Sstevel@tonic-gate 	p->p_wprot = NULL;
33427c478bd9Sstevel@tonic-gate 
3343*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
33447c478bd9Sstevel@tonic-gate }
33457c478bd9Sstevel@tonic-gate 
33467c478bd9Sstevel@tonic-gate /*
33477c478bd9Sstevel@tonic-gate  * Insert a watched area into the list of watched pages.
33487c478bd9Sstevel@tonic-gate  * If oflags is zero then we are adding a new watched area.
33497c478bd9Sstevel@tonic-gate  * Otherwise we are changing the flags of an existing watched area.
33507c478bd9Sstevel@tonic-gate  */
33517c478bd9Sstevel@tonic-gate static int
33527c478bd9Sstevel@tonic-gate set_watched_page(proc_t *p, caddr_t vaddr, caddr_t eaddr,
33537c478bd9Sstevel@tonic-gate 	ulong_t flags, ulong_t oflags)
33547c478bd9Sstevel@tonic-gate {
33557c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
33567c478bd9Sstevel@tonic-gate 	avl_tree_t *pwp_tree;
33577c478bd9Sstevel@tonic-gate 	struct watched_page *pwp, *newpwp;
33587c478bd9Sstevel@tonic-gate 	struct watched_page tpw;
33597c478bd9Sstevel@tonic-gate 	avl_index_t where;
33607c478bd9Sstevel@tonic-gate 	struct seg *seg;
33617c478bd9Sstevel@tonic-gate 	uint_t prot;
33627c478bd9Sstevel@tonic-gate 	caddr_t addr;
33637c478bd9Sstevel@tonic-gate 
33647c478bd9Sstevel@tonic-gate 	/*
33657c478bd9Sstevel@tonic-gate 	 * We need to pre-allocate a list of structures before we grab the
33667c478bd9Sstevel@tonic-gate 	 * address space lock to avoid calling kmem_alloc(KM_SLEEP) with locks
33677c478bd9Sstevel@tonic-gate 	 * held.
33687c478bd9Sstevel@tonic-gate 	 */
33697c478bd9Sstevel@tonic-gate 	newpwp = NULL;
33707c478bd9Sstevel@tonic-gate 	for (addr = (caddr_t)((uintptr_t)vaddr & (uintptr_t)PAGEMASK);
33717c478bd9Sstevel@tonic-gate 	    addr < eaddr; addr += PAGESIZE) {
33727c478bd9Sstevel@tonic-gate 		pwp = kmem_zalloc(sizeof (struct watched_page), KM_SLEEP);
33737c478bd9Sstevel@tonic-gate 		pwp->wp_list = newpwp;
33747c478bd9Sstevel@tonic-gate 		newpwp = pwp;
33757c478bd9Sstevel@tonic-gate 	}
33767c478bd9Sstevel@tonic-gate 
3377*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_ENTER(as, RW_WRITER);
33787c478bd9Sstevel@tonic-gate 
33797c478bd9Sstevel@tonic-gate 	/*
33807c478bd9Sstevel@tonic-gate 	 * Search for an existing watched page to contain the watched area.
33817c478bd9Sstevel@tonic-gate 	 * If none is found, grab a new one from the available list
33827c478bd9Sstevel@tonic-gate 	 * and insert it in the active list, keeping the list sorted
33837c478bd9Sstevel@tonic-gate 	 * by user-level virtual address.
33847c478bd9Sstevel@tonic-gate 	 */
33857c478bd9Sstevel@tonic-gate 	if (p->p_flag & SVFWAIT)
33867c478bd9Sstevel@tonic-gate 		pwp_tree = &p->p_wpage;
33877c478bd9Sstevel@tonic-gate 	else
33887c478bd9Sstevel@tonic-gate 		pwp_tree = &as->a_wpage;
33897c478bd9Sstevel@tonic-gate 
33907c478bd9Sstevel@tonic-gate again:
33917c478bd9Sstevel@tonic-gate 	if (avl_numnodes(pwp_tree) > prnwatch) {
3392*dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_EXIT(as);
33937c478bd9Sstevel@tonic-gate 		while (newpwp != NULL) {
33947c478bd9Sstevel@tonic-gate 			pwp = newpwp->wp_list;
33957c478bd9Sstevel@tonic-gate 			kmem_free(newpwp, sizeof (struct watched_page));
33967c478bd9Sstevel@tonic-gate 			newpwp = pwp;
33977c478bd9Sstevel@tonic-gate 		}
33987c478bd9Sstevel@tonic-gate 		return (E2BIG);
33997c478bd9Sstevel@tonic-gate 	}
34007c478bd9Sstevel@tonic-gate 
34017c478bd9Sstevel@tonic-gate 	tpw.wp_vaddr = (caddr_t)((uintptr_t)vaddr & (uintptr_t)PAGEMASK);
34027c478bd9Sstevel@tonic-gate 	if ((pwp = avl_find(pwp_tree, &tpw, &where)) == NULL) {
34037c478bd9Sstevel@tonic-gate 		pwp = newpwp;
34047c478bd9Sstevel@tonic-gate 		newpwp = newpwp->wp_list;
34057c478bd9Sstevel@tonic-gate 		pwp->wp_list = NULL;
34067c478bd9Sstevel@tonic-gate 		pwp->wp_vaddr = (caddr_t)((uintptr_t)vaddr &
34077c478bd9Sstevel@tonic-gate 		    (uintptr_t)PAGEMASK);
34087c478bd9Sstevel@tonic-gate 		avl_insert(pwp_tree, pwp, where);
34097c478bd9Sstevel@tonic-gate 	}
34107c478bd9Sstevel@tonic-gate 
34117c478bd9Sstevel@tonic-gate 	ASSERT(vaddr >= pwp->wp_vaddr && vaddr < pwp->wp_vaddr + PAGESIZE);
34127c478bd9Sstevel@tonic-gate 
34137c478bd9Sstevel@tonic-gate 	if (oflags & WA_READ)
34147c478bd9Sstevel@tonic-gate 		pwp->wp_read--;
34157c478bd9Sstevel@tonic-gate 	if (oflags & WA_WRITE)
34167c478bd9Sstevel@tonic-gate 		pwp->wp_write--;
34177c478bd9Sstevel@tonic-gate 	if (oflags & WA_EXEC)
34187c478bd9Sstevel@tonic-gate 		pwp->wp_exec--;
34197c478bd9Sstevel@tonic-gate 
34207c478bd9Sstevel@tonic-gate 	ASSERT(pwp->wp_read >= 0);
34217c478bd9Sstevel@tonic-gate 	ASSERT(pwp->wp_write >= 0);
34227c478bd9Sstevel@tonic-gate 	ASSERT(pwp->wp_exec >= 0);
34237c478bd9Sstevel@tonic-gate 
34247c478bd9Sstevel@tonic-gate 	if (flags & WA_READ)
34257c478bd9Sstevel@tonic-gate 		pwp->wp_read++;
34267c478bd9Sstevel@tonic-gate 	if (flags & WA_WRITE)
34277c478bd9Sstevel@tonic-gate 		pwp->wp_write++;
34287c478bd9Sstevel@tonic-gate 	if (flags & WA_EXEC)
34297c478bd9Sstevel@tonic-gate 		pwp->wp_exec++;
34307c478bd9Sstevel@tonic-gate 
34317c478bd9Sstevel@tonic-gate 	if (!(p->p_flag & SVFWAIT)) {
34327c478bd9Sstevel@tonic-gate 		vaddr = pwp->wp_vaddr;
34337c478bd9Sstevel@tonic-gate 		if (pwp->wp_oprot == 0 &&
34347c478bd9Sstevel@tonic-gate 		    (seg = as_segat(as, vaddr)) != NULL) {
34357c478bd9Sstevel@tonic-gate 			SEGOP_GETPROT(seg, vaddr, 0, &prot);
34367c478bd9Sstevel@tonic-gate 			pwp->wp_oprot = (uchar_t)prot;
34377c478bd9Sstevel@tonic-gate 			pwp->wp_prot = (uchar_t)prot;
34387c478bd9Sstevel@tonic-gate 		}
34397c478bd9Sstevel@tonic-gate 		if (pwp->wp_oprot != 0) {
34407c478bd9Sstevel@tonic-gate 			prot = pwp->wp_oprot;
34417c478bd9Sstevel@tonic-gate 			if (pwp->wp_read)
34427c478bd9Sstevel@tonic-gate 				prot &= ~(PROT_READ|PROT_WRITE|PROT_EXEC);
34437c478bd9Sstevel@tonic-gate 			if (pwp->wp_write)
34447c478bd9Sstevel@tonic-gate 				prot &= ~PROT_WRITE;
34457c478bd9Sstevel@tonic-gate 			if (pwp->wp_exec)
34467c478bd9Sstevel@tonic-gate 				prot &= ~(PROT_READ|PROT_WRITE|PROT_EXEC);
34477c478bd9Sstevel@tonic-gate 			if (!(pwp->wp_flags & WP_NOWATCH) &&
34487c478bd9Sstevel@tonic-gate 			    pwp->wp_prot != prot &&
34497c478bd9Sstevel@tonic-gate 			    (pwp->wp_flags & WP_SETPROT) == 0) {
34507c478bd9Sstevel@tonic-gate 				pwp->wp_flags |= WP_SETPROT;
34517c478bd9Sstevel@tonic-gate 				pwp->wp_list = p->p_wprot;
34527c478bd9Sstevel@tonic-gate 				p->p_wprot = pwp;
34537c478bd9Sstevel@tonic-gate 			}
34547c478bd9Sstevel@tonic-gate 			pwp->wp_prot = (uchar_t)prot;
34557c478bd9Sstevel@tonic-gate 		}
34567c478bd9Sstevel@tonic-gate 	}
34577c478bd9Sstevel@tonic-gate 
34587c478bd9Sstevel@tonic-gate 	/*
34597c478bd9Sstevel@tonic-gate 	 * If the watched area extends into the next page then do
34607c478bd9Sstevel@tonic-gate 	 * it over again with the virtual address of the next page.
34617c478bd9Sstevel@tonic-gate 	 */
34627c478bd9Sstevel@tonic-gate 	if ((vaddr = pwp->wp_vaddr + PAGESIZE) < eaddr)
34637c478bd9Sstevel@tonic-gate 		goto again;
34647c478bd9Sstevel@tonic-gate 
3465*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
34667c478bd9Sstevel@tonic-gate 
34677c478bd9Sstevel@tonic-gate 	/*
34687c478bd9Sstevel@tonic-gate 	 * Free any pages we may have over-allocated
34697c478bd9Sstevel@tonic-gate 	 */
34707c478bd9Sstevel@tonic-gate 	while (newpwp != NULL) {
34717c478bd9Sstevel@tonic-gate 		pwp = newpwp->wp_list;
34727c478bd9Sstevel@tonic-gate 		kmem_free(newpwp, sizeof (struct watched_page));
34737c478bd9Sstevel@tonic-gate 		newpwp = pwp;
34747c478bd9Sstevel@tonic-gate 	}
34757c478bd9Sstevel@tonic-gate 
34767c478bd9Sstevel@tonic-gate 	return (0);
34777c478bd9Sstevel@tonic-gate }
34787c478bd9Sstevel@tonic-gate 
34797c478bd9Sstevel@tonic-gate /*
34807c478bd9Sstevel@tonic-gate  * Remove a watched area from the list of watched pages.
34817c478bd9Sstevel@tonic-gate  * A watched area may extend over more than one page.
34827c478bd9Sstevel@tonic-gate  */
34837c478bd9Sstevel@tonic-gate static void
34847c478bd9Sstevel@tonic-gate clear_watched_page(proc_t *p, caddr_t vaddr, caddr_t eaddr, ulong_t flags)
34857c478bd9Sstevel@tonic-gate {
34867c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
34877c478bd9Sstevel@tonic-gate 	struct watched_page *pwp;
34887c478bd9Sstevel@tonic-gate 	struct watched_page tpw;
34897c478bd9Sstevel@tonic-gate 	avl_tree_t *tree;
34907c478bd9Sstevel@tonic-gate 	avl_index_t where;
34917c478bd9Sstevel@tonic-gate 
3492*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_ENTER(as, RW_WRITER);
34937c478bd9Sstevel@tonic-gate 
34947c478bd9Sstevel@tonic-gate 	if (p->p_flag & SVFWAIT)
34957c478bd9Sstevel@tonic-gate 		tree = &p->p_wpage;
34967c478bd9Sstevel@tonic-gate 	else
34977c478bd9Sstevel@tonic-gate 		tree = &as->a_wpage;
34987c478bd9Sstevel@tonic-gate 
34997c478bd9Sstevel@tonic-gate 	tpw.wp_vaddr = vaddr =
35007c478bd9Sstevel@tonic-gate 	    (caddr_t)((uintptr_t)vaddr & (uintptr_t)PAGEMASK);
35017c478bd9Sstevel@tonic-gate 	pwp = avl_find(tree, &tpw, &where);
35027c478bd9Sstevel@tonic-gate 	if (pwp == NULL)
35037c478bd9Sstevel@tonic-gate 		pwp = avl_nearest(tree, where, AVL_AFTER);
35047c478bd9Sstevel@tonic-gate 
35057c478bd9Sstevel@tonic-gate 	while (pwp != NULL && pwp->wp_vaddr < eaddr) {
35067c478bd9Sstevel@tonic-gate 		ASSERT(vaddr <=  pwp->wp_vaddr);
35077c478bd9Sstevel@tonic-gate 
35087c478bd9Sstevel@tonic-gate 		if (flags & WA_READ)
35097c478bd9Sstevel@tonic-gate 			pwp->wp_read--;
35107c478bd9Sstevel@tonic-gate 		if (flags & WA_WRITE)
35117c478bd9Sstevel@tonic-gate 			pwp->wp_write--;
35127c478bd9Sstevel@tonic-gate 		if (flags & WA_EXEC)
35137c478bd9Sstevel@tonic-gate 			pwp->wp_exec--;
35147c478bd9Sstevel@tonic-gate 
35157c478bd9Sstevel@tonic-gate 		if (pwp->wp_read + pwp->wp_write + pwp->wp_exec != 0) {
35167c478bd9Sstevel@tonic-gate 			/*
35177c478bd9Sstevel@tonic-gate 			 * Reset the hat layer's protections on this page.
35187c478bd9Sstevel@tonic-gate 			 */
35197c478bd9Sstevel@tonic-gate 			if (pwp->wp_oprot != 0) {
35207c478bd9Sstevel@tonic-gate 				uint_t prot = pwp->wp_oprot;
35217c478bd9Sstevel@tonic-gate 
35227c478bd9Sstevel@tonic-gate 				if (pwp->wp_read)
35237c478bd9Sstevel@tonic-gate 					prot &=
35247c478bd9Sstevel@tonic-gate 					    ~(PROT_READ|PROT_WRITE|PROT_EXEC);
35257c478bd9Sstevel@tonic-gate 				if (pwp->wp_write)
35267c478bd9Sstevel@tonic-gate 					prot &= ~PROT_WRITE;
35277c478bd9Sstevel@tonic-gate 				if (pwp->wp_exec)
35287c478bd9Sstevel@tonic-gate 					prot &=
35297c478bd9Sstevel@tonic-gate 					    ~(PROT_READ|PROT_WRITE|PROT_EXEC);
35307c478bd9Sstevel@tonic-gate 				if (!(pwp->wp_flags & WP_NOWATCH) &&
35317c478bd9Sstevel@tonic-gate 				    pwp->wp_prot != prot &&
35327c478bd9Sstevel@tonic-gate 				    (pwp->wp_flags & WP_SETPROT) == 0) {
35337c478bd9Sstevel@tonic-gate 					pwp->wp_flags |= WP_SETPROT;
35347c478bd9Sstevel@tonic-gate 					pwp->wp_list = p->p_wprot;
35357c478bd9Sstevel@tonic-gate 					p->p_wprot = pwp;
35367c478bd9Sstevel@tonic-gate 				}
35377c478bd9Sstevel@tonic-gate 				pwp->wp_prot = (uchar_t)prot;
35387c478bd9Sstevel@tonic-gate 			}
35397c478bd9Sstevel@tonic-gate 		} else {
35407c478bd9Sstevel@tonic-gate 			/*
35417c478bd9Sstevel@tonic-gate 			 * No watched areas remain in this page.
35427c478bd9Sstevel@tonic-gate 			 * Reset everything to normal.
35437c478bd9Sstevel@tonic-gate 			 */
35447c478bd9Sstevel@tonic-gate 			if (pwp->wp_oprot != 0) {
35457c478bd9Sstevel@tonic-gate 				pwp->wp_prot = pwp->wp_oprot;
35467c478bd9Sstevel@tonic-gate 				if ((pwp->wp_flags & WP_SETPROT) == 0) {
35477c478bd9Sstevel@tonic-gate 					pwp->wp_flags |= WP_SETPROT;
35487c478bd9Sstevel@tonic-gate 					pwp->wp_list = p->p_wprot;
35497c478bd9Sstevel@tonic-gate 					p->p_wprot = pwp;
35507c478bd9Sstevel@tonic-gate 				}
35517c478bd9Sstevel@tonic-gate 			}
35527c478bd9Sstevel@tonic-gate 		}
35537c478bd9Sstevel@tonic-gate 
35547c478bd9Sstevel@tonic-gate 		pwp = AVL_NEXT(tree, pwp);
35557c478bd9Sstevel@tonic-gate 	}
35567c478bd9Sstevel@tonic-gate 
3557*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
35587c478bd9Sstevel@tonic-gate }
35597c478bd9Sstevel@tonic-gate 
35607c478bd9Sstevel@tonic-gate /*
35617c478bd9Sstevel@tonic-gate  * Return the original protections for the specified page.
35627c478bd9Sstevel@tonic-gate  */
35637c478bd9Sstevel@tonic-gate static void
35647c478bd9Sstevel@tonic-gate getwatchprot(struct as *as, caddr_t addr, uint_t *prot)
35657c478bd9Sstevel@tonic-gate {
35667c478bd9Sstevel@tonic-gate 	struct watched_page *pwp;
35677c478bd9Sstevel@tonic-gate 	struct watched_page tpw;
35687c478bd9Sstevel@tonic-gate 
3569*dc32d872SJosef 'Jeff' Sipek 	ASSERT(AS_LOCK_HELD(as));
35707c478bd9Sstevel@tonic-gate 
35717c478bd9Sstevel@tonic-gate 	tpw.wp_vaddr = (caddr_t)((uintptr_t)addr & (uintptr_t)PAGEMASK);
35727c478bd9Sstevel@tonic-gate 	if ((pwp = avl_find(&as->a_wpage, &tpw, NULL)) != NULL)
35737c478bd9Sstevel@tonic-gate 		*prot = pwp->wp_oprot;
35747c478bd9Sstevel@tonic-gate }
35757c478bd9Sstevel@tonic-gate 
35767c478bd9Sstevel@tonic-gate static prpagev_t *
35777c478bd9Sstevel@tonic-gate pr_pagev_create(struct seg *seg, int check_noreserve)
35787c478bd9Sstevel@tonic-gate {
35797c478bd9Sstevel@tonic-gate 	prpagev_t *pagev = kmem_alloc(sizeof (prpagev_t), KM_SLEEP);
35807c478bd9Sstevel@tonic-gate 	size_t total_pages = seg_pages(seg);
35817c478bd9Sstevel@tonic-gate 
35827c478bd9Sstevel@tonic-gate 	/*
35837c478bd9Sstevel@tonic-gate 	 * Limit the size of our vectors to pagev_lim pages at a time.  We need
35847c478bd9Sstevel@tonic-gate 	 * 4 or 5 bytes of storage per page, so this means we limit ourself
35857c478bd9Sstevel@tonic-gate 	 * to about a megabyte of kernel heap by default.
35867c478bd9Sstevel@tonic-gate 	 */
35877c478bd9Sstevel@tonic-gate 	pagev->pg_npages = MIN(total_pages, pagev_lim);
35887c478bd9Sstevel@tonic-gate 	pagev->pg_pnbase = 0;
35897c478bd9Sstevel@tonic-gate 
35907c478bd9Sstevel@tonic-gate 	pagev->pg_protv =
35917c478bd9Sstevel@tonic-gate 	    kmem_alloc(pagev->pg_npages * sizeof (uint_t), KM_SLEEP);
35927c478bd9Sstevel@tonic-gate 
35937c478bd9Sstevel@tonic-gate 	if (check_noreserve)
35947c478bd9Sstevel@tonic-gate 		pagev->pg_incore =
35957c478bd9Sstevel@tonic-gate 		    kmem_alloc(pagev->pg_npages * sizeof (char), KM_SLEEP);
35967c478bd9Sstevel@tonic-gate 	else
35977c478bd9Sstevel@tonic-gate 		pagev->pg_incore = NULL;
35987c478bd9Sstevel@tonic-gate 
35997c478bd9Sstevel@tonic-gate 	return (pagev);
36007c478bd9Sstevel@tonic-gate }
36017c478bd9Sstevel@tonic-gate 
36027c478bd9Sstevel@tonic-gate static void
36037c478bd9Sstevel@tonic-gate pr_pagev_destroy(prpagev_t *pagev)
36047c478bd9Sstevel@tonic-gate {
36057c478bd9Sstevel@tonic-gate 	if (pagev->pg_incore != NULL)
36067c478bd9Sstevel@tonic-gate 		kmem_free(pagev->pg_incore, pagev->pg_npages * sizeof (char));
36077c478bd9Sstevel@tonic-gate 
36087c478bd9Sstevel@tonic-gate 	kmem_free(pagev->pg_protv, pagev->pg_npages * sizeof (uint_t));
36097c478bd9Sstevel@tonic-gate 	kmem_free(pagev, sizeof (prpagev_t));
36107c478bd9Sstevel@tonic-gate }
36117c478bd9Sstevel@tonic-gate 
36127c478bd9Sstevel@tonic-gate static caddr_t
36137c478bd9Sstevel@tonic-gate pr_pagev_fill(prpagev_t *pagev, struct seg *seg, caddr_t addr, caddr_t eaddr)
36147c478bd9Sstevel@tonic-gate {
36157c478bd9Sstevel@tonic-gate 	ulong_t lastpg = seg_page(seg, eaddr - 1);
36167c478bd9Sstevel@tonic-gate 	ulong_t pn, pnlim;
36177c478bd9Sstevel@tonic-gate 	caddr_t saddr;
36187c478bd9Sstevel@tonic-gate 	size_t len;
36197c478bd9Sstevel@tonic-gate 
36207c478bd9Sstevel@tonic-gate 	ASSERT(addr >= seg->s_base && addr <= eaddr);
36217c478bd9Sstevel@tonic-gate 
36227c478bd9Sstevel@tonic-gate 	if (addr == eaddr)
36237c478bd9Sstevel@tonic-gate 		return (eaddr);
36247c478bd9Sstevel@tonic-gate 
36257c478bd9Sstevel@tonic-gate refill:
36267c478bd9Sstevel@tonic-gate 	ASSERT(addr < eaddr);
36277c478bd9Sstevel@tonic-gate 	pagev->pg_pnbase = seg_page(seg, addr);
36287c478bd9Sstevel@tonic-gate 	pnlim = pagev->pg_pnbase + pagev->pg_npages;
36297c478bd9Sstevel@tonic-gate 	saddr = addr;
36307c478bd9Sstevel@tonic-gate 
36317c478bd9Sstevel@tonic-gate 	if (lastpg < pnlim)
36327c478bd9Sstevel@tonic-gate 		len = (size_t)(eaddr - addr);
36337c478bd9Sstevel@tonic-gate 	else
36347c478bd9Sstevel@tonic-gate 		len = pagev->pg_npages * PAGESIZE;
36357c478bd9Sstevel@tonic-gate 
36367c478bd9Sstevel@tonic-gate 	if (pagev->pg_incore != NULL) {
36377c478bd9Sstevel@tonic-gate 		/*
36387c478bd9Sstevel@tonic-gate 		 * INCORE cleverly has different semantics than GETPROT:
36397c478bd9Sstevel@tonic-gate 		 * it returns info on pages up to but NOT including addr + len.
36407c478bd9Sstevel@tonic-gate 		 */
36417c478bd9Sstevel@tonic-gate 		SEGOP_INCORE(seg, addr, len, pagev->pg_incore);
36427c478bd9Sstevel@tonic-gate 		pn = pagev->pg_pnbase;
36437c478bd9Sstevel@tonic-gate 
36447c478bd9Sstevel@tonic-gate 		do {
36457c478bd9Sstevel@tonic-gate 			/*
36467c478bd9Sstevel@tonic-gate 			 * Guilty knowledge here:  We know that segvn_incore
36477c478bd9Sstevel@tonic-gate 			 * returns more than just the low-order bit that
36487c478bd9Sstevel@tonic-gate 			 * indicates the page is actually in memory.  If any
36497c478bd9Sstevel@tonic-gate 			 * bits are set, then the page has backing store.
36507c478bd9Sstevel@tonic-gate 			 */
36517c478bd9Sstevel@tonic-gate 			if (pagev->pg_incore[pn++ - pagev->pg_pnbase])
36527c478bd9Sstevel@tonic-gate 				goto out;
36537c478bd9Sstevel@tonic-gate 
36547c478bd9Sstevel@tonic-gate 		} while ((addr += PAGESIZE) < eaddr && pn < pnlim);
36557c478bd9Sstevel@tonic-gate 
36567c478bd9Sstevel@tonic-gate 		/*
36577c478bd9Sstevel@tonic-gate 		 * If we examined all the pages in the vector but we're not
36587c478bd9Sstevel@tonic-gate 		 * at the end of the segment, take another lap.
36597c478bd9Sstevel@tonic-gate 		 */
36607c478bd9Sstevel@tonic-gate 		if (addr < eaddr)
36617c478bd9Sstevel@tonic-gate 			goto refill;
36627c478bd9Sstevel@tonic-gate 	}
36637c478bd9Sstevel@tonic-gate 
36647c478bd9Sstevel@tonic-gate 	/*
36657c478bd9Sstevel@tonic-gate 	 * Need to take len - 1 because addr + len is the address of the
36667c478bd9Sstevel@tonic-gate 	 * first byte of the page just past the end of what we want.
36677c478bd9Sstevel@tonic-gate 	 */
36687c478bd9Sstevel@tonic-gate out:
36697c478bd9Sstevel@tonic-gate 	SEGOP_GETPROT(seg, saddr, len - 1, pagev->pg_protv);
36707c478bd9Sstevel@tonic-gate 	return (addr);
36717c478bd9Sstevel@tonic-gate }
36727c478bd9Sstevel@tonic-gate 
36737c478bd9Sstevel@tonic-gate static caddr_t
36747c478bd9Sstevel@tonic-gate pr_pagev_nextprot(prpagev_t *pagev, struct seg *seg,
36757c478bd9Sstevel@tonic-gate     caddr_t *saddrp, caddr_t eaddr, uint_t *protp)
36767c478bd9Sstevel@tonic-gate {
36777c478bd9Sstevel@tonic-gate 	/*
36787c478bd9Sstevel@tonic-gate 	 * Our starting address is either the specified address, or the base
36797c478bd9Sstevel@tonic-gate 	 * address from the start of the pagev.  If the latter is greater,
36807c478bd9Sstevel@tonic-gate 	 * this means a previous call to pr_pagev_fill has already scanned
36817c478bd9Sstevel@tonic-gate 	 * further than the end of the previous mapping.
36827c478bd9Sstevel@tonic-gate 	 */
36837c478bd9Sstevel@tonic-gate 	caddr_t base = seg->s_base + pagev->pg_pnbase * PAGESIZE;
36847c478bd9Sstevel@tonic-gate 	caddr_t addr = MAX(*saddrp, base);
36857c478bd9Sstevel@tonic-gate 	ulong_t pn = seg_page(seg, addr);
36867c478bd9Sstevel@tonic-gate 	uint_t prot, nprot;
36877c478bd9Sstevel@tonic-gate 
36887c478bd9Sstevel@tonic-gate 	/*
36897c478bd9Sstevel@tonic-gate 	 * If we're dealing with noreserve pages, then advance addr to
36907c478bd9Sstevel@tonic-gate 	 * the address of the next page which has backing store.
36917c478bd9Sstevel@tonic-gate 	 */
36927c478bd9Sstevel@tonic-gate 	if (pagev->pg_incore != NULL) {
36937c478bd9Sstevel@tonic-gate 		while (pagev->pg_incore[pn - pagev->pg_pnbase] == 0) {
36947c478bd9Sstevel@tonic-gate 			if ((addr += PAGESIZE) == eaddr) {
36957c478bd9Sstevel@tonic-gate 				*saddrp = addr;
36967c478bd9Sstevel@tonic-gate 				prot = 0;
36977c478bd9Sstevel@tonic-gate 				goto out;
36987c478bd9Sstevel@tonic-gate 			}
36997c478bd9Sstevel@tonic-gate 			if (++pn == pagev->pg_pnbase + pagev->pg_npages) {
37007c478bd9Sstevel@tonic-gate 				addr = pr_pagev_fill(pagev, seg, addr, eaddr);
37017c478bd9Sstevel@tonic-gate 				if (addr == eaddr) {
37027c478bd9Sstevel@tonic-gate 					*saddrp = addr;
37037c478bd9Sstevel@tonic-gate 					prot = 0;
37047c478bd9Sstevel@tonic-gate 					goto out;
37057c478bd9Sstevel@tonic-gate 				}
37067c478bd9Sstevel@tonic-gate 				pn = seg_page(seg, addr);
37077c478bd9Sstevel@tonic-gate 			}
37087c478bd9Sstevel@tonic-gate 		}
37097c478bd9Sstevel@tonic-gate 	}
37107c478bd9Sstevel@tonic-gate 
37117c478bd9Sstevel@tonic-gate 	/*
37127c478bd9Sstevel@tonic-gate 	 * Get the protections on the page corresponding to addr.
37137c478bd9Sstevel@tonic-gate 	 */
37147c478bd9Sstevel@tonic-gate 	pn = seg_page(seg, addr);
37157c478bd9Sstevel@tonic-gate 	ASSERT(pn >= pagev->pg_pnbase);
37167c478bd9Sstevel@tonic-gate 	ASSERT(pn < (pagev->pg_pnbase + pagev->pg_npages));
37177c478bd9Sstevel@tonic-gate 
37187c478bd9Sstevel@tonic-gate 	prot = pagev->pg_protv[pn - pagev->pg_pnbase];
37197c478bd9Sstevel@tonic-gate 	getwatchprot(seg->s_as, addr, &prot);
37207c478bd9Sstevel@tonic-gate 	*saddrp = addr;
37217c478bd9Sstevel@tonic-gate 
37227c478bd9Sstevel@tonic-gate 	/*
37237c478bd9Sstevel@tonic-gate 	 * Now loop until we find a backed page with different protections
37247c478bd9Sstevel@tonic-gate 	 * or we reach the end of this segment.
37257c478bd9Sstevel@tonic-gate 	 */
37267c478bd9Sstevel@tonic-gate 	while ((addr += PAGESIZE) < eaddr) {
37277c478bd9Sstevel@tonic-gate 		/*
37287c478bd9Sstevel@tonic-gate 		 * If pn has advanced to the page number following what we
37297c478bd9Sstevel@tonic-gate 		 * have information on, refill the page vector and reset
37307c478bd9Sstevel@tonic-gate 		 * addr and pn.  If pr_pagev_fill does not return the
37317c478bd9Sstevel@tonic-gate 		 * address of the next page, we have a discontiguity and
37327c478bd9Sstevel@tonic-gate 		 * thus have reached the end of the current mapping.
37337c478bd9Sstevel@tonic-gate 		 */
37347c478bd9Sstevel@tonic-gate 		if (++pn == pagev->pg_pnbase + pagev->pg_npages) {
37357c478bd9Sstevel@tonic-gate 			caddr_t naddr = pr_pagev_fill(pagev, seg, addr, eaddr);
37367c478bd9Sstevel@tonic-gate 			if (naddr != addr)
37377c478bd9Sstevel@tonic-gate 				goto out;
37387c478bd9Sstevel@tonic-gate 			pn = seg_page(seg, addr);
37397c478bd9Sstevel@tonic-gate 		}
37407c478bd9Sstevel@tonic-gate 
37417c478bd9Sstevel@tonic-gate 		/*
37427c478bd9Sstevel@tonic-gate 		 * The previous page's protections are in prot, and it has
37437c478bd9Sstevel@tonic-gate 		 * backing.  If this page is MAP_NORESERVE and has no backing,
37447c478bd9Sstevel@tonic-gate 		 * then end this mapping and return the previous protections.
37457c478bd9Sstevel@tonic-gate 		 */
37467c478bd9Sstevel@tonic-gate 		if (pagev->pg_incore != NULL &&
37477c478bd9Sstevel@tonic-gate 		    pagev->pg_incore[pn - pagev->pg_pnbase] == 0)
37487c478bd9Sstevel@tonic-gate 			break;
37497c478bd9Sstevel@tonic-gate 
37507c478bd9Sstevel@tonic-gate 		/*
37517c478bd9Sstevel@tonic-gate 		 * Otherwise end the mapping if this page's protections (nprot)
37527c478bd9Sstevel@tonic-gate 		 * are different than those in the previous page (prot).
37537c478bd9Sstevel@tonic-gate 		 */
37547c478bd9Sstevel@tonic-gate 		nprot = pagev->pg_protv[pn - pagev->pg_pnbase];
37557c478bd9Sstevel@tonic-gate 		getwatchprot(seg->s_as, addr, &nprot);
37567c478bd9Sstevel@tonic-gate 
37577c478bd9Sstevel@tonic-gate 		if (nprot != prot)
37587c478bd9Sstevel@tonic-gate 			break;
37597c478bd9Sstevel@tonic-gate 	}
37607c478bd9Sstevel@tonic-gate 
37617c478bd9Sstevel@tonic-gate out:
37627c478bd9Sstevel@tonic-gate 	*protp = prot;
37637c478bd9Sstevel@tonic-gate 	return (addr);
37647c478bd9Sstevel@tonic-gate }
37657c478bd9Sstevel@tonic-gate 
37667c478bd9Sstevel@tonic-gate size_t
37677c478bd9Sstevel@tonic-gate pr_getsegsize(struct seg *seg, int reserved)
37687c478bd9Sstevel@tonic-gate {
37697c478bd9Sstevel@tonic-gate 	size_t size = seg->s_size;
37707c478bd9Sstevel@tonic-gate 
37717c478bd9Sstevel@tonic-gate 	/*
37727c478bd9Sstevel@tonic-gate 	 * If we're interested in the reserved space, return the size of the
37737c478bd9Sstevel@tonic-gate 	 * segment itself.  Everything else in this function is a special case
37747c478bd9Sstevel@tonic-gate 	 * to determine the actual underlying size of various segment types.
37757c478bd9Sstevel@tonic-gate 	 */
37767c478bd9Sstevel@tonic-gate 	if (reserved)
37777c478bd9Sstevel@tonic-gate 		return (size);
37787c478bd9Sstevel@tonic-gate 
37797c478bd9Sstevel@tonic-gate 	/*
37807c478bd9Sstevel@tonic-gate 	 * If this is a segvn mapping of a regular file, return the smaller
37817c478bd9Sstevel@tonic-gate 	 * of the segment size and the remaining size of the file beyond
37827c478bd9Sstevel@tonic-gate 	 * the file offset corresponding to seg->s_base.
37837c478bd9Sstevel@tonic-gate 	 */
37847c478bd9Sstevel@tonic-gate 	if (seg->s_ops == &segvn_ops) {
37857c478bd9Sstevel@tonic-gate 		vattr_t vattr;
37867c478bd9Sstevel@tonic-gate 		vnode_t *vp;
37877c478bd9Sstevel@tonic-gate 
37887c478bd9Sstevel@tonic-gate 		vattr.va_mask = AT_SIZE;
37897c478bd9Sstevel@tonic-gate 
37907c478bd9Sstevel@tonic-gate 		if (SEGOP_GETVP(seg, seg->s_base, &vp) == 0 &&
37917c478bd9Sstevel@tonic-gate 		    vp != NULL && vp->v_type == VREG &&
3792da6c28aaSamw 		    VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
37937c478bd9Sstevel@tonic-gate 
37947c478bd9Sstevel@tonic-gate 			u_offset_t fsize = vattr.va_size;
37957c478bd9Sstevel@tonic-gate 			u_offset_t offset = SEGOP_GETOFFSET(seg, seg->s_base);
37967c478bd9Sstevel@tonic-gate 
37977c478bd9Sstevel@tonic-gate 			if (fsize < offset)
37987c478bd9Sstevel@tonic-gate 				fsize = 0;
37997c478bd9Sstevel@tonic-gate 			else
38007c478bd9Sstevel@tonic-gate 				fsize -= offset;
38017c478bd9Sstevel@tonic-gate 
38027c478bd9Sstevel@tonic-gate 			fsize = roundup(fsize, (u_offset_t)PAGESIZE);
38037c478bd9Sstevel@tonic-gate 
38047c478bd9Sstevel@tonic-gate 			if (fsize < (u_offset_t)size)
38057c478bd9Sstevel@tonic-gate 				size = (size_t)fsize;
38067c478bd9Sstevel@tonic-gate 		}
38077c478bd9Sstevel@tonic-gate 
38087c478bd9Sstevel@tonic-gate 		return (size);
38097c478bd9Sstevel@tonic-gate 	}
38107c478bd9Sstevel@tonic-gate 
38117c478bd9Sstevel@tonic-gate 	/*
38127c478bd9Sstevel@tonic-gate 	 * If this is an ISM shared segment, don't include pages that are
38137c478bd9Sstevel@tonic-gate 	 * beyond the real size of the spt segment that backs it.
38147c478bd9Sstevel@tonic-gate 	 */
38157c478bd9Sstevel@tonic-gate 	if (seg->s_ops == &segspt_shmops)
38167c478bd9Sstevel@tonic-gate 		return (MIN(spt_realsize(seg), size));
38177c478bd9Sstevel@tonic-gate 
38187c478bd9Sstevel@tonic-gate 	/*
38197c478bd9Sstevel@tonic-gate 	 * If this is segment is a mapping from /dev/null, then this is a
38207c478bd9Sstevel@tonic-gate 	 * reservation of virtual address space and has no actual size.
38217c478bd9Sstevel@tonic-gate 	 * Such segments are backed by segdev and have type set to neither
38227c478bd9Sstevel@tonic-gate 	 * MAP_SHARED nor MAP_PRIVATE.
38237c478bd9Sstevel@tonic-gate 	 */
38247c478bd9Sstevel@tonic-gate 	if (seg->s_ops == &segdev_ops &&
38257c478bd9Sstevel@tonic-gate 	    ((SEGOP_GETTYPE(seg, seg->s_base) &
38267c478bd9Sstevel@tonic-gate 	    (MAP_SHARED | MAP_PRIVATE)) == 0))
38277c478bd9Sstevel@tonic-gate 		return (0);
38287c478bd9Sstevel@tonic-gate 
38297c478bd9Sstevel@tonic-gate 	/*
38307c478bd9Sstevel@tonic-gate 	 * If this segment doesn't match one of the special types we handle,
38317c478bd9Sstevel@tonic-gate 	 * just return the size of the segment itself.
38327c478bd9Sstevel@tonic-gate 	 */
38337c478bd9Sstevel@tonic-gate 	return (size);
38347c478bd9Sstevel@tonic-gate }
38357c478bd9Sstevel@tonic-gate 
38367c478bd9Sstevel@tonic-gate uint_t
38377c478bd9Sstevel@tonic-gate pr_getprot(struct seg *seg, int reserved, void **tmp,
38387c478bd9Sstevel@tonic-gate 	caddr_t *saddrp, caddr_t *naddrp, caddr_t eaddr)
38397c478bd9Sstevel@tonic-gate {
38407c478bd9Sstevel@tonic-gate 	struct as *as = seg->s_as;
38417c478bd9Sstevel@tonic-gate 
38427c478bd9Sstevel@tonic-gate 	caddr_t saddr = *saddrp;
38437c478bd9Sstevel@tonic-gate 	caddr_t naddr;
38447c478bd9Sstevel@tonic-gate 
38457c478bd9Sstevel@tonic-gate 	int check_noreserve;
38467c478bd9Sstevel@tonic-gate 	uint_t prot;
38477c478bd9Sstevel@tonic-gate 
38487c478bd9Sstevel@tonic-gate 	union {
38497c478bd9Sstevel@tonic-gate 		struct segvn_data *svd;
38507c478bd9Sstevel@tonic-gate 		struct segdev_data *sdp;
38517c478bd9Sstevel@tonic-gate 		void *data;
38527c478bd9Sstevel@tonic-gate 	} s;
38537c478bd9Sstevel@tonic-gate 
38547c478bd9Sstevel@tonic-gate 	s.data = seg->s_data;
38557c478bd9Sstevel@tonic-gate 
3856*dc32d872SJosef 'Jeff' Sipek 	ASSERT(AS_WRITE_HELD(as));
38577c478bd9Sstevel@tonic-gate 	ASSERT(saddr >= seg->s_base && saddr < eaddr);
38587c478bd9Sstevel@tonic-gate 	ASSERT(eaddr <= seg->s_base + seg->s_size);
38597c478bd9Sstevel@tonic-gate 
38607c478bd9Sstevel@tonic-gate 	/*
38617c478bd9Sstevel@tonic-gate 	 * Don't include MAP_NORESERVE pages in the address range
38627c478bd9Sstevel@tonic-gate 	 * unless their mappings have actually materialized.
38637c478bd9Sstevel@tonic-gate 	 * We cheat by knowing that segvn is the only segment
38647c478bd9Sstevel@tonic-gate 	 * driver that supports MAP_NORESERVE.
38657c478bd9Sstevel@tonic-gate 	 */
38667c478bd9Sstevel@tonic-gate 	check_noreserve =
38677c478bd9Sstevel@tonic-gate 	    (!reserved && seg->s_ops == &segvn_ops && s.svd != NULL &&
38687c478bd9Sstevel@tonic-gate 	    (s.svd->vp == NULL || s.svd->vp->v_type != VREG) &&
38697c478bd9Sstevel@tonic-gate 	    (s.svd->flags & MAP_NORESERVE));
38707c478bd9Sstevel@tonic-gate 
38717c478bd9Sstevel@tonic-gate 	/*
38727c478bd9Sstevel@tonic-gate 	 * Examine every page only as a last resort.  We use guilty knowledge
38737c478bd9Sstevel@tonic-gate 	 * of segvn and segdev to avoid this: if there are no per-page
38747c478bd9Sstevel@tonic-gate 	 * protections present in the segment and we don't care about
38757c478bd9Sstevel@tonic-gate 	 * MAP_NORESERVE, then s_data->prot is the prot for the whole segment.
38767c478bd9Sstevel@tonic-gate 	 */
38777c478bd9Sstevel@tonic-gate 	if (!check_noreserve && saddr == seg->s_base &&
38787c478bd9Sstevel@tonic-gate 	    seg->s_ops == &segvn_ops && s.svd != NULL && s.svd->pageprot == 0) {
38797c478bd9Sstevel@tonic-gate 		prot = s.svd->prot;
38807c478bd9Sstevel@tonic-gate 		getwatchprot(as, saddr, &prot);
38817c478bd9Sstevel@tonic-gate 		naddr = eaddr;
38827c478bd9Sstevel@tonic-gate 
38837c478bd9Sstevel@tonic-gate 	} else if (saddr == seg->s_base && seg->s_ops == &segdev_ops &&
38847c478bd9Sstevel@tonic-gate 	    s.sdp != NULL && s.sdp->pageprot == 0) {
38857c478bd9Sstevel@tonic-gate 		prot = s.sdp->prot;
38867c478bd9Sstevel@tonic-gate 		getwatchprot(as, saddr, &prot);
38877c478bd9Sstevel@tonic-gate 		naddr = eaddr;
38887c478bd9Sstevel@tonic-gate 
38897c478bd9Sstevel@tonic-gate 	} else {
38907c478bd9Sstevel@tonic-gate 		prpagev_t *pagev;
38917c478bd9Sstevel@tonic-gate 
38927c478bd9Sstevel@tonic-gate 		/*
38937c478bd9Sstevel@tonic-gate 		 * If addr is sitting at the start of the segment, then
38947c478bd9Sstevel@tonic-gate 		 * create a page vector to store protection and incore
38957c478bd9Sstevel@tonic-gate 		 * information for pages in the segment, and fill it.
38967c478bd9Sstevel@tonic-gate 		 * Otherwise, we expect *tmp to address the prpagev_t
38977c478bd9Sstevel@tonic-gate 		 * allocated by a previous call to this function.
38987c478bd9Sstevel@tonic-gate 		 */
38997c478bd9Sstevel@tonic-gate 		if (saddr == seg->s_base) {
39007c478bd9Sstevel@tonic-gate 			pagev = pr_pagev_create(seg, check_noreserve);
39017c478bd9Sstevel@tonic-gate 			saddr = pr_pagev_fill(pagev, seg, saddr, eaddr);
39027c478bd9Sstevel@tonic-gate 
39037c478bd9Sstevel@tonic-gate 			ASSERT(*tmp == NULL);
39047c478bd9Sstevel@tonic-gate 			*tmp = pagev;
39057c478bd9Sstevel@tonic-gate 
39067c478bd9Sstevel@tonic-gate 			ASSERT(saddr <= eaddr);
39077c478bd9Sstevel@tonic-gate 			*saddrp = saddr;
39087c478bd9Sstevel@tonic-gate 
39097c478bd9Sstevel@tonic-gate 			if (saddr == eaddr) {
39107c478bd9Sstevel@tonic-gate 				naddr = saddr;
39117c478bd9Sstevel@tonic-gate 				prot = 0;
39127c478bd9Sstevel@tonic-gate 				goto out;
39137c478bd9Sstevel@tonic-gate 			}
39147c478bd9Sstevel@tonic-gate 
39157c478bd9Sstevel@tonic-gate 		} else {
39167c478bd9Sstevel@tonic-gate 			ASSERT(*tmp != NULL);
39177c478bd9Sstevel@tonic-gate 			pagev = (prpagev_t *)*tmp;
39187c478bd9Sstevel@tonic-gate 		}
39197c478bd9Sstevel@tonic-gate 
39207c478bd9Sstevel@tonic-gate 		naddr = pr_pagev_nextprot(pagev, seg, saddrp, eaddr, &prot);
39217c478bd9Sstevel@tonic-gate 		ASSERT(naddr <= eaddr);
39227c478bd9Sstevel@tonic-gate 	}
39237c478bd9Sstevel@tonic-gate 
39247c478bd9Sstevel@tonic-gate out:
39257c478bd9Sstevel@tonic-gate 	if (naddr == eaddr)
39267c478bd9Sstevel@tonic-gate 		pr_getprot_done(tmp);
39277c478bd9Sstevel@tonic-gate 	*naddrp = naddr;
39287c478bd9Sstevel@tonic-gate 	return (prot);
39297c478bd9Sstevel@tonic-gate }
39307c478bd9Sstevel@tonic-gate 
39317c478bd9Sstevel@tonic-gate void
39327c478bd9Sstevel@tonic-gate pr_getprot_done(void **tmp)
39337c478bd9Sstevel@tonic-gate {
39347c478bd9Sstevel@tonic-gate 	if (*tmp != NULL) {
39357c478bd9Sstevel@tonic-gate 		pr_pagev_destroy((prpagev_t *)*tmp);
39367c478bd9Sstevel@tonic-gate 		*tmp = NULL;
39377c478bd9Sstevel@tonic-gate 	}
39387c478bd9Sstevel@tonic-gate }
39397c478bd9Sstevel@tonic-gate 
39407c478bd9Sstevel@tonic-gate /*
39417c478bd9Sstevel@tonic-gate  * Return true iff the vnode is a /proc file from the object directory.
39427c478bd9Sstevel@tonic-gate  */
39437c478bd9Sstevel@tonic-gate int
39447c478bd9Sstevel@tonic-gate pr_isobject(vnode_t *vp)
39457c478bd9Sstevel@tonic-gate {
39467c478bd9Sstevel@tonic-gate 	return (vn_matchops(vp, prvnodeops) && VTOP(vp)->pr_type == PR_OBJECT);
39477c478bd9Sstevel@tonic-gate }
39487c478bd9Sstevel@tonic-gate 
39497c478bd9Sstevel@tonic-gate /*
39507c478bd9Sstevel@tonic-gate  * Return true iff the vnode is a /proc file opened by the process itself.
39517c478bd9Sstevel@tonic-gate  */
39527c478bd9Sstevel@tonic-gate int
39537c478bd9Sstevel@tonic-gate pr_isself(vnode_t *vp)
39547c478bd9Sstevel@tonic-gate {
39557c478bd9Sstevel@tonic-gate 	/*
39567c478bd9Sstevel@tonic-gate 	 * XXX: To retain binary compatibility with the old
39577c478bd9Sstevel@tonic-gate 	 * ioctl()-based version of /proc, we exempt self-opens
39587c478bd9Sstevel@tonic-gate 	 * of /proc/<pid> from being marked close-on-exec.
39597c478bd9Sstevel@tonic-gate 	 */
39607c478bd9Sstevel@tonic-gate 	return (vn_matchops(vp, prvnodeops) &&
39617c478bd9Sstevel@tonic-gate 	    (VTOP(vp)->pr_flags & PR_ISSELF) &&
39627c478bd9Sstevel@tonic-gate 	    VTOP(vp)->pr_type != PR_PIDDIR);
39637c478bd9Sstevel@tonic-gate }
39647c478bd9Sstevel@tonic-gate 
39657c478bd9Sstevel@tonic-gate static ssize_t
39667c478bd9Sstevel@tonic-gate pr_getpagesize(struct seg *seg, caddr_t saddr, caddr_t *naddrp, caddr_t eaddr)
39677c478bd9Sstevel@tonic-gate {
39687c478bd9Sstevel@tonic-gate 	ssize_t pagesize, hatsize;
39697c478bd9Sstevel@tonic-gate 
3970*dc32d872SJosef 'Jeff' Sipek 	ASSERT(AS_WRITE_HELD(seg->s_as));
39717c478bd9Sstevel@tonic-gate 	ASSERT(IS_P2ALIGNED(saddr, PAGESIZE));
39727c478bd9Sstevel@tonic-gate 	ASSERT(IS_P2ALIGNED(eaddr, PAGESIZE));
39737c478bd9Sstevel@tonic-gate 	ASSERT(saddr < eaddr);
39747c478bd9Sstevel@tonic-gate 
39757c478bd9Sstevel@tonic-gate 	pagesize = hatsize = hat_getpagesize(seg->s_as->a_hat, saddr);
39767c478bd9Sstevel@tonic-gate 	ASSERT(pagesize == -1 || IS_P2ALIGNED(pagesize, pagesize));
39777c478bd9Sstevel@tonic-gate 	ASSERT(pagesize != 0);
39787c478bd9Sstevel@tonic-gate 
39797c478bd9Sstevel@tonic-gate 	if (pagesize == -1)
39807c478bd9Sstevel@tonic-gate 		pagesize = PAGESIZE;
39817c478bd9Sstevel@tonic-gate 
39827c478bd9Sstevel@tonic-gate 	saddr += P2NPHASE((uintptr_t)saddr, pagesize);
39837c478bd9Sstevel@tonic-gate 
39847c478bd9Sstevel@tonic-gate 	while (saddr < eaddr) {
39857c478bd9Sstevel@tonic-gate 		if (hatsize != hat_getpagesize(seg->s_as->a_hat, saddr))
39867c478bd9Sstevel@tonic-gate 			break;
39877c478bd9Sstevel@tonic-gate 		ASSERT(IS_P2ALIGNED(saddr, pagesize));
39887c478bd9Sstevel@tonic-gate 		saddr += pagesize;
39897c478bd9Sstevel@tonic-gate 	}
39907c478bd9Sstevel@tonic-gate 
39917c478bd9Sstevel@tonic-gate 	*naddrp = ((saddr < eaddr) ? saddr : eaddr);
39927c478bd9Sstevel@tonic-gate 	return (hatsize);
39937c478bd9Sstevel@tonic-gate }
39947c478bd9Sstevel@tonic-gate 
39957c478bd9Sstevel@tonic-gate /*
39967c478bd9Sstevel@tonic-gate  * Return an array of structures with extended memory map information.
39977c478bd9Sstevel@tonic-gate  * We allocate here; the caller must deallocate.
39987c478bd9Sstevel@tonic-gate  */
39997c478bd9Sstevel@tonic-gate int
4000870619e9Sfrankho prgetxmap(proc_t *p, list_t *iolhead)
40017c478bd9Sstevel@tonic-gate {
40027c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
40037c478bd9Sstevel@tonic-gate 	prxmap_t *mp;
40047c478bd9Sstevel@tonic-gate 	struct seg *seg;
40057c478bd9Sstevel@tonic-gate 	struct seg *brkseg, *stkseg;
40067c478bd9Sstevel@tonic-gate 	struct vnode *vp;
40077c478bd9Sstevel@tonic-gate 	struct vattr vattr;
40087c478bd9Sstevel@tonic-gate 	uint_t prot;
40097c478bd9Sstevel@tonic-gate 
4010*dc32d872SJosef 'Jeff' Sipek 	ASSERT(as != &kas && AS_WRITE_HELD(as));
40117c478bd9Sstevel@tonic-gate 
4012870619e9Sfrankho 	/*
4013870619e9Sfrankho 	 * Request an initial buffer size that doesn't waste memory
4014870619e9Sfrankho 	 * if the address space has only a small number of segments.
4015870619e9Sfrankho 	 */
4016870619e9Sfrankho 	pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
40177c478bd9Sstevel@tonic-gate 
40187c478bd9Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL)
40197c478bd9Sstevel@tonic-gate 		return (0);
40207c478bd9Sstevel@tonic-gate 
40217c478bd9Sstevel@tonic-gate 	brkseg = break_seg(p);
40227c478bd9Sstevel@tonic-gate 	stkseg = as_segat(as, prgetstackbase(p));
40237c478bd9Sstevel@tonic-gate 
40247c478bd9Sstevel@tonic-gate 	do {
40257c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
40267c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr, baddr;
40277c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
40287c478bd9Sstevel@tonic-gate 		ssize_t psz;
40297c478bd9Sstevel@tonic-gate 		char *parr;
40307c478bd9Sstevel@tonic-gate 		uint64_t npages;
40317c478bd9Sstevel@tonic-gate 		uint64_t pagenum;
40327c478bd9Sstevel@tonic-gate 
40337c478bd9Sstevel@tonic-gate 		/*
40347c478bd9Sstevel@tonic-gate 		 * Segment loop part one: iterate from the base of the segment
40357c478bd9Sstevel@tonic-gate 		 * to its end, pausing at each address boundary (baddr) between
40367c478bd9Sstevel@tonic-gate 		 * ranges that have different virtual memory protections.
40377c478bd9Sstevel@tonic-gate 		 */
40387c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = baddr) {
40397c478bd9Sstevel@tonic-gate 			prot = pr_getprot(seg, 0, &tmp, &saddr, &baddr, eaddr);
40407c478bd9Sstevel@tonic-gate 			ASSERT(baddr >= saddr && baddr <= eaddr);
40417c478bd9Sstevel@tonic-gate 
40427c478bd9Sstevel@tonic-gate 			/*
40437c478bd9Sstevel@tonic-gate 			 * Segment loop part two: iterate from the current
40447c478bd9Sstevel@tonic-gate 			 * position to the end of the protection boundary,
40457c478bd9Sstevel@tonic-gate 			 * pausing at each address boundary (naddr) between
40467c478bd9Sstevel@tonic-gate 			 * ranges that have different underlying page sizes.
40477c478bd9Sstevel@tonic-gate 			 */
40487c478bd9Sstevel@tonic-gate 			for (; saddr < baddr; saddr = naddr) {
40497c478bd9Sstevel@tonic-gate 				psz = pr_getpagesize(seg, saddr, &naddr, baddr);
40507c478bd9Sstevel@tonic-gate 				ASSERT(naddr >= saddr && naddr <= baddr);
40517c478bd9Sstevel@tonic-gate 
4052870619e9Sfrankho 				mp = pr_iol_newbuf(iolhead, sizeof (*mp));
40537c478bd9Sstevel@tonic-gate 
40547c478bd9Sstevel@tonic-gate 				mp->pr_vaddr = (uintptr_t)saddr;
40557c478bd9Sstevel@tonic-gate 				mp->pr_size = naddr - saddr;
40567c478bd9Sstevel@tonic-gate 				mp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
40577c478bd9Sstevel@tonic-gate 				mp->pr_mflags = 0;
40587c478bd9Sstevel@tonic-gate 				if (prot & PROT_READ)
40597c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_READ;
40607c478bd9Sstevel@tonic-gate 				if (prot & PROT_WRITE)
40617c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_WRITE;
40627c478bd9Sstevel@tonic-gate 				if (prot & PROT_EXEC)
40637c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_EXEC;
40647c478bd9Sstevel@tonic-gate 				if (SEGOP_GETTYPE(seg, saddr) & MAP_SHARED)
40657c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_SHARED;
40667c478bd9Sstevel@tonic-gate 				if (SEGOP_GETTYPE(seg, saddr) & MAP_NORESERVE)
40677c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_NORESERVE;
40687c478bd9Sstevel@tonic-gate 				if (seg->s_ops == &segspt_shmops ||
40697c478bd9Sstevel@tonic-gate 				    (seg->s_ops == &segvn_ops &&
40707c478bd9Sstevel@tonic-gate 				    (SEGOP_GETVP(seg, saddr, &vp) != 0 ||
40717c478bd9Sstevel@tonic-gate 				    vp == NULL)))
40727c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_ANON;
40737c478bd9Sstevel@tonic-gate 				if (seg == brkseg)
40747c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_BREAK;
40757c478bd9Sstevel@tonic-gate 				else if (seg == stkseg)
40767c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_STACK;
40777c478bd9Sstevel@tonic-gate 				if (seg->s_ops == &segspt_shmops)
40787c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_ISM | MA_SHM;
40797c478bd9Sstevel@tonic-gate 
40807c478bd9Sstevel@tonic-gate 				mp->pr_pagesize = PAGESIZE;
40817c478bd9Sstevel@tonic-gate 				if (psz == -1) {
40827c478bd9Sstevel@tonic-gate 					mp->pr_hatpagesize = 0;
40837c478bd9Sstevel@tonic-gate 				} else {
40847c478bd9Sstevel@tonic-gate 					mp->pr_hatpagesize = psz;
40857c478bd9Sstevel@tonic-gate 				}
40867c478bd9Sstevel@tonic-gate 
40877c478bd9Sstevel@tonic-gate 				/*
40887c478bd9Sstevel@tonic-gate 				 * Manufacture a filename for the "object" dir.
40897c478bd9Sstevel@tonic-gate 				 */
40907c478bd9Sstevel@tonic-gate 				mp->pr_dev = PRNODEV;
40917c478bd9Sstevel@tonic-gate 				vattr.va_mask = AT_FSID|AT_NODEID;
40927c478bd9Sstevel@tonic-gate 				if (seg->s_ops == &segvn_ops &&
40937c478bd9Sstevel@tonic-gate 				    SEGOP_GETVP(seg, saddr, &vp) == 0 &&
40947c478bd9Sstevel@tonic-gate 				    vp != NULL && vp->v_type == VREG &&
4095da6c28aaSamw 				    VOP_GETATTR(vp, &vattr, 0, CRED(),
4096da6c28aaSamw 				    NULL) == 0) {
40977c478bd9Sstevel@tonic-gate 					mp->pr_dev = vattr.va_fsid;
40987c478bd9Sstevel@tonic-gate 					mp->pr_ino = vattr.va_nodeid;
40997c478bd9Sstevel@tonic-gate 					if (vp == p->p_exec)
41007c478bd9Sstevel@tonic-gate 						(void) strcpy(mp->pr_mapname,
41017c478bd9Sstevel@tonic-gate 						    "a.out");
41027c478bd9Sstevel@tonic-gate 					else
41037c478bd9Sstevel@tonic-gate 						pr_object_name(mp->pr_mapname,
41047c478bd9Sstevel@tonic-gate 						    vp, &vattr);
41057c478bd9Sstevel@tonic-gate 				}
41067c478bd9Sstevel@tonic-gate 
41077c478bd9Sstevel@tonic-gate 				/*
41087c478bd9Sstevel@tonic-gate 				 * Get the SysV shared memory id, if any.
41097c478bd9Sstevel@tonic-gate 				 */
41107c478bd9Sstevel@tonic-gate 				if ((mp->pr_mflags & MA_SHARED) &&
41117c478bd9Sstevel@tonic-gate 				    p->p_segacct && (mp->pr_shmid = shmgetid(p,
41127c478bd9Sstevel@tonic-gate 				    seg->s_base)) != SHMID_NONE) {
41137c478bd9Sstevel@tonic-gate 					if (mp->pr_shmid == SHMID_FREE)
41147c478bd9Sstevel@tonic-gate 						mp->pr_shmid = -1;
41157c478bd9Sstevel@tonic-gate 
41167c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_SHM;
41177c478bd9Sstevel@tonic-gate 				} else {
41187c478bd9Sstevel@tonic-gate 					mp->pr_shmid = -1;
41197c478bd9Sstevel@tonic-gate 				}
41207c478bd9Sstevel@tonic-gate 
41217c478bd9Sstevel@tonic-gate 				npages = ((uintptr_t)(naddr - saddr)) >>
41227c478bd9Sstevel@tonic-gate 				    PAGESHIFT;
41237c478bd9Sstevel@tonic-gate 				parr = kmem_zalloc(npages, KM_SLEEP);
41247c478bd9Sstevel@tonic-gate 
41257c478bd9Sstevel@tonic-gate 				SEGOP_INCORE(seg, saddr, naddr - saddr, parr);
41267c478bd9Sstevel@tonic-gate 
41277c478bd9Sstevel@tonic-gate 				for (pagenum = 0; pagenum < npages; pagenum++) {
41287c478bd9Sstevel@tonic-gate 					if (parr[pagenum] & SEG_PAGE_INCORE)
41297c478bd9Sstevel@tonic-gate 						mp->pr_rss++;
41307c478bd9Sstevel@tonic-gate 					if (parr[pagenum] & SEG_PAGE_ANON)
41317c478bd9Sstevel@tonic-gate 						mp->pr_anon++;
41327c478bd9Sstevel@tonic-gate 					if (parr[pagenum] & SEG_PAGE_LOCKED)
41337c478bd9Sstevel@tonic-gate 						mp->pr_locked++;
41347c478bd9Sstevel@tonic-gate 				}
41357c478bd9Sstevel@tonic-gate 				kmem_free(parr, npages);
41367c478bd9Sstevel@tonic-gate 			}
41377c478bd9Sstevel@tonic-gate 		}
41387c478bd9Sstevel@tonic-gate 		ASSERT(tmp == NULL);
41397c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
41407c478bd9Sstevel@tonic-gate 
4141870619e9Sfrankho 	return (0);
41427c478bd9Sstevel@tonic-gate }
41437c478bd9Sstevel@tonic-gate 
41447c478bd9Sstevel@tonic-gate /*
41457c478bd9Sstevel@tonic-gate  * Return the process's credentials.  We don't need a 32-bit equivalent of
41467c478bd9Sstevel@tonic-gate  * this function because prcred_t and prcred32_t are actually the same.
41477c478bd9Sstevel@tonic-gate  */
41487c478bd9Sstevel@tonic-gate void
41497c478bd9Sstevel@tonic-gate prgetcred(proc_t *p, prcred_t *pcrp)
41507c478bd9Sstevel@tonic-gate {
41517c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
41527c478bd9Sstevel@tonic-gate 	cred2prcred(p->p_cred, pcrp);
41537c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
41547c478bd9Sstevel@tonic-gate }
41557c478bd9Sstevel@tonic-gate 
41567c478bd9Sstevel@tonic-gate /*
41577c478bd9Sstevel@tonic-gate  * Compute actual size of the prpriv_t structure.
41587c478bd9Sstevel@tonic-gate  */
41597c478bd9Sstevel@tonic-gate 
41607c478bd9Sstevel@tonic-gate size_t
41617c478bd9Sstevel@tonic-gate prgetprivsize(void)
41627c478bd9Sstevel@tonic-gate {
41637c478bd9Sstevel@tonic-gate 	return (priv_prgetprivsize(NULL));
41647c478bd9Sstevel@tonic-gate }
41657c478bd9Sstevel@tonic-gate 
41667c478bd9Sstevel@tonic-gate /*
41677c478bd9Sstevel@tonic-gate  * Return the process's privileges.  We don't need a 32-bit equivalent of
41687c478bd9Sstevel@tonic-gate  * this function because prpriv_t and prpriv32_t are actually the same.
41697c478bd9Sstevel@tonic-gate  */
41707c478bd9Sstevel@tonic-gate void
41717c478bd9Sstevel@tonic-gate prgetpriv(proc_t *p, prpriv_t *pprp)
41727c478bd9Sstevel@tonic-gate {
41737c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
41747c478bd9Sstevel@tonic-gate 	cred2prpriv(p->p_cred, pprp);
41757c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
41767c478bd9Sstevel@tonic-gate }
41777c478bd9Sstevel@tonic-gate 
41787c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
41797c478bd9Sstevel@tonic-gate /*
41807c478bd9Sstevel@tonic-gate  * Return an array of structures with HAT memory map information.
41817c478bd9Sstevel@tonic-gate  * We allocate here; the caller must deallocate.
41827c478bd9Sstevel@tonic-gate  */
41837c478bd9Sstevel@tonic-gate int
4184870619e9Sfrankho prgetxmap32(proc_t *p, list_t *iolhead)
41857c478bd9Sstevel@tonic-gate {
41867c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
41877c478bd9Sstevel@tonic-gate 	prxmap32_t *mp;
41887c478bd9Sstevel@tonic-gate 	struct seg *seg;
41897c478bd9Sstevel@tonic-gate 	struct seg *brkseg, *stkseg;
41907c478bd9Sstevel@tonic-gate 	struct vnode *vp;
41917c478bd9Sstevel@tonic-gate 	struct vattr vattr;
41927c478bd9Sstevel@tonic-gate 	uint_t prot;
41937c478bd9Sstevel@tonic-gate 
4194*dc32d872SJosef 'Jeff' Sipek 	ASSERT(as != &kas && AS_WRITE_HELD(as));
41957c478bd9Sstevel@tonic-gate 
4196870619e9Sfrankho 	/*
4197870619e9Sfrankho 	 * Request an initial buffer size that doesn't waste memory
4198870619e9Sfrankho 	 * if the address space has only a small number of segments.
4199870619e9Sfrankho 	 */
4200870619e9Sfrankho 	pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
42017c478bd9Sstevel@tonic-gate 
42027c478bd9Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL)
42037c478bd9Sstevel@tonic-gate 		return (0);
42047c478bd9Sstevel@tonic-gate 
42057c478bd9Sstevel@tonic-gate 	brkseg = break_seg(p);
42067c478bd9Sstevel@tonic-gate 	stkseg = as_segat(as, prgetstackbase(p));
42077c478bd9Sstevel@tonic-gate 
42087c478bd9Sstevel@tonic-gate 	do {
42097c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
42107c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr, baddr;
42117c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
42127c478bd9Sstevel@tonic-gate 		ssize_t psz;
42137c478bd9Sstevel@tonic-gate 		char *parr;
42147c478bd9Sstevel@tonic-gate 		uint64_t npages;
42157c478bd9Sstevel@tonic-gate 		uint64_t pagenum;
42167c478bd9Sstevel@tonic-gate 
42177c478bd9Sstevel@tonic-gate 		/*
42187c478bd9Sstevel@tonic-gate 		 * Segment loop part one: iterate from the base of the segment
42197c478bd9Sstevel@tonic-gate 		 * to its end, pausing at each address boundary (baddr) between
42207c478bd9Sstevel@tonic-gate 		 * ranges that have different virtual memory protections.
42217c478bd9Sstevel@tonic-gate 		 */
42227c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = baddr) {
42237c478bd9Sstevel@tonic-gate 			prot = pr_getprot(seg, 0, &tmp, &saddr, &baddr, eaddr);
42247c478bd9Sstevel@tonic-gate 			ASSERT(baddr >= saddr && baddr <= eaddr);
42257c478bd9Sstevel@tonic-gate 
42267c478bd9Sstevel@tonic-gate 			/*
42277c478bd9Sstevel@tonic-gate 			 * Segment loop part two: iterate from the current
42287c478bd9Sstevel@tonic-gate 			 * position to the end of the protection boundary,
42297c478bd9Sstevel@tonic-gate 			 * pausing at each address boundary (naddr) between
42307c478bd9Sstevel@tonic-gate 			 * ranges that have different underlying page sizes.
42317c478bd9Sstevel@tonic-gate 			 */
42327c478bd9Sstevel@tonic-gate 			for (; saddr < baddr; saddr = naddr) {
42337c478bd9Sstevel@tonic-gate 				psz = pr_getpagesize(seg, saddr, &naddr, baddr);
42347c478bd9Sstevel@tonic-gate 				ASSERT(naddr >= saddr && naddr <= baddr);
42357c478bd9Sstevel@tonic-gate 
4236870619e9Sfrankho 				mp = pr_iol_newbuf(iolhead, sizeof (*mp));
42377c478bd9Sstevel@tonic-gate 
42387c478bd9Sstevel@tonic-gate 				mp->pr_vaddr = (caddr32_t)(uintptr_t)saddr;
42397c478bd9Sstevel@tonic-gate 				mp->pr_size = (size32_t)(naddr - saddr);
42407c478bd9Sstevel@tonic-gate 				mp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
42417c478bd9Sstevel@tonic-gate 				mp->pr_mflags = 0;
42427c478bd9Sstevel@tonic-gate 				if (prot & PROT_READ)
42437c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_READ;
42447c478bd9Sstevel@tonic-gate 				if (prot & PROT_WRITE)
42457c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_WRITE;
42467c478bd9Sstevel@tonic-gate 				if (prot & PROT_EXEC)
42477c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_EXEC;
42487c478bd9Sstevel@tonic-gate 				if (SEGOP_GETTYPE(seg, saddr) & MAP_SHARED)
42497c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_SHARED;
42507c478bd9Sstevel@tonic-gate 				if (SEGOP_GETTYPE(seg, saddr) & MAP_NORESERVE)
42517c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_NORESERVE;
42527c478bd9Sstevel@tonic-gate 				if (seg->s_ops == &segspt_shmops ||
42537c478bd9Sstevel@tonic-gate 				    (seg->s_ops == &segvn_ops &&
42547c478bd9Sstevel@tonic-gate 				    (SEGOP_GETVP(seg, saddr, &vp) != 0 ||
42557c478bd9Sstevel@tonic-gate 				    vp == NULL)))
42567c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_ANON;
42577c478bd9Sstevel@tonic-gate 				if (seg == brkseg)
42587c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_BREAK;
42597c478bd9Sstevel@tonic-gate 				else if (seg == stkseg)
42607c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_STACK;
42617c478bd9Sstevel@tonic-gate 				if (seg->s_ops == &segspt_shmops)
42627c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_ISM | MA_SHM;
42637c478bd9Sstevel@tonic-gate 
42647c478bd9Sstevel@tonic-gate 				mp->pr_pagesize = PAGESIZE;
42657c478bd9Sstevel@tonic-gate 				if (psz == -1) {
42667c478bd9Sstevel@tonic-gate 					mp->pr_hatpagesize = 0;
42677c478bd9Sstevel@tonic-gate 				} else {
42687c478bd9Sstevel@tonic-gate 					mp->pr_hatpagesize = psz;
42697c478bd9Sstevel@tonic-gate 				}
42707c478bd9Sstevel@tonic-gate 
42717c478bd9Sstevel@tonic-gate 				/*
42727c478bd9Sstevel@tonic-gate 				 * Manufacture a filename for the "object" dir.
42737c478bd9Sstevel@tonic-gate 				 */
42747c478bd9Sstevel@tonic-gate 				mp->pr_dev = PRNODEV32;
42757c478bd9Sstevel@tonic-gate 				vattr.va_mask = AT_FSID|AT_NODEID;
42767c478bd9Sstevel@tonic-gate 				if (seg->s_ops == &segvn_ops &&
42777c478bd9Sstevel@tonic-gate 				    SEGOP_GETVP(seg, saddr, &vp) == 0 &&
42787c478bd9Sstevel@tonic-gate 				    vp != NULL && vp->v_type == VREG &&
4279da6c28aaSamw 				    VOP_GETATTR(vp, &vattr, 0, CRED(),
4280da6c28aaSamw 				    NULL) == 0) {
42817c478bd9Sstevel@tonic-gate 					(void) cmpldev(&mp->pr_dev,
42827c478bd9Sstevel@tonic-gate 					    vattr.va_fsid);
42837c478bd9Sstevel@tonic-gate 					mp->pr_ino = vattr.va_nodeid;
42847c478bd9Sstevel@tonic-gate 					if (vp == p->p_exec)
42857c478bd9Sstevel@tonic-gate 						(void) strcpy(mp->pr_mapname,
42867c478bd9Sstevel@tonic-gate 						    "a.out");
42877c478bd9Sstevel@tonic-gate 					else
42887c478bd9Sstevel@tonic-gate 						pr_object_name(mp->pr_mapname,
42897c478bd9Sstevel@tonic-gate 						    vp, &vattr);
42907c478bd9Sstevel@tonic-gate 				}
42917c478bd9Sstevel@tonic-gate 
42927c478bd9Sstevel@tonic-gate 				/*
42937c478bd9Sstevel@tonic-gate 				 * Get the SysV shared memory id, if any.
42947c478bd9Sstevel@tonic-gate 				 */
42957c478bd9Sstevel@tonic-gate 				if ((mp->pr_mflags & MA_SHARED) &&
42967c478bd9Sstevel@tonic-gate 				    p->p_segacct && (mp->pr_shmid = shmgetid(p,
42977c478bd9Sstevel@tonic-gate 				    seg->s_base)) != SHMID_NONE) {
42987c478bd9Sstevel@tonic-gate 					if (mp->pr_shmid == SHMID_FREE)
42997c478bd9Sstevel@tonic-gate 						mp->pr_shmid = -1;
43007c478bd9Sstevel@tonic-gate 
43017c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_SHM;
43027c478bd9Sstevel@tonic-gate 				} else {
43037c478bd9Sstevel@tonic-gate 					mp->pr_shmid = -1;
43047c478bd9Sstevel@tonic-gate 				}
43057c478bd9Sstevel@tonic-gate 
43067c478bd9Sstevel@tonic-gate 				npages = ((uintptr_t)(naddr - saddr)) >>
43077c478bd9Sstevel@tonic-gate 				    PAGESHIFT;
43087c478bd9Sstevel@tonic-gate 				parr = kmem_zalloc(npages, KM_SLEEP);
43097c478bd9Sstevel@tonic-gate 
43107c478bd9Sstevel@tonic-gate 				SEGOP_INCORE(seg, saddr, naddr - saddr, parr);
43117c478bd9Sstevel@tonic-gate 
43127c478bd9Sstevel@tonic-gate 				for (pagenum = 0; pagenum < npages; pagenum++) {
43137c478bd9Sstevel@tonic-gate 					if (parr[pagenum] & SEG_PAGE_INCORE)
43147c478bd9Sstevel@tonic-gate 						mp->pr_rss++;
43157c478bd9Sstevel@tonic-gate 					if (parr[pagenum] & SEG_PAGE_ANON)
43167c478bd9Sstevel@tonic-gate 						mp->pr_anon++;
43177c478bd9Sstevel@tonic-gate 					if (parr[pagenum] & SEG_PAGE_LOCKED)
43187c478bd9Sstevel@tonic-gate 						mp->pr_locked++;
43197c478bd9Sstevel@tonic-gate 				}
43207c478bd9Sstevel@tonic-gate 				kmem_free(parr, npages);
43217c478bd9Sstevel@tonic-gate 			}
43227c478bd9Sstevel@tonic-gate 		}
43237c478bd9Sstevel@tonic-gate 		ASSERT(tmp == NULL);
43247c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
43257c478bd9Sstevel@tonic-gate 
4326870619e9Sfrankho 	return (0);
43277c478bd9Sstevel@tonic-gate }
43287c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
4329