1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-20 11:11:24 +00:00
freebsd/usr.bin/kdump/kdump.c
John Baldwin 35818d2e94 Add new ktrace records for the start and end of VM faults. This gives
a pair of records similar to syscall entry and return that a user can
use to determine how long page faults take.  The new ktrace records are
enabled via the 'p' trace type, and are enabled in the default set of
trace points.

Reviewed by:	kib
MFC after:	2 weeks
2012-04-05 17:13:14 +00:00

1737 lines
37 KiB
C

/*-
* 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);
}