src/usr.bin/kdump/kdump.c

1811 lines
41 KiB
C

/* $OpenBSD: kdump.c,v 1.160 2023/12/12 15:30:55 deraadt Exp $ */
/*-
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/time.h>
#include <sys/signal.h>
#include <sys/uio.h>
#include <sys/ktrace.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/namei.h>
#include <sys/ptrace.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/siginfo.h>
#include <sys/vmmeter.h>
#include <sys/tty.h>
#include <sys/wait.h>
#define PLEDGENAMES
#include <sys/pledge.h>
#undef PLEDGENAMES
#define _KERNEL
#include <errno.h>
#undef _KERNEL
#include <ddb/db_var.h>
#include <machine/cpu.h>
#include <ctype.h>
#include <err.h>
#include <fcntl.h>
#include <limits.h>
#include <netdb.h>
#include <poll.h>
#include <signal.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <vis.h>
#include "ktrace.h"
#include "kdump.h"
#include "kdump_subr.h"
#include "extern.h"
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
enum {
TIMESTAMP_NONE,
TIMESTAMP_ABSOLUTE,
TIMESTAMP_RELATIVE,
TIMESTAMP_ELAPSED
} timestamp = TIMESTAMP_NONE;
int decimal, iohex, fancy = 1, maxdata = INT_MAX;
int needtid, tail, basecol;
char *tracefile = DEF_TRACEFILE;
struct ktr_header ktr_header;
pid_t pid_opt = -1;
const char *program;
char* utracefilter;
#define eqs(s1, s2) (strcmp((s1), (s2)) == 0)
#include <sys/syscall.h>
#define KTRACE
#define PTRACE
#define NFSCLIENT
#define NFSSERVER
#define SYSVSEM
#define SYSVMSG
#define SYSVSHM
#define ACCOUNTING
#include <kern/syscalls.c>
#undef KTRACE
#undef PTRACE
#undef NFSCLIENT
#undef NFSSERVER
#undef SYSVSEM
#undef SYSVMSG
#undef SYSVSHM
#undef ACCOUNTING
static char *ptrace_ops[] = {
"PT_TRACE_ME", "PT_READ_I", "PT_READ_D", "PT_READ_U",
"PT_WRITE_I", "PT_WRITE_D", "PT_WRITE_U", "PT_CONTINUE",
"PT_KILL", "PT_ATTACH", "PT_DETACH", "PT_IO",
"PT_SET_EVENT_MASK", "PT_GET_EVENT_MASK", "PT_GET_PROCESS_STATE",
"PT_GET_THREAD_FIRST", "PT_GET_THREAD_NEXT",
};
static int fread_tail(void *, size_t, size_t);
static void dumpheader(struct ktr_header *);
static void ktrgenio(struct ktr_genio *, size_t);
static void ktrnamei(const char *, size_t);
static void ktrpsig(struct ktr_psig *);
static void ktrsyscall(struct ktr_syscall *, size_t);
static const char *kresolvsysctl(int, const int *);
static void ktrsysret(struct ktr_sysret *, size_t);
static void ktruser(struct ktr_user *, size_t);
static void ktrexec(const char*, size_t);
static void ktrpledge(struct ktr_pledge *, size_t);
static void usage(void);
static void ioctldecode(int);
static void ptracedecode(int);
static void atfd(int);
static void polltimeout(int);
static void wait4pid(int);
static void signame(int);
static void semctlname(int);
static void shmctlname(int);
static void semgetname(int);
static void flagsandmodename(int);
static void clockname(int);
static void sockoptlevelname(int);
static void ktraceopname(int);
static void idtypeandid(int);
static int screenwidth;
int
main(int argc, char *argv[])
{
int ch, silent;
size_t ktrlen, size;
int trpoints = ALL_POINTS;
const char *errstr;
void *m;
if (screenwidth == 0) {
struct winsize ws;
if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
ws.ws_col > 8)
screenwidth = ws.ws_col;
else
screenwidth = 80;
}
while ((ch = getopt(argc, argv, "f:dHlm:nP:p:RTt:u:xX")) != -1)
switch (ch) {
case 'f':
tracefile = optarg;
break;
case 'd':
decimal = 1;
break;
case 'H':
needtid = 1;
break;
case 'l':
tail = 1;
break;
case 'm':
maxdata = strtonum(optarg, 0, INT_MAX, &errstr);
if (errstr)
errx(1, "-m %s: %s", optarg, errstr);
break;
case 'n':
fancy = 0;
break;
case 'P':
program = optarg;
break;
case 'p':
pid_opt = strtonum(optarg, 1, INT_MAX, &errstr);
if (errstr)
errx(1, "-p %s: %s", optarg, errstr);
break;
case 'R': /* relative timestamp */
if (timestamp == TIMESTAMP_ABSOLUTE)
timestamp = TIMESTAMP_ELAPSED;
else
timestamp = TIMESTAMP_RELATIVE;
break;
case 'T':
if (timestamp == TIMESTAMP_RELATIVE)
timestamp = TIMESTAMP_ELAPSED;
else
timestamp = TIMESTAMP_ABSOLUTE;
break;
case 't':
trpoints = getpoints(optarg, DEF_POINTS);
if (trpoints < 0)
errx(1, "unknown trace point in %s", optarg);
utracefilter = NULL;
break;
case 'u':
utracefilter = optarg;
trpoints = KTRFAC_USER;
break;
case 'x':
iohex = 1;
break;
case 'X':
iohex = 2;
break;
default:
usage();
}
if (argc > optind)
usage();
if (strcmp(tracefile, "-") != 0)
if (unveil(tracefile, "r") == -1)
err(1, "unveil %s", tracefile);
if (unveil(_PATH_PROTOCOLS, "r") == -1)
err(1, "unveil %s", _PATH_PROTOCOLS);
if (pledge("stdio rpath getpw", NULL) == -1)
err(1, "pledge");
m = malloc(size = 1025);
if (m == NULL)
err(1, NULL);
if (strcmp(tracefile, "-") != 0)
if (!freopen(tracefile, "r", stdin))
err(1, "%s", tracefile);
if (fread_tail(&ktr_header, sizeof(struct ktr_header), 1) == 0 ||
ktr_header.ktr_type != htobe32(KTR_START))
errx(1, "%s: not a dump", tracefile);
while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) {
silent = 0;
if (pid_opt != -1 && pid_opt != ktr_header.ktr_pid)
silent = 1;
if (program != NULL &&
strcmp(ktr_header.ktr_comm, program) != 0)
silent = 1;
if (utracefilter == NULL && silent == 0 &&
trpoints & (1<<ktr_header.ktr_type))
dumpheader(&ktr_header);
ktrlen = ktr_header.ktr_len;
if (ktrlen > size) {
void *newm;
if (ktrlen == SIZE_MAX)
errx(1, "data too long");
newm = realloc(m, ktrlen+1);
if (newm == NULL)
err(1, "realloc");
m = newm;
size = ktrlen;
}
if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
errx(1, "data too short");
if (silent)
continue;
if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
continue;
switch (ktr_header.ktr_type) {
case KTR_SYSCALL:
ktrsyscall(m, ktrlen);
break;
case KTR_SYSRET:
ktrsysret(m, ktrlen);
break;
case KTR_NAMEI:
ktrnamei(m, ktrlen);
break;
case KTR_GENIO:
ktrgenio(m, ktrlen);
break;
case KTR_PSIG:
ktrpsig(m);
break;
case KTR_STRUCT:
ktrstruct(m, ktrlen);
break;
case KTR_USER:
ktruser(m, ktrlen);
break;
case KTR_EXECARGS:
case KTR_EXECENV:
ktrexec(m, ktrlen);
break;
case KTR_PLEDGE:
ktrpledge(m, ktrlen);
break;
default:
printf("\n");
break;
}
if (tail)
(void)fflush(stdout);
}
exit(0);
}
static int
fread_tail(void *buf, size_t size, size_t num)
{
int i;
while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
(void)sleep(1);
clearerr(stdin);
}
return (i);
}
static void
dumpheader(struct ktr_header *kth)
{
static struct timespec prevtime;
char unknown[64], *type;
struct timespec temp;
switch (kth->ktr_type) {
case KTR_SYSCALL:
type = "CALL";
break;
case KTR_SYSRET:
type = "RET ";
break;
case KTR_NAMEI:
type = "NAMI";
break;
case KTR_GENIO:
type = "GIO ";
break;
case KTR_PSIG:
type = "PSIG";
break;
case KTR_STRUCT:
type = "STRU";
break;
case KTR_USER:
type = "USER";
break;
case KTR_EXECARGS:
type = "ARGS";
break;
case KTR_EXECENV:
type = "ENV ";
break;
case KTR_PLEDGE:
type = "PLDG";
break;
default:
/* htobe32() not guaranteed to work as case label */
if (kth->ktr_type == htobe32(KTR_START)) {
type = "STRT";
break;
}
(void)snprintf(unknown, sizeof unknown, "UNKNOWN(%u)",
kth->ktr_type);
type = unknown;
}
basecol = printf("%6ld", (long)kth->ktr_pid);
if (needtid)
basecol += printf("/%-7ld", (long)kth->ktr_tid);
basecol += printf(" %-8s ", kth->ktr_comm);
if (timestamp != TIMESTAMP_NONE) {
if (timestamp == TIMESTAMP_ELAPSED) {
if (prevtime.tv_sec == 0)
prevtime = kth->ktr_time;
timespecsub(&kth->ktr_time, &prevtime, &temp);
} else if (timestamp == TIMESTAMP_RELATIVE) {
timespecsub(&kth->ktr_time, &prevtime, &temp);
prevtime = kth->ktr_time;
} else
temp = kth->ktr_time;
basecol += printf("%lld.%06ld ", (long long)temp.tv_sec,
temp.tv_nsec / 1000);
}
basecol += printf("%s ", type);
}
/*
* Base Formatters
*/
/* some syscalls have padding that shouldn't be shown */
static int
pad(long arg)
{
/* nothing printed */
return (1);
}
/* a formatter that just saves the argument for the next formatter */
int arg1;
static int
pass_two(long arg)
{
arg1 = (int)arg;
/* nothing printed */
return (1);
}
static int
pdeclong(long arg)
{
(void)printf("%ld", arg);
return (0);
}
static int
pdeculong(long arg)
{
(void)printf("%lu", arg);
return (0);
}
static int
phexlong(long arg)
{
(void)printf("%#lx", arg);
return (0);
}
static int
pnonfancy(long arg)
{
if (decimal)
(void)printf("%ld", arg);
else
(void)printf("%#lx", arg);
return (0);
}
static void
pdecint(int arg)
{
(void)printf("%d", arg);
}
static void
pdecuint(int arg)
{
(void)printf("%u", arg);
}
static void
phexint(int arg)
{
(void)printf("%#x", arg);
}
static void
poctint(int arg)
{
(void)printf("%#o", arg);
}
#ifdef __LP64__
/* on LP64, long long arguments are the same as long arguments */
#define Phexlonglong Phexlong
#define phexll NULL /* not actually used on LP64 */
/* no padding before long long arguments, nor at end */
#define PAD64 0
#define END64 end_of_args
#else /* __LP64__ */
/* on ILP32, long long arguments are passed as two 32bit args */
#define Phexlonglong PASS_LONGLONG, Phexll
static int
phexll(long arg2)
{
long long val;
#if _BYTE_ORDER == _LITTLE_ENDIAN
val = ((long long)arg2 << 32) | ((long long)arg1 & 0xffffffff);
#else
val = ((long long)arg1 << 32) | ((long long)arg2 & 0xffffffff);
#endif
if (fancy || !decimal)
(void)printf("%#llx", val);
else
(void)printf("%lld", val);
return (0);
}
/*
* Some ILP32 archs naturally align off_t arguments to 8byte boundaries
* Get the compiler to tell if this arch is one of them.
*/
struct padding_test {
int padtest_one;
off_t padtest_two;
};
#define PAD64 (offsetof(struct padding_test,padtest_two) == 8)
#define END64 (PAD64 ? PASS_LONGLONG : end_of_args)
#endif /* __LP64__ */
static int (*long_formatters[])(long) = {
NULL,
pdeclong,
pdeculong,
phexlong,
pass_two,
pass_two,
phexll,
pad,
pnonfancy,
};
static void (*formatters[])(int) = {
NULL,
pdecint,
phexint,
poctint,
pdecuint,
ioctldecode,
ptracedecode,
atfd,
polltimeout,
wait4pid,
signame,
semctlname,
shmctlname,
semgetname,
flagsandmodename,
clockname,
sockoptlevelname,
ktraceopname,
fcntlcmdname,
modename,
flagsname,
openflagsname,
atflagsname,
accessmodename,
mmapprotname,
mmapflagsname,
wait4optname,
sendrecvflagsname,
mountflagsname,
rebootoptname,
flockname,
sockoptname,
sockipprotoname,
socktypename,
sockflagsname,
sockfamilyname,
mlockallname,
shmatname,
whencename,
pathconfname,
rlimitname,
shutdownhowname,
prioname,
madvisebehavname,
msyncflagsname,
clocktypename,
rusagewho,
sigactionflagname,
sigprocmaskhowname,
minheritname,
quotactlname,
sigill_name,
sigtrap_name,
sigemt_name,
sigfpe_name,
sigbus_name,
sigsegv_name,
sigchld_name,
ktracefacname,
itimername,
sigset,
uidname,
gidname,
syslogflagname,
futexflagname,
waitidoptname,
idtypeandid,
};
enum {
/* the end of the (known) arguments is recognized by the zero fill */
end_of_args = 0,
/* negative are the negative of the index into long_formatters[] */
Pdeclong = -1,
Pdeculong = -2,
Phexlong = -3,
PASS_TWO = -4,
/* the remaining long formatters still get called when non-fancy (-n option) */
#define FMT_IS_NONFANCY(x) ((x) <= PASS_LONGLONG)
PASS_LONGLONG = -5,
Phexll = -6,
PAD = -7,
Pnonfancy = -8,
/* positive values are the index into formatters[] */
Pdecint = 1,
Phexint,
Poctint,
Pdecuint,
Ioctldecode,
Ptracedecode,
Atfd,
Polltimeout,
Wait4pid,
Signame,
Semctlname,
Shmctlname,
Semgetname,
Flagsandmodename,
Clockname,
Sockoptlevelname,
Ktraceopname,
Fcntlcmdname,
Modename,
Flagsname,
Openflagsname,
Atflagsname,
Accessmodename,
Mmapprotname,
Mmapflagsname,
Wait4optname,
Sendrecvflagsname,
Mountflagsname,
Rebootoptname,
Flockname,
Sockoptname,
Sockipprotoname,
Socktypename,
Sockflagsname,
Sockfamilyname,
Mlockallname,
Shmatname,
Whencename,
Pathconfname,
Rlimitname,
Shutdownhowname,
Prioname,
Madvisebehavname,
Msyncflagsname,
Clocktypename,
Rusagewho,
Sigactionflagname,
Sigprocmaskhowname,
Minheritname,
Quotactlname,
Sigill_name,
Sigtrap_name,
Sigemt_name,
Sigfpe_name,
Sigbus_name,
Sigsegv_name,
Sigchld_name,
Ktracefacname,
Itimername,
Sigset,
Uidname,
Gidname,
Syslogflagname,
Futexflagname,
Waitidoptname,
Idtypeandid,
};
#define Pptr Phexlong
#define Psize Pdeculong /* size_t for small buffers */
#define Pbigsize Phexlong /* size_t for I/O buffers */
#define Pcount Pdecint /* int for a count of something */
#define Pfd Pdecint
#define Ppath Phexlong
#define Pdev_t Pdecint
#define Ppid_t Pdecint
#define Ppgid Pdecint /* pid or negative pgid */
#define Poff_t Phexlonglong
#define Pmsqid Pdecint
#define Pshmid Pdecint
#define Psemid Pdecint
#define Pkey_t Pdecint
#define Pucount Pdecuint
#define Chflagsname Phexlong /* to be added */
#define Sockprotoname Phexlong /* to be added */
#define Swapctlname Phexlong /* to be added */
#define Msgflgname Phexlong /* to be added */
/* includes relevant entries as of syscalls.master rev 1.238 */
typedef signed char formatter;
static const formatter scargs[][8] = {
[SYS_exit] = { Pdecint },
[SYS_read] = { Pfd, Pptr, Pbigsize },
[SYS_write] = { Pfd, Pptr, Pbigsize },
[SYS_open] = { Ppath, PASS_TWO, Flagsandmodename },
[SYS_close] = { Pfd },
[SYS_getentropy] = { Pptr, Psize },
[SYS___tfork] = { Pptr, Psize },
[SYS_link] = { Ppath, Ppath },
[SYS_unlink] = { Ppath },
[SYS_wait4] = { Wait4pid, Pptr, Wait4optname },
[SYS_chdir] = { Ppath },
[SYS_fchdir] = { Pfd },
[SYS_mknod] = { Ppath, Modename, Pdev_t },
[SYS_chmod] = { Ppath, Modename },
[SYS_chown] = { Ppath, Uidname, Gidname },
[SYS_break] = { Pptr },
[SYS_getrusage] = { Rusagewho, Pptr },
[SYS_mount] = { Pptr, Ppath, Mountflagsname, Pptr },
[SYS_unmount] = { Ppath, Mountflagsname },
[SYS_setuid] = { Uidname },
[SYS_ptrace] = { Ptracedecode, Ppid_t, Pptr, Pdecint },
[SYS_recvmsg] = { Pfd, Pptr, Sendrecvflagsname },
[SYS_sendmsg] = { Pfd, Pptr, Sendrecvflagsname },
[SYS_recvfrom] = { Pfd, Pptr, Pbigsize, Sendrecvflagsname },
[SYS_accept] = { Pfd, Pptr, Pptr },
[SYS_getpeername] = { Pfd, Pptr, Pptr },
[SYS_getsockname] = { Pfd, Pptr, Pptr },
[SYS_access] = { Ppath, Accessmodename },
[SYS_chflags] = { Ppath, Chflagsname },
[SYS_fchflags] = { Pfd, Chflagsname },
[SYS_msyscall] = { Pptr, Pbigsize },
[SYS_stat] = { Ppath, Pptr },
[SYS_lstat] = { Ppath, Pptr },
[SYS_dup] = { Pfd },
[SYS_fstatat] = { Atfd, Ppath, Pptr, Atflagsname },
[SYS_profil] = { Pptr, Pbigsize, Pbigsize, Pdecuint },
[SYS_ktrace] = { Ppath, Ktraceopname, Ktracefacname, Ppgid },
[SYS_sigaction] = { Signame, Pptr, Pptr },
[SYS_sigprocmask] = { Sigprocmaskhowname, Sigset },
[SYS_mmap] = { Pptr, Pbigsize, Mmapprotname, Mmapflagsname, Pfd, Poff_t, END64 },
[SYS_setlogin] = { Pptr },
[SYS_acct] = { Ppath },
[SYS_fstat] = { Pfd, Pptr },
[SYS_ioctl] = { Pfd, Ioctldecode, Pptr },
[SYS_reboot] = { Rebootoptname },
[SYS_revoke] = { Ppath },
[SYS_symlink] = { Ppath, Ppath },
[SYS_readlink] = { Ppath, Pptr, Psize },
[SYS_execve] = { Ppath, Pptr, Pptr },
[SYS_umask] = { Modename },
[SYS_chroot] = { Ppath },
[SYS_getfsstat] = { Pptr, Pbigsize, Mountflagsname },
[SYS_statfs] = { Ppath, Pptr },
[SYS_fstatfs] = { Pfd, Pptr },
[SYS_fhstatfs] = { Pptr, Pptr },
[SYS_gettimeofday] = { Pptr, Pptr },
[SYS_settimeofday] = { Pptr, Pptr },
[SYS_setitimer] = { Itimername, Pptr, Pptr },
[SYS_getitimer] = { Itimername, Pptr },
[SYS_select] = { Pcount, Pptr, Pptr, Pptr, Pptr },
[SYS_kevent] = { Pfd, Pptr, Pcount, Pptr, Pcount, Pptr },
[SYS_munmap] = { Pptr, Pbigsize },
[SYS_mprotect] = { Pptr, Pbigsize, Mmapprotname },
[SYS_madvise] = { Pptr, Pbigsize, Madvisebehavname },
[SYS_utimes] = { Ppath, Pptr },
[SYS_futimes] = { Pfd, Pptr },
[SYS_mquery] = { Pptr, Pbigsize, Mmapprotname, Mmapflagsname, Pfd, Poff_t, END64 },
[SYS_getgroups] = { Pcount, Pptr },
[SYS_setgroups] = { Pcount, Pptr },
[SYS_setpgid] = { Ppid_t, Ppid_t },
[SYS_futex] = { Pptr, Futexflagname, Pcount, Pptr, Pptr },
[SYS_utimensat] = { Atfd, Ppath, Pptr, Atflagsname },
[SYS_futimens] = { Pfd, Pptr },
[SYS_kbind] = { Pptr, Psize, Phexlonglong },
[SYS_clock_gettime] = { Clockname, Pptr },
[SYS_clock_settime] = { Clockname, Pptr },
[SYS_clock_getres] = { Clockname, Pptr },
[SYS_dup2] = { Pfd, Pfd },
[SYS_nanosleep] = { Pptr, Pptr },
[SYS_fcntl] = { Pfd, PASS_TWO, Fcntlcmdname },
[SYS_accept4] = { Pfd, Pptr, Pptr, Sockflagsname },
[SYS___thrsleep] = { Pptr, Clockname, Pptr, Pptr, Pptr },
[SYS_fsync] = { Pfd },
[SYS_setpriority] = { Prioname, Ppid_t, Pdecint },
[SYS_socket] = { Sockfamilyname, Socktypename, Sockprotoname },
[SYS_connect] = { Pfd, Pptr, Pucount },
[SYS_getdents] = { Pfd, Pptr, Pbigsize },
[SYS_getpriority] = { Prioname, Ppid_t },
[SYS_pipe2] = { Pptr, Flagsname },
[SYS_dup3] = { Pfd, Pfd, Flagsname },
[SYS_sigreturn] = { Pptr },
[SYS_bind] = { Pfd, Pptr, Pucount },
[SYS_setsockopt] = { Pfd, PASS_TWO, Sockoptlevelname, Pptr, Pdecint },
[SYS_listen] = { Pfd, Pdecint },
[SYS_chflagsat] = { Atfd, Ppath, Chflagsname, Atflagsname },
[SYS_pledge] = { Pptr, Pptr },
[SYS_ppoll] = { Pptr, Pucount, Pptr, Pptr },
[SYS_pselect] = { Pcount, Pptr, Pptr, Pptr, Pptr, Pptr },
[SYS_sigsuspend] = { Sigset },
[SYS_sendsyslog] = { Pptr, Psize, Syslogflagname },
[SYS_unveil] = { Ppath, Pptr },
[SYS___realpath] = { Ppath, Pptr },
[SYS_recvmmsg] = { Pfd, Pptr, Pucount, Sendrecvflagsname, Pptr },
[SYS_sendmmsg] = { Pfd, Pptr, Pucount, Sendrecvflagsname },
[SYS_getsockopt] = { Pfd, PASS_TWO, Sockoptlevelname, Pptr, Pptr },
[SYS_thrkill] = { Ppid_t, Signame, Pptr },
[SYS_readv] = { Pfd, Pptr, Pcount },
[SYS_writev] = { Pfd, Pptr, Pcount },
[SYS_kill] = { Ppgid, Signame },
[SYS_fchown] = { Pfd, Uidname, Gidname },
[SYS_fchmod] = { Pfd, Modename },
[SYS_setreuid] = { Uidname, Uidname },
[SYS_setregid] = { Gidname, Gidname },
[SYS_rename] = { Ppath, Ppath },
[SYS_flock] = { Pfd, Flockname },
[SYS_mkfifo] = { Ppath, Modename },
[SYS_sendto] = { Pfd, Pptr, Pbigsize, Sendrecvflagsname },
[SYS_shutdown] = { Pfd, Shutdownhowname },
[SYS_socketpair] = { Sockfamilyname, Socktypename, Sockprotoname, Pptr },
[SYS_mkdir] = { Ppath, Modename },
[SYS_rmdir] = { Ppath },
[SYS_adjtime] = { Pptr, Pptr },
[SYS_getlogin_r] = { Pptr, Psize },
[SYS_getthrname] = { Ppid_t, Pptr, Psize },
[SYS_setthrname] = { Ppid_t, Pptr },
[SYS_quotactl] = { Ppath, Quotactlname, Uidname, Pptr },
[SYS_ypconnect] = { Socktypename },
[SYS_nfssvc] = { Phexint, Pptr },
[SYS_mimmutable] = { Pptr, Pbigsize },
[SYS_waitid] = { PASS_TWO, Idtypeandid, Pptr, Waitidoptname },
[SYS_getfh] = { Ppath, Pptr },
[SYS___tmpfd] = { Openflagsname },
[SYS_sysarch] = { Pdecint, Pptr },
[SYS_lseek] = { Pfd, Poff_t, Whencename, END64 },
[SYS_truncate] = { Ppath, Poff_t, END64 },
[SYS_ftruncate] = { Pfd, Poff_t, END64 },
[SYS_pread] = { Pfd, Pptr, Pbigsize, Poff_t, END64 },
[SYS_pwrite] = { Pfd, Pptr, Pbigsize, Poff_t, END64 },
[SYS_preadv] = { Pfd, Pptr, Pcount, Poff_t, END64 },
[SYS_pwritev] = { Pfd, Pptr, Pcount, Poff_t, END64 },
[SYS_setgid] = { Gidname },
[SYS_setegid] = { Gidname },
[SYS_seteuid] = { Uidname },
[SYS_pathconf] = { Ppath, Pathconfname },
[SYS_fpathconf] = { Pfd, Pathconfname },
[SYS_swapctl] = { Swapctlname, Pptr, Pdecint },
[SYS_getrlimit] = { Rlimitname, Pptr },
[SYS_setrlimit] = { Rlimitname, Pptr },
[SYS_sysctl] = { Pptr, Pcount, Pptr, Pptr, Pptr, Psize },
[SYS_mlock] = { Pptr, Pbigsize },
[SYS_munlock] = { Pptr, Pbigsize },
[SYS_getpgid] = { Ppid_t },
[SYS_utrace] = { Pptr, Pptr, Psize },
[SYS_semget] = { Pkey_t, Pcount, Semgetname },
[SYS_msgget] = { Pkey_t, Msgflgname },
[SYS_msgsnd] = { Pmsqid, Pptr, Psize, Msgflgname },
[SYS_msgrcv] = { Pmsqid, Pptr, Psize, Pdeclong, Msgflgname },
[SYS_shmat] = { Pshmid, Pptr, Shmatname },
[SYS_shmdt] = { Pptr },
[SYS_minherit] = { Pptr, Pbigsize, Minheritname },
[SYS_poll] = { Pptr, Pucount, Polltimeout },
[SYS_lchown] = { Ppath, Uidname, Gidname },
[SYS_getsid] = { Ppid_t },
[SYS_msync] = { Pptr, Pbigsize, Msyncflagsname },
[SYS_pipe] = { Pptr },
[SYS_fhopen] = { Pptr, Openflagsname },
[SYS_kqueue1] = { Flagsname },
[SYS_mlockall] = { Mlockallname },
[SYS_getresuid] = { Pptr, Pptr, Pptr },
[SYS_setresuid] = { Uidname, Uidname, Uidname },
[SYS_getresgid] = { Pptr, Pptr, Pptr },
[SYS_setresgid] = { Gidname, Gidname, Gidname },
[SYS_closefrom] = { Pfd },
[SYS_sigaltstack] = { Pptr, Pptr },
[SYS_shmget] = { Pkey_t, Pbigsize, Semgetname },
[SYS_semop] = { Psemid, Pptr, Psize },
[SYS_fhstat] = { Pptr, Pptr },
[SYS___semctl] = { Psemid, Pcount, Semctlname, Pptr },
[SYS_shmctl] = { Pshmid, Shmctlname, Pptr },
[SYS_msgctl] = { Pmsqid, Shmctlname, Pptr },
[SYS___thrwakeup] = { Pptr, Pcount },
[SYS___threxit] = { Pptr },
[SYS___thrsigdivert] = { Sigset, Pptr, Pptr },
[SYS___getcwd] = { Pptr, Psize },
[SYS_adjfreq] = { Pptr, Pptr },
[SYS_setrtable] = { Pdecint },
[SYS_faccessat] = { Atfd, Ppath, Accessmodename, Atflagsname },
[SYS_fchmodat] = { Atfd, Ppath, Modename, Atflagsname },
[SYS_fchownat] = { Atfd, Ppath, Uidname, Gidname, Atflagsname },
[SYS_linkat] = { Atfd, Ppath, Atfd, Ppath, Atflagsname },
[SYS_mkdirat] = { Atfd, Ppath, Modename },
[SYS_mkfifoat] = { Atfd, Ppath, Modename },
[SYS_mknodat] = { Atfd, Ppath, Modename, Pdev_t },
[SYS_openat] = { Atfd, Ppath, PASS_TWO, Flagsandmodename },
[SYS_readlinkat] = { Atfd, Ppath, Pptr, Psize },
[SYS_renameat] = { Atfd, Ppath, Atfd, Ppath },
[SYS_symlinkat] = { Ppath, Atfd, Ppath },
[SYS_unlinkat] = { Atfd, Ppath, Atflagsname },
[SYS___set_tcb] = { Pptr },
};
static void
ktrsyscall(struct ktr_syscall *ktr, size_t ktrlen)
{
register_t *ap;
int narg, code;
char sep;
if (ktr->ktr_argsize > ktrlen)
errx(1, "syscall argument length %d > ktr header length %zu",
ktr->ktr_argsize, ktrlen);
narg = ktr->ktr_argsize / sizeof(register_t);
sep = '\0';
code = ktr->ktr_code;
if (code >= SYS_MAXSYSCALL || code < 0)
(void)printf("[%d]", code);
else
(void)printf("%s", syscallnames[code]);
ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall));
(void)putchar('(');
if (code == SYS_sysctl && fancy) {
const char *s;
int n, i, *top;
n = ap[1];
if (n > CTL_MAXNAME)
n = CTL_MAXNAME;
if (n < 0)
errx(1, "invalid sysctl length %d", n);
if (n > 0) {
top = (int *)(ap + 6);
printf("%d", top[0]);
for (i = 1; i < n; i++)
printf(".%d", top[i]);
if ((s = kresolvsysctl(0, top)) != NULL) {
printf("<%s", s);
for (i = 1; i < n; i++) {
if ((s = kresolvsysctl(i, top)) != NULL)
printf(".%s", s);
else
printf(".%d", top[i]);
}
putchar('>');
}
}
sep = ',';
ap += 2;
narg -= 2;
} else if (code < nitems(scargs)) {
const formatter *fmts = scargs[code];
int fmt;
int arg = 0;
while (arg < narg && (fmt = *fmts) != 0) {
if (PAD64 && fmt == PASS_LONGLONG && (arg & 1))
goto skip;
if (sep)
putchar(sep);
sep = ',';
if (!fancy && !FMT_IS_NONFANCY(fmt))
fmt = Pnonfancy;
if (fmt > 0)
formatters[fmt]((int)*ap);
else if (long_formatters[-fmt](*ap))
sep = '\0';
fmts++;
skip:
ap++;
arg++;
}
narg -= arg;
}
while (narg > 0) {
if (sep)
putchar(sep);
if (decimal)
(void)printf("%ld", (long)*ap);
else
(void)printf("%#lx", (long)*ap);
sep = ',';
ap++;
narg--;
}
(void)printf(")\n");
}
static struct ctlname topname[] = CTL_NAMES;
static struct ctlname kernname[] = CTL_KERN_NAMES;
static struct ctlname vmname[] = CTL_VM_NAMES;
static struct ctlname fsname[] = CTL_FS_NAMES;
static struct ctlname netname[] = CTL_NET_NAMES;
static struct ctlname hwname[] = CTL_HW_NAMES;
static struct ctlname debugname[CTL_DEBUG_MAXID];
static struct ctlname kernmallocname[] = CTL_KERN_MALLOC_NAMES;
static struct ctlname forkstatname[] = CTL_KERN_FORKSTAT_NAMES;
static struct ctlname nchstatsname[] = CTL_KERN_NCHSTATS_NAMES;
static struct ctlname kernprocname[] = {
{ NULL },
{ "all" },
{ "pid" },
{ "pgrp" },
{ "session" },
{ "tty" },
{ "uid" },
{ "ruid" },
{ "kthread" },
};
static struct ctlname ttysname[] = CTL_KERN_TTY_NAMES;
static struct ctlname semname[] = CTL_KERN_SEMINFO_NAMES;
static struct ctlname shmname[] = CTL_KERN_SHMINFO_NAMES;
static struct ctlname watchdogname[] = CTL_KERN_WATCHDOG_NAMES;
static struct ctlname tcname[] = CTL_KERN_TIMECOUNTER_NAMES;
#ifdef CTL_MACHDEP_NAMES
static struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
#endif
static struct ctlname ddbname[] = CTL_DDB_NAMES;
#ifndef nitems
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
#endif
#define SETNAME(name) do { names = (name); limit = nitems(name); } while (0)
static const char *
kresolvsysctl(int depth, const int *top)
{
struct ctlname *names;
size_t limit;
int idx = top[depth];
names = NULL;
switch (depth) {
case 0:
SETNAME(topname);
break;
case 1:
switch (top[0]) {
case CTL_KERN:
SETNAME(kernname);
break;
case CTL_VM:
SETNAME(vmname);
break;
case CTL_FS:
SETNAME(fsname);
break;
case CTL_NET:
SETNAME(netname);
break;
case CTL_DEBUG:
SETNAME(debugname);
break;
case CTL_HW:
SETNAME(hwname);
break;
#ifdef CTL_MACHDEP_NAMES
case CTL_MACHDEP:
SETNAME(machdepname);
break;
#endif
case CTL_DDB:
SETNAME(ddbname);
break;
}
break;
case 2:
switch (top[0]) {
case CTL_KERN:
switch (top[1]) {
case KERN_MALLOCSTATS:
SETNAME(kernmallocname);
break;
case KERN_FORKSTAT:
SETNAME(forkstatname);
break;
case KERN_NCHSTATS:
SETNAME(nchstatsname);
break;
case KERN_TTY:
SETNAME(ttysname);
break;
case KERN_SEMINFO:
SETNAME(semname);
break;
case KERN_SHMINFO:
SETNAME(shmname);
break;
case KERN_WATCHDOG:
SETNAME(watchdogname);
break;
case KERN_PROC:
idx++; /* zero is valid at this level */
SETNAME(kernprocname);
break;
case KERN_TIMECOUNTER:
SETNAME(tcname);
break;
}
}
break;
}
if (names != NULL && idx > 0 && idx < limit)
return (names[idx].ctl_name);
return (NULL);
}
static void
ktrsysret(struct ktr_sysret *ktr, size_t ktrlen)
{
register_t ret = 0;
long long retll;
int error = ktr->ktr_error;
int code = ktr->ktr_code;
if (ktrlen < sizeof(*ktr))
errx(1, "sysret length %zu < ktr header length %zu",
ktrlen, sizeof(*ktr));
ktrlen -= sizeof(*ktr);
if (error == 0) {
if (ktrlen == sizeof(ret)) {
memcpy(&ret, ktr+1, sizeof(ret));
retll = ret;
} else if (ktrlen == sizeof(retll))
memcpy(&retll, ktr+1, sizeof(retll));
else
errx(1, "sysret bogus length %zu", ktrlen);
}
if (code >= SYS_MAXSYSCALL || code < 0)
(void)printf("[%d] ", code);
else
(void)printf("%s ", syscallnames[code]);
doerr:
if (error == 0) {
if (fancy) {
switch (code) {
case SYS_lseek:
(void)printf("%lld", retll);
if (retll < 0 || retll > 9)
(void)printf("/%#llx", retll);
break;
case SYS_sigprocmask:
case SYS_sigpending:
sigset(ret);
break;
case SYS___thrsigdivert:
signame(ret);
break;
case SYS_getuid:
case SYS_geteuid:
uidname(ret);
break;
case SYS_getgid:
case SYS_getegid:
gidname(ret);
break;
/* syscalls that return errno values */
case SYS_getlogin_r:
case SYS___thrsleep:
case SYS_getthrname:
case SYS_setthrname:
if ((error = ret) != 0)
goto doerr;
/* FALLTHROUGH */
default:
(void)printf("%ld", (long)ret);
if (ret < 0 || ret > 9)
(void)printf("/%#lx", (long)ret);
}
} else {
if (decimal)
(void)printf("%lld", retll);
else
(void)printf("%#llx", retll);
}
} else if (error == ERESTART)
(void)printf("RESTART");
else if (error == EJUSTRETURN)
(void)printf("JUSTRETURN");
else {
(void)printf("-1 errno %d", error);
if (fancy)
(void)printf(" %s", strerror(error));
}
(void)putchar('\n');
}
static void
ktrnamei(const char *cp, size_t len)
{
showbufc(basecol, (unsigned char *)cp, len, VIS_DQ | VIS_TAB | VIS_NL);
}
void
showbufc(int col, unsigned char *dp, size_t datalen, int flags)
{
int width;
unsigned char visbuf[5], *cp;
flags |= VIS_CSTYLE;
putchar('"');
col++;
for (; datalen > 0; datalen--, dp++) {
(void)vis(visbuf, *dp, flags, *(dp+1));
cp = visbuf;
/*
* Keep track of printables and
* space chars (like fold(1)).
*/
if (col == 0) {
(void)putchar('\t');
col = 8;
}
switch (*cp) {
case '\n':
col = 0;
(void)putchar('\n');
continue;
case '\t':
width = 8 - (col&07);
break;
default:
width = strlen(cp);
}
if (col + width > (screenwidth-2)) {
(void)printf("\\\n\t");
col = 8;
}
col += width;
do {
(void)putchar(*cp++);
} while (*cp);
}
if (col == 0)
(void)printf(" ");
(void)printf("\"\n");
}
static void
showbuf(unsigned char *dp, size_t datalen)
{
size_t i, j;
int col = 0, bpl;
unsigned char c;
char visbuf[4 * KTR_USER_MAXLEN + 1];
if (utracefilter != NULL) {
strvisx(visbuf, dp, datalen, VIS_SAFE | VIS_OCTAL);
printf("%s", visbuf);
return;
}
if (iohex == 1) {
putchar('\t');
col = 8;
for (i = 0; i < datalen; i++) {
printf("%02x", dp[i]);
col += 3;
if (i < datalen - 1) {
if (col + 3 > screenwidth) {
printf("\n\t");
col = 8;
} else
putchar(' ');
}
}
putchar('\n');
return;
}
if (iohex == 2) {
bpl = (screenwidth - 13)/4;
if (bpl <= 0)
bpl = 1;
for (i = 0; i < datalen; i += bpl) {
printf(" %04zx: ", i);
for (j = 0; j < bpl; j++) {
if (i+j >= datalen)
printf(" ");
else
printf("%02x ", dp[i+j]);
}
putchar(' ');
for (j = 0; j < bpl; j++) {
if (i+j >= datalen)
break;
c = dp[i+j];
if (!isprint(c))
c = '.';
putchar(c);
}
putchar('\n');
}
return;
}
(void)printf(" ");
showbufc(7, dp, datalen, 0);
}
static void
ktrgenio(struct ktr_genio *ktr, size_t len)
{
unsigned char *dp = (unsigned char *)ktr + sizeof(struct ktr_genio);
size_t datalen;
if (len < sizeof(struct ktr_genio))
errx(1, "invalid ktr genio length %zu", len);
datalen = len - sizeof(struct ktr_genio);
printf("fd %d %s %zu bytes\n", ktr->ktr_fd,
ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen);
if (maxdata == 0)
return;
if (datalen > maxdata)
datalen = maxdata;
if (iohex && !datalen)
return;
showbuf(dp, datalen);
}
void
siginfo(const siginfo_t *si, int show_signo)
{
if (show_signo) {
printf("signo=");
signame(si->si_signo);
}
if (si->si_code) {
printf(" code=");
if (!fancy)
printf("<%d>", si->si_code);
else {
switch (si->si_signo) {
case SIGILL:
sigill_name(si->si_code);
break;
case SIGTRAP:
sigtrap_name(si->si_code);
break;
case SIGEMT:
sigemt_name(si->si_code);
break;
case SIGFPE:
sigfpe_name(si->si_code);
break;
case SIGBUS:
sigbus_name(si->si_code);
break;
case SIGSEGV:
sigsegv_name(si->si_code);
break;
case SIGCHLD:
sigchld_name(si->si_code);
break;
default:
printf("<%d>", si->si_code);
break;
}
}
}
switch (si->si_signo) {
case SIGSEGV:
case SIGILL:
case SIGBUS:
case SIGFPE:
printf(" addr=%p trapno=%d", si->si_addr, si->si_trapno);
break;
case SIGCHLD:
if (si->si_code == CLD_EXITED) {
printf(" status=%d", si->si_status);
if (si->si_status < 0 || si->si_status > 9)
(void)printf("/%#x", si->si_status);
} else {
printf(" status=");
signame(si->si_status);
}
printf(" pid=%d uid=", si->si_pid);
uidname(si->si_uid);
break;
default:
break;
}
}
static void
ktrpsig(struct ktr_psig *psig)
{
signame(psig->signo);
printf(" ");
if (psig->action == SIG_DFL)
printf("SIG_DFL");
else {
printf("caught handler=0x%lx mask=", (u_long)psig->action);
sigset(psig->mask);
}
siginfo(&psig->si, 0);
putchar('\n');
}
static void
ktruser(struct ktr_user *usr, size_t len)
{
if (len < sizeof(struct ktr_user))
errx(1, "invalid ktr user length %zu", len);
len -= sizeof(struct ktr_user);
if (utracefilter == NULL) {
printf("%.*s:", KTR_USER_MAXIDLEN, usr->ktr_id);
printf(" %zu bytes\n", len);
showbuf((unsigned char *)(usr + 1), len);
} else if (strncmp(usr->ktr_id, utracefilter, KTR_USER_MAXIDLEN) == 0)
showbuf((unsigned char *)(usr + 1), len);
}
static void
ktrexec(const char *ptr, size_t len)
{
int i, col;
size_t l;
putchar('\n');
i = 0;
while (len > 0) {
l = strnlen(ptr, len);
col = printf("\t[%d] = ", i++);
col += 7; /* tab expands from 1 to 8 columns */
showbufc(col, (unsigned char *)ptr, l, VIS_DQ|VIS_TAB|VIS_NL);
if (l == len) {
printf("\tunterminated argument\n");
break;
}
len -= l + 1;
ptr += l + 1;
}
}
static void
ktrpledge(struct ktr_pledge *pledge, size_t len)
{
const char *name = "";
int i;
if (len < sizeof(struct ktr_pledge))
errx(1, "invalid ktr pledge length %zu", len);
if (pledge->syscall >= SYS_MAXSYSCALL || pledge->syscall < 0)
(void)printf("[%d]", pledge->syscall);
else
(void)printf("%s", syscallnames[pledge->syscall]);
printf(", ");
for (i = 0; pledge->code && pledgenames[i].bits != 0; i++) {
if (pledgenames[i].bits & pledge->code) {
name = pledgenames[i].name;
break;
}
}
printf("\"%s\"", name);
(void)printf(", errno %d", pledge->error);
if (fancy)
(void)printf(" %s", strerror(pledge->error));
printf("\n");
}
static void
usage(void)
{
extern char *__progname;
fprintf(stderr, "usage: %s "
"[-dHlnRTXx] [-f file] [-m maxdata] [-P program] [-p pid] "
"[-t trstr]\n\t[-u label]\n", __progname);
exit(1);
}
/*
* FORMATTERS
*/
static void
ioctldecode(int cmd)
{
char dirbuf[4], *dir = dirbuf;
const char *cp;
if ((cp = ioctlname((unsigned)cmd)) != NULL) {
(void)printf("%s", cp);
return;
}
if (cmd & IOC_IN)
*dir++ = 'W';
if (cmd & IOC_OUT)
*dir++ = 'R';
*dir = '\0';
printf("_IO%s('%c',%d",
dirbuf, (int)((cmd >> 8) & 0xff), cmd & 0xff);
if ((cmd & IOC_VOID) == 0)
printf(decimal ? ",%u)" : ",%#x)", (cmd >> 16) & 0xff);
else
printf(")");
}
static void
ptracedecode(int request)
{
if (request >= 0 && request < nitems(ptrace_ops))
(void)printf("%s", ptrace_ops[request]);
else switch(request) {
#ifdef PT_GETFPREGS
case PT_GETFPREGS:
(void)printf("PT_GETFPREGS");
break;
#endif
case PT_GETREGS:
(void)printf("PT_GETREGS");
break;
#ifdef PT_GETXMMREGS
case PT_GETXMMREGS:
(void)printf("PT_GETXMMREGS");
break;
#endif
#ifdef PT_SETFPREGS
case PT_SETFPREGS:
(void)printf("PT_SETFPREGS");
break;
#endif
case PT_SETREGS:
(void)printf("PT_SETREGS");
break;
#ifdef PT_SETXMMREGS
case PT_SETXMMREGS:
(void)printf("PT_SETXMMREGS");
break;
#endif
#ifdef PT_STEP
case PT_STEP:
(void)printf("PT_STEP");
break;
#endif
#ifdef PT_WCOOKIE
case PT_WCOOKIE:
(void)printf("PT_WCOOKIE");
break;
#endif
default:
pdecint(request);
}
}
static void
atfd(int fd)
{
if (fd == AT_FDCWD)
(void)printf("AT_FDCWD");
else
pdecint(fd);
}
static void
polltimeout(int timeout)
{
if (timeout == INFTIM)
(void)printf("INFTIM");
else
pdecint(timeout);
}
static void
wait4pid(int pid)
{
if (pid == WAIT_ANY)
(void)printf("WAIT_ANY");
else if (pid == WAIT_MYPGRP)
(void)printf("WAIT_MYPGRP");
else
pdecint(pid); /* ppgid */
}
static void
signame(int sig)
{
if (sig > 0 && sig < NSIG)
(void)printf("SIG%s", sys_signame[sig]);
else
(void)printf("SIG %d", sig);
}
void
sigset(int ss)
{
int or = 0;
int cnt = 0;
int i;
for (i = 1; i < NSIG; i++)
if (sigismember(&ss, i))
cnt++;
if (cnt > (NSIG-1)/2) {
ss = ~ss;
putchar('~');
}
if (ss == 0) {
(void)printf("0<>");
return;
}
printf("%#x<", ss);
for (i = 1; i < NSIG; i++)
if (sigismember(&ss, i)) {
if (or) putchar('|'); else or=1;
signame(i);
}
printf(">");
}
static void
semctlname(int cmd)
{
switch (cmd) {
case GETNCNT:
(void)printf("GETNCNT");
break;
case GETPID:
(void)printf("GETPID");
break;
case GETVAL:
(void)printf("GETVAL");
break;
case GETALL:
(void)printf("GETALL");
break;
case GETZCNT:
(void)printf("GETZCNT");
break;
case SETVAL:
(void)printf("SETVAL");
break;
case SETALL:
(void)printf("SETALL");
break;
case IPC_RMID:
(void)printf("IPC_RMID");
break;
case IPC_SET:
(void)printf("IPC_SET");
break;
case IPC_STAT:
(void)printf("IPC_STAT");
break;
default: /* Should not reach */
(void)printf("<invalid=%d>", cmd);
}
}
static void
shmctlname(int cmd)
{
switch (cmd) {
case IPC_RMID:
(void)printf("IPC_RMID");
break;
case IPC_SET:
(void)printf("IPC_SET");
break;
case IPC_STAT:
(void)printf("IPC_STAT");
break;
default: /* Should not reach */
(void)printf("<invalid=%d>", cmd);
}
}
static void
semgetname(int flag)
{
int or = 0;
if_print_or(flag, IPC_CREAT, or);
if_print_or(flag, IPC_EXCL, or);
if_print_or(flag, SEM_R, or);
if_print_or(flag, SEM_A, or);
if_print_or(flag, (SEM_R>>3), or);
if_print_or(flag, (SEM_A>>3), or);
if_print_or(flag, (SEM_R>>6), or);
if_print_or(flag, (SEM_A>>6), or);
if (flag & ~(IPC_CREAT|IPC_EXCL|SEM_R|SEM_A|((SEM_R|SEM_A)>>3)|
((SEM_R|SEM_A)>>6)))
printf("<invalid=%#x>", flag);
}
/*
* Only used by SYS_open and SYS_openat. Unless O_CREAT is set in flags, the
* mode argument is unused (and often bogus and misleading).
*/
static void
flagsandmodename(int mode)
{
openflagsname(arg1);
if ((arg1 & O_CREAT) == O_CREAT) {
(void)putchar(',');
modename(mode);
} else if (!fancy)
(void)printf(",<unused>%#o", mode);
}
static void
clockname(int clockid)
{
clocktypename(__CLOCK_TYPE(clockid));
if (__CLOCK_PTID(clockid) != 0)
printf("(%d)", __CLOCK_PTID(clockid));
}
/*
* [g|s]etsockopt's level argument can either be SOL_SOCKET or a value
* referring to a line in /etc/protocols.
*/
static void
sockoptlevelname(int optname)
{
struct protoent *pe;
if (arg1 == SOL_SOCKET) {
(void)printf("SOL_SOCKET,");
sockoptname(optname);
} else {
pe = getprotobynumber(arg1);
(void)printf("%u<%s>,%d", arg1,
pe != NULL ? pe->p_name : "unknown", optname);
}
}
static void
ktraceopname(int ops)
{
int invalid = 0;
printf("%#x<", ops);
switch (KTROP(ops)) {
case KTROP_SET:
printf("KTROP_SET");
break;
case KTROP_CLEAR:
printf("KTROP_CLEAR");
break;
case KTROP_CLEARFILE:
printf("KTROP_CLEARFILE");
break;
default:
printf("KTROP(%d)", KTROP(ops));
invalid = 1;
break;
}
if (ops & KTRFLAG_DESCEND) printf("|KTRFLAG_DESCEND");
printf(">");
if (invalid || (ops & ~(KTROP((unsigned)-1) | KTRFLAG_DESCEND)))
(void)printf("<invalid>%d", ops);
}
static void
idtypeandid(int id)
{
switch (arg1) {
case P_PID:
printf("P_PID,%d", id);
break;
case P_PGID:
printf("P_PGID,%d", id);
break;
case P_ALL:
printf("P_ALL,<unused>%d", id);
break;
default: /* Should not reach */
printf("<invalid=%d>, <unused>%d", arg1, id);
}
}