prioctl.c revision 406882169e00272f14067d948324d690893e6fe3
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All rights reserved. */
#include <sys/sysmacros.h>
#include <sys/schedctl.h>
#include <sys/old_procfs.h>
#include <sys/contract_impl.h>
#include <sys/ctfs_impl.h>
#if defined(__i386) || defined(__i386_COMPAT)
#endif
static int isprwrioctl(int);
static ulong_t prmaprunflags(long);
static long prmapsetflags(long);
static int
{
int error = 0;
return (EINVAL);
if (error != 0)
return (error);
return (error);
}
return (ESTALE);
}
else
} else {
}
return (error);
}
/*
* Control operations (lots).
*/
/*ARGSUSED*/
#ifdef _SYSCALL32_IMPL
static int
int cmd,
int flag,
int *rvalp,
#else
int
int cmd,
int flag,
int *rvalp,
#endif /* _SYSCALL32_IMPL */
{
proc_t *p;
kthread_t *t;
int error;
int zdisp;
/*
* For copyin()/copyout().
*/
union {
int signo;
int nice;
long flags;
} un;
/*
* Support for old /proc interface.
*/
}
return (ENOTTY);
/*
* Fail ioctls which are logically "write" requests unless
* the user has write permission.
*/
return (EBADF);
/*
* Perform any necessary copyin() operations before
* locking the process. Helps avoid deadlocks and
* improves performance.
*
* Also, detect invalid ioctl codes here to avoid
* locking a process unnnecessarily.
*
* Also, prepare to allocate space that will be needed below,
* case by case.
*/
error = 0;
switch (cmd) {
case PIOCGETPR:
break;
case PIOCGETU:
break;
case PIOCSTOP:
case PIOCWSTOP:
case PIOCLWPIDS:
case PIOCGTRACE:
case PIOCGENTRY:
case PIOCGEXIT:
case PIOCSRLC:
case PIOCRRLC:
case PIOCSFORK:
case PIOCRFORK:
case PIOCGREG:
case PIOCGFPREG:
case PIOCSTATUS:
case PIOCLSTATUS:
case PIOCPSINFO:
case PIOCMAXSIG:
case PIOCGXREGSIZE:
break;
case PIOCSXREG: /* set extra registers */
case PIOCGXREG: /* get extra registers */
#if defined(__sparc)
thingsize = sizeof (prxregset_t);
#else
thingsize = 0;
#endif
break;
case PIOCACTION:
break;
case PIOCGHOLD:
case PIOCNMAP:
case PIOCMAP:
case PIOCGFAULT:
case PIOCCFAULT:
case PIOCCRED:
case PIOCGROUPS:
case PIOCUSAGE:
case PIOCLUSAGE:
break;
case PIOCOPENPD:
/*
* We will need this below.
* Allocate it now, before locking the process.
*/
break;
case PIOCNAUXV:
case PIOCAUXV:
break;
case PIOCNLDT:
case PIOCLDT:
break;
#endif /* __i386 || __amd64 */
#if defined(__sparc)
case PIOCGWIN:
thingsize = sizeof (gwindows_t);
break;
#endif /* __sparc */
case PIOCOPENM: /* open mapped object for reading */
break;
case PIOCRUN: /* make lwp or process runnable */
break;
case PIOCOPENLWP: /* return /proc lwp file descriptor */
break;
case PIOCSTRACE: /* set signal trace mask */
break;
case PIOCSSIG: /* set current signal */
break;
case PIOCKILL: /* send signal */
case PIOCUNKILL: /* delete a signal */
break;
case PIOCNICE: /* set nice priority */
break;
case PIOCSENTRY: /* set syscall entry bit mask */
case PIOCSEXIT: /* set syscall exit bit mask */
break;
case PIOCSET: /* set process flags */
case PIOCRESET: /* reset process flags */
break;
case PIOCSREG: /* set general registers */
break;
case PIOCSFPREG: /* set floating-point registers */
break;
case PIOCSHOLD: /* set signal-hold mask */
break;
case PIOCSFAULT: /* set mask of traced faults */
break;
default:
break;
}
if (error)
return (error);
/*
* If we need kmem_alloc()d space then we allocate it now, before
* grabbing the process lock. Using kmem_alloc(KM_SLEEP) while
* holding the process lock leads to deadlock with the clock thread.
* (The clock thread wakes up the pageout daemon to free up space.
* If the clock thread blocks behind us and we are sleeping waiting
* for space, then space may never become available.)
*/
if (thingsize) {
}
switch (cmd) {
case PIOCPSINFO:
case PIOCGETPR:
case PIOCUSAGE:
case PIOCLUSAGE:
break;
case PIOCSXREG: /* set extra registers */
/*
* perform copyin before grabbing the process lock
*/
if (thing) {
return (EFAULT);
}
}
/* fall through... */
default:
break;
}
if (xpnp)
return (error);
}
/*
*/
t = pcp->prc_thread;
} else {
t = prchoose(p); /* returns locked thread */
thread_unlock(t);
}
}
error = 0;
switch (cmd) {
case PIOCGETPR: /* read struct proc */
{
*prp = *p;
break;
}
case PIOCGETU: /* read u-area */
{
break;
}
case PIOCOPENM: /* open mapped object for reading */
/* propenm() called prunlock(pnp) */
break;
case PIOCSTOP: /* stop process or lwp from running */
case PIOCWSTOP: /* wait for process or lwp to stop */
/*
* Can't apply to a system process.
*/
break;
}
/*
* If an lwp is waiting for itself or its process, don't wait.
* The stopped lwp would never see the fact that it is stopped.
*/
break;
}
break; /* pr_wait_stop() unlocked the process */
else {
/*
*/
thread_unlock(t);
}
break;
case PIOCRUN: /* make lwp or process runnable */
{
/*
* Cannot set an lwp running is it is not stopped.
* Also, no lwp other than the /proc agent lwp can
* be set running so long as the /proc agent lwp exists.
*/
!(t->t_proc_flag & TP_PRSTOP)) ||
break;
}
break;
}
case PIOCLWPIDS: /* get array of lwp identifiers */
{
int nlwp;
int Nlwp;
}
}
goto startover;
}
do {
--nlwp;
}
*idp = 0;
break;
}
case PIOCOPENLWP: /* return /proc lwp file descriptor */
{
int n;
} else
*rvalp = n;
break;
}
case PIOCOPENPD: /* return /proc page data file descriptor */
{
int n;
}
} else
*rvalp = n;
break;
}
case PIOCGTRACE: /* get signal trace mask */
break;
case PIOCSTRACE: /* set signal trace mask */
if (!sigisempty(&p->p_sigmask))
p->p_proc_flag |= P_PR_TRACE;
p->p_proc_flag &= ~P_PR_TRACE;
}
break;
case PIOCSSIG: /* set current signal */
break;
case PIOCKILL: /* send signal */
{
break;
}
case PIOCUNKILL: /* delete a signal */
break;
case PIOCNICE: /* set nice priority */
break;
case PIOCGENTRY: /* get syscall entry bit mask */
case PIOCGEXIT: /* get syscall exit bit mask */
if (cmd == PIOCGENTRY) {
} else {
}
break;
case PIOCSENTRY: /* set syscall entry bit mask */
case PIOCSEXIT: /* set syscall exit bit mask */
break;
case PIOCSRLC: /* obsolete: set running on last /proc close */
break;
case PIOCRRLC: /* obsolete: reset run-on-last-close flag */
break;
case PIOCSFORK: /* obsolete: set inherit-on-fork flag */
break;
case PIOCRFORK: /* obsolete: reset inherit-on-fork flag */
break;
case PIOCSET: /* set process flags */
break;
case PIOCRESET: /* reset process flags */
break;
case PIOCGREG: /* get general registers */
else {
/* drop p_lock while touching the lwp's stack */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
break;
case PIOCSREG: /* set general registers */
else {
/* drop p_lock while touching the lwp's stack */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
break;
case PIOCGFPREG: /* get floating-point registers */
if (!prhasfp()) {
break;
}
else {
/* drop p_lock while touching the lwp's stack */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
break;
case PIOCSFPREG: /* set floating-point registers */
if (!prhasfp())
else {
/* drop p_lock while touching the lwp's stack */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
break;
case PIOCGXREGSIZE: /* get the size of the extra registers */
{
int xregsize;
if (prhasx(p)) {
xregsize = prgetprxregsize(p);
} else {
}
break;
}
case PIOCGXREG: /* get extra registers */
if (prhasx(p)) {
/* drop p_lock to touch the stack */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
} else {
}
if (thing) {
}
break;
case PIOCSXREG: /* set extra registers */
else if (!prhasx(p))
else if (thing) {
/* drop p_lock while touching the lwp's stack */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
if (thing) {
}
break;
case PIOCSTATUS: /* get process/lwp status */
break;
case PIOCLSTATUS: /* get status for process & all lwps */
{
int Nlwp;
int nlwp;
}
}
goto startover;
}
t = p->p_tlist;
do {
--nlwp;
break;
}
case PIOCPSINFO: /* get ps(1) information */
{
oprgetpsinfo(p, psp,
break;
}
case PIOCMAXSIG: /* get maximum signal number */
{
int n = NSIG-1;
break;
}
case PIOCACTION: /* get signal action structures */
{
break;
}
case PIOCGHOLD: /* get signal-hold mask */
break;
case PIOCSHOLD: /* set signal-hold mask */
break;
case PIOCNMAP: /* get number of memory mappings */
{
int n;
n = 0;
else {
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
break;
}
case PIOCMAP: /* get memory map information */
{
error = 0;
} else {
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
/*
* The procfs PIOCMAP ioctl returns an all-zero buffer
* to indicate the end of the prmap[] array.
* Append it to whatever has already been copied out.
*/
break;
}
case PIOCGFAULT: /* get mask of traced faults */
break;
case PIOCSFAULT: /* set mask of traced faults */
break;
case PIOCCFAULT: /* clear current fault */
lwp->lwp_curflt = 0;
break;
case PIOCCRED: /* get process credentials */
{
mutex_enter(&p->p_crlock);
mutex_exit(&p->p_crlock);
break;
}
case PIOCGROUPS: /* get supplementary groups */
{
mutex_enter(&p->p_crlock);
mutex_exit(&p->p_crlock);
break;
}
case PIOCUSAGE: /* get usage info */
{
/*
* For an lwp file descriptor, return just the lwp usage.
* For a process file descriptor, return total usage,
* all current lwps plus all defunct lwps.
*/
t = pcp->prc_thread;
if (t != NULL)
prgetusage(t, pup);
else
} else {
/*
* Add the usage information for each active lwp.
*/
do {
praddusage(t, pup);
}
}
break;
}
case PIOCLUSAGE: /* get detailed usage info */
{
int Nlwp;
int nlwp;
}
thingsize = sizeof (prhusage_t) +
}
goto startover;
}
/*
* First the summation over defunct lwps.
*/
/*
* Fill one prusage struct for each active lwp.
*/
do {
--nlwp;
upup++;
prgetusage(t, pup);
}
break;
}
case PIOCNAUXV: /* get number of aux vector entries */
{
int n = __KERN_NAUXV_IMPL;
break;
}
{
__KERN_NAUXV_IMPL * sizeof (auxv_t));
__KERN_NAUXV_IMPL * sizeof (auxv_t)))
break;
}
case PIOCNLDT: /* get number of LDT entries */
{
int n;
mutex_exit(&p->p_lock);
mutex_enter(&p->p_ldtlock);
n = prnldt(p);
mutex_exit(&p->p_ldtlock);
mutex_enter(&p->p_lock);
break;
}
case PIOCLDT: /* get LDT entries */
{
int n;
mutex_exit(&p->p_lock);
mutex_enter(&p->p_ldtlock);
n = prnldt(p);
}
}
mutex_exit(&p->p_ldtlock);
mutex_enter(&p->p_lock);
goto startover;
}
if (n != 0)
mutex_exit(&p->p_ldtlock);
mutex_enter(&p->p_lock);
/* mark the end of the list with a null entry */
break;
}
#endif /* __i386 || __amd64 */
#if defined(__sparc)
{
/* drop p->p_lock while touching the stack */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
break;
}
#endif /* __sparc */
default:
break;
}
return (error);
}
#ifdef _SYSCALL32_IMPL
void
{
flags = 0L;
if (t->t_state == TS_STOPPED) {
flags |= PR_STOPPED;
if ((t->t_schedflag & TS_PSTART) == 0)
} else if (VSTOPPED(t)) {
}
if (lwp->lwp_asleep)
if (p->p_proc_flag & P_PR_FORK)
if (p->p_proc_flag & P_PR_RUNLCL)
if (p->p_proc_flag & P_PR_KILLCL)
if (p->p_proc_flag & P_PR_ASYNC)
if (p->p_proc_flag & P_PR_BPTADJ)
if (p->p_proc_flag & P_PR_PTRACE)
flags |= PR_PCOMPAT;
if (t->t_proc_flag & TP_MSACCT)
if (VSTOPPED(t)) {
} else {
}
if (t->t_whystop == PR_FAULTED) {
if (t->t_whatstop == FLTPAGE)
} else if (lwp->lwp_curinfo)
}
/*
* Inside local zones, fake zsched's pid as parent pids for
* processes which reference processes outside of the zone.
*/
} else {
}
/*
* Fetch the current instruction, if not a system process.
* We don't attempt this unless the lwp is stopped.
*/
else if (!(flags & PR_STOPPED))
else
/*
* Drop p_lock while touching the lwp's stack.
*/
mutex_exit(&p->p_lock);
int i;
sp->pr_nsysarg = (short)i;
if (t->t_whystop == PR_SYSEXIT &&
i++, auxp++) {
break;
}
}
}
}
mutex_enter(&p->p_lock);
}
void
{
kthread_t *t;
char c, state;
dev_t d;
t = prchoose(p); /* returns locked thread */
else
thread_lock(t);
/* kludge: map thread state enum into process state enum */
if (t == NULL) {
} else {
thread_unlock(t);
}
switch (state) {
default: state = 0; break;
}
switch (state) {
case SSLEEP: c = 'S'; break;
case SRUN: c = 'R'; break;
case SZOMB: c = 'Z'; break;
case SSTOP: c = 'T'; break;
case SIDL: c = 'I'; break;
case SONPROC: c = 'O'; break;
#ifdef SXBRK
case SXBRK: c = 'X'; break;
#endif
default: c = '?'; break;
}
/*
* only export SSYS and SMSACCT; everything else is off-limits to
* userland apps.
*/
mutex_enter(&p->p_crlock);
mutex_exit(&p->p_crlock);
/*
* Inside local zones, fake zsched's pid as parent pids for
* processes which reference processes outside of the zone.
*/
} else {
}
switch (p->p_model) {
case DATAMODEL_ILP32:
break;
case DATAMODEL_LP64:
break;
}
if (wcode)
} else {
if (retval == 0) {
} else {
}
d = cttydev(p);
#ifdef sun
{
/*
* If the controlling terminal is the real
* or workstation console device, map to what the
* user thinks is the console device. Handle case when
* rwsconsdev or rconsdev is set to NODEV for Starfire.
*/
d = uconsdev;
}
#endif
/* compute %cpu for the lwp or process */
pct = 0;
t = p->p_tlist;
do {
break;
} else {
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
}
/*
* If we are looking at an LP64 process, zero out
* the fields that cannot be represented in ILP32.
*/
if (p->p_model != DATAMODEL_ILP32) {
psp->pr_byrssize = 0;
}
}
/*ARGSUSED*/
static int
int cmd,
int flag,
int *rvalp,
{
proc_t *p;
kthread_t *t;
int error;
int zdisp;
/*
* For copyin()/copyout().
*/
union {
int signo;
int nice;
} un32;
/*
* Native objects for internal use.
*/
union {
int signo;
int nice;
long flags;
} un;
/*
* Support for old /proc interface.
*/
}
return (ENOTTY);
/*
* Fail ioctls which are logically "write" requests unless
* the user has write permission.
*/
return (EBADF);
/*
* Perform any necessary copyin() operations before
* locking the process. Helps avoid deadlocks and
* improves performance.
*
* Also, detect invalid ioctl codes here to avoid
* locking a process unnnecessarily.
*
* Also, prepare to allocate space that will be needed below,
* case by case.
*/
error = 0;
switch (cmd) {
case PIOCGETPR:
break;
case PIOCGETU:
break;
case PIOCSTOP:
case PIOCWSTOP:
case PIOCLWPIDS:
case PIOCGTRACE:
case PIOCGENTRY:
case PIOCGEXIT:
case PIOCSRLC:
case PIOCRRLC:
case PIOCSFORK:
case PIOCRFORK:
case PIOCGREG:
case PIOCGFPREG:
case PIOCSTATUS:
case PIOCLSTATUS:
case PIOCPSINFO:
case PIOCMAXSIG:
case PIOCGXREGSIZE:
break;
case PIOCSXREG: /* set extra registers */
case PIOCGXREG: /* get extra registers */
#if defined(__sparc)
thingsize = sizeof (prxregset_t);
#else
thingsize = 0;
#endif
break;
case PIOCACTION:
break;
case PIOCGHOLD:
case PIOCNMAP:
case PIOCMAP:
case PIOCGFAULT:
case PIOCCFAULT:
case PIOCCRED:
case PIOCGROUPS:
case PIOCUSAGE:
case PIOCLUSAGE:
break;
case PIOCOPENPD:
/*
* We will need this below.
* Allocate it now, before locking the process.
*/
break;
case PIOCNAUXV:
case PIOCAUXV:
break;
#if defined(__i386) || defined(__i386_COMPAT)
case PIOCNLDT:
case PIOCLDT:
break;
#endif /* __i386 || __i386_COMPAT */
#if defined(__sparc)
case PIOCGWIN:
thingsize = sizeof (gwindows32_t);
break;
#endif /* __sparc */
case PIOCOPENM: /* open mapped object for reading */
break;
case PIOCRUN: /* make lwp or process runnable */
break;
case PIOCOPENLWP: /* return /proc lwp file descriptor */
break;
case PIOCSTRACE: /* set signal trace mask */
break;
case PIOCSSIG: /* set current signal */
break;
case PIOCKILL: /* send signal */
case PIOCUNKILL: /* delete a signal */
break;
case PIOCNICE: /* set nice priority */
break;
case PIOCSENTRY: /* set syscall entry bit mask */
case PIOCSEXIT: /* set syscall exit bit mask */
break;
case PIOCSET: /* set process flags */
case PIOCRESET: /* reset process flags */
break;
case PIOCSREG: /* set general registers */
break;
case PIOCSFPREG: /* set floating-point registers */
break;
case PIOCSHOLD: /* set signal-hold mask */
break;
case PIOCSFAULT: /* set mask of traced faults */
break;
default:
break;
}
if (error)
return (error);
/*
* If we need kmem_alloc()d space then we allocate it now, before
* grabbing the process lock. Using kmem_alloc(KM_SLEEP) while
* holding the process lock leads to deadlock with the clock thread.
* (The clock thread wakes up the pageout daemon to free up space.
* If the clock thread blocks behind us and we are sleeping waiting
* for space, then space may never become available.)
*/
if (thingsize) {
}
switch (cmd) {
case PIOCPSINFO:
case PIOCGETPR:
case PIOCUSAGE:
case PIOCLUSAGE:
break;
case PIOCSXREG: /* set extra registers */
/*
* perform copyin before grabbing the process lock
*/
if (thing) {
return (EFAULT);
}
}
/* fall through... */
default:
break;
}
if (xpnp)
return (error);
}
/*
*/
t = pcp->prc_thread;
} else {
t = prchoose(p); /* returns locked thread */
thread_unlock(t);
}
}
error = 0;
switch (cmd) {
case PIOCGETPR: /* read struct proc */
{
*prp = *p;
break;
}
case PIOCGETU: /* read u-area */
{
break;
}
case PIOCOPENM: /* open mapped object for reading */
break;
}
/* propenm() called prunlock(pnp) */
break;
case PIOCSTOP: /* stop process or lwp from running */
case PIOCWSTOP: /* wait for process or lwp to stop */
/*
* Can't apply to a system process.
*/
break;
}
/*
* If an lwp is waiting for itself or its process, don't wait.
* The lwp will never see the fact that itself is stopped.
*/
break;
}
break; /* pr_wait_stop() unlocked the process */
else if (PROCESS_NOT_32BIT(p)) {
} else {
/*
*/
thread_unlock(t);
}
break;
case PIOCRUN: /* make lwp or process runnable */
{
/*
* Cannot set an lwp running is it is not stopped.
* Also, no lwp other than the /proc agent lwp can
* be set running so long as the /proc agent lwp exists.
*/
!(t->t_proc_flag & TP_PRSTOP)) ||
break;
}
break;
}
}
break;
}
case PIOCLWPIDS: /* get array of lwp identifiers */
{
int nlwp;
int Nlwp;
}
}
goto startover;
}
do {
--nlwp;
}
*idp = 0;
break;
}
case PIOCOPENLWP: /* return /proc lwp file descriptor */
{
int n;
} else
*rvalp = n;
break;
}
case PIOCOPENPD: /* return /proc page data file descriptor */
{
int n;
if (PROCESS_NOT_32BIT(p)) {
break;
}
}
} else
*rvalp = n;
break;
}
case PIOCGTRACE: /* get signal trace mask */
break;
case PIOCSTRACE: /* set signal trace mask */
if (!sigisempty(&p->p_sigmask))
p->p_proc_flag |= P_PR_TRACE;
p->p_proc_flag &= ~P_PR_TRACE;
}
break;
case PIOCSSIG: /* set current signal */
} else {
}
break;
case PIOCKILL: /* send signal */
break;
case PIOCUNKILL: /* delete a signal */
break;
case PIOCNICE: /* set nice priority */
break;
case PIOCGENTRY: /* get syscall entry bit mask */
case PIOCGEXIT: /* get syscall exit bit mask */
if (cmd == PIOCGENTRY) {
} else {
}
break;
case PIOCSENTRY: /* set syscall entry bit mask */
case PIOCSEXIT: /* set syscall exit bit mask */
break;
case PIOCSRLC: /* obsolete: set running on last /proc close */
break;
case PIOCRRLC: /* obsolete: reset run-on-last-close flag */
break;
case PIOCSFORK: /* obsolete: set inherit-on-fork flag */
break;
case PIOCRFORK: /* obsolete: reset inherit-on-fork flag */
break;
case PIOCSET: /* set process flags */
break;
case PIOCRESET: /* reset process flags */
break;
case PIOCGREG: /* get general registers */
if (PROCESS_NOT_32BIT(p))
else {
/* drop p_lock while touching the lwp's stack */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
if (error == 0 &&
break;
case PIOCSREG: /* set general registers */
if (PROCESS_NOT_32BIT(p))
else {
/* drop p_lock while touching the lwp's stack */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
break;
case PIOCGFPREG: /* get floating-point registers */
if (!prhasfp())
else if (PROCESS_NOT_32BIT(p))
else {
/* drop p_lock while touching the lwp's stack */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
if (error == 0 &&
break;
case PIOCSFPREG: /* set floating-point registers */
if (!prhasfp())
else if (PROCESS_NOT_32BIT(p))
else {
/* drop p_lock while touching the lwp's stack */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
break;
case PIOCGXREGSIZE: /* get the size of the extra registers */
{
int xregsize;
if (prhasx(p)) {
xregsize = prgetprxregsize(p);
} else {
}
break;
}
case PIOCGXREG: /* get extra registers */
if (PROCESS_NOT_32BIT(p))
else if (!prhasx(p))
else {
/* drop p_lock to touch the stack */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
}
if (error == 0 &&
if (thing) {
}
break;
case PIOCSXREG: /* set extra registers */
if (PROCESS_NOT_32BIT(p))
else if (!prhasx(p))
else if (thing) {
/* drop p_lock while touching the lwp's stack */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
if (thing) {
}
break;
case PIOCSTATUS: /* get process/lwp status */
if (PROCESS_NOT_32BIT(p)) {
break;
}
break;
case PIOCLSTATUS: /* get status for process & all lwps */
{
int Nlwp;
int nlwp;
if (PROCESS_NOT_32BIT(p)) {
if (thing) {
}
break;
}
}
}
goto startover;
}
t = p->p_tlist;
do {
--nlwp;
break;
}
case PIOCPSINFO: /* get ps(1) information */
{
oprgetpsinfo32(p, psp,
break;
}
case PIOCMAXSIG: /* get maximum signal number */
{
int n = NSIG-1;
break;
}
case PIOCACTION: /* get signal action structures */
{
if (PROCESS_NOT_32BIT(p))
else {
}
if (error == 0 &&
break;
}
case PIOCGHOLD: /* get signal-hold mask */
break;
case PIOCSHOLD: /* set signal-hold mask */
break;
case PIOCNMAP: /* get number of memory mappings */
{
int n;
n = 0;
else {
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
break;
}
case PIOCMAP: /* get memory map information */
{
error = 0;
} else if (PROCESS_NOT_32BIT(p)) {
} else {
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
/*
* The procfs PIOCMAP ioctl returns an all-zero buffer
* to indicate the end of the prmap[] array.
* Append it to whatever has already been copied out.
*/
if (!error &&
break;
}
case PIOCGFAULT: /* get mask of traced faults */
break;
case PIOCSFAULT: /* set mask of traced faults */
break;
case PIOCCFAULT: /* clear current fault */
lwp->lwp_curflt = 0;
break;
case PIOCCRED: /* get process credentials */
{
mutex_enter(&p->p_crlock);
mutex_exit(&p->p_crlock);
break;
}
case PIOCGROUPS: /* get supplementary groups */
{
mutex_enter(&p->p_crlock);
mutex_exit(&p->p_crlock);
break;
}
case PIOCUSAGE: /* get usage info */
{
/*
* For an lwp file descriptor, return just the lwp usage.
* For a process file descriptor, return total usage,
* all current lwps plus all defunct lwps.
*/
t = pcp->prc_thread;
if (t != NULL)
prgetusage(t, pup);
else
} else {
/*
* Add the usage information for each active lwp.
*/
do {
praddusage(t, pup);
}
}
break;
}
case PIOCLUSAGE: /* get detailed usage info */
{
int Nlwp;
int nlwp;
}
thingsize = sizeof (prhusage_t) +
}
goto startover;
}
/*
* First the summation over defunct lwps.
*/
/*
* Fill one prusage struct for each active lwp.
*/
do {
--nlwp;
upup++;
prgetusage(t, pup);
}
break;
}
case PIOCNAUXV: /* get number of aux vector entries */
{
int n = __KERN_NAUXV_IMPL;
break;
}
{
int i;
if (PROCESS_NOT_32BIT(p)) {
} else {
for (i = 0; i < __KERN_NAUXV_IMPL; i++) {
}
__KERN_NAUXV_IMPL * sizeof (auxv32_t)))
}
break;
}
#if defined(__i386) || defined(__i386_COMPAT)
case PIOCNLDT: /* get number of LDT entries */
{
int n;
mutex_exit(&p->p_lock);
mutex_enter(&p->p_ldtlock);
n = prnldt(p);
mutex_exit(&p->p_ldtlock);
mutex_enter(&p->p_lock);
break;
}
case PIOCLDT: /* get LDT entries */
{
int n;
mutex_exit(&p->p_lock);
mutex_enter(&p->p_ldtlock);
n = prnldt(p);
}
}
mutex_exit(&p->p_ldtlock);
mutex_enter(&p->p_lock);
goto startover;
}
if (n != 0)
mutex_exit(&p->p_ldtlock);
mutex_enter(&p->p_lock);
/* mark the end of the list with a null entry */
break;
}
#endif /* __i386 || __i386_COMPAT */
#if defined(__sparc)
{
if (PROCESS_NOT_32BIT(p)) {
} else {
/* drop p->p_lock while touching the stack */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
break;
}
#endif /* __sparc */
default:
break;
}
return (error);
}
#endif /* _SYSCALL32_IMPL */
/*
* Distinguish "writeable" ioctl requests from others.
*/
static int
isprwrioctl(int cmd)
{
switch (cmd) {
case PIOCSTOP:
case PIOCRUN:
case PIOCSTRACE:
case PIOCSSIG:
case PIOCKILL:
case PIOCUNKILL:
case PIOCNICE:
case PIOCSENTRY:
case PIOCSEXIT:
case PIOCSRLC:
case PIOCRRLC:
case PIOCSREG:
case PIOCSFPREG:
case PIOCSXREG:
case PIOCSHOLD:
case PIOCSFAULT:
case PIOCCFAULT:
case PIOCSFORK:
case PIOCRFORK:
case PIOCSET:
case PIOCRESET:
return (1);
}
return (0);
}
/*
* Map the ioctl() interface run flags to the new interface run flags.
*/
static ulong_t
prmaprunflags(long flags)
{
newflags |= 0x01;
newflags |= 0x02;
newflags |= 0x04;
newflags |= 0x08;
newflags |= 0x10;
return (newflags);
}
/*
* Map the ioctl() interface settable mode flags to the new interface flags.
*/
static long
prmapsetflags(long flags)
{
long newflags = 0;
#define ALLFLAGS \
newflags |= 0x00200000;
newflags |= 0x00400000;
newflags |= 0x00800000;
newflags |= 0x01000000;
newflags |= 0x02000000;
if (flags & PR_PCOMPAT)
newflags |= 0x04000000;
return (newflags);
}
/*
* Apply PIOCRUN options specific to the ioctl() interface.
*/
static void
{
}
if (!sigisempty(&p->p_sigmask))
p->p_proc_flag |= P_PR_TRACE;
p->p_proc_flag &= ~P_PR_TRACE;
}
}
p->p_proc_flag |= P_PR_TRACE;
else if (sigisempty(&p->p_sigmask)) {
p->p_proc_flag &= ~P_PR_TRACE;
}
}
/*
* prsvaddr() must be called before prstep() because
* stepping can depend on the current value of the PC.
* We drop p_lock while touching the lwp's registers (on stack).
*/
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
}
/*
* Common code for PIOCOPENM
* Returns with the process unlocked.
*/
static int
{
int error = 0;
int n;
/*
* By fiat, a system process has no address space.
*/
} else if (cmaddr) {
/*
* We drop p_lock before grabbing the address
* space lock in order to avoid a deadlock with
* the clock thread. The process will not
* disappear and its address space will not
* change because it is marked P_PR_LOCK.
*/
mutex_exit(&p->p_lock);
} else {
}
mutex_enter(&p->p_lock);
} else {
}
if (error == 0) {
if (error) {
} else {
*rvalp = n;
}
}
return (error);
}
/*
* The u-block is mapped in by this routine and unmapped at the end.
*/
void
{
int flags;
flags = 0;
if (t->t_state == TS_STOPPED) {
flags |= PR_STOPPED;
if ((t->t_schedflag & TS_PSTART) == 0)
} else if (VSTOPPED(t)) {
}
if (lwp->lwp_asleep)
if (p->p_proc_flag & P_PR_FORK)
if (p->p_proc_flag & P_PR_RUNLCL)
if (p->p_proc_flag & P_PR_KILLCL)
if (p->p_proc_flag & P_PR_ASYNC)
if (p->p_proc_flag & P_PR_BPTADJ)
if (p->p_proc_flag & P_PR_PTRACE)
flags |= PR_PCOMPAT;
if (t->t_proc_flag & TP_MSACCT)
if (VSTOPPED(t)) {
} else {
}
if (t->t_whystop == PR_FAULTED)
else if (lwp->lwp_curinfo)
}
/*
* Inside local zones, fake zsched's pid as parent pids for
* processes which reference processes outside of the zone.
*/
} else {
}
/*
* Fetch the current instruction, if not a system process.
* We don't attempt this unless the lwp is stopped.
*/
else if (!(flags & PR_STOPPED))
else
/*
* Drop p_lock while touching the lwp's stack.
*/
mutex_exit(&p->p_lock);
int i;
sp->pr_nsysarg = (short)i;
if (t->t_whystop == PR_SYSEXIT &&
i++, auxp++) {
break;
}
}
}
}
mutex_enter(&p->p_lock);
}
/*
* Return old version of information used by ps(1).
*/
void
{
kthread_t *t;
char c, state;
dev_t d;
t = prchoose(p); /* returns locked thread */
else
thread_lock(t);
/* kludge: map thread state enum into process state enum */
if (t == NULL) {
} else {
thread_unlock(t);
}
switch (state) {
default: state = 0; break;
}
switch (state) {
case SSLEEP: c = 'S'; break;
case SRUN: c = 'R'; break;
case SZOMB: c = 'Z'; break;
case SSTOP: c = 'T'; break;
case SIDL: c = 'I'; break;
case SONPROC: c = 'O'; break;
#ifdef SXBRK
case SXBRK: c = 'X'; break;
#endif
default: c = '?'; break;
}
/*
* only export SSYS and SMSACCT; everything else is off-limits to
* userland apps.
*/
mutex_enter(&p->p_crlock);
mutex_exit(&p->p_crlock);
/*
* Inside local zones, fake zsched's pid as parent pids for
* processes which reference processes outside of the zone.
*/
} else {
}
switch (p->p_model) {
case DATAMODEL_ILP32:
break;
case DATAMODEL_LP64:
break;
}
if (wcode)
} else {
if (retval == 0) {
} else {
}
d = cttydev(p);
#ifdef sun
{
/*
* If the controlling terminal is the real
* or workstation console device, map to what the
* user thinks is the console device. Handle case when
* rwsconsdev or rconsdev is set to NODEV for Starfire.
*/
d = uconsdev;
}
#endif
/* compute %cpu for the lwp or process */
pct = 0;
t = p->p_tlist;
do {
break;
} else {
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
}
}
/*
* Return an array of structures with memory map information.
* We allocate here; the caller must deallocate.
* The caller is also responsible to append the zero-filled entry
* that terminates the PIOCMAP output buffer.
*/
static int
{
/*
* Request an initial buffer size that doesn't waste memory
* if the address space has only a small number of segments.
*/
return (0);
do {
continue;
if (prot & PROT_WRITE)
}
return (0);
}
#ifdef _SYSCALL32_IMPL
static int
{
/*
* Request an initial buffer size that doesn't waste memory
* if the address space has only a small number of segments.
*/
return (0);
do {
continue;
if (prot & PROT_WRITE)
}
return (0);
}
#endif /* _SYSCALL32_IMPL */
/*
* Return the size of the old /proc page data file.
*/
{
return (0);
size = sizeof (prpageheader_t);
do {
}
return (size);
}
#ifdef _SYSCALL32_IMPL
{
return (0);
size = sizeof (ioc_prpageheader32_t);
do {
}
return (size);
}
#endif /* _SYSCALL32_IMPL */
/*
* Read old /proc page data information.
*/
int
{
int error;
return (0);
}
return (E2BIG);
}
do {
continue;
/*
* It's possible that the address space can change
* subtlely even though we're holding as->a_lock
* due to the nondeterminism of page_exists() in
* the presence of asychronously flushed pages or
* mapped files whose sizes are changing.
* page_exists() may be called indirectly from
* pr_getprot() by a SEGOP_INCORE() routine.
* If this happens we need to make sure we don't
* overrun the buffer whose size we computed based
* on the initial iteration through the segments.
* Once we've detected an overflow, we need to clean
* up the temporary memory allocated in pr_getprot()
* and retry. If there's a pending signal, we return
* EINTR so that this thread can be dislodged if
* a latent bug causes us to spin indefinitely.
*/
return (EINTR);
goto again;
}
if (prot & PROT_WRITE)
}
return (error);
}
#ifdef _SYSCALL32_IMPL
int
{
int error;
return (0);
}
return (E2BIG);
}
do {
continue;
/*
* It's possible that the address space can change
* subtlely even though we're holding as->a_lock
* due to the nondeterminism of page_exists() in
* the presence of asychronously flushed pages or
* mapped files whose sizes are changing.
* page_exists() may be called indirectly from
* pr_getprot() by a SEGOP_INCORE() routine.
* If this happens we need to make sure we don't
* overrun the buffer whose size we computed based
* on the initial iteration through the segments.
* Once we've detected an overflow, we need to clean
* up the temporary memory allocated in pr_getprot()
* and retry. If there's a pending signal, we return
* EINTR so that this thread can be dislodged if
* a latent bug causes us to spin indefinitely.
*/
return (EINTR);
goto again;
}
if (prot & PROT_WRITE)
}
return (error);
}
#endif /* _SYSCALL32_IMPL */
/*ARGSUSED*/
#ifdef _SYSCALL32_IMPL
int
int cmd,
int flag,
int *rvalp,
{
case DATAMODEL_ILP32:
case DATAMODEL_LP64:
default:
return (ENOSYS);
}
}
#endif /* _SYSCALL32_IMPL */