diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2014-06-20 12:34:21 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2014-06-20 12:34:21 +0400 |
commit | a0e78a24b2c2c665ae535a4a69dc69de8e7f87ef (patch) | |
tree | 2d47c92b5ed713b5fe9081cde85c3c4175f93997 | |
download | truss-a0e78a24b2c2c665ae535a4a69dc69de8e7f87ef.tar.gz |
Initial illumos copyillumos/2014-06-05illumos
commit 5d7b4d438c4a51eccc95e77a83a437b4d48380eb
Author: Matthew Ahrens <mahrens@delphix.com>
Date: Thu Jun 5 13:19:08 2014 -0800
4757 ZFS embedded-data block pointers ("zero block compression")
4913 zfs release should not be subject to space checks
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Max Grossman <max.grossman@delphix.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Christopher Siden <christopher.siden@delphix.com>
Reviewed by: Dan McDonald <danmcd@omniti.com>
Approved by: Dan McDonald <danmcd@omniti.com>
-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 | ||||
-rw-r--r-- | usr/src/man/man1/truss.1 | 673 |
19 files changed, 21600 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 */ diff --git a/usr/src/man/man1/truss.1 b/usr/src/man/man1/truss.1 new file mode 100644 index 0000000..dffd1f6 --- /dev/null +++ b/usr/src/man/man1/truss.1 @@ -0,0 +1,673 @@ +'\" te +.\" Copyright (c) 2007, Sun Microsystems, Inc. All Rights Reserved. +.\" Copyright 1989 AT&T +.\" 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] +.TH TRUSS 1 "Jul 31, 2004" +.SH NAME +truss \- trace system calls and signals +.SH SYNOPSIS +.LP +.nf +\fBtruss\fR [\fB-fcaeildDE\fR] [\fB-\fR [tTvx] [!] \fIsyscall\fR ,...] + [\fB-\fR [sS] [!] \fIsignal\fR ,...] [\fB-\fR [mM] [!] \fIfault\fR ,...] + [\fB-\fR [rw] [!] \fIfd\fR ,...] + [\fB-\fR [uU] [!] \fIlib\fR ,... : [:] [!] \fIfunc\fR ,...] + [\fB-o\fR \fIoutfile\fR] \fIcommand\fR | \fB-p\fR \fIpid\fR[\fI/lwps\fR]... +.fi + +.SH DESCRIPTION +.sp +.LP +The \fBtruss\fR utility executes the specified command and produces a trace of +the system calls it performs, the signals it receives, and the machine faults +it incurs. Each line of the trace output reports either the fault or signal +name or the system call name with its arguments and return value(s). System +call arguments are displayed symbolically when possible using defines from +relevant system headers. For any path name pointer argument, the pointed-to +string is displayed. Error returns are reported using the error code names +described in \fBIntro\fR(3). If, in the case of an error, the kernel reports a +missing privilege, a privilege name as described in \fBprivileges\fR(5) is +reported in square brackets (\fB[ ]\fR) after the error code name. +.sp +.LP +Optionally (see the \fB-u\fR option), \fBtruss\fR also produce an entry/exit +trace of user-level function calls executed by the traced process, indented to +indicate nesting. +.SH OPTIONS +.sp +.LP +For those options that take a list argument, the name \fBall\fR can be used as +a shorthand to specify all possible members of the list. If the list begins +with a \fB!\fR, the meaning of the option is negated (for example, exclude +rather than trace). Multiple occurrences of the same option can be specified. +For the same name in a list, subsequent options (those to the right) override +previous ones (those to the left). +.sp +.LP +The following options are supported: +.sp +.ne 2 +.na +\fB\fB-a\fR\fR +.ad +.sp .6 +.RS 4n +Shows the argument strings that are passed in each \fBexec()\fR system call. +.RE + +.sp +.ne 2 +.na +\fB\fB-c\fR\fR +.ad +.sp .6 +.RS 4n +Counts traced system calls, faults, and signals rather than displaying the +trace line-by-line. A summary report is produced after the traced command +terminates or when \fBtruss\fR is interrupted. If \fB-f\fR is also specified, +the counts include all traced system calls, faults, and signals for child +processes. +.RE + +.sp +.ne 2 +.na +\fB\fB-d\fR\fR +.ad +.sp .6 +.RS 4n +Includes a time stamp on each line of trace output. The time stamp appears as a +field containing \fIseconds\fR\|.\|\fIfraction\fR at the start of the line. +This represents a time in seconds relative to the beginning of the trace. The +first line of the trace output shows the base time from which the individual +time stamps are measured, both as seconds since the epoch (see \fBtime\fR(2)) +and as a date string (see \fBctime\fR(3C) and \fBdate\fR(1)). The times that +are reported are the times that the event in question occurred. For all system +calls, the event is the completion of the system call, not the start of the +system call. +.RE + +.sp +.ne 2 +.na +\fB\fB-D\fR\fR +.ad +.sp .6 +.RS 4n +Includes a time delta on each line of trace output. The value appears as a +field containing \fIseconds\fR\|.\|\fIfraction\fR and represents the elapsed +time for the \fBLWP\fR that incurred the event since the last reported event +incurred by that \fBLWP.\fR Specifically, for system calls, this is not the +time spent within the system call. +.RE + +.sp +.ne 2 +.na +\fB\fB-e\fR\fR +.ad +.sp .6 +.RS 4n +Shows the environment strings that are passed in each \fBexec()\fR system call. +.RE + +.sp +.ne 2 +.na +\fB\fB-E\fR\fR +.ad +.sp .6 +.RS 4n +Includes a time delta on each line of trace output. The value appears as a +field containing \fIseconds\fR\fB\&.\fR\fIfraction\fR and represents the +difference in time elapsed between the beginning and end of a system call. +.sp +In contrast to the \fB-D\fR option, this is the amount of time spent within +the system call. +.RE + +.sp +.ne 2 +.na +\fB\fB-f\fR\fR +.ad +.sp .6 +.RS 4n +Follows all children created by \fBfork()\fR or \fBvfork()\fR and includes +their signals, faults, and system calls in the trace output. Normally, only the +first-level command or process is traced. When \fB-f\fR is specified, the +process-id is included with each line of trace output to indicate which process +executed the system call or received the signal. +.RE + +.sp +.ne 2 +.na +\fB\fB-i\fR\fR +.ad +.sp .6 +.RS 4n +Does not display interruptible sleeping system calls. Certain system calls, +such as \fBopen()\fR and \fBread()\fR on terminal devices or pipes, can sleep +for indefinite periods and are interruptible. Normally, \fBtruss\fR reports +such sleeping system calls if they remain asleep for more than one second. The +system call is reported again a second time when it completes. The \fB-i\fR +option causes such system calls to be reported only once, when they complete. +.RE + +.sp +.ne 2 +.na +\fB\fB-l\fR\fR +.ad +.sp .6 +.RS 4n +Includes the id of the responsible lightweight process (\fILWP\fR) with each +line of trace output. If \fB-f\fR is also specified, both the process-id and +the LWP-id are included. +.RE + +.sp +.ne 2 +.na +\fB\fB-m\fR [\fB!\fR]\fIfault\fR,...\fR +.ad +.sp .6 +.RS 4n +Machine faults to trace or exclude. Those faults specified in the +comma-separated list are traced. Faults can be specified by name or number (see +\fB<sys/fault.h>\fR). If the list begins with a \fB!\fR, the specified faults +are excluded from the trace output. Default is \fB-mall\fR \fB-m\fR +\fB!fltpage\fR. +.RE + +.sp +.ne 2 +.na +\fB\fB-M\fR [\fB!\fR]\fIfault\fR,...\fR +.ad +.sp .6 +.RS 4n +Machine faults that stop the process. The specified faults are added to the set +specified by \fB-m\fR. If one of the specified faults is incurred, \fBtruss\fR +leaves the process stopped and abandoned (see the \fB-T\fR option). Default is +\fB\fR\fB-M\fR\fB!all\fR. +.RE + +.sp +.ne 2 +.na +\fB\fB-o\fR \fIoutfile\fR\fR +.ad +.sp .6 +.RS 4n +File to be used for the trace output. By default, the output goes to standard +error. +.RE + +.sp +.ne 2 +.na +\fB\fB-p\fR\fR +.ad +.sp .6 +.RS 4n +Interprets the \fIcommand\fR arguments to \fBtruss\fR as a list of process-ids +for existing processes (see \fBps\fR(1)) rather than as a command to be +executed. \fBtruss\fR takes control of each process and begins tracing it +provided that the userid and groupid of the process match those of the user or +that the user is a privileged user. Users can trace only selected threads by +appending \fB/\fR\fIthread-id\fR to the process-id. Mutiple threads can be +selected using the \fB-\fR and \fB,\fR delimiters. For example \fB/1,2,7-9\fR +traces threads \fB1\fR, \fB2\fR, \fB7\fR, \fB8\fR, and \fB9\fR. Processes can +also be specified by their names in the \fB/proc\fR directory, for example, +\fB/proc/12345\fR. +.RE + +.sp +.ne 2 +.na +\fB\fB-r\fR [\fB!\fR]\fIfd\fR,...\fR +.ad +.sp .6 +.RS 4n +Shows the full contents of the \fBI/O\fR buffer for each \fBread()\fR on any of +the specified file descriptors. The output is formatted 32 bytes per line and +shows each byte as an \fBASCII\fR character (preceded by one blank) or as a +2-character C language escape sequence for control characters such as +horizontal tab (\|\e\|t) and newline (\|\e\|n). If \fBASCII\fR interpretation +is not possible, the byte is shown in 2-character hexadecimal representation. +(The first 12 bytes of the \fBI/O\fR buffer for each traced \fBprint >read()\fR +are shown even in the absence of \fB-r\fR.) Default is +\fB\fR\fB-r\fR\fB!all\fR. +.RE + +.sp +.ne 2 +.na +\fB\fB-s\fR [\fB!\fR]\fIsignal\fR,...\fR +.ad +.sp .6 +.RS 4n +Signals to trace or exclude. Those signals specified in the comma-separated +list are traced. The trace output reports the receipt of each specified signal, +even if the signal is being ignored (not blocked). (Blocked signals are not +received until they are unblocked.) Signals can be specified by name or number +(see \fB<sys/signal.h>\fR). If the list begins with a \fB!\fR, the specified +signals are excluded from the trace output. Default is \fB-sall\fR. +.RE + +.sp +.ne 2 +.na +\fB\fB-S\fR [\fB!\fR]\fIsignal\fR,...\fR +.ad +.sp .6 +.RS 4n +Signals that stop the process. The specified signals are added to the set +specified by \fB-s\fR. If one of the specified signals is received, \fBtruss\fR +leaves the process stopped and abandoned (see the \fB-T\fR option). Default is +\fB\fR\fB-S\fR\fB!all\fR. +.RE + +.sp +.ne 2 +.na +\fB\fB-t\fR [\fB!\fR]\fIsyscall\fR,...\fR +.ad +.sp .6 +.RS 4n +System calls to trace or exclude. Those system calls specified in the +comma-separated list are traced. If the list begins with a \fB!\fR, the +specified system calls are excluded from the trace output. Default is +\fB-tall\fR. +.RE + +.sp +.ne 2 +.na +\fB\fB-T\fR [\fB!\fR]\fIsyscall\fR,...\fR +.ad +.sp .6 +.RS 4n +Specifies system calls that stop the process. The specified system calls are +added to the set specified by \fB-t\fR. If one of the specified system calls is +encountered, \fBtruss\fR leaves the process stopped and abandoned. That is, +\fBtruss\fR releases the process and exits but leaves the process in the +stopped state at completion of the system call in question. A debugger or other +process inspection tool (see \fBproc\fR(1)) can then be applied to the stopped +process. \fBtruss\fR can be reapplied to the stopped process with the same or +different options to continue tracing. Default is \fB\fR\fB-T\fR\fB!all\fR. +.sp +A process left stopped in this manner cannot be restarted by the application of +\fBkill\fR \fB-CONT\fR because it is stopped on an event of interest via +\fB/proc\fR, not by the default action of a stopping signal (see +\fBsignal.h\fR(3HEAD)). The \fBprun\fR(1) command described in \fBproc\fR(1) +can be used to set the stopped process running again. +.RE + +.sp +.ne 2 +.na +\fB\fB-u\fR +[\fB!\fR]\fIlib\fR,...\fB:\fR[\fB:\fR][\fB!\fR]\fIfunc\fR,\|.\|.\|.\fR +.ad +.sp .6 +.RS 4n +User-level function call tracing. \fIlib\fR,\|.\|.\|. is a comma-separated list +of dynamic library names, excluding the ``\fB\&.so.\fR\fIn\fR'' suffix. +\fIfunc\fR,\|.\|.\|. is a comma-separated list of function names. In both cases +the names can include name-matching metacharacters \fB*\fR,\fB?\fR,\fB[]\fR +with the same meanings as those of \fBsh\fR(1) but as applied to the +library/function name spaces, not to files. An empty library or function list +defaults to \fB*\fR, trace all libraries or functions in a library. A leading +\fB!\fR on either list specifies an exclusion list, names of libraries or +functions not to be traced. Excluding a library excludes all functions in that +library; any function list following a library exclusion list is ignored. +.sp +A single \fB:\fR separating the library list from the function list means to +trace calls into the libraries from outside the libraries, but omit calls made +to functions in a library from other functions in the same library. A double +\fB:\|:\fR means to trace all calls, regardless of origin. +.sp +Library patterns do not match either the executable file or the dynamic linker +unless there is an exact match (\fBl*\fR does not match \fBld.so.1\fR). To +trace functions in either of these objects, the names must be specified +exactly, as in: +.sp +.in +2 +.nf +\fBtruss -u a.out -u ld ...\fR +.fi +.in -2 +.sp + +\fBa.out\fR is the literal name to be used for this purpose; it does not stand +for the name of the executable file. Tracing \fBa.out\fR function calls implies +all calls (default is \fB::\fR). +.sp +Multiple \fB-u\fR options can be specified and they are honored left-to-right. +The id of the thread that performed the function call is included in the trace +output for the call. \fBtruss\fR searches the dynamic symbol table in each +library to find function names and also searches the standard symbol table if +it has not been stripped. +.RE + +.sp +.ne 2 +.na +\fB\fB-U\fR +[\fB!\fR]\fIlib\fR,\|.\|.\|.\|\fB:\fR[\fB:\fR][\fB!\fR]\fIfunc\fR,\|.\|.\|.\fR +.ad +.sp .6 +.RS 4n +User-level function calls that stop the process. The specified functions are +added to the set specified by \fB-u\fR. If one of the specified functions is +called, \fBtruss\fR leaves the process stopped and abandoned (see the \fB-T\fR +option). +.RE + +.sp +.ne 2 +.na +\fB\fB-v\fR [\fB!\fR]\fIsyscall\fR,...\fR +.ad +.sp .6 +.RS 4n +Verbose. Displays the contents of any structures passed by address to the +specified system calls (if traced by \fB-t\fR). Input values as well as values +returned by the operating system are shown. For any field used as both input +and output, only the output value is shown. Default is +\fB\fR\fB-v\fR\fB!all\fR. +.RE + +.sp +.ne 2 +.na +\fB\fB-w\fR [\fB!\fR]\fIfd\fR,...\fR +.ad +.sp .6 +.RS 4n +Shows the contents of the I/O buffer for each \fBwrite()\fR on any of the +specified file descriptors (see the \fB-r\fR option). Default is +\fB\fR\fB-w\fR\fB!all\fR. +.RE + +.sp +.ne 2 +.na +\fB\fB-x\fR [\fB!\fR]\fIsyscall\fR,...\fR +.ad +.sp .6 +.RS 4n +Displays the arguments to the specified system calls (if traced by \fB-t\fR) in +raw form, usually hexadecimal, rather than symbolically. This is for unredeemed +hackers who must see the raw bits to be happy. Default is +\fB\fR\fB-x\fR\fB!all\fR. +.RE + +.sp +.LP +See \fIman pages section 2: System Calls\fR for system call names accepted by +the \fB-t\fR, \fB-T\fR, \fB-v\fR, and \fB-x\fR options. System call numbers are +also accepted. +.sp +.LP +If \fBtruss\fR is used to initiate and trace a specified command and if the +\fB-o\fR option is used or if standard error is redirected to a non-terminal +file, then \fBtruss\fR runs with hangup, interrupt, and quit signals ignored. +This facilitates tracing of interactive programs that catch interrupt and quit +signals from the terminal. +.sp +.LP +If the trace output remains directed to the terminal, or if existing processes +are traced (the \fB-p\fR option), then \fBtruss\fR responds to hangup, +interrupt, and quit signals by releasing all traced processes and exiting. This +enables the user to terminate excessive trace output and to release +previously-existing processes. Released processes continue normally, as though +they had never been touched. +.SH EXAMPLES +.LP +\fBExample 1 \fRTracing a Command +.sp +.LP +The following example produces a trace of the \fBfind\fR(1) command on the +terminal: + +.sp +.in +2 +.nf +example$ \fBtruss find . -print >find.out\fR +.fi +.in -2 +.sp + +.LP +\fBExample 2 \fRTracing Common System Calls +.sp +.LP +The following example shows only a trace of the open, close, read, and write +system calls: + +.sp +.in +2 +.nf +example$ \fBtruss -t open,close,read,write find . -print >find.out\fR +.fi +.in -2 +.sp + +.LP +\fBExample 3 \fRTracing a Shell Script +.sp +.LP +The following example produces a trace of the \fBspell\fR(1) command on the +file \fBtruss.out\fR: + +.sp +.in +2 +.nf +example$ \fBtruss -f -o truss.out spell \fIdocument\fR\fR +.fi +.in -2 +.sp + +.sp +.LP +\fBspell\fR is a shell script, so the \fB-f\fR flag is needed to trace not only +the shell but also the processes created by the shell. (The spell script runs a +pipeline of eight processes.) + +.LP +\fBExample 4 \fRAbbreviating Output +.sp +.LP +The following example abreviates output: + +.sp +.in +2 +.nf +example$ \fBtruss nroff -mm \fIdocument\fR >nroff.out\fR +.fi +.in -2 +.sp + +.sp +.LP +because 97% of the output reports \fBlseek()\fR, \fBread()\fR, and +\fBwrite()\fR system calls. To abbreviate it: + +.sp +.in +2 +.nf +example$ \fBtruss -t !lseek,read,write nroff -mm \fIdocument\fR >nroff.out\fR +.fi +.in -2 +.sp + +.LP +\fBExample 5 \fRTracing Library Calls From Outside the C Library +.sp +.LP +The following example traces all user-level calls made to any function in the C +library from outside the C library: + +.sp +.in +2 +.nf +example$ \fBtruss -u libc ...\fR +.fi +.in -2 +.sp + +.LP +\fBExample 6 \fRTracing library calls from within the C library +.sp +.LP +The following example includes calls made to functions in the C library from +within the C library itself: + +.sp +.in +2 +.nf +example$ \fBtruss -u libc:: ...\fR +.fi +.in -2 +.sp + +.LP +\fBExample 7 \fRTracing Library Calls Other Than the C Library +.sp +.LP +The following example traces all user-level calls made to any library other +than the C library: + +.sp +.in +2 +.nf +example$ \fBtruss -u '*' -u !libc ...\fR +.fi +.in -2 +.sp + +.LP +\fBExample 8 \fRTracing \fBprintf\fR and \fBscanf\fR Function Calls +.sp +.LP +The following example traces all user-level calls to functions in the printf +and scanf family contained in the C library: + +.sp +.in +2 +.nf +example$ \fBtruss -u 'libc:*printf,*scanf' ...\fR +.fi +.in -2 +.sp + +.LP +\fBExample 9 \fRTracing Every User-level Function Call +.sp +.LP +The following example traces every user-level function call from anywhere to +anywhere: + +.sp +.in +2 +.nf +example$ \fBtruss -u a.out -u ld:: -u :: ...\fR +.fi +.in -2 +.sp + +.LP +\fBExample 10 \fRTracing a System Call Verbosely +.sp +.LP +The following example verbosely traces the system call activity of process #1, +\fBinit\fR(1M) (if you are a privileged user): + +.sp +.in +2 +.nf +example# \fBtruss -p -v all 1\fR +.fi +.in -2 +.sp + +.sp +.LP +Interrupting \fBtruss\fR returns \fBinit\fR to normal operation. + +.SH FILES +.sp +.ne 2 +.na +\fB\fB/proc/*\fR\fR +.ad +.RS 11n +Process files +.RE + +.SH SEE ALSO +.sp +.LP +\fBdate\fR(1), \fBfind\fR(1), \fBproc\fR(1), \fBps\fR(1), \fBsh\fR(1), +\fBspell\fR(1), \fBinit\fR(1M), \fBIntro\fR(3), \fBexec\fR(2), \fBfork\fR(2), +\fBlseek\fR(2), \fBopen\fR(2), \fBread\fR(2), \fBtime\fR(2), \fBvfork\fR(2), +\fBwrite\fR(2), \fBctime\fR(3C), \fBsignal.h\fR(3HEAD), \fBproc\fR(4), +\fBattributes\fR(5), \fBprivileges\fR(5), \fBthreads\fR(5) +.sp +.LP +\fIman pages section 2: System Calls\fR +.SH NOTES +.sp +.LP +Some of the system calls described in \fIman pages section 2: System Calls\fR +differ from the actual operating system interfaces. Do not be surprised by +minor deviations of the trace output from the descriptions in that document. +.sp +.LP +Every machine fault (except a page fault) results in the posting of a signal to +the \fBLWP\fR that incurred the fault. A report of a received signal +immediately follows each report of a machine fault (except a page fault) unless +that signal is being blocked. +.sp +.LP +The operating system enforces certain security restrictions on the tracing of +processes. In particular, any command whose object file (\fBa.out\fR) cannot be +read by a user cannot be traced by that user; set-uid and set-gid commands can +be traced only by a privileged user. Unless it is run by a privileged user, +\fBtruss\fR loses control of any process that performs an \fBexec()\fR of a +set-id or unreadable object file; such processes continue normally, though +independently of \fBtruss\fR, from the point of the \fBexec()\fR. +.sp +.LP +To avoid collisions with other controlling processes, \fBtruss\fR does not +trace a process that it detects is being controlled by another process via the +\fB/proc\fR interface. This allows \fBtruss\fR to be applied to +\fBproc\fR(4)-based debuggers as well as to another instance of itself. +.sp +.LP +The trace output contains tab characters under the assumption that standard tab +stops are set (every eight positions). +.sp +.LP +The trace output for multiple processes or for a multithreaded process (one +that contains more than one \fBLWP)\fR is not produced in strict time order. +For example, a \fBread()\fR on a pipe can be reported before the corresponding +\fBwrite()\fR. For any one \fBLWP\fR (a traditional process contains only one), +the output is strictly time-ordered. +.sp +.LP +When tracing more than one process, \fBtruss\fR runs as one controlling process +for each process being traced. For the example of the \fBspell\fR command shown +above, \fBspell\fR itself uses 9 process slots, one for the shell and 8 for the +8-member pipeline, while \fBtruss\fR adds another 9 processes, for a total of +18. +.sp +.LP +Not all possible structures passed in all possible system calls are displayed +under the \fB-v\fR option. |