diff options
Diffstat (limited to 'usr.bin/kdump')
-rw-r--r-- | usr.bin/kdump/Makefile | 40 | ||||
-rw-r--r-- | usr.bin/kdump/kdump.1 | 183 | ||||
-rw-r--r-- | usr.bin/kdump/kdump.c | 1736 | ||||
-rw-r--r-- | usr.bin/kdump/linux_syscalls.conf | 11 | ||||
-rw-r--r-- | usr.bin/kdump/mkioctls | 113 | ||||
-rw-r--r-- | usr.bin/kdump/mksubr | 504 |
6 files changed, 2587 insertions, 0 deletions
diff --git a/usr.bin/kdump/Makefile b/usr.bin/kdump/Makefile new file mode 100644 index 0000000..f19bd16 --- /dev/null +++ b/usr.bin/kdump/Makefile @@ -0,0 +1,40 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 +# $FreeBSD$ + +.if (${MACHINE_ARCH} == "amd64") +SFX= 32 +.endif + +.PATH: ${.CURDIR}/../ktrace + +PROG= kdump +SRCS= kdump_subr.c kdump.c ioctl.c subr.c +DPSRCS= kdump_subr.h +CFLAGS+= -I${.CURDIR}/../ktrace -I${.CURDIR} -I${.CURDIR}/../.. -I. + +.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" +SRCS+= linux_syscalls.c +.endif + +NO_WERROR?= YES + +CLEANFILES= ioctl.c kdump_subr.c kdump_subr.h linux_syscalls.c + +ioctl.c: mkioctls + env MACHINE=${MACHINE} CPP="${CPP}" \ + sh ${.CURDIR}/mkioctls print ${DESTDIR}/usr/include > ${.TARGET} + +kdump_subr.h: mksubr + sh ${.CURDIR}/mksubr ${DESTDIR}/usr/include | \ + sed -n 's/^\([a-z].*)\)$$/void \1;/p' >${.TARGET} + +kdump_subr.c: mksubr kdump_subr.h + sh ${.CURDIR}/mksubr ${DESTDIR}/usr/include >${.TARGET} + +linux_syscalls.c: + /bin/sh ${.CURDIR}/../../sys/kern/makesyscalls.sh \ + ${.CURDIR}/../../sys/${MACHINE_ARCH}/linux${SFX}/syscalls.master ${.CURDIR}/linux_syscalls.conf + echo "int nlinux_syscalls = sizeof(linux_syscallnames) / sizeof(linux_syscallnames[0]);" \ + >> linux_syscalls.c + +.include <bsd.prog.mk> diff --git a/usr.bin/kdump/kdump.1 b/usr.bin/kdump/kdump.1 new file mode 100644 index 0000000..c03985e --- /dev/null +++ b/usr.bin/kdump/kdump.1 @@ -0,0 +1,183 @@ +.\" Copyright (c) 1990, 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. +.\" 4. 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. +.\" +.\" @(#)kdump.1 8.1 (Berkeley) 6/6/93 +.\" $FreeBSD$ +.\" +.Dd April 5, 2012 +.Dt KDUMP 1 +.Os +.Sh NAME +.Nm kdump +.Nd display kernel trace data +.Sh SYNOPSIS +.Nm +.Op Fl dEnlHRsTA +.Op Fl f Ar trfile +.Op Fl m Ar maxdata +.Op Fl p Ar pid +.Op Fl t Ar trstr +.Sh DESCRIPTION +The +.Nm +command displays the kernel trace files produced with +.Xr ktrace 1 +in human readable format. +By default, the file +.Pa ktrace.out +in the current directory is displayed. +.Pp +The options are as follows: +.Bl -tag -width Fl +.It Fl d +Display all numbers in decimal. +.It Fl E +Display elapsed timestamps (time since beginning of trace). +.It Fl f Ar trfile +Display the specified file instead of +.Pa ktrace.out . +.It Fl H +List the thread ID (tid) of the thread with each trace record, if available. +If no thread ID is available, 0 will be printed. +.It Fl l +Loop reading the trace file, once the end-of-file is reached, waiting for +more data. +.It Fl m Ar maxdata +Display at most +.Ar maxdata +bytes when decoding +.Tn I/O . +.It Fl n +Suppress ad hoc translations. +Normally +.Nm +tries to decode many system calls into a more human readable format. +For example, +.Xr ioctl 2 +values are replaced with the macro name and +.Va errno +values are replaced with the +.Xr strerror 3 +string. +Suppressing this feature yields a more consistent output format and is +easily amenable to further processing. +.It Fl p Ar pid +Display only trace events that correspond to the process +.Ar pid . +This may be useful when there are multiple processes recorded in the +same trace file. +.It Fl R +Display relative timestamps (time since previous entry). +.It Fl r +When decoding STRU records, display structure members such as UIDs, +GIDs, dates etc. symbolically instead of numerically. +.It Fl s +Suppress display of I/O data. +.It Fl T +Display absolute timestamps for each entry (seconds since epoch). +.It Fl A +Display description of the ABI of traced process. +.It Fl t Ar trstr +See the +.Fl t +option of +.Xr ktrace 1 . +.El +.Pp +The output format of +.Nm +is line oriented with several fields. +The example below shows a section of a kdump generated by the following +commands: +.Bd -literal -offset indent +?> ktrace echo "ktrace" + +?> kdump + + 85045 echo CALL writev(0x1,0x804b030,0x2) + 85045 echo GIO fd 1 wrote 7 bytes + "ktrace + " + 85045 echo RET writev 7 +.Ed +.Pp +The first field is the PID of the process being traced. +The second field is the name of the program being traced. +The third field is the operation that the kernel performed +on behalf of the process. +If thread IDs are being printed, then an additional thread ID column will be +added to the output between the PID field and program name field. +.Pp +In the first line above, the kernel executes the +.Xr writev 2 +system call on behalf of the process so this is a +.Li CALL +operation. +The fourth field shows the system call that was executed, +including its arguments. +The +.Xr writev 2 +system call takes a file descriptor, in this case 1, or standard +output, then a pointer to the iovector to write, and the number of +iovectors that are to be written. +In the second line we see the operation was +.Li GIO , +for general I/O, and that file descriptor 1 had +seven bytes written to it. +This is followed by the seven bytes that were written, the string +.Qq Li ktrace +with a carriage return and line feed. +The last line is the +.Li RET +operation, showing a return from the kernel, what system call we are +returning from, and the return value that the process received. +Seven bytes were written by the +.Xr writev 2 +system call, so 7 is the return value. +.Pp +The possible operations are: +.Bl -column -offset indent ".Li CALL" ".No data from user process" +.It Sy Name Ta Sy Operation Ta Sy Fourth field +.It Li CALL Ta enter syscall Ta syscall name and arguments +.It Li RET Ta return from syscall Ta syscall name and return value +.It Li NAMI Ta file name lookup Ta path to file +.It Li GIO Ta general I/O Ta fd, read/write, number of bytes +.It Li PSIG Ta signal Ta signal name, handler, mask, code +.It Li CSW Ta context switch Ta stop/resume user/kernel +.It Li USER Ta data from user process Ta the data +.It Li STRU Ta various syscalls Ta structure +.It Li SCTL Ta Xr sysctl 3 requests Ta MIB name +.It Li PFLT Ta enter page fault Ta fault address and type +.It Li PRET Ta return from page fault Ta fault result +.El +.Sh SEE ALSO +.Xr ktrace 1 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.4 . diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c new file mode 100644 index 0000000..4d8e109 --- /dev/null +++ b/usr.bin/kdump/kdump.c @@ -0,0 +1,1736 @@ +/*- + * 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. + * 4. 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. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)kdump.c 8.1 (Berkeley) 6/6/93"; +#endif +#endif /* not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#define _KERNEL +extern int errno; +#include <sys/errno.h> +#undef _KERNEL +#include <sys/param.h> +#include <sys/errno.h> +#define _KERNEL +#include <sys/time.h> +#undef _KERNEL +#include <sys/uio.h> +#include <sys/ktrace.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/sysent.h> +#include <sys/un.h> +#include <sys/queue.h> +#ifdef IPX +#include <sys/types.h> +#include <netipx/ipx.h> +#endif +#ifdef NETATALK +#include <netatalk/at.h> +#endif +#include <arpa/inet.h> +#include <netinet/in.h> +#include <ctype.h> +#include <dlfcn.h> +#include <err.h> +#include <grp.h> +#include <inttypes.h> +#include <locale.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <vis.h> +#include "ktrace.h" +#include "kdump_subr.h" + +u_int abidump(struct ktr_header *); +int fetchprocinfo(struct ktr_header *, u_int *); +int fread_tail(void *, int, int); +void dumpheader(struct ktr_header *); +void ktrsyscall(struct ktr_syscall *, u_int); +void ktrsysret(struct ktr_sysret *, u_int); +void ktrnamei(char *, int); +void hexdump(char *, int, int); +void visdump(char *, int, int); +void ktrgenio(struct ktr_genio *, int); +void ktrpsig(struct ktr_psig *); +void ktrcsw(struct ktr_csw *); +void ktruser_malloc(unsigned char *); +void ktruser_rtld(int, unsigned char *); +void ktruser(int, unsigned char *); +void ktrsockaddr(struct sockaddr *); +void ktrstat(struct stat *); +void ktrstruct(char *, size_t); +void ktrcapfail(struct ktr_cap_fail *); +void ktrfault(struct ktr_fault *); +void ktrfaultend(struct ktr_faultend *); +void usage(void); +void ioctlname(unsigned long, int); + +int timestamp, decimal, fancy = 1, suppressdata, tail, threads, maxdata, + resolv = 0, abiflag = 0; +const char *tracefile = DEF_TRACEFILE; +struct ktr_header ktr_header; + +#define TIME_FORMAT "%b %e %T %Y" +#define eqs(s1, s2) (strcmp((s1), (s2)) == 0) + +#define print_number(i,n,c) do { \ + if (decimal) \ + printf("%c%jd", c, (intmax_t)*i); \ + else \ + printf("%c%#jx", c, (uintmax_t)(u_register_t)*i); \ + i++; \ + n--; \ + c = ','; \ +} while (0) + +#if defined(__amd64__) || defined(__i386__) + +void linux_ktrsyscall(struct ktr_syscall *); +void linux_ktrsysret(struct ktr_sysret *); +extern char *linux_syscallnames[]; +extern int nlinux_syscalls; + +/* + * from linux.h + * Linux syscalls return negative errno's, we do positive and map them + */ +static int bsd_to_linux_errno[ELAST + 1] = { + -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, + -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, + -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, + -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, + -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, + -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, + -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, + -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, + -6, -6, -43, -42, -75,-125, -84, -95, -16, -74, + -72, -67, -71 +}; +#endif + +struct proc_info +{ + TAILQ_ENTRY(proc_info) info; + u_int sv_flags; + pid_t pid; +}; + +TAILQ_HEAD(trace_procs, proc_info) trace_procs; + +int +main(int argc, char *argv[]) +{ + int ch, ktrlen, size; + void *m; + int trpoints = ALL_POINTS; + int drop_logged; + pid_t pid = 0; + u_int sv_flags; + + setlocale(LC_CTYPE, ""); + + while ((ch = getopt(argc,argv,"f:dElm:np:AHRrsTt:")) != -1) + switch (ch) { + case 'A': + abiflag = 1; + break; + case 'f': + tracefile = optarg; + break; + case 'd': + decimal = 1; + break; + case 'l': + tail = 1; + break; + case 'm': + maxdata = atoi(optarg); + break; + case 'n': + fancy = 0; + break; + case 'p': + pid = atoi(optarg); + break; + case 'r': + resolv = 1; + break; + case 's': + suppressdata = 1; + break; + case 'E': + timestamp = 3; /* elapsed timestamp */ + break; + case 'H': + threads = 1; + break; + case 'R': + timestamp = 2; /* relative timestamp */ + break; + case 'T': + timestamp = 1; + break; + case 't': + trpoints = getpoints(optarg); + if (trpoints < 0) + errx(1, "unknown trace point in %s", optarg); + break; + default: + usage(); + } + + if (argc > optind) + usage(); + + m = malloc(size = 1025); + if (m == NULL) + errx(1, "%s", strerror(ENOMEM)); + if (!freopen(tracefile, "r", stdin)) + err(1, "%s", tracefile); + TAILQ_INIT(&trace_procs); + drop_logged = 0; + while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) { + if (ktr_header.ktr_type & KTR_DROP) { + ktr_header.ktr_type &= ~KTR_DROP; + if (!drop_logged && threads) { + printf( + "%6jd %6jd %-8.*s Events dropped.\n", + (intmax_t)ktr_header.ktr_pid, + ktr_header.ktr_tid > 0 ? + (intmax_t)ktr_header.ktr_tid : 0, + MAXCOMLEN, ktr_header.ktr_comm); + drop_logged = 1; + } else if (!drop_logged) { + printf("%6jd %-8.*s Events dropped.\n", + (intmax_t)ktr_header.ktr_pid, MAXCOMLEN, + ktr_header.ktr_comm); + drop_logged = 1; + } + } + if (trpoints & (1<<ktr_header.ktr_type)) + if (pid == 0 || ktr_header.ktr_pid == pid) + dumpheader(&ktr_header); + if ((ktrlen = ktr_header.ktr_len) < 0) + errx(1, "bogus length 0x%x", ktrlen); + if (ktrlen > size) { + m = realloc(m, ktrlen+1); + if (m == NULL) + errx(1, "%s", strerror(ENOMEM)); + size = ktrlen; + } + if (ktrlen && fread_tail(m, ktrlen, 1) == 0) + errx(1, "data too short"); + if (fetchprocinfo(&ktr_header, (u_int *)m) != 0) + continue; + sv_flags = abidump(&ktr_header); + if (pid && ktr_header.ktr_pid != pid) + continue; + if ((trpoints & (1<<ktr_header.ktr_type)) == 0) + continue; + drop_logged = 0; + switch (ktr_header.ktr_type) { + case KTR_SYSCALL: +#if defined(__amd64__) || defined(__i386__) + if ((sv_flags & SV_ABI_MASK) == SV_ABI_LINUX) + linux_ktrsyscall((struct ktr_syscall *)m); + else +#endif + ktrsyscall((struct ktr_syscall *)m, sv_flags); + break; + case KTR_SYSRET: +#if defined(__amd64__) || defined(__i386__) + if ((sv_flags & SV_ABI_MASK) == SV_ABI_LINUX) + linux_ktrsysret((struct ktr_sysret *)m); + else +#endif + ktrsysret((struct ktr_sysret *)m, sv_flags); + break; + case KTR_NAMEI: + case KTR_SYSCTL: + ktrnamei(m, ktrlen); + break; + case KTR_GENIO: + ktrgenio((struct ktr_genio *)m, ktrlen); + break; + case KTR_PSIG: + ktrpsig((struct ktr_psig *)m); + break; + case KTR_CSW: + ktrcsw((struct ktr_csw *)m); + break; + case KTR_USER: + ktruser(ktrlen, m); + break; + case KTR_STRUCT: + ktrstruct(m, ktrlen); + break; + case KTR_CAPFAIL: + ktrcapfail((struct ktr_cap_fail *)m); + break; + case KTR_FAULT: + ktrfault((struct ktr_fault *)m); + break; + case KTR_FAULTEND: + ktrfaultend((struct ktr_faultend *)m); + break; + default: + printf("\n"); + break; + } + if (tail) + fflush(stdout); + } + return 0; +} + +int +fread_tail(void *buf, int size, int num) +{ + int i; + + while ((i = fread(buf, size, num, stdin)) == 0 && tail) { + sleep(1); + clearerr(stdin); + } + return (i); +} + +int +fetchprocinfo(struct ktr_header *kth, u_int *flags) +{ + struct proc_info *pi; + + switch (kth->ktr_type) { + case KTR_PROCCTOR: + TAILQ_FOREACH(pi, &trace_procs, info) { + if (pi->pid == kth->ktr_pid) { + TAILQ_REMOVE(&trace_procs, pi, info); + break; + } + } + pi = malloc(sizeof(struct proc_info)); + if (pi == NULL) + errx(1, "%s", strerror(ENOMEM)); + pi->sv_flags = *flags; + pi->pid = kth->ktr_pid; + TAILQ_INSERT_TAIL(&trace_procs, pi, info); + return (1); + + case KTR_PROCDTOR: + TAILQ_FOREACH(pi, &trace_procs, info) { + if (pi->pid == kth->ktr_pid) { + TAILQ_REMOVE(&trace_procs, pi, info); + free(pi); + break; + } + } + return (1); + } + + return (0); +} + +u_int +abidump(struct ktr_header *kth) +{ + struct proc_info *pi; + const char *abi; + const char *arch; + u_int flags = 0; + + TAILQ_FOREACH(pi, &trace_procs, info) { + if (pi->pid == kth->ktr_pid) { + flags = pi->sv_flags; + break; + } + } + + if (abiflag == 0) + return (flags); + + switch (flags & SV_ABI_MASK) { + case SV_ABI_LINUX: + abi = "L"; + break; + case SV_ABI_FREEBSD: + abi = "F"; + break; + default: + abi = "U"; + break; + } + + if (flags != 0) { + if (flags & SV_LP64) + arch = "64"; + else + arch = "32"; + } else + arch = "00"; + + printf("%s%s ", abi, arch); + + return (flags); +} + +void +dumpheader(struct ktr_header *kth) +{ + static char unknown[64]; + static struct timeval prevtime, temp; + const char *type; + + 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_CSW: + type = "CSW "; + break; + case KTR_USER: + type = "USER"; + break; + case KTR_STRUCT: + type = "STRU"; + break; + case KTR_SYSCTL: + type = "SCTL"; + break; + case KTR_PROCCTOR: + /* FALLTHROUGH */ + case KTR_PROCDTOR: + return; + case KTR_CAPFAIL: + type = "CAP "; + break; + case KTR_FAULT: + type = "PFLT"; + break; + case KTR_FAULTEND: + type = "PRET"; + break; + default: + sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type); + type = unknown; + } + + /* + * The ktr_tid field was previously the ktr_buffer field, which held + * the kernel pointer value for the buffer associated with data + * following the record header. It now holds a threadid, but only + * for trace files after the change. Older trace files still contain + * kernel pointers. Detect this and suppress the results by printing + * negative tid's as 0. + */ + if (threads) + printf("%6jd %6jd %-8.*s ", (intmax_t)kth->ktr_pid, + kth->ktr_tid > 0 ? (intmax_t)kth->ktr_tid : 0, + MAXCOMLEN, kth->ktr_comm); + else + printf("%6jd %-8.*s ", (intmax_t)kth->ktr_pid, MAXCOMLEN, + kth->ktr_comm); + if (timestamp) { + if (timestamp == 3) { + if (prevtime.tv_sec == 0) + prevtime = kth->ktr_time; + timevalsub(&kth->ktr_time, &prevtime); + } + if (timestamp == 2) { + temp = kth->ktr_time; + timevalsub(&kth->ktr_time, &prevtime); + prevtime = temp; + } + printf("%jd.%06ld ", (intmax_t)kth->ktr_time.tv_sec, + kth->ktr_time.tv_usec); + } + printf("%s ", type); +} + +#include <sys/syscall.h> +#define KTRACE +#include <sys/kern/syscalls.c> +#undef KTRACE +int nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]); + +void +ktrsyscall(struct ktr_syscall *ktr, u_int flags) +{ + int narg = ktr->ktr_narg; + register_t *ip; + intmax_t arg; + + if ((flags != 0 && ((flags & SV_ABI_MASK) != SV_ABI_FREEBSD)) || + (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0)) + printf("[%d]", ktr->ktr_code); + else + printf("%s", syscallnames[ktr->ktr_code]); + ip = &ktr->ktr_args[0]; + if (narg) { + char c = '('; + if (fancy && + (flags == 0 || (flags & SV_ABI_MASK) == SV_ABI_FREEBSD)) { + switch (ktr->ktr_code) { + case SYS_ioctl: { + print_number(ip, narg, c); + putchar(c); + ioctlname(*ip, decimal); + c = ','; + ip++; + narg--; + break; + } + case SYS_ptrace: + putchar('('); + ptraceopname(*ip); + c = ','; + ip++; + narg--; + break; + case SYS_access: + case SYS_eaccess: + print_number(ip, narg, c); + putchar(','); + accessmodename(*ip); + ip++; + narg--; + break; + case SYS_open: + print_number(ip, narg, c); + putchar(','); + flagsandmodename(ip[0], ip[1], decimal); + ip += 2; + narg -= 2; + break; + case SYS_wait4: + print_number(ip, narg, c); + print_number(ip, narg, c); + putchar(','); + wait4optname(*ip); + ip++; + narg--; + break; + case SYS_chmod: + case SYS_fchmod: + case SYS_lchmod: + print_number(ip, narg, c); + putchar(','); + modename(*ip); + ip++; + narg--; + break; + case SYS_mknod: + print_number(ip, narg, c); + putchar(','); + modename(*ip); + ip++; + narg--; + break; + case SYS_getfsstat: + print_number(ip, narg, c); + print_number(ip, narg, c); + putchar(','); + getfsstatflagsname(*ip); + ip++; + narg--; + break; + case SYS_mount: + print_number(ip, narg, c); + print_number(ip, narg, c); + putchar(','); + mountflagsname(*ip); + ip++; + narg--; + break; + case SYS_unmount: + print_number(ip, narg, c); + putchar(','); + mountflagsname(*ip); + ip++; + narg--; + break; + case SYS_recvmsg: + case SYS_sendmsg: + print_number(ip, narg, c); + print_number(ip, narg, c); + putchar(','); + sendrecvflagsname(*ip); + ip++; + narg--; + break; + case SYS_recvfrom: + case SYS_sendto: + print_number(ip, narg, c); + print_number(ip, narg, c); + print_number(ip, narg, c); + putchar(','); + sendrecvflagsname(*ip); + ip++; + narg--; + break; + case SYS_chflags: + case SYS_fchflags: + case SYS_lchflags: + print_number(ip, narg, c); + putchar(','); + modename(*ip); + ip++; + narg--; + break; + case SYS_kill: + print_number(ip, narg, c); + putchar(','); + signame(*ip); + ip++; + narg--; + break; + case SYS_reboot: + putchar('('); + rebootoptname(*ip); + ip++; + narg--; + break; + case SYS_umask: + putchar('('); + modename(*ip); + ip++; + narg--; + break; + case SYS_msync: + print_number(ip, narg, c); + print_number(ip, narg, c); + putchar(','); + msyncflagsname(*ip); + ip++; + narg--; + break; +#ifdef SYS_freebsd6_mmap + case SYS_freebsd6_mmap: + print_number(ip, narg, c); + print_number(ip, narg, c); + putchar(','); + mmapprotname(*ip); + putchar(','); + ip++; + narg--; + mmapflagsname(*ip); + ip++; + narg--; + break; +#endif + case SYS_mmap: + print_number(ip, narg, c); + print_number(ip, narg, c); + putchar(','); + mmapprotname(*ip); + putchar(','); + ip++; + narg--; + mmapflagsname(*ip); + ip++; + narg--; + break; + case SYS_mprotect: + print_number(ip, narg, c); + print_number(ip, narg, c); + putchar(','); + mmapprotname(*ip); + ip++; + narg--; + break; + case SYS_madvise: + print_number(ip, narg, c); + print_number(ip, narg, c); + putchar(','); + madvisebehavname(*ip); + ip++; + narg--; + break; + case SYS_setpriority: + print_number(ip, narg, c); + print_number(ip, narg, c); + putchar(','); + prioname(*ip); + ip++; + narg--; + break; + case SYS_fcntl: + print_number(ip, narg, c); + putchar(','); + fcntlcmdname(ip[0], ip[1], decimal); + ip += 2; + narg -= 2; + break; + case SYS_socket: { + int sockdomain; + putchar('('); + sockdomain = *ip; + sockdomainname(sockdomain); + ip++; + narg--; + putchar(','); + socktypename(*ip); + ip++; + narg--; + if (sockdomain == PF_INET || + sockdomain == PF_INET6) { + putchar(','); + sockipprotoname(*ip); + ip++; + narg--; + } + c = ','; + break; + } + case SYS_setsockopt: + case SYS_getsockopt: + print_number(ip, narg, c); + putchar(','); + sockoptlevelname(*ip, decimal); + if (*ip == SOL_SOCKET) { + ip++; + narg--; + putchar(','); + sockoptname(*ip); + } + ip++; + narg--; + break; +#ifdef SYS_freebsd6_lseek + case SYS_freebsd6_lseek: + print_number(ip, narg, c); + /* Hidden 'pad' argument, not in lseek(2) */ + print_number(ip, narg, c); + print_number(ip, narg, c); + putchar(','); + whencename(*ip); + ip++; + narg--; + break; +#endif + case SYS_lseek: + print_number(ip, narg, c); + /* Hidden 'pad' argument, not in lseek(2) */ + print_number(ip, narg, c); + putchar(','); + whencename(*ip); + ip++; + narg--; + break; + case SYS_flock: + print_number(ip, narg, c); + putchar(','); + flockname(*ip); + ip++; + narg--; + break; + case SYS_mkfifo: + case SYS_mkdir: + print_number(ip, narg, c); + putchar(','); + modename(*ip); + ip++; + narg--; + break; + case SYS_shutdown: + print_number(ip, narg, c); + putchar(','); + shutdownhowname(*ip); + ip++; + narg--; + break; + case SYS_socketpair: + putchar('('); + sockdomainname(*ip); + ip++; + narg--; + putchar(','); + socktypename(*ip); + ip++; + narg--; + c = ','; + break; + case SYS_getrlimit: + case SYS_setrlimit: + putchar('('); + rlimitname(*ip); + ip++; + narg--; + c = ','; + break; + case SYS_quotactl: + print_number(ip, narg, c); + putchar(','); + quotactlname(*ip); + ip++; + narg--; + c = ','; + break; + case SYS_nfssvc: + putchar('('); + nfssvcname(*ip); + ip++; + narg--; + c = ','; + break; + case SYS_rtprio: + putchar('('); + rtprioname(*ip); + ip++; + narg--; + c = ','; + break; + case SYS___semctl: + print_number(ip, narg, c); + print_number(ip, narg, c); + putchar(','); + semctlname(*ip); + ip++; + narg--; + break; + case SYS_semget: + print_number(ip, narg, c); + print_number(ip, narg, c); + putchar(','); + semgetname(*ip); + ip++; + narg--; + break; + case SYS_msgctl: + print_number(ip, narg, c); + putchar(','); + shmctlname(*ip); + ip++; + narg--; + break; + case SYS_shmat: + print_number(ip, narg, c); + print_number(ip, narg, c); + putchar(','); + shmatname(*ip); + ip++; + narg--; + break; + case SYS_shmctl: + print_number(ip, narg, c); + putchar(','); + shmctlname(*ip); + ip++; + narg--; + break; + case SYS_minherit: + print_number(ip, narg, c); + print_number(ip, narg, c); + putchar(','); + minheritname(*ip); + ip++; + narg--; + break; + case SYS_rfork: + putchar('('); + rforkname(*ip); + ip++; + narg--; + c = ','; + break; + case SYS_lio_listio: + putchar('('); + lio_listioname(*ip); + ip++; + narg--; + c = ','; + break; + case SYS_mlockall: + putchar('('); + mlockallname(*ip); + ip++; + narg--; + break; + case SYS_sched_setscheduler: + print_number(ip, narg, c); + putchar(','); + schedpolicyname(*ip); + ip++; + narg--; + break; + case SYS_sched_get_priority_max: + case SYS_sched_get_priority_min: + putchar('('); + schedpolicyname(*ip); + ip++; + narg--; + break; + case SYS_sendfile: + print_number(ip, narg, c); + print_number(ip, narg, c); + print_number(ip, narg, c); + print_number(ip, narg, c); + print_number(ip, narg, c); + print_number(ip, narg, c); + putchar(','); + sendfileflagsname(*ip); + ip++; + narg--; + break; + case SYS_kldsym: + print_number(ip, narg, c); + putchar(','); + kldsymcmdname(*ip); + ip++; + narg--; + break; + case SYS_sigprocmask: + putchar('('); + sigprocmaskhowname(*ip); + ip++; + narg--; + c = ','; + break; + case SYS___acl_get_file: + case SYS___acl_set_file: + case SYS___acl_get_fd: + case SYS___acl_set_fd: + case SYS___acl_delete_file: + case SYS___acl_delete_fd: + case SYS___acl_aclcheck_file: + case SYS___acl_aclcheck_fd: + case SYS___acl_get_link: + case SYS___acl_set_link: + case SYS___acl_delete_link: + case SYS___acl_aclcheck_link: + print_number(ip, narg, c); + putchar(','); + acltypename(*ip); + ip++; + narg--; + break; + case SYS_sigaction: + putchar('('); + signame(*ip); + ip++; + narg--; + c = ','; + break; + case SYS_extattrctl: + print_number(ip, narg, c); + putchar(','); + extattrctlname(*ip); + ip++; + narg--; + break; + case SYS_nmount: + print_number(ip, narg, c); + print_number(ip, narg, c); + putchar(','); + mountflagsname(*ip); + ip++; + narg--; + break; + case SYS_thr_create: + print_number(ip, narg, c); + print_number(ip, narg, c); + putchar(','); + thrcreateflagsname(*ip); + ip++; + narg--; + break; + case SYS_thr_kill: + print_number(ip, narg, c); + putchar(','); + signame(*ip); + ip++; + narg--; + break; + case SYS_kldunloadf: + print_number(ip, narg, c); + putchar(','); + kldunloadfflagsname(*ip); + ip++; + narg--; + break; + case SYS_cap_new: + print_number(ip, narg, c); + putchar(','); + arg = *ip; + ip++; + narg--; + /* + * Hack: the second argument is a + * cap_rights_t, which 64 bits wide, so on + * 32-bit systems, it is split between two + * registers. + * + * Since sizeof() is not evaluated by the + * preprocessor, we can't use an #ifdef, + * but the compiler will probably optimize + * the code out anyway. + */ + if (sizeof(cap_rights_t) > sizeof(register_t)) { +#if _BYTE_ORDER == _LITTLE_ENDIAN + arg = ((intmax_t)*ip << 32) + arg; +#else + arg = (arg << 32) + *ip; +#endif + ip++; + narg--; + } + capname(arg); + break; + case SYS_posix_fadvise: + print_number(ip, narg, c); + print_number(ip, narg, c); + print_number(ip, narg, c); + (void)putchar(','); + fadvisebehavname((int)*ip); + ip++; + narg--; + break; + } + } + while (narg > 0) { + print_number(ip, narg, c); + } + putchar(')'); + } + putchar('\n'); +} + +void +ktrsysret(struct ktr_sysret *ktr, u_int flags) +{ + register_t ret = ktr->ktr_retval; + int error = ktr->ktr_error; + int code = ktr->ktr_code; + + if ((flags != 0 && ((flags & SV_ABI_MASK) != SV_ABI_FREEBSD)) || + (code >= nsyscalls || code < 0)) + printf("[%d] ", code); + else + printf("%s ", syscallnames[code]); + + if (error == 0) { + if (fancy) { + printf("%ld", (long)ret); + if (ret < 0 || ret > 9) + printf("/%#lx", (unsigned long)ret); + } else { + if (decimal) + printf("%ld", (long)ret); + else + printf("%#lx", (unsigned long)ret); + } + } else if (error == ERESTART) + printf("RESTART"); + else if (error == EJUSTRETURN) + printf("JUSTRETURN"); + else { + printf("-1 errno %d", ktr->ktr_error); + if (fancy) + printf(" %s", strerror(ktr->ktr_error)); + } + putchar('\n'); +} + +void +ktrnamei(char *cp, int len) +{ + printf("\"%.*s\"\n", len, cp); +} + +void +hexdump(char *p, int len, int screenwidth) +{ + int n, i; + int width; + + width = 0; + do { + width += 2; + i = 13; /* base offset */ + i += (width / 2) + 1; /* spaces every second byte */ + i += (width * 2); /* width of bytes */ + i += 3; /* " |" */ + i += width; /* each byte */ + i += 1; /* "|" */ + } while (i < screenwidth); + width -= 2; + + for (n = 0; n < len; n += width) { + for (i = n; i < n + width; i++) { + if ((i % width) == 0) { /* beginning of line */ + printf(" 0x%04x", i); + } + if ((i % 2) == 0) { + printf(" "); + } + if (i < len) + printf("%02x", p[i] & 0xff); + else + printf(" "); + } + printf(" |"); + for (i = n; i < n + width; i++) { + if (i >= len) + break; + if (p[i] >= ' ' && p[i] <= '~') + printf("%c", p[i]); + else + printf("."); + } + printf("|\n"); + } + if ((i % width) != 0) + printf("\n"); +} + +void +visdump(char *dp, int datalen, int screenwidth) +{ + int col = 0; + char *cp; + int width; + char visbuf[5]; + + printf(" \""); + col = 8; + for (;datalen > 0; datalen--, dp++) { + vis(visbuf, *dp, VIS_CSTYLE, *(dp+1)); + cp = visbuf; + /* + * Keep track of printables and + * space chars (like fold(1)). + */ + if (col == 0) { + putchar('\t'); + col = 8; + } + switch(*cp) { + case '\n': + col = 0; + putchar('\n'); + continue; + case '\t': + width = 8 - (col&07); + break; + default: + width = strlen(cp); + } + if (col + width > (screenwidth-2)) { + printf("\\\n\t"); + col = 8; + } + col += width; + do { + putchar(*cp++); + } while (*cp); + } + if (col == 0) + printf(" "); + printf("\"\n"); +} + +void +ktrgenio(struct ktr_genio *ktr, int len) +{ + int datalen = len - sizeof (struct ktr_genio); + char *dp = (char *)ktr + sizeof (struct ktr_genio); + static int screenwidth = 0; + int i, binary; + + 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; + } + printf("fd %d %s %d byte%s\n", ktr->ktr_fd, + ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen, + datalen == 1 ? "" : "s"); + if (suppressdata) + return; + if (maxdata && datalen > maxdata) + datalen = maxdata; + + for (i = 0, binary = 0; i < datalen && binary == 0; i++) { + if (dp[i] >= 32 && dp[i] < 127) + continue; + if (dp[i] == 10 || dp[i] == 13 || dp[i] == 0 || dp[i] == 9) + continue; + binary = 1; + } + if (binary) + hexdump(dp, datalen, screenwidth); + else + visdump(dp, datalen, screenwidth); +} + +const char *signames[] = { + "NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", /* 1 - 6 */ + "EMT", "FPE", "KILL", "BUS", "SEGV", "SYS", /* 7 - 12 */ + "PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP", /* 13 - 18 */ + "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU", /* 19 - 24 */ + "XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1", /* 25 - 30 */ + "USR2", NULL, /* 31 - 32 */ +}; + +void +ktrpsig(struct ktr_psig *psig) +{ + if (psig->signo > 0 && psig->signo < NSIG) + printf("SIG%s ", signames[psig->signo]); + else + printf("SIG %d ", psig->signo); + if (psig->action == SIG_DFL) + printf("SIG_DFL code=0x%x\n", psig->code); + else { + printf("caught handler=0x%lx mask=0x%x code=0x%x\n", + (u_long)psig->action, psig->mask.__bits[0], psig->code); + } +} + +void +ktrcsw(struct ktr_csw *cs) +{ + printf("%s %s\n", cs->out ? "stop" : "resume", + cs->user ? "user" : "kernel"); +} + +#define UTRACE_DLOPEN_START 1 +#define UTRACE_DLOPEN_STOP 2 +#define UTRACE_DLCLOSE_START 3 +#define UTRACE_DLCLOSE_STOP 4 +#define UTRACE_LOAD_OBJECT 5 +#define UTRACE_UNLOAD_OBJECT 6 +#define UTRACE_ADD_RUNDEP 7 +#define UTRACE_PRELOAD_FINISHED 8 +#define UTRACE_INIT_CALL 9 +#define UTRACE_FINI_CALL 10 + +struct utrace_rtld { + char sig[4]; /* 'RTLD' */ + int event; + void *handle; + void *mapbase; + size_t mapsize; + int refcnt; + char name[MAXPATHLEN]; +}; + +void +ktruser_rtld(int len, unsigned char *p) +{ + struct utrace_rtld *ut = (struct utrace_rtld *)p; + void *parent; + int mode; + + switch (ut->event) { + case UTRACE_DLOPEN_START: + mode = ut->refcnt; + printf("dlopen(%s, ", ut->name); + switch (mode & RTLD_MODEMASK) { + case RTLD_NOW: + printf("RTLD_NOW"); + break; + case RTLD_LAZY: + printf("RTLD_LAZY"); + break; + default: + printf("%#x", mode & RTLD_MODEMASK); + } + if (mode & RTLD_GLOBAL) + printf(" | RTLD_GLOBAL"); + if (mode & RTLD_TRACE) + printf(" | RTLD_TRACE"); + if (mode & ~(RTLD_MODEMASK | RTLD_GLOBAL | RTLD_TRACE)) + printf(" | %#x", mode & + ~(RTLD_MODEMASK | RTLD_GLOBAL | RTLD_TRACE)); + printf(")\n"); + break; + case UTRACE_DLOPEN_STOP: + printf("%p = dlopen(%s) ref %d\n", ut->handle, ut->name, + ut->refcnt); + break; + case UTRACE_DLCLOSE_START: + printf("dlclose(%p) (%s, %d)\n", ut->handle, ut->name, + ut->refcnt); + break; + case UTRACE_DLCLOSE_STOP: + printf("dlclose(%p) finished\n", ut->handle); + break; + case UTRACE_LOAD_OBJECT: + printf("RTLD: loaded %p @ %p - %p (%s)\n", ut->handle, + ut->mapbase, (char *)ut->mapbase + ut->mapsize - 1, + ut->name); + break; + case UTRACE_UNLOAD_OBJECT: + printf("RTLD: unloaded %p @ %p - %p (%s)\n", ut->handle, + ut->mapbase, (char *)ut->mapbase + ut->mapsize - 1, + ut->name); + break; + case UTRACE_ADD_RUNDEP: + parent = ut->mapbase; + printf("RTLD: %p now depends on %p (%s, %d)\n", parent, + ut->handle, ut->name, ut->refcnt); + break; + case UTRACE_PRELOAD_FINISHED: + printf("RTLD: LD_PRELOAD finished\n"); + break; + case UTRACE_INIT_CALL: + printf("RTLD: init %p for %p (%s)\n", ut->mapbase, ut->handle, + ut->name); + break; + case UTRACE_FINI_CALL: + printf("RTLD: fini %p for %p (%s)\n", ut->mapbase, ut->handle, + ut->name); + break; + default: + p += 4; + len -= 4; + printf("RTLD: %d ", len); + while (len--) + if (decimal) + printf(" %d", *p++); + else + printf(" %02x", *p++); + printf("\n"); + } +} + +struct utrace_malloc { + void *p; + size_t s; + void *r; +}; + +void +ktruser_malloc(unsigned char *p) +{ + struct utrace_malloc *ut = (struct utrace_malloc *)p; + + if (ut->p == (void *)(intptr_t)(-1)) + printf("malloc_init()\n"); + else if (ut->s == 0) + printf("free(%p)\n", ut->p); + else if (ut->p == NULL) + printf("%p = malloc(%zu)\n", ut->r, ut->s); + else + printf("%p = realloc(%p, %zu)\n", ut->r, ut->p, ut->s); +} + +void +ktruser(int len, unsigned char *p) +{ + + if (len >= 8 && bcmp(p, "RTLD", 4) == 0) { + ktruser_rtld(len, p); + return; + } + + if (len == sizeof(struct utrace_malloc)) { + ktruser_malloc(p); + return; + } + + printf("%d ", len); + while (len--) + if (decimal) + printf(" %d", *p++); + else + printf(" %02x", *p++); + printf("\n"); +} + +void +ktrsockaddr(struct sockaddr *sa) +{ +/* + TODO: Support additional address families + #include <netnatm/natm.h> + struct sockaddr_natm *natm; + #include <netsmb/netbios.h> + struct sockaddr_nb *nb; +*/ + char addr[64]; + + /* + * note: ktrstruct() has already verified that sa points to a + * buffer at least sizeof(struct sockaddr) bytes long and exactly + * sa->sa_len bytes long. + */ + printf("struct sockaddr { "); + sockfamilyname(sa->sa_family); + printf(", "); + +#define check_sockaddr_len(n) \ + if (sa_##n.s##n##_len < sizeof(struct sockaddr_##n)) { \ + printf("invalid"); \ + break; \ + } + + switch(sa->sa_family) { + case AF_INET: { + struct sockaddr_in sa_in; + + memset(&sa_in, 0, sizeof(sa_in)); + memcpy(&sa_in, sa, sizeof(sa)); + check_sockaddr_len(in); + inet_ntop(AF_INET, &sa_in.sin_addr, addr, sizeof addr); + printf("%s:%u", addr, ntohs(sa_in.sin_port)); + break; + } +#ifdef NETATALK + case AF_APPLETALK: { + struct sockaddr_at sa_at; + struct netrange *nr; + + memset(&sa_at, 0, sizeof(sa_at)); + memcpy(&sa_at, sa, sizeof(sa)); + check_sockaddr_len(at); + nr = &sa_at.sat_range.r_netrange; + printf("%d.%d, %d-%d, %d", ntohs(sa_at.sat_addr.s_net), + sa_at.sat_addr.s_node, ntohs(nr->nr_firstnet), + ntohs(nr->nr_lastnet), nr->nr_phase); + break; + } +#endif + case AF_INET6: { + struct sockaddr_in6 sa_in6; + + memset(&sa_in6, 0, sizeof(sa_in6)); + memcpy(&sa_in6, sa, sizeof(sa)); + check_sockaddr_len(in6); + inet_ntop(AF_INET6, &sa_in6.sin6_addr, addr, sizeof addr); + printf("[%s]:%u", addr, htons(sa_in6.sin6_port)); + break; + } +#ifdef IPX + case AF_IPX: { + struct sockaddr_ipx sa_ipx; + + memset(&sa_ipx, 0, sizeof(sa_ipx)); + memcpy(&sa_ipx, sa, sizeof(sa)); + check_sockaddr_len(ipx); + /* XXX wish we had ipx_ntop */ + printf("%s", ipx_ntoa(sa_ipx.sipx_addr)); + free(sa_ipx); + break; + } +#endif + case AF_UNIX: { + struct sockaddr_un sa_un; + + memset(&sa_un, 0, sizeof(sa_un)); + memcpy(&sa_un, sa, sizeof(sa)); + check_sockaddr_len(un); + printf("%.*s", (int)sizeof(sa_un.sun_path), sa_un.sun_path); + break; + } + default: + printf("unknown address family"); + } + printf(" }\n"); +} + +void +ktrstat(struct stat *statp) +{ + char mode[12], timestr[PATH_MAX + 4]; + struct passwd *pwd; + struct group *grp; + struct tm *tm; + + /* + * note: ktrstruct() has already verified that statp points to a + * buffer exactly sizeof(struct stat) bytes long. + */ + printf("struct stat {"); + strmode(statp->st_mode, mode); + printf("dev=%ju, ino=%ju, mode=%s, nlink=%ju, ", + (uintmax_t)statp->st_dev, (uintmax_t)statp->st_ino, mode, + (uintmax_t)statp->st_nlink); + if (resolv == 0 || (pwd = getpwuid(statp->st_uid)) == NULL) + printf("uid=%ju, ", (uintmax_t)statp->st_uid); + else + printf("uid=\"%s\", ", pwd->pw_name); + if (resolv == 0 || (grp = getgrgid(statp->st_gid)) == NULL) + printf("gid=%ju, ", (uintmax_t)statp->st_gid); + else + printf("gid=\"%s\", ", grp->gr_name); + printf("rdev=%ju, ", (uintmax_t)statp->st_rdev); + printf("atime="); + if (resolv == 0) + printf("%jd", (intmax_t)statp->st_atim.tv_sec); + else { + tm = localtime(&statp->st_atim.tv_sec); + strftime(timestr, sizeof(timestr), TIME_FORMAT, tm); + printf("\"%s\"", timestr); + } + if (statp->st_atim.tv_nsec != 0) + printf(".%09ld, ", statp->st_atim.tv_nsec); + else + printf(", "); + printf("stime="); + if (resolv == 0) + printf("%jd", (intmax_t)statp->st_mtim.tv_sec); + else { + tm = localtime(&statp->st_mtim.tv_sec); + strftime(timestr, sizeof(timestr), TIME_FORMAT, tm); + printf("\"%s\"", timestr); + } + if (statp->st_mtim.tv_nsec != 0) + printf(".%09ld, ", statp->st_mtim.tv_nsec); + else + printf(", "); + printf("ctime="); + if (resolv == 0) + printf("%jd", (intmax_t)statp->st_ctim.tv_sec); + else { + tm = localtime(&statp->st_ctim.tv_sec); + strftime(timestr, sizeof(timestr), TIME_FORMAT, tm); + printf("\"%s\"", timestr); + } + if (statp->st_ctim.tv_nsec != 0) + printf(".%09ld, ", statp->st_ctim.tv_nsec); + else + printf(", "); + printf("birthtime="); + if (resolv == 0) + printf("%jd", (intmax_t)statp->st_birthtim.tv_sec); + else { + tm = localtime(&statp->st_birthtim.tv_sec); + strftime(timestr, sizeof(timestr), TIME_FORMAT, tm); + printf("\"%s\"", timestr); + } + if (statp->st_birthtim.tv_nsec != 0) + printf(".%09ld, ", statp->st_birthtim.tv_nsec); + else + printf(", "); + printf("size=%jd, blksize=%ju, blocks=%jd, flags=0x%x", + (uintmax_t)statp->st_size, (uintmax_t)statp->st_blksize, + (intmax_t)statp->st_blocks, statp->st_flags); + printf(" }\n"); +} + +void +ktrstruct(char *buf, size_t buflen) +{ + char *name, *data; + size_t namelen, datalen; + int i; + struct stat sb; + struct sockaddr_storage ss; + + for (name = buf, namelen = 0; + namelen < buflen && name[namelen] != '\0'; + ++namelen) + /* nothing */; + if (namelen == buflen) + goto invalid; + if (name[namelen] != '\0') + goto invalid; + data = buf + namelen + 1; + datalen = buflen - namelen - 1; + if (datalen == 0) + goto invalid; + /* sanity check */ + for (i = 0; i < (int)namelen; ++i) + if (!isalpha(name[i])) + goto invalid; + if (strcmp(name, "stat") == 0) { + if (datalen != sizeof(struct stat)) + goto invalid; + memcpy(&sb, data, datalen); + ktrstat(&sb); + } else if (strcmp(name, "sockaddr") == 0) { + if (datalen > sizeof(ss)) + goto invalid; + memcpy(&ss, data, datalen); + if (datalen < sizeof(struct sockaddr) || + datalen != ss.ss_len) + goto invalid; + ktrsockaddr((struct sockaddr *)&ss); + } else { + printf("unknown structure\n"); + } + return; +invalid: + printf("invalid record\n"); +} + +void +ktrcapfail(struct ktr_cap_fail *ktr) +{ + switch (ktr->cap_type) { + case CAPFAIL_NOTCAPABLE: + /* operation on fd with insufficient capabilities */ + printf("operation requires "); + capname((intmax_t)ktr->cap_needed); + printf(", process holds "); + capname((intmax_t)ktr->cap_held); + break; + case CAPFAIL_INCREASE: + /* requested more capabilities than fd already has */ + printf("attempt to increase capabilities from "); + capname((intmax_t)ktr->cap_held); + printf(" to "); + capname((intmax_t)ktr->cap_needed); + break; + case CAPFAIL_SYSCALL: + /* called restricted syscall */ + printf("disallowed system call"); + break; + case CAPFAIL_LOOKUP: + /* used ".." in strict-relative mode */ + printf("restricted VFS lookup"); + break; + default: + printf("unknown capability failure: "); + capname((intmax_t)ktr->cap_needed); + printf(" "); + capname((intmax_t)ktr->cap_held); + break; + } + printf("\n"); +} + +void +ktrfault(struct ktr_fault *ktr) +{ + + printf("0x%jx ", ktr->vaddr); + vmprotname(ktr->type); + printf("\n"); +} + +void +ktrfaultend(struct ktr_faultend *ktr) +{ + + vmresultname(ktr->result); + printf("\n"); +} + +#if defined(__amd64__) || defined(__i386__) +void +linux_ktrsyscall(struct ktr_syscall *ktr) +{ + int narg = ktr->ktr_narg; + register_t *ip; + + if (ktr->ktr_code >= nlinux_syscalls || ktr->ktr_code < 0) + printf("[%d]", ktr->ktr_code); + else + printf("%s", linux_syscallnames[ktr->ktr_code]); + ip = &ktr->ktr_args[0]; + if (narg) { + char c = '('; + while (narg > 0) + print_number(ip, narg, c); + putchar(')'); + } + putchar('\n'); +} + +void +linux_ktrsysret(struct ktr_sysret *ktr) +{ + register_t ret = ktr->ktr_retval; + int error = ktr->ktr_error; + int code = ktr->ktr_code; + + if (code >= nlinux_syscalls || code < 0) + printf("[%d] ", code); + else + printf("%s ", linux_syscallnames[code]); + + if (error == 0) { + if (fancy) { + printf("%ld", (long)ret); + if (ret < 0 || ret > 9) + printf("/%#lx", (unsigned long)ret); + } else { + if (decimal) + printf("%ld", (long)ret); + else + printf("%#lx", (unsigned long)ret); + } + } else if (error == ERESTART) + printf("RESTART"); + else if (error == EJUSTRETURN) + printf("JUSTRETURN"); + else { + if (ktr->ktr_error <= ELAST + 1) + error = abs(bsd_to_linux_errno[ktr->ktr_error]); + else + error = 999; + printf("-1 errno %d", error); + if (fancy) + printf(" %s", strerror(ktr->ktr_error)); + } + putchar('\n'); +} +#endif + +void +usage(void) +{ + fprintf(stderr, "usage: kdump [-dEnlHRrsTA] [-f trfile] " + "[-m maxdata] [-p pid] [-t trstr]\n"); + exit(1); +} diff --git a/usr.bin/kdump/linux_syscalls.conf b/usr.bin/kdump/linux_syscalls.conf new file mode 100644 index 0000000..82adb56 --- /dev/null +++ b/usr.bin/kdump/linux_syscalls.conf @@ -0,0 +1,11 @@ +# $FreeBSD$ +sysnames="linux_syscalls.c" +sysproto="/dev/null" +sysproto_h=_LINUX_SYSPROTO_H_ +syshdr="/dev/null" +syssw="/dev/null" +sysmk="/dev/null" +syscallprefix="LINUX_SYS_" +switchname="/dev/null" +namesname="linux_syscallnames" +systrace="/dev/null" diff --git a/usr.bin/kdump/mkioctls b/usr.bin/kdump/mkioctls new file mode 100644 index 0000000..eefe14c --- /dev/null +++ b/usr.bin/kdump/mkioctls @@ -0,0 +1,113 @@ +#!/bin/sh +# +# $FreeBSD$ +# +# When editing this script, keep in mind that truss also uses it. +# + +set -e + +if [ $# -ne 2 -o \( $1 != "print" -a $1 != "return" \) ]; then + echo "usage: sh $0 print|return include-dir" + exit 1 +fi + +style="$1" +includedir="$2" + +LC_ALL=C; export LC_ALL + +# Build a list of headers that have ioctls in them. +# XXX should we use an ANSI cpp? +ioctl_includes=$( + cd $includedir + find -H -s * -name '*.h' | grep -v '.*disk.*\.h' | \ + xargs egrep -l \ +'^#[ ]*define[ ]+[A-Za-z_][A-Za-z0-9_]*[ ]+_IO[^a-z0-9_]' | + awk '{printf("#include <%s>\\n", $1)}' +) + +: ${MACHINE=$(uname -m)} +case "${MACHINE}" in +*pc98*) + ioctl_includes="$ioctl_includes#include <sys/diskpc98.h>\\n" + ;; +*) + ioctl_includes="$ioctl_includes#include <sys/diskmbr.h>\\n" + ;; +esac + +awk -v x="$ioctl_includes" 'BEGIN {print x}' | + $CPP -I$1 -dM -DCOMPAT_43TTY - | + awk -v ioctl_includes="$ioctl_includes" -v style="$style" ' +BEGIN { + print "/* XXX obnoxious prerequisites. */" + print "#define COMPAT_43" + print "#define COMPAT_43TTY" + print "#include <sys/param.h>" + print "#include <sys/devicestat.h>" + print "#include <sys/disklabel.h>" + print "#include <sys/socket.h>" + print "#include <sys/time.h>" + print "#include <sys/tty.h>" + print "#include <bsm/audit.h>" + print "#include <net/ethernet.h>" + print "#include <net/if.h>" + print "#include <net/if_var.h>" + print "#include <net/pfvar.h>" + print "#include <net/route.h>" + print "#include <netinet/in.h>" + print "#include <netinet/ip_mroute.h>" + print "#include <netinet6/in6_var.h>" + print "#include <netinet6/nd6.h>" + print "#include <netinet6/ip6_mroute.h>" + print "#include <stdio.h>" + print "#include <cam/cam.h>" + print "" + print ioctl_includes + print "" + if (style == "print") { + print "void ioctlname(unsigned long val, int decimal);" + print "" + print "void" + print "ioctlname(unsigned long val, int decimal)" + } else { + print "const char *ioctlname(unsigned long val);" + print "" + print "const char *" + print "ioctlname(unsigned long val)" + } + print "{" + print "\tconst char *str = NULL;" + print "" +} + +/^#[ ]*define[ ]+[A-Za-z_][A-Za-z0-9_]*[ ]+_IO/ { + + # find where the name starts + for (i = 1; i <= NF; i++) + if ($i ~ /define/) + break; + ++i; + # + printf("\t"); + if (n++ > 0) + printf("else "); + printf("if (val == %s)\n", $i); + printf("\t\tstr = \"%s\";\n", $i); +} +END { + print "" + if (style == "print") { + print "\tif (str != NULL)" + print "\t\tprintf(\"%s\", str);" + print "\telse if (decimal)" + print "\t\tprintf(\"%lu\", val);" + print "\telse" + print "\t\tprintf(\"%#lx\", val);" + } else { + print "\treturn (str);" + } + print "}" +} +' diff --git a/usr.bin/kdump/mksubr b/usr.bin/kdump/mksubr new file mode 100644 index 0000000..bc466d5 --- /dev/null +++ b/usr.bin/kdump/mksubr @@ -0,0 +1,504 @@ +#!/bin/sh +# +# Copyright (c) 2006 "David Kirchner" <dpk@dpk.net>. 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. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +# +# $FreeBSD$ +# +# Generates kdump_subr.c +# mkioctls is a special-purpose script, and works fine as it is +# now, so it remains independent. The idea behind how it generates +# its list was heavily borrowed here. +# +# Some functions here are automatically generated. This can mean +# the user will see unusual kdump output or errors while building +# if the underlying .h files are changed significantly. +# +# Key: +# AUTO: Completely auto-generated with either the "or" or the "switch" +# method. +# AUTO - Special: Generated automatically, but with some extra commands +# that the auto_*_type() functions are inappropriate for. +# MANUAL: Manually entered and must therefore be manually updated. + +set -e + +LC_ALL=C; export LC_ALL + +if [ -z "$1" ] +then + echo "usage: sh $0 include-dir" + exit 1 +fi +include_dir=$1 + +# +# Automatically generates a C function that will print out the +# numeric input as a pipe-delimited string of the appropriate +# #define keys. ex: +# S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH +# The XOR is necessary to prevent including the "0"-value in every +# line. +# +auto_or_type () { + local name grep file + name=$1 + grep=$2 + file=$3 + + cat <<_EOF_ +/* AUTO */ +void +$name(intmax_t arg) +{ + int or = 0; + printf("%#jx<", (uintmax_t)arg); +_EOF_ + egrep "^#[[:space:]]*define[[:space:]]+"${grep}"[[:space:]]*" \ + $include_dir/$file | \ + awk '{ for (i = 1; i <= NF; i++) \ + if ($i ~ /define/) \ + break; \ + ++i; \ + printf "\tif (!((arg > 0) ^ ((%s) > 0)))\n\t\tif_print_or(arg, %s, or);\n", $i, $i }' +cat <<_EOF_ + printf(">"); + if (or == 0) + printf("<invalid>%jd", arg); +} + +_EOF_ +} + +# +# Automatically generates a C function used when the argument +# maps to a single, specific #definition +# +auto_switch_type () { + local name grep file + name=$1 + grep=$2 + file=$3 + + cat <<_EOF_ +/* AUTO */ +void +$name(intmax_t arg) +{ + switch (arg) { +_EOF_ + egrep "^#[[:space:]]*define[[:space:]]+"${grep}"[[:space:]]*" \ + $include_dir/$file | \ + awk '{ for (i = 1; i <= NF; i++) \ + if ($i ~ /define/) \ + break; \ + ++i; \ + printf "\tcase %s:\n\t\tprintf(\"%s\");\n\t\tbreak;\n", $i, $i }' +cat <<_EOF_ + default: /* Should not reach */ + printf("<invalid=%jd>", arg); + } +} + +_EOF_ +} + +# +# Automatically generates a C function used when the argument +# maps to a #definition +# +auto_if_type () { + local name grep file + name=$1 + grep=$2 + file=$3 + + cat <<_EOF_ +/* AUTO */ +void +$name(intmax_t arg) +{ +_EOF_ + egrep "^#[[:space:]]*define[[:space:]]+"${grep}"[[:space:]]*" \ + $include_dir/$file | \ + awk '{ printf "\t"; \ + if (NR > 1) \ + printf "else " ; \ + printf "if (arg == %s) \n\t\tprintf(\"%s\");\n", $2, $2 }' +cat <<_EOF_ + else /* Should not reach */ + printf("<invalid=%jd>", arg); +} + +_EOF_ +} + +# C start + +cat <<_EOF_ +#include <stdint.h> +#include <stdio.h> +#include <sys/fcntl.h> +#include <sys/stat.h> +#include <sys/unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> +#define _KERNEL +#include <sys/socket.h> +#undef _KERNEL +#include <netinet/in.h> +#include <sys/param.h> +#include <sys/mount.h> +#include <sys/ptrace.h> +#include <sys/resource.h> +#include <sys/reboot.h> +#include <sched.h> +#include <sys/linker.h> +#define _KERNEL +#include <sys/thr.h> +#undef _KERNEL +#include <sys/extattr.h> +#include <sys/acl.h> +#include <aio.h> +#include <sys/sem.h> +#include <sys/ipc.h> +#include <sys/rtprio.h> +#include <sys/shm.h> +#include <nfsserver/nfs.h> +#include <ufs/ufs/quota.h> +#include <sys/capability.h> +#include <vm/vm.h> +#include <vm/vm_param.h> + +#include "kdump_subr.h" + +/* + * These are simple support macros. print_or utilizes a variable + * defined in the calling function to track whether or not it should + * print a logical-OR character ('|') before a string. if_print_or + * simply handles the necessary "if" statement used in many lines + * of this file. + */ +#define print_or(str,orflag) do { \\ + if (orflag) putchar('|'); else orflag = 1; \\ + printf (str); } \\ + while (0) +#define if_print_or(i,flag,orflag) do { \\ + if ((i & flag) == flag) \\ + print_or(#flag,orflag); } \\ + while (0) + +/* MANUAL */ +extern char *signames[]; /* from kdump.c */ +void +signame(int sig) +{ + if (sig > 0 && sig < NSIG) + printf("SIG%s",signames[sig]); + else + printf("SIG %d", sig); +} + +/* MANUAL */ +void +semctlname(int cmd) +{ + switch (cmd) { + case GETNCNT: + printf("GETNCNT"); + break; + case GETPID: + printf("GETPID"); + break; + case GETVAL: + printf("GETVAL"); + break; + case GETALL: + printf("GETALL"); + break; + case GETZCNT: + printf("GETZCNT"); + break; + case SETVAL: + printf("SETVAL"); + break; + case SETALL: + printf("SETALL"); + break; + case IPC_RMID: + printf("IPC_RMID"); + break; + case IPC_SET: + printf("IPC_SET"); + break; + case IPC_STAT: + printf("IPC_STAT"); + break; + default: /* Should not reach */ + printf("<invalid=%d>", cmd); + } +} + +/* MANUAL */ +void +shmctlname(int cmd) +{ + switch (cmd) { + case IPC_RMID: + printf("IPC_RMID"); + break; + case IPC_SET: + printf("IPC_SET"); + break; + case IPC_STAT: + printf("IPC_STAT"); + break; + default: /* Should not reach */ + printf("<invalid=%d>", cmd); + } +} + +/* MANUAL */ +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); +} + +/* + * MANUAL + * + * Only used by SYS_open. Unless O_CREAT is set in flags, the + * mode argument is unused (and often bogus and misleading). + */ +void +flagsandmodename(int flags, int mode, int decimal) +{ + flagsname(flags); + putchar(','); + if ((flags & O_CREAT) == O_CREAT) { + modename (mode); + } else { + if (decimal) { + printf("<unused>%d", mode); + } else { + printf("<unused>%#x", (unsigned int)mode); + } + } +} + +/* + * MANUAL + * + * [g|s]etsockopt's level argument can either be SOL_SOCKET or a value + * referring to a line in /etc/protocols . It might be appropriate + * to use getprotoent(3) here. + */ +void +sockoptlevelname(int level, int decimal) +{ + if (level == SOL_SOCKET) { + printf("SOL_SOCKET"); + } else { + if (decimal) { + printf("%d", level); + } else { + printf("%#x", (unsigned int)level); + } + } +} + +/* + * MANUAL + * + * Used for page fault type. Cannot use auto_or_type since the macro + * values contain a cast. Also, VM_PROT_NONE has to be handled specially. + */ +void +vmprotname (int type) +{ + int or = 0; + + if (type == VM_PROT_NONE) { + (void)printf("VM_PROT_NONE"); + return; + } + if_print_or(type, VM_PROT_READ, or); + if_print_or(type, VM_PROT_WRITE, or); + if_print_or(type, VM_PROT_EXECUTE, or); + if_print_or(type, VM_PROT_COPY, or); +} +_EOF_ + +auto_or_type "accessmodename" "[A-Z]_OK[[:space:]]+0?x?[0-9A-Fa-f]+" "sys/unistd.h" +auto_switch_type "acltypename" "ACL_TYPE_[A-Z4_]+[[:space:]]+0x[0-9]+" "sys/acl.h" +auto_or_type "capname" "CAP_[A-Z]+[[:space:]]+0x[01248]{16}ULL" "sys/capability.h" +auto_switch_type "extattrctlname" "EXTATTR_NAMESPACE_[A-Z]+[[:space:]]+0x[0-9]+" "sys/extattr.h" +auto_switch_type "fadvisebehavname" "POSIX_FADV_[A-Z]+[[:space:]]+[0-9]+" "sys/fcntl.h" +auto_or_type "flagsname" "O_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/fcntl.h" +auto_or_type "flockname" "LOCK_[A-Z]+[[:space:]]+0x[0-9]+" "sys/fcntl.h" +auto_or_type "getfsstatflagsname" "MNT_[A-Z]+[[:space:]]+[1-9][0-9]*" "sys/mount.h" +auto_switch_type "kldsymcmdname" "KLDSYM_[A-Z]+[[:space:]]+[0-9]+" "sys/linker.h" +auto_switch_type "kldunloadfflagsname" "LINKER_UNLOAD_[A-Z]+[[:space:]]+[0-9]+" "sys/linker.h" +auto_switch_type "lio_listioname" "LIO_(NO)?WAIT[[:space:]]+[0-9]+" "aio.h" +auto_switch_type "madvisebehavname" "_?MADV_[A-Z]+[[:space:]]+[0-9]+" "sys/mman.h" +auto_switch_type "minheritname" "INHERIT_[A-Z]+[[:space:]]+[0-9]+" "sys/mman.h" +auto_or_type "mlockallname" "MCL_[A-Z]+[[:space:]]+0x[0-9]+" "sys/mman.h" +auto_or_type "mmapflagsname" "MAP_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/mman.h" +auto_or_type "mmapprotname" "PROT_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/mman.h" +auto_or_type "modename" "S_[A-Z]+[[:space:]]+[0-6]{7}" "sys/stat.h" +auto_or_type "mountflagsname" "MNT_[A-Z]+[[:space:]]+0x[0-9]+" "sys/mount.h" +auto_switch_type "msyncflagsname" "MS_[A-Z]+[[:space:]]+0x[0-9]+" "sys/mman.h" +auto_or_type "nfssvcname" "NFSSVC_[A-Z]+[[:space:]]+0x[0-9]+" "nfsserver/nfs.h" +auto_switch_type "prioname" "PRIO_[A-Z]+[[:space:]]+[0-9]" "sys/resource.h" +auto_switch_type "ptraceopname" "PT_[[:alnum:]_]+[[:space:]]+[0-9]+" "sys/ptrace.h" +auto_switch_type "quotactlname" "Q_[A-Z]+[[:space:]]+0x[0-9]+" "ufs/ufs/quota.h" +auto_or_type "rebootoptname" "RB_[A-Z]+[[:space:]]+0x[0-9]+" "sys/reboot.h" +auto_or_type "rforkname" "RF[A-Z]+[[:space:]]+\([0-9]+<<[0-9]+\)" "sys/unistd.h" +auto_switch_type "rlimitname" "RLIMIT_[A-Z]+[[:space:]]+[0-9]+" "sys/resource.h" +auto_switch_type "schedpolicyname" "SCHED_[A-Z]+[[:space:]]+[0-9]+" "sched.h" +auto_switch_type "sendfileflagsname" "SF_[A-Z]+[[:space:]]+[0-9]+" "sys/socket.h" +auto_or_type "shmatname" "SHM_[A-Z]+[[:space:]]+[0-9]{6}+" "sys/shm.h" +auto_switch_type "shutdownhowname" "SHUT_[A-Z]+[[:space:]]+[0-9]+" "sys/socket.h" +auto_switch_type "sigprocmaskhowname" "SIG_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" +auto_if_type "sockdomainname" "PF_[[:alnum:]]+[[:space:]]+" "sys/socket.h" +auto_if_type "sockfamilyname" "AF_[[:alnum:]]+[[:space:]]+" "sys/socket.h" +auto_if_type "sockipprotoname" "IPPROTO_[[:alnum:]]+[[:space:]]+" "netinet/in.h" +auto_switch_type "sockoptname" "SO_[A-Z]+[[:space:]]+0x[0-9]+" "sys/socket.h" +auto_switch_type "socktypename" "SOCK_[A-Z]+[[:space:]]+[1-9]+[0-9]*" "sys/socket.h" +auto_or_type "thrcreateflagsname" "THR_[A-Z]+[[:space:]]+0x[0-9]+" "sys/thr.h" +auto_switch_type "vmresultname" "KERN_[A-Z]+[[:space:]]+[0-9]+" "vm/vm_param.h" +auto_or_type "wait4optname" "W[A-Z]+[[:space:]]+[0-9]+" "sys/wait.h" +auto_switch_type "whencename" "SEEK_[A-Z]+[[:space:]]+[0-9]+" "sys/unistd.h" + +cat <<_EOF_ +/* + * AUTO - Special + * F_ is used to specify fcntl commands as well as arguments. Both sets are + * grouped in fcntl.h, and this awk script grabs the first group. + */ +void +fcntlcmdname(int cmd, int arg, int decimal) +{ + switch (cmd) { +_EOF_ +egrep "^#[[:space:]]*define[[:space:]]+F_[A-Z]+[[:space:]]+[0-9]+[[:space:]]*" \ + $include_dir/sys/fcntl.h | \ + awk 'BEGIN { o=0 } { for (i = 1; i <= NF; i++) \ + if ($i ~ /define/) \ + break; \ + ++i; \ + if (o <= $(i+1)) \ + printf "\tcase %s:\n\t\tprintf(\"%s\");\n\t\tbreak;\n", $i, $i; \ + else \ + exit; \ + o = $(i+1) }' +cat <<_EOF_ + default: /* Should not reach */ + printf("<invalid=%d>", cmd); + } + putchar(','); + if (cmd == F_GETFD || cmd == F_SETFD) { + if (arg == FD_CLOEXEC) + printf("FD_CLOEXEC"); + else if (arg == 0) + printf("0"); + else { + if (decimal) + printf("<invalid>%d", arg); + else + printf("<invalid>%#x", (unsigned int)arg); + } + } else if (cmd == F_SETFL) { + flagsname(arg); + } else { + if (decimal) + printf("%d", arg); + else + printf("%#x", (unsigned int)arg); + } +} + +/* + * AUTO - Special + * + * The only reason this is not fully automated is due to the + * grep -v RTP_PRIO statement. A better egrep line should + * make this capable of being a auto_switch_type() function. + */ +void +rtprioname(int func) +{ + switch (func) { +_EOF_ +egrep "^#[[:space:]]*define[[:space:]]+RTP_[A-Z]+[[:space:]]+0x[0-9]+[[:space:]]*" \ + $include_dir/sys/rtprio.h | grep -v RTP_PRIO | \ + awk '{ for (i = 1; i <= NF; i++) \ + if ($i ~ /define/) \ + break; \ + ++i; \ + printf "\tcase %s:\n\t\tprintf(\"%s\");\n\t\tbreak;\n", $i, $i }' +cat <<_EOF_ + default: /* Should not reach */ + printf("<invalid=%d>", func); + } +} + +/* + * AUTO - Special + * + * The send and recv functions have a flags argument which can be + * set to 0. There is no corresponding #define. The auto_ functions + * detect this as "invalid", which is incorrect here. + */ +void +sendrecvflagsname(int flags) +{ + int or = 0; + + if (flags == 0) { + printf("0"); + return; + } + + printf("%#x<", flags); +_EOF_ +egrep "^#[[:space:]]*define[[:space:]]+MSG_[A-Z]+[[:space:]]+0x[0-9]+[[:space:]]*" $include_dir/sys/socket.h | \ + awk '{ for (i = 1; i <= NF; i++) \ + if ($i ~ /define/) \ + break; \ + ++i; \ + printf "\tif(!((flags>0)^((%s)>0)))\n\t\tif_print_or(flags, %s, or);\n", $i, $i }' +cat <<_EOF_ + printf(">"); +} + +_EOF_ |