drop net-snmp dep
[unleashed.git] / kernel / fs / proc / prioctl.c
blob0ceb5c17cde828f65e59c4ba66a97d2f58cc0fb4
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2017 Joyent, Inc.
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 /* All rights reserved. */
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/vmparam.h>
34 #include <sys/var.h>
35 #include <sys/cmn_err.h>
36 #include <sys/cred.h>
37 #include <sys/debug.h>
38 #include <sys/errno.h>
39 #include <sys/file.h>
40 #include <sys/inline.h>
41 #include <sys/kmem.h>
42 #include <sys/proc.h>
43 #include <sys/brand.h>
44 #include <sys/sysmacros.h>
45 #include <sys/systm.h>
46 #include <sys/vfs.h>
47 #include <sys/vnode.h>
48 #include <sys/cpuvar.h>
49 #include <sys/session.h>
50 #include <sys/signal.h>
51 #include <sys/auxv.h>
52 #include <sys/user.h>
53 #include <sys/disp.h>
54 #include <sys/class.h>
55 #include <sys/ts.h>
56 #include <sys/mman.h>
57 #include <sys/fault.h>
58 #include <sys/syscall.h>
59 #include <sys/schedctl.h>
60 #include <sys/pset.h>
61 #include <sys/old_procfs.h>
62 #include <sys/zone.h>
63 #include <sys/time.h>
64 #include <sys/msacct.h>
65 #include <vm/rm.h>
66 #include <vm/as.h>
67 #include <vm/rm.h>
68 #include <vm/seg.h>
69 #include <vm/seg_vn.h>
70 #include <sys/contract_impl.h>
71 #include <sys/ctfs_impl.h>
72 #include <sys/ctfs.h>
74 #if defined(__i386) || defined(__i386_COMPAT)
75 #include <sys/sysi86.h>
76 #endif
78 #include <sys/proc/prdata.h>
80 static int isprwrioctl(int);
81 static ulong_t prmaprunflags(long);
82 static long prmapsetflags(long);
83 static void prsetrun(kthread_t *, prrun_t *);
84 static int propenm(prnode_t *, caddr_t, caddr_t, int *, cred_t *);
85 extern void oprgetstatus(kthread_t *, prstatus_t *, zone_t *);
86 extern void oprgetpsinfo(proc_t *, prpsinfo_t *, kthread_t *);
87 static int oprgetmap(proc_t *, list_t *);
89 static int
90 prctioctl(prnode_t *pnp, int cmd, intptr_t arg, int flag, cred_t *cr)
92 int error = 0;
93 ct_kparam_t kparam;
94 ct_param_t *param = &kparam.param;
95 ct_template_t *tmpl;
97 if (cmd != CT_TSET && cmd != CT_TGET)
98 return (EINVAL);
100 error = ctparam_copyin((void *)arg, &kparam, flag, cmd);
101 if (error != 0)
102 return (error);
104 if ((error = prlock(pnp, ZNO)) != 0) {
105 kmem_free(kparam.ctpm_kbuf, param->ctpm_size);
106 return (error);
109 tmpl = pnp->pr_common->prc_thread->t_lwp->lwp_ct_active[pnp->pr_cttype];
110 if (tmpl == NULL) {
111 prunlock(pnp);
112 kmem_free(kparam.ctpm_kbuf, param->ctpm_size);
113 return (ESTALE);
116 if (cmd == CT_TSET)
117 error = ctmpl_set(tmpl, &kparam, cr);
118 else
119 error = ctmpl_get(tmpl, &kparam);
121 prunlock(pnp);
123 if (cmd == CT_TGET && error == 0) {
124 error = ctparam_copyout(&kparam, (void *)arg, flag);
125 } else {
126 kmem_free(kparam.ctpm_kbuf, param->ctpm_size);
129 return (error);
134 * Control operations (lots).
136 /* ARGSUSED */ /* BEGIN CSTYLED */
137 #ifdef _SYSCALL32_IMPL
138 static int
139 prioctl64(
140 struct vnode *vp,
141 int cmd,
142 intptr_t arg,
143 int flag,
144 cred_t *cr,
145 int *rvalp,
146 caller_context_t *ct)
147 #else
149 prioctl(
150 struct vnode *vp,
151 int cmd,
152 intptr_t arg,
153 int flag,
154 cred_t *cr,
155 int *rvalp,
156 caller_context_t *ct)
157 #endif /* _SYSCALL32_IMPL */ /* END CSTYLED */
159 int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
160 caddr_t cmaddr = (caddr_t)arg;
161 proc_t *p;
162 user_t *up;
163 kthread_t *t;
164 klwp_t *lwp;
165 prnode_t *pnp = VTOP(vp);
166 prcommon_t *pcp;
167 prnode_t *xpnp = NULL;
168 int error;
169 int zdisp;
170 void *thing = NULL;
171 size_t thingsize = 0;
174 * For copyin()/copyout().
176 union {
177 caddr_t va;
178 int signo;
179 int nice;
180 uint_t lwpid;
181 long flags;
182 prstatus_t prstat;
183 prrun_t prrun;
184 sigset_t smask;
185 siginfo_t info;
186 sysset_t prmask;
187 prgregset_t regs;
188 prfpregset_t fpregs;
189 prpsinfo_t prps;
190 sigset_t holdmask;
191 fltset_t fltmask;
192 prcred_t prcred;
193 prhusage_t prhusage;
194 prmap_t prmap;
195 auxv_t auxv[__KERN_NAUXV_IMPL];
196 } un;
198 if (pnp->pr_type == PR_TMPL)
199 return (prctioctl(pnp, cmd, arg, flag, cr));
202 * Support for old /proc interface.
204 if (pnp->pr_pidfile != NULL) {
205 ASSERT(pnp->pr_type == PR_PIDDIR);
206 vp = pnp->pr_pidfile;
207 pnp = VTOP(vp);
208 ASSERT(pnp->pr_type == PR_PIDFILE);
211 if (pnp->pr_type != PR_PIDFILE && pnp->pr_type != PR_LWPIDFILE)
212 return (ENOTTY);
215 * Fail ioctls which are logically "write" requests unless
216 * the user has write permission.
218 if ((flag & FWRITE) == 0 && isprwrioctl(cmd))
219 return (EBADF);
222 * Perform any necessary copyin() operations before
223 * locking the process. Helps avoid deadlocks and
224 * improves performance.
226 * Also, detect invalid ioctl codes here to avoid
227 * locking a process unnnecessarily.
229 * Also, prepare to allocate space that will be needed below,
230 * case by case.
232 error = 0;
233 switch (cmd) {
234 case PIOCGETPR:
235 thingsize = sizeof (proc_t);
236 break;
237 case PIOCGETU:
238 thingsize = sizeof (user_t);
239 break;
240 case PIOCSTOP:
241 case PIOCWSTOP:
242 case PIOCLWPIDS:
243 case PIOCGTRACE:
244 case PIOCGENTRY:
245 case PIOCGEXIT:
246 case PIOCSRLC:
247 case PIOCRRLC:
248 case PIOCSFORK:
249 case PIOCRFORK:
250 case PIOCGREG:
251 case PIOCGFPREG:
252 case PIOCSTATUS:
253 case PIOCLSTATUS:
254 case PIOCPSINFO:
255 case PIOCMAXSIG:
256 case PIOCGXREGSIZE:
257 break;
258 case PIOCSXREG: /* set extra registers */
259 case PIOCGXREG: /* get extra registers */
260 thingsize = 0;
261 break;
262 case PIOCACTION:
263 thingsize = (nsig-1) * sizeof (struct sigaction);
264 break;
265 case PIOCGHOLD:
266 case PIOCNMAP:
267 case PIOCMAP:
268 case PIOCGFAULT:
269 case PIOCCFAULT:
270 case PIOCCRED:
271 case PIOCGROUPS:
272 case PIOCUSAGE:
273 case PIOCLUSAGE:
274 break;
275 case PIOCOPENPD:
277 * We will need this below.
278 * Allocate it now, before locking the process.
280 xpnp = prgetnode(vp, PR_OPAGEDATA);
281 break;
282 case PIOCNAUXV:
283 case PIOCAUXV:
284 break;
286 #if defined(__i386) || defined(__amd64)
287 case PIOCNLDT:
288 case PIOCLDT:
289 break;
290 #endif /* __i386 || __amd64 */
293 case PIOCOPENM: /* open mapped object for reading */
294 if (cmaddr == NULL)
295 un.va = NULL;
296 else if (copyin(cmaddr, &un.va, sizeof (un.va)))
297 error = EFAULT;
298 break;
300 case PIOCRUN: /* make lwp or process runnable */
301 if (cmaddr == NULL)
302 un.prrun.pr_flags = 0;
303 else if (copyin(cmaddr, &un.prrun, sizeof (un.prrun)))
304 error = EFAULT;
305 break;
307 case PIOCOPENLWP: /* return /proc lwp file descriptor */
308 if (copyin(cmaddr, &un.lwpid, sizeof (un.lwpid)))
309 error = EFAULT;
310 break;
312 case PIOCSTRACE: /* set signal trace mask */
313 if (copyin(cmaddr, &un.smask, sizeof (un.smask)))
314 error = EFAULT;
315 break;
317 case PIOCSSIG: /* set current signal */
318 if (cmaddr == NULL)
319 un.info.si_signo = 0;
320 else if (copyin(cmaddr, &un.info, sizeof (un.info)))
321 error = EFAULT;
322 break;
324 case PIOCKILL: /* send signal */
325 case PIOCUNKILL: /* delete a signal */
326 if (copyin(cmaddr, &un.signo, sizeof (un.signo)))
327 error = EFAULT;
328 break;
330 case PIOCNICE: /* set nice priority */
331 if (copyin(cmaddr, &un.nice, sizeof (un.nice)))
332 error = EFAULT;
333 break;
335 case PIOCSENTRY: /* set syscall entry bit mask */
336 case PIOCSEXIT: /* set syscall exit bit mask */
337 if (copyin(cmaddr, &un.prmask, sizeof (un.prmask)))
338 error = EFAULT;
339 break;
341 case PIOCSET: /* set process flags */
342 case PIOCRESET: /* reset process flags */
343 if (copyin(cmaddr, &un.flags, sizeof (un.flags)))
344 error = EFAULT;
345 break;
347 case PIOCSREG: /* set general registers */
348 if (copyin(cmaddr, un.regs, sizeof (un.regs)))
349 error = EFAULT;
350 break;
352 case PIOCSFPREG: /* set floating-point registers */
353 if (copyin(cmaddr, &un.fpregs, sizeof (un.fpregs)))
354 error = EFAULT;
355 break;
357 case PIOCSHOLD: /* set signal-hold mask */
358 if (copyin(cmaddr, &un.holdmask, sizeof (un.holdmask)))
359 error = EFAULT;
360 break;
362 case PIOCSFAULT: /* set mask of traced faults */
363 if (copyin(cmaddr, &un.fltmask, sizeof (un.fltmask)))
364 error = EFAULT;
365 break;
367 default:
368 error = EINVAL;
369 break;
372 if (error)
373 return (error);
375 startover:
377 * If we need kmem_alloc()d space then we allocate it now, before
378 * grabbing the process lock. Using kmem_alloc(KM_SLEEP) while
379 * holding the process lock leads to deadlock with the clock thread.
380 * (The clock thread wakes up the pageout daemon to free up space.
381 * If the clock thread blocks behind us and we are sleeping waiting
382 * for space, then space may never become available.)
384 if (thingsize) {
385 ASSERT(thing == NULL);
386 thing = kmem_alloc(thingsize, KM_SLEEP);
389 switch (cmd) {
390 case PIOCPSINFO:
391 case PIOCGETPR:
392 case PIOCUSAGE:
393 case PIOCLUSAGE:
394 zdisp = ZYES;
395 break;
396 case PIOCSXREG: /* set extra registers */
398 * perform copyin before grabbing the process lock
400 if (thing) {
401 if (copyin(cmaddr, thing, thingsize)) {
402 kmem_free(thing, thingsize);
403 return (EFAULT);
406 /* fall through... */
407 default:
408 zdisp = ZNO;
409 break;
412 if ((error = prlock(pnp, zdisp)) != 0) {
413 if (thing != NULL)
414 kmem_free(thing, thingsize);
415 if (xpnp)
416 prfreenode(xpnp);
417 return (error);
420 pcp = pnp->pr_common;
421 p = pcp->prc_proc;
422 ASSERT(p != NULL);
425 * Choose a thread/lwp for the operation.
427 if (zdisp == ZNO && cmd != PIOCSTOP && cmd != PIOCWSTOP) {
428 if (pnp->pr_type == PR_LWPIDFILE && cmd != PIOCLSTATUS) {
429 t = pcp->prc_thread;
430 ASSERT(t != NULL);
431 } else {
432 t = prchoose(p); /* returns locked thread */
433 ASSERT(t != NULL);
434 thread_unlock(t);
436 lwp = ttolwp(t);
439 error = 0;
440 switch (cmd) {
442 case PIOCGETPR: /* read struct proc */
444 proc_t *prp = thing;
446 *prp = *p;
447 prunlock(pnp);
448 if (copyout(prp, cmaddr, sizeof (proc_t)))
449 error = EFAULT;
450 kmem_free(prp, sizeof (proc_t));
451 thing = NULL;
452 break;
455 case PIOCGETU: /* read u-area */
457 user_t *userp = thing;
459 up = PTOU(p);
460 *userp = *up;
461 prunlock(pnp);
462 if (copyout(userp, cmaddr, sizeof (user_t)))
463 error = EFAULT;
464 kmem_free(userp, sizeof (user_t));
465 thing = NULL;
466 break;
469 case PIOCOPENM: /* open mapped object for reading */
470 error = propenm(pnp, cmaddr, un.va, rvalp, cr);
471 /* propenm() called prunlock(pnp) */
472 break;
474 case PIOCSTOP: /* stop process or lwp from running */
475 case PIOCWSTOP: /* wait for process or lwp to stop */
477 * Can't apply to a system process.
479 if ((p->p_flag & SSYS) || p->p_as == &kas) {
480 prunlock(pnp);
481 error = EBUSY;
482 break;
485 if (cmd == PIOCSTOP)
486 pr_stop(pnp);
489 * If an lwp is waiting for itself or its process, don't wait.
490 * The stopped lwp would never see the fact that it is stopped.
492 if ((pnp->pr_type == PR_LWPIDFILE)?
493 (pcp->prc_thread == curthread) : (p == curproc)) {
494 if (cmd == PIOCWSTOP)
495 error = EBUSY;
496 prunlock(pnp);
497 break;
500 if ((error = pr_wait_stop(pnp, (time_t)0)) != 0)
501 break; /* pr_wait_stop() unlocked the process */
503 if (cmaddr == NULL)
504 prunlock(pnp);
505 else {
507 * Return process/lwp status information.
509 t = pr_thread(pnp); /* returns locked thread */
510 thread_unlock(t);
511 oprgetstatus(t, &un.prstat, VTOZONE(vp));
512 prunlock(pnp);
513 if (copyout(&un.prstat, cmaddr, sizeof (un.prstat)))
514 error = EFAULT;
516 break;
518 case PIOCRUN: /* make lwp or process runnable */
520 long flags = un.prrun.pr_flags;
523 * Cannot set an lwp running is it is not stopped.
524 * Also, no lwp other than the /proc agent lwp can
525 * be set running so long as the /proc agent lwp exists.
527 if ((!ISTOPPED(t) && !VSTOPPED(t) &&
528 !(t->t_proc_flag & TP_PRSTOP)) ||
529 (p->p_agenttp != NULL &&
530 (t != p->p_agenttp || pnp->pr_type != PR_LWPIDFILE))) {
531 prunlock(pnp);
532 error = EBUSY;
533 break;
536 if (flags & (PRSHOLD|PRSTRACE|PRSFAULT|PRSVADDR))
537 prsetrun(t, &un.prrun);
539 error = pr_setrun(pnp, prmaprunflags(flags));
541 prunlock(pnp);
542 break;
545 case PIOCLWPIDS: /* get array of lwp identifiers */
547 int nlwp;
548 int Nlwp;
549 id_t *idp;
550 id_t *Bidp;
552 Nlwp = nlwp = p->p_lwpcnt;
554 if (thing && thingsize != (Nlwp+1) * sizeof (id_t)) {
555 kmem_free(thing, thingsize);
556 thing = NULL;
558 if (thing == NULL) {
559 thingsize = (Nlwp+1) * sizeof (id_t);
560 thing = kmem_alloc(thingsize, KM_NOSLEEP);
562 if (thing == NULL) {
563 prunlock(pnp);
564 goto startover;
567 idp = thing;
568 thing = NULL;
569 Bidp = idp;
570 if ((t = p->p_tlist) != NULL) {
571 do {
572 ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
573 ASSERT(nlwp > 0);
574 --nlwp;
575 *idp++ = t->t_tid;
576 } while ((t = t->t_forw) != p->p_tlist);
578 *idp = 0;
579 ASSERT(nlwp == 0);
580 prunlock(pnp);
581 if (copyout(Bidp, cmaddr, (Nlwp+1) * sizeof (id_t)))
582 error = EFAULT;
583 kmem_free(Bidp, (Nlwp+1) * sizeof (id_t));
584 break;
587 case PIOCOPENLWP: /* return /proc lwp file descriptor */
589 vnode_t *xvp;
590 int n;
592 prunlock(pnp);
593 if ((xvp = prlwpnode(pnp, un.lwpid)) == NULL)
594 error = ENOENT;
595 else if (error = fassign(&xvp, flag & (FREAD|FWRITE), &n)) {
596 VN_RELE(xvp);
597 } else
598 *rvalp = n;
599 break;
602 case PIOCOPENPD: /* return /proc page data file descriptor */
604 vnode_t *xvp = PTOV(xpnp);
605 vnode_t *dp = pnp->pr_parent;
606 int n;
608 if (pnp->pr_type == PR_LWPIDFILE) {
609 dp = VTOP(dp)->pr_parent;
610 dp = VTOP(dp)->pr_parent;
612 ASSERT(VTOP(dp)->pr_type == PR_PIDDIR);
614 VN_HOLD(dp);
615 pcp = pnp->pr_pcommon;
616 xpnp->pr_ino = ptoi(pcp->prc_pid);
617 xpnp->pr_common = pcp;
618 xpnp->pr_pcommon = pcp;
619 xpnp->pr_parent = dp;
621 xpnp->pr_next = p->p_plist;
622 p->p_plist = xvp;
624 prunlock(pnp);
625 if (error = fassign(&xvp, FREAD, &n)) {
626 VN_RELE(xvp);
627 } else
628 *rvalp = n;
630 xpnp = NULL;
631 break;
634 case PIOCGTRACE: /* get signal trace mask */
635 prassignset(&un.smask, &p->p_sigmask);
636 prunlock(pnp);
637 if (copyout(&un.smask, cmaddr, sizeof (un.smask)))
638 error = EFAULT;
639 break;
641 case PIOCSTRACE: /* set signal trace mask */
642 prdelset(&un.smask, SIGKILL);
643 prassignset(&p->p_sigmask, &un.smask);
644 if (!sigisempty(&p->p_sigmask))
645 p->p_proc_flag |= P_PR_TRACE;
646 else if (prisempty(&p->p_fltmask)) {
647 up = PTOU(p);
648 if (up->u_systrap == 0)
649 p->p_proc_flag &= ~P_PR_TRACE;
651 prunlock(pnp);
652 break;
654 case PIOCSSIG: /* set current signal */
655 error = pr_setsig(pnp, &un.info);
656 prunlock(pnp);
657 if (un.info.si_signo == SIGKILL && error == 0)
658 pr_wait_die(pnp);
659 break;
661 case PIOCKILL: /* send signal */
663 int sig = (int)un.signo;
665 error = pr_kill(pnp, sig, cr);
666 prunlock(pnp);
667 if (sig == SIGKILL && error == 0)
668 pr_wait_die(pnp);
669 break;
672 case PIOCUNKILL: /* delete a signal */
673 error = pr_unkill(pnp, (int)un.signo);
674 prunlock(pnp);
675 break;
677 case PIOCNICE: /* set nice priority */
678 error = pr_nice(p, (int)un.nice, cr);
679 prunlock(pnp);
680 break;
682 case PIOCGENTRY: /* get syscall entry bit mask */
683 case PIOCGEXIT: /* get syscall exit bit mask */
684 up = PTOU(p);
685 if (cmd == PIOCGENTRY) {
686 prassignset(&un.prmask, &up->u_entrymask);
687 } else {
688 prassignset(&un.prmask, &up->u_exitmask);
690 prunlock(pnp);
691 if (copyout(&un.prmask, cmaddr, sizeof (un.prmask)))
692 error = EFAULT;
693 break;
695 case PIOCSENTRY: /* set syscall entry bit mask */
696 case PIOCSEXIT: /* set syscall exit bit mask */
697 pr_setentryexit(p, &un.prmask, cmd == PIOCSENTRY);
698 prunlock(pnp);
699 break;
701 case PIOCSRLC: /* obsolete: set running on last /proc close */
702 error = pr_set(p, prmapsetflags(PR_RLC));
703 prunlock(pnp);
704 break;
706 case PIOCRRLC: /* obsolete: reset run-on-last-close flag */
707 error = pr_unset(p, prmapsetflags(PR_RLC));
708 prunlock(pnp);
709 break;
711 case PIOCSFORK: /* obsolete: set inherit-on-fork flag */
712 error = pr_set(p, prmapsetflags(PR_FORK));
713 prunlock(pnp);
714 break;
716 case PIOCRFORK: /* obsolete: reset inherit-on-fork flag */
717 error = pr_unset(p, prmapsetflags(PR_FORK));
718 prunlock(pnp);
719 break;
721 case PIOCSET: /* set process flags */
722 error = pr_set(p, prmapsetflags(un.flags));
723 prunlock(pnp);
724 break;
726 case PIOCRESET: /* reset process flags */
727 error = pr_unset(p, prmapsetflags(un.flags));
728 prunlock(pnp);
729 break;
731 case PIOCGREG: /* get general registers */
732 if (t->t_state != TS_STOPPED && !VSTOPPED(t))
733 bzero(un.regs, sizeof (un.regs));
734 else {
735 /* drop p_lock while touching the lwp's stack */
736 mutex_exit(&p->p_lock);
737 prgetprregs(lwp, un.regs);
738 mutex_enter(&p->p_lock);
740 prunlock(pnp);
741 if (copyout(un.regs, cmaddr, sizeof (un.regs)))
742 error = EFAULT;
743 break;
745 case PIOCSREG: /* set general registers */
746 if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t))
747 error = EBUSY;
748 else {
749 /* drop p_lock while touching the lwp's stack */
750 mutex_exit(&p->p_lock);
751 prsetprregs(lwp, un.regs, 0);
752 mutex_enter(&p->p_lock);
754 prunlock(pnp);
755 break;
757 case PIOCGFPREG: /* get floating-point registers */
758 if (!prhasfp()) {
759 prunlock(pnp);
760 error = EINVAL; /* No FP support */
761 break;
764 if (t->t_state != TS_STOPPED && !VSTOPPED(t))
765 bzero(&un.fpregs, sizeof (un.fpregs));
766 else {
767 /* drop p_lock while touching the lwp's stack */
768 mutex_exit(&p->p_lock);
769 prgetprfpregs(lwp, &un.fpregs);
770 mutex_enter(&p->p_lock);
772 prunlock(pnp);
773 if (copyout(&un.fpregs, cmaddr, sizeof (un.fpregs)))
774 error = EFAULT;
775 break;
777 case PIOCSFPREG: /* set floating-point registers */
778 if (!prhasfp())
779 error = EINVAL; /* No FP support */
780 else if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t))
781 error = EBUSY;
782 else {
783 /* drop p_lock while touching the lwp's stack */
784 mutex_exit(&p->p_lock);
785 prsetprfpregs(lwp, &un.fpregs);
786 mutex_enter(&p->p_lock);
788 prunlock(pnp);
789 break;
791 case PIOCGXREGSIZE: /* get the size of the extra registers */
793 int xregsize;
795 if (prhasx(p)) {
796 xregsize = prgetprxregsize(p);
797 prunlock(pnp);
798 if (copyout(&xregsize, cmaddr, sizeof (xregsize)))
799 error = EFAULT;
800 } else {
801 prunlock(pnp);
802 error = EINVAL; /* No extra register support */
804 break;
807 case PIOCGXREG: /* get extra registers */
808 if (prhasx(p)) {
809 bzero(thing, thingsize);
810 if (t->t_state == TS_STOPPED || VSTOPPED(t)) {
811 /* drop p_lock to touch the stack */
812 mutex_exit(&p->p_lock);
813 prgetprxregs(lwp, thing);
814 mutex_enter(&p->p_lock);
816 prunlock(pnp);
817 if (copyout(thing, cmaddr, thingsize))
818 error = EFAULT;
819 } else {
820 prunlock(pnp);
821 error = EINVAL; /* No extra register support */
823 if (thing) {
824 kmem_free(thing, thingsize);
825 thing = NULL;
827 break;
829 case PIOCSXREG: /* set extra registers */
830 if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t))
831 error = EBUSY;
832 else if (!prhasx(p))
833 error = EINVAL; /* No extra register support */
834 else if (thing) {
835 /* drop p_lock while touching the lwp's stack */
836 mutex_exit(&p->p_lock);
837 prsetprxregs(lwp, thing);
838 mutex_enter(&p->p_lock);
840 prunlock(pnp);
841 if (thing) {
842 kmem_free(thing, thingsize);
843 thing = NULL;
845 break;
847 case PIOCSTATUS: /* get process/lwp status */
848 oprgetstatus(t, &un.prstat, VTOZONE(vp));
849 prunlock(pnp);
850 if (copyout(&un.prstat, cmaddr, sizeof (un.prstat)))
851 error = EFAULT;
852 break;
854 case PIOCLSTATUS: /* get status for process & all lwps */
856 int Nlwp;
857 int nlwp;
858 prstatus_t *Bprsp;
859 prstatus_t *prsp;
861 nlwp = Nlwp = p->p_lwpcnt;
863 if (thing && thingsize != (Nlwp+1) * sizeof (prstatus_t)) {
864 kmem_free(thing, thingsize);
865 thing = NULL;
867 if (thing == NULL) {
868 thingsize = (Nlwp+1) * sizeof (prstatus_t);
869 thing = kmem_alloc(thingsize, KM_NOSLEEP);
871 if (thing == NULL) {
872 prunlock(pnp);
873 goto startover;
876 Bprsp = thing;
877 thing = NULL;
878 prsp = Bprsp;
879 oprgetstatus(t, prsp, VTOZONE(vp));
880 t = p->p_tlist;
881 do {
882 ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
883 ASSERT(nlwp > 0);
884 --nlwp;
885 oprgetstatus(t, ++prsp, VTOZONE(vp));
886 } while ((t = t->t_forw) != p->p_tlist);
887 ASSERT(nlwp == 0);
888 prunlock(pnp);
889 if (copyout(Bprsp, cmaddr, (Nlwp+1) * sizeof (prstatus_t)))
890 error = EFAULT;
892 kmem_free(Bprsp, (Nlwp+1) * sizeof (prstatus_t));
893 break;
896 case PIOCPSINFO: /* get ps(1) information */
898 prpsinfo_t *psp = &un.prps;
900 oprgetpsinfo(p, psp,
901 (pnp->pr_type == PR_LWPIDFILE)? pcp->prc_thread : NULL);
903 prunlock(pnp);
904 if (copyout(&un.prps, cmaddr, sizeof (un.prps)))
905 error = EFAULT;
906 break;
909 case PIOCMAXSIG: /* get maximum signal number */
911 int n = nsig-1;
913 prunlock(pnp);
914 if (copyout(&n, cmaddr, sizeof (n)))
915 error = EFAULT;
916 break;
919 case PIOCACTION: /* get signal action structures */
921 uint_t sig;
922 struct sigaction *sap = thing;
924 up = PTOU(p);
925 for (sig = 1; sig < nsig; sig++)
926 prgetaction(p, up, sig, &sap[sig-1]);
927 prunlock(pnp);
928 if (copyout(sap, cmaddr, (nsig-1) * sizeof (struct sigaction)))
929 error = EFAULT;
930 kmem_free(sap, (nsig-1) * sizeof (struct sigaction));
931 thing = NULL;
932 break;
935 case PIOCGHOLD: /* get signal-hold mask */
936 schedctl_finish_sigblock(t);
937 sigktou(&t->t_hold, &un.holdmask);
938 prunlock(pnp);
939 if (copyout(&un.holdmask, cmaddr, sizeof (un.holdmask)))
940 error = EFAULT;
941 break;
943 case PIOCSHOLD: /* set signal-hold mask */
944 pr_sethold(pnp, &un.holdmask);
945 prunlock(pnp);
946 break;
948 case PIOCNMAP: /* get number of memory mappings */
950 int n;
951 struct as *as = p->p_as;
953 if ((p->p_flag & SSYS) || as == &kas)
954 n = 0;
955 else {
956 mutex_exit(&p->p_lock);
957 AS_LOCK_ENTER(as, RW_WRITER);
958 n = prnsegs(as, 0);
959 AS_LOCK_EXIT(as);
960 mutex_enter(&p->p_lock);
962 prunlock(pnp);
963 if (copyout(&n, cmaddr, sizeof (int)))
964 error = EFAULT;
965 break;
968 case PIOCMAP: /* get memory map information */
970 list_t iolhead;
971 struct as *as = p->p_as;
973 if ((p->p_flag & SSYS) || as == &kas) {
974 error = 0;
975 prunlock(pnp);
976 } else {
977 mutex_exit(&p->p_lock);
978 AS_LOCK_ENTER(as, RW_WRITER);
979 error = oprgetmap(p, &iolhead);
980 AS_LOCK_EXIT(as);
981 mutex_enter(&p->p_lock);
982 prunlock(pnp);
984 error = pr_iol_copyout_and_free(&iolhead,
985 &cmaddr, error);
988 * The procfs PIOCMAP ioctl returns an all-zero buffer
989 * to indicate the end of the prmap[] array.
990 * Append it to whatever has already been copied out.
992 bzero(&un.prmap, sizeof (un.prmap));
993 if (!error && copyout(&un.prmap, cmaddr, sizeof (un.prmap)))
994 error = EFAULT;
996 break;
999 case PIOCGFAULT: /* get mask of traced faults */
1000 prassignset(&un.fltmask, &p->p_fltmask);
1001 prunlock(pnp);
1002 if (copyout(&un.fltmask, cmaddr, sizeof (un.fltmask)))
1003 error = EFAULT;
1004 break;
1006 case PIOCSFAULT: /* set mask of traced faults */
1007 pr_setfault(p, &un.fltmask);
1008 prunlock(pnp);
1009 break;
1011 case PIOCCFAULT: /* clear current fault */
1012 lwp->lwp_curflt = 0;
1013 prunlock(pnp);
1014 break;
1016 case PIOCCRED: /* get process credentials */
1018 cred_t *cp;
1020 mutex_enter(&p->p_crlock);
1021 cp = p->p_cred;
1022 un.prcred.pr_euid = crgetuid(cp);
1023 un.prcred.pr_ruid = crgetruid(cp);
1024 un.prcred.pr_suid = crgetsuid(cp);
1025 un.prcred.pr_egid = crgetgid(cp);
1026 un.prcred.pr_rgid = crgetrgid(cp);
1027 un.prcred.pr_sgid = crgetsgid(cp);
1028 un.prcred.pr_ngroups = crgetngroups(cp);
1029 mutex_exit(&p->p_crlock);
1031 prunlock(pnp);
1032 if (copyout(&un.prcred, cmaddr, sizeof (un.prcred)))
1033 error = EFAULT;
1034 break;
1037 case PIOCGROUPS: /* get supplementary groups */
1039 cred_t *cp;
1041 mutex_enter(&p->p_crlock);
1042 cp = p->p_cred;
1043 crhold(cp);
1044 mutex_exit(&p->p_crlock);
1046 prunlock(pnp);
1047 if (copyout(crgetgroups(cp), cmaddr,
1048 MAX(crgetngroups(cp), 1) * sizeof (gid_t)))
1049 error = EFAULT;
1050 crfree(cp);
1051 break;
1054 case PIOCUSAGE: /* get usage info */
1057 * For an lwp file descriptor, return just the lwp usage.
1058 * For a process file descriptor, return total usage,
1059 * all current lwps plus all defunct lwps.
1061 prhusage_t *pup = &un.prhusage;
1062 prusage_t *upup;
1064 bzero(pup, sizeof (*pup));
1065 pup->pr_tstamp = gethrtime();
1067 if (pnp->pr_type == PR_LWPIDFILE) {
1068 t = pcp->prc_thread;
1069 if (t != NULL)
1070 prgetusage(t, pup);
1071 else
1072 error = ENOENT;
1073 } else {
1074 pup->pr_count = p->p_defunct;
1075 pup->pr_create = p->p_mstart;
1076 pup->pr_term = p->p_mterm;
1078 pup->pr_rtime = p->p_mlreal;
1079 pup->pr_utime = p->p_acct[LMS_USER];
1080 pup->pr_stime = p->p_acct[LMS_SYSTEM];
1081 pup->pr_ttime = p->p_acct[LMS_TRAP];
1082 pup->pr_tftime = p->p_acct[LMS_TFAULT];
1083 pup->pr_dftime = p->p_acct[LMS_DFAULT];
1084 pup->pr_kftime = p->p_acct[LMS_KFAULT];
1085 pup->pr_ltime = p->p_acct[LMS_USER_LOCK];
1086 pup->pr_slptime = p->p_acct[LMS_SLEEP];
1087 pup->pr_wtime = p->p_acct[LMS_WAIT_CPU];
1088 pup->pr_stoptime = p->p_acct[LMS_STOPPED];
1090 pup->pr_minf = p->p_ru.minflt;
1091 pup->pr_majf = p->p_ru.majflt;
1092 pup->pr_nswap = p->p_ru.nswap;
1093 pup->pr_inblk = p->p_ru.inblock;
1094 pup->pr_oublk = p->p_ru.oublock;
1095 pup->pr_msnd = p->p_ru.msgsnd;
1096 pup->pr_mrcv = p->p_ru.msgrcv;
1097 pup->pr_sigs = p->p_ru.nsignals;
1098 pup->pr_vctx = p->p_ru.nvcsw;
1099 pup->pr_ictx = p->p_ru.nivcsw;
1100 pup->pr_sysc = p->p_ru.sysc;
1101 pup->pr_ioch = p->p_ru.ioch;
1104 * Add the usage information for each active lwp.
1106 if ((t = p->p_tlist) != NULL &&
1107 !(pcp->prc_flags & PRC_DESTROY)) {
1108 do {
1109 ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
1110 pup->pr_count++;
1111 praddusage(t, pup);
1112 } while ((t = t->t_forw) != p->p_tlist);
1116 prunlock(pnp);
1118 upup = kmem_zalloc(sizeof (*upup), KM_SLEEP);
1119 prcvtusage(&un.prhusage, upup);
1120 if (copyout(upup, cmaddr, sizeof (*upup)))
1121 error = EFAULT;
1122 kmem_free(upup, sizeof (*upup));
1124 break;
1127 case PIOCLUSAGE: /* get detailed usage info */
1129 int Nlwp;
1130 int nlwp;
1131 prusage_t *upup;
1132 prusage_t *Bupup;
1133 prhusage_t *pup;
1134 hrtime_t curtime;
1136 nlwp = Nlwp = (pcp->prc_flags & PRC_DESTROY)? 0 : p->p_lwpcnt;
1138 if (thing && thingsize !=
1139 sizeof (prhusage_t) + (Nlwp+1) * sizeof (prusage_t)) {
1140 kmem_free(thing, thingsize);
1141 thing = NULL;
1143 if (thing == NULL) {
1144 thingsize = sizeof (prhusage_t) +
1145 (Nlwp+1) * sizeof (prusage_t);
1146 thing = kmem_alloc(thingsize, KM_NOSLEEP);
1148 if (thing == NULL) {
1149 prunlock(pnp);
1150 goto startover;
1153 pup = thing;
1154 upup = Bupup = (prusage_t *)(pup + 1);
1156 ASSERT(p == pcp->prc_proc);
1158 curtime = gethrtime();
1161 * First the summation over defunct lwps.
1163 bzero(pup, sizeof (*pup));
1164 pup->pr_count = p->p_defunct;
1165 pup->pr_tstamp = curtime;
1166 pup->pr_create = p->p_mstart;
1167 pup->pr_term = p->p_mterm;
1169 pup->pr_rtime = p->p_mlreal;
1170 pup->pr_utime = p->p_acct[LMS_USER];
1171 pup->pr_stime = p->p_acct[LMS_SYSTEM];
1172 pup->pr_ttime = p->p_acct[LMS_TRAP];
1173 pup->pr_tftime = p->p_acct[LMS_TFAULT];
1174 pup->pr_dftime = p->p_acct[LMS_DFAULT];
1175 pup->pr_kftime = p->p_acct[LMS_KFAULT];
1176 pup->pr_ltime = p->p_acct[LMS_USER_LOCK];
1177 pup->pr_slptime = p->p_acct[LMS_SLEEP];
1178 pup->pr_wtime = p->p_acct[LMS_WAIT_CPU];
1179 pup->pr_stoptime = p->p_acct[LMS_STOPPED];
1181 pup->pr_minf = p->p_ru.minflt;
1182 pup->pr_majf = p->p_ru.majflt;
1183 pup->pr_nswap = p->p_ru.nswap;
1184 pup->pr_inblk = p->p_ru.inblock;
1185 pup->pr_oublk = p->p_ru.oublock;
1186 pup->pr_msnd = p->p_ru.msgsnd;
1187 pup->pr_mrcv = p->p_ru.msgrcv;
1188 pup->pr_sigs = p->p_ru.nsignals;
1189 pup->pr_vctx = p->p_ru.nvcsw;
1190 pup->pr_ictx = p->p_ru.nivcsw;
1191 pup->pr_sysc = p->p_ru.sysc;
1192 pup->pr_ioch = p->p_ru.ioch;
1194 prcvtusage(pup, upup);
1197 * Fill one prusage struct for each active lwp.
1199 if ((t = p->p_tlist) != NULL &&
1200 !(pcp->prc_flags & PRC_DESTROY)) {
1201 do {
1202 ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
1203 ASSERT(nlwp > 0);
1204 --nlwp;
1205 upup++;
1206 prgetusage(t, pup);
1207 prcvtusage(pup, upup);
1208 } while ((t = t->t_forw) != p->p_tlist);
1210 ASSERT(nlwp == 0);
1212 prunlock(pnp);
1213 if (copyout(Bupup, cmaddr, (Nlwp+1) * sizeof (prusage_t)))
1214 error = EFAULT;
1215 kmem_free(thing, thingsize);
1216 thing = NULL;
1217 break;
1220 case PIOCNAUXV: /* get number of aux vector entries */
1222 int n = __KERN_NAUXV_IMPL;
1224 prunlock(pnp);
1225 if (copyout(&n, cmaddr, sizeof (int)))
1226 error = EFAULT;
1227 break;
1230 case PIOCAUXV: /* get aux vector (see sys/auxv.h) */
1232 up = PTOU(p);
1233 bcopy(up->u_auxv, un.auxv,
1234 __KERN_NAUXV_IMPL * sizeof (auxv_t));
1235 prunlock(pnp);
1236 if (copyout(un.auxv, cmaddr,
1237 __KERN_NAUXV_IMPL * sizeof (auxv_t)))
1238 error = EFAULT;
1239 break;
1242 #if defined(__i386) || defined(__amd64)
1243 case PIOCNLDT: /* get number of LDT entries */
1245 int n;
1247 mutex_exit(&p->p_lock);
1248 mutex_enter(&p->p_ldtlock);
1249 n = prnldt(p);
1250 mutex_exit(&p->p_ldtlock);
1251 mutex_enter(&p->p_lock);
1252 prunlock(pnp);
1253 if (copyout(&n, cmaddr, sizeof (n)))
1254 error = EFAULT;
1255 break;
1258 case PIOCLDT: /* get LDT entries */
1260 struct ssd *ssd;
1261 int n;
1263 mutex_exit(&p->p_lock);
1264 mutex_enter(&p->p_ldtlock);
1265 n = prnldt(p);
1267 if (thing && thingsize != (n+1) * sizeof (*ssd)) {
1268 kmem_free(thing, thingsize);
1269 thing = NULL;
1271 if (thing == NULL) {
1272 thingsize = (n+1) * sizeof (*ssd);
1273 thing = kmem_alloc(thingsize, KM_NOSLEEP);
1275 if (thing == NULL) {
1276 mutex_exit(&p->p_ldtlock);
1277 mutex_enter(&p->p_lock);
1278 prunlock(pnp);
1279 goto startover;
1282 ssd = thing;
1283 thing = NULL;
1284 if (n != 0)
1285 prgetldt(p, ssd);
1286 mutex_exit(&p->p_ldtlock);
1287 mutex_enter(&p->p_lock);
1288 prunlock(pnp);
1290 /* mark the end of the list with a null entry */
1291 bzero(&ssd[n], sizeof (*ssd));
1292 if (copyout(ssd, cmaddr, (n+1) * sizeof (*ssd)))
1293 error = EFAULT;
1294 kmem_free(ssd, (n+1) * sizeof (*ssd));
1295 break;
1297 #endif /* __i386 || __amd64 */
1300 default:
1301 prunlock(pnp);
1302 error = EINVAL;
1303 break;
1307 ASSERT(thing == NULL);
1308 ASSERT(xpnp == NULL);
1309 return (error);
1312 #ifdef _SYSCALL32_IMPL
1314 static int oprgetmap32(proc_t *, list_t *);
1316 void
1317 oprgetstatus32(kthread_t *t, prstatus32_t *sp, zone_t *zp)
1319 proc_t *p = ttoproc(t);
1320 klwp_t *lwp = ttolwp(t);
1321 int32_t flags;
1322 user_t *up;
1323 ulong_t instr;
1325 ASSERT(MUTEX_HELD(&p->p_lock));
1327 up = PTOU(p);
1328 bzero(sp, sizeof (*sp));
1329 flags = 0L;
1330 if (t->t_state == TS_STOPPED) {
1331 flags |= PR_STOPPED;
1332 if ((t->t_schedflag & TS_PSTART) == 0)
1333 flags |= PR_ISTOP;
1334 } else if (VSTOPPED(t)) {
1335 flags |= PR_STOPPED|PR_ISTOP;
1337 if (!(flags & PR_ISTOP) && (t->t_proc_flag & TP_PRSTOP))
1338 flags |= PR_DSTOP;
1339 if (lwp->lwp_asleep)
1340 flags |= PR_ASLEEP;
1341 if (p->p_proc_flag & P_PR_FORK)
1342 flags |= PR_FORK;
1343 if (p->p_proc_flag & P_PR_RUNLCL)
1344 flags |= PR_RLC;
1345 if (p->p_proc_flag & P_PR_KILLCL)
1346 flags |= PR_KLC;
1347 if (p->p_proc_flag & P_PR_ASYNC)
1348 flags |= PR_ASYNC;
1349 if (p->p_proc_flag & P_PR_BPTADJ)
1350 flags |= PR_BPTADJ;
1351 if (p->p_proc_flag & P_PR_PTRACE)
1352 flags |= PR_PCOMPAT;
1353 if (t->t_proc_flag & TP_MSACCT)
1354 flags |= PR_MSACCT;
1355 sp->pr_flags = flags;
1356 if (VSTOPPED(t)) {
1357 sp->pr_why = PR_REQUESTED;
1358 sp->pr_what = 0;
1359 } else {
1360 sp->pr_why = t->t_whystop;
1361 sp->pr_what = t->t_whatstop;
1364 if (t->t_whystop == PR_FAULTED) {
1365 siginfo_kto32(&lwp->lwp_siginfo, &sp->pr_info);
1366 if (t->t_whatstop == FLTPAGE)
1367 sp->pr_info.si_addr =
1368 (caddr32_t)(uintptr_t)lwp->lwp_siginfo.si_addr;
1369 } else if (lwp->lwp_curinfo)
1370 siginfo_kto32(&lwp->lwp_curinfo->sq_info, &sp->pr_info);
1372 if (SI_FROMUSER(&lwp->lwp_siginfo) && zp->zone_id != GLOBAL_ZONEID &&
1373 sp->pr_info.si_zoneid != zp->zone_id) {
1374 sp->pr_info.si_pid = zp->zone_zsched->p_pid;
1375 sp->pr_info.si_uid = 0;
1376 sp->pr_info.si_ctid = -1;
1377 sp->pr_info.si_zoneid = zp->zone_id;
1380 sp->pr_cursig = lwp->lwp_cursig;
1381 prassignset(&sp->pr_sigpend, &p->p_sig);
1382 prassignset(&sp->pr_lwppend, &t->t_sig);
1383 schedctl_finish_sigblock(t);
1384 prassignset(&sp->pr_sighold, &t->t_hold);
1385 sp->pr_altstack.ss_sp =
1386 (caddr32_t)(uintptr_t)lwp->lwp_sigaltstack.ss_sp;
1387 sp->pr_altstack.ss_size = (size32_t)lwp->lwp_sigaltstack.ss_size;
1388 sp->pr_altstack.ss_flags = (int32_t)lwp->lwp_sigaltstack.ss_flags;
1389 prgetaction32(p, up, lwp->lwp_cursig, &sp->pr_action);
1390 sp->pr_pid = p->p_pid;
1391 if (curproc->p_zone->zone_id != GLOBAL_ZONEID &&
1392 (p->p_flag & SZONETOP)) {
1393 ASSERT(p->p_zone->zone_id != GLOBAL_ZONEID);
1395 * Inside local zones, fake zsched's pid as parent pids for
1396 * processes which reference processes outside of the zone.
1398 sp->pr_ppid = curproc->p_zone->zone_zsched->p_pid;
1399 } else {
1400 sp->pr_ppid = p->p_ppid;
1402 sp->pr_pgrp = p->p_pgrp;
1403 sp->pr_sid = p->p_sessp->s_sid;
1404 hrt2ts32(mstate_aggr_state(p, LMS_USER), &sp->pr_utime);
1405 hrt2ts32(mstate_aggr_state(p, LMS_SYSTEM), &sp->pr_stime);
1406 TICK_TO_TIMESTRUC32(p->p_cutime, &sp->pr_cutime);
1407 TICK_TO_TIMESTRUC32(p->p_cstime, &sp->pr_cstime);
1408 (void) strncpy(sp->pr_clname, sclass[t->t_cid].cl_name,
1409 sizeof (sp->pr_clname) - 1);
1410 sp->pr_who = t->t_tid;
1411 sp->pr_nlwp = p->p_lwpcnt;
1412 sp->pr_brkbase = (caddr32_t)(uintptr_t)p->p_brkbase;
1413 sp->pr_brksize = (size32_t)p->p_brksize;
1414 sp->pr_stkbase = (caddr32_t)(uintptr_t)prgetstackbase(p);
1415 sp->pr_stksize = (size32_t)p->p_stksize;
1416 sp->pr_oldcontext = (caddr32_t)lwp->lwp_oldcontext;
1417 sp->pr_processor = t->t_cpu->cpu_id;
1418 sp->pr_bind = t->t_bind_cpu;
1421 * Fetch the current instruction, if not a system process.
1422 * We don't attempt this unless the lwp is stopped.
1424 if ((p->p_flag & SSYS) || p->p_as == &kas)
1425 sp->pr_flags |= (PR_ISSYS|PR_PCINVAL);
1426 else if (!(flags & PR_STOPPED))
1427 sp->pr_flags |= PR_PCINVAL;
1428 else if (!prfetchinstr(lwp, &instr))
1429 sp->pr_flags |= PR_PCINVAL;
1430 else
1431 sp->pr_instr = (uint32_t)instr;
1434 * Drop p_lock while touching the lwp's stack.
1436 mutex_exit(&p->p_lock);
1437 if (prisstep(lwp))
1438 sp->pr_flags |= PR_STEP;
1439 if ((flags & (PR_STOPPED|PR_ASLEEP)) && t->t_sysnum) {
1440 int i;
1441 auxv_t *auxp;
1443 sp->pr_syscall = get_syscall32_args(lwp,
1444 (int *)sp->pr_sysarg, &i);
1445 sp->pr_nsysarg = (short)i;
1446 if (t->t_whystop == PR_SYSEXIT && t->t_sysnum == SYS_execve) {
1447 sp->pr_sysarg[0] = 0;
1448 sp->pr_sysarg[1] = (caddr32_t)up->u_argv;
1449 sp->pr_sysarg[2] = (caddr32_t)up->u_envp;
1450 for (i = 0, auxp = up->u_auxv;
1451 i < sizeof (up->u_auxv) / sizeof (up->u_auxv[0]);
1452 i++, auxp++) {
1453 if (auxp->a_type == AT_SUN_EXECNAME) {
1454 sp->pr_sysarg[0] =
1455 (caddr32_t)
1456 (uintptr_t)auxp->a_un.a_ptr;
1457 break;
1462 if ((flags & PR_STOPPED) || t == curthread)
1463 prgetprregs32(lwp, sp->pr_reg);
1464 mutex_enter(&p->p_lock);
1467 void
1468 oprgetpsinfo32(proc_t *p, prpsinfo32_t *psp, kthread_t *tp)
1470 kthread_t *t;
1471 char c, state;
1472 user_t *up;
1473 dev_t d;
1474 uint64_t pct;
1475 int retval, niceval;
1476 cred_t *cred;
1477 struct as *as;
1478 hrtime_t hrutime, hrstime, cur_time;
1480 ASSERT(MUTEX_HELD(&p->p_lock));
1482 bzero(psp, sizeof (*psp));
1484 if ((t = tp) == NULL)
1485 t = prchoose(p); /* returns locked thread */
1486 else
1487 thread_lock(t);
1489 /* kludge: map thread state enum into process state enum */
1491 if (t == NULL) {
1492 state = TS_ZOMB;
1493 } else {
1494 state = VSTOPPED(t) ? TS_STOPPED : t->t_state;
1495 thread_unlock(t);
1498 switch (state) {
1499 case TS_SLEEP: state = SSLEEP; break;
1500 case TS_RUN: state = SRUN; break;
1501 case TS_ONPROC: state = SONPROC; break;
1502 case TS_ZOMB: state = SZOMB; break;
1503 case TS_STOPPED: state = SSTOP; break;
1504 default: state = 0; break;
1506 switch (state) {
1507 case SSLEEP: c = 'S'; break;
1508 case SRUN: c = 'R'; break;
1509 case SZOMB: c = 'Z'; break;
1510 case SSTOP: c = 'T'; break;
1511 case SIDL: c = 'I'; break;
1512 case SONPROC: c = 'O'; break;
1513 #ifdef SXBRK
1514 case SXBRK: c = 'X'; break;
1515 #endif
1516 default: c = '?'; break;
1518 psp->pr_state = state;
1519 psp->pr_sname = c;
1520 psp->pr_zomb = (state == SZOMB);
1522 * only export SSYS and SMSACCT; everything else is off-limits to
1523 * userland apps.
1525 psp->pr_flag = p->p_flag & (SSYS | SMSACCT);
1527 mutex_enter(&p->p_crlock);
1528 cred = p->p_cred;
1529 psp->pr_uid = crgetruid(cred);
1530 psp->pr_gid = crgetrgid(cred);
1531 psp->pr_euid = crgetuid(cred);
1532 psp->pr_egid = crgetgid(cred);
1533 mutex_exit(&p->p_crlock);
1535 psp->pr_pid = p->p_pid;
1536 if (curproc->p_zone->zone_id != GLOBAL_ZONEID &&
1537 (p->p_flag & SZONETOP)) {
1538 ASSERT(p->p_zone->zone_id != GLOBAL_ZONEID);
1540 * Inside local zones, fake zsched's pid as parent pids for
1541 * processes which reference processes outside of the zone.
1543 psp->pr_ppid = curproc->p_zone->zone_zsched->p_pid;
1544 } else {
1545 psp->pr_ppid = p->p_ppid;
1547 psp->pr_pgrp = p->p_pgrp;
1548 psp->pr_sid = p->p_sessp->s_sid;
1549 psp->pr_addr = 0; /* cannot represent 64-bit addr in 32 bits */
1550 hrutime = mstate_aggr_state(p, LMS_USER);
1551 hrstime = mstate_aggr_state(p, LMS_SYSTEM);
1552 hrt2ts32(hrutime + hrstime, &psp->pr_time);
1553 TICK_TO_TIMESTRUC32(p->p_cutime + p->p_cstime, &psp->pr_ctime);
1554 switch (p->p_model) {
1555 case DATAMODEL_ILP32:
1556 psp->pr_dmodel = PR_MODEL_ILP32;
1557 break;
1558 case DATAMODEL_LP64:
1559 psp->pr_dmodel = PR_MODEL_LP64;
1560 break;
1562 if (state == SZOMB || t == NULL) {
1563 int wcode = p->p_wcode; /* must be atomic read */
1565 if (wcode)
1566 psp->pr_wstat = wstat(wcode, p->p_wdata);
1567 psp->pr_lttydev = PRNODEV32;
1568 psp->pr_ottydev = (o_dev_t)PRNODEV32;
1569 psp->pr_size = 0;
1570 psp->pr_rssize = 0;
1571 psp->pr_pctmem = 0;
1572 } else {
1573 up = PTOU(p);
1574 psp->pr_wchan = 0; /* cannot represent in 32 bits */
1575 psp->pr_pri = t->t_pri;
1576 (void) strncpy(psp->pr_clname, sclass[t->t_cid].cl_name,
1577 sizeof (psp->pr_clname) - 1);
1578 retval = CL_DONICE(t, NULL, 0, &niceval);
1579 if (retval == 0) {
1580 psp->pr_oldpri = v.v_maxsyspri - psp->pr_pri;
1581 psp->pr_nice = niceval + NZERO;
1582 } else {
1583 psp->pr_oldpri = 0;
1584 psp->pr_nice = 0;
1586 d = cttydev(p);
1587 #ifdef sun
1589 extern dev_t rwsconsdev, rconsdev, uconsdev;
1591 * If the controlling terminal is the real
1592 * or workstation console device, map to what the
1593 * user thinks is the console device. Handle case when
1594 * rwsconsdev or rconsdev is set to NODEV for Starfire.
1596 if ((d == rwsconsdev || d == rconsdev) && d != NODEV)
1597 d = uconsdev;
1599 #endif
1600 (void) cmpldev(&psp->pr_lttydev, d);
1601 psp->pr_ottydev = cmpdev(d);
1602 TIMESPEC_TO_TIMESPEC32(&psp->pr_start, &up->u_start);
1603 bcopy(up->u_comm, psp->pr_fname,
1604 MIN(sizeof (up->u_comm), sizeof (psp->pr_fname)-1));
1605 bcopy(up->u_psargs, psp->pr_psargs,
1606 MIN(PRARGSZ-1, PSARGSZ));
1607 psp->pr_syscall = t->t_sysnum;
1608 psp->pr_argc = up->u_argc;
1609 psp->pr_argv = (caddr32_t)up->u_argv;
1610 psp->pr_envp = (caddr32_t)up->u_envp;
1612 /* compute %cpu for the lwp or process */
1613 pct = 0;
1614 if ((t = tp) == NULL)
1615 t = p->p_tlist;
1616 cur_time = gethrtime_unscaled();
1617 do {
1618 pct += cpu_update_pct(t, cur_time);
1619 if (tp != NULL) /* just do the one lwp */
1620 break;
1621 } while ((t = t->t_forw) != p->p_tlist);
1623 psp->pr_pctcpu = prgetpctcpu(pct);
1624 psp->pr_cpu = (psp->pr_pctcpu*100 + 0x6000) >> 15; /* [0..99] */
1625 if (psp->pr_cpu > 99)
1626 psp->pr_cpu = 99;
1628 if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
1629 psp->pr_size = 0;
1630 psp->pr_rssize = 0;
1631 psp->pr_pctmem = 0;
1632 } else {
1633 mutex_exit(&p->p_lock);
1634 AS_LOCK_ENTER(as, RW_READER);
1635 psp->pr_size = (size32_t)btopr(as->a_resvsize);
1636 psp->pr_rssize = (size32_t)rm_asrss(as);
1637 psp->pr_pctmem = rm_pctmemory(as);
1638 AS_LOCK_EXIT(as);
1639 mutex_enter(&p->p_lock);
1642 psp->pr_bysize = (size32_t)ptob(psp->pr_size);
1643 psp->pr_byrssize = (size32_t)ptob(psp->pr_rssize);
1646 * If we are looking at an LP64 process, zero out
1647 * the fields that cannot be represented in ILP32.
1649 if (p->p_model != DATAMODEL_ILP32) {
1650 psp->pr_size = 0;
1651 psp->pr_rssize = 0;
1652 psp->pr_bysize = 0;
1653 psp->pr_byrssize = 0;
1654 psp->pr_argv = 0;
1655 psp->pr_envp = 0;
1659 /*ARGSUSED*/
1660 static int
1661 prioctl32(
1662 struct vnode *vp,
1663 int cmd,
1664 intptr_t arg,
1665 int flag,
1666 cred_t *cr,
1667 int *rvalp,
1668 caller_context_t *ct)
1670 int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
1671 caddr_t cmaddr = (caddr_t)arg;
1672 proc_t *p;
1673 user_t *up;
1674 kthread_t *t;
1675 klwp_t *lwp;
1676 prnode_t *pnp = VTOP(vp);
1677 prcommon_t *pcp;
1678 prnode_t *xpnp = NULL;
1679 int error;
1680 int zdisp;
1681 void *thing = NULL;
1682 size_t thingsize = 0;
1685 * For copyin()/copyout().
1687 union {
1688 caddr32_t va;
1689 int signo;
1690 int nice;
1691 uint_t lwpid;
1692 int32_t flags;
1693 prstatus32_t prstat;
1694 prrun32_t prrun;
1695 sigset_t smask;
1696 siginfo32_t info;
1697 sysset_t prmask;
1698 prgregset32_t regs;
1699 prfpregset32_t fpregs;
1700 prpsinfo32_t prps;
1701 sigset_t holdmask;
1702 fltset_t fltmask;
1703 prcred_t prcred;
1704 prusage32_t prusage;
1705 prhusage_t prhusage;
1706 ioc_prmap32_t prmap;
1707 auxv32_t auxv[__KERN_NAUXV_IMPL];
1708 } un32;
1711 * Native objects for internal use.
1713 union {
1714 caddr_t va;
1715 int signo;
1716 int nice;
1717 uint_t lwpid;
1718 long flags;
1719 prstatus_t prstat;
1720 prrun_t prrun;
1721 sigset_t smask;
1722 siginfo_t info;
1723 sysset_t prmask;
1724 prgregset_t regs;
1725 prpsinfo_t prps;
1726 sigset_t holdmask;
1727 fltset_t fltmask;
1728 prcred_t prcred;
1729 prusage_t prusage;
1730 prhusage_t prhusage;
1731 auxv_t auxv[__KERN_NAUXV_IMPL];
1732 } un;
1734 if (pnp->pr_type == PR_TMPL)
1735 return (prctioctl(pnp, cmd, arg, flag, cr));
1738 * Support for old /proc interface.
1740 if (pnp->pr_pidfile != NULL) {
1741 ASSERT(pnp->pr_type == PR_PIDDIR);
1742 vp = pnp->pr_pidfile;
1743 pnp = VTOP(vp);
1744 ASSERT(pnp->pr_type == PR_PIDFILE);
1747 if (pnp->pr_type != PR_PIDFILE && pnp->pr_type != PR_LWPIDFILE)
1748 return (ENOTTY);
1751 * Fail ioctls which are logically "write" requests unless
1752 * the user has write permission.
1754 if ((flag & FWRITE) == 0 && isprwrioctl(cmd))
1755 return (EBADF);
1758 * Perform any necessary copyin() operations before
1759 * locking the process. Helps avoid deadlocks and
1760 * improves performance.
1762 * Also, detect invalid ioctl codes here to avoid
1763 * locking a process unnnecessarily.
1765 * Also, prepare to allocate space that will be needed below,
1766 * case by case.
1768 error = 0;
1769 switch (cmd) {
1770 case PIOCGETPR:
1771 thingsize = sizeof (proc_t);
1772 break;
1773 case PIOCGETU:
1774 thingsize = sizeof (user_t);
1775 break;
1776 case PIOCSTOP:
1777 case PIOCWSTOP:
1778 case PIOCLWPIDS:
1779 case PIOCGTRACE:
1780 case PIOCGENTRY:
1781 case PIOCGEXIT:
1782 case PIOCSRLC:
1783 case PIOCRRLC:
1784 case PIOCSFORK:
1785 case PIOCRFORK:
1786 case PIOCGREG:
1787 case PIOCGFPREG:
1788 case PIOCSTATUS:
1789 case PIOCLSTATUS:
1790 case PIOCPSINFO:
1791 case PIOCMAXSIG:
1792 case PIOCGXREGSIZE:
1793 break;
1794 case PIOCSXREG: /* set extra registers */
1795 case PIOCGXREG: /* get extra registers */
1796 #if defined(__sparc)
1797 thingsize = sizeof (prxregset_t);
1798 #else
1799 thingsize = 0;
1800 #endif
1801 break;
1802 case PIOCACTION:
1803 thingsize = (nsig-1) * sizeof (struct sigaction32);
1804 break;
1805 case PIOCGHOLD:
1806 case PIOCNMAP:
1807 case PIOCMAP:
1808 case PIOCGFAULT:
1809 case PIOCCFAULT:
1810 case PIOCCRED:
1811 case PIOCGROUPS:
1812 case PIOCUSAGE:
1813 case PIOCLUSAGE:
1814 break;
1815 case PIOCOPENPD:
1817 * We will need this below.
1818 * Allocate it now, before locking the process.
1820 xpnp = prgetnode(vp, PR_OPAGEDATA);
1821 break;
1822 case PIOCNAUXV:
1823 case PIOCAUXV:
1824 break;
1826 #if defined(__i386) || defined(__i386_COMPAT)
1827 case PIOCNLDT:
1828 case PIOCLDT:
1829 break;
1830 #endif /* __i386 || __i386_COMPAT */
1832 #if defined(__sparc)
1833 case PIOCGWIN:
1834 thingsize = sizeof (gwindows32_t);
1835 break;
1836 #endif /* __sparc */
1838 case PIOCOPENM: /* open mapped object for reading */
1839 if (cmaddr == NULL)
1840 un32.va = (uintptr_t)NULL;
1841 else if (copyin(cmaddr, &un32.va, sizeof (un32.va)))
1842 error = EFAULT;
1843 break;
1845 case PIOCRUN: /* make lwp or process runnable */
1846 if (cmaddr == NULL)
1847 un32.prrun.pr_flags = 0;
1848 else if (copyin(cmaddr, &un32.prrun, sizeof (un32.prrun)))
1849 error = EFAULT;
1850 break;
1852 case PIOCOPENLWP: /* return /proc lwp file descriptor */
1853 if (copyin(cmaddr, &un32.lwpid, sizeof (un32.lwpid)))
1854 error = EFAULT;
1855 break;
1857 case PIOCSTRACE: /* set signal trace mask */
1858 if (copyin(cmaddr, &un32.smask, sizeof (un32.smask)))
1859 error = EFAULT;
1860 break;
1862 case PIOCSSIG: /* set current signal */
1863 if (cmaddr == NULL)
1864 un32.info.si_signo = 0;
1865 else if (copyin(cmaddr, &un32.info, sizeof (un32.info)))
1866 error = EFAULT;
1867 break;
1869 case PIOCKILL: /* send signal */
1870 case PIOCUNKILL: /* delete a signal */
1871 if (copyin(cmaddr, &un32.signo, sizeof (un32.signo)))
1872 error = EFAULT;
1873 break;
1875 case PIOCNICE: /* set nice priority */
1876 if (copyin(cmaddr, &un32.nice, sizeof (un32.nice)))
1877 error = EFAULT;
1878 break;
1880 case PIOCSENTRY: /* set syscall entry bit mask */
1881 case PIOCSEXIT: /* set syscall exit bit mask */
1882 if (copyin(cmaddr, &un32.prmask, sizeof (un32.prmask)))
1883 error = EFAULT;
1884 break;
1886 case PIOCSET: /* set process flags */
1887 case PIOCRESET: /* reset process flags */
1888 if (copyin(cmaddr, &un32.flags, sizeof (un32.flags)))
1889 error = EFAULT;
1890 break;
1892 case PIOCSREG: /* set general registers */
1893 if (copyin(cmaddr, un32.regs, sizeof (un32.regs)))
1894 error = EFAULT;
1895 break;
1897 case PIOCSFPREG: /* set floating-point registers */
1898 if (copyin(cmaddr, &un32.fpregs, sizeof (un32.fpregs)))
1899 error = EFAULT;
1900 break;
1902 case PIOCSHOLD: /* set signal-hold mask */
1903 if (copyin(cmaddr, &un32.holdmask, sizeof (un32.holdmask)))
1904 error = EFAULT;
1905 break;
1907 case PIOCSFAULT: /* set mask of traced faults */
1908 if (copyin(cmaddr, &un32.fltmask, sizeof (un32.fltmask)))
1909 error = EFAULT;
1910 break;
1912 default:
1913 error = EINVAL;
1914 break;
1917 if (error)
1918 return (error);
1920 startover:
1922 * If we need kmem_alloc()d space then we allocate it now, before
1923 * grabbing the process lock. Using kmem_alloc(KM_SLEEP) while
1924 * holding the process lock leads to deadlock with the clock thread.
1925 * (The clock thread wakes up the pageout daemon to free up space.
1926 * If the clock thread blocks behind us and we are sleeping waiting
1927 * for space, then space may never become available.)
1929 if (thingsize) {
1930 ASSERT(thing == NULL);
1931 thing = kmem_alloc(thingsize, KM_SLEEP);
1934 switch (cmd) {
1935 case PIOCPSINFO:
1936 case PIOCGETPR:
1937 case PIOCUSAGE:
1938 case PIOCLUSAGE:
1939 zdisp = ZYES;
1940 break;
1941 case PIOCSXREG: /* set extra registers */
1943 * perform copyin before grabbing the process lock
1945 if (thing) {
1946 if (copyin(cmaddr, thing, thingsize)) {
1947 kmem_free(thing, thingsize);
1948 return (EFAULT);
1951 /* fall through... */
1952 default:
1953 zdisp = ZNO;
1954 break;
1957 if ((error = prlock(pnp, zdisp)) != 0) {
1958 if (thing != NULL)
1959 kmem_free(thing, thingsize);
1960 if (xpnp)
1961 prfreenode(xpnp);
1962 return (error);
1965 pcp = pnp->pr_common;
1966 p = pcp->prc_proc;
1967 ASSERT(p != NULL);
1970 * Choose a thread/lwp for the operation.
1972 if (zdisp == ZNO && cmd != PIOCSTOP && cmd != PIOCWSTOP) {
1973 if (pnp->pr_type == PR_LWPIDFILE && cmd != PIOCLSTATUS) {
1974 t = pcp->prc_thread;
1975 ASSERT(t != NULL);
1976 } else {
1977 t = prchoose(p); /* returns locked thread */
1978 ASSERT(t != NULL);
1979 thread_unlock(t);
1981 lwp = ttolwp(t);
1984 error = 0;
1985 switch (cmd) {
1987 case PIOCGETPR: /* read struct proc */
1989 proc_t *prp = thing;
1991 *prp = *p;
1992 prunlock(pnp);
1993 if (copyout(prp, cmaddr, sizeof (proc_t)))
1994 error = EFAULT;
1995 kmem_free(prp, sizeof (proc_t));
1996 thing = NULL;
1997 break;
2000 case PIOCGETU: /* read u-area */
2002 user_t *userp = thing;
2004 up = PTOU(p);
2005 *userp = *up;
2006 prunlock(pnp);
2007 if (copyout(userp, cmaddr, sizeof (user_t)))
2008 error = EFAULT;
2009 kmem_free(userp, sizeof (user_t));
2010 thing = NULL;
2011 break;
2014 case PIOCOPENM: /* open mapped object for reading */
2015 if (PROCESS_NOT_32BIT(p) && cmaddr != NULL) {
2016 prunlock(pnp);
2017 error = EOVERFLOW;
2018 break;
2020 error = propenm(pnp, cmaddr,
2021 (caddr_t)(uintptr_t)un32.va, rvalp, cr);
2022 /* propenm() called prunlock(pnp) */
2023 break;
2025 case PIOCSTOP: /* stop process or lwp from running */
2026 case PIOCWSTOP: /* wait for process or lwp to stop */
2028 * Can't apply to a system process.
2030 if ((p->p_flag & SSYS) || p->p_as == &kas) {
2031 prunlock(pnp);
2032 error = EBUSY;
2033 break;
2036 if (cmd == PIOCSTOP)
2037 pr_stop(pnp);
2040 * If an lwp is waiting for itself or its process, don't wait.
2041 * The lwp will never see the fact that itself is stopped.
2043 if ((pnp->pr_type == PR_LWPIDFILE)?
2044 (pcp->prc_thread == curthread) : (p == curproc)) {
2045 if (cmd == PIOCWSTOP)
2046 error = EBUSY;
2047 prunlock(pnp);
2048 break;
2051 if ((error = pr_wait_stop(pnp, (time_t)0)) != 0)
2052 break; /* pr_wait_stop() unlocked the process */
2054 if (cmaddr == NULL)
2055 prunlock(pnp);
2056 else if (PROCESS_NOT_32BIT(p)) {
2057 prunlock(pnp);
2058 error = EOVERFLOW;
2059 } else {
2061 * Return process/lwp status information.
2063 t = pr_thread(pnp); /* returns locked thread */
2064 thread_unlock(t);
2065 oprgetstatus32(t, &un32.prstat, VTOZONE(vp));
2066 prunlock(pnp);
2067 if (copyout(&un32.prstat, cmaddr, sizeof (un32.prstat)))
2068 error = EFAULT;
2070 break;
2072 case PIOCRUN: /* make lwp or process runnable */
2074 long flags = un32.prrun.pr_flags;
2077 * Cannot set an lwp running is it is not stopped.
2078 * Also, no lwp other than the /proc agent lwp can
2079 * be set running so long as the /proc agent lwp exists.
2081 if ((!ISTOPPED(t) && !VSTOPPED(t) &&
2082 !(t->t_proc_flag & TP_PRSTOP)) ||
2083 (p->p_agenttp != NULL &&
2084 (t != p->p_agenttp || pnp->pr_type != PR_LWPIDFILE))) {
2085 prunlock(pnp);
2086 error = EBUSY;
2087 break;
2090 if ((flags & PRSVADDR) && PROCESS_NOT_32BIT(p)) {
2091 prunlock(pnp);
2092 error = EOVERFLOW;
2093 break;
2096 if (flags & (PRSHOLD|PRSTRACE|PRSFAULT|PRSVADDR)) {
2097 un.prrun.pr_flags = (int)flags;
2098 un.prrun.pr_trace = un32.prrun.pr_trace;
2099 un.prrun.pr_sighold = un32.prrun.pr_sighold;
2100 un.prrun.pr_fault = un32.prrun.pr_fault;
2101 un.prrun.pr_vaddr =
2102 (caddr_t)(uintptr_t)un32.prrun.pr_vaddr;
2103 prsetrun(t, &un.prrun);
2106 error = pr_setrun(pnp, prmaprunflags(flags));
2108 prunlock(pnp);
2109 break;
2112 case PIOCLWPIDS: /* get array of lwp identifiers */
2114 int nlwp;
2115 int Nlwp;
2116 id_t *idp;
2117 id_t *Bidp;
2119 Nlwp = nlwp = p->p_lwpcnt;
2121 if (thing && thingsize != (Nlwp+1) * sizeof (id_t)) {
2122 kmem_free(thing, thingsize);
2123 thing = NULL;
2125 if (thing == NULL) {
2126 thingsize = (Nlwp+1) * sizeof (id_t);
2127 thing = kmem_alloc(thingsize, KM_NOSLEEP);
2129 if (thing == NULL) {
2130 prunlock(pnp);
2131 goto startover;
2134 idp = thing;
2135 thing = NULL;
2136 Bidp = idp;
2137 if ((t = p->p_tlist) != NULL) {
2138 do {
2139 ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
2140 ASSERT(nlwp > 0);
2141 --nlwp;
2142 *idp++ = t->t_tid;
2143 } while ((t = t->t_forw) != p->p_tlist);
2145 *idp = 0;
2146 ASSERT(nlwp == 0);
2147 prunlock(pnp);
2148 if (copyout(Bidp, cmaddr, (Nlwp+1) * sizeof (id_t)))
2149 error = EFAULT;
2150 kmem_free(Bidp, (Nlwp+1) * sizeof (id_t));
2151 break;
2154 case PIOCOPENLWP: /* return /proc lwp file descriptor */
2156 vnode_t *xvp;
2157 int n;
2159 prunlock(pnp);
2160 if ((xvp = prlwpnode(pnp, un32.lwpid)) == NULL)
2161 error = ENOENT;
2162 else if (error = fassign(&xvp, flag & (FREAD|FWRITE), &n)) {
2163 VN_RELE(xvp);
2164 } else
2165 *rvalp = n;
2166 break;
2169 case PIOCOPENPD: /* return /proc page data file descriptor */
2171 vnode_t *xvp = PTOV(xpnp);
2172 vnode_t *dp = pnp->pr_parent;
2173 int n;
2175 if (PROCESS_NOT_32BIT(p)) {
2176 prunlock(pnp);
2177 prfreenode(xpnp);
2178 xpnp = NULL;
2179 error = EOVERFLOW;
2180 break;
2183 if (pnp->pr_type == PR_LWPIDFILE) {
2184 dp = VTOP(dp)->pr_parent;
2185 dp = VTOP(dp)->pr_parent;
2187 ASSERT(VTOP(dp)->pr_type == PR_PIDDIR);
2189 VN_HOLD(dp);
2190 pcp = pnp->pr_pcommon;
2191 xpnp->pr_ino = ptoi(pcp->prc_pid);
2192 xpnp->pr_common = pcp;
2193 xpnp->pr_pcommon = pcp;
2194 xpnp->pr_parent = dp;
2196 xpnp->pr_next = p->p_plist;
2197 p->p_plist = xvp;
2199 prunlock(pnp);
2200 if (error = fassign(&xvp, FREAD, &n)) {
2201 VN_RELE(xvp);
2202 } else
2203 *rvalp = n;
2205 xpnp = NULL;
2206 break;
2209 case PIOCGTRACE: /* get signal trace mask */
2210 prassignset(&un32.smask, &p->p_sigmask);
2211 prunlock(pnp);
2212 if (copyout(&un32.smask, cmaddr, sizeof (un32.smask)))
2213 error = EFAULT;
2214 break;
2216 case PIOCSTRACE: /* set signal trace mask */
2217 prdelset(&un32.smask, SIGKILL);
2218 prassignset(&p->p_sigmask, &un32.smask);
2219 if (!sigisempty(&p->p_sigmask))
2220 p->p_proc_flag |= P_PR_TRACE;
2221 else if (prisempty(&p->p_fltmask)) {
2222 up = PTOU(p);
2223 if (up->u_systrap == 0)
2224 p->p_proc_flag &= ~P_PR_TRACE;
2226 prunlock(pnp);
2227 break;
2229 case PIOCSSIG: /* set current signal */
2230 if (un32.info.si_signo != 0 && PROCESS_NOT_32BIT(p)) {
2231 prunlock(pnp);
2232 error = EOVERFLOW;
2233 } else {
2234 bzero(&un.info, sizeof (un.info));
2235 siginfo_32tok(&un32.info, (k_siginfo_t *)&un.info);
2236 error = pr_setsig(pnp, &un.info);
2237 prunlock(pnp);
2238 if (un32.info.si_signo == SIGKILL && error == 0)
2239 pr_wait_die(pnp);
2241 break;
2243 case PIOCKILL: /* send signal */
2244 error = pr_kill(pnp, un32.signo, cr);
2245 prunlock(pnp);
2246 if (un32.signo == SIGKILL && error == 0)
2247 pr_wait_die(pnp);
2248 break;
2250 case PIOCUNKILL: /* delete a signal */
2251 error = pr_unkill(pnp, un32.signo);
2252 prunlock(pnp);
2253 break;
2255 case PIOCNICE: /* set nice priority */
2256 error = pr_nice(p, un32.nice, cr);
2257 prunlock(pnp);
2258 break;
2260 case PIOCGENTRY: /* get syscall entry bit mask */
2261 case PIOCGEXIT: /* get syscall exit bit mask */
2262 up = PTOU(p);
2263 if (cmd == PIOCGENTRY) {
2264 prassignset(&un32.prmask, &up->u_entrymask);
2265 } else {
2266 prassignset(&un32.prmask, &up->u_exitmask);
2268 prunlock(pnp);
2269 if (copyout(&un32.prmask, cmaddr, sizeof (un32.prmask)))
2270 error = EFAULT;
2271 break;
2273 case PIOCSENTRY: /* set syscall entry bit mask */
2274 case PIOCSEXIT: /* set syscall exit bit mask */
2275 pr_setentryexit(p, &un32.prmask, cmd == PIOCSENTRY);
2276 prunlock(pnp);
2277 break;
2279 case PIOCSRLC: /* obsolete: set running on last /proc close */
2280 error = pr_set(p, prmapsetflags(PR_RLC));
2281 prunlock(pnp);
2282 break;
2284 case PIOCRRLC: /* obsolete: reset run-on-last-close flag */
2285 error = pr_unset(p, prmapsetflags(PR_RLC));
2286 prunlock(pnp);
2287 break;
2289 case PIOCSFORK: /* obsolete: set inherit-on-fork flag */
2290 error = pr_set(p, prmapsetflags(PR_FORK));
2291 prunlock(pnp);
2292 break;
2294 case PIOCRFORK: /* obsolete: reset inherit-on-fork flag */
2295 error = pr_unset(p, prmapsetflags(PR_FORK));
2296 prunlock(pnp);
2297 break;
2299 case PIOCSET: /* set process flags */
2300 error = pr_set(p, prmapsetflags((long)un32.flags));
2301 prunlock(pnp);
2302 break;
2304 case PIOCRESET: /* reset process flags */
2305 error = pr_unset(p, prmapsetflags((long)un32.flags));
2306 prunlock(pnp);
2307 break;
2309 case PIOCGREG: /* get general registers */
2310 if (PROCESS_NOT_32BIT(p))
2311 error = EOVERFLOW;
2312 else if (t->t_state != TS_STOPPED && !VSTOPPED(t))
2313 bzero(un32.regs, sizeof (un32.regs));
2314 else {
2315 /* drop p_lock while touching the lwp's stack */
2316 mutex_exit(&p->p_lock);
2317 prgetprregs32(lwp, un32.regs);
2318 mutex_enter(&p->p_lock);
2320 prunlock(pnp);
2321 if (error == 0 &&
2322 copyout(un32.regs, cmaddr, sizeof (un32.regs)))
2323 error = EFAULT;
2324 break;
2326 case PIOCSREG: /* set general registers */
2327 if (PROCESS_NOT_32BIT(p))
2328 error = EOVERFLOW;
2329 else if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t))
2330 error = EBUSY;
2331 else {
2332 /* drop p_lock while touching the lwp's stack */
2333 mutex_exit(&p->p_lock);
2334 prgregset_32ton(lwp, un32.regs, un.regs);
2335 prsetprregs(lwp, un.regs, 0);
2336 mutex_enter(&p->p_lock);
2338 prunlock(pnp);
2339 break;
2341 case PIOCGFPREG: /* get floating-point registers */
2342 if (!prhasfp())
2343 error = EINVAL; /* No FP support */
2344 else if (PROCESS_NOT_32BIT(p))
2345 error = EOVERFLOW;
2346 else if (t->t_state != TS_STOPPED && !VSTOPPED(t))
2347 bzero(&un32.fpregs, sizeof (un32.fpregs));
2348 else {
2349 /* drop p_lock while touching the lwp's stack */
2350 mutex_exit(&p->p_lock);
2351 prgetprfpregs32(lwp, &un32.fpregs);
2352 mutex_enter(&p->p_lock);
2354 prunlock(pnp);
2355 if (error == 0 &&
2356 copyout(&un32.fpregs, cmaddr, sizeof (un32.fpregs)))
2357 error = EFAULT;
2358 break;
2360 case PIOCSFPREG: /* set floating-point registers */
2361 if (!prhasfp())
2362 error = EINVAL; /* No FP support */
2363 else if (PROCESS_NOT_32BIT(p))
2364 error = EOVERFLOW;
2365 else if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t))
2366 error = EBUSY;
2367 else {
2368 /* drop p_lock while touching the lwp's stack */
2369 mutex_exit(&p->p_lock);
2370 prsetprfpregs32(lwp, &un32.fpregs);
2371 mutex_enter(&p->p_lock);
2373 prunlock(pnp);
2374 break;
2376 case PIOCGXREGSIZE: /* get the size of the extra registers */
2378 int xregsize;
2380 if (prhasx(p)) {
2381 xregsize = prgetprxregsize(p);
2382 prunlock(pnp);
2383 if (copyout(&xregsize, cmaddr, sizeof (xregsize)))
2384 error = EFAULT;
2385 } else {
2386 prunlock(pnp);
2387 error = EINVAL; /* No extra register support */
2389 break;
2392 case PIOCGXREG: /* get extra registers */
2393 if (PROCESS_NOT_32BIT(p))
2394 error = EOVERFLOW;
2395 else if (!prhasx(p))
2396 error = EINVAL; /* No extra register support */
2397 else {
2398 bzero(thing, thingsize);
2399 if (t->t_state == TS_STOPPED || VSTOPPED(t)) {
2400 /* drop p_lock to touch the stack */
2401 mutex_exit(&p->p_lock);
2402 prgetprxregs(lwp, thing);
2403 mutex_enter(&p->p_lock);
2406 prunlock(pnp);
2407 if (error == 0 &&
2408 copyout(thing, cmaddr, thingsize))
2409 error = EFAULT;
2410 if (thing) {
2411 kmem_free(thing, thingsize);
2412 thing = NULL;
2414 break;
2416 case PIOCSXREG: /* set extra registers */
2417 if (PROCESS_NOT_32BIT(p))
2418 error = EOVERFLOW;
2419 else if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t))
2420 error = EBUSY;
2421 else if (!prhasx(p))
2422 error = EINVAL; /* No extra register support */
2423 else if (thing) {
2424 /* drop p_lock while touching the lwp's stack */
2425 mutex_exit(&p->p_lock);
2426 prsetprxregs(lwp, thing);
2427 mutex_enter(&p->p_lock);
2429 prunlock(pnp);
2430 if (thing) {
2431 kmem_free(thing, thingsize);
2432 thing = NULL;
2434 break;
2436 case PIOCSTATUS: /* get process/lwp status */
2437 if (PROCESS_NOT_32BIT(p)) {
2438 prunlock(pnp);
2439 error = EOVERFLOW;
2440 break;
2442 oprgetstatus32(t, &un32.prstat, VTOZONE(vp));
2443 prunlock(pnp);
2444 if (copyout(&un32.prstat, cmaddr, sizeof (un32.prstat)))
2445 error = EFAULT;
2446 break;
2448 case PIOCLSTATUS: /* get status for process & all lwps */
2450 int Nlwp;
2451 int nlwp;
2452 prstatus32_t *Bprsp;
2453 prstatus32_t *prsp;
2455 if (PROCESS_NOT_32BIT(p)) {
2456 prunlock(pnp);
2457 if (thing) {
2458 kmem_free(thing, thingsize);
2459 thing = NULL;
2461 error = EOVERFLOW;
2462 break;
2465 nlwp = Nlwp = p->p_lwpcnt;
2467 if (thing && thingsize != (Nlwp+1) * sizeof (prstatus32_t)) {
2468 kmem_free(thing, thingsize);
2469 thing = NULL;
2471 if (thing == NULL) {
2472 thingsize = (Nlwp+1) * sizeof (prstatus32_t);
2473 thing = kmem_alloc(thingsize, KM_NOSLEEP);
2475 if (thing == NULL) {
2476 prunlock(pnp);
2477 goto startover;
2480 Bprsp = (prstatus32_t *)thing;
2481 thing = NULL;
2482 prsp = Bprsp;
2483 oprgetstatus32(t, prsp, VTOZONE(vp));
2484 t = p->p_tlist;
2485 do {
2486 ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
2487 ASSERT(nlwp > 0);
2488 --nlwp;
2489 oprgetstatus32(t, ++prsp, VTOZONE(vp));
2490 } while ((t = t->t_forw) != p->p_tlist);
2491 ASSERT(nlwp == 0);
2492 prunlock(pnp);
2493 if (copyout(Bprsp, cmaddr, (Nlwp+1) * sizeof (prstatus32_t)))
2494 error = EFAULT;
2496 kmem_free(Bprsp, (Nlwp + 1) * sizeof (prstatus32_t));
2497 break;
2500 case PIOCPSINFO: /* get ps(1) information */
2502 prpsinfo32_t *psp = &un32.prps;
2504 oprgetpsinfo32(p, psp,
2505 (pnp->pr_type == PR_LWPIDFILE)? pcp->prc_thread : NULL);
2507 prunlock(pnp);
2508 if (copyout(&un32.prps, cmaddr, sizeof (un32.prps)))
2509 error = EFAULT;
2510 break;
2513 case PIOCMAXSIG: /* get maximum signal number */
2515 int n = nsig-1;
2517 prunlock(pnp);
2518 if (copyout(&n, cmaddr, sizeof (int)))
2519 error = EFAULT;
2520 break;
2523 case PIOCACTION: /* get signal action structures */
2525 uint_t sig;
2526 struct sigaction32 *sap = thing;
2528 if (PROCESS_NOT_32BIT(p))
2529 error = EOVERFLOW;
2530 else {
2531 up = PTOU(p);
2532 for (sig = 1; sig < nsig; sig++)
2533 prgetaction32(p, up, sig, &sap[sig-1]);
2535 prunlock(pnp);
2536 if (error == 0 &&
2537 copyout(sap, cmaddr, (nsig-1)*sizeof (struct sigaction32)))
2538 error = EFAULT;
2539 kmem_free(sap, (nsig-1)*sizeof (struct sigaction32));
2540 thing = NULL;
2541 break;
2544 case PIOCGHOLD: /* get signal-hold mask */
2545 schedctl_finish_sigblock(t);
2546 sigktou(&t->t_hold, &un32.holdmask);
2547 prunlock(pnp);
2548 if (copyout(&un32.holdmask, cmaddr, sizeof (un32.holdmask)))
2549 error = EFAULT;
2550 break;
2552 case PIOCSHOLD: /* set signal-hold mask */
2553 pr_sethold(pnp, &un32.holdmask);
2554 prunlock(pnp);
2555 break;
2557 case PIOCNMAP: /* get number of memory mappings */
2559 int n;
2560 struct as *as = p->p_as;
2562 if ((p->p_flag & SSYS) || as == &kas)
2563 n = 0;
2564 else {
2565 mutex_exit(&p->p_lock);
2566 AS_LOCK_ENTER(as, RW_WRITER);
2567 n = prnsegs(as, 0);
2568 AS_LOCK_EXIT(as);
2569 mutex_enter(&p->p_lock);
2571 prunlock(pnp);
2572 if (copyout(&n, cmaddr, sizeof (int)))
2573 error = EFAULT;
2574 break;
2577 case PIOCMAP: /* get memory map information */
2579 list_t iolhead;
2580 struct as *as = p->p_as;
2582 if ((p->p_flag & SSYS) || as == &kas) {
2583 error = 0;
2584 prunlock(pnp);
2585 } else if (PROCESS_NOT_32BIT(p)) {
2586 error = EOVERFLOW;
2587 prunlock(pnp);
2588 } else {
2589 mutex_exit(&p->p_lock);
2590 AS_LOCK_ENTER(as, RW_WRITER);
2591 error = oprgetmap32(p, &iolhead);
2592 AS_LOCK_EXIT(as);
2593 mutex_enter(&p->p_lock);
2594 prunlock(pnp);
2596 error = pr_iol_copyout_and_free(&iolhead,
2597 &cmaddr, error);
2600 * The procfs PIOCMAP ioctl returns an all-zero buffer
2601 * to indicate the end of the prmap[] array.
2602 * Append it to whatever has already been copied out.
2604 bzero(&un32.prmap, sizeof (un32.prmap));
2605 if (!error &&
2606 copyout(&un32.prmap, cmaddr, sizeof (un32.prmap)))
2607 error = EFAULT;
2608 break;
2611 case PIOCGFAULT: /* get mask of traced faults */
2612 prassignset(&un32.fltmask, &p->p_fltmask);
2613 prunlock(pnp);
2614 if (copyout(&un32.fltmask, cmaddr, sizeof (un32.fltmask)))
2615 error = EFAULT;
2616 break;
2618 case PIOCSFAULT: /* set mask of traced faults */
2619 pr_setfault(p, &un32.fltmask);
2620 prunlock(pnp);
2621 break;
2623 case PIOCCFAULT: /* clear current fault */
2624 lwp->lwp_curflt = 0;
2625 prunlock(pnp);
2626 break;
2628 case PIOCCRED: /* get process credentials */
2630 cred_t *cp;
2632 mutex_enter(&p->p_crlock);
2633 cp = p->p_cred;
2634 un32.prcred.pr_euid = crgetuid(cp);
2635 un32.prcred.pr_ruid = crgetruid(cp);
2636 un32.prcred.pr_suid = crgetsuid(cp);
2637 un32.prcred.pr_egid = crgetgid(cp);
2638 un32.prcred.pr_rgid = crgetrgid(cp);
2639 un32.prcred.pr_sgid = crgetsgid(cp);
2640 un32.prcred.pr_ngroups = crgetngroups(cp);
2641 mutex_exit(&p->p_crlock);
2643 prunlock(pnp);
2644 if (copyout(&un32.prcred, cmaddr, sizeof (un32.prcred)))
2645 error = EFAULT;
2646 break;
2649 case PIOCGROUPS: /* get supplementary groups */
2651 cred_t *cp;
2653 mutex_enter(&p->p_crlock);
2654 cp = p->p_cred;
2655 crhold(cp);
2656 mutex_exit(&p->p_crlock);
2658 prunlock(pnp);
2659 if (copyout(crgetgroups(cp), cmaddr,
2660 MAX(crgetngroups(cp), 1) * sizeof (gid_t)))
2661 error = EFAULT;
2662 crfree(cp);
2663 break;
2666 case PIOCUSAGE: /* get usage info */
2669 * For an lwp file descriptor, return just the lwp usage.
2670 * For a process file descriptor, return total usage,
2671 * all current lwps plus all defunct lwps.
2673 prhusage_t *pup = &un32.prhusage;
2674 prusage32_t *upup;
2676 bzero(pup, sizeof (*pup));
2677 pup->pr_tstamp = gethrtime();
2679 if (pnp->pr_type == PR_LWPIDFILE) {
2680 t = pcp->prc_thread;
2681 if (t != NULL)
2682 prgetusage(t, pup);
2683 else
2684 error = ENOENT;
2685 } else {
2686 pup->pr_count = p->p_defunct;
2687 pup->pr_create = p->p_mstart;
2688 pup->pr_term = p->p_mterm;
2690 pup->pr_rtime = p->p_mlreal;
2691 pup->pr_utime = p->p_acct[LMS_USER];
2692 pup->pr_stime = p->p_acct[LMS_SYSTEM];
2693 pup->pr_ttime = p->p_acct[LMS_TRAP];
2694 pup->pr_tftime = p->p_acct[LMS_TFAULT];
2695 pup->pr_dftime = p->p_acct[LMS_DFAULT];
2696 pup->pr_kftime = p->p_acct[LMS_KFAULT];
2697 pup->pr_ltime = p->p_acct[LMS_USER_LOCK];
2698 pup->pr_slptime = p->p_acct[LMS_SLEEP];
2699 pup->pr_wtime = p->p_acct[LMS_WAIT_CPU];
2700 pup->pr_stoptime = p->p_acct[LMS_STOPPED];
2702 pup->pr_minf = p->p_ru.minflt;
2703 pup->pr_majf = p->p_ru.majflt;
2704 pup->pr_nswap = p->p_ru.nswap;
2705 pup->pr_inblk = p->p_ru.inblock;
2706 pup->pr_oublk = p->p_ru.oublock;
2707 pup->pr_msnd = p->p_ru.msgsnd;
2708 pup->pr_mrcv = p->p_ru.msgrcv;
2709 pup->pr_sigs = p->p_ru.nsignals;
2710 pup->pr_vctx = p->p_ru.nvcsw;
2711 pup->pr_ictx = p->p_ru.nivcsw;
2712 pup->pr_sysc = p->p_ru.sysc;
2713 pup->pr_ioch = p->p_ru.ioch;
2716 * Add the usage information for each active lwp.
2718 if ((t = p->p_tlist) != NULL &&
2719 !(pcp->prc_flags & PRC_DESTROY)) {
2720 do {
2721 ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
2722 pup->pr_count++;
2723 praddusage(t, pup);
2724 } while ((t = t->t_forw) != p->p_tlist);
2728 prunlock(pnp);
2730 upup = kmem_alloc(sizeof (*upup), KM_SLEEP);
2731 prcvtusage32(pup, upup);
2732 if (copyout(upup, cmaddr, sizeof (*upup)))
2733 error = EFAULT;
2734 kmem_free(upup, sizeof (*upup));
2736 break;
2739 case PIOCLUSAGE: /* get detailed usage info */
2741 int Nlwp;
2742 int nlwp;
2743 prusage32_t *upup;
2744 prusage32_t *Bupup;
2745 prhusage_t *pup;
2746 hrtime_t curtime;
2748 nlwp = Nlwp = (pcp->prc_flags & PRC_DESTROY)? 0 : p->p_lwpcnt;
2750 if (thing && thingsize !=
2751 sizeof (prhusage_t) + (Nlwp+1) * sizeof (prusage32_t)) {
2752 kmem_free(thing, thingsize);
2753 thing = NULL;
2755 if (thing == NULL) {
2756 thingsize = sizeof (prhusage_t) +
2757 (Nlwp+1) * sizeof (prusage32_t);
2758 thing = kmem_alloc(thingsize, KM_NOSLEEP);
2760 if (thing == NULL) {
2761 prunlock(pnp);
2762 goto startover;
2765 pup = (prhusage_t *)thing;
2766 upup = Bupup = (prusage32_t *)(pup + 1);
2768 ASSERT(p == pcp->prc_proc);
2770 curtime = gethrtime();
2773 * First the summation over defunct lwps.
2775 bzero(pup, sizeof (*pup));
2776 pup->pr_count = p->p_defunct;
2777 pup->pr_tstamp = curtime;
2778 pup->pr_create = p->p_mstart;
2779 pup->pr_term = p->p_mterm;
2781 pup->pr_rtime = p->p_mlreal;
2782 pup->pr_utime = p->p_acct[LMS_USER];
2783 pup->pr_stime = p->p_acct[LMS_SYSTEM];
2784 pup->pr_ttime = p->p_acct[LMS_TRAP];
2785 pup->pr_tftime = p->p_acct[LMS_TFAULT];
2786 pup->pr_dftime = p->p_acct[LMS_DFAULT];
2787 pup->pr_kftime = p->p_acct[LMS_KFAULT];
2788 pup->pr_ltime = p->p_acct[LMS_USER_LOCK];
2789 pup->pr_slptime = p->p_acct[LMS_SLEEP];
2790 pup->pr_wtime = p->p_acct[LMS_WAIT_CPU];
2791 pup->pr_stoptime = p->p_acct[LMS_STOPPED];
2793 pup->pr_minf = p->p_ru.minflt;
2794 pup->pr_majf = p->p_ru.majflt;
2795 pup->pr_nswap = p->p_ru.nswap;
2796 pup->pr_inblk = p->p_ru.inblock;
2797 pup->pr_oublk = p->p_ru.oublock;
2798 pup->pr_msnd = p->p_ru.msgsnd;
2799 pup->pr_mrcv = p->p_ru.msgrcv;
2800 pup->pr_sigs = p->p_ru.nsignals;
2801 pup->pr_vctx = p->p_ru.nvcsw;
2802 pup->pr_ictx = p->p_ru.nivcsw;
2803 pup->pr_sysc = p->p_ru.sysc;
2804 pup->pr_ioch = p->p_ru.ioch;
2806 prcvtusage32(pup, upup);
2809 * Fill one prusage struct for each active lwp.
2811 if ((t = p->p_tlist) != NULL &&
2812 !(pcp->prc_flags & PRC_DESTROY)) {
2813 do {
2814 ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
2815 ASSERT(nlwp > 0);
2816 --nlwp;
2817 upup++;
2818 prgetusage(t, pup);
2819 prcvtusage32(pup, upup);
2820 } while ((t = t->t_forw) != p->p_tlist);
2822 ASSERT(nlwp == 0);
2824 prunlock(pnp);
2825 if (copyout(Bupup, cmaddr, (Nlwp+1) * sizeof (prusage32_t)))
2826 error = EFAULT;
2827 kmem_free(thing, thingsize);
2828 thing = NULL;
2829 break;
2832 case PIOCNAUXV: /* get number of aux vector entries */
2834 int n = __KERN_NAUXV_IMPL;
2836 prunlock(pnp);
2837 if (copyout(&n, cmaddr, sizeof (int)))
2838 error = EFAULT;
2839 break;
2842 case PIOCAUXV: /* get aux vector (see sys/auxv.h) */
2844 int i;
2846 if (PROCESS_NOT_32BIT(p)) {
2847 prunlock(pnp);
2848 error = EOVERFLOW;
2849 } else {
2850 up = PTOU(p);
2851 for (i = 0; i < __KERN_NAUXV_IMPL; i++) {
2852 un32.auxv[i].a_type = up->u_auxv[i].a_type;
2853 un32.auxv[i].a_un.a_val =
2854 (int32_t)up->u_auxv[i].a_un.a_val;
2856 prunlock(pnp);
2857 if (copyout(un32.auxv, cmaddr,
2858 __KERN_NAUXV_IMPL * sizeof (auxv32_t)))
2859 error = EFAULT;
2861 break;
2864 #if defined(__i386) || defined(__i386_COMPAT)
2865 case PIOCNLDT: /* get number of LDT entries */
2867 int n;
2869 mutex_exit(&p->p_lock);
2870 mutex_enter(&p->p_ldtlock);
2871 n = prnldt(p);
2872 mutex_exit(&p->p_ldtlock);
2873 mutex_enter(&p->p_lock);
2874 prunlock(pnp);
2875 if (copyout(&n, cmaddr, sizeof (n)))
2876 error = EFAULT;
2877 break;
2880 case PIOCLDT: /* get LDT entries */
2882 struct ssd *ssd;
2883 int n;
2885 mutex_exit(&p->p_lock);
2886 mutex_enter(&p->p_ldtlock);
2887 n = prnldt(p);
2889 if (thing && thingsize != (n+1) * sizeof (*ssd)) {
2890 kmem_free(thing, thingsize);
2891 thing = NULL;
2893 if (thing == NULL) {
2894 thingsize = (n+1) * sizeof (*ssd);
2895 thing = kmem_alloc(thingsize, KM_NOSLEEP);
2897 if (thing == NULL) {
2898 mutex_exit(&p->p_ldtlock);
2899 mutex_enter(&p->p_lock);
2900 prunlock(pnp);
2901 goto startover;
2904 ssd = thing;
2905 thing = NULL;
2906 if (n != 0)
2907 prgetldt(p, ssd);
2908 mutex_exit(&p->p_ldtlock);
2909 mutex_enter(&p->p_lock);
2910 prunlock(pnp);
2912 /* mark the end of the list with a null entry */
2913 bzero(&ssd[n], sizeof (*ssd));
2914 if (copyout(ssd, cmaddr, (n+1) * sizeof (*ssd)))
2915 error = EFAULT;
2916 kmem_free(ssd, (n+1) * sizeof (*ssd));
2917 break;
2919 #endif /* __i386 || __i386_COMPAT */
2921 #if defined(__sparc)
2922 case PIOCGWIN: /* get gwindows_t (see sys/reg.h) */
2924 gwindows32_t *gwp = thing;
2926 if (PROCESS_NOT_32BIT(p)) {
2927 prunlock(pnp);
2928 error = EOVERFLOW;
2929 } else {
2930 /* drop p->p_lock while touching the stack */
2931 mutex_exit(&p->p_lock);
2932 bzero(gwp, sizeof (*gwp));
2933 prgetwindows32(lwp, gwp);
2934 mutex_enter(&p->p_lock);
2935 prunlock(pnp);
2936 if (copyout(gwp, cmaddr, sizeof (*gwp)))
2937 error = EFAULT;
2939 kmem_free(gwp, sizeof (*gwp));
2940 thing = NULL;
2941 break;
2943 #endif /* __sparc */
2945 default:
2946 prunlock(pnp);
2947 error = EINVAL;
2948 break;
2952 ASSERT(thing == NULL);
2953 ASSERT(xpnp == NULL);
2954 return (error);
2956 #endif /* _SYSCALL32_IMPL */
2959 * Distinguish "writeable" ioctl requests from others.
2961 static int
2962 isprwrioctl(int cmd)
2964 switch (cmd) {
2965 case PIOCSTOP:
2966 case PIOCRUN:
2967 case PIOCSTRACE:
2968 case PIOCSSIG:
2969 case PIOCKILL:
2970 case PIOCUNKILL:
2971 case PIOCNICE:
2972 case PIOCSENTRY:
2973 case PIOCSEXIT:
2974 case PIOCSRLC:
2975 case PIOCRRLC:
2976 case PIOCSREG:
2977 case PIOCSFPREG:
2978 case PIOCSXREG:
2979 case PIOCSHOLD:
2980 case PIOCSFAULT:
2981 case PIOCCFAULT:
2982 case PIOCSFORK:
2983 case PIOCRFORK:
2984 case PIOCSET:
2985 case PIOCRESET:
2986 return (1);
2988 return (0);
2992 * Map the ioctl() interface run flags to the new interface run flags.
2994 static ulong_t
2995 prmaprunflags(long flags)
2997 ulong_t newflags = 0;
2999 if (flags & PRCSIG)
3000 newflags |= 0x01;
3001 if (flags & PRCFAULT)
3002 newflags |= 0x02;
3003 if (flags & PRSTEP)
3004 newflags |= 0x04;
3005 if (flags & PRSABORT)
3006 newflags |= 0x08;
3007 if (flags & PRSTOP)
3008 newflags |= 0x10;
3009 return (newflags);
3013 * Map the ioctl() interface settable mode flags to the new interface flags.
3015 static long
3016 prmapsetflags(long flags)
3018 long newflags = 0;
3020 #define ALLFLAGS \
3021 (PR_FORK|PR_RLC|PR_KLC|PR_ASYNC|PR_BPTADJ|PR_MSACCT|PR_PCOMPAT)
3023 if (flags & ~ALLFLAGS)
3024 newflags = 0xffff; /* forces EINVAL */
3025 if (flags & PR_FORK)
3026 newflags |= (0x00100000 | 0x08000000);
3027 if (flags & PR_RLC)
3028 newflags |= 0x00200000;
3029 if (flags & PR_KLC)
3030 newflags |= 0x00400000;
3031 if (flags & PR_ASYNC)
3032 newflags |= 0x00800000;
3033 if (flags & PR_MSACCT)
3034 newflags |= 0x01000000;
3035 if (flags & PR_BPTADJ)
3036 newflags |= 0x02000000;
3037 if (flags & PR_PCOMPAT)
3038 newflags |= 0x04000000;
3039 return (newflags);
3043 * Apply PIOCRUN options specific to the ioctl() interface.
3045 static void
3046 prsetrun(kthread_t *t, prrun_t *prp)
3048 proc_t *p = ttoproc(t);
3049 klwp_t *lwp = ttolwp(t);
3050 long flags = prp->pr_flags;
3051 user_t *up = PTOU(p);
3053 ASSERT(MUTEX_HELD(&p->p_lock));
3055 if (flags & PRSHOLD) {
3056 schedctl_finish_sigblock(t);
3057 sigutok(&prp->pr_sighold, &t->t_hold);
3058 t->t_sig_check = 1; /* so ISSIG will be done */
3060 if (flags & PRSTRACE) {
3061 prdelset(&prp->pr_trace, SIGKILL);
3062 prassignset(&p->p_sigmask, &prp->pr_trace);
3063 if (!sigisempty(&p->p_sigmask))
3064 p->p_proc_flag |= P_PR_TRACE;
3065 else if (prisempty(&p->p_fltmask)) {
3066 if (up->u_systrap == 0)
3067 p->p_proc_flag &= ~P_PR_TRACE;
3070 if (flags & PRSFAULT) {
3071 prassignset(&p->p_fltmask, &prp->pr_fault);
3072 if (!prisempty(&p->p_fltmask))
3073 p->p_proc_flag |= P_PR_TRACE;
3074 else if (sigisempty(&p->p_sigmask)) {
3075 if (up->u_systrap == 0)
3076 p->p_proc_flag &= ~P_PR_TRACE;
3080 * prsvaddr() must be called before prstep() because
3081 * stepping can depend on the current value of the PC.
3082 * We drop p_lock while touching the lwp's registers (on stack).
3084 if (flags & PRSVADDR) {
3085 mutex_exit(&p->p_lock);
3086 prsvaddr(lwp, prp->pr_vaddr);
3087 mutex_enter(&p->p_lock);
3092 * Common code for PIOCOPENM
3093 * Returns with the process unlocked.
3095 static int
3096 propenm(prnode_t *pnp, caddr_t cmaddr, caddr_t va, int *rvalp, cred_t *cr)
3098 proc_t *p = pnp->pr_common->prc_proc;
3099 struct as *as = p->p_as;
3100 int error = 0;
3101 struct seg *seg;
3102 struct vnode *xvp;
3103 int n;
3106 * By fiat, a system process has no address space.
3108 if ((p->p_flag & SSYS) || as == &kas) {
3109 error = EINVAL;
3110 } else if (cmaddr) {
3112 * We drop p_lock before grabbing the address
3113 * space lock in order to avoid a deadlock with
3114 * the clock thread. The process will not
3115 * disappear and its address space will not
3116 * change because it is marked P_PR_LOCK.
3118 mutex_exit(&p->p_lock);
3119 AS_LOCK_ENTER(as, RW_READER);
3120 seg = as_segat(as, va);
3121 if (seg != NULL &&
3122 seg->s_ops == &segvn_ops &&
3123 segop_getvp(seg, va, &xvp) == 0 &&
3124 xvp != NULL &&
3125 xvp->v_type == VREG) {
3126 VN_HOLD(xvp);
3127 } else {
3128 error = EINVAL;
3130 AS_LOCK_EXIT(as);
3131 mutex_enter(&p->p_lock);
3132 } else if ((xvp = p->p_exec) == NULL) {
3133 error = EINVAL;
3134 } else {
3135 VN_HOLD(xvp);
3138 prunlock(pnp);
3140 if (error == 0) {
3141 if ((error = fop_access(xvp, VREAD, 0, cr, NULL)) == 0)
3142 error = fassign(&xvp, FREAD, &n);
3143 if (error) {
3144 VN_RELE(xvp);
3145 } else {
3146 *rvalp = n;
3150 return (error);
3154 * Return old version of process/lwp status.
3155 * The u-block is mapped in by this routine and unmapped at the end.
3157 void
3158 oprgetstatus(kthread_t *t, prstatus_t *sp, zone_t *zp)
3160 proc_t *p = ttoproc(t);
3161 klwp_t *lwp = ttolwp(t);
3162 int flags;
3163 user_t *up;
3164 ulong_t instr;
3166 ASSERT(MUTEX_HELD(&p->p_lock));
3168 up = PTOU(p);
3169 bzero(sp, sizeof (*sp));
3170 flags = 0;
3171 if (t->t_state == TS_STOPPED) {
3172 flags |= PR_STOPPED;
3173 if ((t->t_schedflag & TS_PSTART) == 0)
3174 flags |= PR_ISTOP;
3175 } else if (VSTOPPED(t)) {
3176 flags |= PR_STOPPED|PR_ISTOP;
3178 if (!(flags & PR_ISTOP) && (t->t_proc_flag & TP_PRSTOP))
3179 flags |= PR_DSTOP;
3180 if (lwp->lwp_asleep)
3181 flags |= PR_ASLEEP;
3182 if (p->p_proc_flag & P_PR_FORK)
3183 flags |= PR_FORK;
3184 if (p->p_proc_flag & P_PR_RUNLCL)
3185 flags |= PR_RLC;
3186 if (p->p_proc_flag & P_PR_KILLCL)
3187 flags |= PR_KLC;
3188 if (p->p_proc_flag & P_PR_ASYNC)
3189 flags |= PR_ASYNC;
3190 if (p->p_proc_flag & P_PR_BPTADJ)
3191 flags |= PR_BPTADJ;
3192 if (p->p_proc_flag & P_PR_PTRACE)
3193 flags |= PR_PCOMPAT;
3194 if (t->t_proc_flag & TP_MSACCT)
3195 flags |= PR_MSACCT;
3196 sp->pr_flags = flags;
3197 if (VSTOPPED(t)) {
3198 sp->pr_why = PR_REQUESTED;
3199 sp->pr_what = 0;
3200 } else {
3201 sp->pr_why = t->t_whystop;
3202 sp->pr_what = t->t_whatstop;
3205 if (t->t_whystop == PR_FAULTED)
3206 bcopy(&lwp->lwp_siginfo,
3207 &sp->pr_info, sizeof (k_siginfo_t));
3208 else if (lwp->lwp_curinfo)
3209 bcopy(&lwp->lwp_curinfo->sq_info,
3210 &sp->pr_info, sizeof (k_siginfo_t));
3212 if (SI_FROMUSER(&lwp->lwp_siginfo) && zp->zone_id != GLOBAL_ZONEID &&
3213 sp->pr_info.si_zoneid != zp->zone_id) {
3214 sp->pr_info.si_pid = zp->zone_zsched->p_pid;
3215 sp->pr_info.si_uid = 0;
3216 sp->pr_info.si_ctid = -1;
3217 sp->pr_info.si_zoneid = zp->zone_id;
3220 sp->pr_cursig = lwp->lwp_cursig;
3221 prassignset(&sp->pr_sigpend, &p->p_sig);
3222 prassignset(&sp->pr_lwppend, &t->t_sig);
3223 schedctl_finish_sigblock(t);
3224 prassignset(&sp->pr_sighold, &t->t_hold);
3225 sp->pr_altstack = lwp->lwp_sigaltstack;
3226 prgetaction(p, up, lwp->lwp_cursig, &sp->pr_action);
3227 sp->pr_pid = p->p_pid;
3228 if (curproc->p_zone->zone_id != GLOBAL_ZONEID &&
3229 (p->p_flag & SZONETOP)) {
3230 ASSERT(p->p_zone->zone_id != GLOBAL_ZONEID);
3232 * Inside local zones, fake zsched's pid as parent pids for
3233 * processes which reference processes outside of the zone.
3235 sp->pr_ppid = curproc->p_zone->zone_zsched->p_pid;
3236 } else {
3237 sp->pr_ppid = p->p_ppid;
3239 sp->pr_pgrp = p->p_pgrp;
3240 sp->pr_sid = p->p_sessp->s_sid;
3241 hrt2ts(mstate_aggr_state(p, LMS_USER), &sp->pr_utime);
3242 hrt2ts(mstate_aggr_state(p, LMS_SYSTEM), &sp->pr_stime);
3243 TICK_TO_TIMESTRUC(p->p_cutime, &sp->pr_cutime);
3244 TICK_TO_TIMESTRUC(p->p_cstime, &sp->pr_cstime);
3245 (void) strncpy(sp->pr_clname, sclass[t->t_cid].cl_name,
3246 sizeof (sp->pr_clname) - 1);
3247 sp->pr_who = t->t_tid;
3248 sp->pr_nlwp = p->p_lwpcnt;
3249 sp->pr_brkbase = p->p_brkbase;
3250 sp->pr_brksize = p->p_brksize;
3251 sp->pr_stkbase = prgetstackbase(p);
3252 sp->pr_stksize = p->p_stksize;
3253 sp->pr_oldcontext = (struct ucontext *)lwp->lwp_oldcontext;
3254 sp->pr_processor = t->t_cpu->cpu_id;
3255 sp->pr_bind = t->t_bind_cpu;
3258 * Fetch the current instruction, if not a system process.
3259 * We don't attempt this unless the lwp is stopped.
3261 if ((p->p_flag & SSYS) || p->p_as == &kas)
3262 sp->pr_flags |= (PR_ISSYS|PR_PCINVAL);
3263 else if (!(flags & PR_STOPPED))
3264 sp->pr_flags |= PR_PCINVAL;
3265 else if (!prfetchinstr(lwp, &instr))
3266 sp->pr_flags |= PR_PCINVAL;
3267 else
3268 sp->pr_instr = instr;
3271 * Drop p_lock while touching the lwp's stack.
3273 mutex_exit(&p->p_lock);
3274 if (prisstep(lwp))
3275 sp->pr_flags |= PR_STEP;
3276 if ((flags & (PR_STOPPED|PR_ASLEEP)) && t->t_sysnum) {
3277 int i;
3278 auxv_t *auxp;
3280 sp->pr_syscall = get_syscall_args(lwp,
3281 (long *)sp->pr_sysarg, &i);
3282 sp->pr_nsysarg = (short)i;
3283 if (t->t_whystop == PR_SYSEXIT && t->t_sysnum == SYS_execve) {
3284 sp->pr_sysarg[0] = 0;
3285 sp->pr_sysarg[1] = (uintptr_t)up->u_argv;
3286 sp->pr_sysarg[2] = (uintptr_t)up->u_envp;
3287 for (i = 0, auxp = up->u_auxv;
3288 i < sizeof (up->u_auxv) / sizeof (up->u_auxv[0]);
3289 i++, auxp++) {
3290 if (auxp->a_type == AT_SUN_EXECNAME) {
3291 sp->pr_sysarg[0] =
3292 (uintptr_t)auxp->a_un.a_ptr;
3293 break;
3298 if ((flags & PR_STOPPED) || t == curthread)
3299 prgetprregs(lwp, sp->pr_reg);
3300 mutex_enter(&p->p_lock);
3304 * Return old version of information used by ps(1).
3306 void
3307 oprgetpsinfo(proc_t *p, prpsinfo_t *psp, kthread_t *tp)
3309 kthread_t *t;
3310 char c, state;
3311 user_t *up;
3312 dev_t d;
3313 uint64_t pct;
3314 int retval, niceval;
3315 cred_t *cred;
3316 struct as *as;
3317 hrtime_t hrutime, hrstime, cur_time;
3319 ASSERT(MUTEX_HELD(&p->p_lock));
3321 bzero(psp, sizeof (*psp));
3323 if ((t = tp) == NULL)
3324 t = prchoose(p); /* returns locked thread */
3325 else
3326 thread_lock(t);
3328 /* kludge: map thread state enum into process state enum */
3330 if (t == NULL) {
3331 state = TS_ZOMB;
3332 } else {
3333 state = VSTOPPED(t) ? TS_STOPPED : t->t_state;
3334 thread_unlock(t);
3337 switch (state) {
3338 case TS_SLEEP: state = SSLEEP; break;
3339 case TS_RUN: state = SRUN; break;
3340 case TS_ONPROC: state = SONPROC; break;
3341 case TS_ZOMB: state = SZOMB; break;
3342 case TS_STOPPED: state = SSTOP; break;
3343 default: state = 0; break;
3345 switch (state) {
3346 case SSLEEP: c = 'S'; break;
3347 case SRUN: c = 'R'; break;
3348 case SZOMB: c = 'Z'; break;
3349 case SSTOP: c = 'T'; break;
3350 case SIDL: c = 'I'; break;
3351 case SONPROC: c = 'O'; break;
3352 #ifdef SXBRK
3353 case SXBRK: c = 'X'; break;
3354 #endif
3355 default: c = '?'; break;
3357 psp->pr_state = state;
3358 psp->pr_sname = c;
3359 psp->pr_zomb = (state == SZOMB);
3361 * only export SSYS and SMSACCT; everything else is off-limits to
3362 * userland apps.
3364 psp->pr_flag = p->p_flag & (SSYS | SMSACCT);
3366 mutex_enter(&p->p_crlock);
3367 cred = p->p_cred;
3368 psp->pr_uid = crgetruid(cred);
3369 psp->pr_gid = crgetrgid(cred);
3370 psp->pr_euid = crgetuid(cred);
3371 psp->pr_egid = crgetgid(cred);
3372 mutex_exit(&p->p_crlock);
3374 psp->pr_pid = p->p_pid;
3375 if (curproc->p_zone->zone_id != GLOBAL_ZONEID &&
3376 (p->p_flag & SZONETOP)) {
3377 ASSERT(p->p_zone->zone_id != GLOBAL_ZONEID);
3379 * Inside local zones, fake zsched's pid as parent pids for
3380 * processes which reference processes outside of the zone.
3382 psp->pr_ppid = curproc->p_zone->zone_zsched->p_pid;
3383 } else {
3384 psp->pr_ppid = p->p_ppid;
3386 psp->pr_pgrp = p->p_pgrp;
3387 psp->pr_sid = p->p_sessp->s_sid;
3388 psp->pr_addr = prgetpsaddr(p);
3389 hrutime = mstate_aggr_state(p, LMS_USER);
3390 hrstime = mstate_aggr_state(p, LMS_SYSTEM);
3391 hrt2ts(hrutime + hrstime, &psp->pr_time);
3392 TICK_TO_TIMESTRUC(p->p_cutime + p->p_cstime, &psp->pr_ctime);
3393 switch (p->p_model) {
3394 case DATAMODEL_ILP32:
3395 psp->pr_dmodel = PR_MODEL_ILP32;
3396 break;
3397 case DATAMODEL_LP64:
3398 psp->pr_dmodel = PR_MODEL_LP64;
3399 break;
3401 if (state == SZOMB || t == NULL) {
3402 int wcode = p->p_wcode; /* must be atomic read */
3404 if (wcode)
3405 psp->pr_wstat = wstat(wcode, p->p_wdata);
3406 psp->pr_lttydev = PRNODEV;
3407 psp->pr_ottydev = (o_dev_t)PRNODEV;
3408 psp->pr_size = 0;
3409 psp->pr_rssize = 0;
3410 psp->pr_pctmem = 0;
3411 } else {
3412 up = PTOU(p);
3413 psp->pr_wchan = t->t_wchan;
3414 psp->pr_pri = t->t_pri;
3415 (void) strncpy(psp->pr_clname, sclass[t->t_cid].cl_name,
3416 sizeof (psp->pr_clname) - 1);
3417 retval = CL_DONICE(t, NULL, 0, &niceval);
3418 if (retval == 0) {
3419 psp->pr_oldpri = v.v_maxsyspri - psp->pr_pri;
3420 psp->pr_nice = niceval + NZERO;
3421 } else {
3422 psp->pr_oldpri = 0;
3423 psp->pr_nice = 0;
3425 d = cttydev(p);
3426 #ifdef sun
3428 extern dev_t rwsconsdev, rconsdev, uconsdev;
3430 * If the controlling terminal is the real
3431 * or workstation console device, map to what the
3432 * user thinks is the console device. Handle case when
3433 * rwsconsdev or rconsdev is set to NODEV for Starfire.
3435 if ((d == rwsconsdev || d == rconsdev) && d != NODEV)
3436 d = uconsdev;
3438 #endif
3439 psp->pr_lttydev = (d == NODEV) ? PRNODEV : d;
3440 psp->pr_ottydev = cmpdev(d);
3441 psp->pr_start = up->u_start;
3442 bcopy(up->u_comm, psp->pr_fname,
3443 MIN(sizeof (up->u_comm), sizeof (psp->pr_fname)-1));
3444 bcopy(up->u_psargs, psp->pr_psargs,
3445 MIN(PRARGSZ-1, PSARGSZ));
3446 psp->pr_syscall = t->t_sysnum;
3447 psp->pr_argc = up->u_argc;
3448 psp->pr_argv = (char **)up->u_argv;
3449 psp->pr_envp = (char **)up->u_envp;
3451 /* compute %cpu for the lwp or process */
3452 pct = 0;
3453 if ((t = tp) == NULL)
3454 t = p->p_tlist;
3455 cur_time = gethrtime_unscaled();
3456 do {
3457 pct += cpu_update_pct(t, cur_time);
3458 if (tp != NULL) /* just do the one lwp */
3459 break;
3460 } while ((t = t->t_forw) != p->p_tlist);
3462 psp->pr_pctcpu = prgetpctcpu(pct);
3463 psp->pr_cpu = (psp->pr_pctcpu*100 + 0x6000) >> 15; /* [0..99] */
3464 if (psp->pr_cpu > 99)
3465 psp->pr_cpu = 99;
3467 if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
3468 psp->pr_size = 0;
3469 psp->pr_rssize = 0;
3470 psp->pr_pctmem = 0;
3471 } else {
3472 mutex_exit(&p->p_lock);
3473 AS_LOCK_ENTER(as, RW_READER);
3474 psp->pr_size = btopr(as->a_resvsize);
3475 psp->pr_rssize = rm_asrss(as);
3476 psp->pr_pctmem = rm_pctmemory(as);
3477 AS_LOCK_EXIT(as);
3478 mutex_enter(&p->p_lock);
3481 psp->pr_bysize = ptob(psp->pr_size);
3482 psp->pr_byrssize = ptob(psp->pr_rssize);
3486 * Return an array of structures with memory map information.
3487 * We allocate here; the caller must deallocate.
3488 * The caller is also responsible to append the zero-filled entry
3489 * that terminates the PIOCMAP output buffer.
3491 static int
3492 oprgetmap(proc_t *p, list_t *iolhead)
3494 struct as *as = p->p_as;
3495 prmap_t *mp;
3496 struct seg *seg;
3497 struct seg *brkseg, *stkseg;
3498 uint_t prot;
3500 ASSERT(as != &kas && AS_WRITE_HELD(as));
3503 * Request an initial buffer size that doesn't waste memory
3504 * if the address space has only a small number of segments.
3506 pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
3508 if ((seg = AS_SEGFIRST(as)) == NULL)
3509 return (0);
3511 brkseg = break_seg(p);
3512 stkseg = as_segat(as, prgetstackbase(p));
3514 do {
3515 caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
3516 caddr_t saddr, naddr;
3517 void *tmp = NULL;
3519 if ((seg->s_flags & S_HOLE) != 0) {
3520 continue;
3523 for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
3524 prot = pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
3525 if (saddr == naddr)
3526 continue;
3528 mp = pr_iol_newbuf(iolhead, sizeof (*mp));
3530 mp->pr_vaddr = saddr;
3531 mp->pr_size = naddr - saddr;
3532 mp->pr_off = segop_getoffset(seg, saddr);
3533 mp->pr_mflags = 0;
3534 if (prot & PROT_READ)
3535 mp->pr_mflags |= MA_READ;
3536 if (prot & PROT_WRITE)
3537 mp->pr_mflags |= MA_WRITE;
3538 if (prot & PROT_EXEC)
3539 mp->pr_mflags |= MA_EXEC;
3540 if (segop_gettype(seg, saddr) & MAP_SHARED)
3541 mp->pr_mflags |= MA_SHARED;
3542 if (seg == brkseg)
3543 mp->pr_mflags |= MA_BREAK;
3544 else if (seg == stkseg)
3545 mp->pr_mflags |= MA_STACK;
3546 mp->pr_pagesize = PAGESIZE;
3548 ASSERT(tmp == NULL);
3549 } while ((seg = AS_SEGNEXT(as, seg)) != NULL);
3551 return (0);
3554 #ifdef _SYSCALL32_IMPL
3555 static int
3556 oprgetmap32(proc_t *p, list_t *iolhead)
3558 struct as *as = p->p_as;
3559 ioc_prmap32_t *mp;
3560 struct seg *seg;
3561 struct seg *brkseg, *stkseg;
3562 uint_t prot;
3564 ASSERT(as != &kas && AS_WRITE_HELD(as));
3567 * Request an initial buffer size that doesn't waste memory
3568 * if the address space has only a small number of segments.
3570 pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
3572 if ((seg = AS_SEGFIRST(as)) == NULL)
3573 return (0);
3575 brkseg = break_seg(p);
3576 stkseg = as_segat(as, prgetstackbase(p));
3578 do {
3579 caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
3580 caddr_t saddr, naddr;
3581 void *tmp = NULL;
3583 if ((seg->s_flags & S_HOLE) != 0) {
3584 continue;
3587 for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
3588 prot = pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
3589 if (saddr == naddr)
3590 continue;
3592 mp = pr_iol_newbuf(iolhead, sizeof (*mp));
3594 mp->pr_vaddr = (caddr32_t)(uintptr_t)saddr;
3595 mp->pr_size = (size32_t)(naddr - saddr);
3596 mp->pr_off = (off32_t)segop_getoffset(seg, saddr);
3597 mp->pr_mflags = 0;
3598 if (prot & PROT_READ)
3599 mp->pr_mflags |= MA_READ;
3600 if (prot & PROT_WRITE)
3601 mp->pr_mflags |= MA_WRITE;
3602 if (prot & PROT_EXEC)
3603 mp->pr_mflags |= MA_EXEC;
3604 if (segop_gettype(seg, saddr) & MAP_SHARED)
3605 mp->pr_mflags |= MA_SHARED;
3606 if (seg == brkseg)
3607 mp->pr_mflags |= MA_BREAK;
3608 else if (seg == stkseg)
3609 mp->pr_mflags |= MA_STACK;
3610 mp->pr_pagesize = PAGESIZE;
3612 ASSERT(tmp == NULL);
3613 } while ((seg = AS_SEGNEXT(as, seg)) != NULL);
3615 return (0);
3617 #endif /* _SYSCALL32_IMPL */
3620 * Return the size of the old /proc page data file.
3622 size_t
3623 oprpdsize(struct as *as)
3625 struct seg *seg;
3626 size_t size;
3628 ASSERT(as != &kas && AS_WRITE_HELD(as));
3630 if ((seg = AS_SEGFIRST(as)) == NULL)
3631 return (0);
3633 size = sizeof (prpageheader_t);
3634 do {
3635 caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
3636 caddr_t saddr, naddr;
3637 void *tmp = NULL;
3638 size_t npage;
3640 if ((seg->s_flags & S_HOLE) != 0) {
3641 continue;
3644 for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
3645 (void) pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
3646 if ((npage = (naddr - saddr) / PAGESIZE) != 0)
3647 size += sizeof (prasmap_t) + roundlong(npage);
3649 ASSERT(tmp == NULL);
3650 } while ((seg = AS_SEGNEXT(as, seg)) != NULL);
3652 return (size);
3655 #ifdef _SYSCALL32_IMPL
3656 size_t
3657 oprpdsize32(struct as *as)
3659 struct seg *seg;
3660 size_t size;
3662 ASSERT(as != &kas && AS_WRITE_HELD(as));
3664 if ((seg = AS_SEGFIRST(as)) == NULL)
3665 return (0);
3667 size = sizeof (ioc_prpageheader32_t);
3668 do {
3669 caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
3670 caddr_t saddr, naddr;
3671 void *tmp = NULL;
3672 size_t npage;
3674 if ((seg->s_flags & S_HOLE) != 0) {
3675 continue;
3678 for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
3679 (void) pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
3680 if ((npage = (naddr - saddr) / PAGESIZE) != 0)
3681 size += sizeof (ioc_prmap32_t) + round4(npage);
3683 ASSERT(tmp == NULL);
3684 } while ((seg = AS_SEGNEXT(as, seg)) != NULL);
3686 return (size);
3688 #endif /* _SYSCALL32_IMPL */
3691 * Read old /proc page data information.
3694 oprpdread(struct as *as, uint_t hatid, struct uio *uiop)
3696 caddr_t buf;
3697 size_t size;
3698 prpageheader_t *php;
3699 prasmap_t *pmp;
3700 struct seg *seg;
3701 int error;
3703 again:
3704 AS_LOCK_ENTER(as, RW_WRITER);
3706 if ((seg = AS_SEGFIRST(as)) == NULL) {
3707 AS_LOCK_EXIT(as);
3708 return (0);
3710 size = oprpdsize(as);
3711 if (uiop->uio_resid < size) {
3712 AS_LOCK_EXIT(as);
3713 return (E2BIG);
3716 buf = kmem_zalloc(size, KM_SLEEP);
3717 php = (prpageheader_t *)buf;
3718 pmp = (prasmap_t *)(buf + sizeof (prpageheader_t));
3720 hrt2ts(gethrtime(), &php->pr_tstamp);
3721 php->pr_nmap = 0;
3722 php->pr_npage = 0;
3723 do {
3724 caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
3725 caddr_t saddr, naddr;
3726 void *tmp = NULL;
3728 if ((seg->s_flags & S_HOLE) != 0) {
3729 continue;
3732 for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
3733 size_t len;
3734 size_t npage;
3735 uint_t prot;
3736 uintptr_t next;
3738 prot = pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
3739 if ((len = naddr - saddr) == 0)
3740 continue;
3741 npage = len / PAGESIZE;
3742 next = (uintptr_t)(pmp + 1) + roundlong(npage);
3744 * It's possible that the address space can change
3745 * subtlely even though we're holding as->a_lock
3746 * due to the nondeterminism of page_exists() in
3747 * the presence of asychronously flushed pages or
3748 * mapped files whose sizes are changing.
3749 * page_exists() may be called indirectly from
3750 * pr_getprot() by a segop_incore() routine.
3751 * If this happens we need to make sure we don't
3752 * overrun the buffer whose size we computed based
3753 * on the initial iteration through the segments.
3754 * Once we've detected an overflow, we need to clean
3755 * up the temporary memory allocated in pr_getprot()
3756 * and retry. If there's a pending signal, we return
3757 * EINTR so that this thread can be dislodged if
3758 * a latent bug causes us to spin indefinitely.
3760 if (next > (uintptr_t)buf + size) {
3761 pr_getprot_done(&tmp);
3762 AS_LOCK_EXIT(as);
3764 kmem_free(buf, size);
3766 if (ISSIG(curthread, JUSTLOOKING))
3767 return (EINTR);
3769 goto again;
3772 php->pr_nmap++;
3773 php->pr_npage += npage;
3774 pmp->pr_vaddr = saddr;
3775 pmp->pr_npage = npage;
3776 pmp->pr_off = segop_getoffset(seg, saddr);
3777 pmp->pr_mflags = 0;
3778 if (prot & PROT_READ)
3779 pmp->pr_mflags |= MA_READ;
3780 if (prot & PROT_WRITE)
3781 pmp->pr_mflags |= MA_WRITE;
3782 if (prot & PROT_EXEC)
3783 pmp->pr_mflags |= MA_EXEC;
3784 if (segop_gettype(seg, saddr) & MAP_SHARED)
3785 pmp->pr_mflags |= MA_SHARED;
3786 pmp->pr_pagesize = PAGESIZE;
3787 hat_getstat(as, saddr, len, hatid,
3788 (char *)(pmp + 1), HAT_SYNC_ZERORM);
3789 pmp = (prasmap_t *)next;
3791 ASSERT(tmp == NULL);
3792 } while ((seg = AS_SEGNEXT(as, seg)) != NULL);
3794 AS_LOCK_EXIT(as);
3796 ASSERT((uintptr_t)pmp <= (uintptr_t)buf + size);
3797 error = uiomove(buf, (caddr_t)pmp - buf, UIO_READ, uiop);
3798 kmem_free(buf, size);
3800 return (error);
3803 #ifdef _SYSCALL32_IMPL
3805 oprpdread32(struct as *as, uint_t hatid, struct uio *uiop)
3807 caddr_t buf;
3808 size_t size;
3809 ioc_prpageheader32_t *php;
3810 ioc_prasmap32_t *pmp;
3811 struct seg *seg;
3812 int error;
3814 again:
3815 AS_LOCK_ENTER(as, RW_WRITER);
3817 if ((seg = AS_SEGFIRST(as)) == NULL) {
3818 AS_LOCK_EXIT(as);
3819 return (0);
3821 size = oprpdsize32(as);
3822 if (uiop->uio_resid < size) {
3823 AS_LOCK_EXIT(as);
3824 return (E2BIG);
3827 buf = kmem_zalloc(size, KM_SLEEP);
3828 php = (ioc_prpageheader32_t *)buf;
3829 pmp = (ioc_prasmap32_t *)(buf + sizeof (ioc_prpageheader32_t));
3831 hrt2ts32(gethrtime(), &php->pr_tstamp);
3832 php->pr_nmap = 0;
3833 php->pr_npage = 0;
3834 do {
3835 caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
3836 caddr_t saddr, naddr;
3837 void *tmp = NULL;
3839 if ((seg->s_flags & S_HOLE) != 0) {
3840 continue;
3843 for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
3844 size_t len;
3845 size_t npage;
3846 uint_t prot;
3847 uintptr_t next;
3849 prot = pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
3850 if ((len = naddr - saddr) == 0)
3851 continue;
3852 npage = len / PAGESIZE;
3853 next = (uintptr_t)(pmp + 1) + round4(npage);
3855 * It's possible that the address space can change
3856 * subtlely even though we're holding as->a_lock
3857 * due to the nondeterminism of page_exists() in
3858 * the presence of asychronously flushed pages or
3859 * mapped files whose sizes are changing.
3860 * page_exists() may be called indirectly from
3861 * pr_getprot() by a segop_incore() routine.
3862 * If this happens we need to make sure we don't
3863 * overrun the buffer whose size we computed based
3864 * on the initial iteration through the segments.
3865 * Once we've detected an overflow, we need to clean
3866 * up the temporary memory allocated in pr_getprot()
3867 * and retry. If there's a pending signal, we return
3868 * EINTR so that this thread can be dislodged if
3869 * a latent bug causes us to spin indefinitely.
3871 if (next > (uintptr_t)buf + size) {
3872 pr_getprot_done(&tmp);
3873 AS_LOCK_EXIT(as);
3875 kmem_free(buf, size);
3877 if (ISSIG(curthread, JUSTLOOKING))
3878 return (EINTR);
3880 goto again;
3883 php->pr_nmap++;
3884 php->pr_npage += npage;
3885 pmp->pr_vaddr = (uint32_t)(uintptr_t)saddr;
3886 pmp->pr_npage = (uint32_t)npage;
3887 pmp->pr_off = (int32_t)segop_getoffset(seg, saddr);
3888 pmp->pr_mflags = 0;
3889 if (prot & PROT_READ)
3890 pmp->pr_mflags |= MA_READ;
3891 if (prot & PROT_WRITE)
3892 pmp->pr_mflags |= MA_WRITE;
3893 if (prot & PROT_EXEC)
3894 pmp->pr_mflags |= MA_EXEC;
3895 if (segop_gettype(seg, saddr) & MAP_SHARED)
3896 pmp->pr_mflags |= MA_SHARED;
3897 pmp->pr_pagesize = PAGESIZE;
3898 hat_getstat(as, saddr, len, hatid,
3899 (char *)(pmp + 1), HAT_SYNC_ZERORM);
3900 pmp = (ioc_prasmap32_t *)next;
3902 ASSERT(tmp == NULL);
3903 } while ((seg = AS_SEGNEXT(as, seg)) != NULL);
3905 AS_LOCK_EXIT(as);
3907 ASSERT((uintptr_t)pmp == (uintptr_t)buf + size);
3908 error = uiomove(buf, (caddr_t)pmp - buf, UIO_READ, uiop);
3909 kmem_free(buf, size);
3911 return (error);
3913 #endif /* _SYSCALL32_IMPL */
3915 /*ARGSUSED*/
3916 #ifdef _SYSCALL32_IMPL
3918 prioctl(
3919 struct vnode *vp,
3920 int cmd,
3921 intptr_t arg,
3922 int flag,
3923 cred_t *cr,
3924 int *rvalp,
3925 caller_context_t *ct)
3927 switch (curproc->p_model) {
3928 case DATAMODEL_ILP32:
3929 return (prioctl32(vp, cmd, arg, flag, cr, rvalp, ct));
3930 case DATAMODEL_LP64:
3931 return (prioctl64(vp, cmd, arg, flag, cr, rvalp, ct));
3932 default:
3933 return (ENOSYS);
3936 #endif /* _SYSCALL32_IMPL */