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