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