diff options
Diffstat (limited to 'usr/src/cmd/truss')
-rw-r--r-- | usr/src/cmd/truss/actions.c | 1135 | ||||
-rw-r--r-- | usr/src/cmd/truss/codes.c | 2372 | ||||
-rw-r--r-- | usr/src/cmd/truss/expound.c | 5605 | ||||
-rw-r--r-- | usr/src/cmd/truss/fcall.c | 1911 | ||||
-rw-r--r-- | usr/src/cmd/truss/htbl.c | 262 | ||||
-rw-r--r-- | usr/src/cmd/truss/htbl.h | 95 | ||||
-rw-r--r-- | usr/src/cmd/truss/ipc.c | 417 | ||||
-rw-r--r-- | usr/src/cmd/truss/listopts.c | 661 | ||||
-rw-r--r-- | usr/src/cmd/truss/main.c | 2718 | ||||
-rw-r--r-- | usr/src/cmd/truss/print.c | 2850 | ||||
-rw-r--r-- | usr/src/cmd/truss/print.h | 154 | ||||
-rw-r--r-- | usr/src/cmd/truss/procset.c | 137 | ||||
-rw-r--r-- | usr/src/cmd/truss/proto.h | 154 | ||||
-rw-r--r-- | usr/src/cmd/truss/ramdata.c | 137 | ||||
-rw-r--r-- | usr/src/cmd/truss/ramdata.h | 317 | ||||
-rw-r--r-- | usr/src/cmd/truss/stat.c | 192 | ||||
-rw-r--r-- | usr/src/cmd/truss/systable.c | 1736 | ||||
-rw-r--r-- | usr/src/cmd/truss/systable.h | 74 |
18 files changed, 20927 insertions, 0 deletions
diff --git a/usr/src/cmd/truss/actions.c b/usr/src/cmd/truss/actions.c new file mode 100644 index 0000000..52c75e5 --- /dev/null +++ b/usr/src/cmd/truss/actions.c @@ -0,0 +1,1135 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 1988 AT&T */ +/* All Rights Reserved */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <string.h> +#include <memory.h> +#include <errno.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stack.h> +#include <signal.h> +#include <sys/isa_defs.h> +#include <libproc.h> +#include <priv.h> +#include "ramdata.h" +#include "systable.h" +#include "print.h" +#include "proto.h" + +/* + * Actions to take when process stops. + */ + +/* + * Function prototypes for static routines in this module. + */ +int stopsig(private_t *); +void showpaths(private_t *, const struct systable *); +void showargs(private_t *, int); +void dumpargs(private_t *, long, const char *); + +/* + * Report an lwp to be sleeping (if true). + */ +void +report_sleeping(private_t *pri, int dotrace) +{ + const lwpstatus_t *Lsp = pri->lwpstat; + int sys = Lsp->pr_syscall; + + if (!prismember(&trace, sys) || !dotrace || + !(Lsp->pr_flags & (PR_ASLEEP|PR_VFORKP))) { + /* Make sure we catch sysexit even if we're not tracing it. */ + (void) Psysexit(Proc, sys, TRUE); + return; + } + + pri->length = 0; + pri->Errno = 0; + pri->ErrPriv = PRIV_NONE; + pri->Rval1 = pri->Rval2 = 0; + (void) sysentry(pri, dotrace); + make_pname(pri, 0); + putpname(pri); + timestamp(pri); + pri->length += printf("%s", pri->sys_string); + pri->sys_leng = 0; + *pri->sys_string = '\0'; + pri->length >>= 3; + if (Lsp->pr_flags & PR_VFORKP) + pri->length += 2; + if (pri->length >= 4) + (void) fputc(' ', stdout); + for (; pri->length < 4; pri->length++) + (void) fputc('\t', stdout); + if (Lsp->pr_flags & PR_VFORKP) + (void) fputs("(waiting for child to exit()/exec()...)\n", + stdout); + else + (void) fputs("(sleeping...)\n", stdout); + pri->length = 0; + if (prismember(&verbose, sys)) { + int raw = prismember(&rawout, sys); + pri->Errno = 1; + expound(pri, 0, raw); + pri->Errno = 0; + } + Flush(); +} + +/* + * requested() gets called for these reasons: + * flag == JOBSIG: report nothing; change state to JOBSTOP + * flag == JOBSTOP: report "Continued ..." + * default: report sleeping system call + * + * It returns a new flag: JOBSTOP or SLEEPING or 0. + */ +int +requested(private_t *pri, int flag, int dotrace) +{ + const lwpstatus_t *Lsp = pri->lwpstat; + int sig = Lsp->pr_cursig; + int newflag = 0; + + switch (flag) { + case JOBSIG: + return (JOBSTOP); + + case JOBSTOP: + if (dotrace && !cflag && prismember(&signals, sig)) { + pri->length = 0; + putpname(pri); + timestamp(pri); + (void) printf(" Continued with signal #%d, %s", + sig, signame(pri, sig)); + if (Lsp->pr_action.sa_handler == SIG_DFL) + (void) printf(" [default]"); + else if (Lsp->pr_action.sa_handler == SIG_IGN) + (void) printf(" [ignored]"); + else + (void) printf(" [caught]"); + (void) fputc('\n', stdout); + Flush(); + } + newflag = 0; + break; + + default: + newflag = SLEEPING; + if (!cflag) + report_sleeping(pri, dotrace); + break; + } + + return (newflag); +} + +int +jobcontrol(private_t *pri, int dotrace) +{ + const lwpstatus_t *Lsp = pri->lwpstat; + int sig = stopsig(pri); + + if (sig == 0) + return (0); + + if (dotrace && !cflag && /* not just counting */ + prismember(&signals, sig)) { /* tracing this signal */ + int sys; + + pri->length = 0; + putpname(pri); + timestamp(pri); + (void) printf(" Stopped by signal #%d, %s", + sig, signame(pri, sig)); + if ((Lsp->pr_flags & PR_ASLEEP) && + (sys = Lsp->pr_syscall) > 0 && sys <= PRMAXSYS) + (void) printf(", in %s()", + sysname(pri, sys, getsubcode(pri))); + (void) fputc('\n', stdout); + Flush(); + } + + return (JOBSTOP); +} + +/* + * Return the signal the process stopped on iff process is already stopped on + * PR_JOBCONTROL or is stopped on PR_SIGNALLED or PR_REQUESTED with a current + * signal that will cause a JOBCONTROL stop when the process is set running. + */ +int +stopsig(private_t *pri) +{ + const lwpstatus_t *Lsp = pri->lwpstat; + int sig = 0; + + if (Lsp->pr_flags & PR_STOPPED) { + switch (Lsp->pr_why) { + case PR_JOBCONTROL: + sig = Lsp->pr_what; + if (sig < 0 || sig > PRMAXSIG) + sig = 0; + break; + case PR_SIGNALLED: + case PR_REQUESTED: + if (Lsp->pr_action.sa_handler == SIG_DFL) { + switch (Lsp->pr_cursig) { + case SIGSTOP: + sig = SIGSTOP; + break; + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: + if (!(Lsp->pr_flags & PR_ORPHAN)) + sig = Lsp->pr_cursig; + break; + } + } + break; + } + } + + return (sig); +} + +int +signalled(private_t *pri, int flag, int dotrace) +{ + const lwpstatus_t *Lsp = pri->lwpstat; + int sig = Lsp->pr_what; + + if (sig <= 0 || sig > PRMAXSIG) /* check bounds */ + return (0); + + if (dotrace && cflag) { /* just counting */ + (void) mutex_lock(&count_lock); + Cp->sigcount[sig]++; + (void) mutex_unlock(&count_lock); + } + + if (sig == SIGCONT && (flag == JOBSIG || flag == JOBSTOP)) + flag = requested(pri, JOBSTOP, dotrace); + else if ((flag = jobcontrol(pri, dotrace)) == 0 && + !cflag && dotrace && + prismember(&signals, sig)) { + int sys; + + pri->length = 0; + putpname(pri); + timestamp(pri); + (void) printf(" Received signal #%d, %s", + sig, signame(pri, sig)); + if ((Lsp->pr_flags & PR_ASLEEP) && + (sys = Lsp->pr_syscall) > 0 && sys <= PRMAXSYS) + (void) printf(", in %s()", + sysname(pri, sys, getsubcode(pri))); + if (Lsp->pr_action.sa_handler == SIG_DFL) + (void) printf(" [default]"); + else if (Lsp->pr_action.sa_handler == SIG_IGN) + (void) printf(" [ignored]"); + else + (void) printf(" [caught]"); + (void) fputc('\n', stdout); + if (Lsp->pr_info.si_code != 0 || + Lsp->pr_info.si_pid != 0) + print_siginfo(pri, &Lsp->pr_info); + Flush(); + } + + if (flag == JOBSTOP) + flag = JOBSIG; + return (flag); +} + +int +faulted(private_t *pri, int dotrace) +{ + const lwpstatus_t *Lsp = pri->lwpstat; + int flt = Lsp->pr_what; + + if ((uint_t)flt > PRMAXFAULT || !prismember(&faults, flt) || !dotrace) + return (0); + + (void) mutex_lock(&count_lock); + Cp->fltcount[flt]++; + (void) mutex_unlock(&count_lock); + + if (cflag) /* just counting */ + return (1); + + pri->length = 0; + putpname(pri); + timestamp(pri); + + (void) printf(" Incurred fault #%d, %s %%pc = 0x%.8lX", + flt, proc_fltname(flt, pri->flt_name, sizeof (pri->flt_name)), + (long)Lsp->pr_reg[R_PC]); + + if (flt == FLTPAGE) + (void) printf(" addr = 0x%.8lX", + (long)Lsp->pr_info.si_addr); + (void) fputc('\n', stdout); + if (Lsp->pr_info.si_signo != 0) + print_siginfo(pri, &Lsp->pr_info); + Flush(); + return (1); +} + +/* + * Set up pri->sys_nargs and pri->sys_args[] (syscall args). + */ +void +setupsysargs(private_t *pri, int what) +{ + const lwpstatus_t *Lsp = pri->lwpstat; + int nargs; + int i; + +#if sparc + /* determine whether syscall is indirect */ + pri->sys_indirect = (Lsp->pr_reg[R_G1] == SYS_syscall)? 1 : 0; +#else + pri->sys_indirect = 0; +#endif + + (void) memset(pri->sys_args, 0, sizeof (pri->sys_args)); + if (what != Lsp->pr_syscall) { /* assertion */ + (void) printf("%s\t*** Inconsistent syscall: %d vs %d ***\n", + pri->pname, what, Lsp->pr_syscall); + } + nargs = Lsp->pr_nsysarg; + for (i = 0; + i < nargs && i < sizeof (pri->sys_args) / sizeof (pri->sys_args[0]); + i++) + pri->sys_args[i] = Lsp->pr_sysarg[i]; + pri->sys_nargs = nargs; +} + +#define ISREAD(code) \ + ((code) == SYS_read || (code) == SYS_pread || \ + (code) == SYS_pread64 || (code) == SYS_readv || \ + (code) == SYS_recv || (code) == SYS_recvfrom) +#define ISWRITE(code) \ + ((code) == SYS_write || (code) == SYS_pwrite || \ + (code) == SYS_pwrite64 || (code) == SYS_writev || \ + (code) == SYS_send || (code) == SYS_sendto) + +/* + * Return TRUE iff syscall is being traced. + */ +int +sysentry(private_t *pri, int dotrace) +{ + pid_t pid = Pstatus(Proc)->pr_pid; + const lwpstatus_t *Lsp = pri->lwpstat; + long arg; + int nargs; + int i; + int x; + int len; + char *s; + const struct systable *stp; + int what = Lsp->pr_what; + int subcode; + int istraced; + int raw; + + /* for reporting sleeping system calls */ + if (what == 0 && (Lsp->pr_flags & (PR_ASLEEP|PR_VFORKP))) + what = Lsp->pr_syscall; + + /* protect ourself from operating system error */ + if (what <= 0 || what > PRMAXSYS) + what = 0; + + /* + * Set up the system call arguments (pri->sys_nargs & pri->sys_args[]). + */ + setupsysargs(pri, what); + nargs = pri->sys_nargs; + + /* get systable entry for this syscall */ + subcode = getsubcode(pri); + stp = subsys(what, subcode); + + if (nargs > stp->nargs) + nargs = stp->nargs; + pri->sys_nargs = nargs; + + /* + * Fetch and remember first argument if it's a string, + * or second argument if SYS_openat or SYS_openat64. + */ + pri->sys_valid = FALSE; + if ((nargs > 0 && stp->arg[0] == STG) || + (nargs > 1 && (what == SYS_openat || what == SYS_openat64))) { + long offset; + uint32_t offset32; + + /* + * Special case for exit from exec(). + * The address in pri->sys_args[0] refers to the old process + * image. We must fetch the string from the new image. + */ + if (Lsp->pr_why == PR_SYSEXIT && what == SYS_execve) { + psinfo_t psinfo; + long argv; + auxv_t auxv[32]; + int naux; + + offset = 0; + naux = proc_get_auxv(pid, auxv, 32); + for (i = 0; i < naux; i++) { + if (auxv[i].a_type == AT_SUN_EXECNAME) { + offset = (long)auxv[i].a_un.a_ptr; + break; + } + } + if (offset == 0 && + proc_get_psinfo(pid, &psinfo) == 0) { + argv = (long)psinfo.pr_argv; + if (data_model == PR_MODEL_LP64) + (void) Pread(Proc, &offset, + sizeof (offset), argv); + else { + offset32 = 0; + (void) Pread(Proc, &offset32, + sizeof (offset32), argv); + offset = offset32; + } + } + } else if (stp->arg[0] == STG) { + offset = pri->sys_args[0]; + } else { + offset = pri->sys_args[1]; + } + if ((s = fetchstring(pri, offset, PATH_MAX)) != NULL) { + pri->sys_valid = TRUE; + len = strlen(s); + /* reallocate if necessary */ + while (len >= pri->sys_psize) { + free(pri->sys_path); + pri->sys_path = my_malloc(pri->sys_psize *= 2, + "pathname buffer"); + } + (void) strcpy(pri->sys_path, s); /* remember pathname */ + } + } + + istraced = dotrace && prismember(&trace, what); + raw = prismember(&rawout, what); + + /* force tracing of read/write buffer dump syscalls */ + if (!istraced && nargs > 2) { + int fdp1 = (int)pri->sys_args[0] + 1; + + if (ISREAD(what)) { + if (prismember(&readfd, fdp1)) + istraced = TRUE; + } else if (ISWRITE(what)) { + if (prismember(&writefd, fdp1)) + istraced = TRUE; + } + } + + pri->sys_leng = 0; + if (cflag || !istraced) /* just counting */ + *pri->sys_string = 0; + else { + int argprinted = FALSE; + const char *name; + + name = sysname(pri, what, raw? -1 : subcode); + grow(pri, strlen(name) + 1); + pri->sys_leng = snprintf(pri->sys_string, pri->sys_ssize, + "%s(", name); + for (i = 0; i < nargs; i++) { + arg = pri->sys_args[i]; + x = stp->arg[i]; + + if (!raw && pri->sys_valid && + ((i == 0 && x == STG) || + (i == 1 && (what == SYS_openat || + what == SYS_openat64)))) { /* already fetched */ + if (argprinted) + outstring(pri, ", "); + escape_string(pri, pri->sys_path); + argprinted = TRUE; + } else if (x != NOV && (x != HID || raw)) { + if (argprinted) + outstring(pri, ", "); + if (x == LLO) + (*Print[x])(pri, raw, arg, + pri->sys_args[++i]); + else + (*Print[x])(pri, raw, arg); + argprinted = TRUE; + } + } + outstring(pri, ")"); + } + + return (istraced); +} +#undef ISREAD +#undef ISWRITE + +/* + * sysexit() returns non-zero if anything was printed. + */ +int +sysexit(private_t *pri, int dotrace) +{ + const lwpstatus_t *Lsp = pri->lwpstat; + int what = Lsp->pr_what; + struct syscount *scp; + const struct systable *stp; + int subcode; + int istraced; + int raw; + + /* protect ourself from operating system error */ + if (what <= 0 || what > PRMAXSYS) + return (0); + + /* + * If we aren't supposed to be tracing this one, then + * delete it from the traced signal set. We got here + * because the process was sleeping in an untraced syscall. + */ + if (!prismember(&traceeven, what)) { + (void) Psysexit(Proc, what, FALSE); + return (0); + } + + /* pick up registers & set pri->Errno before anything else */ + pri->Errno = Lsp->pr_errno; + pri->ErrPriv = Lsp->pr_errpriv; + pri->Rval1 = Lsp->pr_rval1; + pri->Rval2 = Lsp->pr_rval2; + + switch (what) { + case SYS_exit: /* these are traced on entry */ + case SYS_lwp_exit: + case SYS_context: + istraced = dotrace && prismember(&trace, what); + break; + case SYS_execve: /* this is normally traced on entry */ + istraced = dotrace && prismember(&trace, what); + if (pri->exec_string && *pri->exec_string) { + if (!cflag && istraced) { /* print exec() string now */ + if (pri->exec_pname[0] != '\0') + (void) fputs(pri->exec_pname, stdout); + timestamp(pri); + (void) fputs(pri->exec_string, stdout); + } + pri->exec_pname[0] = '\0'; + pri->exec_string[0] = '\0'; + break; + } + /* FALLTHROUGH */ + default: + /* we called sysentry() in main() for these */ + if (what == SYS_openat || what == SYS_openat64 || + what == SYS_open || what == SYS_open64) + istraced = dotrace && prismember(&trace, what); + else + istraced = sysentry(pri, dotrace) && dotrace; + pri->length = 0; + if (!cflag && istraced) { + putpname(pri); + timestamp(pri); + pri->length += printf("%s", pri->sys_string); + } + pri->sys_leng = 0; + *pri->sys_string = '\0'; + break; + } + + /* get systable entry for this syscall */ + subcode = getsubcode(pri); + stp = subsys(what, subcode); + + if (cflag && istraced) { + (void) mutex_lock(&count_lock); + scp = Cp->syscount[what]; + if (what == SYS_forksys && subcode >= 3) + scp += subcode - 3; + else if (subcode != -1 && + (what != SYS_openat && what != SYS_openat64 && + what != SYS_open && what != SYS_open64 && + what != SYS_lwp_create)) + scp += subcode; + scp->count++; + accumulate(&scp->stime, &Lsp->pr_stime, &pri->syslast); + accumulate(&Cp->usrtotal, &Lsp->pr_utime, &pri->usrlast); + pri->syslast = Lsp->pr_stime; + pri->usrlast = Lsp->pr_utime; + (void) mutex_unlock(&count_lock); + } + + raw = prismember(&rawout, what); + + if (!cflag && istraced) { + if ((what == SYS_vfork || what == SYS_forksys) && + pri->Errno == 0 && pri->Rval2 != 0) { + pri->length &= ~07; + if (strlen(sysname(pri, what, raw? -1 : subcode)) < 6) { + (void) fputc('\t', stdout); + pri->length += 8; + } + pri->length += + 7 + printf("\t(returning as child ...)"); + } + if (what == SYS_lwp_create && + pri->Errno == 0 && pri->Rval1 == 0) { + pri->length &= ~07; + pri->length += + 7 + printf("\t(returning as new lwp ...)"); + } + if (pri->Errno != 0 || what != SYS_execve) { + /* prepare to print the return code */ + pri->length >>= 3; + if (pri->length >= 6) + (void) fputc(' ', stdout); + for (; pri->length < 6; pri->length++) + (void) fputc('\t', stdout); + } + } + pri->length = 0; + + if (pri->Errno != 0) { /* error in syscall */ + if (istraced) { + if (cflag) + scp->error++; + else { + const char *ename = errname(pri->Errno); + const char *privname; + + (void) printf("Err#%d", pri->Errno); + if (ename != NULL) { + (void) fputc(' ', stdout); + (void) fputs(ename, stdout); + } + switch (pri->ErrPriv) { + case PRIV_NONE: + privname = NULL; + break; + case PRIV_ALL: + privname = "ALL"; + break; + case PRIV_MULTIPLE: + privname = "MULTIPLE"; + break; + case PRIV_ALLZONE: + privname = "ZONE"; + break; + default: + privname = priv_getbynum(pri->ErrPriv); + break; + } + if (privname != NULL) + (void) printf(" [%s]", privname); + + (void) fputc('\n', stdout); + } + } + } else { + /* show arguments on successful exec */ + if (what == SYS_execve) { + if (!cflag && istraced) + showargs(pri, raw); + } else if (!cflag && istraced) { + const char *fmt = NULL; + long rv1 = pri->Rval1; + long rv2 = pri->Rval2; + +#ifdef _LP64 + /* + * 32-bit system calls return 32-bit values. We + * later mask out the upper bits if we want to + * print these as unsigned values. + */ + if (data_model == PR_MODEL_ILP32) { + rv1 = (int)rv1; + rv2 = (int)rv2; + } +#endif + + switch (what) { + case SYS_llseek: + rv1 &= 0xffffffff; + rv2 &= 0xffffffff; +#ifdef _LONG_LONG_LTOH /* first long of a longlong is the low order */ + if (rv2 != 0) { + long temp = rv1; + fmt = "= 0x%lX%.8lX"; + rv1 = rv2; + rv2 = temp; + break; + } +#else /* the other way around */ + if (rv1 != 0) { + fmt = "= 0x%lX%.8lX"; + break; + } + rv1 = rv2; /* ugly */ +#endif + /* FALLTHROUGH */ + case SYS_lseek: + case SYS_ulimit: + if (rv1 & 0xff000000) { +#ifdef _LP64 + if (data_model == PR_MODEL_ILP32) + rv1 &= 0xffffffff; +#endif + fmt = "= 0x%.8lX"; + } + break; + case SYS_sigtimedwait: + if (raw) + /* EMPTY */; + else if ((fmt = rawsigname(pri, rv1)) != NULL) { + rv1 = (long)fmt; /* filthy */ + fmt = "= %s"; + } + break; + case SYS_port: +#ifdef _LP64 + if (data_model == PR_MODEL_LP64) { + rv2 = rv1 & 0xffffffff; + rv1 = rv1 >> 32; + } +#endif + break; + } + + if (fmt == NULL) { + switch (stp->rval[0]) { + case HEX: +#ifdef _LP64 + if (data_model == PR_MODEL_ILP32) + rv1 &= 0xffffffff; +#endif + fmt = "= 0x%.8lX"; + break; + case HHX: +#ifdef _LP64 + if (data_model == PR_MODEL_ILP32) + rv1 &= 0xffffffff; +#endif + fmt = "= 0x%.4lX"; + break; + case OCT: +#ifdef _LP64 + if (data_model == PR_MODEL_ILP32) + rv1 &= 0xffffffff; +#endif + fmt = "= %#lo"; + break; + case UNS: +#ifdef _LP64 + if (data_model == PR_MODEL_ILP32) + rv1 &= 0xffffffff; +#endif + fmt = "= %lu"; + break; + default: + fmt = "= %ld"; + break; + } + } + + (void) printf(fmt, rv1, rv2); + + switch (stp->rval[1]) { + case NOV: + fmt = NULL; + break; + case HEX: +#ifdef _LP64 + if (data_model == PR_MODEL_ILP32) + rv2 &= 0xffffffff; +#endif + fmt = " [0x%.8lX]"; + break; + case HHX: +#ifdef _LP64 + if (data_model == PR_MODEL_ILP32) + rv2 &= 0xffffffff; +#endif + fmt = " [0x%.4lX]"; + break; + case OCT: +#ifdef _LP64 + if (data_model == PR_MODEL_ILP32) + rv2 &= 0xffffffff; +#endif + fmt = " [%#lo]"; + break; + case UNS: +#ifdef _LP64 + if (data_model == PR_MODEL_ILP32) + rv2 &= 0xffffffff; +#endif + fmt = " [%lu]"; + break; + default: + fmt = " [%ld]"; + break; + } + + if (fmt != NULL) + (void) printf(fmt, rv2); + (void) fputc('\n', stdout); + } + + if (what == SYS_vfork || what == SYS_forksys) { + if (pri->Rval2 == 0) /* child was created */ + pri->child = pri->Rval1; + else if (cflag && istraced) /* this is the child */ + scp->count--; + } + if (what == SYS_lwp_create && pri->Rval1 == 0 && + cflag && istraced) /* this is the created lwp */ + scp->count--; + } + +#define ISREAD(code) \ + ((code) == SYS_read || (code) == SYS_pread || (code) == SYS_pread64 || \ + (code) == SYS_recv || (code) == SYS_recvfrom) +#define ISWRITE(code) \ + ((code) == SYS_write || (code) == SYS_pwrite || \ + (code) == SYS_pwrite64 || (code) == SYS_send || (code) == SYS_sendto) + + if (!cflag && istraced) { + int fdp1 = (int)pri->sys_args[0] + 1; /* filedescriptor + 1 */ + + if (raw) { + if (what != SYS_execve) + showpaths(pri, stp); + if (ISREAD(what) || ISWRITE(what)) { + if (pri->iob_buf[0] != '\0') + (void) printf("%s 0x%.8lX: %s\n", + pri->pname, pri->sys_args[1], + pri->iob_buf); + } + } + + /* + * Show buffer contents for read()/pread() or write()/pwrite(). + * IOBSIZE bytes have already been shown; + * don't show them again unless there's more. + */ + if ((ISREAD(what) && pri->Errno == 0 && + prismember(&readfd, fdp1)) || + (ISWRITE(what) && prismember(&writefd, fdp1))) { + long nb = ISWRITE(what) ? pri->sys_args[2] : pri->Rval1; + + if (nb > IOBSIZE) { + /* enter region of lengthy output */ + if (nb > MYBUFSIZ / 4) + Eserialize(); + + showbuffer(pri, pri->sys_args[1], nb); + + /* exit region of lengthy output */ + if (nb > MYBUFSIZ / 4) + Xserialize(); + } + } +#undef ISREAD +#undef ISWRITE + /* + * Do verbose interpretation if requested. + * If buffer contents for read or write have been requested and + * this is a readv() or writev(), force verbose interpretation. + */ + if (prismember(&verbose, what) || + ((what == SYS_readv || what == SYS_recvmsg) && + pri->Errno == 0 && prismember(&readfd, fdp1)) || + ((what == SYS_writev || what == SYS_sendfilev || + what == SYS_sendmsg) && + prismember(&writefd, fdp1))) + expound(pri, pri->Rval1, raw); + } + + return (!cflag && istraced); +} + +void +showpaths(private_t *pri, const struct systable *stp) +{ + int what = pri->lwpstat->pr_what; + int i; + + for (i = 0; i < pri->sys_nargs; i++) { + if (stp->arg[i] == ATC && (int)pri->sys_args[i] == AT_FDCWD) { + (void) printf("%s 0x%.8X: AT_FDCWD\n", + pri->pname, AT_FDCWD); + } else if ((stp->arg[i] == STG) || + (stp->arg[i] == RST && !pri->Errno) || + (stp->arg[i] == RLK && !pri->Errno && pri->Rval1 > 0)) { + long addr = pri->sys_args[i]; + int maxleng = + (stp->arg[i] == RLK)? (int)pri->Rval1 : PATH_MAX; + char *s; + + if (pri->sys_valid && + ((i == 0 && stp->arg[0] == STG) || + (i == 1 && (what == SYS_openat || + what == SYS_openat64)))) /* already fetched */ + s = pri->sys_path; + else + s = fetchstring(pri, addr, + maxleng > PATH_MAX ? PATH_MAX : maxleng); + + if (s != (char *)NULL) + (void) printf("%s 0x%.8lX: \"%s\"\n", + pri->pname, addr, s); + } + } +} + +/* + * Display arguments to successful exec(). + */ +void +showargs(private_t *pri, int raw) +{ + const lwpstatus_t *Lsp = pri->lwpstat; + int nargs; + long ap; + int ptrsize; + int fail; + + pri->length = 0; + ptrsize = (data_model == PR_MODEL_LP64)? 8 : 4; + +#if defined(__i386) || defined(__amd64) /* XX64 */ + ap = (long)Lsp->pr_reg[R_SP]; + fail = (Pread(Proc, &nargs, sizeof (nargs), ap) != sizeof (nargs)); + ap += ptrsize; +#endif /* i386 */ + +#if sparc + if (data_model == PR_MODEL_LP64) { + int64_t xnargs; + ap = (long)(Lsp->pr_reg[R_SP]) + 16 * sizeof (int64_t) + + STACK_BIAS; + fail = (Pread(Proc, &xnargs, sizeof (xnargs), ap) != + sizeof (xnargs)); + nargs = (int)xnargs; + } else { + ap = (long)(Lsp->pr_reg[R_SP]) + 16 * sizeof (int32_t); + fail = (Pread(Proc, &nargs, sizeof (nargs), ap) != + sizeof (nargs)); + } + ap += ptrsize; +#endif /* sparc */ + + if (fail) { + (void) printf("\n%s\t*** Bad argument list? ***\n", pri->pname); + return; + } + + (void) printf(" argc = %d\n", nargs); + if (raw) + showpaths(pri, &systable[SYS_execve]); + + show_cred(pri, FALSE, FALSE); + + if (aflag || eflag) { /* dump args or environment */ + + /* enter region of (potentially) lengthy output */ + Eserialize(); + + if (aflag) /* dump the argument list */ + dumpargs(pri, ap, "argv:"); + ap += (nargs+1) * ptrsize; + if (eflag) /* dump the environment */ + dumpargs(pri, ap, "envp:"); + + /* exit region of lengthy output */ + Xserialize(); + } +} + +void +dumpargs(private_t *pri, long ap, const char *str) +{ + char *string; + unsigned int leng = 0; + int ptrsize; + long arg = 0; + char *argaddr; + char badaddr[32]; + + if (interrupt) + return; + +#ifdef _LP64 + if (data_model == PR_MODEL_LP64) { + argaddr = (char *)&arg; + ptrsize = 8; + } else { +#if defined(_LITTLE_ENDIAN) + argaddr = (char *)&arg; +#else + argaddr = (char *)&arg + 4; +#endif + ptrsize = 4; + } +#else + argaddr = (char *)&arg; + ptrsize = 4; +#endif + putpname(pri); + (void) fputc(' ', stdout); + (void) fputs(str, stdout); + leng += 1 + strlen(str); + + while (!interrupt) { + if (Pread(Proc, argaddr, ptrsize, ap) != ptrsize) { + (void) printf("\n%s\t*** Bad argument list? ***\n", + pri->pname); + return; + } + ap += ptrsize; + + if (arg == 0) + break; + string = fetchstring(pri, arg, PATH_MAX); + if (string == NULL) { + (void) sprintf(badaddr, "BadAddress:0x%.8lX", arg); + string = badaddr; + } + if ((leng += strlen(string)) < 63) { + (void) fputc(' ', stdout); + leng++; + } else { + (void) fputc('\n', stdout); + leng = 0; + putpname(pri); + (void) fputs(" ", stdout); + leng += 2 + strlen(string); + } + (void) fputs(string, stdout); + } + (void) fputc('\n', stdout); +} + +/* + * Display contents of read() or write() buffer. + */ +void +showbuffer(private_t *pri, long offset, long count) +{ + char buffer[320]; + int nbytes; + char *buf; + int n; + + while (count > 0 && !interrupt) { + nbytes = (count < sizeof (buffer))? count : sizeof (buffer); + if ((nbytes = Pread(Proc, buffer, nbytes, offset)) <= 0) + break; + count -= nbytes; + offset += nbytes; + buf = buffer; + while (nbytes > 0 && !interrupt) { + char obuf[65]; + + n = (nbytes < 32)? nbytes : 32; + showbytes(buf, n, obuf); + + putpname(pri); + (void) fputs(" ", stdout); + (void) fputs(obuf, stdout); + (void) fputc('\n', stdout); + nbytes -= n; + buf += n; + } + } +} + +void +showbytes(const char *buf, int n, char *obuf) +{ + int c; + + while (--n >= 0) { + int c1 = '\\'; + int c2; + + switch (c = (*buf++ & 0xff)) { + case '\0': + c2 = '0'; + break; + case '\b': + c2 = 'b'; + break; + case '\t': + c2 = 't'; + break; + case '\n': + c2 = 'n'; + break; + case '\v': + c2 = 'v'; + break; + case '\f': + c2 = 'f'; + break; + case '\r': + c2 = 'r'; + break; + default: + if (isprint(c)) { + c1 = ' '; + c2 = c; + } else { + c1 = c>>4; + c1 += (c1 < 10)? '0' : 'A'-10; + c2 = c&0xf; + c2 += (c2 < 10)? '0' : 'A'-10; + } + break; + } + *obuf++ = (char)c1; + *obuf++ = (char)c2; + } + + *obuf = '\0'; +} diff --git a/usr/src/cmd/truss/codes.c b/usr/src/cmd/truss/codes.c new file mode 100644 index 0000000..069268d --- /dev/null +++ b/usr/src/cmd/truss/codes.c @@ -0,0 +1,2372 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + * Copyright (c) 2014, OmniTI Computer Consulting, Inc. All rights reserved. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <libproc.h> + +#include <ctype.h> +#include <string.h> +#include <sys/dlpi.h> +#include <sys/ipc.h> +#include <sys/ipc_impl.h> +#include <sys/msg.h> +#include <sys/sem.h> +#include <sys/shm.h> +#include <sys/fstyp.h> +#if defined(__i386) || defined(__amd64) +#include <sys/sysi86.h> +#endif /* __i386 */ +#include <sys/unistd.h> +#include <sys/file.h> +#include <sys/tiuser.h> +#include <sys/timod.h> +#include <sys/stream.h> +#include <sys/stropts.h> +#include <sys/termios.h> +#include <sys/termiox.h> +#include <sys/jioctl.h> +#include <sys/filio.h> +#include <fcntl.h> +#include <sys/termio.h> +#include <sys/stermio.h> +#include <sys/ttold.h> +#include <sys/mount.h> +#include <sys/utssys.h> +#include <sys/sysconfig.h> +#include <sys/statvfs.h> +#include <sys/kstat.h> +#include <sys/audio.h> +#include <sys/mixer.h> +#include <sys/cpc_impl.h> +#include <sys/devpoll.h> +#include <sys/strredir.h> +#include <sys/sockio.h> +#include <netinet/ip_mroute.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <sys/ptyvar.h> +#include <sys/des.h> +#include <sys/prnio.h> +#include <sys/dtrace.h> +#include <sys/crypto/ioctladmin.h> +#include <sys/crypto/ioctl.h> +#include <sys/kbio.h> +#include <sys/ptms.h> +#include <sys/aggr.h> +#include <sys/dld.h> +#include <net/simnet.h> +#include <sys/vnic.h> +#include <sys/fs/zfs.h> +#include <inet/kssl/kssl.h> +#include <sys/dkio.h> +#include <sys/fdio.h> +#include <sys/cdio.h> +#include <sys/scsi/impl/uscsi.h> +#include <sys/devinfo_impl.h> +#include <sys/dumpadm.h> +#include <sys/mntio.h> +#include <inet/iptun.h> +#include <sys/zcons.h> +#include <sys/usb/clients/hid/hid.h> +#include <sys/pm.h> +#include <sys/soundcard.h> + +#include "ramdata.h" +#include "proto.h" + +#define FCNTLMIN F_DUPFD +#define FCNTLMAX F_BADFD +const char *const FCNTLname[] = { + "F_DUPFD", + "F_GETFD", + "F_SETFD", + "F_GETFL", + "F_SETFL", + "F_O_GETLK", + "F_SETLK", + "F_SETLKW", + "F_CHKFL", + "F_DUP2FD", + "F_ALLOCSP", + "F_FREESP", + NULL, /* 12 */ + NULL, /* 13 */ + "F_GETLK", + NULL, /* 15 */ + NULL, /* 16 */ + NULL, /* 17 */ + NULL, /* 18 */ + NULL, /* 19 */ + NULL, /* 20 */ + NULL, /* 21 */ + NULL, /* 22 */ + "F_GETOWN", + "F_SETOWN", + "F_REVOKE", + "F_HASREMOTELOCKS", + "F_FREESP64", + NULL, /* 28 */ + NULL, /* 29 */ + NULL, /* 30 */ + NULL, /* 31 */ + NULL, /* 32 */ + "F_GETLK64", + "F_SETLK64", + "F_SETLKW64", + "F_DUP2FD_CLOEXEC", + "F_DUPFD_CLOEXEC", + NULL, /* 38 */ + NULL, /* 39 */ + "F_SHARE", + "F_UNSHARE", + "F_SETLK_NBMAND", + "F_SHARE_NBMAND", + "F_SETLK64_NBMAND", + NULL, /* 45 */ + "F_BADFD" +}; + +#define SYSFSMIN GETFSIND +#define SYSFSMAX GETNFSTYP +const char *const SYSFSname[] = { + "GETFSIND", + "GETFSTYP", + "GETNFSTYP" +}; + +#define SCONFMIN _CONFIG_NGROUPS +#define SCONFMAX _CONFIG_EPHID_MAX +const char *const SCONFname[] = { + "_CONFIG_NGROUPS", /* 2 */ + "_CONFIG_CHILD_MAX", /* 3 */ + "_CONFIG_OPEN_FILES", /* 4 */ + "_CONFIG_POSIX_VER", /* 5 */ + "_CONFIG_PAGESIZE", /* 6 */ + "_CONFIG_CLK_TCK", /* 7 */ + "_CONFIG_XOPEN_VER", /* 8 */ + "_CONFIG_HRESCLK_TCK", /* 9 */ + "_CONFIG_PROF_TCK", /* 10 */ + "_CONFIG_NPROC_CONF", /* 11 */ + "_CONFIG_NPROC_ONLN", /* 12 */ + "_CONFIG_AIO_LISTIO_MAX", /* 13 */ + "_CONFIG_AIO_MAX", /* 14 */ + "_CONFIG_AIO_PRIO_DELTA_MAX", /* 15 */ + "_CONFIG_DELAYTIMER_MAX", /* 16 */ + "_CONFIG_MQ_OPEN_MAX", /* 17 */ + "_CONFIG_MQ_PRIO_MAX", /* 18 */ + "_CONFIG_RTSIG_MAX", /* 19 */ + "_CONFIG_SEM_NSEMS_MAX", /* 20 */ + "_CONFIG_SEM_VALUE_MAX", /* 21 */ + "_CONFIG_SIGQUEUE_MAX", /* 22 */ + "_CONFIG_SIGRT_MIN", /* 23 */ + "_CONFIG_SIGRT_MAX", /* 24 */ + "_CONFIG_TIMER_MAX", /* 25 */ + "_CONFIG_PHYS_PAGES", /* 26 */ + "_CONFIG_AVPHYS_PAGES", /* 27 */ + "_CONFIG_COHERENCY", /* 28 */ + "_CONFIG_SPLIT_CACHE", /* 29 */ + "_CONFIG_ICACHESZ", /* 30 */ + "_CONFIG_DCACHESZ", /* 31 */ + "_CONFIG_ICACHELINESZ", /* 32 */ + "_CONFIG_DCACHELINESZ", /* 33 */ + "_CONFIG_ICACHEBLKSZ", /* 34 */ + "_CONFIG_DCACHEBLKSZ", /* 35 */ + "_CONFIG_DCACHETBLKSZ", /* 36 */ + "_CONFIG_ICACHE_ASSOC", /* 37 */ + "_CONFIG_DCACHE_ASSOC", /* 38 */ + NULL, /* 39 */ + NULL, /* 40 */ + NULL, /* 41 */ + "_CONFIG_MAXPID", /* 42 */ + "_CONFIG_STACK_PROT", /* 43 */ + "_CONFIG_NPROC_MAX", /* 44 */ + "_CONFIG_CPUID_MAX", /* 45 */ + "_CONFIG_SYMLOOP_MAX", /* 46 */ + "_CONFIG_EPHID_MAX", /* 47 */ +}; + +#define PATHCONFMIN _PC_LINK_MAX +#define PATHCONFMAX _PC_XATTR_EXISTS +const char *const PATHCONFname[] = { + "_PC_LINK_MAX", /* 1 */ + "_PC_MAX_CANON", /* 2 */ + "_PC_MAX_INPUT", /* 3 */ + "_PC_NAME_MAX", /* 4 */ + "_PC_PATH_MAX", /* 5 */ + "_PC_PIPE_BUF", /* 6 */ + "_PC_NO_TRUNC", /* 7 */ + "_PC_VDISABLE", /* 8 */ + "_PC_CHOWN_RESTRICTED", /* 9 */ + "_PC_ASYNC_IO", /* 10 */ + "_PC_PRIO_IO", /* 11 */ + "_PC_SYNC_IO", /* 12 */ + "_PC_ALLOC_SIZE_MIN", /* 13 */ + "_PC_REC_INCR_XFER_SIZE", /* 14 */ + "_PC_REC_MAX_XFER_SIZE", /* 15 */ + "_PC_REC_MIN_XFER_SIZE", /* 16 */ + "_PC_REC_XFER_ALIGN", /* 17 */ + "_PC_SYMLINK_MAX", /* 18 */ + "_PC_2_SYMLINKS", /* 19 */ + "_PC_ACL_ENABLED", /* 20 */ + "_PC_MIN_HOLE_SIZE", /* 21 */ + "_PC_CASE_BEHAVIOR", /* 22 */ + "_PC_SATTR_ENABLED", /* 23 */ + "_PC_SATTR_EXISTS", /* 24 */ + "_PC_ACCESS_FILTERING", /* 25 */ + "_PC_TIMESTAMP_RESOLUTION", /* 26 */ + NULL, /* 27 */ + NULL, /* 28 */ + NULL, /* 29 */ + NULL, /* 30 */ + NULL, /* 31 */ + NULL, /* 32 */ + NULL, /* 33 */ + NULL, /* 34 */ + NULL, /* 35 */ + NULL, /* 36 */ + NULL, /* 37 */ + NULL, /* 38 */ + NULL, /* 39 */ + NULL, /* 40 */ + NULL, /* 41 */ + NULL, /* 42 */ + NULL, /* 43 */ + NULL, /* 44 */ + NULL, /* 45 */ + NULL, /* 46 */ + NULL, /* 47 */ + NULL, /* 48 */ + NULL, /* 49 */ + NULL, /* 50 */ + NULL, /* 51 */ + NULL, /* 52 */ + NULL, /* 53 */ + NULL, /* 54 */ + NULL, /* 55 */ + NULL, /* 56 */ + NULL, /* 57 */ + NULL, /* 58 */ + NULL, /* 59 */ + NULL, /* 60 */ + NULL, /* 61 */ + NULL, /* 62 */ + NULL, /* 63 */ + NULL, /* 64 */ + NULL, /* 65 */ + NULL, /* 66 */ + "_PC_FILESIZEBITS", /* 67 */ + NULL, /* 68 */ + NULL, /* 69 */ + NULL, /* 70 */ + NULL, /* 71 */ + NULL, /* 72 */ + NULL, /* 73 */ + NULL, /* 74 */ + NULL, /* 75 */ + NULL, /* 76 */ + NULL, /* 77 */ + NULL, /* 78 */ + NULL, /* 79 */ + NULL, /* 80 */ + NULL, /* 81 */ + NULL, /* 82 */ + NULL, /* 83 */ + NULL, /* 84 */ + NULL, /* 85 */ + NULL, /* 86 */ + NULL, /* 87 */ + NULL, /* 88 */ + NULL, /* 89 */ + NULL, /* 90 */ + NULL, /* 91 */ + NULL, /* 92 */ + NULL, /* 93 */ + NULL, /* 94 */ + NULL, /* 95 */ + NULL, /* 96 */ + NULL, /* 97 */ + NULL, /* 98 */ + NULL, /* 99 */ + "_PC_XATTR_ENABLED", /* 100 */ + "_PC_XATTR_EXISTS", /* 101, _PC_LAST */ +}; + +const struct ioc { + uint_t code; + const char *name; + const char *datastruct; +} ioc[] = { + { (uint_t)TCGETA, "TCGETA", NULL }, + { (uint_t)TCSETA, "TCSETA", NULL }, + { (uint_t)TCSETAW, "TCSETAW", NULL }, + { (uint_t)TCSETAF, "TCSETAF", NULL }, + { (uint_t)TCFLSH, "TCFLSH", NULL }, + { (uint_t)TIOCKBON, "TIOCKBON", NULL }, + { (uint_t)TIOCKBOF, "TIOCKBOF", NULL }, + { (uint_t)KBENABLED, "KBENABLED", NULL }, + { (uint_t)TCGETS, "TCGETS", NULL }, + { (uint_t)TCSETS, "TCSETS", NULL }, + { (uint_t)TCSETSW, "TCSETSW", NULL }, + { (uint_t)TCSETSF, "TCSETSF", NULL }, + { (uint_t)TCXONC, "TCXONC", NULL }, + { (uint_t)TCSBRK, "TCSBRK", NULL }, + { (uint_t)TCDSET, "TCDSET", NULL }, + { (uint_t)RTS_TOG, "RTS_TOG", NULL }, + { (uint_t)TIOCSWINSZ, "TIOCSWINSZ", NULL }, + { (uint_t)TIOCGWINSZ, "TIOCGWINSZ", NULL }, + { (uint_t)TIOCGETD, "TIOCGETD", NULL }, + { (uint_t)TIOCSETD, "TIOCSETD", NULL }, + { (uint_t)TIOCHPCL, "TIOCHPCL", NULL }, + { (uint_t)TIOCGETP, "TIOCGETP", NULL }, + { (uint_t)TIOCSETP, "TIOCSETP", NULL }, + { (uint_t)TIOCSETN, "TIOCSETN", NULL }, + { (uint_t)TIOCEXCL, "TIOCEXCL", NULL }, + { (uint_t)TIOCNXCL, "TIOCNXCL", NULL }, + { (uint_t)TIOCFLUSH, "TIOCFLUSH", NULL }, + { (uint_t)TIOCSETC, "TIOCSETC", NULL }, + { (uint_t)TIOCGETC, "TIOCGETC", NULL }, + { (uint_t)TIOCGPGRP, "TIOCGPGRP", NULL }, + { (uint_t)TIOCSPGRP, "TIOCSPGRP", NULL }, + { (uint_t)TIOCGSID, "TIOCGSID", NULL }, + { (uint_t)TIOCSTI, "TIOCSTI", NULL }, + { (uint_t)TIOCMSET, "TIOCMSET", NULL }, + { (uint_t)TIOCMBIS, "TIOCMBIS", NULL }, + { (uint_t)TIOCMBIC, "TIOCMBIC", NULL }, + { (uint_t)TIOCMGET, "TIOCMGET", NULL }, + { (uint_t)TIOCREMOTE, "TIOCREMOTE", NULL }, + { (uint_t)TIOCSIGNAL, "TIOCSIGNAL", NULL }, + { (uint_t)TIOCSTART, "TIOCSTART", NULL }, + { (uint_t)TIOCSTOP, "TIOCSTOP", NULL }, + { (uint_t)TIOCNOTTY, "TIOCNOTTY", NULL }, + { (uint_t)TIOCSCTTY, "TIOCSCTTY", NULL }, + { (uint_t)TIOCOUTQ, "TIOCOUTQ", NULL }, + { (uint_t)TIOCGLTC, "TIOCGLTC", NULL }, + { (uint_t)TIOCSLTC, "TIOCSLTC", NULL }, + { (uint_t)TIOCCDTR, "TIOCCDTR", NULL }, + { (uint_t)TIOCSDTR, "TIOCSDTR", NULL }, + { (uint_t)TIOCCBRK, "TIOCCBRK", NULL }, + { (uint_t)TIOCSBRK, "TIOCSBRK", NULL }, + { (uint_t)TIOCLGET, "TIOCLGET", NULL }, + { (uint_t)TIOCLSET, "TIOCLSET", NULL }, + { (uint_t)TIOCLBIC, "TIOCLBIC", NULL }, + { (uint_t)TIOCLBIS, "TIOCLBIS", NULL }, + + { (uint_t)TIOCSILOOP, "TIOCSILOOP", NULL }, + { (uint_t)TIOCCILOOP, "TIOCSILOOP", NULL }, + + { (uint_t)TIOCGPPS, "TIOCGPPS", NULL }, + { (uint_t)TIOCSPPS, "TIOCSPPS", NULL }, + { (uint_t)TIOCGPPSEV, "TIOCGPPSEV", NULL }, + + { (uint_t)TIOCPKT, "TIOCPKT", NULL }, /* ptyvar.h */ + { (uint_t)TIOCUCNTL, "TIOCUCNTL", NULL }, + { (uint_t)TIOCTCNTL, "TIOCTCNTL", NULL }, + { (uint_t)TIOCISPACE, "TIOCISPACE", NULL }, + { (uint_t)TIOCISIZE, "TIOCISIZE", NULL }, + { (uint_t)TIOCSSIZE, "TIOCSSIZE", "ttysize" }, + { (uint_t)TIOCGSIZE, "TIOCGSIZE", "ttysize" }, + + /* + * Unfortunately, the DLIOC and LDIOC codes overlap. Since the LDIOC + * ioctls (for xenix compatibility) are far less likely to be used, we + * give preference to DLIOC. + */ + { (uint_t)DLIOCRAW, "DLIOCRAW", NULL }, + { (uint_t)DLIOCNATIVE, "DLIOCNATIVE", NULL }, + { (uint_t)DLIOCIPNETINFO, "DLIOCIPNETINFO", NULL}, + { (uint_t)DLIOCLOWLINK, "DLIOCLOWLINK", NULL }, + + { (uint_t)LDOPEN, "LDOPEN", NULL }, + { (uint_t)LDCLOSE, "LDCLOSE", NULL }, + { (uint_t)LDCHG, "LDCHG", NULL }, + { (uint_t)LDGETT, "LDGETT", NULL }, + { (uint_t)LDSETT, "LDSETT", NULL }, + { (uint_t)LDSMAP, "LDSMAP", NULL }, + { (uint_t)LDGMAP, "LDGMAP", NULL }, + { (uint_t)LDNMAP, "LDNMAP", NULL }, + { (uint_t)TCGETX, "TCGETX", NULL }, + { (uint_t)TCSETX, "TCSETX", NULL }, + { (uint_t)TCSETXW, "TCSETXW", NULL }, + { (uint_t)TCSETXF, "TCSETXF", NULL }, + { (uint_t)FIORDCHK, "FIORDCHK", NULL }, + { (uint_t)FIOCLEX, "FIOCLEX", NULL }, + { (uint_t)FIONCLEX, "FIONCLEX", NULL }, + { (uint_t)FIONREAD, "FIONREAD", NULL }, + { (uint_t)FIONBIO, "FIONBIO", NULL }, + { (uint_t)FIOASYNC, "FIOASYNC", NULL }, + { (uint_t)FIOSETOWN, "FIOSETOWN", NULL }, + { (uint_t)FIOGETOWN, "FIOGETOWN", NULL }, +#ifdef DIOCGETP + { (uint_t)DIOCGETP, "DIOCGETP", NULL }, + { (uint_t)DIOCSETP, "DIOCSETP", NULL }, +#endif +#ifdef DIOCGETC + { (uint_t)DIOCGETC, "DIOCGETC", NULL }, + { (uint_t)DIOCGETB, "DIOCGETB", NULL }, + { (uint_t)DIOCSETE, "DIOCSETE", NULL }, +#endif +#ifdef IFFORMAT + { (uint_t)IFFORMAT, "IFFORMAT", NULL }, + { (uint_t)IFBCHECK, "IFBCHECK", NULL }, + { (uint_t)IFCONFIRM, "IFCONFIRM", NULL }, +#endif +#ifdef LIOCGETP + { (uint_t)LIOCGETP, "LIOCGETP", NULL }, + { (uint_t)LIOCSETP, "LIOCSETP", NULL }, + { (uint_t)LIOCGETS, "LIOCGETS", NULL }, + { (uint_t)LIOCSETS, "LIOCSETS", NULL }, +#endif +#ifdef JBOOT + { (uint_t)JBOOT, "JBOOT", NULL }, + { (uint_t)JTERM, "JTERM", NULL }, + { (uint_t)JMPX, "JMPX", NULL }, +#ifdef JTIMO + { (uint_t)JTIMO, "JTIMO", NULL }, +#endif + { (uint_t)JWINSIZE, "JWINSIZE", NULL }, + { (uint_t)JTIMOM, "JTIMOM", NULL }, + { (uint_t)JZOMBOOT, "JZOMBOOT", NULL }, + { (uint_t)JAGENT, "JAGENT", NULL }, + { (uint_t)JTRUN, "JTRUN", NULL }, + { (uint_t)JXTPROTO, "JXTPROTO", NULL }, +#endif + { (uint_t)KSTAT_IOC_CHAIN_ID, "KSTAT_IOC_CHAIN_ID", NULL }, + { (uint_t)KSTAT_IOC_READ, "KSTAT_IOC_READ", NULL }, + { (uint_t)KSTAT_IOC_WRITE, "KSTAT_IOC_WRITE", NULL }, + { (uint_t)STGET, "STGET", NULL }, + { (uint_t)STSET, "STSET", NULL }, + { (uint_t)STTHROW, "STTHROW", NULL }, + { (uint_t)STWLINE, "STWLINE", NULL }, + { (uint_t)STTSV, "STTSV", NULL }, + { (uint_t)I_NREAD, "I_NREAD", NULL }, + { (uint_t)I_PUSH, "I_PUSH", NULL }, + { (uint_t)I_POP, "I_POP", NULL }, + { (uint_t)I_LOOK, "I_LOOK", NULL }, + { (uint_t)I_FLUSH, "I_FLUSH", NULL }, + { (uint_t)I_SRDOPT, "I_SRDOPT", NULL }, + { (uint_t)I_GRDOPT, "I_GRDOPT", NULL }, + { (uint_t)I_STR, "I_STR", NULL }, + { (uint_t)I_SETSIG, "I_SETSIG", NULL }, + { (uint_t)I_GETSIG, "I_GETSIG", NULL }, + { (uint_t)I_FIND, "I_FIND", NULL }, + { (uint_t)I_LINK, "I_LINK", NULL }, + { (uint_t)I_UNLINK, "I_UNLINK", NULL }, + { (uint_t)I_PEEK, "I_PEEK", NULL }, + { (uint_t)I_FDINSERT, "I_FDINSERT", NULL }, + { (uint_t)I_SENDFD, "I_SENDFD", NULL }, + { (uint_t)I_RECVFD, "I_RECVFD", NULL }, + { (uint_t)I_SWROPT, "I_SWROPT", NULL }, + { (uint_t)I_GWROPT, "I_GWROPT", NULL }, + { (uint_t)I_LIST, "I_LIST", NULL }, + { (uint_t)I_PLINK, "I_PLINK", NULL }, + { (uint_t)I_PUNLINK, "I_PUNLINK", NULL }, + { (uint_t)I_FLUSHBAND, "I_FLUSHBAND", NULL }, + { (uint_t)I_CKBAND, "I_CKBAND", NULL }, + { (uint_t)I_GETBAND, "I_GETBAND", NULL }, + { (uint_t)I_ATMARK, "I_ATMARK", NULL }, + { (uint_t)I_SETCLTIME, "I_SETCLTIME", NULL }, + { (uint_t)I_GETCLTIME, "I_GETCLTIME", NULL }, + { (uint_t)I_CANPUT, "I_CANPUT", NULL }, + { (uint_t)I_ANCHOR, "I_ANCHOR", NULL }, + { (uint_t)_I_CMD, "_I_CMD", NULL }, +#ifdef TI_GETINFO + { (uint_t)TI_GETINFO, "TI_GETINFO", NULL }, + { (uint_t)TI_OPTMGMT, "TI_OPTMGMT", NULL }, + { (uint_t)TI_BIND, "TI_BIND", NULL }, + { (uint_t)TI_UNBIND, "TI_UNBIND", NULL }, +#endif +#ifdef TI_CAPABILITY + { (uint_t)TI_CAPABILITY, "TI_CAPABILITY", NULL }, +#endif +#ifdef TI_GETMYNAME + { (uint_t)TI_GETMYNAME, "TI_GETMYNAME", NULL }, + { (uint_t)TI_GETPEERNAME, "TI_GETPEERNAME", NULL }, + { (uint_t)TI_SETMYNAME, "TI_SETMYNAME", NULL }, + { (uint_t)TI_SETPEERNAME, "TI_SETPEERNAME", NULL }, +#endif +#ifdef V_PREAD + { (uint_t)V_PREAD, "V_PREAD", NULL }, + { (uint_t)V_PWRITE, "V_PWRITE", NULL }, + { (uint_t)V_PDREAD, "V_PDREAD", NULL }, + { (uint_t)V_PDWRITE, "V_PDWRITE", NULL }, +#if !defined(__i386) && !defined(__amd64) + { (uint_t)V_GETSSZ, "V_GETSSZ", NULL }, +#endif /* !__i386 */ +#endif + /* audio */ + { (uint_t)AUDIO_GETINFO, "AUDIO_GETINFO", NULL }, + { (uint_t)AUDIO_SETINFO, "AUDIO_SETINFO", NULL }, + { (uint_t)AUDIO_DRAIN, "AUDIO_DRAIN", NULL }, + { (uint_t)AUDIO_GETDEV, "AUDIO_GETDEV", NULL }, + { (uint_t)AUDIO_DIAG_LOOPBACK, "AUDIO_DIAG_LOOPBACK", NULL }, + { (uint_t)AUDIO_GET_CH_NUMBER, "AUDIO_GET_CH_NUMBER", NULL }, + { (uint_t)AUDIO_GET_CH_TYPE, "AUDIO_GET_CH_TYPE", NULL }, + { (uint_t)AUDIO_GET_NUM_CHS, "AUDIO_GET_NUM_CHS", NULL }, + { (uint_t)AUDIO_GET_AD_DEV, "AUDIO_GET_AD_DEV", NULL }, + { (uint_t)AUDIO_GET_APM_DEV, "AUDIO_GET_APM_DEV", NULL }, + { (uint_t)AUDIO_GET_AS_DEV, "AUDIO_GET_AS_DEV", NULL }, + { (uint_t)AUDIO_MIXER_MULTIPLE_OPEN, "AUDIO_MIXER_MULTIPLE_OPEN", + NULL }, + { (uint_t)AUDIO_MIXER_SINGLE_OPEN, "AUDIO_MIXER_SINGLE_OPEN", + NULL }, + { (uint_t)AUDIO_MIXER_GET_SAMPLE_RATES, "AUDIO_MIXER_GET_SAMPLE_RATES", + NULL }, + { (uint_t)AUDIO_MIXERCTL_GETINFO, "AUDIO_MIXERCTL_GETINFO", + NULL }, + { (uint_t)AUDIO_MIXERCTL_SETINFO, "AUDIO_MIXERCTL_SETINFO", + NULL }, + { (uint_t)AUDIO_MIXERCTL_GET_CHINFO, "AUDIO_MIXERCTL_GET_CHINFO", + NULL }, + { (uint_t)AUDIO_MIXERCTL_SET_CHINFO, "AUDIO_MIXERCTL_SET_CHINFO", + NULL }, + { (uint_t)AUDIO_MIXERCTL_GET_MODE, "AUDIO_MIXERCTL_GET_MODE", + NULL }, + { (uint_t)AUDIO_MIXERCTL_SET_MODE, "AUDIO_MIXERCTL_SET_MODE", + NULL }, + /* new style Boomer (OSS) ioctls */ + { (uint_t)SNDCTL_SYSINFO, "SNDCTL_SYSINFO", NULL }, + { (uint_t)SNDCTL_AUDIOINFO, "SNDCTL_AUDIOINFO", NULL }, + { (uint_t)SNDCTL_AUDIOINFO_EX, "SNDCTL_AUDIOINFO_EX", NULL }, + { (uint_t)SNDCTL_MIXERINFO, "SNDCTL_MIXERINFO", NULL }, + { (uint_t)SNDCTL_CARDINFO, "SNDCTL_CARDINFO", NULL }, + { (uint_t)SNDCTL_ENGINEINFO, "SNDCTL_ENGINEINFO", NULL }, + { (uint_t)SNDCTL_MIX_NRMIX, "SNDCTL_MIX_NRMIX", NULL }, + { (uint_t)SNDCTL_MIX_NREXT, "SNDCTL_MIX_NREXT", NULL }, + { (uint_t)SNDCTL_MIX_EXTINFO, "SNDCTL_MIX_EXTINFO", NULL }, + { (uint_t)SNDCTL_MIX_READ, "SNDCTL_MIX_READ", NULL }, + { (uint_t)SNDCTL_MIX_WRITE, "SNDCTL_MIX_WRITE", NULL }, + { (uint_t)SNDCTL_MIX_ENUMINFO, "SNDCTL_MIX_ENUMINFO", NULL }, + { (uint_t)SNDCTL_MIX_DESCRIPTION, "SNDCTL_MIX_DESCRIPTION", + NULL }, + { (uint_t)SNDCTL_SETSONG, "SNDCTL_SETSONG", NULL }, + { (uint_t)SNDCTL_GETSONG, "SNDCTL_GETSONG", NULL }, + { (uint_t)SNDCTL_SETNAME, "SNDCTL_SETNAME", NULL }, + { (uint_t)SNDCTL_SETLABEL, "SNDCTL_SETLABEL", NULL }, + { (uint_t)SNDCTL_GETLABEL, "SNDCTL_GETLABEL", NULL }, + { (uint_t)SNDCTL_DSP_HALT, "SNDCTL_DSP_HALT", NULL }, + { (uint_t)SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET", NULL }, + { (uint_t)SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC", NULL }, + { (uint_t)SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED", NULL }, + { (uint_t)SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO", NULL }, + { (uint_t)SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE", + NULL }, + { (uint_t)SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE", + NULL }, + { (uint_t)SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS", NULL }, + { (uint_t)SNDCTL_DSP_POST, "SNDCTL_DSP_POST", NULL }, + { (uint_t)SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE", NULL }, + { (uint_t)SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT", + NULL }, + { (uint_t)SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS", NULL }, + { (uint_t)SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT", NULL }, + { (uint_t)SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE", NULL }, + { (uint_t)SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE", NULL }, + { (uint_t)SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_CAPS", NULL }, + { (uint_t)SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER", + NULL }, + { (uint_t)SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER", + NULL }, + { (uint_t)SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR", NULL }, + { (uint_t)SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR", NULL }, + { (uint_t)SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO", NULL }, + { (uint_t)SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX", NULL }, + { (uint_t)SNDCTL_DSP_PROFILE, "SNDCTL_DSP_PROFILE", NULL }, + { (uint_t)SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY", NULL }, + { (uint_t)SNDCTL_DSP_GETPLAYVOL, "SNDCTL_DSP_GETPLAYVOL", + NULL }, + { (uint_t)SNDCTL_DSP_SETPLAYVOL, "SNDCTL_DSP_SETPLAYVOL", + NULL }, + { (uint_t)SNDCTL_DSP_GETERROR, "SNDCTL_DSP_GETERROR", NULL }, + { (uint_t)SNDCTL_DSP_READCTL, "SNDCTL_DSP_READCTL", NULL }, + { (uint_t)SNDCTL_DSP_WRITECTL, "SNDCTL_DSP_WRITECTL", NULL }, + { (uint_t)SNDCTL_DSP_SYNCGROUP, "SNDCTL_DSP_SYNCGROUP", NULL }, + { (uint_t)SNDCTL_DSP_SYNCSTART, "SNDCTL_DSP_SYNCSTART", NULL }, + { (uint_t)SNDCTL_DSP_COOKEDMODE, "SNDCTL_DSP_COOKEDMODE", + NULL }, + { (uint_t)SNDCTL_DSP_SILENCE, "SNDCTL_DSP_SILENCE", NULL }, + { (uint_t)SNDCTL_DSP_SKIP, "SNDCTL_DSP_SKIP", NULL }, + { (uint_t)SNDCTL_DSP_HALT_INPUT, "SNDCTL_DSP_HALT_INPUT", + NULL }, + { (uint_t)SNDCTL_DSP_HALT_OUTPUT, "SNDCTL_DSP_HALT_OUTPUT", + NULL }, + { (uint_t)SNDCTL_DSP_LOW_WATER, "SNDCTL_DSP_LOW_WATER", NULL }, + { (uint_t)SNDCTL_DSP_CURRENT_OPTR, "SNDCTL_DSP_CURRENT_OPTR", + NULL }, + { (uint_t)SNDCTL_DSP_CURRENT_IPTR, "SNDCTL_DSP_CURRENT_IPTR", + NULL }, + { (uint_t)SNDCTL_DSP_GET_RECSRC_NAMES, "SNDCTL_DSP_GET_RECSRC_NAMES", + NULL }, + { (uint_t)SNDCTL_DSP_GET_RECSRC, "SNDCTL_DSP_GET_RECSRC", + NULL }, + { (uint_t)SNDCTL_DSP_SET_RECSRC, "SNDCTL_DSP_SET_RECSRC", + NULL }, + { (uint_t)SNDCTL_DSP_GET_PLAYTGT_NAMES, "SNDCTL_DSP_GET_PLAYTGT_NAMES", + NULL }, + { (uint_t)SNDCTL_DSP_GET_PLAYTGT, "SNDCTL_DSP_GET_PLAYTGT", + NULL }, + { (uint_t)SNDCTL_DSP_SET_PLAYTGT, "SNDCTL_DSP_SET_PLAYTGT", + NULL }, + { (uint_t)SNDCTL_DSP_GETRECVOL, "SNDCTL_DSP_GETRECVOL", + NULL }, + { (uint_t)SNDCTL_DSP_SETRECVOL, "SNDCTL_DSP_SETRECVOL", + NULL }, + { (uint_t)SNDCTL_DSP_GET_CHNORDER, "SNDCTL_DSP_GET_CHNORDER", + NULL }, + { (uint_t)SNDCTL_DSP_SET_CHNORDER, "SNDCTL_DSP_SET_CHNORDER", + NULL }, + { (uint_t)SNDCTL_DSP_GETIPEAKS, "SNDCTL_DSP_GETIPEAKS", NULL }, + { (uint_t)SNDCTL_DSP_GETOPEAKS, "SNDCTL_DSP_GETOPEAKS", NULL }, + { (uint_t)SNDCTL_DSP_POLICY, "SNDCTL_DSP_POLICY", NULL }, + { (uint_t)SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK", + NULL }, + { (uint_t)SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL", + NULL }, + { (uint_t)SOUND_MIXER_READ_VOLUME, "SOUND_MIXER_READ_VOLUME", + NULL }, + { (uint_t)SOUND_MIXER_READ_OGAIN, "SOUND_MIXER_READ_OGAIN", + NULL }, + { (uint_t)SOUND_MIXER_READ_PCM, "SOUND_MIXER_READ_PCM", NULL }, + { (uint_t)SOUND_MIXER_READ_IGAIN, "SOUND_MIXER_READ_IGAIN", + NULL }, + { (uint_t)SOUND_MIXER_READ_RECLEV, "SOUND_MIXER_READ_RECLEV", + NULL }, + { (uint_t)SOUND_MIXER_READ_RECSRC, "SOUND_MIXER_READ_RECSRC", + NULL }, + { (uint_t)SOUND_MIXER_READ_DEVMASK, "SOUND_MIXER_READ_DEVMASK", + NULL }, + { (uint_t)SOUND_MIXER_READ_RECMASK, "SOUND_MIXER_READ_RECMASK", + NULL }, + { (uint_t)SOUND_MIXER_READ_CAPS, "SOUND_MIXER_READ_CAPS", + NULL }, + { (uint_t)SOUND_MIXER_READ_STEREODEVS, "SOUND_MIXER_READ_STEREODEVS", + NULL }, + { (uint_t)SOUND_MIXER_READ_RECGAIN, "SOUND_MIXER_READ_RECGAIN", + NULL }, + { (uint_t)SOUND_MIXER_READ_MONGAIN, "SOUND_MIXER_READ_MONGAIN", + NULL }, + { (uint_t)SOUND_MIXER_WRITE_VOLUME, "SOUND_MIXER_WRITE_VOLUME", + NULL }, + { (uint_t)SOUND_MIXER_WRITE_OGAIN, "SOUND_MIXER_WRITE_OGAIN", + NULL }, + { (uint_t)SOUND_MIXER_WRITE_PCM, "SOUND_MIXER_WRITE_PCM", + NULL }, + { (uint_t)SOUND_MIXER_WRITE_IGAIN, "SOUND_MIXER_WRITE_IGAIN", + NULL }, + { (uint_t)SOUND_MIXER_WRITE_RECLEV, "SOUND_MIXER_WRITE_RECLEV", + NULL }, + { (uint_t)SOUND_MIXER_WRITE_RECSRC, "SOUND_MIXER_WRITE_RECSRC", + NULL }, + { (uint_t)SOUND_MIXER_WRITE_RECGAIN, "SOUND_MIXER_WRITE_RECGAIN", + NULL }, + { (uint_t)SOUND_MIXER_WRITE_MONGAIN, "SOUND_MIXER_WRITE_MONGAIN", + NULL }, + + /* STREAMS redirection ioctls */ + { (uint_t)SRIOCSREDIR, "SRIOCSREDIR", NULL }, + { (uint_t)SRIOCISREDIR, "SRIOCISREDIR", NULL }, + { (uint_t)CPCIO_BIND, "CPCIO_BIND", NULL }, + { (uint_t)CPCIO_SAMPLE, "CPCIO_SAMPLE", NULL }, + { (uint_t)CPCIO_RELE, "CPCIO_RELE", NULL }, + /* /dev/poll ioctl() control codes */ + { (uint_t)DP_POLL, "DP_POLL", NULL }, + { (uint_t)DP_ISPOLLED, "DP_ISPOLLED", NULL }, + /* the old /proc ioctl() control codes */ +#define PIOC ('q'<<8) + { (uint_t)(PIOC|1), "PIOCSTATUS", NULL }, + { (uint_t)(PIOC|2), "PIOCSTOP", NULL }, + { (uint_t)(PIOC|3), "PIOCWSTOP", NULL }, + { (uint_t)(PIOC|4), "PIOCRUN", NULL }, + { (uint_t)(PIOC|5), "PIOCGTRACE", NULL }, + { (uint_t)(PIOC|6), "PIOCSTRACE", NULL }, + { (uint_t)(PIOC|7), "PIOCSSIG", NULL }, + { (uint_t)(PIOC|8), "PIOCKILL", NULL }, + { (uint_t)(PIOC|9), "PIOCUNKILL", NULL }, + { (uint_t)(PIOC|10), "PIOCGHOLD", NULL }, + { (uint_t)(PIOC|11), "PIOCSHOLD", NULL }, + { (uint_t)(PIOC|12), "PIOCMAXSIG", NULL }, + { (uint_t)(PIOC|13), "PIOCACTION", NULL }, + { (uint_t)(PIOC|14), "PIOCGFAULT", NULL }, + { (uint_t)(PIOC|15), "PIOCSFAULT", NULL }, + { (uint_t)(PIOC|16), "PIOCCFAULT", NULL }, + { (uint_t)(PIOC|17), "PIOCGENTRY", NULL }, + { (uint_t)(PIOC|18), "PIOCSENTRY", NULL }, + { (uint_t)(PIOC|19), "PIOCGEXIT", NULL }, + { (uint_t)(PIOC|20), "PIOCSEXIT", NULL }, + { (uint_t)(PIOC|21), "PIOCSFORK", NULL }, + { (uint_t)(PIOC|22), "PIOCRFORK", NULL }, + { (uint_t)(PIOC|23), "PIOCSRLC", NULL }, + { (uint_t)(PIOC|24), "PIOCRRLC", NULL }, + { (uint_t)(PIOC|25), "PIOCGREG", NULL }, + { (uint_t)(PIOC|26), "PIOCSREG", NULL }, + { (uint_t)(PIOC|27), "PIOCGFPREG", NULL }, + { (uint_t)(PIOC|28), "PIOCSFPREG", NULL }, + { (uint_t)(PIOC|29), "PIOCNICE", NULL }, + { (uint_t)(PIOC|30), "PIOCPSINFO", NULL }, + { (uint_t)(PIOC|31), "PIOCNMAP", NULL }, + { (uint_t)(PIOC|32), "PIOCMAP", NULL }, + { (uint_t)(PIOC|33), "PIOCOPENM", NULL }, + { (uint_t)(PIOC|34), "PIOCCRED", NULL }, + { (uint_t)(PIOC|35), "PIOCGROUPS", NULL }, + { (uint_t)(PIOC|36), "PIOCGETPR", NULL }, + { (uint_t)(PIOC|37), "PIOCGETU", NULL }, + { (uint_t)(PIOC|38), "PIOCSET", NULL }, + { (uint_t)(PIOC|39), "PIOCRESET", NULL }, + { (uint_t)(PIOC|43), "PIOCUSAGE", NULL }, + { (uint_t)(PIOC|44), "PIOCOPENPD", NULL }, + { (uint_t)(PIOC|45), "PIOCLWPIDS", NULL }, + { (uint_t)(PIOC|46), "PIOCOPENLWP", NULL }, + { (uint_t)(PIOC|47), "PIOCLSTATUS", NULL }, + { (uint_t)(PIOC|48), "PIOCLUSAGE", NULL }, + { (uint_t)(PIOC|49), "PIOCNAUXV", NULL }, + { (uint_t)(PIOC|50), "PIOCAUXV", NULL }, + { (uint_t)(PIOC|51), "PIOCGXREGSIZE", NULL }, + { (uint_t)(PIOC|52), "PIOCGXREG", NULL }, + { (uint_t)(PIOC|53), "PIOCSXREG", NULL }, + { (uint_t)(PIOC|101), "PIOCGWIN", NULL }, + { (uint_t)(PIOC|103), "PIOCNLDT", NULL }, + { (uint_t)(PIOC|104), "PIOCLDT", NULL }, + + /* ioctl's applicable on sockets */ + { (uint_t)SIOCSHIWAT, "SIOCSHIWAT", NULL }, + { (uint_t)SIOCGHIWAT, "SIOCGHIWAT", NULL }, + { (uint_t)SIOCSLOWAT, "SIOCSLOWAT", NULL }, + { (uint_t)SIOCGLOWAT, "SIOCGLOWAT", NULL }, + { (uint_t)SIOCATMARK, "SIOCATMARK", NULL }, + { (uint_t)SIOCSPGRP, "SIOCSPGRP", NULL }, + { (uint_t)SIOCGPGRP, "SIOCGPGRP", NULL }, + { (uint_t)SIOCADDRT, "SIOCADDRT", "rtentry" }, + { (uint_t)SIOCDELRT, "SIOCDELRT", "rtentry" }, + { (uint_t)SIOCGETVIFCNT, "SIOCGETVIFCNT", "sioc_vif_req" }, + { (uint_t)SIOCGETSGCNT, "SIOCGETSGCNT", "sioc_sg_req" }, + { (uint_t)SIOCGETLSGCNT, "SIOCGETLSGCNT", "sioc_lsg_req" }, + { (uint_t)SIOCSIFADDR, "SIOCSIFADDR", "ifreq" }, + { (uint_t)SIOCGIFADDR, "SIOCGIFADDR", "ifreq" }, + { (uint_t)SIOCSIFDSTADDR, "SIOCSIFDSTADDR", "ifreq" }, + { (uint_t)SIOCGIFDSTADDR, "SIOCGIFDSTADDR", "ifreq" }, + { (uint_t)SIOCSIFFLAGS, "SIOCSIFFLAGS", "ifreq" }, + { (uint_t)SIOCGIFFLAGS, "SIOCGIFFLAGS", "ifreq" }, + { (uint_t)SIOCSIFMEM, "SIOCSIFMEM", "ifreq" }, + { (uint_t)SIOCGIFMEM, "SIOCGIFMEM", "ifreq" }, + { (uint_t)SIOCGIFCONF, "SIOCGIFCONF", "ifconf" }, + { (uint_t)SIOCSIFMTU, "SIOCSIFMTU", "ifreq" }, + { (uint_t)SIOCGIFMTU, "SIOCGIFMTU", "ifreq" }, + { (uint_t)SIOCGIFBRDADDR, "SIOCGIFBRDADDR", "ifreq" }, + { (uint_t)SIOCSIFBRDADDR, "SIOCSIFBRDADDR", "ifreq" }, + { (uint_t)SIOCGIFNETMASK, "SIOCGIFNETMASK", "ifreq" }, + { (uint_t)SIOCSIFNETMASK, "SIOCSIFNETMASK", "ifreq" }, + { (uint_t)SIOCGIFMETRIC, "SIOCGIFMETRIC", "ifreq" }, + { (uint_t)SIOCSIFMETRIC, "SIOCSIFMETRIC", "ifreq" }, + { (uint_t)SIOCSARP, "SIOCSARP", "arpreq" }, + { (uint_t)SIOCGARP, "SIOCGARP", "arpreq" }, + { (uint_t)SIOCDARP, "SIOCDARP", "arpreq" }, + { (uint_t)SIOCUPPER, "SIOCUPPER", "ifreq" }, + { (uint_t)SIOCLOWER, "SIOCLOWER", "ifreq" }, + { (uint_t)SIOCSETSYNC, "SIOCSETSYNC", "ifreq" }, + { (uint_t)SIOCGETSYNC, "SIOCGETSYNC", "ifreq" }, + { (uint_t)SIOCSSDSTATS, "SIOCSSDSTATS", "ifreq" }, + { (uint_t)SIOCSSESTATS, "SIOCSSESTATS", "ifreq" }, + { (uint_t)SIOCSPROMISC, "SIOCSPROMISC", NULL }, + { (uint_t)SIOCADDMULTI, "SIOCADDMULTI", "ifreq" }, + { (uint_t)SIOCDELMULTI, "SIOCDELMULTI", "ifreq" }, + { (uint_t)SIOCGETNAME, "SIOCGETNAME", "sockaddr" }, + { (uint_t)SIOCGETPEER, "SIOCGETPEER", "sockaddr" }, + { (uint_t)IF_UNITSEL, "IF_UNITSEL", NULL }, + { (uint_t)SIOCXPROTO, "SIOCXPROTO", NULL }, + { (uint_t)SIOCIFDETACH, "SIOCIFDETACH", "ifreq" }, + { (uint_t)SIOCGENPSTATS, "SIOCGENPSTATS", "ifreq" }, + { (uint_t)SIOCX25XMT, "SIOCX25XMT", "ifreq" }, + { (uint_t)SIOCX25RCV, "SIOCX25RCV", "ifreq" }, + { (uint_t)SIOCX25TBL, "SIOCX25TBL", "ifreq" }, + { (uint_t)SIOCSLGETREQ, "SIOCSLGETREQ", "ifreq" }, + { (uint_t)SIOCSLSTAT, "SIOCSLSTAT", "ifreq" }, + { (uint_t)SIOCSIFNAME, "SIOCSIFNAME", "ifreq" }, + { (uint_t)SIOCGENADDR, "SIOCGENADDR", "ifreq" }, + { (uint_t)SIOCGIFNUM, "SIOCGIFNUM", NULL }, + { (uint_t)SIOCGIFMUXID, "SIOCGIFMUXID", "ifreq" }, + { (uint_t)SIOCSIFMUXID, "SIOCSIFMUXID", "ifreq" }, + { (uint_t)SIOCGIFINDEX, "SIOCGIFINDEX", "ifreq" }, + { (uint_t)SIOCSIFINDEX, "SIOCSIFINDEX", "ifreq" }, + { (uint_t)SIOCLIFREMOVEIF, "SIOCLIFREMOVEIF", "lifreq" }, + { (uint_t)SIOCLIFADDIF, "SIOCLIFADDIF", "lifreq" }, + { (uint_t)SIOCSLIFADDR, "SIOCSLIFADDR", "lifreq" }, + { (uint_t)SIOCGLIFADDR, "SIOCGLIFADDR", "lifreq" }, + { (uint_t)SIOCSLIFDSTADDR, "SIOCSLIFDSTADDR", "lifreq" }, + { (uint_t)SIOCGLIFDSTADDR, "SIOCGLIFDSTADDR", "lifreq" }, + { (uint_t)SIOCSLIFFLAGS, "SIOCSLIFFLAGS", "lifreq" }, + { (uint_t)SIOCGLIFFLAGS, "SIOCGLIFFLAGS", "lifreq" }, + { (uint_t)SIOCGLIFCONF, "SIOCGLIFCONF", "lifconf" }, + { (uint_t)SIOCSLIFMTU, "SIOCSLIFMTU", "lifreq" }, + { (uint_t)SIOCGLIFMTU, "SIOCGLIFMTU", "lifreq" }, + { (uint_t)SIOCGLIFBRDADDR, "SIOCGLIFBRDADDR", "lifreq" }, + { (uint_t)SIOCSLIFBRDADDR, "SIOCSLIFBRDADDR", "lifreq" }, + { (uint_t)SIOCGLIFNETMASK, "SIOCGLIFNETMASK", "lifreq" }, + { (uint_t)SIOCSLIFNETMASK, "SIOCSLIFNETMASK", "lifreq" }, + { (uint_t)SIOCGLIFMETRIC, "SIOCGLIFMETRIC", "lifreq" }, + { (uint_t)SIOCSLIFMETRIC, "SIOCSLIFMETRIC", "lifreq" }, + { (uint_t)SIOCSLIFNAME, "SIOCSLIFNAME", "lifreq" }, + { (uint_t)SIOCGLIFNUM, "SIOCGLIFNUM", "lifnum" }, + { (uint_t)SIOCGLIFMUXID, "SIOCGLIFMUXID", "lifreq" }, + { (uint_t)SIOCSLIFMUXID, "SIOCSLIFMUXID", "lifreq" }, + { (uint_t)SIOCGLIFINDEX, "SIOCGLIFINDEX", "lifreq" }, + { (uint_t)SIOCSLIFINDEX, "SIOCSLIFINDEX", "lifreq" }, + { (uint_t)SIOCSLIFTOKEN, "SIOCSLIFTOKEN", "lifreq" }, + { (uint_t)SIOCGLIFTOKEN, "SIOCGLIFTOKEN", "lifreq" }, + { (uint_t)SIOCSLIFSUBNET, "SIOCSLIFSUBNET", "lifreq" }, + { (uint_t)SIOCGLIFSUBNET, "SIOCGLIFSUBNET", "lifreq" }, + { (uint_t)SIOCSLIFLNKINFO, "SIOCSLIFLNKINFO", "lifreq" }, + { (uint_t)SIOCGLIFLNKINFO, "SIOCGLIFLNKINFO", "lifreq" }, + { (uint_t)SIOCLIFDELND, "SIOCLIFDELND", "lifreq" }, + { (uint_t)SIOCLIFGETND, "SIOCLIFGETND", "lifreq" }, + { (uint_t)SIOCLIFSETND, "SIOCLIFSETND", "lifreq" }, + { (uint_t)SIOCTMYADDR, "SIOCTMYADDR", "sioc_addrreq" }, + { (uint_t)SIOCTONLINK, "SIOCTONLINK", "sioc_addrreq" }, + { (uint_t)SIOCTMYSITE, "SIOCTMYSITE", "sioc_addrreq" }, + { (uint_t)SIOCGLIFBINDING, "SIOCGLIFBINDING", "lifreq" }, + { (uint_t)SIOCSLIFGROUPNAME, "SIOCSLIFGROUPNAME", "lifreq" }, + { (uint_t)SIOCGLIFGROUPNAME, "SIOCGLIFGROUPNAME", "lifreq" }, + { (uint_t)SIOCGLIFGROUPINFO, "SIOCGLIFGROUPINFO", "lifgroupinfo" }, + { (uint_t)SIOCGDSTINFO, "SIOCGDSTINFO", NULL }, + { (uint_t)SIOCGIP6ADDRPOLICY, "SIOCGIP6ADDRPOLICY", NULL }, + { (uint_t)SIOCSIP6ADDRPOLICY, "SIOCSIP6ADDRPOLICY", NULL }, + { (uint_t)SIOCSXARP, "SIOCSXARP", "xarpreq" }, + { (uint_t)SIOCGXARP, "SIOCGXARP", "xarpreq" }, + { (uint_t)SIOCDXARP, "SIOCDXARP", "xarpreq" }, + { (uint_t)SIOCGLIFZONE, "SIOCGLIFZONE", "lifreq" }, + { (uint_t)SIOCSLIFZONE, "SIOCSLIFZONE", "lifreq" }, + { (uint_t)SIOCSCTPSOPT, "SIOCSCTPSOPT", NULL }, + { (uint_t)SIOCSCTPGOPT, "SIOCSCTPGOPT", NULL }, + { (uint_t)SIOCSCTPPEELOFF, "SIOPCSCTPPEELOFF", "int" }, + { (uint_t)SIOCGLIFUSESRC, "SIOCGLIFUSESRC", "lifreq" }, + { (uint_t)SIOCSLIFUSESRC, "SIOCSLIFUSESRC", "lifreq" }, + { (uint_t)SIOCGLIFSRCOF, "SIOCGLIFSRCOF", "lifsrcof" }, + { (uint_t)SIOCGMSFILTER, "SIOCGMSFILTER", "group_filter" }, + { (uint_t)SIOCSMSFILTER, "SIOCSMSFILTER", "group_filter" }, + { (uint_t)SIOCGIPMSFILTER, "SIOCGIPMSFILTER", "ip_msfilter" }, + { (uint_t)SIOCSIPMSFILTER, "SIOCSIPMSFILTER", "ip_msfilter" }, + { (uint_t)SIOCGLIFDADSTATE, "SIOCGLIFDADSTATE", "lifreq" }, + { (uint_t)SIOCSLIFPREFIX, "SIOCSLIFPREFIX", "lifreq" }, + { (uint_t)SIOCGSTAMP, "SIOCGSTAMP", "timeval" }, + { (uint_t)SIOCGIFHWADDR, "SIOCGIFHWADDR", "ifreq" }, + { (uint_t)SIOCGLIFHWADDR, "SIOCGLIFHWADDR", "lifreq" }, + + /* DES encryption */ + { (uint_t)DESIOCBLOCK, "DESIOCBLOCK", "desparams" }, + { (uint_t)DESIOCQUICK, "DESIOCQUICK", "desparams" }, + + /* Printing system */ + { (uint_t)PRNIOC_GET_IFCAP, "PRNIOC_GET_IFCAP", NULL }, + { (uint_t)PRNIOC_SET_IFCAP, "PRNIOC_SET_IFCAP", NULL }, + { (uint_t)PRNIOC_GET_IFINFO, "PRNIOC_GET_IFINFO", + "prn_interface_info" }, + { (uint_t)PRNIOC_GET_STATUS, "PRNIOC_GET_STATUS", NULL }, + { (uint_t)PRNIOC_GET_1284_DEVID, "PRNIOC_GET_1284_DEVID", + "prn_1284_device_id" }, + { (uint_t)PRNIOC_GET_1284_STATUS, + "PRNIOC_GET_IFCANIOC_GET_1284_STATUS", NULL }, + { (uint_t)PRNIOC_GET_TIMEOUTS, "PRNIOC_GET_TIMEOUTS", + "prn_timeouts" }, + { (uint_t)PRNIOC_SET_TIMEOUTS, "PRNIOC_SET_TIMEOUTS", + "prn_timeouts" }, + { (uint_t)PRNIOC_RESET, "PRNIOC_RESET", NULL }, + + /* DTrace */ + { (uint_t)DTRACEIOC_PROVIDER, "DTRACEIOC_PROVIDER", NULL }, + { (uint_t)DTRACEIOC_PROBES, "DTRACEIOC_PROBES", NULL }, + { (uint_t)DTRACEIOC_BUFSNAP, "DTRACEIOC_BUFSNAP", NULL }, + { (uint_t)DTRACEIOC_PROBEMATCH, "DTRACEIOC_PROBEMATCH", NULL }, + { (uint_t)DTRACEIOC_ENABLE, "DTRACEIOC_ENABLE", NULL }, + { (uint_t)DTRACEIOC_AGGSNAP, "DTRACEIOC_AGGSNAP", NULL }, + { (uint_t)DTRACEIOC_EPROBE, "DTRACEIOC_EPROBE", NULL }, + { (uint_t)DTRACEIOC_PROBEARG, "DTRACEIOC_PROBEARG", NULL }, + { (uint_t)DTRACEIOC_CONF, "DTRACEIOC_CONF", NULL }, + { (uint_t)DTRACEIOC_STATUS, "DTRACEIOC_STATUS", NULL }, + { (uint_t)DTRACEIOC_GO, "DTRACEIOC_GO", NULL }, + { (uint_t)DTRACEIOC_STOP, "DTRACEIOC_STOP", NULL }, + { (uint_t)DTRACEIOC_AGGDESC, "DTRACEIOC_AGGDESC", NULL }, + { (uint_t)DTRACEIOC_FORMAT, "DTRACEIOC_FORMAT", NULL }, + { (uint_t)DTRACEIOC_DOFGET, "DTRACEIOC_DOFGET", NULL }, + { (uint_t)DTRACEIOC_REPLICATE, "DTRACEIOC_REPLICATE", NULL }, + + { (uint_t)DTRACEHIOC_ADD, "DTRACEHIOC_ADD", NULL }, + { (uint_t)DTRACEHIOC_REMOVE, "DTRACEHIOC_REMOVE", NULL }, + { (uint_t)DTRACEHIOC_ADDDOF, "DTRACEHIOC_ADDDOF", NULL }, + + /* /dev/cryptoadm ioctl() control codes */ + { (uint_t)CRYPTO_GET_VERSION, "CRYPTO_GET_VERSION", NULL }, + { (uint_t)CRYPTO_GET_DEV_LIST, "CRYPTO_GET_DEV_LIST", NULL }, + { (uint_t)CRYPTO_GET_SOFT_LIST, "CRYPTO_GET_SOFT_LIST", NULL }, + { (uint_t)CRYPTO_GET_DEV_INFO, "CRYPTO_GET_DEV_INFO", NULL }, + { (uint_t)CRYPTO_GET_SOFT_INFO, "CRYPTO_GET_SOFT_INFO", NULL }, + { (uint_t)CRYPTO_LOAD_DEV_DISABLED, "CRYPTO_LOAD_DEV_DISABLED", + NULL }, + { (uint_t)CRYPTO_LOAD_SOFT_DISABLED, "CRYPTO_LOAD_SOFT_DISABLED", + NULL }, + { (uint_t)CRYPTO_UNLOAD_SOFT_MODULE, "CRYPTO_UNLOAD_SOFT_MODULE", + NULL }, + { (uint_t)CRYPTO_LOAD_SOFT_CONFIG, "CRYPTO_LOAD_SOFT_CONFIG", + NULL }, + { (uint_t)CRYPTO_POOL_CREATE, "CRYPTO_POOL_CREATE", NULL }, + { (uint_t)CRYPTO_POOL_WAIT, "CRYPTO_POOL_WAIT", NULL }, + { (uint_t)CRYPTO_POOL_RUN, "CRYPTO_POOL_RUN", NULL }, + { (uint_t)CRYPTO_LOAD_DOOR, "CRYPTO_LOAD_DOOR", NULL }, + + /* /dev/crypto ioctl() control codes */ + { (uint_t)CRYPTO_GET_FUNCTION_LIST, "CRYPTO_GET_FUNCTION_LIST", + NULL }, + { (uint_t)CRYPTO_GET_MECHANISM_NUMBER, "CRYPTO_GET_MECHANISM_NUMBER", + NULL }, + { (uint_t)CRYPTO_OPEN_SESSION, "CRYPTO_OPEN_SESSION", NULL }, + { (uint_t)CRYPTO_CLOSE_SESSION, "CRYPTO_CLOSE_SESSION", NULL }, + { (uint_t)CRYPTO_CLOSE_ALL_SESSIONS, "CRYPTO_CLOSE_ALL_SESSIONS", + NULL }, + { (uint_t)CRYPTO_LOGIN, "CRYPTO_LOGIN", NULL }, + { (uint_t)CRYPTO_LOGOUT, "CRYPTO_LOGOUT", NULL }, + { (uint_t)CRYPTO_ENCRYPT, "CRYPTO_ENCRYPT", NULL }, + { (uint_t)CRYPTO_ENCRYPT_INIT, "CRYPTO_ENCRYPT_INIT", NULL }, + { (uint_t)CRYPTO_ENCRYPT_UPDATE, "CRYPTO_ENCRYPT_UPDATE", + NULL }, + { (uint_t)CRYPTO_ENCRYPT_FINAL, "CRYPTO_ENCRYPT_FINAL", NULL }, + { (uint_t)CRYPTO_DECRYPT, "CRYPTO_DECRYPT", NULL }, + { (uint_t)CRYPTO_DECRYPT_INIT, "CRYPTO_DECRYPT_INIT", NULL }, + { (uint_t)CRYPTO_DECRYPT_UPDATE, "CRYPTO_DECRYPT_UPDATE", + NULL }, + { (uint_t)CRYPTO_DECRYPT_FINAL, "CRYPTO_DECRYPT_FINAL", NULL }, + { (uint_t)CRYPTO_DIGEST, "CRYPTO_DIGEST", NULL }, + { (uint_t)CRYPTO_DIGEST_INIT, "CRYPTO_DIGEST_INIT", NULL }, + { (uint_t)CRYPTO_DIGEST_UPDATE, "CRYPTO_DIGEST_UPDATE", NULL }, + { (uint_t)CRYPTO_DIGEST_KEY, "CRYPTO_DIGEST_KEY", NULL }, + { (uint_t)CRYPTO_DIGEST_FINAL, "CRYPTO_DIGEST_FINAL", NULL }, + { (uint_t)CRYPTO_MAC, "CRYPTO_MAC", NULL }, + { (uint_t)CRYPTO_MAC_INIT, "CRYPTO_MAC_INIT", NULL }, + { (uint_t)CRYPTO_MAC_UPDATE, "CRYPTO_MAC_UPDATE", NULL }, + { (uint_t)CRYPTO_MAC_FINAL, "CRYPTO_MAC_FINAL", NULL }, + { (uint_t)CRYPTO_SIGN, "CRYPTO_SIGN", NULL }, + { (uint_t)CRYPTO_SIGN_INIT, "CRYPTO_SIGN_INIT", NULL }, + { (uint_t)CRYPTO_SIGN_UPDATE, "CRYPTO_SIGN_UPDATE", NULL }, + { (uint_t)CRYPTO_SIGN_FINAL, "CRYPTO_SIGN_FINAL", NULL }, + { (uint_t)CRYPTO_SIGN_RECOVER_INIT, "CRYPTO_SIGN_RECOVER_INIT", + NULL }, + { (uint_t)CRYPTO_SIGN_RECOVER, "CRYPTO_SIGN_RECOVER", NULL }, + { (uint_t)CRYPTO_VERIFY, "CRYPTO_VERIFY", NULL }, + { (uint_t)CRYPTO_VERIFY_INIT, "CRYPTO_VERIFY_INIT", NULL }, + { (uint_t)CRYPTO_VERIFY_UPDATE, "CRYPTO_VERIFY_UPDATE", NULL }, + { (uint_t)CRYPTO_VERIFY_FINAL, "CRYPTO_VERIFY_FINAL", NULL }, + { (uint_t)CRYPTO_VERIFY_RECOVER_INIT, "CRYPTO_VERIFY_RECOVER_INIT", + NULL }, + { (uint_t)CRYPTO_VERIFY_RECOVER, "CRYPTO_VERIFY_RECOVER", + NULL }, + { (uint_t)CRYPTO_DIGEST_ENCRYPT_UPDATE, "CRYPTO_DIGEST_ENCRYPT_UPDATE", + NULL }, + { (uint_t)CRYPTO_DECRYPT_DIGEST_UPDATE, "CRYPTO_DECRYPT_DIGEST_UPDATE", + NULL }, + { (uint_t)CRYPTO_SIGN_ENCRYPT_UPDATE, "CRYPTO_SIGN_ENCRYPT_UPDATE", + NULL }, + { (uint_t)CRYPTO_DECRYPT_VERIFY_UPDATE, "CRYPTO_DECRYPT_VERIFY_UPDATE", + NULL }, + { (uint_t)CRYPTO_SEED_RANDOM, "CRYPTO_SEED_RANDOM", NULL }, + { (uint_t)CRYPTO_GENERATE_RANDOM, "CRYPTO_GENERATE_RANDOM", + NULL }, + { (uint_t)CRYPTO_OBJECT_CREATE, "CRYPTO_OBJECT_CREATE", NULL }, + { (uint_t)CRYPTO_OBJECT_COPY, "CRYPTO_OBJECT_COPY", NULL }, + { (uint_t)CRYPTO_OBJECT_DESTROY, "CRYPTO_OBJECT_DESTROY", + NULL }, + { (uint_t)CRYPTO_OBJECT_GET_ATTRIBUTE_VALUE, + "CRYPTO_OBJECT_GET_ATTRIBUTE_VALUE", NULL }, + { (uint_t)CRYPTO_OBJECT_GET_SIZE, "CRYPTO_OBJECT_GET_SIZE", NULL }, + { (uint_t)CRYPTO_OBJECT_SET_ATTRIBUTE_VALUE, + "CRYPTO_OBJECT_SET_ATTRIBUTE_VALUE", NULL }, + { (uint_t)CRYPTO_OBJECT_FIND_INIT, "CRYPTO_OBJECT_FIND_INIT", + NULL }, + { (uint_t)CRYPTO_OBJECT_FIND_UPDATE, "CRYPTO_OBJECT_FIND_UPDATE", + NULL }, + { (uint_t)CRYPTO_OBJECT_FIND_FINAL, "CRYPTO_OBJECT_FIND_FINAL", + NULL }, + { (uint_t)CRYPTO_GENERATE_KEY, "CRYPTO_GENERATE_KEY", NULL }, + { (uint_t)CRYPTO_GENERATE_KEY_PAIR, "CRYPTO_GENERATE_KEY_PAIR", + NULL }, + { (uint_t)CRYPTO_WRAP_KEY, "CRYPTO_WRAP_KEY", NULL }, + { (uint_t)CRYPTO_UNWRAP_KEY, "CRYPTO_UNWRAP_KEY", NULL }, + { (uint_t)CRYPTO_DERIVE_KEY, "CRYPTO_DERIVE_KEY", NULL }, + { (uint_t)CRYPTO_GET_PROVIDER_LIST, "CRYPTO_GET_PROVIDER_LIST", + NULL }, + { (uint_t)CRYPTO_GET_PROVIDER_INFO, "CRYPTO_GET_PROVIDER_INFO", + NULL }, + { (uint_t)CRYPTO_GET_PROVIDER_MECHANISMS, + "CRYPTO_GET_PROVIDER_MECHANISMS", NULL }, + { (uint_t)CRYPTO_GET_PROVIDER_MECHANISM_INFO, + "CRYPTO_GET_PROVIDER_MECHANISM_INFO", NULL }, + { (uint_t)CRYPTO_INIT_TOKEN, "CRYPTO_INIT_TOKEN", NULL }, + { (uint_t)CRYPTO_INIT_PIN, "CRYPTO_INIT_PIN", NULL }, + { (uint_t)CRYPTO_SET_PIN, "CRYPTO_SET_PIN", NULL }, + { (uint_t)CRYPTO_NOSTORE_GENERATE_KEY, + "CRYPTO_NOSTORE_GENERATE_KEY", NULL }, + { (uint_t)CRYPTO_NOSTORE_GENERATE_KEY_PAIR, + "CRYPTO_NOSTORE_GENERATE_KEY_PAIR", NULL }, + { (uint_t)CRYPTO_NOSTORE_DERIVE_KEY, + "CRYPTO_NOSTORE_DERIVE_KEY", NULL }, + { (uint_t)CRYPTO_FIPS140_STATUS, "CRYPTO_FIPS140_STATUS", NULL }, + { (uint_t)CRYPTO_FIPS140_SET, "CRYPTO_FIPS140_SET", NULL }, + + /* kbio ioctls */ + { (uint_t)KIOCTRANS, "KIOCTRANS", NULL }, + { (uint_t)KIOCGTRANS, "KIOCGTRANS", NULL }, + { (uint_t)KIOCTRANSABLE, "KIOCTRANSABLE", NULL }, + { (uint_t)KIOCGTRANSABLE, "KIOCGTRANSABLE", NULL }, + { (uint_t)KIOCSETKEY, "KIOCSETKEY", NULL }, + { (uint_t)KIOCGETKEY, "KIOCGETKEY", NULL }, + { (uint_t)KIOCCMD, "KIOCCMD", NULL }, + { (uint_t)KIOCTYPE, "KIOCTYPE", NULL }, + { (uint_t)KIOCSDIRECT, "KIOCSDIRECT", NULL }, + { (uint_t)KIOCGDIRECT, "KIOCGDIRECT", NULL }, + { (uint_t)KIOCSKEY, "KIOCSKEY", NULL }, + { (uint_t)KIOCGKEY, "KIOCGKEY", NULL }, + { (uint_t)KIOCSLED, "KIOCSLED", NULL }, + { (uint_t)KIOCGLED, "KIOCGLED", NULL }, + { (uint_t)KIOCSCOMPAT, "KIOCSCOMPAT", NULL }, + { (uint_t)KIOCGCOMPAT, "KIOCGCOMPAT", NULL }, + { (uint_t)KIOCSLAYOUT, "KIOCSLAYOUT", NULL }, + { (uint_t)KIOCLAYOUT, "KIOCLAYOUT", NULL }, + { (uint_t)KIOCSKABORTEN, "KIOCSKABORTEN", NULL }, + { (uint_t)KIOCGRPTDELAY, "KIOCGRPTDELAY", NULL }, + { (uint_t)KIOCSRPTDELAY, "KIOCSRPTDELAY", NULL }, + { (uint_t)KIOCGRPTRATE, "KIOCGRPTRATE", NULL }, + { (uint_t)KIOCSRPTRATE, "KIOCSRPTRATE", NULL }, + { (uint_t)KIOCSETFREQ, "KIOCSETFREQ", NULL }, + { (uint_t)KIOCMKTONE, "KIOCMKTONE", NULL }, + + /* ptm/pts driver I_STR ioctls */ + { (uint_t)ISPTM, "ISPTM", NULL}, + { (uint_t)UNLKPT, "UNLKPT", NULL}, + { (uint_t)PTSSTTY, "PTSSTTY", NULL}, + { (uint_t)ZONEPT, "ZONEPT", NULL}, + { (uint_t)OWNERPT, "OWNERPT", NULL}, + + /* aggr link aggregation pseudo driver ioctls */ + { (uint_t)LAIOC_CREATE, "LAIOC_CREATE", "laioc_create"}, + { (uint_t)LAIOC_DELETE, "LAIOC_DELETE", "laioc_delete"}, + { (uint_t)LAIOC_INFO, "LAIOC_INFO", "laioc_info"}, + { (uint_t)LAIOC_ADD, "LAIOC_ADD", + "laioc_add_rem"}, + { (uint_t)LAIOC_REMOVE, "LAIOC_REMOVE", + "laioc_add_rem"}, + { (uint_t)LAIOC_MODIFY, "LAIOC_MODIFY", "laioc_modify"}, + + /* dld data-link ioctls */ + { (uint_t)DLDIOC_ATTR, "DLDIOC_ATTR", "dld_ioc_attr"}, + { (uint_t)DLDIOC_PHYS_ATTR, "DLDIOC_PHYS_ATTR", + "dld_ioc_phys_attr"}, + { (uint_t)DLDIOC_DOORSERVER, "DLDIOC_DOORSERVER", "dld_ioc_door"}, + { (uint_t)DLDIOC_RENAME, "DLDIOC_RENAME", "dld_ioc_rename"}, + { (uint_t)DLDIOC_SECOBJ_GET, "DLDIOC_SECOBJ_GET", + "dld_ioc_secobj_get"}, + { (uint_t)DLDIOC_SECOBJ_SET, "DLDIOC_SECOBJ_SET", + "dld_ioc_secobj_set"}, + { (uint_t)DLDIOC_SECOBJ_UNSET, "DLDIOC_SECOBJ_UNSET", + "dld_ioc_secobj_unset"}, + { (uint_t)DLDIOC_MACADDRGET, "DLDIOC_MACADDRGET", + "dld_ioc_macaddrget"}, + { (uint_t)DLDIOC_SETMACPROP, "DLDIOC_SETMACPROP", + "dld_ioc_macprop_s"}, + { (uint_t)DLDIOC_GETMACPROP, "DLDIOC_GETMACPROP", + "dld_ioc_macprop_s"}, + { (uint_t)DLDIOC_ADDFLOW, "DLDIOC_ADDFLOW", + "dld_ioc_addflow"}, + { (uint_t)DLDIOC_REMOVEFLOW, "DLDIOC_REMOVEFLOW", + "dld_ioc_removeflow"}, + { (uint_t)DLDIOC_MODIFYFLOW, "DLDIOC_MODIFYFLOW", + "dld_ioc_modifyflow"}, + { (uint_t)DLDIOC_WALKFLOW, "DLDIOC_WALKFLOW", + "dld_ioc_walkflow"}, + { (uint_t)DLDIOC_USAGELOG, "DLDIOC_USAGELOG", + "dld_ioc_usagelog"}, + + /* simnet ioctls */ + { (uint_t)SIMNET_IOC_CREATE, "SIMNET_IOC_CREATE", + "simnet_ioc_create"}, + { (uint_t)SIMNET_IOC_DELETE, "SIMNET_IOC_DELETE", + "simnet_ioc_delete"}, + { (uint_t)SIMNET_IOC_INFO, "SIMNET_IOC_INFO", + "simnet_ioc_info"}, + { (uint_t)SIMNET_IOC_MODIFY, "SIMNET_IOC_MODIFY", + "simnet_ioc_info"}, + + /* vnic ioctls */ + { (uint_t)VNIC_IOC_CREATE, "VNIC_IOC_CREATE", + "vnic_ioc_create"}, + { (uint_t)VNIC_IOC_DELETE, "VNIC_IOC_DELETE", + "vnic_ioc_delete"}, + { (uint_t)VNIC_IOC_INFO, "VNIC_IOC_INFO", + "vnic_ioc_info"}, + + /* ZFS ioctls */ + { (uint_t)ZFS_IOC_POOL_CREATE, "ZFS_IOC_POOL_CREATE", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_POOL_DESTROY, "ZFS_IOC_POOL_DESTROY", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_POOL_IMPORT, "ZFS_IOC_POOL_IMPORT", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_POOL_EXPORT, "ZFS_IOC_POOL_EXPORT", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_POOL_CONFIGS, "ZFS_IOC_POOL_CONFIGS", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_POOL_STATS, "ZFS_IOC_POOL_STATS", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_POOL_TRYIMPORT, "ZFS_IOC_POOL_TRYIMPORT", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_POOL_SCAN, "ZFS_IOC_POOL_SCAN", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_POOL_FREEZE, "ZFS_IOC_POOL_FREEZE", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_POOL_UPGRADE, "ZFS_IOC_POOL_UPGRADE", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_POOL_GET_HISTORY, "ZFS_IOC_POOL_GET_HISTORY", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_VDEV_ADD, "ZFS_IOC_VDEV_ADD", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_VDEV_REMOVE, "ZFS_IOC_VDEV_REMOVE", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_VDEV_SET_STATE, "ZFS_IOC_VDEV_SET_STATE", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_VDEV_ATTACH, "ZFS_IOC_VDEV_ATTACH", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_VDEV_DETACH, "ZFS_IOC_VDEV_DETACH", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_VDEV_SETPATH, "ZFS_IOC_VDEV_SETPATH", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_VDEV_SETFRU, "ZFS_IOC_VDEV_SETFRU", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_OBJSET_STATS, "ZFS_IOC_OBJSET_STATS", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_OBJSET_ZPLPROPS, "ZFS_IOC_OBJSET_ZPLPROPS", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_DATASET_LIST_NEXT, "ZFS_IOC_DATASET_LIST_NEXT", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_SNAPSHOT_LIST_NEXT, "ZFS_IOC_SNAPSHOT_LIST_NEXT", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_SET_PROP, "ZFS_IOC_SET_PROP", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_CREATE, "ZFS_IOC_CREATE", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_DESTROY, "ZFS_IOC_DESTROY", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_ROLLBACK, "ZFS_IOC_ROLLBACK", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_RENAME, "ZFS_IOC_RENAME", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_RECV, "ZFS_IOC_RECV", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_SEND, "ZFS_IOC_SEND", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_INJECT_FAULT, "ZFS_IOC_INJECT_FAULT", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_CLEAR_FAULT, "ZFS_IOC_CLEAR_FAULT", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_INJECT_LIST_NEXT, "ZFS_IOC_INJECT_LIST_NEXT", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_ERROR_LOG, "ZFS_IOC_ERROR_LOG", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_CLEAR, "ZFS_IOC_CLEAR", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_PROMOTE, "ZFS_IOC_PROMOTE", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_SNAPSHOT, "ZFS_IOC_SNAPSHOT", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_DSOBJ_TO_DSNAME, "ZFS_IOC_DSOBJ_TO_DSNAME", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_OBJ_TO_PATH, "ZFS_IOC_OBJ_TO_PATH", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_POOL_SET_PROPS, "ZFS_IOC_POOL_SET_PROPS", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_POOL_GET_PROPS, "ZFS_IOC_POOL_GET_PROPS", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_SET_FSACL, "ZFS_IOC_SET_FSACL", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_GET_FSACL, "ZFS_IOC_GET_FSACL", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_SHARE, "ZFS_IOC_SHARE", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_INHERIT_PROP, "ZFS_IOC_INHERIT_PROP", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_SMB_ACL, "ZFS_IOC_SMB_ACL", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_USERSPACE_ONE, "ZFS_IOC_USERSPACE_ONE", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_USERSPACE_MANY, "ZFS_IOC_USERSPACE_MANY", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_USERSPACE_UPGRADE, "ZFS_IOC_USERSPACE_UPGRADE", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_HOLD, "ZFS_IOC_HOLD", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_RELEASE, "ZFS_IOC_RELEASE", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_GET_HOLDS, "ZFS_IOC_GET_HOLDS", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_OBJSET_RECVD_PROPS, "ZFS_IOC_OBJSET_RECVD_PROPS", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_VDEV_SPLIT, "ZFS_IOC_VDEV_SPLIT", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_NEXT_OBJ, "ZFS_IOC_NEXT_OBJ", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_DIFF, "ZFS_IOC_DIFF", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_TMP_SNAPSHOT, "ZFS_IOC_TMP_SNAPSHOT", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_OBJ_TO_STATS, "ZFS_IOC_OBJ_TO_STATS", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_SPACE_WRITTEN, "ZFS_IOC_SPACE_WRITTEN", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_DESTROY_SNAPS, "ZFS_IOC_DESTROY_SNAPS", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_POOL_REGUID, "ZFS_IOC_POOL_REGUID", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_POOL_REOPEN, "ZFS_IOC_POOL_REOPEN", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_SEND_PROGRESS, "ZFS_IOC_SEND_PROGRESS", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_LOG_HISTORY, "ZFS_IOC_LOG_HISTORY", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_SEND_NEW, "ZFS_IOC_SEND_NEW", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_SEND_SPACE, "ZFS_IOC_SEND_SPACE", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_CLONE, "ZFS_IOC_CLONE", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_BOOKMARK, "ZFS_IOC_BOOKMARK", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_GET_BOOKMARKS, "ZFS_IOC_GET_BOOKMARKS", + "zfs_cmd_t" }, + { (uint_t)ZFS_IOC_DESTROY_BOOKMARKS, "ZFS_IOC_DESTROY_BOOKMARKS", + "zfs_cmd_t" }, + + /* kssl ioctls */ + { (uint_t)KSSL_ADD_ENTRY, "KSSL_ADD_ENTRY", + "kssl_params_t"}, + { (uint_t)KSSL_DELETE_ENTRY, "KSSL_DELETE_ENTRY", + "sockaddr_in"}, + + /* disk ioctls - (0x04 << 8) - dkio.h */ + { (uint_t)DKIOCGGEOM, "DKIOCGGEOM", + "struct dk_geom"}, + { (uint_t)DKIOCINFO, "DKIOCINFO", + "struct dk_info"}, + { (uint_t)DKIOCEJECT, "DKIOCEJECT", + NULL}, + { (uint_t)DKIOCGVTOC, "DKIOCGVTOC", + "struct vtoc"}, + { (uint_t)DKIOCSVTOC, "DKIOCSVTOC", + "struct vtoc"}, + { (uint_t)DKIOCGEXTVTOC, "DKIOCGEXTVTOC", + "struct extvtoc"}, + { (uint_t)DKIOCSEXTVTOC, "DKIOCSEXTVTOC", + "struct extvtoc"}, + { (uint_t)DKIOCFLUSHWRITECACHE, "DKIOCFLUSHWRITECACHE", + NULL}, + { (uint_t)DKIOCGETWCE, "DKIOCGETWCE", + NULL}, + { (uint_t)DKIOCSETWCE, "DKIOCSETWCE", + NULL}, + { (uint_t)DKIOCSGEOM, "DKIOCSGEOM", + "struct dk_geom"}, + { (uint_t)DKIOCSAPART, "DKIOCSAPART", + "struct dk_allmap"}, + { (uint_t)DKIOCGAPART, "DKIOCGAPART", + "struct dk_allmap"}, + { (uint_t)DKIOCG_PHYGEOM, "DKIOCG_PHYGEOM", + "struct dk_geom"}, + { (uint_t)DKIOCG_VIRTGEOM, "DKIOCG_VIRTGEOM", + "struct dk_geom"}, + { (uint_t)DKIOCLOCK, "DKIOCLOCK", + NULL}, + { (uint_t)DKIOCUNLOCK, "DKIOCUNLOCK", + NULL}, + { (uint_t)DKIOCSTATE, "DKIOCSTATE", + NULL}, + { (uint_t)DKIOCREMOVABLE, "DKIOCREMOVABLE", + NULL}, + { (uint_t)DKIOCHOTPLUGGABLE, "DKIOCHOTPLUGGABLE", + NULL}, + { (uint_t)DKIOCADDBAD, "DKIOCADDBAD", + NULL}, + { (uint_t)DKIOCGETDEF, "DKIOCGETDEF", + NULL}, + { (uint_t)DKIOCPARTINFO, "DKIOCPARTINFO", + "struct part_info"}, + { (uint_t)DKIOCEXTPARTINFO, "DKIOCEXTPARTINFO", + "struct extpart_info"}, + { (uint_t)DKIOCGMEDIAINFO, "DKIOCGMEDIAINFO", + "struct dk_minfo"}, + { (uint_t)DKIOCGMBOOT, "DKIOCGMBOOT", + NULL}, + { (uint_t)DKIOCSMBOOT, "DKIOCSMBOOT", + NULL}, + { (uint_t)DKIOCSETEFI, "DKIOCSETEFI", + "struct dk_efi"}, + { (uint_t)DKIOCGETEFI, "DKIOCGETEFI", + "struct dk_efi"}, + { (uint_t)DKIOCPARTITION, "DKIOCPARTITION", + "struct partition64"}, + { (uint_t)DKIOCGETVOLCAP, "DKIOCGETVOLCAP", + "struct volcap_t"}, + { (uint_t)DKIOCSETVOLCAP, "DKIOCSETVOLCAP", + "struct volcap_t"}, + { (uint_t)DKIOCDMR, "DKIOCDMR", + "struct vol_directed_rd"}, + { (uint_t)DKIOCDUMPINIT, "DKIOCDUMPINIT", + NULL}, + { (uint_t)DKIOCDUMPFINI, "DKIOCDUMPFINI", + NULL}, + { (uint_t)DKIOCREADONLY, "DKIOCREADONLY", + NULL}, + + /* disk ioctls - (0x04 << 8) - fdio.h */ + { (uint_t)FDIOGCHAR, "FDIOGCHAR", + "struct fd_char"}, + { (uint_t)FDIOSCHAR, "FDIOSCHAR", + "struct fd_char"}, + { (uint_t)FDEJECT, "FDEJECT", + NULL}, + { (uint_t)FDGETCHANGE, "FDGETCHANGE", + NULL}, + { (uint_t)FDGETDRIVECHAR, "FDGETDRIVECHAR", + "struct fd_drive"}, + { (uint_t)FDSETDRIVECHAR, "FDSETDRIVECHAR", + "struct fd_drive"}, + { (uint_t)FDGETSEARCH, "FDGETSEARCH", + NULL}, + { (uint_t)FDSETSEARCH, "FDSETSEARCH", + NULL}, + { (uint_t)FDIOCMD, "FDIOCMD", + "struct fd_cmd"}, + { (uint_t)FDRAW, "FDRAW", + "struct fd_raw"}, + { (uint_t)FDDEFGEOCHAR, "FDDEFGEOCHAR", + NULL}, + + /* disk ioctls - (0x04 << 8) - cdio.h */ + { (uint_t)CDROMPAUSE, "CDROMPAUSE", + NULL}, + { (uint_t)CDROMRESUME, "CDROMRESUME", + NULL}, + { (uint_t)CDROMPLAYMSF, "CDROMPLAYMSF", + "struct cdrom_msf"}, + { (uint_t)CDROMPLAYTRKIND, "CDROMPLAYTRKIND", + "struct cdrom_ti"}, + { (uint_t)CDROMREADTOCHDR, "CDROMREADTOCHDR", + "struct cdrom_tochdr"}, + { (uint_t)CDROMREADTOCENTRY, "CDROMREADTOCENTRY", + "struct cdrom_tocentry"}, + { (uint_t)CDROMSTOP, "CDROMSTOP", + NULL}, + { (uint_t)CDROMSTART, "CDROMSTART", + NULL}, + { (uint_t)CDROMEJECT, "CDROMEJECT", + NULL}, + { (uint_t)CDROMVOLCTRL, "CDROMVOLCTRL", + "struct cdrom_volctrl"}, + { (uint_t)CDROMSUBCHNL, "CDROMSUBCHNL", + "struct cdrom_subchnl"}, + { (uint_t)CDROMREADMODE2, "CDROMREADMODE2", + "struct cdrom_read"}, + { (uint_t)CDROMREADMODE1, "CDROMREADMODE1", + "struct cdrom_read"}, + { (uint_t)CDROMREADOFFSET, "CDROMREADOFFSET", + NULL}, + { (uint_t)CDROMGBLKMODE, "CDROMGBLKMODE", + NULL}, + { (uint_t)CDROMSBLKMODE, "CDROMSBLKMODE", + NULL}, + { (uint_t)CDROMCDDA, "CDROMCDDA", + "struct cdrom_cdda"}, + { (uint_t)CDROMCDXA, "CDROMCDXA", + "struct cdrom_cdxa"}, + { (uint_t)CDROMSUBCODE, "CDROMSUBCODE", + "struct cdrom_subcode"}, + { (uint_t)CDROMGDRVSPEED, "CDROMGDRVSPEED", + NULL}, + { (uint_t)CDROMSDRVSPEED, "CDROMSDRVSPEED", + NULL}, + { (uint_t)CDROMCLOSETRAY, "CDROMCLOSETRAY", + NULL}, + + /* disk ioctls - (0x04 << 8) - uscsi.h */ + { (uint_t)USCSICMD, "USCSICMD", + "struct uscsi_cmd"}, + + /* dumpadm ioctls - (0xdd << 8) */ + { (uint_t)DIOCGETDEV, "DIOCGETDEV", + NULL}, + + /* mntio ioctls - ('m' << 8) */ + { (uint_t)MNTIOC_NMNTS, "MNTIOC_NMNTS", + NULL}, + { (uint_t)MNTIOC_GETDEVLIST, "MNTIOC_GETDEVLIST", + NULL}, + { (uint_t)MNTIOC_SETTAG, "MNTIOC_SETTAG", + "struct mnttagdesc"}, + { (uint_t)MNTIOC_CLRTAG, "MNTIOC_CLRTAG", + "struct mnttagdesc"}, + { (uint_t)MNTIOC_SHOWHIDDEN, "MNTIOC_SHOWHIDDEN", + NULL}, + { (uint_t)MNTIOC_GETMNTENT, "MNTIOC_GETMNTENT", + "struct mnttab"}, + { (uint_t)MNTIOC_GETEXTMNTENT, "MNTIOC_GETEXTMNTENT", + "struct extmnttab"}, + { (uint_t)MNTIOC_GETMNTANY, "MNTIOC_GETMNTANY", + "struct mnttab"}, + + /* devinfo ioctls - ('df' << 8) - devinfo_impl.h */ + { (uint_t)DINFOUSRLD, "DINFOUSRLD", + NULL}, + { (uint_t)DINFOLODRV, "DINFOLODRV", + NULL}, + { (uint_t)DINFOIDENT, "DINFOIDENT", + NULL}, + + { (uint_t)IPTUN_CREATE, "IPTUN_CREATE", "iptun_kparams_t"}, + { (uint_t)IPTUN_DELETE, "IPTUN_DELETE", "datalink_id_t"}, + { (uint_t)IPTUN_MODIFY, "IPTUN_MODIFY", "iptun_kparams_t"}, + { (uint_t)IPTUN_INFO, "IPTUN_INFO", NULL}, + { (uint_t)IPTUN_SET_6TO4RELAY, "IPTUN_SET_6TO4RELAY", NULL}, + { (uint_t)IPTUN_GET_6TO4RELAY, "IPTUN_GET_6TO4RELAY", NULL}, + + /* zcons ioctls */ + { (uint_t)ZC_HOLDSLAVE, "ZC_HOLDSLAVE", NULL }, + { (uint_t)ZC_RELEASESLAVE, "ZC_RELEASESLAVE", NULL }, + + /* hid ioctls - ('h' << 8) - hid.h */ + { (uint_t)HIDIOCKMGDIRECT, "HIDIOCKMGDIRECT", NULL }, + { (uint_t)HIDIOCKMSDIRECT, "HIDIOCKMSDIRECT", NULL }, + + /* pm ioctls */ + { (uint_t)PM_SCHEDULE, "PM_SCHEDULE", NULL }, + { (uint_t)PM_GET_IDLE_TIME, "PM_GET_IDLE_TIME", NULL }, + { (uint_t)PM_GET_NUM_CMPTS, "PM_GET_NUM_CMPTS", NULL }, + { (uint_t)PM_GET_THRESHOLD, "PM_GET_THRESHOLD", NULL }, + { (uint_t)PM_SET_THRESHOLD, "PM_SET_THRESHOLD", NULL }, + { (uint_t)PM_GET_NORM_PWR, "PM_GET_NORM_PWR", NULL }, + { (uint_t)PM_SET_CUR_PWR, "PM_SET_CUR_PWR", NULL }, + { (uint_t)PM_GET_CUR_PWR, "PM_GET_CUR_PWR", NULL }, + { (uint_t)PM_GET_NUM_DEPS, "PM_GET_NUM_DEPS", NULL }, + { (uint_t)PM_GET_DEP, "PM_GET_DEP", NULL }, + { (uint_t)PM_ADD_DEP, "PM_ADD_DEP", NULL }, + { (uint_t)PM_REM_DEP, "PM_REM_DEP", NULL }, + { (uint_t)PM_REM_DEVICE, "PM_REM_DEVICE", NULL }, + { (uint_t)PM_REM_DEVICES, "PM_REM_DEVICES", NULL }, + { (uint_t)PM_DISABLE_AUTOPM, "PM_DISABLE_AUTOPM", NULL }, + { (uint_t)PM_REENABLE_AUTOPM, "PM_REENABLE_AUTOPM", NULL }, + { (uint_t)PM_SET_NORM_PWR, "PM_SET_NORM_PWR", NULL }, + { (uint_t)PM_GET_SYSTEM_THRESHOLD, "PM_GET_SYSTEM_THRESHOLD", + NULL }, + { (uint_t)PM_GET_DEFAULT_SYSTEM_THRESHOLD, + "PM_GET_DEFAULT_SYSTEM_THRESHOLD", NULL }, + { (uint_t)PM_SET_SYSTEM_THRESHOLD, "PM_SET_SYSTEM_THRESHOLD", + NULL }, + { (uint_t)PM_START_PM, "PM_START_PM", NULL }, + { (uint_t)PM_STOP_PM, "PM_STOP_PM", NULL }, + { (uint_t)PM_RESET_PM, "PM_RESET_PM", NULL }, + { (uint_t)PM_GET_PM_STATE, "PM_GET_PM_STATE", NULL }, + { (uint_t)PM_GET_AUTOS3_STATE, "PM_GET_AUTOS3_STATE", NULL }, + { (uint_t)PM_GET_S3_SUPPORT_STATE, "PM_GET_S3_SUPPORT_STATE", + NULL }, + { (uint_t)PM_IDLE_DOWN, "PM_IDLE_DOWN", NULL }, + { (uint_t)PM_START_CPUPM, "PM_START_CPUPM", NULL }, + { (uint_t)PM_START_CPUPM_EV, "PM_START_CPUPM_EV", NULL }, + { (uint_t)PM_START_CPUPM_POLL, "PM_START_CPUPM_POLL", NULL }, + { (uint_t)PM_STOP_CPUPM, "PM_STOP_CPUPM", NULL }, + { (uint_t)PM_GET_CPU_THRESHOLD, "PM_GET_CPU_THRESHOLD", NULL }, + { (uint_t)PM_SET_CPU_THRESHOLD, "PM_SET_CPU_THRESHOLD", NULL }, + { (uint_t)PM_GET_CPUPM_STATE, "PM_GET_CPUPM_STATE", NULL }, + { (uint_t)PM_START_AUTOS3, "PM_START_AUTOS3", NULL }, + { (uint_t)PM_STOP_AUTOS3, "PM_STOP_AUTOS3", NULL }, + { (uint_t)PM_ENABLE_S3, "PM_ENABLE_S3", NULL }, + { (uint_t)PM_DISABLE_S3, "PM_DISABLE_S3", NULL }, + { (uint_t)PM_ENTER_S3, "PM_ENTER_S3", NULL }, + { (uint_t)PM_DISABLE_CPU_DEEP_IDLE, "PM_DISABLE_CPU_DEEP_IDLE", + NULL }, + { (uint_t)PM_ENABLE_CPU_DEEP_IDLE, "PM_START_CPU_DEEP_IDLE", + NULL }, + { (uint_t)PM_DEFAULT_CPU_DEEP_IDLE, "PM_DFLT_CPU_DEEP_IDLE", + NULL }, +#ifdef _SYSCALL32 + { (uint_t)PM_GET_STATE_CHANGE, "PM_GET_STATE_CHANGE", + "pm_state_change32_t" }, + { (uint_t)PM_GET_STATE_CHANGE_WAIT, "PM_GET_STATE_CHANGE_WAIT", + "pm_state_change32_t" }, + { (uint_t)PM_DIRECT_NOTIFY, "PM_DIRECT_NOTIFY", + "pm_state_change32_t" }, + { (uint_t)PM_DIRECT_NOTIFY_WAIT, "PM_DIRECT_NOTIFY_WAIT", + "pm_state_change32_t" }, + { (uint_t)PM_REPARSE_PM_PROPS, "PM_REPARSE_PM_PROPS", + "pm_req32_t" }, + { (uint_t)PM_SET_DEVICE_THRESHOLD, "PM_SET_DEVICE_THRESHOLD", + "pm_req32_t" }, + { (uint_t)PM_GET_STATS, "PM_GET_STATS", + "pm_req32_t" }, + { (uint_t)PM_GET_DEVICE_THRESHOLD, "PM_GET_DEVICE_THRESHOLD", + "pm_req32_t" }, + { (uint_t)PM_GET_POWER_NAME, "PM_GET_POWER_NAME", + "pm_req32_t" }, + { (uint_t)PM_GET_POWER_LEVELS, "PM_GET_POWER_LEVELS", + "pm_req32_t" }, + { (uint_t)PM_GET_NUM_COMPONENTS, "PM_GET_NUM_COMPONENTS", + "pm_req32_t" }, + { (uint_t)PM_GET_COMPONENT_NAME, "PM_GET_COMPONENT_NAME", + "pm_req32_t" }, + { (uint_t)PM_GET_NUM_POWER_LEVELS, "PM_GET_NUM_POWER_LEVELS", + "pm_req32_t" }, + { (uint_t)PM_DIRECT_PM, "PM_DIRECT_PM", + "pm_req32_t" }, + { (uint_t)PM_RELEASE_DIRECT_PM, "PM_RELEASE_DIRECT_PM", + "pm_req32_t" }, + { (uint_t)PM_RESET_DEVICE_THRESHOLD, "PM_RESET_DEVICE_THRESHOLD", + "pm_req32_t" }, + { (uint_t)PM_GET_DEVICE_TYPE, "PM_GET_DEVICE_TYPE", + "pm_req32_t" }, + { (uint_t)PM_SET_COMPONENT_THRESHOLDS, "PM_SET_COMPONENT_THRESHOLDS", + "pm_req32_t" }, + { (uint_t)PM_GET_COMPONENT_THRESHOLDS, "PM_GET_COMPONENT_THRESHOLDS", + "pm_req32_t" }, + { (uint_t)PM_GET_DEVICE_THRESHOLD_BASIS, + "PM_GET_DEVICE_THRESHOLD_BASIS", "pm_req32_t" }, + { (uint_t)PM_SET_CURRENT_POWER, "PM_SET_CURRENT_POWER", + "pm_req32_t" }, + { (uint_t)PM_GET_CURRENT_POWER, "PM_GET_CURRENT_POWER", + "pm_req32_t" }, + { (uint_t)PM_GET_FULL_POWER, "PM_GET_FULL_POWER", + "pm_req32_t" }, + { (uint_t)PM_ADD_DEPENDENT, "PM_ADD_DEPENDENT", + "pm_req32_t" }, + { (uint_t)PM_GET_TIME_IDLE, "PM_GET_TIME_IDLE", + "pm_req32_t" }, + { (uint_t)PM_ADD_DEPENDENT_PROPERTY, "PM_ADD_DEPENDENT_PROPERTY", + "pm_req32_t" }, + { (uint_t)PM_GET_CMD_NAME, "PM_GET_CMD_NAME", + "pm_req32_t" }, + { (uint_t)PM_SEARCH_LIST, "PM_SEARCH_LIST", + "pm_searchargs32_t" }, +#else /* _SYSCALL32 */ + { (uint_t)PM_GET_STATE_CHANGE, "PM_GET_STATE_CHANGE", + "pm_state_change_t" }, + { (uint_t)PM_GET_STATE_CHANGE_WAIT, "PM_GET_STATE_CHANGE_WAIT", + "pm_state_change_t" }, + { (uint_t)PM_DIRECT_NOTIFY, "PM_DIRECT_NOTIFY", + "pm_state_change_t" }, + { (uint_t)PM_DIRECT_NOTIFY_WAIT, "PM_DIRECT_NOTIFY_WAIT", + "pm_state_change_t" }, + { (uint_t)PM_REPARSE_PM_PROPS, "PM_REPARSE_PM_PROPS", + "pm_req_t" }, + { (uint_t)PM_SET_DEVICE_THRESHOLD, "PM_SET_DEVICE_THRESHOLD", + "pm_req_t" }, + { (uint_t)PM_GET_STATS, "PM_GET_STATS", + "pm_req_t" }, + { (uint_t)PM_GET_DEVICE_THRESHOLD, "PM_GET_DEVICE_THRESHOLD", + "pm_req_t" }, + { (uint_t)PM_GET_POWER_NAME, "PM_GET_POWER_NAME", + "pm_req_t" }, + { (uint_t)PM_GET_POWER_LEVELS, "PM_GET_POWER_LEVELS", + "pm_req_t" }, + { (uint_t)PM_GET_NUM_COMPONENTS, "PM_GET_NUM_COMPONENTS", + "pm_req_t" }, + { (uint_t)PM_GET_COMPONENT_NAME, "PM_GET_COMPONENT_NAME", + "pm_req_t" }, + { (uint_t)PM_GET_NUM_POWER_LEVELS, "PM_GET_NUM_POWER_LEVELS", + "pm_req_t" }, + { (uint_t)PM_DIRECT_PM, "PM_DIRECT_PM", + "pm_req_t" }, + { (uint_t)PM_RELEASE_DIRECT_PM, "PM_RELEASE_DIRECT_PM", + "pm_req_t" }, + { (uint_t)PM_RESET_DEVICE_THRESHOLD, "PM_RESET_DEVICE_THRESHOLD", + "pm_req_t" }, + { (uint_t)PM_GET_DEVICE_TYPE, "PM_GET_DEVICE_TYPE", + "pm_req_t" }, + { (uint_t)PM_SET_COMPONENT_THRESHOLDS, "PM_SET_COMPONENT_THRESHOLDS", + "pm_req_t" }, + { (uint_t)PM_GET_COMPONENT_THRESHOLDS, "PM_GET_COMPONENT_THRESHOLDS", + "pm_req_t" }, + { (uint_t)PM_GET_DEVICE_THRESHOLD_BASIS, + "PM_GET_DEVICE_THRESHOLD_BASIS", "pm_req_t" }, + { (uint_t)PM_SET_CURRENT_POWER, "PM_SET_CURRENT_POWER", + "pm_req_t" }, + { (uint_t)PM_GET_CURRENT_POWER, "PM_GET_CURRENT_POWER", + "pm_req_t" }, + { (uint_t)PM_GET_FULL_POWER, "PM_GET_FULL_POWER", + "pm_req_t" }, + { (uint_t)PM_ADD_DEPENDENT, "PM_ADD_DEPENDENT", + "pm_req_t" }, + { (uint_t)PM_GET_TIME_IDLE, "PM_GET_TIME_IDLE", + "pm_req_t" }, + { (uint_t)PM_ADD_DEPENDENT_PROPERTY, "PM_ADD_DEPENDENT_PROPERTY", + "pm_req_t" }, + { (uint_t)PM_GET_CMD_NAME, "PM_GET_CMD_NAME", + "pm_req_t" }, + { (uint_t)PM_SEARCH_LIST, "PM_SEARCH_LIST", + "pm_searchargs_t" }, +#endif /* _SYSCALL */ + + { (uint_t)0, NULL, NULL } +}; + +void +ioctl_ioccom(char *buf, size_t size, uint_t code, int nbytes, int x, int y) +{ + const char *inoutstr; + + if (code & IOC_VOID) + inoutstr = ""; + else if ((code & IOC_INOUT) == IOC_INOUT) + inoutstr = "WR"; + else + inoutstr = code & IOC_IN ? "W" : "R"; + + if (isascii(x) && isprint(x)) + (void) snprintf(buf, size, "_IO%sN('%c', %d, %d)", inoutstr, + x, y, nbytes); + else + (void) snprintf(buf, size, "_IO%sN(0x%x, %d, %d)", inoutstr, + x, y, nbytes); +} + + +const char * +ioctlname(private_t *pri, uint_t code) +{ + const struct ioc *ip; + const char *str = NULL; + + for (ip = &ioc[0]; ip->name; ip++) { + if (code == ip->code) { + str = ip->name; + break; + } + } + + /* + * Developers hide ascii ioctl names in the ioctl subcode; for example + * 0x445210 should be printed 'D'<<16|'R'<<8|10. We allow for all + * three high order bytes (called hi, mid and lo) to contain ascii + * characters. + */ + if (str == NULL) { + int c_hi = code >> 24; + int c_mid = (code >> 16) & 0xff; + int c_mid_nm = (code >> 16); + int c_lo = (code >> 8) & 0xff; + int c_lo_nm = code >> 8; + + if (isascii(c_lo) && isprint(c_lo) && + isascii(c_mid) && isprint(c_mid) && + isascii(c_hi) && isprint(c_hi)) + (void) sprintf(pri->code_buf, + "(('%c'<<24)|('%c'<<16)|('%c'<<8)|%d)", + c_hi, c_mid, c_lo, code & 0xff); + else if (isascii(c_lo) && isprint(c_lo) && + isascii(c_mid_nm) && isprint(c_mid_nm)) + (void) sprintf(pri->code_buf, + "(('%c'<<16)|('%c'<<8)|%d)", c_mid, c_lo, + code & 0xff); + else if (isascii(c_lo_nm) && isprint(c_lo_nm)) + (void) sprintf(pri->code_buf, "(('%c'<<8)|%d)", + c_lo_nm, code & 0xff); + else if (code & (IOC_VOID|IOC_INOUT)) + ioctl_ioccom(pri->code_buf, sizeof (pri->code_buf), + code, c_mid, c_lo, code & 0xff); + else + (void) sprintf(pri->code_buf, "0x%.4X", code); + str = (const char *)pri->code_buf; + } + + return (str); +} + + +const char * +ioctldatastruct(uint_t code) +{ + const struct ioc *ip; + const char *str = NULL; + + for (ip = &ioc[0]; ip->name != NULL; ip++) { + if (code == ip->code) { + str = ip->datastruct; + break; + } + } + return (str); +} + + +const char * +fcntlname(int code) +{ + const char *str = NULL; + + if (code >= FCNTLMIN && code <= FCNTLMAX) + str = FCNTLname[code-FCNTLMIN]; + return (str); +} + +const char * +sfsname(int code) +{ + const char *str = NULL; + + if (code >= SYSFSMIN && code <= SYSFSMAX) + str = SYSFSname[code-SYSFSMIN]; + return (str); +} + +/* ARGSUSED */ +const char * +si86name(int code) +{ + const char *str = NULL; + +#if defined(__i386) || defined(__amd64) + switch (code) { + case SI86SWPI: str = "SI86SWPI"; break; + case SI86SYM: str = "SI86SYM"; break; + case SI86CONF: str = "SI86CONF"; break; + case SI86BOOT: str = "SI86BOOT"; break; + case SI86AUTO: str = "SI86AUTO"; break; + case SI86EDT: str = "SI86EDT"; break; + case SI86SWAP: str = "SI86SWAP"; break; + case SI86FPHW: str = "SI86FPHW"; break; + case SI86FPSTART: str = "SI86FPSTART"; break; + case GRNON: str = "GRNON"; break; + case GRNFLASH: str = "GRNFLASH"; break; + case STIME: str = "STIME"; break; + case SETNAME: str = "SETNAME"; break; + case RNVR: str = "RNVR"; break; + case WNVR: str = "WNVR"; break; + case RTODC: str = "RTODC"; break; + case CHKSER: str = "CHKSER"; break; + case SI86NVPRT: str = "SI86NVPRT"; break; + case SANUPD: str = "SANUPD"; break; + case SI86KSTR: str = "SI86KSTR"; break; + case SI86MEM: str = "SI86MEM"; break; + case SI86TODEMON: str = "SI86TODEMON"; break; + case SI86CCDEMON: str = "SI86CCDEMON"; break; + case SI86CACHE: str = "SI86CACHE"; break; + case SI86DELMEM: str = "SI86DELMEM"; break; + case SI86ADDMEM: str = "SI86ADDMEM"; break; +/* 71 through 74 reserved for VPIX */ + case SI86V86: str = "SI86V86"; break; + case SI86SLTIME: str = "SI86SLTIME"; break; + case SI86DSCR: str = "SI86DSCR"; break; + case RDUBLK: str = "RDUBLK"; break; +/* NFA entry point */ + case SI86NFA: str = "SI86NFA"; break; + case SI86VM86: str = "SI86VM86"; break; + case SI86VMENABLE: str = "SI86VMENABLE"; break; + case SI86LIMUSER: str = "SI86LIMUSER"; break; + case SI86RDID: str = "SI86RDID"; break; + case SI86RDBOOT: str = "SI86RDBOOT"; break; +/* Merged Product defines */ + case SI86SHFIL: str = "SI86SHFIL"; break; + case SI86PCHRGN: str = "SI86PCHRGN"; break; + case SI86BADVISE: str = "SI86BADVISE"; break; + case SI86SHRGN: str = "SI86SHRGN"; break; + case SI86CHIDT: str = "SI86CHIDT"; break; + case SI86EMULRDA: str = "SI86EMULRDA"; break; +/* RTC commands */ + case WTODC: str = "WTODC"; break; + case SGMTL: str = "SGMTL"; break; + case GGMTL: str = "GGMTL"; break; + case RTCSYNC: str = "RTCSYNC"; break; + } +#endif /* __i386 */ + + return (str); +} + +const char * +utscode(int code) +{ + const char *str = NULL; + + switch (code) { + case UTS_UNAME: str = "UNAME"; break; + case UTS_USTAT: str = "USTAT"; break; + case UTS_FUSERS: str = "FUSERS"; break; + } + + return (str); +} + +const char * +rctlsyscode(int code) +{ + const char *str = NULL; + switch (code) { + case 0: str = "GETRCTL"; break; + case 1: str = "SETRCTL"; break; + case 2: str = "RCTLSYS_LST"; break; + case 3: str = "RCTLSYS_CTL"; break; + case 4: str = "RCTLSYS_SETPROJ"; break; + default: str = "UNKNOWN"; break; + } + return (str); +} + +const char * +rctl_local_action(private_t *pri, uint_t val) +{ + uint_t action = val & (~RCTL_LOCAL_ACTION_MASK); + + char *s = pri->code_buf; + + *s = '\0'; + + if (action & RCTL_LOCAL_NOACTION) { + action ^= RCTL_LOCAL_NOACTION; + (void) strlcat(s, "|RCTL_LOCAL_NOACTION", + sizeof (pri->code_buf)); + } + if (action & RCTL_LOCAL_SIGNAL) { + action ^= RCTL_LOCAL_SIGNAL; + (void) strlcat(s, "|RCTL_LOCAL_SIGNAL", + sizeof (pri->code_buf)); + } + if (action & RCTL_LOCAL_DENY) { + action ^= RCTL_LOCAL_DENY; + (void) strlcat(s, "|RCTL_LOCAL_DENY", + sizeof (pri->code_buf)); + } + + if ((action & (~RCTL_LOCAL_ACTION_MASK)) != 0) + return (NULL); + else if (*s != '\0') + return (s+1); + else + return (NULL); +} + + +const char * +rctl_local_flags(private_t *pri, uint_t val) +{ + uint_t pval = val & RCTL_LOCAL_ACTION_MASK; + char *s = pri->code_buf; + + *s = '\0'; + + if (pval & RCTL_LOCAL_MAXIMAL) { + pval ^= RCTL_LOCAL_MAXIMAL; + (void) strlcat(s, "|RCTL_LOCAL_MAXIMAL", + sizeof (pri->code_buf)); + } + + if ((pval & RCTL_LOCAL_ACTION_MASK) != 0) + return (NULL); + else if (*s != '\0') + return (s+1); + else + return (NULL); +} + + +const char * +sconfname(int code) +{ + const char *str = NULL; + + if (code >= SCONFMIN && code <= SCONFMAX) + str = SCONFname[code-SCONFMIN]; + return (str); +} + +const char * +pathconfname(int code) +{ + const char *str = NULL; + + if (code >= PATHCONFMIN && code <= PATHCONFMAX) + str = PATHCONFname[code-PATHCONFMIN]; + return (str); +} + +#define ALL_O_FLAGS \ + (O_NDELAY|O_APPEND|O_SYNC|O_DSYNC|O_NONBLOCK|O_CREAT|O_TRUNC\ + |O_EXCL|O_NOCTTY|O_LARGEFILE|O_RSYNC|O_XATTR|O_NOFOLLOW|O_NOLINKS\ + |O_CLOEXEC|FXATTRDIROPEN) + +const char * +openarg(private_t *pri, int arg) +{ + char *str = pri->code_buf; + + if ((arg & ~(O_ACCMODE | ALL_O_FLAGS)) != 0) + return (NULL); + + switch (arg & O_ACCMODE) { + default: + return (NULL); + case O_RDONLY: + (void) strcpy(str, "O_RDONLY"); + break; + case O_WRONLY: + (void) strcpy(str, "O_WRONLY"); + break; + case O_RDWR: + (void) strcpy(str, "O_RDWR"); + break; + case O_SEARCH: + (void) strcpy(str, "O_SEARCH"); + break; + case O_EXEC: + (void) strcpy(str, "O_EXEC"); + break; + } + + if (arg & O_NDELAY) + (void) strlcat(str, "|O_NDELAY", sizeof (pri->code_buf)); + if (arg & O_APPEND) + (void) strlcat(str, "|O_APPEND", sizeof (pri->code_buf)); + if (arg & O_SYNC) + (void) strlcat(str, "|O_SYNC", sizeof (pri->code_buf)); + if (arg & O_DSYNC) + (void) strlcat(str, "|O_DSYNC", sizeof (pri->code_buf)); + if (arg & O_NONBLOCK) + (void) strlcat(str, "|O_NONBLOCK", sizeof (pri->code_buf)); + if (arg & O_CREAT) + (void) strlcat(str, "|O_CREAT", sizeof (pri->code_buf)); + if (arg & O_TRUNC) + (void) strlcat(str, "|O_TRUNC", sizeof (pri->code_buf)); + if (arg & O_EXCL) + (void) strlcat(str, "|O_EXCL", sizeof (pri->code_buf)); + if (arg & O_NOCTTY) + (void) strlcat(str, "|O_NOCTTY", sizeof (pri->code_buf)); + if (arg & O_LARGEFILE) + (void) strlcat(str, "|O_LARGEFILE", sizeof (pri->code_buf)); + if (arg & O_RSYNC) + (void) strlcat(str, "|O_RSYNC", sizeof (pri->code_buf)); + if (arg & O_XATTR) + (void) strlcat(str, "|O_XATTR", sizeof (pri->code_buf)); + if (arg & O_NOFOLLOW) + (void) strlcat(str, "|O_NOFOLLOW", sizeof (pri->code_buf)); + if (arg & O_NOLINKS) + (void) strlcat(str, "|O_NOLINKS", sizeof (pri->code_buf)); + if (arg & O_CLOEXEC) + (void) strlcat(str, "|O_CLOEXEC", sizeof (pri->code_buf)); + if (arg & FXATTRDIROPEN) + (void) strlcat(str, "|FXATTRDIROPEN", sizeof (pri->code_buf)); + + return ((const char *)str); +} + +const char * +whencearg(int arg) +{ + const char *str = NULL; + + switch (arg) { + case SEEK_SET: str = "SEEK_SET"; break; + case SEEK_CUR: str = "SEEK_CUR"; break; + case SEEK_END: str = "SEEK_END"; break; + case SEEK_DATA: str = "SEEK_DATA"; break; + case SEEK_HOLE: str = "SEEK_HOLE"; break; + } + + return (str); +} + +#define IPC_FLAGS (IPC_ALLOC|IPC_CREAT|IPC_EXCL|IPC_NOWAIT) + +char * +ipcflags(private_t *pri, int arg) +{ + char *str = pri->code_buf; + + if (arg & 0777) + (void) sprintf(str, "0%.3o", arg&0777); + else + *str = '\0'; + + if (arg & IPC_ALLOC) + (void) strcat(str, "|IPC_ALLOC"); + if (arg & IPC_CREAT) + (void) strcat(str, "|IPC_CREAT"); + if (arg & IPC_EXCL) + (void) strcat(str, "|IPC_EXCL"); + if (arg & IPC_NOWAIT) + (void) strcat(str, "|IPC_NOWAIT"); + + return (str); +} + +const char * +msgflags(private_t *pri, int arg) +{ + char *str; + + if (arg == 0 || (arg & ~(IPC_FLAGS|MSG_NOERROR|0777)) != 0) + return ((char *)NULL); + + str = ipcflags(pri, arg); + + if (arg & MSG_NOERROR) + (void) strcat(str, "|MSG_NOERROR"); + + if (*str == '|') + str++; + return ((const char *)str); +} + +const char * +semflags(private_t *pri, int arg) +{ + char *str; + + if (arg == 0 || (arg & ~(IPC_FLAGS|SEM_UNDO|0777)) != 0) + return ((char *)NULL); + + str = ipcflags(pri, arg); + + if (arg & SEM_UNDO) + (void) strcat(str, "|SEM_UNDO"); + + if (*str == '|') + str++; + return ((const char *)str); +} + +const char * +shmflags(private_t *pri, int arg) +{ + char *str; + + if (arg == 0 || (arg & ~(IPC_FLAGS|SHM_RDONLY|SHM_RND|0777)) != 0) + return ((char *)NULL); + + str = ipcflags(pri, arg); + + if (arg & SHM_RDONLY) + (void) strcat(str, "|SHM_RDONLY"); + if (arg & SHM_RND) + (void) strcat(str, "|SHM_RND"); + + if (*str == '|') + str++; + return ((const char *)str); +} + +#define MSGCMDMIN 0 +#define MSGCMDMAX IPC_STAT64 +const char *const MSGCMDname[MSGCMDMAX+1] = { + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + "IPC_RMID", /* 10 */ + "IPC_SET", /* 11 */ + "IPC_STAT", /* 12 */ + "IPC_SET64", /* 13 */ + "IPC_STAT64", /* 14 */ +}; + +#define SEMCMDMIN 0 +#define SEMCMDMAX IPC_STAT64 +const char *const SEMCMDname[SEMCMDMAX+1] = { + NULL, /* 0 */ + NULL, /* 1 */ + NULL, /* 2 */ + "GETNCNT", /* 3 */ + "GETPID", /* 4 */ + "GETVAL", /* 5 */ + "GETALL", /* 6 */ + "GETZCNT", /* 7 */ + "SETVAL", /* 8 */ + "SETALL", /* 9 */ + "IPC_RMID", /* 10 */ + "IPC_SET", /* 11 */ + "IPC_STAT", /* 12 */ + "IPC_SET64", /* 13 */ + "IPC_STAT64", /* 14 */ +}; + +#define SHMCMDMIN 0 +#define SHMCMDMAX IPC_STAT64 +const char *const SHMCMDname[SHMCMDMAX+1] = { + NULL, /* 0 */ + NULL, /* 1 */ + NULL, /* 2 */ + "SHM_LOCK", /* 3 */ + "SHM_UNLOCK", /* 4 */ + NULL, NULL, NULL, NULL, NULL, /* 5 NULLs */ + "IPC_RMID", /* 10 */ + "IPC_SET", /* 11 */ + "IPC_STAT", /* 12 */ + "IPC_SET64", /* 13 */ + "IPC_STAT64", /* 14 */ +}; + +const char * +msgcmd(int arg) +{ + const char *str = NULL; + + if (arg >= MSGCMDMIN && arg <= MSGCMDMAX) + str = MSGCMDname[arg-MSGCMDMIN]; + return (str); +} + +const char * +semcmd(int arg) +{ + const char *str = NULL; + + if (arg >= SEMCMDMIN && arg <= SEMCMDMAX) + str = SEMCMDname[arg-SEMCMDMIN]; + return (str); +} + +const char * +shmcmd(int arg) +{ + const char *str = NULL; + + if (arg >= SHMCMDMIN && arg <= SHMCMDMAX) + str = SHMCMDname[arg-SHMCMDMIN]; + return (str); +} + +const char * +strrdopt(int arg) /* streams read option (I_SRDOPT I_GRDOPT) */ +{ + const char *str = NULL; + + switch (arg) { + case RNORM: str = "RNORM"; break; + case RMSGD: str = "RMSGD"; break; + case RMSGN: str = "RMSGN"; break; + } + + return (str); +} + +/* bit map of streams events (I_SETSIG & I_GETSIG) */ +const char * +strevents(private_t *pri, int arg) +{ + char *str = pri->code_buf; + + if (arg & ~(S_INPUT|S_HIPRI|S_OUTPUT|S_MSG|S_ERROR|S_HANGUP)) + return ((char *)NULL); + + *str = '\0'; + if (arg & S_INPUT) + (void) strcat(str, "|S_INPUT"); + if (arg & S_HIPRI) + (void) strcat(str, "|S_HIPRI"); + if (arg & S_OUTPUT) + (void) strcat(str, "|S_OUTPUT"); + if (arg & S_MSG) + (void) strcat(str, "|S_MSG"); + if (arg & S_ERROR) + (void) strcat(str, "|S_ERROR"); + if (arg & S_HANGUP) + (void) strcat(str, "|S_HANGUP"); + + return ((const char *)(str+1)); +} + +const char * +tiocflush(private_t *pri, int arg) /* bit map passsed by TIOCFLUSH */ +{ + char *str = pri->code_buf; + + if (arg & ~(FREAD|FWRITE)) + return ((char *)NULL); + + *str = '\0'; + if (arg & FREAD) + (void) strcat(str, "|FREAD"); + if (arg & FWRITE) + (void) strcat(str, "|FWRITE"); + + return ((const char *)(str+1)); +} + +const char * +strflush(int arg) /* streams flush option (I_FLUSH) */ +{ + const char *str = NULL; + + switch (arg) { + case FLUSHR: str = "FLUSHR"; break; + case FLUSHW: str = "FLUSHW"; break; + case FLUSHRW: str = "FLUSHRW"; break; + } + + return (str); +} + +#define ALL_MOUNT_FLAGS (MS_RDONLY|MS_FSS|MS_DATA|MS_NOSUID|MS_REMOUNT| \ + MS_NOTRUNC|MS_OVERLAY|MS_OPTIONSTR|MS_GLOBAL|MS_FORCE|MS_NOMNTTAB) + +const char * +mountflags(private_t *pri, int arg) /* bit map of mount syscall flags */ +{ + char *str = pri->code_buf; + size_t used = 0; + + if (arg & ~ALL_MOUNT_FLAGS) + return ((char *)NULL); + + *str = '\0'; + if (arg & MS_RDONLY) + used = strlcat(str, "|MS_RDONLY", sizeof (pri->code_buf)); + if (arg & MS_FSS) + used = strlcat(str, "|MS_FSS", sizeof (pri->code_buf)); + if (arg & MS_DATA) + used = strlcat(str, "|MS_DATA", sizeof (pri->code_buf)); + if (arg & MS_NOSUID) + used = strlcat(str, "|MS_NOSUID", sizeof (pri->code_buf)); + if (arg & MS_REMOUNT) + used = strlcat(str, "|MS_REMOUNT", sizeof (pri->code_buf)); + if (arg & MS_NOTRUNC) + used = strlcat(str, "|MS_NOTRUNC", sizeof (pri->code_buf)); + if (arg & MS_OVERLAY) + used = strlcat(str, "|MS_OVERLAY", sizeof (pri->code_buf)); + if (arg & MS_OPTIONSTR) + used = strlcat(str, "|MS_OPTIONSTR", sizeof (pri->code_buf)); + if (arg & MS_GLOBAL) + used = strlcat(str, "|MS_GLOBAL", sizeof (pri->code_buf)); + if (arg & MS_FORCE) + used = strlcat(str, "|MS_FORCE", sizeof (pri->code_buf)); + if (arg & MS_NOMNTTAB) + used = strlcat(str, "|MS_NOMNTTAB", sizeof (pri->code_buf)); + + if (used == 0 || used >= sizeof (pri->code_buf)) + return ((char *)NULL); /* use prt_hex() */ + + return ((const char *)(str+1)); +} + +const char * +svfsflags(private_t *pri, ulong_t arg) /* bit map of statvfs syscall flags */ +{ + char *str = pri->code_buf; + + if (arg & ~(ST_RDONLY|ST_NOSUID|ST_NOTRUNC)) { + (void) sprintf(str, "0x%lx", arg); + return (str); + } + *str = '\0'; + if (arg & ST_RDONLY) + (void) strcat(str, "|ST_RDONLY"); + if (arg & ST_NOSUID) + (void) strcat(str, "|ST_NOSUID"); + if (arg & ST_NOTRUNC) + (void) strcat(str, "|ST_NOTRUNC"); + if (*str == '\0') + (void) strcat(str, "|0"); + return ((const char *)(str+1)); +} + +const char * +fuiname(int arg) /* fusers() input argument */ +{ + const char *str = NULL; + + switch (arg) { + case F_FILE_ONLY: str = "F_FILE_ONLY"; break; + case F_CONTAINED: str = "F_CONTAINED"; break; + } + + return (str); +} + +const char * +fuflags(private_t *pri, int arg) /* fusers() output flags */ +{ + char *str = pri->code_buf; + + if (arg & ~(F_CDIR|F_RDIR|F_TEXT|F_MAP|F_OPEN|F_TRACE|F_TTY)) { + (void) sprintf(str, "0x%x", arg); + return (str); + } + *str = '\0'; + if (arg & F_CDIR) + (void) strcat(str, "|F_CDIR"); + if (arg & F_RDIR) + (void) strcat(str, "|F_RDIR"); + if (arg & F_TEXT) + (void) strcat(str, "|F_TEXT"); + if (arg & F_MAP) + (void) strcat(str, "|F_MAP"); + if (arg & F_OPEN) + (void) strcat(str, "|F_OPEN"); + if (arg & F_TRACE) + (void) strcat(str, "|F_TRACE"); + if (arg & F_TTY) + (void) strcat(str, "|F_TTY"); + if (*str == '\0') + (void) strcat(str, "|0"); + return ((const char *)(str+1)); +} + + +const char * +ipprotos(int arg) /* IP protocols cf. netinet/in.h */ +{ + switch (arg) { + case IPPROTO_IP: return ("IPPROTO_IP"); + case IPPROTO_ICMP: return ("IPPROTO_ICMP"); + case IPPROTO_IGMP: return ("IPPROTO_IGMP"); + case IPPROTO_GGP: return ("IPPROTO_GGP"); + case IPPROTO_ENCAP: return ("IPPROTO_ENCAP"); + case IPPROTO_TCP: return ("IPPROTO_TCP"); + case IPPROTO_EGP: return ("IPPROTO_EGP"); + case IPPROTO_PUP: return ("IPPROTO_PUP"); + case IPPROTO_UDP: return ("IPPROTO_UDP"); + case IPPROTO_IDP: return ("IPPROTO_IDP"); + case IPPROTO_IPV6: return ("IPPROTO_IPV6"); + case IPPROTO_ROUTING: return ("IPPROTO_ROUTING"); + case IPPROTO_FRAGMENT: return ("IPPROTO_FRAGMENT"); + case IPPROTO_RSVP: return ("IPPROTO_RSVP"); + case IPPROTO_ESP: return ("IPPROTO_ESP"); + case IPPROTO_AH: return ("IPPROTO_AH"); + case IPPROTO_ICMPV6: return ("IPPROTO_ICMPV6"); + case IPPROTO_NONE: return ("IPPROTO_NONE"); + case IPPROTO_DSTOPTS: return ("IPPROTO_DSTOPTS"); + case IPPROTO_HELLO: return ("IPPROTO_HELLO"); + case IPPROTO_ND: return ("IPPROTO_ND"); + case IPPROTO_EON: return ("IPPROTO_EON"); + case IPPROTO_PIM: return ("IPPROTO_PIM"); + case IPPROTO_SCTP: return ("IPPROTO_SCTP"); + case IPPROTO_RAW: return ("IPPROTO_RAW"); + default: return (NULL); + } +} diff --git a/usr/src/cmd/truss/expound.c b/usr/src/cmd/truss/expound.c new file mode 100644 index 0000000..915ec46 --- /dev/null +++ b/usr/src/cmd/truss/expound.c @@ -0,0 +1,5605 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2012 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#define _SYSCALL32 + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <libproc.h> +#include <string.h> +#include <limits.h> +#include <sys/statfs.h> +#include <sys/times.h> +#include <sys/timex.h> +#include <sys/utssys.h> +#include <sys/utsname.h> +#include <sys/ipc.h> +#include <sys/ipc_impl.h> +#include <sys/msg.h> +#include <sys/msg_impl.h> +#include <sys/sem.h> +#include <sys/sem_impl.h> +#include <sys/shm.h> +#include <sys/shm_impl.h> +#include <sys/dirent.h> +#include <ustat.h> +#include <fcntl.h> +#include <time.h> +#include <sys/termios.h> +#include <sys/termiox.h> +#include <sys/termio.h> +#include <sys/ttold.h> +#include <sys/jioctl.h> +#include <sys/filio.h> +#include <stropts.h> +#include <poll.h> +#include <sys/uio.h> +#include <sys/resource.h> +#include <sys/statvfs.h> +#include <sys/time.h> +#include <sys/aio.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/un.h> +#include <sys/byteorder.h> +#include <arpa/inet.h> +#include <sys/audioio.h> +#include <sys/cladm.h> +#include <sys/synch.h> +#include <sys/synch32.h> +#include <sys/sysmacros.h> +#include <sys/sendfile.h> +#include <priv.h> +#include <ucred.h> +#include <sys/ucred.h> +#include <sys/port_impl.h> +#include <sys/zone.h> +#include <sys/priv_impl.h> +#include <sys/priv.h> +#include <tsol/label.h> +#include <sys/nvpair.h> +#include <libnvpair.h> +#include <sys/rctl_impl.h> +#include <sys/socketvar.h> +#include <sys/fs/zfs.h> +#include <sys/zfs_ioctl.h> + +#include "ramdata.h" +#include "systable.h" +#include "proto.h" + +void show_sigset(private_t *, long, const char *); +void show_ioctl(private_t *, int, long); +void show_zfs_ioc(private_t *, long); + +static void +mk_ctime(char *str, size_t maxsize, time_t value) +{ + (void) strftime(str, maxsize, "%b %e %H:%M:%S %Z %Y", + localtime(&value)); +} + +void +prtime(private_t *pri, const char *name, time_t value) +{ + char str[80]; + + mk_ctime(str, sizeof (str), value); + (void) printf("%s\t%s%s [ %lu ]\n", + pri->pname, + name, + str, + value); +} + +void +prtimeval(private_t *pri, const char *name, struct timeval *value) +{ + char str[80]; + + mk_ctime(str, sizeof (str), value->tv_sec); + (void) printf("%s\t%s%s [ %lu.%6.6lu ]\n", + pri->pname, + name, + str, + value->tv_sec, + value->tv_usec); +} + +void +prtimestruc(private_t *pri, const char *name, timestruc_t *value) +{ + char str[80]; + + mk_ctime(str, sizeof (str), value->tv_sec); + (void) printf("%s\t%s%s [ %lu.%9.9lu ]\n", + pri->pname, + name, + str, + value->tv_sec, + value->tv_nsec); +} + +static void +show_utimens(private_t *pri, long offset) +{ + struct { + timespec_t atime; + timespec_t mtime; + } utimbuf; + + if (offset == 0) + return; + + if (data_model == PR_MODEL_NATIVE) { + if (Pread(Proc, &utimbuf, sizeof (utimbuf), offset) + != sizeof (utimbuf)) + return; + } else { + struct { + timespec32_t atime; + timespec32_t mtime; + } utimbuf32; + + if (Pread(Proc, &utimbuf32, sizeof (utimbuf32), offset) + != sizeof (utimbuf32)) + return; + + TIMESPEC32_TO_TIMESPEC(&utimbuf.atime, &utimbuf32.atime); + TIMESPEC32_TO_TIMESPEC(&utimbuf.mtime, &utimbuf32.mtime); + } + + /* print access and modification times */ + if (utimbuf.atime.tv_nsec == UTIME_OMIT) + (void) printf("%s\tat = UTIME_OMIT\n", pri->pname); + else if (utimbuf.atime.tv_nsec == UTIME_NOW) + (void) printf("%s\tat = UTIME_NOW\n", pri->pname); + else + prtimestruc(pri, "at = ", &utimbuf.atime); + if (utimbuf.mtime.tv_nsec == UTIME_OMIT) + (void) printf("%s\tmt = UTIME_OMIT\n", pri->pname); + else if (utimbuf.mtime.tv_nsec == UTIME_NOW) + (void) printf("%s\tmt = UTIME_NOW\n", pri->pname); + else + prtimestruc(pri, "mt = ", &utimbuf.mtime); +} + +void +show_timeofday(private_t *pri) +{ + struct timeval tod; + long offset; + + if (pri->sys_nargs < 1 || (offset = pri->sys_args[0]) == NULL) + return; + + if (data_model == PR_MODEL_NATIVE) { + if (Pread(Proc, &tod, sizeof (tod), offset) + != sizeof (tod)) + return; + } else { + struct timeval32 tod32; + + if (Pread(Proc, &tod32, sizeof (tod32), offset) + != sizeof (tod32)) + return; + + TIMEVAL32_TO_TIMEVAL(&tod, &tod32); + } + + prtimeval(pri, "time: ", &tod); +} + +void +show_itimerval(private_t *pri, long offset, const char *name) +{ + struct itimerval itimerval; + + if (offset == 0) + return; + + if (data_model == PR_MODEL_NATIVE) { + if (Pread(Proc, &itimerval, sizeof (itimerval), offset) + != sizeof (itimerval)) + return; + } else { + struct itimerval32 itimerval32; + + if (Pread(Proc, &itimerval32, sizeof (itimerval32), offset) + != sizeof (itimerval32)) + return; + + ITIMERVAL32_TO_ITIMERVAL(&itimerval, &itimerval32); + } + + (void) printf( + "%s\t%s: interval: %4ld.%6.6ld sec value: %4ld.%6.6ld sec\n", + pri->pname, + name, + itimerval.it_interval.tv_sec, + itimerval.it_interval.tv_usec, + itimerval.it_value.tv_sec, + itimerval.it_value.tv_usec); +} + +void +show_timeval(private_t *pri, long offset, const char *name) +{ + struct timeval timeval; + + if (offset == 0) + return; + + if (data_model == PR_MODEL_NATIVE) { + if (Pread(Proc, &timeval, sizeof (timeval), offset) + != sizeof (timeval)) + return; + } else { + struct timeval32 timeval32; + + if (Pread(Proc, &timeval32, sizeof (timeval32), offset) + != sizeof (timeval32)) + return; + + TIMEVAL32_TO_TIMEVAL(&timeval, &timeval32); + } + + (void) printf( + "%s\t%s: %ld.%6.6ld sec\n", + pri->pname, + name, + timeval.tv_sec, + timeval.tv_usec); +} + +void +show_timestruc(private_t *pri, long offset, const char *name) +{ + timestruc_t timestruc; + + if (offset == 0) + return; + + if (data_model == PR_MODEL_NATIVE) { + if (Pread(Proc, ×truc, sizeof (timestruc), offset) + != sizeof (timestruc)) + return; + } else { + timestruc32_t timestruc32; + + if (Pread(Proc, ×truc32, sizeof (timestruc32), offset) + != sizeof (timestruc32)) + return; + + TIMESPEC32_TO_TIMESPEC(×truc, ×truc32); + } + + (void) printf( + "%s\t%s: %ld.%9.9ld sec\n", + pri->pname, + name, + timestruc.tv_sec, + timestruc.tv_nsec); +} + +void +show_stime(private_t *pri) +{ + if (pri->sys_nargs >= 1) { + /* print new system time */ + prtime(pri, "systime = ", (time_t)pri->sys_args[0]); + } +} + +void +show_times(private_t *pri) +{ + long hz = sysconf(_SC_CLK_TCK); + long offset; + struct tms tms; + + if (pri->sys_nargs < 1 || (offset = pri->sys_args[0]) == NULL) + return; + + if (data_model == PR_MODEL_NATIVE) { + if (Pread(Proc, &tms, sizeof (tms), offset) + != sizeof (tms)) + return; + } else { + struct tms32 tms32; + + if (Pread(Proc, &tms32, sizeof (tms32), offset) + != sizeof (tms32)) + return; + + /* + * This looks a bit odd (since the values are actually + * signed), but we need to suppress sign extension to + * preserve compatibility (we've always printed these + * numbers as unsigned quantities). + */ + tms.tms_utime = (unsigned)tms32.tms_utime; + tms.tms_stime = (unsigned)tms32.tms_stime; + tms.tms_cutime = (unsigned)tms32.tms_cutime; + tms.tms_cstime = (unsigned)tms32.tms_cstime; + } + + (void) printf( + "%s\tutim=%-6lu stim=%-6lu cutim=%-6lu cstim=%-6lu (HZ=%ld)\n", + pri->pname, + tms.tms_utime, + tms.tms_stime, + tms.tms_cutime, + tms.tms_cstime, + hz); +} + +void +show_uname(private_t *pri, long offset) +{ + /* + * Old utsname buffer (no longer accessible in <sys/utsname.h>). + */ + struct { + char sysname[9]; + char nodename[9]; + char release[9]; + char version[9]; + char machine[9]; + } ubuf; + + if (offset != NULL && + Pread(Proc, &ubuf, sizeof (ubuf), offset) == sizeof (ubuf)) { + (void) printf( + "%s\tsys=%-9.9snod=%-9.9srel=%-9.9sver=%-9.9smch=%.9s\n", + pri->pname, + ubuf.sysname, + ubuf.nodename, + ubuf.release, + ubuf.version, + ubuf.machine); + } +} + +/* XX64 -- definition of 'struct ustat' is strange -- check out the defn */ +void +show_ustat(private_t *pri, long offset) +{ + struct ustat ubuf; + + if (offset != NULL && + Pread(Proc, &ubuf, sizeof (ubuf), offset) == sizeof (ubuf)) { + (void) printf( + "%s\ttfree=%-6ld tinode=%-5lu fname=%-6.6s fpack=%-.6s\n", + pri->pname, + ubuf.f_tfree, + ubuf.f_tinode, + ubuf.f_fname, + ubuf.f_fpack); + } +} + +#ifdef _LP64 +void +show_ustat32(private_t *pri, long offset) +{ + struct ustat32 ubuf; + + if (offset != NULL && + Pread(Proc, &ubuf, sizeof (ubuf), offset) == sizeof (ubuf)) { + (void) printf( + "%s\ttfree=%-6d tinode=%-5u fname=%-6.6s fpack=%-.6s\n", + pri->pname, + ubuf.f_tfree, + ubuf.f_tinode, + ubuf.f_fname, + ubuf.f_fpack); + } +} +#endif /* _LP64 */ + +void +show_fusers(private_t *pri, long offset, long nproc) +{ + f_user_t fubuf; + int serial = (nproc > 4); + + if (offset == 0) + return; + + /* enter region of lengthy output */ + if (serial) + Eserialize(); + + while (nproc > 0 && + Pread(Proc, &fubuf, sizeof (fubuf), offset) == sizeof (fubuf)) { + (void) printf("%s\tpid=%-5d uid=%-5u flags=%s\n", + pri->pname, + (int)fubuf.fu_pid, + fubuf.fu_uid, + fuflags(pri, fubuf.fu_flags)); + nproc--; + offset += sizeof (fubuf); + } + + /* exit region of lengthy output */ + if (serial) + Xserialize(); +} + +void +show_utssys(private_t *pri, long r0) +{ + if (pri->sys_nargs >= 3) { + switch (pri->sys_args[2]) { + case UTS_UNAME: + show_uname(pri, (long)pri->sys_args[0]); + break; + case UTS_USTAT: + show_ustat(pri, (long)pri->sys_args[0]); + break; + case UTS_FUSERS: + show_fusers(pri, (long)pri->sys_args[3], r0); + break; + } + } +} + +#ifdef _LP64 +void +show_utssys32(private_t *pri, long r0) +{ + if (pri->sys_nargs >= 3) { + switch (pri->sys_args[2]) { + case UTS_UNAME: + show_uname(pri, (long)pri->sys_args[0]); + break; + case UTS_USTAT: + show_ustat32(pri, (long)pri->sys_args[0]); + break; + case UTS_FUSERS: + show_fusers(pri, (long)pri->sys_args[3], r0); + break; + } + } +} +#endif /* _LP64 */ + +void +show_cladm(private_t *pri, int code, int function, long offset) +{ + int arg; + + switch (code) { + case CL_INITIALIZE: + switch (function) { + case CL_GET_BOOTFLAG: + if (Pread(Proc, &arg, sizeof (arg), offset) + == sizeof (arg)) { + if (arg & CLUSTER_CONFIGURED) + (void) printf("%s\tbootflags=" + "CLUSTER_CONFIGURED", pri->pname); + if (arg & CLUSTER_BOOTED) + (void) printf("|CLUSTER_BOOTED\n"); + } + break; + } + break; + case CL_CONFIG: + switch (function) { + case CL_NODEID: + case CL_HIGHEST_NODEID: + if (Pread(Proc, &arg, sizeof (arg), offset) + == sizeof (arg)) + (void) printf("%s\tnodeid=%d\n", + pri->pname, arg); + } + break; + } +} + +#define ALL_LOCK_TYPES \ + (USYNC_PROCESS | LOCK_ERRORCHECK | LOCK_RECURSIVE | \ + LOCK_PRIO_INHERIT | LOCK_PRIO_PROTECT | LOCK_ROBUST | \ + USYNC_PROCESS_ROBUST) + +/* return cv and mutex types */ +const char * +synch_type(private_t *pri, uint_t type) +{ + char *str = pri->code_buf; + + if (type & USYNC_PROCESS) + (void) strcpy(str, "USYNC_PROCESS"); + else + (void) strcpy(str, "USYNC_THREAD"); + + if (type & LOCK_ERRORCHECK) + (void) strcat(str, "|LOCK_ERRORCHECK"); + if (type & LOCK_RECURSIVE) + (void) strcat(str, "|LOCK_RECURSIVE"); + if (type & LOCK_PRIO_INHERIT) + (void) strcat(str, "|LOCK_PRIO_INHERIT"); + if (type & LOCK_PRIO_PROTECT) + (void) strcat(str, "|LOCK_PRIO_PROTECT"); + if (type & LOCK_ROBUST) + (void) strcat(str, "|LOCK_ROBUST"); + if (type & USYNC_PROCESS_ROBUST) + (void) strcat(str, "|USYNC_PROCESS_ROBUST"); + + if ((type &= ~ALL_LOCK_TYPES) != 0) + (void) sprintf(str + strlen(str), "|0x%.4X", type); + + return ((const char *)str); +} + +void +show_mutex(private_t *pri, long offset) +{ + lwp_mutex_t mutex; + + if (Pread(Proc, &mutex, sizeof (mutex), offset) == sizeof (mutex)) { + (void) printf("%s\tmutex type: %s\n", + pri->pname, + synch_type(pri, mutex.mutex_type)); + } +} + +void +show_condvar(private_t *pri, long offset) +{ + lwp_cond_t condvar; + + if (Pread(Proc, &condvar, sizeof (condvar), offset) + == sizeof (condvar)) { + (void) printf("%s\tcondvar type: %s\n", + pri->pname, + synch_type(pri, condvar.cond_type)); + } +} + +void +show_sema(private_t *pri, long offset) +{ + lwp_sema_t sema; + + if (Pread(Proc, &sema, sizeof (sema), offset) == sizeof (sema)) { + (void) printf("%s\tsema type: %s count = %u\n", + pri->pname, + synch_type(pri, sema.sema_type), + sema.sema_count); + } +} + +void +show_rwlock(private_t *pri, long offset) +{ + lwp_rwlock_t rwlock; + + if (Pread(Proc, &rwlock, sizeof (rwlock), offset) == sizeof (rwlock)) { + (void) printf("%s\trwlock type: %s readers = %d\n", + pri->pname, + synch_type(pri, rwlock.rwlock_type), + rwlock.rwlock_readers); + } +} + +/* represent character as itself ('c') or octal (012) */ +char * +show_char(char *buf, int c) +{ + const char *fmt; + + if (c >= ' ' && c < 0177) + fmt = "'%c'"; + else + fmt = "%.3o"; + + (void) sprintf(buf, fmt, c&0xff); + return (buf); +} + +void +show_termio(private_t *pri, long offset) +{ + struct termio termio; + char cbuf[8]; + int i; + + if (Pread(Proc, &termio, sizeof (termio), offset) == sizeof (termio)) { + (void) printf( + "%s\tiflag=0%.6o oflag=0%.6o cflag=0%.6o lflag=0%.6o line=%d\n", + pri->pname, + termio.c_iflag, + termio.c_oflag, + termio.c_cflag, + termio.c_lflag, + termio.c_line); + (void) printf("%s\t cc: ", pri->pname); + for (i = 0; i < NCC; i++) + (void) printf(" %s", + show_char(cbuf, (int)termio.c_cc[i])); + (void) fputc('\n', stdout); + } +} + +void +show_termios(private_t *pri, long offset) +{ + struct termios termios; + char cbuf[8]; + int i; + + if (Pread(Proc, &termios, sizeof (termios), offset) + == sizeof (termios)) { + (void) printf( + "%s\tiflag=0%.6o oflag=0%.6o cflag=0%.6o lflag=0%.6o\n", + pri->pname, + termios.c_iflag, + termios.c_oflag, + termios.c_cflag, + termios.c_lflag); + (void) printf("%s\t cc: ", pri->pname); + for (i = 0; i < NCCS; i++) { + if (i == NCC) /* show new chars on new line */ + (void) printf("\n%s\t\t", pri->pname); + (void) printf(" %s", + show_char(cbuf, (int)termios.c_cc[i])); + } + (void) fputc('\n', stdout); + } +} + +void +show_termiox(private_t *pri, long offset) +{ + struct termiox termiox; + int i; + + if (Pread(Proc, &termiox, sizeof (termiox), offset) + == sizeof (termiox)) { + (void) printf("%s\thflag=0%.3o cflag=0%.3o rflag=0%.3o", + pri->pname, + termiox.x_hflag, + termiox.x_cflag, + termiox.x_rflag[0]); + for (i = 1; i < NFF; i++) + (void) printf(",0%.3o", termiox.x_rflag[i]); + (void) printf(" sflag=0%.3o\n", + termiox.x_sflag); + } +} + +void +show_sgttyb(private_t *pri, long offset) +{ + struct sgttyb sgttyb; + + if (Pread(Proc, &sgttyb, sizeof (sgttyb), offset) == sizeof (sgttyb)) { + char erase[8]; + char kill[8]; + + (void) printf( + "%s\tispeed=%-2d ospeed=%-2d erase=%s kill=%s flags=0x%.8x\n", + pri->pname, + sgttyb.sg_ispeed&0xff, + sgttyb.sg_ospeed&0xff, + show_char(erase, sgttyb.sg_erase), + show_char(kill, sgttyb.sg_kill), + sgttyb.sg_flags); + } +} + +void +show_ltchars(private_t *pri, long offset) +{ + struct ltchars ltchars; + char *p; + char cbuf[8]; + int i; + + if (Pread(Proc, <chars, sizeof (ltchars), offset) + == sizeof (ltchars)) { + (void) printf("%s\t cc: ", pri->pname); + for (p = (char *)<chars, i = 0; i < sizeof (ltchars); i++) + (void) printf(" %s", show_char(cbuf, (int)*p++)); + (void) fputc('\n', stdout); + } +} + +void +show_tchars(private_t *pri, long offset) +{ + struct tchars tchars; + char *p; + char cbuf[8]; + int i; + + if (Pread(Proc, &tchars, sizeof (tchars), offset) == sizeof (tchars)) { + (void) printf("%s\t cc: ", pri->pname); + for (p = (char *)&tchars, i = 0; i < sizeof (tchars); i++) + (void) printf(" %s", show_char(cbuf, (int)*p++)); + (void) fputc('\n', stdout); + } +} + +void +show_termcb(private_t *pri, long offset) +{ + struct termcb termcb; + + if (Pread(Proc, &termcb, sizeof (termcb), offset) == sizeof (termcb)) { + (void) printf( + "%s\tflgs=0%.2o termt=%d crow=%d ccol=%d vrow=%d lrow=%d\n", + pri->pname, + termcb.st_flgs&0xff, + termcb.st_termt&0xff, + termcb.st_crow&0xff, + termcb.st_ccol&0xff, + termcb.st_vrow&0xff, + termcb.st_lrow&0xff); + } +} + +/* integer value pointed to by ioctl() arg */ +void +show_strint(private_t *pri, int code, long offset) +{ + int val; + + if (Pread(Proc, &val, sizeof (val), offset) == sizeof (val)) { + const char *s = NULL; + + switch (code) { /* interpret these symbolically */ + case I_GRDOPT: + s = strrdopt(val); + break; + case I_GETSIG: + s = strevents(pri, val); + break; + case TIOCFLUSH: + s = tiocflush(pri, val); + break; + } + + if (s == NULL) + (void) printf("%s\t0x%.8lX: %d\n", + pri->pname, offset, val); + else + (void) printf("%s\t0x%.8lX: %s\n", + pri->pname, offset, s); + } +} + +void +show_strioctl(private_t *pri, long offset) +{ + struct strioctl strioctl; + + if (Pread(Proc, &strioctl, sizeof (strioctl), offset) == + sizeof (strioctl)) { + (void) printf( + "%s\tcmd=%s timout=%d len=%d dp=0x%.8lX\n", + pri->pname, + ioctlname(pri, strioctl.ic_cmd), + strioctl.ic_timout, + strioctl.ic_len, + (long)strioctl.ic_dp); + + if (pri->recur++ == 0) /* avoid indefinite recursion */ + show_ioctl(pri, strioctl.ic_cmd, + (long)strioctl.ic_dp); + --pri->recur; + } +} + +#ifdef _LP64 +void +show_strioctl32(private_t *pri, long offset) +{ + struct strioctl32 strioctl; + + if (Pread(Proc, &strioctl, sizeof (strioctl), offset) == + sizeof (strioctl)) { + (void) printf( + "%s\tcmd=%s timout=%d len=%d dp=0x%.8lX\n", + pri->pname, + ioctlname(pri, strioctl.ic_cmd), + strioctl.ic_timout, + strioctl.ic_len, + (long)strioctl.ic_dp); + + if (pri->recur++ == 0) /* avoid indefinite recursion */ + show_ioctl(pri, strioctl.ic_cmd, + (long)strioctl.ic_dp); + --pri->recur; + } +} +#endif /* _LP64 */ + +void +print_strbuf(private_t *pri, struct strbuf *sp, const char *name, int dump) +{ + (void) printf( + "%s\t%s: maxlen=%-4d len=%-4d buf=0x%.8lX", + pri->pname, + name, + sp->maxlen, + sp->len, + (long)sp->buf); + /* + * Should we show the buffer contents? + * Keyed to the '-r fds' and '-w fds' options? + */ + if (sp->buf == NULL || sp->len <= 0) + (void) fputc('\n', stdout); + else { + int nb = (sp->len > 8)? 8 : sp->len; + char buffer[8]; + char obuf[40]; + + if (Pread(Proc, buffer, (size_t)nb, (long)sp->buf) == nb) { + (void) strcpy(obuf, ": \""); + showbytes(buffer, nb, obuf+3); + (void) strcat(obuf, + (nb == sp->len)? + (const char *)"\"" : (const char *)"\".."); + (void) fputs(obuf, stdout); + } + (void) fputc('\n', stdout); + if (dump && sp->len > 8) + showbuffer(pri, (long)sp->buf, (long)sp->len); + } +} + +#ifdef _LP64 +void +print_strbuf32(private_t *pri, struct strbuf32 *sp, const char *name, int dump) +{ + (void) printf( + "%s\t%s: maxlen=%-4d len=%-4d buf=0x%.8lX", + pri->pname, + name, + sp->maxlen, + sp->len, + (long)sp->buf); + /* + * Should we show the buffer contents? + * Keyed to the '-r fds' and '-w fds' options? + */ + if (sp->buf == NULL || sp->len <= 0) + (void) fputc('\n', stdout); + else { + int nb = (sp->len > 8)? 8 : sp->len; + char buffer[8]; + char obuf[40]; + + if (Pread(Proc, buffer, (size_t)nb, (long)sp->buf) == nb) { + (void) strcpy(obuf, ": \""); + showbytes(buffer, nb, obuf+3); + (void) strcat(obuf, + (nb == sp->len)? + (const char *)"\"" : (const char *)"\".."); + (void) fputs(obuf, stdout); + } + (void) fputc('\n', stdout); + if (dump && sp->len > 8) + showbuffer(pri, (long)sp->buf, (long)sp->len); + } +} +#endif /* _LP64 */ + +/* strpeek and strfdinsert flags word */ +const char * +strflags(private_t *pri, int flags) +{ + const char *s; + + switch (flags) { + case 0: + s = "0"; + break; + case RS_HIPRI: + s = "RS_HIPRI"; + break; + default: + (void) sprintf(pri->code_buf, "0x%.4X", flags); + s = pri->code_buf; + } + + return (s); +} + +void +show_strpeek(private_t *pri, long offset) +{ + struct strpeek strpeek; + + if (Pread(Proc, &strpeek, sizeof (strpeek), offset) + == sizeof (strpeek)) { + + print_strbuf(pri, &strpeek.ctlbuf, "ctl", FALSE); + print_strbuf(pri, &strpeek.databuf, "dat", FALSE); + + (void) printf("%s\tflags=%s\n", + pri->pname, + strflags(pri, strpeek.flags)); + } +} + +#ifdef _LP64 +void +show_strpeek32(private_t *pri, long offset) +{ + struct strpeek32 strpeek; + + if (Pread(Proc, &strpeek, sizeof (strpeek), offset) + == sizeof (strpeek)) { + + print_strbuf32(pri, &strpeek.ctlbuf, "ctl", FALSE); + print_strbuf32(pri, &strpeek.databuf, "dat", FALSE); + + (void) printf("%s\tflags=%s\n", + pri->pname, + strflags(pri, strpeek.flags)); + } +} +#endif /* _LP64 */ + +void +show_strfdinsert(private_t *pri, long offset) +{ + struct strfdinsert strfdinsert; + + if (Pread(Proc, &strfdinsert, sizeof (strfdinsert), offset) == + sizeof (strfdinsert)) { + + print_strbuf(pri, &strfdinsert.ctlbuf, "ctl", FALSE); + print_strbuf(pri, &strfdinsert.databuf, "dat", FALSE); + + (void) printf("%s\tflags=%s fildes=%d offset=%d\n", + pri->pname, + strflags(pri, strfdinsert.flags), + strfdinsert.fildes, + strfdinsert.offset); + } +} + +#ifdef _LP64 +void +show_strfdinsert32(private_t *pri, long offset) +{ + struct strfdinsert32 strfdinsert; + + if (Pread(Proc, &strfdinsert, sizeof (strfdinsert), offset) == + sizeof (strfdinsert)) { + + print_strbuf32(pri, &strfdinsert.ctlbuf, "ctl", FALSE); + print_strbuf32(pri, &strfdinsert.databuf, "dat", FALSE); + + (void) printf("%s\tflags=%s fildes=%d offset=%d\n", + pri->pname, + strflags(pri, strfdinsert.flags), + strfdinsert.fildes, + strfdinsert.offset); + } +} +#endif /* _LP64 */ + +void +show_strrecvfd(private_t *pri, long offset) +{ + struct strrecvfd strrecvfd; + + if (Pread(Proc, &strrecvfd, sizeof (strrecvfd), offset) == + sizeof (strrecvfd)) { + (void) printf( + "%s\tfd=%-5d uid=%-5u gid=%u\n", + pri->pname, + strrecvfd.fd, + strrecvfd.uid, + strrecvfd.gid); + } +} + +void +show_strlist(private_t *pri, long offset) +{ + struct str_list strlist; + struct str_mlist list; + int count; + + if (Pread(Proc, &strlist, sizeof (strlist), offset) == + sizeof (strlist)) { + (void) printf("%s\tnmods=%d modlist=0x%.8lX\n", + pri->pname, + strlist.sl_nmods, + (long)strlist.sl_modlist); + + count = strlist.sl_nmods; + offset = (long)strlist.sl_modlist; + while (!interrupt && --count >= 0) { + if (Pread(Proc, &list, sizeof (list), offset) != + sizeof (list)) + break; + (void) printf("%s\t\t\"%.*s\"\n", + pri->pname, + (int)sizeof (list.l_name), + list.l_name); + offset += sizeof (struct str_mlist); + } + } +} + +#ifdef _LP64 +void +show_strlist32(private_t *pri, long offset) +{ + struct str_list32 strlist; + struct str_mlist list; + int count; + + if (Pread(Proc, &strlist, sizeof (strlist), offset) == + sizeof (strlist)) { + (void) printf("%s\tnmods=%d modlist=0x%.8lX\n", + pri->pname, + strlist.sl_nmods, + (long)strlist.sl_modlist); + + count = strlist.sl_nmods; + offset = (long)strlist.sl_modlist; + while (!interrupt && --count >= 0) { + if (Pread(Proc, &list, sizeof (list), offset) != + sizeof (list)) + break; + (void) printf("%s\t\t\"%.*s\"\n", + pri->pname, + (int)sizeof (list.l_name), + list.l_name); + offset += sizeof (struct str_mlist); + } + } +} +#endif /* _LP64 */ + +void +show_jwinsize(private_t *pri, long offset) +{ + struct jwinsize jwinsize; + + if (Pread(Proc, &jwinsize, sizeof (jwinsize), offset) == + sizeof (jwinsize)) { + (void) printf( + "%s\tbytesx=%-3u bytesy=%-3u bitsx=%-3u bitsy=%-3u\n", + pri->pname, + (unsigned)jwinsize.bytesx, + (unsigned)jwinsize.bytesy, + (unsigned)jwinsize.bitsx, + (unsigned)jwinsize.bitsy); + } +} + +void +show_winsize(private_t *pri, long offset) +{ + struct winsize winsize; + + if (Pread(Proc, &winsize, sizeof (winsize), offset) + == sizeof (winsize)) { + (void) printf( + "%s\trow=%-3d col=%-3d xpixel=%-3d ypixel=%-3d\n", + pri->pname, + winsize.ws_row, + winsize.ws_col, + winsize.ws_xpixel, + winsize.ws_ypixel); + } +} + +struct audio_stuff { + uint_t bit; + const char *str; +}; + +const struct audio_stuff audio_output_ports[] = { + { AUDIO_SPEAKER, "SPEAKER" }, + { AUDIO_HEADPHONE, "HEADPHONE" }, + { AUDIO_LINE_OUT, "LINE_OUT" }, + { AUDIO_SPDIF_OUT, "SPDIF_OUT" }, + { AUDIO_AUX1_OUT, "AUX1_OUT" }, + { AUDIO_AUX2_OUT, "AUX2_OUT" }, + { 0, NULL } +}; + +const struct audio_stuff audio_input_ports[] = { + { AUDIO_MICROPHONE, "MICROPHONE" }, + { AUDIO_LINE_IN, "LINE_IN" }, + { AUDIO_CD, "CD" }, + { AUDIO_SPDIF_IN, "SPDIF_IN" }, + { AUDIO_AUX1_IN, "AUX1_IN" }, + { AUDIO_AUX2_IN, "AUX2_IN" }, + { AUDIO_CODEC_LOOPB_IN, "CODEC_LOOPB_IN" }, + { AUDIO_SUNVTS, "SUNVTS" }, + { 0, NULL } +}; + +static const struct audio_stuff audio_hw_features[] = { + { AUDIO_HWFEATURE_DUPLEX, "DUPLEX" }, + { AUDIO_HWFEATURE_MSCODEC, "MSCODEC" }, + { AUDIO_HWFEATURE_IN2OUT, "IN2OUT" }, + { AUDIO_HWFEATURE_PLAY, "PLAY" }, + { AUDIO_HWFEATURE_RECORD, "RECORD" }, + { 0, NULL } +}; + +static const struct audio_stuff audio_sw_features[] = { + { AUDIO_SWFEATURE_MIXER, "MIXER" }, + { 0, NULL } +}; + +void +show_audio_features(const private_t *pri, + const struct audio_stuff *audio_porttab, uint_t features, + const char *name) +{ + (void) printf("%s\t%s=", pri->pname, name); + if (features == 0) { + (void) printf("0\n"); + return; + } + + for (; audio_porttab->bit != 0; ++audio_porttab) { + if (features & audio_porttab->bit) { + (void) printf(audio_porttab->str); + features &= ~audio_porttab->bit; + if (features) + (void) putchar('|'); + } + } + if (features) + (void) printf("0x%x", features); + (void) putchar('\n'); +} + +void +show_audio_ports(private_t *pri, const char *mode, + const char *field, uint_t ports) +{ + const struct audio_stuff *audio_porttab; + + (void) printf("%s\t%s\t%s=", pri->pname, mode, field); + if (ports == 0) { + (void) printf("0\n"); + return; + } + if (*mode == 'p') + audio_porttab = audio_output_ports; + else + audio_porttab = audio_input_ports; + for (; audio_porttab->bit != 0; ++audio_porttab) { + if (ports & audio_porttab->bit) { + (void) printf(audio_porttab->str); + ports &= ~audio_porttab->bit; + if (ports) + (void) putchar('|'); + } + } + if (ports) + (void) printf("0x%x", ports); + (void) putchar('\n'); +} + +void +show_audio_prinfo(private_t *pri, const char *mode, struct audio_prinfo *au_pr) +{ + const char *s; + + /* + * The following values describe the audio data encoding. + */ + + (void) printf("%s\t%s\tsample_rate=%u channels=%u precision=%u\n", + pri->pname, mode, + au_pr->sample_rate, + au_pr->channels, + au_pr->precision); + + s = NULL; + switch (au_pr->encoding) { + case AUDIO_ENCODING_NONE: s = "NONE"; break; + case AUDIO_ENCODING_ULAW: s = "ULAW"; break; + case AUDIO_ENCODING_ALAW: s = "ALAW"; break; + case AUDIO_ENCODING_LINEAR: s = "LINEAR"; break; + case AUDIO_ENCODING_DVI: s = "DVI"; break; + case AUDIO_ENCODING_LINEAR8: s = "LINEAR8"; break; + } + if (s) + (void) printf("%s\t%s\tencoding=%s\n", pri->pname, mode, s); + else { + (void) printf("%s\t%s\tencoding=%u\n", + pri->pname, mode, au_pr->encoding); + } + + /* + * The following values control audio device configuration + */ + + (void) printf( + "%s\t%s\tgain=%u buffer_size=%u\n", + pri->pname, mode, + au_pr->gain, + au_pr->buffer_size); + show_audio_ports(pri, mode, "port", au_pr->port); + show_audio_ports(pri, mode, "avail_ports", au_pr->avail_ports); + show_audio_ports(pri, mode, "mod_ports", au_pr->mod_ports); + + /* + * The following values describe driver state + */ + + (void) printf("%s\t%s\tsamples=%u eof=%u pause=%u error=%u\n", + pri->pname, mode, + au_pr->samples, + au_pr->eof, + au_pr->pause, + au_pr->error); + (void) printf("%s\t%s\twaiting=%u balance=%u minordev=%u\n", + pri->pname, mode, + au_pr->waiting, + au_pr->balance, + au_pr->minordev); + + /* + * The following values are read-only state flags + */ + (void) printf("%s\t%s\topen=%u active=%u\n", + pri->pname, mode, + au_pr->open, + au_pr->active); +} + +void +show_audio_info(private_t *pri, long offset) +{ + struct audio_info au; + + if (Pread(Proc, &au, sizeof (au), offset) == sizeof (au)) { + show_audio_prinfo(pri, "play", &au.play); + show_audio_prinfo(pri, "record", &au.record); + (void) printf("%s\tmonitor_gain=%u output_muted=%u\n", + pri->pname, au.monitor_gain, au.output_muted); + show_audio_features(pri, audio_hw_features, au.hw_features, + "hw_features"); + show_audio_features(pri, audio_sw_features, au.sw_features, + "sw_features"); + show_audio_features(pri, audio_sw_features, + au.sw_features_enabled, "sw_features_enabled"); + } +} + +void +show_ioctl(private_t *pri, int code, long offset) +{ + int lp64 = (data_model == PR_MODEL_LP64); + int err = pri->Errno; /* don't display output parameters */ + /* for a failed system call */ +#ifndef _LP64 + if (lp64) + return; +#endif + if (offset == 0) + return; + + switch (code) { + case TCGETA: + if (err) + break; + /*FALLTHROUGH*/ + case TCSETA: + case TCSETAW: + case TCSETAF: + show_termio(pri, offset); + break; + case TCGETS: + if (err) + break; + /*FALLTHROUGH*/ + case TCSETS: + case TCSETSW: + case TCSETSF: + show_termios(pri, offset); + break; + case TCGETX: + if (err) + break; + /*FALLTHROUGH*/ + case TCSETX: + case TCSETXW: + case TCSETXF: + show_termiox(pri, offset); + break; + case TIOCGETP: + if (err) + break; + /*FALLTHROUGH*/ + case TIOCSETN: + case TIOCSETP: + show_sgttyb(pri, offset); + break; + case TIOCGLTC: + if (err) + break; + /*FALLTHROUGH*/ + case TIOCSLTC: + show_ltchars(pri, offset); + break; + case TIOCGETC: + if (err) + break; + /*FALLTHROUGH*/ + case TIOCSETC: + show_tchars(pri, offset); + break; + case LDGETT: + if (err) + break; + /*FALLTHROUGH*/ + case LDSETT: + show_termcb(pri, offset); + break; + /* streams ioctl()s */ +#if 0 + /* these are displayed as strings in the arg list */ + /* by prt_ioa(). don't display them again here */ + case I_PUSH: + case I_LOOK: + case I_FIND: + /* these are displayed as decimal in the arg list */ + /* by prt_ioa(). don't display them again here */ + case I_LINK: + case I_UNLINK: + case I_SENDFD: + /* these are displayed symbolically in the arg list */ + /* by prt_ioa(). don't display them again here */ + case I_SRDOPT: + case I_SETSIG: + case I_FLUSH: + break; + /* this one just ignores the argument */ + case I_POP: + break; +#endif + /* these return something in an int pointed to by arg */ + case I_NREAD: + case I_GRDOPT: + case I_GETSIG: + case TIOCGSID: + case TIOCGPGRP: + case TIOCLGET: + case FIONREAD: + case FIORDCHK: + if (err) + break; + /*FALLTHROUGH*/ + /* these pass something in an int pointed to by arg */ + case TIOCSPGRP: + case TIOCFLUSH: + case TIOCLBIS: + case TIOCLBIC: + case TIOCLSET: + show_strint(pri, code, offset); + break; + /* these all point to structures */ + case I_STR: +#ifdef _LP64 + if (lp64) + show_strioctl(pri, offset); + else + show_strioctl32(pri, offset); +#else + show_strioctl(pri, offset); +#endif + break; + case I_PEEK: +#ifdef _LP64 + if (lp64) + show_strpeek(pri, offset); + else + show_strpeek32(pri, offset); +#else + show_strpeek(pri, offset); +#endif + break; + case I_FDINSERT: +#ifdef _LP64 + if (lp64) + show_strfdinsert(pri, offset); + else + show_strfdinsert32(pri, offset); +#else + show_strfdinsert(pri, offset); +#endif + break; + case I_RECVFD: + if (err) + break; + show_strrecvfd(pri, offset); + break; + case I_LIST: + if (err) + break; +#ifdef _LP64 + if (lp64) + show_strlist(pri, offset); + else + show_strlist32(pri, offset); +#else + show_strlist(pri, offset); +#endif + break; + case JWINSIZE: + if (err) + break; + show_jwinsize(pri, offset); + break; + case TIOCGWINSZ: + if (err) + break; + /*FALLTHROUGH*/ + case TIOCSWINSZ: + show_winsize(pri, offset); + break; + case AUDIO_GETINFO: + case (int)AUDIO_SETINFO: + show_audio_info(pri, offset); + break; + + default: + if ((code & ~0xff) == ZFS_IOC) { + show_zfs_ioc(pri, offset); + break; + } + + if (code & IOC_INOUT) { + const char *str = ioctldatastruct(code); + + (void) printf("\t\t%s", + (code & IOC_INOUT) == IOC_INOUT ? "write/read" : + code & IOC_IN ? "write" : "read"); + if (str != NULL) { + (void) printf(" (struct %s)\n", str); + } else { + (void) printf(" %d bytes\n", + (code >> 16) & IOCPARM_MASK); + } + } + } +} + +void +show_statvfs(private_t *pri) +{ + long offset; + struct statvfs statvfs; + char *cp; + + if (pri->sys_nargs > 1 && (offset = pri->sys_args[1]) != NULL && + Pread(Proc, &statvfs, sizeof (statvfs), offset) + == sizeof (statvfs)) { + (void) printf( + "%s\tbsize=%-10lu frsize=%-9lu blocks=%-8llu bfree=%-9llu\n", + pri->pname, + statvfs.f_bsize, + statvfs.f_frsize, + (u_longlong_t)statvfs.f_blocks, + (u_longlong_t)statvfs.f_bfree); + (void) printf( + "%s\tbavail=%-9llu files=%-10llu ffree=%-9llu favail=%-9llu\n", + pri->pname, + (u_longlong_t)statvfs.f_bavail, + (u_longlong_t)statvfs.f_files, + (u_longlong_t)statvfs.f_ffree, + (u_longlong_t)statvfs.f_favail); + (void) printf( + "%s\tfsid=0x%-9.4lX basetype=%-7.16s namemax=%ld\n", + pri->pname, + statvfs.f_fsid, + statvfs.f_basetype, + (long)statvfs.f_namemax); + (void) printf( + "%s\tflag=%s\n", + pri->pname, + svfsflags(pri, (ulong_t)statvfs.f_flag)); + cp = statvfs.f_fstr + strlen(statvfs.f_fstr); + if (cp < statvfs.f_fstr + sizeof (statvfs.f_fstr) - 1 && + *(cp+1) != '\0') + *cp = ' '; + (void) printf("%s\tfstr=\"%.*s\"\n", + pri->pname, + (int)sizeof (statvfs.f_fstr), + statvfs.f_fstr); + } +} + +#ifdef _LP64 +void +show_statvfs32(private_t *pri) +{ + long offset; + struct statvfs32 statvfs; + char *cp; + + if (pri->sys_nargs > 1 && (offset = pri->sys_args[1]) != NULL && + Pread(Proc, &statvfs, sizeof (statvfs), offset) + == sizeof (statvfs)) { + (void) printf( + "%s\tbsize=%-10u frsize=%-9u blocks=%-8u bfree=%-9u\n", + pri->pname, + statvfs.f_bsize, + statvfs.f_frsize, + statvfs.f_blocks, + statvfs.f_bfree); + (void) printf( + "%s\tbavail=%-9u files=%-10u ffree=%-9u favail=%-9u\n", + pri->pname, + statvfs.f_bavail, + statvfs.f_files, + statvfs.f_ffree, + statvfs.f_favail); + (void) printf( + "%s\tfsid=0x%-9.4X basetype=%-7.16s namemax=%d\n", + pri->pname, + statvfs.f_fsid, + statvfs.f_basetype, + (int)statvfs.f_namemax); + (void) printf( + "%s\tflag=%s\n", + pri->pname, + svfsflags(pri, (ulong_t)statvfs.f_flag)); + cp = statvfs.f_fstr + strlen(statvfs.f_fstr); + if (cp < statvfs.f_fstr + sizeof (statvfs.f_fstr) - 1 && + *(cp+1) != '\0') + *cp = ' '; + (void) printf("%s\tfstr=\"%.*s\"\n", + pri->pname, + (int)sizeof (statvfs.f_fstr), + statvfs.f_fstr); + } +} +#endif /* _LP64 */ + +void +show_statvfs64(private_t *pri) +{ + long offset; + struct statvfs64_32 statvfs; + char *cp; + + if (pri->sys_nargs > 1 && (offset = pri->sys_args[1]) != NULL && + Pread(Proc, &statvfs, sizeof (statvfs), offset) + == sizeof (statvfs)) { + (void) printf( + "%s\tbsize=%-10u frsize=%-9u blocks=%-8llu bfree=%-9llu\n", + pri->pname, + statvfs.f_bsize, + statvfs.f_frsize, + (u_longlong_t)statvfs.f_blocks, + (u_longlong_t)statvfs.f_bfree); + (void) printf( + "%s\tbavail=%-9llu files=%-10llu ffree=%-9llu favail=%-9llu\n", + pri->pname, + (u_longlong_t)statvfs.f_bavail, + (u_longlong_t)statvfs.f_files, + (u_longlong_t)statvfs.f_ffree, + (u_longlong_t)statvfs.f_favail); + (void) printf( + "%s\tfsid=0x%-9.4X basetype=%-7.16s namemax=%d\n", + pri->pname, + statvfs.f_fsid, + statvfs.f_basetype, + (int)statvfs.f_namemax); + (void) printf( + "%s\tflag=%s\n", + pri->pname, + svfsflags(pri, (ulong_t)statvfs.f_flag)); + cp = statvfs.f_fstr + strlen(statvfs.f_fstr); + if (cp < statvfs.f_fstr + sizeof (statvfs.f_fstr) - 1 && + *(cp+1) != '\0') + *cp = ' '; + (void) printf("%s\tfstr=\"%.*s\"\n", + pri->pname, + (int)sizeof (statvfs.f_fstr), + statvfs.f_fstr); + } +} + +void +show_statfs(private_t *pri) +{ + long offset; + struct statfs statfs; + + if (pri->sys_nargs >= 2 && (offset = pri->sys_args[1]) != NULL && + Pread(Proc, &statfs, sizeof (statfs), offset) == sizeof (statfs)) { + (void) printf( + "%s\tfty=%d bsz=%ld fsz=%ld blk=%ld bfr=%ld fil=%lu ffr=%lu\n", + pri->pname, + statfs.f_fstyp, + statfs.f_bsize, + statfs.f_frsize, + statfs.f_blocks, + statfs.f_bfree, + statfs.f_files, + statfs.f_ffree); + (void) printf("%s\t fname=%.6s fpack=%.6s\n", + pri->pname, + statfs.f_fname, + statfs.f_fpack); + } +} + +#ifdef _LP64 +void +show_statfs32(private_t *pri) +{ + long offset; + struct statfs32 statfs; + + if (pri->sys_nargs >= 2 && (offset = pri->sys_args[1]) != NULL && + Pread(Proc, &statfs, sizeof (statfs), offset) == sizeof (statfs)) { + (void) printf( + "%s\tfty=%d bsz=%d fsz=%d blk=%d bfr=%d fil=%u ffr=%u\n", + pri->pname, + statfs.f_fstyp, + statfs.f_bsize, + statfs.f_frsize, + statfs.f_blocks, + statfs.f_bfree, + statfs.f_files, + statfs.f_ffree); + (void) printf("%s\t fname=%.6s fpack=%.6s\n", + pri->pname, + statfs.f_fname, + statfs.f_fpack); + } +} +#endif /* _LP64 */ + +void +show_flock32(private_t *pri, long offset) +{ + struct flock32 flock; + + if (Pread(Proc, &flock, sizeof (flock), offset) == sizeof (flock)) { + const char *str = NULL; + + (void) printf("%s\ttyp=", pri->pname); + + switch (flock.l_type) { + case F_RDLCK: + str = "F_RDLCK"; + break; + case F_WRLCK: + str = "F_WRLCK"; + break; + case F_UNLCK: + str = "F_UNLCK"; + break; + } + if (str != NULL) + (void) printf("%s", str); + else + (void) printf("%-7d", flock.l_type); + + str = whencearg(flock.l_whence); + if (str != NULL) + (void) printf(" whence=%s", str); + else + (void) printf(" whence=%-8u", flock.l_whence); + + (void) printf( + " start=%-5d len=%-5d sys=%-2u pid=%d\n", + flock.l_start, + flock.l_len, + flock.l_sysid, + flock.l_pid); + } +} + +void +show_flock64(private_t *pri, long offset) +{ + struct flock64 flock; + + if (Pread(Proc, &flock, sizeof (flock), offset) == sizeof (flock)) { + const char *str = NULL; + + (void) printf("%s\ttyp=", pri->pname); + + switch (flock.l_type) { + case F_RDLCK: + str = "F_RDLCK"; + break; + case F_WRLCK: + str = "F_WRLCK"; + break; + case F_UNLCK: + str = "F_UNLCK"; + break; + } + if (str != NULL) + (void) printf("%s", str); + else + (void) printf("%-7d", flock.l_type); + + str = whencearg(flock.l_whence); + if (str != NULL) + (void) printf(" whence=%s", str); + else + (void) printf(" whence=%-8u", flock.l_whence); + + (void) printf( + " start=%-5lld len=%-5lld sys=%-2u pid=%d\n", + (long long)flock.l_start, + (long long)flock.l_len, + flock.l_sysid, + (int)flock.l_pid); + } +} + +void +show_share(private_t *pri, long offset) +{ + struct fshare fshare; + + if (Pread(Proc, &fshare, sizeof (fshare), offset) == sizeof (fshare)) { + const char *str = NULL; + int manddny = 0; + + (void) printf("%s\taccess=", pri->pname); + + switch (fshare.f_access) { + case F_RDACC: + str = "F_RDACC"; + break; + case F_WRACC: + str = "F_WRACC"; + break; + case F_RWACC: + str = "F_RWACC"; + break; + } + if (str != NULL) + (void) printf("%s", str); + else + (void) printf("%-7d", fshare.f_access); + + str = NULL; + if (fshare.f_deny & F_MANDDNY) { + fshare.f_deny &= ~F_MANDDNY; + manddny = 1; + } + switch (fshare.f_deny) { + case F_NODNY: + str = "F_NODNY"; + break; + case F_RDDNY: + str = "F_RDDNY"; + break; + case F_WRDNY: + str = "F_WRDNY"; + break; + case F_RWDNY: + str = "F_RWDNY"; + break; + case F_COMPAT: + str = "F_COMPAT"; + break; + } + if (str != NULL) { + if (manddny) + (void) printf(" deny=F_MANDDNY|%s", str); + else + (void) printf(" deny=%s", str); + } else { + (void) printf(" deny=0x%x", manddny? + fshare.f_deny | F_MANDDNY : fshare.f_deny); + } + + (void) printf(" id=%x\n", fshare.f_id); + } +} + +void +show_ffg(private_t *pri) +{ + (void) putchar('\t'); + (void) putchar('\t'); + prt_ffg(pri, 0, pri->Rval1); + (void) puts(pri->sys_string); +} + +/* print values in fcntl() pointed-to structure */ +void +show_fcntl(private_t *pri) +{ + long offset; + + if (pri->sys_nargs >= 2 && pri->sys_args[1] == F_GETFL) { + show_ffg(pri); + return; + } + + if (pri->sys_nargs < 3 || (offset = pri->sys_args[2]) == NULL) + return; + + switch (pri->sys_args[1]) { +#ifdef _LP64 + case F_GETLK: + case F_SETLK: + case F_SETLKW: + case F_FREESP: + case F_ALLOCSP: + case F_SETLK_NBMAND: + if (data_model == PR_MODEL_LP64) + show_flock64(pri, offset); + else + show_flock32(pri, offset); + break; + case 33: /* F_GETLK64 */ + case 34: /* F_SETLK64 */ + case 35: /* F_SETLKW64 */ + case 27: /* F_FREESP64 */ + case 28: /* F_ALLOCSP64 */ + case 44: /* F_SETLK64_NBMAND */ + show_flock64(pri, offset); + break; +#else /* _LP64 */ + case F_GETLK: + case F_SETLK: + case F_SETLKW: + case F_FREESP: + case F_ALLOCSP: + case F_SETLK_NBMAND: + show_flock32(pri, offset); + break; + case F_GETLK64: + case F_SETLK64: + case F_SETLKW64: + case F_FREESP64: + case F_ALLOCSP64: + case F_SETLK64_NBMAND: + show_flock64(pri, offset); + break; +#endif /* _LP64 */ + case F_SHARE: + case F_UNSHARE: + show_share(pri, offset); + break; + } +} + +void +show_strbuf(private_t *pri, long offset, const char *name, int dump) +{ + struct strbuf strbuf; + + if (Pread(Proc, &strbuf, sizeof (strbuf), offset) == sizeof (strbuf)) + print_strbuf(pri, &strbuf, name, dump); +} + +#ifdef _LP64 +void +show_strbuf32(private_t *pri, long offset, const char *name, int dump) +{ + struct strbuf32 strbuf; + + if (Pread(Proc, &strbuf, sizeof (strbuf), offset) == sizeof (strbuf)) + print_strbuf32(pri, &strbuf, name, dump); +} +#endif /* _LP64 */ + +void +show_gp_msg(private_t *pri, int what) +{ + long offset; + int dump = FALSE; + int fdp1 = pri->sys_args[0] + 1; + + switch (what) { + case SYS_getmsg: + case SYS_getpmsg: + if (pri->Errno == 0 && prismember(&readfd, fdp1)) + dump = TRUE; + break; + case SYS_putmsg: + case SYS_putpmsg: + if (prismember(&writefd, fdp1)) + dump = TRUE; + break; + } + + /* enter region of lengthy output */ + if (dump) + Eserialize(); + +#ifdef _LP64 + if (pri->sys_nargs >= 2 && (offset = pri->sys_args[1]) != NULL) { + if (data_model == PR_MODEL_LP64) + show_strbuf(pri, offset, "ctl", dump); + else + show_strbuf32(pri, offset, "ctl", dump); + } + if (pri->sys_nargs >= 3 && (offset = pri->sys_args[2]) != NULL) { + if (data_model == PR_MODEL_LP64) + show_strbuf(pri, offset, "dat", dump); + else + show_strbuf32(pri, offset, "dat", dump); + } +#else /* _LP64 */ + if (pri->sys_nargs >= 2 && (offset = pri->sys_args[1]) != NULL) + show_strbuf(pri, offset, "ctl", dump); + if (pri->sys_nargs >= 3 && (offset = pri->sys_args[2]) != NULL) + show_strbuf(pri, offset, "dat", dump); +#endif /* _LP64 */ + + /* exit region of lengthy output */ + if (dump) + Xserialize(); +} + +void +show_int(private_t *pri, long offset, const char *name) +{ + int value; + + if (offset != 0 && + Pread(Proc, &value, sizeof (value), offset) == sizeof (value)) + (void) printf("%s\t%s:\t%d\n", + pri->pname, + name, + value); +} + +void +show_hhex_int(private_t *pri, long offset, const char *name) +{ + int value; + + if (Pread(Proc, &value, sizeof (value), offset) == sizeof (value)) + (void) printf("%s\t%s:\t0x%.4X\n", + pri->pname, + name, + value); +} + +#define ALL_POLL_FLAGS (POLLIN|POLLPRI|POLLOUT| \ + POLLRDNORM|POLLRDBAND|POLLWRBAND|POLLERR|POLLHUP|POLLNVAL) + +const char * +pollevent(private_t *pri, int arg) +{ + char *str = pri->code_buf; + + if (arg == 0) + return ("0"); + if (arg & ~ALL_POLL_FLAGS) { + (void) sprintf(str, "0x%-5X", arg); + return ((const char *)str); + } + + *str = '\0'; + if (arg & POLLIN) + (void) strcat(str, "|POLLIN"); + if (arg & POLLPRI) + (void) strcat(str, "|POLLPRI"); + if (arg & POLLOUT) + (void) strcat(str, "|POLLOUT"); + if (arg & POLLRDNORM) + (void) strcat(str, "|POLLRDNORM"); + if (arg & POLLRDBAND) + (void) strcat(str, "|POLLRDBAND"); + if (arg & POLLWRBAND) + (void) strcat(str, "|POLLWRBAND"); + if (arg & POLLERR) + (void) strcat(str, "|POLLERR"); + if (arg & POLLHUP) + (void) strcat(str, "|POLLHUP"); + if (arg & POLLNVAL) + (void) strcat(str, "|POLLNVAL"); + + return ((const char *)(str+1)); +} + +static void +show_one_pollfd(private_t *pri, struct pollfd *ppollfd) +{ + /* + * can't print both events and revents in same printf. + * pollevent() returns a pointer to a TSD location. + */ + (void) printf("%s\tfd=%-2d ev=%s", + pri->pname, ppollfd->fd, pollevent(pri, ppollfd->events)); + (void) printf(" rev=%s\n", pollevent(pri, ppollfd->revents)); +} + +static void +show_all_pollfds(private_t *pri, long offset, int nfds) +{ + struct pollfd pollfd[2]; + int skip = -1; + + for (; nfds && !interrupt; nfds--, offset += sizeof (struct pollfd)) { + if (Pread(Proc, &pollfd[0], sizeof (struct pollfd), offset) != + sizeof (struct pollfd)) + continue; + + if (skip >= 0 && pollfd[0].fd == pollfd[1].fd && + pollfd[0].events == pollfd[1].events && + pollfd[0].revents == pollfd[1].revents) { + skip++; + continue; + } + + if (skip > 0) + (void) printf("%s\t...last pollfd structure" + " repeated %d time%s...\n", + pri->pname, skip, (skip == 1 ? "" : "s")); + + skip = 0; + show_one_pollfd(pri, &pollfd[0]); + pollfd[1] = pollfd[0]; + } + + if (skip > 0) + (void) printf( + "%s\t...last pollfd structure repeated %d time%s...\n", + pri->pname, skip, (skip == 1 ? "" : "s")); +} + +void +show_pollsys(private_t *pri) +{ + long offset; + int nfds; + int serial = 0; + + if (pri->sys_nargs < 2) + return; + + offset = pri->sys_args[0]; + nfds = pri->sys_args[1]; + + /* enter region of lengthy output */ + if (offset != NULL && nfds > 32) { + Eserialize(); + serial = 1; + } + + if (offset != NULL && nfds > 0) + show_all_pollfds(pri, offset, nfds); + + if (pri->sys_nargs > 2) + show_timestruc(pri, (long)pri->sys_args[2], "timeout"); + + if (pri->sys_nargs > 3) + show_sigset(pri, (long)pri->sys_args[3], "sigmask"); + + /* exit region of lengthy output */ + if (serial) + Xserialize(); +} + +static void +show_perm64(private_t *pri, struct ipc_perm64 *ip) +{ + (void) printf("%s\tu=%-5u g=%-5u cu=%-5u cg=%-5u z=%-5d " + "m=0%.6o key=%d projid=%-5d\n", + pri->pname, + ip->ipcx_uid, + ip->ipcx_gid, + ip->ipcx_cuid, + ip->ipcx_cgid, + (int)ip->ipcx_zoneid, + (unsigned int)ip->ipcx_mode, + ip->ipcx_key, + (int)ip->ipcx_projid); +} + +void +show_perm(private_t *pri, struct ipc_perm *ip) +{ + (void) printf( + "%s\tu=%-5u g=%-5u cu=%-5u cg=%-5u m=0%.6o seq=%u key=%d\n", + pri->pname, + ip->uid, + ip->gid, + ip->cuid, + ip->cgid, + (int)ip->mode, + ip->seq, + ip->key); +} + +#ifdef _LP64 +void +show_perm32(private_t *pri, struct ipc_perm32 *ip) +{ + (void) printf( + "%s\tu=%-5u g=%-5u cu=%-5u cg=%-5u m=0%.6o seq=%u key=%d\n", + pri->pname, + ip->uid, + ip->gid, + ip->cuid, + ip->cgid, + ip->mode, + ip->seq, + ip->key); +} +#endif /* _LP64 */ + +static void +show_msgctl64(private_t *pri, long offset) +{ + struct msqid_ds64 msgq; + + if (offset != NULL && + Pread(Proc, &msgq, sizeof (msgq), offset) == sizeof (msgq)) { + show_perm64(pri, &msgq.msgx_perm); + + (void) printf("%s\tbytes=%-5llu msgs=%-5llu maxby=%-5llu " + "lspid=%-5d lrpid=%-5d\n", pri->pname, + (unsigned long long)msgq.msgx_cbytes, + (unsigned long long)msgq.msgx_qnum, + (unsigned long long)msgq.msgx_qbytes, + (int)msgq.msgx_lspid, + (int)msgq.msgx_lrpid); + + prtime(pri, " st = ", (time_t)msgq.msgx_stime); + prtime(pri, " rt = ", (time_t)msgq.msgx_rtime); + prtime(pri, " ct = ", (time_t)msgq.msgx_ctime); + } +} + +void +show_msgctl(private_t *pri, long offset) +{ + struct msqid_ds msgq; + + if (offset != NULL && + Pread(Proc, &msgq, sizeof (msgq), offset) == sizeof (msgq)) { + show_perm(pri, &msgq.msg_perm); + + (void) printf( + "%s\tbytes=%-5lu msgs=%-5lu maxby=%-5lu lspid=%-5u lrpid=%-5u\n", + pri->pname, + msgq.msg_cbytes, + msgq.msg_qnum, + msgq.msg_qbytes, + (int)msgq.msg_lspid, + (int)msgq.msg_lrpid); + + prtime(pri, " st = ", msgq.msg_stime); + prtime(pri, " rt = ", msgq.msg_rtime); + prtime(pri, " ct = ", msgq.msg_ctime); + } +} + +#ifdef _LP64 +void +show_msgctl32(private_t *pri, long offset) +{ + struct msqid_ds32 msgq; + + if (offset != NULL && + Pread(Proc, &msgq, sizeof (msgq), offset) == sizeof (msgq)) { + show_perm32(pri, &msgq.msg_perm); + + (void) printf( + "%s\tbytes=%-5u msgs=%-5u maxby=%-5u lspid=%-5u lrpid=%-5u\n", + pri->pname, + msgq.msg_cbytes, + msgq.msg_qnum, + msgq.msg_qbytes, + msgq.msg_lspid, + msgq.msg_lrpid); + + prtime(pri, " st = ", msgq.msg_stime); + prtime(pri, " rt = ", msgq.msg_rtime); + prtime(pri, " ct = ", msgq.msg_ctime); + } +} +#endif /* _LP64 */ + +void +show_msgbuf(private_t *pri, long offset, long msgsz) +{ + struct msgbuf msgb; + + if (offset != NULL && + Pread(Proc, &msgb, sizeof (msgb.mtype), offset) == + sizeof (msgb.mtype)) { + /* enter region of lengthy output */ + if (msgsz > MYBUFSIZ / 4) + Eserialize(); + + (void) printf("%s\tmtype=%lu mtext[]=\n", + pri->pname, + msgb.mtype); + showbuffer(pri, + (long)(offset + sizeof (msgb.mtype)), msgsz); + + /* exit region of lengthy output */ + if (msgsz > MYBUFSIZ / 4) + Xserialize(); + } +} + +#ifdef _LP64 +void +show_msgbuf32(private_t *pri, long offset, long msgsz) +{ + struct ipcmsgbuf32 msgb; + + if (offset != NULL && + Pread(Proc, &msgb, sizeof (msgb.mtype), offset) == + sizeof (msgb.mtype)) { + /* enter region of lengthy output */ + if (msgsz > MYBUFSIZ / 4) + Eserialize(); + + (void) printf("%s\tmtype=%u mtext[]=\n", + pri->pname, + msgb.mtype); + showbuffer(pri, + (long)(offset + sizeof (msgb.mtype)), msgsz); + + /* exit region of lengthy output */ + if (msgsz > MYBUFSIZ / 4) + Xserialize(); + } +} +#endif /* _LP64 */ + +#ifdef _LP64 +void +show_msgsys(private_t *pri, long msgsz) +{ + switch (pri->sys_args[0]) { + case 0: /* msgget() */ + break; + case 1: /* msgctl() */ + if (pri->sys_nargs > 3) { + switch (pri->sys_args[2]) { + case IPC_STAT: + if (pri->Errno) + break; + /*FALLTHROUGH*/ + case IPC_SET: + if (data_model == PR_MODEL_LP64) + show_msgctl(pri, + (long)pri->sys_args[3]); + else + show_msgctl32(pri, + (long)pri->sys_args[3]); + break; + case IPC_STAT64: + if (pri->Errno) + break; + /*FALLTHROUGH*/ + case IPC_SET64: + show_msgctl64(pri, (long)pri->sys_args[3]); + break; + } + } + break; + case 2: /* msgrcv() */ + if (!pri->Errno && pri->sys_nargs > 2) { + if (data_model == PR_MODEL_LP64) + show_msgbuf(pri, pri->sys_args[2], msgsz); + else + show_msgbuf32(pri, pri->sys_args[2], msgsz); + } + break; + case 3: /* msgsnd() */ + if (pri->sys_nargs > 3) { + if (data_model == PR_MODEL_LP64) + show_msgbuf(pri, pri->sys_args[2], + pri->sys_args[3]); + else + show_msgbuf32(pri, pri->sys_args[2], + pri->sys_args[3]); + } + break; + case 4: /* msgids() */ + case 5: /* msgsnap() */ + default: /* unexpected subcode */ + break; + } +} +#else /* _LP64 */ +void +show_msgsys(private_t *pri, long msgsz) +{ + switch (pri->sys_args[0]) { + case 0: /* msgget() */ + break; + case 1: /* msgctl() */ + if (pri->sys_nargs > 3) { + switch (pri->sys_args[2]) { + case IPC_STAT: + if (pri->Errno) + break; + /*FALLTHROUGH*/ + case IPC_SET: + show_msgctl(pri, (long)pri->sys_args[3]); + break; + case IPC_STAT64: + if (pri->Errno) + break; + /*FALLTHROUGH*/ + case IPC_SET64: + show_msgctl64(pri, (long)pri->sys_args[3]); + break; + } + } + break; + case 2: /* msgrcv() */ + if (!pri->Errno && pri->sys_nargs > 2) + show_msgbuf(pri, pri->sys_args[2], msgsz); + break; + case 3: /* msgsnd() */ + if (pri->sys_nargs > 3) + show_msgbuf(pri, pri->sys_args[2], + pri->sys_args[3]); + break; + case 4: /* msgids() */ + case 5: /* msgsnap() */ + default: /* unexpected subcode */ + break; + } +} +#endif /* _LP64 */ + +static void +show_semctl64(private_t *pri, long offset) +{ + struct semid_ds64 semds; + + if (offset != NULL && + Pread(Proc, &semds, sizeof (semds), offset) == sizeof (semds)) { + show_perm64(pri, &semds.semx_perm); + + (void) printf("%s\tnsems=%u\n", pri->pname, semds.semx_nsems); + + prtime(pri, " ot = ", (time_t)semds.semx_otime); + prtime(pri, " ct = ", (time_t)semds.semx_ctime); + } +} + +void +show_semctl(private_t *pri, long offset) +{ + struct semid_ds semds; + + if (offset != NULL && + Pread(Proc, &semds, sizeof (semds), offset) == sizeof (semds)) { + show_perm(pri, &semds.sem_perm); + + (void) printf("%s\tnsems=%u\n", + pri->pname, + semds.sem_nsems); + + prtime(pri, " ot = ", semds.sem_otime); + prtime(pri, " ct = ", semds.sem_ctime); + } +} + +#ifdef _LP64 +void +show_semctl32(private_t *pri, long offset) +{ + struct semid_ds32 semds; + + if (offset != NULL && + Pread(Proc, &semds, sizeof (semds), offset) == sizeof (semds)) { + show_perm32(pri, &semds.sem_perm); + + (void) printf("%s\tnsems=%u\n", + pri->pname, + semds.sem_nsems); + + prtime(pri, " ot = ", semds.sem_otime); + prtime(pri, " ct = ", semds.sem_ctime); + } +} +#endif /* _LP64 */ + +void +show_semop(private_t *pri, long offset, long nsops, long timeout) +{ + struct sembuf sembuf; + const char *str; + + if (offset == 0) + return; + + if (nsops > 40) /* let's not be ridiculous */ + nsops = 40; + + for (; nsops > 0 && !interrupt; --nsops, offset += sizeof (sembuf)) { + if (Pread(Proc, &sembuf, sizeof (sembuf), offset) != + sizeof (sembuf)) + break; + + (void) printf("%s\tsemnum=%-5u semop=%-5d semflg=", + pri->pname, + sembuf.sem_num, + sembuf.sem_op); + + if (sembuf.sem_flg == 0) + (void) printf("0\n"); + else if ((str = semflags(pri, sembuf.sem_flg)) != NULL) + (void) printf("%s\n", str); + else + (void) printf("0%.6o\n", sembuf.sem_flg); + } + if (timeout) + show_timestruc(pri, timeout, "timeout"); +} + +void +show_semsys(private_t *pri) +{ + switch (pri->sys_args[0]) { + case 0: /* semctl() */ + if (pri->sys_nargs > 4) { + switch (pri->sys_args[3]) { + case IPC_STAT: + if (pri->Errno) + break; + /*FALLTHROUGH*/ + case IPC_SET: +#ifdef _LP64 + if (data_model == PR_MODEL_LP64) + show_semctl(pri, + (long)pri->sys_args[4]); + else + show_semctl32(pri, + (long)pri->sys_args[4]); +#else + show_semctl(pri, (long)pri->sys_args[4]); +#endif + break; + case IPC_STAT64: + if (pri->Errno) + break; + /*FALLTHROUGH*/ + case IPC_SET64: + show_semctl64(pri, (long)pri->sys_args[4]); + break; + } + } + break; + case 1: /* semget() */ + break; + case 2: /* semop() */ + if (pri->sys_nargs > 3) + show_semop(pri, (long)pri->sys_args[2], + pri->sys_args[3], 0); + break; + case 3: /* semids() */ + break; + case 4: /* semtimedop() */ + if (pri->sys_nargs > 4) + show_semop(pri, (long)pri->sys_args[2], + pri->sys_args[3], pri->sys_args[4]); + break; + default: /* unexpected subcode */ + break; + } +} + +static void +show_shmctl64(private_t *pri, long offset) +{ + struct shmid_ds64 shmds; + + if (offset != NULL && + Pread(Proc, &shmds, sizeof (shmds), offset) == sizeof (shmds)) { + show_perm64(pri, &shmds.shmx_perm); + + (void) printf( + "%s\tsize=%-6llu lpid=%-5d cpid=%-5d na=%-5llu cna=%llu\n", + pri->pname, + (unsigned long long)shmds.shmx_segsz, + (int)shmds.shmx_lpid, + (int)shmds.shmx_cpid, + (unsigned long long)shmds.shmx_nattch, + (unsigned long long)shmds.shmx_cnattch); + + prtime(pri, " at = ", (time_t)shmds.shmx_atime); + prtime(pri, " dt = ", (time_t)shmds.shmx_dtime); + prtime(pri, " ct = ", (time_t)shmds.shmx_ctime); + } +} + +void +show_shmctl(private_t *pri, long offset) +{ + struct shmid_ds shmds; + + if (offset != NULL && + Pread(Proc, &shmds, sizeof (shmds), offset) == sizeof (shmds)) { + show_perm(pri, &shmds.shm_perm); + + (void) printf( + "%s\tsize=%-6lu lpid=%-5u cpid=%-5u na=%-5lu cna=%lu\n", + pri->pname, + (ulong_t)shmds.shm_segsz, + (int)shmds.shm_lpid, + (int)shmds.shm_cpid, + shmds.shm_nattch, + shmds.shm_cnattch); + + prtime(pri, " at = ", shmds.shm_atime); + prtime(pri, " dt = ", shmds.shm_dtime); + prtime(pri, " ct = ", shmds.shm_ctime); + } +} + +#ifdef _LP64 +void +show_shmctl32(private_t *pri, long offset) +{ + struct shmid_ds32 shmds; + + if (offset != NULL && + Pread(Proc, &shmds, sizeof (shmds), offset) == sizeof (shmds)) { + show_perm32(pri, &shmds.shm_perm); + + (void) printf( + "%s\tsize=%-6u lpid=%-5u cpid=%-5u na=%-5u cna=%u\n", + pri->pname, + shmds.shm_segsz, + shmds.shm_lpid, + shmds.shm_cpid, + shmds.shm_nattch, + shmds.shm_cnattch); + + prtime(pri, " at = ", shmds.shm_atime); + prtime(pri, " dt = ", shmds.shm_dtime); + prtime(pri, " ct = ", shmds.shm_ctime); + } +} +#endif /* _LP64 */ + +void +show_shmsys(private_t *pri) +{ + switch (pri->sys_args[0]) { + case 0: /* shmat() */ + break; + case 1: /* shmctl() */ + if (pri->sys_nargs > 3) { + switch (pri->sys_args[2]) { + case IPC_STAT: + if (pri->Errno) + break; + /*FALLTHROUGH*/ + case IPC_SET: +#ifdef _LP64 + if (data_model == PR_MODEL_LP64) + show_shmctl(pri, + (long)pri->sys_args[3]); + else + show_shmctl32(pri, + (long)pri->sys_args[3]); +#else + show_shmctl(pri, (long)pri->sys_args[3]); +#endif + break; + case IPC_STAT64: + if (pri->Errno) + break; + /*FALLTHROUGH*/ + case IPC_SET64: + show_shmctl64(pri, (long)pri->sys_args[3]); + break; + } + } + break; + case 2: /* shmdt() */ + case 3: /* shmget() */ + case 4: /* shmids() */ + default: /* unexpected subcode */ + break; + } +} + +void +show_groups(private_t *pri, long offset, long count) +{ + int groups[100]; + + if (count > 100) + count = 100; + + if (count > 0 && offset != NULL && + Pread(Proc, &groups[0], count*sizeof (int), offset) == + count*sizeof (int)) { + int n; + + (void) printf("%s\t", pri->pname); + for (n = 0; !interrupt && n < count; n++) { + if (n != 0 && n%10 == 0) + (void) printf("\n%s\t", pri->pname); + (void) printf(" %5d", groups[n]); + } + (void) fputc('\n', stdout); + } +} + +/* + * This assumes that a sigset_t is simply an array of ints. + */ +char * +sigset_string(private_t *pri, sigset_t *sp) +{ + char *s = pri->code_buf; + int n = sizeof (*sp) / sizeof (int32_t); + int32_t *lp = (int32_t *)sp; + + while (--n >= 0) { + int32_t val = *lp++; + + if (val == 0) + s += sprintf(s, " 0"); + else + s += sprintf(s, " 0x%.8X", val); + } + + return (pri->code_buf); +} + +void +show_sigset(private_t *pri, long offset, const char *name) +{ + sigset_t sigset; + + if (offset != NULL && + Pread(Proc, &sigset, sizeof (sigset), offset) == sizeof (sigset)) { + (void) printf("%s\t%s =%s\n", + pri->pname, name, sigset_string(pri, &sigset)); + } +} + +#ifdef _LP64 +void +show_sigaltstack32(private_t *pri, long offset, const char *name) +{ + struct sigaltstack32 altstack; + + if (offset != NULL && + Pread(Proc, &altstack, sizeof (altstack), offset) == + sizeof (altstack)) { + (void) printf("%s\t%s: sp=0x%.8X size=%u flags=0x%.4X\n", + pri->pname, + name, + altstack.ss_sp, + altstack.ss_size, + altstack.ss_flags); + } +} +#endif /* _LP64 */ + +void +show_sigaltstack(private_t *pri, long offset, const char *name) +{ + struct sigaltstack altstack; + +#ifdef _LP64 + if (data_model != PR_MODEL_LP64) { + show_sigaltstack32(pri, offset, name); + return; + } +#endif + if (offset != NULL && + Pread(Proc, &altstack, sizeof (altstack), offset) == + sizeof (altstack)) { + (void) printf("%s\t%s: sp=0x%.8lX size=%lu flags=0x%.4X\n", + pri->pname, + name, + (ulong_t)altstack.ss_sp, + (ulong_t)altstack.ss_size, + altstack.ss_flags); + } +} + +#ifdef _LP64 +void +show_sigaction32(private_t *pri, long offset, const char *name, long odisp) +{ + struct sigaction32 sigaction; + + if (offset != NULL && + Pread(Proc, &sigaction, sizeof (sigaction), offset) == + sizeof (sigaction)) { + /* This is stupid, we shouldn't have to do this */ + if (odisp != NULL) + sigaction.sa_handler = (caddr32_t)odisp; + (void) printf( + "%s %s: hand = 0x%.8X mask =%s flags = 0x%.4X\n", + pri->pname, + name, + sigaction.sa_handler, + sigset_string(pri, (sigset_t *)&sigaction.sa_mask), + sigaction.sa_flags); + } +} +#endif /* _LP64 */ + +void +show_sigaction(private_t *pri, long offset, const char *name, long odisp) +{ + struct sigaction sigaction; + +#ifdef _LP64 + if (data_model != PR_MODEL_LP64) { + show_sigaction32(pri, offset, name, odisp); + return; + } +#endif + if (offset != NULL && + Pread(Proc, &sigaction, sizeof (sigaction), offset) == + sizeof (sigaction)) { + /* This is stupid, we shouldn't have to do this */ + if (odisp != NULL) + sigaction.sa_handler = (void (*)())odisp; + (void) printf( + "%s %s: hand = 0x%.8lX mask =%s flags = 0x%.4X\n", + pri->pname, + name, + (long)sigaction.sa_handler, + sigset_string(pri, &sigaction.sa_mask), + sigaction.sa_flags); + } +} + +#ifdef _LP64 +void +print_siginfo32(private_t *pri, const siginfo32_t *sip) +{ + const char *code = NULL; + + (void) printf("%s siginfo: %s", pri->pname, + signame(pri, sip->si_signo)); + + if (sip->si_signo != 0 && SI_FROMUSER(sip) && sip->si_pid != 0) { + (void) printf(" pid=%d uid=%d", sip->si_pid, sip->si_uid); + if (sip->si_code != 0) + (void) printf(" code=%d", sip->si_code); + (void) fputc('\n', stdout); + return; + } + + switch (sip->si_signo) { + default: + (void) fputc('\n', stdout); + return; + case SIGILL: + case SIGTRAP: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + case SIGEMT: + case SIGCLD: + case SIGPOLL: + case SIGXFSZ: + break; + } + + switch (sip->si_signo) { + case SIGILL: + switch (sip->si_code) { + case ILL_ILLOPC: code = "ILL_ILLOPC"; break; + case ILL_ILLOPN: code = "ILL_ILLOPN"; break; + case ILL_ILLADR: code = "ILL_ILLADR"; break; + case ILL_ILLTRP: code = "ILL_ILLTRP"; break; + case ILL_PRVOPC: code = "ILL_PRVOPC"; break; + case ILL_PRVREG: code = "ILL_PRVREG"; break; + case ILL_COPROC: code = "ILL_COPROC"; break; + case ILL_BADSTK: code = "ILL_BADSTK"; break; + } + break; + case SIGTRAP: + switch (sip->si_code) { + case TRAP_BRKPT: code = "TRAP_BRKPT"; break; + case TRAP_TRACE: code = "TRAP_TRACE"; break; + case TRAP_RWATCH: code = "TRAP_RWATCH"; break; + case TRAP_WWATCH: code = "TRAP_WWATCH"; break; + case TRAP_XWATCH: code = "TRAP_XWATCH"; break; + case TRAP_DTRACE: code = "TRAP_DTRACE"; break; + } + break; + case SIGFPE: + switch (sip->si_code) { + case FPE_INTDIV: code = "FPE_INTDIV"; break; + case FPE_INTOVF: code = "FPE_INTOVF"; break; + case FPE_FLTDIV: code = "FPE_FLTDIV"; break; + case FPE_FLTOVF: code = "FPE_FLTOVF"; break; + case FPE_FLTUND: code = "FPE_FLTUND"; break; + case FPE_FLTRES: code = "FPE_FLTRES"; break; + case FPE_FLTINV: code = "FPE_FLTINV"; break; + case FPE_FLTSUB: code = "FPE_FLTSUB"; break; +#if defined(FPE_FLTDEN) + case FPE_FLTDEN: code = "FPE_FLTDEN"; break; +#endif + } + break; + case SIGSEGV: + switch (sip->si_code) { + case SEGV_MAPERR: code = "SEGV_MAPERR"; break; + case SEGV_ACCERR: code = "SEGV_ACCERR"; break; + } + break; + case SIGEMT: + switch (sip->si_code) { +#ifdef EMT_TAGOVF + case EMT_TAGOVF: code = "EMT_TAGOVF"; break; +#endif + case EMT_CPCOVF: code = "EMT_CPCOVF"; break; + } + break; + case SIGBUS: + switch (sip->si_code) { + case BUS_ADRALN: code = "BUS_ADRALN"; break; + case BUS_ADRERR: code = "BUS_ADRERR"; break; + case BUS_OBJERR: code = "BUS_OBJERR"; break; + } + break; + case SIGCLD: + switch (sip->si_code) { + case CLD_EXITED: code = "CLD_EXITED"; break; + case CLD_KILLED: code = "CLD_KILLED"; break; + case CLD_DUMPED: code = "CLD_DUMPED"; break; + case CLD_TRAPPED: code = "CLD_TRAPPED"; break; + case CLD_STOPPED: code = "CLD_STOPPED"; break; + case CLD_CONTINUED: code = "CLD_CONTINUED"; break; + } + break; + case SIGPOLL: + switch (sip->si_code) { + case POLL_IN: code = "POLL_IN"; break; + case POLL_OUT: code = "POLL_OUT"; break; + case POLL_MSG: code = "POLL_MSG"; break; + case POLL_ERR: code = "POLL_ERR"; break; + case POLL_PRI: code = "POLL_PRI"; break; + case POLL_HUP: code = "POLL_HUP"; break; + } + break; + } + + if (code == NULL) { + (void) sprintf(pri->code_buf, "code=%d", sip->si_code); + code = (const char *)pri->code_buf; + } + + switch (sip->si_signo) { + case SIGILL: + case SIGTRAP: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + case SIGEMT: + (void) printf(" %s addr=0x%.8X", + code, + sip->si_addr); + break; + case SIGCLD: + (void) printf(" %s pid=%d status=0x%.4X", + code, + sip->si_pid, + sip->si_status); + break; + case SIGPOLL: + case SIGXFSZ: + (void) printf(" %s fd=%d band=%d", + code, + sip->si_fd, + sip->si_band); + break; + } + + if (sip->si_errno != 0) { + const char *ename = errname(sip->si_errno); + + (void) printf(" errno=%d", sip->si_errno); + if (ename != NULL) + (void) printf("(%s)", ename); + } + + (void) fputc('\n', stdout); +} +#endif /* _LP64 */ + +void +print_siginfo(private_t *pri, const siginfo_t *sip) +{ + const char *code = NULL; + + (void) printf("%s siginfo: %s", pri->pname, + signame(pri, sip->si_signo)); + + if (sip->si_signo != 0 && SI_FROMUSER(sip) && sip->si_pid != 0) { + (void) printf(" pid=%d uid=%u", + (int)sip->si_pid, + sip->si_uid); + if (sip->si_code != 0) + (void) printf(" code=%d", sip->si_code); + (void) fputc('\n', stdout); + return; + } + + switch (sip->si_signo) { + default: + (void) fputc('\n', stdout); + return; + case SIGILL: + case SIGTRAP: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + case SIGEMT: + case SIGCLD: + case SIGPOLL: + case SIGXFSZ: + break; + } + + switch (sip->si_signo) { + case SIGILL: + switch (sip->si_code) { + case ILL_ILLOPC: code = "ILL_ILLOPC"; break; + case ILL_ILLOPN: code = "ILL_ILLOPN"; break; + case ILL_ILLADR: code = "ILL_ILLADR"; break; + case ILL_ILLTRP: code = "ILL_ILLTRP"; break; + case ILL_PRVOPC: code = "ILL_PRVOPC"; break; + case ILL_PRVREG: code = "ILL_PRVREG"; break; + case ILL_COPROC: code = "ILL_COPROC"; break; + case ILL_BADSTK: code = "ILL_BADSTK"; break; + } + break; + case SIGTRAP: + switch (sip->si_code) { + case TRAP_BRKPT: code = "TRAP_BRKPT"; break; + case TRAP_TRACE: code = "TRAP_TRACE"; break; + case TRAP_RWATCH: code = "TRAP_RWATCH"; break; + case TRAP_WWATCH: code = "TRAP_WWATCH"; break; + case TRAP_XWATCH: code = "TRAP_XWATCH"; break; + case TRAP_DTRACE: code = "TRAP_DTRACE"; break; + } + break; + case SIGFPE: + switch (sip->si_code) { + case FPE_INTDIV: code = "FPE_INTDIV"; break; + case FPE_INTOVF: code = "FPE_INTOVF"; break; + case FPE_FLTDIV: code = "FPE_FLTDIV"; break; + case FPE_FLTOVF: code = "FPE_FLTOVF"; break; + case FPE_FLTUND: code = "FPE_FLTUND"; break; + case FPE_FLTRES: code = "FPE_FLTRES"; break; + case FPE_FLTINV: code = "FPE_FLTINV"; break; + case FPE_FLTSUB: code = "FPE_FLTSUB"; break; +#if defined(FPE_FLTDEN) + case FPE_FLTDEN: code = "FPE_FLTDEN"; break; +#endif + } + break; + case SIGSEGV: + switch (sip->si_code) { + case SEGV_MAPERR: code = "SEGV_MAPERR"; break; + case SEGV_ACCERR: code = "SEGV_ACCERR"; break; + } + break; + case SIGEMT: + switch (sip->si_code) { +#ifdef EMT_TAGOVF + case EMT_TAGOVF: code = "EMT_TAGOVF"; break; +#endif + case EMT_CPCOVF: code = "EMT_CPCOVF"; break; + } + break; + case SIGBUS: + switch (sip->si_code) { + case BUS_ADRALN: code = "BUS_ADRALN"; break; + case BUS_ADRERR: code = "BUS_ADRERR"; break; + case BUS_OBJERR: code = "BUS_OBJERR"; break; + } + break; + case SIGCLD: + switch (sip->si_code) { + case CLD_EXITED: code = "CLD_EXITED"; break; + case CLD_KILLED: code = "CLD_KILLED"; break; + case CLD_DUMPED: code = "CLD_DUMPED"; break; + case CLD_TRAPPED: code = "CLD_TRAPPED"; break; + case CLD_STOPPED: code = "CLD_STOPPED"; break; + case CLD_CONTINUED: code = "CLD_CONTINUED"; break; + } + break; + case SIGPOLL: + switch (sip->si_code) { + case POLL_IN: code = "POLL_IN"; break; + case POLL_OUT: code = "POLL_OUT"; break; + case POLL_MSG: code = "POLL_MSG"; break; + case POLL_ERR: code = "POLL_ERR"; break; + case POLL_PRI: code = "POLL_PRI"; break; + case POLL_HUP: code = "POLL_HUP"; break; + } + break; + } + + if (code == NULL) { + (void) sprintf(pri->code_buf, "code=%d", sip->si_code); + code = (const char *)pri->code_buf; + } + + switch (sip->si_signo) { + case SIGILL: + case SIGTRAP: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + case SIGEMT: + (void) printf(" %s addr=0x%.8lX", + code, + (long)sip->si_addr); + break; + case SIGCLD: + (void) printf(" %s pid=%d status=0x%.4X", + code, + (int)sip->si_pid, + sip->si_status); + break; + case SIGPOLL: + case SIGXFSZ: + (void) printf(" %s fd=%d band=%ld", + code, + sip->si_fd, + sip->si_band); + break; + } + + if (sip->si_errno != 0) { + const char *ename = errname(sip->si_errno); + + (void) printf(" errno=%d", sip->si_errno); + if (ename != NULL) + (void) printf("(%s)", ename); + } + + (void) fputc('\n', stdout); +} + +#ifdef _LP64 +void +show_siginfo32(private_t *pri, long offset) +{ + struct siginfo32 siginfo; + + if (offset != NULL && + Pread(Proc, &siginfo, sizeof (siginfo), offset) == sizeof (siginfo)) + print_siginfo32(pri, &siginfo); +} +#endif /* _LP64 */ + +void +show_siginfo(private_t *pri, long offset) +{ + struct siginfo siginfo; + +#ifdef _LP64 + if (data_model != PR_MODEL_LP64) { + show_siginfo32(pri, offset); + return; + } +#endif + if (offset != NULL && + Pread(Proc, &siginfo, sizeof (siginfo), offset) == sizeof (siginfo)) + print_siginfo(pri, &siginfo); +} + +void +show_bool(private_t *pri, long offset, int count) +{ + int serial = (count > MYBUFSIZ / 4); + + /* enter region of lengthy output */ + if (serial) + Eserialize(); + + while (count > 0) { + char buf[32]; + int nb = (count < 32)? count : 32; + int i; + + if (Pread(Proc, buf, (size_t)nb, offset) != nb) + break; + + (void) printf("%s ", pri->pname); + for (i = 0; i < nb; i++) + (void) printf(" %d", buf[i]); + (void) fputc('\n', stdout); + + count -= nb; + offset += nb; + } + + /* exit region of lengthy output */ + if (serial) + Xserialize(); +} + +#ifdef _LP64 +void +show_iovec32(private_t *pri, long offset, int niov, int showbuf, long count) +{ + iovec32_t iovec[16]; + iovec32_t *ip; + long nb; + int serial = (count > MYBUFSIZ / 4 && showbuf); + + if (niov > 16) /* is this the real limit? */ + niov = 16; + + if (offset != NULL && niov > 0 && + Pread(Proc, &iovec[0], niov*sizeof (iovec32_t), offset) + == niov*sizeof (iovec32_t)) { + /* enter region of lengthy output */ + if (serial) + Eserialize(); + + for (ip = &iovec[0]; niov-- && !interrupt; ip++) { + (void) printf("%s\tiov_base = 0x%.8X iov_len = %d\n", + pri->pname, + ip->iov_base, + ip->iov_len); + if ((nb = count) > 0) { + if (nb > ip->iov_len) + nb = ip->iov_len; + if (nb > 0) + count -= nb; + } + if (showbuf && nb > 0) + showbuffer(pri, (long)ip->iov_base, nb); + } + + /* exit region of lengthy output */ + if (serial) + Xserialize(); + } +} +#endif /* _LP64 */ + +void +show_iovec(private_t *pri, long offset, long niov, int showbuf, long count) +{ + iovec_t iovec[16]; + iovec_t *ip; + long nb; + int serial = (count > MYBUFSIZ / 4 && showbuf); + +#ifdef _LP64 + if (data_model != PR_MODEL_LP64) { + show_iovec32(pri, offset, niov, showbuf, count); + return; + } +#endif + if (niov > 16) /* is this the real limit? */ + niov = 16; + + if (offset != NULL && niov > 0 && + Pread(Proc, &iovec[0], niov*sizeof (iovec_t), offset) + == niov*sizeof (iovec_t)) { + /* enter region of lengthy output */ + if (serial) + Eserialize(); + + for (ip = &iovec[0]; niov-- && !interrupt; ip++) { + (void) printf("%s\tiov_base = 0x%.8lX iov_len = %lu\n", + pri->pname, + (long)ip->iov_base, + ip->iov_len); + if ((nb = count) > 0) { + if (nb > ip->iov_len) + nb = ip->iov_len; + if (nb > 0) + count -= nb; + } + if (showbuf && nb > 0) + showbuffer(pri, (long)ip->iov_base, nb); + } + + /* exit region of lengthy output */ + if (serial) + Xserialize(); + } +} + +void +show_dents32(private_t *pri, long offset, long count) +{ + long buf[MYBUFSIZ / sizeof (long)]; + struct dirent32 *dp; + int serial = (count > 100); + + if (offset == 0) + return; + + /* enter region of lengthy output */ + if (serial) + Eserialize(); + + while (count > 0 && !interrupt) { + int nb = count < MYBUFSIZ? (int)count : MYBUFSIZ; + + if ((nb = Pread(Proc, &buf[0], (size_t)nb, offset)) <= 0) + break; + + dp = (struct dirent32 *)&buf[0]; + if (nb < (int)(dp->d_name - (char *)dp)) + break; + if ((unsigned)nb < dp->d_reclen) { + /* getdents() error? */ + (void) printf( + "%s ino=%-5u off=%-4d rlen=%-3d\n", + pri->pname, + dp->d_ino, + dp->d_off, + dp->d_reclen); + break; + } + + while (!interrupt && + nb >= (int)(dp->d_name - (char *)dp) && + (unsigned)nb >= dp->d_reclen) { + (void) printf( + "%s ino=%-5u off=%-4d rlen=%-3d \"%.*s\"\n", + pri->pname, + dp->d_ino, + dp->d_off, + dp->d_reclen, + dp->d_reclen - (int)(dp->d_name - (char *)dp), + dp->d_name); + nb -= dp->d_reclen; + count -= dp->d_reclen; + offset += dp->d_reclen; + /* LINTED improper alignment */ + dp = (struct dirent32 *)((char *)dp + dp->d_reclen); + } + } + + /* exit region of lengthy output */ + if (serial) + Xserialize(); +} + +void +show_dents64(private_t *pri, long offset, long count) +{ + long long buf[MYBUFSIZ / sizeof (long long)]; + struct dirent64 *dp; + int serial = (count > 100); + + if (offset == 0) + return; + + /* enter region of lengthy output */ + if (serial) + Eserialize(); + + while (count > 0 && !interrupt) { + int nb = count < MYBUFSIZ? (int)count : MYBUFSIZ; + + if ((nb = Pread(Proc, &buf[0], (size_t)nb, offset)) <= 0) + break; + + dp = (struct dirent64 *)&buf[0]; + if (nb < (int)(dp->d_name - (char *)dp)) + break; + if ((unsigned)nb < dp->d_reclen) { + /* getdents() error? */ + (void) printf( + "%s ino=%-5llu off=%-4lld rlen=%-3d\n", + pri->pname, + (long long)dp->d_ino, + (long long)dp->d_off, + dp->d_reclen); + break; + } + + while (!interrupt && + nb >= (int)(dp->d_name - (char *)dp) && + (unsigned)nb >= dp->d_reclen) { + (void) printf( + "%s ino=%-5llu off=%-4lld rlen=%-3d \"%.*s\"\n", + pri->pname, + (long long)dp->d_ino, + (long long)dp->d_off, + dp->d_reclen, + dp->d_reclen - (int)(dp->d_name - (char *)dp), + dp->d_name); + nb -= dp->d_reclen; + count -= dp->d_reclen; + offset += dp->d_reclen; + /* LINTED improper alignment */ + dp = (struct dirent64 *)((char *)dp + dp->d_reclen); + } + } + + /* exit region of lengthy output */ + if (serial) + Xserialize(); +} + +void +show_rlimit32(private_t *pri, long offset) +{ + struct rlimit32 rlimit; + + if (offset != NULL && + Pread(Proc, &rlimit, sizeof (rlimit), offset) == sizeof (rlimit)) { + (void) printf("%s\t", pri->pname); + switch (rlimit.rlim_cur) { + case RLIM32_INFINITY: + (void) fputs("cur = RLIM_INFINITY", stdout); + break; + case RLIM32_SAVED_MAX: + (void) fputs("cur = RLIM_SAVED_MAX", stdout); + break; + case RLIM32_SAVED_CUR: + (void) fputs("cur = RLIM_SAVED_CUR", stdout); + break; + default: + (void) printf("cur = %lu", (long)rlimit.rlim_cur); + break; + } + switch (rlimit.rlim_max) { + case RLIM32_INFINITY: + (void) fputs(" max = RLIM_INFINITY\n", stdout); + break; + case RLIM32_SAVED_MAX: + (void) fputs(" max = RLIM_SAVED_MAX\n", stdout); + break; + case RLIM32_SAVED_CUR: + (void) fputs(" max = RLIM_SAVED_CUR\n", stdout); + break; + default: + (void) printf(" max = %lu\n", (long)rlimit.rlim_max); + break; + } + } +} + +void +show_rlimit64(private_t *pri, long offset) +{ + struct rlimit64 rlimit; + + if (offset != NULL && + Pread(Proc, &rlimit, sizeof (rlimit), offset) == sizeof (rlimit)) { + (void) printf("%s\t", pri->pname); + switch (rlimit.rlim_cur) { + case RLIM64_INFINITY: + (void) fputs("cur = RLIM64_INFINITY", stdout); + break; + case RLIM64_SAVED_MAX: + (void) fputs("cur = RLIM64_SAVED_MAX", stdout); + break; + case RLIM64_SAVED_CUR: + (void) fputs("cur = RLIM64_SAVED_CUR", stdout); + break; + default: + (void) printf("cur = %llu", + (unsigned long long)rlimit.rlim_cur); + break; + } + switch (rlimit.rlim_max) { + case RLIM64_INFINITY: + (void) fputs(" max = RLIM64_INFINITY\n", stdout); + break; + case RLIM64_SAVED_MAX: + (void) fputs(" max = RLIM64_SAVED_MAX\n", stdout); + break; + case RLIM64_SAVED_CUR: + (void) fputs(" max = RLIM64_SAVED_CUR\n", stdout); + break; + default: + (void) printf(" max = %llu\n", + (unsigned long long)rlimit.rlim_max); + break; + } + } +} + +void +show_nuname(private_t *pri, long offset) +{ + struct utsname ubuf; + + if (offset != NULL && + Pread(Proc, &ubuf, sizeof (ubuf), offset) == sizeof (ubuf)) { + (void) printf( + "%s\tsys=%s nod=%s rel=%s ver=%s mch=%s\n", + pri->pname, + ubuf.sysname, + ubuf.nodename, + ubuf.release, + ubuf.version, + ubuf.machine); + } +} + +void +show_adjtime(private_t *pri, long off1, long off2) +{ + show_timeval(pri, off1, " delta"); + show_timeval(pri, off2, "olddelta"); +} + +void +show_sockaddr(private_t *pri, + const char *str, long addroff, long lenoff, long len) +{ + /* + * A buffer large enough for PATH_MAX size AF_UNIX address, which is + * also large enough to store a sockaddr_in or a sockaddr_in6. + */ + long buf[(sizeof (short) + PATH_MAX + sizeof (long) - 1) + / sizeof (long)]; + struct sockaddr *sa = (struct sockaddr *)buf; + struct sockaddr_in *sin = (struct sockaddr_in *)buf; + struct sockaddr_un *soun = (struct sockaddr_un *)buf; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)buf; + char addrbuf[INET6_ADDRSTRLEN]; + + if (lenoff != 0) { + uint_t ilen; + if (Pread(Proc, &ilen, sizeof (ilen), lenoff) != sizeof (ilen)) + return; + len = ilen; + } + + if (len >= sizeof (buf)) /* protect against ridiculous length */ + len = sizeof (buf) - 1; + if (Pread(Proc, buf, len, addroff) != len) + return; + + switch (sa->sa_family) { + case AF_INET6: + (void) printf("%s\tAF_INET6 %s = %s port = %u\n", + pri->pname, str, + inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, + sizeof (addrbuf)), + ntohs(sin6->sin6_port)); + (void) printf("%s\tscope id = %u source id = 0x%x\n" + "%s\tflow class = 0x%02x flow label = 0x%05x\n", + pri->pname, ntohl(sin6->sin6_scope_id), + ntohl(sin6->__sin6_src_id), + pri->pname, + ntohl((sin6->sin6_flowinfo & IPV6_FLOWINFO_TCLASS) >> 20), + ntohl(sin6->sin6_flowinfo & IPV6_FLOWINFO_FLOWLABEL)); + break; + case AF_INET: + (void) printf("%s\tAF_%s %s = %s port = %u\n", + pri->pname, "INET", + str, inet_ntop(AF_INET, &sin->sin_addr, addrbuf, + sizeof (addrbuf)), ntohs(sin->sin_port)); + break; + case AF_UNIX: + len -= sizeof (soun->sun_family); + if (len >= 0) { + /* Null terminate */ + soun->sun_path[len] = NULL; + (void) printf("%s\tAF_UNIX %s = %s\n", pri->pname, + str, soun->sun_path); + } + break; + } +} + +void +show_msghdr(private_t *pri, long offset) +{ + const lwpstatus_t *Lsp = pri->lwpstat; + int what = Lsp->pr_what; + int err = pri->Errno; + struct msghdr msg; + int showbuf = FALSE; + int i = pri->sys_args[0]+1; + long nb = (what == SYS_recvmsg)? pri->Rval1 : 32*1024; + + if (Pread(Proc, &msg, sizeof (msg), offset) != sizeof (msg)) + return; + + if (msg.msg_name != NULL && msg.msg_namelen != 0) + show_sockaddr(pri, "msg_name", + (long)msg.msg_name, 0, (long)msg.msg_namelen); + + /* + * Print the iovec if the syscall was successful and the fd is + * part of the set being traced. + */ + if ((what == SYS_recvmsg && !err && + prismember(&readfd, i)) || + (what == SYS_sendmsg && + prismember(&writefd, i))) + showbuf = TRUE; + + show_iovec(pri, (long)msg.msg_iov, msg.msg_iovlen, showbuf, nb); + +} + +#ifdef _LP64 +void +show_msghdr32(private_t *pri, long offset) +{ + struct msghdr32 { + caddr32_t msg_name; + uint32_t msg_namelen; + caddr32_t msg_iov; + int32_t msg_iovlen; + } msg; + const lwpstatus_t *Lsp = pri->lwpstat; + int what = Lsp->pr_what; + int err = pri->Errno; + int showbuf = FALSE; + int i = pri->sys_args[0]+1; + long nb = (what == SYS_recvmsg)? pri->Rval1 : 32*1024; + + if (Pread(Proc, &msg, sizeof (msg), offset) != sizeof (msg)) + return; + + if (msg.msg_name != NULL && msg.msg_namelen != 0) + show_sockaddr(pri, "msg_name", + (long)msg.msg_name, 0, (long)msg.msg_namelen); + /* + * Print the iovec if the syscall was successful and the fd is + * part of the set being traced. + */ + if ((what == SYS_recvmsg && !err && + prismember(&readfd, i)) || + (what == SYS_sendmsg && + prismember(&writefd, i))) + showbuf = TRUE; + + show_iovec32(pri, (long)msg.msg_iov, msg.msg_iovlen, showbuf, nb); + +} +#endif /* _LP64 */ + +static void +show_doorargs(private_t *pri, long offset) +{ + door_arg_t args; + + if (Pread(Proc, &args, sizeof (args), offset) == sizeof (args)) { + (void) printf("%s\tdata_ptr=0x%lX data_size=%lu\n", + pri->pname, + (ulong_t)args.data_ptr, + (ulong_t)args.data_size); + (void) printf("%s\tdesc_ptr=0x%lX desc_num=%u\n", + pri->pname, + (ulong_t)args.desc_ptr, + args.desc_num); + (void) printf("%s\trbuf=0x%lX rsize=%lu\n", + pri->pname, + (ulong_t)args.rbuf, + (ulong_t)args.rsize); + } +} + +static void +show_ucred_privsets(private_t *pri, ucred_t *uc) +{ + int i = 0; + const priv_set_t *s; + priv_ptype_t sn; + char *str; + + while ((sn = priv_getsetbynum(i++)) != NULL) { + s = ucred_getprivset(uc, sn); + + if (s == NULL) + continue; + + (void) printf("%s\t%c: %s\n", + pri->pname, + *sn, + str = priv_set_to_str(s, ',', PRIV_STR_SHORT)); + + free(str); + } +} + +static void +show_ucred(private_t *pri, long offset) +{ + ucred_t *uc = _ucred_alloc(); + size_t sz; + + if (uc == NULL) + return; + + sz = Pread(Proc, uc, uc->uc_size, offset); + + /* + * A new uc_size is read, it could be smaller than the previously + * value. We accept short reads that fill the whole header. + */ + if (sz >= sizeof (ucred_t) && sz >= uc->uc_size) { + (void) printf("%s\teuid=%u egid=%u\n", + pri->pname, + ucred_geteuid(uc), + ucred_getegid(uc)); + (void) printf("%s\truid=%u rgid=%u\n", + pri->pname, + ucred_getruid(uc), + ucred_getrgid(uc)); + (void) printf("%s\tpid=%d zoneid=%d\n", + pri->pname, + (int)ucred_getpid(uc), + (int)ucred_getzoneid(uc)); + show_ucred_privsets(pri, uc); + } + ucred_free(uc); +} + +static void +show_privset(private_t *pri, long offset, size_t size, char *label) +{ + priv_set_t *tmp = priv_allocset(); + size_t sz; + + if (tmp == NULL) + return; + + sz = Pread(Proc, tmp, size, offset); + + if (sz == size) { + char *str = priv_set_to_str(tmp, ',', PRIV_STR_SHORT); + if (str != NULL) { + (void) printf("%s\t%s%s\n", pri->pname, label, str); + free(str); + } + } + priv_freeset(tmp); +} + +static void +show_doorinfo(private_t *pri, long offset) +{ + door_info_t info; + door_attr_t attr; + + if (Pread(Proc, &info, sizeof (info), offset) != sizeof (info)) + return; + (void) printf("%s\ttarget=%d proc=0x%llX data=0x%llX\n", + pri->pname, + (int)info.di_target, + info.di_proc, + info.di_data); + attr = info.di_attributes; + (void) printf("%s\tattributes=%s\n", pri->pname, door_flags(pri, attr)); + (void) printf("%s\tuniquifier=%llu\n", pri->pname, info.di_uniquifier); +} + +static void +show_doorparam(private_t *pri, long offset) +{ + ulong_t val; + + if (Pread(Proc, &val, sizeof (val), offset) == sizeof (val)) { + (void) printf("%s\tvalue=%lu\n", + pri->pname, + val); + } +} + +#ifdef _LP64 + +static void +show_doorargs32(private_t *pri, long offset) +{ + struct door_arg32 args; + + if (Pread(Proc, &args, sizeof (args), offset) == sizeof (args)) { + (void) printf("%s\tdata_ptr=%X data_size=%u\n", + pri->pname, + args.data_ptr, + args.data_size); + (void) printf("%s\tdesc_ptr=0x%X desc_num=%u\n", + pri->pname, + args.desc_ptr, + args.desc_num); + (void) printf("%s\trbuf=0x%X rsize=%u\n", + pri->pname, + args.rbuf, + args.rsize); + } +} + +static void +show_doorparam32(private_t *pri, long offset) +{ + uint_t val; + + if (Pread(Proc, &val, sizeof (val), offset) == sizeof (val)) { + (void) printf("%s\tvalue=%u\n", + pri->pname, + val); + } +} + +#endif /* _LP64 */ + +static void +show_doors(private_t *pri) +{ + switch (pri->sys_args[5]) { + case DOOR_CALL: +#ifdef _LP64 + if (data_model == PR_MODEL_LP64) + show_doorargs(pri, (long)pri->sys_args[1]); + else + show_doorargs32(pri, (long)pri->sys_args[1]); +#else + show_doorargs(pri, (long)pri->sys_args[1]); +#endif + break; + case DOOR_UCRED: + if (!pri->Errno) + show_ucred(pri, (long)pri->sys_args[0]); + break; + case DOOR_INFO: + if (!pri->Errno) + show_doorinfo(pri, (long)pri->sys_args[1]); + break; + case DOOR_GETPARAM: + if (!pri->Errno) { +#ifdef _LP64 + if (data_model == PR_MODEL_LP64) + show_doorparam(pri, (long)pri->sys_args[2]); + else + show_doorparam32(pri, (long)pri->sys_args[2]); +#else + show_doorparam(pri, (long)pri->sys_args[2]); +#endif + } + break; + } +} + +static void +show_portargs(private_t *pri, long offset) +{ + port_event_t args; + + if (Pread(Proc, &args, sizeof (args), offset) == sizeof (args)) { + (void) printf("%s\tevents=0x%x source=%u\n", + pri->pname, + args.portev_events, + args.portev_source); + (void) printf("%s\tobject=0x%p user=0x%p\n", + pri->pname, + (void *)args.portev_object, + (void *)args.portev_user); + } +} + + +#ifdef _LP64 + +static void +show_portargs32(private_t *pri, long offset) +{ + port_event32_t args; + + if (Pread(Proc, &args, sizeof (args), offset) == sizeof (args)) { + (void) printf("%s\tevents=0x%x source=%u\n", + pri->pname, + args.portev_events, + args.portev_source); + (void) printf("%s\tobject=0x%x user=0x%x\n", + pri->pname, + args.portev_object, + args.portev_user); + } +} + +#endif /* _LP64 */ + +static void +show_ports(private_t *pri) +{ + switch (pri->sys_args[0]) { + case PORT_GET: +#ifdef _LP64 + if (data_model == PR_MODEL_LP64) + show_portargs(pri, (long)pri->sys_args[2]); + else + show_portargs32(pri, (long)pri->sys_args[2]); +#else + show_portargs(pri, (long)pri->sys_args[2]); +#endif + break; + } +} + +#define MAX_SNDFL_PRD 16 + +#ifdef _LP64 + +static void +show_ksendfilevec32(private_t *pri, int fd, + ksendfilevec32_t *sndvec, int sfvcnt) +{ + ksendfilevec32_t *snd_ptr, snd[MAX_SNDFL_PRD]; + size_t cpy_rqst; + + Eserialize(); + while (sfvcnt > 0) { + cpy_rqst = MIN(sfvcnt, MAX_SNDFL_PRD); + sfvcnt -= cpy_rqst; + cpy_rqst *= sizeof (snd[0]); + + if (Pread(Proc, snd, cpy_rqst, (uintptr_t)sndvec) != cpy_rqst) + break; + + snd_ptr = &snd[0]; + + while (cpy_rqst) { + (void) printf( + "sfv_fd=%d\tsfv_flag=0x%x\t" + "sfv_off=%d\tsfv_len=%u\n", + snd_ptr->sfv_fd, + snd_ptr->sfv_flag, + snd_ptr->sfv_off, + snd_ptr->sfv_len); + + if (snd_ptr->sfv_fd == SFV_FD_SELF && + prismember(&writefd, fd)) { + showbuffer(pri, + (long)snd_ptr->sfv_off & 0xffffffff, + (long)snd_ptr->sfv_len); + } + + cpy_rqst -= sizeof (snd[0]); + snd_ptr++; + } + + sndvec += MAX_SNDFL_PRD; + } + Xserialize(); +} + +static void +show_ksendfilevec64(private_t *pri, int fd, + ksendfilevec64_t *sndvec, int sfvcnt) +{ + ksendfilevec64_t *snd_ptr, snd[MAX_SNDFL_PRD]; + size_t cpy_rqst; + + Eserialize(); + while (sfvcnt > 0) { + cpy_rqst = MIN(sfvcnt, MAX_SNDFL_PRD); + sfvcnt -= cpy_rqst; + cpy_rqst *= sizeof (snd[0]); + + if (Pread(Proc, snd, cpy_rqst, (uintptr_t)sndvec) != cpy_rqst) + break; + + snd_ptr = &snd[0]; + + while (cpy_rqst) { + (void) printf( + "sfv_fd=%d\tsfv_flag=0x%x\t" + "sfv_off=%ld\tsfv_len=%u\n", + snd_ptr->sfv_fd, + snd_ptr->sfv_flag, + snd_ptr->sfv_off, + snd_ptr->sfv_len); + + if (snd_ptr->sfv_fd == SFV_FD_SELF && + prismember(&writefd, fd)) { + showbuffer(pri, + (long)snd_ptr->sfv_off & 0xffffffff, + (long)snd_ptr->sfv_len); + } + + cpy_rqst -= sizeof (snd[0]); + snd_ptr++; + } + + sndvec += MAX_SNDFL_PRD; + } + Xserialize(); +} + +#endif /* _LP64 */ + +/*ARGSUSED*/ +static void +show_sendfilevec(private_t *pri, int fd, sendfilevec_t *sndvec, int sfvcnt) +{ + sendfilevec_t *snd_ptr, snd[MAX_SNDFL_PRD]; + size_t cpy_rqst; + +#ifdef _LP64 + if (data_model != PR_MODEL_LP64) { + show_ksendfilevec32(pri, fd, + (ksendfilevec32_t *)sndvec, sfvcnt); + return; + } +#endif + Eserialize(); + while (sfvcnt > 0) { + cpy_rqst = MIN(sfvcnt, MAX_SNDFL_PRD); + sfvcnt -= cpy_rqst; + cpy_rqst *= sizeof (snd[0]); + + if (Pread(Proc, snd, cpy_rqst, (uintptr_t)sndvec) != cpy_rqst) + break; + + snd_ptr = &snd[0]; + + while (cpy_rqst) { + (void) printf( + "sfv_fd=%d\tsfv_flag=0x%x\t" + "sfv_off=%ld\tsfv_len=%lu\n", + snd_ptr->sfv_fd, + snd_ptr->sfv_flag, + snd_ptr->sfv_off, + (ulong_t)snd_ptr->sfv_len); + + if (snd_ptr->sfv_fd == SFV_FD_SELF && + prismember(&writefd, fd)) { + showbuffer(pri, (long)snd_ptr->sfv_off, + (long)snd_ptr->sfv_len); + } + + cpy_rqst -= sizeof (snd[0]); + snd_ptr++; + } + + sndvec += MAX_SNDFL_PRD; + } + Xserialize(); +} + +/*ARGSUSED*/ +static void +show_sendfilevec64(private_t *pri, int fd, sendfilevec64_t *sndvec, int sfvcnt) +{ + sendfilevec64_t *snd_ptr, snd[MAX_SNDFL_PRD]; + size_t cpy_rqst; + +#ifdef _LP64 + if (data_model != PR_MODEL_LP64) { + show_ksendfilevec64(pri, fd, + (ksendfilevec64_t *)sndvec, sfvcnt); + return; + } +#endif + + Eserialize(); + while (sfvcnt > 0) { + cpy_rqst = MIN(sfvcnt, MAX_SNDFL_PRD); + sfvcnt -= cpy_rqst; + cpy_rqst *= sizeof (snd[0]); + + if (Pread(Proc, snd, cpy_rqst, (uintptr_t)sndvec) != cpy_rqst) + break; + + snd_ptr = &snd[0]; + + while (cpy_rqst) { + (void) printf( +#ifdef _LP64 + "sfv_fd=%d\tsfv_flag=0x%x\t" + "sfv_off=%ld\tsfv_len=%lu\n", +#else + "sfv_fd=%d\tsfv_flag=0x%x\t" + "sfv_off=%lld\tsfv_len=%lu\n", +#endif + snd_ptr->sfv_fd, + snd_ptr->sfv_flag, + snd_ptr->sfv_off, + (ulong_t)snd_ptr->sfv_len); + + if (snd_ptr->sfv_fd == SFV_FD_SELF && + prismember(&writefd, fd)) { + showbuffer(pri, (long)snd_ptr->sfv_off, + (long)snd_ptr->sfv_len); + } + + cpy_rqst -= sizeof (snd[0]); + snd_ptr++; + } + + sndvec += MAX_SNDFL_PRD; + } + Xserialize(); +} + +static void +show_memcntl_mha(private_t *pri, long offset) +{ + struct memcntl_mha mha; + const char *s = NULL; + + if (Pread(Proc, &mha, sizeof (mha), offset) == sizeof (mha)) { + switch (mha.mha_cmd) { + case MHA_MAPSIZE_VA: s = "MHA_MAPSIZE_VA"; break; + case MHA_MAPSIZE_BSSBRK: s = "MHA_MAPSIZE_BSSBRK"; break; + case MHA_MAPSIZE_STACK: s = "MHA_MAPSIZE_STACK"; break; + } + if (s) + (void) printf("%s\tmha_cmd=%s mha_flags=0x%x" + " mha_pagesize=%lu\n", + pri->pname, s, mha.mha_flags, + (ulong_t)mha.mha_pagesize); + else + (void) printf("%s\tmha_cmd=0x%.8x mha_flags=0x%x" + " mha_pagesize=%lu\n", + pri->pname, mha.mha_cmd, mha.mha_flags, + (ulong_t)mha.mha_pagesize); + } +} + +#ifdef _LP64 + +static void +show_memcntl_mha32(private_t *pri, long offset) +{ + struct memcntl_mha32 mha32; + const char *s = NULL; + + if (Pread(Proc, &mha32, sizeof (mha32), offset) == + sizeof (mha32)) { + switch (mha32.mha_cmd) { + case MHA_MAPSIZE_VA: s = "MHA_MAPSIZE_VA"; break; + case MHA_MAPSIZE_BSSBRK: s = "MHA_MAPSIZE_BSSBRK"; break; + case MHA_MAPSIZE_STACK: s = "MHA_MAPSIZE_STACK"; break; + } + if (s) + (void) printf("%s\tmha_cmd=%s mha_flags=0x%x" + " mha_pagesize=%u\n", + pri->pname, s, mha32.mha_flags, mha32.mha_pagesize); + else + (void) printf("%s\tmha_cmd=0x%.8x mha_flags=0x%x" + " mha_pagesize=%u\n", + pri->pname, mha32.mha_cmd, mha32.mha_flags, + mha32.mha_pagesize); + } +} + +#endif /* _LP64 */ + +static void +show_memcntl(private_t *pri) +{ + + if ((int)pri->sys_args[2] != MC_HAT_ADVISE) + return; +#ifdef _LP64 + if (data_model == PR_MODEL_LP64) + show_memcntl_mha(pri, (long)pri->sys_args[3]); + else + show_memcntl_mha32(pri, (long)pri->sys_args[3]); +#else + show_memcntl_mha(pri, (long)pri->sys_args[3]); +#endif +} + +void +show_ids(private_t *pri, long offset, int count) +{ + id_t buf[MYBUFSIZ / sizeof (id_t)]; + id_t *idp; + int serial = (count > MYBUFSIZ / 48); + + if (offset == 0) + return; + + /* enter region of lengthy output */ + if (serial) + Eserialize(); + + while (count > 0 && !interrupt) { + ssize_t nb = (count * sizeof (id_t) < MYBUFSIZ)? + count * sizeof (id_t) : MYBUFSIZ; + + if ((nb = Pread(Proc, &buf[0], (size_t)nb, offset)) < 0 || + nb < sizeof (id_t)) + break; + + idp = buf; + while (!interrupt && nb >= sizeof (id_t)) { + (void) printf("%s\t%8d\n", pri->pname, (int)*idp); + offset += sizeof (id_t); + nb -= sizeof (id_t); + idp++; + count--; + } + } + + /* exit region of lengthy output */ + if (serial) + Xserialize(); +} + +void +show_ntp_gettime(private_t *pri) +{ + struct ntptimeval ntv; + long offset; + + if (pri->sys_nargs < 1 || (offset = pri->sys_args[0]) == NULL) + return; + + if (data_model == PR_MODEL_NATIVE) { + if (Pread(Proc, &ntv, sizeof (ntv), offset) + != sizeof (ntv)) + return; + } else { + struct ntptimeval32 ntv32; + + if (Pread(Proc, &ntv32, sizeof (ntv32), offset) + != sizeof (ntv32)) + return; + + TIMEVAL32_TO_TIMEVAL(&ntv.time, &ntv32.time); + ntv.maxerror = ntv32.maxerror; + ntv.esterror = ntv32.esterror; + } + + (void) printf("\ttime: %ld.%6.6ld sec\n", + ntv.time.tv_sec, ntv.time.tv_usec); + (void) printf("\tmaxerror: %11d usec\n", ntv.maxerror); + (void) printf("\testerror: %11d usec\n", ntv.esterror); +} + +static char * +get_timex_modes(private_t *pri, uint32_t val) +{ + char *str = pri->code_buf; + size_t used = 0; + + *str = '\0'; + if (val & MOD_OFFSET) + used = strlcat(str, "|MOD_OFFSET", sizeof (pri->code_buf)); + if (val & MOD_FREQUENCY) + used = strlcat(str, "|MOD_FREQUENCY", sizeof (pri->code_buf)); + if (val & MOD_MAXERROR) + used = strlcat(str, "|MOD_MAXERROR", sizeof (pri->code_buf)); + if (val & MOD_ESTERROR) + used = strlcat(str, "|MOD_ESTERROR", sizeof (pri->code_buf)); + if (val & MOD_STATUS) + used = strlcat(str, "|MOD_STATUS", sizeof (pri->code_buf)); + if (val & MOD_TIMECONST) + used = strlcat(str, "|MOD_TIMECONST", sizeof (pri->code_buf)); + if (val & MOD_CLKB) + used = strlcat(str, "|MOD_CLKB", sizeof (pri->code_buf)); + if (val & MOD_CLKA) + used = strlcat(str, "|MOD_CLKA", sizeof (pri->code_buf)); + + if (used == 0 || used >= sizeof (pri->code_buf)) + (void) snprintf(str, sizeof (pri->code_buf), " 0x%.4x", val); + + return (str + 1); +} + +static char * +get_timex_status(private_t *pri, int32_t val) +{ + char *str = pri->code_buf; + size_t used = 0; + + *str = '\0'; + if (val & STA_PLL) + used = strlcat(str, "|STA_PLL", sizeof (pri->code_buf)); + if (val & STA_PPSFREQ) + used = strlcat(str, "|STA_PPSFREQ", sizeof (pri->code_buf)); + if (val & STA_PPSTIME) + used = strlcat(str, "|STA_PPSTIME", sizeof (pri->code_buf)); + if (val & STA_FLL) + used = strlcat(str, "|STA_FLL", sizeof (pri->code_buf)); + + if (val & STA_INS) + used = strlcat(str, "|STA_INS", sizeof (pri->code_buf)); + if (val & STA_DEL) + used = strlcat(str, "|STA_DEL", sizeof (pri->code_buf)); + if (val & STA_UNSYNC) + used = strlcat(str, "|STA_UNSYNC", sizeof (pri->code_buf)); + if (val & STA_FREQHOLD) + used = strlcat(str, "|STA_FREQHOLD", sizeof (pri->code_buf)); + + if (val & STA_PPSSIGNAL) + used = strlcat(str, "|STA_PPSSIGNAL", sizeof (pri->code_buf)); + if (val & STA_PPSJITTER) + used = strlcat(str, "|STA_PPSJITTER", sizeof (pri->code_buf)); + if (val & STA_PPSWANDER) + used = strlcat(str, "|STA_PPSWANDER", sizeof (pri->code_buf)); + if (val & STA_PPSERROR) + used = strlcat(str, "|STA_PPSERROR", sizeof (pri->code_buf)); + + if (val & STA_CLOCKERR) + used = strlcat(str, "|STA_CLOCKERR", sizeof (pri->code_buf)); + + if (used == 0 || used >= sizeof (pri->code_buf)) + (void) snprintf(str, sizeof (pri->code_buf), " 0x%.4x", val); + + return (str + 1); +} + +void +show_ntp_adjtime(private_t *pri) +{ + struct timex timex; + long offset; + + if (pri->sys_nargs < 1 || (offset = pri->sys_args[0]) == NULL) + return; + + if (Pread(Proc, &timex, sizeof (timex), offset) != sizeof (timex)) + return; + + (void) printf("\tmodes: %s\n", get_timex_modes(pri, timex.modes)); + (void) printf("\toffset: %11d usec\n", timex.offset); + (void) printf("\tfreq: %11d scaled ppm\n", timex.freq); + (void) printf("\tmaxerror: %11d usec\n", timex.maxerror); + (void) printf("\testerror: %11d usec\n", timex.esterror); + (void) printf("\tstatus: %s\n", get_timex_status(pri, timex.status)); + (void) printf("\tconstant: %11d\n", timex.constant); + (void) printf("\tprecision: %11d usec\n", timex.precision); + (void) printf("\ttolerance: %11d scaled ppm\n", timex.tolerance); + (void) printf("\tppsfreq: %11d scaled ppm\n", timex.ppsfreq); + (void) printf("\tjitter: %11d usec\n", timex.jitter); + (void) printf("\tshift: %11d sec\n", timex.shift); + (void) printf("\tstabil: %11d scaled ppm\n", timex.stabil); + (void) printf("\tjitcnt: %11d\n", timex.jitcnt); + (void) printf("\tcalcnt: %11d\n", timex.calcnt); + (void) printf("\terrcnt: %11d\n", timex.errcnt); + (void) printf("\tstbcnt: %11d\n", timex.stbcnt); +} + +void +show_getrusage(long offset) +{ + struct rusage r; + if (Pread(Proc, &r, sizeof (r), offset) != sizeof (r)) + return; + (void) printf("\t user time: %ld.%6.6ld sec\n", + r.ru_utime.tv_sec, + r.ru_utime.tv_usec); + (void) printf("\t system time: %ld.%6.6ld sec\n", + r.ru_stime.tv_sec, + r.ru_stime.tv_usec); + (void) printf("\t max rss: <unimpl> %ld\n", + r.ru_maxrss); + (void) printf("\t shared data: <unimpl> %ld\n", + r.ru_ixrss); + (void) printf("\t unshared data: <unimpl> %ld\n", + r.ru_idrss); + (void) printf("\t unshared stack: <unimpl> %ld\n", + r.ru_isrss); + (void) printf("\t minor faults: %ld\n", + r.ru_minflt); + (void) printf("\t major faults: %ld\n", + r.ru_majflt); + (void) printf("\t # of swaps: %ld\n", + r.ru_nswap); + (void) printf("\t blocked inputs: %ld\n", + r.ru_inblock); + (void) printf("\t blocked outputs: %ld\n", + r.ru_oublock); + (void) printf("\t msgs sent: %ld\n", + r.ru_msgsnd); + (void) printf("\t msgs rcv'd: %ld\n", + r.ru_msgrcv); + (void) printf("\t signals rcv'd: %ld\n", + r.ru_nsignals); + (void) printf("\tvol cntxt swtchs: %ld\n", + r.ru_nvcsw); + (void) printf("\tinv cntxt swtchs: %ld\n", + r.ru_nivcsw); +} + +#ifdef _LP64 +void +show_getrusage32(long offset) +{ + struct rusage32 r; + if (Pread(Proc, &r, sizeof (r), offset) != sizeof (r)) + return; + (void) printf("\t user time: %d.%6.6d sec\n", + r.ru_utime.tv_sec, + r.ru_utime.tv_usec); + (void) printf("\t system time: %d.%6.6d sec\n", + r.ru_stime.tv_sec, + r.ru_stime.tv_usec); + (void) printf("\t max rss: <unimpl> %d\n", + r.ru_maxrss); + (void) printf("\t shared data: <unimpl> %d\n", + r.ru_ixrss); + (void) printf("\t unshared data: <unimpl> %d\n", + r.ru_idrss); + (void) printf("\t unshared stack: <unimpl> %d\n", + r.ru_isrss); + (void) printf("\t minor faults: %d\n", + r.ru_minflt); + (void) printf("\t major faults: %d\n", + r.ru_majflt); + (void) printf("\t # of swaps: %d\n", + r.ru_nswap); + (void) printf("\t blocked inputs: %d\n", + r.ru_inblock); + (void) printf("\t blocked outputs: %d\n", + r.ru_oublock); + (void) printf("\t msgs sent: %d\n", + r.ru_msgsnd); + (void) printf("\t msgs rcv'd: %d\n", + r.ru_msgrcv); + (void) printf("\t signals rcv'd: %d\n", + r.ru_nsignals); + (void) printf("\tvol cntxt swtchs: %d\n", + r.ru_nvcsw); + (void) printf("\tinv cntxt swtchs: %d\n", + r.ru_nivcsw); +} +#endif + +/* + * Utility function to print a packed nvlist by unpacking + * and calling the libnvpair pretty printer. Frees all + * allocated memory internally. + */ +static void +show_packed_nvlist(private_t *pri, uintptr_t offset, size_t size) +{ + nvlist_t *nvl = NULL; + size_t readsize; + char *buf; + + if ((offset == 0) || (size == 0)) { + return; + } + + buf = my_malloc(size, "nvlist decode buffer"); + readsize = Pread(Proc, buf, size, offset); + if (readsize != size) { + (void) printf("%s\t<?>", pri->pname); + } else { + int result; + + result = nvlist_unpack(buf, size, &nvl, 0); + if (result == 0) { + dump_nvlist(nvl, 8); + nvlist_free(nvl); + } else { + (void) printf("%s\tunpack of nvlist" + " failed: %d\n", pri->pname, result); + } + } + free(buf); +} + +static void +show_zone_create_args(private_t *pri, long offset) +{ + zone_def args; + char zone_name[ZONENAME_MAX]; + char zone_root[MAXPATHLEN]; + char *zone_zfs = NULL; + + if (Pread(Proc, &args, sizeof (args), offset) == sizeof (args)) { + + if (Pread_string(Proc, zone_name, sizeof (zone_name), + (uintptr_t)args.zone_name) == -1) + (void) strcpy(zone_name, "<?>"); + + if (Pread_string(Proc, zone_root, sizeof (zone_root), + (uintptr_t)args.zone_root) == -1) + (void) strcpy(zone_root, "<?>"); + + if (args.zfsbufsz > 0) { + zone_zfs = malloc(MIN(4, args.zfsbufsz)); + if (zone_zfs != NULL) { + if (Pread(Proc, zone_zfs, args.zfsbufsz, + (uintptr_t)args.zfsbuf) == -1) + (void) strcpy(zone_zfs, "<?>"); + } + } else { + zone_zfs = ""; + } + + (void) printf("%s\t zone_name: %s\n", pri->pname, + zone_name); + (void) printf("%s\t zone_root: %s\n", pri->pname, + zone_root); + + show_privset(pri, (uintptr_t)args.zone_privs, + args.zone_privssz, " zone_privs: "); + + (void) printf("%s\t rctlbuf: 0x%p\n", pri->pname, + (void *)args.rctlbuf); + (void) printf("%s\t rctlbufsz: %lu\n", pri->pname, + (ulong_t)args.rctlbufsz); + + show_packed_nvlist(pri, (uintptr_t)args.rctlbuf, + args.rctlbufsz); + + (void) printf("%s\t zfs: %s\n", pri->pname, zone_zfs); + + (void) printf("%s\textended_error: 0x%p\n", pri->pname, + (void *)args.extended_error); + + if (is_system_labeled()) { + char *label_str = NULL; + bslabel_t zone_label; + + (void) printf("%s\t match: %d\n", pri->pname, + args.match); + (void) printf("%s\t doi: %d\n", pri->pname, + args.doi); + + if (Pread_string(Proc, (char *)&zone_label, + sizeof (zone_label), (uintptr_t)args.label) != -1) { + /* show the label as string */ + if (label_to_str(&zone_label, &label_str, + M_LABEL, SHORT_NAMES) != 0) { + /* have to dump label as raw string */ + (void) label_to_str(&zone_label, + &label_str, M_INTERNAL, + SHORT_NAMES); + } + } + + (void) printf("%s\t label: %s\n", + pri->pname, label_str != NULL ? label_str : "<?>"); + if (label_str) + free(label_str); + } + + if (args.zfsbufsz > 0) + free(zone_zfs); + } +} + + +#ifdef _LP64 + +static void +show_zone_create_args32(private_t *pri, long offset) +{ + zone_def32 args; + char zone_name[ZONENAME_MAX]; + char zone_root[MAXPATHLEN]; + char *zone_zfs = NULL; + + if (Pread(Proc, &args, sizeof (args), offset) == sizeof (args)) { + + if (Pread_string(Proc, zone_name, sizeof (zone_name), + (uintptr_t)args.zone_name) == -1) + (void) strcpy(zone_name, "<?>"); + + if (Pread_string(Proc, zone_root, sizeof (zone_root), + (uintptr_t)args.zone_root) == -1) + (void) strcpy(zone_root, "<?>"); + + if (args.zfsbufsz > 0) { + zone_zfs = malloc(MIN(4, args.zfsbufsz)); + if (zone_zfs != NULL) { + if (Pread(Proc, zone_zfs, args.zfsbufsz, + (uintptr_t)args.zfsbuf) == -1) + (void) strcpy(zone_zfs, "<?>"); + } + } else { + zone_zfs = ""; + } + + (void) printf("%s\t zone_name: %s\n", pri->pname, + zone_name); + (void) printf("%s\t zone_root: %s\n", pri->pname, + zone_root); + + show_privset(pri, (uintptr_t)args.zone_privs, + args.zone_privssz, " zone_privs: "); + + (void) printf("%s\t rctlbuf: 0x%x\n", pri->pname, + (caddr32_t)args.rctlbuf); + (void) printf("%s\t rctlbufsz: %lu\n", pri->pname, + (ulong_t)args.rctlbufsz); + + show_packed_nvlist(pri, (uintptr_t)args.rctlbuf, + args.rctlbufsz); + + (void) printf("%s\t zfs: %s\n", pri->pname, zone_zfs); + + (void) printf("%s\textended_error: 0x%x\n", pri->pname, + (caddr32_t)args.extended_error); + + if (is_system_labeled()) { + char *label_str = NULL; + bslabel_t zone_label; + + (void) printf("%s\t match: %d\n", pri->pname, + args.match); + (void) printf("%s\t doi: %d\n", pri->pname, + args.doi); + + if (Pread_string(Proc, (char *)&zone_label, + sizeof (zone_label), (caddr32_t)args.label) != -1) { + /* show the label as string */ + if (label_to_str(&zone_label, &label_str, + M_LABEL, SHORT_NAMES) != 0) { + /* have to dump label as raw string */ + (void) label_to_str(&zone_label, + &label_str, M_INTERNAL, + SHORT_NAMES); + } + } + (void) printf("%s\t label: %s\n", + pri->pname, label_str != NULL ? label_str : "<?>"); + if (label_str) + free(label_str); + } + + if (args.zfsbufsz > 0) + free(zone_zfs); + } +} + +#endif + +static void +show_zones(private_t *pri) +{ + switch (pri->sys_args[0]) { + case ZONE_CREATE: +#ifdef _LP64 + if (data_model == PR_MODEL_LP64) + show_zone_create_args(pri, (long)pri->sys_args[1]); + else + show_zone_create_args32(pri, (long)pri->sys_args[1]); +#else + show_zone_create_args(pri, (long)pri->sys_args[1]); +#endif + break; + } +} + +static void +show_rctlblk(private_t *pri, long _rctlblk) +{ + rctlblk_t *blk; + int size = rctlblk_size(); + size_t readsize; + const char *s; + + blk = my_malloc(size, "rctlblk decode buffer"); + readsize = Pread(Proc, blk, size, _rctlblk); + if (readsize != size) { + (void) printf("%s\t\t<?>", pri->pname); + } else { + (void) printf("%s\t\t Privilege: 0x%x\n", + pri->pname, + rctlblk_get_privilege(blk)); + (void) printf("%s\t\t Value: %lld\n", + pri->pname, + rctlblk_get_value(blk)); + (void) printf("%s\t\tEnforced Value: %lld\n", + pri->pname, + rctlblk_get_enforced_value(blk)); + + { + int sig, act; + act = rctlblk_get_local_action(blk, &sig); + + s = rctl_local_action(pri, act); + if (s == NULL) { + (void) printf("%s\t\t Local action: 0x%x\n", + pri->pname, act); + } else { + (void) printf("%s\t\t Local action: %s\n", + pri->pname, s); + } + + if (act & RCTL_LOCAL_SIGNAL) { + (void) printf("%s\t\t " + "For signal %s\n", + pri->pname, signame(pri, sig)); + } + } + + s = rctl_local_flags(pri, rctlblk_get_local_flags(blk)); + if (s == NULL) { + (void) printf("%s\t\t Local flags: 0x%x\n", + pri->pname, rctlblk_get_local_flags(blk)); + } else { + (void) printf("%s\t\t Local flags: %s\n", + pri->pname, s); + } + +#ifdef _LP64 + (void) printf("%s\t\t Recipient PID: %d\n", + pri->pname, + rctlblk_get_recipient_pid(blk)); +#else + (void) printf("%s\t\t Recipient PID: %ld\n", + pri->pname, + rctlblk_get_recipient_pid(blk)); +#endif + (void) printf("%s\t\t Firing Time: %lld\n", + pri->pname, + rctlblk_get_firing_time(blk)); + } + free(blk); +} + +static void +show_rctls(private_t *pri) +{ + int entry; + + switch (pri->sys_args[0]) { + case 0: /* getrctl */ + case 1: /* setrctl */ + /* + * If these offsets look a little odd, remember that they're + * into the _raw_ system call + */ + (void) printf("%s\tOld rctlblk: 0x%lx\n", pri->pname, + pri->sys_args[2]); + if (pri->sys_args[2] != NULL) { + show_rctlblk(pri, pri->sys_args[2]); + } + (void) printf("%s\tNew rctlblk: 0x%lx\n", pri->pname, + pri->sys_args[3]); + if (pri->sys_args[3] != NULL) { + show_rctlblk(pri, pri->sys_args[3]); + } + break; + case 4: /* setprojrctl */ + for (entry = 0; entry < pri->sys_args[4]; entry++) { + (void) printf("%s\tNew rctlblk[%d]: 0x%lx\n", + pri->pname, entry, + (long)RCTLBLK_INC(pri->sys_args[3], entry)); + if (RCTLBLK_INC(pri->sys_args[3], entry) != NULL) { + show_rctlblk(pri, + (long)RCTLBLK_INC(pri->sys_args[3], entry)); + } + } + } +} + +void +show_utimesys(private_t *pri) +{ + switch (pri->sys_args[0]) { + case 0: /* futimens() */ + if (pri->sys_nargs > 2) + show_utimens(pri, (long)pri->sys_args[2]); + break; + case 1: /* utimensat */ + if (pri->sys_nargs > 3) + show_utimens(pri, (long)pri->sys_args[3]); + break; + default: /* unexpected subcode */ + break; + } +} + +#ifdef _LP64 +static void +show_sockconfig_filter_prop32(private_t *pri, long addr) +{ + struct sockconfig_filter_props32 props; + const char *s = NULL; + char buf[MAX(FILNAME_MAX, MODMAXNAMELEN)]; + sof_socktuple32_t *tup; + size_t sz; + int i; + + if (Pread(Proc, &props, sizeof (props), addr) == sizeof (props)) { + if (Pread_string(Proc, buf, sizeof (buf), + (uintptr_t)props.sfp_modname) == -1) + (void) strcpy(buf, "<?>"); + (void) printf("%s\tmodule name: %s\n", pri->pname, buf); + (void) printf("%s\tattach semantics: %s", pri->pname, + props.sfp_autoattach ? "automatic" : "progammatic"); + if (props.sfp_autoattach) { + buf[0] = '\0'; + switch (props.sfp_hint) { + case SOF_HINT_TOP: s = "top"; break; + case SOF_HINT_BOTTOM: s = "bottom"; break; + case SOF_HINT_BEFORE: + case SOF_HINT_AFTER: + s = (props.sfp_hint == SOF_HINT_BEFORE) ? + "before" : "after"; + if (Pread_string(Proc, buf, sizeof (buf), + (uintptr_t)props.sfp_hintarg) == -1) + (void) strcpy(buf, "<?>"); + } + if (s != NULL) { + (void) printf(", placement: %s %s", s, buf); + } + } + (void) printf("\n"); + (void) printf("%s\tsocket tuples:\n", pri->pname); + if (props.sfp_socktuple_cnt == 0) { + (void) printf("\t\t<empty>\n"); + return; + } + sz = props.sfp_socktuple_cnt * sizeof (*tup); + tup = my_malloc(sz, "socket tuple buffer"); + if (Pread(Proc, tup, sz, (uintptr_t)props.sfp_socktuple) == sz) + for (i = 0; i < props.sfp_socktuple_cnt; i++) { + (void) printf( + "\t\tfamily: %d, type: %d, proto: %d\n", + tup[i].sofst_family, tup[i].sofst_type, + tup[i].sofst_protocol); + } + } +} +#endif /* _LP64 */ +static void +show_sockconfig_filter_prop(private_t *pri, long addr) +{ + struct sockconfig_filter_props props; + const char *s = NULL; + char buf[MAX(FILNAME_MAX, MODMAXNAMELEN)]; + sof_socktuple_t *tup; + size_t sz; + int i; + + if (Pread(Proc, &props, sizeof (props), addr) == sizeof (props)) { + if (Pread_string(Proc, buf, sizeof (buf), + (uintptr_t)props.sfp_modname) == -1) + (void) strcpy(buf, "<?>"); + (void) printf("%s\tmodule name: %s\n", pri->pname, buf); + (void) printf("%s\tattach semantics: %s", pri->pname, + props.sfp_autoattach ? "automatic" : "progammatic"); + if (props.sfp_autoattach) { + buf[0] = '\0'; + switch (props.sfp_hint) { + case SOF_HINT_TOP: s = "top"; break; + case SOF_HINT_BOTTOM: s = "bottom"; break; + case SOF_HINT_BEFORE: + case SOF_HINT_AFTER: + s = (props.sfp_hint == SOF_HINT_BEFORE) ? + "before" : "after"; + if (Pread_string(Proc, buf, sizeof (buf), + (uintptr_t)props.sfp_hintarg) == -1) + (void) strcpy(buf, "<?>"); + } + if (s != NULL) { + (void) printf(", placement: %s", s); + } + } + (void) printf("\n"); + (void) printf("%s\tsocket tuples:\n", pri->pname); + if (props.sfp_socktuple_cnt == 0) { + (void) printf("\t\t<empty>\n"); + return; + } + sz = props.sfp_socktuple_cnt * sizeof (*tup); + tup = my_malloc(sz, "socket tuple buffer"); + if (Pread(Proc, tup, sz, (uintptr_t)props.sfp_socktuple) == sz) + for (i = 0; i < props.sfp_socktuple_cnt; i++) { + (void) printf( + "\t\tfamily: %d, type: %d, proto: %d\n", + tup[i].sofst_family, tup[i].sofst_type, + tup[i].sofst_protocol); + } + } +} + +void +show_sockconfig(private_t *pri) +{ + switch (pri->sys_args[0]) { + case SOCKCONFIG_ADD_FILTER: +#ifdef _LP64 + if (data_model == PR_MODEL_LP64) + show_sockconfig_filter_prop(pri, + (long)pri->sys_args[2]); + else + show_sockconfig_filter_prop32(pri, + (long)pri->sys_args[2]); +#else + show_sockconfig_filter_prop(pri, (long)pri->sys_args[2]); +#endif + break; + default: + break; + } +} + +void +show_zfs_ioc(private_t *pri, long addr) +{ + static const zfs_share_t zero_share = {0}; + static const dmu_objset_stats_t zero_objstats = {0}; + static const struct drr_begin zero_drrbegin = {0}; + static const zinject_record_t zero_injectrec = {0}; + static const zfs_stat_t zero_zstat = {0}; + zfs_cmd_t zc; + + if (Pread(Proc, &zc, sizeof (zc), addr) != sizeof (zc)) { + (void) printf(" zfs_ioctl read failed\n"); + return; + } + + if (zc.zc_name[0]) + (void) printf(" zc_name=%s\n", zc.zc_name); + if (zc.zc_value[0]) + (void) printf(" zc_value=%s\n", zc.zc_value); + if (zc.zc_string[0]) + (void) printf(" zc_string=%s\n", zc.zc_string); + if (zc.zc_guid != 0) { + (void) printf(" zc_guid=%llu\n", + (u_longlong_t)zc.zc_guid); + } + if (zc.zc_nvlist_conf_size) { + (void) printf(" nvlist_conf:\n"); + show_packed_nvlist(pri, zc.zc_nvlist_conf, + zc.zc_nvlist_conf_size); + } + if (zc.zc_nvlist_src_size) { + (void) printf(" nvlist_src:\n"); + show_packed_nvlist(pri, zc.zc_nvlist_src, + zc.zc_nvlist_src_size); + } + if (zc.zc_nvlist_dst_size) { + (void) printf(" nvlist_dst:\n"); + show_packed_nvlist(pri, zc.zc_nvlist_dst, + zc.zc_nvlist_dst_size); + } + if (zc.zc_cookie != 0) { + (void) printf(" zc_cookie=%llu\n", + (u_longlong_t)zc.zc_cookie); + } + if (zc.zc_objset_type != 0) { + (void) printf(" zc_objset_type=%llu\n", + (u_longlong_t)zc.zc_objset_type); + } + if (zc.zc_perm_action != 0) { + (void) printf(" zc_perm_action=%llu\n", + (u_longlong_t)zc.zc_perm_action); + } + if (zc.zc_history != 0) { + (void) printf(" zc_history=%llu\n", + (u_longlong_t)zc.zc_history); + } + if (zc.zc_obj != 0) { + (void) printf(" zc_obj=%llu\n", + (u_longlong_t)zc.zc_obj); + } + if (zc.zc_iflags != 0) { + (void) printf(" zc_obj=0x%llx\n", + (u_longlong_t)zc.zc_iflags); + } + + if (memcmp(&zc.zc_share, &zero_share, sizeof (zc.zc_share))) { + zfs_share_t *z = &zc.zc_share; + (void) printf(" zc_share:\n"); + if (z->z_exportdata) { + (void) printf("\tz_exportdata=0x%llx\n", + (u_longlong_t)z->z_exportdata); + } + if (z->z_sharedata) { + (void) printf("\tz_sharedata=0x%llx\n", + (u_longlong_t)z->z_sharedata); + } + if (z->z_sharetype) { + (void) printf("\tz_sharetype=%llu\n", + (u_longlong_t)z->z_sharetype); + } + if (z->z_sharemax) { + (void) printf("\tz_sharemax=%llu\n", + (u_longlong_t)z->z_sharemax); + } + } + + if (memcmp(&zc.zc_objset_stats, &zero_objstats, + sizeof (zc.zc_objset_stats))) { + dmu_objset_stats_t *dds = &zc.zc_objset_stats; + (void) printf(" zc_objset_stats:\n"); + if (dds->dds_num_clones) { + (void) printf("\tdds_num_clones=%llu\n", + (u_longlong_t)dds->dds_num_clones); + } + if (dds->dds_creation_txg) { + (void) printf("\tdds_creation_txg=%llu\n", + (u_longlong_t)dds->dds_creation_txg); + } + if (dds->dds_guid) { + (void) printf("\tdds_guid=%llu\n", + (u_longlong_t)dds->dds_guid); + } + if (dds->dds_type) + (void) printf("\tdds_type=%u\n", dds->dds_type); + if (dds->dds_is_snapshot) { + (void) printf("\tdds_is_snapshot=%u\n", + dds->dds_is_snapshot); + } + if (dds->dds_inconsistent) { + (void) printf("\tdds_inconsitent=%u\n", + dds->dds_inconsistent); + } + if (dds->dds_origin[0]) { + (void) printf("\tdds_origin=%s\n", dds->dds_origin); + } + } + + if (memcmp(&zc.zc_begin_record, &zero_drrbegin, + sizeof (zc.zc_begin_record))) { + struct drr_begin *drr = &zc.zc_begin_record; + (void) printf(" zc_begin_record:\n"); + if (drr->drr_magic) { + (void) printf("\tdrr_magic=%llu\n", + (u_longlong_t)drr->drr_magic); + } + if (drr->drr_versioninfo) { + (void) printf("\tdrr_versioninfo=%llu\n", + (u_longlong_t)drr->drr_versioninfo); + } + if (drr->drr_creation_time) { + (void) printf("\tdrr_creation_time=%llu\n", + (u_longlong_t)drr->drr_creation_time); + } + if (drr->drr_type) + (void) printf("\tdrr_type=%u\n", drr->drr_type); + if (drr->drr_flags) + (void) printf("\tdrr_flags=0x%x\n", drr->drr_flags); + if (drr->drr_toguid) { + (void) printf("\tdrr_toguid=%llu\n", + (u_longlong_t)drr->drr_toguid); + } + if (drr->drr_fromguid) { + (void) printf("\tdrr_fromguid=%llu\n", + (u_longlong_t)drr->drr_fromguid); + } + if (drr->drr_toname[0]) { + (void) printf("\tdrr_toname=%s\n", drr->drr_toname); + } + } + + if (memcmp(&zc.zc_inject_record, &zero_injectrec, + sizeof (zc.zc_inject_record))) { + zinject_record_t *zi = &zc.zc_inject_record; + (void) printf(" zc_inject_record:\n"); + if (zi->zi_objset) { + (void) printf("\tzi_objset=%llu\n", + (u_longlong_t)zi->zi_objset); + } + if (zi->zi_object) { + (void) printf("\tzi_object=%llu\n", + (u_longlong_t)zi->zi_object); + } + if (zi->zi_start) { + (void) printf("\tzi_start=%llu\n", + (u_longlong_t)zi->zi_start); + } + if (zi->zi_end) { + (void) printf("\tzi_end=%llu\n", + (u_longlong_t)zi->zi_end); + } + if (zi->zi_guid) { + (void) printf("\tzi_guid=%llu\n", + (u_longlong_t)zi->zi_guid); + } + if (zi->zi_level) { + (void) printf("\tzi_level=%lu\n", + (ulong_t)zi->zi_level); + } + if (zi->zi_error) { + (void) printf("\tzi_error=%lu\n", + (ulong_t)zi->zi_error); + } + if (zi->zi_type) { + (void) printf("\tzi_type=%llu\n", + (u_longlong_t)zi->zi_type); + } + if (zi->zi_freq) { + (void) printf("\tzi_freq=%lu\n", + (ulong_t)zi->zi_freq); + } + if (zi->zi_failfast) { + (void) printf("\tzi_failfast=%lu\n", + (ulong_t)zi->zi_failfast); + } + if (zi->zi_func[0]) + (void) printf("\tzi_func=%s\n", zi->zi_func); + if (zi->zi_iotype) { + (void) printf("\tzi_iotype=%lu\n", + (ulong_t)zi->zi_iotype); + } + if (zi->zi_duration) { + (void) printf("\tzi_duration=%ld\n", + (long)zi->zi_duration); + } + if (zi->zi_timer) { + (void) printf("\tzi_timer=%llu\n", + (u_longlong_t)zi->zi_timer); + } + } + + if (zc.zc_defer_destroy) { + (void) printf(" zc_defer_destroy=%d\n", + (int)zc.zc_defer_destroy); + } + if (zc.zc_flags) { + (void) printf(" zc_flags=0x%x\n", + zc.zc_flags); + } + if (zc.zc_action_handle) { + (void) printf(" zc_action_handle=%llu\n", + (u_longlong_t)zc.zc_action_handle); + } + if (zc.zc_cleanup_fd >= 0) + (void) printf(" zc_cleanup_fd=%d\n", zc.zc_cleanup_fd); + if (zc.zc_sendobj) { + (void) printf(" zc_sendobj=%llu\n", + (u_longlong_t)zc.zc_sendobj); + } + if (zc.zc_fromobj) { + (void) printf(" zc_fromobj=%llu\n", + (u_longlong_t)zc.zc_fromobj); + } + if (zc.zc_createtxg) { + (void) printf(" zc_createtxg=%llu\n", + (u_longlong_t)zc.zc_createtxg); + } + + if (memcmp(&zc.zc_stat, &zero_zstat, sizeof (zc.zc_stat))) { + zfs_stat_t *zs = &zc.zc_stat; + (void) printf(" zc_stat:\n"); + if (zs->zs_gen) { + (void) printf("\tzs_gen=%llu\n", + (u_longlong_t)zs->zs_gen); + } + if (zs->zs_mode) { + (void) printf("\tzs_mode=%llu\n", + (u_longlong_t)zs->zs_mode); + } + if (zs->zs_links) { + (void) printf("\tzs_links=%llu\n", + (u_longlong_t)zs->zs_links); + } + if (zs->zs_ctime[0]) { + (void) printf("\tzs_ctime[0]=%llu\n", + (u_longlong_t)zs->zs_ctime[0]); + } + if (zs->zs_ctime[1]) { + (void) printf("\tzs_ctime[1]=%llu\n", + (u_longlong_t)zs->zs_ctime[1]); + } + } +} + +/* expound verbosely upon syscall arguments */ +/*ARGSUSED*/ +void +expound(private_t *pri, long r0, int raw) +{ + const lwpstatus_t *Lsp = pri->lwpstat; + int lp64 = (data_model == PR_MODEL_LP64); + int what = Lsp->pr_what; + int err = pri->Errno; /* don't display output parameters */ + /* for a failed system call */ +#ifndef _LP64 + /* We are a 32-bit truss; we can't grok a 64-bit process */ + if (lp64) + return; +#endif + /* for reporting sleeping system calls */ + if (what == 0 && (Lsp->pr_flags & (PR_ASLEEP|PR_VFORKP))) + what = Lsp->pr_syscall; + + switch (what) { + case SYS_gettimeofday: + if (!err) + show_timeofday(pri); + break; + case SYS_getitimer: + if (!err && pri->sys_nargs > 1) + show_itimerval(pri, (long)pri->sys_args[1], + " value"); + break; + case SYS_setitimer: + if (pri->sys_nargs > 1) + show_itimerval(pri, (long)pri->sys_args[1], + " value"); + if (!err && pri->sys_nargs > 2) + show_itimerval(pri, (long)pri->sys_args[2], + "ovalue"); + break; + case SYS_stime: + show_stime(pri); + break; + case SYS_times: + if (!err) + show_times(pri); + break; + case SYS_utssys: + if (err) + break; +#ifdef _LP64 + if (lp64) + show_utssys(pri, r0); + else + show_utssys32(pri, r0); +#else + show_utssys(pri, r0); +#endif + break; + case SYS_ioctl: + if (pri->sys_nargs >= 3) /* each case must decide for itself */ + show_ioctl(pri, pri->sys_args[1], + (long)pri->sys_args[2]); + break; + case SYS_fstatat: + if (!err && pri->sys_nargs >= 3) + show_stat(pri, (long)pri->sys_args[2]); + break; + case SYS_fstatat64: + if (!err && pri->sys_nargs >= 3) + show_stat64_32(pri, (long)pri->sys_args[2]); + break; + case SYS_stat: + case SYS_fstat: + case SYS_lstat: + if (!err && pri->sys_nargs >= 2) + show_stat(pri, (long)pri->sys_args[1]); + break; + case SYS_stat64: + case SYS_fstat64: + case SYS_lstat64: + if (!err && pri->sys_nargs >= 2) + show_stat64_32(pri, (long)pri->sys_args[1]); + break; + case SYS_statvfs: + case SYS_fstatvfs: + if (err) + break; +#ifdef _LP64 + if (!lp64) { + show_statvfs32(pri); + break; + } +#endif + show_statvfs(pri); + break; + case SYS_statvfs64: + case SYS_fstatvfs64: + if (err) + break; + show_statvfs64(pri); + break; + case SYS_statfs: + case SYS_fstatfs: + if (err) + break; +#ifdef _LP64 + if (lp64) + show_statfs(pri); + else + show_statfs32(pri); +#else + show_statfs(pri); +#endif + break; + case SYS_fcntl: + show_fcntl(pri); + break; + case SYS_msgsys: + show_msgsys(pri, r0); /* each case must decide for itself */ + break; + case SYS_semsys: + show_semsys(pri); /* each case must decide for itself */ + break; + case SYS_shmsys: + show_shmsys(pri); /* each case must decide for itself */ + break; + case SYS_getdents: + if (err || pri->sys_nargs <= 1 || r0 <= 0) + break; +#ifdef _LP64 + if (!lp64) { + show_dents32(pri, (long)pri->sys_args[1], r0); + break; + } + /* FALLTHROUGH */ +#else + show_dents32(pri, (long)pri->sys_args[1], r0); + break; +#endif + case SYS_getdents64: + if (err || pri->sys_nargs <= 1 || r0 <= 0) + break; + show_dents64(pri, (long)pri->sys_args[1], r0); + break; + case SYS_getmsg: + show_gp_msg(pri, what); + if (pri->sys_nargs > 3) + show_hhex_int(pri, (long)pri->sys_args[3], "flags"); + break; + case SYS_getpmsg: + show_gp_msg(pri, what); + if (pri->sys_nargs > 3) + show_hhex_int(pri, (long)pri->sys_args[3], "band"); + if (pri->sys_nargs > 4) + show_hhex_int(pri, (long)pri->sys_args[4], "flags"); + break; + case SYS_putmsg: + case SYS_putpmsg: + show_gp_msg(pri, what); + break; + case SYS_pollsys: + show_pollsys(pri); + break; + case SYS_setgroups: + if (pri->sys_nargs > 1 && (r0 = pri->sys_args[0]) > 0) + show_groups(pri, (long)pri->sys_args[1], r0); + break; + case SYS_getgroups: + if (!err && pri->sys_nargs > 1 && pri->sys_args[0] > 0) + show_groups(pri, (long)pri->sys_args[1], r0); + break; + case SYS_sigprocmask: + if (pri->sys_nargs > 1) + show_sigset(pri, (long)pri->sys_args[1], " set"); + if (!err && pri->sys_nargs > 2) + show_sigset(pri, (long)pri->sys_args[2], "oset"); + break; + case SYS_sigsuspend: + case SYS_sigtimedwait: + if (pri->sys_nargs > 0) + show_sigset(pri, (long)pri->sys_args[0], "sigmask"); + if (!err && pri->sys_nargs > 1) + show_siginfo(pri, (long)pri->sys_args[1]); + if (pri->sys_nargs > 2) + show_timestruc(pri, (long)pri->sys_args[2], "timeout"); + break; + case SYS_sigaltstack: + if (pri->sys_nargs > 0) + show_sigaltstack(pri, (long)pri->sys_args[0], + "new"); + if (!err && pri->sys_nargs > 1) + show_sigaltstack(pri, (long)pri->sys_args[1], + "old"); + break; + case SYS_sigaction: + if (pri->sys_nargs > 1) + show_sigaction(pri, (long)pri->sys_args[1], + "new", NULL); + if (!err && pri->sys_nargs > 2) + show_sigaction(pri, (long)pri->sys_args[2], + "old", r0); + break; + case SYS_signotify: + if (pri->sys_nargs > 1) + show_siginfo(pri, (long)pri->sys_args[1]); + break; + case SYS_sigresend: + if (pri->sys_nargs > 1) + show_siginfo(pri, (long)pri->sys_args[1]); + if (pri->sys_nargs > 2) + show_sigset(pri, (long)pri->sys_args[2], "sigmask"); + break; + case SYS_sigpending: + if (!err && pri->sys_nargs > 1) + show_sigset(pri, (long)pri->sys_args[1], "sigmask"); + break; + case SYS_waitid: + if (!err && pri->sys_nargs > 2) + show_siginfo(pri, (long)pri->sys_args[2]); + break; + case SYS_sigsendsys: + if (pri->sys_nargs > 0) + show_procset(pri, (long)pri->sys_args[0]); + break; + case SYS_priocntlsys: + if (pri->sys_nargs > 1) + show_procset(pri, (long)pri->sys_args[1]); + break; + case SYS_mincore: + if (!err && pri->sys_nargs > 2) + show_bool(pri, (long)pri->sys_args[2], + (pri->sys_args[1] + pagesize - 1) / pagesize); + break; + case SYS_readv: + case SYS_writev: + if (pri->sys_nargs > 2) { + int i = pri->sys_args[0]+1; + int showbuf = FALSE; + long nb = (what == SYS_readv)? r0 : 32*1024; + + if ((what == SYS_readv && !err && + prismember(&readfd, i)) || + (what == SYS_writev && + prismember(&writefd, i))) + showbuf = TRUE; + show_iovec(pri, (long)pri->sys_args[1], + pri->sys_args[2], showbuf, nb); + } + break; + case SYS_getrlimit: + if (err) + break; + /*FALLTHROUGH*/ + case SYS_setrlimit: + if (pri->sys_nargs <= 1) + break; +#ifdef _LP64 + if (lp64) + show_rlimit64(pri, (long)pri->sys_args[1]); + else + show_rlimit32(pri, (long)pri->sys_args[1]); +#else + show_rlimit32(pri, (long)pri->sys_args[1]); +#endif + break; + case SYS_getrlimit64: + if (err) + break; + /*FALLTHROUGH*/ + case SYS_setrlimit64: + if (pri->sys_nargs <= 1) + break; + show_rlimit64(pri, (long)pri->sys_args[1]); + break; + case SYS_uname: + if (!err && pri->sys_nargs > 0) + show_nuname(pri, (long)pri->sys_args[0]); + break; + case SYS_adjtime: + if (!err && pri->sys_nargs > 1) + show_adjtime(pri, (long)pri->sys_args[0], + (long)pri->sys_args[1]); + break; + case SYS_lwp_info: + if (!err && pri->sys_nargs > 0) + show_timestruc(pri, (long)pri->sys_args[0], "cpu time"); + break; + case SYS_lwp_wait: + if (!err && pri->sys_nargs > 1) + show_int(pri, (long)pri->sys_args[1], "lwpid"); + break; + case SYS_lwp_mutex_wakeup: + case SYS_lwp_mutex_unlock: + case SYS_lwp_mutex_trylock: + case SYS_lwp_mutex_register: + if (pri->sys_nargs > 0) + show_mutex(pri, (long)pri->sys_args[0]); + break; + case SYS_lwp_mutex_timedlock: + if (pri->sys_nargs > 0) + show_mutex(pri, (long)pri->sys_args[0]); + if (pri->sys_nargs > 1) + show_timestruc(pri, (long)pri->sys_args[1], "timeout"); + break; + case SYS_lwp_cond_wait: + if (pri->sys_nargs > 0) + show_condvar(pri, (long)pri->sys_args[0]); + if (pri->sys_nargs > 1) + show_mutex(pri, (long)pri->sys_args[1]); + if (pri->sys_nargs > 2) + show_timestruc(pri, (long)pri->sys_args[2], "timeout"); + break; + case SYS_lwp_cond_signal: + case SYS_lwp_cond_broadcast: + if (pri->sys_nargs > 0) + show_condvar(pri, (long)pri->sys_args[0]); + break; + case SYS_lwp_sema_trywait: + case SYS_lwp_sema_post: + if (pri->sys_nargs > 0) + show_sema(pri, (long)pri->sys_args[0]); + break; + case SYS_lwp_sema_timedwait: + if (pri->sys_nargs > 0) + show_sema(pri, (long)pri->sys_args[0]); + if (pri->sys_nargs > 1) + show_timestruc(pri, (long)pri->sys_args[1], "timeout"); + break; + case SYS_lwp_rwlock_sys: + if (pri->sys_nargs > 1) + show_rwlock(pri, (long)pri->sys_args[1]); + if (pri->sys_nargs > 2 && + (pri->sys_args[0] == 0 || pri->sys_args[0] == 1)) + show_timestruc(pri, (long)pri->sys_args[2], "timeout"); + break; + case SYS_lwp_create: + /* XXX print some values in ucontext ??? */ + if (!err && pri->sys_nargs > 2) + show_int(pri, (long)pri->sys_args[2], "lwpid"); + break; + case SYS_kaio: + if (pri->sys_args[0] == AIOWAIT && !err && pri->sys_nargs > 1) + show_timeval(pri, (long)pri->sys_args[1], "timeout"); + break; + case SYS_nanosleep: + if (pri->sys_nargs > 0) + show_timestruc(pri, (long)pri->sys_args[0], "tmout"); + if (pri->sys_nargs > 1 && (err == 0 || err == EINTR)) + show_timestruc(pri, (long)pri->sys_args[1], "resid"); + break; + case SYS_privsys: + switch (pri->sys_args[0]) { + case PRIVSYS_SETPPRIV: + case PRIVSYS_GETPPRIV: + if (!err) + show_privset(pri, (long)pri->sys_args[3], + (size_t)pri->sys_args[4], ""); + } + break; + case SYS_ucredsys: + switch (pri->sys_args[0]) { + case UCREDSYS_UCREDGET: + case UCREDSYS_GETPEERUCRED: + if (err == 0) + show_ucred(pri, (long)pri->sys_args[2]); + break; + } + break; + case SYS_bind: + case SYS_connect: + if (pri->sys_nargs > 2) + show_sockaddr(pri, "name", (long)pri->sys_args[1], + 0, (long)pri->sys_args[2]); + break; + case SYS_sendto: + if (pri->sys_nargs > 5) + show_sockaddr(pri, "to", (long)pri->sys_args[4], 0, + pri->sys_args[5]); + break; + case SYS_accept: + if (!err && pri->sys_nargs > 2) + show_sockaddr(pri, "name", (long)pri->sys_args[1], + (long)pri->sys_args[2], 0); + break; + case SYS_getsockname: + case SYS_getpeername: + if (!err && pri->sys_nargs > 2) + show_sockaddr(pri, "name", (long)pri->sys_args[1], + (long)pri->sys_args[2], 0); + break; + case SYS_cladm: + if (!err && pri->sys_nargs > 2) + show_cladm(pri, pri->sys_args[0], pri->sys_args[1], + (long)pri->sys_args[2]); + break; + case SYS_recvfrom: + if (!err && pri->sys_nargs > 5) + show_sockaddr(pri, "from", (long)pri->sys_args[4], + (long)pri->sys_args[5], 0); + break; + case SYS_recvmsg: + if (err) + break; + /* FALLTHROUGH */ + case SYS_sendmsg: + if (pri->sys_nargs <= 2) + break; +#ifdef _LP64 + if (lp64) + show_msghdr(pri, pri->sys_args[1]); + else + show_msghdr32(pri, pri->sys_args[1]); +#else + show_msghdr(pri, pri->sys_args[1]); +#endif + break; + case SYS_door: + show_doors(pri); + break; + case SYS_sendfilev: + if (pri->sys_nargs != 5) + break; + + if (pri->sys_args[0] == SENDFILEV) { + show_sendfilevec(pri, (int)pri->sys_args[1], + (sendfilevec_t *)pri->sys_args[2], + (int)pri->sys_args[3]); + } else if (pri->sys_args[0] == SENDFILEV64) { + show_sendfilevec64(pri, (int)pri->sys_args[1], + (sendfilevec64_t *)pri->sys_args[2], + (int)pri->sys_args[3]); + } + break; + case SYS_memcntl: + show_memcntl(pri); + break; + case SYS_lwp_park: + /* + * subcode 0: lwp_park(timespec_t *, id_t) + * subcode 4: lwp_set_park(timespec_t *, id_t) + */ + if (pri->sys_nargs > 1 && + (pri->sys_args[0] == 0 || pri->sys_args[0] == 4)) + show_timestruc(pri, (long)pri->sys_args[1], "timeout"); + /* subcode 2: lwp_unpark_all(id_t *, int) */ + if (pri->sys_nargs > 2 && pri->sys_args[0] == 2) + show_ids(pri, (long)pri->sys_args[1], + (int)pri->sys_args[2]); + break; + case SYS_ntp_gettime: + if (!err) + show_ntp_gettime(pri); + break; + case SYS_ntp_adjtime: + if (!err) + show_ntp_adjtime(pri); + break; + case SYS_rusagesys: + if (!err) + if (pri->sys_args[0] == _RUSAGESYS_GETRUSAGE) { +#ifdef _LP64 + if (!lp64) + show_getrusage32(pri->sys_args[1]); + else +#endif + show_getrusage(pri->sys_args[1]); + } + break; + case SYS_port: + show_ports(pri); + break; + case SYS_zone: + show_zones(pri); + break; + case SYS_rctlsys: + show_rctls(pri); + break; + case SYS_utimesys: + show_utimesys(pri); + break; + case SYS_sockconfig: + show_sockconfig(pri); + break; + } +} diff --git a/usr/src/cmd/truss/fcall.c b/usr/src/cmd/truss/fcall.c new file mode 100644 index 0000000..e1fe503 --- /dev/null +++ b/usr/src/cmd/truss/fcall.c @@ -0,0 +1,1911 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#define _SYSCALL32 + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <string.h> +#include <memory.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stack.h> +#include <signal.h> +#include <limits.h> +#include <sys/isa_defs.h> +#include <proc_service.h> +#include <dlfcn.h> +#include <fnmatch.h> +#include <libproc.h> +#include "ramdata.h" +#include "systable.h" +#include "print.h" +#include "proto.h" +#include "htbl.h" + +/* + * Functions supporting library function call tracing. + */ + +typedef struct { + prmap_t *pmap; + int nmap; +} ph_map_t; + +/* + * static functions in this file. + */ +void function_entry(private_t *, struct bkpt *, struct callstack *); +void function_return(private_t *, struct callstack *); +int object_iter(void *, const prmap_t *, const char *); +int object_present(void *, const prmap_t *, const char *); +int symbol_iter(void *, const GElf_Sym *, const char *); +uintptr_t get_return_address(uintptr_t *); +int get_arguments(long *argp); +uintptr_t previous_fp(uintptr_t, uintptr_t *); +int lwp_stack_traps(void *cd, const lwpstatus_t *Lsp); +int thr_stack_traps(const td_thrhandle_t *Thp, void *cd); +struct bkpt *create_bkpt(uintptr_t, int, int); +void set_deferred_breakpoints(void); + +#define DEF_MAXCALL 16 /* initial value of Stk->maxcall */ + +#define FAULT_ADDR ((uintptr_t)(0-8)) + +#define HASHSZ 2048 +#define bpt_hash(addr) ((((addr) >> 13) ^ ((addr) >> 2)) & 0x7ff) + +static void +setup_thread_agent(void) +{ + struct bkpt *Bp; + td_notify_t notify; + td_thr_events_t events; + + if (Thr_agent != NULL) /* only once */ + return; + if (td_init() != TD_OK || td_ta_new(Proc, &Thr_agent) != TD_OK) + Thr_agent = NULL; + else { + td_event_emptyset(&events); + td_event_addset(&events, TD_CREATE); + if (td_ta_event_addr(Thr_agent, TD_CREATE, ¬ify) == TD_OK && + notify.type == NOTIFY_BPT && + td_ta_set_event(Thr_agent, &events) == TD_OK && + (Bp = create_bkpt(notify.u.bptaddr, 0, 1)) != NULL) + Bp->flags |= BPT_TD_CREATE; + } +} + +/* + * Delete all breakpoints in the range [base .. base+size) + * from the breakpoint hash table. + */ +static void +delete_breakpoints(uintptr_t base, size_t size) +{ + struct bkpt **Bpp; + struct bkpt *Bp; + int i; + + if (bpt_hashtable == NULL) + return; + for (i = 0; i < HASHSZ; i++) { + Bpp = &bpt_hashtable[i]; + while ((Bp = *Bpp) != NULL) { + if (Bp->addr < base || Bp->addr >= base + size) { + Bpp = &Bp->next; + continue; + } + *Bpp = Bp->next; + if (Bp->sym_name) + free(Bp->sym_name); + free(Bp); + } + } +} + +/* + * Establishment of breakpoints on traced library functions. + */ +void +establish_breakpoints(void) +{ + if (Dynpat == NULL) + return; + + /* allocate the breakpoint hash table */ + if (bpt_hashtable == NULL) { + bpt_hashtable = my_malloc(HASHSZ * sizeof (struct bkpt *), + NULL); + (void) memset(bpt_hashtable, 0, + HASHSZ * sizeof (struct bkpt *)); + } + + /* + * Set special rtld_db event breakpoints, first time only. + */ + if (Rdb_agent == NULL && + (Rdb_agent = Prd_agent(Proc)) != NULL) { + rd_notify_t notify; + struct bkpt *Bp; + + (void) rd_event_enable(Rdb_agent, 1); + if (rd_event_addr(Rdb_agent, RD_PREINIT, ¬ify) == RD_OK && + (Bp = create_bkpt(notify.u.bptaddr, 0, 1)) != NULL) + Bp->flags |= BPT_PREINIT; + if (rd_event_addr(Rdb_agent, RD_POSTINIT, ¬ify) == RD_OK && + (Bp = create_bkpt(notify.u.bptaddr, 0, 1)) != NULL) + Bp->flags |= BPT_POSTINIT; + if (rd_event_addr(Rdb_agent, RD_DLACTIVITY, ¬ify) == RD_OK && + (Bp = create_bkpt(notify.u.bptaddr, 0, 1)) != NULL) + Bp->flags |= BPT_DLACTIVITY; + } + + /* + * Set special thread event breakpoint, first time libc is seen. + */ + if (Thr_agent == NULL) + setup_thread_agent(); + + /* + * Tell libproc to update its mappings. + */ + Pupdate_maps(Proc); + + /* + * If rtld_db told us a library was being deleted, + * first mark all of the dynlibs as not present, then + * iterate over the shared objects, marking only those + * present that really are present, and finally delete + * all of the not-present dynlibs. + */ + if (delete_library) { + struct dynlib **Dpp; + struct dynlib *Dp; + + for (Dp = Dynlib; Dp != NULL; Dp = Dp->next) + Dp->present = FALSE; + (void) Pobject_iter(Proc, object_present, NULL); + Dpp = &Dynlib; + while ((Dp = *Dpp) != NULL) { + if (Dp->present) { + Dpp = &Dp->next; + continue; + } + delete_breakpoints(Dp->base, Dp->size); + *Dpp = Dp->next; + free(Dp->lib_name); + free(Dp->match_name); + free(Dp->prt_name); + free(Dp); + } + delete_library = FALSE; + } + + /* + * Iterate over the shared objects, creating breakpoints. + */ + (void) Pobject_iter(Proc, object_iter, NULL); + + /* + * Now actually set all the breakpoints we just created. + */ + set_deferred_breakpoints(); +} + +/* + * Initial establishment of stacks in a newly-grabbed process. + * establish_breakpoints() has already been called. + */ +void +establish_stacks(void) +{ + const pstatus_t *Psp = Pstatus(Proc); + char mapfile[64]; + int mapfd; + struct stat statb; + prmap_t *Pmap = NULL; + int nmap = 0; + ph_map_t ph_map; + + (void) sprintf(mapfile, "/proc/%d/rmap", (int)Psp->pr_pid); + if ((mapfd = open(mapfile, O_RDONLY)) < 0 || + fstat(mapfd, &statb) != 0 || + statb.st_size < sizeof (prmap_t) || + (Pmap = my_malloc(statb.st_size, NULL)) == NULL || + (nmap = pread(mapfd, Pmap, statb.st_size, 0L)) <= 0 || + (nmap /= sizeof (prmap_t)) == 0) { + if (Pmap != NULL) + free(Pmap); + Pmap = NULL; + nmap = 0; + } + if (mapfd >= 0) + (void) close(mapfd); + + /* + * Iterate over lwps, establishing stacks. + */ + ph_map.pmap = Pmap; + ph_map.nmap = nmap; + (void) Plwp_iter(Proc, lwp_stack_traps, &ph_map); + if (Pmap != NULL) + free(Pmap); + + if (Thr_agent == NULL) + return; + + /* + * Iterate over unbound threads, establishing stacks. + */ + (void) td_ta_thr_iter(Thr_agent, thr_stack_traps, NULL, + TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, + TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); +} + +void +do_symbol_iter(const char *object_name, struct dynpat *Dyp) +{ + if (*Dyp->Dp->prt_name == '\0') + object_name = PR_OBJ_EXEC; + + /* + * Always search the dynamic symbol table. + */ + (void) Psymbol_iter(Proc, object_name, + PR_DYNSYM, BIND_WEAK|BIND_GLOBAL|TYPE_FUNC, + symbol_iter, Dyp); + + /* + * Search the static symbol table if this is the + * executable file or if we are being asked to + * report internal calls within the library. + */ + if (object_name == PR_OBJ_EXEC || Dyp->internal) + (void) Psymbol_iter(Proc, object_name, + PR_SYMTAB, BIND_ANY|TYPE_FUNC, + symbol_iter, Dyp); +} + +/* ARGSUSED */ +int +object_iter(void *cd, const prmap_t *pmp, const char *object_name) +{ + char name[100]; + struct dynpat *Dyp; + struct dynlib *Dp; + const char *str; + char *s; + int i; + + if ((pmp->pr_mflags & MA_WRITE) || !(pmp->pr_mflags & MA_EXEC)) + return (0); + + /* + * Set special thread event breakpoint, first time libc is seen. + */ + if (Thr_agent == NULL && strstr(object_name, "/libc.so.") != NULL) + setup_thread_agent(); + + for (Dp = Dynlib; Dp != NULL; Dp = Dp->next) + if (strcmp(object_name, Dp->lib_name) == 0 || + (strcmp(Dp->lib_name, "a.out") == 0 && + strcmp(pmp->pr_mapname, "a.out") == 0)) + break; + + if (Dp == NULL) { + Dp = my_malloc(sizeof (struct dynlib), NULL); + (void) memset(Dp, 0, sizeof (struct dynlib)); + if (strcmp(pmp->pr_mapname, "a.out") == 0) { + Dp->lib_name = strdup(pmp->pr_mapname); + Dp->match_name = strdup(pmp->pr_mapname); + Dp->prt_name = strdup(""); + } else { + Dp->lib_name = strdup(object_name); + if ((str = strrchr(object_name, '/')) != NULL) + str++; + else + str = object_name; + (void) strncpy(name, str, sizeof (name) - 2); + name[sizeof (name) - 2] = '\0'; + if ((s = strstr(name, ".so")) != NULL) + *s = '\0'; + Dp->match_name = strdup(name); + (void) strcat(name, ":"); + Dp->prt_name = strdup(name); + } + Dp->next = Dynlib; + Dynlib = Dp; + } + + if (Dp->built || + (not_consist && strcmp(Dp->prt_name, "ld:") != 0)) /* kludge */ + return (0); + + if (hflag && not_consist) + (void) fprintf(stderr, "not_consist is TRUE, building %s\n", + Dp->lib_name); + + Dp->base = pmp->pr_vaddr; + Dp->size = pmp->pr_size; + + /* + * For every dynlib pattern that matches this library's name, + * iterate through all of the library's symbols looking for + * matching symbol name patterns. + */ + for (Dyp = Dynpat; Dyp != NULL; Dyp = Dyp->next) { + if (interrupt|sigusr1) + break; + for (i = 0; i < Dyp->nlibpat; i++) { + if (interrupt|sigusr1) + break; + if (fnmatch(Dyp->libpat[i], Dp->match_name, 0) != 0) + continue; /* no match */ + + /* + * Require an exact match for the executable (a.out) + * and for the dynamic linker (ld.so.1). + */ + if ((strcmp(Dp->match_name, "a.out") == 0 || + strcmp(Dp->match_name, "ld") == 0) && + strcmp(Dyp->libpat[i], Dp->match_name) != 0) + continue; + + /* + * Set Dyp->Dp to Dp so symbol_iter() can use it. + */ + Dyp->Dp = Dp; + do_symbol_iter(object_name, Dyp); + Dyp->Dp = NULL; + } + } + + Dp->built = TRUE; + return (interrupt | sigusr1); +} + +/* ARGSUSED */ +int +object_present(void *cd, const prmap_t *pmp, const char *object_name) +{ + struct dynlib *Dp; + + for (Dp = Dynlib; Dp != NULL; Dp = Dp->next) { + if (Dp->base == pmp->pr_vaddr) + Dp->present = TRUE; + } + + return (0); +} + +/* + * Search for an existing breakpoint at the 'pc' location. + */ +struct bkpt * +get_bkpt(uintptr_t pc) +{ + struct bkpt *Bp; + + for (Bp = bpt_hashtable[bpt_hash(pc)]; Bp != NULL; Bp = Bp->next) + if (pc == Bp->addr) + break; + + return (Bp); +} + +/* + * Create a breakpoint at 'pc', if one is not there already. + * 'ret' is true when creating a function return breakpoint, in which case + * fail and return NULL if the breakpoint would be created in writeable data. + * If 'set' it true, set the breakpoint in the process now. + */ +struct bkpt * +create_bkpt(uintptr_t pc, int ret, int set) +{ + uint_t hix = bpt_hash(pc); + struct bkpt *Bp; + const prmap_t *pmp; + + for (Bp = bpt_hashtable[hix]; Bp != NULL; Bp = Bp->next) + if (pc == Bp->addr) + return (Bp); + + /* + * Don't set return breakpoints on writeable data + * or on any space other than executable text. + * Don't set breakpoints in the child of a vfork() + * because that would modify the parent's address space. + */ + if (is_vfork_child || + (ret && + ((pmp = Paddr_to_text_map(Proc, pc)) == NULL || + !(pmp->pr_mflags & MA_EXEC) || + (pmp->pr_mflags & MA_WRITE)))) + return (NULL); + + /* create a new unnamed breakpoint */ + Bp = my_malloc(sizeof (struct bkpt), NULL); + Bp->sym_name = NULL; + Bp->dyn = NULL; + Bp->addr = pc; + Bp->instr = 0; + Bp->flags = 0; + if (set && Psetbkpt(Proc, Bp->addr, &Bp->instr) == 0) + Bp->flags |= BPT_ACTIVE; + Bp->next = bpt_hashtable[hix]; + bpt_hashtable[hix] = Bp; + + return (Bp); +} + +/* + * Set all breakpoints that haven't been set yet. + * Deactivate all breakpoints from modules that are not present any more. + */ +void +set_deferred_breakpoints(void) +{ + struct bkpt *Bp; + int i; + + if (is_vfork_child) + return; + + for (i = 0; i < HASHSZ; i++) { + for (Bp = bpt_hashtable[i]; Bp != NULL; Bp = Bp->next) { + if (!(Bp->flags & BPT_ACTIVE)) { + if (!(Bp->flags & BPT_EXCLUDE) && + Psetbkpt(Proc, Bp->addr, &Bp->instr) == 0) + Bp->flags |= BPT_ACTIVE; + } else if (Paddr_to_text_map(Proc, Bp->addr) == NULL) { + Bp->flags &= ~BPT_ACTIVE; + } + } + } +} + +int +symbol_iter(void *cd, const GElf_Sym *sym, const char *sym_name) +{ + struct dynpat *Dyp = cd; + struct dynlib *Dp = Dyp->Dp; + uintptr_t pc = sym->st_value; + struct bkpt *Bp; + int i; + + /* ignore any undefined symbols */ + if (sym->st_shndx == SHN_UNDEF) + return (0); + + /* + * Arbitrarily omit "_start" from the executable. + * (Avoid indentation before main().) + */ + if (*Dp->prt_name == '\0' && strcmp(sym_name, "_start") == 0) + return (0); + + /* + * Arbitrarily omit "_rt_boot" from the dynamic linker. + * (Avoid indentation before main().) + */ + if (strcmp(Dp->match_name, "ld") == 0 && + strcmp(sym_name, "_rt_boot") == 0) + return (0); + + /* + * Arbitrarily omit any symbols whose name starts with '.'. + * Apparantly putting a breakpoint on .umul causes a + * fatal error in libthread (%y is not restored correctly + * when a single step is taken). Looks like a /proc bug. + */ + if (*sym_name == '.') + return (0); + + /* + * For each pattern in the array of symbol patterns, + * if the pattern matches the symbol name, then + * create a breakpoint at the function in question. + */ + for (i = 0; i < Dyp->nsympat; i++) { + if (interrupt|sigusr1) + break; + if (fnmatch(Dyp->sympat[i], sym_name, 0) != 0) + continue; + + if ((Bp = create_bkpt(pc, 0, 0)) == NULL) /* can't fail */ + return (0); + + /* + * New breakpoints receive a name now. + * For existing breakpoints, prefer the subset name if possible, + * else prefer the shorter name. + */ + if (Bp->sym_name == NULL) { + Bp->sym_name = strdup(sym_name); + } else if (strstr(Bp->sym_name, sym_name) != NULL || + strlen(Bp->sym_name) > strlen(sym_name)) { + free(Bp->sym_name); + Bp->sym_name = strdup(sym_name); + } + Bp->dyn = Dp; + Bp->flags |= Dyp->flag; + if (Dyp->exclude) + Bp->flags |= BPT_EXCLUDE; + else if (Dyp->internal || *Dp->prt_name == '\0') + Bp->flags |= BPT_INTERNAL; + return (0); + } + + return (interrupt | sigusr1); +} + +/* For debugging only ---- */ +void +report_htable_stats(void) +{ + const pstatus_t *Psp = Pstatus(Proc); + struct callstack *Stk; + struct bkpt *Bp; + uint_t Min = 1000000; + uint_t Max = 0; + uint_t Avg = 0; + uint_t Total = 0; + uint_t i, j; + uint_t bucket[HASHSZ]; + + if (Dynpat == NULL || !hflag) + return; + + hflag = FALSE; + (void) memset(bucket, 0, sizeof (bucket)); + + for (i = 0; i < HASHSZ; i++) { + j = 0; + for (Bp = bpt_hashtable[i]; Bp != NULL; Bp = Bp->next) + j++; + if (j < Min) + Min = j; + if (j > Max) + Max = j; + if (j < HASHSZ) + bucket[j]++; + Total += j; + } + Avg = (Total + HASHSZ / 2) / HASHSZ; + (void) fprintf(stderr, "truss hash table statistics --------\n"); + (void) fprintf(stderr, " Total = %u\n", Total); + (void) fprintf(stderr, " Min = %u\n", Min); + (void) fprintf(stderr, " Max = %u\n", Max); + (void) fprintf(stderr, " Avg = %u\n", Avg); + for (i = 0; i < HASHSZ; i++) + if (bucket[i]) + (void) fprintf(stderr, " %3u buckets of size %d\n", + bucket[i], i); + + (void) fprintf(stderr, "truss-detected stacks --------\n"); + for (Stk = callstack; Stk != NULL; Stk = Stk->next) { + (void) fprintf(stderr, + " base = 0x%.8lx end = 0x%.8lx size = %ld\n", + (ulong_t)Stk->stkbase, + (ulong_t)Stk->stkend, + (ulong_t)(Stk->stkend - Stk->stkbase)); + } + (void) fprintf(stderr, "primary unix stack --------\n"); + (void) fprintf(stderr, + " base = 0x%.8lx end = 0x%.8lx size = %ld\n", + (ulong_t)Psp->pr_stkbase, + (ulong_t)(Psp->pr_stkbase + Psp->pr_stksize), + (ulong_t)Psp->pr_stksize); + (void) fprintf(stderr, "nthr_create = %u\n", nthr_create); +} + +void +make_lwp_stack(const lwpstatus_t *Lsp, prmap_t *Pmap, int nmap) +{ + const pstatus_t *Psp = Pstatus(Proc); + uintptr_t sp = Lsp->pr_reg[R_SP]; + id_t lwpid = Lsp->pr_lwpid; + struct callstack *Stk; + td_thrhandle_t th; + td_thrinfo_t thrinfo; + + if (data_model != PR_MODEL_LP64) + sp = (uint32_t)sp; + + /* check to see if we already have this stack */ + if (sp == 0) + return; + for (Stk = callstack; Stk != NULL; Stk = Stk->next) + if (sp >= Stk->stkbase && sp < Stk->stkend) + return; + + Stk = my_malloc(sizeof (struct callstack), NULL); + Stk->next = callstack; + callstack = Stk; + nstack++; + Stk->tref = 0; + Stk->tid = 0; + Stk->nthr_create = 0; + Stk->ncall = 0; + Stk->maxcall = DEF_MAXCALL; + Stk->stack = my_malloc(DEF_MAXCALL * sizeof (*Stk->stack), NULL); + + /* primary stack */ + if (sp >= Psp->pr_stkbase && sp < Psp->pr_stkbase + Psp->pr_stksize) { + Stk->stkbase = Psp->pr_stkbase; + Stk->stkend = Stk->stkbase + Psp->pr_stksize; + return; + } + + /* alternate stack */ + if ((Lsp->pr_altstack.ss_flags & SS_ONSTACK) && + sp >= (uintptr_t)Lsp->pr_altstack.ss_sp && + sp < (uintptr_t)Lsp->pr_altstack.ss_sp + + Lsp->pr_altstack.ss_size) { + Stk->stkbase = (uintptr_t)Lsp->pr_altstack.ss_sp; + Stk->stkend = Stk->stkbase + Lsp->pr_altstack.ss_size; + return; + } + + /* thread stacks? */ + if (Thr_agent != NULL && + td_ta_map_lwp2thr(Thr_agent, lwpid, &th) == TD_OK && + td_thr_get_info(&th, &thrinfo) == TD_OK && + sp >= (uintptr_t)thrinfo.ti_stkbase - thrinfo.ti_stksize && + sp < (uintptr_t)thrinfo.ti_stkbase) { + /* The bloody fools got this backwards! */ + Stk->stkend = (uintptr_t)thrinfo.ti_stkbase; + Stk->stkbase = Stk->stkend - thrinfo.ti_stksize; + return; + } + + /* last chance -- try the raw memory map */ + for (; nmap; nmap--, Pmap++) { + if (sp >= Pmap->pr_vaddr && + sp < Pmap->pr_vaddr + Pmap->pr_size) { + Stk->stkbase = Pmap->pr_vaddr; + Stk->stkend = Pmap->pr_vaddr + Pmap->pr_size; + return; + } + } + + callstack = Stk->next; + nstack--; + free(Stk->stack); + free(Stk); +} + +void +make_thr_stack(const td_thrhandle_t *Thp, prgregset_t reg) +{ + const pstatus_t *Psp = Pstatus(Proc); + td_thrinfo_t thrinfo; + uintptr_t sp = reg[R_SP]; + struct callstack *Stk; + + if (data_model != PR_MODEL_LP64) + sp = (uint32_t)sp; + + /* check to see if we already have this stack */ + if (sp == 0) + return; + for (Stk = callstack; Stk != NULL; Stk = Stk->next) + if (sp >= Stk->stkbase && sp < Stk->stkend) + return; + + Stk = my_malloc(sizeof (struct callstack), NULL); + Stk->next = callstack; + callstack = Stk; + nstack++; + Stk->tref = 0; + Stk->tid = 0; + Stk->nthr_create = 0; + Stk->ncall = 0; + Stk->maxcall = DEF_MAXCALL; + Stk->stack = my_malloc(DEF_MAXCALL * sizeof (*Stk->stack), NULL); + + /* primary stack */ + if (sp >= Psp->pr_stkbase && sp < Psp->pr_stkbase + Psp->pr_stksize) { + Stk->stkbase = Psp->pr_stkbase; + Stk->stkend = Stk->stkbase + Psp->pr_stksize; + return; + } + + if (td_thr_get_info(Thp, &thrinfo) == TD_OK && + sp >= (uintptr_t)thrinfo.ti_stkbase - thrinfo.ti_stksize && + sp < (uintptr_t)thrinfo.ti_stkbase) { + /* The bloody fools got this backwards! */ + Stk->stkend = (uintptr_t)thrinfo.ti_stkbase; + Stk->stkbase = Stk->stkend - thrinfo.ti_stksize; + return; + } + + callstack = Stk->next; + nstack--; + free(Stk->stack); + free(Stk); +} + +struct callstack * +find_lwp_stack(uintptr_t sp) +{ + const pstatus_t *Psp = Pstatus(Proc); + char mapfile[64]; + int mapfd; + struct stat statb; + prmap_t *Pmap = NULL; + prmap_t *pmap = NULL; + int nmap = 0; + struct callstack *Stk = NULL; + + /* + * Get the address space map. + */ + (void) sprintf(mapfile, "/proc/%d/rmap", (int)Psp->pr_pid); + if ((mapfd = open(mapfile, O_RDONLY)) < 0 || + fstat(mapfd, &statb) != 0 || + statb.st_size < sizeof (prmap_t) || + (Pmap = my_malloc(statb.st_size, NULL)) == NULL || + (nmap = pread(mapfd, Pmap, statb.st_size, 0L)) <= 0 || + (nmap /= sizeof (prmap_t)) == 0) { + if (Pmap != NULL) + free(Pmap); + if (mapfd >= 0) + (void) close(mapfd); + return (NULL); + } + (void) close(mapfd); + + for (pmap = Pmap; nmap--; pmap++) { + if (sp >= pmap->pr_vaddr && + sp < pmap->pr_vaddr + pmap->pr_size) { + Stk = my_malloc(sizeof (struct callstack), NULL); + Stk->next = callstack; + callstack = Stk; + nstack++; + Stk->stkbase = pmap->pr_vaddr; + Stk->stkend = pmap->pr_vaddr + pmap->pr_size; + Stk->tref = 0; + Stk->tid = 0; + Stk->nthr_create = 0; + Stk->ncall = 0; + Stk->maxcall = DEF_MAXCALL; + Stk->stack = my_malloc( + DEF_MAXCALL * sizeof (*Stk->stack), NULL); + break; + } + } + + free(Pmap); + return (Stk); +} + +struct callstack * +find_stack(uintptr_t sp) +{ + const pstatus_t *Psp = Pstatus(Proc); + private_t *pri = get_private(); + const lwpstatus_t *Lsp = pri->lwpstat; + id_t lwpid = Lsp->pr_lwpid; +#if defined(__sparc) + prgreg_t tref = Lsp->pr_reg[R_G7]; +#elif defined(__amd64) + prgreg_t tref = Lsp->pr_reg[REG_FS]; +#elif defined(__i386) + prgreg_t tref = Lsp->pr_reg[GS]; +#endif + struct callstack *Stk = NULL; + td_thrhandle_t th; + td_thrinfo_t thrinfo; + td_err_e error; + + /* primary stack */ + if (sp >= Psp->pr_stkbase && sp < Psp->pr_stkbase + Psp->pr_stksize) { + Stk = my_malloc(sizeof (struct callstack), NULL); + Stk->next = callstack; + callstack = Stk; + nstack++; + Stk->stkbase = Psp->pr_stkbase; + Stk->stkend = Stk->stkbase + Psp->pr_stksize; + Stk->tref = 0; + Stk->tid = 0; + Stk->nthr_create = 0; + Stk->ncall = 0; + Stk->maxcall = DEF_MAXCALL; + Stk->stack = my_malloc(DEF_MAXCALL * sizeof (*Stk->stack), + NULL); + return (Stk); + } + + /* alternate stack */ + if ((Lsp->pr_altstack.ss_flags & SS_ONSTACK) && + sp >= (uintptr_t)Lsp->pr_altstack.ss_sp && + sp < (uintptr_t)Lsp->pr_altstack.ss_sp + + Lsp->pr_altstack.ss_size) { + Stk = my_malloc(sizeof (struct callstack), NULL); + Stk->next = callstack; + callstack = Stk; + nstack++; + Stk->stkbase = (uintptr_t)Lsp->pr_altstack.ss_sp; + Stk->stkend = Stk->stkbase + Lsp->pr_altstack.ss_size; + Stk->tref = 0; + Stk->tid = 0; + Stk->nthr_create = 0; + Stk->ncall = 0; + Stk->maxcall = DEF_MAXCALL; + Stk->stack = my_malloc(DEF_MAXCALL * sizeof (*Stk->stack), + NULL); + return (Stk); + } + + if (Thr_agent == NULL) + return (find_lwp_stack(sp)); + + /* thread stacks? */ + if ((error = td_ta_map_lwp2thr(Thr_agent, lwpid, &th)) != TD_OK) { + if (hflag) + (void) fprintf(stderr, + "cannot get thread handle for " + "lwp#%d, error=%d, tref=0x%.8lx\n", + (int)lwpid, error, (long)tref); + return (NULL); + } + + if ((error = td_thr_get_info(&th, &thrinfo)) != TD_OK) { + if (hflag) + (void) fprintf(stderr, + "cannot get thread info for " + "lwp#%d, error=%d, tref=0x%.8lx\n", + (int)lwpid, error, (long)tref); + return (NULL); + } + + if (sp >= (uintptr_t)thrinfo.ti_stkbase - thrinfo.ti_stksize && + sp < (uintptr_t)thrinfo.ti_stkbase) { + Stk = my_malloc(sizeof (struct callstack), NULL); + Stk->next = callstack; + callstack = Stk; + nstack++; + /* The bloody fools got this backwards! */ + Stk->stkend = (uintptr_t)thrinfo.ti_stkbase; + Stk->stkbase = Stk->stkend - thrinfo.ti_stksize; + Stk->tref = tref; + Stk->tid = thrinfo.ti_tid; + Stk->nthr_create = nthr_create; + Stk->ncall = 0; + Stk->maxcall = DEF_MAXCALL; + Stk->stack = my_malloc(DEF_MAXCALL * sizeof (*Stk->stack), + NULL); + return (Stk); + } + + /* stack bounds failure -- complain bitterly */ + if (hflag) { + (void) fprintf(stderr, + "sp not within thread stack: " + "sp=0x%.8lx stkbase=0x%.8lx stkend=0x%.8lx\n", + (ulong_t)sp, + /* The bloody fools got this backwards! */ + (ulong_t)thrinfo.ti_stkbase - thrinfo.ti_stksize, + (ulong_t)thrinfo.ti_stkbase); + } + + return (NULL); +} + +void +get_tid(struct callstack *Stk) +{ + private_t *pri = get_private(); + const lwpstatus_t *Lsp = pri->lwpstat; + id_t lwpid = Lsp->pr_lwpid; +#if defined(__sparc) + prgreg_t tref = Lsp->pr_reg[R_G7]; +#elif defined(__amd64) + prgreg_t tref = (data_model == PR_MODEL_LP64) ? + Lsp->pr_reg[REG_FS] : Lsp->pr_reg[REG_GS]; +#elif defined(__i386) + prgreg_t tref = Lsp->pr_reg[GS]; +#endif + td_thrhandle_t th; + td_thrinfo_t thrinfo; + td_err_e error; + + if (Thr_agent == NULL) { + Stk->tref = 0; + Stk->tid = 0; + Stk->nthr_create = 0; + return; + } + + /* + * Shortcut here -- + * If we have a matching tref and no new threads have + * been created since the last time we encountered this + * stack, then we don't have to go through the overhead + * of calling td_ta_map_lwp2thr() to get the thread-id. + */ + if (tref == Stk->tref && Stk->nthr_create == nthr_create) + return; + + if ((error = td_ta_map_lwp2thr(Thr_agent, lwpid, &th)) != TD_OK) { + if (hflag) + (void) fprintf(stderr, + "cannot get thread handle for " + "lwp#%d, error=%d, tref=0x%.8lx\n", + (int)lwpid, error, (long)tref); + Stk->tref = 0; + Stk->tid = 0; + Stk->nthr_create = 0; + } else if ((error = td_thr_get_info(&th, &thrinfo)) != TD_OK) { + if (hflag) + (void) fprintf(stderr, + "cannot get thread info for " + "lwp#%d, error=%d, tref=0x%.8lx\n", + (int)lwpid, error, (long)tref); + Stk->tref = 0; + Stk->tid = 0; + Stk->nthr_create = 0; + } else { + Stk->tref = tref; + Stk->tid = thrinfo.ti_tid; + Stk->nthr_create = nthr_create; + } +} + +struct callstack * +callstack_info(uintptr_t sp, uintptr_t fp, int makeid) +{ + struct callstack *Stk; + uintptr_t trash; + + if (sp == 0 || + Pread(Proc, &trash, sizeof (trash), sp) != sizeof (trash)) + return (NULL); + + for (Stk = callstack; Stk != NULL; Stk = Stk->next) + if (sp >= Stk->stkbase && sp < Stk->stkend) + break; + + /* + * If we didn't find the stack, do it the hard way. + */ + if (Stk == NULL) { + uintptr_t stkbase = sp; + uintptr_t stkend; + uint_t minsize; + +#if defined(i386) || defined(__amd64) +#ifdef _LP64 + if (data_model == PR_MODEL_LP64) + minsize = 2 * sizeof (uintptr_t); /* fp + pc */ + else +#endif + minsize = 2 * sizeof (uint32_t); +#else +#ifdef _LP64 + if (data_model != PR_MODEL_LP64) + minsize = SA32(MINFRAME32); + else + minsize = SA64(MINFRAME64); +#else + minsize = SA(MINFRAME); +#endif +#endif /* i386 */ + stkend = sp + minsize; + + while (Stk == NULL && fp != 0 && fp >= sp) { + stkend = fp + minsize; + for (Stk = callstack; Stk != NULL; Stk = Stk->next) + if ((fp >= Stk->stkbase && fp < Stk->stkend) || + (stkend > Stk->stkbase && + stkend <= Stk->stkend)) + break; + if (Stk == NULL) + fp = previous_fp(fp, NULL); + } + + if (Stk != NULL) /* the stack grew */ + Stk->stkbase = stkbase; + } + + if (Stk == NULL && makeid) /* new stack */ + Stk = find_stack(sp); + + if (Stk == NULL) + return (NULL); + + /* + * Ensure that there is room for at least one more entry. + */ + if (Stk->ncall == Stk->maxcall) { + Stk->maxcall *= 2; + Stk->stack = my_realloc(Stk->stack, + Stk->maxcall * sizeof (*Stk->stack), NULL); + } + + if (makeid) + get_tid(Stk); + + return (Stk); +} + +/* + * Reset the breakpoint information (called on successful exec()). + */ +void +reset_breakpoints(void) +{ + struct dynlib *Dp; + struct bkpt *Bp; + struct callstack *Stk; + int i; + + if (Dynpat == NULL) + return; + + /* destroy all previous dynamic library information */ + while ((Dp = Dynlib) != NULL) { + Dynlib = Dp->next; + free(Dp->lib_name); + free(Dp->match_name); + free(Dp->prt_name); + free(Dp); + } + + /* destroy all previous breakpoint trap information */ + if (bpt_hashtable != NULL) { + for (i = 0; i < HASHSZ; i++) { + while ((Bp = bpt_hashtable[i]) != NULL) { + bpt_hashtable[i] = Bp->next; + if (Bp->sym_name) + free(Bp->sym_name); + free(Bp); + } + } + } + + /* destroy all the callstack information */ + while ((Stk = callstack) != NULL) { + callstack = Stk->next; + free(Stk->stack); + free(Stk); + } + + /* we are not a multi-threaded process anymore */ + if (Thr_agent != NULL) + (void) td_ta_delete(Thr_agent); + Thr_agent = NULL; + + /* tell libproc to clear out its mapping information */ + Preset_maps(Proc); + Rdb_agent = NULL; + + /* Reestablish the symbols from the executable */ + (void) establish_breakpoints(); +} + +/* + * Clear breakpoints from the process (called before Prelease()). + * Don't actually destroy the breakpoint table; + * threads currently fielding breakpoints will need it. + */ +void +clear_breakpoints(void) +{ + struct bkpt *Bp; + int i; + + if (Dynpat == NULL) + return; + + /* + * Change all breakpoint traps back to normal instructions. + * We attempt to remove a breakpoint from every address which + * may have ever contained a breakpoint to protect our victims. + */ + report_htable_stats(); /* report stats first */ + for (i = 0; i < HASHSZ; i++) { + for (Bp = bpt_hashtable[i]; Bp != NULL; Bp = Bp->next) { + if (Bp->flags & BPT_ACTIVE) + (void) Pdelbkpt(Proc, Bp->addr, Bp->instr); + Bp->flags &= ~BPT_ACTIVE; + } + } + + if (Thr_agent != NULL) { + td_thr_events_t events; + + td_event_fillset(&events); + (void) td_ta_clear_event(Thr_agent, &events); + (void) td_ta_delete(Thr_agent); + } + Thr_agent = NULL; +} + +/* + * Reestablish the breakpoint traps in the process. + * Called after resuming from a vfork() in the parent. + */ +void +reestablish_traps(void) +{ + struct bkpt *Bp; + ulong_t instr; + int i; + + if (Dynpat == NULL || is_vfork_child) + return; + + for (i = 0; i < HASHSZ; i++) { + for (Bp = bpt_hashtable[i]; Bp != NULL; Bp = Bp->next) { + if ((Bp->flags & BPT_ACTIVE) && + Psetbkpt(Proc, Bp->addr, &instr) != 0) + Bp->flags &= ~BPT_ACTIVE; + } + } +} + +void +show_function_call(private_t *pri, + struct callstack *Stk, struct dynlib *Dp, struct bkpt *Bp) +{ + long arg[8]; + int narg; + int i; + + narg = get_arguments(arg); + make_pname(pri, (Stk != NULL)? Stk->tid : 0); + putpname(pri); + timestamp(pri); + if (Stk != NULL) { + for (i = 1; i < Stk->ncall; i++) { + (void) fputc(' ', stdout); + (void) fputc(' ', stdout); + } + } + (void) printf("-> %s%s(", Dp->prt_name, Bp->sym_name); + for (i = 0; i < narg; i++) { + (void) printf("0x%lx", arg[i]); + if (i < narg-1) { + (void) fputc(',', stdout); + (void) fputc(' ', stdout); + } + } + (void) printf(")\n"); + Flush(); +} + +/* ARGSUSED */ +void +show_function_return(private_t *pri, long rval, int stret, + struct callstack *Stk, struct dynlib *Dp, struct bkpt *Bp) +{ + int i; + + make_pname(pri, Stk->tid); + putpname(pri); + timestamp(pri); + for (i = 0; i < Stk->ncall; i++) { + (void) fputc(' ', stdout); + (void) fputc(' ', stdout); + } + (void) printf("<- %s%s() = ", Dp->prt_name, Bp->sym_name); + if (stret) { + (void) printf("struct return\n"); + } else if (data_model == PR_MODEL_LP64) { + if (rval >= (64 * 1024) || -rval >= (64 * 1024)) + (void) printf("0x%lx\n", rval); + else + (void) printf("%ld\n", rval); + } else { + int rval32 = (int)rval; + if (rval32 >= (64 * 1024) || -rval32 >= (64 * 1024)) + (void) printf("0x%x\n", rval32); + else + (void) printf("%d\n", rval32); + } + Flush(); +} + +/* + * Called to deal with function-call tracing. + * Return 0 on normal success, 1 to indicate a BPT_HANG success, + * and -1 on failure (not tracing functions or unknown breakpoint). + */ +int +function_trace(private_t *pri, int first, int clear, int dotrace) +{ + struct ps_lwphandle *Lwp = pri->Lwp; + const lwpstatus_t *Lsp = pri->lwpstat; + uintptr_t pc = Lsp->pr_reg[R_PC]; + uintptr_t sp = Lsp->pr_reg[R_SP]; + uintptr_t fp = Lsp->pr_reg[R_FP]; + struct bkpt *Bp; + struct dynlib *Dp; + struct callstack *Stk; + ulong_t instr; + int active; + int rval = 0; + + if (Dynpat == NULL) + return (-1); + + if (data_model != PR_MODEL_LP64) { + pc = (uint32_t)pc; + sp = (uint32_t)sp; + fp = (uint32_t)fp; + } + + if ((Bp = get_bkpt(pc)) == NULL) { + if (hflag) + (void) fprintf(stderr, + "function_trace(): " + "cannot find breakpoint for pc: 0x%.8lx\n", + (ulong_t)pc); + return (-1); + } + + if ((Bp->flags & (BPT_PREINIT|BPT_POSTINIT|BPT_DLACTIVITY)) && !clear) { + rd_event_msg_t event_msg; + + if (hflag) { + if (Bp->flags & BPT_PREINIT) + (void) fprintf(stderr, "function_trace(): " + "RD_PREINIT breakpoint\n"); + if (Bp->flags & BPT_POSTINIT) + (void) fprintf(stderr, "function_trace(): " + "RD_POSTINIT breakpoint\n"); + if (Bp->flags & BPT_DLACTIVITY) + (void) fprintf(stderr, "function_trace(): " + "RD_DLACTIVITY breakpoint\n"); + } + if (rd_event_getmsg(Rdb_agent, &event_msg) == RD_OK) { + if (event_msg.type == RD_DLACTIVITY) { + switch (event_msg.u.state) { + case RD_CONSISTENT: + establish_breakpoints(); + break; + case RD_ADD: + not_consist = TRUE; /* kludge */ + establish_breakpoints(); + not_consist = FALSE; + break; + case RD_DELETE: + delete_library = TRUE; + break; + default: + break; + } + } + if (hflag) { + const char *et; + char buf[32]; + + switch (event_msg.type) { + case RD_NONE: + et = "RD_NONE"; + break; + case RD_PREINIT: + et = "RD_PREINIT"; + break; + case RD_POSTINIT: + et = "RD_POSTINIT"; + break; + case RD_DLACTIVITY: + et = "RD_DLACTIVITY"; + break; + default: + (void) sprintf(buf, "0x%x", + event_msg.type); + et = buf; + break; + } + (void) fprintf(stderr, + "event_msg.type = %s ", et); + switch (event_msg.u.state) { + case RD_NOSTATE: + et = "RD_NOSTATE"; + break; + case RD_CONSISTENT: + et = "RD_CONSISTENT"; + break; + case RD_ADD: + et = "RD_ADD"; + break; + case RD_DELETE: + et = "RD_DELETE"; + break; + default: + (void) sprintf(buf, "0x%x", + event_msg.u.state); + et = buf; + break; + } + (void) fprintf(stderr, + "event_msg.u.state = %s\n", et); + } + } + } + + if ((Bp->flags & BPT_TD_CREATE) && !clear) { + nthr_create++; + if (hflag) + (void) fprintf(stderr, "function_trace(): " + "BPT_TD_CREATE breakpoint\n"); + /* we don't care about the event message */ + } + + Dp = Bp->dyn; + + if (dotrace) { + if ((Stk = callstack_info(sp, fp, 1)) == NULL) { + if (Dp != NULL && !clear) { + if (cflag) { + add_fcall(fcall_tbl, Dp->prt_name, + Bp->sym_name, (unsigned long)1); + } + else + show_function_call(pri, NULL, Dp, Bp); + if ((Bp->flags & BPT_HANG) && !first) + rval = 1; + } + } else if (!clear) { + if (Dp != NULL) { + function_entry(pri, Bp, Stk); + if ((Bp->flags & BPT_HANG) && !first) + rval = 1; + } else { + function_return(pri, Stk); + } + } + } + + /* + * Single-step the traced instruction. Since it's possible that + * another thread has deactivated this breakpoint, we indicate + * that we have reactivated it by virtue of executing it. + * + * To avoid a deadlock with some other thread in the process + * performing a fork() or a thr_suspend() operation, we must + * drop and later reacquire truss_lock. Some fancy dancing here. + */ + active = (Bp->flags & BPT_ACTIVE); + Bp->flags |= BPT_ACTIVE; + instr = Bp->instr; + (void) mutex_unlock(&truss_lock); + (void) Lxecbkpt(Lwp, instr); + (void) mutex_lock(&truss_lock); + + if (rval || clear) { /* leave process stopped and abandoned */ +#if defined(__i386) + /* + * Leave it stopped in a state that a stack trace is reasonable. + */ + /* XX64 needs to be updated for amd64 & gcc */ + if (rval && instr == 0x55) { /* pushl %ebp */ + /* step it over the movl %esp,%ebp */ + (void) mutex_unlock(&truss_lock); + (void) Lsetrun(Lwp, 0, PRCFAULT|PRSTEP); + /* we're wrapping up; wait one second at most */ + (void) Lwait(Lwp, MILLISEC); + (void) mutex_lock(&truss_lock); + } +#endif + if (get_bkpt(pc) != Bp) + abend("function_trace: lost breakpoint", NULL); + (void) Pdelbkpt(Proc, Bp->addr, Bp->instr); + Bp->flags &= ~BPT_ACTIVE; + (void) mutex_unlock(&truss_lock); + (void) Lsetrun(Lwp, 0, PRCFAULT|PRSTOP); + /* we're wrapping up; wait one second at most */ + (void) Lwait(Lwp, MILLISEC); + (void) mutex_lock(&truss_lock); + } else { + if (get_bkpt(pc) != Bp) + abend("function_trace: lost breakpoint", NULL); + if (!active || !(Bp->flags & BPT_ACTIVE)) { + (void) Pdelbkpt(Proc, Bp->addr, Bp->instr); + Bp->flags &= ~BPT_ACTIVE; + } + } + return (rval); +} + +void +function_entry(private_t *pri, struct bkpt *Bp, struct callstack *Stk) +{ + const lwpstatus_t *Lsp = pri->lwpstat; + uintptr_t sp = Lsp->pr_reg[R_SP]; + uintptr_t rpc = get_return_address(&sp); + struct dynlib *Dp = Bp->dyn; + int oldframe = FALSE; + int i; + +#ifdef _LP64 + if (data_model != PR_MODEL_LP64) { + sp = (uint32_t)sp; + rpc = (uint32_t)rpc; + } +#endif + + /* + * If the sp is not within the stack bounds, forget it. + * If the symbol's 'internal' flag is false, + * don't report internal calls within the library. + */ + if (!(sp >= Stk->stkbase && sp < Stk->stkend) || + (!(Bp->flags & BPT_INTERNAL) && + rpc >= Dp->base && rpc < Dp->base + Dp->size)) + return; + + for (i = 0; i < Stk->ncall; i++) { + if (sp >= Stk->stack[i].sp) { + Stk->ncall = i; + if (sp == Stk->stack[i].sp) + oldframe = TRUE; + break; + } + } + + /* + * Breakpoints for function returns are set here + * If we're counting function calls, there is no need to set + * a breakpoint upon return + */ + + if (!oldframe && !cflag) { + (void) create_bkpt(rpc, 1, 1); /* may or may not be set */ + Stk->stack[Stk->ncall].sp = sp; /* record it anyeay */ + Stk->stack[Stk->ncall].pc = rpc; + Stk->stack[Stk->ncall].fcn = Bp; + } + Stk->ncall++; + if (cflag) { + add_fcall(fcall_tbl, Dp->prt_name, Bp->sym_name, + (unsigned long)1); + } else { + show_function_call(pri, Stk, Dp, Bp); + } +} + +/* + * We are here because we hit an unnamed breakpoint. + * Attempt to match this up with a return pc on the stack + * and report the function return. + */ +void +function_return(private_t *pri, struct callstack *Stk) +{ + const lwpstatus_t *Lsp = pri->lwpstat; + uintptr_t sp = Lsp->pr_reg[R_SP]; + uintptr_t fp = Lsp->pr_reg[R_FP]; + int i; + +#ifdef _LP64 + if (data_model != PR_MODEL_LP64) { + sp = (uint32_t)sp; + fp = (uint32_t)fp; + } +#endif + + if (fp < sp + 8) + fp = sp + 8; + + for (i = Stk->ncall - 1; i >= 0; i--) { + if (sp <= Stk->stack[i].sp && fp > Stk->stack[i].sp) { + Stk->ncall = i; + break; + } + } + +#if defined(i386) || defined(__amd64) + if (i < 0) { + /* probably __mul64() or friends -- try harder */ + int j; + for (j = 0; i < 0 && j < 8; j++) { /* up to 8 args */ + sp -= 4; + for (i = Stk->ncall - 1; i >= 0; i--) { + if (sp <= Stk->stack[i].sp && + fp > Stk->stack[i].sp) { + Stk->ncall = i; + break; + } + } + } + } +#endif + + if ((i >= 0) && (!cflag)) { + show_function_return(pri, Lsp->pr_reg[R_R0], 0, + Stk, Stk->stack[i].fcn->dyn, Stk->stack[i].fcn); + } +} + +#if defined(__sparc) +#define FPADJUST 0 +#elif defined(__amd64) +#define FPADJUST 8 +#elif defined(__i386) +#define FPADJUST 4 +#endif + +void +trap_one_stack(prgregset_t reg) +{ + struct dynlib *Dp; + struct bkpt *Bp; + struct callstack *Stk; + GElf_Sym sym; + char sym_name[32]; + uintptr_t sp = reg[R_SP]; + uintptr_t pc = reg[R_PC]; + uintptr_t fp; + uintptr_t rpc; + uint_t nframe = 0; + uint_t maxframe = 8; + struct { + uintptr_t sp; /* %sp within called function */ + uintptr_t pc; /* %pc within called function */ + uintptr_t rsp; /* the return sp */ + uintptr_t rpc; /* the return pc */ + } *frame = my_malloc(maxframe * sizeof (*frame), NULL); + + /* + * Gather stack frames bottom to top. + */ + while (sp != 0) { + fp = sp; /* remember higest non-null sp */ + frame[nframe].sp = sp; + frame[nframe].pc = pc; + sp = previous_fp(sp, &pc); + frame[nframe].rsp = sp; + frame[nframe].rpc = pc; + if (++nframe == maxframe) { + maxframe *= 2; + frame = my_realloc(frame, maxframe * sizeof (*frame), + NULL); + } + } + + /* + * Scan for function return breakpoints top to bottom. + */ + while (nframe--) { + /* lookup the called function in the symbol tables */ + if (Plookup_by_addr(Proc, frame[nframe].pc, sym_name, + sizeof (sym_name), &sym) != 0) + continue; + + pc = sym.st_value; /* entry point of the function */ + rpc = frame[nframe].rpc; /* caller's return pc */ + + /* lookup the function in the breakpoint table */ + if ((Bp = get_bkpt(pc)) == NULL || (Dp = Bp->dyn) == NULL) + continue; + + if (!(Bp->flags & BPT_INTERNAL) && + rpc >= Dp->base && rpc < Dp->base + Dp->size) + continue; + + sp = frame[nframe].rsp + FPADJUST; /* %sp at time of call */ + if ((Stk = callstack_info(sp, fp, 0)) == NULL) + continue; /* can't happen? */ + + if (create_bkpt(rpc, 1, 1) != NULL) { + Stk->stack[Stk->ncall].sp = sp; + Stk->stack[Stk->ncall].pc = rpc; + Stk->stack[Stk->ncall].fcn = Bp; + Stk->ncall++; + } + } + + free(frame); +} + +int +lwp_stack_traps(void *cd, const lwpstatus_t *Lsp) +{ + ph_map_t *ph_map = (ph_map_t *)cd; + prgregset_t reg; + + (void) memcpy(reg, Lsp->pr_reg, sizeof (prgregset_t)); + make_lwp_stack(Lsp, ph_map->pmap, ph_map->nmap); + trap_one_stack(reg); + + return (interrupt | sigusr1); +} + +/* ARGSUSED */ +int +thr_stack_traps(const td_thrhandle_t *Thp, void *cd) +{ + prgregset_t reg; + + /* + * We have already dealt with all the lwps. + * We only care about unbound threads here (TD_PARTIALREG). + */ + if (td_thr_getgregs(Thp, reg) != TD_PARTIALREG) + return (0); + + make_thr_stack(Thp, reg); + trap_one_stack(reg); + + return (interrupt | sigusr1); +} + +#if defined(__sparc) + +uintptr_t +previous_fp(uintptr_t sp, uintptr_t *rpc) +{ + uintptr_t fp = 0; + uintptr_t pc = 0; + +#ifdef _LP64 + if (data_model == PR_MODEL_LP64) { + struct rwindow64 rwin; + if (Pread(Proc, &rwin, sizeof (rwin), sp + STACK_BIAS) + == sizeof (rwin)) { + fp = (uintptr_t)rwin.rw_fp; + pc = (uintptr_t)rwin.rw_rtn; + } + if (fp != 0 && + Pread(Proc, &rwin, sizeof (rwin), fp + STACK_BIAS) + != sizeof (rwin)) + fp = pc = 0; + } else { + struct rwindow32 rwin; +#else /* _LP64 */ + struct rwindow rwin; +#endif /* _LP64 */ + if (Pread(Proc, &rwin, sizeof (rwin), sp) == sizeof (rwin)) { + fp = (uint32_t)rwin.rw_fp; + pc = (uint32_t)rwin.rw_rtn; + } + if (fp != 0 && + Pread(Proc, &rwin, sizeof (rwin), fp) != sizeof (rwin)) + fp = pc = 0; +#ifdef _LP64 + } +#endif + if (rpc) + *rpc = pc; + return (fp); +} + +/* ARGSUSED */ +uintptr_t +get_return_address(uintptr_t *psp) +{ + instr_t inst; + private_t *pri = get_private(); + const lwpstatus_t *Lsp = pri->lwpstat; + uintptr_t rpc; + + rpc = (uintptr_t)Lsp->pr_reg[R_O7] + 8; + if (data_model != PR_MODEL_LP64) + rpc = (uint32_t)rpc; + + /* check for structure return (bletch!) */ + if (Pread(Proc, &inst, sizeof (inst), rpc) == sizeof (inst) && + inst < 0x1000) + rpc += sizeof (instr_t); + + return (rpc); +} + +int +get_arguments(long *argp) +{ + private_t *pri = get_private(); + const lwpstatus_t *Lsp = pri->lwpstat; + int i; + + if (data_model != PR_MODEL_LP64) + for (i = 0; i < 4; i++) + argp[i] = (uint_t)Lsp->pr_reg[R_O0+i]; + else + for (i = 0; i < 4; i++) + argp[i] = (long)Lsp->pr_reg[R_O0+i]; + return (4); +} + +#endif /* __sparc */ + +#if defined(__i386) || defined(__amd64) + +uintptr_t +previous_fp(uintptr_t fp, uintptr_t *rpc) +{ + uintptr_t frame[2]; + uintptr_t trash[2]; + + if (Pread(Proc, frame, sizeof (frame), fp) != sizeof (frame) || + (frame[0] != 0 && + Pread(Proc, trash, sizeof (trash), frame[0]) != sizeof (trash))) + frame[0] = frame[1] = 0; + + if (rpc) + *rpc = frame[1]; + return (frame[0]); +} + +#endif + +#if defined(__amd64) || defined(__i386) + +/* + * Examine the instruction at the return location of a function call + * and return the byte count by which the stack is adjusted on return. + * It the instruction at the return location is an addl, as expected, + * then adjust the return pc by the size of that instruction so that + * we will place the return breakpoint on the following instruction. + * This allows programs that interrogate their own stacks and record + * function calls and arguments to work correctly even while we interfere. + * Return the count on success, -1 on failure. + */ +int +return_count32(uint32_t *ppc) +{ + uintptr_t pc = *ppc; + struct bkpt *Bp; + int count; + uchar_t instr[6]; /* instruction at pc */ + + if ((count = Pread(Proc, instr, sizeof (instr), pc)) < 0) + return (-1); + + /* find the replaced instruction at pc (if any) */ + if ((Bp = get_bkpt(pc)) != NULL && (Bp->flags & BPT_ACTIVE)) + instr[0] = (uchar_t)Bp->instr; + + if (count != sizeof (instr) && + (count < 3 || instr[0] != 0x83)) + return (-1); + + /* + * A bit of disassembly of the instruction is required here. + */ + if (instr[1] != 0xc4) { /* not an addl mumble,%esp inctruction */ + count = 0; + } else if (instr[0] == 0x81) { /* count is a longword */ + count = instr[2]+(instr[3]<<8)+(instr[4]<<16)+(instr[5]<<24); + *ppc += 6; + } else if (instr[0] == 0x83) { /* count is a byte */ + count = instr[2]; + *ppc += 3; + } else { /* not an addl inctruction */ + count = 0; + } + + return (count); +} + +uintptr_t +get_return_address32(uintptr_t *psp) +{ + uint32_t sp = *psp; + uint32_t rpc; + int count; + + *psp += 4; /* account for popping the stack on return */ + if (Pread(Proc, &rpc, sizeof (rpc), sp) != sizeof (rpc)) + return (0); + if ((count = return_count32(&rpc)) < 0) + count = 0; + *psp += count; /* expected sp on return */ + return (rpc); +} + +uintptr_t +get_return_address(uintptr_t *psp) +{ +#ifdef _LP64 + uintptr_t rpc; + uintptr_t sp = *psp; + + if (data_model == PR_MODEL_LP64) { + if (Pread(Proc, &rpc, sizeof (rpc), sp) != sizeof (rpc)) + return (0); + /* + * Ignore arguments pushed on the stack. See comments in + * get_arguments(). + */ + return (rpc); + } else +#endif + return (get_return_address32(psp)); +} + + +int +get_arguments32(long *argp) +{ + private_t *pri = get_private(); + const lwpstatus_t *Lsp = pri->lwpstat; + uint32_t frame[5]; /* return pc + 4 args */ + int narg; + int count; + int i; + + narg = Pread(Proc, frame, sizeof (frame), + (uintptr_t)Lsp->pr_reg[R_SP]); + narg -= sizeof (greg32_t); + if (narg <= 0) + return (0); + narg /= sizeof (greg32_t); /* no more than 4 */ + + /* + * Given the return PC, determine the number of arguments. + */ + if ((count = return_count32(&frame[0])) < 0) + narg = 0; + else { + count /= sizeof (greg32_t); + if (narg > count) + narg = count; + } + + for (i = 0; i < narg; i++) + argp[i] = (long)frame[i+1]; + + return (narg); +} + +int +get_arguments(long *argp) +{ +#ifdef _LP64 + private_t *pri = get_private(); + const lwpstatus_t *Lsp = pri->lwpstat; + + if (data_model == PR_MODEL_LP64) { + /* + * On amd64, we do not know how many arguments are passed to + * each function. While it may be possible to detect if we + * have more than 6 arguments, it is of marginal value. + * Instead, assume that we always have 6 arguments, which are + * passed via registers. + */ + argp[0] = Lsp->pr_reg[REG_RDI]; + argp[1] = Lsp->pr_reg[REG_RSI]; + argp[2] = Lsp->pr_reg[REG_RDX]; + argp[3] = Lsp->pr_reg[REG_RCX]; + argp[4] = Lsp->pr_reg[REG_R8]; + argp[5] = Lsp->pr_reg[REG_R9]; + return (6); + } else +#endif + return (get_arguments32(argp)); +} + +#endif /* __amd64 || __i386 */ diff --git a/usr/src/cmd/truss/htbl.c b/usr/src/cmd/truss/htbl.c new file mode 100644 index 0000000..b8f3184 --- /dev/null +++ b/usr/src/cmd/truss/htbl.c @@ -0,0 +1,262 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 + * or http://www.opensolaris.org/os/licensing. + * 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 2002 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <synch.h> +#include <thread.h> +#include <memory.h> +#include <assert.h> +#include <libproc.h> +#include "ramdata.h" +#include "proto.h" +#include "htbl.h" + + +htbl_t * +init_hash(unsigned int size) +{ + htbl_t *htp; + hashb_t *temp; + int i; + + if ((size & (size - 1)) != 0) + abend("Size must be power of two", NULL); + + htp = (htbl_t *)my_malloc(sizeof (htbl_t), NULL); + htp->size = size; + htp->tbl = (hashb_t *) + my_calloc((size_t)size, sizeof (hashb_t), NULL); + + /* Init mutexes */ + for (i = 0; i < size; i++) { + temp = &htp->tbl[i]; + (void) mutex_init(&temp->block, USYNC_THREAD, NULL); + } + + return (htp); +} + +void +destroy_hash(htbl_t *htp) +{ + int i; + hentry_t *tmp; + hentry_t *prev; + hashb_t *cur; + + for (i = 0; i < htp->size; i++) { + cur = &htp->tbl[i]; + (void) mutex_destroy(&cur->block); + tmp = cur->first; + + while (tmp != NULL) { + prev = tmp; + tmp = tmp->next; + + free(prev->key); + prev->key = NULL; + free(prev->lib); + prev->lib = NULL; + + free((char *)prev); + if (tmp != NULL) + tmp->prev = NULL; + } + } + free((char *)htp->tbl); + htp->tbl = NULL; + free(htp); +} + +static unsigned int +hash_str(char *str, unsigned int sz) +{ + uint_t hash = 0; + uint_t g; + char *p; + + assert(str != NULL); + for (p = str; *p != '\0'; p++) { + hash = (hash << 4) + *p; + if ((g = (hash & 0xf0000000)) != 0) { + hash ^= (g >> 24); + hash ^= g; + } + } + + return (hash & (sz - 1)); +} + + +void +add_fcall(htbl_t *htp, char *lib, char *key, unsigned long cnt) +{ + unsigned int bucket; + hentry_t *tmp; + hentry_t *new; + hashb_t *cur; + + bucket = hash_str(key, htp->size); + cur = &htp->tbl[bucket]; + + (void) mutex_lock(&cur->block); + + tmp = cur->first; + while (tmp != NULL) { + if (strcmp(tmp->key, key) == 0) { + if (strcmp(tmp->lib, lib) == 0) { + tmp->count += cnt; + (void) mutex_unlock(&cur->block); + return; + } + } + tmp = tmp->next; + } + + /* + * If we're still here, there was no such fcall recorded + * so we make a new entry and add it to the table + */ + + new = (hentry_t *)my_malloc(sizeof (hentry_t), NULL); + new->key = strdup(key); + if (new->key == NULL) + abend("Out of memory in htbl.c", NULL); + new->lib = strdup(lib); + if (new->lib == NULL) + abend("Out of memory in htbl.c", NULL); + new->count = cnt; + new->prev = NULL; + new->next = cur->first; + tmp = new->next; + if (tmp != NULL) { + tmp->prev = new; + } + cur->first = new; + + (void) mutex_unlock(&cur->block); +} + +/* + * iterate_hash locks the table and returns an enumeration struct + * using this it is possible to iterate through the entries of a hash table + * once finished, use iter_free to unlock the table and free the struct + */ + +hiter_t * +iterate_hash(htbl_t *tbl) +{ + int b; + int i; + hiter_t *new; + hashb_t *cur; + hentry_t *tmp = NULL; + + new = (hiter_t *)my_malloc(sizeof (hiter_t), NULL); + new->table = tbl; + + for (i = 0; i < tbl->size; i++) { + cur = &tbl->tbl[i]; + (void) mutex_lock(&cur->block); + if (tmp == NULL) { + tmp = cur->first; + b = i; + } + } + + new->next = tmp; + new->bucket = b; + + return (new); +} + +void +iter_free(hiter_t *itr) +{ + int i; + hashb_t *cur; + htbl_t *tbl; + + tbl = itr->table; + for (i = 0; i < tbl->size; i++) { + cur = &tbl->tbl[i]; + (void) mutex_unlock(&cur->block); + } + + free(itr); +} + +hentry_t * +iter_next(hiter_t *itr) +{ + int i; + hentry_t *tmp; + hentry_t *ret; + hashb_t *cur = NULL; + htbl_t *hash; + + ret = itr->next; + + + if (ret == NULL) + return (ret); + + hash = itr->table; + tmp = ret->next; + i = itr->bucket; + + if (tmp == NULL) { + for (i = i + 1; i < hash->size; i++) { + cur = &hash->tbl[i]; + tmp = cur->first; + if (tmp != NULL) + break; + } + } + + itr->next = tmp; + itr->bucket = i; + + return (ret); +} + +size_t +elements_in_table(htbl_t *tbl) +{ + size_t elem = 0; + hiter_t *itr = iterate_hash(tbl); + hentry_t *tmp = iter_next(itr); + while (tmp != NULL) { + elem++; + tmp = iter_next(itr); + } + iter_free(itr); + return (elem); +} diff --git a/usr/src/cmd/truss/htbl.h b/usr/src/cmd/truss/htbl.h new file mode 100644 index 0000000..fa37988 --- /dev/null +++ b/usr/src/cmd/truss/htbl.h @@ -0,0 +1,95 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 + * or http://www.opensolaris.org/os/licensing. + * 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 2002 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _HTBL_H +#define _HTBL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdlib.h> + +typedef struct hentry { + struct hentry *next; /* next entry in hash chain */ + struct hentry *prev; /* previous entry in hash chain */ + char *lib; /* library name */ + char *key; /* hash key (function name) */ + unsigned long count; /* number of occurances of fn */ +} hentry_t; + +typedef struct hashb { + hentry_t *first; /* first entry in bucket */ + mutex_t block; /* bucket lock */ +} hashb_t; + +typedef struct htbl { + unsigned int size; /* size of tbl in buckets */ + hashb_t *tbl; /* ptr to buckets */ +} htbl_t; + +typedef struct hiter { + int bucket; /* bucket in current iteration */ + hentry_t *next; /* next entry in iteration */ + htbl_t *table; /* ptr to table */ +} hiter_t; + +/* + * HD_hashntry specifies that the entry written to disk contains information + * about function calls and is stored in the hash table. When read back from + * disk this is merged into the parent's hash table + * + * HD_cts_syscts specifies that the entry written to disk is a struct counts + * struct syscount pair. This contains information about system calls, + * signals, and faults. When read back from disk, the information is added + * to the struct count / struct syscount information kept by the parent. + */ + +typedef enum hdtype { HD_hashntry, HD_cts_syscts } hdtype_t; + +typedef struct hdntry { + hdtype_t type; /* type of entry we've written to disk */ + size_t sz_lib; /* size of library string on disk */ + size_t sz_key; /* size of key string on disk */ + unsigned long count; /* count of occurrances of key */ +} hdntry_t; + + +extern htbl_t *init_hash(unsigned int); +extern void destroy_hash(htbl_t *); +extern hiter_t *iterate_hash(htbl_t *); +extern hentry_t *iter_next(hiter_t *); +extern void iter_free(hiter_t *); +extern void add_fcall(htbl_t *, char *, char *, unsigned long); +extern size_t elements_in_table(htbl_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _HTBL_H */ diff --git a/usr/src/cmd/truss/ipc.c b/usr/src/cmd/truss/ipc.c new file mode 100644 index 0000000..2bb3465 --- /dev/null +++ b/usr/src/cmd/truss/ipc.c @@ -0,0 +1,417 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2010 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <string.h> +#include <signal.h> +#include <stropts.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/termio.h> +#include <libproc.h> +#include "ramdata.h" +#include "proto.h" + +/* + * Routines related to interprocess communication + * among the truss processes which are controlling + * multiple traced processes. + */ + +/* + * Function prototypes for static routines in this module. + */ +void Ecritical(int); +void Xcritical(int); + +/* + * Ensure everyone keeps out of each other's way + * while writing lines of trace output. + */ +void +Flush() +{ + /* + * Except for regions bounded by Eserialize()/Xserialize(), + * this is the only place anywhere in the program where a + * write() to the trace output file takes place, so here + * is where we detect errors writing to the output. + */ + + errno = 0; + + Ecritical(0); + (void) fflush(stdout); + Xcritical(0); + + if (ferror(stdout) && errno) /* error on write(), probably EPIPE */ + interrupt = SIGTERM; /* post an interrupt */ +} + +/* + * Eserialize() and Xserialize() are used to bracket + * a region which may produce large amounts of output, + * such as showargs()/dumpargs(). + */ + +void +Eserialize() +{ + /* serialize output */ + Ecritical(0); +} + +void +Xserialize() +{ + (void) fflush(stdout); + Xcritical(0); +} + +/* + * Enter critical region --- Wait on mutex, lock out other processes. + * Lock zero is used to serialize output in situations where multiple processes + * may be writing to stdout/stderr and order must be preserved. Most of these + * are in expound.c + * Lock one is used to protect the table of processes currently being traced + * every time a pid is added or removed from the table Ecritical(1)/Xcritical(1) + * get called. + */ +void +Ecritical(int num) +{ + int rv; + + if (num == 0) + rv = mutex_lock(&gps->ps_mutex0); + else if (num == 1) + rv = mutex_lock(&gps->ps_mutex1); + else + abend("Invalid mutex specified", NULL); + + if (rv != 0) { + char mnum[2]; + mnum[0] = '0' + num; + mnum[1] = '\0'; + errno = rv; + perror(command); + errmsg("cannot grab mutex #", mnum); + } +} + +/* + * Exit critical region --- + * Release other processes waiting on mutex. + */ +void +Xcritical(int num) +{ + int rv; + + if (num == 0) + rv = mutex_unlock(&gps->ps_mutex0); + else if (num == 1) + rv = mutex_unlock(&gps->ps_mutex1); + else + abend("Invalid mutex specified", NULL); + + + if (rv != 0) { + char mnum[2]; + mnum[0] = '0' + num; + mnum[1] = '\0'; + errno = rv; + perror(command); + errmsg("cannot release mutex #", mnum); + } +} + +/* + * Add process to set of those being traced. + */ +void +procadd(pid_t spid, const char *lwplist) +{ + int i; + int j = -1; + + if (gps == NULL) + return; + + Ecritical(1); + for (i = 0; i < sizeof (gps->tpid) / sizeof (gps->tpid[0]); i++) { + if (gps->tpid[i] == 0) { + if (j == -1) /* remember first vacant slot */ + j = i; + if (gps->spid[i] == 0) /* this slot is better */ + break; + } + } + if (i < sizeof (gps->tpid) / sizeof (gps->tpid[0])) + j = i; + if (j >= 0) { + gps->tpid[j] = getpid(); + gps->spid[j] = spid; + gps->lwps[j] = lwplist; + } + Xcritical(1); +} + +/* + * Delete process from set of those being traced. + */ +void +procdel() +{ + int i; + pid_t tpid; + + if (gps == NULL) + return; + + tpid = getpid(); + + Ecritical(1); + for (i = 0; i < sizeof (gps->tpid) / sizeof (gps->tpid[0]); i++) { + if (gps->tpid[i] == tpid) { + gps->tpid[i] = 0; + break; + } + } + Xcritical(1); +} + +/* + * Determine if the lwp for this process should be traced. + */ +int +lwptrace(pid_t spid, lwpid_t lwpid) +{ + int i; + pid_t tpid; + const char *lwps; + + if (gps == NULL) + return (0); + + tpid = getpid(); + + Ecritical(1); + for (i = 0; i < sizeof (gps->tpid) / sizeof (gps->tpid[0]); i++) { + if (gps->tpid[i] == tpid && + gps->spid[i] == spid) + break; + } + lwps = gps->lwps[i]; + Xcritical(1); + + return (proc_lwp_in_set(lwps, lwpid)); +} + +/* + * Check for open of a /proc/nnnnn file. + * Return 0 if this is not an open of a /proc file. + * Return 1 if the process opened itself. + * Return 2 if the process failed to open another process + * in truss's set of controlled processes. + * Return 3 if the process successfully opened another process + * in truss's set of controlled processes. + * We notify and wait for the other controlling truss process + * to terminate before returning in cases 2 and 3. + */ +/* ARGSUSED */ +int +checkproc(private_t *pri) +{ + char *path = pri->sys_path; + const pstatus_t *Psp = Pstatus(Proc); + struct ps_lwphandle *Lwp = pri->Lwp; + const lwpstatus_t *Lsp = pri->lwpstat; + int what = Lsp->pr_what; /* one of the SYS_open* syscalls */ + int err = Lsp->pr_errno; + int pid; + int i; + const char *dirname; + char *next; + char *sp1; + char *sp2; + prgreg_t pc; + + /* + * A bit heuristic ... + * Test for the cases: + * 1234 + * 1234/as + * 1234/ctl + * 1234/lwp/24/lwpctl + * .../1234 + * .../1234/as + * .../1234/ctl + * .../1234/lwp/24/lwpctl + * Insert a '\0', if necessary, so the path becomes ".../1234". + * + * Along the way, watch out for /proc/self and /proc/1234/lwp/agent + */ + if ((sp1 = strrchr(path, '/')) == NULL) /* last component */ + /* EMPTY */; + else if (isdigit(*(sp1+1))) { + sp1 += strlen(sp1); + while (--sp1 > path && isdigit(*sp1)) + ; + if (*sp1 != '/') + return (0); + } else if (strcmp(sp1+1, "as") == 0 || + strcmp(sp1+1, "ctl") == 0) { + *sp1 = '\0'; + } else if (strcmp(sp1+1, "lwpctl") == 0) { + /* + * .../1234/lwp/24/lwpctl + * ............ ^-- sp1 + */ + if (sp1-6 >= path && strncmp(sp1-6, "/agent", 6) == 0) + sp1 -= 6; + else { + while (--sp1 > path && isdigit(*sp1)) + ; + } + if (*sp1 != '/' || + (sp1 -= 4) <= path || + strncmp(sp1, "/lwp", 4) != 0) + return (0); + *sp1 = '\0'; + } else if (strcmp(sp1+1, "self") != 0) { + return (0); + } + + if ((sp2 = strrchr(path, '/')) == NULL) + dirname = path; + else + dirname = sp2 + 1; + + if (strcmp(dirname, "self") == 0) { + pid = Psp->pr_pid; + } else if ((pid = strtol(dirname, &next, 10)) < 0 || + *next != '\0') { /* dirname not a number */ + if (sp1 != NULL) + *sp1 = '/'; + return (0); + } + if (sp2 == NULL) + dirname = "."; + else { + *sp2 = '\0'; + dirname = path; + } + + if (!Pisprocdir(Proc, dirname) || /* file not in a /proc directory */ + pid == getpid() || /* process opened truss's /proc file */ + pid == 0) { /* process opened process 0 */ + if (sp1 != NULL) + *sp1 = '/'; + if (sp2 != NULL) + *sp2 = '/'; + return (0); + } + if (sp1 != NULL) + *sp1 = '/'; + if (sp2 != NULL) + *sp2 = '/'; + + /* + * Process did open a /proc file --- + */ + if (pid == Psp->pr_pid) { /* process opened its own /proc file */ + /* + * In SunOS 5.6 and beyond, self-opens always succeed. + */ + return (1); + } + + /* + * Search for a matching pid in our set of controlled processes. + */ + for (i = 0; i < sizeof (gps->tpid)/sizeof (gps->tpid[0]); i++) { + if (gps->spid[i] == pid) { + pid = gps->tpid[i]; + break; + } + } + if (i >= sizeof (gps->tpid) / sizeof (gps->tpid[0])) { + /* + * The process opened a /proc file, but not one we care about. + */ + return (0); + } + + /* + * Notify and wait for the controlling process to terminate. + */ + while (pid && gps->tpid[i] == pid) { + if (kill(pid, SIGUSR1) == -1) + break; + (void) usleep(1000000); + } + Ecritical(1); + if (gps->tpid[i] == 0) + gps->spid[i] = 0; + Xcritical(1); + + if (err) { /* prepare to reissue the failed open() system call */ +#if defined(__sparc) + (void) Lgetareg(Lwp, R_PC, &pc); + if (pri->sys_indirect) { + (void) Lputareg(Lwp, R_G1, (prgreg_t)SYS_syscall); + (void) Lputareg(Lwp, R_O0, (prgreg_t)what); + for (i = 0; i < 5; i++) + (void) Lputareg(Lwp, R_O1+i, pri->sys_args[i]); + } else { + (void) Lputareg(Lwp, R_G1, (prgreg_t)what); + for (i = 0; i < 6; i++) + (void) Lputareg(Lwp, R_O0+i, pri->sys_args[i]); + } + (void) Lputareg(Lwp, R_nPC, pc); +#elif defined(__amd64) + (void) Lgetareg(Lwp, R_PC, &pc); + (void) Lputareg(Lwp, REG_RAX, (prgreg_t)what); +#elif defined(__i386) + (void) Lgetareg(Lwp, R_PC, &pc); + (void) Lputareg(Lwp, EAX, (prgreg_t)what); +#else +#error "unrecognized architecture" +#endif + (void) Pissyscall_prev(Proc, pc, (uintptr_t *)&pc); + (void) Lputareg(Lwp, R_PC, pc); + return (2); + } + + return (3); +} diff --git a/usr/src/cmd/truss/listopts.c b/usr/src/cmd/truss/listopts.c new file mode 100644 index 0000000..17d9a50 --- /dev/null +++ b/usr/src/cmd/truss/listopts.c @@ -0,0 +1,661 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <string.h> +#include <memory.h> +#include <sys/types.h> +#include <signal.h> +#include <libproc.h> +#include "ramdata.h" +#include "systable.h" +#include "proto.h" + +/* XXX A bug in the <string.h> header file requires this */ +extern char *strtok_r(char *s1, const char *s2, char **lasts); + +/* + * option procesing --- + * Routines for scanning syscall, signal, fault + * and file descriptor lists. + */ + +/* + * Function prototypes for static routines in this module. + */ +void upcase(char *); + +const char white[] = " \t\n"; /* white space characters */ +const char sepr[] = " ,\t\n"; /* list separator characters */ +const char csepr[] = " :,\t\n"; /* same, with ':' added */ + +/* + * Scan list of syscall names. + * Return 0 on success, != 0 on any failure. + */ +int +syslist(char *str, /* string of syscall names */ + sysset_t *setp, /* syscall set */ + int *fp) /* first-time flag */ +{ + char *name; + int exclude = FALSE; + int rc = 0; + char *lasts; + + name = strtok_r(str, sepr, &lasts); + + if (name != NULL && *name == '!') { /* exclude from set */ + exclude = TRUE; + if (*++name == '\0') + name = strtok_r(NULL, sepr, &lasts); + } else if (!*fp) { /* first time, clear the set */ + premptyset(setp); + *fp = TRUE; + } + + for (; name; name = strtok_r(NULL, sepr, &lasts)) { + int sys; + int sysx; + int sysxx; + int sys64; + char *next; + + if (*name == '!') { /* exclude remainder from set */ + exclude = TRUE; + while (*++name == '!') + /* empty */; + if (*name == '\0') + continue; + } + + sys = strtol(name, &next, 0); + sysx = sysxx = sys64 = 0; + if (sys < 0 || sys > PRMAXSYS || *next != '\0') + sys = 0; + if (sys == 0) { + const struct systable *stp = systable; + for (; sys == 0 && stp->nargs >= 0; stp++) + if (stp->name && strcmp(stp->name, name) == 0) + sys = stp-systable; + } + if (sys == 0) { + const struct sysalias *sap = sysalias; + for (; sys == 0 && sap->name; sap++) + if (strcmp(sap->name, name) == 0) + sys = sap->number; + } + if (sys > 0 && sys <= PRMAXSYS) { + switch (sys) { + case SYS_fstatat: /* set both if either */ + case SYS_fstatat64: + sys = SYS_fstatat; + sys64 = SYS_fstatat64; + goto def; + + case SYS_stat: /* set all if either */ + case SYS_stat64: + sys = SYS_stat; + sys64 = SYS_stat64; + sysx = SYS_fstatat; + sysxx = SYS_fstatat64; + goto def; + + case SYS_lstat: /* set all if either */ + case SYS_lstat64: + sys = SYS_lstat; + sys64 = SYS_lstat64; + sysx = SYS_fstatat; + sysxx = SYS_fstatat64; + goto def; + + case SYS_fstat: /* set all if either */ + case SYS_fstat64: + sys = SYS_fstat; + sys64 = SYS_fstat64; + sysx = SYS_fstatat; + sysxx = SYS_fstatat64; + goto def; + + case SYS_getdents: /* set both if either */ + case SYS_getdents64: + sys = SYS_getdents; + sys64 = SYS_getdents64; + goto def; + + case SYS_mmap: /* set both if either */ + case SYS_mmap64: + sys = SYS_mmap; + sys64 = SYS_mmap64; + goto def; + + case SYS_statvfs: /* set both if either */ + case SYS_statvfs64: + sys = SYS_statvfs; + sys64 = SYS_statvfs64; + goto def; + + case SYS_fstatvfs: /* set both if either */ + case SYS_fstatvfs64: + sys = SYS_fstatvfs; + sys64 = SYS_fstatvfs64; + goto def; + + case SYS_setrlimit: /* set both if either */ + case SYS_setrlimit64: + sys = SYS_setrlimit; + sys64 = SYS_setrlimit64; + goto def; + + case SYS_getrlimit: /* set both if either */ + case SYS_getrlimit64: + sys = SYS_getrlimit; + sys64 = SYS_getrlimit64; + goto def; + + case SYS_pread: /* set both if either */ + case SYS_pread64: + sys = SYS_pread; + sys64 = SYS_pread64; + goto def; + + case SYS_pwrite: /* set both if either */ + case SYS_pwrite64: + sys = SYS_pwrite; + sys64 = SYS_pwrite64; + goto def; + + case SYS_openat: /* set all if any */ + case SYS_openat64: + case SYS_open: + case SYS_open64: + sys = SYS_openat; + sys64 = SYS_openat64; + sysx = SYS_open; + sysxx = SYS_open64; + goto def; + + case SYS_forksys: /* set both if either */ + case SYS_vfork: + sysx = SYS_forksys; + sys = SYS_vfork; + goto def; + + case SYS_sigprocmask: /* set both if either */ + case SYS_lwp_sigmask: + sysx = SYS_sigprocmask; + sys = SYS_lwp_sigmask; + goto def; + + case SYS_lseek: /* set both if either */ + case SYS_llseek: + sysx = SYS_lseek; + sys = SYS_llseek; + goto def; + + case SYS_rename: /* set both */ + sysx = SYS_renameat; + goto def; + + case SYS_link: /* set both */ + sysx = SYS_linkat; + goto def; + + case SYS_unlink: /* set both */ + case SYS_rmdir: /* set both */ + sysx = SYS_unlinkat; + goto def; + + case SYS_symlink: /* set both */ + sysx = SYS_symlinkat; + goto def; + + case SYS_readlink: /* set both */ + sysx = SYS_readlinkat; + goto def; + + case SYS_chmod: /* set both */ + case SYS_fchmod: /* set both */ + sysx = SYS_fchmodat; + goto def; + + case SYS_chown: /* set both */ + case SYS_lchown: /* set both */ + case SYS_fchown: /* set both */ + sysx = SYS_fchownat; + goto def; + + case SYS_mkdir: /* set both */ + sysx = SYS_mkdirat; + goto def; + + case SYS_mknod: /* set both */ + sysx = SYS_mknodat; + goto def; + + case SYS_access: /* set both */ + sysx = SYS_faccessat; + goto def; + + default: + def: + if (exclude) { + prdelset(setp, sys); + if (sysx) + prdelset(setp, sysx); + if (sysxx) + prdelset(setp, sysxx); + if (sys64) + prdelset(setp, sys64); + } else { + praddset(setp, sys); + if (sysx) + praddset(setp, sysx); + if (sysxx) + praddset(setp, sysxx); + if (sys64) + praddset(setp, sys64); + } + break; + } + } else if (strcmp(name, "all") == 0 || + strcmp(name, "ALL") == 0) { + if (exclude) { + premptyset(setp); + } else { + prfillset(setp); + } + } else { + (void) fprintf(stderr, + "%s: unrecognized syscall: %s\n", + command, name); + rc = -1; + } + } + + return (rc); +} + +/* + * List of signals to trace. + * Return 0 on success, != 0 on any failure. + */ +int +siglist(private_t *pri, + char *str, /* string of signal names */ + sigset_t *setp, /* signal set */ + int *fp) /* first-time flag */ +{ + char *name; + int exclude = FALSE; + int rc = 0; + char *lasts; + + upcase(str); + name = strtok_r(str, sepr, &lasts); + + if (name != NULL && *name == '!') { /* exclude from set */ + exclude = TRUE; + if (*++name == '\0') + name = strtok_r(NULL, sepr, &lasts); + } else if (!*fp) { /* first time, clear the set */ + premptyset(setp); + *fp = TRUE; + } + + for (; name; name = strtok_r(NULL, sepr, &lasts)) { + int sig; + char *next; + + if (*name == '!') { /* exclude remainder from set */ + exclude = TRUE; + while (*++name == '!') + /* empty */; + if (*name == '\0') + continue; + } + + sig = strtol(name, &next, 0); + if (sig <= 0 || sig > PRMAXSIG || *next != '\0') { + for (sig = 1; sig <= PRMAXSIG; sig++) { + const char *sname = rawsigname(pri, sig); + if (sname == NULL) + continue; + if (strcmp(sname, name) == 0 || + strcmp(sname+3, name) == 0) + break; + } + if (sig > PRMAXSIG) + sig = 0; + } + if (sig > 0 && sig <= PRMAXSIG) { + if (exclude) { + prdelset(setp, sig); + } else { + praddset(setp, sig); + } + } else if (strcmp(name, "ALL") == 0) { + if (exclude) { + premptyset(setp); + } else { + prfillset(setp); + } + } else { + (void) fprintf(stderr, + "%s: unrecognized signal name/number: %s\n", + command, name); + rc = -1; + } + } + + return (rc); +} + +/* + * List of faults to trace. + * return 0 on success, != 0 on any failure. + */ +int +fltlist(char *str, /* string of fault names */ + fltset_t *setp, /* fault set */ + int *fp) /* first-time flag */ +{ + char *name; + int exclude = FALSE; + int rc = 0; + char *lasts; + + upcase(str); + name = strtok_r(str, sepr, &lasts); + + if (name != NULL && *name == '!') { /* exclude from set */ + exclude = TRUE; + if (*++name == '\0') + name = strtok_r(NULL, sepr, &lasts); + } else if (!*fp) { /* first time, clear the set */ + premptyset(setp); + *fp = TRUE; + } + + for (; name; name = strtok_r(NULL, sepr, &lasts)) { + int flt; + char *next; + + if (*name == '!') { /* exclude remainder from set */ + exclude = TRUE; + while (*++name == '!') + /* empty */; + if (*name == '\0') + continue; + } + + flt = strtol(name, &next, 0); + if (flt <= 0 || flt > PRMAXFAULT || *next != '\0') { + for (flt = 1; flt <= PRMAXFAULT; flt++) { + char fname[32]; + + if (proc_fltname(flt, fname, + sizeof (fname)) == NULL) + continue; + + if (strcmp(fname, name) == 0 || + strcmp(fname+3, name) == 0) + break; + } + if (flt > PRMAXFAULT) + flt = 0; + } + if (flt > 0 && flt <= PRMAXFAULT) { + if (exclude) { + prdelset(setp, flt); + } else { + praddset(setp, flt); + } + } else if (strcmp(name, "ALL") == 0) { + if (exclude) { + premptyset(setp); + } else { + prfillset(setp); + } + } else { + (void) fprintf(stderr, + "%s: unrecognized fault name/number: %s\n", + command, name); + rc = -1; + } + } + + return (rc); +} + +/* + * Gather file descriptors to dump. + * Return 0 on success, != 0 on any failure. + */ +int +fdlist(char *str, /* string of filedescriptors */ + fileset_t *setp) /* set of boolean flags */ +{ + char *name; + int exclude = FALSE; + int rc = 0; + char *lasts; + + upcase(str); + name = strtok_r(str, sepr, &lasts); + + if (name != NULL && *name == '!') { /* exclude from set */ + exclude = TRUE; + if (*++name == '\0') + name = strtok_r(NULL, sepr, &lasts); + } + + for (; name; name = strtok_r(NULL, sepr, &lasts)) { + int fd; + char *next; + + if (*name == '!') { /* exclude remainder from set */ + exclude = TRUE; + while (*++name == '!') + /* empty */; + if (*name == '\0') + continue; + } + + fd = strtol(name, &next, 0); + if (fd >= 0 && fd < NOFILES_MAX && *next == '\0') { + fd++; + if (exclude) { + prdelset(setp, fd); + } else { + praddset(setp, fd); + } + } else if (strcmp(name, "ALL") == 0) { + if (exclude) { + premptyset(setp); + } else { + prfillset(setp); + } + } else { + (void) fprintf(stderr, + "%s: filedescriptor not in range[0..%d]: %s\n", + command, NOFILES_MAX-1, name); + rc = -1; + } + } + + return (rc); +} + +void +upcase(char *str) +{ + int c; + + while ((c = *str) != '\0') + *str++ = toupper(c); +} + +/* + * 'arg' points to a string like: + * libc,libnsl,... : printf,read,write,... + * or + * libc,libnsl,... :: printf,read,write,... + * with possible filename pattern-matching metacharacters. + * + * Assumption: No library or function name can contain ',' or ':'. + */ +int +liblist(char *arg, int hang) +{ + const char *star = "*"; + struct dynpat *Dyp; + char *pat; + char *fpat; + char *lasts; + uint_t maxpat; + + /* append a new dynpat structure to the end of the Dynpat list */ + Dyp = my_malloc(sizeof (struct dynpat), NULL); + Dyp->next = NULL; + if (Lastpat == NULL) + Dynpat = Lastpat = Dyp; + else { + Lastpat->next = Dyp; + Lastpat = Dyp; + } + Dyp->flag = hang? BPT_HANG : 0; + Dyp->exclude_lib = 0; + Dyp->exclude = 0; + Dyp->internal = 0; + Dyp->Dp = NULL; + + /* + * Find the beginning of the filename patterns + * and null-terminate the library name patterns. + */ + if ((fpat = strchr(arg, ':')) != NULL) + *fpat++ = '\0'; + + /* + * Library name patterns. + */ + pat = strtok_r(arg, sepr, &lasts); + + /* '!' introduces an exclusion list */ + if (pat != NULL && *pat == '!') { + Dyp->exclude_lib = 1; + pat += strspn(pat, "!"); + if (*pat == '\0') + pat = strtok_r(NULL, sepr, &lasts); + /* force exclusion of all functions as well */ + Dyp->exclude = 1; + Dyp->internal = 1; + fpat = NULL; + } + + if (pat == NULL) { + /* empty list means all libraries */ + Dyp->libpat = my_malloc(sizeof (char *), NULL); + Dyp->libpat[0] = star; + Dyp->nlibpat = 1; + } else { + /* + * We are now at the library list. + * Generate the list and count the library name patterns. + */ + maxpat = 1; + Dyp->libpat = my_malloc(maxpat * sizeof (char *), NULL); + Dyp->nlibpat = 0; + Dyp->libpat[Dyp->nlibpat++] = pat; + while ((pat = strtok_r(NULL, sepr, &lasts)) != NULL) { + if (Dyp->nlibpat == maxpat) { + maxpat *= 2; + Dyp->libpat = my_realloc(Dyp->libpat, + maxpat * sizeof (char *), NULL); + } + Dyp->libpat[Dyp->nlibpat++] = pat; + } + } + + /* + * Function name patterns. + */ + if (fpat == NULL) + pat = NULL; + else { + /* + * We have already seen a ':'. Look for another. + * Double ':' means trace internal calls. + */ + fpat += strspn(fpat, white); + if (*fpat == ':') { + Dyp->internal = 1; + *fpat++ = '\0'; + } + pat = strtok_r(fpat, csepr, &lasts); + } + + /* '!' introduces an exclusion list */ + if (pat != NULL && *pat == '!') { + Dyp->exclude = 1; + Dyp->internal = 1; + pat += strspn(pat, "!"); + if (*pat == '\0') + pat = strtok_r(NULL, sepr, &lasts); + } + + if (pat == NULL) { + /* empty function list means exclude all functions */ + Dyp->sympat = my_malloc(sizeof (char *), NULL); + Dyp->sympat[0] = star; + Dyp->nsympat = 1; + } else { + /* + * We are now at the function list. + * Generate the list and count the symbol name patterns. + */ + maxpat = 1; + Dyp->sympat = my_malloc(maxpat * sizeof (char *), NULL); + Dyp->nsympat = 0; + Dyp->sympat[Dyp->nsympat++] = pat; + while ((pat = strtok_r(NULL, sepr, &lasts)) != NULL) { + if (Dyp->nsympat == maxpat) { + maxpat *= 2; + Dyp->sympat = my_realloc(Dyp->sympat, + maxpat * sizeof (char *), NULL); + } + Dyp->sympat[Dyp->nsympat++] = pat; + } + } + + return (0); +} diff --git a/usr/src/cmd/truss/main.c b/usr/src/cmd/truss/main.c new file mode 100644 index 0000000..151c749 --- /dev/null +++ b/usr/src/cmd/truss/main.c @@ -0,0 +1,2718 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ + +#include <stdio.h> +#include <stdio_ext.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <ctype.h> +#include <string.h> +#include <memory.h> +#include <signal.h> +#include <wait.h> +#include <limits.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/times.h> +#include <sys/fstyp.h> +#include <sys/fsid.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/resource.h> +#include <libproc.h> +#include <priv.h> +#include "ramdata.h" +#include "proto.h" +#include "htbl.h" + +/* + * The user can trace individual threads by using the 'pid/1,3-6,8-' syntax. + * This structure keeps track of pid/lwp specifications. If there are no LWPs + * specified, then 'lwps' will be NULL. + */ +typedef struct proc_set { + pid_t pid; + const char *lwps; +} proc_set_t; + +/* + * Function prototypes for static routines in this file. + */ +void setup_basetime(hrtime_t, struct timeval *); +int xcreat(char *); +void setoutput(int); +void report(private_t *, time_t); +void prtim(timestruc_t *); +void pids(char *, proc_set_t *); +void psargs(private_t *); +int control(private_t *, pid_t); +int grabit(private_t *, proc_set_t *); +void release(private_t *, pid_t); +void intr(int); +int wait4all(void); +void letgo(private_t *); +void child_to_file(); +void file_to_parent(); +void per_proc_init(); +int lib_sort(const void *, const void *); +int key_sort(const void *, const void *); + +void *worker_thread(void *); +void main_thread(int); + +/* + * Test for empty set. + * is_empty() should not be called directly. + */ +int is_empty(const uint32_t *, size_t); +#define isemptyset(sp) \ + is_empty((uint32_t *)(sp), sizeof (*(sp)) / sizeof (uint32_t)) + +/* + * OR the second set into the first set. + * or_set() should not be called directly. + */ +void or_set(uint32_t *, const uint32_t *, size_t); +#define prorset(sp1, sp2) \ + or_set((uint32_t *)(sp1), (uint32_t *)(sp2), \ + sizeof (*(sp1)) / sizeof (uint32_t)) + +/* fetch or allocate thread-private data */ +private_t * +get_private() +{ + void *value; + private_t *pri = NULL; + + if (thr_getspecific(private_key, &value) == 0) + pri = value; + if (pri == NULL) { + pri = my_malloc(sizeof (*pri), NULL); + (void) memset(pri, 0, sizeof (*pri)); + pri->sys_path = my_malloc(pri->sys_psize = 16, NULL); + pri->sys_string = my_malloc(pri->sys_ssize = 32, NULL); + if (thr_setspecific(private_key, pri) == ENOMEM) + abend("memory allocation failure", NULL); + } + return (pri); +} + +/* destructor function for thread-private data */ +void +free_private(void *value) +{ + private_t *pri = value; + + if (pri->sys_path) + free(pri->sys_path); + if (pri->sys_string) + free(pri->sys_string); + if (pri->exec_string) + free(pri->exec_string); + if (pri->str_buffer) + free(pri->str_buffer); + free(pri); +} + +/* + * This is called by the main thread (via create_thread()) + * and is also called from other threads in worker_thread() + * while holding truss_lock. No further locking is required. + */ +void +insert_lwpid(lwpid_t lwpid) +{ + int i; + + truss_nlwp++; + for (i = 0; i < truss_maxlwp; i++) { + if (truss_lwpid[i] == 0) + break; + } + if (i == truss_maxlwp) { + /* double the size of the array */ + truss_lwpid = my_realloc(truss_lwpid, + truss_maxlwp * 2 * sizeof (lwpid_t), NULL); + (void) memset(&truss_lwpid[truss_maxlwp], 0, + truss_maxlwp * sizeof (lwpid_t)); + truss_maxlwp *= 2; + } + truss_lwpid[i] = lwpid; +} + +/* + * This is called from the first worker thread to encounter one of + * (leave_hung || interrupt || sigusr1). It must notify all other + * worker threads of the same condition. truss_lock is held. + */ +void +broadcast_signals(void) +{ + static int int_notified = FALSE; + static int usr1_notified = FALSE; + static int usr2_notified = FALSE; + lwpid_t my_id = thr_self(); + lwpid_t lwpid; + int i; + + if (interrupt && !int_notified) { + int_notified = TRUE; + for (i = 0; i < truss_maxlwp; i++) { + if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id) + (void) thr_kill(lwpid, interrupt); + } + } + if (sigusr1 && !usr1_notified) { + usr1_notified = TRUE; + for (i = 0; i < truss_maxlwp; i++) { + if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id) + (void) thr_kill(lwpid, SIGUSR1); + } + } + if (leave_hung && !usr2_notified) { + usr2_notified = TRUE; + for (i = 0; i < truss_maxlwp; i++) { + if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id) + (void) thr_kill(lwpid, SIGUSR2); + } + } +} + +static struct ps_lwphandle * +grab_lwp(lwpid_t who) +{ + struct ps_lwphandle *Lwp; + int gcode; + + if ((Lwp = Lgrab(Proc, who, &gcode)) == NULL) { + if (gcode != G_NOPROC) { + (void) fprintf(stderr, + "%s: cannot grab LWP %u in process %d," + " reason: %s\n", + command, who, (int)Pstatus(Proc)->pr_pid, + Lgrab_error(gcode)); + interrupt = SIGTERM; /* post an interrupt */ + } + } + return (Lwp); +} + +/* + * Iteration function called for each initial lwp in the controlled process. + */ +/* ARGSUSED */ +int +create_thread(void *arg, const lwpstatus_t *Lsp) +{ + struct ps_lwphandle *new_Lwp; + lwpid_t lwpid; + int *count = arg; + + if (lwptrace(Pstatus(Proc)->pr_pid, Lsp->pr_lwpid)) + *count += 1; + + if ((new_Lwp = grab_lwp(Lsp->pr_lwpid)) != NULL) { + if (thr_create(NULL, 0, worker_thread, new_Lwp, + THR_BOUND | THR_SUSPENDED, &lwpid) != 0) + abend("cannot create lwp to follow child lwp", NULL); + insert_lwpid(lwpid); + } + return (0); +} + +int +main(int argc, char *argv[]) +{ + private_t *pri; + struct tms tms; + struct rlimit rlim; + int ofd = -1; + int opt; + int i; + int first; + int errflg = FALSE; + int badname = FALSE; + proc_set_t *grab = NULL; + const pstatus_t *Psp; + const lwpstatus_t *Lsp; + int sharedmem; + + /* a few of these need to be initialized to NULL */ + Cp = NULL; + fcall_tbl = NULL; + + /* + * Make sure fd's 0, 1, and 2 are allocated, + * just in case truss was invoked from init. + */ + while ((i = open("/dev/null", O_RDWR)) >= 0 && i < 2) + ; + if (i > 2) + (void) close(i); + + starttime = times(&tms); /* for elapsed timing */ + + /* this should be per-traced-process */ + pagesize = sysconf(_SC_PAGESIZE); + + /* command name (e.g., "truss") */ + if ((command = strrchr(argv[0], '/')) != NULL) + command++; + else + command = argv[0]; + + /* set up the initial private data */ + (void) mutex_init(&truss_lock, USYNC_THREAD, NULL); + (void) mutex_init(&count_lock, USYNC_THREAD, NULL); + (void) cond_init(&truss_cv, USYNC_THREAD, NULL); + if (thr_keycreate(&private_key, free_private) == ENOMEM) + abend("memory allocation failure", NULL); + pri = get_private(); + + Euid = geteuid(); + Egid = getegid(); + Ruid = getuid(); + Rgid = getgid(); + ancestor = getpid(); + + prfillset(&trace); /* default: trace all system calls */ + premptyset(&verbose); /* default: no syscall verbosity */ + premptyset(&rawout); /* default: no raw syscall interpretation */ + + prfillset(&signals); /* default: trace all signals */ + + prfillset(&faults); /* default: trace all faults */ + prdelset(&faults, FLTPAGE); /* except this one */ + + premptyset(&readfd); /* default: dump no buffers */ + premptyset(&writefd); + + premptyset(&syshang); /* default: hang on no system calls */ + premptyset(&sighang); /* default: hang on no signals */ + premptyset(&flthang); /* default: hang on no faults */ + + (void) sigemptyset(&emptyset); /* for unblocking all signals */ + (void) sigfillset(&fillset); /* for blocking all signals */ + +#define OPTIONS "FpfcaeildDEht:T:v:x:s:S:m:M:u:U:r:w:o:" + while ((opt = getopt(argc, argv, OPTIONS)) != EOF) { + switch (opt) { + case 'F': /* force grabbing (no O_EXCL) */ + Fflag = PGRAB_FORCE; + break; + case 'p': /* grab processes */ + pflag = TRUE; + break; + case 'f': /* follow children */ + fflag = TRUE; + break; + case 'c': /* don't trace, just count */ + cflag = TRUE; + iflag = TRUE; /* implies no interruptable syscalls */ + break; + case 'a': /* display argument lists */ + aflag = TRUE; + break; + case 'e': /* display environments */ + eflag = TRUE; + break; + case 'i': /* don't show interruptable syscalls */ + iflag = TRUE; + break; + case 'l': /* show lwp id for each syscall */ + lflag = TRUE; + break; + case 'h': /* debugging: report hash stats */ + hflag = TRUE; + break; + case 'd': /* show time stamps */ + dflag = TRUE; + break; + case 'D': /* show time deltas */ + Dflag = TRUE; + break; + case 'E': + Eflag = TRUE; /* show syscall times */ + break; + case 't': /* system calls to trace */ + if (syslist(optarg, &trace, &tflag)) + badname = TRUE; + break; + case 'T': /* system calls to hang process */ + if (syslist(optarg, &syshang, &Tflag)) + badname = TRUE; + break; + case 'v': /* verbose interpretation of syscalls */ + if (syslist(optarg, &verbose, &vflag)) + badname = TRUE; + break; + case 'x': /* raw interpretation of syscalls */ + if (syslist(optarg, &rawout, &xflag)) + badname = TRUE; + break; + case 's': /* signals to trace */ + if (siglist(pri, optarg, &signals, &sflag)) + badname = TRUE; + break; + case 'S': /* signals to hang process */ + if (siglist(pri, optarg, &sighang, &Sflag)) + badname = TRUE; + break; + case 'm': /* machine faults to trace */ + if (fltlist(optarg, &faults, &mflag)) + badname = TRUE; + break; + case 'M': /* machine faults to hang process */ + if (fltlist(optarg, &flthang, &Mflag)) + badname = TRUE; + break; + case 'u': /* user library functions to trace */ + if (liblist(optarg, 0)) + badname = TRUE; + break; + case 'U': /* user library functions to hang */ + if (liblist(optarg, 1)) + badname = TRUE; + break; + case 'r': /* show contents of read(fd) */ + if (fdlist(optarg, &readfd)) + badname = TRUE; + break; + case 'w': /* show contents of write(fd) */ + if (fdlist(optarg, &writefd)) + badname = TRUE; + break; + case 'o': /* output file for trace */ + oflag = TRUE; + if (ofd >= 0) + (void) close(ofd); + if ((ofd = xcreat(optarg)) < 0) { + perror(optarg); + badname = TRUE; + } + break; + default: + errflg = TRUE; + break; + } + } + + if (badname) + exit(2); + + /* if -a or -e was specified, force tracing of exec() */ + if (aflag || eflag) + praddset(&trace, SYS_execve); + + /* + * Make sure that all system calls, signals, and machine faults + * that hang the process are added to their trace sets. + */ + prorset(&trace, &syshang); + prorset(&signals, &sighang); + prorset(&faults, &flthang); + + argc -= optind; + argv += optind; + + /* collect the specified process ids */ + if (pflag && argc > 0) { + grab = my_malloc(argc * sizeof (proc_set_t), + "memory for process-ids"); + while (argc-- > 0) + pids(*argv++, grab); + } + + if (errflg || (argc <= 0 && ngrab <= 0)) { + (void) fprintf(stderr, + "usage:\t%s [-fcaeildDEF] [-[tTvx] [!]syscalls] [-[sS] [!]signals]\\\n", + command); + (void) fprintf(stderr, + "\t[-[mM] [!]faults] [-[rw] [!]fds] [-[uU] [!]libs:[:][!]funcs]\\\n"); + (void) fprintf(stderr, + "\t[-o outfile] command | -p pid[/lwps] ...\n"); + exit(2); + } + + if (argc > 0) { /* create the controlled process */ + int err; + char path[PATH_MAX]; + + Proc = Pcreate(argv[0], &argv[0], &err, path, sizeof (path)); + if (Proc == NULL) { + switch (err) { + case C_PERM: + (void) fprintf(stderr, + "%s: cannot trace set-id or " + "unreadable object file: %s\n", + command, path); + break; + case C_LP64: + (void) fprintf(stderr, + "%s: cannot control _LP64 " + "program: %s\n", + command, path); + break; + case C_NOEXEC: + (void) fprintf(stderr, + "%s: cannot execute program: %s\n", + command, argv[0]); + break; + case C_NOENT: + (void) fprintf(stderr, + "%s: cannot find program: %s\n", + command, argv[0]); + break; + case C_STRANGE: + break; + default: + (void) fprintf(stderr, "%s: %s\n", + command, Pcreate_error(err)); + break; + } + exit(2); + } + if (fflag || Dynpat != NULL) + (void) Psetflags(Proc, PR_FORK); + else + (void) Punsetflags(Proc, PR_FORK); + Psp = Pstatus(Proc); + Lsp = &Psp->pr_lwp; + pri->lwpstat = Lsp; + data_model = Psp->pr_dmodel; + created = Psp->pr_pid; + make_pname(pri, 0); + (void) sysentry(pri, 1); + pri->length = 0; + if (!cflag && prismember(&trace, SYS_execve)) { + pri->exec_string = my_realloc(pri->exec_string, + strlen(pri->sys_string) + 1, NULL); + (void) strcpy(pri->exec_pname, pri->pname); + (void) strcpy(pri->exec_string, pri->sys_string); + pri->length += strlen(pri->sys_string); + pri->exec_lwpid = pri->lwpstat->pr_lwpid; + pri->sys_leng = 0; + *pri->sys_string = '\0'; + } + pri->syslast = Psp->pr_stime; + pri->usrlast = Psp->pr_utime; + } + + /* + * Now that we have created the victim process, + * give ourself a million file descriptors. + * This is enough to deal with a multithreaded + * victim process that has half a million lwps. + */ + rlim.rlim_cur = 1024 * 1024; + rlim.rlim_max = 1024 * 1024; + if ((Euid != 0 || setrlimit(RLIMIT_NOFILE, &rlim) != 0) && + getrlimit(RLIMIT_NOFILE, &rlim) == 0) { + /* + * Failing the million, give ourself as many + * file descriptors as we can get. + */ + rlim.rlim_cur = rlim.rlim_max; + (void) setrlimit(RLIMIT_NOFILE, &rlim); + } + (void) enable_extended_FILE_stdio(-1, -1); + + setoutput(ofd); /* establish truss output */ + istty = isatty(1); + + if (setvbuf(stdout, (char *)NULL, _IOFBF, MYBUFSIZ) != 0) + abend("setvbuf() failure", NULL); + + /* + * Set up signal dispositions. + */ + if (created && (oflag || !istty)) { /* ignore interrupts */ + (void) sigset(SIGHUP, SIG_IGN); + (void) sigset(SIGINT, SIG_IGN); + (void) sigset(SIGQUIT, SIG_IGN); + } else { /* receive interrupts */ + if (sigset(SIGHUP, SIG_IGN) == SIG_DFL) + (void) sigset(SIGHUP, intr); + if (sigset(SIGINT, SIG_IGN) == SIG_DFL) + (void) sigset(SIGINT, intr); + if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL) + (void) sigset(SIGQUIT, intr); + } + (void) sigset(SIGTERM, intr); + (void) sigset(SIGUSR1, intr); + (void) sigset(SIGUSR2, intr); + (void) sigset(SIGPIPE, intr); + + /* don't accumulate zombie children */ + (void) sigset(SIGCLD, SIG_IGN); + + /* create shared mem space for global mutexes */ + + sharedmem = (fflag || Dynpat != NULL || ngrab > 1); + gps = (void *)mmap(NULL, sizeof (struct global_psinfo), + PROT_READ|PROT_WRITE, + MAP_ANON | (sharedmem? MAP_SHARED : MAP_PRIVATE), + -1, (off_t)0); + if (gps == MAP_FAILED) + abend("cannot allocate ", "memory for counts"); + i = sharedmem? USYNC_PROCESS : USYNC_THREAD; + (void) mutex_init(&gps->ps_mutex0, i, NULL); + (void) mutex_init(&gps->ps_mutex1, i, NULL); + (void) mutex_init(&gps->fork_lock, i, NULL); + (void) cond_init(&gps->fork_cv, i, NULL); + + + /* config tmp file if counting and following */ + if (fflag && cflag) { + char *tmps = tempnam("/var/tmp", "truss"); + sfd = open(tmps, O_CREAT|O_APPEND|O_EXCL|O_RDWR, 0600); + if (sfd == -1) + abend("Error creating tmpfile", NULL); + if (unlink(tmps) == -1) + abend("Error unlinking tmpfile", NULL); + free(tmps); + tmps = NULL; + } + + if (created) { + per_proc_init(); + procadd(created, NULL); + show_cred(pri, TRUE, FALSE); + } else { /* grab the specified processes */ + int gotone = FALSE; + + i = 0; + while (i < ngrab) { /* grab first process */ + if (grabit(pri, &grab[i++])) { + Psp = Pstatus(Proc); + Lsp = &Psp->pr_lwp; + gotone = TRUE; + break; + } + } + if (!gotone) + abend(NULL, NULL); + per_proc_init(); + while (i < ngrab) { /* grab the remainder */ + proc_set_t *set = &grab[i++]; + + (void) mutex_lock(&truss_lock); + switch (fork()) { + case -1: + (void) fprintf(stderr, + "%s: cannot fork to control process, pid# %d\n", + command, (int)set->pid); + /* FALLTHROUGH */ + default: + (void) mutex_unlock(&truss_lock); + continue; /* parent carries on */ + + case 0: /* child grabs process */ + (void) mutex_unlock(&truss_lock); + Pfree(Proc); + descendent = TRUE; + if (grabit(pri, set)) { + Psp = Pstatus(Proc); + Lsp = &Psp->pr_lwp; + per_proc_init(); + break; + } + exit(2); + } + break; + } + free(grab); + } + + + /* + * If running setuid-root, become root for real to avoid + * affecting the per-user limitation on the maximum number + * of processes (one benefit of running setuid-root). + */ + if (Rgid != Egid) + (void) setgid(Egid); + if (Ruid != Euid) + (void) setuid(Euid); + + if (!created && aflag && prismember(&trace, SYS_execve)) { + psargs(pri); + Flush(); + } + + if (created && Pstate(Proc) != PS_STOP) /* assertion */ + if (!(interrupt | sigusr1)) + abend("ASSERT error: process is not stopped", NULL); + + traceeven = trace; /* trace these system calls */ + + /* trace these regardless, even if we don't report results */ + praddset(&traceeven, SYS_exit); + praddset(&traceeven, SYS_lwp_create); + praddset(&traceeven, SYS_lwp_exit); + praddset(&traceeven, SYS_execve); + praddset(&traceeven, SYS_openat); + praddset(&traceeven, SYS_openat64); + praddset(&traceeven, SYS_open); + praddset(&traceeven, SYS_open64); + praddset(&traceeven, SYS_vfork); + praddset(&traceeven, SYS_forksys); + + /* for I/O buffer dumps, force tracing of read()s and write()s */ + if (!isemptyset(&readfd)) { + praddset(&traceeven, SYS_read); + praddset(&traceeven, SYS_readv); + praddset(&traceeven, SYS_pread); + praddset(&traceeven, SYS_pread64); + praddset(&traceeven, SYS_recv); + praddset(&traceeven, SYS_recvfrom); + praddset(&traceeven, SYS_recvmsg); + } + if (!isemptyset(&writefd)) { + praddset(&traceeven, SYS_write); + praddset(&traceeven, SYS_writev); + praddset(&traceeven, SYS_pwrite); + praddset(&traceeven, SYS_pwrite64); + praddset(&traceeven, SYS_send); + praddset(&traceeven, SYS_sendto); + praddset(&traceeven, SYS_sendmsg); + } + + if (cflag || Eflag) { + Psetsysentry(Proc, &traceeven); + } + Psetsysexit(Proc, &traceeven); + + /* special case -- cannot trace sysexit because context is changed */ + if (prismember(&trace, SYS_context)) { + (void) Psysentry(Proc, SYS_context, TRUE); + (void) Psysexit(Proc, SYS_context, FALSE); + prdelset(&traceeven, SYS_context); + } + + /* special case -- trace exec() on entry to get the args */ + (void) Psysentry(Proc, SYS_execve, TRUE); + + /* special case -- sysexit never reached */ + (void) Psysentry(Proc, SYS_exit, TRUE); + (void) Psysentry(Proc, SYS_lwp_exit, TRUE); + (void) Psysexit(Proc, SYS_exit, FALSE); + (void) Psysexit(Proc, SYS_lwp_exit, FALSE); + + Psetsignal(Proc, &signals); /* trace these signals */ + Psetfault(Proc, &faults); /* trace these faults */ + + /* for function call tracing */ + if (Dynpat != NULL) { + /* trace these regardless, to deal with function calls */ + (void) Pfault(Proc, FLTBPT, TRUE); + (void) Pfault(Proc, FLTTRACE, TRUE); + + /* needed for x86 */ + (void) Psetflags(Proc, PR_BPTADJ); + + /* + * Find functions and set breakpoints on grabbed process. + * A process stopped on exec() gets its breakpoints set below. + */ + if ((Lsp->pr_why != PR_SYSENTRY && + Lsp->pr_why != PR_SYSEXIT) || + Lsp->pr_what != SYS_execve) { + establish_breakpoints(); + establish_stacks(); + } + } + + /* + * Use asynchronous-stop for multithreaded truss. + * truss runs one lwp for each lwp in the target process. + */ + (void) Psetflags(Proc, PR_ASYNC); + + /* flush out all tracing flags now. */ + Psync(Proc); + + /* + * If we grabbed a running process, set it running again. + * Since we are tracing lwp_create() and lwp_exit(), the + * lwps will not change in the process until we create all + * of the truss worker threads. + * We leave a created process stopped so its exec() can be reported. + */ + first = created? FALSE : TRUE; + if (!created && + ((Pstate(Proc) == PS_STOP && Lsp->pr_why == PR_REQUESTED) || + (Lsp->pr_flags & PR_DSTOP))) + first = FALSE; + + main_thread(first); + return (0); +} + +/* + * Called from main() and from control() after fork(). + */ +void +main_thread(int first) +{ + private_t *pri = get_private(); + struct tms tms; + int flags; + int retc; + int i; + int count; + + /* + * Block all signals in the main thread. + * Some worker thread will receive signals. + */ + (void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL); + + /* + * If we are dealing with a previously hung process, + * arrange not to leave it hung on the same system call. + */ + primary_lwp = (first && Pstate(Proc) == PS_STOP)? + Pstatus(Proc)->pr_lwp.pr_lwpid : 0; + + /* + * Create worker threads to match the lwps in the target process. + */ + truss_nlwp = 0; + truss_maxlwp = 1; + truss_lwpid = my_realloc(truss_lwpid, sizeof (lwpid_t), NULL); + truss_lwpid[0] = 0; + count = 0; + (void) Plwp_iter(Proc, create_thread, &count); + + if (count == 0) { + (void) printf("(Warning: no matching active LWPs found, " + "waiting)\n"); + Flush(); + } + + /* + * Set all of the truss worker threads running now. + */ + (void) mutex_lock(&truss_lock); + for (i = 0; i < truss_maxlwp; i++) { + if (truss_lwpid[i]) + (void) thr_continue(truss_lwpid[i]); + } + (void) mutex_unlock(&truss_lock); + + /* + * Wait until all worker threads terminate. + */ + while (thr_join(0, NULL, NULL) == 0) + continue; + + (void) Punsetflags(Proc, PR_ASYNC); + Psync(Proc); + if (sigusr1) + letgo(pri); + flags = PRELEASE_CLEAR; + if (leave_hung) + flags |= PRELEASE_HANG; + Prelease(Proc, flags); + + procdel(); + retc = (leave_hung? 0 : wait4all()); + + if (!descendent) { + interrupt = 0; /* another interrupt kills the report */ + if (cflag) { + if (fflag) + file_to_parent(); + report(pri, times(&tms) - starttime); + } + } else if (cflag && fflag) { + child_to_file(); + } + + exit(retc); /* exit with exit status of created process, else 0 */ +} + +void * +worker_thread(void *arg) +{ + struct ps_lwphandle *Lwp = (struct ps_lwphandle *)arg; + const pstatus_t *Psp = Pstatus(Proc); + const lwpstatus_t *Lsp = Lstatus(Lwp); + struct syscount *scp; + lwpid_t who = Lsp->pr_lwpid; + int first = (who == primary_lwp); + private_t *pri = get_private(); + int req_flag = 0; + int leave_it_hung = FALSE; + int reset_traps = FALSE; + int gcode; + int what; + int ow_in_effect = 0; + long ow_syscall = 0; + long ow_subcode = 0; + char *ow_string = NULL; + sysset_t full_set; + sysset_t running_set; + int dotrace = lwptrace(Psp->pr_pid, Lsp->pr_lwpid); + + pri->Lwp = Lwp; + pri->lwpstat = Lsp; + pri->syslast = Lsp->pr_stime; + pri->usrlast = Lsp->pr_utime; + make_pname(pri, 0); + + prfillset(&full_set); + + /* we were created with all signals blocked; unblock them */ + (void) thr_sigsetmask(SIG_SETMASK, &emptyset, NULL); + + /* + * Run this loop until the victim lwp terminates or we receive + * a termination condition (leave_hung | interrupt | sigusr1). + */ + for (;;) { + if (interrupt | sigusr1) { + (void) Lstop(Lwp, MILLISEC); + if (Lstate(Lwp) == PS_RUN) + break; + } + if (Lstate(Lwp) == PS_RUN) { + /* millisecond timeout is for sleeping syscalls */ + uint_t tout = (iflag || req_flag)? 0 : MILLISEC; + + /* + * If we are to leave this lwp stopped in sympathy + * with another lwp that has been left hung, or if + * we have been interrupted or instructed to release + * our victim process, and this lwp is stopped but + * not on an event of interest to /proc, then just + * leave it in that state. + */ + if ((leave_hung | interrupt | sigusr1) && + (Lsp->pr_flags & (PR_STOPPED|PR_ISTOP)) + == PR_STOPPED) + break; + + (void) Lwait(Lwp, tout); + if (Lstate(Lwp) == PS_RUN && + tout != 0 && !(interrupt | sigusr1)) { + (void) mutex_lock(&truss_lock); + if ((Lsp->pr_flags & PR_STOPPED) && + Lsp->pr_why == PR_JOBCONTROL) + req_flag = jobcontrol(pri, dotrace); + else + req_flag = requested(pri, req_flag, + dotrace); + (void) mutex_unlock(&truss_lock); + } + continue; + } + data_model = Psp->pr_dmodel; + if (Lstate(Lwp) == PS_UNDEAD) + break; + if (Lstate(Lwp) == PS_LOST) { /* we lost control */ + /* + * After exec(), only one LWP remains in the process. + * /proc makes the thread following that LWP receive + * EAGAIN (PS_LOST) if the program being exec()ed + * is a set-id program. Every other controlling + * thread receives ENOENT (because its LWP vanished). + * We are the controlling thread for the exec()ing LWP. + * We must wait until all of our siblings terminate + * before attempting to reopen the process. + */ + (void) mutex_lock(&truss_lock); + while (truss_nlwp > 1) + (void) cond_wait(&truss_cv, &truss_lock); + if (Preopen(Proc) == 0) { /* we got control back */ + /* + * We have to free and re-grab the LWP. + * The process is guaranteed to be at exit + * from exec() or execve() and have only + * one LWP, namely this one, and the LWP + * is guaranteed to have lwpid == 1. + * This "cannot fail". + */ + who = 1; + Lfree(Lwp); + pri->Lwp = Lwp = + Lgrab(Proc, who, &gcode); + if (Lwp == NULL) + abend("Lgrab error: ", + Lgrab_error(gcode)); + pri->lwpstat = Lsp = Lstatus(Lwp); + (void) mutex_unlock(&truss_lock); + continue; + } + + /* we really lost it */ + if (pri->exec_string && *pri->exec_string) { + if (pri->exec_pname[0] != '\0') + (void) fputs(pri->exec_pname, stdout); + timestamp(pri); + (void) fputs(pri->exec_string, stdout); + (void) fputc('\n', stdout); + } else if (pri->length) { + (void) fputc('\n', stdout); + } + if (pri->sys_valid) + (void) printf( + "%s\t*** cannot trace across exec() of %s ***\n", + pri->pname, pri->sys_path); + else + (void) printf( + "%s\t*** lost control of process ***\n", + pri->pname); + pri->length = 0; + Flush(); + (void) mutex_unlock(&truss_lock); + break; + } + if (Lstate(Lwp) != PS_STOP) { + (void) fprintf(stderr, + "%s: state = %d\n", command, Lstate(Lwp)); + abend(pri->pname, "uncaught status of subject lwp"); + } + + make_pname(pri, 0); + + (void) mutex_lock(&truss_lock); + + what = Lsp->pr_what; + req_flag = 0; + + switch (Lsp->pr_why) { + case PR_REQUESTED: + break; + case PR_SIGNALLED: + req_flag = signalled(pri, req_flag, dotrace); + if (Sflag && !first && prismember(&sighang, what)) + leave_it_hung = TRUE; + break; + case PR_FAULTED: + if (what == FLTBPT) { + int rval; + + (void) Pstop(Proc, 0); + rval = function_trace(pri, first, 0, dotrace); + if (rval == 1) + leave_it_hung = TRUE; + if (rval >= 0) + break; + } + if (faulted(pri, dotrace) && + Mflag && !first && prismember(&flthang, what)) + leave_it_hung = TRUE; + break; + case PR_JOBCONTROL: /* can't happen except first time */ + req_flag = jobcontrol(pri, dotrace); + break; + case PR_SYSENTRY: + /* protect ourself from operating system error */ + if (what <= 0 || what > PRMAXSYS) + what = PRMAXSYS; + pri->length = 0; + /* + * ow_in_effect checks to see whether or not we + * are attempting to quantify the time spent in + * a one way system call. This is necessary as + * some system calls never return, yet it is desireable + * to determine how much time the traced process + * spends in these calls. To do this, a one way + * flag is set on SYSENTRY when the call is recieved. + * After this, the call mask for the SYSENTRY events + * is filled so that the traced process will stop + * on the entry to the very next system call. + * This appears to the the best way to determine + * system time elapsed between a one way system call. + * Once the next call occurs, values that have been + * stashed are used to record the correct syscall + * and time, and the SYSENTRY event mask is restored + * so that the traced process may continue. + */ + if (dotrace && ow_in_effect) { + if (cflag) { + (void) mutex_lock(&count_lock); + scp = Cp->syscount[ow_syscall]; + if (ow_subcode != -1) + scp += ow_subcode; + scp->count++; + accumulate(&scp->stime, + &Lsp->pr_stime, &pri->syslast); + accumulate(&Cp->usrtotal, + &Lsp->pr_utime, &pri->usrlast); + pri->syslast = Lsp->pr_stime; + pri->usrlast = Lsp->pr_utime; + (void) mutex_unlock(&count_lock); + } else if (Eflag) { + putpname(pri); + timestamp(pri); + (void) printf("%s\n", ow_string); + free(ow_string); + ow_string = NULL; + pri->syslast = Lsp->pr_stime; + } + ow_in_effect = 0; + Psetsysentry(Proc, &running_set); + } + + /* + * Special cases. Most syscalls are traced on exit. + */ + switch (what) { + case SYS_exit: /* exit() */ + case SYS_lwp_exit: /* lwp_exit() */ + case SYS_context: /* [get|set]context() */ + if (dotrace && cflag && + prismember(&trace, what)) { + ow_in_effect = 1; + ow_syscall = what; + ow_subcode = getsubcode(pri); + pri->syslast = Lsp->pr_stime; + running_set = + (Pstatus(Proc))->pr_sysentry; + Psetsysentry(Proc, &full_set); + } else if (dotrace && Eflag && + prismember(&trace, what)) { + (void) sysentry(pri, dotrace); + ow_in_effect = 1; + ow_string = my_malloc( + strlen(pri->sys_string) + 1, NULL); + (void) strcpy(ow_string, + pri->sys_string); + running_set = + (Pstatus(Proc))->pr_sysentry; + Psetsysentry(Proc, &full_set); + pri->syslast = Lsp->pr_stime; + } else if (dotrace && + prismember(&trace, what)) { + (void) sysentry(pri, dotrace); + putpname(pri); + timestamp(pri); + pri->length += + printf("%s\n", pri->sys_string); + Flush(); + } + pri->sys_leng = 0; + *pri->sys_string = '\0'; + + if (what == SYS_exit) + exit_called = TRUE; + break; + case SYS_execve: + show_cred(pri, FALSE, TRUE); + (void) sysentry(pri, dotrace); + if (dotrace && !cflag && + prismember(&trace, what)) { + pri->exec_string = + my_realloc(pri->exec_string, + strlen(pri->sys_string) + 1, + NULL); + (void) strcpy(pri->exec_pname, + pri->pname); + (void) strcpy(pri->exec_string, + pri->sys_string); + pri->length += strlen(pri->sys_string); + pri->exec_lwpid = Lsp->pr_lwpid; + } + pri->sys_leng = 0; + *pri->sys_string = '\0'; + break; + default: + if (dotrace && (cflag || Eflag) && + prismember(&trace, what)) { + pri->syslast = Lsp->pr_stime; + } + break; + } + if (dotrace && Tflag && !first && + (prismember(&syshang, what) || + (exit_called && prismember(&syshang, SYS_exit)))) + leave_it_hung = TRUE; + break; + case PR_SYSEXIT: + /* check for write open of a /proc file */ + if (what == SYS_openat || what == SYS_openat64 || + what == SYS_open || what == SYS_open64) { + int readonly; + + (void) sysentry(pri, dotrace); + pri->Errno = Lsp->pr_errno; + pri->ErrPriv = Lsp->pr_errpriv; + readonly = + ((what == SYS_openat || + what == SYS_openat64) && + pri->sys_nargs > 2 && + (pri->sys_args[2]&0x3) == O_RDONLY) || + ((what == SYS_open || + what == SYS_open64) && + pri->sys_nargs > 1 && + (pri->sys_args[1]&0x3) == O_RDONLY); + if ((pri->Errno == 0 || pri->Errno == EBUSY) && + pri->sys_valid && !readonly) { + int rv = checkproc(pri); + if (rv == 1 && Fflag != PGRAB_FORCE) { + /* + * The process opened itself + * and no -F flag was specified. + * Just print the open() call + * and let go of the process. + */ + if (dotrace && !cflag && + prismember(&trace, what)) { + putpname(pri); + timestamp(pri); + (void) printf("%s\n", + pri->sys_string); + Flush(); + } + sigusr1 = TRUE; + (void) mutex_unlock( + &truss_lock); + goto out; + } + if (rv == 2) { + /* + * Process opened someone else. + * The open is being reissued. + * Don't report this one. + */ + pri->sys_leng = 0; + *pri->sys_string = '\0'; + pri->sys_nargs = 0; + break; + } + } + } + if (what == SYS_execve && pri->Errno == 0) { + /* + * Refresh the data model on exec() in case it + * is different from the parent. Lwait() + * doesn't update process-wide status, so we + * have to explicitly call Pstopstatus() to get + * the new state. + */ + (void) Pstopstatus(Proc, PCNULL, 0); + data_model = Psp->pr_dmodel; + } + if (sysexit(pri, dotrace)) + Flush(); + if (what == SYS_lwp_create && pri->Rval1 != 0) { + struct ps_lwphandle *new_Lwp; + lwpid_t lwpid; + + if ((new_Lwp = grab_lwp(pri->Rval1)) != NULL) { + (void) thr_sigsetmask(SIG_SETMASK, + &fillset, NULL); + if (thr_create(NULL, 0, worker_thread, + new_Lwp, THR_BOUND | THR_SUSPENDED, + &lwpid) != 0) + abend("cannot create lwp ", + "to follow child lwp"); + insert_lwpid(lwpid); + (void) thr_continue(lwpid); + (void) thr_sigsetmask(SIG_SETMASK, + &emptyset, NULL); + } + } + pri->sys_nargs = 0; + if (dotrace && Tflag && !first && + prismember(&syshang, what)) + leave_it_hung = TRUE; + if (what == SYS_execve && pri->Errno == 0) { + is_vfork_child = FALSE; + reset_breakpoints(); + /* + * exec() resets the calling LWP's lwpid to 1. + * If the LWP has changed its lwpid, then + * we have to free and re-grab the LWP + * in order to keep libproc consistent. + * This "cannot fail". + */ + if (who != Lsp->pr_lwpid) { + /* + * We must wait for all of our + * siblings to terminate. + */ + while (truss_nlwp > 1) + (void) cond_wait(&truss_cv, + &truss_lock); + who = Lsp->pr_lwpid; + Lfree(Lwp); + pri->Lwp = Lwp = + Lgrab(Proc, who, &gcode); + if (Lwp == NULL) + abend("Lgrab error: ", + Lgrab_error(gcode)); + pri->lwpstat = Lsp = Lstatus(Lwp); + } + } + break; + default: + req_flag = 0; + (void) fprintf(stderr, + "unknown reason for stopping: %d/%d\n", + Lsp->pr_why, what); + abend(NULL, NULL); + } + + if (pri->child) { /* controlled process fork()ed */ + if (fflag || Dynpat != NULL) { + if (Lsp->pr_why == PR_SYSEXIT && + (Lsp->pr_what == SYS_vfork || + (Lsp->pr_what == SYS_forksys && + Lsp->pr_sysarg[0] == 2))) { + is_vfork_child = TRUE; + (void) Pstop(Proc, 0); + } + if (control(pri, pri->child)) { + (void) mutex_unlock(&truss_lock); + pri->child = 0; + if (!fflag) { + /* + * If this is vfork(), then + * this clears the breakpoints + * in the parent's address space + * as well as in the child's. + */ + clear_breakpoints(); + Prelease(Proc, PRELEASE_CLEAR); + _exit(0); + } + main_thread(FALSE); + /* NOTREACHED */ + } + + /* + * Here, we are still the parent truss. + * If the child messes with the breakpoints and + * this is vfork(), we have to set them again. + */ + if (Dynpat != NULL && is_vfork_child && !fflag) + reset_traps = TRUE; + is_vfork_child = FALSE; + } + pri->child = 0; + } + + if (leave_it_hung) { + (void) mutex_unlock(&truss_lock); + break; + } + + if (reset_traps) { + /* + * To recover from vfork, we must catch the lwp + * that issued the vfork() when it returns to user + * level, with all other lwps remaining stopped. + * For this purpose, we have directed all lwps to + * stop and we now set the vfork()ing lwp running + * with the PRSTEP flag. We expect to capture it + * when it stops again showing PR_FAULTED/FLTTRACE. + * We are holding truss_lock, so no other threads + * in truss will set any other lwps in the victim + * process running. + */ + reset_traps = FALSE; + (void) Lsetrun(Lwp, 0, PRSTEP); + do { + (void) Lwait(Lwp, 0); + } while (Lstate(Lwp) == PS_RUN); + if (Lstate(Lwp) == PS_STOP && + Lsp->pr_why == PR_FAULTED && + Lsp->pr_what == FLTTRACE) { + reestablish_traps(); + (void) Lsetrun(Lwp, 0, PRCFAULT|PRSTOP); + } else { + (void) printf("%s\t*** Expected PR_FAULTED/" + "FLTTRACE stop following vfork()\n", + pri->pname); + } + } + + if (Lstate(Lwp) == PS_STOP) { + int flags = 0; + + if (interrupt | sigusr1) { + (void) mutex_unlock(&truss_lock); + break; + } + /* + * If we must leave this lwp hung is sympathy with + * another lwp that is being left hung on purpose, + * then push the state onward toward PR_REQUESTED. + */ + if (leave_hung) { + if (Lsp->pr_why == PR_REQUESTED) { + (void) mutex_unlock(&truss_lock); + break; + } + flags |= PRSTOP; + } + if (Lsetrun(Lwp, 0, flags) != 0 && + Lstate(Lwp) != PS_LOST && + Lstate(Lwp) != PS_UNDEAD) { + (void) mutex_unlock(&truss_lock); + perror("Lsetrun"); + abend("cannot start subject lwp", NULL); + /* NOTREACHED */ + } + } + first = FALSE; + + (void) mutex_unlock(&truss_lock); + } + +out: + /* block all signals in preparation for exiting */ + (void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL); + + if (Lstate(Lwp) == PS_UNDEAD || Lstate(Lwp) == PS_LOST) + (void) mutex_lock(&truss_lock); + else { + (void) Lstop(Lwp, MILLISEC); + (void) mutex_lock(&truss_lock); + if (Lstate(Lwp) == PS_STOP && + Lsp->pr_why == PR_FAULTED && + Lsp->pr_what == FLTBPT) + (void) function_trace(pri, 0, 1, dotrace); + } + + if (dotrace && ow_in_effect) { + if (cflag) { + (void) mutex_lock(&count_lock); + scp = Cp->syscount[ow_syscall]; + if (ow_subcode != -1) + scp += ow_subcode; + scp->count++; + accumulate(&scp->stime, + &Lsp->pr_stime, &pri->syslast); + accumulate(&Cp->usrtotal, + &Lsp->pr_utime, &pri->usrlast); + pri->syslast = Lsp->pr_stime; + pri->usrlast = Lsp->pr_utime; + (void) mutex_unlock(&count_lock); + } else if (Eflag) { + putpname(pri); + timestamp(pri); + (void) printf("%s\n", ow_string); + free(ow_string); + ow_string = NULL; + pri->syslast = Lsp->pr_stime; + } + ow_in_effect = 0; + Psetsysentry(Proc, &running_set); + } + + if (Lstate(Lwp) == PS_UNDEAD || Lstate(Lwp) == PS_LOST) { + /* + * The victim thread has exited or we lost control of + * the process. Remove ourself from the list of all + * truss threads and notify everyone waiting for this. + */ + lwpid_t my_id = thr_self(); + int i; + + for (i = 0; i < truss_maxlwp; i++) { + if (truss_lwpid[i] == my_id) { + truss_lwpid[i] = 0; + break; + } + } + if (--truss_nlwp != 0) { + (void) cond_broadcast(&truss_cv); + } else { + /* + * The last truss worker thread is terminating. + * The address space is gone (UNDEAD) or is + * inaccessible (LOST) so we cannot clear the + * breakpoints. Just report the htable stats. + */ + report_htable_stats(); + } + } else { + /* + * The victim thread is not a zombie thread, and we have not + * lost control of the process. We must have gotten here due + * to (leave_hung || leave_it_hung || interrupt || sigusr1). + * In these cases, we must carefully uninstrument the process + * and either set it running or leave it stopped and abandoned. + */ + static int nstopped = 0; + static int cleared = 0; + + if (leave_it_hung) + leave_hung = TRUE; + if ((leave_hung | interrupt | sigusr1) == 0) + abend("(leave_hung | interrupt | sigusr1) == 0", NULL); + + /* + * The first truss thread through here needs to instruct all + * application threads to stop -- they're not necessarily + * going to stop on their own. + */ + if (nstopped++ == 0) + (void) Pdstop(Proc); + + /* + * Notify all other worker threads about the reason + * for being here (leave_hung || interrupt || sigusr1). + */ + broadcast_signals(); + + /* + * Once the last thread has reached this point, then and + * only then is it safe to remove breakpoints and other + * instrumentation. Since breakpoints are executed without + * truss_lock held, a monitor thread can't exit until all + * breakpoints have been removed, and we can't be sure the + * procedure to execute a breakpoint won't temporarily + * reinstall a breakpont. Accordingly, we need to wait + * until all threads are in a known state. + */ + while (nstopped != truss_nlwp) + (void) cond_wait(&truss_cv, &truss_lock); + + /* + * All truss threads have reached this point. + * One of them clears the breakpoints and + * wakes up everybody else to finish up. + */ + if (cleared++ == 0) { + /* + * All threads should already be stopped, + * but just to be safe... + */ + (void) Pstop(Proc, MILLISEC); + clear_breakpoints(); + (void) Psysexit(Proc, SYS_vfork, FALSE); + (void) Psysexit(Proc, SYS_forksys, FALSE); + (void) Punsetflags(Proc, PR_FORK); + Psync(Proc); + fflag = 0; + (void) cond_broadcast(&truss_cv); + } + + if (!leave_hung && Lstate(Lwp) == PS_STOP) + (void) Lsetrun(Lwp, 0, 0); + } + + (void) Lfree(Lwp); + (void) mutex_unlock(&truss_lock); + return (NULL); +} + +/* + * Give a base date for time stamps, adjusted to the + * stop time of the selected (first or created) process. + */ +void +setup_basetime(hrtime_t basehrtime, struct timeval *basedate) +{ + const pstatus_t *Psp = Pstatus(Proc); + (void) mutex_lock(&count_lock); + Cp->basetime = Psp->pr_lwp.pr_tstamp; + (void) mutex_unlock(&count_lock); + + if ((dflag|Dflag) && !cflag) { + const struct tm *ptm; + const char *ptime; + const char *pdst; + hrtime_t delta = basehrtime - + ((hrtime_t)Cp->basetime.tv_sec * NANOSEC + + Cp->basetime.tv_nsec); + + if (delta > 0) { + basedate->tv_sec -= (time_t)(delta / NANOSEC); + basedate->tv_usec -= (delta % NANOSEC) / 1000; + if (basedate->tv_usec < 0) { + basedate->tv_sec--; + basedate->tv_usec += MICROSEC; + } + } + ptm = localtime(&basedate->tv_sec); + ptime = asctime(ptm); + if ((pdst = tzname[ptm->tm_isdst ? 1 : 0]) == NULL) + pdst = "???"; + if (dflag) { + (void) printf( + "Base time stamp: %ld.%4.4ld [ %.20s%s %.4s ]\n", + basedate->tv_sec, basedate->tv_usec / 100, + ptime, pdst, ptime + 20); + Flush(); + } + } +} + +/* + * Performs per-process initializations. If truss is following a victim + * process it will fork additional truss processes to follow new processes + * created. Here is where each new truss process gets its per-process data + * initialized. + */ + +void +per_proc_init() +{ + void *pmem; + struct timeval basedate; + hrtime_t basehrtime; + struct syscount *scp; + int i; + timestruc_t c_basetime; + + /* Make sure we only configure the basetime for the first truss proc */ + + if (Cp == NULL) { + pmem = my_malloc(sizeof (struct counts) + maxsyscalls() * + sizeof (struct syscount), NULL); + Cp = (struct counts *)pmem; + basehrtime = gethrtime(); + (void) gettimeofday(&basedate, NULL); + setup_basetime(basehrtime, &basedate); + } + + c_basetime = Cp->basetime; + + (void) memset(Cp, 0, sizeof (struct counts) + maxsyscalls() * + sizeof (struct syscount)); + + Cp->basetime = c_basetime; + + if (fcall_tbl != NULL) + destroy_hash(fcall_tbl); + fcall_tbl = init_hash(4096); + + (void) mutex_lock(&count_lock); + scp = (struct syscount *)(Cp + 1); + for (i = 0; i <= PRMAXSYS; i++) { + Cp->syscount[i] = scp; + scp += nsubcodes(i); + } + (void) mutex_unlock(&count_lock); +} + + +/* + * Writes child state to a tempfile where it can be read and + * accumulated by the parent process. The file descriptor is shared + * among the processes. Ordering of writes does not matter, it is, however, + * necessary to ensure that all writes are atomic. + */ + +void +child_to_file() +{ + hiter_t *itr; + hentry_t *ntry; + hdntry_t fentry; + char *s = NULL; + char *t = NULL; + unsigned char *buf = NULL; + size_t bufsz = 0; + size_t i = 0; + size_t j = 0; + + /* ensure that we are in fact a child process */ + if (!descendent) + return; + + /* enumerate fcall_tbl (tbl locked until freed) */ + if (Dynpat != NULL) { + itr = iterate_hash(fcall_tbl); + + ntry = iter_next(itr); + while (ntry != NULL) { + fentry.type = HD_hashntry; + fentry.count = ntry->count; + s = ntry->key; + t = ntry->lib; + i = strlen(s) + 1; + j = strlen(t) + 1; + fentry.sz_key = i; + fentry.sz_lib = j; + if (i + sizeof (fentry) > bufsz) { + buf = my_realloc(buf, i + j + sizeof (fentry), + NULL); + bufsz = i + j + sizeof (fentry); + } + (void) memcpy(buf, &fentry, sizeof (fentry)); + (void) strlcpy((char *)(buf + sizeof (fentry)), t, j); + (void) strlcpy((char *)(buf + sizeof (fentry) + j), + s, i); + if (write(sfd, buf, sizeof (fentry) + i + j) == -1) + abend("Error writing to tmp file", NULL); + ntry = iter_next(itr); + } + iter_free(itr); + } + + /* Now write the count/syscount structs down */ + bufsz = sizeof (fentry) + (sizeof (struct counts) + maxsyscalls() * + sizeof (struct syscount)); + buf = my_realloc(buf, bufsz, NULL); + fentry.type = HD_cts_syscts; + fentry.count = 0; /* undefined, really */ + fentry.sz_key = bufsz - sizeof (fentry); + fentry.sz_lib = 0; /* also undefined */ + (void) memcpy(buf, &fentry, sizeof (fentry)); + (void) memcpy((char *)(buf + sizeof (fentry)), Cp, + bufsz - sizeof (fentry)); + if (write(sfd, buf, bufsz) == -1) + abend("Error writing cts/syscts to tmpfile", NULL); + + free(buf); +} + +/* + * The following reads entries from the tempfile back to the parent + * so that information can be collected and summed for overall statistics. + * This reads records out of the tempfile. If they are hash table entries, + * the record is merged with the hash table kept by the parent process. + * If the information is a struct count/struct syscount pair, they are + * copied and added into the count/syscount array kept by the parent. + */ + +void +file_to_parent() +{ + hdntry_t ntry; + char *s = NULL; + char *t = NULL; + size_t c_offset = 0; + size_t filesz; + size_t t_strsz = 0; + size_t s_strsz = 0; + struct stat fsi; + + if (descendent) + return; + + if (fstat(sfd, &fsi) == -1) + abend("Error stat-ing tempfile", NULL); + filesz = fsi.st_size; + + while (c_offset < filesz) { + /* first get hdntry */ + if (pread(sfd, &ntry, sizeof (hdntry_t), c_offset) != + sizeof (hdntry_t)) + abend("Unable to perform full read of hdntry", NULL); + c_offset += sizeof (hdntry_t); + + switch (ntry.type) { + case HD_hashntry: + + /* first get lib string */ + if (ntry.sz_lib > t_strsz) { + t = my_realloc(t, ntry.sz_lib, NULL); + t_strsz = ntry.sz_lib; + } + + (void) memset(t, 0, t_strsz); + + /* now actually get the string */ + if (pread(sfd, t, ntry.sz_lib, c_offset) != ntry.sz_lib) + abend("Unable to perform full read of lib str", + NULL); + c_offset += ntry.sz_lib; + + /* now get key string */ + + if (ntry.sz_key > s_strsz) { + s = my_realloc(s, ntry.sz_key, NULL); + s_strsz = ntry.sz_key; + } + (void) memset(s, 0, s_strsz); + if (pread(sfd, s, ntry.sz_key, c_offset) != ntry.sz_key) + abend("Unable to perform full read of key str", + NULL); + c_offset += ntry.sz_key; + + add_fcall(fcall_tbl, t, s, ntry.count); + break; + + case HD_cts_syscts: + { + struct counts *ncp; + size_t bfsz = sizeof (struct counts) + maxsyscalls() + * sizeof (struct syscount); + int i; + struct syscount *sscp; + + if (ntry.sz_key != bfsz) + abend("cts/syscts size does not sanity check", + NULL); + ncp = my_malloc(ntry.sz_key, NULL); + + if (pread(sfd, ncp, ntry.sz_key, c_offset) != + ntry.sz_key) + abend("Unable to perform full read of cts", + NULL); + c_offset += ntry.sz_key; + + sscp = (struct syscount *)(ncp + 1); + + (void) mutex_lock(&count_lock); + + Cp->usrtotal.tv_sec += ncp->usrtotal.tv_sec; + Cp->usrtotal.tv_nsec += ncp->usrtotal.tv_nsec; + if (Cp->usrtotal.tv_nsec >= NANOSEC) { + Cp->usrtotal.tv_nsec -= NANOSEC; + Cp->usrtotal.tv_sec++; + } + for (i = 0; i <= PRMAXSYS; i++) { + ncp->syscount[i] = sscp; + sscp += nsubcodes(i); + } + + for (i = 0; i <= PRMAXFAULT; i++) { + Cp->fltcount[i] += ncp->fltcount[i]; + } + + for (i = 0; i <= PRMAXSIG; i++) { + Cp->sigcount[i] += ncp->sigcount[i]; + } + + for (i = 0; i <= PRMAXSYS; i++) { + struct syscount *scp = Cp->syscount[i]; + struct syscount *nscp = ncp->syscount[i]; + int n = nsubcodes(i); + int subcode; + + for (subcode = 0; subcode < n; subcode++, + scp++, nscp++) { + scp->count += nscp->count; + scp->error += nscp->error; + scp->stime.tv_sec += nscp->stime.tv_sec; + scp->stime.tv_nsec += + nscp->stime.tv_nsec; + if (scp->stime.tv_nsec >= NANOSEC) { + scp->stime.tv_nsec -= NANOSEC; + scp->stime.tv_sec++; + } + } + } + (void) mutex_unlock(&count_lock); + free(ncp); + break; + } + default: + + abend("Unknown file entry type encountered", NULL); + break; + + } + + if (fstat(sfd, &fsi) == -1) + abend("Error stat-ing tempfile", NULL); + filesz = fsi.st_size; + } + if (s != NULL) + free(s); + if (t != NULL) + free(t); +} + +void +make_pname(private_t *pri, id_t tid) +{ + if (!cflag) { + int ff = (fflag || ngrab > 1); + int lf = (lflag | tid | (Thr_agent != NULL) | (truss_nlwp > 1)); + pid_t pid = Pstatus(Proc)->pr_pid; + id_t lwpid = pri->lwpstat->pr_lwpid; + + if (ff != pri->pparam.ff || + lf != pri->pparam.lf || + pid != pri->pparam.pid || + lwpid != pri->pparam.lwpid || + tid != pri->pparam.tid) { + char *s = pri->pname; + + if (ff) + s += sprintf(s, "%d", (int)pid); + if (lf) + s += sprintf(s, "/%d", (int)lwpid); + if (tid) + s += sprintf(s, "@%d", (int)tid); + if (ff || lf) + *s++ = ':', *s++ = '\t'; + if (ff && lf && s < pri->pname + 9) + *s++ = '\t'; + *s = '\0'; + pri->pparam.ff = ff; + pri->pparam.lf = lf; + pri->pparam.pid = pid; + pri->pparam.lwpid = lwpid; + pri->pparam.tid = tid; + } + } +} + +/* + * Print the pri->pname[] string, if any. + */ +void +putpname(private_t *pri) +{ + if (pri->pname[0]) + (void) fputs(pri->pname, stdout); +} + +/* + * Print the timestamp, if requested (-d, -D, or -E). + */ +void +timestamp(private_t *pri) +{ + const lwpstatus_t *Lsp = pri->lwpstat; + int seconds; + int fraction; + + if (!(dflag|Dflag|Eflag) || !(Lsp->pr_flags & PR_STOPPED)) + return; + + seconds = Lsp->pr_tstamp.tv_sec - Cp->basetime.tv_sec; + fraction = Lsp->pr_tstamp.tv_nsec - Cp->basetime.tv_nsec; + if (fraction < 0) { + seconds--; + fraction += NANOSEC; + } + /* fraction in 1/10 milliseconds, rounded up */ + fraction = (fraction + 50000) / 100000; + if (fraction >= (MILLISEC * 10)) { + seconds++; + fraction -= (MILLISEC * 10); + } + + if (dflag) /* time stamp */ + (void) printf("%2d.%4.4d\t", seconds, fraction); + + if (Dflag) { /* time delta */ + int oseconds = pri->seconds; + int ofraction = pri->fraction; + + pri->seconds = seconds; + pri->fraction = fraction; + seconds -= oseconds; + fraction -= ofraction; + if (fraction < 0) { + seconds--; + fraction += (MILLISEC * 10); + } + (void) printf("%2d.%4.4d\t", seconds, fraction); + } + + if (Eflag) { + seconds = Lsp->pr_stime.tv_sec - pri->syslast.tv_sec; + fraction = Lsp->pr_stime.tv_nsec - pri->syslast.tv_nsec; + + if (fraction < 0) { + seconds--; + fraction += NANOSEC; + } + /* fraction in 1/10 milliseconds, rounded up */ + fraction = (fraction + 50000) / 100000; + if (fraction >= (MILLISEC * 10)) { + seconds++; + fraction -= (MILLISEC * 10); + } + (void) printf("%2d.%4.4d\t", seconds, fraction); + } +} + +/* + * Create output file, being careful about + * suid/sgid and file descriptor 0, 1, 2 issues. + */ +int +xcreat(char *path) +{ + int fd; + int mode = 0666; + + if (Euid == Ruid && Egid == Rgid) /* not set-id */ + fd = creat(path, mode); + else if (access(path, F_OK) != 0) { /* file doesn't exist */ + /* if directory permissions OK, create file & set ownership */ + + char *dir; + char *p; + char dot[4]; + + /* generate path for directory containing file */ + if ((p = strrchr(path, '/')) == NULL) { /* no '/' */ + p = dir = dot; + *p++ = '.'; /* current directory */ + *p = '\0'; + } else if (p == path) { /* leading '/' */ + p = dir = dot; + *p++ = '/'; /* root directory */ + *p = '\0'; + } else { /* embedded '/' */ + dir = path; /* directory path */ + *p = '\0'; + } + + if (access(dir, W_OK|X_OK) != 0) { + /* not writeable/searchable */ + *p = '/'; + fd = -1; + } else { /* create file and set ownership correctly */ + *p = '/'; + if ((fd = creat(path, mode)) >= 0) + (void) chown(path, (int)Ruid, (int)Rgid); + } + } else if (access(path, W_OK) != 0) /* file not writeable */ + fd = -1; + else + fd = creat(path, mode); + + /* + * Make sure it's not one of 0, 1, or 2. + * This allows truss to work when spawned by init(1m). + */ + if (0 <= fd && fd <= 2) { + int dfd = fcntl(fd, F_DUPFD, 3); + (void) close(fd); + fd = dfd; + } + + /* + * Mark it close-on-exec so created processes don't inherit it. + */ + if (fd >= 0) + (void) fcntl(fd, F_SETFD, FD_CLOEXEC); + + return (fd); +} + +void +setoutput(int ofd) +{ + if (ofd < 0) { + (void) close(1); + (void) fcntl(2, F_DUPFD, 1); + } else if (ofd != 1) { + (void) close(1); + (void) fcntl(ofd, F_DUPFD, 1); + (void) close(ofd); + /* if no stderr, make it the same file */ + if ((ofd = dup(2)) < 0) + (void) fcntl(1, F_DUPFD, 2); + else + (void) close(ofd); + } +} + +/* + * Accumulate time differencies: a += e - s; + */ +void +accumulate(timestruc_t *ap, const timestruc_t *ep, const timestruc_t *sp) +{ + ap->tv_sec += ep->tv_sec - sp->tv_sec; + ap->tv_nsec += ep->tv_nsec - sp->tv_nsec; + if (ap->tv_nsec >= NANOSEC) { + ap->tv_nsec -= NANOSEC; + ap->tv_sec++; + } else if (ap->tv_nsec < 0) { + ap->tv_nsec += NANOSEC; + ap->tv_sec--; + } +} + +int +lib_sort(const void *p1, const void *p2) +{ + int cmpr = 0; + long i; + long j; + + hentry_t *t1 = (hentry_t *)p1; + hentry_t *t2 = (hentry_t *)p2; + + char *p = t1->lib; + char *q = t2->lib; + + if ((cmpr = strcmp(p, q)) == 0) { + i = t1->count; + j = t2->count; + if (i > j) + return (-1); + else if (i < j) + return (1); + else { + p = t1->key; + q = t2->key; + return (strcmp(p, q)); + } + } else + return (cmpr); +} + +void +report(private_t *pri, time_t lapse) /* elapsed time, clock ticks */ +{ + int i; + long count; + const char *name; + long error; + long total; + long errtot; + timestruc_t tickzero; + timestruc_t ticks; + timestruc_t ticktot; + + if (descendent) + return; + + for (i = 0, total = 0; i <= PRMAXFAULT && !interrupt; i++) { + if ((count = Cp->fltcount[i]) != 0) { + if (total == 0) /* produce header */ + (void) printf("faults -------------\n"); + + name = proc_fltname(i, pri->flt_name, + sizeof (pri->flt_name)); + + (void) printf("%s%s\t%4ld\n", name, + (((int)strlen(name) < 8)? + (const char *)"\t" : (const char *)""), + count); + total += count; + } + } + if (total && !interrupt) + (void) printf("total:\t\t%4ld\n\n", total); + + for (i = 0, total = 0; i <= PRMAXSIG && !interrupt; i++) { + if ((count = Cp->sigcount[i]) != 0) { + if (total == 0) /* produce header */ + (void) printf("signals ------------\n"); + name = signame(pri, i); + (void) printf("%s%s\t%4ld\n", name, + (((int)strlen(name) < 8)? + (const char *)"\t" : (const char *)""), + count); + total += count; + } + } + if (total && !interrupt) + (void) printf("total:\t\t%4ld\n\n", total); + + if ((Dynpat != NULL) && !interrupt) { + size_t elem = elements_in_table(fcall_tbl); + hiter_t *itr = iterate_hash(fcall_tbl); + hentry_t *tmp = iter_next(itr); + hentry_t *stbl = my_malloc(elem * sizeof (hentry_t), NULL); + i = 0; + while ((tmp != NULL) && (i < elem)) { + stbl[i].prev = tmp->prev; + stbl[i].next = tmp->next; + stbl[i].lib = tmp->lib; + stbl[i].key = tmp->key; + stbl[i].count = tmp->count; + tmp = iter_next(itr); + i++; + } + qsort((void *)stbl, elem, sizeof (hentry_t), + lib_sort); + (void) printf( + "\n%-20s %-40s %s\n", "Library:", "Function", "calls"); + for (i = 0; i < elem; i++) { + (void) printf("%-20s %-40s %ld\n", stbl[i].lib, + stbl[i].key, stbl[i].count); + } + iter_free(itr); + free(stbl); + itr = NULL; + } + + if (!interrupt) + (void) printf( + "\nsyscall seconds calls errors\n"); + + total = errtot = 0; + tickzero.tv_sec = ticks.tv_sec = ticktot.tv_sec = 0; + tickzero.tv_nsec = ticks.tv_nsec = ticktot.tv_nsec = 0; + for (i = 0; i <= PRMAXSYS && !interrupt; i++) { + struct syscount *scp = Cp->syscount[i]; + int n = nsubcodes(i); + int subcode; + + for (subcode = 0; subcode < n; subcode++, scp++) { + if ((count = scp->count) != 0 || scp->error) { + (void) printf("%-19.19s ", + sysname(pri, i, subcode)); + + ticks = scp->stime; + accumulate(&ticktot, &ticks, &tickzero); + prtim(&ticks); + + (void) printf(" %7ld", count); + if ((error = scp->error) != 0) + (void) printf(" %7ld", error); + (void) fputc('\n', stdout); + total += count; + errtot += error; + } + } + } + + if (!interrupt) { + (void) printf( + " -------- ------ ----\n"); + (void) printf("sys totals: "); + prtim(&ticktot); + (void) printf(" %7ld %6ld\n", total, errtot); + } + + if (!interrupt) { + (void) printf("usr time: "); + prtim(&Cp->usrtotal); + (void) fputc('\n', stdout); + } + + if (!interrupt) { + int hz = (int)sysconf(_SC_CLK_TCK); + + ticks.tv_sec = lapse / hz; + ticks.tv_nsec = (lapse % hz) * (1000000000 / hz); + (void) printf("elapsed: "); + prtim(&ticks); + (void) fputc('\n', stdout); + } +} + +void +prtim(timestruc_t *tp) +{ + time_t sec; + + if ((sec = tp->tv_sec) != 0) /* whole seconds */ + (void) printf("%5lu", sec); + else + (void) printf(" "); + + (void) printf(".%3.3ld", tp->tv_nsec/1000000); /* fraction */ +} + +/* + * Gather process id's. + * Return 0 on success, != 0 on failure. + */ +void +pids(char *arg, proc_set_t *grab) +{ + pid_t pid = -1; + int i; + const char *lwps = NULL; + + if ((pid = proc_arg_xpsinfo(arg, PR_ARG_PIDS, NULL, &i, &lwps)) < 0) { + (void) fprintf(stderr, "%s: cannot trace '%s': %s\n", + command, arg, Pgrab_error(i)); + return; + } + + for (i = 0; i < ngrab; i++) + if (grab[i].pid == pid) /* duplicate */ + break; + + if (i == ngrab) { + grab[ngrab].pid = pid; + grab[ngrab].lwps = lwps; + ngrab++; + } else { + (void) fprintf(stderr, "%s: duplicate process-id ignored: %d\n", + command, (int)pid); + } +} + +/* + * Report psargs string. + */ +void +psargs(private_t *pri) +{ + pid_t pid = Pstatus(Proc)->pr_pid; + psinfo_t psinfo; + + if (proc_get_psinfo(pid, &psinfo) == 0) + (void) printf("%spsargs: %.64s\n", + pri->pname, psinfo.pr_psargs); + else { + perror("psargs()"); + (void) printf("%s\t*** Cannot read psinfo file for pid %d\n", + pri->pname, (int)pid); + } +} + +char * +fetchstring(private_t *pri, long addr, int maxleng) +{ + int nbyte; + int leng = 0; + char string[41]; + + string[40] = '\0'; + if (pri->str_bsize == 0) /* initial allocation of string buffer */ + pri->str_buffer = + my_malloc(pri->str_bsize = 16, "string buffer"); + *pri->str_buffer = '\0'; + + for (nbyte = 40; nbyte == 40 && leng < maxleng; addr += 40) { + if ((nbyte = Pread(Proc, string, 40, addr)) <= 0) + return (leng? pri->str_buffer : NULL); + if (nbyte > 0 && + (nbyte = strlen(string)) > 0) { + while (leng + nbyte >= pri->str_bsize) + pri->str_buffer = + my_realloc(pri->str_buffer, + pri->str_bsize *= 2, "string buffer"); + (void) strcpy(pri->str_buffer+leng, string); + leng += nbyte; + } + } + + if (leng > maxleng) + leng = maxleng; + pri->str_buffer[leng] = '\0'; + + return (pri->str_buffer); +} + +static priv_set_t * +getset(prpriv_t *p, priv_ptype_t set) +{ + return ((priv_set_t *) + &p->pr_sets[priv_getsetbyname(set) * p->pr_setsize]); +} + +void +show_cred(private_t *pri, int new, int loadonly) +{ + prcred_t cred; + prpriv_t *privs; + + if (proc_get_cred(Pstatus(Proc)->pr_pid, &cred, 0) < 0) { + perror("show_cred() - credential"); + (void) printf("%s\t*** Cannot get credentials\n", pri->pname); + return; + } + if ((privs = proc_get_priv(Pstatus(Proc)->pr_pid)) == NULL) { + perror("show_cred() - privileges"); + (void) printf("%s\t*** Cannot get privileges\n", pri->pname); + return; + } + + if (!loadonly && !cflag && prismember(&trace, SYS_execve)) { + if (new) + credentials = cred; + if ((new && cred.pr_ruid != cred.pr_suid) || + cred.pr_ruid != credentials.pr_ruid || + cred.pr_suid != credentials.pr_suid) + (void) printf( + "%s *** SUID: ruid/euid/suid = %d / %d / %d ***\n", + pri->pname, + (int)cred.pr_ruid, + (int)cred.pr_euid, + (int)cred.pr_suid); + if ((new && cred.pr_rgid != cred.pr_sgid) || + cred.pr_rgid != credentials.pr_rgid || + cred.pr_sgid != credentials.pr_sgid) + (void) printf( + "%s *** SGID: rgid/egid/sgid = %d / %d / %d ***\n", + pri->pname, + (int)cred.pr_rgid, + (int)cred.pr_egid, + (int)cred.pr_sgid); + if (privdata != NULL && cred.pr_euid != 0) { + priv_set_t *npset = getset(privs, PRIV_PERMITTED); + priv_set_t *opset = getset(privdata, PRIV_PERMITTED); + char *s, *t; + if (!priv_issubset(npset, opset)) { + /* Use the to be freed privdata as scratch */ + priv_inverse(opset); + priv_intersect(npset, opset); + s = priv_set_to_str(opset, ',', PRIV_STR_SHORT); + t = priv_set_to_str(npset, ',', PRIV_STR_SHORT); + (void) printf("%s *** FPRIV: P/E: %s ***\n", + pri->pname, + strlen(s) > strlen(t) ? t : s); + free(s); + free(t); + } + } + } + + if (privdata != NULL) + free(privdata); + credentials = cred; + privdata = privs; +} + +/* + * Take control of a child process. + * We come here with truss_lock held. + */ +int +control(private_t *pri, pid_t pid) +{ + const pstatus_t *Psp; + const lwpstatus_t *Lsp; + pid_t childpid = 0; + long flags; + int rc; + + (void) mutex_lock(&gps->fork_lock); + while (gps->fork_pid != 0) + (void) cond_wait(&gps->fork_cv, &gps->fork_lock); + gps->fork_pid = getpid(); /* parent pid */ + if ((childpid = fork()) == -1) { + (void) printf("%s\t*** Cannot fork() to control process #%d\n", + pri->pname, (int)pid); + Flush(); + gps->fork_pid = 0; + (void) cond_broadcast(&gps->fork_cv); + (void) mutex_unlock(&gps->fork_lock); + release(pri, pid); + return (FALSE); + } + + if (childpid != 0) { + /* + * The parent carries on, after a brief pause. + * The parent must wait until the child executes procadd(pid). + */ + while (gps->fork_pid != childpid) + (void) cond_wait(&gps->fork_cv, &gps->fork_lock); + gps->fork_pid = 0; + (void) cond_broadcast(&gps->fork_cv); + (void) mutex_unlock(&gps->fork_lock); + return (FALSE); + } + + childpid = getpid(); + descendent = TRUE; + exit_called = FALSE; + Pfree(Proc); /* forget old process */ + + /* + * The parent process owns the shared gps->fork_lock. + * The child must grab it again. + */ + (void) mutex_lock(&gps->fork_lock); + + /* + * Child grabs the process and retains the tracing flags. + */ + if ((Proc = Pgrab(pid, PGRAB_RETAIN, &rc)) == NULL) { + (void) fprintf(stderr, + "%s: cannot control child process, pid# %d: %s\n", + command, (int)pid, Pgrab_error(rc)); + gps->fork_pid = childpid; + (void) cond_broadcast(&gps->fork_cv); + (void) mutex_unlock(&gps->fork_lock); + exit(2); + } + + per_proc_init(); + /* + * Add ourself to the set of truss processes + * and notify the parent to carry on. + */ + procadd(pid, NULL); + gps->fork_pid = childpid; + (void) cond_broadcast(&gps->fork_cv); + (void) mutex_unlock(&gps->fork_lock); + + /* + * We may have grabbed the child before it is fully stopped on exit + * from fork. Wait one second (at most) for it to settle down. + */ + (void) Pwait(Proc, MILLISEC); + if (Rdb_agent != NULL) + Rdb_agent = Prd_agent(Proc); + + Psp = Pstatus(Proc); + Lsp = &Psp->pr_lwp; + pri->lwpstat = Lsp; + data_model = Psp->pr_dmodel; + + make_pname(pri, 0); + + pri->syslast = Psp->pr_stime; + pri->usrlast = Psp->pr_utime; + + flags = PR_FORK | PR_ASYNC; + if (Dynpat != NULL) + flags |= PR_BPTADJ; /* needed for x86 */ + (void) Psetflags(Proc, flags); + + return (TRUE); +} + +/* + * Take control of an existing process. + */ +int +grabit(private_t *pri, proc_set_t *set) +{ + const pstatus_t *Psp; + const lwpstatus_t *Lsp; + int gcode; + + /* + * Don't force the takeover unless the -F option was specified. + */ + if ((Proc = Pgrab(set->pid, Fflag, &gcode)) == NULL) { + (void) fprintf(stderr, "%s: %s: %d\n", + command, Pgrab_error(gcode), (int)set->pid); + pri->lwpstat = NULL; + return (FALSE); + } + Psp = Pstatus(Proc); + Lsp = &Psp->pr_lwp; + pri->lwpstat = Lsp; + + make_pname(pri, 0); + + data_model = Psp->pr_dmodel; + pri->syslast = Psp->pr_stime; + pri->usrlast = Psp->pr_utime; + + if (fflag || Dynpat != NULL) + (void) Psetflags(Proc, PR_FORK); + else + (void) Punsetflags(Proc, PR_FORK); + procadd(set->pid, set->lwps); + show_cred(pri, TRUE, FALSE); + return (TRUE); +} + +/* + * Release process from control. + */ +void +release(private_t *pri, pid_t pid) +{ + /* + * The process in question is the child of a traced process. + * We are here to turn off the inherited tracing flags. + */ + int fd; + char ctlname[100]; + long ctl[2]; + + ctl[0] = PCSET; + ctl[1] = PR_RLC; + + /* process is freshly forked, no need for exclusive open */ + (void) sprintf(ctlname, "/proc/%d/ctl", (int)pid); + if ((fd = open(ctlname, O_WRONLY)) < 0 || + write(fd, (char *)ctl, sizeof (ctl)) < 0) { + perror("release()"); + (void) printf( + "%s\t*** Cannot release child process, pid# %d\n", + pri->pname, (int)pid); + Flush(); + } + if (fd >= 0) /* run-on-last-close sets the process running */ + (void) close(fd); +} + +void +intr(int sig) +{ + /* + * SIGUSR1 is special. It is used by one truss process to tell + * another truss process to release its controlled process. + * SIGUSR2 is also special. It is used to wake up threads waiting + * for a victim lwp to stop after an event that will leave the + * process hung (stopped and abandoned) has occurred. + */ + if (sig == SIGUSR1) { + sigusr1 = TRUE; + } else if (sig == SIGUSR2) { + void *value; + private_t *pri; + struct ps_lwphandle *Lwp; + + if (thr_getspecific(private_key, &value) == 0 && + (pri = value) != NULL && + (Lwp = pri->Lwp) != NULL) + (void) Lstop(Lwp, MILLISEC / 10); + } else { + interrupt = sig; + } +} + +void +errmsg(const char *s, const char *q) +{ + char msg[512]; + + if (s || q) { + msg[0] = '\0'; + if (command) { + (void) strcpy(msg, command); + (void) strcat(msg, ": "); + } + if (s) + (void) strcat(msg, s); + if (q) + (void) strcat(msg, q); + (void) strcat(msg, "\n"); + (void) write(2, msg, (size_t)strlen(msg)); + } +} + +void +abend(const char *s, const char *q) +{ + (void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL); + if (Proc) { + Flush(); + errmsg(s, q); + clear_breakpoints(); + (void) Punsetflags(Proc, PR_ASYNC); + Prelease(Proc, created? PRELEASE_KILL : PRELEASE_CLEAR); + procdel(); + (void) wait4all(); + } else { + errmsg(s, q); + } + exit(2); +} + +/* + * Allocate memory. + * If allocation fails then print a message and abort. + */ +void * +my_realloc(void *buf, size_t size, const char *msg) +{ + if ((buf = realloc(buf, size)) == NULL) { + if (msg != NULL) + abend("cannot allocate ", msg); + else + abend("memory allocation failure", NULL); + } + + return (buf); +} + +void * +my_calloc(size_t nelem, size_t elsize, const char *msg) +{ + void *buf = NULL; + + if ((buf = calloc(nelem, elsize)) == NULL) { + if (msg != NULL) + abend("cannot allocate ", msg); + else + abend("memory allocation failure", NULL); + } + + return (buf); +} + +void * +my_malloc(size_t size, const char *msg) +{ + return (my_realloc(NULL, size, msg)); +} + +int +wait4all() +{ + int i; + pid_t pid; + int rc = 0; + int status; + + for (i = 0; i < 10; i++) { + while ((pid = wait(&status)) != -1) { + /* return exit() code of the created process */ + if (pid == created) { + if (WIFEXITED(status)) + rc = WEXITSTATUS(status); + else + rc |= 0x80; /* +128 to indicate sig */ + } + } + if (errno != EINTR && errno != ERESTART) + break; + } + + if (i >= 10) /* repeated interrupts */ + rc = 2; + + return (rc); +} + +void +letgo(private_t *pri) +{ + (void) printf("%s\t*** process otherwise traced, releasing ...\n", + pri->pname); +} + +/* + * Test for empty set. + * support routine used by isemptyset() macro. + */ +int +is_empty(const uint32_t *sp, /* pointer to set (array of int32's) */ + size_t n) /* number of int32's in set */ +{ + if (n) { + do { + if (*sp++) + return (FALSE); + } while (--n); + } + + return (TRUE); +} + +/* + * OR the second set into the first. + * The sets must be the same size. + */ +void +or_set(uint32_t *sp1, const uint32_t *sp2, size_t n) +{ + if (n) { + do { + *sp1++ |= *sp2++; + } while (--n); + } +} diff --git a/usr/src/cmd/truss/print.c b/usr/src/cmd/truss/print.c new file mode 100644 index 0000000..f49197a --- /dev/null +++ b/usr/src/cmd/truss/print.c @@ -0,0 +1,2850 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. */ + +#define _SYSCALL32 /* make 32-bit compat headers visible */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <termio.h> +#include <stddef.h> +#include <limits.h> +#include <fcntl.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/resource.h> +#include <sys/ulimit.h> +#include <sys/utsname.h> +#include <sys/kstat.h> +#include <sys/modctl.h> +#include <sys/acl.h> +#include <stropts.h> +#include <sys/isa_defs.h> +#include <sys/systeminfo.h> +#include <sys/cladm.h> +#include <sys/lwp.h> +#include <bsm/audit.h> +#include <libproc.h> +#include <priv.h> +#include <sys/aio.h> +#include <sys/aiocb.h> +#include <sys/corectl.h> +#include <sys/cpc_impl.h> +#include <sys/priocntl.h> +#include <sys/tspriocntl.h> +#include <sys/iapriocntl.h> +#include <sys/rtpriocntl.h> +#include <sys/fsspriocntl.h> +#include <sys/fxpriocntl.h> +#include <netdb.h> +#include <nss_dbdefs.h> +#include <sys/socketvar.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <netinet/udp.h> +#include <netinet/sctp.h> +#include <net/route.h> +#include <sys/utrap.h> +#include <sys/lgrp_user.h> +#include <sys/door.h> +#include <sys/tsol/tndb.h> +#include <sys/rctl.h> +#include <sys/rctl_impl.h> +#include <sys/fork.h> +#include <sys/task.h> +#include "ramdata.h" +#include "print.h" +#include "proto.h" +#include "systable.h" + +void grow(private_t *, int nbyte); + +#define GROW(nb) if (pri->sys_leng + (nb) >= pri->sys_ssize) grow(pri, (nb)) + + +/*ARGSUSED*/ +void +prt_nov(private_t *pri, int raw, long val) /* print nothing */ +{ +} + +/*ARGSUSED*/ +void +prt_dec(private_t *pri, int raw, long val) /* print as decimal */ +{ + GROW(24); + if (data_model == PR_MODEL_ILP32) + pri->sys_leng += sprintf(pri->sys_string + pri->sys_leng, + "%d", (int)val); + else + pri->sys_leng += sprintf(pri->sys_string + pri->sys_leng, + "%ld", val); +} + +/*ARGSUSED*/ +void +prt_uns(private_t *pri, int raw, long val) /* print as unsigned decimal */ +{ + GROW(24); + if (data_model == PR_MODEL_ILP32) + pri->sys_leng += sprintf(pri->sys_string + pri->sys_leng, + "%u", (int)val); + else + pri->sys_leng += sprintf(pri->sys_string + pri->sys_leng, + "%lu", val); +} + +/* print as unsigned decimal, except for -1 */ +void +prt_un1(private_t *pri, int raw, long val) +{ + if ((int)val == -1) + prt_dec(pri, raw, val); + else + prt_uns(pri, raw, val); +} + +/*ARGSUSED*/ +void +prt_oct(private_t *pri, int raw, long val) /* print as octal */ +{ + GROW(24); + if (data_model == PR_MODEL_ILP32) + pri->sys_leng += sprintf(pri->sys_string + pri->sys_leng, + "%#o", (int)val); + else + pri->sys_leng += sprintf(pri->sys_string + pri->sys_leng, + "%#lo", val); +} + +/*ARGSUSED*/ +void +prt_hex(private_t *pri, int raw, long val) /* print as hexadecimal */ +{ + GROW(20); + if (data_model == PR_MODEL_ILP32) + pri->sys_leng += sprintf(pri->sys_string + pri->sys_leng, + "0x%.8X", (int)val); + else + pri->sys_leng += sprintf(pri->sys_string + pri->sys_leng, + "0x%.8lX", val); +} + +/* print as hexadecimal (half size) */ +/*ARGSUSED*/ +void +prt_hhx(private_t *pri, int raw, long val) +{ + GROW(20); + if (data_model == PR_MODEL_ILP32) + pri->sys_leng += sprintf(pri->sys_string + pri->sys_leng, + "0x%.4X", (int)val); + else + pri->sys_leng += sprintf(pri->sys_string + pri->sys_leng, + "0x%.4lX", val); +} + +/* print as decimal if small, else hexadecimal */ +/*ARGSUSED*/ +void +prt_dex(private_t *pri, int raw, long val) +{ + if (val & 0xff000000) + prt_hex(pri, 0, val); + else + prt_dec(pri, 0, val); +} + +/* print long long offset */ +/*ARGSUSED*/ +void +prt_llo(private_t *pri, int raw, long val1, long val2) +{ + int hival; + int loval; + +#ifdef _LONG_LONG_LTOH + hival = (int)val2; + loval = (int)val1; +#else + hival = (int)val1; + loval = (int)val2; +#endif + + if (hival == 0) { + prt_dex(pri, 0, loval); + } else { + GROW(18); + pri->sys_leng += + sprintf(pri->sys_string + pri->sys_leng, "0x%.8X%.8X", + hival, loval); + } +} + +void +escape_string(private_t *pri, const char *s) +{ + /* + * We want to avoid outputting unprintable characters that may + * destroy the user's terminal. So we do one pass to find any + * unprintable characters, size the array appropriately, and + * then walk each character by hand. Those that are unprintable + * are replaced by a hex escape (\xNN). We also escape quotes for + * completeness. + */ + int i, unprintable, quotes; + size_t len = strlen(s); + for (i = 0, unprintable = 0, quotes = 0; i < len; i++) { + if (!isprint(s[i])) + unprintable++; + if (s[i] == '"') + quotes++; + } + + GROW(len + 3 * unprintable + quotes + 2); + + pri->sys_string[pri->sys_leng++] = '"'; + for (i = 0; i < len; i++) { + if (s[i] == '"') + pri->sys_string[pri->sys_leng++] = '\\'; + + if (isprint(s[i])) { + pri->sys_string[pri->sys_leng++] = s[i]; + } else { + pri->sys_leng += sprintf(pri->sys_string + + pri->sys_leng, "\\x%02x", (uint8_t)s[i]); + } + } + pri->sys_string[pri->sys_leng++] = '"'; +} + +void +prt_stg(private_t *pri, int raw, long val) /* print as string */ +{ + char *s = raw? NULL : fetchstring(pri, (long)val, PATH_MAX); + + if (s == NULL) + prt_hex(pri, 0, val); + else + escape_string(pri, s); +} + +/* print as string returned from syscall */ +void +prt_rst(private_t *pri, int raw, long val) +{ + char *s = (raw || pri->Errno)? NULL : + fetchstring(pri, (long)val, PATH_MAX); + + if (s == NULL) + prt_hex(pri, 0, val); + else { + GROW((int)strlen(s) + 2); + pri->sys_leng += snprintf(pri->sys_string + pri->sys_leng, + pri->sys_ssize - pri->sys_leng, "\"%s\"", s); + } +} + +/* print contents of readlink() buffer */ +void +prt_rlk(private_t *pri, int raw, long val) +{ + char *s = (raw || pri->Errno || pri->Rval1 <= 0)? NULL : + fetchstring(pri, (long)val, + (pri->Rval1 > PATH_MAX)? PATH_MAX : (int)pri->Rval1); + + if (s == NULL) + prt_hex(pri, 0, val); + else { + GROW((int)strlen(s) + 2); + pri->sys_leng += snprintf(pri->sys_string + pri->sys_leng, + pri->sys_ssize - pri->sys_leng, "\"%s\"", s); + } +} + +void +prt_ioc(private_t *pri, int raw, long val) /* print ioctl code */ +{ + const char *s = raw? NULL : ioctlname(pri, (int)val); + + if (s == NULL) + prt_hex(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_ioa(private_t *pri, int raw, long val) /* print ioctl argument */ +{ + const char *s; + + /* cheating -- look at the ioctl() code */ + switch (pri->sys_args[1]) { + + /* kstat ioctl()s */ + case KSTAT_IOC_READ: + case KSTAT_IOC_WRITE: +#ifdef _LP64 + if (data_model == PR_MODEL_ILP32) + prt_stg(pri, raw, + val + offsetof(kstat32_t, ks_name[0])); + else +#endif + prt_stg(pri, raw, + val + offsetof(kstat_t, ks_name[0])); + break; + + /* streams ioctl()s */ + case I_LOOK: + prt_rst(pri, raw, val); + break; + case I_PUSH: + case I_FIND: + prt_stg(pri, raw, val); + break; + case I_LINK: + case I_UNLINK: + case I_SENDFD: + prt_dec(pri, 0, val); + break; + case I_SRDOPT: + if (raw || (s = strrdopt(val)) == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); + break; + case I_SETSIG: + if (raw || (s = strevents(pri, val)) == NULL) + prt_hex(pri, 0, val); + else + outstring(pri, s); + break; + case I_FLUSH: + if (raw || (s = strflush(val)) == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); + break; + + /* tty ioctl()s */ + case TCSBRK: + case TCXONC: + case TCFLSH: + case TCDSET: + prt_dec(pri, 0, val); + break; + + default: + prt_hex(pri, 0, val); + break; + } +} + +void +prt_pip(private_t *pri, int raw, long val) /* print pipe code */ +{ + const char *s = NULL; + + if (!raw) { + switch (val) { + case O_CLOEXEC: + s = "O_CLOEXEC"; + break; + case O_NONBLOCK: + s = "O_NONBLOCK"; + break; + case O_CLOEXEC|O_NONBLOCK: + s = "O_CLOEXEC|O_NONBLOCK"; + break; + } + } + + if (s == NULL) + prt_dex(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_pfd(private_t *pri, int raw, long val) /* print pipe code */ +{ + int fds[2]; + char str[32]; + + /* the fds only have meaning if the return value is 0 */ + if (!raw && + pri->Rval1 >= 0 && + Pread(Proc, fds, sizeof (fds), (long)val) == sizeof (fds)) { + (void) snprintf(str, sizeof (str), "[%d,%d]", fds[0], fds[1]); + outstring(pri, str); + } else { + prt_hex(pri, 0, val); + } +} + +void +prt_fcn(private_t *pri, int raw, long val) /* print fcntl code */ +{ + const char *s = raw? NULL : fcntlname(val); + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_s86(private_t *pri, int raw, long val) /* print sysi86 code */ +{ + + const char *s = raw? NULL : si86name(val); + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_uts(private_t *pri, int raw, long val) /* print utssys code */ +{ + const char *s = raw? NULL : utscode(val); + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_msc(private_t *pri, int raw, long val) /* print msgsys command */ +{ + const char *s = raw? NULL : msgcmd(val); + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_msf(private_t *pri, int raw, long val) /* print msgsys flags */ +{ + const char *s = raw? NULL : msgflags(pri, (int)val); + + if (s == NULL) + prt_oct(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_smc(private_t *pri, int raw, long val) /* print semsys command */ +{ + const char *s = raw? NULL : semcmd(val); + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_sef(private_t *pri, int raw, long val) /* print semsys flags */ +{ + const char *s = raw? NULL : semflags(pri, (int)val); + + if (s == NULL) + prt_oct(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_shc(private_t *pri, int raw, long val) /* print shmsys command */ +{ + const char *s = raw? NULL : shmcmd(val); + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_shf(private_t *pri, int raw, long val) /* print shmsys flags */ +{ + const char *s = raw? NULL : shmflags(pri, (int)val); + + if (s == NULL) + prt_oct(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_sfs(private_t *pri, int raw, long val) /* print sysfs code */ +{ + const char *s = raw? NULL : sfsname(val); + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_opn(private_t *pri, int raw, long val) /* print open code */ +{ + const char *s = raw? NULL : openarg(pri, val); + + if (s == NULL) + prt_oct(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_sig(private_t *pri, int raw, long val) /* print signal name */ +{ + const char *s = raw? NULL : signame(pri, (int)val); + + if (s == NULL) + prt_hex(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_smf(private_t *pri, int raw, long val) /* print streams message flags */ +{ + switch (val) { + case 0: + prt_dec(pri, 0, val); + break; + case RS_HIPRI: + if (raw) + prt_hhx(pri, 0, val); + else + outstring(pri, "RS_HIPRI"); + break; + default: + prt_hhx(pri, 0, val); + break; + } +} + +void +prt_mtf(private_t *pri, int raw, long val) /* print mount flags */ +{ + const char *s = raw? NULL : mountflags(pri, val); + + if (s == NULL) + prt_hex(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_mft(private_t *pri, int raw, long val) /* print mount file system type */ +{ + if (val >= 0 && val < 256) + prt_dec(pri, 0, val); + else if (raw) + prt_hex(pri, 0, val); + else + prt_stg(pri, raw, val); +} + +#define ISREAD(code) \ + ((code) == SYS_read || (code) == SYS_pread || (code) == SYS_pread64 || \ + (code) == SYS_recv || (code) == SYS_recvfrom) +#define ISWRITE(code) \ + ((code) == SYS_write || (code) == SYS_pwrite || \ + (code) == SYS_pwrite64 || (code) == SYS_send || (code) == SYS_sendto) + +/* print contents of read() or write() I/O buffer */ +void +prt_iob(private_t *pri, int raw, long val) +{ + const lwpstatus_t *Lsp = pri->lwpstat; + int syscall = Lsp->pr_what; + int fdp1 = pri->sys_args[0] + 1; + ssize_t nbyte = ISWRITE(syscall)? pri->sys_args[2] : + (pri->Errno? 0 : pri->Rval1); + int elsewhere = FALSE; /* TRUE iff dumped elsewhere */ + char buffer[IOBSIZE]; + + pri->iob_buf[0] = '\0'; + + if (Lsp->pr_why == PR_SYSEXIT && nbyte > IOBSIZE) { + if (ISREAD(syscall)) + elsewhere = prismember(&readfd, fdp1); + else + elsewhere = prismember(&writefd, fdp1); + } + + if (nbyte <= 0 || elsewhere) + prt_hex(pri, 0, val); + else { + int nb = nbyte > IOBSIZE? IOBSIZE : (int)nbyte; + + if (Pread(Proc, buffer, (size_t)nb, (long)val) != nb) + prt_hex(pri, 0, val); + else { + pri->iob_buf[0] = '"'; + showbytes(buffer, nb, pri->iob_buf + 1); + (void) strlcat(pri->iob_buf, + (nb == nbyte)? + (const char *)"\"" : (const char *)"\"..", + sizeof (pri->iob_buf)); + if (raw) + prt_hex(pri, 0, val); + else + outstring(pri, pri->iob_buf); + } + } +} +#undef ISREAD +#undef ISWRITE + +void +prt_idt(private_t *pri, int raw, long val) /* print idtype_t, waitid() arg */ +{ + const char *s = raw? NULL : idtype_enum(pri, val); + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_wop(private_t *pri, int raw, long val) /* print waitid() options */ +{ + const char *s = raw? NULL : woptions(pri, (int)val); + + if (s == NULL) + prt_oct(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_whn(private_t *pri, int raw, long val) /* print lseek() whence argument */ +{ + const char *s = raw? NULL : whencearg(val); + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +/*ARGSUSED*/ +void +prt_spm(private_t *pri, int raw, long val) /* print sigprocmask argument */ +{ + const char *s = NULL; + + if (!raw) { + switch (val) { + case SIG_BLOCK: s = "SIG_BLOCK"; break; + case SIG_UNBLOCK: s = "SIG_UNBLOCK"; break; + case SIG_SETMASK: s = "SIG_SETMASK"; break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +const char * +mmap_protect(private_t *pri, long arg) +{ + char *str = pri->code_buf; + + if (arg & ~(PROT_READ|PROT_WRITE|PROT_EXEC)) + return ((char *)NULL); + + if (arg == PROT_NONE) + return ("PROT_NONE"); + + *str = '\0'; + if (arg & PROT_READ) + (void) strlcat(str, "|PROT_READ", sizeof (pri->code_buf)); + if (arg & PROT_WRITE) + (void) strlcat(str, "|PROT_WRITE", sizeof (pri->code_buf)); + if (arg & PROT_EXEC) + (void) strlcat(str, "|PROT_EXEC", sizeof (pri->code_buf)); + return ((const char *)(str + 1)); +} + +const char * +mmap_type(private_t *pri, long arg) +{ + char *str = pri->code_buf; + size_t used; + +#define CBSIZE sizeof (pri->code_buf) + switch (arg & MAP_TYPE) { + case MAP_SHARED: + used = strlcpy(str, "MAP_SHARED", CBSIZE); + break; + case MAP_PRIVATE: + used = strlcpy(str, "MAP_PRIVATE", CBSIZE); + break; + default: + used = snprintf(str, CBSIZE, "%ld", arg&MAP_TYPE); + break; + } + + arg &= ~(_MAP_NEW|MAP_TYPE); + + if (arg & ~(MAP_FIXED|MAP_RENAME|MAP_NORESERVE|MAP_ANON|MAP_ALIGN| + MAP_TEXT|MAP_INITDATA|MAP_32BIT)) + (void) snprintf(str + used, sizeof (pri->code_buf) - used, + "|0x%lX", arg); + else { + if (arg & MAP_FIXED) + (void) strlcat(str, "|MAP_FIXED", CBSIZE); + if (arg & MAP_RENAME) + (void) strlcat(str, "|MAP_RENAME", CBSIZE); + if (arg & MAP_NORESERVE) + (void) strlcat(str, "|MAP_NORESERVE", CBSIZE); + if (arg & MAP_ANON) + (void) strlcat(str, "|MAP_ANON", CBSIZE); + if (arg & MAP_ALIGN) + (void) strlcat(str, "|MAP_ALIGN", CBSIZE); + if (arg & MAP_TEXT) + (void) strlcat(str, "|MAP_TEXT", CBSIZE); + if (arg & MAP_INITDATA) + (void) strlcat(str, "|MAP_INITDATA", CBSIZE); + if (arg & MAP_32BIT) + (void) strlcat(str, "|MAP_32BIT", CBSIZE); + } + + return ((const char *)str); +#undef CBSIZE +} + +void +prt_mpr(private_t *pri, int raw, long val) /* print mmap()/mprotect() flags */ +{ + const char *s = raw? NULL : mmap_protect(pri, val); + + if (s == NULL) + prt_hhx(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_mty(private_t *pri, int raw, long val) /* print mmap() mapping type flags */ +{ + const char *s = raw? NULL : mmap_type(pri, val); + + if (s == NULL) + prt_hhx(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_mob(private_t *pri, int raw, long val) /* print mmapobj() flags */ +{ + if (val == 0) + prt_dec(pri, 0, val); + else if (raw || (val & ~(MMOBJ_PADDING|MMOBJ_INTERPRET)) != 0) + prt_hhx(pri, 0, val); + else { +#define CBSIZE sizeof (pri->code_buf) + char *s = pri->code_buf; + + *s = '\0'; + if (val & MMOBJ_PADDING) + (void) strlcat(s, "|MMOBJ_PADDING", CBSIZE); + if (val & MMOBJ_INTERPRET) + (void) strlcat(s, "|MMOBJ_INTERPRET", CBSIZE); + outstring(pri, s + 1); +#undef CBSIZE + } +} + +/*ARGSUSED*/ +void +prt_mcf(private_t *pri, int raw, long val) /* print memcntl() function */ +{ + const char *s = NULL; + + if (!raw) { + switch (val) { + case MC_SYNC: s = "MC_SYNC"; break; + case MC_LOCK: s = "MC_LOCK"; break; + case MC_UNLOCK: s = "MC_UNLOCK"; break; + case MC_ADVISE: s = "MC_ADVISE"; break; + case MC_LOCKAS: s = "MC_LOCKAS"; break; + case MC_UNLOCKAS: s = "MC_UNLOCKAS"; break; + case MC_HAT_ADVISE: s = "MC_HAT_ADVISE"; break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_mad(private_t *pri, int raw, long val) /* print madvise() argument */ +{ + const char *s = NULL; + + if (!raw) { + switch (val) { + case MADV_NORMAL: s = "MADV_NORMAL"; break; + case MADV_RANDOM: s = "MADV_RANDOM"; break; + case MADV_SEQUENTIAL: s = "MADV_SEQUENTIAL"; break; + case MADV_WILLNEED: s = "MADV_WILLNEED"; break; + case MADV_DONTNEED: s = "MADV_DONTNEED"; break; + case MADV_FREE: s = "MADV_FREE"; break; + case MADV_ACCESS_DEFAULT: s = "MADV_ACCESS_DEFAULT"; break; + case MADV_ACCESS_LWP: s = "MADV_ACCESS_LWP"; break; + case MADV_ACCESS_MANY: s = "MADV_ACCESS_MANY"; break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_mc4(private_t *pri, int raw, long val) /* print memcntl() (4th) argument */ +{ + if (val == 0) + prt_dec(pri, 0, val); + else if (raw) + prt_hhx(pri, 0, val); + else { + char *s = NULL; + +#define CBSIZE sizeof (pri->code_buf) + /* cheating -- look at memcntl func */ + switch (pri->sys_args[2]) { + case MC_ADVISE: + prt_mad(pri, 0, val); + return; + + case MC_SYNC: + if ((val & ~(MS_SYNC|MS_ASYNC|MS_INVALIDATE)) == 0) { + *(s = pri->code_buf) = '\0'; + if (val & MS_SYNC) + (void) strlcat(s, "|MS_SYNC", CBSIZE); + if (val & MS_ASYNC) + (void) strlcat(s, "|MS_ASYNC", CBSIZE); + if (val & MS_INVALIDATE) + (void) strlcat(s, "|MS_INVALIDATE", + CBSIZE); + } + break; + + case MC_LOCKAS: + case MC_UNLOCKAS: + if ((val & ~(MCL_CURRENT|MCL_FUTURE)) == 0) { + *(s = pri->code_buf) = '\0'; + if (val & MCL_CURRENT) + (void) strlcat(s, "|MCL_CURRENT", + CBSIZE); + if (val & MCL_FUTURE) + (void) strlcat(s, "|MCL_FUTURE", + CBSIZE); + } + break; + } +#undef CBSIZE + + if (s == NULL || *s == '\0') + prt_hhx(pri, 0, val); + else + outstring(pri, ++s); + } +} + +void +prt_mc5(private_t *pri, int raw, long val) /* print memcntl() (5th) argument */ +{ + char *s; + +#define CBSIZE sizeof (pri->code_buf) + if (val == 0) + prt_dec(pri, 0, val); + else if (raw || (val & ~VALID_ATTR)) + prt_hhx(pri, 0, val); + else { + s = pri->code_buf; + *s = '\0'; + if (val & SHARED) + (void) strlcat(s, "|SHARED", CBSIZE); + if (val & PRIVATE) + (void) strlcat(s, "|PRIVATE", CBSIZE); + if (val & PROT_READ) + (void) strlcat(s, "|PROT_READ", CBSIZE); + if (val & PROT_WRITE) + (void) strlcat(s, "|PROT_WRITE", CBSIZE); + if (val & PROT_EXEC) + (void) strlcat(s, "|PROT_EXEC", CBSIZE); + if (*s == '\0') + prt_hhx(pri, 0, val); + else + outstring(pri, ++s); + } +#undef CBSIZE +} + +void +prt_ulm(private_t *pri, int raw, long val) /* print ulimit() argument */ +{ + const char *s = NULL; + + if (!raw) { + switch (val) { + case UL_GFILLIM: s = "UL_GFILLIM"; break; + case UL_SFILLIM: s = "UL_SFILLIM"; break; + case UL_GMEMLIM: s = "UL_GMEMLIM"; break; + case UL_GDESLIM: s = "UL_GDESLIM"; break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_rlm(private_t *pri, int raw, long val) /* print get/setrlimit() argument */ +{ + const char *s = NULL; + + if (!raw) { + switch (val) { + case RLIMIT_CPU: s = "RLIMIT_CPU"; break; + case RLIMIT_FSIZE: s = "RLIMIT_FSIZE"; break; + case RLIMIT_DATA: s = "RLIMIT_DATA"; break; + case RLIMIT_STACK: s = "RLIMIT_STACK"; break; + case RLIMIT_CORE: s = "RLIMIT_CORE"; break; + case RLIMIT_NOFILE: s = "RLIMIT_NOFILE"; break; + case RLIMIT_VMEM: s = "RLIMIT_VMEM"; break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_cnf(private_t *pri, int raw, long val) /* print sysconfig code */ +{ + const char *s = raw? NULL : sconfname(val); + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_inf(private_t *pri, int raw, long val) /* print sysinfo code */ +{ + const char *s = NULL; + + if (!raw) { + switch (val) { + case SI_SYSNAME: s = "SI_SYSNAME"; break; + case SI_HOSTNAME: s = "SI_HOSTNAME"; break; + case SI_RELEASE: s = "SI_RELEASE"; break; + case SI_VERSION: s = "SI_VERSION"; break; + case SI_MACHINE: s = "SI_MACHINE"; break; + case SI_ARCHITECTURE: s = "SI_ARCHITECTURE"; break; + case SI_ARCHITECTURE_32:s = "SI_ARCHITECTURE_32"; break; + case SI_ARCHITECTURE_64:s = "SI_ARCHITECTURE_64"; break; + case SI_ARCHITECTURE_K: s = "SI_ARCHITECTURE_K"; break; + case SI_HW_SERIAL: s = "SI_HW_SERIAL"; break; + case SI_HW_PROVIDER: s = "SI_HW_PROVIDER"; break; + case SI_SRPC_DOMAIN: s = "SI_SRPC_DOMAIN"; break; + case SI_SET_HOSTNAME: s = "SI_SET_HOSTNAME"; break; + case SI_SET_SRPC_DOMAIN: s = "SI_SET_SRPC_DOMAIN"; break; + case SI_PLATFORM: s = "SI_PLATFORM"; break; + case SI_ISALIST: s = "SI_ISALIST"; break; + case SI_DHCP_CACHE: s = "SI_DHCP_CACHE"; break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_ptc(private_t *pri, int raw, long val) /* print pathconf code */ +{ + const char *s = raw? NULL : pathconfname(val); + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_fui(private_t *pri, int raw, long val) /* print fusers() input argument */ +{ + const char *s = raw? NULL : fuiname(val); + + if (s == NULL) + prt_hhx(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_lwf(private_t *pri, int raw, long val) /* print lwp_create() flags */ +{ + char *s; + + if (val == 0) + prt_dec(pri, 0, val); + else if (raw || + (val & ~(LWP_DAEMON|LWP_DETACHED|LWP_SUSPENDED))) + prt_hhx(pri, 0, val); + else { +#define CBSIZE sizeof (pri->code_buf) + s = pri->code_buf; + *s = '\0'; + if (val & LWP_DAEMON) + (void) strlcat(s, "|LWP_DAEMON", CBSIZE); + if (val & LWP_DETACHED) + (void) strlcat(s, "|LWP_DETACHED", CBSIZE); + if (val & LWP_SUSPENDED) + (void) strlcat(s, "|LWP_SUSPENDED", CBSIZE); + outstring(pri, ++s); +#undef CBSIZE + } +} + +void +prt_itm(private_t *pri, int raw, long val) /* print [get|set]itimer() arg */ +{ + const char *s = NULL; + + if (!raw) { + switch (val) { + case ITIMER_REAL: s = "ITIMER_REAL"; break; + case ITIMER_VIRTUAL: s = "ITIMER_VIRTUAL"; break; + case ITIMER_PROF: s = "ITIMER_PROF"; break; +#ifdef ITIMER_REALPROF + case ITIMER_REALPROF: s = "ITIMER_REALPROF"; break; +#endif + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_mod(private_t *pri, int raw, long val) /* print modctl() code */ +{ + const char *s = NULL; + + if (!raw) { + switch (val) { + case MODLOAD: s = "MODLOAD"; break; + case MODUNLOAD: s = "MODUNLOAD"; break; + case MODINFO: s = "MODINFO"; break; + case MODRESERVED: s = "MODRESERVED"; break; + case MODSETMINIROOT: s = "MODSETMINIROOT"; break; + case MODADDMAJBIND: s = "MODADDMAJBIND"; break; + case MODGETPATH: s = "MODGETPATH"; break; + case MODGETPATHLEN: s = "MODGETPATHLEN"; break; + case MODREADSYSBIND: s = "MODREADSYSBIND"; break; + case MODGETMAJBIND: s = "MODGETMAJBIND"; break; + case MODGETNAME: s = "MODGETNAME"; break; + case MODSIZEOF_DEVID: s = "MODSIZEOF_DEVID"; break; + case MODGETDEVID: s = "MODGETDEVID"; break; + case MODSIZEOF_MINORNAME: s = "MODSIZEOF_MINORNAME"; break; + case MODGETMINORNAME: s = "MODGETMINORNAME"; break; + case MODGETFBNAME: s = "MODGETFBNAME"; break; + case MODEVENTS: s = "MODEVENTS"; break; + case MODREREADDACF: s = "MODREREADDACF"; break; + case MODLOADDRVCONF: s = "MODLOADDRVCONF"; break; + case MODUNLOADDRVCONF: s = "MODUNLOADDRVCONF"; break; + case MODREMMAJBIND: s = "MODREMMAJBIND"; break; + case MODDEVT2INSTANCE: s = "MODDEVT2INSTANCE"; break; + case MODGETDEVFSPATH_LEN: s = "MODGETDEVFSPATH_LEN"; break; + case MODGETDEVFSPATH: s = "MODGETDEVFSPATH"; break; + case MODDEVID2PATHS: s = "MODDEVID2PATHS"; break; + case MODSETDEVPOLICY: s = "MODSETDEVPOLICY"; break; + case MODGETDEVPOLICY: s = "MODGETDEVPOLICY"; break; + case MODALLOCPRIV: s = "MODALLOCPRIV"; break; + case MODGETDEVPOLICYBYNAME: + s = "MODGETDEVPOLICYBYNAME"; break; + case MODLOADMINORPERM: s = "MODLOADMINORPERM"; break; + case MODADDMINORPERM: s = "MODADDMINORPERM"; break; + case MODREMMINORPERM: s = "MODREMMINORPERM"; break; + case MODREMDRVCLEANUP: s = "MODREMDRVCLEANUP"; break; + case MODDEVEXISTS: s = "MODDEVEXISTS"; break; + case MODDEVREADDIR: s = "MODDEVREADDIR"; break; + case MODDEVEMPTYDIR: s = "MODDEVEMPTYDIR"; break; + case MODDEVNAME: s = "MODDEVNAME"; break; + case MODGETDEVFSPATH_MI_LEN: + s = "MODGETDEVFSPATH_MI_LEN"; break; + case MODGETDEVFSPATH_MI: + s = "MODGETDEVFSPATH_MI"; break; + case MODREMDRVALIAS: s = "MODREMDRVALIAS"; break; + case MODHPOPS: s = "MODHPOPS"; break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_acl(private_t *pri, int raw, long val) /* print acl() code */ +{ + const char *s = NULL; + + if (!raw) { + switch (val) { + case GETACL: s = "GETACL"; break; + case SETACL: s = "SETACL"; break; + case GETACLCNT: s = "GETACLCNT"; break; + case ACE_GETACL: s = "ACE_GETACL"; break; + case ACE_SETACL: s = "ACE_SETACL"; break; + case ACE_GETACLCNT: s = "ACE_GETACLCNT"; break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_aio(private_t *pri, int raw, long val) /* print kaio() code */ +{ + const char *s = NULL; + char buf[32]; + + if (!raw) { + switch (val & ~AIO_POLL_BIT) { + case AIOREAD: s = "AIOREAD"; break; + case AIOWRITE: s = "AIOWRITE"; break; + case AIOWAIT: s = "AIOWAIT"; break; + case AIOCANCEL: s = "AIOCANCEL"; break; + case AIONOTIFY: s = "AIONOTIFY"; break; + case AIOINIT: s = "AIOINIT"; break; + case AIOSTART: s = "AIOSTART"; break; + case AIOLIO: s = "AIOLIO"; break; + case AIOSUSPEND: s = "AIOSUSPEND"; break; + case AIOERROR: s = "AIOERROR"; break; + case AIOLIOWAIT: s = "AIOLIOWAIT"; break; + case AIOAREAD: s = "AIOAREAD"; break; + case AIOAWRITE: s = "AIOAWRITE"; break; + /* + * We have to hardcode the values for the 64-bit versions of + * these calls, because <sys/aio.h> defines them to be identical + * when compiled 64-bit. If our target is 32-bit, we still need + * to decode them correctly. + */ + case 13: s = "AIOLIO64"; break; + case 14: s = "AIOSUSPEND64"; break; + case 15: s = "AUIOERROR64"; break; + case 16: s = "AIOLIOWAIT64"; break; + case 17: s = "AIOAREAD64"; break; + case 18: s = "AIOAWRITE64"; break; + case 19: s = "AIOCANCEL64"; break; + + /* + * AIOFSYNC doesn't correspond to a syscall. + */ + case AIOWAITN: s = "AIOWAITN"; break; + } + if (s != NULL && (val & AIO_POLL_BIT)) { + (void) strlcpy(buf, s, sizeof (buf)); + (void) strlcat(buf, "|AIO_POLL_BIT", sizeof (buf)); + s = (const char *)buf; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_aud(private_t *pri, int raw, long val) /* print auditsys() code */ +{ + const char *s = NULL; + + if (!raw) { + switch (val) { + case BSM_GETAUID: s = "BSM_GETAUID"; break; + case BSM_SETAUID: s = "BSM_SETAUID"; break; + case BSM_GETAUDIT: s = "BSM_GETAUDIT"; break; + case BSM_SETAUDIT: s = "BSM_SETAUDIT"; break; + case BSM_AUDIT: s = "BSM_AUDIT"; break; + case BSM_AUDITCTL: s = "BSM_AUDITCTL"; break; + case BSM_GETAUDIT_ADDR: s = "BSM_GETAUDIT_ADDR"; break; + case BSM_SETAUDIT_ADDR: s = "BSM_SETAUDIT_ADDR"; break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_cor(private_t *pri, int raw, long val) /* print corectl() subcode */ +{ + const char *s = NULL; + + if (!raw) { + switch (val) { + case CC_SET_OPTIONS: + s = "CC_SET_OPTIONS"; break; + case CC_GET_OPTIONS: + s = "CC_GET_OPTIONS"; break; + case CC_SET_GLOBAL_PATH: + s = "CC_SET_GLOBAL_PATH"; break; + case CC_GET_GLOBAL_PATH: + s = "CC_GET_GLOBAL_PATH"; break; + case CC_SET_PROCESS_PATH: + s = "CC_SET_PROCESS_PATH"; break; + case CC_GET_PROCESS_PATH: + s = "CC_GET_PROCESS_PATH"; break; + case CC_SET_GLOBAL_CONTENT: + s = "CC_SET_GLOBAL_CONTENT"; break; + case CC_GET_GLOBAL_CONTENT: + s = "CC_GET_GLOBAL_CONTENT"; break; + case CC_SET_PROCESS_CONTENT: + s = "CC_SET_PROCESS_CONTENT"; break; + case CC_GET_PROCESS_CONTENT: + s = "CC_GET_PROCESS_CONTENT"; break; + case CC_SET_DEFAULT_PATH: + s = "CC_SET_DEFAULT_PATH"; break; + case CC_GET_DEFAULT_PATH: + s = "CC_GET_DEFAULT_PATH"; break; + case CC_SET_DEFAULT_CONTENT: + s = "CC_SET_DEFAULT_CONTENT"; break; + case CC_GET_DEFAULT_CONTENT: + s = "CC_GET_DEFAULT_CONTENT"; break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_cco(private_t *pri, int raw, long val) /* print corectl() options */ +{ + char *s; + + if (val == 0) + prt_dec(pri, 0, val); + else if (raw || (val & ~CC_OPTIONS)) + prt_hhx(pri, 0, val); + else { +#define CBSIZE sizeof (pri->code_buf) + s = pri->code_buf; + *s = '\0'; + if (val & CC_GLOBAL_PATH) + (void) strlcat(s, "|CC_GLOBAL_PATH", CBSIZE); + if (val & CC_PROCESS_PATH) + (void) strlcat(s, "|CC_PROCESS_PATH", CBSIZE); + if (val & CC_GLOBAL_SETID) + (void) strlcat(s, "|CC_GLOBAL_SETID", CBSIZE); + if (val & CC_PROCESS_SETID) + (void) strlcat(s, "|CC_PROCESS_SETID", CBSIZE); + if (val & CC_GLOBAL_LOG) + (void) strlcat(s, "|CC_GLOBAL_LOG", CBSIZE); + if (*s == '\0') + prt_hhx(pri, 0, val); + else + outstring(pri, ++s); +#undef CBSIZE + } +} + +void +prt_ccc(private_t *pri, int raw, long val) /* print corectl() content */ +{ + core_content_t ccc; + + if (Pread(Proc, &ccc, sizeof (ccc), val) != sizeof (ccc)) + prt_hex(pri, 0, val); + else if (!raw && proc_content2str(ccc, pri->code_buf, + sizeof (pri->code_buf)) >= 0) + outstring(pri, pri->code_buf); + else + prt_hhx(pri, 0, (long)ccc); +} + +void +prt_rcc(private_t *pri, int raw, long val) /* print corectl() ret. cont. */ +{ + core_content_t ccc; + + if (pri->Errno || Pread(Proc, &ccc, sizeof (ccc), val) != sizeof (ccc)) + prt_hex(pri, 0, val); + else if (!raw && proc_content2str(ccc, pri->code_buf, + sizeof (pri->code_buf)) >= 0) + outstring(pri, pri->code_buf); + else + prt_hhx(pri, 0, (long)ccc); +} + +void +prt_cpc(private_t *pri, int raw, long val) /* print cpc() subcode */ +{ + const char *s = NULL; + + if (!raw) { + switch (val) { + case CPC_BIND: s = "CPC_BIND"; break; + case CPC_SAMPLE: s = "CPC_SAMPLE"; break; + case CPC_INVALIDATE: s = "CPC_INVALIDATE"; break; + case CPC_RELE: s = "CPC_RELE"; break; + case CPC_EVLIST_SIZE: s = "CPC_EVLIST_SIZE"; break; + case CPC_LIST_EVENTS: s = "CPC_LIST_EVENTS"; break; + case CPC_ATTRLIST_SIZE: s = "CPC_ATTRLIST_SIZE"; break; + case CPC_LIST_ATTRS: s = "CPC_LIST_ATTRS"; break; + case CPC_IMPL_NAME: s = "CPC_IMPL_NAME"; break; + case CPC_CPUREF: s = "CPC_CPUREF"; break; + case CPC_USR_EVENTS: s = "CPC_USR_EVENTS"; break; + case CPC_SYS_EVENTS: s = "CPC_SYS_EVENTS"; break; + case CPC_NPIC: s = "CPC_NPIC"; break; + case CPC_CAPS: s = "CPC_CAPS"; break; + case CPC_ENABLE: s = "CPC_ENABLE"; break; + case CPC_DISABLE: s = "CPC_DISABLE"; break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +outstring(private_t *pri, const char *s) +{ + int len = strlen(s); + + GROW(len); + (void) strcpy(pri->sys_string + pri->sys_leng, s); + pri->sys_leng += len; +} + +void +grow(private_t *pri, int nbyte) /* reallocate format buffer if necessary */ +{ + while (pri->sys_leng + nbyte >= pri->sys_ssize) + pri->sys_string = my_realloc(pri->sys_string, + pri->sys_ssize *= 2, "format buffer"); +} + +void +prt_clc(private_t *pri, int raw, long val) +{ + const char *s = NULL; + + if (!raw) { + switch (val) { + case CL_INITIALIZE: s = "CL_INITIALIZE"; break; + case CL_CONFIG: s = "CL_CONFIG"; break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_clf(private_t *pri, int raw, long val) +{ + const char *s = NULL; + + if (!raw) { + switch (pri->sys_args[0]) { + case CL_CONFIG: + switch (pri->sys_args[1]) { + case CL_NODEID: + s = "CL_NODEID"; break; + case CL_HIGHEST_NODEID: + s = "CL_HIGHEST_NODEID"; break; + } + break; + case CL_INITIALIZE: + switch (pri->sys_args[1]) { + case CL_GET_BOOTFLAG: + s = "CL_GET_BOOTFLAG"; break; + } + break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +void +prt_sqc(private_t *pri, int raw, long val) /* print sigqueue() si_code */ +{ + const char *s = NULL; + + if (!raw) { + switch ((int)val) { + case SI_QUEUE: s = "SI_QUEUE"; break; + case SI_TIMER: s = "SI_TIMER"; break; + case SI_ASYNCIO: s = "SI_ASYNCIO"; break; + case SI_MESGQ: s = "SI_MESGQ"; break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +/* + * print priocntlsys() (key, value) pair key. + */ +void +print_pck(private_t *pri, int raw, long val) +{ + const char *s = NULL; + char clname[PC_CLNMSZ]; + + if ((pri->sys_args[2] != PC_GETXPARMS && + pri->sys_args[2] != PC_SETXPARMS) || val == 0 || raw) { + prt_dec(pri, 0, val); + return; + } + + if (pri->sys_args[3] == NULL) { + if (val == PC_KY_CLNAME) { + s = "PC_KY_CLNAME"; + outstring(pri, s); + } else + prt_dec(pri, 0, val); + return; + } + + if (Pread(Proc, &clname, PC_CLNMSZ, pri->sys_args[3]) != PC_CLNMSZ) { + prt_dec(pri, 0, val); + return; + } + + if (strcmp(clname, "TS") == 0) { + switch (val) { + case TS_KY_UPRILIM: s = "TS_KY_UPRILIM"; break; + case TS_KY_UPRI: s = "TS_KY_UPRI"; break; + default: break; + } + } else if (strcmp(clname, "IA") == 0) { + switch (val) { + case IA_KY_UPRILIM: s = "IA_KY_UPRILIM"; break; + case IA_KY_UPRI: s = "IA_KY_UPRI"; break; + case IA_KY_MODE: s = "IA_KY_MODE"; break; + default: break; + } + } else if (strcmp(clname, "RT") == 0) { + switch (val) { + case RT_KY_PRI: s = "RT_KY_PRI"; break; + case RT_KY_TQSECS: s = "RT_KY_TQSECS"; break; + case RT_KY_TQNSECS: s = "RT_KY_TQNSECS"; break; + case RT_KY_TQSIG: s = "RT_KY_TQSIG"; break; + default: break; + } + } else if (strcmp(clname, "FSS") == 0) { + switch (val) { + case FSS_KY_UPRILIM: s = "FSS_KY_UPRILIM"; break; + case FSS_KY_UPRI: s = "FSS_KY_UPRI"; break; + default: break; + } + } else if (strcmp(clname, "FX") == 0) { + switch (val) { + case FX_KY_UPRILIM: s = "FX_KY_UPRILIM"; break; + case FX_KY_UPRI: s = "FX_KY_UPRI"; break; + case FX_KY_TQSECS: s = "FX_KY_TQSECS"; break; + case FX_KY_TQNSECS: s = "FX_KY_TQNSECS"; break; + default: break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +/* + * print priocntlsys() fourth argument. + */ +/*ARGSUSED*/ +void +prt_pc4(private_t *pri, int raw, long val) +{ + /* look at pricntlsys function */ + if ((pri->sys_args[2] != PC_GETXPARMS && + pri->sys_args[2] != PC_SETXPARMS)) + prt_hex(pri, 0, val); + else if (val) + prt_stg(pri, 0, val); + else + prt_dec(pri, 0, val); +} + +/* + * print priocntlsys() (key, value) pairs (5th argument). + */ +/*ARGSUSED*/ +void +prt_pc5(private_t *pri, int raw, long val) +{ + pc_vaparms_t prms; + pc_vaparm_t *vpp = &prms.pc_parms[0]; + uint_t cnt; + + + /* look at pricntlsys function */ + if ((pri->sys_args[2] != PC_GETXPARMS && + pri->sys_args[2] != PC_SETXPARMS) || val == 0) { + prt_dec(pri, 0, 0); + return; + } + + if (Pread(Proc, &prms, sizeof (prms), val) != sizeof (prms)) { + prt_hex(pri, 0, val); + return; + } + + if ((cnt = prms.pc_vaparmscnt) > PC_VAPARMCNT) + return; + + for (; cnt--; vpp++) { + print_pck(pri, 0, vpp->pc_key); + outstring(pri, ", "); + prt_hex(pri, 0, (long)vpp->pc_parm); + outstring(pri, ", "); + } + + prt_dec(pri, 0, PC_KY_NULL); +} + +/* + * Print processor set id, including logical expansion of "special" ids. + */ +void +prt_pst(private_t *pri, int raw, long val) +{ + const char *s = NULL; + + if (!raw) { + switch ((psetid_t)val) { + case PS_NONE: s = "PS_NONE"; break; + case PS_QUERY: s = "PS_QUERY"; break; + case PS_MYID: s = "PS_MYID"; break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +/* + * Print meminfo() argument. + */ +/*ARGSUSED*/ +void +prt_mif(private_t *pri, int raw, long val) +{ + struct meminfo minfo; + +#ifdef _LP64 + if (data_model == PR_MODEL_ILP32) { + struct meminfo32 minfo32; + + if (Pread(Proc, &minfo32, sizeof (struct meminfo32), val) != + sizeof (struct meminfo32)) { + prt_dec(pri, 0, pri->sys_args[1]); /* addr_count */ + outstring(pri, ", "); + prt_hex(pri, 0, val); + return; + } + /* + * arrange the arguments in the order that user calls with + */ + prt_hex(pri, 0, minfo32.mi_inaddr); + outstring(pri, ", "); + prt_dec(pri, 0, pri->sys_args[1]); /* addr_count */ + outstring(pri, ", "); + prt_hex(pri, 0, minfo32.mi_info_req); + outstring(pri, ", "); + prt_dec(pri, 0, minfo32.mi_info_count); + outstring(pri, ", "); + prt_hex(pri, 0, minfo32.mi_outdata); + outstring(pri, ", "); + prt_hex(pri, 0, minfo32.mi_validity); + return; + } +#endif + if (Pread(Proc, &minfo, sizeof (struct meminfo), val) != + sizeof (struct meminfo)) { + prt_dec(pri, 0, pri->sys_args[1]); /* addr_count */ + outstring(pri, ", "); + prt_hex(pri, 0, val); + return; + } + /* + * arrange the arguments in the order that user calls with + */ + prt_hex(pri, 0, (long)minfo.mi_inaddr); + outstring(pri, ", "); + prt_dec(pri, 0, pri->sys_args[1]); /* addr_count */ + outstring(pri, ", "); + prt_hex(pri, 0, (long)minfo.mi_info_req); + outstring(pri, ", "); + prt_dec(pri, 0, minfo.mi_info_count); + outstring(pri, ", "); + prt_hex(pri, 0, (long)minfo.mi_outdata); + outstring(pri, ", "); + prt_hex(pri, 0, (long)minfo.mi_validity); +} + + +/* + * Print so_socket() 1st argument. + */ +/*ARGSUSED*/ +void +prt_pfm(private_t *pri, int raw, long val) +{ + /* Protocol Families have same names as Address Families */ + if ((ulong_t)val < MAX_AFCODES) { + outstring(pri, "PF_"); + outstring(pri, afcodes[val]); + } else { + prt_dec(pri, 0, val); + } +} + +/* + * Print sockconfig() subcode. + */ +/*ARGSUSED*/ +void +prt_skc(private_t *pri, int raw, long val) +{ + const char *s = NULL; + + if (!raw) { + switch (val) { + case SOCKCONFIG_ADD_SOCK: + s = "SOCKCONFIG_ADD_SOCK"; break; + case SOCKCONFIG_REMOVE_SOCK: + s = "SOCKCONFIG_REMOVE_SOCK"; break; + case SOCKCONFIG_ADD_FILTER: + s = "SOCKCONFIG_ADD_FILTER"; break; + case SOCKCONFIG_REMOVE_FILTER: + s = "SOCKCONFIG_REMOVE_FILTER"; break; + } + } + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} +/* + * Print so_socket() 2nd argument. + */ +/*ARGSUSED*/ +void +prt_skt(private_t *pri, int raw, long val) +{ + const char *s; + long type = val & SOCK_TYPE_MASK; + + if ((ulong_t)type <= MAX_SOCKTYPES && + (s = socktype_codes[type]) != NULL) { + outstring(pri, s); + if ((val & SOCK_CLOEXEC) != 0) { + outstring(pri, "|SOCK_CLOEXEC"); + } + } else { + prt_dec(pri, 0, val); + } +} + + +/* + * Print so_socket() 3rd argument. + */ +/*ARGSUSED*/ +void +prt_skp(private_t *pri, int raw, long val) +{ + const char *s; + + /* cheating -- look at the protocol-family */ + switch (pri->sys_args[0]) { + case PF_INET6: + case PF_INET: + case PF_NCA: if ((s = ipprotos((int)val)) != NULL) { + outstring(pri, s); + break; + } + /* FALLTHROUGH */ + default: prt_dec(pri, 0, val); + break; + } +} + + +/* + * Print so_socket() 5th argument. + */ +/*ARGSUSED*/ +void +prt_skv(private_t *pri, int raw, long val) +{ + switch (val) { + case SOV_STREAM: outstring(pri, "SOV_STREAM"); break; + case SOV_DEFAULT: outstring(pri, "SOV_DEFAULT"); break; + case SOV_SOCKSTREAM: outstring(pri, "SOV_SOCKSTREAM"); break; + case SOV_SOCKBSD: outstring(pri, "SOV_SOCKBSD"); break; + case SOV_XPG4_2: outstring(pri, "SOV_XPG4_2"); break; + default: prt_dec(pri, 0, val); break; + } +} + +/* + * Print accept4() flags argument. + */ +void +prt_acf(private_t *pri, int raw, long val) +{ + int first = 1; + if (raw || !val || + (val & ~(SOCK_CLOEXEC|SOCK_NDELAY|SOCK_NONBLOCK))) { + prt_dex(pri, 0, val); + return; + } + + if (val & SOCK_CLOEXEC) { + outstring(pri, "|SOCK_CLOEXEC" + first); + first = 0; + } + if (val & SOCK_NDELAY) { + outstring(pri, "|SOCK_NDELAY" + first); + first = 0; + } + if (val & SOCK_NONBLOCK) { + outstring(pri, "|SOCK_NONBLOCK" + first); + } +} + + +/* + * Print setsockopt()/getsockopt() 2nd argument. + */ +/*ARGSUSED*/ +void +prt_sol(private_t *pri, int raw, long val) +{ + if (val == SOL_SOCKET) { + outstring(pri, "SOL_SOCKET"); + } else if (val == SOL_ROUTE) { + outstring(pri, "SOL_ROUTE"); + } else { + const struct protoent *p; + struct protoent res; + char buf[NSS_BUFLEN_PROTOCOLS]; + + if ((p = getprotobynumber_r(val, &res, + (char *)buf, sizeof (buf))) != NULL) + outstring(pri, p->p_name); + else + prt_dec(pri, 0, val); + } +} + + +const char * +sol_optname(private_t *pri, long val) +{ +#define CBSIZE sizeof (pri->code_buf) + if (val >= SO_SNDBUF) { + switch (val) { + case SO_SNDBUF: return ("SO_SNDBUF"); + case SO_RCVBUF: return ("SO_RCVBUF"); + case SO_SNDLOWAT: return ("SO_SNDLOWAT"); + case SO_RCVLOWAT: return ("SO_RCVLOWAT"); + case SO_SNDTIMEO: return ("SO_SNDTIMEO"); + case SO_RCVTIMEO: return ("SO_RCVTIMEO"); + case SO_ERROR: return ("SO_ERROR"); + case SO_TYPE: return ("SO_TYPE"); + case SO_PROTOTYPE: return ("SO_PROTOTYPE"); + case SO_ANON_MLP: return ("SO_ANON_MLP"); + case SO_MAC_EXEMPT: return ("SO_MAC_EXEMPT"); + case SO_ALLZONES: return ("SO_ALLZONES"); + case SO_MAC_IMPLICIT: return ("SO_MAC_IMPLICIT"); + case SO_VRRP: return ("SO_VRRP"); + case SO_EXCLBIND: return ("SO_EXCLBIND"); + case SO_DOMAIN: return ("SO_DOMAIN"); + + default: (void) snprintf(pri->code_buf, CBSIZE, + "0x%lx", val); + return (pri->code_buf); + } + } else { + char *s = pri->code_buf; + size_t used = 1; + long val2; + + *s = '\0'; + val2 = val & ~(SO_DEBUG|SO_ACCEPTCONN|SO_REUSEADDR|SO_KEEPALIVE| + SO_DONTROUTE|SO_BROADCAST|SO_USELOOPBACK|SO_LINGER| + SO_OOBINLINE|SO_DGRAM_ERRIND|SO_RECVUCRED); + if (val2) + used = snprintf(s, CBSIZE, "|0x%lx", val2); + if (val & SO_DEBUG) + used = strlcat(s, "|SO_DEBUG", CBSIZE); + if (val & SO_ACCEPTCONN) + used = strlcat(s, "|SO_ACCEPTCONN", CBSIZE); + if (val & SO_REUSEADDR) + used = strlcat(s, "|SO_REUSEADDR", CBSIZE); + if (val & SO_KEEPALIVE) + used = strlcat(s, "|SO_KEEPALIVE", CBSIZE); + if (val & SO_DONTROUTE) + used = strlcat(s, "|SO_DONTROUTE", CBSIZE); + if (val & SO_BROADCAST) + used = strlcat(s, "|SO_BROADCAST", CBSIZE); + if (val & SO_USELOOPBACK) + used = strlcat(s, "|SO_USELOOPBACK", CBSIZE); + if (val & SO_LINGER) + used = strlcat(s, "|SO_LINGER", CBSIZE); + if (val & SO_OOBINLINE) + used = strlcat(s, "|SO_OOBINLINE", CBSIZE); + if (val & SO_DGRAM_ERRIND) + used = strlcat(s, "|SO_DGRAM_ERRIND", CBSIZE); + if (val & SO_RECVUCRED) + used = strlcat(s, "|SO_RECVUCRED", CBSIZE); + if (used >= CBSIZE || val == 0) + (void) snprintf(s + 1, CBSIZE-1, "0x%lx", val); + return ((const char *)(s + 1)); + } +#undef CBSIZE +} + +const char * +route_optname(private_t *pri, long val) +{ + switch (val) { + case RT_AWARE: + return ("RT_AWARE"); + default: + (void) snprintf(pri->code_buf, sizeof (pri->code_buf), + "0x%lx", val); + return (pri->code_buf); + } +} + +const char * +tcp_optname(private_t *pri, long val) +{ + switch (val) { + case TCP_NODELAY: return ("TCP_NODELAY"); + case TCP_MAXSEG: return ("TCP_MAXSEG"); + case TCP_KEEPALIVE: return ("TCP_KEEPALIVE"); + case TCP_NOTIFY_THRESHOLD: return ("TCP_NOTIFY_THRESHOLD"); + case TCP_ABORT_THRESHOLD: return ("TCP_ABORT_THRESHOLD"); + case TCP_CONN_NOTIFY_THRESHOLD: return ("TCP_CONN_NOTIFY_THRESHOLD"); + case TCP_CONN_ABORT_THRESHOLD: return ("TCP_CONN_ABORT_THRESHOLD"); + case TCP_RECVDSTADDR: return ("TCP_RECVDSTADDR"); + case TCP_ANONPRIVBIND: return ("TCP_ANONPRIVBIND"); + case TCP_EXCLBIND: return ("TCP_EXCLBIND"); + case TCP_INIT_CWND: return ("TCP_INIT_CWND"); + case TCP_KEEPALIVE_THRESHOLD: return ("TCP_KEEPALIVE_THRESHOLD"); + case TCP_KEEPALIVE_ABORT_THRESHOLD: + return ("TCP_KEEPALIVE_ABORT_THRESHOLD"); + case TCP_CORK: return ("TCP_CORK"); + case TCP_RTO_INITIAL: return ("TCP_RTO_INITIAL"); + case TCP_RTO_MIN: return ("TCP_RTO_MIN"); + case TCP_RTO_MAX: return ("TCP_RTO_MAX"); + case TCP_LINGER2: return ("TCP_LINGER2"); + + default: (void) snprintf(pri->code_buf, + sizeof (pri->code_buf), + "0x%lx", val); + return (pri->code_buf); + } +} + + +const char * +sctp_optname(private_t *pri, long val) +{ + switch (val) { + case SCTP_RTOINFO: return ("SCTP_RTOINFO"); + case SCTP_ASSOCINFO: return ("SCTP_ASSOCINFO"); + case SCTP_INITMSG: return ("SCTP_INITMSG"); + case SCTP_NODELAY: return ("SCTP_NODELAY"); + case SCTP_AUTOCLOSE: return ("SCTP_AUTOCLOSE"); + case SCTP_SET_PEER_PRIMARY_ADDR: + return ("SCTP_SET_PEER_PRIMARY_ADDR"); + case SCTP_PRIMARY_ADDR: return ("SCTP_PRIMARY_ADDR"); + case SCTP_ADAPTATION_LAYER: return ("SCTP_ADAPTATION_LAYER"); + case SCTP_DISABLE_FRAGMENTS: return ("SCTP_DISABLE_FRAGMENTS"); + case SCTP_PEER_ADDR_PARAMS: return ("SCTP_PEER_ADDR_PARAMS"); + case SCTP_DEFAULT_SEND_PARAM: return ("SCTP_DEFAULT_SEND_PARAM"); + case SCTP_EVENTS: return ("SCTP_EVENTS"); + case SCTP_I_WANT_MAPPED_V4_ADDR: + return ("SCTP_I_WANT_MAPPED_V4_ADDR"); + case SCTP_MAXSEG: return ("SCTP_MAXSEG"); + case SCTP_STATUS: return ("SCTP_STATUS"); + case SCTP_GET_PEER_ADDR_INFO: return ("SCTP_GET_PEER_ADDR_INFO"); + + case SCTP_ADD_ADDR: return ("SCTP_ADD_ADDR"); + case SCTP_REM_ADDR: return ("SCTP_REM_ADDR"); + + default: (void) snprintf(pri->code_buf, + sizeof (pri->code_buf), + "0x%lx", val); + return (pri->code_buf); + } +} + + +const char * +udp_optname(private_t *pri, long val) +{ + switch (val) { + case UDP_CHECKSUM: return ("UDP_CHECKSUM"); + case UDP_ANONPRIVBIND: return ("UDP_ANONPRIVBIND"); + case UDP_EXCLBIND: return ("UDP_EXCLBIND"); + case UDP_RCVHDR: return ("UDP_RCVHDR"); + case UDP_NAT_T_ENDPOINT: return ("UDP_NAT_T_ENDPOINT"); + + default: (void) snprintf(pri->code_buf, + sizeof (pri->code_buf), "0x%lx", + val); + return (pri->code_buf); + } +} + + +/* + * Print setsockopt()/getsockopt() 3rd argument. + */ +/*ARGSUSED*/ +void +prt_son(private_t *pri, int raw, long val) +{ + /* cheating -- look at the level */ + switch (pri->sys_args[1]) { + case SOL_SOCKET: outstring(pri, sol_optname(pri, val)); + break; + case SOL_ROUTE: outstring(pri, route_optname(pri, val)); + break; + case IPPROTO_TCP: outstring(pri, tcp_optname(pri, val)); + break; + case IPPROTO_UDP: outstring(pri, udp_optname(pri, val)); + break; + case IPPROTO_SCTP: outstring(pri, sctp_optname(pri, val)); + break; + default: prt_dec(pri, 0, val); + break; + } +} + + +/* + * Print utrap type + */ +/*ARGSUSED*/ +void +prt_utt(private_t *pri, int raw, long val) +{ + const char *s = NULL; + +#ifdef __sparc + if (!raw) { + switch (val) { + case UT_INSTRUCTION_DISABLED: + s = "UT_INSTRUCTION_DISABLED"; break; + case UT_INSTRUCTION_ERROR: + s = "UT_INSTRUCTION_ERROR"; break; + case UT_INSTRUCTION_PROTECTION: + s = "UT_INSTRUCTION_PROTECTION"; break; + case UT_ILLTRAP_INSTRUCTION: + s = "UT_ILLTRAP_INSTRUCTION"; break; + case UT_ILLEGAL_INSTRUCTION: + s = "UT_ILLEGAL_INSTRUCTION"; break; + case UT_PRIVILEGED_OPCODE: + s = "UT_PRIVILEGED_OPCODE"; break; + case UT_FP_DISABLED: + s = "UT_FP_DISABLED"; break; + case UT_FP_EXCEPTION_IEEE_754: + s = "UT_FP_EXCEPTION_IEEE_754"; break; + case UT_FP_EXCEPTION_OTHER: + s = "UT_FP_EXCEPTION_OTHER"; break; + case UT_TAG_OVERFLOW: + s = "UT_TAG_OVERFLOW"; break; + case UT_DIVISION_BY_ZERO: + s = "UT_DIVISION_BY_ZERO"; break; + case UT_DATA_EXCEPTION: + s = "UT_DATA_EXCEPTION"; break; + case UT_DATA_ERROR: + s = "UT_DATA_ERROR"; break; + case UT_DATA_PROTECTION: + s = "UT_DATA_PROTECTION"; break; + case UT_MEM_ADDRESS_NOT_ALIGNED: + s = "UT_MEM_ADDRESS_NOT_ALIGNED"; break; + case UT_PRIVILEGED_ACTION: + s = "UT_PRIVILEGED_ACTION"; break; + case UT_ASYNC_DATA_ERROR: + s = "UT_ASYNC_DATA_ERROR"; break; + case UT_TRAP_INSTRUCTION_16: + s = "UT_TRAP_INSTRUCTION_16"; break; + case UT_TRAP_INSTRUCTION_17: + s = "UT_TRAP_INSTRUCTION_17"; break; + case UT_TRAP_INSTRUCTION_18: + s = "UT_TRAP_INSTRUCTION_18"; break; + case UT_TRAP_INSTRUCTION_19: + s = "UT_TRAP_INSTRUCTION_19"; break; + case UT_TRAP_INSTRUCTION_20: + s = "UT_TRAP_INSTRUCTION_20"; break; + case UT_TRAP_INSTRUCTION_21: + s = "UT_TRAP_INSTRUCTION_21"; break; + case UT_TRAP_INSTRUCTION_22: + s = "UT_TRAP_INSTRUCTION_22"; break; + case UT_TRAP_INSTRUCTION_23: + s = "UT_TRAP_INSTRUCTION_23"; break; + case UT_TRAP_INSTRUCTION_24: + s = "UT_TRAP_INSTRUCTION_24"; break; + case UT_TRAP_INSTRUCTION_25: + s = "UT_TRAP_INSTRUCTION_25"; break; + case UT_TRAP_INSTRUCTION_26: + s = "UT_TRAP_INSTRUCTION_26"; break; + case UT_TRAP_INSTRUCTION_27: + s = "UT_TRAP_INSTRUCTION_27"; break; + case UT_TRAP_INSTRUCTION_28: + s = "UT_TRAP_INSTRUCTION_28"; break; + case UT_TRAP_INSTRUCTION_29: + s = "UT_TRAP_INSTRUCTION_29"; break; + case UT_TRAP_INSTRUCTION_30: + s = "UT_TRAP_INSTRUCTION_30"; break; + case UT_TRAP_INSTRUCTION_31: + s = "UT_TRAP_INSTRUCTION_31"; break; + } + } +#endif /* __sparc */ + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + + +/* + * Print utrap handler + */ +void +prt_uth(private_t *pri, int raw, long val) +{ + const char *s = NULL; + + if (!raw) { + switch (val) { + case (long)UTH_NOCHANGE: s = "UTH_NOCHANGE"; break; + } + } + + if (s == NULL) + prt_hex(pri, 0, val); + else + outstring(pri, s); +} + +const char * +access_flags(private_t *pri, long arg) +{ +#define E_OK 010 + char *str = pri->code_buf; + + if (arg & ~(R_OK|W_OK|X_OK|E_OK)) + return (NULL); + + /* NB: F_OK == 0 */ + if (arg == F_OK) + return ("F_OK"); + if (arg == E_OK) + return ("F_OK|E_OK"); + + *str = '\0'; + if (arg & R_OK) + (void) strlcat(str, "|R_OK", sizeof (pri->code_buf)); + if (arg & W_OK) + (void) strlcat(str, "|W_OK", sizeof (pri->code_buf)); + if (arg & X_OK) + (void) strlcat(str, "|X_OK", sizeof (pri->code_buf)); + if (arg & E_OK) + (void) strlcat(str, "|E_OK", sizeof (pri->code_buf)); + return ((const char *)(str + 1)); +#undef E_OK +} + +/* + * Print access() flags. + */ +void +prt_acc(private_t *pri, int raw, long val) +{ + const char *s = raw? NULL : access_flags(pri, val); + + if (s == NULL) + prt_dex(pri, 0, val); + else + outstring(pri, s); +} + +/* + * Print shutdown() "how" (2nd) argument + */ +void +prt_sht(private_t *pri, int raw, long val) +{ + if (raw) { + prt_dex(pri, 0, val); + return; + } + switch (val) { + case SHUT_RD: outstring(pri, "SHUT_RD"); break; + case SHUT_WR: outstring(pri, "SHUT_WR"); break; + case SHUT_RDWR: outstring(pri, "SHUT_RDWR"); break; + default: prt_dec(pri, 0, val); break; + } +} + +/* + * Print fcntl() F_SETFL flags (3rd) argument or fdsync flag (2nd arg) + */ +static struct fcntl_flags { + long val; + const char *name; +} fcntl_flags[] = { +#define FC_FL(flag) { (long)flag, "|" # flag } + FC_FL(FREVOKED), + FC_FL(FREAD), + FC_FL(FWRITE), + FC_FL(FNDELAY), + FC_FL(FAPPEND), + FC_FL(FSYNC), + FC_FL(FDSYNC), + FC_FL(FRSYNC), + FC_FL(FOFFMAX), + FC_FL(FNONBLOCK), + FC_FL(FCREAT), + FC_FL(FTRUNC), + FC_FL(FEXCL), + FC_FL(FNOCTTY), + FC_FL(FXATTR), + FC_FL(FASYNC), + FC_FL(FNODSYNC) +#undef FC_FL +}; + +void +prt_ffg(private_t *pri, int raw, long val) +{ +#define CBSIZE sizeof (pri->code_buf) + char *s = pri->code_buf; + size_t used = 1; + struct fcntl_flags *fp; + + if (raw) { + (void) snprintf(s, CBSIZE, "0x%lx", val); + outstring(pri, s); + return; + } + if (val == 0) { + outstring(pri, "(no flags)"); + return; + } + + *s = '\0'; + for (fp = fcntl_flags; + fp < &fcntl_flags[sizeof (fcntl_flags) / sizeof (*fp)]; fp++) { + if (val & fp->val) { + used = strlcat(s, fp->name, CBSIZE); + val &= ~fp->val; + } + } + + if (val != 0 && used <= CBSIZE) + used += snprintf(s + used, CBSIZE - used, "|0x%lx", val); + + if (used >= CBSIZE) + (void) snprintf(s + 1, CBSIZE-1, "0x%lx", val); + outstring(pri, s + 1); +#undef CBSIZE +} + +void +prt_prs(private_t *pri, int raw, long val) +{ + static size_t setsize; + priv_set_t *set = priv_allocset(); + + if (setsize == 0) { + const priv_impl_info_t *info = getprivimplinfo(); + if (info != NULL) + setsize = info->priv_setsize * sizeof (priv_chunk_t); + } + + if (setsize != 0 && !raw && set != NULL && + Pread(Proc, set, setsize, val) == setsize) { + int i; + + outstring(pri, "{"); + for (i = 0; i < setsize / sizeof (priv_chunk_t); i++) { + char buf[9]; /* 8 hex digits + '\0' */ + (void) snprintf(buf, sizeof (buf), "%08x", + ((priv_chunk_t *)set)[i]); + outstring(pri, buf); + } + + outstring(pri, "}"); + } else { + prt_hex(pri, 0, val); + } + + if (set != NULL) + priv_freeset(set); +} + +/* + * Print privilege set operation. + */ +void +prt_pro(private_t *pri, int raw, long val) +{ + const char *s = NULL; + + if (!raw) { + switch ((priv_op_t)val) { + case PRIV_ON: s = "PRIV_ON"; break; + case PRIV_OFF: s = "PRIV_OFF"; break; + case PRIV_SET: s = "PRIV_SET"; break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +/* + * Print privilege set name + */ +void +prt_prn(private_t *pri, int raw, long val) +{ + const char *s = NULL; + + if (!raw) + s = priv_getsetbynum((int)val); + + if (s == NULL) + prt_dec(pri, 0, val); + else { + char *dup = strdup(s); + char *q; + + /* Do the best we can in this case */ + if (dup == NULL) { + outstring(pri, s); + return; + } + + outstring(pri, "PRIV_"); + + q = dup; + + while (*q != '\0') { + *q = toupper(*q); + q++; + } + outstring(pri, dup); + free(dup); + } +} + +/* + * Print process flag names. + */ +void +prt_pfl(private_t *pri, int raw, long val) +{ + const char *s = NULL; + + if (!raw) { + switch ((int)val) { + case PRIV_DEBUG: s = "PRIV_DEBUG"; break; + case PRIV_AWARE: s = "PRIV_AWARE"; break; + case PRIV_XPOLICY: s = "PRIV_XPOLICY"; break; + case PRIV_AWARE_RESET: s = "PRIV_AWARE_RESET"; break; + case PRIV_PFEXEC: s = "PRIV_PFEXEC"; break; + case NET_MAC_AWARE: s = "NET_MAC_AWARE"; break; + case NET_MAC_AWARE_INHERIT: + s = "NET_MAC_AWARE_INHERIT"; + break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +/* + * Print lgrp_affinity_{get,set}() arguments. + */ +/*ARGSUSED*/ +void +prt_laf(private_t *pri, int raw, long val) +{ + lgrp_affinity_args_t laff; + + if (Pread(Proc, &laff, sizeof (lgrp_affinity_args_t), val) != + sizeof (lgrp_affinity_args_t)) { + prt_hex(pri, 0, val); + return; + } + /* + * arrange the arguments in the order that user calls with + */ + prt_dec(pri, 0, laff.idtype); + outstring(pri, ", "); + prt_dec(pri, 0, laff.id); + outstring(pri, ", "); + prt_dec(pri, 0, laff.lgrp); + outstring(pri, ", "); + if (pri->sys_args[0] == LGRP_SYS_AFFINITY_SET) + prt_dec(pri, 0, laff.aff); +} + +/* + * Print a key_t as IPC_PRIVATE if it is 0. + */ +void +prt_key(private_t *pri, int raw, long val) +{ + if (!raw && val == 0) + outstring(pri, "IPC_PRIVATE"); + else + prt_dec(pri, 0, val); +} + + +/* + * Print zone_getattr() attribute types. + */ +void +prt_zga(private_t *pri, int raw, long val) +{ + const char *s = NULL; + + if (!raw) { + switch ((int)val) { + case ZONE_ATTR_NAME: s = "ZONE_ATTR_NAME"; break; + case ZONE_ATTR_ROOT: s = "ZONE_ATTR_ROOT"; break; + case ZONE_ATTR_STATUS: s = "ZONE_ATTR_STATUS"; break; + case ZONE_ATTR_PRIVSET: s = "ZONE_ATTR_PRIVSET"; break; + case ZONE_ATTR_UNIQID: s = "ZONE_ATTR_UNIQID"; break; + case ZONE_ATTR_POOLID: s = "ZONE_ATTR_POOLID"; break; + case ZONE_ATTR_INITPID: s = "ZONE_ATTR_INITPID"; break; + case ZONE_ATTR_SLBL: s = "ZONE_ATTR_SLBL"; break; + case ZONE_ATTR_INITNAME: s = "ZONE_ATTR_INITNAME"; break; + case ZONE_ATTR_BOOTARGS: s = "ZONE_ATTR_BOOTARGS"; break; + case ZONE_ATTR_BRAND: s = "ZONE_ATTR_BRAND"; break; + case ZONE_ATTR_FLAGS: s = "ZONE_ATTR_FLAGS"; break; + case ZONE_ATTR_PHYS_MCAP: s = "ZONE_ATTR_PHYS_MCAP"; break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +/* + * Print a file descriptor as AT_FDCWD if necessary + */ +void +prt_atc(private_t *pri, int raw, long val) +{ + if ((int)val == AT_FDCWD) { + if (raw) + prt_hex(pri, 0, (uint_t)AT_FDCWD); + else + outstring(pri, "AT_FDCWD"); + } else { + prt_dec(pri, 0, val); + } +} + +/* + * Print Trusted Networking database operation codes (labelsys; tn*) + */ +static void +prt_tnd(private_t *pri, int raw, long val) +{ + const char *s = NULL; + + if (!raw) { + switch ((tsol_dbops_t)val) { + case TNDB_NOOP: s = "TNDB_NOOP"; break; + case TNDB_LOAD: s = "TNDB_LOAD"; break; + case TNDB_DELETE: s = "TNDB_DELETE"; break; + case TNDB_FLUSH: s = "TNDB_FLUSH"; break; + case TNDB_GET: s = "TNDB_GET"; break; + } + } + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +/* + * Print LIO_XX flags + */ +void +prt_lio(private_t *pri, int raw, long val) +{ + if (raw) + prt_dec(pri, 0, val); + else if (val == LIO_WAIT) + outstring(pri, "LIO_WAIT"); + else if (val == LIO_NOWAIT) + outstring(pri, "LIO_NOWAIT"); + else + prt_dec(pri, 0, val); +} + +const char * +door_flags(private_t *pri, long val) +{ + door_attr_t attr = (door_attr_t)val; + char *str = pri->code_buf; + + *str = '\0'; +#define PROCESS_FLAG(flg) \ + if (attr & flg) { \ + (void) strlcat(str, "|" #flg, sizeof (pri->code_buf)); \ + attr &= ~flg; \ + } + + PROCESS_FLAG(DOOR_UNREF); + PROCESS_FLAG(DOOR_UNREF_MULTI); + PROCESS_FLAG(DOOR_PRIVATE); + PROCESS_FLAG(DOOR_REFUSE_DESC); + PROCESS_FLAG(DOOR_NO_CANCEL); + PROCESS_FLAG(DOOR_LOCAL); + PROCESS_FLAG(DOOR_REVOKED); + PROCESS_FLAG(DOOR_IS_UNREF); +#undef PROCESS_FLAG + + if (attr != 0 || *str == '\0') { + size_t len = strlen(str); + (void) snprintf(str + len, sizeof (pri->code_buf) - len, + "|0x%X", attr); + } + + return (str + 1); +} + +/* + * Print door_create() flags + */ +void +prt_dfl(private_t *pri, int raw, long val) +{ + if (raw) + prt_hex(pri, 0, val); + else + outstring(pri, door_flags(pri, val)); +} + +/* + * Print door_*param() param argument + */ +void +prt_dpm(private_t *pri, int raw, long val) +{ + if (raw) + prt_hex(pri, 0, val); + else if (val == DOOR_PARAM_DESC_MAX) + outstring(pri, "DOOR_PARAM_DESC_MAX"); + else if (val == DOOR_PARAM_DATA_MIN) + outstring(pri, "DOOR_PARAM_DATA_MIN"); + else if (val == DOOR_PARAM_DATA_MAX) + outstring(pri, "DOOR_PARAM_DATA_MAX"); + else + prt_hex(pri, 0, val); +} + +/* + * Print rctlsys subcodes + */ +void +prt_rsc(private_t *pri, int raw, long val) /* print utssys code */ +{ + const char *s = raw? NULL : rctlsyscode(val); + + if (s == NULL) + prt_dec(pri, 0, val); + else + outstring(pri, s); +} + +/* + * Print getrctl flags + */ +void +prt_rgf(private_t *pri, int raw, long val) +{ + long action = val & (~RCTLSYS_ACTION_MASK); + + if (raw) + prt_hex(pri, 0, val); + else if (action == RCTL_FIRST) + outstring(pri, "RCTL_FIRST"); + else if (action == RCTL_NEXT) + outstring(pri, "RCTL_NEXT"); + else if (action == RCTL_USAGE) + outstring(pri, "RCTL_USAGE"); + else + prt_hex(pri, 0, val); +} + +/* + * Print setrctl flags + */ +void +prt_rsf(private_t *pri, int raw, long val) +{ + long action = val & (~RCTLSYS_ACTION_MASK); + long pval = val & RCTL_LOCAL_ACTION_MASK; + char *s = pri->code_buf; + + if (raw) { + prt_hex(pri, 0, val); + return; + } else if (action == RCTL_INSERT) + (void) strcpy(s, "RCTL_INSERT"); + else if (action == RCTL_DELETE) + (void) strcpy(s, "RCTL_DELETE"); + else if (action == RCTL_REPLACE) + (void) strcpy(s, "RCTL_REPLACE"); + else { + prt_hex(pri, 0, val); + return; + } + + if (pval & RCTL_USE_RECIPIENT_PID) { + pval ^= RCTL_USE_RECIPIENT_PID; + (void) strlcat(s, "|RCTL_USE_RECIPIENT_PID", + sizeof (pri->code_buf)); + } + + if ((pval & RCTLSYS_ACTION_MASK) != 0) + prt_hex(pri, 0, val); + else if (*s != '\0') + outstring(pri, s); + else + prt_hex(pri, 0, val); +} + +/* + * Print rctlctl flags + */ +void +prt_rcf(private_t *pri, int raw, long val) +{ + long action = val & (~RCTLSYS_ACTION_MASK); + + if (raw) + prt_hex(pri, 0, val); + else if (action == RCTLCTL_GET) + outstring(pri, "RCTLCTL_GET"); + else if (action == RCTLCTL_SET) + outstring(pri, "RCTLCTL_SET"); + else + prt_hex(pri, 0, val); +} + +/* + * Print setprojrctl flags + */ +void +prt_spf(private_t *pri, int raw, long val) +{ + long action = val & TASK_PROJ_MASK; + + if (!raw && (action == TASK_PROJ_PURGE)) + outstring(pri, "TASK_PROJ_PURGE"); + else + prt_hex(pri, 0, val); +} + +/* + * Print forkx() flags + */ +void +prt_fxf(private_t *pri, int raw, long val) +{ + char *str; + + if (val == 0) + outstring(pri, "0"); + else if (raw || (val & ~(FORK_NOSIGCHLD | FORK_WAITPID))) + prt_hhx(pri, 0, val); + else { + str = pri->code_buf; + *str = '\0'; + if (val & FORK_NOSIGCHLD) + (void) strlcat(str, "|FORK_NOSIGCHLD", + sizeof (pri->code_buf)); + if (val & FORK_WAITPID) + (void) strlcat(str, "|FORK_WAITPID", + sizeof (pri->code_buf)); + outstring(pri, str + 1); + } +} + +/* + * Print faccessat() flag + */ +void +prt_fat(private_t *pri, int raw, long val) +{ + if (val == 0) + outstring(pri, "0"); + else if (!raw && val == AT_EACCESS) + outstring(pri, "AT_EACCESS"); + else + prt_hex(pri, 0, val); +} + +/* + * Print unlinkat() flag + */ +void +prt_uat(private_t *pri, int raw, long val) +{ + if (val == 0) + outstring(pri, "0"); + else if (!raw && val == AT_REMOVEDIR) + outstring(pri, "AT_REMOVEDIR"); + else + prt_hex(pri, 0, val); +} + +/* + * Print AT_SYMLINK_NOFOLLOW / AT_SYMLINK_FOLLOW flag + */ +void +prt_snf(private_t *pri, int raw, long val) +{ + if (val == 0) + outstring(pri, "0"); + else if (!raw && val == AT_SYMLINK_NOFOLLOW) + outstring(pri, "AT_SYMLINK_NOFOLLOW"); + else if (!raw && val == AT_SYMLINK_FOLLOW) + outstring(pri, "AT_SYMLINK_FOLLOW"); + else + prt_hex(pri, 0, val); +} + +/* + * Array of pointers to print functions, one for each format. + */ +void (* const Print[])() = { + prt_nov, /* NOV -- no value */ + prt_dec, /* DEC -- print value in decimal */ + prt_oct, /* OCT -- print value in octal */ + prt_hex, /* HEX -- print value in hexadecimal */ + prt_dex, /* DEX -- print value in hexadecimal if big enough */ + prt_stg, /* STG -- print value as string */ + prt_ioc, /* IOC -- print ioctl code */ + prt_fcn, /* FCN -- print fcntl code */ + prt_s86, /* S86 -- print sysi86 code */ + prt_uts, /* UTS -- print utssys code */ + prt_opn, /* OPN -- print open code */ + prt_sig, /* SIG -- print signal name plus flags */ + prt_uat, /* UAT -- print unlinkat() flag */ + prt_msc, /* MSC -- print msgsys command */ + prt_msf, /* MSF -- print msgsys flags */ + prt_smc, /* SMC -- print semsys command */ + prt_sef, /* SEF -- print semsys flags */ + prt_shc, /* SHC -- print shmsys command */ + prt_shf, /* SHF -- print shmsys flags */ + prt_fat, /* FAT -- print faccessat( flag */ + prt_sfs, /* SFS -- print sysfs code */ + prt_rst, /* RST -- print string returned by syscall */ + prt_smf, /* SMF -- print streams message flags */ + prt_ioa, /* IOA -- print ioctl argument */ + prt_pip, /* PIP -- print pipe flags */ + prt_mtf, /* MTF -- print mount flags */ + prt_mft, /* MFT -- print mount file system type */ + prt_iob, /* IOB -- print contents of I/O buffer */ + prt_hhx, /* HHX -- print value in hexadecimal (half size) */ + prt_wop, /* WOP -- print waitsys() options */ + prt_spm, /* SPM -- print sigprocmask argument */ + prt_rlk, /* RLK -- print readlink buffer */ + prt_mpr, /* MPR -- print mmap()/mprotect() flags */ + prt_mty, /* MTY -- print mmap() mapping type flags */ + prt_mcf, /* MCF -- print memcntl() function */ + prt_mc4, /* MC4 -- print memcntl() (fourth) argument */ + prt_mc5, /* MC5 -- print memcntl() (fifth) argument */ + prt_mad, /* MAD -- print madvise() argument */ + prt_ulm, /* ULM -- print ulimit() argument */ + prt_rlm, /* RLM -- print get/setrlimit() argument */ + prt_cnf, /* CNF -- print sysconfig() argument */ + prt_inf, /* INF -- print sysinfo() argument */ + prt_ptc, /* PTC -- print pathconf/fpathconf() argument */ + prt_fui, /* FUI -- print fusers() input argument */ + prt_idt, /* IDT -- print idtype_t, waitid() argument */ + prt_lwf, /* LWF -- print lwp_create() flags */ + prt_itm, /* ITM -- print [get|set]itimer() arg */ + prt_llo, /* LLO -- print long long offset arg */ + prt_mod, /* MOD -- print modctl() subcode */ + prt_whn, /* WHN -- print lseek() whence arguiment */ + prt_acl, /* ACL -- print acl() code */ + prt_aio, /* AIO -- print kaio() code */ + prt_aud, /* AUD -- print auditsys() code */ + prt_uns, /* DEC -- print value in unsigned decimal */ + prt_clc, /* CLC -- print cladm command argument */ + prt_clf, /* CLF -- print cladm flag argument */ + prt_cor, /* COR -- print corectl() subcode */ + prt_cco, /* CCO -- print corectl() options */ + prt_ccc, /* CCC -- print corectl() content */ + prt_rcc, /* RCC -- print corectl() returned content */ + prt_cpc, /* CPC -- print cpc() subcode */ + prt_sqc, /* SQC -- print sigqueue() si_code argument */ + prt_pc4, /* PC4 -- print priocntlsys() (fourth) argument */ + prt_pc5, /* PC5 -- print priocntlsys() (key, value) pairs */ + prt_pst, /* PST -- print processor set id */ + prt_mif, /* MIF -- print meminfo() arguments */ + prt_pfm, /* PFM -- print so_socket() proto-family (1st) arg */ + prt_skt, /* SKT -- print so_socket() socket-type (2nd) arg */ + prt_skp, /* SKP -- print so_socket() protocol (3rd) arg */ + prt_skv, /* SKV -- print socket version arg */ + prt_sol, /* SOL -- print [sg]etsockopt() level (2nd) arg */ + prt_son, /* SON -- print [sg]etsockopt() opt-name (3rd) arg */ + prt_utt, /* UTT -- print utrap type */ + prt_uth, /* UTH -- print utrap handler */ + prt_acc, /* ACC -- print access() flags */ + prt_sht, /* SHT -- print shutdown() how (2nd) argument */ + prt_ffg, /* FFG -- print fcntl() flags (3rd) argument */ + prt_prs, /* PRS -- print privilege set */ + prt_pro, /* PRO -- print privilege set operation */ + prt_prn, /* PRN -- print privilege set name */ + prt_pfl, /* PFL -- print privilege/process flag name */ + prt_laf, /* LAF -- print lgrp_affinity arguments */ + prt_key, /* KEY -- print key_t 0 as IPC_PRIVATE */ + prt_zga, /* ZGA -- print zone_getattr attribute types */ + prt_atc, /* ATC -- print AT_FDCWD or file descriptor */ + prt_lio, /* LIO -- print LIO_XX flags */ + prt_dfl, /* DFL -- print door_create() flags */ + prt_dpm, /* DPM -- print DOOR_PARAM_XX flags */ + prt_tnd, /* TND -- print trusted network data base opcode */ + prt_rsc, /* RSC -- print rctlsys() subcodes */ + prt_rgf, /* RGF -- print getrctl() flags */ + prt_rsf, /* RSF -- print setrctl() flags */ + prt_rcf, /* RCF -- print rctlsys_ctl() flags */ + prt_fxf, /* FXF -- print forkx() flags */ + prt_spf, /* SPF -- print rctlsys_projset() flags */ + prt_un1, /* UN1 -- as prt_uns except for -1 */ + prt_mob, /* MOB -- print mmapobj() flags */ + prt_snf, /* SNF -- print AT_SYMLINK_[NO]FOLLOW flag */ + prt_skc, /* SKC -- print sockconfig() subcode */ + prt_acf, /* ACF -- print accept4 flags */ + prt_pfd, /* PFD -- print pipe fds */ + prt_dec, /* HID -- hidden argument, make this the last one */ +}; diff --git a/usr/src/cmd/truss/print.h b/usr/src/cmd/truss/print.h new file mode 100644 index 0000000..9a9a43b --- /dev/null +++ b/usr/src/cmd/truss/print.h @@ -0,0 +1,154 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* Copyright (c) 2013, OmniTI Computer Consulting, Inc. All right reserved. */ + +#ifndef _TRUSS_PRINT_H +#define _TRUSS_PRINT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Argument & return value print codes. + */ +#define NOV 0 /* no value */ +#define DEC 1 /* print value in decimal */ +#define OCT 2 /* print value in octal */ +#define HEX 3 /* print value in hexadecimal */ +#define DEX 4 /* print value in hexadecimal if big enough */ +#define STG 5 /* print value as string */ +#define IOC 6 /* print ioctl code */ +#define FCN 7 /* print fcntl code */ +#define S86 8 /* print sysi86 code */ +#define UTS 9 /* print utssys code */ +#define OPN 10 /* print open code */ +#define SIG 11 /* print signal name plus flags */ +#define UAT 12 /* print unlinkat() flag */ +#define MSC 13 /* print msgsys command */ +#define MSF 14 /* print msgsys flags */ +#define SMC 15 /* print semsys command */ +#define SEF 16 /* print semsys flags */ +#define SHC 17 /* print shmsys command */ +#define SHF 18 /* print shmsys flags */ +#define FAT 19 /* print faccessat() flag */ +#define SFS 20 /* print sysfs code */ +#define RST 21 /* print string returned by sys call */ +#define SMF 22 /* print streams message flags */ +#define IOA 23 /* print ioctl argument */ +#define PIP 24 /* print pipe flags */ +#define MTF 25 /* print mount flags */ +#define MFT 26 /* print mount file system type */ +#define IOB 27 /* print contents of I/O buffer */ +#define HHX 28 /* print value in hexadecimal (half size) */ +#define WOP 29 /* print waitsys() options */ +#define SPM 30 /* print sigprocmask argument */ +#define RLK 31 /* print readlink buffer */ +#define MPR 32 /* print mmap()/mprotect() flags */ +#define MTY 33 /* print mmap() mapping type flags */ +#define MCF 34 /* print memcntl() function */ +#define MC4 35 /* print memcntl() (fourth) argument */ +#define MC5 36 /* print memcntl() (fifth) argument */ +#define MAD 37 /* print madvise() argument */ +#define ULM 38 /* print ulimit() argument */ +#define RLM 39 /* print get/setrlimit() argument */ +#define CNF 40 /* print sysconfig() argument */ +#define INF 41 /* print sysinfo() argument */ +#define PTC 42 /* print pathconf/fpathconf() argument */ +#define FUI 43 /* print fusers() input argument */ +#define IDT 44 /* print idtype_t, waitid() argument */ +#define LWF 45 /* print lwp_create() flags */ +#define ITM 46 /* print [get|set]itimer() arg */ +#define LLO 47 /* print long long offset */ +#define MOD 48 /* print modctl() code */ +#define WHN 49 /* print lseek() whence argument */ +#define ACL 50 /* print acl() code */ +#define AIO 51 /* print kaio() code */ +#define AUD 52 /* print auditsys() code */ +#define UNS 53 /* print value in unsigned decimal */ +#define CLC 54 /* print cladm() command argument */ +#define CLF 55 /* print cladm() flag argument */ +#define COR 56 /* print corectl() subcode */ +#define CCO 57 /* print corectl() options */ +#define CCC 58 /* print corectl() content */ +#define RCC 59 /* print corectl() content */ +#define CPC 60 /* print cpc() subcode */ +#define SQC 61 /* print sigqueue() si_code argument */ +#define PC4 62 /* print priocntlsys() (fourth) argument */ +#define PC5 63 /* print priocntlsys() (key-value) pairs */ +#define PST 64 /* print processor set id */ +#define MIF 65 /* print meminfo() argument */ +#define PFM 66 /* print so_socket() proto-family (1st) arg */ +#define SKT 67 /* print so_socket() socket type (2nd) arg */ +#define SKP 68 /* print so_socket() protocol (3rd) arg */ +#define SKV 69 /* print so_socket() version (5th) arg */ +#define SOL 70 /* print [sg]etsockopt() level (2nd) arg */ +#define SON 71 /* print [sg]etsockopt() name (3rd) arg */ +#define UTT 72 /* print utrap type */ +#define UTH 73 /* print utrap handler */ +#define ACC 74 /* print access flags */ +#define SHT 75 /* print shutdown() "how" (2nd) arg */ +#define FFG 76 /* print fcntl() flags (3rd) arg */ +#define PRS 77 /* privilege set */ +#define PRO 78 /* privilege set operation */ +#define PRN 79 /* privilege set name */ +#define PFL 80 /* privilege/process flag name */ +#define LAF 81 /* print lgrp_affinity arguments */ +#define KEY 82 /* print key_t 0 as IPC_PRIVATE */ +#define ZGA 83 /* print zone_getattr attribute types */ +#define ATC 84 /* print AT_FDCWD or file descriptor */ +#define LIO 85 /* print LIO_XX flags */ +#define DFL 86 /* print door_create() flags */ +#define DPM 87 /* print DOOR_PARAM_XX flags */ +#define TND 88 /* print trusted network data base opcode */ +#define RSC 89 /* print rctlsys subcode */ +#define RGF 90 /* print rctlsys_get flags */ +#define RSF 91 /* print rctlsys_set flags */ +#define RCF 92 /* print rctlsys_ctl flags */ +#define FXF 93 /* print forkx flags */ +#define SPF 94 /* print rctlsys_projset flags */ +#define UN1 95 /* unsigned except for -1 */ +#define MOB 96 /* print mmapobj() flags */ +#define SNF 97 /* print AT_SYMLINK_[NO]FOLLOW flag */ +#define SKC 98 /* print sockconfig subcode */ +#define ACF 99 /* accept4 flags */ +#define PFD 100 /* pipe fds[2] */ +#define HID 101 /* hidden argument, don't print */ + /* make sure HID is always the last member */ + +/* + * Print routines, indexed by print codes. + */ +extern void (* const Print[])(); + +#ifdef __cplusplus +} +#endif + +#endif /* _TRUSS_PRINT_H */ diff --git a/usr/src/cmd/truss/procset.c b/usr/src/cmd/truss/procset.c new file mode 100644 index 0000000..4ba72bd --- /dev/null +++ b/usr/src/cmd/truss/procset.c @@ -0,0 +1,137 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 + * or http://www.opensolaris.org/os/licensing. + * 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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <libproc.h> +#include "ramdata.h" +#include "proto.h" + +/* + * Function prototypes for static routines in this module. + */ +const char *idop_enum(private_t *, idop_t); + +void +show_procset(private_t *pri, long offset) +{ + procset_t procset; + procset_t *psp = &procset; + + if (Pread(Proc, psp, sizeof (*psp), offset) == sizeof (*psp)) { + (void) printf("%s\top=%s", + pri->pname, idop_enum(pri, psp->p_op)); + (void) printf(" ltyp=%s lid=%ld", + idtype_enum(pri, psp->p_lidtype), (long)psp->p_lid); + (void) printf(" rtyp=%s rid=%ld\n", + idtype_enum(pri, psp->p_ridtype), (long)psp->p_rid); + } +} + +const char * +idop_enum(private_t *pri, idop_t arg) +{ + const char *str; + + switch (arg) { + case POP_DIFF: str = "POP_DIFF"; break; + case POP_AND: str = "POP_AND"; break; + case POP_OR: str = "POP_OR"; break; + case POP_XOR: str = "POP_XOR"; break; + default: + (void) sprintf(pri->code_buf, "%d", arg); + str = (const char *)pri->code_buf; + break; + } + + return (str); +} + +const char * +idtype_enum(private_t *pri, long arg) +{ + const char *str; + + switch (arg) { + case P_PID: str = "P_PID"; break; + case P_PPID: str = "P_PPID"; break; + case P_PGID: str = "P_PGID"; break; + case P_SID: str = "P_SID"; break; + case P_CID: str = "P_CID"; break; + case P_UID: str = "P_UID"; break; + case P_GID: str = "P_GID"; break; + case P_ALL: str = "P_ALL"; break; + case P_LWPID: str = "P_LWPID"; break; + case P_TASKID: str = "P_TASKID"; break; + case P_PROJID: str = "P_PROJID"; break; + case P_ZONEID: str = "P_ZONEID"; break; + case P_CTID: str = "P_CTID"; break; + default: + (void) sprintf(pri->code_buf, "%ld", arg); + str = (const char *)pri->code_buf; + break; + } + + return (str); +} + +const char * +woptions(private_t *pri, int arg) +{ + char *str = pri->code_buf; + + if (arg == 0) + return ("0"); + if (arg & + ~(WEXITED|WTRAPPED|WSTOPPED|WCONTINUED|WNOHANG|WNOWAIT)) + return (NULL); + + *str = '\0'; + if (arg & WEXITED) + (void) strcat(str, "|WEXITED"); + if (arg & WTRAPPED) + (void) strcat(str, "|WTRAPPED"); + if (arg & WSTOPPED) + (void) strcat(str, "|WSTOPPED"); + if (arg & WCONTINUED) + (void) strcat(str, "|WCONTINUED"); + if (arg & WNOHANG) + (void) strcat(str, "|WNOHANG"); + if (arg & WNOWAIT) + (void) strcat(str, "|WNOWAIT"); + + return ((const char *)(str+1)); +} diff --git a/usr/src/cmd/truss/proto.h b/usr/src/cmd/truss/proto.h new file mode 100644 index 0000000..670fe95 --- /dev/null +++ b/usr/src/cmd/truss/proto.h @@ -0,0 +1,154 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#ifndef _PROTO_H +#define _PROTO_H + +#include <sys/procset.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* avoid a bit of stdio locking */ +#define fputc putc_unlocked + +/* force (via setvbuf()) a reasonably large output file buffer size */ +#define MYBUFSIZ 8192 + +/* + * Function prototypes for most external functions. + */ + +extern private_t *get_private(void); +extern void *my_malloc(size_t, const char *); +extern void *my_realloc(void *, size_t, const char *); +extern void *my_calloc(size_t, size_t, const char *); +extern void make_pname(private_t *, id_t); +extern int requested(private_t *, int, int); +extern int jobcontrol(private_t *, int); +extern int signalled(private_t *, int, int); +extern int faulted(private_t *, int); +extern int sysentry(private_t *, int); +extern int sysexit(private_t *, int); +extern void showbuffer(private_t *, long, long); +extern void showbytes(const char *, int, char *); +extern void accumulate(timestruc_t *, + const timestruc_t *, const timestruc_t *); + +extern const char *ioctlname(private_t *, uint_t); +extern const char *ioctldatastruct(uint_t); +extern const char *fcntlname(int); +extern const char *sfsname(int); +extern const char *si86name(int); +extern const char *utscode(int); +extern const char *openarg(private_t *, int); +extern const char *whencearg(int); +extern const char *msgflags(private_t *, int); +extern const char *semflags(private_t *, int); +extern const char *shmflags(private_t *, int); +extern const char *msgcmd(int); +extern const char *semcmd(int); +extern const char *shmcmd(int); +extern const char *strrdopt(int); +extern const char *strevents(private_t *, int); +extern const char *tiocflush(private_t *, int); +extern const char *strflush(int); +extern const char *mountflags(private_t *, int); +extern const char *svfsflags(private_t *, ulong_t); +extern const char *sconfname(int); +extern const char *pathconfname(int); +extern const char *fuiname(int); +extern const char *fuflags(private_t *, int); +extern const char *ipprotos(int); +extern const char *rctlsyscode(int); +extern const char *rctl_local_flags(private_t *, uint_t val); +extern const char *rctl_local_action(private_t *, uint_t val); + +extern void expound(private_t *, long, int); +extern void prtimestruc(private_t *, const char *, timestruc_t *); +extern void print_siginfo(private_t *, const siginfo_t *); + +extern void Flush(void); +extern void Eserialize(void); +extern void Xserialize(void); +extern void procadd(pid_t, const char *lwplist); +extern int lwptrace(pid_t, lwpid_t); +extern void procdel(void); +extern int checkproc(private_t *); + +extern int syslist(char *, sysset_t *, int *); +extern int siglist(private_t *, char *, sigset_t *, int *); +extern int fltlist(char *, fltset_t *, int *); +extern int fdlist(char *, fileset_t *); +extern int liblist(char *, int); + +extern char *fetchstring(private_t *, long, int); +extern void show_cred(private_t *, int, int); +extern void errmsg(const char *, const char *); +extern void abend(const char *, const char *); + +extern void outstring(private_t *, const char *); +extern void grow(private_t *, int); + +extern void show_procset(private_t *, long); +extern const char *idtype_enum(private_t *, long); +extern const char *woptions(private_t *, int); + +extern void putpname(private_t *); +extern void timestamp(private_t *); + +extern const char *errname(int); +extern const char *sysname(private_t *, int, int); +extern const char *rawsigname(private_t *, int); +extern const char *signame(private_t *, int); + +extern int getsubcode(private_t *); +extern int maxsyscalls(void); +extern int nsubcodes(int); + +extern void show_stat(private_t *, long); +extern void show_stat64_32(private_t *, long); + +extern void establish_breakpoints(void); +extern void establish_stacks(void); +extern void reset_breakpoints(void); +extern void clear_breakpoints(void); +extern int function_trace(private_t *, int, int, int); +extern void reestablish_traps(void); +extern void report_htable_stats(void); + +extern const char *door_flags(private_t *, long); +extern void prt_ffg(private_t *, int, long); +extern void escape_string(private_t *, const char *); + +#ifdef __cplusplus +} +#endif + +#endif /* _PROTO_H */ diff --git a/usr/src/cmd/truss/ramdata.c b/usr/src/cmd/truss/ramdata.c new file mode 100644 index 0000000..abb8ee2 --- /dev/null +++ b/usr/src/cmd/truss/ramdata.c @@ -0,0 +1,137 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <libproc.h> +#include "ramdata.h" +#include "proto.h" +#include "htbl.h" + +/* + * ramdata.c -- read/write data definitions are collected here. + * Default initialization of zero applies in all cases. + */ + +thread_key_t private_key; /* set by thr_keycreate() */ +char *command; /* name of command ("truss") */ +int interrupt; /* interrupt signal was received */ +int sigusr1; /* received SIGUSR1 (release process) */ +int sfd; /* shared tmp file descriptor */ +pid_t created; /* if process was created, its process id */ +uid_t Euid; /* truss's effective uid */ +uid_t Egid; /* truss's effective gid */ +uid_t Ruid; /* truss's real uid */ +uid_t Rgid; /* truss's real gid */ +prcred_t credentials; /* traced process credentials */ +prpriv_t *privdata; /* traced process privileges */ +int istty; /* TRUE iff output is a tty */ +time_t starttime; /* start time */ + +int Fflag; /* option flags from getopt() */ +int fflag; +int cflag; +int aflag; +int eflag; +int iflag; +int lflag; +int tflag; +int pflag; +int sflag; +int mflag; +int oflag; +int vflag; +int xflag; +int hflag; + +int dflag; +int Dflag; +int Eflag; +int Tflag; +int Sflag; +int Mflag; + +sysset_t trace; /* sys calls to trace */ +sysset_t traceeven; /* sys calls to trace even if not reported */ +sysset_t verbose; /* sys calls to be verbose about */ +sysset_t rawout; /* sys calls to show in raw mode */ +sigset_t signals; /* signals to trace */ +fltset_t faults; /* faults to trace */ +fileset_t readfd; /* read() file descriptors to dump */ +fileset_t writefd; /* write() file descriptors to dump */ + +mutex_t truss_lock; /* protects almost everything */ +cond_t truss_cv; +mutex_t count_lock; /* lock protecting count struct Cp */ + +htbl_t *fcall_tbl; /* ptr to hash tbl counting function calls */ + +int truss_nlwp; /* number of truss lwps */ +int truss_maxlwp; /* number of entries in truss_lwpid */ +lwpid_t *truss_lwpid; /* array of truss lwpid's */ + +struct counts *Cp; /* for counting: malloc() or shared memory */ +struct global_psinfo *gps; /* contains global process information */ + +struct dynlib *Dynlib; /* for tracing functions in shared libraries */ +struct dynpat *Dynpat; +struct dynpat *Lastpat; +struct bkpt **bpt_hashtable; /* breakpoint hash table */ +uint_t nthr_create; /* number of thr_create() calls seen so far */ +struct callstack *callstack; /* the callstack array */ +uint_t nstack; /* number of detected stacks */ +rd_agent_t *Rdb_agent; /* run-time linker debug handle */ +td_thragent_t *Thr_agent; /* thread debug handle */ +int not_consist; /* used while rebuilding breakpoint table */ +int delete_library; /* used while rebuilding breakpoint table */ + +pid_t ancestor; /* top-level parent process id */ +int descendent; /* TRUE iff descendent of top level */ +int is_vfork_child; /* TRUE iff process is a vfork()ed child */ + +int ngrab; /* number of pid's that were grabbed */ + +struct ps_prochandle *Proc; /* global reference to process */ +int data_model; /* PR_MODEL_LP64 or PR_MODEL_ILP32 */ + +long pagesize; /* bytes per page; should be per-process */ + +int exit_called; /* _exit() syscall was seen */ + +lwpid_t primary_lwp; /* representative lwp on process grab */ + +sysset_t syshang; /* sys calls to make process hang */ +sigset_t sighang; /* signals to make process hang */ +fltset_t flthang; /* faults to make process hang */ + +sigset_t emptyset; /* no signals, for thr_sigsetmask() */ +sigset_t fillset; /* all signals, for thr_sigsetmask() */ + +int leave_hung; /* if TRUE, leave the process hung */ diff --git a/usr/src/cmd/truss/ramdata.h b/usr/src/cmd/truss/ramdata.h new file mode 100644 index 0000000..7884228 --- /dev/null +++ b/usr/src/cmd/truss/ramdata.h @@ -0,0 +1,317 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#ifndef _RAMDATA_H +#define _RAMDATA_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * ramdata.h -- read/write data declarations. + */ + +#include <errno.h> +#include <signal.h> +#include <synch.h> +#include <thread.h> +#include <thread_db.h> +#include "htbl.h" + +/* + * Set type for possible filedescriptors. + */ +#define NOFILES_MAX (64 * 1024) +typedef struct { + uint32_t word[(NOFILES_MAX+31)/32]; +} fileset_t; + +/* + * Previous stop state enumeration (used by signalled() and requested()). + */ +#define SLEEPING 1 +#define JOBSIG 2 +#define JOBSTOP 3 + +/* + * Simple convenience. + */ +#ifdef TRUE +#undef TRUE +#endif +#ifdef FALSE +#undef FALSE +#endif +#define TRUE 1 +#define FALSE 0 + +/* + * Definition of private data. See get_private(). + */ + +#define IOBSIZE 12 /* number of bytes shown by prt_iob() */ + +#define CACHE_LN_SZ 64 + +typedef struct private { + struct ps_lwphandle *Lwp; /* non-NULL for each lwp controller */ + const lwpstatus_t *lwpstat; /* lwp status information while stopped */ + int length; /* length of printf() output so far */ + pid_t child; /* pid of fork()ed child process */ + char pname[32]; /* formatted pid/tid of controlled lwp */ + struct { /* remembered parameters for make_pname() */ + int ff; + int lf; + pid_t pid; + id_t lwpid; + id_t tid; + } pparam; + int Errno; /* errno for controlled process's syscall */ + int ErrPriv; /* privilege missing for last syscall */ + long Rval1; /* rval1 (%r0) for syscall */ + long Rval2; /* rval2 (%r1) for syscall */ + timestruc_t syslast; /* most recent value of stime */ + timestruc_t usrlast; /* most recent value of utime */ + long sys_args[9]; /* the arguments to the last syscall */ + int sys_nargs; /* number of arguments to the last syscall */ + int sys_indirect; /* if TRUE, this is an indirect system call */ + char sys_name[12]; /* name of unknown system call */ + char raw_sig_name[SIG2STR_MAX+4]; /* name of known signal */ + char sig_name[12]; /* name of unknown signal */ + char flt_name[12]; /* name of unknown fault */ + char *sys_path; /* pathname given to syscall */ + size_t sys_psize; /* sizeof(*sys_path) */ + int sys_valid; /* pathname was fetched and is valid */ + char *sys_string; /* buffer for formatted syscall string */ + size_t sys_ssize; /* sizeof(*sys_string) */ + size_t sys_leng; /* strlen(sys_string) */ + char *exec_string; /* copy of sys_string for exec() only */ + char exec_pname[32]; /* formatted pid for exec() only */ + id_t exec_lwpid; /* lwpid that performed the exec */ + char *str_buffer; /* fetchstring() buffer */ + size_t str_bsize; /* sizeof(*str_buffer) */ + char iob_buf[2*IOBSIZE+8]; /* where prt_iob() leaves its stuff */ + char code_buf[160]; /* for symbolic arguments, e.g., ioctl codes */ + int recur; /* show_strioctl() -- to prevent recursion */ + int seconds; /* seconds, fraction for timestamps */ + int fraction; /* fraction in 1/10 milliseconds */ +} private_t; + +extern thread_key_t private_key; /* set by thr_keycreate() */ + +extern char *command; /* name of command ("truss") */ +extern int interrupt; /* interrupt signal was received */ +extern int sigusr1; /* received SIGUSR1 (release process) */ +extern int sfd; /* file descriptor to shared tmp file */ +extern pid_t created; /* if process was created, its process id */ +extern uid_t Euid; /* truss's effective uid */ +extern uid_t Egid; /* truss's effective gid */ +extern uid_t Ruid; /* truss's real uid */ +extern uid_t Rgid; /* truss's real gid */ +extern prcred_t credentials; /* traced process credentials */ +extern prpriv_t *privdata; /* traced process privileges */ +extern int istty; /* TRUE iff output is a tty */ +extern time_t starttime; /* start time */ + +extern int Fflag; /* option flags from getopt() */ +extern int fflag; +extern int cflag; +extern int aflag; +extern int eflag; +extern int iflag; +extern int lflag; +extern int tflag; +extern int pflag; +extern int sflag; +extern int mflag; +extern int oflag; +extern int vflag; +extern int xflag; +extern int hflag; + +extern int dflag; +extern int Dflag; +extern int Eflag; +extern int Tflag; +extern int Sflag; +extern int Mflag; + +extern sysset_t trace; /* sys calls to trace */ +extern sysset_t traceeven; /* sys calls to trace even if not reported */ +extern sysset_t verbose; /* sys calls to be verbose about */ +extern sysset_t rawout; /* sys calls to show in raw mode */ +extern sigset_t signals; /* signals to trace */ +extern fltset_t faults; /* faults to trace */ +extern fileset_t readfd; /* read() file descriptors to dump */ +extern fileset_t writefd; /* write() file descriptors to dump */ + +#pragma align CACHE_LN_SZ(truss_lock, count_lock) +extern mutex_t truss_lock; /* protects almost everything */ +extern cond_t truss_cv; /* condition variable associated w truss_lock */ +extern mutex_t count_lock; /* lock protecting count struct Cp */ + +extern htbl_t *fcall_tbl; /* function call hash table (per-proc) */ + +extern int truss_nlwp; /* number of truss lwps */ +extern int truss_maxlwp; /* number of entries in truss_lwpid */ +extern lwpid_t *truss_lwpid; /* array of truss lwpid's */ + + +struct syscount { + long count; /* system call count */ + long error; /* system call errors */ + timestruc_t stime; /* time spent in system call */ +}; + +struct counts { /* structure for keeping counts */ + long sigcount[PRMAXSIG+1]; /* signals count [0..PRMAXSIG] */ + long fltcount[PRMAXFAULT+1]; /* faults count [0..MAXFAULT] */ + struct syscount *syscount[PRMAXSYS+1]; + timestruc_t systotal; /* total time spent in kernel */ + timestruc_t usrtotal; /* total time spent in user mode */ + timestruc_t basetime; /* base time for timestamps */ +}; + +struct global_psinfo { + mutex_t fork_lock; /* protects list of truss pids */ + cond_t fork_cv; + char p1[CACHE_LN_SZ - (sizeof (mutex_t) + sizeof (cond_t))]; + mutex_t ps_mutex0; /* see ipc.c:Ecritical */ + char p2[CACHE_LN_SZ - sizeof (mutex_t)]; + mutex_t ps_mutex1; /* see ipc.c:Ecritical */ + char p3[CACHE_LN_SZ - sizeof (mutex_t)]; + pid_t fork_pid; + pid_t tpid[1000]; /* truss process pid */ + pid_t spid[1000]; /* subject process pid */ + const char *lwps[1000]; /* optional lwp list */ +}; + +extern struct counts *Cp; /* for counting: malloc() or shared memory */ +extern struct global_psinfo *gps; /* ptr to global_psinfo struct */ + +struct bkpt { /* to describe one function's entry point */ + struct bkpt *next; /* hash table linked list */ + char *sym_name; /* function name */ + struct dynlib *dyn; /* enclosing library */ + uintptr_t addr; /* function address, breakpointed */ + ulong_t instr; /* original instruction at addr */ + int flags; /* see below */ +}; +#define BPT_HANG 0x01 /* leave stopped and abandoned when called */ +#define BPT_EXCLUDE 0x02 /* function found but is being excluded */ +#define BPT_INTERNAL 0x04 /* trace internal calls on this function */ +#define BPT_ACTIVE 0x08 /* function breakpoint is set in process */ +#define BPT_PREINIT 0x10 /* PREINIT event in ld.so.1 */ +#define BPT_POSTINIT 0x20 /* POSTINIT event in ld.so.1 */ +#define BPT_DLACTIVITY 0x40 /* DLACTIVITY event in ld.so.1 */ +#define BPT_TD_CREATE 0x80 /* TD_CREATE threading event */ + +struct dynlib { /* structure for tracing functions */ + struct dynlib *next; + char *lib_name; /* full library name */ + char *match_name; /* library name used in name matching */ + char *prt_name; /* library name for printing */ + int built; /* if true, bkpt list has been built */ + int present; /* true if library is still present */ + uintptr_t base; /* library's mapping base */ + size_t size; /* library's mapping size */ +}; + +struct dynpat { /* structure specifying patterns for dynlib's */ + struct dynpat *next; + const char **libpat; /* array of patterns for library names */ + const char **sympat; /* array of patterns for symbol names */ + int nlibpat; /* number of library patterns */ + int nsympat; /* number of symbol patterns */ + char flag; /* 0 or BPT_HANG */ + char exclude_lib; /* if true, exclude these libraries */ + char exclude; /* if true, exclude these functions */ + char internal; /* if true, trace internal calls */ + struct dynlib *Dp; /* set to the dynlib instance when searching */ +}; + +extern struct dynlib *Dynlib; /* for tracing functions in shared libraries */ +extern struct dynpat *Dynpat; +extern struct dynpat *Lastpat; +extern struct bkpt **bpt_hashtable; /* breakpoint hash table */ +extern uint_t nthr_create; /* number of thr_create() calls seen so far */ + +struct callstack { + struct callstack *next; + uintptr_t stkbase; /* stkbase < stkend */ + uintptr_t stkend; /* stkend == base + size */ + prgreg_t tref; /* %g7 (sparc) or %gs (intel) */ + id_t tid; /* thread-id */ + uint_t nthr_create; /* value of nthr_create last time we looked */ + uint_t ncall; /* number of elements in stack */ + uint_t maxcall; /* max elements in stack (malloc'd) */ + struct { + uintptr_t sp; /* %sp for function call */ + uintptr_t pc; /* value of the return %pc */ + struct bkpt *fcn; /* name of function called */ + } *stack; /* pointer to the call stack info */ +}; + +extern struct callstack *callstack; /* the callstack list */ +extern uint_t nstack; /* number of detected stacks */ +extern rd_agent_t *Rdb_agent; /* run-time linker debug handle */ +extern td_thragent_t *Thr_agent; /* thread debug handle */ +extern int not_consist; /* used while rebuilding breakpoint table */ +extern int delete_library; /* used while rebuilding breakpoint table */ + +extern pid_t ancestor; /* top-level parent process id */ +extern int descendent; /* TRUE iff descendent of top level */ +extern int is_vfork_child; /* TRUE iff process is a vfork()ed child */ + +extern int ngrab; /* number of pid's that were grabbed */ + +extern struct ps_prochandle *Proc; /* global reference to process */ +extern int data_model; /* PR_MODEL_LP64 or PR_MODEL_ILP32 */ + +extern long pagesize; /* bytes per page; should be per-process */ + +extern int exit_called; /* _exit() syscall was seen */ + +extern lwpid_t primary_lwp; /* representative lwp on process grab */ + +extern sysset_t syshang; /* sys calls to make process hang */ +extern sigset_t sighang; /* signals to make process hang */ +extern fltset_t flthang; /* faults to make process hang */ + +extern sigset_t emptyset; /* no signals, for thr_sigsetmask() */ +extern sigset_t fillset; /* all signals, for thr_sigsetmask() */ + +extern int leave_hung; /* if TRUE, leave the process hung */ + + +#ifdef __cplusplus +} +#endif + +#endif /* _RAMDATA_H */ diff --git a/usr/src/cmd/truss/stat.c b/usr/src/cmd/truss/stat.c new file mode 100644 index 0000000..f5ecab0 --- /dev/null +++ b/usr/src/cmd/truss/stat.c @@ -0,0 +1,192 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#define _SYSCALL32 + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/signal.h> +#include <sys/fault.h> +#include <sys/syscall.h> +#include <libproc.h> +#include "ramdata.h" +#include "proto.h" + +void show_stat32(private_t *, long); +#ifdef _LP64 +void show_stat64(private_t *, long); +#endif + +void +show_stat(private_t *pri, long offset) +{ +#ifdef _LP64 + if (data_model == PR_MODEL_LP64) + show_stat64(pri, offset); + else + show_stat32(pri, offset); +#else + show_stat32(pri, offset); +#endif +} + +void +show_stat32(private_t *pri, long offset) +{ + struct stat32 statb; + timestruc_t ts; + + if (offset != NULL && + Pread(Proc, &statb, sizeof (statb), offset) == sizeof (statb)) { + (void) printf( + "%s d=0x%.8X i=%-5u m=0%.6o l=%-2u u=%-5u g=%-5u", + pri->pname, + statb.st_dev, + statb.st_ino, + statb.st_mode, + statb.st_nlink, + statb.st_uid, + statb.st_gid); + + switch (statb.st_mode & S_IFMT) { + case S_IFCHR: + case S_IFBLK: + (void) printf(" rdev=0x%.8X\n", statb.st_rdev); + break; + default: + (void) printf(" sz=%u\n", statb.st_size); + break; + } + + TIMESPEC32_TO_TIMESPEC(&ts, &statb.st_atim); + prtimestruc(pri, "at = ", &ts); + TIMESPEC32_TO_TIMESPEC(&ts, &statb.st_mtim); + prtimestruc(pri, "mt = ", &ts); + TIMESPEC32_TO_TIMESPEC(&ts, &statb.st_ctim); + prtimestruc(pri, "ct = ", &ts); + + (void) printf( + "%s bsz=%-5d blks=%-5d fs=%.*s\n", + pri->pname, + statb.st_blksize, + statb.st_blocks, + _ST_FSTYPSZ, + statb.st_fstype); + } +} + +void +show_stat64_32(private_t *pri, long offset) +{ + struct stat64_32 statb; + timestruc_t ts; + + if (offset != NULL && + Pread(Proc, &statb, sizeof (statb), offset) == sizeof (statb)) { + (void) printf( + "%s d=0x%.8X i=%-5llu m=0%.6o l=%-2u u=%-5u g=%-5u", + pri->pname, + statb.st_dev, + (u_longlong_t)statb.st_ino, + statb.st_mode, + statb.st_nlink, + statb.st_uid, + statb.st_gid); + + switch (statb.st_mode & S_IFMT) { + case S_IFCHR: + case S_IFBLK: + (void) printf(" rdev=0x%.8X\n", statb.st_rdev); + break; + default: + (void) printf(" sz=%llu\n", (long long)statb.st_size); + break; + } + + TIMESPEC32_TO_TIMESPEC(&ts, &statb.st_atim); + prtimestruc(pri, "at = ", &ts); + TIMESPEC32_TO_TIMESPEC(&ts, &statb.st_mtim); + prtimestruc(pri, "mt = ", &ts); + TIMESPEC32_TO_TIMESPEC(&ts, &statb.st_ctim); + prtimestruc(pri, "ct = ", &ts); + + (void) printf("%s bsz=%-5d blks=%-5lld fs=%.*s\n", + pri->pname, + statb.st_blksize, + (longlong_t)statb.st_blocks, + _ST_FSTYPSZ, + statb.st_fstype); + } +} + +#ifdef _LP64 +void +show_stat64(private_t *pri, long offset) +{ + struct stat64 statb; + + if (offset != NULL && + Pread(Proc, &statb, sizeof (statb), offset) == sizeof (statb)) { + (void) printf( + "%s d=0x%.16lX i=%-5lu m=0%.6o l=%-2u u=%-5u g=%-5u", + pri->pname, + statb.st_dev, + statb.st_ino, + statb.st_mode, + statb.st_nlink, + statb.st_uid, + statb.st_gid); + + switch (statb.st_mode & S_IFMT) { + case S_IFCHR: + case S_IFBLK: + (void) printf(" rdev=0x%.16lX\n", statb.st_rdev); + break; + default: + (void) printf(" sz=%lu\n", statb.st_size); + break; + } + + prtimestruc(pri, "at = ", (timestruc_t *)&statb.st_atim); + prtimestruc(pri, "mt = ", (timestruc_t *)&statb.st_mtim); + prtimestruc(pri, "ct = ", (timestruc_t *)&statb.st_ctim); + + (void) printf( + "%s bsz=%-5d blks=%-5ld fs=%.*s\n", + pri->pname, + statb.st_blksize, + statb.st_blocks, + _ST_FSTYPSZ, + statb.st_fstype); + } +} +#endif /* _LP64 */ diff --git a/usr/src/cmd/truss/systable.c b/usr/src/cmd/truss/systable.c new file mode 100644 index 0000000..3cd07c6 --- /dev/null +++ b/usr/src/cmd/truss/systable.c @@ -0,0 +1,1736 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. */ + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <sys/types.h> +#include <libproc.h> +#include <sys/aio.h> +#include <sys/port_impl.h> +#include "ramdata.h" +#include "systable.h" +#include "print.h" +#include "proto.h" + +/* + * Tables of information about system calls - read-only data. + */ + +const char *const errcode[] = { /* error code names */ + NULL, /* 0 */ + "EPERM", /* 1 */ + "ENOENT", /* 2 */ + "ESRCH", /* 3 */ + "EINTR", /* 4 */ + "EIO", /* 5 */ + "ENXIO", /* 6 */ + "E2BIG", /* 7 */ + "ENOEXEC", /* 8 */ + "EBADF", /* 9 */ + "ECHILD", /* 10 */ + "EAGAIN", /* 11 */ + "ENOMEM", /* 12 */ + "EACCES", /* 13 */ + "EFAULT", /* 14 */ + "ENOTBLK", /* 15 */ + "EBUSY", /* 16 */ + "EEXIST", /* 17 */ + "EXDEV", /* 18 */ + "ENODEV", /* 19 */ + "ENOTDIR", /* 20 */ + "EISDIR", /* 21 */ + "EINVAL", /* 22 */ + "ENFILE", /* 23 */ + "EMFILE", /* 24 */ + "ENOTTY", /* 25 */ + "ETXTBSY", /* 26 */ + "EFBIG", /* 27 */ + "ENOSPC", /* 28 */ + "ESPIPE", /* 29 */ + "EROFS", /* 30 */ + "EMLINK", /* 31 */ + "EPIPE", /* 32 */ + "EDOM", /* 33 */ + "ERANGE", /* 34 */ + "ENOMSG", /* 35 */ + "EIDRM", /* 36 */ + "ECHRNG", /* 37 */ + "EL2NSYNC", /* 38 */ + "EL3HLT", /* 39 */ + "EL3RST", /* 40 */ + "ELNRNG", /* 41 */ + "EUNATCH", /* 42 */ + "ENOCSI", /* 43 */ + "EL2HLT", /* 44 */ + "EDEADLK", /* 45 */ + "ENOLCK", /* 46 */ + "ECANCELED", /* 47 */ + "ENOTSUP", /* 48 */ + "EDQUOT", /* 49 */ + "EBADE", /* 50 */ + "EBADR", /* 51 */ + "EXFULL", /* 52 */ + "ENOANO", /* 53 */ + "EBADRQC", /* 54 */ + "EBADSLT", /* 55 */ + "EDEADLOCK", /* 56 */ + "EBFONT", /* 57 */ + "EOWNERDEAD", /* 58 */ + "ENOTRECOVERABLE", /* 59 */ + "ENOSTR", /* 60 */ + "ENODATA", /* 61 */ + "ETIME", /* 62 */ + "ENOSR", /* 63 */ + "ENONET", /* 64 */ + "ENOPKG", /* 65 */ + "EREMOTE", /* 66 */ + "ENOLINK", /* 67 */ + "EADV", /* 68 */ + "ESRMNT", /* 69 */ + "ECOMM", /* 70 */ + "EPROTO", /* 71 */ + "ELOCKUNMAPPED", /* 72 */ + "ENOTACTIVE", /* 73 */ + "EMULTIHOP", /* 74 */ + NULL, /* 75 */ + NULL, /* 76 */ + "EBADMSG", /* 77 */ + "ENAMETOOLONG", /* 78 */ + "EOVERFLOW", /* 79 */ + "ENOTUNIQ", /* 80 */ + "EBADFD", /* 81 */ + "EREMCHG", /* 82 */ + "ELIBACC", /* 83 */ + "ELIBBAD", /* 84 */ + "ELIBSCN", /* 85 */ + "ELIBMAX", /* 86 */ + "ELIBEXEC", /* 87 */ + "EILSEQ", /* 88 */ + "ENOSYS", /* 89 */ + "ELOOP", /* 90 */ + "ERESTART", /* 91 */ + "ESTRPIPE", /* 92 */ + "ENOTEMPTY", /* 93 */ + "EUSERS", /* 94 */ + "ENOTSOCK", /* 95 */ + "EDESTADDRREQ", /* 96 */ + "EMSGSIZE", /* 97 */ + "EPROTOTYPE", /* 98 */ + "ENOPROTOOPT", /* 99 */ + NULL, /* 100 */ + NULL, /* 101 */ + NULL, /* 102 */ + NULL, /* 103 */ + NULL, /* 104 */ + NULL, /* 105 */ + NULL, /* 106 */ + NULL, /* 107 */ + NULL, /* 108 */ + NULL, /* 109 */ + NULL, /* 110 */ + NULL, /* 111 */ + NULL, /* 112 */ + NULL, /* 113 */ + NULL, /* 114 */ + NULL, /* 115 */ + NULL, /* 116 */ + NULL, /* 117 */ + NULL, /* 118 */ + NULL, /* 119 */ + "EPROTONOSUPPORT", /* 120 */ + "ESOCKTNOSUPPORT", /* 121 */ + "EOPNOTSUPP", /* 122 */ + "EPFNOSUPPORT", /* 123 */ + "EAFNOSUPPORT", /* 124 */ + "EADDRINUSE", /* 125 */ + "EADDRNOTAVAIL", /* 126 */ + "ENETDOWN", /* 127 */ + "ENETUNREACH", /* 128 */ + "ENETRESET", /* 129 */ + "ECONNABORTED", /* 130 */ + "ECONNRESET", /* 131 */ + "ENOBUFS", /* 132 */ + "EISCONN", /* 133 */ + "ENOTCONN", /* 134 */ + NULL, /* 135 */ + NULL, /* 136 */ + NULL, /* 137 */ + NULL, /* 138 */ + NULL, /* 139 */ + NULL, /* 140 */ + NULL, /* 141 */ + NULL, /* 142 */ + "ESHUTDOWN", /* 143 */ + "ETOOMANYREFS", /* 144 */ + "ETIMEDOUT", /* 145 */ + "ECONNREFUSED", /* 146 */ + "EHOSTDOWN", /* 147 */ + "EHOSTUNREACH", /* 148 */ + "EALREADY", /* 149 */ + "EINPROGRESS", /* 150 */ + "ESTALE" /* 151 */ +}; + +#define NERRCODE (sizeof (errcode) / sizeof (char *)) + + +const char * +errname(int err) /* return the error code name (NULL if none) */ +{ + const char *ename = NULL; + + if (err >= 0 && err < NERRCODE) + ename = errcode[err]; + + return (ename); +} + + +const struct systable systable[] = { +{ NULL, 8, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX}, +{"_exit", 1, DEC, NOV, DEC}, /* 1 */ +{ NULL, 8, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX}, +{"read", 3, DEC, NOV, DEC, IOB, UNS}, /* 3 */ +{"write", 3, DEC, NOV, DEC, IOB, UNS}, /* 4 */ +{"open", 3, DEC, NOV, STG, OPN, OCT}, /* 5 */ +{"close", 1, DEC, NOV, DEC}, /* 6 */ +{"linkat", 5, DEC, NOV, ATC, STG, ATC, STG, SNF}, /* 7 */ +{ NULL, 8, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX}, +{"link", 2, DEC, NOV, STG, STG}, /* 9 */ +{"unlink", 1, DEC, NOV, STG}, /* 10 */ +{"symlinkat", 3, DEC, NOV, STG, ATC, STG}, /* 11 */ +{"chdir", 1, DEC, NOV, STG}, /* 12 */ +{"time", 0, DEC, NOV}, /* 13 */ +{"mknod", 3, DEC, NOV, STG, OCT, HEX}, /* 14 */ +{"chmod", 2, DEC, NOV, STG, OCT}, /* 15 */ +{"chown", 3, DEC, NOV, STG, DEC, DEC}, /* 16 */ +{"brk", 1, DEC, NOV, HEX}, /* 17 */ +{"stat", 2, DEC, NOV, STG, HEX}, /* 18 */ +{"lseek", 3, DEC, NOV, DEC, DEX, WHN}, /* 19 */ +{"getpid", 0, DEC, DEC}, /* 20 */ +{"mount", 8, DEC, NOV, STG, STG, MTF, MFT, HEX, DEC, HEX, DEC}, /* 21 */ +{"readlinkat", 4, DEC, NOV, ATC, STG, RLK, UNS}, /* 22 */ +{"setuid", 1, DEC, NOV, UNS}, /* 23 */ +{"getuid", 0, UNS, UNS}, /* 24 */ +{"stime", 1, DEC, NOV, DEC}, /* 25 */ +{"pcsample", 2, DEC, NOV, HEX, DEC}, /* 26 */ +{"alarm", 1, DEC, NOV, UNS}, /* 27 */ +{"fstat", 2, DEC, NOV, DEC, HEX}, /* 28 */ +{"pause", 0, DEC, NOV}, /* 29 */ +{ NULL, 8, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX}, +{"stty", 2, DEC, NOV, DEC, DEC}, /* 31 */ +{"gtty", 2, DEC, NOV, DEC, DEC}, /* 32 */ +{"access", 2, DEC, NOV, STG, ACC}, /* 33 */ +{"nice", 1, DEC, NOV, DEC}, /* 34 */ +{"statfs", 4, DEC, NOV, STG, HEX, DEC, DEC}, /* 35 */ +{"sync", 0, DEC, NOV}, /* 36 */ +{"kill", 2, DEC, NOV, DEC, SIG}, /* 37 */ +{"fstatfs", 4, DEC, NOV, DEC, HEX, DEC, DEC}, /* 38 */ +{"pgrpsys", 3, DEC, NOV, DEC, DEC, DEC}, /* 39 */ +{"uucopystr", 3, DEC, NOV, STG, RST, UNS}, /* 40 */ +{ NULL, 8, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX}, +{"pipe", 2, DEC, NOV, PFD, PIP}, /* 42 */ +{"times", 1, DEC, NOV, HEX}, /* 43 */ +{"profil", 4, DEC, NOV, HEX, UNS, HEX, OCT}, /* 44 */ +{"faccessat", 4, DEC, NOV, ATC, STG, ACC, FAT}, /* 45 */ +{"setgid", 1, DEC, NOV, UNS}, /* 46 */ +{"getgid", 0, UNS, UNS}, /* 47 */ +{"mknodat", 4, DEC, NOV, ATC, STG, OCT, HEX}, /* 48 */ +{"msgsys", 6, DEC, NOV, DEC, DEC, DEC, DEC, DEC, DEC}, /* 49 */ +{"sysi86", 4, HEX, NOV, S86, HEX, HEX, HEX, DEC, DEC}, /* 50 */ +{"acct", 1, DEC, NOV, STG}, /* 51 */ +{"shmsys", 4, DEC, NOV, DEC, HEX, HEX, HEX}, /* 52 */ +{"semsys", 5, DEC, NOV, DEC, HEX, HEX, HEX, HEX}, /* 53 */ +{"ioctl", 3, DEC, NOV, DEC, IOC, IOA}, /* 54 */ +{"uadmin", 3, DEC, NOV, DEC, DEC, DEC}, /* 55 */ +{"fchownat", 5, DEC, NOV, ATC, STG, DEC, DEC, SNF}, /* 56 */ +{"utssys", 4, DEC, NOV, HEX, DEC, UTS, HEX}, /* 57 */ +{"fdsync", 2, DEC, NOV, DEC, FFG}, /* 58 */ +{"execve", 3, DEC, NOV, STG, HEX, HEX}, /* 59 */ +{"umask", 1, OCT, NOV, OCT}, /* 60 */ +{"chroot", 1, DEC, NOV, STG}, /* 61 */ +{"fcntl", 3, DEC, NOV, DEC, FCN, HEX}, /* 62 */ +{"ulimit", 2, DEX, NOV, ULM, DEC}, /* 63 */ +{"renameat", 4, DEC, NOV, ATC, STG, ATC, STG}, /* 64 */ +{"unlinkat", 3, DEC, NOV, ATC, STG, UAT}, /* 65 */ +{"fstatat", 4, DEC, NOV, ATC, STG, HEX, SNF}, /* 66 */ +{"fstatat64", 4, DEC, NOV, ATC, STG, HEX, SNF}, /* 67 */ +{"openat", 4, DEC, NOV, ATC, STG, OPN, OCT}, /* 68 */ +{"openat64", 4, DEC, NOV, ATC, STG, OPN, OCT}, /* 69 */ +{"tasksys", 5, DEC, NOV, DEC, DEC, DEC, HEX, DEC}, /* 70 */ +{"acctctl", 3, DEC, NOV, HEX, HEX, UNS}, /* 71 */ +{"exacctsys", 6, DEC, NOV, DEC, IDT, DEC, HEX, DEC, HEX}, /* 72 */ +{"getpagesizes", 2, DEC, NOV, HEX, DEC}, /* 73 */ +{"rctlsys", 6, DEC, NOV, RSC, STG, HEX, HEX, DEC, DEC}, /* 74 */ +{"sidsys", 4, UNS, UNS, DEC, DEC, DEC, DEC}, /* 75 */ +{ NULL, 8, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX}, +{"lwp_park", 3, DEC, NOV, DEC, HEX, DEC}, /* 77 */ +{"sendfilev", 5, DEC, NOV, DEC, DEC, HEX, DEC, HEX}, /* 78 */ +{"rmdir", 1, DEC, NOV, STG}, /* 79 */ +{"mkdir", 2, DEC, NOV, STG, OCT}, /* 80 */ +{"getdents", 3, DEC, NOV, DEC, HEX, UNS}, /* 81 */ +{"privsys", 5, HEX, NOV, DEC, DEC, DEC, HEX, DEC}, /* 82 */ +{"ucredsys", 3, DEC, NOV, DEC, DEC, HEX}, /* 83 */ +{"sysfs", 3, DEC, NOV, SFS, DEX, DEX}, /* 84 */ +{"getmsg", 4, DEC, NOV, DEC, HEX, HEX, HEX}, /* 85 */ +{"putmsg", 4, DEC, NOV, DEC, HEX, HEX, SMF}, /* 86 */ +{ NULL, 8, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX}, +{"lstat", 2, DEC, NOV, STG, HEX}, /* 88 */ +{"symlink", 2, DEC, NOV, STG, STG}, /* 89 */ +{"readlink", 3, DEC, NOV, STG, RLK, UNS}, /* 90 */ +{"setgroups", 2, DEC, NOV, DEC, HEX}, /* 91 */ +{"getgroups", 2, DEC, NOV, DEC, HEX}, /* 92 */ +{"fchmod", 2, DEC, NOV, DEC, OCT}, /* 93 */ +{"fchown", 3, DEC, NOV, DEC, DEC, DEC}, /* 94 */ +{"sigprocmask", 3, DEC, NOV, SPM, HEX, HEX}, /* 95 */ +{"sigsuspend", 1, DEC, NOV, HEX}, /* 96 */ +{"sigaltstack", 2, DEC, NOV, HEX, HEX}, /* 97 */ +{"sigaction", 3, DEC, NOV, SIG, HEX, HEX}, /* 98 */ +{"sigpendsys", 2, DEC, NOV, DEC, HEX}, /* 99 */ +{"context", 2, DEC, NOV, DEC, HEX}, /* 100 */ +{"fchmodat", 4, DEC, NOV, ATC, STG, OCT, SNF}, /* 101 */ +{"mkdirat", 3, DEC, NOV, ATC, STG, OCT}, /* 102 */ +{"statvfs", 2, DEC, NOV, STG, HEX}, /* 103 */ +{"fstatvfs", 2, DEC, NOV, DEC, HEX}, /* 104 */ +{"getloadavg", 2, DEC, NOV, HEX, DEC}, /* 105 */ +{"nfssys", 2, DEC, NOV, DEC, HEX}, /* 106 */ +{"waitid", 4, DEC, NOV, IDT, DEC, HEX, WOP}, /* 107 */ +{"sigsendsys", 2, DEC, NOV, HEX, SIG}, /* 108 */ +{"hrtsys", 5, DEC, NOV, DEC, HEX, HEX, HEX, HEX}, /* 109 */ +{"utimesys", 5, DEC, NOV, DEC, HEX, HEX, HEX, HEX}, /* 110 */ +{"sigresend", 3, DEC, NOV, SIG, HEX, HEX}, /* 111 */ +{"priocntlsys", 5, DEC, NOV, DEC, HEX, DEC, PC4, PC5}, /* 112 */ +{"pathconf", 2, DEC, NOV, STG, PTC}, /* 113 */ +{"mincore", 3, DEC, NOV, HEX, UNS, HEX}, /* 114 */ +{"mmap", 6, HEX, NOV, HEX, UNS, MPR, MTY, DEC, DEC}, /* 115 */ +{"mprotect", 3, DEC, NOV, HEX, UNS, MPR}, /* 116 */ +{"munmap", 2, DEC, NOV, HEX, UNS}, /* 117 */ +{"fpathconf", 2, DEC, NOV, DEC, PTC}, /* 118 */ +{"vfork", 0, DEC, NOV}, /* 119 */ +{"fchdir", 1, DEC, NOV, DEC}, /* 120 */ +{"readv", 3, DEC, NOV, DEC, HEX, DEC}, /* 121 */ +{"writev", 3, DEC, NOV, DEC, HEX, DEC}, /* 122 */ +{ NULL, 8, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX}, +{ NULL, 8, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX}, +{ NULL, 8, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX}, +{ NULL, 8, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX}, +{"mmapobj", 5, DEC, NOV, DEC, MOB, HEX, HEX, HEX}, /* 127 */ +{"setrlimit", 2, DEC, NOV, RLM, HEX}, /* 128 */ +{"getrlimit", 2, DEC, NOV, RLM, HEX}, /* 129 */ +{"lchown", 3, DEC, NOV, STG, DEC, DEC}, /* 130 */ +{"memcntl", 6, DEC, NOV, HEX, UNS, MCF, MC4, MC5, DEC}, /* 131 */ +{"getpmsg", 5, DEC, NOV, DEC, HEX, HEX, HEX, HEX}, /* 132 */ +{"putpmsg", 5, DEC, NOV, DEC, HEX, HEX, DEC, HHX}, /* 133 */ +{"rename", 2, DEC, NOV, STG, STG}, /* 134 */ +{"uname", 1, DEC, NOV, HEX}, /* 135 */ +{"setegid", 1, DEC, NOV, UNS}, /* 136 */ +{"sysconfig", 1, DEC, NOV, CNF}, /* 137 */ +{"adjtime", 2, DEC, NOV, HEX, HEX}, /* 138 */ +{"sysinfo", 3, DEC, NOV, INF, RST, DEC}, /* 139 */ +{"sharefs", 3, DEC, NOV, DEC, HEX, DEC}, /* 140 */ +{"seteuid", 1, DEC, NOV, UNS}, /* 141 */ +{"forksys", 2, DEC, NOV, DEC, HHX}, /* 142 */ +{ NULL, 8, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX}, +{"sigtimedwait", 3, DEC, NOV, HEX, HEX, HEX}, /* 144 */ +{"lwp_info", 1, DEC, NOV, HEX}, /* 145 */ +{"yield", 0, DEC, NOV}, /* 146 */ +{ NULL, 8, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX}, +{"lwp_sema_post", 1, DEC, NOV, HEX}, /* 148 */ +{"lwp_sema_trywait", 1, DEC, NOV, HEX}, /* 149 */ +{"lwp_detach", 1, DEC, NOV, DEC}, /* 150 */ +{"corectl", 4, DEC, NOV, DEC, HEX, HEX, HEX}, /* 151 */ +{"modctl", 5, DEC, NOV, MOD, HEX, HEX, HEX, HEX}, /* 152 */ +{"fchroot", 1, DEC, NOV, DEC}, /* 153 */ +{ NULL, 8, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX}, +{"vhangup", 0, DEC, NOV}, /* 155 */ +{"gettimeofday", 1, DEC, NOV, HEX}, /* 156 */ +{"getitimer", 2, DEC, NOV, ITM, HEX}, /* 157 */ +{"setitimer", 3, DEC, NOV, ITM, HEX, HEX}, /* 158 */ +{"lwp_create", 3, DEC, NOV, HEX, LWF, HEX}, /* 159 */ +{"lwp_exit", 0, DEC, NOV}, /* 160 */ +{"lwp_suspend", 1, DEC, NOV, DEC}, /* 161 */ +{"lwp_continue", 1, DEC, NOV, DEC}, /* 162 */ +{"lwp_kill", 2, DEC, NOV, DEC, SIG}, /* 163 */ +{"lwp_self", 0, DEC, NOV}, /* 164 */ +{"lwp_sigmask", 5, HEX, HEX, SPM, HEX, HEX, HEX, HEX}, /* 165 */ +{"lwp_private", 3, HEX, NOV, DEC, DEC, HEX}, /* 166 */ +{"lwp_wait", 2, DEC, NOV, DEC, HEX}, /* 167 */ +{"lwp_mutex_wakeup", 2, DEC, NOV, HEX, DEC}, /* 168 */ +{ NULL, 8, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX}, +{"lwp_cond_wait", 4, DEC, NOV, HEX, HEX, HEX, DEC}, /* 170 */ +{"lwp_cond_signal", 1, DEC, NOV, HEX}, /* 171 */ +{"lwp_cond_broadcast", 1, DEC, NOV, HEX}, /* 172 */ +{"pread", 4, DEC, NOV, DEC, IOB, UNS, DEX}, /* 173 */ +{"pwrite", 4, DEC, NOV, DEC, IOB, UNS, DEX}, /* 174 */ +{"llseek", 4, LLO, NOV, DEC, LLO, HID, WHN}, /* 175 */ +{"inst_sync", 2, DEC, NOV, STG, DEC}, /* 176 */ +{"brand", 6, DEC, NOV, DEC, HEX, HEX, HEX, HEX, HEX}, /* 177 */ +{"kaio", 7, DEC, NOV, AIO, HEX, HEX, HEX, HEX, HEX, HEX}, /* 178 */ +{"cpc", 5, DEC, NOV, CPC, DEC, HEX, HEX, HEX}, /* 179 */ +{"lgrpsys", 3, DEC, NOV, DEC, DEC, HEX}, /* 180 */ +{"rusagesys", 5, DEC, NOV, DEC, HEX, DEC, HEX, HEX}, /* 181 */ +{"portfs", 6, HEX, HEX, DEC, HEX, HEX, HEX, HEX, HEX}, /* 182 */ +{"pollsys", 4, DEC, NOV, HEX, DEC, HEX, HEX}, /* 183 */ +{"labelsys", 2, DEC, NOV, DEC, HEX}, /* 184 */ +{"acl", 4, DEC, NOV, STG, ACL, DEC, HEX}, /* 185 */ +{"auditsys", 4, DEC, NOV, AUD, HEX, HEX, HEX}, /* 186 */ +{"processor_bind", 4, DEC, NOV, IDT, DEC, DEC, HEX}, /* 187 */ +{"processor_info", 2, DEC, NOV, DEC, HEX}, /* 188 */ +{"p_online", 2, DEC, NOV, DEC, DEC}, /* 189 */ +{"sigqueue", 5, DEC, NOV, DEC, SIG, HEX, SQC, DEC}, /* 190 */ +{"clock_gettime", 2, DEC, NOV, DEC, HEX}, /* 191 */ +{"clock_settime", 2, DEC, NOV, DEC, HEX}, /* 192 */ +{"clock_getres", 2, DEC, NOV, DEC, HEX}, /* 193 */ +{"timer_create", 3, DEC, NOV, DEC, HEX, HEX}, /* 194 */ +{"timer_delete", 1, DEC, NOV, DEC}, /* 195 */ +{"timer_settime", 4, DEC, NOV, DEC, DEC, HEX, HEX}, /* 196 */ +{"timer_gettime", 2, DEC, NOV, DEC, HEX}, /* 197 */ +{"timer_getoverrun", 1, DEC, NOV, DEC}, /* 198 */ +{"nanosleep", 2, DEC, NOV, HEX, HEX}, /* 199 */ +{"facl", 4, DEC, NOV, DEC, ACL, DEC, HEX}, /* 200 */ +{"door", 6, DEC, NOV, DEC, HEX, HEX, HEX, HEX, DEC}, /* 201 */ +{"setreuid", 2, DEC, NOV, UN1, UN1}, /* 202 */ +{"setregid", 2, DEC, NOV, UN1, UN1}, /* 203 */ +{"install_utrap", 3, DEC, NOV, DEC, HEX, HEX}, /* 204 */ +{"signotify", 3, DEC, NOV, DEC, HEX, HEX}, /* 205 */ +{"schedctl", 0, HEX, NOV}, /* 206 */ +{"pset", 5, DEC, NOV, DEC, HEX, HEX, HEX, HEX}, /* 207 */ +{"sparc_utrap_install", 5, DEC, NOV, UTT, UTH, UTH, HEX, HEX}, /* 208 */ +{"resolvepath", 3, DEC, NOV, STG, RLK, DEC}, /* 209 */ +{"lwp_mutex_timedlock", 3, DEC, NOV, HEX, HEX, HEX}, /* 210 */ +{"lwp_sema_timedwait", 3, DEC, NOV, HEX, HEX, DEC}, /* 211 */ +{"lwp_rwlock_sys", 3, DEC, NOV, DEC, HEX, HEX}, /* 212 */ +{"getdents64", 3, DEC, NOV, DEC, HEX, UNS}, /* 213 */ +{"mmap64", 7, HEX, NOV, HEX, UNS, MPR, MTY, DEC, LLO, HID}, /* 214 */ +{"stat64", 2, DEC, NOV, STG, HEX}, /* 215 */ +{"lstat64", 2, DEC, NOV, STG, HEX}, /* 216 */ +{"fstat64", 2, DEC, NOV, DEC, HEX}, /* 217 */ +{"statvfs64", 2, DEC, NOV, STG, HEX}, /* 218 */ +{"fstatvfs64", 2, DEC, NOV, DEC, HEX}, /* 219 */ +{"setrlimit64", 2, DEC, NOV, RLM, HEX}, /* 220 */ +{"getrlimit64", 2, DEC, NOV, RLM, HEX}, /* 221 */ +{"pread64", 5, DEC, NOV, DEC, IOB, UNS, LLO, HID}, /* 222 */ +{"pwrite64", 5, DEC, NOV, DEC, IOB, UNS, LLO, HID}, /* 223 */ +{ NULL, 8, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX}, +{"open64", 3, DEC, NOV, STG, OPN, OCT}, /* 225 */ +{"rpcmod", 3, DEC, NOV, DEC, HEX}, /* 226 */ +{"zone", 5, DEC, NOV, DEC, HEX, HEX, HEX, HEX}, /* 227 */ +{"autofssys", 2, DEC, NOV, DEC, HEX}, /* 228 */ +{"getcwd", 3, DEC, NOV, RST, DEC}, /* 229 */ +{"so_socket", 5, DEC, NOV, PFM, SKT, SKP, STG, SKV}, /* 230 */ +{"so_socketpair", 1, DEC, NOV, HEX}, /* 231 */ +{"bind", 4, DEC, NOV, DEC, HEX, DEC, SKV}, /* 232 */ +{"listen", 3, DEC, NOV, DEC, DEC, SKV}, /* 233 */ +{"accept", 5, DEC, NOV, DEC, HEX, HEX, SKV, ACF}, /* 234 */ +{"connect", 4, DEC, NOV, DEC, HEX, DEC, SKV}, /* 235 */ +{"shutdown", 3, DEC, NOV, DEC, SHT, SKV}, /* 236 */ +{"recv", 4, DEC, NOV, DEC, IOB, DEC, DEC}, /* 237 */ +{"recvfrom", 6, DEC, NOV, DEC, IOB, DEC, DEC, HEX, HEX}, /* 238 */ +{"recvmsg", 3, DEC, NOV, DEC, HEX, DEC}, /* 239 */ +{"send", 4, DEC, NOV, DEC, IOB, DEC, DEC}, /* 240 */ +{"sendmsg", 3, DEC, NOV, DEC, HEX, DEC}, /* 241 */ +{"sendto", 6, DEC, NOV, DEC, IOB, DEC, DEC, HEX, DEC}, /* 242 */ +{"getpeername", 4, DEC, NOV, DEC, HEX, HEX, SKV}, /* 243 */ +{"getsockname", 4, DEC, NOV, DEC, HEX, HEX, SKV}, /* 244 */ +{"getsockopt", 6, DEC, NOV, DEC, SOL, SON, HEX, HEX, SKV}, /* 245 */ +{"setsockopt", 6, DEC, NOV, DEC, SOL, SON, HEX, DEC, SKV}, /* 246 */ +{"sockconfig", 5, DEC, NOV, DEC, HEX, HEX, HEX, HEX}, /* 247 */ +{"ntp_gettime", 1, DEC, NOV, HEX}, /* 248 */ +{"ntp_adjtime", 1, DEC, NOV, HEX}, /* 249 */ +{"lwp_mutex_unlock", 1, DEC, NOV, HEX}, /* 250 */ +{"lwp_mutex_trylock", 2, DEC, NOV, HEX, HEX}, /* 251 */ +{"lwp_mutex_register", 2, DEC, NOV, HEX, HEX}, /* 252 */ +{"cladm", 3, DEC, NOV, CLC, CLF, HEX}, /* 253 */ +{"uucopy", 3, DEC, NOV, HEX, HEX, UNS}, /* 254 */ +{"umount2", 2, DEC, NOV, STG, MTF}, /* 255 */ +{ NULL, -1, DEC, NOV}, +}; + +/* SYSEND == max syscall number + 1 */ +#define SYSEND ((sizeof (systable) / sizeof (struct systable))-1) + + +/* + * The following are for interpreting syscalls with sub-codes. + */ + +const struct systable faccessattable[] = { +{"faccessat", 4, DEC, NOV, ATC, STG, ACC, FAT}, /* 0 */ +{"access", 3, DEC, NOV, HID, STG, ACC}, /* 1 */ +}; +#define NACCESSCODE (sizeof (faccessattable) / sizeof (struct systable)) + +const struct systable fchmodattable[] = { +{"fchmodat", 4, DEC, NOV, ATC, STG, OCT, SNF}, /* 0 */ +{"chmod", 3, DEC, NOV, HID, STG, OCT}, /* 1 */ +{"fchmodat", 4, DEC, NOV, ATC, STG, OCT, SNF}, /* 2 */ +{"fchmod", 3, DEC, NOV, DEC, HID, OCT}, /* 3 */ +}; +#define NCHMODCODE (sizeof (fchmodattable) / sizeof (struct systable)) + +const struct systable fchownattable[] = { +{"fchownat", 5, DEC, NOV, ATC, STG, DEC, DEC, SNF}, /* 0 */ +{"chown", 4, DEC, NOV, HID, STG, DEC, DEC}, /* 1 */ +{"lchown", 4, DEC, NOV, HID, STG, DEC, DEC}, /* 2 */ +{"fchown", 4, DEC, NOV, DEC, HID, DEC, DEC}, /* 3 */ +}; +#define NCHOWNCODE (sizeof (fchownattable) / sizeof (struct systable)) + +const struct systable mkdiratattable[] = { +{"mkdirat", 3, DEC, NOV, ATC, STG, OCT}, /* 0 */ +{"mkdir", 3, DEC, NOV, HID, STG, OCT}, /* 1 */ +}; +#define NMKDIRCODE (sizeof (mkdiratattable) / sizeof (struct systable)) + +const struct systable mknodatattable[] = { +{"mknodat", 4, DEC, NOV, ATC, STG, OCT, HEX}, /* 0 */ +{"mknod", 4, DEC, NOV, HID, STG, OCT, HEX}, /* 1 */ +}; +#define NMKMODCODE (sizeof (mknodatattable) / sizeof (struct systable)) + +const struct systable renameattable[] = { +{"renameat", 4, DEC, NOV, ATC, STG, ATC, STG}, /* 0 */ +{"rename", 4, DEC, NOV, HID, STG, HID, STG}, /* 1 */ +}; +#define NRENAMECODE (sizeof (renameattable) / sizeof (struct systable)) + +const struct systable linkattable[] = { +{"linkat", 5, DEC, NOV, ATC, STG, ATC, STG, SNF}, /* 0 */ +{"link", 4, DEC, NOV, HID, STG, HID, STG}, /* 1 */ +}; +#define NLINKATCODE (sizeof (linkattable) / sizeof (struct systable)) + +const struct systable unlinkattable[] = { +{"unlinkat", 3, DEC, NOV, ATC, STG, UAT}, /* 0 */ +{"unlink", 2, DEC, NOV, HID, STG}, /* 1 */ +{"rmdir", 2, DEC, NOV, HID, STG}, /* 2 */ +}; +#define NUNLINKCODE (sizeof (unlinkattable) / sizeof (struct systable)) + +const struct systable symlinkattable[] = { +{"symlinkat", 3, DEC, NOV, STG, ATC, STG}, /* 0 */ +{"symlink", 3, DEC, NOV, STG, HID, STG}, /* 1 */ +}; +#define NSYMLINKCODE (sizeof (symlinkattable) / sizeof (struct systable)) + +const struct systable readlinkattable[] = { +{"readlinkat", 4, DEC, NOV, ATC, STG, RLK, UNS}, /* 0 */ +{"readlink", 4, DEC, NOV, HID, STG, RLK, UNS}, /* 1 */ +}; +#define NREADLINKCODE (sizeof (readlinkattable) / sizeof (struct systable)) + +const struct systable fstatattable[] = { +{"fstatat", 4, DEC, NOV, ATC, STG, HEX, SNF}, /* 0 */ +{"stat", 3, DEC, NOV, HID, STG, HEX}, /* 1 */ +{"lstat", 3, DEC, NOV, HID, STG, HEX}, /* 2 */ +{"fstat", 3, DEC, NOV, DEC, HID, HEX}, /* 3 */ +}; +#define NSTATCODE (sizeof (fstatattable) / sizeof (struct systable)) + +const struct systable fstatat64table[] = { +{"fstatat64", 4, DEC, NOV, ATC, STG, HEX, SNF}, /* 0 */ +{"stat64", 3, DEC, NOV, HID, STG, HEX}, /* 1 */ +{"lstat64", 3, DEC, NOV, HID, STG, HEX}, /* 2 */ +{"fstat64", 3, DEC, NOV, DEC, HID, HEX}, /* 3 */ +}; +#define NSTAT64CODE (sizeof (fstatat64table) / sizeof (struct systable)) + +const struct systable openattable[] = { +{"openat", 3, DEC, NOV, ATC, STG, OPN}, /* 0 */ +{"openat", 4, DEC, NOV, ATC, STG, OPN, OCT}, /* 1 */ +{"open", 3, DEC, NOV, HID, STG, OPN}, /* 2 */ +{"open", 4, DEC, NOV, HID, STG, OPN, OCT}, /* 3 */ +}; +#define NOPENATCODE (sizeof (openattable) / sizeof (struct systable)) + +const struct systable openat64table[] = { +{"openat64", 3, DEC, NOV, ATC, STG, OPN}, /* 0 */ +{"openat64", 4, DEC, NOV, ATC, STG, OPN, OCT}, /* 1 */ +{"open64", 3, DEC, NOV, HID, STG, OPN}, /* 2 */ +{"open64", 4, DEC, NOV, HID, STG, OPN, OCT}, /* 3 */ +}; +#define NOPENAT64CODE (sizeof (openat64table) / sizeof (struct systable)) + +const struct systable opentable[] = { +{"open", 2, DEC, NOV, STG, OPN}, /* 0 */ +{"open", 3, DEC, NOV, STG, OPN, OCT}, /* 1 */ +}; +#define NOPENCODE (sizeof (opentable) / sizeof (struct systable)) + +const struct systable open64table[] = { +{"open64", 2, DEC, NOV, STG, OPN}, /* 0 */ +{"open64", 3, DEC, NOV, STG, OPN, OCT}, /* 1 */ +}; +#define NOPEN64CODE (sizeof (open64table) / sizeof (struct systable)) + +const struct systable fcntltable[] = { +{"fcntl", 3, DEC, NOV, DEC, FCN, HEX}, /* 0: default */ +{"fcntl", 2, DEC, NOV, DEC, FCN}, /* 1: no arg */ +{"fcntl", 3, DEC, NOV, DEC, FCN, FFG}, /* 2: F_SETFL */ +}; +#define NFCNTLCODE (sizeof (fcntltable) / sizeof (struct systable)) + +const struct systable msgtable[] = { +{"msgget", 3, DEC, NOV, HID, KEY, MSF}, /* 0 */ +{"msgctl", 4, DEC, NOV, HID, DEC, MSC, HEX}, /* 1 */ +{"msgrcv", 6, DEC, NOV, HID, DEC, HEX, UNS, DEC, MSF}, /* 2 */ +{"msgsnd", 5, DEC, NOV, HID, DEC, HEX, UNS, MSF}, /* 3 */ +{"msgids", 4, DEC, NOV, HID, HEX, UNS, HEX}, /* 4 */ +{"msgsnap", 5, DEC, NOV, HID, DEC, HEX, UNS, DEC}, /* 5 */ +}; +#define NMSGCODE (sizeof (msgtable) / sizeof (struct systable)) + +const struct systable semtable[] = { +{"semctl", 5, DEC, NOV, HID, DEC, DEC, SMC, DEX}, /* 0 */ +{"semget", 4, DEC, NOV, HID, KEY, DEC, SEF}, /* 1 */ +{"semop", 4, DEC, NOV, HID, DEC, HEX, UNS}, /* 2 */ +{"semids", 4, DEC, NOV, HID, HEX, UNS, HEX}, /* 3 */ +{"semtimedop", 5, DEC, NOV, HID, DEC, HEX, UNS, HEX}, /* 4 */ +}; +#define NSEMCODE (sizeof (semtable) / sizeof (struct systable)) + +const struct systable shmtable[] = { +{"shmat", 4, HEX, NOV, HID, DEC, DEX, SHF}, /* 0 */ +{"shmctl", 4, DEC, NOV, HID, DEC, SHC, DEX}, /* 1 */ +{"shmdt", 2, DEC, NOV, HID, HEX}, /* 2 */ +{"shmget", 4, DEC, NOV, HID, KEY, UNS, SHF}, /* 3 */ +{"shmids", 4, DEC, NOV, HID, HEX, UNS, HEX}, /* 4 */ +}; +#define NSHMCODE (sizeof (shmtable) / sizeof (struct systable)) + +const struct systable pidtable[] = { +{"getpgrp", 1, DEC, NOV, HID}, /* 0 */ +{"setpgrp", 1, DEC, NOV, HID}, /* 1 */ +{"getsid", 2, DEC, NOV, HID, DEC}, /* 2 */ +{"setsid", 1, DEC, NOV, HID}, /* 3 */ +{"getpgid", 2, DEC, NOV, HID, DEC}, /* 4 */ +{"setpgid", 3, DEC, NOV, HID, DEC, DEC}, /* 5 */ +}; +#define NPIDCODE (sizeof (pidtable) / sizeof (struct systable)) + +const struct systable sfstable[] = { +{"sysfs", 3, DEC, NOV, SFS, DEX, DEX}, /* 0 */ +{"sysfs", 2, DEC, NOV, SFS, STG}, /* 1 */ +{"sysfs", 3, DEC, NOV, SFS, DEC, RST}, /* 2 */ +{"sysfs", 1, DEC, NOV, SFS}, /* 3 */ +}; +#define NSFSCODE (sizeof (sfstable) / sizeof (struct systable)) + +const struct systable utstable[] = { +{"utssys", 3, DEC, NOV, HEX, DEC, UTS}, /* 0 */ +{"utssys", 4, DEC, NOV, HEX, HEX, HEX, HEX}, /* err */ +{"utssys", 3, DEC, NOV, HEX, HHX, UTS}, /* 2 */ +{"utssys", 4, DEC, NOV, STG, FUI, UTS, HEX} /* 3 */ +}; +#define NUTSCODE (sizeof (utstable) / sizeof (struct systable)) + +const struct systable rctltable[] = { +{"getrctl", 6, DEC, NOV, HID, STG, HEX, HEX, HID, RGF}, /* 0 */ +{"setrctl", 6, DEC, NOV, HID, STG, HEX, HEX, HID, RSF}, /* 1 */ +{"rctlsys_lst", 6, DEC, NOV, HID, HID, HEX, HID, HEX, HID}, /* 2 */ +{"rctlsys_ctl", 6, DEC, NOV, HID, STG, HEX, HID, HID, RCF}, /* 3 */ +{"setprojrctl", 6, DEC, NOV, HID, STG, HID, HEX, HEX, SPF}, /* 4 */ +}; +#define NRCTLCODE (sizeof (rctltable) / sizeof (struct systable)) + +const struct systable sgptable[] = { +{"sigpendsys", 2, DEC, NOV, DEC, HEX}, /* err */ +{"sigpending", 2, DEC, NOV, HID, HEX}, /* 1 */ +{"sigfillset", 2, DEC, NOV, HID, HEX}, /* 2 */ +}; +#define NSGPCODE (sizeof (sgptable) / sizeof (struct systable)) + +const struct systable ctxtable[] = { +{"getcontext", 2, DEC, NOV, HID, HEX}, /* 0 */ +{"setcontext", 2, DEC, NOV, HID, HEX}, /* 1 */ +{"getustack", 2, DEC, NOV, HID, HEX}, /* 2 */ +{"setustack", 2, DEC, NOV, HID, HEX}, /* 3 */ +}; +#define NCTXCODE (sizeof (ctxtable) / sizeof (struct systable)) + +const struct systable hrttable[] = { +{"hrtcntl", 5, DEC, NOV, HID, DEC, DEC, HEX, HEX}, /* 0 */ +{"hrtalarm", 3, DEC, NOV, HID, HEX, DEC}, /* 1 */ +{"hrtsleep", 2, DEC, NOV, HID, HEX}, /* 2 */ +{"hrtcancel", 3, DEC, NOV, HID, HEX, DEC}, /* 3 */ +}; +#define NHRTCODE (sizeof (hrttable) / sizeof (struct systable)) + +const struct systable cortable[] = { +{"corectl", 4, DEC, NOV, COR, HEX, HEX, HEX}, /* 0 */ +{"corectl", 2, DEC, NOV, COR, CCO}, /* 1 */ +{"corectl", 1, HHX, NOV, COR}, /* 2 */ +{"corectl", 3, DEC, NOV, COR, STG, DEC}, /* 3 */ +{"corectl", 3, DEC, NOV, COR, RST, DEC}, /* 4 */ +{"corectl", 4, DEC, NOV, COR, STG, DEC, DEC}, /* 5 */ +{"corectl", 4, DEC, NOV, COR, RST, DEC, DEC}, /* 6 */ +{"corectl", 2, DEC, NOV, COR, CCC}, /* 7 */ +{"corectl", 2, DEC, NOV, COR, RCC}, /* 8 */ +{"corectl", 3, DEC, NOV, COR, CCC, DEC}, /* 9 */ +{"corectl", 3, DEC, NOV, COR, RCC, DEC}, /* 10 */ +{"corectl", 3, DEC, NOV, COR, STG, DEC}, /* 11 */ +{"corectl", 3, DEC, NOV, COR, RST, DEC}, /* 12 */ +{"corectl", 2, DEC, NOV, COR, CCC}, /* 13 */ +{"corectl", 2, DEC, NOV, COR, RCC}, /* 14 */ +}; +#define NCORCODE (sizeof (cortable) / sizeof (struct systable)) + +const struct systable aiotable[] = { +{"kaio", 7, DEC, NOV, AIO, DEC, HEX, DEC, LLO, HID, HEX}, /* 0 */ +{"kaio", 7, DEC, NOV, AIO, DEC, HEX, DEC, LLO, HID, HEX}, /* 1 */ +{"kaio", 3, DEC, NOV, AIO, HEX, DEC}, /* 2 */ +{"kaio", 3, DEC, NOV, AIO, DEC, HEX}, /* 3 */ +{"kaio", 1, DEC, NOV, AIO}, /* 4 */ +{"kaio", 1, DEC, NOV, AIO}, /* 5 */ +{"kaio", 1, DEC, NOV, AIO}, /* 6 */ +{"kaio", 5, DEC, NOV, AIO, LIO, HEX, DEC, HEX}, /* 7 */ +{"kaio", 5, DEC, NOV, AIO, HEX, DEC, HEX, DEC}, /* 8 */ +{"kaio", 2, DEC, NOV, AIO, HEX}, /* 9 */ +{"kaio", 5, DEC, NOV, AIO, LIO, HEX, DEC, HEX}, /* 10 */ +{"kaio", 2, DEC, NOV, AIO, HEX}, /* 11 */ +{"kaio", 2, DEC, NOV, AIO, HEX}, /* 12 */ +{"kaio", 5, DEC, NOV, AIO, LIO, HEX, DEC, HEX}, /* 13 */ +{"kaio", 5, DEC, NOV, AIO, HEX, DEC, HEX, DEC}, /* 14 */ +{"kaio", 2, DEC, NOV, AIO, HEX}, /* 15 */ +{"kaio", 5, DEC, NOV, AIO, LIO, HEX, DEC, HEX}, /* 16 */ +{"kaio", 2, DEC, NOV, AIO, HEX}, /* 17 */ +{"kaio", 2, DEC, NOV, AIO, HEX}, /* 18 */ +{"kaio", 3, DEC, NOV, AIO, DEC, HEX}, /* 19 */ +{"kaio", 1, DEC, NOV, AIO}, /* 20 */ +{"kaio", 5, DEC, NOV, AIO, HEX, DEC, HEX, HEX}, /* 21 */ +}; +#define NAIOCODE (sizeof (aiotable) / sizeof (struct systable)) + +const struct systable doortable[] = { +{"door_create", 3, DEC, NOV, HEX, HEX, DFL}, /* 0 */ +{"door_revoke", 1, DEC, NOV, DEC}, /* 1 */ +{"door_info", 2, DEC, NOV, DEC, HEX}, /* 2 */ +{"door_call", 2, DEC, NOV, DEC, HEX}, /* 3 */ +{"door_return", 4, DEC, NOV, HEX, DEC, HEX, DEC}, /* 4 (old) */ +{"door_cred", 1, DEC, NOV, HEX}, /* 5 (old) */ +{"door_bind", 1, DEC, NOV, DEC}, /* 6 */ +{"door_unbind", 0, DEC, NOV}, /* 7 */ +{"door_unref", 0, DEC, NOV}, /* 8 */ +{"door_ucred", 1, DEC, NOV, HEX}, /* 9 */ +{"door_return", 5, DEC, NOV, HEX, DEC, HEX, HEX, DEC}, /* 10 */ +{"door_getparam", 3, DEC, NOV, DEC, DPM, HEX}, /* 11 */ +{"door_setparam", 3, DEC, NOV, DEC, DPM, DEC}, /* 12 */ +}; +#define NDOORCODE (sizeof (doortable) / sizeof (struct systable)) + +const struct systable psettable[] = { +{"pset_create", 2, DEC, NOV, HID, HEX}, /* 0 */ +{"pset_destroy", 2, DEC, NOV, HID, PST}, /* 1 */ +{"pset_assign", 4, DEC, NOV, HID, PST, DEC, HEX}, /* 2 */ +{"pset_info", 5, DEC, NOV, HID, PST, HEX, HEX, HEX}, /* 3 */ +{"pset_bind", 5, DEC, NOV, HID, PST, IDT, DEC, HEX}, /* 4 */ +{"pset_getloadavg", 4, DEC, NOV, HID, PST, HEX, DEC}, /* 5 */ +{"pset_list", 3, DEC, NOV, HID, HEX, HEX}, /* 6 */ +{"pset_setattr", 3, DEC, NOV, HID, PST, HEX}, /* 7 */ +{"pset_getattr", 3, DEC, NOV, HID, PST, HEX}, /* 8 */ +{"pset_assign_forced", 4, DEC, NOV, HID, PST, DEC, HEX}, /* 9 */ +}; +#define NPSETCODE (sizeof (psettable) / sizeof (struct systable)) + +const struct systable lwpcreatetable[] = { +{"lwp_create", 3, DEC, NOV, HEX, LWF, HEX}, /* 0 */ +{"lwp_create", 0, DEC, NOV}, /* 1 */ +}; +#define NLWPCREATECODE (sizeof (lwpcreatetable) / sizeof (struct systable)) + +static const struct systable tasksystable[] = { +{"settaskid", 3, DEC, NOV, HID, DEC, HEX}, /* 0 */ +{"gettaskid", 1, DEC, NOV, HID}, /* 1 */ +{"getprojid", 1, DEC, NOV, HID}, /* 2 */ +}; +#define NTASKSYSCODE (sizeof (tasksystable) / sizeof (struct systable)) + +static const struct systable privsystable[] = { +{"setppriv", 4, DEC, NOV, HID, PRO, PRN, PRS}, /* 0 */ +{"getppriv", 4, DEC, NOV, HID, HID, PRN, PRS}, /* 1 */ +{"getprivimplinfo", 5, DEC, NOV, HID, HID, HID, HEX, DEC}, /* 2 */ +{"setpflags", 3, DEC, NOV, HID, PFL, DEC}, /* 3 */ +{"getpflags", 2, DEC, NOV, HID, PFL}, /* 4 */ +{"issetugid", 0, DEC, NOV, HID}, /* 5 */ +}; +#define NPRIVSYSCODE (sizeof (privsystable) / sizeof (struct systable)) + +static const struct systable exacctsystable[] = { +{"getacct", 5, DEC, NOV, HID, IDT, DEC, HEX, UNS}, /* 0 */ +{"putacct", 6, DEC, NOV, HID, IDT, DEC, HEX, UNS, HEX}, /* 1 */ +{"wracct", 4, DEC, NOV, HID, IDT, DEC, HEX}, /* 2 */ +}; +#define NEXACCTSYSCODE (sizeof (exacctsystable) / sizeof (struct systable)) + +static const struct systable lwpparktable[] = { +{"lwp_park", 3, DEC, NOV, HID, HEX, DEC}, /* 0 */ +{"lwp_unpark", 2, DEC, NOV, HID, DEC}, /* 1 */ +{"lwp_unpark_all", 3, DEC, NOV, HID, HEX, DEC}, /* 2 */ +{"lwp_unpark_cancel", 2, DEC, NOV, HID, DEC}, /* 3 */ +{"lwp_set_park", 3, DEC, NOV, HID, HEX, DEC}, /* 4 */ +}; +#define NLWPPARKCODE (sizeof (lwpparktable) / sizeof (struct systable)) + +static const struct systable lwprwlocktable[] = { +{"lwp_rwlock_rdlock", 3, DEC, NOV, HID, HEX, HEX}, /* 0 */ +{"lwp_rwlock_wrlock", 3, DEC, NOV, HID, HEX, HEX}, /* 1 */ +{"lwp_rwlock_tryrdlock", 2, DEC, NOV, HID, HEX}, /* 2 */ +{"lwp_rwlock_trywrlock", 2, DEC, NOV, HID, HEX}, /* 3 */ +{"lwp_rwlock_unlock", 2, DEC, NOV, HID, HEX}, /* 4 */ +}; +#define NLWPRWLOCKCODE (sizeof (lwprwlocktable) / sizeof (struct systable)) + +static const struct systable sendfilevsystable[] = { +{"sendfilev", 5, DEC, NOV, DEC, DEC, HEX, DEC, HEX}, /* 0 */ +{"sendfilev64", 5, DEC, NOV, DEC, DEC, HEX, DEC, HEX}, /* 1 */ +}; +#define NSENDFILESYSCODE \ + (sizeof (sendfilevsystable) / sizeof (struct systable)) + +static const struct systable lgrpsystable[] = { +{"meminfo", 3, DEC, NOV, HID, NOV, MIF}, /* 0 */ +{"_lgrpsys", 3, DEC, NOV, DEC, DEC, NOV}, /* 1 */ +{"lgrp_version", 3, DEC, NOV, HID, DEC, NOV}, /* 2 */ +{"_lgrpsys", 3, DEC, NOV, DEC, HEX, HEX}, /* 3 */ +{"lgrp_affinity_get", 3, DEC, NOV, HID, NOV, LAF}, /* 4 */ +{"lgrp_affinity_set", 3, DEC, NOV, HID, NOV, LAF}, /* 5 */ +{"lgrp_latency", 3, DEC, NOV, HID, DEC, DEC}, /* 6 */ +}; +#define NLGRPSYSCODE (sizeof (lgrpsystable) / sizeof (struct systable)) + +static const struct systable rusagesystable[] = { +{"getrusage", 2, DEC, NOV, HID, HEX}, /* 0 */ +{"getrusage_chld", 2, DEC, NOV, HID, HEX}, /* 1 */ +{"getrusage_lwp", 2, DEC, NOV, HID, HEX}, /* 2 */ +{"getvmusage", 5, DEC, NOV, HID, HEX, DEC, HEX, HEX}, /* 3 */ +}; +#define NRUSAGESYSCODE \ + (sizeof (rusagesystable) / sizeof (struct systable)) + +static const struct systable ucredsystable[] = { +{"ucred_get", 3, DEC, NOV, HID, DEC, HEX}, +{"getpeerucred", 3, DEC, NOV, HID, DEC, HEX}, +}; +#define NUCREDSYSCODE \ + (sizeof (ucredsystable) / sizeof (struct systable)) + +const struct systable portfstable[] = { +{"port_create", 2, DEC, NOV, HID, DEC}, /* 0 */ +{"port_associate", 6, DEC, NOV, HID, DEC, DEC, HEX, HEX, HEX}, /* 1 */ +{"port_dissociate", 4, DEC, NOV, HID, DEC, DEC, HEX}, /* 2 */ +{"port_send", 4, DEC, NOV, HID, DEC, HEX, HEX}, /* 3 */ +{"port_sendn", 6, DEC, DEC, HID, HEX, HEX, DEC, HEX, HEX}, /* 4 */ +{"port_get", 4, DEC, NOV, HID, DEC, HEX, HEX}, /* 5 */ +{"port_getn", 6, DEC, DEC, HID, DEC, HEX, DEC, DEC, HEX}, /* 6 */ +{"port_alert", 5, DEC, NOV, HID, DEC, HEX, HEX, HEX}, /* 7 */ +{"port_dispatch", 6, DEC, NOV, HID, DEC, DEC, HEX, HEX, HEX}, /* 8 */ +}; +#define NPORTCODE (sizeof (portfstable) / sizeof (struct systable)) + +static const struct systable zonetable[] = { +{"zone_create", 2, DEC, NOV, HID, HEX}, /* 0 */ +{"zone_destroy", 2, DEC, NOV, HID, DEC}, /* 1 */ +{"zone_getattr", 5, DEC, NOV, HID, DEC, ZGA, HEX, DEC}, /* 2 */ +{"zone_enter", 2, DEC, NOV, HID, DEC}, /* 3 */ +{"zone_list", 3, DEC, NOV, HID, HEX, HEX}, /* 4 */ +{"zone_shutdown", 2, DEC, NOV, HID, DEC}, /* 5 */ +{"zone_lookup", 2, DEC, NOV, HID, STG}, /* 6 */ +{"zone_boot", 2, DEC, NOV, HID, DEC}, /* 7 */ +{"zone_version", 2, HEX, NOV, HID, DEC}, /* 8 */ +{"zone_setattr", 5, DEC, NOV, HID, DEC, ZGA, HEX, DEC}, /* 9 */ +{"zone_add_datalink", 3, DEC, NOV, HID, DEC, STG}, /* 10 */ +{"zone_remove_datalink", 3, DEC, NOV, HID, DEC, STG}, /* 11 */ +{"zone_check_datalink", 3, DEC, NOV, HID, HEX, STG}, /* 12 */ +{"zone_list_datalink", 4, DEC, NOV, HID, DEC, HEX, HEX}, /* 13 */ +}; +#define NZONECODE (sizeof (zonetable) / sizeof (struct systable)) + +static const struct systable labeltable[] = { +{"labelsys", 3, DEC, NOV, HID, HEX, HEX}, /* 0 */ +{"is_system_labeled", 1, DEC, NOV, HID}, /* 1 */ +{"tnrh", 3, DEC, NOV, HID, TND, HEX}, /* 2 */ +{"tnrhtp", 3, DEC, NOV, HID, TND, HEX}, /* 3 */ +{"tnmlp", 3, DEC, NOV, HID, TND, HEX}, /* 4 */ +{"getlabel", 3, DEC, NOV, HID, STG, HEX}, /* 5 */ +{"fgetlabel", 3, DEC, NOV, HID, DEC, HEX}, /* 6 */ +}; +#define NLABELCODE (sizeof (labeltable) / sizeof (struct systable)) + +const struct systable forktable[] = { +/* parent codes */ +{"forkx", 2, DEC, NOV, HID, FXF}, /* 0 */ +{"forkallx", 2, DEC, NOV, HID, FXF}, /* 1 */ +{"vforkx", 2, DEC, NOV, HID, FXF}, /* 2 */ +/* child codes */ +{"forkx", 0, DEC, NOV}, /* 3 */ +{"forkallx", 0, DEC, NOV}, /* 4 */ +{"vforkx", 0, DEC, NOV}, /* 5 */ +}; +#define NFORKCODE (sizeof (forktable) / sizeof (struct systable)) + +const struct systable sidsystable[] = { +{"allocids", 4, UNS, UNS, HID, DEC, DEC, DEC}, /* 0 */ +{"idmap_reg", 2, DEC, NOV, HID, DEC}, /* 1 */ +{"idmap_unreg", 2, DEC, NOV, HID, DEC}, /* 2 */ +}; +#define NSIDSYSCODE (sizeof (sidsystable) / sizeof (struct systable)) + +const struct systable utimesystable[] = { +{"futimens", 3, DEC, NOV, HID, DEC, HEX}, /* 0 */ +{"utimensat", 5, DEC, NOV, HID, ATC, STG, HEX, SNF}, /* 1 */ +}; +#define NUTIMESYSCODE (sizeof (utimesystable) / sizeof (struct systable)) + +const struct systable sockconfigtable[] = { +{"sockconfig", 5, DEC, NOV, SKC, DEC, DEC, DEC, STG}, /* 0 */ +{"sockconfig", 4, DEC, NOV, SKC, DEC, DEC, DEC}, /* 1 */ +{"sockconfig", 3, DEC, NOV, SKC, STG, HEX }, /* 2 */ +{"sockconfig", 2, DEC, NOV, SKC, STG }, /* 3 */ +}; +#define NSOCKCONFIGCODE (sizeof (sockconfigtable) / sizeof (struct systable)) + +const struct sysalias sysalias[] = { + { "exit", SYS_exit }, + { "fork", SYS_forksys }, + { "fork1", SYS_forksys }, + { "forkall", SYS_forksys }, + { "forkx", SYS_forksys }, + { "forkallx", SYS_forksys }, + { "vforkx", SYS_forksys }, + { "sbrk", SYS_brk }, + { "getppid", SYS_getpid }, + { "geteuid", SYS_getuid }, + { "getpgrp", SYS_pgrpsys }, + { "setpgrp", SYS_pgrpsys }, + { "getsid", SYS_pgrpsys }, + { "setsid", SYS_pgrpsys }, + { "getpgid", SYS_pgrpsys }, + { "setpgid", SYS_pgrpsys }, + { "getegid", SYS_getgid }, + { "msgget", SYS_msgsys }, + { "msgctl", SYS_msgsys }, + { "msgctl64", SYS_msgsys }, + { "msgrcv", SYS_msgsys }, + { "msgsnd", SYS_msgsys }, + { "msgids", SYS_msgsys }, + { "msgsnap", SYS_msgsys }, + { "msgop", SYS_msgsys }, + { "shmat", SYS_shmsys }, + { "shmctl", SYS_shmsys }, + { "shmctl64", SYS_shmsys }, + { "shmdt", SYS_shmsys }, + { "shmget", SYS_shmsys }, + { "shmids", SYS_shmsys }, + { "shmop", SYS_shmsys }, + { "semctl", SYS_semsys }, + { "semctl64", SYS_semsys }, + { "semget", SYS_semsys }, + { "semids", SYS_semsys }, + { "semop", SYS_semsys }, + { "semtimedop", SYS_semsys }, + { "uname", SYS_utssys }, + { "ustat", SYS_utssys }, + { "fusers", SYS_utssys }, + { "exec", SYS_execve }, + { "execl", SYS_execve }, + { "execv", SYS_execve }, + { "execle", SYS_execve }, + { "execlp", SYS_execve }, + { "execvp", SYS_execve }, + { "sigfillset", SYS_sigpending }, + { "getcontext", SYS_context }, + { "setcontext", SYS_context }, + { "getustack", SYS_context }, + { "setustack", SYS_context }, + { "hrtcntl", SYS_hrtsys }, + { "hrtalarm", SYS_hrtsys }, + { "hrtsleep", SYS_hrtsys }, + { "hrtcancel", SYS_hrtsys }, + { "aioread", SYS_kaio }, + { "aiowrite", SYS_kaio }, + { "aiowait", SYS_kaio }, + { "aiocancel", SYS_kaio }, + { "aionotify", SYS_kaio }, + { "audit", SYS_auditsys }, + { "door_create", SYS_door }, + { "door_revoke", SYS_door }, + { "door_info", SYS_door }, + { "door_call", SYS_door }, + { "door_return", SYS_door }, + { "door_bind", SYS_door }, + { "door_unbind", SYS_door }, + { "door_unref", SYS_door }, + { "door_ucred", SYS_door }, + { "door_getparam", SYS_door }, + { "door_setparam", SYS_door }, + { "pset_create", SYS_pset }, + { "pset_destroy", SYS_pset }, + { "pset_assign", SYS_pset }, + { "pset_info", SYS_pset }, + { "pset_bind", SYS_pset }, + { "pset_getloadavg", SYS_pset }, + { "pset_list", SYS_pset }, + { "pset_setattr", SYS_pset }, + { "pset_getattr", SYS_pset }, + { "pset_assign_forced", SYS_pset }, + { "settaskid", SYS_tasksys }, + { "gettaskid", SYS_tasksys }, + { "getprojid", SYS_tasksys }, + { "setppriv", SYS_privsys }, + { "getppriv", SYS_privsys }, + { "getprivimplinfo", SYS_privsys }, + { "setpflags", SYS_privsys }, + { "getpflags", SYS_privsys }, + { "getacct", SYS_exacctsys }, + { "putacct", SYS_exacctsys }, + { "wracct", SYS_exacctsys }, + { "lwp_cond_timedwait", SYS_lwp_cond_wait }, + { "lwp_sema_wait", SYS_lwp_sema_timedwait }, + { "lwp_park", SYS_lwp_park }, + { "lwp_unpark", SYS_lwp_park }, + { "lwp_unpark_all", SYS_lwp_park }, + { "lwp_rwlock_rdlock", SYS_lwp_rwlock_sys }, + { "lwp_rwlock_wrlock", SYS_lwp_rwlock_sys }, + { "lwp_rwlock_tryrdlock", SYS_lwp_rwlock_sys }, + { "lwp_rwlock_trywrlock", SYS_lwp_rwlock_sys }, + { "lwp_rwlock_unlock", SYS_lwp_rwlock_sys }, + { "lwp_mutex_lock", SYS_lwp_mutex_timedlock }, + { "sendfilev64", SYS_sendfilev }, + { "creat", SYS_open }, + { "creat64", SYS_open64 }, + { "openattrdirat", SYS_openat }, + { "lgrpsys", SYS_lgrpsys }, + { "getrusage", SYS_rusagesys }, + { "getrusage_chld", SYS_rusagesys }, + { "getrusage_lwp", SYS_rusagesys }, + { "getvmusage", SYS_rusagesys }, + { "getpeerucred", SYS_ucredsys }, + { "ucred_get", SYS_ucredsys }, + { "port_create", SYS_port }, + { "port_associate", SYS_port }, + { "port_dissociate", SYS_port }, + { "port_send", SYS_port }, + { "port_sendn", SYS_port }, + { "port_get", SYS_port }, + { "port_getn", SYS_port }, + { "port_alert", SYS_port }, + { "port_dispatch", SYS_port }, + { "zone_create", SYS_zone }, + { "zone_destroy", SYS_zone }, + { "zone_getattr", SYS_zone }, + { "zone_setattr", SYS_zone }, + { "zone_enter", SYS_zone }, + { "getzoneid", SYS_zone }, + { "zone_list", SYS_zone }, + { "zone_shutdown", SYS_zone }, + { "zone_add_datalink", SYS_zone }, + { "zone_remove_datalink", SYS_zone }, + { "zone_check_datalink", SYS_zone }, + { "zone_list_datalink", SYS_zone }, + { "is_system_labeled", SYS_labelsys }, + { "tnrh", SYS_labelsys }, + { "tnrhtp", SYS_labelsys }, + { "tnmlp", SYS_labelsys }, + { "getlabel", SYS_labelsys }, + { "fgetlabel", SYS_labelsys }, + { "getrctl", SYS_rctlsys }, + { "setrctl", SYS_rctlsys }, + { "rctlsys_lst", SYS_rctlsys }, + { "rctlsys_ctl", SYS_rctlsys }, + { "allocids", SYS_sidsys }, + { "futimens", SYS_utimesys }, + { "utimensat", SYS_utimesys }, + { "poll", SYS_pollsys }, + { "umount", SYS_umount2 }, + { "wait", SYS_waitid }, + { NULL, 0 } /* end-of-list */ +}; + +/* + * Return structure to interpret system call with sub-codes. + */ +const struct systable * +subsys(int syscall, int subcode) +{ + const struct systable *stp = NULL; + + if (subcode != -1) { + switch (syscall) { + case SYS_faccessat: + if ((unsigned)subcode < NACCESSCODE) + stp = &faccessattable[subcode]; + break; + case SYS_fchmodat: + if ((unsigned)subcode < NCHMODCODE) + stp = &fchmodattable[subcode]; + break; + case SYS_fchownat: + if ((unsigned)subcode < NCHOWNCODE) + stp = &fchownattable[subcode]; + break; + case SYS_mkdirat: + if ((unsigned)subcode < NMKDIRCODE) + stp = &mkdiratattable[subcode]; + break; + case SYS_mknodat: + if ((unsigned)subcode < NMKMODCODE) + stp = &mknodatattable[subcode]; + break; + case SYS_renameat: + if ((unsigned)subcode < NRENAMECODE) + stp = &renameattable[subcode]; + break; + case SYS_linkat: + if ((unsigned)subcode < NLINKATCODE) + stp = &linkattable[subcode]; + break; + case SYS_unlinkat: + if ((unsigned)subcode < NUNLINKCODE) + stp = &unlinkattable[subcode]; + break; + case SYS_symlinkat: + if ((unsigned)subcode < NSYMLINKCODE) + stp = &symlinkattable[subcode]; + break; + case SYS_readlinkat: + if ((unsigned)subcode < NREADLINKCODE) + stp = &readlinkattable[subcode]; + break; + case SYS_fstatat: + if ((unsigned)subcode < NSTATCODE) + stp = &fstatattable[subcode]; + break; + case SYS_fstatat64: + if ((unsigned)subcode < NSTAT64CODE) + stp = &fstatat64table[subcode]; + break; + case SYS_openat: + if ((unsigned)subcode < NOPENATCODE) + stp = &openattable[subcode]; + break; + case SYS_openat64: + if ((unsigned)subcode < NOPENAT64CODE) + stp = &openat64table[subcode]; + break; + case SYS_open: + if ((unsigned)subcode < NOPENCODE) + stp = &opentable[subcode]; + break; + case SYS_open64: + if ((unsigned)subcode < NOPEN64CODE) + stp = &open64table[subcode]; + break; + case SYS_msgsys: /* msgsys() */ + if ((unsigned)subcode < NMSGCODE) + stp = &msgtable[subcode]; + break; + case SYS_semsys: /* semsys() */ + if ((unsigned)subcode < NSEMCODE) + stp = &semtable[subcode]; + break; + case SYS_shmsys: /* shmsys() */ + if ((unsigned)subcode < NSHMCODE) + stp = &shmtable[subcode]; + break; + case SYS_pgrpsys: /* pgrpsys() */ + if ((unsigned)subcode < NPIDCODE) + stp = &pidtable[subcode]; + break; + case SYS_utssys: /* utssys() */ + if ((unsigned)subcode < NUTSCODE) + stp = &utstable[subcode]; + break; + case SYS_sysfs: /* sysfs() */ + if ((unsigned)subcode < NSFSCODE) + stp = &sfstable[subcode]; + break; + case SYS_sigpending: /* sigpending()/sigfillset() */ + if ((unsigned)subcode < NSGPCODE) + stp = &sgptable[subcode]; + break; + case SYS_context: /* [get|set]context() */ + if ((unsigned)subcode < NCTXCODE) + stp = &ctxtable[subcode]; + break; + case SYS_hrtsys: /* hrtsys() */ + if ((unsigned)subcode < NHRTCODE) + stp = &hrttable[subcode]; + break; + case SYS_corectl: /* corectl() */ + if ((unsigned)subcode < NCORCODE) + stp = &cortable[subcode]; + break; + case SYS_kaio: /* kaio() */ + if ((unsigned)subcode < NAIOCODE) + stp = &aiotable[subcode]; + break; + case SYS_door: /* doors */ + if ((unsigned)subcode < NDOORCODE) + stp = &doortable[subcode]; + break; + case SYS_pset: /* pset() */ + if ((unsigned)subcode < NPSETCODE) + stp = &psettable[subcode]; + break; + case SYS_lwp_create: /* lwp_create() */ + if ((unsigned)subcode < NLWPCREATECODE) + stp = &lwpcreatetable[subcode]; + break; + case SYS_tasksys: /* tasks */ + if ((unsigned)subcode < NTASKSYSCODE) + stp = &tasksystable[subcode]; + break; + case SYS_exacctsys: /* exacct */ + if ((unsigned)subcode < NEXACCTSYSCODE) + stp = &exacctsystable[subcode]; + break; + case SYS_privsys: /* privileges */ + if ((unsigned)subcode < NPRIVSYSCODE) + stp = &privsystable[subcode]; + break; + case SYS_lwp_park: /* lwp_park */ + if ((unsigned)subcode < NLWPPARKCODE) + stp = &lwpparktable[subcode]; + break; + case SYS_lwp_rwlock_sys: + if ((unsigned)subcode < NLWPRWLOCKCODE) + stp = &lwprwlocktable[subcode]; + break; + case SYS_sendfilev: /* sendfilev */ + if ((unsigned)subcode < NSENDFILESYSCODE) + stp = &sendfilevsystable[subcode]; + break; + case SYS_lgrpsys: /* lgrpsys */ + if ((unsigned)subcode < NLGRPSYSCODE) + stp = &lgrpsystable[subcode]; + break; + case SYS_rusagesys: /* rusagesys */ + if ((unsigned)subcode < NRUSAGESYSCODE) + stp = &rusagesystable[subcode]; + break; + case SYS_fcntl: /* fcntl */ + if ((unsigned)subcode < NFCNTLCODE) + stp = &fcntltable[subcode]; + break; + case SYS_ucredsys: + if ((unsigned)subcode < NUCREDSYSCODE) + stp = &ucredsystable[subcode]; + break; + case SYS_port: /* portfs */ + if ((unsigned)subcode < NPORTCODE) + stp = &portfstable[subcode]; + break; + case SYS_zone: /* zone family */ + if ((unsigned)subcode < NZONECODE) + stp = &zonetable[subcode]; + break; + case SYS_labelsys: /* label family */ + if ((unsigned)subcode < NLABELCODE) + stp = &labeltable[subcode]; + break; + case SYS_rctlsys: /* rctl family */ + if ((unsigned)subcode < NRCTLCODE) + stp = &rctltable[subcode]; + break; + case SYS_forksys: /* fork family */ + if ((unsigned)subcode < NFORKCODE) + stp = &forktable[subcode]; + break; + case SYS_sidsys: /* SID family */ + if ((unsigned)subcode < NSIDSYSCODE) + stp = &sidsystable[subcode]; + break; + case SYS_utimesys: /* utime family */ + if ((unsigned)subcode < NUTIMESYSCODE) + stp = &utimesystable[subcode]; + break; + case SYS_sockconfig: /* sockconfig family */ + if ((unsigned)subcode < NSOCKCONFIGCODE) + stp = &sockconfigtable[subcode]; + break; + } + } + + if (stp == NULL) + stp = &systable[((unsigned)syscall < SYSEND)? syscall : 0]; + + return (stp); +} + +/* + * Return the name of the system call. + */ +const char * +sysname(private_t *pri, int syscall, int subcode) +{ + const struct systable *stp = subsys(syscall, subcode); + const char *name = stp->name; /* may be NULL */ + + if (name == NULL) { /* manufacture a name */ + (void) sprintf(pri->sys_name, "sys#%d", syscall); + name = pri->sys_name; + } + + return (name); +} + +/* + * Return the name of the signal. + * Return NULL if unknown signal. + */ +const char * +rawsigname(private_t *pri, int sig) +{ + /* + * The C library function sig2str() omits the leading "SIG". + */ + (void) strcpy(pri->raw_sig_name, "SIG"); + + if (sig > 0 && sig2str(sig, pri->raw_sig_name+3) == 0) + return (pri->raw_sig_name); + return (NULL); +} + +/* + * Return the name of the signal. + * Manufacture a name for unknown signal. + */ +const char * +signame(private_t *pri, int sig) +{ + const char *name = rawsigname(pri, sig); + + if (name == NULL) { /* manufacture a name */ + (void) sprintf(pri->sig_name, "SIG#%d", sig); + name = pri->sig_name; + } + + return (name); +} + +/* + * Determine the subcode for this syscall, if any. + */ +int +getsubcode(private_t *pri) +{ + const lwpstatus_t *Lsp = pri->lwpstat; + int syscall = Lsp->pr_syscall; + int nsysarg = Lsp->pr_nsysarg; + int subcode = -1; + int arg0; + + if (syscall > 0 && nsysarg > 0 && !prismember(&rawout, syscall)) { + arg0 = Lsp->pr_sysarg[0]; + switch (syscall) { + case SYS_utssys: /* utssys() */ + if (nsysarg > 2) + subcode = Lsp->pr_sysarg[2]; + break; + case SYS_faccessat: + if (nsysarg > 3) + subcode = ((int)Lsp->pr_sysarg[0] == AT_FDCWD && + Lsp->pr_sysarg[3] == 0)? 1 : 0; + break; + case SYS_fchmodat: + if (nsysarg > 1 && Lsp->pr_sysarg[1] == NULL) { + subcode = 3; + break; + } + if (nsysarg > 0 && (int)Lsp->pr_sysarg[0] != AT_FDCWD) { + subcode = 0; + break; + } + if (nsysarg > 3) + subcode = (Lsp->pr_sysarg[3] == 0)? 1 : + (Lsp->pr_sysarg[3] == AT_SYMLINK_NOFOLLOW)? + 2 : 0; + break; + case SYS_fchownat: + if (nsysarg > 1 && Lsp->pr_sysarg[1] == NULL) { + subcode = 3; + break; + } + if (nsysarg > 0 && (int)Lsp->pr_sysarg[0] != AT_FDCWD) { + subcode = 0; + break; + } + if (nsysarg > 4) + subcode = (Lsp->pr_sysarg[4] == 0)? 1 : + (Lsp->pr_sysarg[4] == AT_SYMLINK_NOFOLLOW)? + 2 : 0; + break; + case SYS_mkdirat: + case SYS_mknodat: + case SYS_readlinkat: + if (nsysarg > 0) + subcode = ((int)Lsp->pr_sysarg[0] == AT_FDCWD)? + 1 : 0; + break; + case SYS_renameat: + if (nsysarg > 2) + subcode = ((int)Lsp->pr_sysarg[0] == AT_FDCWD && + (int)Lsp->pr_sysarg[2] == AT_FDCWD)? 1 : 0; + break; + case SYS_linkat: + if (nsysarg > 4) + subcode = ((int)Lsp->pr_sysarg[0] == AT_FDCWD && + (int)Lsp->pr_sysarg[2] == AT_FDCWD && + Lsp->pr_sysarg[4] == 0)? 1 : 0; + break; + case SYS_unlinkat: + if (nsysarg > 2) + subcode = + ((int)Lsp->pr_sysarg[0] != AT_FDCWD)? 0 : + (Lsp->pr_sysarg[2] == AT_REMOVEDIR)? 2 : + (Lsp->pr_sysarg[2] == 0)? 1 : 0; + break; + case SYS_symlinkat: + if (nsysarg > 1) + subcode = ((int)Lsp->pr_sysarg[1] == AT_FDCWD)? + 1 : 0; + break; + case SYS_fstatat: + case SYS_fstatat64: + if (nsysarg > 1 && Lsp->pr_sysarg[1] == NULL) { + subcode = 3; + break; + } + if (nsysarg > 0 && (int)Lsp->pr_sysarg[0] != AT_FDCWD) { + subcode = 0; + break; + } + if (nsysarg > 3) + subcode = (Lsp->pr_sysarg[3] == 0)? 1 : + (Lsp->pr_sysarg[3] == AT_SYMLINK_NOFOLLOW)? + 2 : 0; + break; + case SYS_openat: /* openat() w/ and w/o AT_FDCWD */ + case SYS_openat64: /* and with and w/o O_CREAT */ + if (nsysarg > 2) + subcode = ((int)Lsp->pr_sysarg[0] == AT_FDCWD)? + ((Lsp->pr_sysarg[2] & O_CREAT)? 3 : 2) : + ((Lsp->pr_sysarg[2] & O_CREAT)? 1 : 0); + break; + case SYS_open: /* open() w/ and w/o O_CREAT */ + case SYS_open64: + if (nsysarg > 1) + subcode = (Lsp->pr_sysarg[1] & O_CREAT)? 1 : 0; + break; + case SYS_kaio: /* kaio() */ + subcode = arg0 & ~AIO_POLL_BIT; + break; + case SYS_door: /* doors */ + if (nsysarg > 5) + subcode = Lsp->pr_sysarg[5]; + break; + case SYS_lwp_create: /* lwp_create() */ + subcode = /* 0 for parent, 1 for child */ + (Lsp->pr_why == PR_SYSEXIT && Lsp->pr_errno == 0 && + Lsp->pr_rval1 == 0); + break; + case SYS_forksys: /* forksys */ + subcode = arg0; + if (Lsp->pr_why == PR_SYSEXIT && Lsp->pr_errno == 0 && + pri->Rval2 != 0) /* this is the child */ + subcode += 3; + break; + case SYS_msgsys: /* msgsys() */ + case SYS_semsys: /* semsys() */ + case SYS_shmsys: /* shmsys() */ + case SYS_pgrpsys: /* pgrpsys() */ + case SYS_sysfs: /* sysfs() */ + case SYS_sigpending: /* sigpending()/sigfillset() */ + case SYS_context: /* [get|set]context() */ + case SYS_hrtsys: /* hrtsys() */ + case SYS_corectl: /* corectl() */ + case SYS_pset: /* pset() */ + case SYS_tasksys: /* tasks */ + case SYS_privsys: /* privileges */ + case SYS_exacctsys: /* exacct */ + case SYS_lwp_park: /* lwp_park */ + case SYS_lwp_rwlock_sys: /* lwp_rwlock_*() */ + case SYS_sendfilev: /* sendfilev */ + case SYS_lgrpsys: /* lgrpsys */ + case SYS_rusagesys: /* rusagesys */ + case SYS_ucredsys: /* ucredsys */ + case SYS_zone: /* zone */ + case SYS_labelsys: /* labelsys */ + case SYS_rctlsys: /* rctlsys */ + case SYS_sidsys: /* sidsys */ + case SYS_utimesys: /* utimesys */ + case SYS_sockconfig: /* sockconfig */ + subcode = arg0; + break; + case SYS_fcntl: /* fcntl() */ + if (nsysarg > 2) { + switch (Lsp->pr_sysarg[1]) { + default: subcode = 0; break; + case F_GETFL: + case F_GETOWN: + case F_GETXFL: subcode = 1; break; + case F_SETFL: subcode = 2; break; + } + } + break; + case SYS_port: /* portfs */ + subcode = arg0 & PORT_CODE_MASK; + break; + } + } + + return (subcode); +} + +/* + * Return the maximum number of system calls, counting + * all system calls with subcodes as separate calls. + */ +int +maxsyscalls() +{ + return (PRMAXSYS + 1 + + NACCESSCODE - 1 + + NCHMODCODE - 1 + + NCHOWNCODE - 1 + + NMKDIRCODE - 1 + + NMKMODCODE - 1 + + NRENAMECODE - 1 + + NLINKATCODE - 1 + + NUNLINKCODE - 1 + + NSYMLINKCODE - 1 + + NREADLINKCODE - 1 + + NSTATCODE - 1 + + NSTAT64CODE - 1 + + NOPENATCODE - 1 + + NOPENAT64CODE - 1 + + NOPENCODE - 1 + + NOPEN64CODE - 1 + + NMSGCODE - 1 + + NSEMCODE - 1 + + NSHMCODE - 1 + + NPIDCODE - 1 + + NSFSCODE - 1 + + NUTSCODE - 1 + + NSGPCODE - 1 + + NCTXCODE - 1 + + NHRTCODE - 1 + + NCORCODE - 1 + + NAIOCODE - 1 + + NDOORCODE - 1 + + NPSETCODE - 1 + + NLWPCREATECODE - 1 + + NTASKSYSCODE - 1 + + NEXACCTSYSCODE - 1 + + NLWPPARKCODE - 1 + + NLWPRWLOCKCODE - 1 + + NSENDFILESYSCODE - 1 + + NLGRPSYSCODE - 1 + + NRUSAGESYSCODE - 1 + + NFCNTLCODE - 1 + + NPRIVSYSCODE - 1 + + NUCREDSYSCODE - 1 + + NPORTCODE - 1 + + NZONECODE - 1 + + NLABELCODE - 1 + + NRCTLCODE - 1 + + NFORKCODE - 1 + + NSIDSYSCODE - 1 + + NUTIMESYSCODE - 1 + + NSOCKCONFIGCODE - 1); +} + +/* + * Return the number of subcodes for the specified system call number. + */ +int +nsubcodes(int syscall) +{ + switch (syscall) { + case SYS_faccessat: + return (NACCESSCODE); + case SYS_fchmodat: + return (NCHMODCODE); + case SYS_fchownat: + return (NCHOWNCODE); + case SYS_mkdirat: + return (NMKDIRCODE); + case SYS_mknodat: + return (NMKMODCODE); + case SYS_renameat: + return (NRENAMECODE); + case SYS_linkat: + return (NLINKATCODE); + case SYS_unlinkat: + return (NUNLINKCODE); + case SYS_symlinkat: + return (NSYMLINKCODE); + case SYS_readlinkat: + return (NREADLINKCODE); + case SYS_fstatat: + return (NSTATCODE); + case SYS_fstatat64: + return (NSTAT64CODE); + case SYS_openat: + return (NOPENATCODE); + case SYS_openat64: + return (NOPENAT64CODE); + case SYS_open: + return (NOPENCODE); + case SYS_open64: + return (NOPEN64CODE); + case SYS_msgsys: + return (NMSGCODE); + case SYS_semsys: + return (NSEMCODE); + case SYS_shmsys: + return (NSHMCODE); + case SYS_pgrpsys: + return (NPIDCODE); + case SYS_utssys: + return (NUTSCODE); + case SYS_sysfs: + return (NSFSCODE); + case SYS_sigpending: + return (NSGPCODE); + case SYS_context: + return (NCTXCODE); + case SYS_hrtsys: + return (NHRTCODE); + case SYS_corectl: + return (NCORCODE); + case SYS_kaio: + return (NAIOCODE); + case SYS_door: + return (NDOORCODE); + case SYS_pset: + return (NPSETCODE); + case SYS_lwp_create: + return (NLWPCREATECODE); + case SYS_tasksys: + return (NTASKSYSCODE); + case SYS_exacctsys: + return (NEXACCTSYSCODE); + case SYS_privsys: + return (NPRIVSYSCODE); + case SYS_lwp_park: + return (NLWPPARKCODE); + case SYS_lwp_rwlock_sys: + return (NLWPRWLOCKCODE); + case SYS_sendfilev: + return (NSENDFILESYSCODE); + case SYS_lgrpsys: + return (NLGRPSYSCODE); + case SYS_rusagesys: + return (NRUSAGESYSCODE); + case SYS_fcntl: + return (NFCNTLCODE); + case SYS_ucredsys: + return (NUCREDSYSCODE); + case SYS_port: + return (NPORTCODE); + case SYS_zone: + return (NZONECODE); + case SYS_labelsys: + return (NLABELCODE); + case SYS_rctlsys: + return (NRCTLCODE); + case SYS_forksys: + return (NFORKCODE); + case SYS_sidsys: + return (NSIDSYSCODE); + case SYS_utimesys: + return (NUTIMESYSCODE); + case SYS_sockconfig: + return (NSOCKCONFIGCODE); + default: + return (1); + } +} + + + +/* Socket address families (and protocol families) */ +const char * const afcodes[] = { + "UNSPEC", /* 0 */ + "UNIX", /* 1 */ + "INET", /* 2 */ + "IMPLINK", /* 3 */ + "PUP", /* 4 */ + "CHAOS", /* 5 */ + "NS", /* 6 */ + "NBS", /* 7 */ + "ECMA", /* 8 */ + "DATAKIT", /* 9 */ + "CCITT", /* 10 */ + "SNA", /* 11 */ + "DECnet", /* 12 */ + "DLI", /* 13 */ + "LAT", /* 14 */ + "HYLINK", /* 15 */ + "APPLETALK", /* 16 */ + "NIT", /* 17 */ + "802", /* 18 */ + "OSI", /* 19 */ + "X25", /* 20 */ + "OSINET", /* 21 */ + "GOSIP", /* 22 */ + "IPX", /* 23 */ + "ROUTE", /* 24 */ + "LINK", /* 25 */ + "INET6", /* 26 */ + "KEY", /* 27 */ + "NCA", /* 28 */ + "POLICY", /* 29 */ + "RDS", /* 30 */ + "TRILL", /* 31 */ + "PACKET" /* 32 */ +}; +#if MAX_AFCODES != 33 +#error Need to update address-family table +#endif + + +const char * const socktype_codes[] = { /* cf socket.h */ + NULL, + "SOCK_DGRAM", /* 1 */ + "SOCK_STREAM", /* 2 */ + NULL, + "SOCK_RAW", /* 4 */ + "SOCK_RDM", /* 5 */ + "SOCK_SEQPACKET" /* 6 */ +}; +#if MAX_SOCKTYPES != 7 +#error Need to update socket-type table +#endif diff --git a/usr/src/cmd/truss/systable.h b/usr/src/cmd/truss/systable.h new file mode 100644 index 0000000..031c708 --- /dev/null +++ b/usr/src/cmd/truss/systable.h @@ -0,0 +1,74 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1992-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#ifndef _TRUSS_SYSTABLE_H +#define _TRUSS_SYSTABLE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/socket.h> + + + +#ifdef __cplusplus +extern "C" { +#endif + +struct systable { + const char *name; /* name of system call */ + short nargs; /* number of arguments */ + char rval[2]; /* return value types */ + char arg[8]; /* argument types */ +}; + +/* the system call table */ +extern const struct systable systable[]; + + +struct sysalias { + const char *name; /* alias name of system call */ + int number; /* number of system call */ +}; + +extern const struct sysalias sysalias[]; + +extern const struct systable *subsys(int, int); + +extern const char * const afcodes[]; +#define MAX_AFCODES (AF_MAX+1) + +extern const char * const socktype_codes[]; +#define MAX_SOCKTYPES 7 + +#ifdef __cplusplus +} +#endif + +#endif /* _TRUSS_SYSTABLE_H */ |