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