xref: /illumos-gate/usr/src/uts/common/fs/proc/prsubr.c (revision 2b395c3c2a39cdc00f9fe7ac497795bd112f7663)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
58ace1d31Ssudheer  * Common Development and Distribution License (the "License").
68ace1d31Ssudheer  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2197eda132Sraf 
227c478bd9Sstevel@tonic-gate /*
23872650ccSGangadhar Mylapuram  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
244e18e297SPatrick Mooney  * Copyright 2019 Joyent, Inc.
25a02120c4SAndy Fiddaman  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
26da29c6a3SDan McDonald  * Copyright 2022 MNX Cloud, Inc.
2737e2cd25SPatrick Mooney  * Copyright 2022 Oxide Computer Company
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
317c478bd9Sstevel@tonic-gate /*	  All Rights Reserved	*/
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
357c478bd9Sstevel@tonic-gate #include <sys/param.h>
367c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
377c478bd9Sstevel@tonic-gate #include <sys/cred.h>
387c478bd9Sstevel@tonic-gate #include <sys/priv.h>
397c478bd9Sstevel@tonic-gate #include <sys/debug.h>
407c478bd9Sstevel@tonic-gate #include <sys/errno.h>
417c478bd9Sstevel@tonic-gate #include <sys/inline.h>
427c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
437c478bd9Sstevel@tonic-gate #include <sys/mman.h>
447c478bd9Sstevel@tonic-gate #include <sys/proc.h>
45eb9dbf0cSRoger A. Faulkner #include <sys/brand.h>
467c478bd9Sstevel@tonic-gate #include <sys/sobject.h>
477c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
487c478bd9Sstevel@tonic-gate #include <sys/systm.h>
497c478bd9Sstevel@tonic-gate #include <sys/uio.h>
507c478bd9Sstevel@tonic-gate #include <sys/var.h>
517c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
527c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
537c478bd9Sstevel@tonic-gate #include <sys/session.h>
547c478bd9Sstevel@tonic-gate #include <sys/pcb.h>
557c478bd9Sstevel@tonic-gate #include <sys/signal.h>
567c478bd9Sstevel@tonic-gate #include <sys/user.h>
577c478bd9Sstevel@tonic-gate #include <sys/disp.h>
587c478bd9Sstevel@tonic-gate #include <sys/class.h>
597c478bd9Sstevel@tonic-gate #include <sys/ts.h>
607c478bd9Sstevel@tonic-gate #include <sys/bitmap.h>
617c478bd9Sstevel@tonic-gate #include <sys/poll.h>
627c478bd9Sstevel@tonic-gate #include <sys/shm_impl.h>
637c478bd9Sstevel@tonic-gate #include <sys/fault.h>
647c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
657c478bd9Sstevel@tonic-gate #include <sys/procfs.h>
667c478bd9Sstevel@tonic-gate #include <sys/processor.h>
677c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
687c478bd9Sstevel@tonic-gate #include <sys/copyops.h>
697c478bd9Sstevel@tonic-gate #include <sys/time.h>
707c478bd9Sstevel@tonic-gate #include <sys/msacct.h>
71a02120c4SAndy Fiddaman #include <sys/flock_impl.h>
72a02120c4SAndy Fiddaman #include <sys/stropts.h>
73a02120c4SAndy Fiddaman #include <sys/strsubr.h>
74a02120c4SAndy Fiddaman #include <sys/pathname.h>
75a02120c4SAndy Fiddaman #include <sys/mode.h>
76a02120c4SAndy Fiddaman #include <sys/socketvar.h>
77a02120c4SAndy Fiddaman #include <sys/autoconf.h>
78a02120c4SAndy Fiddaman #include <sys/dtrace.h>
79a02120c4SAndy Fiddaman #include <sys/timod.h>
808950e535SAndy Fiddaman #include <sys/fs/namenode.h>
81a02120c4SAndy Fiddaman #include <netinet/udp.h>
82a02120c4SAndy Fiddaman #include <netinet/tcp.h>
83a02120c4SAndy Fiddaman #include <inet/cc.h>
847c478bd9Sstevel@tonic-gate #include <vm/as.h>
857c478bd9Sstevel@tonic-gate #include <vm/rm.h>
867c478bd9Sstevel@tonic-gate #include <vm/seg.h>
877c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h>
887c478bd9Sstevel@tonic-gate #include <vm/seg_dev.h>
897c478bd9Sstevel@tonic-gate #include <vm/seg_spt.h>
907c478bd9Sstevel@tonic-gate #include <vm/page.h>
917c478bd9Sstevel@tonic-gate #include <sys/vmparam.h>
927c478bd9Sstevel@tonic-gate #include <sys/swap.h>
937c478bd9Sstevel@tonic-gate #include <fs/proc/prdata.h>
947c478bd9Sstevel@tonic-gate #include <sys/task.h>
957c478bd9Sstevel@tonic-gate #include <sys/project.h>
967c478bd9Sstevel@tonic-gate #include <sys/contract_impl.h>
977c478bd9Sstevel@tonic-gate #include <sys/contract/process.h>
987c478bd9Sstevel@tonic-gate #include <sys/contract/process_impl.h>
997c478bd9Sstevel@tonic-gate #include <sys/schedctl.h>
1007c478bd9Sstevel@tonic-gate #include <sys/pool.h>
1017c478bd9Sstevel@tonic-gate #include <sys/zone.h>
1027c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
103870619e9Sfrankho #include <sys/sdt.h>
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate #define	MAX_ITERS_SPIN	5
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate typedef struct prpagev {
1087c478bd9Sstevel@tonic-gate 	uint_t *pg_protv;	/* vector of page permissions */
1097c478bd9Sstevel@tonic-gate 	char *pg_incore;	/* vector of incore flags */
1107c478bd9Sstevel@tonic-gate 	size_t pg_npages;	/* number of pages in protv and incore */
1117c478bd9Sstevel@tonic-gate 	ulong_t pg_pnbase;	/* pn within segment of first protv element */
1127c478bd9Sstevel@tonic-gate } prpagev_t;
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate size_t pagev_lim = 256 * 1024;	/* limit on number of pages in prpagev_t */
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate extern struct seg_ops segdev_ops;	/* needs a header file */
1177c478bd9Sstevel@tonic-gate extern struct seg_ops segspt_shmops;	/* needs a header file */
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate static	int	set_watched_page(proc_t *, caddr_t, caddr_t, ulong_t, ulong_t);
1207c478bd9Sstevel@tonic-gate static	void	clear_watched_page(proc_t *, caddr_t, caddr_t, ulong_t);
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate /*
1237c478bd9Sstevel@tonic-gate  * Choose an lwp from the complete set of lwps for the process.
1247c478bd9Sstevel@tonic-gate  * This is called for any operation applied to the process
1257c478bd9Sstevel@tonic-gate  * file descriptor that requires an lwp to operate upon.
1267c478bd9Sstevel@tonic-gate  *
1277c478bd9Sstevel@tonic-gate  * Returns a pointer to the thread for the selected LWP,
1287c478bd9Sstevel@tonic-gate  * and with the dispatcher lock held for the thread.
1297c478bd9Sstevel@tonic-gate  *
1307c478bd9Sstevel@tonic-gate  * The algorithm for choosing an lwp is critical for /proc semantics;
1317c478bd9Sstevel@tonic-gate  * don't touch this code unless you know all of the implications.
1327c478bd9Sstevel@tonic-gate  */
1337c478bd9Sstevel@tonic-gate kthread_t *
prchoose(proc_t * p)1347c478bd9Sstevel@tonic-gate prchoose(proc_t *p)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 	kthread_t *t;
1377c478bd9Sstevel@tonic-gate 	kthread_t *t_onproc = NULL;	/* running on processor */
1387c478bd9Sstevel@tonic-gate 	kthread_t *t_run = NULL;	/* runnable, on disp queue */
1397c478bd9Sstevel@tonic-gate 	kthread_t *t_sleep = NULL;	/* sleeping */
1407c478bd9Sstevel@tonic-gate 	kthread_t *t_hold = NULL;	/* sleeping, performing hold */
1417c478bd9Sstevel@tonic-gate 	kthread_t *t_susp = NULL;	/* suspended stop */
1427c478bd9Sstevel@tonic-gate 	kthread_t *t_jstop = NULL;	/* jobcontrol stop, w/o directed stop */
1437c478bd9Sstevel@tonic-gate 	kthread_t *t_jdstop = NULL;	/* jobcontrol stop with directed stop */
1447c478bd9Sstevel@tonic-gate 	kthread_t *t_req = NULL;	/* requested stop */
1457c478bd9Sstevel@tonic-gate 	kthread_t *t_istop = NULL;	/* event-of-interest stop */
1461959771bSJonathan Haslam 	kthread_t *t_dtrace = NULL;	/* DTrace stop */
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	/*
1517c478bd9Sstevel@tonic-gate 	 * If the agent lwp exists, it takes precedence over all others.
1527c478bd9Sstevel@tonic-gate 	 */
1537c478bd9Sstevel@tonic-gate 	if ((t = p->p_agenttp) != NULL) {
1547c478bd9Sstevel@tonic-gate 		thread_lock(t);
1557c478bd9Sstevel@tonic-gate 		return (t);
1567c478bd9Sstevel@tonic-gate 	}
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	if ((t = p->p_tlist) == NULL)	/* start at the head of the list */
1597c478bd9Sstevel@tonic-gate 		return (t);
1607c478bd9Sstevel@tonic-gate 	do {		/* for eacn lwp in the process */
1617c478bd9Sstevel@tonic-gate 		if (VSTOPPED(t)) {	/* virtually stopped */
1627c478bd9Sstevel@tonic-gate 			if (t_req == NULL)
1637c478bd9Sstevel@tonic-gate 				t_req = t;
1647c478bd9Sstevel@tonic-gate 			continue;
1657c478bd9Sstevel@tonic-gate 		}
1667c478bd9Sstevel@tonic-gate 
1674c819f48SJerry Jelinek 		/* If this is a process kernel thread, ignore it. */
1684c819f48SJerry Jelinek 		if ((t->t_proc_flag & TP_KTHREAD) != 0) {
1694c819f48SJerry Jelinek 			continue;
1704c819f48SJerry Jelinek 		}
1714c819f48SJerry Jelinek 
1727c478bd9Sstevel@tonic-gate 		thread_lock(t);		/* make sure thread is in good state */
1737c478bd9Sstevel@tonic-gate 		switch (t->t_state) {
1747c478bd9Sstevel@tonic-gate 		default:
1757c478bd9Sstevel@tonic-gate 			panic("prchoose: bad thread state %d, thread 0x%p",
1767c478bd9Sstevel@tonic-gate 			    t->t_state, (void *)t);
1777c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1787c478bd9Sstevel@tonic-gate 		case TS_SLEEP:
1797c478bd9Sstevel@tonic-gate 			/* this is filthy */
1807c478bd9Sstevel@tonic-gate 			if (t->t_wchan == (caddr_t)&p->p_holdlwps &&
1817c478bd9Sstevel@tonic-gate 			    t->t_wchan0 == NULL) {
1827c478bd9Sstevel@tonic-gate 				if (t_hold == NULL)
1837c478bd9Sstevel@tonic-gate 					t_hold = t;
1847c478bd9Sstevel@tonic-gate 			} else {
1857c478bd9Sstevel@tonic-gate 				if (t_sleep == NULL)
1867c478bd9Sstevel@tonic-gate 					t_sleep = t;
1877c478bd9Sstevel@tonic-gate 			}
1887c478bd9Sstevel@tonic-gate 			break;
1897c478bd9Sstevel@tonic-gate 		case TS_RUN:
190c97ad5cdSakolb 		case TS_WAIT:
1917c478bd9Sstevel@tonic-gate 			if (t_run == NULL)
1927c478bd9Sstevel@tonic-gate 				t_run = t;
1937c478bd9Sstevel@tonic-gate 			break;
1947c478bd9Sstevel@tonic-gate 		case TS_ONPROC:
1957c478bd9Sstevel@tonic-gate 			if (t_onproc == NULL)
1967c478bd9Sstevel@tonic-gate 				t_onproc = t;
1977c478bd9Sstevel@tonic-gate 			break;
1987c478bd9Sstevel@tonic-gate 		case TS_ZOMB:		/* last possible choice */
1997c478bd9Sstevel@tonic-gate 			break;
2007c478bd9Sstevel@tonic-gate 		case TS_STOPPED:
2017c478bd9Sstevel@tonic-gate 			switch (t->t_whystop) {
2027c478bd9Sstevel@tonic-gate 			case PR_SUSPENDED:
2037c478bd9Sstevel@tonic-gate 				if (t_susp == NULL)
2047c478bd9Sstevel@tonic-gate 					t_susp = t;
2057c478bd9Sstevel@tonic-gate 				break;
2067c478bd9Sstevel@tonic-gate 			case PR_JOBCONTROL:
2077c478bd9Sstevel@tonic-gate 				if (t->t_proc_flag & TP_PRSTOP) {
2087c478bd9Sstevel@tonic-gate 					if (t_jdstop == NULL)
2097c478bd9Sstevel@tonic-gate 						t_jdstop = t;
2107c478bd9Sstevel@tonic-gate 				} else {
2117c478bd9Sstevel@tonic-gate 					if (t_jstop == NULL)
2127c478bd9Sstevel@tonic-gate 						t_jstop = t;
2137c478bd9Sstevel@tonic-gate 				}
2147c478bd9Sstevel@tonic-gate 				break;
2157c478bd9Sstevel@tonic-gate 			case PR_REQUESTED:
2161959771bSJonathan Haslam 				if (t->t_dtrace_stop && t_dtrace == NULL)
2171959771bSJonathan Haslam 					t_dtrace = t;
2181959771bSJonathan Haslam 				else if (t_req == NULL)
2197c478bd9Sstevel@tonic-gate 					t_req = t;
2207c478bd9Sstevel@tonic-gate 				break;
2217c478bd9Sstevel@tonic-gate 			case PR_SYSENTRY:
2227c478bd9Sstevel@tonic-gate 			case PR_SYSEXIT:
2237c478bd9Sstevel@tonic-gate 			case PR_SIGNALLED:
2247c478bd9Sstevel@tonic-gate 			case PR_FAULTED:
2257c478bd9Sstevel@tonic-gate 				/*
2267c478bd9Sstevel@tonic-gate 				 * Make an lwp calling exit() be the
2277c478bd9Sstevel@tonic-gate 				 * last lwp seen in the process.
2287c478bd9Sstevel@tonic-gate 				 */
2297c478bd9Sstevel@tonic-gate 				if (t_istop == NULL ||
2307c478bd9Sstevel@tonic-gate 				    (t_istop->t_whystop == PR_SYSENTRY &&
2317c478bd9Sstevel@tonic-gate 				    t_istop->t_whatstop == SYS_exit))
2327c478bd9Sstevel@tonic-gate 					t_istop = t;
2337c478bd9Sstevel@tonic-gate 				break;
2347c478bd9Sstevel@tonic-gate 			case PR_CHECKPOINT:	/* can't happen? */
2357c478bd9Sstevel@tonic-gate 				break;
2367c478bd9Sstevel@tonic-gate 			default:
2377c478bd9Sstevel@tonic-gate 				panic("prchoose: bad t_whystop %d, thread 0x%p",
2387c478bd9Sstevel@tonic-gate 				    t->t_whystop, (void *)t);
2397c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
2407c478bd9Sstevel@tonic-gate 			}
2417c478bd9Sstevel@tonic-gate 			break;
2427c478bd9Sstevel@tonic-gate 		}
2437c478bd9Sstevel@tonic-gate 		thread_unlock(t);
2447c478bd9Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	if (t_onproc)
2477c478bd9Sstevel@tonic-gate 		t = t_onproc;
2487c478bd9Sstevel@tonic-gate 	else if (t_run)
2497c478bd9Sstevel@tonic-gate 		t = t_run;
2507c478bd9Sstevel@tonic-gate 	else if (t_sleep)
2517c478bd9Sstevel@tonic-gate 		t = t_sleep;
2527c478bd9Sstevel@tonic-gate 	else if (t_jstop)
2537c478bd9Sstevel@tonic-gate 		t = t_jstop;
2547c478bd9Sstevel@tonic-gate 	else if (t_jdstop)
2557c478bd9Sstevel@tonic-gate 		t = t_jdstop;
2567c478bd9Sstevel@tonic-gate 	else if (t_istop)
2577c478bd9Sstevel@tonic-gate 		t = t_istop;
2581959771bSJonathan Haslam 	else if (t_dtrace)
2591959771bSJonathan Haslam 		t = t_dtrace;
2607c478bd9Sstevel@tonic-gate 	else if (t_req)
2617c478bd9Sstevel@tonic-gate 		t = t_req;
2627c478bd9Sstevel@tonic-gate 	else if (t_hold)
2637c478bd9Sstevel@tonic-gate 		t = t_hold;
2647c478bd9Sstevel@tonic-gate 	else if (t_susp)
2657c478bd9Sstevel@tonic-gate 		t = t_susp;
2667c478bd9Sstevel@tonic-gate 	else			/* TS_ZOMB */
2677c478bd9Sstevel@tonic-gate 		t = p->p_tlist;
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	if (t != NULL)
2707c478bd9Sstevel@tonic-gate 		thread_lock(t);
2717c478bd9Sstevel@tonic-gate 	return (t);
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate /*
2757c478bd9Sstevel@tonic-gate  * Wakeup anyone sleeping on the /proc vnode for the process/lwp to stop.
2767c478bd9Sstevel@tonic-gate  * Also call pollwakeup() if any lwps are waiting in poll() for POLLPRI
2777c478bd9Sstevel@tonic-gate  * on the /proc file descriptor.  Called from stop() when a traced
2787c478bd9Sstevel@tonic-gate  * process stops on an event of interest.  Also called from exit()
2797c478bd9Sstevel@tonic-gate  * and prinvalidate() to indicate POLLHUP and POLLERR respectively.
2807c478bd9Sstevel@tonic-gate  */
2817c478bd9Sstevel@tonic-gate void
prnotify(struct vnode * vp)2827c478bd9Sstevel@tonic-gate prnotify(struct vnode *vp)
2837c478bd9Sstevel@tonic-gate {
2847c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = VTOP(vp)->pr_common;
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	mutex_enter(&pcp->prc_mutex);
2877c478bd9Sstevel@tonic-gate 	cv_broadcast(&pcp->prc_wait);
2887c478bd9Sstevel@tonic-gate 	mutex_exit(&pcp->prc_mutex);
2897c478bd9Sstevel@tonic-gate 	if (pcp->prc_flags & PRC_POLL) {
2907c478bd9Sstevel@tonic-gate 		/*
2917c478bd9Sstevel@tonic-gate 		 * We call pollwakeup() with POLLHUP to ensure that
2927c478bd9Sstevel@tonic-gate 		 * the pollers are awakened even if they are polling
2937c478bd9Sstevel@tonic-gate 		 * for nothing (i.e., waiting for the process to exit).
2947c478bd9Sstevel@tonic-gate 		 * This enables the use of the PRC_POLL flag for optimization
2957c478bd9Sstevel@tonic-gate 		 * (we can turn off PRC_POLL only if we know no pollers remain).
2967c478bd9Sstevel@tonic-gate 		 */
2977c478bd9Sstevel@tonic-gate 		pcp->prc_flags &= ~PRC_POLL;
2987c478bd9Sstevel@tonic-gate 		pollwakeup(&pcp->prc_pollhead, POLLHUP);
2997c478bd9Sstevel@tonic-gate 	}
3007c478bd9Sstevel@tonic-gate }
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate /* called immediately below, in prfree() */
3037c478bd9Sstevel@tonic-gate static void
prfreenotify(vnode_t * vp)3047c478bd9Sstevel@tonic-gate prfreenotify(vnode_t *vp)
3057c478bd9Sstevel@tonic-gate {
3067c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
3077c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	while (vp != NULL) {
3107c478bd9Sstevel@tonic-gate 		pnp = VTOP(vp);
3117c478bd9Sstevel@tonic-gate 		pcp = pnp->pr_common;
3127c478bd9Sstevel@tonic-gate 		ASSERT(pcp->prc_thread == NULL);
3137c478bd9Sstevel@tonic-gate 		pcp->prc_proc = NULL;
3147c478bd9Sstevel@tonic-gate 		/*
3157c478bd9Sstevel@tonic-gate 		 * We can't call prnotify() here because we are holding
3167c478bd9Sstevel@tonic-gate 		 * pidlock.  We assert that there is no need to.
3177c478bd9Sstevel@tonic-gate 		 */
3187c478bd9Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
3197c478bd9Sstevel@tonic-gate 		cv_broadcast(&pcp->prc_wait);
3207c478bd9Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
3217c478bd9Sstevel@tonic-gate 		ASSERT(!(pcp->prc_flags & PRC_POLL));
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 		vp = pnp->pr_next;
3247c478bd9Sstevel@tonic-gate 		pnp->pr_next = NULL;
3257c478bd9Sstevel@tonic-gate 	}
3267c478bd9Sstevel@tonic-gate }
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate /*
3297c478bd9Sstevel@tonic-gate  * Called from a hook in freeproc() when a traced process is removed
3307c478bd9Sstevel@tonic-gate  * from the process table.  The proc-table pointers of all associated
3317c478bd9Sstevel@tonic-gate  * /proc vnodes are cleared to indicate that the process has gone away.
3327c478bd9Sstevel@tonic-gate  */
3337c478bd9Sstevel@tonic-gate void
prfree(proc_t * p)3347c478bd9Sstevel@tonic-gate prfree(proc_t *p)
3357c478bd9Sstevel@tonic-gate {
3367c478bd9Sstevel@tonic-gate 	uint_t slot = p->p_slot;
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock));
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	/*
3417c478bd9Sstevel@tonic-gate 	 * Block the process against /proc so it can be freed.
3427c478bd9Sstevel@tonic-gate 	 * It cannot be freed while locked by some controlling process.
3437c478bd9Sstevel@tonic-gate 	 * Lock ordering:
3447c478bd9Sstevel@tonic-gate 	 *	pidlock -> pr_pidlock -> p->p_lock -> pcp->prc_mutex
3457c478bd9Sstevel@tonic-gate 	 */
3467c478bd9Sstevel@tonic-gate 	mutex_enter(&pr_pidlock);	/* protects pcp->prc_proc */
3477c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
3487c478bd9Sstevel@tonic-gate 	while (p->p_proc_flag & P_PR_LOCK) {
3497c478bd9Sstevel@tonic-gate 		mutex_exit(&pr_pidlock);
3507c478bd9Sstevel@tonic-gate 		cv_wait(&pr_pid_cv[slot], &p->p_lock);
3517c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
3527c478bd9Sstevel@tonic-gate 		mutex_enter(&pr_pidlock);
3537c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
3547c478bd9Sstevel@tonic-gate 	}
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	ASSERT(p->p_tlist == NULL);
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	prfreenotify(p->p_plist);
3597c478bd9Sstevel@tonic-gate 	p->p_plist = NULL;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	prfreenotify(p->p_trace);
3627c478bd9Sstevel@tonic-gate 	p->p_trace = NULL;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	/*
3657c478bd9Sstevel@tonic-gate 	 * We broadcast to wake up everyone waiting for this process.
3667c478bd9Sstevel@tonic-gate 	 * No one can reach this process from this point on.
3677c478bd9Sstevel@tonic-gate 	 */
3687c478bd9Sstevel@tonic-gate 	cv_broadcast(&pr_pid_cv[slot]);
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
3717c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate /*
3757c478bd9Sstevel@tonic-gate  * Called from a hook in exit() when a traced process is becoming a zombie.
3767c478bd9Sstevel@tonic-gate  */
3777c478bd9Sstevel@tonic-gate void
prexit(proc_t * p)3787c478bd9Sstevel@tonic-gate prexit(proc_t *p)
3797c478bd9Sstevel@tonic-gate {
3807c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	if (pr_watch_active(p)) {
3837c478bd9Sstevel@tonic-gate 		pr_free_watchpoints(p);
3847c478bd9Sstevel@tonic-gate 		watch_disable(curthread);
3857c478bd9Sstevel@tonic-gate 	}
3867c478bd9Sstevel@tonic-gate 	/* pr_free_watched_pages() is called in exit(), after dropping p_lock */
3877c478bd9Sstevel@tonic-gate 	if (p->p_trace) {
3887c478bd9Sstevel@tonic-gate 		VTOP(p->p_trace)->pr_common->prc_flags |= PRC_DESTROY;
3897c478bd9Sstevel@tonic-gate 		prnotify(p->p_trace);
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate 	cv_broadcast(&pr_pid_cv[p->p_slot]);	/* pauselwps() */
3927c478bd9Sstevel@tonic-gate }
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate /*
3957c478bd9Sstevel@tonic-gate  * Called when a thread calls lwp_exit().
3967c478bd9Sstevel@tonic-gate  */
3977c478bd9Sstevel@tonic-gate void
prlwpexit(kthread_t * t)3987c478bd9Sstevel@tonic-gate prlwpexit(kthread_t *t)
3997c478bd9Sstevel@tonic-gate {
4007c478bd9Sstevel@tonic-gate 	vnode_t *vp;
4017c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
4027c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
4037c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(t);
4047c478bd9Sstevel@tonic-gate 	lwpent_t *lep = p->p_lwpdir[t->t_dslot].ld_entry;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	ASSERT(t == curthread);
4077c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	/*
4107c478bd9Sstevel@tonic-gate 	 * The process must be blocked against /proc to do this safely.
4117c478bd9Sstevel@tonic-gate 	 * The lwp must not disappear while the process is marked P_PR_LOCK.
4127c478bd9Sstevel@tonic-gate 	 * It is the caller's responsibility to have called prbarrier(p).
4137c478bd9Sstevel@tonic-gate 	 */
4147c478bd9Sstevel@tonic-gate 	ASSERT(!(p->p_proc_flag & P_PR_LOCK));
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	for (vp = p->p_plist; vp != NULL; vp = pnp->pr_next) {
4177c478bd9Sstevel@tonic-gate 		pnp = VTOP(vp);
4187c478bd9Sstevel@tonic-gate 		pcp = pnp->pr_common;
4197c478bd9Sstevel@tonic-gate 		if (pcp->prc_thread == t) {
4207c478bd9Sstevel@tonic-gate 			pcp->prc_thread = NULL;
4217c478bd9Sstevel@tonic-gate 			pcp->prc_flags |= PRC_DESTROY;
4227c478bd9Sstevel@tonic-gate 		}
4237c478bd9Sstevel@tonic-gate 	}
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	for (vp = lep->le_trace; vp != NULL; vp = pnp->pr_next) {
4267c478bd9Sstevel@tonic-gate 		pnp = VTOP(vp);
4277c478bd9Sstevel@tonic-gate 		pcp = pnp->pr_common;
4287c478bd9Sstevel@tonic-gate 		pcp->prc_thread = NULL;
4297c478bd9Sstevel@tonic-gate 		pcp->prc_flags |= PRC_DESTROY;
4307c478bd9Sstevel@tonic-gate 		prnotify(vp);
4317c478bd9Sstevel@tonic-gate 	}
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	if (p->p_trace)
4347c478bd9Sstevel@tonic-gate 		prnotify(p->p_trace);
4357c478bd9Sstevel@tonic-gate }
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate /*
4387c478bd9Sstevel@tonic-gate  * Called when a zombie thread is joined or when a
4397c478bd9Sstevel@tonic-gate  * detached lwp exits.  Called from lwp_hash_out().
4407c478bd9Sstevel@tonic-gate  */
4417c478bd9Sstevel@tonic-gate void
prlwpfree(proc_t * p,lwpent_t * lep)4427c478bd9Sstevel@tonic-gate prlwpfree(proc_t *p, lwpent_t *lep)
4437c478bd9Sstevel@tonic-gate {
4447c478bd9Sstevel@tonic-gate 	vnode_t *vp;
4457c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
4467c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	/*
4517c478bd9Sstevel@tonic-gate 	 * The process must be blocked against /proc to do this safely.
4527c478bd9Sstevel@tonic-gate 	 * The lwp must not disappear while the process is marked P_PR_LOCK.
4537c478bd9Sstevel@tonic-gate 	 * It is the caller's responsibility to have called prbarrier(p).
4547c478bd9Sstevel@tonic-gate 	 */
4557c478bd9Sstevel@tonic-gate 	ASSERT(!(p->p_proc_flag & P_PR_LOCK));
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	vp = lep->le_trace;
4587c478bd9Sstevel@tonic-gate 	lep->le_trace = NULL;
4597c478bd9Sstevel@tonic-gate 	while (vp) {
4607c478bd9Sstevel@tonic-gate 		prnotify(vp);
4617c478bd9Sstevel@tonic-gate 		pnp = VTOP(vp);
4627c478bd9Sstevel@tonic-gate 		pcp = pnp->pr_common;
4637c478bd9Sstevel@tonic-gate 		ASSERT(pcp->prc_thread == NULL &&
4647c478bd9Sstevel@tonic-gate 		    (pcp->prc_flags & PRC_DESTROY));
4657c478bd9Sstevel@tonic-gate 		pcp->prc_tslot = -1;
4667c478bd9Sstevel@tonic-gate 		vp = pnp->pr_next;
4677c478bd9Sstevel@tonic-gate 		pnp->pr_next = NULL;
4687c478bd9Sstevel@tonic-gate 	}
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	if (p->p_trace)
4717c478bd9Sstevel@tonic-gate 		prnotify(p->p_trace);
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate /*
4757c478bd9Sstevel@tonic-gate  * Called from a hook in exec() when a thread starts exec().
4767c478bd9Sstevel@tonic-gate  */
4777c478bd9Sstevel@tonic-gate void
prexecstart(void)4787c478bd9Sstevel@tonic-gate prexecstart(void)
4797c478bd9Sstevel@tonic-gate {
4807c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
4817c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	/*
4847c478bd9Sstevel@tonic-gate 	 * The P_PR_EXEC flag blocks /proc operations for
4857c478bd9Sstevel@tonic-gate 	 * the duration of the exec().
4867c478bd9Sstevel@tonic-gate 	 * We can't start exec() while the process is
4877c478bd9Sstevel@tonic-gate 	 * locked by /proc, so we call prbarrier().
4887c478bd9Sstevel@tonic-gate 	 * lwp_nostop keeps the process from being stopped
4897c478bd9Sstevel@tonic-gate 	 * via job control for the duration of the exec().
4907c478bd9Sstevel@tonic-gate 	 */
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
4937c478bd9Sstevel@tonic-gate 	prbarrier(p);
4947c478bd9Sstevel@tonic-gate 	lwp->lwp_nostop++;
4957c478bd9Sstevel@tonic-gate 	p->p_proc_flag |= P_PR_EXEC;
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate /*
4997c478bd9Sstevel@tonic-gate  * Called from a hook in exec() when a thread finishes exec().
5007c478bd9Sstevel@tonic-gate  * The thread may or may not have succeeded.  Some other thread
5017c478bd9Sstevel@tonic-gate  * may have beat it to the punch.
5027c478bd9Sstevel@tonic-gate  */
5037c478bd9Sstevel@tonic-gate void
prexecend(void)5047c478bd9Sstevel@tonic-gate prexecend(void)
5057c478bd9Sstevel@tonic-gate {
5067c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
5077c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
5087c478bd9Sstevel@tonic-gate 	vnode_t *vp;
5097c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
5107c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
5117c478bd9Sstevel@tonic-gate 	model_t model = p->p_model;
5127c478bd9Sstevel@tonic-gate 	id_t tid = curthread->t_tid;
5137c478bd9Sstevel@tonic-gate 	int tslot = curthread->t_dslot;
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	lwp->lwp_nostop--;
5187c478bd9Sstevel@tonic-gate 	if (p->p_flag & SEXITLWPS) {
5197c478bd9Sstevel@tonic-gate 		/*
5207c478bd9Sstevel@tonic-gate 		 * We are on our way to exiting because some
5217c478bd9Sstevel@tonic-gate 		 * other thread beat us in the race to exec().
5227c478bd9Sstevel@tonic-gate 		 * Don't clear the P_PR_EXEC flag in this case.
5237c478bd9Sstevel@tonic-gate 		 */
5247c478bd9Sstevel@tonic-gate 		return;
5257c478bd9Sstevel@tonic-gate 	}
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	/*
5287c478bd9Sstevel@tonic-gate 	 * Wake up anyone waiting in /proc for the process to complete exec().
5297c478bd9Sstevel@tonic-gate 	 */
5307c478bd9Sstevel@tonic-gate 	p->p_proc_flag &= ~P_PR_EXEC;
5317c478bd9Sstevel@tonic-gate 	if ((vp = p->p_trace) != NULL) {
5327c478bd9Sstevel@tonic-gate 		pcp = VTOP(vp)->pr_common;
5337c478bd9Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
5347c478bd9Sstevel@tonic-gate 		cv_broadcast(&pcp->prc_wait);
5357c478bd9Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
5367c478bd9Sstevel@tonic-gate 		for (; vp != NULL; vp = pnp->pr_next) {
5377c478bd9Sstevel@tonic-gate 			pnp = VTOP(vp);
5387c478bd9Sstevel@tonic-gate 			pnp->pr_common->prc_datamodel = model;
5397c478bd9Sstevel@tonic-gate 		}
5407c478bd9Sstevel@tonic-gate 	}
5417c478bd9Sstevel@tonic-gate 	if ((vp = p->p_lwpdir[tslot].ld_entry->le_trace) != NULL) {
5427c478bd9Sstevel@tonic-gate 		/*
5437c478bd9Sstevel@tonic-gate 		 * We dealt with the process common above.
5447c478bd9Sstevel@tonic-gate 		 */
5457c478bd9Sstevel@tonic-gate 		ASSERT(p->p_trace != NULL);
5467c478bd9Sstevel@tonic-gate 		pcp = VTOP(vp)->pr_common;
5477c478bd9Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
5487c478bd9Sstevel@tonic-gate 		cv_broadcast(&pcp->prc_wait);
5497c478bd9Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
5507c478bd9Sstevel@tonic-gate 		for (; vp != NULL; vp = pnp->pr_next) {
5517c478bd9Sstevel@tonic-gate 			pnp = VTOP(vp);
5527c478bd9Sstevel@tonic-gate 			pcp = pnp->pr_common;
5537c478bd9Sstevel@tonic-gate 			pcp->prc_datamodel = model;
5547c478bd9Sstevel@tonic-gate 			pcp->prc_tid = tid;
5557c478bd9Sstevel@tonic-gate 			pcp->prc_tslot = tslot;
5567c478bd9Sstevel@tonic-gate 		}
5577c478bd9Sstevel@tonic-gate 	}
5587c478bd9Sstevel@tonic-gate }
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate /*
5617c478bd9Sstevel@tonic-gate  * Called from a hook in relvm() just before freeing the address space.
5627c478bd9Sstevel@tonic-gate  * We free all the watched areas now.
5637c478bd9Sstevel@tonic-gate  */
5647c478bd9Sstevel@tonic-gate void
prrelvm(void)5657c478bd9Sstevel@tonic-gate prrelvm(void)
5667c478bd9Sstevel@tonic-gate {
5677c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
5707c478bd9Sstevel@tonic-gate 	prbarrier(p);	/* block all other /proc operations */
5717c478bd9Sstevel@tonic-gate 	if (pr_watch_active(p)) {
5727c478bd9Sstevel@tonic-gate 		pr_free_watchpoints(p);
5737c478bd9Sstevel@tonic-gate 		watch_disable(curthread);
5747c478bd9Sstevel@tonic-gate 	}
5757c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
5767c478bd9Sstevel@tonic-gate 	pr_free_watched_pages(p);
5777c478bd9Sstevel@tonic-gate }
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate /*
5807c478bd9Sstevel@tonic-gate  * Called from hooks in exec-related code when a traced process
5817c478bd9Sstevel@tonic-gate  * attempts to exec(2) a setuid/setgid program or an unreadable
5827c478bd9Sstevel@tonic-gate  * file.  Rather than fail the exec we invalidate the associated
5837c478bd9Sstevel@tonic-gate  * /proc vnodes so that subsequent attempts to use them will fail.
5847c478bd9Sstevel@tonic-gate  *
5857c478bd9Sstevel@tonic-gate  * All /proc vnodes, except directory vnodes, are retained on a linked
5867c478bd9Sstevel@tonic-gate  * list (rooted at p_plist in the process structure) until last close.
5877c478bd9Sstevel@tonic-gate  *
5887c478bd9Sstevel@tonic-gate  * A controlling process must re-open the /proc files in order to
5897c478bd9Sstevel@tonic-gate  * regain control.
5907c478bd9Sstevel@tonic-gate  */
5917c478bd9Sstevel@tonic-gate void
prinvalidate(struct user * up)5927c478bd9Sstevel@tonic-gate prinvalidate(struct user *up)
5937c478bd9Sstevel@tonic-gate {
5947c478bd9Sstevel@tonic-gate 	kthread_t *t = curthread;
5957c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(t);
5967c478bd9Sstevel@tonic-gate 	vnode_t *vp;
5977c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
5987c478bd9Sstevel@tonic-gate 	int writers = 0;
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
6017c478bd9Sstevel@tonic-gate 	prbarrier(p);	/* block all other /proc operations */
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	/*
6047c478bd9Sstevel@tonic-gate 	 * At this moment, there can be only one lwp in the process.
6057c478bd9Sstevel@tonic-gate 	 */
6067c478bd9Sstevel@tonic-gate 	ASSERT(p->p_lwpcnt == 1 && p->p_zombcnt == 0);
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	/*
6097c478bd9Sstevel@tonic-gate 	 * Invalidate any currently active /proc vnodes.
6107c478bd9Sstevel@tonic-gate 	 */
6117c478bd9Sstevel@tonic-gate 	for (vp = p->p_plist; vp != NULL; vp = pnp->pr_next) {
6127c478bd9Sstevel@tonic-gate 		pnp = VTOP(vp);
6137c478bd9Sstevel@tonic-gate 		switch (pnp->pr_type) {
6147c478bd9Sstevel@tonic-gate 		case PR_PSINFO:		/* these files can read by anyone */
6157c478bd9Sstevel@tonic-gate 		case PR_LPSINFO:
6167c478bd9Sstevel@tonic-gate 		case PR_LWPSINFO:
6177c478bd9Sstevel@tonic-gate 		case PR_LWPDIR:
6187c478bd9Sstevel@tonic-gate 		case PR_LWPIDDIR:
6197c478bd9Sstevel@tonic-gate 		case PR_USAGE:
6207c478bd9Sstevel@tonic-gate 		case PR_LUSAGE:
6217c478bd9Sstevel@tonic-gate 		case PR_LWPUSAGE:
6227c478bd9Sstevel@tonic-gate 			break;
6237c478bd9Sstevel@tonic-gate 		default:
6247c478bd9Sstevel@tonic-gate 			pnp->pr_flags |= PR_INVAL;
6257c478bd9Sstevel@tonic-gate 			break;
6267c478bd9Sstevel@tonic-gate 		}
6277c478bd9Sstevel@tonic-gate 	}
6287c478bd9Sstevel@tonic-gate 	/*
6297c478bd9Sstevel@tonic-gate 	 * Wake up anyone waiting for the process or lwp.
6307c478bd9Sstevel@tonic-gate 	 * p->p_trace is guaranteed to be non-NULL if there
6317c478bd9Sstevel@tonic-gate 	 * are any open /proc files for this process.
6327c478bd9Sstevel@tonic-gate 	 */
6337c478bd9Sstevel@tonic-gate 	if ((vp = p->p_trace) != NULL) {
6347c478bd9Sstevel@tonic-gate 		prcommon_t *pcp = VTOP(vp)->pr_pcommon;
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 		prnotify(vp);
6377c478bd9Sstevel@tonic-gate 		/*
6387c478bd9Sstevel@tonic-gate 		 * Are there any writers?
6397c478bd9Sstevel@tonic-gate 		 */
6407c478bd9Sstevel@tonic-gate 		if ((writers = pcp->prc_writers) != 0) {
6417c478bd9Sstevel@tonic-gate 			/*
6427c478bd9Sstevel@tonic-gate 			 * Clear the exclusive open flag (old /proc interface).
6437c478bd9Sstevel@tonic-gate 			 * Set prc_selfopens equal to prc_writers so that
6447c478bd9Sstevel@tonic-gate 			 * the next O_EXCL|O_WRITE open will succeed
6457c478bd9Sstevel@tonic-gate 			 * even with existing (though invalid) writers.
6467c478bd9Sstevel@tonic-gate 			 * prclose() must decrement prc_selfopens when
6477c478bd9Sstevel@tonic-gate 			 * the invalid files are closed.
6487c478bd9Sstevel@tonic-gate 			 */
6497c478bd9Sstevel@tonic-gate 			pcp->prc_flags &= ~PRC_EXCL;
6507c478bd9Sstevel@tonic-gate 			ASSERT(pcp->prc_selfopens <= writers);
6517c478bd9Sstevel@tonic-gate 			pcp->prc_selfopens = writers;
6527c478bd9Sstevel@tonic-gate 		}
6537c478bd9Sstevel@tonic-gate 	}
6547c478bd9Sstevel@tonic-gate 	vp = p->p_lwpdir[t->t_dslot].ld_entry->le_trace;
6557c478bd9Sstevel@tonic-gate 	while (vp != NULL) {
6567c478bd9Sstevel@tonic-gate 		/*
6577c478bd9Sstevel@tonic-gate 		 * We should not invalidate the lwpiddir vnodes,
6587c478bd9Sstevel@tonic-gate 		 * but the necessities of maintaining the old
6597c478bd9Sstevel@tonic-gate 		 * ioctl()-based version of /proc require it.
6607c478bd9Sstevel@tonic-gate 		 */
6617c478bd9Sstevel@tonic-gate 		pnp = VTOP(vp);
6627c478bd9Sstevel@tonic-gate 		pnp->pr_flags |= PR_INVAL;
6637c478bd9Sstevel@tonic-gate 		prnotify(vp);
6647c478bd9Sstevel@tonic-gate 		vp = pnp->pr_next;
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	/*
6687c478bd9Sstevel@tonic-gate 	 * If any tracing flags are in effect and any vnodes are open for
6697c478bd9Sstevel@tonic-gate 	 * writing then set the requested-stop and run-on-last-close flags.
6707c478bd9Sstevel@tonic-gate 	 * Otherwise, clear all tracing flags.
6717c478bd9Sstevel@tonic-gate 	 */
6727c478bd9Sstevel@tonic-gate 	t->t_proc_flag &= ~TP_PAUSE;
6737c478bd9Sstevel@tonic-gate 	if ((p->p_proc_flag & P_PR_TRACE) && writers) {
6747c478bd9Sstevel@tonic-gate 		t->t_proc_flag |= TP_PRSTOP;
6757c478bd9Sstevel@tonic-gate 		aston(t);		/* so ISSIG will see the flag */
6767c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_RUNLCL;
6777c478bd9Sstevel@tonic-gate 	} else {
6787c478bd9Sstevel@tonic-gate 		premptyset(&up->u_entrymask);		/* syscalls */
6797c478bd9Sstevel@tonic-gate 		premptyset(&up->u_exitmask);
6807c478bd9Sstevel@tonic-gate 		up->u_systrap = 0;
6817c478bd9Sstevel@tonic-gate 		premptyset(&p->p_sigmask);		/* signals */
6827c478bd9Sstevel@tonic-gate 		premptyset(&p->p_fltmask);		/* faults */
6837c478bd9Sstevel@tonic-gate 		t->t_proc_flag &= ~(TP_PRSTOP|TP_PRVSTOP|TP_STOPPING);
6847c478bd9Sstevel@tonic-gate 		p->p_proc_flag &= ~(P_PR_RUNLCL|P_PR_KILLCL|P_PR_TRACE);
6857c478bd9Sstevel@tonic-gate 		prnostep(ttolwp(t));
6867c478bd9Sstevel@tonic-gate 	}
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate /*
6927c478bd9Sstevel@tonic-gate  * Acquire the controlled process's p_lock and mark it P_PR_LOCK.
6937c478bd9Sstevel@tonic-gate  * Return with pr_pidlock held in all cases.
6947c478bd9Sstevel@tonic-gate  * Return with p_lock held if the the process still exists.
6957c478bd9Sstevel@tonic-gate  * Return value is the process pointer if the process still exists, else NULL.
6967c478bd9Sstevel@tonic-gate  * If we lock the process, give ourself kernel priority to avoid deadlocks;
6977c478bd9Sstevel@tonic-gate  * this is undone in prunlock().
6987c478bd9Sstevel@tonic-gate  */
6997c478bd9Sstevel@tonic-gate proc_t *
pr_p_lock(prnode_t * pnp)7007c478bd9Sstevel@tonic-gate pr_p_lock(prnode_t *pnp)
7017c478bd9Sstevel@tonic-gate {
7027c478bd9Sstevel@tonic-gate 	proc_t *p;
7037c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	mutex_enter(&pr_pidlock);
7067c478bd9Sstevel@tonic-gate 	if ((pcp = pnp->pr_pcommon) == NULL || (p = pcp->prc_proc) == NULL)
7077c478bd9Sstevel@tonic-gate 		return (NULL);
7087c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
7097c478bd9Sstevel@tonic-gate 	while (p->p_proc_flag & P_PR_LOCK) {
7107c478bd9Sstevel@tonic-gate 		/*
7117c478bd9Sstevel@tonic-gate 		 * This cv/mutex pair is persistent even if
7127c478bd9Sstevel@tonic-gate 		 * the process disappears while we sleep.
7137c478bd9Sstevel@tonic-gate 		 */
7147c478bd9Sstevel@tonic-gate 		kcondvar_t *cv = &pr_pid_cv[p->p_slot];
7157c478bd9Sstevel@tonic-gate 		kmutex_t *mp = &p->p_lock;
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 		mutex_exit(&pr_pidlock);
7187c478bd9Sstevel@tonic-gate 		cv_wait(cv, mp);
7197c478bd9Sstevel@tonic-gate 		mutex_exit(mp);
7207c478bd9Sstevel@tonic-gate 		mutex_enter(&pr_pidlock);
7217c478bd9Sstevel@tonic-gate 		if (pcp->prc_proc == NULL)
7227c478bd9Sstevel@tonic-gate 			return (NULL);
7237c478bd9Sstevel@tonic-gate 		ASSERT(p == pcp->prc_proc);
7247c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
7257c478bd9Sstevel@tonic-gate 	}
7267c478bd9Sstevel@tonic-gate 	p->p_proc_flag |= P_PR_LOCK;
7277c478bd9Sstevel@tonic-gate 	return (p);
7287c478bd9Sstevel@tonic-gate }
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate /*
7317c478bd9Sstevel@tonic-gate  * Lock the target process by setting P_PR_LOCK and grabbing p->p_lock.
7327c478bd9Sstevel@tonic-gate  * This prevents any lwp of the process from disappearing and
7337c478bd9Sstevel@tonic-gate  * blocks most operations that a process can perform on itself.
7347c478bd9Sstevel@tonic-gate  * Returns 0 on success, a non-zero error number on failure.
7357c478bd9Sstevel@tonic-gate  *
7367c478bd9Sstevel@tonic-gate  * 'zdisp' is ZYES or ZNO to indicate whether prlock() should succeed when
7377c478bd9Sstevel@tonic-gate  * the subject process is a zombie (ZYES) or fail for zombies (ZNO).
7387c478bd9Sstevel@tonic-gate  *
7397c478bd9Sstevel@tonic-gate  * error returns:
7407c478bd9Sstevel@tonic-gate  *	ENOENT: process or lwp has disappeared or process is exiting
7417c478bd9Sstevel@tonic-gate  *		(or has become a zombie and zdisp == ZNO).
7427c478bd9Sstevel@tonic-gate  *	EAGAIN: procfs vnode has become invalid.
7437c478bd9Sstevel@tonic-gate  *	EINTR:  signal arrived while waiting for exec to complete.
7447c478bd9Sstevel@tonic-gate  */
7457c478bd9Sstevel@tonic-gate int
prlock(prnode_t * pnp,int zdisp)7467c478bd9Sstevel@tonic-gate prlock(prnode_t *pnp, int zdisp)
7477c478bd9Sstevel@tonic-gate {
7487c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
7497c478bd9Sstevel@tonic-gate 	proc_t *p;
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate again:
7527c478bd9Sstevel@tonic-gate 	pcp = pnp->pr_common;
7537c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
7547c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 	/*
7577c478bd9Sstevel@tonic-gate 	 * Return ENOENT immediately if there is no process.
7587c478bd9Sstevel@tonic-gate 	 */
7597c478bd9Sstevel@tonic-gate 	if (p == NULL)
7607c478bd9Sstevel@tonic-gate 		return (ENOENT);
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	ASSERT(p == pcp->prc_proc && p->p_stat != 0 && p->p_stat != SIDL);
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 	/*
7657c478bd9Sstevel@tonic-gate 	 * Return ENOENT if process entered zombie state or is exiting
7667c478bd9Sstevel@tonic-gate 	 * and the 'zdisp' flag is set to ZNO indicating not to lock zombies.
7677c478bd9Sstevel@tonic-gate 	 */
7687c478bd9Sstevel@tonic-gate 	if (zdisp == ZNO &&
76997eda132Sraf 	    ((pcp->prc_flags & PRC_DESTROY) || (p->p_flag & SEXITING))) {
7707c478bd9Sstevel@tonic-gate 		prunlock(pnp);
7717c478bd9Sstevel@tonic-gate 		return (ENOENT);
7727c478bd9Sstevel@tonic-gate 	}
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	/*
7757c478bd9Sstevel@tonic-gate 	 * If lwp-specific, check to see if lwp has disappeared.
7767c478bd9Sstevel@tonic-gate 	 */
7777c478bd9Sstevel@tonic-gate 	if (pcp->prc_flags & PRC_LWP) {
7787c478bd9Sstevel@tonic-gate 		if ((zdisp == ZNO && (pcp->prc_flags & PRC_DESTROY)) ||
7797c478bd9Sstevel@tonic-gate 		    pcp->prc_tslot == -1) {
7807c478bd9Sstevel@tonic-gate 			prunlock(pnp);
7817c478bd9Sstevel@tonic-gate 			return (ENOENT);
7827c478bd9Sstevel@tonic-gate 		}
7837c478bd9Sstevel@tonic-gate 	}
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 	/*
7867c478bd9Sstevel@tonic-gate 	 * Return EAGAIN if we have encountered a security violation.
7877c478bd9Sstevel@tonic-gate 	 * (The process exec'd a set-id or unreadable executable file.)
7887c478bd9Sstevel@tonic-gate 	 */
7897c478bd9Sstevel@tonic-gate 	if (pnp->pr_flags & PR_INVAL) {
7907c478bd9Sstevel@tonic-gate 		prunlock(pnp);
7917c478bd9Sstevel@tonic-gate 		return (EAGAIN);
7927c478bd9Sstevel@tonic-gate 	}
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	/*
7957c478bd9Sstevel@tonic-gate 	 * If process is undergoing an exec(), wait for
7967c478bd9Sstevel@tonic-gate 	 * completion and then start all over again.
7977c478bd9Sstevel@tonic-gate 	 */
7987c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_EXEC) {
7997c478bd9Sstevel@tonic-gate 		pcp = pnp->pr_pcommon;	/* Put on the correct sleep queue */
8007c478bd9Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
8017c478bd9Sstevel@tonic-gate 		prunlock(pnp);
8027c478bd9Sstevel@tonic-gate 		if (!cv_wait_sig(&pcp->prc_wait, &pcp->prc_mutex)) {
8037c478bd9Sstevel@tonic-gate 			mutex_exit(&pcp->prc_mutex);
8047c478bd9Sstevel@tonic-gate 			return (EINTR);
8057c478bd9Sstevel@tonic-gate 		}
8067c478bd9Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
8077c478bd9Sstevel@tonic-gate 		goto again;
8087c478bd9Sstevel@tonic-gate 	}
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	/*
8117c478bd9Sstevel@tonic-gate 	 * We return holding p->p_lock.
8127c478bd9Sstevel@tonic-gate 	 */
8137c478bd9Sstevel@tonic-gate 	return (0);
8147c478bd9Sstevel@tonic-gate }
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate /*
8177c478bd9Sstevel@tonic-gate  * Undo prlock() and pr_p_lock().
8187c478bd9Sstevel@tonic-gate  * p->p_lock is still held; pr_pidlock is no longer held.
8197c478bd9Sstevel@tonic-gate  *
8207c478bd9Sstevel@tonic-gate  * prunmark() drops the P_PR_LOCK flag and wakes up another thread,
8217c478bd9Sstevel@tonic-gate  * if any, waiting for the flag to be dropped; it retains p->p_lock.
8227c478bd9Sstevel@tonic-gate  *
8237c478bd9Sstevel@tonic-gate  * prunlock() calls prunmark() and then drops p->p_lock.
8247c478bd9Sstevel@tonic-gate  */
8257c478bd9Sstevel@tonic-gate void
prunmark(proc_t * p)8267c478bd9Sstevel@tonic-gate prunmark(proc_t *p)
8277c478bd9Sstevel@tonic-gate {
8287c478bd9Sstevel@tonic-gate 	ASSERT(p->p_proc_flag & P_PR_LOCK);
8297c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	cv_signal(&pr_pid_cv[p->p_slot]);
8327c478bd9Sstevel@tonic-gate 	p->p_proc_flag &= ~P_PR_LOCK;
8337c478bd9Sstevel@tonic-gate }
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate void
prunlock(prnode_t * pnp)8367c478bd9Sstevel@tonic-gate prunlock(prnode_t *pnp)
8377c478bd9Sstevel@tonic-gate {
8387c1a8fa4Sraf 	prcommon_t *pcp = pnp->pr_common;
8397c1a8fa4Sraf 	proc_t *p = pcp->prc_proc;
8407c478bd9Sstevel@tonic-gate 
8417c1a8fa4Sraf 	/*
8427c1a8fa4Sraf 	 * If we (or someone) gave it a SIGKILL, and it is not
8437c1a8fa4Sraf 	 * already a zombie, set it running unconditionally.
8447c1a8fa4Sraf 	 */
8457c1a8fa4Sraf 	if ((p->p_flag & SKILLED) &&
8467c1a8fa4Sraf 	    !(p->p_flag & SEXITING) &&
8477c1a8fa4Sraf 	    !(pcp->prc_flags & PRC_DESTROY) &&
8487c1a8fa4Sraf 	    !((pcp->prc_flags & PRC_LWP) && pcp->prc_tslot == -1))
8497c1a8fa4Sraf 		(void) pr_setrun(pnp, 0);
8507c478bd9Sstevel@tonic-gate 	prunmark(p);
8517c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
8527c478bd9Sstevel@tonic-gate }
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate /*
8557c478bd9Sstevel@tonic-gate  * Called while holding p->p_lock to delay until the process is unlocked.
8567c478bd9Sstevel@tonic-gate  * We enter holding p->p_lock; p->p_lock is dropped and reacquired.
8577c478bd9Sstevel@tonic-gate  * The process cannot become locked again until p->p_lock is dropped.
8587c478bd9Sstevel@tonic-gate  */
8597c478bd9Sstevel@tonic-gate void
prbarrier(proc_t * p)8607c478bd9Sstevel@tonic-gate prbarrier(proc_t *p)
8617c478bd9Sstevel@tonic-gate {
8627c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_LOCK) {
8657c478bd9Sstevel@tonic-gate 		/* The process is locked; delay until not locked */
8667c478bd9Sstevel@tonic-gate 		uint_t slot = p->p_slot;
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 		while (p->p_proc_flag & P_PR_LOCK)
8697c478bd9Sstevel@tonic-gate 			cv_wait(&pr_pid_cv[slot], &p->p_lock);
8707c478bd9Sstevel@tonic-gate 		cv_signal(&pr_pid_cv[slot]);
8717c478bd9Sstevel@tonic-gate 	}
8727c478bd9Sstevel@tonic-gate }
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate /*
8757c478bd9Sstevel@tonic-gate  * Return process/lwp status.
8767c478bd9Sstevel@tonic-gate  * The u-block is mapped in by this routine and unmapped at the end.
8777c478bd9Sstevel@tonic-gate  */
8787c478bd9Sstevel@tonic-gate void
prgetstatus(proc_t * p,pstatus_t * sp,zone_t * zp)8797c478bd9Sstevel@tonic-gate prgetstatus(proc_t *p, pstatus_t *sp, zone_t *zp)
8807c478bd9Sstevel@tonic-gate {
8817c478bd9Sstevel@tonic-gate 	kthread_t *t;
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	t = prchoose(p);	/* returns locked thread */
8867c478bd9Sstevel@tonic-gate 	ASSERT(t != NULL);
8877c478bd9Sstevel@tonic-gate 	thread_unlock(t);
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	/* just bzero the process part, prgetlwpstatus() does the rest */
8907c478bd9Sstevel@tonic-gate 	bzero(sp, sizeof (pstatus_t) - sizeof (lwpstatus_t));
8917c478bd9Sstevel@tonic-gate 	sp->pr_nlwp = p->p_lwpcnt;
8927c478bd9Sstevel@tonic-gate 	sp->pr_nzomb = p->p_zombcnt;
8937c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_sigpend, &p->p_sig);
8947c478bd9Sstevel@tonic-gate 	sp->pr_brkbase = (uintptr_t)p->p_brkbase;
8957c478bd9Sstevel@tonic-gate 	sp->pr_brksize = p->p_brksize;
8967c478bd9Sstevel@tonic-gate 	sp->pr_stkbase = (uintptr_t)prgetstackbase(p);
8977c478bd9Sstevel@tonic-gate 	sp->pr_stksize = p->p_stksize;
8987c478bd9Sstevel@tonic-gate 	sp->pr_pid = p->p_pid;
8997c478bd9Sstevel@tonic-gate 	if (curproc->p_zone->zone_id != GLOBAL_ZONEID &&
9007c478bd9Sstevel@tonic-gate 	    (p->p_flag & SZONETOP)) {
9017c478bd9Sstevel@tonic-gate 		ASSERT(p->p_zone->zone_id != GLOBAL_ZONEID);
9027c478bd9Sstevel@tonic-gate 		/*
9037c478bd9Sstevel@tonic-gate 		 * Inside local zones, fake zsched's pid as parent pids for
9047c478bd9Sstevel@tonic-gate 		 * processes which reference processes outside of the zone.
9057c478bd9Sstevel@tonic-gate 		 */
9067c478bd9Sstevel@tonic-gate 		sp->pr_ppid = curproc->p_zone->zone_zsched->p_pid;
9077c478bd9Sstevel@tonic-gate 	} else {
9087c478bd9Sstevel@tonic-gate 		sp->pr_ppid = p->p_ppid;
9097c478bd9Sstevel@tonic-gate 	}
9107c478bd9Sstevel@tonic-gate 	sp->pr_pgid  = p->p_pgrp;
9117c478bd9Sstevel@tonic-gate 	sp->pr_sid   = p->p_sessp->s_sid;
9127c478bd9Sstevel@tonic-gate 	sp->pr_taskid = p->p_task->tk_tkid;
9137c478bd9Sstevel@tonic-gate 	sp->pr_projid = p->p_task->tk_proj->kpj_id;
9147c478bd9Sstevel@tonic-gate 	sp->pr_zoneid = p->p_zone->zone_id;
9157c478bd9Sstevel@tonic-gate 	hrt2ts(mstate_aggr_state(p, LMS_USER), &sp->pr_utime);
9167c478bd9Sstevel@tonic-gate 	hrt2ts(mstate_aggr_state(p, LMS_SYSTEM), &sp->pr_stime);
9177c478bd9Sstevel@tonic-gate 	TICK_TO_TIMESTRUC(p->p_cutime, &sp->pr_cutime);
9187c478bd9Sstevel@tonic-gate 	TICK_TO_TIMESTRUC(p->p_cstime, &sp->pr_cstime);
9197c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_sigtrace, &p->p_sigmask);
9207c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_flttrace, &p->p_fltmask);
9217c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_sysentry, &PTOU(p)->u_entrymask);
9227c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_sysexit, &PTOU(p)->u_exitmask);
9237c478bd9Sstevel@tonic-gate 	switch (p->p_model) {
9247c478bd9Sstevel@tonic-gate 	case DATAMODEL_ILP32:
9257c478bd9Sstevel@tonic-gate 		sp->pr_dmodel = PR_MODEL_ILP32;
9267c478bd9Sstevel@tonic-gate 		break;
9277c478bd9Sstevel@tonic-gate 	case DATAMODEL_LP64:
9287c478bd9Sstevel@tonic-gate 		sp->pr_dmodel = PR_MODEL_LP64;
9297c478bd9Sstevel@tonic-gate 		break;
9307c478bd9Sstevel@tonic-gate 	}
9317c478bd9Sstevel@tonic-gate 	if (p->p_agenttp)
9327c478bd9Sstevel@tonic-gate 		sp->pr_agentid = p->p_agenttp->t_tid;
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 	/* get the chosen lwp's status */
9357c478bd9Sstevel@tonic-gate 	prgetlwpstatus(t, &sp->pr_lwp, zp);
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	/* replicate the flags */
9387c478bd9Sstevel@tonic-gate 	sp->pr_flags = sp->pr_lwp.pr_flags;
9397c478bd9Sstevel@tonic-gate }
9407c478bd9Sstevel@tonic-gate 
94172a6dc12SPatrick Mooney /*
94272a6dc12SPatrick Mooney  * Query mask of held signals for a given thread.
94372a6dc12SPatrick Mooney  *
94472a6dc12SPatrick Mooney  * This makes use of schedctl_sigblock() to query if userspace has requested
94572a6dc12SPatrick Mooney  * that all maskable signals be held.  While it would be tempting to call
94672a6dc12SPatrick Mooney  * schedctl_finish_sigblock() and apply that update to t->t_hold, it cannot be
94772a6dc12SPatrick Mooney  * done safely without the risk of racing with the thread under consideration.
94872a6dc12SPatrick Mooney  */
94972a6dc12SPatrick Mooney void
prgethold(kthread_t * t,sigset_t * sp)95072a6dc12SPatrick Mooney prgethold(kthread_t *t, sigset_t *sp)
95172a6dc12SPatrick Mooney {
95272a6dc12SPatrick Mooney 	k_sigset_t set;
95372a6dc12SPatrick Mooney 
95472a6dc12SPatrick Mooney 	if (schedctl_sigblock(t)) {
95572a6dc12SPatrick Mooney 		set.__sigbits[0] = FILLSET0 & ~CANTMASK0;
95672a6dc12SPatrick Mooney 		set.__sigbits[1] = FILLSET1 & ~CANTMASK1;
95772a6dc12SPatrick Mooney 		set.__sigbits[2] = FILLSET2 & ~CANTMASK2;
95872a6dc12SPatrick Mooney 	} else {
95972a6dc12SPatrick Mooney 		set = t->t_hold;
96072a6dc12SPatrick Mooney 	}
96172a6dc12SPatrick Mooney 	sigktou(&set, sp);
96272a6dc12SPatrick Mooney }
96372a6dc12SPatrick Mooney 
9647c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
9657c478bd9Sstevel@tonic-gate void
prgetlwpstatus32(kthread_t * t,lwpstatus32_t * sp,zone_t * zp)9667c478bd9Sstevel@tonic-gate prgetlwpstatus32(kthread_t *t, lwpstatus32_t *sp, zone_t *zp)
9677c478bd9Sstevel@tonic-gate {
9687c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(t);
9697c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
9707c478bd9Sstevel@tonic-gate 	struct mstate *ms = &lwp->lwp_mstate;
9717c478bd9Sstevel@tonic-gate 	hrtime_t usr, sys;
9727c478bd9Sstevel@tonic-gate 	int flags;
9737c478bd9Sstevel@tonic-gate 	ulong_t instr;
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 	bzero(sp, sizeof (*sp));
9787c478bd9Sstevel@tonic-gate 	flags = 0L;
9797c478bd9Sstevel@tonic-gate 	if (t->t_state == TS_STOPPED) {
9807c478bd9Sstevel@tonic-gate 		flags |= PR_STOPPED;
9817c478bd9Sstevel@tonic-gate 		if ((t->t_schedflag & TS_PSTART) == 0)
9827c478bd9Sstevel@tonic-gate 			flags |= PR_ISTOP;
9837c478bd9Sstevel@tonic-gate 	} else if (VSTOPPED(t)) {
9847c478bd9Sstevel@tonic-gate 		flags |= PR_STOPPED|PR_ISTOP;
9857c478bd9Sstevel@tonic-gate 	}
9867c478bd9Sstevel@tonic-gate 	if (!(flags & PR_ISTOP) && (t->t_proc_flag & TP_PRSTOP))
9877c478bd9Sstevel@tonic-gate 		flags |= PR_DSTOP;
9887c478bd9Sstevel@tonic-gate 	if (lwp->lwp_asleep)
9897c478bd9Sstevel@tonic-gate 		flags |= PR_ASLEEP;
9907c478bd9Sstevel@tonic-gate 	if (t == p->p_agenttp)
9917c478bd9Sstevel@tonic-gate 		flags |= PR_AGENT;
9927c478bd9Sstevel@tonic-gate 	if (!(t->t_proc_flag & TP_TWAIT))
9937c478bd9Sstevel@tonic-gate 		flags |= PR_DETACH;
9947c478bd9Sstevel@tonic-gate 	if (t->t_proc_flag & TP_DAEMON)
9957c478bd9Sstevel@tonic-gate 		flags |= PR_DAEMON;
9967c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_FORK)
9977c478bd9Sstevel@tonic-gate 		flags |= PR_FORK;
9987c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_RUNLCL)
9997c478bd9Sstevel@tonic-gate 		flags |= PR_RLC;
10007c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_KILLCL)
10017c478bd9Sstevel@tonic-gate 		flags |= PR_KLC;
10027c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_ASYNC)
10037c478bd9Sstevel@tonic-gate 		flags |= PR_ASYNC;
10047c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_BPTADJ)
10057c478bd9Sstevel@tonic-gate 		flags |= PR_BPTADJ;
10067c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_PTRACE)
10077c478bd9Sstevel@tonic-gate 		flags |= PR_PTRACE;
10087c478bd9Sstevel@tonic-gate 	if (p->p_flag & SMSACCT)
10097c478bd9Sstevel@tonic-gate 		flags |= PR_MSACCT;
10107c478bd9Sstevel@tonic-gate 	if (p->p_flag & SMSFORK)
10117c478bd9Sstevel@tonic-gate 		flags |= PR_MSFORK;
10127c478bd9Sstevel@tonic-gate 	if (p->p_flag & SVFWAIT)
10137c478bd9Sstevel@tonic-gate 		flags |= PR_VFORKP;
10147c478bd9Sstevel@tonic-gate 	sp->pr_flags = flags;
10157c478bd9Sstevel@tonic-gate 	if (VSTOPPED(t)) {
10167c478bd9Sstevel@tonic-gate 		sp->pr_why   = PR_REQUESTED;
10177c478bd9Sstevel@tonic-gate 		sp->pr_what  = 0;
10187c478bd9Sstevel@tonic-gate 	} else {
10197c478bd9Sstevel@tonic-gate 		sp->pr_why   = t->t_whystop;
10207c478bd9Sstevel@tonic-gate 		sp->pr_what  = t->t_whatstop;
10217c478bd9Sstevel@tonic-gate 	}
10227c478bd9Sstevel@tonic-gate 	sp->pr_lwpid = t->t_tid;
10237c478bd9Sstevel@tonic-gate 	sp->pr_cursig  = lwp->lwp_cursig;
10247c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_lwppend, &t->t_sig);
102572a6dc12SPatrick Mooney 	prgethold(t, &sp->pr_lwphold);
10267c478bd9Sstevel@tonic-gate 	if (t->t_whystop == PR_FAULTED) {
10277c478bd9Sstevel@tonic-gate 		siginfo_kto32(&lwp->lwp_siginfo, &sp->pr_info);
10287c478bd9Sstevel@tonic-gate 		if (t->t_whatstop == FLTPAGE)
10297c478bd9Sstevel@tonic-gate 			sp->pr_info.si_addr =
10307c478bd9Sstevel@tonic-gate 			    (caddr32_t)(uintptr_t)lwp->lwp_siginfo.si_addr;
10317c478bd9Sstevel@tonic-gate 	} else if (lwp->lwp_curinfo)
10327c478bd9Sstevel@tonic-gate 		siginfo_kto32(&lwp->lwp_curinfo->sq_info, &sp->pr_info);
10337c478bd9Sstevel@tonic-gate 	if (SI_FROMUSER(&lwp->lwp_siginfo) && zp->zone_id != GLOBAL_ZONEID &&
10347c478bd9Sstevel@tonic-gate 	    sp->pr_info.si_zoneid != zp->zone_id) {
10357c478bd9Sstevel@tonic-gate 		sp->pr_info.si_pid = zp->zone_zsched->p_pid;
10367c478bd9Sstevel@tonic-gate 		sp->pr_info.si_uid = 0;
10377c478bd9Sstevel@tonic-gate 		sp->pr_info.si_ctid = -1;
10387c478bd9Sstevel@tonic-gate 		sp->pr_info.si_zoneid = zp->zone_id;
10397c478bd9Sstevel@tonic-gate 	}
10407c478bd9Sstevel@tonic-gate 	sp->pr_altstack.ss_sp =
10417c478bd9Sstevel@tonic-gate 	    (caddr32_t)(uintptr_t)lwp->lwp_sigaltstack.ss_sp;
10427c478bd9Sstevel@tonic-gate 	sp->pr_altstack.ss_size = (size32_t)lwp->lwp_sigaltstack.ss_size;
10437c478bd9Sstevel@tonic-gate 	sp->pr_altstack.ss_flags = (int32_t)lwp->lwp_sigaltstack.ss_flags;
10447c478bd9Sstevel@tonic-gate 	prgetaction32(p, PTOU(p), lwp->lwp_cursig, &sp->pr_action);
10457c478bd9Sstevel@tonic-gate 	sp->pr_oldcontext = (caddr32_t)lwp->lwp_oldcontext;
10467c478bd9Sstevel@tonic-gate 	sp->pr_ustack = (caddr32_t)lwp->lwp_ustack;
10477c478bd9Sstevel@tonic-gate 	(void) strncpy(sp->pr_clname, sclass[t->t_cid].cl_name,
10487c478bd9Sstevel@tonic-gate 	    sizeof (sp->pr_clname) - 1);
10497c478bd9Sstevel@tonic-gate 	if (flags & PR_STOPPED)
10507c478bd9Sstevel@tonic-gate 		hrt2ts32(t->t_stoptime, &sp->pr_tstamp);
10517c478bd9Sstevel@tonic-gate 	usr = ms->ms_acct[LMS_USER];
10527c478bd9Sstevel@tonic-gate 	sys = ms->ms_acct[LMS_SYSTEM] + ms->ms_acct[LMS_TRAP];
10537c478bd9Sstevel@tonic-gate 	scalehrtime(&usr);
10547c478bd9Sstevel@tonic-gate 	scalehrtime(&sys);
10557c478bd9Sstevel@tonic-gate 	hrt2ts32(usr, &sp->pr_utime);
10567c478bd9Sstevel@tonic-gate 	hrt2ts32(sys, &sp->pr_stime);
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 	/*
10597c478bd9Sstevel@tonic-gate 	 * Fetch the current instruction, if not a system process.
10607c478bd9Sstevel@tonic-gate 	 * We don't attempt this unless the lwp is stopped.
10617c478bd9Sstevel@tonic-gate 	 */
10627c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
10637c478bd9Sstevel@tonic-gate 		sp->pr_flags |= (PR_ISSYS|PR_PCINVAL);
10647c478bd9Sstevel@tonic-gate 	else if (!(flags & PR_STOPPED))
10657c478bd9Sstevel@tonic-gate 		sp->pr_flags |= PR_PCINVAL;
10667c478bd9Sstevel@tonic-gate 	else if (!prfetchinstr(lwp, &instr))
10677c478bd9Sstevel@tonic-gate 		sp->pr_flags |= PR_PCINVAL;
10687c478bd9Sstevel@tonic-gate 	else
10697c478bd9Sstevel@tonic-gate 		sp->pr_instr = (uint32_t)instr;
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	/*
10727c478bd9Sstevel@tonic-gate 	 * Drop p_lock while touching the lwp's stack.
10737c478bd9Sstevel@tonic-gate 	 */
10747c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
10757c478bd9Sstevel@tonic-gate 	if (prisstep(lwp))
10767c478bd9Sstevel@tonic-gate 		sp->pr_flags |= PR_STEP;
10777c478bd9Sstevel@tonic-gate 	if ((flags & (PR_STOPPED|PR_ASLEEP)) && t->t_sysnum) {
10787c478bd9Sstevel@tonic-gate 		int i;
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 		sp->pr_syscall = get_syscall32_args(lwp,
10817c478bd9Sstevel@tonic-gate 		    (int *)sp->pr_sysarg, &i);
10827c478bd9Sstevel@tonic-gate 		sp->pr_nsysarg = (ushort_t)i;
10837c478bd9Sstevel@tonic-gate 	}
10847c478bd9Sstevel@tonic-gate 	if ((flags & PR_STOPPED) || t == curthread)
10857c478bd9Sstevel@tonic-gate 		prgetprregs32(lwp, sp->pr_reg);
10867c478bd9Sstevel@tonic-gate 	if ((t->t_state == TS_STOPPED && t->t_whystop == PR_SYSEXIT) ||
10877c478bd9Sstevel@tonic-gate 	    (flags & PR_VFORKP)) {
10887c478bd9Sstevel@tonic-gate 		long r1, r2;
10897c478bd9Sstevel@tonic-gate 		user_t *up;
10907c478bd9Sstevel@tonic-gate 		auxv_t *auxp;
10917c478bd9Sstevel@tonic-gate 		int i;
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate 		sp->pr_errno = prgetrvals(lwp, &r1, &r2);
10947c478bd9Sstevel@tonic-gate 		if (sp->pr_errno == 0) {
10957c478bd9Sstevel@tonic-gate 			sp->pr_rval1 = (int32_t)r1;
10967c478bd9Sstevel@tonic-gate 			sp->pr_rval2 = (int32_t)r2;
10977c478bd9Sstevel@tonic-gate 			sp->pr_errpriv = PRIV_NONE;
10987c478bd9Sstevel@tonic-gate 		} else
10997c478bd9Sstevel@tonic-gate 			sp->pr_errpriv = lwp->lwp_badpriv;
11007c478bd9Sstevel@tonic-gate 
11018fd04b83SRoger A. Faulkner 		if (t->t_sysnum == SYS_execve) {
11027c478bd9Sstevel@tonic-gate 			up = PTOU(p);
11037c478bd9Sstevel@tonic-gate 			sp->pr_sysarg[0] = 0;
11047c478bd9Sstevel@tonic-gate 			sp->pr_sysarg[1] = (caddr32_t)up->u_argv;
11057c478bd9Sstevel@tonic-gate 			sp->pr_sysarg[2] = (caddr32_t)up->u_envp;
1106*2b395c3cSAndy Fiddaman 			sp->pr_sysarg[3] = 0;
11077c478bd9Sstevel@tonic-gate 			for (i = 0, auxp = up->u_auxv;
11087c478bd9Sstevel@tonic-gate 			    i < sizeof (up->u_auxv) / sizeof (up->u_auxv[0]);
11097c478bd9Sstevel@tonic-gate 			    i++, auxp++) {
11107c478bd9Sstevel@tonic-gate 				if (auxp->a_type == AT_SUN_EXECNAME) {
11117c478bd9Sstevel@tonic-gate 					sp->pr_sysarg[0] =
111225b463cdSethindra 					    (caddr32_t)
111325b463cdSethindra 					    (uintptr_t)auxp->a_un.a_ptr;
11147c478bd9Sstevel@tonic-gate 					break;
11157c478bd9Sstevel@tonic-gate 				}
11167c478bd9Sstevel@tonic-gate 			}
11177c478bd9Sstevel@tonic-gate 		}
11187c478bd9Sstevel@tonic-gate 	}
11197c478bd9Sstevel@tonic-gate 	if (prhasfp())
11207c478bd9Sstevel@tonic-gate 		prgetprfpregs32(lwp, &sp->pr_fpreg);
11217c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
11227c478bd9Sstevel@tonic-gate }
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate void
prgetstatus32(proc_t * p,pstatus32_t * sp,zone_t * zp)11257c478bd9Sstevel@tonic-gate prgetstatus32(proc_t *p, pstatus32_t *sp, zone_t *zp)
11267c478bd9Sstevel@tonic-gate {
11277c478bd9Sstevel@tonic-gate 	kthread_t *t;
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 	t = prchoose(p);	/* returns locked thread */
11327c478bd9Sstevel@tonic-gate 	ASSERT(t != NULL);
11337c478bd9Sstevel@tonic-gate 	thread_unlock(t);
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate 	/* just bzero the process part, prgetlwpstatus32() does the rest */
11367c478bd9Sstevel@tonic-gate 	bzero(sp, sizeof (pstatus32_t) - sizeof (lwpstatus32_t));
11377c478bd9Sstevel@tonic-gate 	sp->pr_nlwp = p->p_lwpcnt;
11387c478bd9Sstevel@tonic-gate 	sp->pr_nzomb = p->p_zombcnt;
11397c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_sigpend, &p->p_sig);
11407c478bd9Sstevel@tonic-gate 	sp->pr_brkbase = (uint32_t)(uintptr_t)p->p_brkbase;
11417c478bd9Sstevel@tonic-gate 	sp->pr_brksize = (uint32_t)p->p_brksize;
11427c478bd9Sstevel@tonic-gate 	sp->pr_stkbase = (uint32_t)(uintptr_t)prgetstackbase(p);
11437c478bd9Sstevel@tonic-gate 	sp->pr_stksize = (uint32_t)p->p_stksize;
11447c478bd9Sstevel@tonic-gate 	sp->pr_pid   = p->p_pid;
11457c478bd9Sstevel@tonic-gate 	if (curproc->p_zone->zone_id != GLOBAL_ZONEID &&
11467c478bd9Sstevel@tonic-gate 	    (p->p_flag & SZONETOP)) {
11477c478bd9Sstevel@tonic-gate 		ASSERT(p->p_zone->zone_id != GLOBAL_ZONEID);
11487c478bd9Sstevel@tonic-gate 		/*
11497c478bd9Sstevel@tonic-gate 		 * Inside local zones, fake zsched's pid as parent pids for
11507c478bd9Sstevel@tonic-gate 		 * processes which reference processes outside of the zone.
11517c478bd9Sstevel@tonic-gate 		 */
11527c478bd9Sstevel@tonic-gate 		sp->pr_ppid = curproc->p_zone->zone_zsched->p_pid;
11537c478bd9Sstevel@tonic-gate 	} else {
11547c478bd9Sstevel@tonic-gate 		sp->pr_ppid = p->p_ppid;
11557c478bd9Sstevel@tonic-gate 	}
11567c478bd9Sstevel@tonic-gate 	sp->pr_pgid  = p->p_pgrp;
11577c478bd9Sstevel@tonic-gate 	sp->pr_sid   = p->p_sessp->s_sid;
11587c478bd9Sstevel@tonic-gate 	sp->pr_taskid = p->p_task->tk_tkid;
11597c478bd9Sstevel@tonic-gate 	sp->pr_projid = p->p_task->tk_proj->kpj_id;
11607c478bd9Sstevel@tonic-gate 	sp->pr_zoneid = p->p_zone->zone_id;
11617c478bd9Sstevel@tonic-gate 	hrt2ts32(mstate_aggr_state(p, LMS_USER), &sp->pr_utime);
11627c478bd9Sstevel@tonic-gate 	hrt2ts32(mstate_aggr_state(p, LMS_SYSTEM), &sp->pr_stime);
11637c478bd9Sstevel@tonic-gate 	TICK_TO_TIMESTRUC32(p->p_cutime, &sp->pr_cutime);
11647c478bd9Sstevel@tonic-gate 	TICK_TO_TIMESTRUC32(p->p_cstime, &sp->pr_cstime);
11657c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_sigtrace, &p->p_sigmask);
11667c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_flttrace, &p->p_fltmask);
11677c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_sysentry, &PTOU(p)->u_entrymask);
11687c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_sysexit, &PTOU(p)->u_exitmask);
11697c478bd9Sstevel@tonic-gate 	switch (p->p_model) {
11707c478bd9Sstevel@tonic-gate 	case DATAMODEL_ILP32:
11717c478bd9Sstevel@tonic-gate 		sp->pr_dmodel = PR_MODEL_ILP32;
11727c478bd9Sstevel@tonic-gate 		break;
11737c478bd9Sstevel@tonic-gate 	case DATAMODEL_LP64:
11747c478bd9Sstevel@tonic-gate 		sp->pr_dmodel = PR_MODEL_LP64;
11757c478bd9Sstevel@tonic-gate 		break;
11767c478bd9Sstevel@tonic-gate 	}
11777c478bd9Sstevel@tonic-gate 	if (p->p_agenttp)
11787c478bd9Sstevel@tonic-gate 		sp->pr_agentid = p->p_agenttp->t_tid;
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 	/* get the chosen lwp's status */
11817c478bd9Sstevel@tonic-gate 	prgetlwpstatus32(t, &sp->pr_lwp, zp);
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	/* replicate the flags */
11847c478bd9Sstevel@tonic-gate 	sp->pr_flags = sp->pr_lwp.pr_flags;
11857c478bd9Sstevel@tonic-gate }
11867c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate /*
11897c478bd9Sstevel@tonic-gate  * Return lwp status.
11907c478bd9Sstevel@tonic-gate  */
11917c478bd9Sstevel@tonic-gate void
prgetlwpstatus(kthread_t * t,lwpstatus_t * sp,zone_t * zp)11927c478bd9Sstevel@tonic-gate prgetlwpstatus(kthread_t *t, lwpstatus_t *sp, zone_t *zp)
11937c478bd9Sstevel@tonic-gate {
11947c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(t);
11957c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
11967c478bd9Sstevel@tonic-gate 	struct mstate *ms = &lwp->lwp_mstate;
11977c478bd9Sstevel@tonic-gate 	hrtime_t usr, sys;
11987c478bd9Sstevel@tonic-gate 	int flags;
11997c478bd9Sstevel@tonic-gate 	ulong_t instr;
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 	bzero(sp, sizeof (*sp));
12047c478bd9Sstevel@tonic-gate 	flags = 0L;
12057c478bd9Sstevel@tonic-gate 	if (t->t_state == TS_STOPPED) {
12067c478bd9Sstevel@tonic-gate 		flags |= PR_STOPPED;
12077c478bd9Sstevel@tonic-gate 		if ((t->t_schedflag & TS_PSTART) == 0)
12087c478bd9Sstevel@tonic-gate 			flags |= PR_ISTOP;
12097c478bd9Sstevel@tonic-gate 	} else if (VSTOPPED(t)) {
12107c478bd9Sstevel@tonic-gate 		flags |= PR_STOPPED|PR_ISTOP;
12117c478bd9Sstevel@tonic-gate 	}
12127c478bd9Sstevel@tonic-gate 	if (!(flags & PR_ISTOP) && (t->t_proc_flag & TP_PRSTOP))
12137c478bd9Sstevel@tonic-gate 		flags |= PR_DSTOP;
12147c478bd9Sstevel@tonic-gate 	if (lwp->lwp_asleep)
12157c478bd9Sstevel@tonic-gate 		flags |= PR_ASLEEP;
12167c478bd9Sstevel@tonic-gate 	if (t == p->p_agenttp)
12177c478bd9Sstevel@tonic-gate 		flags |= PR_AGENT;
12187c478bd9Sstevel@tonic-gate 	if (!(t->t_proc_flag & TP_TWAIT))
12197c478bd9Sstevel@tonic-gate 		flags |= PR_DETACH;
12207c478bd9Sstevel@tonic-gate 	if (t->t_proc_flag & TP_DAEMON)
12217c478bd9Sstevel@tonic-gate 		flags |= PR_DAEMON;
12227c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_FORK)
12237c478bd9Sstevel@tonic-gate 		flags |= PR_FORK;
12247c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_RUNLCL)
12257c478bd9Sstevel@tonic-gate 		flags |= PR_RLC;
12267c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_KILLCL)
12277c478bd9Sstevel@tonic-gate 		flags |= PR_KLC;
12287c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_ASYNC)
12297c478bd9Sstevel@tonic-gate 		flags |= PR_ASYNC;
12307c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_BPTADJ)
12317c478bd9Sstevel@tonic-gate 		flags |= PR_BPTADJ;
12327c478bd9Sstevel@tonic-gate 	if (p->p_proc_flag & P_PR_PTRACE)
12337c478bd9Sstevel@tonic-gate 		flags |= PR_PTRACE;
12347c478bd9Sstevel@tonic-gate 	if (p->p_flag & SMSACCT)
12357c478bd9Sstevel@tonic-gate 		flags |= PR_MSACCT;
12367c478bd9Sstevel@tonic-gate 	if (p->p_flag & SMSFORK)
12377c478bd9Sstevel@tonic-gate 		flags |= PR_MSFORK;
12387c478bd9Sstevel@tonic-gate 	if (p->p_flag & SVFWAIT)
12397c478bd9Sstevel@tonic-gate 		flags |= PR_VFORKP;
12407c478bd9Sstevel@tonic-gate 	if (p->p_pgidp->pid_pgorphaned)
12417c478bd9Sstevel@tonic-gate 		flags |= PR_ORPHAN;
1242657b1f3dSraf 	if (p->p_pidflag & CLDNOSIGCHLD)
1243657b1f3dSraf 		flags |= PR_NOSIGCHLD;
1244657b1f3dSraf 	if (p->p_pidflag & CLDWAITPID)
1245657b1f3dSraf 		flags |= PR_WAITPID;
12467c478bd9Sstevel@tonic-gate 	sp->pr_flags = flags;
12477c478bd9Sstevel@tonic-gate 	if (VSTOPPED(t)) {
12487c478bd9Sstevel@tonic-gate 		sp->pr_why   = PR_REQUESTED;
12497c478bd9Sstevel@tonic-gate 		sp->pr_what  = 0;
12507c478bd9Sstevel@tonic-gate 	} else {
12517c478bd9Sstevel@tonic-gate 		sp->pr_why   = t->t_whystop;
12527c478bd9Sstevel@tonic-gate 		sp->pr_what  = t->t_whatstop;
12537c478bd9Sstevel@tonic-gate 	}
12547c478bd9Sstevel@tonic-gate 	sp->pr_lwpid = t->t_tid;
12557c478bd9Sstevel@tonic-gate 	sp->pr_cursig  = lwp->lwp_cursig;
12567c478bd9Sstevel@tonic-gate 	prassignset(&sp->pr_lwppend, &t->t_sig);
125772a6dc12SPatrick Mooney 	prgethold(t, &sp->pr_lwphold);
12587c478bd9Sstevel@tonic-gate 	if (t->t_whystop == PR_FAULTED)
12597c478bd9Sstevel@tonic-gate 		bcopy(&lwp->lwp_siginfo,
12607c478bd9Sstevel@tonic-gate 		    &sp->pr_info, sizeof (k_siginfo_t));
12617c478bd9Sstevel@tonic-gate 	else if (lwp->lwp_curinfo)
12627c478bd9Sstevel@tonic-gate 		bcopy(&lwp->lwp_curinfo->sq_info,
12637c478bd9Sstevel@tonic-gate 		    &sp->pr_info, sizeof (k_siginfo_t));
12647c478bd9Sstevel@tonic-gate 	if (SI_FROMUSER(&lwp->lwp_siginfo) && zp->zone_id != GLOBAL_ZONEID &&
12657c478bd9Sstevel@tonic-gate 	    sp->pr_info.si_zoneid != zp->zone_id) {
12667c478bd9Sstevel@tonic-gate 		sp->pr_info.si_pid = zp->zone_zsched->p_pid;
12677c478bd9Sstevel@tonic-gate 		sp->pr_info.si_uid = 0;
12687c478bd9Sstevel@tonic-gate 		sp->pr_info.si_ctid = -1;
12697c478bd9Sstevel@tonic-gate 		sp->pr_info.si_zoneid = zp->zone_id;
12707c478bd9Sstevel@tonic-gate 	}
12717c478bd9Sstevel@tonic-gate 	sp->pr_altstack = lwp->lwp_sigaltstack;
12727c478bd9Sstevel@tonic-gate 	prgetaction(p, PTOU(p), lwp->lwp_cursig, &sp->pr_action);
12737c478bd9Sstevel@tonic-gate 	sp->pr_oldcontext = (uintptr_t)lwp->lwp_oldcontext;
12747c478bd9Sstevel@tonic-gate 	sp->pr_ustack = lwp->lwp_ustack;
12757c478bd9Sstevel@tonic-gate 	(void) strncpy(sp->pr_clname, sclass[t->t_cid].cl_name,
12767c478bd9Sstevel@tonic-gate 	    sizeof (sp->pr_clname) - 1);
12777c478bd9Sstevel@tonic-gate 	if (flags & PR_STOPPED)
12787c478bd9Sstevel@tonic-gate 		hrt2ts(t->t_stoptime, &sp->pr_tstamp);
12797c478bd9Sstevel@tonic-gate 	usr = ms->ms_acct[LMS_USER];
12807c478bd9Sstevel@tonic-gate 	sys = ms->ms_acct[LMS_SYSTEM] + ms->ms_acct[LMS_TRAP];
12817c478bd9Sstevel@tonic-gate 	scalehrtime(&usr);
12827c478bd9Sstevel@tonic-gate 	scalehrtime(&sys);
12837c478bd9Sstevel@tonic-gate 	hrt2ts(usr, &sp->pr_utime);
12847c478bd9Sstevel@tonic-gate 	hrt2ts(sys, &sp->pr_stime);
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 	/*
12877c478bd9Sstevel@tonic-gate 	 * Fetch the current instruction, if not a system process.
12887c478bd9Sstevel@tonic-gate 	 * We don't attempt this unless the lwp is stopped.
12897c478bd9Sstevel@tonic-gate 	 */
12907c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
12917c478bd9Sstevel@tonic-gate 		sp->pr_flags |= (PR_ISSYS|PR_PCINVAL);
12927c478bd9Sstevel@tonic-gate 	else if (!(flags & PR_STOPPED))
12937c478bd9Sstevel@tonic-gate 		sp->pr_flags |= PR_PCINVAL;
12947c478bd9Sstevel@tonic-gate 	else if (!prfetchinstr(lwp, &instr))
12957c478bd9Sstevel@tonic-gate 		sp->pr_flags |= PR_PCINVAL;
12967c478bd9Sstevel@tonic-gate 	else
12977c478bd9Sstevel@tonic-gate 		sp->pr_instr = instr;
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 	/*
13007c478bd9Sstevel@tonic-gate 	 * Drop p_lock while touching the lwp's stack.
13017c478bd9Sstevel@tonic-gate 	 */
13027c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
13037c478bd9Sstevel@tonic-gate 	if (prisstep(lwp))
13047c478bd9Sstevel@tonic-gate 		sp->pr_flags |= PR_STEP;
13057c478bd9Sstevel@tonic-gate 	if ((flags & (PR_STOPPED|PR_ASLEEP)) && t->t_sysnum) {
13067c478bd9Sstevel@tonic-gate 		int i;
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 		sp->pr_syscall = get_syscall_args(lwp,
13097c478bd9Sstevel@tonic-gate 		    (long *)sp->pr_sysarg, &i);
13107c478bd9Sstevel@tonic-gate 		sp->pr_nsysarg = (ushort_t)i;
13117c478bd9Sstevel@tonic-gate 	}
13127c478bd9Sstevel@tonic-gate 	if ((flags & PR_STOPPED) || t == curthread)
13137c478bd9Sstevel@tonic-gate 		prgetprregs(lwp, sp->pr_reg);
13147c478bd9Sstevel@tonic-gate 	if ((t->t_state == TS_STOPPED && t->t_whystop == PR_SYSEXIT) ||
13157c478bd9Sstevel@tonic-gate 	    (flags & PR_VFORKP)) {
13167c478bd9Sstevel@tonic-gate 		user_t *up;
13177c478bd9Sstevel@tonic-gate 		auxv_t *auxp;
13187c478bd9Sstevel@tonic-gate 		int i;
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate 		sp->pr_errno = prgetrvals(lwp, &sp->pr_rval1, &sp->pr_rval2);
13217c478bd9Sstevel@tonic-gate 		if (sp->pr_errno == 0)
13227c478bd9Sstevel@tonic-gate 			sp->pr_errpriv = PRIV_NONE;
13237c478bd9Sstevel@tonic-gate 		else
13247c478bd9Sstevel@tonic-gate 			sp->pr_errpriv = lwp->lwp_badpriv;
13257c478bd9Sstevel@tonic-gate 
13268fd04b83SRoger A. Faulkner 		if (t->t_sysnum == SYS_execve) {
13277c478bd9Sstevel@tonic-gate 			up = PTOU(p);
13287c478bd9Sstevel@tonic-gate 			sp->pr_sysarg[0] = 0;
13297c478bd9Sstevel@tonic-gate 			sp->pr_sysarg[1] = (uintptr_t)up->u_argv;
13307c478bd9Sstevel@tonic-gate 			sp->pr_sysarg[2] = (uintptr_t)up->u_envp;
1331*2b395c3cSAndy Fiddaman 			sp->pr_sysarg[3] = 0;
13327c478bd9Sstevel@tonic-gate 			for (i = 0, auxp = up->u_auxv;
13337c478bd9Sstevel@tonic-gate 			    i < sizeof (up->u_auxv) / sizeof (up->u_auxv[0]);
13347c478bd9Sstevel@tonic-gate 			    i++, auxp++) {
13357c478bd9Sstevel@tonic-gate 				if (auxp->a_type == AT_SUN_EXECNAME) {
13367c478bd9Sstevel@tonic-gate 					sp->pr_sysarg[0] =
13377c478bd9Sstevel@tonic-gate 					    (uintptr_t)auxp->a_un.a_ptr;
13387c478bd9Sstevel@tonic-gate 					break;
13397c478bd9Sstevel@tonic-gate 				}
13407c478bd9Sstevel@tonic-gate 			}
13417c478bd9Sstevel@tonic-gate 		}
13427c478bd9Sstevel@tonic-gate 	}
13437c478bd9Sstevel@tonic-gate 	if (prhasfp())
13447c478bd9Sstevel@tonic-gate 		prgetprfpregs(lwp, &sp->pr_fpreg);
13457c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
13467c478bd9Sstevel@tonic-gate }
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate /*
13497c478bd9Sstevel@tonic-gate  * Get the sigaction structure for the specified signal.  The u-block
13507c478bd9Sstevel@tonic-gate  * must already have been mapped in by the caller.
13517c478bd9Sstevel@tonic-gate  */
13527c478bd9Sstevel@tonic-gate void
prgetaction(proc_t * p,user_t * up,uint_t sig,struct sigaction * sp)13537c478bd9Sstevel@tonic-gate prgetaction(proc_t *p, user_t *up, uint_t sig, struct sigaction *sp)
13547c478bd9Sstevel@tonic-gate {
1355eb9dbf0cSRoger A. Faulkner 	int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
1356eb9dbf0cSRoger A. Faulkner 
13577c478bd9Sstevel@tonic-gate 	bzero(sp, sizeof (*sp));
13587c478bd9Sstevel@tonic-gate 
1359eb9dbf0cSRoger A. Faulkner 	if (sig != 0 && (unsigned)sig < nsig) {
13607c478bd9Sstevel@tonic-gate 		sp->sa_handler = up->u_signal[sig-1];
13617c478bd9Sstevel@tonic-gate 		prassignset(&sp->sa_mask, &up->u_sigmask[sig-1]);
13627c478bd9Sstevel@tonic-gate 		if (sigismember(&up->u_sigonstack, sig))
13637c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_ONSTACK;
13647c478bd9Sstevel@tonic-gate 		if (sigismember(&up->u_sigresethand, sig))
13657c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_RESETHAND;
13667c478bd9Sstevel@tonic-gate 		if (sigismember(&up->u_sigrestart, sig))
13677c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_RESTART;
13687c478bd9Sstevel@tonic-gate 		if (sigismember(&p->p_siginfo, sig))
13697c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_SIGINFO;
13707c478bd9Sstevel@tonic-gate 		if (sigismember(&up->u_signodefer, sig))
13717c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_NODEFER;
13727c478bd9Sstevel@tonic-gate 		if (sig == SIGCLD) {
13737c478bd9Sstevel@tonic-gate 			if (p->p_flag & SNOWAIT)
13747c478bd9Sstevel@tonic-gate 				sp->sa_flags |= SA_NOCLDWAIT;
13757c478bd9Sstevel@tonic-gate 			if ((p->p_flag & SJCTL) == 0)
13767c478bd9Sstevel@tonic-gate 				sp->sa_flags |= SA_NOCLDSTOP;
13777c478bd9Sstevel@tonic-gate 		}
13787c478bd9Sstevel@tonic-gate 	}
13797c478bd9Sstevel@tonic-gate }
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
13827c478bd9Sstevel@tonic-gate void
prgetaction32(proc_t * p,user_t * up,uint_t sig,struct sigaction32 * sp)13837c478bd9Sstevel@tonic-gate prgetaction32(proc_t *p, user_t *up, uint_t sig, struct sigaction32 *sp)
13847c478bd9Sstevel@tonic-gate {
1385eb9dbf0cSRoger A. Faulkner 	int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
1386eb9dbf0cSRoger A. Faulkner 
13877c478bd9Sstevel@tonic-gate 	bzero(sp, sizeof (*sp));
13887c478bd9Sstevel@tonic-gate 
1389eb9dbf0cSRoger A. Faulkner 	if (sig != 0 && (unsigned)sig < nsig) {
13907c478bd9Sstevel@tonic-gate 		sp->sa_handler = (caddr32_t)(uintptr_t)up->u_signal[sig-1];
13917c478bd9Sstevel@tonic-gate 		prassignset(&sp->sa_mask, &up->u_sigmask[sig-1]);
13927c478bd9Sstevel@tonic-gate 		if (sigismember(&up->u_sigonstack, sig))
13937c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_ONSTACK;
13947c478bd9Sstevel@tonic-gate 		if (sigismember(&up->u_sigresethand, sig))
13957c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_RESETHAND;
13967c478bd9Sstevel@tonic-gate 		if (sigismember(&up->u_sigrestart, sig))
13977c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_RESTART;
13987c478bd9Sstevel@tonic-gate 		if (sigismember(&p->p_siginfo, sig))
13997c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_SIGINFO;
14007c478bd9Sstevel@tonic-gate 		if (sigismember(&up->u_signodefer, sig))
14017c478bd9Sstevel@tonic-gate 			sp->sa_flags |= SA_NODEFER;
14027c478bd9Sstevel@tonic-gate 		if (sig == SIGCLD) {
14037c478bd9Sstevel@tonic-gate 			if (p->p_flag & SNOWAIT)
14047c478bd9Sstevel@tonic-gate 				sp->sa_flags |= SA_NOCLDWAIT;
14057c478bd9Sstevel@tonic-gate 			if ((p->p_flag & SJCTL) == 0)
14067c478bd9Sstevel@tonic-gate 				sp->sa_flags |= SA_NOCLDSTOP;
14077c478bd9Sstevel@tonic-gate 		}
14087c478bd9Sstevel@tonic-gate 	}
14097c478bd9Sstevel@tonic-gate }
14107c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
14117c478bd9Sstevel@tonic-gate 
14127c478bd9Sstevel@tonic-gate /*
14137c478bd9Sstevel@tonic-gate  * Count the number of segments in this process's address space.
14147c478bd9Sstevel@tonic-gate  */
14154e18e297SPatrick Mooney uint_t
prnsegs(struct as * as,int reserved)14167c478bd9Sstevel@tonic-gate prnsegs(struct as *as, int reserved)
14177c478bd9Sstevel@tonic-gate {
14184e18e297SPatrick Mooney 	uint_t n = 0;
14197c478bd9Sstevel@tonic-gate 	struct seg *seg;
14207c478bd9Sstevel@tonic-gate 
1421dc32d872SJosef 'Jeff' Sipek 	ASSERT(as != &kas && AS_WRITE_HELD(as));
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 	for (seg = AS_SEGFIRST(as); seg != NULL; seg = AS_SEGNEXT(as, seg)) {
14247c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, reserved);
14257c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr;
14267c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
14277c478bd9Sstevel@tonic-gate 
1428284ce987SPatrick Mooney 		if ((seg->s_flags & S_HOLE) != 0) {
1429284ce987SPatrick Mooney 			continue;
1430284ce987SPatrick Mooney 		}
1431284ce987SPatrick Mooney 
14327c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
14337c478bd9Sstevel@tonic-gate 			(void) pr_getprot(seg, reserved, &tmp,
14347c478bd9Sstevel@tonic-gate 			    &saddr, &naddr, eaddr);
14354e18e297SPatrick Mooney 			if (saddr != naddr) {
14367c478bd9Sstevel@tonic-gate 				n++;
14374e18e297SPatrick Mooney 				/*
14384e18e297SPatrick Mooney 				 * prnsegs() was formerly designated to return
14394e18e297SPatrick Mooney 				 * an 'int' despite having no ability or use
14404e18e297SPatrick Mooney 				 * for negative results.  As part of changing
14414e18e297SPatrick Mooney 				 * it to 'uint_t', keep the old effective limit
14424e18e297SPatrick Mooney 				 * of INT_MAX in place.
14434e18e297SPatrick Mooney 				 */
14444e18e297SPatrick Mooney 				if (n == INT_MAX) {
14454e18e297SPatrick Mooney 					pr_getprot_done(&tmp);
14464e18e297SPatrick Mooney 					ASSERT(tmp == NULL);
14474e18e297SPatrick Mooney 					return (n);
14484e18e297SPatrick Mooney 				}
14494e18e297SPatrick Mooney 			}
14507c478bd9Sstevel@tonic-gate 		}
14517c478bd9Sstevel@tonic-gate 
14527c478bd9Sstevel@tonic-gate 		ASSERT(tmp == NULL);
14537c478bd9Sstevel@tonic-gate 	}
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate 	return (n);
14567c478bd9Sstevel@tonic-gate }
14577c478bd9Sstevel@tonic-gate 
14587c478bd9Sstevel@tonic-gate /*
14597c478bd9Sstevel@tonic-gate  * Convert uint32_t to decimal string w/o leading zeros.
14607c478bd9Sstevel@tonic-gate  * Add trailing null characters if 'len' is greater than string length.
14617c478bd9Sstevel@tonic-gate  * Return the string length.
14627c478bd9Sstevel@tonic-gate  */
14637c478bd9Sstevel@tonic-gate int
pr_u32tos(uint32_t n,char * s,int len)14647c478bd9Sstevel@tonic-gate pr_u32tos(uint32_t n, char *s, int len)
14657c478bd9Sstevel@tonic-gate {
14667c478bd9Sstevel@tonic-gate 	char cbuf[11];		/* 32-bit unsigned integer fits in 10 digits */
14677c478bd9Sstevel@tonic-gate 	char *cp = cbuf;
14687c478bd9Sstevel@tonic-gate 	char *end = s + len;
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 	do {
14717c478bd9Sstevel@tonic-gate 		*cp++ = (char)(n % 10 + '0');
14727c478bd9Sstevel@tonic-gate 		n /= 10;
14737c478bd9Sstevel@tonic-gate 	} while (n);
14747c478bd9Sstevel@tonic-gate 
14757c478bd9Sstevel@tonic-gate 	len = (int)(cp - cbuf);
14767c478bd9Sstevel@tonic-gate 
14777c478bd9Sstevel@tonic-gate 	do {
14787c478bd9Sstevel@tonic-gate 		*s++ = *--cp;
14797c478bd9Sstevel@tonic-gate 	} while (cp > cbuf);
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 	while (s < end)		/* optional pad */
14827c478bd9Sstevel@tonic-gate 		*s++ = '\0';
14837c478bd9Sstevel@tonic-gate 
14847c478bd9Sstevel@tonic-gate 	return (len);
14857c478bd9Sstevel@tonic-gate }
14867c478bd9Sstevel@tonic-gate 
14877c478bd9Sstevel@tonic-gate /*
14887c478bd9Sstevel@tonic-gate  * Convert uint64_t to decimal string w/o leading zeros.
14897c478bd9Sstevel@tonic-gate  * Return the string length.
14907c478bd9Sstevel@tonic-gate  */
14917c478bd9Sstevel@tonic-gate static int
pr_u64tos(uint64_t n,char * s)14927c478bd9Sstevel@tonic-gate pr_u64tos(uint64_t n, char *s)
14937c478bd9Sstevel@tonic-gate {
14947c478bd9Sstevel@tonic-gate 	char cbuf[21];		/* 64-bit unsigned integer fits in 20 digits */
14957c478bd9Sstevel@tonic-gate 	char *cp = cbuf;
14967c478bd9Sstevel@tonic-gate 	int len;
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 	do {
14997c478bd9Sstevel@tonic-gate 		*cp++ = (char)(n % 10 + '0');
15007c478bd9Sstevel@tonic-gate 		n /= 10;
15017c478bd9Sstevel@tonic-gate 	} while (n);
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate 	len = (int)(cp - cbuf);
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate 	do {
15067c478bd9Sstevel@tonic-gate 		*s++ = *--cp;
15077c478bd9Sstevel@tonic-gate 	} while (cp > cbuf);
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate 	return (len);
15107c478bd9Sstevel@tonic-gate }
15117c478bd9Sstevel@tonic-gate 
1512da29c6a3SDan McDonald /*
1513da29c6a3SDan McDonald  * Similar to getf() / getf_gen(), but for the specified process.  On success,
1514da29c6a3SDan McDonald  * returns the fp with fp->f_count incremented.  The caller MUST call
1515da29c6a3SDan McDonald  * closef(fp) on the returned fp after completing any actions using that fp.
1516da29c6a3SDan McDonald  * We return a reference-held (fp->f_count bumped) file_t so no other closef()
1517da29c6a3SDan McDonald  * can invoke destructive VOP_CLOSE actions while we're inspecting the
1518da29c6a3SDan McDonald  * process's FD.
1519da29c6a3SDan McDonald  *
1520da29c6a3SDan McDonald  * Returns NULL for errors: either an empty process-table slot post-fi_lock
1521da29c6a3SDan McDonald  * and UF_ENTER, or too many mutex_tryenter() failures on the file_t's f_tlock.
1522da29c6a3SDan McDonald  * Both failure modes have DTrace probes.
1523da29c6a3SDan McDonald  *
1524da29c6a3SDan McDonald  * The current design of the procfs "close" code path uses the following lock
1525da29c6a3SDan McDonald  * order of:
1526da29c6a3SDan McDonald  *
1527da29c6a3SDan McDonald  *   1: (file_t) f_tlock
1528da29c6a3SDan McDonald  *   2: (proc_t) p_lock AND setting p->p_proc_flag's P_PR_LOCK
1529da29c6a3SDan McDonald  *
1530da29c6a3SDan McDonald  * That happens because closef() holds f_tlock while calling fop_close(),
1531da29c6a3SDan McDonald  * which can be prclose(), which currently waits on and sets P_PR_LOCK at its
1532da29c6a3SDan McDonald  * beginning.
1533da29c6a3SDan McDonald  *
1534da29c6a3SDan McDonald  * That lock order creates a challenge for pr_getf, which needs to take those
1535da29c6a3SDan McDonald  * locks in the opposite order when the fd points to a procfs file descriptor.
1536da29c6a3SDan McDonald  * The solution chosen here is to use mutex_tryenter on f_tlock and retry some
1537da29c6a3SDan McDonald  * (limited) number of times, failing if we don't get both locks.
1538da29c6a3SDan McDonald  *
1539da29c6a3SDan McDonald  * The cases where this can fail are rare, and all involve a procfs caller
1540da29c6a3SDan McDonald  * asking for info (eg. FDINFO) on another procfs FD.  In these cases,
1541da29c6a3SDan McDonald  * returning EBADF (which results from a NULL return from pr_getf()) is
1542da29c6a3SDan McDonald  * acceptable.
1543da29c6a3SDan McDonald  *
1544da29c6a3SDan McDonald  * One can increase the number of tries in pr_getf_maxtries if one is worried
1545da29c6a3SDan McDonald  * about the contentuous case.
1546da29c6a3SDan McDonald  */
1547da29c6a3SDan McDonald 
1548da29c6a3SDan McDonald uint64_t pr_getf_tryfails; /* Bumped for statistic purposes. */
1549da29c6a3SDan McDonald int pr_getf_maxtries = 3;  /* So you can tune it from /etc/system */
1550da29c6a3SDan McDonald 
1551a02120c4SAndy Fiddaman file_t *
pr_getf(proc_t * p,uint_t fd,short * flag)1552a02120c4SAndy Fiddaman pr_getf(proc_t *p, uint_t fd, short *flag)
1553a02120c4SAndy Fiddaman {
1554a02120c4SAndy Fiddaman 	uf_entry_t *ufp;
1555a02120c4SAndy Fiddaman 	uf_info_t *fip;
1556a02120c4SAndy Fiddaman 	file_t *fp;
1557da29c6a3SDan McDonald 	int tries = 0;
1558a02120c4SAndy Fiddaman 
1559a02120c4SAndy Fiddaman 	ASSERT(MUTEX_HELD(&p->p_lock) && (p->p_proc_flag & P_PR_LOCK));
1560a02120c4SAndy Fiddaman 
1561da29c6a3SDan McDonald retry:
1562a02120c4SAndy Fiddaman 	fip = P_FINFO(p);
1563a02120c4SAndy Fiddaman 
1564a02120c4SAndy Fiddaman 	if (fd >= fip->fi_nfiles)
1565a02120c4SAndy Fiddaman 		return (NULL);
1566a02120c4SAndy Fiddaman 
1567a02120c4SAndy Fiddaman 	mutex_exit(&p->p_lock);
1568a02120c4SAndy Fiddaman 	mutex_enter(&fip->fi_lock);
1569a02120c4SAndy Fiddaman 	UF_ENTER(ufp, fip, fd);
1570a02120c4SAndy Fiddaman 	if ((fp = ufp->uf_file) != NULL && fp->f_count > 0) {
1571da29c6a3SDan McDonald 		if (mutex_tryenter(&fp->f_tlock)) {
1572da29c6a3SDan McDonald 			ASSERT(fp->f_count > 0);
1573da29c6a3SDan McDonald 			fp->f_count++;
1574da29c6a3SDan McDonald 			mutex_exit(&fp->f_tlock);
1575a02120c4SAndy Fiddaman 			if (flag != NULL)
1576a02120c4SAndy Fiddaman 				*flag = ufp->uf_flag;
1577a02120c4SAndy Fiddaman 		} else {
1578da29c6a3SDan McDonald 			/*
1579da29c6a3SDan McDonald 			 * Note the number of mutex_trylock attempts.
1580da29c6a3SDan McDonald 			 *
1581da29c6a3SDan McDonald 			 * The exit path will catch this and try again if we
1582da29c6a3SDan McDonald 			 * are below the retry threshhold (pr_getf_maxtries).
1583da29c6a3SDan McDonald 			 */
1584da29c6a3SDan McDonald 			tries++;
1585da29c6a3SDan McDonald 			pr_getf_tryfails++;
1586da29c6a3SDan McDonald 			/*
1587da29c6a3SDan McDonald 			 * If we hit pr_getf_maxtries, we'll return NULL.
1588da29c6a3SDan McDonald 			 * DTrace scripts looking for this sort of failure
1589da29c6a3SDan McDonald 			 * should check when arg1 is pr_getf_maxtries.
1590da29c6a3SDan McDonald 			 */
1591da29c6a3SDan McDonald 			DTRACE_PROBE2(pr_getf_tryfail, file_t *, fp, int,
1592da29c6a3SDan McDonald 			    tries);
1593a02120c4SAndy Fiddaman 			fp = NULL;
1594a02120c4SAndy Fiddaman 		}
1595da29c6a3SDan McDonald 	} else {
1596da29c6a3SDan McDonald 		fp = NULL;
1597da29c6a3SDan McDonald 		/* If we fail here, someone else closed this FD. */
1598da29c6a3SDan McDonald 		DTRACE_PROBE1(pr_getf_emptyslot, int, tries);
1599da29c6a3SDan McDonald 		tries = pr_getf_maxtries; /* Don't bother retrying. */
1600da29c6a3SDan McDonald 	}
1601a02120c4SAndy Fiddaman 	UF_EXIT(ufp);
1602a02120c4SAndy Fiddaman 	mutex_exit(&fip->fi_lock);
1603a02120c4SAndy Fiddaman 	mutex_enter(&p->p_lock);
1604a02120c4SAndy Fiddaman 
1605da29c6a3SDan McDonald 	/* Use goto instead of tail-recursion so we can keep "tries" around. */
1606da29c6a3SDan McDonald 	if (fp == NULL) {
1607da29c6a3SDan McDonald 		/* "tries" starts at 1. */
1608da29c6a3SDan McDonald 		if (tries < pr_getf_maxtries)
1609da29c6a3SDan McDonald 			goto retry;
1610da29c6a3SDan McDonald 	} else {
1611da29c6a3SDan McDonald 		/*
1612da29c6a3SDan McDonald 		 * Probes here will detect successes after arg1's number of
1613da29c6a3SDan McDonald 		 * mutex_tryenter() calls.
1614da29c6a3SDan McDonald 		 */
1615da29c6a3SDan McDonald 		DTRACE_PROBE2(pr_getf_trysuccess, file_t *, fp, int, tries + 1);
1616a02120c4SAndy Fiddaman 	}
1617a02120c4SAndy Fiddaman 
1618da29c6a3SDan McDonald 	return (fp);
1619a02120c4SAndy Fiddaman }
1620a02120c4SAndy Fiddaman 
162137e2cd25SPatrick Mooney 
162237e2cd25SPatrick Mooney /*
162337e2cd25SPatrick Mooney  * Just as pr_getf() is a little unusual in how it goes about making the file_t
162437e2cd25SPatrick Mooney  * safe for procfs consumers to access it, so too is pr_releasef() for safely
162537e2cd25SPatrick Mooney  * releasing that "hold".  The "hold" is unlike normal file descriptor activity
162637e2cd25SPatrick Mooney  * -- procfs is just an interloper here, wanting access to the vnode_t without
162737e2cd25SPatrick Mooney  * risk of a racing close() disrupting the state.  Just as pr_getf() avoids some
162837e2cd25SPatrick Mooney  * of the typical file_t behavior (such as auditing) when establishing its hold,
162937e2cd25SPatrick Mooney  * so too should pr_releasef().  It should not go through the motions of
163037e2cd25SPatrick Mooney  * closef() (since it is not a true close()) unless racing activity causes it to
163137e2cd25SPatrick Mooney  * be the last actor holding the refcount above zero.
163237e2cd25SPatrick Mooney  *
163337e2cd25SPatrick Mooney  * Under normal circumstances, we expect to find file_t`f_count > 1 after
163437e2cd25SPatrick Mooney  * the successful pr_getf() call.  We are, after all, accessing a resource
163537e2cd25SPatrick Mooney  * already held by the process in question.  We would also expect to rarely race
163637e2cd25SPatrick Mooney  * with a close() of the underlying fd, meaning that file_t`f_count > 1 would
163737e2cd25SPatrick Mooney  * still holds at pr_releasef() time.  That would mean we only need to decrement
163837e2cd25SPatrick Mooney  * f_count, leaving it to the process to later close the fd (thus triggering
163937e2cd25SPatrick Mooney  * VOP_CLOSE(), etc).
164037e2cd25SPatrick Mooney  *
164137e2cd25SPatrick Mooney  * It is only when that process manages to close() the fd while we have it
164237e2cd25SPatrick Mooney  * "held" in procfs that we must make a trip through the traditional closef()
164337e2cd25SPatrick Mooney  * logic to ensure proper tear-down of the file_t.
164437e2cd25SPatrick Mooney  */
164537e2cd25SPatrick Mooney void
pr_releasef(file_t * fp)164637e2cd25SPatrick Mooney pr_releasef(file_t *fp)
164737e2cd25SPatrick Mooney {
164837e2cd25SPatrick Mooney 	mutex_enter(&fp->f_tlock);
164937e2cd25SPatrick Mooney 	if (fp->f_count > 1) {
165037e2cd25SPatrick Mooney 		/*
165137e2cd25SPatrick Mooney 		 * This is the most common case: The file is still held open by
165237e2cd25SPatrick Mooney 		 * the process, and we simply need to release our hold by
165337e2cd25SPatrick Mooney 		 * decrementing f_count
165437e2cd25SPatrick Mooney 		 */
165537e2cd25SPatrick Mooney 		fp->f_count--;
165637e2cd25SPatrick Mooney 		mutex_exit(&fp->f_tlock);
165737e2cd25SPatrick Mooney 	} else {
165837e2cd25SPatrick Mooney 		/*
165937e2cd25SPatrick Mooney 		 * A rare occasion: The process snuck a close() of this file
166037e2cd25SPatrick Mooney 		 * while we were doing our business in procfs.  Given that
166137e2cd25SPatrick Mooney 		 * f_count == 1, we are the only one with a reference to the
166237e2cd25SPatrick Mooney 		 * file_t and need to take a trip through closef() to free it.
166337e2cd25SPatrick Mooney 		 */
166437e2cd25SPatrick Mooney 		mutex_exit(&fp->f_tlock);
166537e2cd25SPatrick Mooney 		(void) closef(fp);
166637e2cd25SPatrick Mooney 	}
166737e2cd25SPatrick Mooney }
166837e2cd25SPatrick Mooney 
16697c478bd9Sstevel@tonic-gate void
pr_object_name(char * name,vnode_t * vp,struct vattr * vattr)16707c478bd9Sstevel@tonic-gate pr_object_name(char *name, vnode_t *vp, struct vattr *vattr)
16717c478bd9Sstevel@tonic-gate {
16727c478bd9Sstevel@tonic-gate 	char *s = name;
16737c478bd9Sstevel@tonic-gate 	struct vfs *vfsp;
16747c478bd9Sstevel@tonic-gate 	struct vfssw *vfsswp;
16757c478bd9Sstevel@tonic-gate 
16767c478bd9Sstevel@tonic-gate 	if ((vfsp = vp->v_vfsp) != NULL &&
16777c478bd9Sstevel@tonic-gate 	    ((vfsswp = vfssw + vfsp->vfs_fstype), vfsswp->vsw_name) &&
16787c478bd9Sstevel@tonic-gate 	    *vfsswp->vsw_name) {
16797c478bd9Sstevel@tonic-gate 		(void) strcpy(s, vfsswp->vsw_name);
16807c478bd9Sstevel@tonic-gate 		s += strlen(s);
16817c478bd9Sstevel@tonic-gate 		*s++ = '.';
16827c478bd9Sstevel@tonic-gate 	}
16837c478bd9Sstevel@tonic-gate 	s += pr_u32tos(getmajor(vattr->va_fsid), s, 0);
16847c478bd9Sstevel@tonic-gate 	*s++ = '.';
16857c478bd9Sstevel@tonic-gate 	s += pr_u32tos(getminor(vattr->va_fsid), s, 0);
16867c478bd9Sstevel@tonic-gate 	*s++ = '.';
16877c478bd9Sstevel@tonic-gate 	s += pr_u64tos(vattr->va_nodeid, s);
16887c478bd9Sstevel@tonic-gate 	*s++ = '\0';
16897c478bd9Sstevel@tonic-gate }
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate struct seg *
break_seg(proc_t * p)16927c478bd9Sstevel@tonic-gate break_seg(proc_t *p)
16937c478bd9Sstevel@tonic-gate {
16947c478bd9Sstevel@tonic-gate 	caddr_t addr = p->p_brkbase;
16957c478bd9Sstevel@tonic-gate 	struct seg *seg;
16967c478bd9Sstevel@tonic-gate 	struct vnode *vp;
16977c478bd9Sstevel@tonic-gate 
16987c478bd9Sstevel@tonic-gate 	if (p->p_brksize != 0)
16997c478bd9Sstevel@tonic-gate 		addr += p->p_brksize - 1;
17007c478bd9Sstevel@tonic-gate 	seg = as_segat(p->p_as, addr);
17017c478bd9Sstevel@tonic-gate 	if (seg != NULL && seg->s_ops == &segvn_ops &&
17027c478bd9Sstevel@tonic-gate 	    (SEGOP_GETVP(seg, seg->s_base, &vp) != 0 || vp == NULL))
17037c478bd9Sstevel@tonic-gate 		return (seg);
17047c478bd9Sstevel@tonic-gate 	return (NULL);
17057c478bd9Sstevel@tonic-gate }
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate /*
1708870619e9Sfrankho  * Implementation of service functions to handle procfs generic chained
1709870619e9Sfrankho  * copyout buffers.
1710870619e9Sfrankho  */
1711870619e9Sfrankho typedef struct pr_iobuf_list {
1712870619e9Sfrankho 	list_node_t	piol_link;	/* buffer linkage */
1713870619e9Sfrankho 	size_t		piol_size;	/* total size (header + data) */
1714870619e9Sfrankho 	size_t		piol_usedsize;	/* amount to copy out from this buf */
1715870619e9Sfrankho } piol_t;
1716870619e9Sfrankho 
1717870619e9Sfrankho #define	MAPSIZE	(64 * 1024)
1718870619e9Sfrankho #define	PIOL_DATABUF(iol)	((void *)(&(iol)[1]))
1719870619e9Sfrankho 
1720870619e9Sfrankho void
pr_iol_initlist(list_t * iolhead,size_t itemsize,int n)1721870619e9Sfrankho pr_iol_initlist(list_t *iolhead, size_t itemsize, int n)
1722870619e9Sfrankho {
1723870619e9Sfrankho 	piol_t	*iol;
1724870619e9Sfrankho 	size_t	initial_size = MIN(1, n) * itemsize;
1725870619e9Sfrankho 
1726870619e9Sfrankho 	list_create(iolhead, sizeof (piol_t), offsetof(piol_t, piol_link));
1727870619e9Sfrankho 
1728870619e9Sfrankho 	ASSERT(list_head(iolhead) == NULL);
1729870619e9Sfrankho 	ASSERT(itemsize < MAPSIZE - sizeof (*iol));
1730870619e9Sfrankho 	ASSERT(initial_size > 0);
1731870619e9Sfrankho 
1732870619e9Sfrankho 	/*
1733870619e9Sfrankho 	 * Someone creating chained copyout buffers may ask for less than
1734870619e9Sfrankho 	 * MAPSIZE if the amount of data to be buffered is known to be
1735870619e9Sfrankho 	 * smaller than that.
1736870619e9Sfrankho 	 * But in order to prevent involuntary self-denial of service,
1737870619e9Sfrankho 	 * the requested input size is clamped at MAPSIZE.
1738870619e9Sfrankho 	 */
1739870619e9Sfrankho 	initial_size = MIN(MAPSIZE, initial_size + sizeof (*iol));
1740870619e9Sfrankho 	iol = kmem_alloc(initial_size, KM_SLEEP);
1741870619e9Sfrankho 	list_insert_head(iolhead, iol);
1742870619e9Sfrankho 	iol->piol_usedsize = 0;
1743870619e9Sfrankho 	iol->piol_size = initial_size;
1744870619e9Sfrankho }
1745870619e9Sfrankho 
1746870619e9Sfrankho void *
pr_iol_newbuf(list_t * iolhead,size_t itemsize)1747870619e9Sfrankho pr_iol_newbuf(list_t *iolhead, size_t itemsize)
1748870619e9Sfrankho {
1749870619e9Sfrankho 	piol_t	*iol;
1750870619e9Sfrankho 	char	*new;
1751870619e9Sfrankho 
1752870619e9Sfrankho 	ASSERT(itemsize < MAPSIZE - sizeof (*iol));
1753870619e9Sfrankho 	ASSERT(list_head(iolhead) != NULL);
1754870619e9Sfrankho 
1755870619e9Sfrankho 	iol = (piol_t *)list_tail(iolhead);
1756870619e9Sfrankho 
1757870619e9Sfrankho 	if (iol->piol_size <
1758870619e9Sfrankho 	    iol->piol_usedsize + sizeof (*iol) + itemsize) {
1759870619e9Sfrankho 		/*
1760870619e9Sfrankho 		 * Out of space in the current buffer. Allocate more.
1761870619e9Sfrankho 		 */
1762870619e9Sfrankho 		piol_t *newiol;
1763870619e9Sfrankho 
1764870619e9Sfrankho 		newiol = kmem_alloc(MAPSIZE, KM_SLEEP);
1765870619e9Sfrankho 		newiol->piol_size = MAPSIZE;
1766870619e9Sfrankho 		newiol->piol_usedsize = 0;
1767870619e9Sfrankho 
1768870619e9Sfrankho 		list_insert_after(iolhead, iol, newiol);
1769870619e9Sfrankho 		iol = list_next(iolhead, iol);
1770870619e9Sfrankho 		ASSERT(iol == newiol);
1771870619e9Sfrankho 	}
1772870619e9Sfrankho 	new = (char *)PIOL_DATABUF(iol) + iol->piol_usedsize;
1773870619e9Sfrankho 	iol->piol_usedsize += itemsize;
1774870619e9Sfrankho 	bzero(new, itemsize);
1775870619e9Sfrankho 	return (new);
1776870619e9Sfrankho }
1777870619e9Sfrankho 
1778a02120c4SAndy Fiddaman void
pr_iol_freelist(list_t * iolhead)1779a02120c4SAndy Fiddaman pr_iol_freelist(list_t *iolhead)
1780a02120c4SAndy Fiddaman {
1781a02120c4SAndy Fiddaman 	piol_t	*iol;
1782a02120c4SAndy Fiddaman 
1783a02120c4SAndy Fiddaman 	while ((iol = list_head(iolhead)) != NULL) {
1784a02120c4SAndy Fiddaman 		list_remove(iolhead, iol);
1785a02120c4SAndy Fiddaman 		kmem_free(iol, iol->piol_size);
1786a02120c4SAndy Fiddaman 	}
1787a02120c4SAndy Fiddaman 	list_destroy(iolhead);
1788a02120c4SAndy Fiddaman }
1789a02120c4SAndy Fiddaman 
1790870619e9Sfrankho int
pr_iol_copyout_and_free(list_t * iolhead,caddr_t * tgt,int errin)1791870619e9Sfrankho pr_iol_copyout_and_free(list_t *iolhead, caddr_t *tgt, int errin)
1792870619e9Sfrankho {
1793870619e9Sfrankho 	int error = errin;
1794870619e9Sfrankho 	piol_t	*iol;
1795870619e9Sfrankho 
1796870619e9Sfrankho 	while ((iol = list_head(iolhead)) != NULL) {
1797870619e9Sfrankho 		list_remove(iolhead, iol);
1798870619e9Sfrankho 		if (!error) {
1799870619e9Sfrankho 			if (copyout(PIOL_DATABUF(iol), *tgt,
1800870619e9Sfrankho 			    iol->piol_usedsize))
1801870619e9Sfrankho 				error = EFAULT;
1802870619e9Sfrankho 			*tgt += iol->piol_usedsize;
1803870619e9Sfrankho 		}
1804870619e9Sfrankho 		kmem_free(iol, iol->piol_size);
1805870619e9Sfrankho 	}
1806870619e9Sfrankho 	list_destroy(iolhead);
1807870619e9Sfrankho 
1808870619e9Sfrankho 	return (error);
1809870619e9Sfrankho }
1810870619e9Sfrankho 
1811870619e9Sfrankho int
pr_iol_uiomove_and_free(list_t * iolhead,uio_t * uiop,int errin)1812870619e9Sfrankho pr_iol_uiomove_and_free(list_t *iolhead, uio_t *uiop, int errin)
1813870619e9Sfrankho {
1814870619e9Sfrankho 	offset_t	off = uiop->uio_offset;
1815870619e9Sfrankho 	char		*base;
1816870619e9Sfrankho 	size_t		size;
1817870619e9Sfrankho 	piol_t		*iol;
1818870619e9Sfrankho 	int		error = errin;
1819870619e9Sfrankho 
1820870619e9Sfrankho 	while ((iol = list_head(iolhead)) != NULL) {
1821870619e9Sfrankho 		list_remove(iolhead, iol);
1822870619e9Sfrankho 		base = PIOL_DATABUF(iol);
1823870619e9Sfrankho 		size = iol->piol_usedsize;
1824870619e9Sfrankho 		if (off <= size && error == 0 && uiop->uio_resid > 0)
1825870619e9Sfrankho 			error = uiomove(base + off, size - off,
1826870619e9Sfrankho 			    UIO_READ, uiop);
1827870619e9Sfrankho 		off = MAX(0, off - (offset_t)size);
1828870619e9Sfrankho 		kmem_free(iol, iol->piol_size);
1829870619e9Sfrankho 	}
1830870619e9Sfrankho 	list_destroy(iolhead);
1831870619e9Sfrankho 
1832870619e9Sfrankho 	return (error);
1833870619e9Sfrankho }
1834870619e9Sfrankho 
1835870619e9Sfrankho /*
18367c478bd9Sstevel@tonic-gate  * Return an array of structures with memory map information.
18377c478bd9Sstevel@tonic-gate  * We allocate here; the caller must deallocate.
18387c478bd9Sstevel@tonic-gate  */
18397c478bd9Sstevel@tonic-gate int
prgetmap(proc_t * p,int reserved,list_t * iolhead)1840870619e9Sfrankho prgetmap(proc_t *p, int reserved, list_t *iolhead)
18417c478bd9Sstevel@tonic-gate {
18427c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
18437c478bd9Sstevel@tonic-gate 	prmap_t *mp;
18447c478bd9Sstevel@tonic-gate 	struct seg *seg;
18457c478bd9Sstevel@tonic-gate 	struct seg *brkseg, *stkseg;
18467c478bd9Sstevel@tonic-gate 	struct vnode *vp;
18477c478bd9Sstevel@tonic-gate 	struct vattr vattr;
18487c478bd9Sstevel@tonic-gate 	uint_t prot;
18497c478bd9Sstevel@tonic-gate 
1850dc32d872SJosef 'Jeff' Sipek 	ASSERT(as != &kas && AS_WRITE_HELD(as));
18517c478bd9Sstevel@tonic-gate 
1852870619e9Sfrankho 	/*
1853870619e9Sfrankho 	 * Request an initial buffer size that doesn't waste memory
1854870619e9Sfrankho 	 * if the address space has only a small number of segments.
1855870619e9Sfrankho 	 */
1856870619e9Sfrankho 	pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
18577c478bd9Sstevel@tonic-gate 
18587c478bd9Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL)
18597c478bd9Sstevel@tonic-gate 		return (0);
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 	brkseg = break_seg(p);
18627c478bd9Sstevel@tonic-gate 	stkseg = as_segat(as, prgetstackbase(p));
18637c478bd9Sstevel@tonic-gate 
18647c478bd9Sstevel@tonic-gate 	do {
18657c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, reserved);
18667c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr;
18677c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
18687c478bd9Sstevel@tonic-gate 
1869284ce987SPatrick Mooney 		if ((seg->s_flags & S_HOLE) != 0) {
1870284ce987SPatrick Mooney 			continue;
1871284ce987SPatrick Mooney 		}
1872284ce987SPatrick Mooney 
18737c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
18747c478bd9Sstevel@tonic-gate 			prot = pr_getprot(seg, reserved, &tmp,
18757c478bd9Sstevel@tonic-gate 			    &saddr, &naddr, eaddr);
18767c478bd9Sstevel@tonic-gate 			if (saddr == naddr)
18777c478bd9Sstevel@tonic-gate 				continue;
18787c478bd9Sstevel@tonic-gate 
1879870619e9Sfrankho 			mp = pr_iol_newbuf(iolhead, sizeof (*mp));
1880870619e9Sfrankho 
18817c478bd9Sstevel@tonic-gate 			mp->pr_vaddr = (uintptr_t)saddr;
18827c478bd9Sstevel@tonic-gate 			mp->pr_size = naddr - saddr;
18837c478bd9Sstevel@tonic-gate 			mp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
18847c478bd9Sstevel@tonic-gate 			mp->pr_mflags = 0;
18857c478bd9Sstevel@tonic-gate 			if (prot & PROT_READ)
18867c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_READ;
18877c478bd9Sstevel@tonic-gate 			if (prot & PROT_WRITE)
18887c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_WRITE;
18897c478bd9Sstevel@tonic-gate 			if (prot & PROT_EXEC)
18907c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_EXEC;
18917c478bd9Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_SHARED)
18927c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_SHARED;
18937c478bd9Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_NORESERVE)
18947c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_NORESERVE;
18957c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops ||
18967c478bd9Sstevel@tonic-gate 			    (seg->s_ops == &segvn_ops &&
18977c478bd9Sstevel@tonic-gate 			    (SEGOP_GETVP(seg, saddr, &vp) != 0 || vp == NULL)))
18987c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_ANON;
18997c478bd9Sstevel@tonic-gate 			if (seg == brkseg)
19007c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_BREAK;
19017c478bd9Sstevel@tonic-gate 			else if (seg == stkseg) {
19027c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_STACK;
19037c478bd9Sstevel@tonic-gate 				if (reserved) {
19047c478bd9Sstevel@tonic-gate 					size_t maxstack =
19057c478bd9Sstevel@tonic-gate 					    ((size_t)p->p_stk_ctl +
19067c478bd9Sstevel@tonic-gate 					    PAGEOFFSET) & PAGEMASK;
19077c478bd9Sstevel@tonic-gate 					mp->pr_vaddr =
19087c478bd9Sstevel@tonic-gate 					    (uintptr_t)prgetstackbase(p) +
19097c478bd9Sstevel@tonic-gate 					    p->p_stksize - maxstack;
19107c478bd9Sstevel@tonic-gate 					mp->pr_size = (uintptr_t)naddr -
19117c478bd9Sstevel@tonic-gate 					    mp->pr_vaddr;
19127c478bd9Sstevel@tonic-gate 				}
19137c478bd9Sstevel@tonic-gate 			}
19147c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops)
19157c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_ISM | MA_SHM;
19167c478bd9Sstevel@tonic-gate 			mp->pr_pagesize = PAGESIZE;
19177c478bd9Sstevel@tonic-gate 
19187c478bd9Sstevel@tonic-gate 			/*
19197c478bd9Sstevel@tonic-gate 			 * Manufacture a filename for the "object" directory.
19207c478bd9Sstevel@tonic-gate 			 */
19217c478bd9Sstevel@tonic-gate 			vattr.va_mask = AT_FSID|AT_NODEID;
19227c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segvn_ops &&
19237c478bd9Sstevel@tonic-gate 			    SEGOP_GETVP(seg, saddr, &vp) == 0 &&
19247c478bd9Sstevel@tonic-gate 			    vp != NULL && vp->v_type == VREG &&
1925da6c28aaSamw 			    VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
19267c478bd9Sstevel@tonic-gate 				if (vp == p->p_exec)
19277c478bd9Sstevel@tonic-gate 					(void) strcpy(mp->pr_mapname, "a.out");
19287c478bd9Sstevel@tonic-gate 				else
19297c478bd9Sstevel@tonic-gate 					pr_object_name(mp->pr_mapname,
19307c478bd9Sstevel@tonic-gate 					    vp, &vattr);
19317c478bd9Sstevel@tonic-gate 			}
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate 			/*
19347c478bd9Sstevel@tonic-gate 			 * Get the SysV shared memory id, if any.
19357c478bd9Sstevel@tonic-gate 			 */
19367c478bd9Sstevel@tonic-gate 			if ((mp->pr_mflags & MA_SHARED) && p->p_segacct &&
19377c478bd9Sstevel@tonic-gate 			    (mp->pr_shmid = shmgetid(p, seg->s_base)) !=
19387c478bd9Sstevel@tonic-gate 			    SHMID_NONE) {
19397c478bd9Sstevel@tonic-gate 				if (mp->pr_shmid == SHMID_FREE)
19407c478bd9Sstevel@tonic-gate 					mp->pr_shmid = -1;
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_SHM;
19437c478bd9Sstevel@tonic-gate 			} else {
19447c478bd9Sstevel@tonic-gate 				mp->pr_shmid = -1;
19457c478bd9Sstevel@tonic-gate 			}
19467c478bd9Sstevel@tonic-gate 		}
19477c478bd9Sstevel@tonic-gate 		ASSERT(tmp == NULL);
19487c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
19497c478bd9Sstevel@tonic-gate 
1950870619e9Sfrankho 	return (0);
19517c478bd9Sstevel@tonic-gate }
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
19547c478bd9Sstevel@tonic-gate int
prgetmap32(proc_t * p,int reserved,list_t * iolhead)1955870619e9Sfrankho prgetmap32(proc_t *p, int reserved, list_t *iolhead)
19567c478bd9Sstevel@tonic-gate {
19577c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
19587c478bd9Sstevel@tonic-gate 	prmap32_t *mp;
19597c478bd9Sstevel@tonic-gate 	struct seg *seg;
19607c478bd9Sstevel@tonic-gate 	struct seg *brkseg, *stkseg;
19617c478bd9Sstevel@tonic-gate 	struct vnode *vp;
19627c478bd9Sstevel@tonic-gate 	struct vattr vattr;
19637c478bd9Sstevel@tonic-gate 	uint_t prot;
19647c478bd9Sstevel@tonic-gate 
1965dc32d872SJosef 'Jeff' Sipek 	ASSERT(as != &kas && AS_WRITE_HELD(as));
19667c478bd9Sstevel@tonic-gate 
1967870619e9Sfrankho 	/*
1968870619e9Sfrankho 	 * Request an initial buffer size that doesn't waste memory
1969870619e9Sfrankho 	 * if the address space has only a small number of segments.
1970870619e9Sfrankho 	 */
1971870619e9Sfrankho 	pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
19727c478bd9Sstevel@tonic-gate 
19737c478bd9Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL)
19747c478bd9Sstevel@tonic-gate 		return (0);
19757c478bd9Sstevel@tonic-gate 
19767c478bd9Sstevel@tonic-gate 	brkseg = break_seg(p);
19777c478bd9Sstevel@tonic-gate 	stkseg = as_segat(as, prgetstackbase(p));
19787c478bd9Sstevel@tonic-gate 
19797c478bd9Sstevel@tonic-gate 	do {
19807c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, reserved);
19817c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr;
19827c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
19837c478bd9Sstevel@tonic-gate 
1984284ce987SPatrick Mooney 		if ((seg->s_flags & S_HOLE) != 0) {
1985284ce987SPatrick Mooney 			continue;
1986284ce987SPatrick Mooney 		}
1987284ce987SPatrick Mooney 
19887c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
19897c478bd9Sstevel@tonic-gate 			prot = pr_getprot(seg, reserved, &tmp,
19907c478bd9Sstevel@tonic-gate 			    &saddr, &naddr, eaddr);
19917c478bd9Sstevel@tonic-gate 			if (saddr == naddr)
19927c478bd9Sstevel@tonic-gate 				continue;
19937c478bd9Sstevel@tonic-gate 
1994870619e9Sfrankho 			mp = pr_iol_newbuf(iolhead, sizeof (*mp));
1995870619e9Sfrankho 
19967c478bd9Sstevel@tonic-gate 			mp->pr_vaddr = (caddr32_t)(uintptr_t)saddr;
19977c478bd9Sstevel@tonic-gate 			mp->pr_size = (size32_t)(naddr - saddr);
19987c478bd9Sstevel@tonic-gate 			mp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
19997c478bd9Sstevel@tonic-gate 			mp->pr_mflags = 0;
20007c478bd9Sstevel@tonic-gate 			if (prot & PROT_READ)
20017c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_READ;
20027c478bd9Sstevel@tonic-gate 			if (prot & PROT_WRITE)
20037c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_WRITE;
20047c478bd9Sstevel@tonic-gate 			if (prot & PROT_EXEC)
20057c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_EXEC;
20067c478bd9Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_SHARED)
20077c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_SHARED;
20087c478bd9Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_NORESERVE)
20097c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_NORESERVE;
20107c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops ||
20117c478bd9Sstevel@tonic-gate 			    (seg->s_ops == &segvn_ops &&
20127c478bd9Sstevel@tonic-gate 			    (SEGOP_GETVP(seg, saddr, &vp) != 0 || vp == NULL)))
20137c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_ANON;
20147c478bd9Sstevel@tonic-gate 			if (seg == brkseg)
20157c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_BREAK;
20167c478bd9Sstevel@tonic-gate 			else if (seg == stkseg) {
20177c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_STACK;
20187c478bd9Sstevel@tonic-gate 				if (reserved) {
20197c478bd9Sstevel@tonic-gate 					size_t maxstack =
20207c478bd9Sstevel@tonic-gate 					    ((size_t)p->p_stk_ctl +
20217c478bd9Sstevel@tonic-gate 					    PAGEOFFSET) & PAGEMASK;
20227c478bd9Sstevel@tonic-gate 					uintptr_t vaddr =
20237c478bd9Sstevel@tonic-gate 					    (uintptr_t)prgetstackbase(p) +
20247c478bd9Sstevel@tonic-gate 					    p->p_stksize - maxstack;
20257c478bd9Sstevel@tonic-gate 					mp->pr_vaddr = (caddr32_t)vaddr;
20267c478bd9Sstevel@tonic-gate 					mp->pr_size = (size32_t)
20277c478bd9Sstevel@tonic-gate 					    ((uintptr_t)naddr - vaddr);
20287c478bd9Sstevel@tonic-gate 				}
20297c478bd9Sstevel@tonic-gate 			}
20307c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops)
20317c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_ISM | MA_SHM;
20327c478bd9Sstevel@tonic-gate 			mp->pr_pagesize = PAGESIZE;
20337c478bd9Sstevel@tonic-gate 
20347c478bd9Sstevel@tonic-gate 			/*
20357c478bd9Sstevel@tonic-gate 			 * Manufacture a filename for the "object" directory.
20367c478bd9Sstevel@tonic-gate 			 */
20377c478bd9Sstevel@tonic-gate 			vattr.va_mask = AT_FSID|AT_NODEID;
20387c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segvn_ops &&
20397c478bd9Sstevel@tonic-gate 			    SEGOP_GETVP(seg, saddr, &vp) == 0 &&
20407c478bd9Sstevel@tonic-gate 			    vp != NULL && vp->v_type == VREG &&
2041da6c28aaSamw 			    VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
20427c478bd9Sstevel@tonic-gate 				if (vp == p->p_exec)
20437c478bd9Sstevel@tonic-gate 					(void) strcpy(mp->pr_mapname, "a.out");
20447c478bd9Sstevel@tonic-gate 				else
20457c478bd9Sstevel@tonic-gate 					pr_object_name(mp->pr_mapname,
20467c478bd9Sstevel@tonic-gate 					    vp, &vattr);
20477c478bd9Sstevel@tonic-gate 			}
20487c478bd9Sstevel@tonic-gate 
20497c478bd9Sstevel@tonic-gate 			/*
20507c478bd9Sstevel@tonic-gate 			 * Get the SysV shared memory id, if any.
20517c478bd9Sstevel@tonic-gate 			 */
20527c478bd9Sstevel@tonic-gate 			if ((mp->pr_mflags & MA_SHARED) && p->p_segacct &&
20537c478bd9Sstevel@tonic-gate 			    (mp->pr_shmid = shmgetid(p, seg->s_base)) !=
20547c478bd9Sstevel@tonic-gate 			    SHMID_NONE) {
20557c478bd9Sstevel@tonic-gate 				if (mp->pr_shmid == SHMID_FREE)
20567c478bd9Sstevel@tonic-gate 					mp->pr_shmid = -1;
20577c478bd9Sstevel@tonic-gate 
20587c478bd9Sstevel@tonic-gate 				mp->pr_mflags |= MA_SHM;
20597c478bd9Sstevel@tonic-gate 			} else {
20607c478bd9Sstevel@tonic-gate 				mp->pr_shmid = -1;
20617c478bd9Sstevel@tonic-gate 			}
20627c478bd9Sstevel@tonic-gate 		}
20637c478bd9Sstevel@tonic-gate 		ASSERT(tmp == NULL);
20647c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
20657c478bd9Sstevel@tonic-gate 
2066870619e9Sfrankho 	return (0);
20677c478bd9Sstevel@tonic-gate }
20687c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
20697c478bd9Sstevel@tonic-gate 
20707c478bd9Sstevel@tonic-gate /*
20717c478bd9Sstevel@tonic-gate  * Return the size of the /proc page data file.
20727c478bd9Sstevel@tonic-gate  */
20737c478bd9Sstevel@tonic-gate size_t
prpdsize(struct as * as)20747c478bd9Sstevel@tonic-gate prpdsize(struct as *as)
20757c478bd9Sstevel@tonic-gate {
20767c478bd9Sstevel@tonic-gate 	struct seg *seg;
20777c478bd9Sstevel@tonic-gate 	size_t size;
20787c478bd9Sstevel@tonic-gate 
2079dc32d872SJosef 'Jeff' Sipek 	ASSERT(as != &kas && AS_WRITE_HELD(as));
20807c478bd9Sstevel@tonic-gate 
20817c478bd9Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL)
20827c478bd9Sstevel@tonic-gate 		return (0);
20837c478bd9Sstevel@tonic-gate 
20847c478bd9Sstevel@tonic-gate 	size = sizeof (prpageheader_t);
20857c478bd9Sstevel@tonic-gate 	do {
20867c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
20877c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr;
20887c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
20897c478bd9Sstevel@tonic-gate 		size_t npage;
20907c478bd9Sstevel@tonic-gate 
2091284ce987SPatrick Mooney 		if ((seg->s_flags & S_HOLE) != 0) {
2092284ce987SPatrick Mooney 			continue;
2093284ce987SPatrick Mooney 		}
2094284ce987SPatrick Mooney 
20957c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
20967c478bd9Sstevel@tonic-gate 			(void) pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
20977c478bd9Sstevel@tonic-gate 			if ((npage = (naddr - saddr) / PAGESIZE) != 0)
20987c478bd9Sstevel@tonic-gate 				size += sizeof (prasmap_t) + round8(npage);
20997c478bd9Sstevel@tonic-gate 		}
21007c478bd9Sstevel@tonic-gate 		ASSERT(tmp == NULL);
21017c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
21027c478bd9Sstevel@tonic-gate 
21037c478bd9Sstevel@tonic-gate 	return (size);
21047c478bd9Sstevel@tonic-gate }
21057c478bd9Sstevel@tonic-gate 
21067c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
21077c478bd9Sstevel@tonic-gate size_t
prpdsize32(struct as * as)21087c478bd9Sstevel@tonic-gate prpdsize32(struct as *as)
21097c478bd9Sstevel@tonic-gate {
21107c478bd9Sstevel@tonic-gate 	struct seg *seg;
21117c478bd9Sstevel@tonic-gate 	size_t size;
21127c478bd9Sstevel@tonic-gate 
2113dc32d872SJosef 'Jeff' Sipek 	ASSERT(as != &kas && AS_WRITE_HELD(as));
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL)
21167c478bd9Sstevel@tonic-gate 		return (0);
21177c478bd9Sstevel@tonic-gate 
21187c478bd9Sstevel@tonic-gate 	size = sizeof (prpageheader32_t);
21197c478bd9Sstevel@tonic-gate 	do {
21207c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
21217c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr;
21227c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
21237c478bd9Sstevel@tonic-gate 		size_t npage;
21247c478bd9Sstevel@tonic-gate 
2125284ce987SPatrick Mooney 		if ((seg->s_flags & S_HOLE) != 0) {
2126284ce987SPatrick Mooney 			continue;
2127284ce987SPatrick Mooney 		}
2128284ce987SPatrick Mooney 
21297c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
21307c478bd9Sstevel@tonic-gate 			(void) pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
21317c478bd9Sstevel@tonic-gate 			if ((npage = (naddr - saddr) / PAGESIZE) != 0)
21327c478bd9Sstevel@tonic-gate 				size += sizeof (prasmap32_t) + round8(npage);
21337c478bd9Sstevel@tonic-gate 		}
21347c478bd9Sstevel@tonic-gate 		ASSERT(tmp == NULL);
21357c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
21367c478bd9Sstevel@tonic-gate 
21377c478bd9Sstevel@tonic-gate 	return (size);
21387c478bd9Sstevel@tonic-gate }
21397c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
21407c478bd9Sstevel@tonic-gate 
21417c478bd9Sstevel@tonic-gate /*
21427c478bd9Sstevel@tonic-gate  * Read page data information.
21437c478bd9Sstevel@tonic-gate  */
21447c478bd9Sstevel@tonic-gate int
prpdread(proc_t * p,uint_t hatid,struct uio * uiop)21457c478bd9Sstevel@tonic-gate prpdread(proc_t *p, uint_t hatid, struct uio *uiop)
21467c478bd9Sstevel@tonic-gate {
21477c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
21487c478bd9Sstevel@tonic-gate 	caddr_t buf;
21497c478bd9Sstevel@tonic-gate 	size_t size;
21507c478bd9Sstevel@tonic-gate 	prpageheader_t *php;
21517c478bd9Sstevel@tonic-gate 	prasmap_t *pmp;
21527c478bd9Sstevel@tonic-gate 	struct seg *seg;
21537c478bd9Sstevel@tonic-gate 	int error;
21547c478bd9Sstevel@tonic-gate 
21557c478bd9Sstevel@tonic-gate again:
2156dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_ENTER(as, RW_WRITER);
21577c478bd9Sstevel@tonic-gate 
21587c478bd9Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL) {
2159dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_EXIT(as);
21607c478bd9Sstevel@tonic-gate 		return (0);
21617c478bd9Sstevel@tonic-gate 	}
21627c478bd9Sstevel@tonic-gate 	size = prpdsize(as);
21637c478bd9Sstevel@tonic-gate 	if (uiop->uio_resid < size) {
2164dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_EXIT(as);
21657c478bd9Sstevel@tonic-gate 		return (E2BIG);
21667c478bd9Sstevel@tonic-gate 	}
21677c478bd9Sstevel@tonic-gate 
21687c478bd9Sstevel@tonic-gate 	buf = kmem_zalloc(size, KM_SLEEP);
21697c478bd9Sstevel@tonic-gate 	php = (prpageheader_t *)buf;
21707c478bd9Sstevel@tonic-gate 	pmp = (prasmap_t *)(buf + sizeof (prpageheader_t));
21717c478bd9Sstevel@tonic-gate 
21727c478bd9Sstevel@tonic-gate 	hrt2ts(gethrtime(), &php->pr_tstamp);
21737c478bd9Sstevel@tonic-gate 	php->pr_nmap = 0;
21747c478bd9Sstevel@tonic-gate 	php->pr_npage = 0;
21757c478bd9Sstevel@tonic-gate 	do {
21767c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
21777c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr;
21787c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
21797c478bd9Sstevel@tonic-gate 
2180284ce987SPatrick Mooney 		if ((seg->s_flags & S_HOLE) != 0) {
2181284ce987SPatrick Mooney 			continue;
2182284ce987SPatrick Mooney 		}
2183284ce987SPatrick Mooney 
21847c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
21857c478bd9Sstevel@tonic-gate 			struct vnode *vp;
21867c478bd9Sstevel@tonic-gate 			struct vattr vattr;
21877c478bd9Sstevel@tonic-gate 			size_t len;
21887c478bd9Sstevel@tonic-gate 			size_t npage;
21897c478bd9Sstevel@tonic-gate 			uint_t prot;
21907c478bd9Sstevel@tonic-gate 			uintptr_t next;
21917c478bd9Sstevel@tonic-gate 
21927c478bd9Sstevel@tonic-gate 			prot = pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
21937c478bd9Sstevel@tonic-gate 			if ((len = (size_t)(naddr - saddr)) == 0)
21947c478bd9Sstevel@tonic-gate 				continue;
21957c478bd9Sstevel@tonic-gate 			npage = len / PAGESIZE;
21967c478bd9Sstevel@tonic-gate 			next = (uintptr_t)(pmp + 1) + round8(npage);
21977c478bd9Sstevel@tonic-gate 			/*
21987c478bd9Sstevel@tonic-gate 			 * It's possible that the address space can change
21997c478bd9Sstevel@tonic-gate 			 * subtlely even though we're holding as->a_lock
22007c478bd9Sstevel@tonic-gate 			 * due to the nondeterminism of page_exists() in
22017c478bd9Sstevel@tonic-gate 			 * the presence of asychronously flushed pages or
22027c478bd9Sstevel@tonic-gate 			 * mapped files whose sizes are changing.
22037c478bd9Sstevel@tonic-gate 			 * page_exists() may be called indirectly from
22047c478bd9Sstevel@tonic-gate 			 * pr_getprot() by a SEGOP_INCORE() routine.
22057c478bd9Sstevel@tonic-gate 			 * If this happens we need to make sure we don't
22067c478bd9Sstevel@tonic-gate 			 * overrun the buffer whose size we computed based
22077c478bd9Sstevel@tonic-gate 			 * on the initial iteration through the segments.
22087c478bd9Sstevel@tonic-gate 			 * Once we've detected an overflow, we need to clean
22097c478bd9Sstevel@tonic-gate 			 * up the temporary memory allocated in pr_getprot()
22107c478bd9Sstevel@tonic-gate 			 * and retry. If there's a pending signal, we return
22117c478bd9Sstevel@tonic-gate 			 * EINTR so that this thread can be dislodged if
22127c478bd9Sstevel@tonic-gate 			 * a latent bug causes us to spin indefinitely.
22137c478bd9Sstevel@tonic-gate 			 */
22147c478bd9Sstevel@tonic-gate 			if (next > (uintptr_t)buf + size) {
22157c478bd9Sstevel@tonic-gate 				pr_getprot_done(&tmp);
2216dc32d872SJosef 'Jeff' Sipek 				AS_LOCK_EXIT(as);
22177c478bd9Sstevel@tonic-gate 
22187c478bd9Sstevel@tonic-gate 				kmem_free(buf, size);
22197c478bd9Sstevel@tonic-gate 
22207c478bd9Sstevel@tonic-gate 				if (ISSIG(curthread, JUSTLOOKING))
22217c478bd9Sstevel@tonic-gate 					return (EINTR);
22227c478bd9Sstevel@tonic-gate 
22237c478bd9Sstevel@tonic-gate 				goto again;
22247c478bd9Sstevel@tonic-gate 			}
22257c478bd9Sstevel@tonic-gate 
22267c478bd9Sstevel@tonic-gate 			php->pr_nmap++;
22277c478bd9Sstevel@tonic-gate 			php->pr_npage += npage;
22287c478bd9Sstevel@tonic-gate 			pmp->pr_vaddr = (uintptr_t)saddr;
22297c478bd9Sstevel@tonic-gate 			pmp->pr_npage = npage;
22307c478bd9Sstevel@tonic-gate 			pmp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
22317c478bd9Sstevel@tonic-gate 			pmp->pr_mflags = 0;
22327c478bd9Sstevel@tonic-gate 			if (prot & PROT_READ)
22337c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_READ;
22347c478bd9Sstevel@tonic-gate 			if (prot & PROT_WRITE)
22357c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_WRITE;
22367c478bd9Sstevel@tonic-gate 			if (prot & PROT_EXEC)
22377c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_EXEC;
22387c478bd9Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_SHARED)
22397c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_SHARED;
22407c478bd9Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_NORESERVE)
22417c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_NORESERVE;
22427c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops ||
22437c478bd9Sstevel@tonic-gate 			    (seg->s_ops == &segvn_ops &&
22447c478bd9Sstevel@tonic-gate 			    (SEGOP_GETVP(seg, saddr, &vp) != 0 || vp == NULL)))
22457c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_ANON;
22467c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops)
22477c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_ISM | MA_SHM;
22487c478bd9Sstevel@tonic-gate 			pmp->pr_pagesize = PAGESIZE;
22497c478bd9Sstevel@tonic-gate 			/*
22507c478bd9Sstevel@tonic-gate 			 * Manufacture a filename for the "object" directory.
22517c478bd9Sstevel@tonic-gate 			 */
22527c478bd9Sstevel@tonic-gate 			vattr.va_mask = AT_FSID|AT_NODEID;
22537c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segvn_ops &&
22547c478bd9Sstevel@tonic-gate 			    SEGOP_GETVP(seg, saddr, &vp) == 0 &&
22557c478bd9Sstevel@tonic-gate 			    vp != NULL && vp->v_type == VREG &&
2256da6c28aaSamw 			    VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
22577c478bd9Sstevel@tonic-gate 				if (vp == p->p_exec)
22587c478bd9Sstevel@tonic-gate 					(void) strcpy(pmp->pr_mapname, "a.out");
22597c478bd9Sstevel@tonic-gate 				else
22607c478bd9Sstevel@tonic-gate 					pr_object_name(pmp->pr_mapname,
22617c478bd9Sstevel@tonic-gate 					    vp, &vattr);
22627c478bd9Sstevel@tonic-gate 			}
22637c478bd9Sstevel@tonic-gate 
22647c478bd9Sstevel@tonic-gate 			/*
22657c478bd9Sstevel@tonic-gate 			 * Get the SysV shared memory id, if any.
22667c478bd9Sstevel@tonic-gate 			 */
22677c478bd9Sstevel@tonic-gate 			if ((pmp->pr_mflags & MA_SHARED) && p->p_segacct &&
22687c478bd9Sstevel@tonic-gate 			    (pmp->pr_shmid = shmgetid(p, seg->s_base)) !=
22697c478bd9Sstevel@tonic-gate 			    SHMID_NONE) {
22707c478bd9Sstevel@tonic-gate 				if (pmp->pr_shmid == SHMID_FREE)
22717c478bd9Sstevel@tonic-gate 					pmp->pr_shmid = -1;
22727c478bd9Sstevel@tonic-gate 
22737c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_SHM;
22747c478bd9Sstevel@tonic-gate 			} else {
22757c478bd9Sstevel@tonic-gate 				pmp->pr_shmid = -1;
22767c478bd9Sstevel@tonic-gate 			}
22777c478bd9Sstevel@tonic-gate 
22787c478bd9Sstevel@tonic-gate 			hat_getstat(as, saddr, len, hatid,
22797c478bd9Sstevel@tonic-gate 			    (char *)(pmp + 1), HAT_SYNC_ZERORM);
22807c478bd9Sstevel@tonic-gate 			pmp = (prasmap_t *)next;
22817c478bd9Sstevel@tonic-gate 		}
22827c478bd9Sstevel@tonic-gate 		ASSERT(tmp == NULL);
22837c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
22847c478bd9Sstevel@tonic-gate 
2285dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
22867c478bd9Sstevel@tonic-gate 
22877c478bd9Sstevel@tonic-gate 	ASSERT((uintptr_t)pmp <= (uintptr_t)buf + size);
22887c478bd9Sstevel@tonic-gate 	error = uiomove(buf, (caddr_t)pmp - buf, UIO_READ, uiop);
22897c478bd9Sstevel@tonic-gate 	kmem_free(buf, size);
22907c478bd9Sstevel@tonic-gate 
22917c478bd9Sstevel@tonic-gate 	return (error);
22927c478bd9Sstevel@tonic-gate }
22937c478bd9Sstevel@tonic-gate 
22947c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
22957c478bd9Sstevel@tonic-gate int
prpdread32(proc_t * p,uint_t hatid,struct uio * uiop)22967c478bd9Sstevel@tonic-gate prpdread32(proc_t *p, uint_t hatid, struct uio *uiop)
22977c478bd9Sstevel@tonic-gate {
22987c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
22997c478bd9Sstevel@tonic-gate 	caddr_t buf;
23007c478bd9Sstevel@tonic-gate 	size_t size;
23017c478bd9Sstevel@tonic-gate 	prpageheader32_t *php;
23027c478bd9Sstevel@tonic-gate 	prasmap32_t *pmp;
23037c478bd9Sstevel@tonic-gate 	struct seg *seg;
23047c478bd9Sstevel@tonic-gate 	int error;
23057c478bd9Sstevel@tonic-gate 
23067c478bd9Sstevel@tonic-gate again:
2307dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_ENTER(as, RW_WRITER);
23087c478bd9Sstevel@tonic-gate 
23097c478bd9Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL) {
2310dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_EXIT(as);
23117c478bd9Sstevel@tonic-gate 		return (0);
23127c478bd9Sstevel@tonic-gate 	}
23137c478bd9Sstevel@tonic-gate 	size = prpdsize32(as);
23147c478bd9Sstevel@tonic-gate 	if (uiop->uio_resid < size) {
2315dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_EXIT(as);
23167c478bd9Sstevel@tonic-gate 		return (E2BIG);
23177c478bd9Sstevel@tonic-gate 	}
23187c478bd9Sstevel@tonic-gate 
23197c478bd9Sstevel@tonic-gate 	buf = kmem_zalloc(size, KM_SLEEP);
23207c478bd9Sstevel@tonic-gate 	php = (prpageheader32_t *)buf;
23217c478bd9Sstevel@tonic-gate 	pmp = (prasmap32_t *)(buf + sizeof (prpageheader32_t));
23227c478bd9Sstevel@tonic-gate 
23237c478bd9Sstevel@tonic-gate 	hrt2ts32(gethrtime(), &php->pr_tstamp);
23247c478bd9Sstevel@tonic-gate 	php->pr_nmap = 0;
23257c478bd9Sstevel@tonic-gate 	php->pr_npage = 0;
23267c478bd9Sstevel@tonic-gate 	do {
23277c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
23287c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr;
23297c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
23307c478bd9Sstevel@tonic-gate 
2331284ce987SPatrick Mooney 		if ((seg->s_flags & S_HOLE) != 0) {
2332284ce987SPatrick Mooney 			continue;
2333284ce987SPatrick Mooney 		}
2334284ce987SPatrick Mooney 
23357c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
23367c478bd9Sstevel@tonic-gate 			struct vnode *vp;
23377c478bd9Sstevel@tonic-gate 			struct vattr vattr;
23387c478bd9Sstevel@tonic-gate 			size_t len;
23397c478bd9Sstevel@tonic-gate 			size_t npage;
23407c478bd9Sstevel@tonic-gate 			uint_t prot;
23417c478bd9Sstevel@tonic-gate 			uintptr_t next;
23427c478bd9Sstevel@tonic-gate 
23437c478bd9Sstevel@tonic-gate 			prot = pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
23447c478bd9Sstevel@tonic-gate 			if ((len = (size_t)(naddr - saddr)) == 0)
23457c478bd9Sstevel@tonic-gate 				continue;
23467c478bd9Sstevel@tonic-gate 			npage = len / PAGESIZE;
23477c478bd9Sstevel@tonic-gate 			next = (uintptr_t)(pmp + 1) + round8(npage);
23487c478bd9Sstevel@tonic-gate 			/*
23497c478bd9Sstevel@tonic-gate 			 * It's possible that the address space can change
23507c478bd9Sstevel@tonic-gate 			 * subtlely even though we're holding as->a_lock
23517c478bd9Sstevel@tonic-gate 			 * due to the nondeterminism of page_exists() in
23527c478bd9Sstevel@tonic-gate 			 * the presence of asychronously flushed pages or
23537c478bd9Sstevel@tonic-gate 			 * mapped files whose sizes are changing.
23547c478bd9Sstevel@tonic-gate 			 * page_exists() may be called indirectly from
23557c478bd9Sstevel@tonic-gate 			 * pr_getprot() by a SEGOP_INCORE() routine.
23567c478bd9Sstevel@tonic-gate 			 * If this happens we need to make sure we don't
23577c478bd9Sstevel@tonic-gate 			 * overrun the buffer whose size we computed based
23587c478bd9Sstevel@tonic-gate 			 * on the initial iteration through the segments.
23597c478bd9Sstevel@tonic-gate 			 * Once we've detected an overflow, we need to clean
23607c478bd9Sstevel@tonic-gate 			 * up the temporary memory allocated in pr_getprot()
23617c478bd9Sstevel@tonic-gate 			 * and retry. If there's a pending signal, we return
23627c478bd9Sstevel@tonic-gate 			 * EINTR so that this thread can be dislodged if
23637c478bd9Sstevel@tonic-gate 			 * a latent bug causes us to spin indefinitely.
23647c478bd9Sstevel@tonic-gate 			 */
23657c478bd9Sstevel@tonic-gate 			if (next > (uintptr_t)buf + size) {
23667c478bd9Sstevel@tonic-gate 				pr_getprot_done(&tmp);
2367dc32d872SJosef 'Jeff' Sipek 				AS_LOCK_EXIT(as);
23687c478bd9Sstevel@tonic-gate 
23697c478bd9Sstevel@tonic-gate 				kmem_free(buf, size);
23707c478bd9Sstevel@tonic-gate 
23717c478bd9Sstevel@tonic-gate 				if (ISSIG(curthread, JUSTLOOKING))
23727c478bd9Sstevel@tonic-gate 					return (EINTR);
23737c478bd9Sstevel@tonic-gate 
23747c478bd9Sstevel@tonic-gate 				goto again;
23757c478bd9Sstevel@tonic-gate 			}
23767c478bd9Sstevel@tonic-gate 
23777c478bd9Sstevel@tonic-gate 			php->pr_nmap++;
23787c478bd9Sstevel@tonic-gate 			php->pr_npage += npage;
23797c478bd9Sstevel@tonic-gate 			pmp->pr_vaddr = (caddr32_t)(uintptr_t)saddr;
23807c478bd9Sstevel@tonic-gate 			pmp->pr_npage = (size32_t)npage;
23817c478bd9Sstevel@tonic-gate 			pmp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
23827c478bd9Sstevel@tonic-gate 			pmp->pr_mflags = 0;
23837c478bd9Sstevel@tonic-gate 			if (prot & PROT_READ)
23847c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_READ;
23857c478bd9Sstevel@tonic-gate 			if (prot & PROT_WRITE)
23867c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_WRITE;
23877c478bd9Sstevel@tonic-gate 			if (prot & PROT_EXEC)
23887c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_EXEC;
23897c478bd9Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_SHARED)
23907c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_SHARED;
23917c478bd9Sstevel@tonic-gate 			if (SEGOP_GETTYPE(seg, saddr) & MAP_NORESERVE)
23927c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_NORESERVE;
23937c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops ||
23947c478bd9Sstevel@tonic-gate 			    (seg->s_ops == &segvn_ops &&
23957c478bd9Sstevel@tonic-gate 			    (SEGOP_GETVP(seg, saddr, &vp) != 0 || vp == NULL)))
23967c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_ANON;
23977c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segspt_shmops)
23987c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_ISM | MA_SHM;
23997c478bd9Sstevel@tonic-gate 			pmp->pr_pagesize = PAGESIZE;
24007c478bd9Sstevel@tonic-gate 			/*
24017c478bd9Sstevel@tonic-gate 			 * Manufacture a filename for the "object" directory.
24027c478bd9Sstevel@tonic-gate 			 */
24037c478bd9Sstevel@tonic-gate 			vattr.va_mask = AT_FSID|AT_NODEID;
24047c478bd9Sstevel@tonic-gate 			if (seg->s_ops == &segvn_ops &&
24057c478bd9Sstevel@tonic-gate 			    SEGOP_GETVP(seg, saddr, &vp) == 0 &&
24067c478bd9Sstevel@tonic-gate 			    vp != NULL && vp->v_type == VREG &&
2407da6c28aaSamw 			    VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
24087c478bd9Sstevel@tonic-gate 				if (vp == p->p_exec)
24097c478bd9Sstevel@tonic-gate 					(void) strcpy(pmp->pr_mapname, "a.out");
24107c478bd9Sstevel@tonic-gate 				else
24117c478bd9Sstevel@tonic-gate 					pr_object_name(pmp->pr_mapname,
24127c478bd9Sstevel@tonic-gate 					    vp, &vattr);
24137c478bd9Sstevel@tonic-gate 			}
24147c478bd9Sstevel@tonic-gate 
24157c478bd9Sstevel@tonic-gate 			/*
24167c478bd9Sstevel@tonic-gate 			 * Get the SysV shared memory id, if any.
24177c478bd9Sstevel@tonic-gate 			 */
24187c478bd9Sstevel@tonic-gate 			if ((pmp->pr_mflags & MA_SHARED) && p->p_segacct &&
24197c478bd9Sstevel@tonic-gate 			    (pmp->pr_shmid = shmgetid(p, seg->s_base)) !=
24207c478bd9Sstevel@tonic-gate 			    SHMID_NONE) {
24217c478bd9Sstevel@tonic-gate 				if (pmp->pr_shmid == SHMID_FREE)
24227c478bd9Sstevel@tonic-gate 					pmp->pr_shmid = -1;
24237c478bd9Sstevel@tonic-gate 
24247c478bd9Sstevel@tonic-gate 				pmp->pr_mflags |= MA_SHM;
24257c478bd9Sstevel@tonic-gate 			} else {
24267c478bd9Sstevel@tonic-gate 				pmp->pr_shmid = -1;
24277c478bd9Sstevel@tonic-gate 			}
24287c478bd9Sstevel@tonic-gate 
24297c478bd9Sstevel@tonic-gate 			hat_getstat(as, saddr, len, hatid,
24307c478bd9Sstevel@tonic-gate 			    (char *)(pmp + 1), HAT_SYNC_ZERORM);
24317c478bd9Sstevel@tonic-gate 			pmp = (prasmap32_t *)next;
24327c478bd9Sstevel@tonic-gate 		}
24337c478bd9Sstevel@tonic-gate 		ASSERT(tmp == NULL);
24347c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
24357c478bd9Sstevel@tonic-gate 
2436dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
24377c478bd9Sstevel@tonic-gate 
24387c478bd9Sstevel@tonic-gate 	ASSERT((uintptr_t)pmp <= (uintptr_t)buf + size);
24397c478bd9Sstevel@tonic-gate 	error = uiomove(buf, (caddr_t)pmp - buf, UIO_READ, uiop);
24407c478bd9Sstevel@tonic-gate 	kmem_free(buf, size);
24417c478bd9Sstevel@tonic-gate 
24427c478bd9Sstevel@tonic-gate 	return (error);
24437c478bd9Sstevel@tonic-gate }
24447c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
24457c478bd9Sstevel@tonic-gate 
24467c478bd9Sstevel@tonic-gate ushort_t
prgetpctcpu(uint64_t pct)24477c478bd9Sstevel@tonic-gate prgetpctcpu(uint64_t pct)
24487c478bd9Sstevel@tonic-gate {
24497c478bd9Sstevel@tonic-gate 	/*
24507c478bd9Sstevel@tonic-gate 	 * The value returned will be relevant in the zone of the examiner,
24517c478bd9Sstevel@tonic-gate 	 * which may not be the same as the zone which performed the procfs
24527c478bd9Sstevel@tonic-gate 	 * mount.
24537c478bd9Sstevel@tonic-gate 	 */
24547c478bd9Sstevel@tonic-gate 	int nonline = zone_ncpus_online_get(curproc->p_zone);
24557c478bd9Sstevel@tonic-gate 
24567c478bd9Sstevel@tonic-gate 	/*
24577c478bd9Sstevel@tonic-gate 	 * Prorate over online cpus so we don't exceed 100%
24587c478bd9Sstevel@tonic-gate 	 */
24597c478bd9Sstevel@tonic-gate 	if (nonline > 1)
24607c478bd9Sstevel@tonic-gate 		pct /= nonline;
24617c478bd9Sstevel@tonic-gate 	pct >>= 16;		/* convert to 16-bit scaled integer */
24627c478bd9Sstevel@tonic-gate 	if (pct > 0x8000)	/* might happen, due to rounding */
24637c478bd9Sstevel@tonic-gate 		pct = 0x8000;
24647c478bd9Sstevel@tonic-gate 	return ((ushort_t)pct);
24657c478bd9Sstevel@tonic-gate }
24667c478bd9Sstevel@tonic-gate 
24677c478bd9Sstevel@tonic-gate /*
24687c478bd9Sstevel@tonic-gate  * Return information used by ps(1).
24697c478bd9Sstevel@tonic-gate  */
24707c478bd9Sstevel@tonic-gate void
prgetpsinfo(proc_t * p,psinfo_t * psp)24717c478bd9Sstevel@tonic-gate prgetpsinfo(proc_t *p, psinfo_t *psp)
24727c478bd9Sstevel@tonic-gate {
24737c478bd9Sstevel@tonic-gate 	kthread_t *t;
24747c478bd9Sstevel@tonic-gate 	struct cred *cred;
24757c478bd9Sstevel@tonic-gate 	hrtime_t hrutime, hrstime;
24767c478bd9Sstevel@tonic-gate 
24777c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
24787c478bd9Sstevel@tonic-gate 
24797c478bd9Sstevel@tonic-gate 	if ((t = prchoose(p)) == NULL)	/* returns locked thread */
24807c478bd9Sstevel@tonic-gate 		bzero(psp, sizeof (*psp));
24817c478bd9Sstevel@tonic-gate 	else {
24827c478bd9Sstevel@tonic-gate 		thread_unlock(t);
24837c478bd9Sstevel@tonic-gate 		bzero(psp, sizeof (*psp) - sizeof (psp->pr_lwp));
24847c478bd9Sstevel@tonic-gate 	}
24857c478bd9Sstevel@tonic-gate 
24867c478bd9Sstevel@tonic-gate 	/*
24877c478bd9Sstevel@tonic-gate 	 * only export SSYS and SMSACCT; everything else is off-limits to
24887c478bd9Sstevel@tonic-gate 	 * userland apps.
24897c478bd9Sstevel@tonic-gate 	 */
24907c478bd9Sstevel@tonic-gate 	psp->pr_flag = p->p_flag & (SSYS | SMSACCT);
24917c478bd9Sstevel@tonic-gate 	psp->pr_nlwp = p->p_lwpcnt;
24927c478bd9Sstevel@tonic-gate 	psp->pr_nzomb = p->p_zombcnt;
24937c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
24947c478bd9Sstevel@tonic-gate 	cred = p->p_cred;
24957c478bd9Sstevel@tonic-gate 	psp->pr_uid = crgetruid(cred);
24967c478bd9Sstevel@tonic-gate 	psp->pr_euid = crgetuid(cred);
24977c478bd9Sstevel@tonic-gate 	psp->pr_gid = crgetrgid(cred);
24987c478bd9Sstevel@tonic-gate 	psp->pr_egid = crgetgid(cred);
24997c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
25007c478bd9Sstevel@tonic-gate 	psp->pr_pid = p->p_pid;
25017c478bd9Sstevel@tonic-gate 	if (curproc->p_zone->zone_id != GLOBAL_ZONEID &&
25027c478bd9Sstevel@tonic-gate 	    (p->p_flag & SZONETOP)) {
25037c478bd9Sstevel@tonic-gate 		ASSERT(p->p_zone->zone_id != GLOBAL_ZONEID);
25047c478bd9Sstevel@tonic-gate 		/*
25057c478bd9Sstevel@tonic-gate 		 * Inside local zones, fake zsched's pid as parent pids for
25067c478bd9Sstevel@tonic-gate 		 * processes which reference processes outside of the zone.
25077c478bd9Sstevel@tonic-gate 		 */
25087c478bd9Sstevel@tonic-gate 		psp->pr_ppid = curproc->p_zone->zone_zsched->p_pid;
25097c478bd9Sstevel@tonic-gate 	} else {
25107c478bd9Sstevel@tonic-gate 		psp->pr_ppid = p->p_ppid;
25117c478bd9Sstevel@tonic-gate 	}
25127c478bd9Sstevel@tonic-gate 	psp->pr_pgid = p->p_pgrp;
25137c478bd9Sstevel@tonic-gate 	psp->pr_sid = p->p_sessp->s_sid;
25147c478bd9Sstevel@tonic-gate 	psp->pr_taskid = p->p_task->tk_tkid;
25157c478bd9Sstevel@tonic-gate 	psp->pr_projid = p->p_task->tk_proj->kpj_id;
25167c478bd9Sstevel@tonic-gate 	psp->pr_poolid = p->p_pool->pool_id;
25177c478bd9Sstevel@tonic-gate 	psp->pr_zoneid = p->p_zone->zone_id;
25187c478bd9Sstevel@tonic-gate 	if ((psp->pr_contract = PRCTID(p)) == 0)
25197c478bd9Sstevel@tonic-gate 		psp->pr_contract = -1;
25207c478bd9Sstevel@tonic-gate 	psp->pr_addr = (uintptr_t)prgetpsaddr(p);
25217c478bd9Sstevel@tonic-gate 	switch (p->p_model) {
25227c478bd9Sstevel@tonic-gate 	case DATAMODEL_ILP32:
25237c478bd9Sstevel@tonic-gate 		psp->pr_dmodel = PR_MODEL_ILP32;
25247c478bd9Sstevel@tonic-gate 		break;
25257c478bd9Sstevel@tonic-gate 	case DATAMODEL_LP64:
25267c478bd9Sstevel@tonic-gate 		psp->pr_dmodel = PR_MODEL_LP64;
25277c478bd9Sstevel@tonic-gate 		break;
25287c478bd9Sstevel@tonic-gate 	}
25297c478bd9Sstevel@tonic-gate 	hrutime = mstate_aggr_state(p, LMS_USER);
25307c478bd9Sstevel@tonic-gate 	hrstime = mstate_aggr_state(p, LMS_SYSTEM);
25317c478bd9Sstevel@tonic-gate 	hrt2ts((hrutime + hrstime), &psp->pr_time);
25327c478bd9Sstevel@tonic-gate 	TICK_TO_TIMESTRUC(p->p_cutime + p->p_cstime, &psp->pr_ctime);
25337c478bd9Sstevel@tonic-gate 
25347c478bd9Sstevel@tonic-gate 	if (t == NULL) {
25357c478bd9Sstevel@tonic-gate 		int wcode = p->p_wcode;		/* must be atomic read */
25367c478bd9Sstevel@tonic-gate 
25377c478bd9Sstevel@tonic-gate 		if (wcode)
25387c478bd9Sstevel@tonic-gate 			psp->pr_wstat = wstat(wcode, p->p_wdata);
25397c478bd9Sstevel@tonic-gate 		psp->pr_ttydev = PRNODEV;
25407c478bd9Sstevel@tonic-gate 		psp->pr_lwp.pr_state = SZOMB;
25417c478bd9Sstevel@tonic-gate 		psp->pr_lwp.pr_sname = 'Z';
25427c478bd9Sstevel@tonic-gate 		psp->pr_lwp.pr_bindpro = PBIND_NONE;
25437c478bd9Sstevel@tonic-gate 		psp->pr_lwp.pr_bindpset = PS_NONE;
25447c478bd9Sstevel@tonic-gate 	} else {
25457c478bd9Sstevel@tonic-gate 		user_t *up = PTOU(p);
25467c478bd9Sstevel@tonic-gate 		struct as *as;
25477c478bd9Sstevel@tonic-gate 		dev_t d;
25487c478bd9Sstevel@tonic-gate 		extern dev_t rwsconsdev, rconsdev, uconsdev;
25497c478bd9Sstevel@tonic-gate 
25507c478bd9Sstevel@tonic-gate 		d = cttydev(p);
25517c478bd9Sstevel@tonic-gate 		/*
25527c478bd9Sstevel@tonic-gate 		 * If the controlling terminal is the real
25537c478bd9Sstevel@tonic-gate 		 * or workstation console device, map to what the
255425b463cdSethindra 		 * user thinks is the console device. Handle case when
255525b463cdSethindra 		 * rwsconsdev or rconsdev is set to NODEV for Starfire.
25567c478bd9Sstevel@tonic-gate 		 */
255725b463cdSethindra 		if ((d == rwsconsdev || d == rconsdev) && d != NODEV)
25587c478bd9Sstevel@tonic-gate 			d = uconsdev;
25597c478bd9Sstevel@tonic-gate 		psp->pr_ttydev = (d == NODEV) ? PRNODEV : d;
25607c478bd9Sstevel@tonic-gate 		psp->pr_start = up->u_start;
25617c478bd9Sstevel@tonic-gate 		bcopy(up->u_comm, psp->pr_fname,
25627c478bd9Sstevel@tonic-gate 		    MIN(sizeof (up->u_comm), sizeof (psp->pr_fname)-1));
25637c478bd9Sstevel@tonic-gate 		bcopy(up->u_psargs, psp->pr_psargs,
25647c478bd9Sstevel@tonic-gate 		    MIN(PRARGSZ-1, PSARGSZ));
25657c478bd9Sstevel@tonic-gate 		psp->pr_argc = up->u_argc;
25667c478bd9Sstevel@tonic-gate 		psp->pr_argv = up->u_argv;
25677c478bd9Sstevel@tonic-gate 		psp->pr_envp = up->u_envp;
25687c478bd9Sstevel@tonic-gate 
25697c478bd9Sstevel@tonic-gate 		/* get the chosen lwp's lwpsinfo */
25707c478bd9Sstevel@tonic-gate 		prgetlwpsinfo(t, &psp->pr_lwp);
25717c478bd9Sstevel@tonic-gate 
25727c478bd9Sstevel@tonic-gate 		/* compute %cpu for the process */
25737c478bd9Sstevel@tonic-gate 		if (p->p_lwpcnt == 1)
25747c478bd9Sstevel@tonic-gate 			psp->pr_pctcpu = psp->pr_lwp.pr_pctcpu;
25757c478bd9Sstevel@tonic-gate 		else {
25767c478bd9Sstevel@tonic-gate 			uint64_t pct = 0;
25777c478bd9Sstevel@tonic-gate 			hrtime_t cur_time = gethrtime_unscaled();
25787c478bd9Sstevel@tonic-gate 
25797c478bd9Sstevel@tonic-gate 			t = p->p_tlist;
25807c478bd9Sstevel@tonic-gate 			do {
25817c478bd9Sstevel@tonic-gate 				pct += cpu_update_pct(t, cur_time);
25827c478bd9Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
25837c478bd9Sstevel@tonic-gate 
25847c478bd9Sstevel@tonic-gate 			psp->pr_pctcpu = prgetpctcpu(pct);
25857c478bd9Sstevel@tonic-gate 		}
25867c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
25877c478bd9Sstevel@tonic-gate 			psp->pr_size = 0;
25887c478bd9Sstevel@tonic-gate 			psp->pr_rssize = 0;
25897c478bd9Sstevel@tonic-gate 		} else {
25907c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
2591dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_READER);
259240688216SSudheer A 			psp->pr_size = btopr(as->a_resvsize) *
259340688216SSudheer A 			    (PAGESIZE / 1024);
25947c478bd9Sstevel@tonic-gate 			psp->pr_rssize = rm_asrss(as) * (PAGESIZE / 1024);
25957c478bd9Sstevel@tonic-gate 			psp->pr_pctmem = rm_pctmemory(as);
2596dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
25977c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
25987c478bd9Sstevel@tonic-gate 		}
25997c478bd9Sstevel@tonic-gate 	}
26007c478bd9Sstevel@tonic-gate }
26017c478bd9Sstevel@tonic-gate 
2602a02120c4SAndy Fiddaman static size_t
prfdinfomisc(list_t * data,uint_t type,const void * val,size_t vlen)2603a02120c4SAndy Fiddaman prfdinfomisc(list_t *data, uint_t type, const void *val, size_t vlen)
2604a02120c4SAndy Fiddaman {
2605a02120c4SAndy Fiddaman 	pr_misc_header_t *misc;
2606a02120c4SAndy Fiddaman 	size_t len;
2607a02120c4SAndy Fiddaman 
2608a02120c4SAndy Fiddaman 	len = PRFDINFO_ROUNDUP(sizeof (*misc) + vlen);
2609a02120c4SAndy Fiddaman 
2610a02120c4SAndy Fiddaman 	if (data != NULL) {
2611a02120c4SAndy Fiddaman 		misc = pr_iol_newbuf(data, len);
2612a02120c4SAndy Fiddaman 		misc->pr_misc_type = type;
2613a02120c4SAndy Fiddaman 		misc->pr_misc_size = len;
2614a02120c4SAndy Fiddaman 		misc++;
2615a02120c4SAndy Fiddaman 		bcopy((char *)val, (char *)misc, vlen);
2616a02120c4SAndy Fiddaman 	}
2617a02120c4SAndy Fiddaman 
2618a02120c4SAndy Fiddaman 	return (len);
2619a02120c4SAndy Fiddaman }
2620a02120c4SAndy Fiddaman 
2621a02120c4SAndy Fiddaman /*
2622a02120c4SAndy Fiddaman  * There's no elegant way to determine if a character device
2623a02120c4SAndy Fiddaman  * supports TLI, so just check a hardcoded list of known TLI
2624a02120c4SAndy Fiddaman  * devices.
2625a02120c4SAndy Fiddaman  */
2626a02120c4SAndy Fiddaman 
2627a02120c4SAndy Fiddaman static boolean_t
pristli(vnode_t * vp)2628a02120c4SAndy Fiddaman pristli(vnode_t *vp)
2629a02120c4SAndy Fiddaman {
2630a02120c4SAndy Fiddaman 	static const char *tlidevs[] = {
2631a02120c4SAndy Fiddaman 	    "udp", "udp6", "tcp", "tcp6"
2632a02120c4SAndy Fiddaman 	};
2633a02120c4SAndy Fiddaman 	char *devname;
2634a02120c4SAndy Fiddaman 	uint_t i;
2635a02120c4SAndy Fiddaman 
2636a02120c4SAndy Fiddaman 	ASSERT(vp != NULL);
2637a02120c4SAndy Fiddaman 
2638a02120c4SAndy Fiddaman 	if (vp->v_type != VCHR || vp->v_stream == NULL || vp->v_rdev == 0)
2639a02120c4SAndy Fiddaman 		return (B_FALSE);
2640a02120c4SAndy Fiddaman 
2641a02120c4SAndy Fiddaman 	if ((devname = mod_major_to_name(getmajor(vp->v_rdev))) == NULL)
2642a02120c4SAndy Fiddaman 		return (B_FALSE);
2643a02120c4SAndy Fiddaman 
2644a02120c4SAndy Fiddaman 	for (i = 0; i < ARRAY_SIZE(tlidevs); i++) {
2645a02120c4SAndy Fiddaman 		if (strcmp(devname, tlidevs[i]) == 0)
2646a02120c4SAndy Fiddaman 			return (B_TRUE);
2647a02120c4SAndy Fiddaman 	}
2648a02120c4SAndy Fiddaman 
2649a02120c4SAndy Fiddaman 	return (B_FALSE);
2650a02120c4SAndy Fiddaman }
2651a02120c4SAndy Fiddaman 
2652a02120c4SAndy Fiddaman static size_t
prfdinfopath(proc_t * p,vnode_t * vp,list_t * data,cred_t * cred)2653a02120c4SAndy Fiddaman prfdinfopath(proc_t *p, vnode_t *vp, list_t *data, cred_t *cred)
2654a02120c4SAndy Fiddaman {
2655a02120c4SAndy Fiddaman 	char *pathname;
2656a02120c4SAndy Fiddaman 	size_t pathlen;
2657a02120c4SAndy Fiddaman 	size_t sz = 0;
2658a02120c4SAndy Fiddaman 
26598950e535SAndy Fiddaman 	/*
26608950e535SAndy Fiddaman 	 * The global zone's path to a file in a non-global zone can exceed
26618950e535SAndy Fiddaman 	 * MAXPATHLEN.
26628950e535SAndy Fiddaman 	 */
26638950e535SAndy Fiddaman 	pathlen = MAXPATHLEN * 2 + 1;
2664a02120c4SAndy Fiddaman 	pathname = kmem_alloc(pathlen, KM_SLEEP);
2665a02120c4SAndy Fiddaman 
266619ee9cd1SAndy Fiddaman 	if (vnodetopath(NULL, vp, pathname, pathlen, cred) == 0) {
2667a02120c4SAndy Fiddaman 		sz += prfdinfomisc(data, PR_PATHNAME,
2668a02120c4SAndy Fiddaman 		    pathname, strlen(pathname) + 1);
2669a02120c4SAndy Fiddaman 	}
2670a02120c4SAndy Fiddaman 
2671a02120c4SAndy Fiddaman 	kmem_free(pathname, pathlen);
26728950e535SAndy Fiddaman 
2673a02120c4SAndy Fiddaman 	return (sz);
2674a02120c4SAndy Fiddaman }
2675a02120c4SAndy Fiddaman 
2676a02120c4SAndy Fiddaman static size_t
prfdinfotlisockopt(vnode_t * vp,list_t * data,cred_t * cred)2677a02120c4SAndy Fiddaman prfdinfotlisockopt(vnode_t *vp, list_t *data, cred_t *cred)
2678a02120c4SAndy Fiddaman {
2679a02120c4SAndy Fiddaman 	strcmd_t strcmd;
2680a02120c4SAndy Fiddaman 	int32_t rval;
2681a02120c4SAndy Fiddaman 	size_t sz = 0;
2682a02120c4SAndy Fiddaman 
2683a02120c4SAndy Fiddaman 	strcmd.sc_cmd = TI_GETMYNAME;
2684a02120c4SAndy Fiddaman 	strcmd.sc_timeout = 1;
2685a02120c4SAndy Fiddaman 	strcmd.sc_len = STRCMDBUFSIZE;
2686a02120c4SAndy Fiddaman 
2687a02120c4SAndy Fiddaman 	if (VOP_IOCTL(vp, _I_CMD, (intptr_t)&strcmd, FKIOCTL, cred,
2688a02120c4SAndy Fiddaman 	    &rval, NULL) == 0 && strcmd.sc_len > 0) {
2689a02120c4SAndy Fiddaman 		sz += prfdinfomisc(data, PR_SOCKETNAME, strcmd.sc_buf,
2690a02120c4SAndy Fiddaman 		    strcmd.sc_len);
2691a02120c4SAndy Fiddaman 	}
2692a02120c4SAndy Fiddaman 
2693a02120c4SAndy Fiddaman 	strcmd.sc_cmd = TI_GETPEERNAME;
2694a02120c4SAndy Fiddaman 	strcmd.sc_timeout = 1;
2695a02120c4SAndy Fiddaman 	strcmd.sc_len = STRCMDBUFSIZE;
2696a02120c4SAndy Fiddaman 
2697a02120c4SAndy Fiddaman 	if (VOP_IOCTL(vp, _I_CMD, (intptr_t)&strcmd, FKIOCTL, cred,
2698a02120c4SAndy Fiddaman 	    &rval, NULL) == 0 && strcmd.sc_len > 0) {
2699a02120c4SAndy Fiddaman 		sz += prfdinfomisc(data, PR_PEERSOCKNAME, strcmd.sc_buf,
2700a02120c4SAndy Fiddaman 		    strcmd.sc_len);
2701a02120c4SAndy Fiddaman 	}
2702a02120c4SAndy Fiddaman 
2703a02120c4SAndy Fiddaman 	return (sz);
2704a02120c4SAndy Fiddaman }
2705a02120c4SAndy Fiddaman 
2706a02120c4SAndy Fiddaman static size_t
prfdinfosockopt(vnode_t * vp,list_t * data,cred_t * cred)2707a02120c4SAndy Fiddaman prfdinfosockopt(vnode_t *vp, list_t *data, cred_t *cred)
2708a02120c4SAndy Fiddaman {
2709a02120c4SAndy Fiddaman 	sonode_t *so;
2710a02120c4SAndy Fiddaman 	socklen_t vlen;
2711a02120c4SAndy Fiddaman 	size_t sz = 0;
2712a02120c4SAndy Fiddaman 	uint_t i;
2713a02120c4SAndy Fiddaman 
2714a02120c4SAndy Fiddaman 	if (vp->v_stream != NULL) {
2715a02120c4SAndy Fiddaman 		so = VTOSO(vp->v_stream->sd_vnode);
2716a02120c4SAndy Fiddaman 
2717a02120c4SAndy Fiddaman 		if (so->so_version == SOV_STREAM)
2718a02120c4SAndy Fiddaman 			so = NULL;
2719a02120c4SAndy Fiddaman 	} else {
2720a02120c4SAndy Fiddaman 		so = VTOSO(vp);
2721a02120c4SAndy Fiddaman 	}
2722a02120c4SAndy Fiddaman 
2723a02120c4SAndy Fiddaman 	if (so == NULL)
2724a02120c4SAndy Fiddaman 		return (0);
2725a02120c4SAndy Fiddaman 
2726a02120c4SAndy Fiddaman 	DTRACE_PROBE1(sonode, sonode_t *, so);
2727a02120c4SAndy Fiddaman 
2728a02120c4SAndy Fiddaman 	/* prmisc - PR_SOCKETNAME */
2729a02120c4SAndy Fiddaman 
2730a02120c4SAndy Fiddaman 	struct sockaddr_storage buf;
2731a02120c4SAndy Fiddaman 	struct sockaddr *name = (struct sockaddr *)&buf;
2732a02120c4SAndy Fiddaman 
2733a02120c4SAndy Fiddaman 	vlen = sizeof (buf);
2734a02120c4SAndy Fiddaman 	if (SOP_GETSOCKNAME(so, name, &vlen, cred) == 0 && vlen > 0)
2735a02120c4SAndy Fiddaman 		sz += prfdinfomisc(data, PR_SOCKETNAME, name, vlen);
2736a02120c4SAndy Fiddaman 
2737a02120c4SAndy Fiddaman 	/* prmisc - PR_PEERSOCKNAME */
2738a02120c4SAndy Fiddaman 
2739a02120c4SAndy Fiddaman 	vlen = sizeof (buf);
2740a02120c4SAndy Fiddaman 	if (SOP_GETPEERNAME(so, name, &vlen, B_FALSE, cred) == 0 && vlen > 0)
2741a02120c4SAndy Fiddaman 		sz += prfdinfomisc(data, PR_PEERSOCKNAME, name, vlen);
2742a02120c4SAndy Fiddaman 
2743a02120c4SAndy Fiddaman 	/* prmisc - PR_SOCKOPTS_BOOL_OPTS */
2744a02120c4SAndy Fiddaman 
2745a02120c4SAndy Fiddaman 	static struct boolopt {
2746a02120c4SAndy Fiddaman 		int		level;
2747a02120c4SAndy Fiddaman 		int		opt;
2748a02120c4SAndy Fiddaman 		int		bopt;
2749a02120c4SAndy Fiddaman 	} boolopts[] = {
2750a02120c4SAndy Fiddaman 		{ SOL_SOCKET, SO_DEBUG,		PR_SO_DEBUG },
2751a02120c4SAndy Fiddaman 		{ SOL_SOCKET, SO_REUSEADDR,	PR_SO_REUSEADDR },
2752a02120c4SAndy Fiddaman #ifdef SO_REUSEPORT
2753a02120c4SAndy Fiddaman 		/* SmartOS and OmniOS have SO_REUSEPORT */
2754a02120c4SAndy Fiddaman 		{ SOL_SOCKET, SO_REUSEPORT,	PR_SO_REUSEPORT },
2755a02120c4SAndy Fiddaman #endif
2756a02120c4SAndy Fiddaman 		{ SOL_SOCKET, SO_KEEPALIVE,	PR_SO_KEEPALIVE },
2757a02120c4SAndy Fiddaman 		{ SOL_SOCKET, SO_DONTROUTE,	PR_SO_DONTROUTE },
2758a02120c4SAndy Fiddaman 		{ SOL_SOCKET, SO_BROADCAST,	PR_SO_BROADCAST },
2759a02120c4SAndy Fiddaman 		{ SOL_SOCKET, SO_OOBINLINE,	PR_SO_OOBINLINE },
2760a02120c4SAndy Fiddaman 		{ SOL_SOCKET, SO_DGRAM_ERRIND,	PR_SO_DGRAM_ERRIND },
2761a02120c4SAndy Fiddaman 		{ SOL_SOCKET, SO_ALLZONES,	PR_SO_ALLZONES },
2762a02120c4SAndy Fiddaman 		{ SOL_SOCKET, SO_MAC_EXEMPT,	PR_SO_MAC_EXEMPT },
2763a02120c4SAndy Fiddaman 		{ SOL_SOCKET, SO_MAC_IMPLICIT,	PR_SO_MAC_IMPLICIT },
2764a02120c4SAndy Fiddaman 		{ SOL_SOCKET, SO_EXCLBIND,	PR_SO_EXCLBIND },
2765a02120c4SAndy Fiddaman 		{ SOL_SOCKET, SO_VRRP,		PR_SO_VRRP },
2766a02120c4SAndy Fiddaman 		{ IPPROTO_UDP, UDP_NAT_T_ENDPOINT,
2767a02120c4SAndy Fiddaman 		    PR_UDP_NAT_T_ENDPOINT }
2768a02120c4SAndy Fiddaman 	};
2769a02120c4SAndy Fiddaman 	prsockopts_bool_opts_t opts;
2770a02120c4SAndy Fiddaman 	int val;
2771a02120c4SAndy Fiddaman 
2772a02120c4SAndy Fiddaman 	if (data != NULL) {
2773a02120c4SAndy Fiddaman 		opts.prsock_bool_opts = 0;
2774a02120c4SAndy Fiddaman 
2775a02120c4SAndy Fiddaman 		for (i = 0; i < ARRAY_SIZE(boolopts); i++) {
2776a02120c4SAndy Fiddaman 			vlen = sizeof (val);
2777a02120c4SAndy Fiddaman 			if (SOP_GETSOCKOPT(so, boolopts[i].level,
2778a02120c4SAndy Fiddaman 			    boolopts[i].opt, &val, &vlen, 0, cred) == 0 &&
2779a02120c4SAndy Fiddaman 			    val != 0) {
2780a02120c4SAndy Fiddaman 				opts.prsock_bool_opts |= boolopts[i].bopt;
2781a02120c4SAndy Fiddaman 			}
2782a02120c4SAndy Fiddaman 		}
2783a02120c4SAndy Fiddaman 	}
2784a02120c4SAndy Fiddaman 
2785a02120c4SAndy Fiddaman 	sz += prfdinfomisc(data, PR_SOCKOPTS_BOOL_OPTS, &opts, sizeof (opts));
2786a02120c4SAndy Fiddaman 
2787a02120c4SAndy Fiddaman 	/* prmisc - PR_SOCKOPT_LINGER */
2788a02120c4SAndy Fiddaman 
2789a02120c4SAndy Fiddaman 	struct linger l;
2790a02120c4SAndy Fiddaman 
2791a02120c4SAndy Fiddaman 	vlen = sizeof (l);
2792a02120c4SAndy Fiddaman 	if (SOP_GETSOCKOPT(so, SOL_SOCKET, SO_LINGER, &l, &vlen,
2793a02120c4SAndy Fiddaman 	    0, cred) == 0 && vlen > 0) {
2794a02120c4SAndy Fiddaman 		sz += prfdinfomisc(data, PR_SOCKOPT_LINGER, &l, vlen);
2795a02120c4SAndy Fiddaman 	}
2796a02120c4SAndy Fiddaman 
2797a02120c4SAndy Fiddaman 	/* prmisc - PR_SOCKOPT_* int types */
2798a02120c4SAndy Fiddaman 
2799a02120c4SAndy Fiddaman 	static struct sopt {
2800a02120c4SAndy Fiddaman 		int		level;
2801a02120c4SAndy Fiddaman 		int		opt;
2802a02120c4SAndy Fiddaman 		int		bopt;
2803a02120c4SAndy Fiddaman 	} sopts[] = {
2804a02120c4SAndy Fiddaman 		{ SOL_SOCKET, SO_TYPE,		PR_SOCKOPT_TYPE },
2805a02120c4SAndy Fiddaman 		{ SOL_SOCKET, SO_SNDBUF,	PR_SOCKOPT_SNDBUF },
2806a02120c4SAndy Fiddaman 		{ SOL_SOCKET, SO_RCVBUF,	PR_SOCKOPT_RCVBUF }
2807a02120c4SAndy Fiddaman 	};
2808a02120c4SAndy Fiddaman 
2809a02120c4SAndy Fiddaman 	for (i = 0; i < ARRAY_SIZE(sopts); i++) {
2810a02120c4SAndy Fiddaman 		vlen = sizeof (val);
2811a02120c4SAndy Fiddaman 		if (SOP_GETSOCKOPT(so, sopts[i].level, sopts[i].opt,
2812a02120c4SAndy Fiddaman 		    &val, &vlen, 0, cred) == 0 && vlen > 0) {
2813a02120c4SAndy Fiddaman 			sz += prfdinfomisc(data, sopts[i].bopt, &val, vlen);
2814a02120c4SAndy Fiddaman 		}
2815a02120c4SAndy Fiddaman 	}
2816a02120c4SAndy Fiddaman 
2817a02120c4SAndy Fiddaman 	/* prmisc - PR_SOCKOPT_IP_NEXTHOP */
2818a02120c4SAndy Fiddaman 
2819a02120c4SAndy Fiddaman 	in_addr_t nexthop_val;
2820a02120c4SAndy Fiddaman 
2821a02120c4SAndy Fiddaman 	vlen = sizeof (nexthop_val);
2822a02120c4SAndy Fiddaman 	if (SOP_GETSOCKOPT(so, IPPROTO_IP, IP_NEXTHOP,
2823a02120c4SAndy Fiddaman 	    &nexthop_val, &vlen, 0, cred) == 0 && vlen > 0) {
2824a02120c4SAndy Fiddaman 		sz += prfdinfomisc(data, PR_SOCKOPT_IP_NEXTHOP,
2825a02120c4SAndy Fiddaman 		    &nexthop_val, vlen);
2826a02120c4SAndy Fiddaman 	}
2827a02120c4SAndy Fiddaman 
2828a02120c4SAndy Fiddaman 	/* prmisc - PR_SOCKOPT_IPV6_NEXTHOP */
2829a02120c4SAndy Fiddaman 
2830a02120c4SAndy Fiddaman 	struct sockaddr_in6 nexthop6_val;
2831a02120c4SAndy Fiddaman 
2832a02120c4SAndy Fiddaman 	vlen = sizeof (nexthop6_val);
2833a02120c4SAndy Fiddaman 	if (SOP_GETSOCKOPT(so, IPPROTO_IPV6, IPV6_NEXTHOP,
2834a02120c4SAndy Fiddaman 	    &nexthop6_val, &vlen, 0, cred) == 0 && vlen > 0) {
2835a02120c4SAndy Fiddaman 		sz += prfdinfomisc(data, PR_SOCKOPT_IPV6_NEXTHOP,
2836a02120c4SAndy Fiddaman 		    &nexthop6_val, vlen);
2837a02120c4SAndy Fiddaman 	}
2838a02120c4SAndy Fiddaman 
2839a02120c4SAndy Fiddaman 	/* prmisc - PR_SOCKOPT_TCP_CONGESTION */
2840a02120c4SAndy Fiddaman 
2841a02120c4SAndy Fiddaman 	char cong[CC_ALGO_NAME_MAX];
2842a02120c4SAndy Fiddaman 
2843a02120c4SAndy Fiddaman 	vlen = sizeof (cong);
2844a02120c4SAndy Fiddaman 	if (SOP_GETSOCKOPT(so, IPPROTO_TCP, TCP_CONGESTION,
2845a02120c4SAndy Fiddaman 	    &cong, &vlen, 0, cred) == 0 && vlen > 0) {
2846a02120c4SAndy Fiddaman 		sz += prfdinfomisc(data, PR_SOCKOPT_TCP_CONGESTION, cong, vlen);
2847a02120c4SAndy Fiddaman 	}
2848a02120c4SAndy Fiddaman 
2849a02120c4SAndy Fiddaman 	/* prmisc - PR_SOCKFILTERS_PRIV */
2850a02120c4SAndy Fiddaman 
2851a02120c4SAndy Fiddaman 	struct fil_info fi;
2852a02120c4SAndy Fiddaman 
2853a02120c4SAndy Fiddaman 	vlen = sizeof (fi);
2854a02120c4SAndy Fiddaman 	if (SOP_GETSOCKOPT(so, SOL_FILTER, FIL_LIST,
2855a02120c4SAndy Fiddaman 	    &fi, &vlen, 0, cred) == 0 && vlen != 0) {
2856a02120c4SAndy Fiddaman 		pr_misc_header_t *misc;
2857a02120c4SAndy Fiddaman 		size_t len;
2858a02120c4SAndy Fiddaman 
2859a02120c4SAndy Fiddaman 		/*
2860a02120c4SAndy Fiddaman 		 * We limit the number of returned filters to 32.
2861a02120c4SAndy Fiddaman 		 * This is the maximum number that pfiles will print
2862a02120c4SAndy Fiddaman 		 * anyway.
2863a02120c4SAndy Fiddaman 		 */
2864a02120c4SAndy Fiddaman 		vlen = MIN(32, fi.fi_pos + 1);
2865a02120c4SAndy Fiddaman 		vlen *= sizeof (fi);
2866a02120c4SAndy Fiddaman 
2867a02120c4SAndy Fiddaman 		len = PRFDINFO_ROUNDUP(sizeof (*misc) + vlen);
2868a02120c4SAndy Fiddaman 		sz += len;
2869a02120c4SAndy Fiddaman 
2870a02120c4SAndy Fiddaman 		if (data != NULL) {
2871a02120c4SAndy Fiddaman 			/*
2872a02120c4SAndy Fiddaman 			 * So that the filter list can be built incrementally,
2873a02120c4SAndy Fiddaman 			 * prfdinfomisc() is not used here. Instead we
2874a02120c4SAndy Fiddaman 			 * allocate a buffer directly on the copyout list using
2875a02120c4SAndy Fiddaman 			 * pr_iol_newbuf()
2876a02120c4SAndy Fiddaman 			 */
2877a02120c4SAndy Fiddaman 			misc = pr_iol_newbuf(data, len);
2878a02120c4SAndy Fiddaman 			misc->pr_misc_type = PR_SOCKFILTERS_PRIV;
2879a02120c4SAndy Fiddaman 			misc->pr_misc_size = len;
2880a02120c4SAndy Fiddaman 			misc++;
2881a02120c4SAndy Fiddaman 			len = vlen;
2882a02120c4SAndy Fiddaman 			if (SOP_GETSOCKOPT(so, SOL_FILTER, FIL_LIST,
2883a02120c4SAndy Fiddaman 			    misc, &vlen, 0, cred) == 0) {
2884a02120c4SAndy Fiddaman 				/*
2885a02120c4SAndy Fiddaman 				 * In case the number of filters has reduced
2886a02120c4SAndy Fiddaman 				 * since the first call, explicitly zero out
2887a02120c4SAndy Fiddaman 				 * any unpopulated space.
2888a02120c4SAndy Fiddaman 				 */
2889a02120c4SAndy Fiddaman 				if (vlen < len)
2890a02120c4SAndy Fiddaman 					bzero(misc + vlen, len - vlen);
2891a02120c4SAndy Fiddaman 			} else {
2892a02120c4SAndy Fiddaman 				/* Something went wrong, zero out the result */
2893a02120c4SAndy Fiddaman 				bzero(misc, vlen);
2894a02120c4SAndy Fiddaman 			}
2895a02120c4SAndy Fiddaman 		}
2896a02120c4SAndy Fiddaman 	}
2897a02120c4SAndy Fiddaman 
2898a02120c4SAndy Fiddaman 	return (sz);
2899a02120c4SAndy Fiddaman }
2900a02120c4SAndy Fiddaman 
29018950e535SAndy Fiddaman typedef struct prfdinfo_nm_path_cbdata {
29028950e535SAndy Fiddaman 	proc_t		*nmp_p;
29038950e535SAndy Fiddaman 	u_offset_t	nmp_sz;
29048950e535SAndy Fiddaman 	list_t		*nmp_data;
29058950e535SAndy Fiddaman } prfdinfo_nm_path_cbdata_t;
29068950e535SAndy Fiddaman 
29078950e535SAndy Fiddaman static int
prfdinfo_nm_path(const struct namenode * np,cred_t * cred,void * arg)29088950e535SAndy Fiddaman prfdinfo_nm_path(const struct namenode *np, cred_t *cred, void *arg)
29098950e535SAndy Fiddaman {
29108950e535SAndy Fiddaman 	prfdinfo_nm_path_cbdata_t *cb = arg;
29118950e535SAndy Fiddaman 
29128950e535SAndy Fiddaman 	cb->nmp_sz += prfdinfopath(cb->nmp_p, np->nm_vnode, cb->nmp_data, cred);
29138950e535SAndy Fiddaman 
29148950e535SAndy Fiddaman 	return (0);
29158950e535SAndy Fiddaman }
29168950e535SAndy Fiddaman 
2917a02120c4SAndy Fiddaman u_offset_t
prgetfdinfosize(proc_t * p,vnode_t * vp,cred_t * cred)2918a02120c4SAndy Fiddaman prgetfdinfosize(proc_t *p, vnode_t *vp, cred_t *cred)
2919a02120c4SAndy Fiddaman {
2920a02120c4SAndy Fiddaman 	u_offset_t sz;
2921a02120c4SAndy Fiddaman 
2922a02120c4SAndy Fiddaman 	/*
2923a02120c4SAndy Fiddaman 	 * All fdinfo files will be at least this big -
2924a02120c4SAndy Fiddaman 	 * sizeof fdinfo struct + zero length trailer
2925a02120c4SAndy Fiddaman 	 */
2926a02120c4SAndy Fiddaman 	sz = offsetof(prfdinfo_t, pr_misc) + sizeof (pr_misc_header_t);
2927a02120c4SAndy Fiddaman 
2928a02120c4SAndy Fiddaman 	/* Pathname */
29298950e535SAndy Fiddaman 	switch (vp->v_type) {
29308950e535SAndy Fiddaman 	case VDOOR: {
29318950e535SAndy Fiddaman 		prfdinfo_nm_path_cbdata_t cb = {
29328950e535SAndy Fiddaman 			.nmp_p		= p,
29338950e535SAndy Fiddaman 			.nmp_data	= NULL,
29348950e535SAndy Fiddaman 			.nmp_sz		= 0
29358950e535SAndy Fiddaman 		};
29368950e535SAndy Fiddaman 
29378950e535SAndy Fiddaman 		(void) nm_walk_mounts(vp, prfdinfo_nm_path, cred, &cb);
29388950e535SAndy Fiddaman 		sz += cb.nmp_sz;
29398950e535SAndy Fiddaman 		break;
29408950e535SAndy Fiddaman 	}
29418950e535SAndy Fiddaman 	case VSOCK:
29428950e535SAndy Fiddaman 		break;
29438950e535SAndy Fiddaman 	default:
2944a02120c4SAndy Fiddaman 		sz += prfdinfopath(p, vp, NULL, cred);
29458950e535SAndy Fiddaman 	}
2946a02120c4SAndy Fiddaman 
2947a02120c4SAndy Fiddaman 	/* Socket options */
2948a02120c4SAndy Fiddaman 	if (vp->v_type == VSOCK)
2949a02120c4SAndy Fiddaman 		sz += prfdinfosockopt(vp, NULL, cred);
2950a02120c4SAndy Fiddaman 
2951a02120c4SAndy Fiddaman 	/* TLI/XTI sockets */
2952a02120c4SAndy Fiddaman 	if (pristli(vp))
2953a02120c4SAndy Fiddaman 		sz += prfdinfotlisockopt(vp, NULL, cred);
2954a02120c4SAndy Fiddaman 
2955a02120c4SAndy Fiddaman 	return (sz);
2956a02120c4SAndy Fiddaman }
2957a02120c4SAndy Fiddaman 
2958a02120c4SAndy Fiddaman int
prgetfdinfo(proc_t * p,vnode_t * vp,prfdinfo_t * fdinfo,cred_t * cred,cred_t * file_cred,list_t * data)2959a02120c4SAndy Fiddaman prgetfdinfo(proc_t *p, vnode_t *vp, prfdinfo_t *fdinfo, cred_t *cred,
296019ee9cd1SAndy Fiddaman     cred_t *file_cred, list_t *data)
2961a02120c4SAndy Fiddaman {
2962a02120c4SAndy Fiddaman 	vattr_t vattr;
2963a02120c4SAndy Fiddaman 	int error;
2964a02120c4SAndy Fiddaman 
2965a02120c4SAndy Fiddaman 	/*
2966a02120c4SAndy Fiddaman 	 * The buffer has been initialised to zero by pr_iol_newbuf().
2967a02120c4SAndy Fiddaman 	 * Initialise defaults for any values that should not default to zero.
2968a02120c4SAndy Fiddaman 	 */
2969a02120c4SAndy Fiddaman 	fdinfo->pr_uid = (uid_t)-1;
2970a02120c4SAndy Fiddaman 	fdinfo->pr_gid = (gid_t)-1;
2971a02120c4SAndy Fiddaman 	fdinfo->pr_size = -1;
2972a02120c4SAndy Fiddaman 	fdinfo->pr_locktype = F_UNLCK;
2973a02120c4SAndy Fiddaman 	fdinfo->pr_lockpid = -1;
2974a02120c4SAndy Fiddaman 	fdinfo->pr_locksysid = -1;
2975a02120c4SAndy Fiddaman 	fdinfo->pr_peerpid = -1;
2976a02120c4SAndy Fiddaman 
2977a02120c4SAndy Fiddaman 	/* Offset */
2978a02120c4SAndy Fiddaman 
2979a02120c4SAndy Fiddaman 	/*
2980a02120c4SAndy Fiddaman 	 * pr_offset has already been set from the underlying file_t.
2981a02120c4SAndy Fiddaman 	 * Check if it is plausible and reset to -1 if not.
2982a02120c4SAndy Fiddaman 	 */
2983a02120c4SAndy Fiddaman 	if (fdinfo->pr_offset != -1 &&
2984a02120c4SAndy Fiddaman 	    VOP_SEEK(vp, 0, (offset_t *)&fdinfo->pr_offset, NULL) != 0)
2985a02120c4SAndy Fiddaman 		fdinfo->pr_offset = -1;
2986a02120c4SAndy Fiddaman 
298719ee9cd1SAndy Fiddaman 	/*
298819ee9cd1SAndy Fiddaman 	 * Attributes
298919ee9cd1SAndy Fiddaman 	 *
299019ee9cd1SAndy Fiddaman 	 * We have two cred_t structures available here.
299119ee9cd1SAndy Fiddaman 	 * 'cred' is the caller's credential, and 'file_cred' is the credential
299219ee9cd1SAndy Fiddaman 	 * for the file being inspected.
299319ee9cd1SAndy Fiddaman 	 *
299419ee9cd1SAndy Fiddaman 	 * When looking up the file attributes, file_cred is used in order
299519ee9cd1SAndy Fiddaman 	 * that the correct ownership is set for doors and FIFOs. Since the
299619ee9cd1SAndy Fiddaman 	 * caller has permission to read the fdinfo file in proc, this does
299719ee9cd1SAndy Fiddaman 	 * not expose any additional information.
299819ee9cd1SAndy Fiddaman 	 */
2999a02120c4SAndy Fiddaman 	vattr.va_mask = AT_STAT;
300019ee9cd1SAndy Fiddaman 	if (VOP_GETATTR(vp, &vattr, 0, file_cred, NULL) == 0) {
3001a02120c4SAndy Fiddaman 		fdinfo->pr_major = getmajor(vattr.va_fsid);
3002a02120c4SAndy Fiddaman 		fdinfo->pr_minor = getminor(vattr.va_fsid);
3003a02120c4SAndy Fiddaman 		fdinfo->pr_rmajor = getmajor(vattr.va_rdev);
3004a02120c4SAndy Fiddaman 		fdinfo->pr_rminor = getminor(vattr.va_rdev);
3005a02120c4SAndy Fiddaman 		fdinfo->pr_ino = (ino64_t)vattr.va_nodeid;
3006a02120c4SAndy Fiddaman 		fdinfo->pr_size = (off64_t)vattr.va_size;
3007a02120c4SAndy Fiddaman 		fdinfo->pr_mode = VTTOIF(vattr.va_type) | vattr.va_mode;
3008a02120c4SAndy Fiddaman 		fdinfo->pr_uid = vattr.va_uid;
3009a02120c4SAndy Fiddaman 		fdinfo->pr_gid = vattr.va_gid;
3010a02120c4SAndy Fiddaman 		if (vp->v_type == VSOCK)
3011a02120c4SAndy Fiddaman 			fdinfo->pr_fileflags |= sock_getfasync(vp);
3012a02120c4SAndy Fiddaman 	}
3013a02120c4SAndy Fiddaman 
3014a02120c4SAndy Fiddaman 	/* locks */
3015a02120c4SAndy Fiddaman 
3016a02120c4SAndy Fiddaman 	flock64_t bf;
3017a02120c4SAndy Fiddaman 
3018a02120c4SAndy Fiddaman 	bzero(&bf, sizeof (bf));
3019a02120c4SAndy Fiddaman 	bf.l_type = F_WRLCK;
3020a02120c4SAndy Fiddaman 
3021a02120c4SAndy Fiddaman 	if (VOP_FRLOCK(vp, F_GETLK, &bf,
3022a02120c4SAndy Fiddaman 	    (uint16_t)(fdinfo->pr_fileflags & 0xffff), 0, NULL,
3023a02120c4SAndy Fiddaman 	    cred, NULL) == 0 && bf.l_type != F_UNLCK) {
3024a02120c4SAndy Fiddaman 		fdinfo->pr_locktype = bf.l_type;
3025a02120c4SAndy Fiddaman 		fdinfo->pr_lockpid = bf.l_pid;
3026a02120c4SAndy Fiddaman 		fdinfo->pr_locksysid = bf.l_sysid;
3027a02120c4SAndy Fiddaman 	}
3028a02120c4SAndy Fiddaman 
3029a02120c4SAndy Fiddaman 	/* peer cred */
3030a02120c4SAndy Fiddaman 
3031a02120c4SAndy Fiddaman 	k_peercred_t kpc;
3032a02120c4SAndy Fiddaman 
3033a02120c4SAndy Fiddaman 	switch (vp->v_type) {
3034a02120c4SAndy Fiddaman 	case VFIFO:
3035a02120c4SAndy Fiddaman 	case VSOCK: {
3036a02120c4SAndy Fiddaman 		int32_t rval;
3037a02120c4SAndy Fiddaman 
3038a02120c4SAndy Fiddaman 		error = VOP_IOCTL(vp, _I_GETPEERCRED, (intptr_t)&kpc,
3039a02120c4SAndy Fiddaman 		    FKIOCTL, cred, &rval, NULL);
3040a02120c4SAndy Fiddaman 		break;
3041a02120c4SAndy Fiddaman 	}
3042a02120c4SAndy Fiddaman 	case VCHR: {
3043a02120c4SAndy Fiddaman 		struct strioctl strioc;
3044a02120c4SAndy Fiddaman 		int32_t rval;
3045a02120c4SAndy Fiddaman 
3046a02120c4SAndy Fiddaman 		if (vp->v_stream == NULL) {
3047a02120c4SAndy Fiddaman 			error = ENOTSUP;
3048a02120c4SAndy Fiddaman 			break;
3049a02120c4SAndy Fiddaman 		}
3050a02120c4SAndy Fiddaman 		strioc.ic_cmd = _I_GETPEERCRED;
3051a02120c4SAndy Fiddaman 		strioc.ic_timout = INFTIM;
3052a02120c4SAndy Fiddaman 		strioc.ic_len = (int)sizeof (k_peercred_t);
3053a02120c4SAndy Fiddaman 		strioc.ic_dp = (char *)&kpc;
3054a02120c4SAndy Fiddaman 
3055a02120c4SAndy Fiddaman 		error = strdoioctl(vp->v_stream, &strioc, FNATIVE | FKIOCTL,
3056a02120c4SAndy Fiddaman 		    STR_NOSIG | K_TO_K, cred, &rval);
3057a02120c4SAndy Fiddaman 		break;
3058a02120c4SAndy Fiddaman 	}
3059a02120c4SAndy Fiddaman 	default:
3060a02120c4SAndy Fiddaman 		error = ENOTSUP;
3061a02120c4SAndy Fiddaman 		break;
3062a02120c4SAndy Fiddaman 	}
3063a02120c4SAndy Fiddaman 
3064a02120c4SAndy Fiddaman 	if (error == 0 && kpc.pc_cr != NULL) {
3065a02120c4SAndy Fiddaman 		proc_t *peerp;
3066a02120c4SAndy Fiddaman 
3067a02120c4SAndy Fiddaman 		fdinfo->pr_peerpid = kpc.pc_cpid;
3068a02120c4SAndy Fiddaman 
3069a02120c4SAndy Fiddaman 		crfree(kpc.pc_cr);
3070a02120c4SAndy Fiddaman 
3071a02120c4SAndy Fiddaman 		mutex_enter(&pidlock);
3072a02120c4SAndy Fiddaman 		if ((peerp = prfind(fdinfo->pr_peerpid)) != NULL) {
3073a02120c4SAndy Fiddaman 			user_t *up;
3074a02120c4SAndy Fiddaman 
3075a02120c4SAndy Fiddaman 			mutex_enter(&peerp->p_lock);
3076a02120c4SAndy Fiddaman 			mutex_exit(&pidlock);
3077a02120c4SAndy Fiddaman 
3078a02120c4SAndy Fiddaman 			up = PTOU(peerp);
3079a02120c4SAndy Fiddaman 			bcopy(up->u_comm, fdinfo->pr_peername,
3080a02120c4SAndy Fiddaman 			    MIN(sizeof (up->u_comm),
3081a02120c4SAndy Fiddaman 			    sizeof (fdinfo->pr_peername) - 1));
3082a02120c4SAndy Fiddaman 
3083a02120c4SAndy Fiddaman 			mutex_exit(&peerp->p_lock);
3084a02120c4SAndy Fiddaman 		} else {
3085a02120c4SAndy Fiddaman 			mutex_exit(&pidlock);
3086a02120c4SAndy Fiddaman 		}
3087a02120c4SAndy Fiddaman 	}
3088a02120c4SAndy Fiddaman 
30898950e535SAndy Fiddaman 	/* pathname */
3090a02120c4SAndy Fiddaman 
30918950e535SAndy Fiddaman 	switch (vp->v_type) {
30928950e535SAndy Fiddaman 	case VDOOR: {
30938950e535SAndy Fiddaman 		prfdinfo_nm_path_cbdata_t cb = {
30948950e535SAndy Fiddaman 			.nmp_p		= p,
30958950e535SAndy Fiddaman 			.nmp_data	= data,
30968950e535SAndy Fiddaman 			.nmp_sz		= 0
30978950e535SAndy Fiddaman 		};
30988950e535SAndy Fiddaman 
30998950e535SAndy Fiddaman 		(void) nm_walk_mounts(vp, prfdinfo_nm_path, cred, &cb);
31008950e535SAndy Fiddaman 		break;
31018950e535SAndy Fiddaman 	}
31028950e535SAndy Fiddaman 	case VSOCK:
31038950e535SAndy Fiddaman 		/*
31048950e535SAndy Fiddaman 		 * Don't attempt to determine the path for a socket as the
31058950e535SAndy Fiddaman 		 * vnode has no associated v_path. It will cause a linear scan
31068950e535SAndy Fiddaman 		 * of the dnlc table and result in no path being found.
31078950e535SAndy Fiddaman 		 */
31088950e535SAndy Fiddaman 		break;
31098950e535SAndy Fiddaman 	default:
31108950e535SAndy Fiddaman 		(void) prfdinfopath(p, vp, data, cred);
31118950e535SAndy Fiddaman 	}
31128950e535SAndy Fiddaman 
31138950e535SAndy Fiddaman 	/* socket options */
3114a02120c4SAndy Fiddaman 	if (vp->v_type == VSOCK)
3115a02120c4SAndy Fiddaman 		(void) prfdinfosockopt(vp, data, cred);
3116a02120c4SAndy Fiddaman 
3117a02120c4SAndy Fiddaman 	/* TLI/XTI stream sockets */
3118a02120c4SAndy Fiddaman 	if (pristli(vp))
3119a02120c4SAndy Fiddaman 		(void) prfdinfotlisockopt(vp, data, cred);
3120a02120c4SAndy Fiddaman 
3121a02120c4SAndy Fiddaman 	/*
3122a02120c4SAndy Fiddaman 	 * Add a terminating header with a zero size.
3123a02120c4SAndy Fiddaman 	 */
3124a02120c4SAndy Fiddaman 	pr_misc_header_t *misc;
3125a02120c4SAndy Fiddaman 
3126a02120c4SAndy Fiddaman 	misc = pr_iol_newbuf(data, sizeof (*misc));
3127a02120c4SAndy Fiddaman 	misc->pr_misc_size = 0;
3128a02120c4SAndy Fiddaman 	misc->pr_misc_type = (uint_t)-1;
3129a02120c4SAndy Fiddaman 
3130a02120c4SAndy Fiddaman 	return (0);
3131a02120c4SAndy Fiddaman }
3132a02120c4SAndy Fiddaman 
31337c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
31347c478bd9Sstevel@tonic-gate void
prgetpsinfo32(proc_t * p,psinfo32_t * psp)31357c478bd9Sstevel@tonic-gate prgetpsinfo32(proc_t *p, psinfo32_t *psp)
31367c478bd9Sstevel@tonic-gate {
31377c478bd9Sstevel@tonic-gate 	kthread_t *t;
31387c478bd9Sstevel@tonic-gate 	struct cred *cred;
31397c478bd9Sstevel@tonic-gate 	hrtime_t hrutime, hrstime;
31407c478bd9Sstevel@tonic-gate 
31417c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
31427c478bd9Sstevel@tonic-gate 
31437c478bd9Sstevel@tonic-gate 	if ((t = prchoose(p)) == NULL)	/* returns locked thread */
31447c478bd9Sstevel@tonic-gate 		bzero(psp, sizeof (*psp));
31457c478bd9Sstevel@tonic-gate 	else {
31467c478bd9Sstevel@tonic-gate 		thread_unlock(t);
31477c478bd9Sstevel@tonic-gate 		bzero(psp, sizeof (*psp) - sizeof (psp->pr_lwp));
31487c478bd9Sstevel@tonic-gate 	}
31497c478bd9Sstevel@tonic-gate 
31507c478bd9Sstevel@tonic-gate 	/*
31517c478bd9Sstevel@tonic-gate 	 * only export SSYS and SMSACCT; everything else is off-limits to
31527c478bd9Sstevel@tonic-gate 	 * userland apps.
31537c478bd9Sstevel@tonic-gate 	 */
31547c478bd9Sstevel@tonic-gate 	psp->pr_flag = p->p_flag & (SSYS | SMSACCT);
31557c478bd9Sstevel@tonic-gate 	psp->pr_nlwp = p->p_lwpcnt;
31567c478bd9Sstevel@tonic-gate 	psp->pr_nzomb = p->p_zombcnt;
31577c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
31587c478bd9Sstevel@tonic-gate 	cred = p->p_cred;
31597c478bd9Sstevel@tonic-gate 	psp->pr_uid = crgetruid(cred);
31607c478bd9Sstevel@tonic-gate 	psp->pr_euid = crgetuid(cred);
31617c478bd9Sstevel@tonic-gate 	psp->pr_gid = crgetrgid(cred);
31627c478bd9Sstevel@tonic-gate 	psp->pr_egid = crgetgid(cred);
31637c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
31647c478bd9Sstevel@tonic-gate 	psp->pr_pid = p->p_pid;
31657c478bd9Sstevel@tonic-gate 	if (curproc->p_zone->zone_id != GLOBAL_ZONEID &&
31667c478bd9Sstevel@tonic-gate 	    (p->p_flag & SZONETOP)) {
31677c478bd9Sstevel@tonic-gate 		ASSERT(p->p_zone->zone_id != GLOBAL_ZONEID);
31687c478bd9Sstevel@tonic-gate 		/*
31697c478bd9Sstevel@tonic-gate 		 * Inside local zones, fake zsched's pid as parent pids for
31707c478bd9Sstevel@tonic-gate 		 * processes which reference processes outside of the zone.
31717c478bd9Sstevel@tonic-gate 		 */
31727c478bd9Sstevel@tonic-gate 		psp->pr_ppid = curproc->p_zone->zone_zsched->p_pid;
31737c478bd9Sstevel@tonic-gate 	} else {
31747c478bd9Sstevel@tonic-gate 		psp->pr_ppid = p->p_ppid;
31757c478bd9Sstevel@tonic-gate 	}
31767c478bd9Sstevel@tonic-gate 	psp->pr_pgid = p->p_pgrp;
31777c478bd9Sstevel@tonic-gate 	psp->pr_sid = p->p_sessp->s_sid;
31787c478bd9Sstevel@tonic-gate 	psp->pr_taskid = p->p_task->tk_tkid;
31797c478bd9Sstevel@tonic-gate 	psp->pr_projid = p->p_task->tk_proj->kpj_id;
31807c478bd9Sstevel@tonic-gate 	psp->pr_poolid = p->p_pool->pool_id;
31817c478bd9Sstevel@tonic-gate 	psp->pr_zoneid = p->p_zone->zone_id;
31827c478bd9Sstevel@tonic-gate 	if ((psp->pr_contract = PRCTID(p)) == 0)
31837c478bd9Sstevel@tonic-gate 		psp->pr_contract = -1;
31847c478bd9Sstevel@tonic-gate 	psp->pr_addr = 0;	/* cannot represent 64-bit addr in 32 bits */
31857c478bd9Sstevel@tonic-gate 	switch (p->p_model) {
31867c478bd9Sstevel@tonic-gate 	case DATAMODEL_ILP32:
31877c478bd9Sstevel@tonic-gate 		psp->pr_dmodel = PR_MODEL_ILP32;
31887c478bd9Sstevel@tonic-gate 		break;
31897c478bd9Sstevel@tonic-gate 	case DATAMODEL_LP64:
31907c478bd9Sstevel@tonic-gate 		psp->pr_dmodel = PR_MODEL_LP64;
31917c478bd9Sstevel@tonic-gate 		break;
31927c478bd9Sstevel@tonic-gate 	}
31937c478bd9Sstevel@tonic-gate 	hrutime = mstate_aggr_state(p, LMS_USER);
31947c478bd9Sstevel@tonic-gate 	hrstime = mstate_aggr_state(p, LMS_SYSTEM);
31957c478bd9Sstevel@tonic-gate 	hrt2ts32(hrutime + hrstime, &psp->pr_time);
31967c478bd9Sstevel@tonic-gate 	TICK_TO_TIMESTRUC32(p->p_cutime + p->p_cstime, &psp->pr_ctime);
31977c478bd9Sstevel@tonic-gate 
31987c478bd9Sstevel@tonic-gate 	if (t == NULL) {
31997c478bd9Sstevel@tonic-gate 		extern int wstat(int, int);	/* needs a header file */
32007c478bd9Sstevel@tonic-gate 		int wcode = p->p_wcode;		/* must be atomic read */
32017c478bd9Sstevel@tonic-gate 
32027c478bd9Sstevel@tonic-gate 		if (wcode)
32037c478bd9Sstevel@tonic-gate 			psp->pr_wstat = wstat(wcode, p->p_wdata);
32047c478bd9Sstevel@tonic-gate 		psp->pr_ttydev = PRNODEV32;
32057c478bd9Sstevel@tonic-gate 		psp->pr_lwp.pr_state = SZOMB;
32067c478bd9Sstevel@tonic-gate 		psp->pr_lwp.pr_sname = 'Z';
32077c478bd9Sstevel@tonic-gate 	} else {
32087c478bd9Sstevel@tonic-gate 		user_t *up = PTOU(p);
32097c478bd9Sstevel@tonic-gate 		struct as *as;
32107c478bd9Sstevel@tonic-gate 		dev_t d;
32117c478bd9Sstevel@tonic-gate 		extern dev_t rwsconsdev, rconsdev, uconsdev;
32127c478bd9Sstevel@tonic-gate 
32137c478bd9Sstevel@tonic-gate 		d = cttydev(p);
32147c478bd9Sstevel@tonic-gate 		/*
32157c478bd9Sstevel@tonic-gate 		 * If the controlling terminal is the real
32167c478bd9Sstevel@tonic-gate 		 * or workstation console device, map to what the
321725b463cdSethindra 		 * user thinks is the console device. Handle case when
321825b463cdSethindra 		 * rwsconsdev or rconsdev is set to NODEV for Starfire.
32197c478bd9Sstevel@tonic-gate 		 */
322025b463cdSethindra 		if ((d == rwsconsdev || d == rconsdev) && d != NODEV)
32217c478bd9Sstevel@tonic-gate 			d = uconsdev;
32227c478bd9Sstevel@tonic-gate 		(void) cmpldev(&psp->pr_ttydev, d);
32237c478bd9Sstevel@tonic-gate 		TIMESPEC_TO_TIMESPEC32(&psp->pr_start, &up->u_start);
32247c478bd9Sstevel@tonic-gate 		bcopy(up->u_comm, psp->pr_fname,
32257c478bd9Sstevel@tonic-gate 		    MIN(sizeof (up->u_comm), sizeof (psp->pr_fname)-1));
32267c478bd9Sstevel@tonic-gate 		bcopy(up->u_psargs, psp->pr_psargs,
32277c478bd9Sstevel@tonic-gate 		    MIN(PRARGSZ-1, PSARGSZ));
32287c478bd9Sstevel@tonic-gate 		psp->pr_argc = up->u_argc;
32297c478bd9Sstevel@tonic-gate 		psp->pr_argv = (caddr32_t)up->u_argv;
32307c478bd9Sstevel@tonic-gate 		psp->pr_envp = (caddr32_t)up->u_envp;
32317c478bd9Sstevel@tonic-gate 
32327c478bd9Sstevel@tonic-gate 		/* get the chosen lwp's lwpsinfo */
32337c478bd9Sstevel@tonic-gate 		prgetlwpsinfo32(t, &psp->pr_lwp);
32347c478bd9Sstevel@tonic-gate 
32357c478bd9Sstevel@tonic-gate 		/* compute %cpu for the process */
32367c478bd9Sstevel@tonic-gate 		if (p->p_lwpcnt == 1)
32377c478bd9Sstevel@tonic-gate 			psp->pr_pctcpu = psp->pr_lwp.pr_pctcpu;
32387c478bd9Sstevel@tonic-gate 		else {
32397c478bd9Sstevel@tonic-gate 			uint64_t pct = 0;
32407c478bd9Sstevel@tonic-gate 			hrtime_t cur_time;
32417c478bd9Sstevel@tonic-gate 
32427c478bd9Sstevel@tonic-gate 			t = p->p_tlist;
32437c478bd9Sstevel@tonic-gate 			cur_time = gethrtime_unscaled();
32447c478bd9Sstevel@tonic-gate 			do {
32457c478bd9Sstevel@tonic-gate 				pct += cpu_update_pct(t, cur_time);
32467c478bd9Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
32477c478bd9Sstevel@tonic-gate 
32487c478bd9Sstevel@tonic-gate 			psp->pr_pctcpu = prgetpctcpu(pct);
32497c478bd9Sstevel@tonic-gate 		}
32507c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
32517c478bd9Sstevel@tonic-gate 			psp->pr_size = 0;
32527c478bd9Sstevel@tonic-gate 			psp->pr_rssize = 0;
32537c478bd9Sstevel@tonic-gate 		} else {
32547c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
3255dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_READER);
32567c478bd9Sstevel@tonic-gate 			psp->pr_size = (size32_t)
325740688216SSudheer A 			    (btopr(as->a_resvsize) * (PAGESIZE / 1024));
32587c478bd9Sstevel@tonic-gate 			psp->pr_rssize = (size32_t)
32597c478bd9Sstevel@tonic-gate 			    (rm_asrss(as) * (PAGESIZE / 1024));
32607c478bd9Sstevel@tonic-gate 			psp->pr_pctmem = rm_pctmemory(as);
3261dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
32627c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
32637c478bd9Sstevel@tonic-gate 		}
32647c478bd9Sstevel@tonic-gate 	}
32657c478bd9Sstevel@tonic-gate 
32667c478bd9Sstevel@tonic-gate 	/*
32677c478bd9Sstevel@tonic-gate 	 * If we are looking at an LP64 process, zero out
32687c478bd9Sstevel@tonic-gate 	 * the fields that cannot be represented in ILP32.
32697c478bd9Sstevel@tonic-gate 	 */
32707c478bd9Sstevel@tonic-gate 	if (p->p_model != DATAMODEL_ILP32) {
32717c478bd9Sstevel@tonic-gate 		psp->pr_size = 0;
32727c478bd9Sstevel@tonic-gate 		psp->pr_rssize = 0;
32737c478bd9Sstevel@tonic-gate 		psp->pr_argv = 0;
32747c478bd9Sstevel@tonic-gate 		psp->pr_envp = 0;
32757c478bd9Sstevel@tonic-gate 	}
32767c478bd9Sstevel@tonic-gate }
3277f971a346SBryan Cantrill 
32787c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
32797c478bd9Sstevel@tonic-gate 
32807c478bd9Sstevel@tonic-gate void
prgetlwpsinfo(kthread_t * t,lwpsinfo_t * psp)32817c478bd9Sstevel@tonic-gate prgetlwpsinfo(kthread_t *t, lwpsinfo_t *psp)
32827c478bd9Sstevel@tonic-gate {
32837c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
32847c478bd9Sstevel@tonic-gate 	sobj_ops_t *sobj;
32857c478bd9Sstevel@tonic-gate 	char c, state;
32867c478bd9Sstevel@tonic-gate 	uint64_t pct;
32877c478bd9Sstevel@tonic-gate 	int retval, niceval;
32887c478bd9Sstevel@tonic-gate 	hrtime_t hrutime, hrstime;
32897c478bd9Sstevel@tonic-gate 
32907c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
32917c478bd9Sstevel@tonic-gate 
32927c478bd9Sstevel@tonic-gate 	bzero(psp, sizeof (*psp));
32937c478bd9Sstevel@tonic-gate 
32947c478bd9Sstevel@tonic-gate 	psp->pr_flag = 0;	/* lwpsinfo_t.pr_flag is deprecated */
32957c478bd9Sstevel@tonic-gate 	psp->pr_lwpid = t->t_tid;
32967c478bd9Sstevel@tonic-gate 	psp->pr_addr = (uintptr_t)t;
32977c478bd9Sstevel@tonic-gate 	psp->pr_wchan = (uintptr_t)t->t_wchan;
32987c478bd9Sstevel@tonic-gate 
32997c478bd9Sstevel@tonic-gate 	/* map the thread state enum into a process state enum */
33007c478bd9Sstevel@tonic-gate 	state = VSTOPPED(t) ? TS_STOPPED : t->t_state;
33017c478bd9Sstevel@tonic-gate 	switch (state) {
33027c478bd9Sstevel@tonic-gate 	case TS_SLEEP:		state = SSLEEP;		c = 'S';	break;
33037c478bd9Sstevel@tonic-gate 	case TS_RUN:		state = SRUN;		c = 'R';	break;
33047c478bd9Sstevel@tonic-gate 	case TS_ONPROC:		state = SONPROC;	c = 'O';	break;
33057c478bd9Sstevel@tonic-gate 	case TS_ZOMB:		state = SZOMB;		c = 'Z';	break;
33067c478bd9Sstevel@tonic-gate 	case TS_STOPPED:	state = SSTOP;		c = 'T';	break;
3307c97ad5cdSakolb 	case TS_WAIT:		state = SWAIT;		c = 'W';	break;
33087c478bd9Sstevel@tonic-gate 	default:		state = 0;		c = '?';	break;
33097c478bd9Sstevel@tonic-gate 	}
33107c478bd9Sstevel@tonic-gate 	psp->pr_state = state;
33117c478bd9Sstevel@tonic-gate 	psp->pr_sname = c;
33127c478bd9Sstevel@tonic-gate 	if ((sobj = t->t_sobj_ops) != NULL)
33137c478bd9Sstevel@tonic-gate 		psp->pr_stype = SOBJ_TYPE(sobj);
33147c478bd9Sstevel@tonic-gate 	retval = CL_DONICE(t, NULL, 0, &niceval);
33157c478bd9Sstevel@tonic-gate 	if (retval == 0) {
33167c478bd9Sstevel@tonic-gate 		psp->pr_oldpri = v.v_maxsyspri - t->t_pri;
33177c478bd9Sstevel@tonic-gate 		psp->pr_nice = niceval + NZERO;
33187c478bd9Sstevel@tonic-gate 	}
33197c478bd9Sstevel@tonic-gate 	psp->pr_syscall = t->t_sysnum;
33207c478bd9Sstevel@tonic-gate 	psp->pr_pri = t->t_pri;
33217c478bd9Sstevel@tonic-gate 	psp->pr_start.tv_sec = t->t_start;
33227c478bd9Sstevel@tonic-gate 	psp->pr_start.tv_nsec = 0L;
33237c478bd9Sstevel@tonic-gate 	hrutime = lwp->lwp_mstate.ms_acct[LMS_USER];
33247c478bd9Sstevel@tonic-gate 	scalehrtime(&hrutime);
33257c478bd9Sstevel@tonic-gate 	hrstime = lwp->lwp_mstate.ms_acct[LMS_SYSTEM] +
33267c478bd9Sstevel@tonic-gate 	    lwp->lwp_mstate.ms_acct[LMS_TRAP];
33277c478bd9Sstevel@tonic-gate 	scalehrtime(&hrstime);
33287c478bd9Sstevel@tonic-gate 	hrt2ts(hrutime + hrstime, &psp->pr_time);
33297c478bd9Sstevel@tonic-gate 	/* compute %cpu for the lwp */
33307c478bd9Sstevel@tonic-gate 	pct = cpu_update_pct(t, gethrtime_unscaled());
33317c478bd9Sstevel@tonic-gate 	psp->pr_pctcpu = prgetpctcpu(pct);
33327c478bd9Sstevel@tonic-gate 	psp->pr_cpu = (psp->pr_pctcpu*100 + 0x6000) >> 15;	/* [0..99] */
33337c478bd9Sstevel@tonic-gate 	if (psp->pr_cpu > 99)
33347c478bd9Sstevel@tonic-gate 		psp->pr_cpu = 99;
33357c478bd9Sstevel@tonic-gate 
33367c478bd9Sstevel@tonic-gate 	(void) strncpy(psp->pr_clname, sclass[t->t_cid].cl_name,
33377c478bd9Sstevel@tonic-gate 	    sizeof (psp->pr_clname) - 1);
33387c478bd9Sstevel@tonic-gate 	bzero(psp->pr_name, sizeof (psp->pr_name));	/* XXX ??? */
33397c478bd9Sstevel@tonic-gate 	psp->pr_onpro = t->t_cpu->cpu_id;
33407c478bd9Sstevel@tonic-gate 	psp->pr_bindpro = t->t_bind_cpu;
33417c478bd9Sstevel@tonic-gate 	psp->pr_bindpset = t->t_bind_pset;
3342c6402783Sakolb 	psp->pr_lgrp = t->t_lpl->lpl_lgrpid;
33437c478bd9Sstevel@tonic-gate }
33447c478bd9Sstevel@tonic-gate 
33457c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
33467c478bd9Sstevel@tonic-gate void
prgetlwpsinfo32(kthread_t * t,lwpsinfo32_t * psp)33477c478bd9Sstevel@tonic-gate prgetlwpsinfo32(kthread_t *t, lwpsinfo32_t *psp)
33487c478bd9Sstevel@tonic-gate {
33497c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
33507c478bd9Sstevel@tonic-gate 	sobj_ops_t *sobj;
33517c478bd9Sstevel@tonic-gate 	char c, state;
33527c478bd9Sstevel@tonic-gate 	uint64_t pct;
33537c478bd9Sstevel@tonic-gate 	int retval, niceval;
33547c478bd9Sstevel@tonic-gate 	hrtime_t hrutime, hrstime;
33557c478bd9Sstevel@tonic-gate 
335672a6dc12SPatrick Mooney 	ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
33577c478bd9Sstevel@tonic-gate 
33587c478bd9Sstevel@tonic-gate 	bzero(psp, sizeof (*psp));
33597c478bd9Sstevel@tonic-gate 
33607c478bd9Sstevel@tonic-gate 	psp->pr_flag = 0;	/* lwpsinfo_t.pr_flag is deprecated */
33617c478bd9Sstevel@tonic-gate 	psp->pr_lwpid = t->t_tid;
33627c478bd9Sstevel@tonic-gate 	psp->pr_addr = 0;	/* cannot represent 64-bit addr in 32 bits */
33637c478bd9Sstevel@tonic-gate 	psp->pr_wchan = 0;	/* cannot represent 64-bit addr in 32 bits */
33647c478bd9Sstevel@tonic-gate 
33657c478bd9Sstevel@tonic-gate 	/* map the thread state enum into a process state enum */
33667c478bd9Sstevel@tonic-gate 	state = VSTOPPED(t) ? TS_STOPPED : t->t_state;
33677c478bd9Sstevel@tonic-gate 	switch (state) {
33687c478bd9Sstevel@tonic-gate 	case TS_SLEEP:		state = SSLEEP;		c = 'S';	break;
33697c478bd9Sstevel@tonic-gate 	case TS_RUN:		state = SRUN;		c = 'R';	break;
33707c478bd9Sstevel@tonic-gate 	case TS_ONPROC:		state = SONPROC;	c = 'O';	break;
33717c478bd9Sstevel@tonic-gate 	case TS_ZOMB:		state = SZOMB;		c = 'Z';	break;
33727c478bd9Sstevel@tonic-gate 	case TS_STOPPED:	state = SSTOP;		c = 'T';	break;
3373c97ad5cdSakolb 	case TS_WAIT:		state = SWAIT;		c = 'W';	break;
33747c478bd9Sstevel@tonic-gate 	default:		state = 0;		c = '?';	break;
33757c478bd9Sstevel@tonic-gate 	}
33767c478bd9Sstevel@tonic-gate 	psp->pr_state = state;
33777c478bd9Sstevel@tonic-gate 	psp->pr_sname = c;
33787c478bd9Sstevel@tonic-gate 	if ((sobj = t->t_sobj_ops) != NULL)
33797c478bd9Sstevel@tonic-gate 		psp->pr_stype = SOBJ_TYPE(sobj);
33807c478bd9Sstevel@tonic-gate 	retval = CL_DONICE(t, NULL, 0, &niceval);
33817c478bd9Sstevel@tonic-gate 	if (retval == 0) {
33827c478bd9Sstevel@tonic-gate 		psp->pr_oldpri = v.v_maxsyspri - t->t_pri;
33837c478bd9Sstevel@tonic-gate 		psp->pr_nice = niceval + NZERO;
33847c478bd9Sstevel@tonic-gate 	} else {
33857c478bd9Sstevel@tonic-gate 		psp->pr_oldpri = 0;
33867c478bd9Sstevel@tonic-gate 		psp->pr_nice = 0;
33877c478bd9Sstevel@tonic-gate 	}
33887c478bd9Sstevel@tonic-gate 	psp->pr_syscall = t->t_sysnum;
33897c478bd9Sstevel@tonic-gate 	psp->pr_pri = t->t_pri;
33907c478bd9Sstevel@tonic-gate 	psp->pr_start.tv_sec = (time32_t)t->t_start;
33917c478bd9Sstevel@tonic-gate 	psp->pr_start.tv_nsec = 0L;
33927c478bd9Sstevel@tonic-gate 	hrutime = lwp->lwp_mstate.ms_acct[LMS_USER];
33937c478bd9Sstevel@tonic-gate 	scalehrtime(&hrutime);
33947c478bd9Sstevel@tonic-gate 	hrstime = lwp->lwp_mstate.ms_acct[LMS_SYSTEM] +
33957c478bd9Sstevel@tonic-gate 	    lwp->lwp_mstate.ms_acct[LMS_TRAP];
33967c478bd9Sstevel@tonic-gate 	scalehrtime(&hrstime);
33977c478bd9Sstevel@tonic-gate 	hrt2ts32(hrutime + hrstime, &psp->pr_time);
33987c478bd9Sstevel@tonic-gate 	/* compute %cpu for the lwp */
33997c478bd9Sstevel@tonic-gate 	pct = cpu_update_pct(t, gethrtime_unscaled());
34007c478bd9Sstevel@tonic-gate 	psp->pr_pctcpu = prgetpctcpu(pct);
34017c478bd9Sstevel@tonic-gate 	psp->pr_cpu = (psp->pr_pctcpu*100 + 0x6000) >> 15;	/* [0..99] */
34027c478bd9Sstevel@tonic-gate 	if (psp->pr_cpu > 99)
34037c478bd9Sstevel@tonic-gate 		psp->pr_cpu = 99;
34047c478bd9Sstevel@tonic-gate 
34057c478bd9Sstevel@tonic-gate 	(void) strncpy(psp->pr_clname, sclass[t->t_cid].cl_name,
34067c478bd9Sstevel@tonic-gate 	    sizeof (psp->pr_clname) - 1);
34077c478bd9Sstevel@tonic-gate 	bzero(psp->pr_name, sizeof (psp->pr_name));	/* XXX ??? */
34087c478bd9Sstevel@tonic-gate 	psp->pr_onpro = t->t_cpu->cpu_id;
34097c478bd9Sstevel@tonic-gate 	psp->pr_bindpro = t->t_bind_cpu;
34107c478bd9Sstevel@tonic-gate 	psp->pr_bindpset = t->t_bind_pset;
3411c6402783Sakolb 	psp->pr_lgrp = t->t_lpl->lpl_lgrpid;
34127c478bd9Sstevel@tonic-gate }
34137c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
34147c478bd9Sstevel@tonic-gate 
3415f971a346SBryan Cantrill #ifdef _SYSCALL32_IMPL
3416f971a346SBryan Cantrill 
3417f971a346SBryan Cantrill #define	PR_COPY_FIELD(s, d, field)	 d->field = s->field
3418f971a346SBryan Cantrill 
3419f971a346SBryan Cantrill #define	PR_COPY_FIELD_ILP32(s, d, field)				\
3420f971a346SBryan Cantrill 	if (s->pr_dmodel == PR_MODEL_ILP32) {			\
3421f971a346SBryan Cantrill 		d->field = s->field;				\
3422f971a346SBryan Cantrill 	}
3423f971a346SBryan Cantrill 
3424f971a346SBryan Cantrill #define	PR_COPY_TIMESPEC(s, d, field)				\
3425f971a346SBryan Cantrill 	TIMESPEC_TO_TIMESPEC32(&d->field, &s->field);
3426f971a346SBryan Cantrill 
3427f971a346SBryan Cantrill #define	PR_COPY_BUF(s, d, field)				\
3428f971a346SBryan Cantrill 	bcopy(s->field, d->field, sizeof (d->field));
3429f971a346SBryan Cantrill 
3430f971a346SBryan Cantrill #define	PR_IGNORE_FIELD(s, d, field)
3431f971a346SBryan Cantrill 
3432f971a346SBryan Cantrill void
lwpsinfo_kto32(const struct lwpsinfo * src,struct lwpsinfo32 * dest)3433f971a346SBryan Cantrill lwpsinfo_kto32(const struct lwpsinfo *src, struct lwpsinfo32 *dest)
3434f971a346SBryan Cantrill {
3435f971a346SBryan Cantrill 	bzero(dest, sizeof (*dest));
3436f971a346SBryan Cantrill 
3437f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_flag);
3438f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_lwpid);
3439f971a346SBryan Cantrill 	PR_IGNORE_FIELD(src, dest, pr_addr);
3440f971a346SBryan Cantrill 	PR_IGNORE_FIELD(src, dest, pr_wchan);
3441f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_stype);
3442f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_state);
3443f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_sname);
3444f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_nice);
3445f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_syscall);
3446f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_oldpri);
3447f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_cpu);
3448f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_pri);
3449f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_pctcpu);
3450f971a346SBryan Cantrill 	PR_COPY_TIMESPEC(src, dest, pr_start);
3451f971a346SBryan Cantrill 	PR_COPY_BUF(src, dest, pr_clname);
3452f971a346SBryan Cantrill 	PR_COPY_BUF(src, dest, pr_name);
3453f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_onpro);
3454f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_bindpro);
3455f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_bindpset);
3456f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_lgrp);
3457f971a346SBryan Cantrill }
3458f971a346SBryan Cantrill 
3459f971a346SBryan Cantrill void
psinfo_kto32(const struct psinfo * src,struct psinfo32 * dest)3460f971a346SBryan Cantrill psinfo_kto32(const struct psinfo *src, struct psinfo32 *dest)
3461f971a346SBryan Cantrill {
3462f971a346SBryan Cantrill 	bzero(dest, sizeof (*dest));
3463f971a346SBryan Cantrill 
3464f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_flag);
3465f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_nlwp);
3466f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_pid);
3467f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_ppid);
3468f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_pgid);
3469f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_sid);
3470f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_uid);
3471f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_euid);
3472f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_gid);
3473f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_egid);
3474f971a346SBryan Cantrill 	PR_IGNORE_FIELD(src, dest, pr_addr);
3475f971a346SBryan Cantrill 	PR_COPY_FIELD_ILP32(src, dest, pr_size);
3476f971a346SBryan Cantrill 	PR_COPY_FIELD_ILP32(src, dest, pr_rssize);
3477f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_ttydev);
3478f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_pctcpu);
3479f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_pctmem);
3480f971a346SBryan Cantrill 	PR_COPY_TIMESPEC(src, dest, pr_start);
3481f971a346SBryan Cantrill 	PR_COPY_TIMESPEC(src, dest, pr_time);
3482f971a346SBryan Cantrill 	PR_COPY_TIMESPEC(src, dest, pr_ctime);
3483f971a346SBryan Cantrill 	PR_COPY_BUF(src, dest, pr_fname);
3484f971a346SBryan Cantrill 	PR_COPY_BUF(src, dest, pr_psargs);
3485f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_wstat);
3486f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_argc);
3487f971a346SBryan Cantrill 	PR_COPY_FIELD_ILP32(src, dest, pr_argv);
3488f971a346SBryan Cantrill 	PR_COPY_FIELD_ILP32(src, dest, pr_envp);
3489f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_dmodel);
3490f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_taskid);
3491f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_projid);
3492f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_nzomb);
3493f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_poolid);
3494f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_contract);
3495f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_poolid);
3496f971a346SBryan Cantrill 	PR_COPY_FIELD(src, dest, pr_poolid);
3497f971a346SBryan Cantrill 
3498f971a346SBryan Cantrill 	lwpsinfo_kto32(&src->pr_lwp, &dest->pr_lwp);
3499f971a346SBryan Cantrill }
3500f971a346SBryan Cantrill 
3501f971a346SBryan Cantrill #undef	PR_COPY_FIELD
3502f971a346SBryan Cantrill #undef	PR_COPY_FIELD_ILP32
3503f971a346SBryan Cantrill #undef	PR_COPY_TIMESPEC
3504f971a346SBryan Cantrill #undef	PR_COPY_BUF
3505f971a346SBryan Cantrill #undef	PR_IGNORE_FIELD
3506f971a346SBryan Cantrill 
3507f971a346SBryan Cantrill #endif	/* _SYSCALL32_IMPL */
3508f971a346SBryan Cantrill 
35097c478bd9Sstevel@tonic-gate /*
35107c478bd9Sstevel@tonic-gate  * This used to get called when microstate accounting was disabled but
35117c478bd9Sstevel@tonic-gate  * microstate information was requested.  Since Microstate accounting is on
35127c478bd9Sstevel@tonic-gate  * regardless of the proc flags, this simply makes it appear to procfs that
35137c478bd9Sstevel@tonic-gate  * microstate accounting is on.  This is relatively meaningless since you
35147c478bd9Sstevel@tonic-gate  * can't turn it off, but this is here for the sake of appearances.
35157c478bd9Sstevel@tonic-gate  */
35167c478bd9Sstevel@tonic-gate 
35177c478bd9Sstevel@tonic-gate /*ARGSUSED*/
35187c478bd9Sstevel@tonic-gate void
estimate_msacct(kthread_t * t,hrtime_t curtime)35197c478bd9Sstevel@tonic-gate estimate_msacct(kthread_t *t, hrtime_t curtime)
35207c478bd9Sstevel@tonic-gate {
35217c478bd9Sstevel@tonic-gate 	proc_t *p;
35227c478bd9Sstevel@tonic-gate 
35237c478bd9Sstevel@tonic-gate 	if (t == NULL)
35247c478bd9Sstevel@tonic-gate 		return;
35257c478bd9Sstevel@tonic-gate 
35267c478bd9Sstevel@tonic-gate 	p = ttoproc(t);
35277c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
35287c478bd9Sstevel@tonic-gate 
35297c478bd9Sstevel@tonic-gate 	/*
35307c478bd9Sstevel@tonic-gate 	 * A system process (p0) could be referenced if the thread is
35317c478bd9Sstevel@tonic-gate 	 * in the process of exiting.  Don't turn on microstate accounting
35327c478bd9Sstevel@tonic-gate 	 * in that case.
35337c478bd9Sstevel@tonic-gate 	 */
35347c478bd9Sstevel@tonic-gate 	if (p->p_flag & SSYS)
35357c478bd9Sstevel@tonic-gate 		return;
35367c478bd9Sstevel@tonic-gate 
35377c478bd9Sstevel@tonic-gate 	/*
35387c478bd9Sstevel@tonic-gate 	 * Loop through all the LWPs (kernel threads) in the process.
35397c478bd9Sstevel@tonic-gate 	 */
35407c478bd9Sstevel@tonic-gate 	t = p->p_tlist;
35417c478bd9Sstevel@tonic-gate 	do {
35427c478bd9Sstevel@tonic-gate 		t->t_proc_flag |= TP_MSACCT;
35437c478bd9Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
35447c478bd9Sstevel@tonic-gate 
35457c478bd9Sstevel@tonic-gate 	p->p_flag |= SMSACCT;			/* set process-wide MSACCT */
35467c478bd9Sstevel@tonic-gate }
35477c478bd9Sstevel@tonic-gate 
35487c478bd9Sstevel@tonic-gate /*
35497c478bd9Sstevel@tonic-gate  * It's not really possible to disable microstate accounting anymore.
35507c478bd9Sstevel@tonic-gate  * However, this routine simply turns off the ms accounting flags in a process
35517c478bd9Sstevel@tonic-gate  * This way procfs can still pretend to turn microstate accounting on and
35527c478bd9Sstevel@tonic-gate  * off for a process, but it actually doesn't do anything.  This is
35537c478bd9Sstevel@tonic-gate  * a neutered form of preemptive idiot-proofing.
35547c478bd9Sstevel@tonic-gate  */
35557c478bd9Sstevel@tonic-gate void
disable_msacct(proc_t * p)35567c478bd9Sstevel@tonic-gate disable_msacct(proc_t *p)
35577c478bd9Sstevel@tonic-gate {
35587c478bd9Sstevel@tonic-gate 	kthread_t *t;
35597c478bd9Sstevel@tonic-gate 
35607c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
35617c478bd9Sstevel@tonic-gate 
35627c478bd9Sstevel@tonic-gate 	p->p_flag &= ~SMSACCT;		/* clear process-wide MSACCT */
35637c478bd9Sstevel@tonic-gate 	/*
35647c478bd9Sstevel@tonic-gate 	 * Loop through all the LWPs (kernel threads) in the process.
35657c478bd9Sstevel@tonic-gate 	 */
35667c478bd9Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL) {
35677c478bd9Sstevel@tonic-gate 		do {
35687c478bd9Sstevel@tonic-gate 			/* clear per-thread flag */
35697c478bd9Sstevel@tonic-gate 			t->t_proc_flag &= ~TP_MSACCT;
35707c478bd9Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
35717c478bd9Sstevel@tonic-gate 	}
35727c478bd9Sstevel@tonic-gate }
35737c478bd9Sstevel@tonic-gate 
35747c478bd9Sstevel@tonic-gate /*
35757c478bd9Sstevel@tonic-gate  * Return resource usage information.
35767c478bd9Sstevel@tonic-gate  */
35777c478bd9Sstevel@tonic-gate void
prgetusage(kthread_t * t,prhusage_t * pup)35787c478bd9Sstevel@tonic-gate prgetusage(kthread_t *t, prhusage_t *pup)
35797c478bd9Sstevel@tonic-gate {
35807c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
35817c478bd9Sstevel@tonic-gate 	hrtime_t *mstimep;
35827c478bd9Sstevel@tonic-gate 	struct mstate *ms = &lwp->lwp_mstate;
35837c478bd9Sstevel@tonic-gate 	int state;
35847c478bd9Sstevel@tonic-gate 	int i;
35857c478bd9Sstevel@tonic-gate 	hrtime_t curtime;
35867c478bd9Sstevel@tonic-gate 	hrtime_t waitrq;
35877c478bd9Sstevel@tonic-gate 	hrtime_t tmp1;
35887c478bd9Sstevel@tonic-gate 
35897c478bd9Sstevel@tonic-gate 	curtime = gethrtime_unscaled();
35907c478bd9Sstevel@tonic-gate 
35917c478bd9Sstevel@tonic-gate 	pup->pr_lwpid	= t->t_tid;
35927c478bd9Sstevel@tonic-gate 	pup->pr_count	= 1;
35937c478bd9Sstevel@tonic-gate 	pup->pr_create	= ms->ms_start;
35947c478bd9Sstevel@tonic-gate 	pup->pr_term    = ms->ms_term;
35957c478bd9Sstevel@tonic-gate 	scalehrtime(&pup->pr_create);
35967c478bd9Sstevel@tonic-gate 	scalehrtime(&pup->pr_term);
35977c478bd9Sstevel@tonic-gate 	if (ms->ms_term == 0) {
35987c478bd9Sstevel@tonic-gate 		pup->pr_rtime = curtime - ms->ms_start;
35997c478bd9Sstevel@tonic-gate 		scalehrtime(&pup->pr_rtime);
36007c478bd9Sstevel@tonic-gate 	} else {
36017c478bd9Sstevel@tonic-gate 		pup->pr_rtime = ms->ms_term - ms->ms_start;
36027c478bd9Sstevel@tonic-gate 		scalehrtime(&pup->pr_rtime);
36037c478bd9Sstevel@tonic-gate 	}
36047c478bd9Sstevel@tonic-gate 
36057c478bd9Sstevel@tonic-gate 
36067c478bd9Sstevel@tonic-gate 	pup->pr_utime    = ms->ms_acct[LMS_USER];
36077c478bd9Sstevel@tonic-gate 	pup->pr_stime    = ms->ms_acct[LMS_SYSTEM];
36087c478bd9Sstevel@tonic-gate 	pup->pr_ttime    = ms->ms_acct[LMS_TRAP];
36097c478bd9Sstevel@tonic-gate 	pup->pr_tftime   = ms->ms_acct[LMS_TFAULT];
36107c478bd9Sstevel@tonic-gate 	pup->pr_dftime   = ms->ms_acct[LMS_DFAULT];
36117c478bd9Sstevel@tonic-gate 	pup->pr_kftime   = ms->ms_acct[LMS_KFAULT];
36127c478bd9Sstevel@tonic-gate 	pup->pr_ltime    = ms->ms_acct[LMS_USER_LOCK];
36137c478bd9Sstevel@tonic-gate 	pup->pr_slptime  = ms->ms_acct[LMS_SLEEP];
36147c478bd9Sstevel@tonic-gate 	pup->pr_wtime    = ms->ms_acct[LMS_WAIT_CPU];
36157c478bd9Sstevel@tonic-gate 	pup->pr_stoptime = ms->ms_acct[LMS_STOPPED];
36167c478bd9Sstevel@tonic-gate 
36177c478bd9Sstevel@tonic-gate 	prscaleusage(pup);
36187c478bd9Sstevel@tonic-gate 
36197c478bd9Sstevel@tonic-gate 	/*
36207c478bd9Sstevel@tonic-gate 	 * Adjust for time waiting in the dispatcher queue.
36217c478bd9Sstevel@tonic-gate 	 */
36227c478bd9Sstevel@tonic-gate 	waitrq = t->t_waitrq;	/* hopefully atomic */
36237c478bd9Sstevel@tonic-gate 	if (waitrq != 0) {
3624872650ccSGangadhar Mylapuram 		if (waitrq > curtime) {
3625872650ccSGangadhar Mylapuram 			curtime = gethrtime_unscaled();
3626872650ccSGangadhar Mylapuram 		}
36277c478bd9Sstevel@tonic-gate 		tmp1 = curtime - waitrq;
36287c478bd9Sstevel@tonic-gate 		scalehrtime(&tmp1);
36297c478bd9Sstevel@tonic-gate 		pup->pr_wtime += tmp1;
36307c478bd9Sstevel@tonic-gate 		curtime = waitrq;
36317c478bd9Sstevel@tonic-gate 	}
36327c478bd9Sstevel@tonic-gate 
36337c478bd9Sstevel@tonic-gate 	/*
36347c478bd9Sstevel@tonic-gate 	 * Adjust for time spent in current microstate.
36357c478bd9Sstevel@tonic-gate 	 */
36367c478bd9Sstevel@tonic-gate 	if (ms->ms_state_start > curtime) {
36377c478bd9Sstevel@tonic-gate 		curtime = gethrtime_unscaled();
36387c478bd9Sstevel@tonic-gate 	}
36397c478bd9Sstevel@tonic-gate 
36407c478bd9Sstevel@tonic-gate 	i = 0;
36417c478bd9Sstevel@tonic-gate 	do {
36427c478bd9Sstevel@tonic-gate 		switch (state = t->t_mstate) {
36437c478bd9Sstevel@tonic-gate 		case LMS_SLEEP:
36447c478bd9Sstevel@tonic-gate 			/*
36457c478bd9Sstevel@tonic-gate 			 * Update the timer for the current sleep state.
36467c478bd9Sstevel@tonic-gate 			 */
36477c478bd9Sstevel@tonic-gate 			switch (state = ms->ms_prev) {
36487c478bd9Sstevel@tonic-gate 			case LMS_TFAULT:
36497c478bd9Sstevel@tonic-gate 			case LMS_DFAULT:
36507c478bd9Sstevel@tonic-gate 			case LMS_KFAULT:
36517c478bd9Sstevel@tonic-gate 			case LMS_USER_LOCK:
36527c478bd9Sstevel@tonic-gate 				break;
36537c478bd9Sstevel@tonic-gate 			default:
36547c478bd9Sstevel@tonic-gate 				state = LMS_SLEEP;
36557c478bd9Sstevel@tonic-gate 				break;
36567c478bd9Sstevel@tonic-gate 			}
36577c478bd9Sstevel@tonic-gate 			break;
36587c478bd9Sstevel@tonic-gate 		case LMS_TFAULT:
36597c478bd9Sstevel@tonic-gate 		case LMS_DFAULT:
36607c478bd9Sstevel@tonic-gate 		case LMS_KFAULT:
36617c478bd9Sstevel@tonic-gate 		case LMS_USER_LOCK:
36627c478bd9Sstevel@tonic-gate 			state = LMS_SYSTEM;
36637c478bd9Sstevel@tonic-gate 			break;
36647c478bd9Sstevel@tonic-gate 		}
36657c478bd9Sstevel@tonic-gate 		switch (state) {
36667c478bd9Sstevel@tonic-gate 		case LMS_USER:		mstimep = &pup->pr_utime;	break;
36677c478bd9Sstevel@tonic-gate 		case LMS_SYSTEM:	mstimep = &pup->pr_stime;	break;
36687c478bd9Sstevel@tonic-gate 		case LMS_TRAP:		mstimep = &pup->pr_ttime;	break;
36697c478bd9Sstevel@tonic-gate 		case LMS_TFAULT:	mstimep = &pup->pr_tftime;	break;
36707c478bd9Sstevel@tonic-gate 		case LMS_DFAULT:	mstimep = &pup->pr_dftime;	break;
36717c478bd9Sstevel@tonic-gate 		case LMS_KFAULT:	mstimep = &pup->pr_kftime;	break;
36727c478bd9Sstevel@tonic-gate 		case LMS_USER_LOCK:	mstimep = &pup->pr_ltime;	break;
36737c478bd9Sstevel@tonic-gate 		case LMS_SLEEP:		mstimep = &pup->pr_slptime;	break;
36747c478bd9Sstevel@tonic-gate 		case LMS_WAIT_CPU:	mstimep = &pup->pr_wtime;	break;
36757c478bd9Sstevel@tonic-gate 		case LMS_STOPPED:	mstimep = &pup->pr_stoptime;	break;
36767c478bd9Sstevel@tonic-gate 		default:		panic("prgetusage: unknown microstate");
36777c478bd9Sstevel@tonic-gate 		}
36787c478bd9Sstevel@tonic-gate 		tmp1 = curtime - ms->ms_state_start;
36798ace1d31Ssudheer 		if (tmp1 < 0) {
36807c478bd9Sstevel@tonic-gate 			curtime = gethrtime_unscaled();
36817c478bd9Sstevel@tonic-gate 			i++;
36827c478bd9Sstevel@tonic-gate 			continue;
36837c478bd9Sstevel@tonic-gate 		}
36847c478bd9Sstevel@tonic-gate 		scalehrtime(&tmp1);
36858ace1d31Ssudheer 	} while (tmp1 < 0 && i < MAX_ITERS_SPIN);
36867c478bd9Sstevel@tonic-gate 
36877c478bd9Sstevel@tonic-gate 	*mstimep += tmp1;
36887c478bd9Sstevel@tonic-gate 
36897c478bd9Sstevel@tonic-gate 	/* update pup timestamp */
36907c478bd9Sstevel@tonic-gate 	pup->pr_tstamp = curtime;
36917c478bd9Sstevel@tonic-gate 	scalehrtime(&pup->pr_tstamp);
36927c478bd9Sstevel@tonic-gate 
36937c478bd9Sstevel@tonic-gate 	/*
36947c478bd9Sstevel@tonic-gate 	 * Resource usage counters.
36957c478bd9Sstevel@tonic-gate 	 */
36967c478bd9Sstevel@tonic-gate 	pup->pr_minf  = lwp->lwp_ru.minflt;
36977c478bd9Sstevel@tonic-gate 	pup->pr_majf  = lwp->lwp_ru.majflt;
36987c478bd9Sstevel@tonic-gate 	pup->pr_nswap = lwp->lwp_ru.nswap;
36997c478bd9Sstevel@tonic-gate 	pup->pr_inblk = lwp->lwp_ru.inblock;
37007c478bd9Sstevel@tonic-gate 	pup->pr_oublk = lwp->lwp_ru.oublock;
37017c478bd9Sstevel@tonic-gate 	pup->pr_msnd  = lwp->lwp_ru.msgsnd;
37027c478bd9Sstevel@tonic-gate 	pup->pr_mrcv  = lwp->lwp_ru.msgrcv;
37037c478bd9Sstevel@tonic-gate 	pup->pr_sigs  = lwp->lwp_ru.nsignals;
37047c478bd9Sstevel@tonic-gate 	pup->pr_vctx  = lwp->lwp_ru.nvcsw;
37057c478bd9Sstevel@tonic-gate 	pup->pr_ictx  = lwp->lwp_ru.nivcsw;
37067c478bd9Sstevel@tonic-gate 	pup->pr_sysc  = lwp->lwp_ru.sysc;
37077c478bd9Sstevel@tonic-gate 	pup->pr_ioch  = lwp->lwp_ru.ioch;
37087c478bd9Sstevel@tonic-gate }
37097c478bd9Sstevel@tonic-gate 
37107c478bd9Sstevel@tonic-gate /*
37117c478bd9Sstevel@tonic-gate  * Convert ms_acct stats from unscaled high-res time to nanoseconds
37127c478bd9Sstevel@tonic-gate  */
37137c478bd9Sstevel@tonic-gate void
prscaleusage(prhusage_t * usg)37147c478bd9Sstevel@tonic-gate prscaleusage(prhusage_t *usg)
37157c478bd9Sstevel@tonic-gate {
37167c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_utime);
37177c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_stime);
37187c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_ttime);
37197c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_tftime);
37207c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_dftime);
37217c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_kftime);
37227c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_ltime);
37237c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_slptime);
37247c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_wtime);
37257c478bd9Sstevel@tonic-gate 	scalehrtime(&usg->pr_stoptime);
37267c478bd9Sstevel@tonic-gate }
37277c478bd9Sstevel@tonic-gate 
37287c478bd9Sstevel@tonic-gate 
37297c478bd9Sstevel@tonic-gate /*
37307c478bd9Sstevel@tonic-gate  * Sum resource usage information.
37317c478bd9Sstevel@tonic-gate  */
37327c478bd9Sstevel@tonic-gate void
praddusage(kthread_t * t,prhusage_t * pup)37337c478bd9Sstevel@tonic-gate praddusage(kthread_t *t, prhusage_t *pup)
37347c478bd9Sstevel@tonic-gate {
37357c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
37367c478bd9Sstevel@tonic-gate 	hrtime_t *mstimep;
37377c478bd9Sstevel@tonic-gate 	struct mstate *ms = &lwp->lwp_mstate;
37387c478bd9Sstevel@tonic-gate 	int state;
37397c478bd9Sstevel@tonic-gate 	int i;
37407c478bd9Sstevel@tonic-gate 	hrtime_t curtime;
37417c478bd9Sstevel@tonic-gate 	hrtime_t waitrq;
37427c478bd9Sstevel@tonic-gate 	hrtime_t tmp;
37437c478bd9Sstevel@tonic-gate 	prhusage_t conv;
37447c478bd9Sstevel@tonic-gate 
37457c478bd9Sstevel@tonic-gate 	curtime = gethrtime_unscaled();
37467c478bd9Sstevel@tonic-gate 
37477c478bd9Sstevel@tonic-gate 	if (ms->ms_term == 0) {
37487c478bd9Sstevel@tonic-gate 		tmp = curtime - ms->ms_start;
37497c478bd9Sstevel@tonic-gate 		scalehrtime(&tmp);
37507c478bd9Sstevel@tonic-gate 		pup->pr_rtime += tmp;
37517c478bd9Sstevel@tonic-gate 	} else {
37527c478bd9Sstevel@tonic-gate 		tmp = ms->ms_term - ms->ms_start;
37537c478bd9Sstevel@tonic-gate 		scalehrtime(&tmp);
37547c478bd9Sstevel@tonic-gate 		pup->pr_rtime += tmp;
37557c478bd9Sstevel@tonic-gate 	}
37567c478bd9Sstevel@tonic-gate 
37577c478bd9Sstevel@tonic-gate 	conv.pr_utime = ms->ms_acct[LMS_USER];
37587c478bd9Sstevel@tonic-gate 	conv.pr_stime = ms->ms_acct[LMS_SYSTEM];
37597c478bd9Sstevel@tonic-gate 	conv.pr_ttime = ms->ms_acct[LMS_TRAP];
37607c478bd9Sstevel@tonic-gate 	conv.pr_tftime = ms->ms_acct[LMS_TFAULT];
37617c478bd9Sstevel@tonic-gate 	conv.pr_dftime = ms->ms_acct[LMS_DFAULT];
37627c478bd9Sstevel@tonic-gate 	conv.pr_kftime = ms->ms_acct[LMS_KFAULT];
37637c478bd9Sstevel@tonic-gate 	conv.pr_ltime = ms->ms_acct[LMS_USER_LOCK];
37647c478bd9Sstevel@tonic-gate 	conv.pr_slptime = ms->ms_acct[LMS_SLEEP];
37657c478bd9Sstevel@tonic-gate 	conv.pr_wtime = ms->ms_acct[LMS_WAIT_CPU];
37667c478bd9Sstevel@tonic-gate 	conv.pr_stoptime = ms->ms_acct[LMS_STOPPED];
37677c478bd9Sstevel@tonic-gate 
37687c478bd9Sstevel@tonic-gate 	prscaleusage(&conv);
37697c478bd9Sstevel@tonic-gate 
37707c478bd9Sstevel@tonic-gate 	pup->pr_utime	+= conv.pr_utime;
37717c478bd9Sstevel@tonic-gate 	pup->pr_stime	+= conv.pr_stime;
37727c478bd9Sstevel@tonic-gate 	pup->pr_ttime	+= conv.pr_ttime;
37737c478bd9Sstevel@tonic-gate 	pup->pr_tftime	+= conv.pr_tftime;
37747c478bd9Sstevel@tonic-gate 	pup->pr_dftime	+= conv.pr_dftime;
37757c478bd9Sstevel@tonic-gate 	pup->pr_kftime	+= conv.pr_kftime;
37767c478bd9Sstevel@tonic-gate 	pup->pr_ltime	+= conv.pr_ltime;
37777c478bd9Sstevel@tonic-gate 	pup->pr_slptime	+= conv.pr_slptime;
37787c478bd9Sstevel@tonic-gate 	pup->pr_wtime	+= conv.pr_wtime;
37797c478bd9Sstevel@tonic-gate 	pup->pr_stoptime += conv.pr_stoptime;
37807c478bd9Sstevel@tonic-gate 
37817c478bd9Sstevel@tonic-gate 	/*
37827c478bd9Sstevel@tonic-gate 	 * Adjust for time waiting in the dispatcher queue.
37837c478bd9Sstevel@tonic-gate 	 */
37847c478bd9Sstevel@tonic-gate 	waitrq = t->t_waitrq;	/* hopefully atomic */
37857c478bd9Sstevel@tonic-gate 	if (waitrq != 0) {
3786872650ccSGangadhar Mylapuram 		if (waitrq > curtime) {
3787872650ccSGangadhar Mylapuram 			curtime = gethrtime_unscaled();
3788872650ccSGangadhar Mylapuram 		}
37897c478bd9Sstevel@tonic-gate 		tmp = curtime - waitrq;
37907c478bd9Sstevel@tonic-gate 		scalehrtime(&tmp);
37917c478bd9Sstevel@tonic-gate 		pup->pr_wtime += tmp;
37927c478bd9Sstevel@tonic-gate 		curtime = waitrq;
37937c478bd9Sstevel@tonic-gate 	}
37947c478bd9Sstevel@tonic-gate 
37957c478bd9Sstevel@tonic-gate 	/*
37967c478bd9Sstevel@tonic-gate 	 * Adjust for time spent in current microstate.
37977c478bd9Sstevel@tonic-gate 	 */
37987c478bd9Sstevel@tonic-gate 	if (ms->ms_state_start > curtime) {
37997c478bd9Sstevel@tonic-gate 		curtime = gethrtime_unscaled();
38007c478bd9Sstevel@tonic-gate 	}
38017c478bd9Sstevel@tonic-gate 
38027c478bd9Sstevel@tonic-gate 	i = 0;
38037c478bd9Sstevel@tonic-gate 	do {
38047c478bd9Sstevel@tonic-gate 		switch (state = t->t_mstate) {
38057c478bd9Sstevel@tonic-gate 		case LMS_SLEEP:
38067c478bd9Sstevel@tonic-gate 			/*
38077c478bd9Sstevel@tonic-gate 			 * Update the timer for the current sleep state.
38087c478bd9Sstevel@tonic-gate 			 */
38097c478bd9Sstevel@tonic-gate 			switch (state = ms->ms_prev) {
38107c478bd9Sstevel@tonic-gate 			case LMS_TFAULT:
38117c478bd9Sstevel@tonic-gate 			case LMS_DFAULT:
38127c478bd9Sstevel@tonic-gate 			case LMS_KFAULT:
38137c478bd9Sstevel@tonic-gate 			case LMS_USER_LOCK:
38147c478bd9Sstevel@tonic-gate 				break;
38157c478bd9Sstevel@tonic-gate 			default:
38167c478bd9Sstevel@tonic-gate 				state = LMS_SLEEP;
38177c478bd9Sstevel@tonic-gate 				break;
38187c478bd9Sstevel@tonic-gate 			}
38197c478bd9Sstevel@tonic-gate 			break;
38207c478bd9Sstevel@tonic-gate 		case LMS_TFAULT:
38217c478bd9Sstevel@tonic-gate 		case LMS_DFAULT:
38227c478bd9Sstevel@tonic-gate 		case LMS_KFAULT:
38237c478bd9Sstevel@tonic-gate 		case LMS_USER_LOCK:
38247c478bd9Sstevel@tonic-gate 			state = LMS_SYSTEM;
38257c478bd9Sstevel@tonic-gate 			break;
38267c478bd9Sstevel@tonic-gate 		}
38277c478bd9Sstevel@tonic-gate 		switch (state) {
38287c478bd9Sstevel@tonic-gate 		case LMS_USER:		mstimep = &pup->pr_utime;	break;
38297c478bd9Sstevel@tonic-gate 		case LMS_SYSTEM:	mstimep = &pup->pr_stime;	break;
38307c478bd9Sstevel@tonic-gate 		case LMS_TRAP:		mstimep = &pup->pr_ttime;	break;
38317c478bd9Sstevel@tonic-gate 		case LMS_TFAULT:	mstimep = &pup->pr_tftime;	break;
38327c478bd9Sstevel@tonic-gate 		case LMS_DFAULT:	mstimep = &pup->pr_dftime;	break;
38337c478bd9Sstevel@tonic-gate 		case LMS_KFAULT:	mstimep = &pup->pr_kftime;	break;
38347c478bd9Sstevel@tonic-gate 		case LMS_USER_LOCK:	mstimep = &pup->pr_ltime;	break;
38357c478bd9Sstevel@tonic-gate 		case LMS_SLEEP:		mstimep = &pup->pr_slptime;	break;
38367c478bd9Sstevel@tonic-gate 		case LMS_WAIT_CPU:	mstimep = &pup->pr_wtime;	break;
38377c478bd9Sstevel@tonic-gate 		case LMS_STOPPED:	mstimep = &pup->pr_stoptime;	break;
38387c478bd9Sstevel@tonic-gate 		default:		panic("praddusage: unknown microstate");
38397c478bd9Sstevel@tonic-gate 		}
38407c478bd9Sstevel@tonic-gate 		tmp = curtime - ms->ms_state_start;
38418ace1d31Ssudheer 		if (tmp < 0) {
38427c478bd9Sstevel@tonic-gate 			curtime = gethrtime_unscaled();
38437c478bd9Sstevel@tonic-gate 			i++;
38447c478bd9Sstevel@tonic-gate 			continue;
38457c478bd9Sstevel@tonic-gate 		}
38467c478bd9Sstevel@tonic-gate 		scalehrtime(&tmp);
38478ace1d31Ssudheer 	} while (tmp < 0 && i < MAX_ITERS_SPIN);
38487c478bd9Sstevel@tonic-gate 
38497c478bd9Sstevel@tonic-gate 	*mstimep += tmp;
38507c478bd9Sstevel@tonic-gate 
38517c478bd9Sstevel@tonic-gate 	/* update pup timestamp */
38527c478bd9Sstevel@tonic-gate 	pup->pr_tstamp = curtime;
38537c478bd9Sstevel@tonic-gate 	scalehrtime(&pup->pr_tstamp);
38547c478bd9Sstevel@tonic-gate 
38557c478bd9Sstevel@tonic-gate 	/*
38567c478bd9Sstevel@tonic-gate 	 * Resource usage counters.
38577c478bd9Sstevel@tonic-gate 	 */
38587c478bd9Sstevel@tonic-gate 	pup->pr_minf  += lwp->lwp_ru.minflt;
38597c478bd9Sstevel@tonic-gate 	pup->pr_majf  += lwp->lwp_ru.majflt;
38607c478bd9Sstevel@tonic-gate 	pup->pr_nswap += lwp->lwp_ru.nswap;
38617c478bd9Sstevel@tonic-gate 	pup->pr_inblk += lwp->lwp_ru.inblock;
38627c478bd9Sstevel@tonic-gate 	pup->pr_oublk += lwp->lwp_ru.oublock;
38637c478bd9Sstevel@tonic-gate 	pup->pr_msnd  += lwp->lwp_ru.msgsnd;
38647c478bd9Sstevel@tonic-gate 	pup->pr_mrcv  += lwp->lwp_ru.msgrcv;
38657c478bd9Sstevel@tonic-gate 	pup->pr_sigs  += lwp->lwp_ru.nsignals;
38667c478bd9Sstevel@tonic-gate 	pup->pr_vctx  += lwp->lwp_ru.nvcsw;
38677c478bd9Sstevel@tonic-gate 	pup->pr_ictx  += lwp->lwp_ru.nivcsw;
38687c478bd9Sstevel@tonic-gate 	pup->pr_sysc  += lwp->lwp_ru.sysc;
38697c478bd9Sstevel@tonic-gate 	pup->pr_ioch  += lwp->lwp_ru.ioch;
38707c478bd9Sstevel@tonic-gate }
38717c478bd9Sstevel@tonic-gate 
38727c478bd9Sstevel@tonic-gate /*
38737c478bd9Sstevel@tonic-gate  * Convert a prhusage_t to a prusage_t.
38747c478bd9Sstevel@tonic-gate  * This means convert each hrtime_t to a timestruc_t
38757c478bd9Sstevel@tonic-gate  * and copy the count fields uint64_t => ulong_t.
38767c478bd9Sstevel@tonic-gate  */
38777c478bd9Sstevel@tonic-gate void
prcvtusage(prhusage_t * pup,prusage_t * upup)38787c478bd9Sstevel@tonic-gate prcvtusage(prhusage_t *pup, prusage_t *upup)
38797c478bd9Sstevel@tonic-gate {
38807c478bd9Sstevel@tonic-gate 	uint64_t *ullp;
38817c478bd9Sstevel@tonic-gate 	ulong_t *ulp;
38827c478bd9Sstevel@tonic-gate 	int i;
38837c478bd9Sstevel@tonic-gate 
38847c478bd9Sstevel@tonic-gate 	upup->pr_lwpid = pup->pr_lwpid;
38857c478bd9Sstevel@tonic-gate 	upup->pr_count = pup->pr_count;
38867c478bd9Sstevel@tonic-gate 
38877c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_tstamp,	&upup->pr_tstamp);
38887c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_create,	&upup->pr_create);
38897c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_term,	&upup->pr_term);
38907c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_rtime,	&upup->pr_rtime);
38917c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_utime,	&upup->pr_utime);
38927c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_stime,	&upup->pr_stime);
38937c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_ttime,	&upup->pr_ttime);
38947c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_tftime,	&upup->pr_tftime);
38957c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_dftime,	&upup->pr_dftime);
38967c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_kftime,	&upup->pr_kftime);
38977c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_ltime,	&upup->pr_ltime);
38987c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_slptime,	&upup->pr_slptime);
38997c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_wtime,	&upup->pr_wtime);
39007c478bd9Sstevel@tonic-gate 	hrt2ts(pup->pr_stoptime, &upup->pr_stoptime);
39017c478bd9Sstevel@tonic-gate 	bzero(upup->filltime, sizeof (upup->filltime));
39027c478bd9Sstevel@tonic-gate 
39037c478bd9Sstevel@tonic-gate 	ullp = &pup->pr_minf;
39047c478bd9Sstevel@tonic-gate 	ulp = &upup->pr_minf;
39057c478bd9Sstevel@tonic-gate 	for (i = 0; i < 22; i++)
39067c478bd9Sstevel@tonic-gate 		*ulp++ = (ulong_t)*ullp++;
39077c478bd9Sstevel@tonic-gate }
39087c478bd9Sstevel@tonic-gate 
39097c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
39107c478bd9Sstevel@tonic-gate void
prcvtusage32(prhusage_t * pup,prusage32_t * upup)39117c478bd9Sstevel@tonic-gate prcvtusage32(prhusage_t *pup, prusage32_t *upup)
39127c478bd9Sstevel@tonic-gate {
39137c478bd9Sstevel@tonic-gate 	uint64_t *ullp;
39147c478bd9Sstevel@tonic-gate 	uint32_t *ulp;
39157c478bd9Sstevel@tonic-gate 	int i;
39167c478bd9Sstevel@tonic-gate 
39177c478bd9Sstevel@tonic-gate 	upup->pr_lwpid = pup->pr_lwpid;
39187c478bd9Sstevel@tonic-gate 	upup->pr_count = pup->pr_count;
39197c478bd9Sstevel@tonic-gate 
39207c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_tstamp,	&upup->pr_tstamp);
39217c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_create,	&upup->pr_create);
39227c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_term,		&upup->pr_term);
39237c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_rtime,		&upup->pr_rtime);
39247c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_utime,		&upup->pr_utime);
39257c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_stime,		&upup->pr_stime);
39267c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_ttime,		&upup->pr_ttime);
39277c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_tftime,	&upup->pr_tftime);
39287c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_dftime,	&upup->pr_dftime);
39297c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_kftime,	&upup->pr_kftime);
39307c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_ltime,		&upup->pr_ltime);
39317c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_slptime,	&upup->pr_slptime);
39327c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_wtime,		&upup->pr_wtime);
39337c478bd9Sstevel@tonic-gate 	hrt2ts32(pup->pr_stoptime,	&upup->pr_stoptime);
39347c478bd9Sstevel@tonic-gate 	bzero(upup->filltime, sizeof (upup->filltime));
39357c478bd9Sstevel@tonic-gate 
39367c478bd9Sstevel@tonic-gate 	ullp = &pup->pr_minf;
39377c478bd9Sstevel@tonic-gate 	ulp = &upup->pr_minf;
39387c478bd9Sstevel@tonic-gate 	for (i = 0; i < 22; i++)
39397c478bd9Sstevel@tonic-gate 		*ulp++ = (uint32_t)*ullp++;
39407c478bd9Sstevel@tonic-gate }
39417c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
39427c478bd9Sstevel@tonic-gate 
39437c478bd9Sstevel@tonic-gate /*
39447c478bd9Sstevel@tonic-gate  * Determine whether a set is empty.
39457c478bd9Sstevel@tonic-gate  */
39467c478bd9Sstevel@tonic-gate int
setisempty(uint32_t * sp,uint_t n)39477c478bd9Sstevel@tonic-gate setisempty(uint32_t *sp, uint_t n)
39487c478bd9Sstevel@tonic-gate {
39497c478bd9Sstevel@tonic-gate 	while (n--)
39507c478bd9Sstevel@tonic-gate 		if (*sp++)
39517c478bd9Sstevel@tonic-gate 			return (0);
39527c478bd9Sstevel@tonic-gate 	return (1);
39537c478bd9Sstevel@tonic-gate }
39547c478bd9Sstevel@tonic-gate 
39557c478bd9Sstevel@tonic-gate /*
39567c478bd9Sstevel@tonic-gate  * Utility routine for establishing a watched area in the process.
39577c478bd9Sstevel@tonic-gate  * Keep the list of watched areas sorted by virtual address.
39587c478bd9Sstevel@tonic-gate  */
39597c478bd9Sstevel@tonic-gate int
set_watched_area(proc_t * p,struct watched_area * pwa)39607c478bd9Sstevel@tonic-gate set_watched_area(proc_t *p, struct watched_area *pwa)
39617c478bd9Sstevel@tonic-gate {
39627c478bd9Sstevel@tonic-gate 	caddr_t vaddr = pwa->wa_vaddr;
39637c478bd9Sstevel@tonic-gate 	caddr_t eaddr = pwa->wa_eaddr;
39647c478bd9Sstevel@tonic-gate 	ulong_t flags = pwa->wa_flags;
39657c478bd9Sstevel@tonic-gate 	struct watched_area *target;
39667c478bd9Sstevel@tonic-gate 	avl_index_t where;
39677c478bd9Sstevel@tonic-gate 	int error = 0;
39687c478bd9Sstevel@tonic-gate 
39697c478bd9Sstevel@tonic-gate 	/* we must not be holding p->p_lock, but the process must be locked */
39707c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&p->p_lock));
39717c478bd9Sstevel@tonic-gate 	ASSERT(p->p_proc_flag & P_PR_LOCK);
39727c478bd9Sstevel@tonic-gate 
39737c478bd9Sstevel@tonic-gate 	/*
39747c478bd9Sstevel@tonic-gate 	 * If this is our first watchpoint, enable watchpoints for the process.
39757c478bd9Sstevel@tonic-gate 	 */
39767c478bd9Sstevel@tonic-gate 	if (!pr_watch_active(p)) {
39777c478bd9Sstevel@tonic-gate 		kthread_t *t;
39787c478bd9Sstevel@tonic-gate 
39797c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
39807c478bd9Sstevel@tonic-gate 		if ((t = p->p_tlist) != NULL) {
39817c478bd9Sstevel@tonic-gate 			do {
39827c478bd9Sstevel@tonic-gate 				watch_enable(t);
39837c478bd9Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
39847c478bd9Sstevel@tonic-gate 		}
39857c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
39867c478bd9Sstevel@tonic-gate 	}
39877c478bd9Sstevel@tonic-gate 
39887c478bd9Sstevel@tonic-gate 	target = pr_find_watched_area(p, pwa, &where);
39897c478bd9Sstevel@tonic-gate 	if (target != NULL) {
39907c478bd9Sstevel@tonic-gate 		/*
39917c478bd9Sstevel@tonic-gate 		 * We discovered an existing, overlapping watched area.
39927c478bd9Sstevel@tonic-gate 		 * Allow it only if it is an exact match.
39937c478bd9Sstevel@tonic-gate 		 */
39947c478bd9Sstevel@tonic-gate 		if (target->wa_vaddr != vaddr ||
39957c478bd9Sstevel@tonic-gate 		    target->wa_eaddr != eaddr)
39967c478bd9Sstevel@tonic-gate 			error = EINVAL;
39977c478bd9Sstevel@tonic-gate 		else if (target->wa_flags != flags) {
39987c478bd9Sstevel@tonic-gate 			error = set_watched_page(p, vaddr, eaddr,
39997c478bd9Sstevel@tonic-gate 			    flags, target->wa_flags);
40007c478bd9Sstevel@tonic-gate 			target->wa_flags = flags;
40017c478bd9Sstevel@tonic-gate 		}
40027c478bd9Sstevel@tonic-gate 		kmem_free(pwa, sizeof (struct watched_area));
40037c478bd9Sstevel@tonic-gate 	} else {
40047c478bd9Sstevel@tonic-gate 		avl_insert(&p->p_warea, pwa, where);
40057c478bd9Sstevel@tonic-gate 		error = set_watched_page(p, vaddr, eaddr, flags, 0);
40067c478bd9Sstevel@tonic-gate 	}
40077c478bd9Sstevel@tonic-gate 
40087c478bd9Sstevel@tonic-gate 	return (error);
40097c478bd9Sstevel@tonic-gate }
40107c478bd9Sstevel@tonic-gate 
40117c478bd9Sstevel@tonic-gate /*
40127c478bd9Sstevel@tonic-gate  * Utility routine for clearing a watched area in the process.
40137c478bd9Sstevel@tonic-gate  * Must be an exact match of the virtual address.
40147c478bd9Sstevel@tonic-gate  * size and flags don't matter.
40157c478bd9Sstevel@tonic-gate  */
40167c478bd9Sstevel@tonic-gate int
clear_watched_area(proc_t * p,struct watched_area * pwa)40177c478bd9Sstevel@tonic-gate clear_watched_area(proc_t *p, struct watched_area *pwa)
40187c478bd9Sstevel@tonic-gate {
40197c478bd9Sstevel@tonic-gate 	struct watched_area *found;
40207c478bd9Sstevel@tonic-gate 
40217c478bd9Sstevel@tonic-gate 	/* we must not be holding p->p_lock, but the process must be locked */
40227c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&p->p_lock));
40237c478bd9Sstevel@tonic-gate 	ASSERT(p->p_proc_flag & P_PR_LOCK);
40247c478bd9Sstevel@tonic-gate 
40257c478bd9Sstevel@tonic-gate 
40267c478bd9Sstevel@tonic-gate 	if (!pr_watch_active(p)) {
40277c478bd9Sstevel@tonic-gate 		kmem_free(pwa, sizeof (struct watched_area));
40287c478bd9Sstevel@tonic-gate 		return (0);
40297c478bd9Sstevel@tonic-gate 	}
40307c478bd9Sstevel@tonic-gate 
40317c478bd9Sstevel@tonic-gate 	/*
40327c478bd9Sstevel@tonic-gate 	 * Look for a matching address in the watched areas.  If a match is
40337c478bd9Sstevel@tonic-gate 	 * found, clear the old watched area and adjust the watched page(s).  It
40347c478bd9Sstevel@tonic-gate 	 * is not an error if there is no match.
40357c478bd9Sstevel@tonic-gate 	 */
40367c478bd9Sstevel@tonic-gate 	if ((found = pr_find_watched_area(p, pwa, NULL)) != NULL &&
40377c478bd9Sstevel@tonic-gate 	    found->wa_vaddr == pwa->wa_vaddr) {
40387c478bd9Sstevel@tonic-gate 		clear_watched_page(p, found->wa_vaddr, found->wa_eaddr,
40397c478bd9Sstevel@tonic-gate 		    found->wa_flags);
40407c478bd9Sstevel@tonic-gate 		avl_remove(&p->p_warea, found);
40417c478bd9Sstevel@tonic-gate 		kmem_free(found, sizeof (struct watched_area));
40427c478bd9Sstevel@tonic-gate 	}
40437c478bd9Sstevel@tonic-gate 
40447c478bd9Sstevel@tonic-gate 	kmem_free(pwa, sizeof (struct watched_area));
40457c478bd9Sstevel@tonic-gate 
40467c478bd9Sstevel@tonic-gate 	/*
40477c478bd9Sstevel@tonic-gate 	 * If we removed the last watched area from the process, disable
40487c478bd9Sstevel@tonic-gate 	 * watchpoints.
40497c478bd9Sstevel@tonic-gate 	 */
40507c478bd9Sstevel@tonic-gate 	if (!pr_watch_active(p)) {
40517c478bd9Sstevel@tonic-gate 		kthread_t *t;
40527c478bd9Sstevel@tonic-gate 
40537c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
40547c478bd9Sstevel@tonic-gate 		if ((t = p->p_tlist) != NULL) {
40557c478bd9Sstevel@tonic-gate 			do {
40567c478bd9Sstevel@tonic-gate 				watch_disable(t);
40577c478bd9Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
40587c478bd9Sstevel@tonic-gate 		}
40597c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
40607c478bd9Sstevel@tonic-gate 	}
40617c478bd9Sstevel@tonic-gate 
40627c478bd9Sstevel@tonic-gate 	return (0);
40637c478bd9Sstevel@tonic-gate }
40647c478bd9Sstevel@tonic-gate 
40657c478bd9Sstevel@tonic-gate /*
40667c478bd9Sstevel@tonic-gate  * Frees all the watched_area structures
40677c478bd9Sstevel@tonic-gate  */
40687c478bd9Sstevel@tonic-gate void
pr_free_watchpoints(proc_t * p)40697c478bd9Sstevel@tonic-gate pr_free_watchpoints(proc_t *p)
40707c478bd9Sstevel@tonic-gate {
40717c478bd9Sstevel@tonic-gate 	struct watched_area *delp;
40727c478bd9Sstevel@tonic-gate 	void *cookie;
40737c478bd9Sstevel@tonic-gate 
40747c478bd9Sstevel@tonic-gate 	cookie = NULL;
40757c478bd9Sstevel@tonic-gate 	while ((delp = avl_destroy_nodes(&p->p_warea, &cookie)) != NULL)
40767c478bd9Sstevel@tonic-gate 		kmem_free(delp, sizeof (struct watched_area));
40777c478bd9Sstevel@tonic-gate 
40787c478bd9Sstevel@tonic-gate 	avl_destroy(&p->p_warea);
40797c478bd9Sstevel@tonic-gate }
40807c478bd9Sstevel@tonic-gate 
40817c478bd9Sstevel@tonic-gate /*
40827c478bd9Sstevel@tonic-gate  * This one is called by the traced process to unwatch all the
40837c478bd9Sstevel@tonic-gate  * pages while deallocating the list of watched_page structs.
40847c478bd9Sstevel@tonic-gate  */
40857c478bd9Sstevel@tonic-gate void
pr_free_watched_pages(proc_t * p)40867c478bd9Sstevel@tonic-gate pr_free_watched_pages(proc_t *p)
40877c478bd9Sstevel@tonic-gate {
40887c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
40897c478bd9Sstevel@tonic-gate 	struct watched_page *pwp;
40907c478bd9Sstevel@tonic-gate 	uint_t prot;
40917c478bd9Sstevel@tonic-gate 	int    retrycnt, err;
40927c478bd9Sstevel@tonic-gate 	void *cookie;
40937c478bd9Sstevel@tonic-gate 
40947c478bd9Sstevel@tonic-gate 	if (as == NULL || avl_numnodes(&as->a_wpage) == 0)
40957c478bd9Sstevel@tonic-gate 		return;
40967c478bd9Sstevel@tonic-gate 
40977c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&curproc->p_lock));
4098dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_ENTER(as, RW_WRITER);
40997c478bd9Sstevel@tonic-gate 
41007c478bd9Sstevel@tonic-gate 	pwp = avl_first(&as->a_wpage);
41017c478bd9Sstevel@tonic-gate 
41027c478bd9Sstevel@tonic-gate 	cookie = NULL;
41037c478bd9Sstevel@tonic-gate 	while ((pwp = avl_destroy_nodes(&as->a_wpage, &cookie)) != NULL) {
41047c478bd9Sstevel@tonic-gate 		retrycnt = 0;
41057c478bd9Sstevel@tonic-gate 		if ((prot = pwp->wp_oprot) != 0) {
41067c478bd9Sstevel@tonic-gate 			caddr_t addr = pwp->wp_vaddr;
41077c478bd9Sstevel@tonic-gate 			struct seg *seg;
41087c478bd9Sstevel@tonic-gate 		retry:
41097c478bd9Sstevel@tonic-gate 
41107c478bd9Sstevel@tonic-gate 			if ((pwp->wp_prot != prot ||
41117c478bd9Sstevel@tonic-gate 			    (pwp->wp_flags & WP_NOWATCH)) &&
41127c478bd9Sstevel@tonic-gate 			    (seg = as_segat(as, addr)) != NULL) {
41137c478bd9Sstevel@tonic-gate 				err = SEGOP_SETPROT(seg, addr, PAGESIZE, prot);
41147c478bd9Sstevel@tonic-gate 				if (err == IE_RETRY) {
41157c478bd9Sstevel@tonic-gate 					ASSERT(retrycnt == 0);
41167c478bd9Sstevel@tonic-gate 					retrycnt++;
41177c478bd9Sstevel@tonic-gate 					goto retry;
41187c478bd9Sstevel@tonic-gate 				}
41197c478bd9Sstevel@tonic-gate 			}
41207c478bd9Sstevel@tonic-gate 		}
41217c478bd9Sstevel@tonic-gate 		kmem_free(pwp, sizeof (struct watched_page));
41227c478bd9Sstevel@tonic-gate 	}
41237c478bd9Sstevel@tonic-gate 
41247c478bd9Sstevel@tonic-gate 	avl_destroy(&as->a_wpage);
41257c478bd9Sstevel@tonic-gate 	p->p_wprot = NULL;
41267c478bd9Sstevel@tonic-gate 
4127dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
41287c478bd9Sstevel@tonic-gate }
41297c478bd9Sstevel@tonic-gate 
41307c478bd9Sstevel@tonic-gate /*
41317c478bd9Sstevel@tonic-gate  * Insert a watched area into the list of watched pages.
41327c478bd9Sstevel@tonic-gate  * If oflags is zero then we are adding a new watched area.
41337c478bd9Sstevel@tonic-gate  * Otherwise we are changing the flags of an existing watched area.
41347c478bd9Sstevel@tonic-gate  */
41357c478bd9Sstevel@tonic-gate static int
set_watched_page(proc_t * p,caddr_t vaddr,caddr_t eaddr,ulong_t flags,ulong_t oflags)41367c478bd9Sstevel@tonic-gate set_watched_page(proc_t *p, caddr_t vaddr, caddr_t eaddr,
41377c478bd9Sstevel@tonic-gate     ulong_t flags, ulong_t oflags)
41387c478bd9Sstevel@tonic-gate {
41397c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
41407c478bd9Sstevel@tonic-gate 	avl_tree_t *pwp_tree;
41417c478bd9Sstevel@tonic-gate 	struct watched_page *pwp, *newpwp;
41427c478bd9Sstevel@tonic-gate 	struct watched_page tpw;
41437c478bd9Sstevel@tonic-gate 	avl_index_t where;
41447c478bd9Sstevel@tonic-gate 	struct seg *seg;
41457c478bd9Sstevel@tonic-gate 	uint_t prot;
41467c478bd9Sstevel@tonic-gate 	caddr_t addr;
41477c478bd9Sstevel@tonic-gate 
41487c478bd9Sstevel@tonic-gate 	/*
41497c478bd9Sstevel@tonic-gate 	 * We need to pre-allocate a list of structures before we grab the
41507c478bd9Sstevel@tonic-gate 	 * address space lock to avoid calling kmem_alloc(KM_SLEEP) with locks
41517c478bd9Sstevel@tonic-gate 	 * held.
41527c478bd9Sstevel@tonic-gate 	 */
41537c478bd9Sstevel@tonic-gate 	newpwp = NULL;
41547c478bd9Sstevel@tonic-gate 	for (addr = (caddr_t)((uintptr_t)vaddr & (uintptr_t)PAGEMASK);
41557c478bd9Sstevel@tonic-gate 	    addr < eaddr; addr += PAGESIZE) {
41567c478bd9Sstevel@tonic-gate 		pwp = kmem_zalloc(sizeof (struct watched_page), KM_SLEEP);
41577c478bd9Sstevel@tonic-gate 		pwp->wp_list = newpwp;
41587c478bd9Sstevel@tonic-gate 		newpwp = pwp;
41597c478bd9Sstevel@tonic-gate 	}
41607c478bd9Sstevel@tonic-gate 
4161dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_ENTER(as, RW_WRITER);
41627c478bd9Sstevel@tonic-gate 
41637c478bd9Sstevel@tonic-gate 	/*
41647c478bd9Sstevel@tonic-gate 	 * Search for an existing watched page to contain the watched area.
41657c478bd9Sstevel@tonic-gate 	 * If none is found, grab a new one from the available list
41667c478bd9Sstevel@tonic-gate 	 * and insert it in the active list, keeping the list sorted
41677c478bd9Sstevel@tonic-gate 	 * by user-level virtual address.
41687c478bd9Sstevel@tonic-gate 	 */
41697c478bd9Sstevel@tonic-gate 	if (p->p_flag & SVFWAIT)
41707c478bd9Sstevel@tonic-gate 		pwp_tree = &p->p_wpage;
41717c478bd9Sstevel@tonic-gate 	else
41727c478bd9Sstevel@tonic-gate 		pwp_tree = &as->a_wpage;
41737c478bd9Sstevel@tonic-gate 
41747c478bd9Sstevel@tonic-gate again:
41757c478bd9Sstevel@tonic-gate 	if (avl_numnodes(pwp_tree) > prnwatch) {
4176dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_EXIT(as);
41777c478bd9Sstevel@tonic-gate 		while (newpwp != NULL) {
41787c478bd9Sstevel@tonic-gate 			pwp = newpwp->wp_list;
41797c478bd9Sstevel@tonic-gate 			kmem_free(newpwp, sizeof (struct watched_page));
41807c478bd9Sstevel@tonic-gate 			newpwp = pwp;
41817c478bd9Sstevel@tonic-gate 		}
41827c478bd9Sstevel@tonic-gate 		return (E2BIG);
41837c478bd9Sstevel@tonic-gate 	}
41847c478bd9Sstevel@tonic-gate 
41857c478bd9Sstevel@tonic-gate 	tpw.wp_vaddr = (caddr_t)((uintptr_t)vaddr & (uintptr_t)PAGEMASK);
41867c478bd9Sstevel@tonic-gate 	if ((pwp = avl_find(pwp_tree, &tpw, &where)) == NULL) {
41877c478bd9Sstevel@tonic-gate 		pwp = newpwp;
41887c478bd9Sstevel@tonic-gate 		newpwp = newpwp->wp_list;
41897c478bd9Sstevel@tonic-gate 		pwp->wp_list = NULL;
41907c478bd9Sstevel@tonic-gate 		pwp->wp_vaddr = (caddr_t)((uintptr_t)vaddr &
41917c478bd9Sstevel@tonic-gate 		    (uintptr_t)PAGEMASK);
41927c478bd9Sstevel@tonic-gate 		avl_insert(pwp_tree, pwp, where);
41937c478bd9Sstevel@tonic-gate 	}
41947c478bd9Sstevel@tonic-gate 
41957c478bd9Sstevel@tonic-gate 	ASSERT(vaddr >= pwp->wp_vaddr && vaddr < pwp->wp_vaddr + PAGESIZE);
41967c478bd9Sstevel@tonic-gate 
41977c478bd9Sstevel@tonic-gate 	if (oflags & WA_READ)
41987c478bd9Sstevel@tonic-gate 		pwp->wp_read--;
41997c478bd9Sstevel@tonic-gate 	if (oflags & WA_WRITE)
42007c478bd9Sstevel@tonic-gate 		pwp->wp_write--;
42017c478bd9Sstevel@tonic-gate 	if (oflags & WA_EXEC)
42027c478bd9Sstevel@tonic-gate 		pwp->wp_exec--;
42037c478bd9Sstevel@tonic-gate 
42047c478bd9Sstevel@tonic-gate 	ASSERT(pwp->wp_read >= 0);
42057c478bd9Sstevel@tonic-gate 	ASSERT(pwp->wp_write >= 0);
42067c478bd9Sstevel@tonic-gate 	ASSERT(pwp->wp_exec >= 0);
42077c478bd9Sstevel@tonic-gate 
42087c478bd9Sstevel@tonic-gate 	if (flags & WA_READ)
42097c478bd9Sstevel@tonic-gate 		pwp->wp_read++;
42107c478bd9Sstevel@tonic-gate 	if (flags & WA_WRITE)
42117c478bd9Sstevel@tonic-gate 		pwp->wp_write++;
42127c478bd9Sstevel@tonic-gate 	if (flags & WA_EXEC)
42137c478bd9Sstevel@tonic-gate 		pwp->wp_exec++;
42147c478bd9Sstevel@tonic-gate 
42157c478bd9Sstevel@tonic-gate 	if (!(p->p_flag & SVFWAIT)) {
42167c478bd9Sstevel@tonic-gate 		vaddr = pwp->wp_vaddr;
42177c478bd9Sstevel@tonic-gate 		if (pwp->wp_oprot == 0 &&
42187c478bd9Sstevel@tonic-gate 		    (seg = as_segat(as, vaddr)) != NULL) {
42197c478bd9Sstevel@tonic-gate 			SEGOP_GETPROT(seg, vaddr, 0, &prot);
42207c478bd9Sstevel@tonic-gate 			pwp->wp_oprot = (uchar_t)prot;
42217c478bd9Sstevel@tonic-gate 			pwp->wp_prot = (uchar_t)prot;
42227c478bd9Sstevel@tonic-gate 		}
42237c478bd9Sstevel@tonic-gate 		if (pwp->wp_oprot != 0) {
42247c478bd9Sstevel@tonic-gate 			prot = pwp->wp_oprot;
42257c478bd9Sstevel@tonic-gate 			if (pwp->wp_read)
42267c478bd9Sstevel@tonic-gate 				prot &= ~(PROT_READ|PROT_WRITE|PROT_EXEC);
42277c478bd9Sstevel@tonic-gate 			if (pwp->wp_write)
42287c478bd9Sstevel@tonic-gate 				prot &= ~PROT_WRITE;
42297c478bd9Sstevel@tonic-gate 			if (pwp->wp_exec)
42307c478bd9Sstevel@tonic-gate 				prot &= ~(PROT_READ|PROT_WRITE|PROT_EXEC);
42317c478bd9Sstevel@tonic-gate 			if (!(pwp->wp_flags & WP_NOWATCH) &&
42327c478bd9Sstevel@tonic-gate 			    pwp->wp_prot != prot &&
42337c478bd9Sstevel@tonic-gate 			    (pwp->wp_flags & WP_SETPROT) == 0) {
42347c478bd9Sstevel@tonic-gate 				pwp->wp_flags |= WP_SETPROT;
42357c478bd9Sstevel@tonic-gate 				pwp->wp_list = p->p_wprot;
42367c478bd9Sstevel@tonic-gate 				p->p_wprot = pwp;
42377c478bd9Sstevel@tonic-gate 			}
42387c478bd9Sstevel@tonic-gate 			pwp->wp_prot = (uchar_t)prot;
42397c478bd9Sstevel@tonic-gate 		}
42407c478bd9Sstevel@tonic-gate 	}
42417c478bd9Sstevel@tonic-gate 
42427c478bd9Sstevel@tonic-gate 	/*
42437c478bd9Sstevel@tonic-gate 	 * If the watched area extends into the next page then do
42447c478bd9Sstevel@tonic-gate 	 * it over again with the virtual address of the next page.
42457c478bd9Sstevel@tonic-gate 	 */
42467c478bd9Sstevel@tonic-gate 	if ((vaddr = pwp->wp_vaddr + PAGESIZE) < eaddr)
42477c478bd9Sstevel@tonic-gate 		goto again;
42487c478bd9Sstevel@tonic-gate 
4249dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
42507c478bd9Sstevel@tonic-gate 
42517c478bd9Sstevel@tonic-gate 	/*
42527c478bd9Sstevel@tonic-gate 	 * Free any pages we may have over-allocated
42537c478bd9Sstevel@tonic-gate 	 */
42547c478bd9Sstevel@tonic-gate 	while (newpwp != NULL) {
42557c478bd9Sstevel@tonic-gate 		pwp = newpwp->wp_list;
42567c478bd9Sstevel@tonic-gate 		kmem_free(newpwp, sizeof (struct watched_page));
42577c478bd9Sstevel@tonic-gate 		newpwp = pwp;
42587c478bd9Sstevel@tonic-gate 	}
42597c478bd9Sstevel@tonic-gate 
42607c478bd9Sstevel@tonic-gate 	return (0);
42617c478bd9Sstevel@tonic-gate }
42627c478bd9Sstevel@tonic-gate 
42637c478bd9Sstevel@tonic-gate /*
42647c478bd9Sstevel@tonic-gate  * Remove a watched area from the list of watched pages.
42657c478bd9Sstevel@tonic-gate  * A watched area may extend over more than one page.
42667c478bd9Sstevel@tonic-gate  */
42677c478bd9Sstevel@tonic-gate static void
clear_watched_page(proc_t * p,caddr_t vaddr,caddr_t eaddr,ulong_t flags)42687c478bd9Sstevel@tonic-gate clear_watched_page(proc_t *p, caddr_t vaddr, caddr_t eaddr, ulong_t flags)
42697c478bd9Sstevel@tonic-gate {
42707c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
42717c478bd9Sstevel@tonic-gate 	struct watched_page *pwp;
42727c478bd9Sstevel@tonic-gate 	struct watched_page tpw;
42737c478bd9Sstevel@tonic-gate 	avl_tree_t *tree;
42747c478bd9Sstevel@tonic-gate 	avl_index_t where;
42757c478bd9Sstevel@tonic-gate 
4276dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_ENTER(as, RW_WRITER);
42777c478bd9Sstevel@tonic-gate 
42787c478bd9Sstevel@tonic-gate 	if (p->p_flag & SVFWAIT)
42797c478bd9Sstevel@tonic-gate 		tree = &p->p_wpage;
42807c478bd9Sstevel@tonic-gate 	else
42817c478bd9Sstevel@tonic-gate 		tree = &as->a_wpage;
42827c478bd9Sstevel@tonic-gate 
42837c478bd9Sstevel@tonic-gate 	tpw.wp_vaddr = vaddr =
42847c478bd9Sstevel@tonic-gate 	    (caddr_t)((uintptr_t)vaddr & (uintptr_t)PAGEMASK);
42857c478bd9Sstevel@tonic-gate 	pwp = avl_find(tree, &tpw, &where);
42867c478bd9Sstevel@tonic-gate 	if (pwp == NULL)
42877c478bd9Sstevel@tonic-gate 		pwp = avl_nearest(tree, where, AVL_AFTER);
42887c478bd9Sstevel@tonic-gate 
42897c478bd9Sstevel@tonic-gate 	while (pwp != NULL && pwp->wp_vaddr < eaddr) {
42907c478bd9Sstevel@tonic-gate 		ASSERT(vaddr <=  pwp->wp_vaddr);
42917c478bd9Sstevel@tonic-gate 
42927c478bd9Sstevel@tonic-gate 		if (flags & WA_READ)
42937c478bd9Sstevel@tonic-gate 			pwp->wp_read--;
42947c478bd9Sstevel@tonic-gate 		if (flags & WA_WRITE)
42957c478bd9Sstevel@tonic-gate 			pwp->wp_write--;
42967c478bd9Sstevel@tonic-gate 		if (flags & WA_EXEC)
42977c478bd9Sstevel@tonic-gate 			pwp->wp_exec--;
42987c478bd9Sstevel@tonic-gate 
42997c478bd9Sstevel@tonic-gate 		if (pwp->wp_read + pwp->wp_write + pwp->wp_exec != 0) {
43007c478bd9Sstevel@tonic-gate 			/*
43017c478bd9Sstevel@tonic-gate 			 * Reset the hat layer's protections on this page.
43027c478bd9Sstevel@tonic-gate 			 */
43037c478bd9Sstevel@tonic-gate 			if (pwp->wp_oprot != 0) {
43047c478bd9Sstevel@tonic-gate 				uint_t prot = pwp->wp_oprot;
43057c478bd9Sstevel@tonic-gate 
43067c478bd9Sstevel@tonic-gate 				if (pwp->wp_read)
43077c478bd9Sstevel@tonic-gate 					prot &=
43087c478bd9Sstevel@tonic-gate 					    ~(PROT_READ|PROT_WRITE|PROT_EXEC);
43097c478bd9Sstevel@tonic-gate 				if (pwp->wp_write)
43107c478bd9Sstevel@tonic-gate 					prot &= ~PROT_WRITE;
43117c478bd9Sstevel@tonic-gate 				if (pwp->wp_exec)
43127c478bd9Sstevel@tonic-gate 					prot &=
43137c478bd9Sstevel@tonic-gate 					    ~(PROT_READ|PROT_WRITE|PROT_EXEC);
43147c478bd9Sstevel@tonic-gate 				if (!(pwp->wp_flags & WP_NOWATCH) &&
43157c478bd9Sstevel@tonic-gate 				    pwp->wp_prot != prot &&
43167c478bd9Sstevel@tonic-gate 				    (pwp->wp_flags & WP_SETPROT) == 0) {
43177c478bd9Sstevel@tonic-gate 					pwp->wp_flags |= WP_SETPROT;
43187c478bd9Sstevel@tonic-gate 					pwp->wp_list = p->p_wprot;
43197c478bd9Sstevel@tonic-gate 					p->p_wprot = pwp;
43207c478bd9Sstevel@tonic-gate 				}
43217c478bd9Sstevel@tonic-gate 				pwp->wp_prot = (uchar_t)prot;
43227c478bd9Sstevel@tonic-gate 			}
43237c478bd9Sstevel@tonic-gate 		} else {
43247c478bd9Sstevel@tonic-gate 			/*
43257c478bd9Sstevel@tonic-gate 			 * No watched areas remain in this page.
43267c478bd9Sstevel@tonic-gate 			 * Reset everything to normal.
43277c478bd9Sstevel@tonic-gate 			 */
43287c478bd9Sstevel@tonic-gate 			if (pwp->wp_oprot != 0) {
43297c478bd9Sstevel@tonic-gate 				pwp->wp_prot = pwp->wp_oprot;
43307c478bd9Sstevel@tonic-gate 				if ((pwp->wp_flags & WP_SETPROT) == 0) {
43317c478bd9Sstevel@tonic-gate 					pwp->wp_flags |= WP_SETPROT;
43327c478bd9Sstevel@tonic-gate 					pwp->wp_list = p->p_wprot;
43337c478bd9Sstevel@tonic-gate 					p->p_wprot = pwp;
43347c478bd9Sstevel@tonic-gate 				}
43357c478bd9Sstevel@tonic-gate 			}
43367c478bd9Sstevel@tonic-gate 		}
43377c478bd9Sstevel@tonic-gate 
43387c478bd9Sstevel@tonic-gate 		pwp = AVL_NEXT(tree, pwp);
43397c478bd9Sstevel@tonic-gate 	}
43407c478bd9Sstevel@tonic-gate 
4341dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
43427c478bd9Sstevel@tonic-gate }
43437c478bd9Sstevel@tonic-gate 
43447c478bd9Sstevel@tonic-gate /*
43457c478bd9Sstevel@tonic-gate  * Return the original protections for the specified page.
43467c478bd9Sstevel@tonic-gate  */
43477c478bd9Sstevel@tonic-gate static void
getwatchprot(struct as * as,caddr_t addr,uint_t * prot)43487c478bd9Sstevel@tonic-gate getwatchprot(struct as *as, caddr_t addr, uint_t *prot)
43497c478bd9Sstevel@tonic-gate {
43507c478bd9Sstevel@tonic-gate 	struct watched_page *pwp;
43517c478bd9Sstevel@tonic-gate 	struct watched_page tpw;
43527c478bd9Sstevel@tonic-gate 
4353dc32d872SJosef 'Jeff' Sipek 	ASSERT(AS_LOCK_HELD(as));
43547c478bd9Sstevel@tonic-gate 
43557c478bd9Sstevel@tonic-gate 	tpw.wp_vaddr = (caddr_t)((uintptr_t)addr & (uintptr_t)PAGEMASK);
43567c478bd9Sstevel@tonic-gate 	if ((pwp = avl_find(&as->a_wpage, &tpw, NULL)) != NULL)
43577c478bd9Sstevel@tonic-gate 		*prot = pwp->wp_oprot;
43587c478bd9Sstevel@tonic-gate }
43597c478bd9Sstevel@tonic-gate 
43607c478bd9Sstevel@tonic-gate static prpagev_t *
pr_pagev_create(struct seg * seg,int check_noreserve)43617c478bd9Sstevel@tonic-gate pr_pagev_create(struct seg *seg, int check_noreserve)
43627c478bd9Sstevel@tonic-gate {
43637c478bd9Sstevel@tonic-gate 	prpagev_t *pagev = kmem_alloc(sizeof (prpagev_t), KM_SLEEP);
43647c478bd9Sstevel@tonic-gate 	size_t total_pages = seg_pages(seg);
43657c478bd9Sstevel@tonic-gate 
43667c478bd9Sstevel@tonic-gate 	/*
43677c478bd9Sstevel@tonic-gate 	 * Limit the size of our vectors to pagev_lim pages at a time.  We need
43687c478bd9Sstevel@tonic-gate 	 * 4 or 5 bytes of storage per page, so this means we limit ourself
43697c478bd9Sstevel@tonic-gate 	 * to about a megabyte of kernel heap by default.
43707c478bd9Sstevel@tonic-gate 	 */
43717c478bd9Sstevel@tonic-gate 	pagev->pg_npages = MIN(total_pages, pagev_lim);
43727c478bd9Sstevel@tonic-gate 	pagev->pg_pnbase = 0;
43737c478bd9Sstevel@tonic-gate 
43747c478bd9Sstevel@tonic-gate 	pagev->pg_protv =
43757c478bd9Sstevel@tonic-gate 	    kmem_alloc(pagev->pg_npages * sizeof (uint_t), KM_SLEEP);
43767c478bd9Sstevel@tonic-gate 
43777c478bd9Sstevel@tonic-gate 	if (check_noreserve)
43787c478bd9Sstevel@tonic-gate 		pagev->pg_incore =
43797c478bd9Sstevel@tonic-gate 		    kmem_alloc(pagev->pg_npages * sizeof (char), KM_SLEEP);
43807c478bd9Sstevel@tonic-gate 	else
43817c478bd9Sstevel@tonic-gate 		pagev->pg_incore = NULL;
43827c478bd9Sstevel@tonic-gate 
43837c478bd9Sstevel@tonic-gate 	return (pagev);
43847c478bd9Sstevel@tonic-gate }
43857c478bd9Sstevel@tonic-gate 
43867c478bd9Sstevel@tonic-gate static void
pr_pagev_destroy(prpagev_t * pagev)43877c478bd9Sstevel@tonic-gate pr_pagev_destroy(prpagev_t *pagev)
43887c478bd9Sstevel@tonic-gate {
43897c478bd9Sstevel@tonic-gate 	if (pagev->pg_incore != NULL)
43907c478bd9Sstevel@tonic-gate 		kmem_free(pagev->pg_incore, pagev->pg_npages * sizeof (char));
43917c478bd9Sstevel@tonic-gate 
43927c478bd9Sstevel@tonic-gate 	kmem_free(pagev->pg_protv, pagev->pg_npages * sizeof (uint_t));
43937c478bd9Sstevel@tonic-gate 	kmem_free(pagev, sizeof (prpagev_t));
43947c478bd9Sstevel@tonic-gate }
43957c478bd9Sstevel@tonic-gate 
43967c478bd9Sstevel@tonic-gate static caddr_t
pr_pagev_fill(prpagev_t * pagev,struct seg * seg,caddr_t addr,caddr_t eaddr)43977c478bd9Sstevel@tonic-gate pr_pagev_fill(prpagev_t *pagev, struct seg *seg, caddr_t addr, caddr_t eaddr)
43987c478bd9Sstevel@tonic-gate {
43997c478bd9Sstevel@tonic-gate 	ulong_t lastpg = seg_page(seg, eaddr - 1);
44007c478bd9Sstevel@tonic-gate 	ulong_t pn, pnlim;
44017c478bd9Sstevel@tonic-gate 	caddr_t saddr;
44027c478bd9Sstevel@tonic-gate 	size_t len;
44037c478bd9Sstevel@tonic-gate 
44047c478bd9Sstevel@tonic-gate 	ASSERT(addr >= seg->s_base && addr <= eaddr);
44057c478bd9Sstevel@tonic-gate 
44067c478bd9Sstevel@tonic-gate 	if (addr == eaddr)
44077c478bd9Sstevel@tonic-gate 		return (eaddr);
44087c478bd9Sstevel@tonic-gate 
44097c478bd9Sstevel@tonic-gate refill:
44107c478bd9Sstevel@tonic-gate 	ASSERT(addr < eaddr);
44117c478bd9Sstevel@tonic-gate 	pagev->pg_pnbase = seg_page(seg, addr);
44127c478bd9Sstevel@tonic-gate 	pnlim = pagev->pg_pnbase + pagev->pg_npages;
44137c478bd9Sstevel@tonic-gate 	saddr = addr;
44147c478bd9Sstevel@tonic-gate 
44157c478bd9Sstevel@tonic-gate 	if (lastpg < pnlim)
44167c478bd9Sstevel@tonic-gate 		len = (size_t)(eaddr - addr);
44177c478bd9Sstevel@tonic-gate 	else
44187c478bd9Sstevel@tonic-gate 		len = pagev->pg_npages * PAGESIZE;
44197c478bd9Sstevel@tonic-gate 
44207c478bd9Sstevel@tonic-gate 	if (pagev->pg_incore != NULL) {
44217c478bd9Sstevel@tonic-gate 		/*
44227c478bd9Sstevel@tonic-gate 		 * INCORE cleverly has different semantics than GETPROT:
44237c478bd9Sstevel@tonic-gate 		 * it returns info on pages up to but NOT including addr + len.
44247c478bd9Sstevel@tonic-gate 		 */
44257c478bd9Sstevel@tonic-gate 		SEGOP_INCORE(seg, addr, len, pagev->pg_incore);
44267c478bd9Sstevel@tonic-gate 		pn = pagev->pg_pnbase;
44277c478bd9Sstevel@tonic-gate 
44287c478bd9Sstevel@tonic-gate 		do {
44297c478bd9Sstevel@tonic-gate 			/*
44307c478bd9Sstevel@tonic-gate 			 * Guilty knowledge here:  We know that segvn_incore
44317c478bd9Sstevel@tonic-gate 			 * returns more than just the low-order bit that
44327c478bd9Sstevel@tonic-gate 			 * indicates the page is actually in memory.  If any
44337c478bd9Sstevel@tonic-gate 			 * bits are set, then the page has backing store.
44347c478bd9Sstevel@tonic-gate 			 */
44357c478bd9Sstevel@tonic-gate 			if (pagev->pg_incore[pn++ - pagev->pg_pnbase])
44367c478bd9Sstevel@tonic-gate 				goto out;
44377c478bd9Sstevel@tonic-gate 
44387c478bd9Sstevel@tonic-gate 		} while ((addr += PAGESIZE) < eaddr && pn < pnlim);
44397c478bd9Sstevel@tonic-gate 
44407c478bd9Sstevel@tonic-gate 		/*
44417c478bd9Sstevel@tonic-gate 		 * If we examined all the pages in the vector but we're not
44427c478bd9Sstevel@tonic-gate 		 * at the end of the segment, take another lap.
44437c478bd9Sstevel@tonic-gate 		 */
44447c478bd9Sstevel@tonic-gate 		if (addr < eaddr)
44457c478bd9Sstevel@tonic-gate 			goto refill;
44467c478bd9Sstevel@tonic-gate 	}
44477c478bd9Sstevel@tonic-gate 
44487c478bd9Sstevel@tonic-gate 	/*
44497c478bd9Sstevel@tonic-gate 	 * Need to take len - 1 because addr + len is the address of the
44507c478bd9Sstevel@tonic-gate 	 * first byte of the page just past the end of what we want.
44517c478bd9Sstevel@tonic-gate 	 */
44527c478bd9Sstevel@tonic-gate out:
44537c478bd9Sstevel@tonic-gate 	SEGOP_GETPROT(seg, saddr, len - 1, pagev->pg_protv);
44547c478bd9Sstevel@tonic-gate 	return (addr);
44557c478bd9Sstevel@tonic-gate }
44567c478bd9Sstevel@tonic-gate 
44577c478bd9Sstevel@tonic-gate static caddr_t
pr_pagev_nextprot(prpagev_t * pagev,struct seg * seg,caddr_t * saddrp,caddr_t eaddr,uint_t * protp)44587c478bd9Sstevel@tonic-gate pr_pagev_nextprot(prpagev_t *pagev, struct seg *seg,
44597c478bd9Sstevel@tonic-gate     caddr_t *saddrp, caddr_t eaddr, uint_t *protp)
44607c478bd9Sstevel@tonic-gate {
44617c478bd9Sstevel@tonic-gate 	/*
44627c478bd9Sstevel@tonic-gate 	 * Our starting address is either the specified address, or the base
44637c478bd9Sstevel@tonic-gate 	 * address from the start of the pagev.  If the latter is greater,
44647c478bd9Sstevel@tonic-gate 	 * this means a previous call to pr_pagev_fill has already scanned
44657c478bd9Sstevel@tonic-gate 	 * further than the end of the previous mapping.
44667c478bd9Sstevel@tonic-gate 	 */
44677c478bd9Sstevel@tonic-gate 	caddr_t base = seg->s_base + pagev->pg_pnbase * PAGESIZE;
44687c478bd9Sstevel@tonic-gate 	caddr_t addr = MAX(*saddrp, base);
44697c478bd9Sstevel@tonic-gate 	ulong_t pn = seg_page(seg, addr);
44707c478bd9Sstevel@tonic-gate 	uint_t prot, nprot;
44717c478bd9Sstevel@tonic-gate 
44727c478bd9Sstevel@tonic-gate 	/*
44737c478bd9Sstevel@tonic-gate 	 * If we're dealing with noreserve pages, then advance addr to
44747c478bd9Sstevel@tonic-gate 	 * the address of the next page which has backing store.
44757c478bd9Sstevel@tonic-gate 	 */
44767c478bd9Sstevel@tonic-gate 	if (pagev->pg_incore != NULL) {
44777c478bd9Sstevel@tonic-gate 		while (pagev->pg_incore[pn - pagev->pg_pnbase] == 0) {
44787c478bd9Sstevel@tonic-gate 			if ((addr += PAGESIZE) == eaddr) {
44797c478bd9Sstevel@tonic-gate 				*saddrp = addr;
44807c478bd9Sstevel@tonic-gate 				prot = 0;
44817c478bd9Sstevel@tonic-gate 				goto out;
44827c478bd9Sstevel@tonic-gate 			}
44837c478bd9Sstevel@tonic-gate 			if (++pn == pagev->pg_pnbase + pagev->pg_npages) {
44847c478bd9Sstevel@tonic-gate 				addr = pr_pagev_fill(pagev, seg, addr, eaddr);
44857c478bd9Sstevel@tonic-gate 				if (addr == eaddr) {
44867c478bd9Sstevel@tonic-gate 					*saddrp = addr;
44877c478bd9Sstevel@tonic-gate 					prot = 0;
44887c478bd9Sstevel@tonic-gate 					goto out;
44897c478bd9Sstevel@tonic-gate 				}
44907c478bd9Sstevel@tonic-gate 				pn = seg_page(seg, addr);
44917c478bd9Sstevel@tonic-gate 			}
44927c478bd9Sstevel@tonic-gate 		}
44937c478bd9Sstevel@tonic-gate 	}
44947c478bd9Sstevel@tonic-gate 
44957c478bd9Sstevel@tonic-gate 	/*
44967c478bd9Sstevel@tonic-gate 	 * Get the protections on the page corresponding to addr.
44977c478bd9Sstevel@tonic-gate 	 */
44987c478bd9Sstevel@tonic-gate 	pn = seg_page(seg, addr);
44997c478bd9Sstevel@tonic-gate 	ASSERT(pn >= pagev->pg_pnbase);
45007c478bd9Sstevel@tonic-gate 	ASSERT(pn < (pagev->pg_pnbase + pagev->pg_npages));
45017c478bd9Sstevel@tonic-gate 
45027c478bd9Sstevel@tonic-gate 	prot = pagev->pg_protv[pn - pagev->pg_pnbase];
45037c478bd9Sstevel@tonic-gate 	getwatchprot(seg->s_as, addr, &prot);
45047c478bd9Sstevel@tonic-gate 	*saddrp = addr;
45057c478bd9Sstevel@tonic-gate 
45067c478bd9Sstevel@tonic-gate 	/*
45077c478bd9Sstevel@tonic-gate 	 * Now loop until we find a backed page with different protections
45087c478bd9Sstevel@tonic-gate 	 * or we reach the end of this segment.
45097c478bd9Sstevel@tonic-gate 	 */
45107c478bd9Sstevel@tonic-gate 	while ((addr += PAGESIZE) < eaddr) {
45117c478bd9Sstevel@tonic-gate 		/*
45127c478bd9Sstevel@tonic-gate 		 * If pn has advanced to the page number following what we
45137c478bd9Sstevel@tonic-gate 		 * have information on, refill the page vector and reset
45147c478bd9Sstevel@tonic-gate 		 * addr and pn.  If pr_pagev_fill does not return the
45157c478bd9Sstevel@tonic-gate 		 * address of the next page, we have a discontiguity and
45167c478bd9Sstevel@tonic-gate 		 * thus have reached the end of the current mapping.
45177c478bd9Sstevel@tonic-gate 		 */
45187c478bd9Sstevel@tonic-gate 		if (++pn == pagev->pg_pnbase + pagev->pg_npages) {
45197c478bd9Sstevel@tonic-gate 			caddr_t naddr = pr_pagev_fill(pagev, seg, addr, eaddr);
45207c478bd9Sstevel@tonic-gate 			if (naddr != addr)
45217c478bd9Sstevel@tonic-gate 				goto out;
45227c478bd9Sstevel@tonic-gate 			pn = seg_page(seg, addr);
45237c478bd9Sstevel@tonic-gate 		}
45247c478bd9Sstevel@tonic-gate 
45257c478bd9Sstevel@tonic-gate 		/*
45267c478bd9Sstevel@tonic-gate 		 * The previous page's protections are in prot, and it has
45277c478bd9Sstevel@tonic-gate 		 * backing.  If this page is MAP_NORESERVE and has no backing,
45287c478bd9Sstevel@tonic-gate 		 * then end this mapping and return the previous protections.
45297c478bd9Sstevel@tonic-gate 		 */
45307c478bd9Sstevel@tonic-gate 		if (pagev->pg_incore != NULL &&
45317c478bd9Sstevel@tonic-gate 		    pagev->pg_incore[pn - pagev->pg_pnbase] == 0)
45327c478bd9Sstevel@tonic-gate 			break;
45337c478bd9Sstevel@tonic-gate 
45347c478bd9Sstevel@tonic-gate 		/*
45357c478bd9Sstevel@tonic-gate 		 * Otherwise end the mapping if this page's protections (nprot)
45367c478bd9Sstevel@tonic-gate 		 * are different than those in the previous page (prot).
45377c478bd9Sstevel@tonic-gate 		 */
45387c478bd9Sstevel@tonic-gate 		nprot = pagev->pg_protv[pn - pagev->pg_pnbase];
45397c478bd9Sstevel@tonic-gate 		getwatchprot(seg->s_as, addr, &nprot);
45407c478bd9Sstevel@tonic-gate 
45417c478bd9Sstevel@tonic-gate 		if (nprot != prot)
45427c478bd9Sstevel@tonic-gate 			break;
45437c478bd9Sstevel@tonic-gate 	}
45447c478bd9Sstevel@tonic-gate 
45457c478bd9Sstevel@tonic-gate out:
45467c478bd9Sstevel@tonic-gate 	*protp = prot;
45477c478bd9Sstevel@tonic-gate 	return (addr);
45487c478bd9Sstevel@tonic-gate }
45497c478bd9Sstevel@tonic-gate 
45507c478bd9Sstevel@tonic-gate size_t
pr_getsegsize(struct seg * seg,int reserved)45517c478bd9Sstevel@tonic-gate pr_getsegsize(struct seg *seg, int reserved)
45527c478bd9Sstevel@tonic-gate {
45537c478bd9Sstevel@tonic-gate 	size_t size = seg->s_size;
45547c478bd9Sstevel@tonic-gate 
45557c478bd9Sstevel@tonic-gate 	/*
45567c478bd9Sstevel@tonic-gate 	 * If we're interested in the reserved space, return the size of the
45577c478bd9Sstevel@tonic-gate 	 * segment itself.  Everything else in this function is a special case
45587c478bd9Sstevel@tonic-gate 	 * to determine the actual underlying size of various segment types.
45597c478bd9Sstevel@tonic-gate 	 */
45607c478bd9Sstevel@tonic-gate 	if (reserved)
45617c478bd9Sstevel@tonic-gate 		return (size);
45627c478bd9Sstevel@tonic-gate 
45637c478bd9Sstevel@tonic-gate 	/*
45647c478bd9Sstevel@tonic-gate 	 * If this is a segvn mapping of a regular file, return the smaller
45657c478bd9Sstevel@tonic-gate 	 * of the segment size and the remaining size of the file beyond
45667c478bd9Sstevel@tonic-gate 	 * the file offset corresponding to seg->s_base.
45677c478bd9Sstevel@tonic-gate 	 */
45687c478bd9Sstevel@tonic-gate 	if (seg->s_ops == &segvn_ops) {
45697c478bd9Sstevel@tonic-gate 		vattr_t vattr;
45707c478bd9Sstevel@tonic-gate 		vnode_t *vp;
45717c478bd9Sstevel@tonic-gate 
45727c478bd9Sstevel@tonic-gate 		vattr.va_mask = AT_SIZE;
45737c478bd9Sstevel@tonic-gate 
45747c478bd9Sstevel@tonic-gate 		if (SEGOP_GETVP(seg, seg->s_base, &vp) == 0 &&
45757c478bd9Sstevel@tonic-gate 		    vp != NULL && vp->v_type == VREG &&
4576da6c28aaSamw 		    VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
45777c478bd9Sstevel@tonic-gate 
45787c478bd9Sstevel@tonic-gate 			u_offset_t fsize = vattr.va_size;
45797c478bd9Sstevel@tonic-gate 			u_offset_t offset = SEGOP_GETOFFSET(seg, seg->s_base);
45807c478bd9Sstevel@tonic-gate 
45817c478bd9Sstevel@tonic-gate 			if (fsize < offset)
45827c478bd9Sstevel@tonic-gate 				fsize = 0;
45837c478bd9Sstevel@tonic-gate 			else
45847c478bd9Sstevel@tonic-gate 				fsize -= offset;
45857c478bd9Sstevel@tonic-gate 
45867c478bd9Sstevel@tonic-gate 			fsize = roundup(fsize, (u_offset_t)PAGESIZE);
45877c478bd9Sstevel@tonic-gate 
45887c478bd9Sstevel@tonic-gate 			if (fsize < (u_offset_t)size)
45897c478bd9Sstevel@tonic-gate 				size = (size_t)fsize;
45907c478bd9Sstevel@tonic-gate 		}
45917c478bd9Sstevel@tonic-gate 
45927c478bd9Sstevel@tonic-gate 		return (size);
45937c478bd9Sstevel@tonic-gate 	}
45947c478bd9Sstevel@tonic-gate 
45957c478bd9Sstevel@tonic-gate 	/*
45967c478bd9Sstevel@tonic-gate 	 * If this is an ISM shared segment, don't include pages that are
45977c478bd9Sstevel@tonic-gate 	 * beyond the real size of the spt segment that backs it.
45987c478bd9Sstevel@tonic-gate 	 */
45997c478bd9Sstevel@tonic-gate 	if (seg->s_ops == &segspt_shmops)
46007c478bd9Sstevel@tonic-gate 		return (MIN(spt_realsize(seg), size));
46017c478bd9Sstevel@tonic-gate 
46027c478bd9Sstevel@tonic-gate 	/*
46037c478bd9Sstevel@tonic-gate 	 * If this is segment is a mapping from /dev/null, then this is a
46047c478bd9Sstevel@tonic-gate 	 * reservation of virtual address space and has no actual size.
46057c478bd9Sstevel@tonic-gate 	 * Such segments are backed by segdev and have type set to neither
46067c478bd9Sstevel@tonic-gate 	 * MAP_SHARED nor MAP_PRIVATE.
46077c478bd9Sstevel@tonic-gate 	 */
46087c478bd9Sstevel@tonic-gate 	if (seg->s_ops == &segdev_ops &&
46097c478bd9Sstevel@tonic-gate 	    ((SEGOP_GETTYPE(seg, seg->s_base) &
46107c478bd9Sstevel@tonic-gate 	    (MAP_SHARED | MAP_PRIVATE)) == 0))
46117c478bd9Sstevel@tonic-gate 		return (0);
46127c478bd9Sstevel@tonic-gate 
46137c478bd9Sstevel@tonic-gate 	/*
46147c478bd9Sstevel@tonic-gate 	 * If this segment doesn't match one of the special types we handle,
46157c478bd9Sstevel@tonic-gate 	 * just return the size of the segment itself.
46167c478bd9Sstevel@tonic-gate 	 */
46177c478bd9Sstevel@tonic-gate 	return (size);
46187c478bd9Sstevel@tonic-gate }
46197c478bd9Sstevel@tonic-gate 
46207c478bd9Sstevel@tonic-gate uint_t
pr_getprot(struct seg * seg,int reserved,void ** tmp,caddr_t * saddrp,caddr_t * naddrp,caddr_t eaddr)46217c478bd9Sstevel@tonic-gate pr_getprot(struct seg *seg, int reserved, void **tmp,
46227c478bd9Sstevel@tonic-gate     caddr_t *saddrp, caddr_t *naddrp, caddr_t eaddr)
46237c478bd9Sstevel@tonic-gate {
46247c478bd9Sstevel@tonic-gate 	struct as *as = seg->s_as;
46257c478bd9Sstevel@tonic-gate 
46267c478bd9Sstevel@tonic-gate 	caddr_t saddr = *saddrp;
46277c478bd9Sstevel@tonic-gate 	caddr_t naddr;
46287c478bd9Sstevel@tonic-gate 
46297c478bd9Sstevel@tonic-gate 	int check_noreserve;
46307c478bd9Sstevel@tonic-gate 	uint_t prot;
46317c478bd9Sstevel@tonic-gate 
46327c478bd9Sstevel@tonic-gate 	union {
46337c478bd9Sstevel@tonic-gate 		struct segvn_data *svd;
46347c478bd9Sstevel@tonic-gate 		struct segdev_data *sdp;
46357c478bd9Sstevel@tonic-gate 		void *data;
46367c478bd9Sstevel@tonic-gate 	} s;
46377c478bd9Sstevel@tonic-gate 
46387c478bd9Sstevel@tonic-gate 	s.data = seg->s_data;
46397c478bd9Sstevel@tonic-gate 
4640dc32d872SJosef 'Jeff' Sipek 	ASSERT(AS_WRITE_HELD(as));
46417c478bd9Sstevel@tonic-gate 	ASSERT(saddr >= seg->s_base && saddr < eaddr);
46427c478bd9Sstevel@tonic-gate 	ASSERT(eaddr <= seg->s_base + seg->s_size);
46437c478bd9Sstevel@tonic-gate 
46447c478bd9Sstevel@tonic-gate 	/*
46457c478bd9Sstevel@tonic-gate 	 * Don't include MAP_NORESERVE pages in the address range
46467c478bd9Sstevel@tonic-gate 	 * unless their mappings have actually materialized.
46477c478bd9Sstevel@tonic-gate 	 * We cheat by knowing that segvn is the only segment
46487c478bd9Sstevel@tonic-gate 	 * driver that supports MAP_NORESERVE.
46497c478bd9Sstevel@tonic-gate 	 */
46507c478bd9Sstevel@tonic-gate 	check_noreserve =
46517c478bd9Sstevel@tonic-gate 	    (!reserved && seg->s_ops == &segvn_ops && s.svd != NULL &&
46527c478bd9Sstevel@tonic-gate 	    (s.svd->vp == NULL || s.svd->vp->v_type != VREG) &&
46537c478bd9Sstevel@tonic-gate 	    (s.svd->flags & MAP_NORESERVE));
46547c478bd9Sstevel@tonic-gate 
46557c478bd9Sstevel@tonic-gate 	/*
46567c478bd9Sstevel@tonic-gate 	 * Examine every page only as a last resort.  We use guilty knowledge
46577c478bd9Sstevel@tonic-gate 	 * of segvn and segdev to avoid this: if there are no per-page
46587c478bd9Sstevel@tonic-gate 	 * protections present in the segment and we don't care about
46597c478bd9Sstevel@tonic-gate 	 * MAP_NORESERVE, then s_data->prot is the prot for the whole segment.
46607c478bd9Sstevel@tonic-gate 	 */
46617c478bd9Sstevel@tonic-gate 	if (!check_noreserve && saddr == seg->s_base &&
46627c478bd9Sstevel@tonic-gate 	    seg->s_ops == &segvn_ops && s.svd != NULL && s.svd->pageprot == 0) {
46637c478bd9Sstevel@tonic-gate 		prot = s.svd->prot;
46647c478bd9Sstevel@tonic-gate 		getwatchprot(as, saddr, &prot);
46657c478bd9Sstevel@tonic-gate 		naddr = eaddr;
46667c478bd9Sstevel@tonic-gate 
46677c478bd9Sstevel@tonic-gate 	} else if (saddr == seg->s_base && seg->s_ops == &segdev_ops &&
46687c478bd9Sstevel@tonic-gate 	    s.sdp != NULL && s.sdp->pageprot == 0) {
46697c478bd9Sstevel@tonic-gate 		prot = s.sdp->prot;
46707c478bd9Sstevel@tonic-gate 		getwatchprot(as, saddr, &prot);
46717c478bd9Sstevel@tonic-gate 		naddr = eaddr;
46727c478bd9Sstevel@tonic-gate 
46737c478bd9Sstevel@tonic-gate 	} else {
46747c478bd9Sstevel@tonic-gate 		prpagev_t *pagev;
46757c478bd9Sstevel@tonic-gate 
46767c478bd9Sstevel@tonic-gate 		/*
46777c478bd9Sstevel@tonic-gate 		 * If addr is sitting at the start of the segment, then
46787c478bd9Sstevel@tonic-gate 		 * create a page vector to store protection and incore
46797c478bd9Sstevel@tonic-gate 		 * information for pages in the segment, and fill it.
46807c478bd9Sstevel@tonic-gate 		 * Otherwise, we expect *tmp to address the prpagev_t
46817c478bd9Sstevel@tonic-gate 		 * allocated by a previous call to this function.
46827c478bd9Sstevel@tonic-gate 		 */
46837c478bd9Sstevel@tonic-gate 		if (saddr == seg->s_base) {
46847c478bd9Sstevel@tonic-gate 			pagev = pr_pagev_create(seg, check_noreserve);
46857c478bd9Sstevel@tonic-gate 			saddr = pr_pagev_fill(pagev, seg, saddr, eaddr);
46867c478bd9Sstevel@tonic-gate 
46877c478bd9Sstevel@tonic-gate 			ASSERT(*tmp == NULL);
46887c478bd9Sstevel@tonic-gate 			*tmp = pagev;
46897c478bd9Sstevel@tonic-gate 
46907c478bd9Sstevel@tonic-gate 			ASSERT(saddr <= eaddr);
46917c478bd9Sstevel@tonic-gate 			*saddrp = saddr;
46927c478bd9Sstevel@tonic-gate 
46937c478bd9Sstevel@tonic-gate 			if (saddr == eaddr) {
46947c478bd9Sstevel@tonic-gate 				naddr = saddr;
46957c478bd9Sstevel@tonic-gate 				prot = 0;
46967c478bd9Sstevel@tonic-gate 				goto out;
46977c478bd9Sstevel@tonic-gate 			}
46987c478bd9Sstevel@tonic-gate 
46997c478bd9Sstevel@tonic-gate 		} else {
47007c478bd9Sstevel@tonic-gate 			ASSERT(*tmp != NULL);
47017c478bd9Sstevel@tonic-gate 			pagev = (prpagev_t *)*tmp;
47027c478bd9Sstevel@tonic-gate 		}
47037c478bd9Sstevel@tonic-gate 
47047c478bd9Sstevel@tonic-gate 		naddr = pr_pagev_nextprot(pagev, seg, saddrp, eaddr, &prot);
47057c478bd9Sstevel@tonic-gate 		ASSERT(naddr <= eaddr);
47067c478bd9Sstevel@tonic-gate 	}
47077c478bd9Sstevel@tonic-gate 
47087c478bd9Sstevel@tonic-gate out:
47097c478bd9Sstevel@tonic-gate 	if (naddr == eaddr)
47107c478bd9Sstevel@tonic-gate 		pr_getprot_done(tmp);
47117c478bd9Sstevel@tonic-gate 	*naddrp = naddr;
47127c478bd9Sstevel@tonic-gate 	return (prot);
47137c478bd9Sstevel@tonic-gate }
47147c478bd9Sstevel@tonic-gate 
47157c478bd9Sstevel@tonic-gate void
pr_getprot_done(void ** tmp)47167c478bd9Sstevel@tonic-gate pr_getprot_done(void **tmp)
47177c478bd9Sstevel@tonic-gate {
47187c478bd9Sstevel@tonic-gate 	if (*tmp != NULL) {
47197c478bd9Sstevel@tonic-gate 		pr_pagev_destroy((prpagev_t *)*tmp);
47207c478bd9Sstevel@tonic-gate 		*tmp = NULL;
47217c478bd9Sstevel@tonic-gate 	}
47227c478bd9Sstevel@tonic-gate }
47237c478bd9Sstevel@tonic-gate 
47247c478bd9Sstevel@tonic-gate /*
47257c478bd9Sstevel@tonic-gate  * Return true iff the vnode is a /proc file from the object directory.
47267c478bd9Sstevel@tonic-gate  */
47277c478bd9Sstevel@tonic-gate int
pr_isobject(vnode_t * vp)47287c478bd9Sstevel@tonic-gate pr_isobject(vnode_t *vp)
47297c478bd9Sstevel@tonic-gate {
47307c478bd9Sstevel@tonic-gate 	return (vn_matchops(vp, prvnodeops) && VTOP(vp)->pr_type == PR_OBJECT);
47317c478bd9Sstevel@tonic-gate }
47327c478bd9Sstevel@tonic-gate 
47337c478bd9Sstevel@tonic-gate /*
47347c478bd9Sstevel@tonic-gate  * Return true iff the vnode is a /proc file opened by the process itself.
47357c478bd9Sstevel@tonic-gate  */
47367c478bd9Sstevel@tonic-gate int
pr_isself(vnode_t * vp)47377c478bd9Sstevel@tonic-gate pr_isself(vnode_t *vp)
47387c478bd9Sstevel@tonic-gate {
47397c478bd9Sstevel@tonic-gate 	/*
47407c478bd9Sstevel@tonic-gate 	 * XXX: To retain binary compatibility with the old
47417c478bd9Sstevel@tonic-gate 	 * ioctl()-based version of /proc, we exempt self-opens
47427c478bd9Sstevel@tonic-gate 	 * of /proc/<pid> from being marked close-on-exec.
47437c478bd9Sstevel@tonic-gate 	 */
47447c478bd9Sstevel@tonic-gate 	return (vn_matchops(vp, prvnodeops) &&
47457c478bd9Sstevel@tonic-gate 	    (VTOP(vp)->pr_flags & PR_ISSELF) &&
47467c478bd9Sstevel@tonic-gate 	    VTOP(vp)->pr_type != PR_PIDDIR);
47477c478bd9Sstevel@tonic-gate }
47487c478bd9Sstevel@tonic-gate 
47497c478bd9Sstevel@tonic-gate static ssize_t
pr_getpagesize(struct seg * seg,caddr_t saddr,caddr_t * naddrp,caddr_t eaddr)47507c478bd9Sstevel@tonic-gate pr_getpagesize(struct seg *seg, caddr_t saddr, caddr_t *naddrp, caddr_t eaddr)
47517c478bd9Sstevel@tonic-gate {
47527c478bd9Sstevel@tonic-gate 	ssize_t pagesize, hatsize;
47537c478bd9Sstevel@tonic-gate 
4754dc32d872SJosef 'Jeff' Sipek 	ASSERT(AS_WRITE_HELD(seg->s_as));
47557c478bd9Sstevel@tonic-gate 	ASSERT(IS_P2ALIGNED(saddr, PAGESIZE));
47567c478bd9Sstevel@tonic-gate 	ASSERT(IS_P2ALIGNED(eaddr, PAGESIZE));
47577c478bd9Sstevel@tonic-gate 	ASSERT(saddr < eaddr);
47587c478bd9Sstevel@tonic-gate 
47597c478bd9Sstevel@tonic-gate 	pagesize = hatsize = hat_getpagesize(seg->s_as->a_hat, saddr);
47607c478bd9Sstevel@tonic-gate 	ASSERT(pagesize == -1 || IS_P2ALIGNED(pagesize, pagesize));
47617c478bd9Sstevel@tonic-gate 	ASSERT(pagesize != 0);
47627c478bd9Sstevel@tonic-gate 
47637c478bd9Sstevel@tonic-gate 	if (pagesize == -1)
47647c478bd9Sstevel@tonic-gate 		pagesize = PAGESIZE;
47657c478bd9Sstevel@tonic-gate 
47667c478bd9Sstevel@tonic-gate 	saddr += P2NPHASE((uintptr_t)saddr, pagesize);
47677c478bd9Sstevel@tonic-gate 
47687c478bd9Sstevel@tonic-gate 	while (saddr < eaddr) {
47697c478bd9Sstevel@tonic-gate 		if (hatsize != hat_getpagesize(seg->s_as->a_hat, saddr))
47707c478bd9Sstevel@tonic-gate 			break;
47717c478bd9Sstevel@tonic-gate 		ASSERT(IS_P2ALIGNED(saddr, pagesize));
47727c478bd9Sstevel@tonic-gate 		saddr += pagesize;
47737c478bd9Sstevel@tonic-gate 	}
47747c478bd9Sstevel@tonic-gate 
47757c478bd9Sstevel@tonic-gate 	*naddrp = ((saddr < eaddr) ? saddr : eaddr);
47767c478bd9Sstevel@tonic-gate 	return (hatsize);
47777c478bd9Sstevel@tonic-gate }
47787c478bd9Sstevel@tonic-gate 
47797c478bd9Sstevel@tonic-gate /*
47807c478bd9Sstevel@tonic-gate  * Return an array of structures with extended memory map information.
47817c478bd9Sstevel@tonic-gate  * We allocate here; the caller must deallocate.
47827c478bd9Sstevel@tonic-gate  */
47837c478bd9Sstevel@tonic-gate int
prgetxmap(proc_t * p,list_t * iolhead)4784870619e9Sfrankho prgetxmap(proc_t *p, list_t *iolhead)
47857c478bd9Sstevel@tonic-gate {
47867c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
47877c478bd9Sstevel@tonic-gate 	prxmap_t *mp;
47887c478bd9Sstevel@tonic-gate 	struct seg *seg;
47897c478bd9Sstevel@tonic-gate 	struct seg *brkseg, *stkseg;
47907c478bd9Sstevel@tonic-gate 	struct vnode *vp;
47917c478bd9Sstevel@tonic-gate 	struct vattr vattr;
47927c478bd9Sstevel@tonic-gate 	uint_t prot;
47937c478bd9Sstevel@tonic-gate 
4794dc32d872SJosef 'Jeff' Sipek 	ASSERT(as != &kas && AS_WRITE_HELD(as));
47957c478bd9Sstevel@tonic-gate 
4796870619e9Sfrankho 	/*
4797870619e9Sfrankho 	 * Request an initial buffer size that doesn't waste memory
4798870619e9Sfrankho 	 * if the address space has only a small number of segments.
4799870619e9Sfrankho 	 */
4800870619e9Sfrankho 	pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
48017c478bd9Sstevel@tonic-gate 
48027c478bd9Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL)
48037c478bd9Sstevel@tonic-gate 		return (0);
48047c478bd9Sstevel@tonic-gate 
48057c478bd9Sstevel@tonic-gate 	brkseg = break_seg(p);
48067c478bd9Sstevel@tonic-gate 	stkseg = as_segat(as, prgetstackbase(p));
48077c478bd9Sstevel@tonic-gate 
48087c478bd9Sstevel@tonic-gate 	do {
48097c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
48107c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr, baddr;
48117c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
48127c478bd9Sstevel@tonic-gate 		ssize_t psz;
48137c478bd9Sstevel@tonic-gate 		char *parr;
48147c478bd9Sstevel@tonic-gate 		uint64_t npages;
48157c478bd9Sstevel@tonic-gate 		uint64_t pagenum;
48167c478bd9Sstevel@tonic-gate 
4817284ce987SPatrick Mooney 		if ((seg->s_flags & S_HOLE) != 0) {
4818284ce987SPatrick Mooney 			continue;
4819284ce987SPatrick Mooney 		}
48207c478bd9Sstevel@tonic-gate 		/*
48217c478bd9Sstevel@tonic-gate 		 * Segment loop part one: iterate from the base of the segment
48227c478bd9Sstevel@tonic-gate 		 * to its end, pausing at each address boundary (baddr) between
48237c478bd9Sstevel@tonic-gate 		 * ranges that have different virtual memory protections.
48247c478bd9Sstevel@tonic-gate 		 */
48257c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = baddr) {
48267c478bd9Sstevel@tonic-gate 			prot = pr_getprot(seg, 0, &tmp, &saddr, &baddr, eaddr);
48277c478bd9Sstevel@tonic-gate 			ASSERT(baddr >= saddr && baddr <= eaddr);
48287c478bd9Sstevel@tonic-gate 
48297c478bd9Sstevel@tonic-gate 			/*
48307c478bd9Sstevel@tonic-gate 			 * Segment loop part two: iterate from the current
48317c478bd9Sstevel@tonic-gate 			 * position to the end of the protection boundary,
48327c478bd9Sstevel@tonic-gate 			 * pausing at each address boundary (naddr) between
48337c478bd9Sstevel@tonic-gate 			 * ranges that have different underlying page sizes.
48347c478bd9Sstevel@tonic-gate 			 */
48357c478bd9Sstevel@tonic-gate 			for (; saddr < baddr; saddr = naddr) {
48367c478bd9Sstevel@tonic-gate 				psz = pr_getpagesize(seg, saddr, &naddr, baddr);
48377c478bd9Sstevel@tonic-gate 				ASSERT(naddr >= saddr && naddr <= baddr);
48387c478bd9Sstevel@tonic-gate 
4839870619e9Sfrankho 				mp = pr_iol_newbuf(iolhead, sizeof (*mp));
48407c478bd9Sstevel@tonic-gate 
48417c478bd9Sstevel@tonic-gate 				mp->pr_vaddr = (uintptr_t)saddr;
48427c478bd9Sstevel@tonic-gate 				mp->pr_size = naddr - saddr;
48437c478bd9Sstevel@tonic-gate 				mp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
48447c478bd9Sstevel@tonic-gate 				mp->pr_mflags = 0;
48457c478bd9Sstevel@tonic-gate 				if (prot & PROT_READ)
48467c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_READ;
48477c478bd9Sstevel@tonic-gate 				if (prot & PROT_WRITE)
48487c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_WRITE;
48497c478bd9Sstevel@tonic-gate 				if (prot & PROT_EXEC)
48507c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_EXEC;
48517c478bd9Sstevel@tonic-gate 				if (SEGOP_GETTYPE(seg, saddr) & MAP_SHARED)
48527c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_SHARED;
48537c478bd9Sstevel@tonic-gate 				if (SEGOP_GETTYPE(seg, saddr) & MAP_NORESERVE)
48547c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_NORESERVE;
48557c478bd9Sstevel@tonic-gate 				if (seg->s_ops == &segspt_shmops ||
48567c478bd9Sstevel@tonic-gate 				    (seg->s_ops == &segvn_ops &&
48577c478bd9Sstevel@tonic-gate 				    (SEGOP_GETVP(seg, saddr, &vp) != 0 ||
48587c478bd9Sstevel@tonic-gate 				    vp == NULL)))
48597c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_ANON;
48607c478bd9Sstevel@tonic-gate 				if (seg == brkseg)
48617c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_BREAK;
48627c478bd9Sstevel@tonic-gate 				else if (seg == stkseg)
48637c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_STACK;
48647c478bd9Sstevel@tonic-gate 				if (seg->s_ops == &segspt_shmops)
48657c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_ISM | MA_SHM;
48667c478bd9Sstevel@tonic-gate 
48677c478bd9Sstevel@tonic-gate 				mp->pr_pagesize = PAGESIZE;
48687c478bd9Sstevel@tonic-gate 				if (psz == -1) {
48697c478bd9Sstevel@tonic-gate 					mp->pr_hatpagesize = 0;
48707c478bd9Sstevel@tonic-gate 				} else {
48717c478bd9Sstevel@tonic-gate 					mp->pr_hatpagesize = psz;
48727c478bd9Sstevel@tonic-gate 				}
48737c478bd9Sstevel@tonic-gate 
48747c478bd9Sstevel@tonic-gate 				/*
48757c478bd9Sstevel@tonic-gate 				 * Manufacture a filename for the "object" dir.
48767c478bd9Sstevel@tonic-gate 				 */
48777c478bd9Sstevel@tonic-gate 				mp->pr_dev = PRNODEV;
48787c478bd9Sstevel@tonic-gate 				vattr.va_mask = AT_FSID|AT_NODEID;
48797c478bd9Sstevel@tonic-gate 				if (seg->s_ops == &segvn_ops &&
48807c478bd9Sstevel@tonic-gate 				    SEGOP_GETVP(seg, saddr, &vp) == 0 &&
48817c478bd9Sstevel@tonic-gate 				    vp != NULL && vp->v_type == VREG &&
4882da6c28aaSamw 				    VOP_GETATTR(vp, &vattr, 0, CRED(),
4883da6c28aaSamw 				    NULL) == 0) {
48847c478bd9Sstevel@tonic-gate 					mp->pr_dev = vattr.va_fsid;
48857c478bd9Sstevel@tonic-gate 					mp->pr_ino = vattr.va_nodeid;
48867c478bd9Sstevel@tonic-gate 					if (vp == p->p_exec)
48877c478bd9Sstevel@tonic-gate 						(void) strcpy(mp->pr_mapname,
48887c478bd9Sstevel@tonic-gate 						    "a.out");
48897c478bd9Sstevel@tonic-gate 					else
48907c478bd9Sstevel@tonic-gate 						pr_object_name(mp->pr_mapname,
48917c478bd9Sstevel@tonic-gate 						    vp, &vattr);
48927c478bd9Sstevel@tonic-gate 				}
48937c478bd9Sstevel@tonic-gate 
48947c478bd9Sstevel@tonic-gate 				/*
48957c478bd9Sstevel@tonic-gate 				 * Get the SysV shared memory id, if any.
48967c478bd9Sstevel@tonic-gate 				 */
48977c478bd9Sstevel@tonic-gate 				if ((mp->pr_mflags & MA_SHARED) &&
48987c478bd9Sstevel@tonic-gate 				    p->p_segacct && (mp->pr_shmid = shmgetid(p,
48997c478bd9Sstevel@tonic-gate 				    seg->s_base)) != SHMID_NONE) {
49007c478bd9Sstevel@tonic-gate 					if (mp->pr_shmid == SHMID_FREE)
49017c478bd9Sstevel@tonic-gate 						mp->pr_shmid = -1;
49027c478bd9Sstevel@tonic-gate 
49037c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_SHM;
49047c478bd9Sstevel@tonic-gate 				} else {
49057c478bd9Sstevel@tonic-gate 					mp->pr_shmid = -1;
49067c478bd9Sstevel@tonic-gate 				}
49077c478bd9Sstevel@tonic-gate 
49087c478bd9Sstevel@tonic-gate 				npages = ((uintptr_t)(naddr - saddr)) >>
49097c478bd9Sstevel@tonic-gate 				    PAGESHIFT;
49107c478bd9Sstevel@tonic-gate 				parr = kmem_zalloc(npages, KM_SLEEP);
49117c478bd9Sstevel@tonic-gate 
49127c478bd9Sstevel@tonic-gate 				SEGOP_INCORE(seg, saddr, naddr - saddr, parr);
49137c478bd9Sstevel@tonic-gate 
49147c478bd9Sstevel@tonic-gate 				for (pagenum = 0; pagenum < npages; pagenum++) {
49157c478bd9Sstevel@tonic-gate 					if (parr[pagenum] & SEG_PAGE_INCORE)
49167c478bd9Sstevel@tonic-gate 						mp->pr_rss++;
49177c478bd9Sstevel@tonic-gate 					if (parr[pagenum] & SEG_PAGE_ANON)
49187c478bd9Sstevel@tonic-gate 						mp->pr_anon++;
49197c478bd9Sstevel@tonic-gate 					if (parr[pagenum] & SEG_PAGE_LOCKED)
49207c478bd9Sstevel@tonic-gate 						mp->pr_locked++;
49217c478bd9Sstevel@tonic-gate 				}
49227c478bd9Sstevel@tonic-gate 				kmem_free(parr, npages);
49237c478bd9Sstevel@tonic-gate 			}
49247c478bd9Sstevel@tonic-gate 		}
49257c478bd9Sstevel@tonic-gate 		ASSERT(tmp == NULL);
49267c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
49277c478bd9Sstevel@tonic-gate 
4928870619e9Sfrankho 	return (0);
49297c478bd9Sstevel@tonic-gate }
49307c478bd9Sstevel@tonic-gate 
49317c478bd9Sstevel@tonic-gate /*
49327c478bd9Sstevel@tonic-gate  * Return the process's credentials.  We don't need a 32-bit equivalent of
49337c478bd9Sstevel@tonic-gate  * this function because prcred_t and prcred32_t are actually the same.
49347c478bd9Sstevel@tonic-gate  */
49357c478bd9Sstevel@tonic-gate void
prgetcred(proc_t * p,prcred_t * pcrp)49367c478bd9Sstevel@tonic-gate prgetcred(proc_t *p, prcred_t *pcrp)
49377c478bd9Sstevel@tonic-gate {
49387c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
49397c478bd9Sstevel@tonic-gate 	cred2prcred(p->p_cred, pcrp);
49407c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
4941d2a70789SRichard Lowe }
4942d2a70789SRichard Lowe 
4943d2a70789SRichard Lowe void
prgetsecflags(proc_t * p,prsecflags_t * psfp)4944d2a70789SRichard Lowe prgetsecflags(proc_t *p, prsecflags_t *psfp)
4945d2a70789SRichard Lowe {
4946d2a70789SRichard Lowe 	ASSERT(psfp != NULL);
4947d2a70789SRichard Lowe 
4948552c19f2SRobert Mustacchi 	bzero(psfp, sizeof (*psfp));
4949d2a70789SRichard Lowe 	psfp->pr_version = PRSECFLAGS_VERSION_CURRENT;
4950d2a70789SRichard Lowe 	psfp->pr_lower = p->p_secflags.psf_lower;
4951d2a70789SRichard Lowe 	psfp->pr_upper = p->p_secflags.psf_upper;
4952d2a70789SRichard Lowe 	psfp->pr_effective = p->p_secflags.psf_effective;
4953d2a70789SRichard Lowe 	psfp->pr_inherit = p->p_secflags.psf_inherit;
49547c478bd9Sstevel@tonic-gate }
49557c478bd9Sstevel@tonic-gate 
49567c478bd9Sstevel@tonic-gate /*
49577c478bd9Sstevel@tonic-gate  * Compute actual size of the prpriv_t structure.
49587c478bd9Sstevel@tonic-gate  */
49597c478bd9Sstevel@tonic-gate 
49607c478bd9Sstevel@tonic-gate size_t
prgetprivsize(void)49617c478bd9Sstevel@tonic-gate prgetprivsize(void)
49627c478bd9Sstevel@tonic-gate {
49637c478bd9Sstevel@tonic-gate 	return (priv_prgetprivsize(NULL));
49647c478bd9Sstevel@tonic-gate }
49657c478bd9Sstevel@tonic-gate 
49667c478bd9Sstevel@tonic-gate /*
49677c478bd9Sstevel@tonic-gate  * Return the process's privileges.  We don't need a 32-bit equivalent of
49687c478bd9Sstevel@tonic-gate  * this function because prpriv_t and prpriv32_t are actually the same.
49697c478bd9Sstevel@tonic-gate  */
49707c478bd9Sstevel@tonic-gate void
prgetpriv(proc_t * p,prpriv_t * pprp)49717c478bd9Sstevel@tonic-gate prgetpriv(proc_t *p, prpriv_t *pprp)
49727c478bd9Sstevel@tonic-gate {
49737c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
49747c478bd9Sstevel@tonic-gate 	cred2prpriv(p->p_cred, pprp);
49757c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
49767c478bd9Sstevel@tonic-gate }
49777c478bd9Sstevel@tonic-gate 
49787c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
49797c478bd9Sstevel@tonic-gate /*
49807c478bd9Sstevel@tonic-gate  * Return an array of structures with HAT memory map information.
49817c478bd9Sstevel@tonic-gate  * We allocate here; the caller must deallocate.
49827c478bd9Sstevel@tonic-gate  */
49837c478bd9Sstevel@tonic-gate int
prgetxmap32(proc_t * p,list_t * iolhead)4984870619e9Sfrankho prgetxmap32(proc_t *p, list_t *iolhead)
49857c478bd9Sstevel@tonic-gate {
49867c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
49877c478bd9Sstevel@tonic-gate 	prxmap32_t *mp;
49887c478bd9Sstevel@tonic-gate 	struct seg *seg;
49897c478bd9Sstevel@tonic-gate 	struct seg *brkseg, *stkseg;
49907c478bd9Sstevel@tonic-gate 	struct vnode *vp;
49917c478bd9Sstevel@tonic-gate 	struct vattr vattr;
49927c478bd9Sstevel@tonic-gate 	uint_t prot;
49937c478bd9Sstevel@tonic-gate 
4994dc32d872SJosef 'Jeff' Sipek 	ASSERT(as != &kas && AS_WRITE_HELD(as));
49957c478bd9Sstevel@tonic-gate 
4996870619e9Sfrankho 	/*
4997870619e9Sfrankho 	 * Request an initial buffer size that doesn't waste memory
4998870619e9Sfrankho 	 * if the address space has only a small number of segments.
4999870619e9Sfrankho 	 */
5000870619e9Sfrankho 	pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
50017c478bd9Sstevel@tonic-gate 
50027c478bd9Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL)
50037c478bd9Sstevel@tonic-gate 		return (0);
50047c478bd9Sstevel@tonic-gate 
50057c478bd9Sstevel@tonic-gate 	brkseg = break_seg(p);
50067c478bd9Sstevel@tonic-gate 	stkseg = as_segat(as, prgetstackbase(p));
50077c478bd9Sstevel@tonic-gate 
50087c478bd9Sstevel@tonic-gate 	do {
50097c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
50107c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr, baddr;
50117c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
50127c478bd9Sstevel@tonic-gate 		ssize_t psz;
50137c478bd9Sstevel@tonic-gate 		char *parr;
50147c478bd9Sstevel@tonic-gate 		uint64_t npages;
50157c478bd9Sstevel@tonic-gate 		uint64_t pagenum;
50167c478bd9Sstevel@tonic-gate 
5017284ce987SPatrick Mooney 		if ((seg->s_flags & S_HOLE) != 0) {
5018284ce987SPatrick Mooney 			continue;
5019284ce987SPatrick Mooney 		}
5020284ce987SPatrick Mooney 
50217c478bd9Sstevel@tonic-gate 		/*
50227c478bd9Sstevel@tonic-gate 		 * Segment loop part one: iterate from the base of the segment
50237c478bd9Sstevel@tonic-gate 		 * to its end, pausing at each address boundary (baddr) between
50247c478bd9Sstevel@tonic-gate 		 * ranges that have different virtual memory protections.
50257c478bd9Sstevel@tonic-gate 		 */
50267c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = baddr) {
50277c478bd9Sstevel@tonic-gate 			prot = pr_getprot(seg, 0, &tmp, &saddr, &baddr, eaddr);
50287c478bd9Sstevel@tonic-gate 			ASSERT(baddr >= saddr && baddr <= eaddr);
50297c478bd9Sstevel@tonic-gate 
50307c478bd9Sstevel@tonic-gate 			/*
50317c478bd9Sstevel@tonic-gate 			 * Segment loop part two: iterate from the current
50327c478bd9Sstevel@tonic-gate 			 * position to the end of the protection boundary,
50337c478bd9Sstevel@tonic-gate 			 * pausing at each address boundary (naddr) between
50347c478bd9Sstevel@tonic-gate 			 * ranges that have different underlying page sizes.
50357c478bd9Sstevel@tonic-gate 			 */
50367c478bd9Sstevel@tonic-gate 			for (; saddr < baddr; saddr = naddr) {
50377c478bd9Sstevel@tonic-gate 				psz = pr_getpagesize(seg, saddr, &naddr, baddr);
50387c478bd9Sstevel@tonic-gate 				ASSERT(naddr >= saddr && naddr <= baddr);
50397c478bd9Sstevel@tonic-gate 
5040870619e9Sfrankho 				mp = pr_iol_newbuf(iolhead, sizeof (*mp));
50417c478bd9Sstevel@tonic-gate 
50427c478bd9Sstevel@tonic-gate 				mp->pr_vaddr = (caddr32_t)(uintptr_t)saddr;
50437c478bd9Sstevel@tonic-gate 				mp->pr_size = (size32_t)(naddr - saddr);
50447c478bd9Sstevel@tonic-gate 				mp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
50457c478bd9Sstevel@tonic-gate 				mp->pr_mflags = 0;
50467c478bd9Sstevel@tonic-gate 				if (prot & PROT_READ)
50477c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_READ;
50487c478bd9Sstevel@tonic-gate 				if (prot & PROT_WRITE)
50497c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_WRITE;
50507c478bd9Sstevel@tonic-gate 				if (prot & PROT_EXEC)
50517c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_EXEC;
50527c478bd9Sstevel@tonic-gate 				if (SEGOP_GETTYPE(seg, saddr) & MAP_SHARED)
50537c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_SHARED;
50547c478bd9Sstevel@tonic-gate 				if (SEGOP_GETTYPE(seg, saddr) & MAP_NORESERVE)
50557c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_NORESERVE;
50567c478bd9Sstevel@tonic-gate 				if (seg->s_ops == &segspt_shmops ||
50577c478bd9Sstevel@tonic-gate 				    (seg->s_ops == &segvn_ops &&
50587c478bd9Sstevel@tonic-gate 				    (SEGOP_GETVP(seg, saddr, &vp) != 0 ||
50597c478bd9Sstevel@tonic-gate 				    vp == NULL)))
50607c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_ANON;
50617c478bd9Sstevel@tonic-gate 				if (seg == brkseg)
50627c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_BREAK;
50637c478bd9Sstevel@tonic-gate 				else if (seg == stkseg)
50647c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_STACK;
50657c478bd9Sstevel@tonic-gate 				if (seg->s_ops == &segspt_shmops)
50667c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_ISM | MA_SHM;
50677c478bd9Sstevel@tonic-gate 
50687c478bd9Sstevel@tonic-gate 				mp->pr_pagesize = PAGESIZE;
50697c478bd9Sstevel@tonic-gate 				if (psz == -1) {
50707c478bd9Sstevel@tonic-gate 					mp->pr_hatpagesize = 0;
50717c478bd9Sstevel@tonic-gate 				} else {
50727c478bd9Sstevel@tonic-gate 					mp->pr_hatpagesize = psz;
50737c478bd9Sstevel@tonic-gate 				}
50747c478bd9Sstevel@tonic-gate 
50757c478bd9Sstevel@tonic-gate 				/*
50767c478bd9Sstevel@tonic-gate 				 * Manufacture a filename for the "object" dir.
50777c478bd9Sstevel@tonic-gate 				 */
50787c478bd9Sstevel@tonic-gate 				mp->pr_dev = PRNODEV32;
50797c478bd9Sstevel@tonic-gate 				vattr.va_mask = AT_FSID|AT_NODEID;
50807c478bd9Sstevel@tonic-gate 				if (seg->s_ops == &segvn_ops &&
50817c478bd9Sstevel@tonic-gate 				    SEGOP_GETVP(seg, saddr, &vp) == 0 &&
50827c478bd9Sstevel@tonic-gate 				    vp != NULL && vp->v_type == VREG &&
5083da6c28aaSamw 				    VOP_GETATTR(vp, &vattr, 0, CRED(),
5084da6c28aaSamw 				    NULL) == 0) {
50857c478bd9Sstevel@tonic-gate 					(void) cmpldev(&mp->pr_dev,
50867c478bd9Sstevel@tonic-gate 					    vattr.va_fsid);
50877c478bd9Sstevel@tonic-gate 					mp->pr_ino = vattr.va_nodeid;
50887c478bd9Sstevel@tonic-gate 					if (vp == p->p_exec)
50897c478bd9Sstevel@tonic-gate 						(void) strcpy(mp->pr_mapname,
50907c478bd9Sstevel@tonic-gate 						    "a.out");
50917c478bd9Sstevel@tonic-gate 					else
50927c478bd9Sstevel@tonic-gate 						pr_object_name(mp->pr_mapname,
50937c478bd9Sstevel@tonic-gate 						    vp, &vattr);
50947c478bd9Sstevel@tonic-gate 				}
50957c478bd9Sstevel@tonic-gate 
50967c478bd9Sstevel@tonic-gate 				/*
50977c478bd9Sstevel@tonic-gate 				 * Get the SysV shared memory id, if any.
50987c478bd9Sstevel@tonic-gate 				 */
50997c478bd9Sstevel@tonic-gate 				if ((mp->pr_mflags & MA_SHARED) &&
51007c478bd9Sstevel@tonic-gate 				    p->p_segacct && (mp->pr_shmid = shmgetid(p,
51017c478bd9Sstevel@tonic-gate 				    seg->s_base)) != SHMID_NONE) {
51027c478bd9Sstevel@tonic-gate 					if (mp->pr_shmid == SHMID_FREE)
51037c478bd9Sstevel@tonic-gate 						mp->pr_shmid = -1;
51047c478bd9Sstevel@tonic-gate 
51057c478bd9Sstevel@tonic-gate 					mp->pr_mflags |= MA_SHM;
51067c478bd9Sstevel@tonic-gate 				} else {
51077c478bd9Sstevel@tonic-gate 					mp->pr_shmid = -1;
51087c478bd9Sstevel@tonic-gate 				}
51097c478bd9Sstevel@tonic-gate 
51107c478bd9Sstevel@tonic-gate 				npages = ((uintptr_t)(naddr - saddr)) >>
51117c478bd9Sstevel@tonic-gate 				    PAGESHIFT;
51127c478bd9Sstevel@tonic-gate 				parr = kmem_zalloc(npages, KM_SLEEP);
51137c478bd9Sstevel@tonic-gate 
51147c478bd9Sstevel@tonic-gate 				SEGOP_INCORE(seg, saddr, naddr - saddr, parr);
51157c478bd9Sstevel@tonic-gate 
51167c478bd9Sstevel@tonic-gate 				for (pagenum = 0; pagenum < npages; pagenum++) {
51177c478bd9Sstevel@tonic-gate 					if (parr[pagenum] & SEG_PAGE_INCORE)
51187c478bd9Sstevel@tonic-gate 						mp->pr_rss++;
51197c478bd9Sstevel@tonic-gate 					if (parr[pagenum] & SEG_PAGE_ANON)
51207c478bd9Sstevel@tonic-gate 						mp->pr_anon++;
51217c478bd9Sstevel@tonic-gate 					if (parr[pagenum] & SEG_PAGE_LOCKED)
51227c478bd9Sstevel@tonic-gate 						mp->pr_locked++;
51237c478bd9Sstevel@tonic-gate 				}
51247c478bd9Sstevel@tonic-gate 				kmem_free(parr, npages);
51257c478bd9Sstevel@tonic-gate 			}
51267c478bd9Sstevel@tonic-gate 		}
51277c478bd9Sstevel@tonic-gate 		ASSERT(tmp == NULL);
51287c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
51297c478bd9Sstevel@tonic-gate 
5130870619e9Sfrankho 	return (0);
51317c478bd9Sstevel@tonic-gate }
51327c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
5133