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