kdump.c revision 99112
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1988, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
341590Srgrimes#ifndef lint
3527443Scharnierstatic const char copyright[] =
361590Srgrimes"@(#) Copyright (c) 1988, 1993\n\
371590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
381590Srgrimes#endif /* not lint */
391590Srgrimes
401590Srgrimes#ifndef lint
4127443Scharnier#if 0
421590Srgrimesstatic char sccsid[] = "@(#)kdump.c	8.1 (Berkeley) 6/6/93";
4327443Scharnier#endif
441590Srgrimes#endif /* not lint */
4599112Sobrien#include <sys/cdefs.h>
4699112Sobrien__FBSDID("$FreeBSD: head/usr.bin/kdump/kdump.c 99112 2002-06-30 05:25:07Z obrien $");
471590Srgrimes
4855206Speter#define _KERNEL
492215Scsgrextern int errno;
502215Scsgr#include <sys/errno.h>
5155206Speter#undef _KERNEL
521590Srgrimes#include <sys/param.h>
531590Srgrimes#include <sys/errno.h>
541590Srgrimes#include <sys/time.h>
551590Srgrimes#include <sys/uio.h>
561590Srgrimes#include <sys/ktrace.h>
571590Srgrimes#include <sys/ioctl.h>
581590Srgrimes#include <sys/ptrace.h>
5927443Scharnier#include <err.h>
6027443Scharnier#include <locale.h>
611590Srgrimes#include <stdio.h>
621590Srgrimes#include <stdlib.h>
631590Srgrimes#include <string.h>
6427443Scharnier#include <unistd.h>
6527443Scharnier#include <vis.h>
661590Srgrimes#include "ktrace.h"
671590Srgrimes
681590Srgrimesint timestamp, decimal, fancy = 1, tail, maxdata;
691590Srgrimeschar *tracefile = DEF_TRACEFILE;
701590Srgrimesstruct ktr_header ktr_header;
711590Srgrimes
721590Srgrimes#define eqs(s1, s2)	(strcmp((s1), (s2)) == 0)
731590Srgrimes
741590Srgrimesmain(argc, argv)
751590Srgrimes	int argc;
761590Srgrimes	char *argv[];
771590Srgrimes{
781590Srgrimes	int ch, ktrlen, size;
791590Srgrimes	register void *m;
801590Srgrimes	int trpoints = ALL_POINTS;
811590Srgrimes
8211823Sache	(void) setlocale(LC_CTYPE, "");
8311823Sache
8424360Simp	while ((ch = getopt(argc,argv,"f:dlm:nRTt:")) != -1)
851590Srgrimes		switch((char)ch) {
861590Srgrimes		case 'f':
871590Srgrimes			tracefile = optarg;
881590Srgrimes			break;
891590Srgrimes		case 'd':
901590Srgrimes			decimal = 1;
911590Srgrimes			break;
921590Srgrimes		case 'l':
931590Srgrimes			tail = 1;
941590Srgrimes			break;
951590Srgrimes		case 'm':
961590Srgrimes			maxdata = atoi(optarg);
971590Srgrimes			break;
981590Srgrimes		case 'n':
991590Srgrimes			fancy = 0;
1001590Srgrimes			break;
1011590Srgrimes		case 'R':
1021590Srgrimes			timestamp = 2;	/* relative timestamp */
1031590Srgrimes			break;
1041590Srgrimes		case 'T':
1051590Srgrimes			timestamp = 1;
1061590Srgrimes			break;
1071590Srgrimes		case 't':
1081590Srgrimes			trpoints = getpoints(optarg);
10927443Scharnier			if (trpoints < 0)
11027443Scharnier				errx(1, "unknown trace point in %s", optarg);
1111590Srgrimes			break;
1121590Srgrimes		default:
1131590Srgrimes			usage();
1141590Srgrimes		}
1151590Srgrimes
11619853Sfenner	if (argc > optind)
1171590Srgrimes		usage();
1181590Srgrimes
1191590Srgrimes	m = (void *)malloc(size = 1025);
12027443Scharnier	if (m == NULL)
12127443Scharnier		errx(1, "%s", strerror(ENOMEM));
12227443Scharnier	if (!freopen(tracefile, "r", stdin))
12327443Scharnier		err(1, "%s", tracefile);
1241590Srgrimes	while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) {
1251590Srgrimes		if (trpoints & (1<<ktr_header.ktr_type))
1261590Srgrimes			dumpheader(&ktr_header);
12727443Scharnier		if ((ktrlen = ktr_header.ktr_len) < 0)
12827443Scharnier			errx(1, "bogus length 0x%x", ktrlen);
1291590Srgrimes		if (ktrlen > size) {
1301590Srgrimes			m = (void *)realloc(m, ktrlen+1);
13127443Scharnier			if (m == NULL)
13227443Scharnier				errx(1, "%s", strerror(ENOMEM));
1331590Srgrimes			size = ktrlen;
1341590Srgrimes		}
13527443Scharnier		if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
13627443Scharnier			errx(1, "data too short");
1371590Srgrimes		if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
1381590Srgrimes			continue;
1391590Srgrimes		switch (ktr_header.ktr_type) {
1401590Srgrimes		case KTR_SYSCALL:
1411590Srgrimes			ktrsyscall((struct ktr_syscall *)m);
1421590Srgrimes			break;
1431590Srgrimes		case KTR_SYSRET:
1441590Srgrimes			ktrsysret((struct ktr_sysret *)m);
1451590Srgrimes			break;
1461590Srgrimes		case KTR_NAMEI:
1471590Srgrimes			ktrnamei(m, ktrlen);
1481590Srgrimes			break;
1491590Srgrimes		case KTR_GENIO:
1501590Srgrimes			ktrgenio((struct ktr_genio *)m, ktrlen);
1511590Srgrimes			break;
1521590Srgrimes		case KTR_PSIG:
1531590Srgrimes			ktrpsig((struct ktr_psig *)m);
1541590Srgrimes			break;
1551590Srgrimes		case KTR_CSW:
1561590Srgrimes			ktrcsw((struct ktr_csw *)m);
1571590Srgrimes			break;
15818400Sphk		case KTR_USER:
15918470Sphk			ktruser(ktrlen, m);
16018400Sphk			break;
1611590Srgrimes		}
1621590Srgrimes		if (tail)
1631590Srgrimes			(void)fflush(stdout);
1641590Srgrimes	}
1651590Srgrimes}
1661590Srgrimes
1671590Srgrimesfread_tail(buf, size, num)
1681590Srgrimes	char *buf;
1691590Srgrimes	int num, size;
1701590Srgrimes{
1711590Srgrimes	int i;
1721590Srgrimes
1731590Srgrimes	while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
1741590Srgrimes		(void)sleep(1);
1751590Srgrimes		clearerr(stdin);
1761590Srgrimes	}
1771590Srgrimes	return (i);
1781590Srgrimes}
1791590Srgrimes
1801590Srgrimesdumpheader(kth)
1811590Srgrimes	struct ktr_header *kth;
1821590Srgrimes{
1831590Srgrimes	static char unknown[64];
1841590Srgrimes	static struct timeval prevtime, temp;
1851590Srgrimes	char *type;
1861590Srgrimes
1871590Srgrimes	switch (kth->ktr_type) {
1881590Srgrimes	case KTR_SYSCALL:
1891590Srgrimes		type = "CALL";
1901590Srgrimes		break;
1911590Srgrimes	case KTR_SYSRET:
1921590Srgrimes		type = "RET ";
1931590Srgrimes		break;
1941590Srgrimes	case KTR_NAMEI:
1951590Srgrimes		type = "NAMI";
1961590Srgrimes		break;
1971590Srgrimes	case KTR_GENIO:
1981590Srgrimes		type = "GIO ";
1991590Srgrimes		break;
2001590Srgrimes	case KTR_PSIG:
2011590Srgrimes		type = "PSIG";
2021590Srgrimes		break;
2031590Srgrimes	case KTR_CSW:
2041590Srgrimes		type = "CSW";
2051590Srgrimes		break;
20618400Sphk	case KTR_USER:
20718400Sphk		type = "USER";
20818400Sphk		break;
2091590Srgrimes	default:
2101590Srgrimes		(void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type);
2111590Srgrimes		type = unknown;
2121590Srgrimes	}
2131590Srgrimes
21447349Sjmz	(void)printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN, kth->ktr_comm);
2151590Srgrimes	if (timestamp) {
2161590Srgrimes		if (timestamp == 2) {
2171590Srgrimes			temp = kth->ktr_time;
2181590Srgrimes			timevalsub(&kth->ktr_time, &prevtime);
2191590Srgrimes			prevtime = temp;
2201590Srgrimes		}
2211590Srgrimes		(void)printf("%ld.%06ld ",
2221590Srgrimes		    kth->ktr_time.tv_sec, kth->ktr_time.tv_usec);
2231590Srgrimes	}
2241590Srgrimes	(void)printf("%s  ", type);
2251590Srgrimes}
2261590Srgrimes
2271590Srgrimes#include <sys/syscall.h>
2281590Srgrimes#define KTRACE
2294721Sphk#include <sys/kern/syscalls.c>
2301590Srgrimes#undef KTRACE
2311590Srgrimesint nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]);
2321590Srgrimes
2331590Srgrimesstatic char *ptrace_ops[] = {
2341590Srgrimes	"PT_TRACE_ME",	"PT_READ_I",	"PT_READ_D",	"PT_READ_U",
2351590Srgrimes	"PT_WRITE_I",	"PT_WRITE_D",	"PT_WRITE_U",	"PT_CONTINUE",
23648234Sbde	"PT_KILL",	"PT_STEP",	"PT_ATTACH",	"PT_DETACH",
2371590Srgrimes};
2381590Srgrimes
2391590Srgrimesktrsyscall(ktr)
2401590Srgrimes	register struct ktr_syscall *ktr;
2411590Srgrimes{
2421590Srgrimes	register narg = ktr->ktr_narg;
24347957Sdt	register register_t *ip;
2441590Srgrimes	char *ioctlname();
2451590Srgrimes
2461590Srgrimes	if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0)
2471590Srgrimes		(void)printf("[%d]", ktr->ktr_code);
2481590Srgrimes	else
2491590Srgrimes		(void)printf("%s", syscallnames[ktr->ktr_code]);
25047957Sdt	ip = &ktr->ktr_args[0];
2511590Srgrimes	if (narg) {
2521590Srgrimes		char c = '(';
2531590Srgrimes		if (fancy) {
2541590Srgrimes			if (ktr->ktr_code == SYS_ioctl) {
2551590Srgrimes				char *cp;
2561590Srgrimes				if (decimal)
25747957Sdt					(void)printf("(%ld", (long)*ip);
2581590Srgrimes				else
25947957Sdt					(void)printf("(%#lx", (long)*ip);
2601590Srgrimes				ip++;
2611590Srgrimes				narg--;
2621590Srgrimes				if ((cp = ioctlname(*ip)) != NULL)
2631590Srgrimes					(void)printf(",%s", cp);
2641590Srgrimes				else {
2651590Srgrimes					if (decimal)
26647957Sdt						(void)printf(",%ld", (long)*ip);
2671590Srgrimes					else
26847957Sdt						(void)printf(",%#lx ", (long)*ip);
2691590Srgrimes				}
2701590Srgrimes				c = ',';
2711590Srgrimes				ip++;
2721590Srgrimes				narg--;
2731590Srgrimes			} else if (ktr->ktr_code == SYS_ptrace) {
27448234Sbde				if (*ip < sizeof(ptrace_ops) /
27548234Sbde				    sizeof(ptrace_ops[0]) && *ip >= 0)
2761590Srgrimes					(void)printf("(%s", ptrace_ops[*ip]);
27748234Sbde#ifdef PT_GETREGS
27848234Sbde				else if (*ip == PT_GETREGS)
27948234Sbde					(void)printf("(%s", "PT_GETREGS");
28048234Sbde#endif
28148234Sbde#ifdef PT_SETREGS
28248234Sbde				else if (*ip == PT_SETREGS)
28348234Sbde					(void)printf("(%s", "PT_SETREGS");
28448234Sbde#endif
28548234Sbde#ifdef PT_GETFPREGS
28648234Sbde				else if (*ip == PT_GETFPREGS)
28748234Sbde					(void)printf("(%s", "PT_GETFPREGS");
28848234Sbde#endif
28948234Sbde#ifdef PT_SETFPREGS
29048234Sbde				else if (*ip == PT_SETFPREGS)
29148234Sbde					(void)printf("(%s", "PT_SETFPREGS");
29248234Sbde#endif
29348852Sbde#ifdef PT_GETDBREGS
29448852Sbde				else if (*ip == PT_GETDBREGS)
29548852Sbde					(void)printf("(%s", "PT_GETDBREGS");
29648852Sbde#endif
29748852Sbde#ifdef PT_SETDBREGS
29848852Sbde				else if (*ip == PT_SETDBREGS)
29948852Sbde					(void)printf("(%s", "PT_SETDBREGS");
30048852Sbde#endif
3011590Srgrimes				else
30247957Sdt					(void)printf("(%ld", (long)*ip);
3031590Srgrimes				c = ',';
3041590Srgrimes				ip++;
3051590Srgrimes				narg--;
3061590Srgrimes			}
3071590Srgrimes		}
3081590Srgrimes		while (narg) {
3091590Srgrimes			if (decimal)
31047957Sdt				(void)printf("%c%ld", c, (long)*ip);
3111590Srgrimes			else
31247957Sdt				(void)printf("%c%#lx", c, (long)*ip);
3131590Srgrimes			c = ',';
3141590Srgrimes			ip++;
3151590Srgrimes			narg--;
3161590Srgrimes		}
3171590Srgrimes		(void)putchar(')');
3181590Srgrimes	}
3191590Srgrimes	(void)putchar('\n');
3201590Srgrimes}
3211590Srgrimes
3221590Srgrimesktrsysret(ktr)
3231590Srgrimes	struct ktr_sysret *ktr;
3241590Srgrimes{
32547957Sdt	register register_t ret = ktr->ktr_retval;
3261590Srgrimes	register int error = ktr->ktr_error;
3271590Srgrimes	register int code = ktr->ktr_code;
3281590Srgrimes
3291590Srgrimes	if (code >= nsyscalls || code < 0)
3301590Srgrimes		(void)printf("[%d] ", code);
3311590Srgrimes	else
3321590Srgrimes		(void)printf("%s ", syscallnames[code]);
3331590Srgrimes
3341590Srgrimes	if (error == 0) {
3351590Srgrimes		if (fancy) {
3361590Srgrimes			(void)printf("%d", ret);
3371590Srgrimes			if (ret < 0 || ret > 9)
33847957Sdt				(void)printf("/%#lx", (long)ret);
3391590Srgrimes		} else {
3401590Srgrimes			if (decimal)
34147957Sdt				(void)printf("%ld", (long)ret);
3421590Srgrimes			else
34347957Sdt				(void)printf("%#lx", (long)ret);
3441590Srgrimes		}
3451590Srgrimes	} else if (error == ERESTART)
3461590Srgrimes		(void)printf("RESTART");
3471590Srgrimes	else if (error == EJUSTRETURN)
3481590Srgrimes		(void)printf("JUSTRETURN");
3491590Srgrimes	else {
3501590Srgrimes		(void)printf("-1 errno %d", ktr->ktr_error);
3511590Srgrimes		if (fancy)
3521590Srgrimes			(void)printf(" %s", strerror(ktr->ktr_error));
3531590Srgrimes	}
3541590Srgrimes	(void)putchar('\n');
3551590Srgrimes}
3561590Srgrimes
3578874Srgrimesktrnamei(cp, len)
3581590Srgrimes	char *cp;
3591590Srgrimes{
3601590Srgrimes	(void)printf("\"%.*s\"\n", len, cp);
3611590Srgrimes}
3621590Srgrimes
3631590Srgrimesktrgenio(ktr, len)
3641590Srgrimes	struct ktr_genio *ktr;
3651590Srgrimes{
3661590Srgrimes	register int datalen = len - sizeof (struct ktr_genio);
3671590Srgrimes	register char *dp = (char *)ktr + sizeof (struct ktr_genio);
3681590Srgrimes	register char *cp;
3691590Srgrimes	register int col = 0;
3701590Srgrimes	register width;
3711590Srgrimes	char visbuf[5];
3721590Srgrimes	static screenwidth = 0;
3731590Srgrimes
3741590Srgrimes	if (screenwidth == 0) {
3751590Srgrimes		struct winsize ws;
3761590Srgrimes
3771590Srgrimes		if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
3781590Srgrimes		    ws.ws_col > 8)
3791590Srgrimes			screenwidth = ws.ws_col;
3801590Srgrimes		else
3811590Srgrimes			screenwidth = 80;
3821590Srgrimes	}
38325995Scharnier	printf("fd %d %s %d byte%s\n", ktr->ktr_fd,
38425995Scharnier		ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen,
38525995Scharnier		datalen == 1 ? "" : "s");
3861590Srgrimes	if (maxdata && datalen > maxdata)
3871590Srgrimes		datalen = maxdata;
3881590Srgrimes	(void)printf("       \"");
3891590Srgrimes	col = 8;
3901590Srgrimes	for (;datalen > 0; datalen--, dp++) {
3911590Srgrimes		(void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
3921590Srgrimes		cp = visbuf;
3931590Srgrimes		/*
3941590Srgrimes		 * Keep track of printables and
3951590Srgrimes		 * space chars (like fold(1)).
3961590Srgrimes		 */
3971590Srgrimes		if (col == 0) {
3981590Srgrimes			(void)putchar('\t');
3991590Srgrimes			col = 8;
4001590Srgrimes		}
4011590Srgrimes		switch(*cp) {
4021590Srgrimes		case '\n':
4031590Srgrimes			col = 0;
4041590Srgrimes			(void)putchar('\n');
4051590Srgrimes			continue;
4061590Srgrimes		case '\t':
4071590Srgrimes			width = 8 - (col&07);
4081590Srgrimes			break;
4091590Srgrimes		default:
4101590Srgrimes			width = strlen(cp);
4111590Srgrimes		}
4121590Srgrimes		if (col + width > (screenwidth-2)) {
4131590Srgrimes			(void)printf("\\\n\t");
4141590Srgrimes			col = 8;
4151590Srgrimes		}
4161590Srgrimes		col += width;
4171590Srgrimes		do {
4181590Srgrimes			(void)putchar(*cp++);
4191590Srgrimes		} while (*cp);
4201590Srgrimes	}
4211590Srgrimes	if (col == 0)
4221590Srgrimes		(void)printf("       ");
4231590Srgrimes	(void)printf("\"\n");
4241590Srgrimes}
4251590Srgrimes
4261590Srgrimeschar *signames[] = {
4271590Srgrimes	"NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT",	/*  1 - 6  */
4281590Srgrimes	"EMT", "FPE", "KILL", "BUS", "SEGV", "SYS",		/*  7 - 12 */
4291590Srgrimes	"PIPE", "ALRM",  "TERM", "URG", "STOP", "TSTP",		/* 13 - 18 */
4301590Srgrimes	"CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU",		/* 19 - 24 */
4311590Srgrimes	"XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1",	/* 25 - 30 */
4321590Srgrimes	"USR2", NULL,						/* 31 - 32 */
4331590Srgrimes};
4341590Srgrimes
4351590Srgrimesktrpsig(psig)
4361590Srgrimes	struct ktr_psig *psig;
4371590Srgrimes{
4381590Srgrimes	(void)printf("SIG%s ", signames[psig->signo]);
4391590Srgrimes	if (psig->action == SIG_DFL)
4401590Srgrimes		(void)printf("SIG_DFL\n");
4411590Srgrimes	else
44247957Sdt		(void)printf("caught handler=0x%lx mask=0x%x code=0x%x\n",
44347957Sdt		    (u_long)psig->action, psig->mask, psig->code);
4441590Srgrimes}
4451590Srgrimes
4461590Srgrimesktrcsw(cs)
4471590Srgrimes	struct ktr_csw *cs;
4481590Srgrimes{
4491590Srgrimes	(void)printf("%s %s\n", cs->out ? "stop" : "resume",
4501590Srgrimes		cs->user ? "user" : "kernel");
4511590Srgrimes}
4521590Srgrimes
45318470Sphkktruser(len, p)
45418470Sphk	int len;
45518470Sphk	unsigned char *p;
45618400Sphk{
45718470Sphk	(void)printf("%d ", len);
45818470Sphk	while (len--)
45918400Sphk		(void)printf(" %02x", *p++);
46018400Sphk	(void)printf("\n");
46118400Sphk
46218400Sphk}
46318400Sphk
4641590Srgrimesusage()
4651590Srgrimes{
4661590Srgrimes	(void)fprintf(stderr,
46718400Sphk	    "usage: kdump [-dnlRT] [-f trfile] [-m maxdata] [-t [cnisuw]]\n");
4681590Srgrimes	exit(1);
4691590Srgrimes}
470