kdump.c revision 48852
1169689Skan/*-
2169689Skan * Copyright (c) 1988, 1993
3169689Skan *	The Regents of the University of California.  All rights reserved.
4169689Skan *
5169689Skan * Redistribution and use in source and binary forms, with or without
6169689Skan * modification, are permitted provided that the following conditions
7169689Skan * are met:
8169689Skan * 1. Redistributions of source code must retain the above copyright
9169689Skan *    notice, this list of conditions and the following disclaimer.
10169689Skan * 2. Redistributions in binary form must reproduce the above copyright
11169689Skan *    notice, this list of conditions and the following disclaimer in the
12169689Skan *    documentation and/or other materials provided with the distribution.
13169689Skan * 3. All advertising materials mentioning features or use of this software
14169689Skan *    must display the following acknowledgement:
15169689Skan *	This product includes software developed by the University of
16169689Skan *	California, Berkeley and its contributors.
17169689Skan * 4. Neither the name of the University nor the names of its contributors
18169689Skan *    may be used to endorse or promote products derived from this software
19169689Skan *    without specific prior written permission.
20169689Skan *
21169689Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22169689Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23169689Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24169689Skan * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28169689Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31169689Skan * SUCH DAMAGE.
32169689Skan */
33169689Skan
34169689Skan#ifndef lint
35169689Skanstatic const char copyright[] =
36169689Skan"@(#) Copyright (c) 1988, 1993\n\
37169689Skan	The Regents of the University of California.  All rights reserved.\n";
38169689Skan#endif /* not lint */
39169689Skan
40169689Skan#ifndef lint
41169689Skan#if 0
42169689Skanstatic char sccsid[] = "@(#)kdump.c	8.1 (Berkeley) 6/6/93";
43169689Skan#endif
44169689Skanstatic const char rcsid[] =
45169689Skan	"$Id: kdump.c,v 1.14 1999/06/26 07:31:13 bde Exp $";
46169689Skan#endif /* not lint */
47169689Skan
48169689Skan#define KERNEL
49169689Skanextern int errno;
50169689Skan#include <sys/errno.h>
51169689Skan#undef KERNEL
52169689Skan#include <sys/param.h>
53169689Skan#include <sys/errno.h>
54169689Skan#include <sys/time.h>
55169689Skan#include <sys/uio.h>
56169689Skan#include <sys/ktrace.h>
57169689Skan#include <sys/ioctl.h>
58169689Skan#include <sys/ptrace.h>
59169689Skan#include <err.h>
60169689Skan#include <locale.h>
61169689Skan#include <stdio.h>
62169689Skan#include <stdlib.h>
63169689Skan#include <string.h>
64169689Skan#include <unistd.h>
65169689Skan#include <vis.h>
66169689Skan#include "ktrace.h"
67169689Skan
68169689Skanint timestamp, decimal, fancy = 1, tail, maxdata;
69169689Skanchar *tracefile = DEF_TRACEFILE;
70169689Skanstruct ktr_header ktr_header;
71169689Skan
72169689Skan#define eqs(s1, s2)	(strcmp((s1), (s2)) == 0)
73169689Skan
74169689Skanmain(argc, argv)
75169689Skan	int argc;
76169689Skan	char *argv[];
77169689Skan{
78169689Skan	int ch, ktrlen, size;
79169689Skan	register void *m;
80169689Skan	int trpoints = ALL_POINTS;
81169689Skan
82169689Skan	(void) setlocale(LC_CTYPE, "");
83169689Skan
84169689Skan	while ((ch = getopt(argc,argv,"f:dlm:nRTt:")) != -1)
85169689Skan		switch((char)ch) {
86169689Skan		case 'f':
87169689Skan			tracefile = optarg;
88169689Skan			break;
89169689Skan		case 'd':
90169689Skan			decimal = 1;
91169689Skan			break;
92169689Skan		case 'l':
93169689Skan			tail = 1;
94169689Skan			break;
95169689Skan		case 'm':
96169689Skan			maxdata = atoi(optarg);
97169689Skan			break;
98169689Skan		case 'n':
99169689Skan			fancy = 0;
100169689Skan			break;
101169689Skan		case 'R':
102169689Skan			timestamp = 2;	/* relative timestamp */
103169689Skan			break;
104169689Skan		case 'T':
105169689Skan			timestamp = 1;
106169689Skan			break;
107169689Skan		case 't':
108169689Skan			trpoints = getpoints(optarg);
109169689Skan			if (trpoints < 0)
110169689Skan				errx(1, "unknown trace point in %s", optarg);
111169689Skan			break;
112169689Skan		default:
113169689Skan			usage();
114169689Skan		}
115169689Skan
116169689Skan	if (argc > optind)
117169689Skan		usage();
118169689Skan
119169689Skan	m = (void *)malloc(size = 1025);
120169689Skan	if (m == NULL)
121169689Skan		errx(1, "%s", strerror(ENOMEM));
122169689Skan	if (!freopen(tracefile, "r", stdin))
123169689Skan		err(1, "%s", tracefile);
124169689Skan	while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) {
125169689Skan		if (trpoints & (1<<ktr_header.ktr_type))
126169689Skan			dumpheader(&ktr_header);
127169689Skan		if ((ktrlen = ktr_header.ktr_len) < 0)
128169689Skan			errx(1, "bogus length 0x%x", ktrlen);
129169689Skan		if (ktrlen > size) {
130169689Skan			m = (void *)realloc(m, ktrlen+1);
131169689Skan			if (m == NULL)
132169689Skan				errx(1, "%s", strerror(ENOMEM));
133169689Skan			size = ktrlen;
134169689Skan		}
135169689Skan		if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
136169689Skan			errx(1, "data too short");
137169689Skan		if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
138169689Skan			continue;
139169689Skan		switch (ktr_header.ktr_type) {
140169689Skan		case KTR_SYSCALL:
141169689Skan			ktrsyscall((struct ktr_syscall *)m);
142169689Skan			break;
143169689Skan		case KTR_SYSRET:
144169689Skan			ktrsysret((struct ktr_sysret *)m);
145169689Skan			break;
146169689Skan		case KTR_NAMEI:
147169689Skan			ktrnamei(m, ktrlen);
148169689Skan			break;
149169689Skan		case KTR_GENIO:
150169689Skan			ktrgenio((struct ktr_genio *)m, ktrlen);
151169689Skan			break;
152169689Skan		case KTR_PSIG:
153169689Skan			ktrpsig((struct ktr_psig *)m);
154169689Skan			break;
155169689Skan		case KTR_CSW:
156169689Skan			ktrcsw((struct ktr_csw *)m);
157169689Skan			break;
158169689Skan		case KTR_USER:
159169689Skan			ktruser(ktrlen, m);
160169689Skan			break;
161169689Skan		}
162169689Skan		if (tail)
163169689Skan			(void)fflush(stdout);
164169689Skan	}
165169689Skan}
166169689Skan
167169689Skanfread_tail(buf, size, num)
168169689Skan	char *buf;
169169689Skan	int num, size;
170169689Skan{
171169689Skan	int i;
172169689Skan
173169689Skan	while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
174169689Skan		(void)sleep(1);
175169689Skan		clearerr(stdin);
176169689Skan	}
177169689Skan	return (i);
178169689Skan}
179169689Skan
180169689Skandumpheader(kth)
181169689Skan	struct ktr_header *kth;
182169689Skan{
183169689Skan	static char unknown[64];
184169689Skan	static struct timeval prevtime, temp;
185169689Skan	char *type;
186169689Skan
187169689Skan	switch (kth->ktr_type) {
188169689Skan	case KTR_SYSCALL:
189169689Skan		type = "CALL";
190169689Skan		break;
191169689Skan	case KTR_SYSRET:
192169689Skan		type = "RET ";
193169689Skan		break;
194169689Skan	case KTR_NAMEI:
195169689Skan		type = "NAMI";
196169689Skan		break;
197169689Skan	case KTR_GENIO:
198169689Skan		type = "GIO ";
199169689Skan		break;
200169689Skan	case KTR_PSIG:
201169689Skan		type = "PSIG";
202169689Skan		break;
203169689Skan	case KTR_CSW:
204169689Skan		type = "CSW";
205169689Skan		break;
206169689Skan	case KTR_USER:
207169689Skan		type = "USER";
208169689Skan		break;
209169689Skan	default:
210169689Skan		(void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type);
211169689Skan		type = unknown;
212169689Skan	}
213169689Skan
214169689Skan	(void)printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN, kth->ktr_comm);
215169689Skan	if (timestamp) {
216169689Skan		if (timestamp == 2) {
217169689Skan			temp = kth->ktr_time;
218169689Skan			timevalsub(&kth->ktr_time, &prevtime);
219169689Skan			prevtime = temp;
220169689Skan		}
221169689Skan		(void)printf("%ld.%06ld ",
222169689Skan		    kth->ktr_time.tv_sec, kth->ktr_time.tv_usec);
223169689Skan	}
224169689Skan	(void)printf("%s  ", type);
225169689Skan}
226169689Skan
227169689Skan#include <sys/syscall.h>
228169689Skan#define KTRACE
229169689Skan#include <sys/kern/syscalls.c>
230169689Skan#undef KTRACE
231169689Skanint nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]);
232169689Skan
233169689Skanstatic char *ptrace_ops[] = {
234169689Skan	"PT_TRACE_ME",	"PT_READ_I",	"PT_READ_D",	"PT_READ_U",
235169689Skan	"PT_WRITE_I",	"PT_WRITE_D",	"PT_WRITE_U",	"PT_CONTINUE",
236169689Skan	"PT_KILL",	"PT_STEP",	"PT_ATTACH",	"PT_DETACH",
237169689Skan};
238169689Skan
239169689Skanktrsyscall(ktr)
240169689Skan	register struct ktr_syscall *ktr;
241169689Skan{
242169689Skan	register narg = ktr->ktr_narg;
243169689Skan	register register_t *ip;
244169689Skan	char *ioctlname();
245169689Skan
246169689Skan	if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0)
247169689Skan		(void)printf("[%d]", ktr->ktr_code);
248169689Skan	else
249169689Skan		(void)printf("%s", syscallnames[ktr->ktr_code]);
250169689Skan	ip = &ktr->ktr_args[0];
251169689Skan	if (narg) {
252169689Skan		char c = '(';
253169689Skan		if (fancy) {
254169689Skan			if (ktr->ktr_code == SYS_ioctl) {
255169689Skan				char *cp;
256169689Skan				if (decimal)
257169689Skan					(void)printf("(%ld", (long)*ip);
258169689Skan				else
259169689Skan					(void)printf("(%#lx", (long)*ip);
260169689Skan				ip++;
261169689Skan				narg--;
262169689Skan				if ((cp = ioctlname(*ip)) != NULL)
263169689Skan					(void)printf(",%s", cp);
264169689Skan				else {
265169689Skan					if (decimal)
266169689Skan						(void)printf(",%ld", (long)*ip);
267169689Skan					else
268169689Skan						(void)printf(",%#lx ", (long)*ip);
269169689Skan				}
270169689Skan				c = ',';
271169689Skan				ip++;
272169689Skan				narg--;
273169689Skan			} else if (ktr->ktr_code == SYS_ptrace) {
274169689Skan				if (*ip < sizeof(ptrace_ops) /
275169689Skan				    sizeof(ptrace_ops[0]) && *ip >= 0)
276169689Skan					(void)printf("(%s", ptrace_ops[*ip]);
277169689Skan#ifdef PT_GETREGS
278169689Skan				else if (*ip == PT_GETREGS)
279169689Skan					(void)printf("(%s", "PT_GETREGS");
280169689Skan#endif
281169689Skan#ifdef PT_SETREGS
282169689Skan				else if (*ip == PT_SETREGS)
283169689Skan					(void)printf("(%s", "PT_SETREGS");
284169689Skan#endif
285169689Skan#ifdef PT_GETFPREGS
286169689Skan				else if (*ip == PT_GETFPREGS)
287169689Skan					(void)printf("(%s", "PT_GETFPREGS");
288169689Skan#endif
289169689Skan#ifdef PT_SETFPREGS
290169689Skan				else if (*ip == PT_SETFPREGS)
291169689Skan					(void)printf("(%s", "PT_SETFPREGS");
292169689Skan#endif
293169689Skan#ifdef PT_GETDBREGS
294169689Skan				else if (*ip == PT_GETDBREGS)
295169689Skan					(void)printf("(%s", "PT_GETDBREGS");
296169689Skan#endif
297169689Skan#ifdef PT_SETDBREGS
298169689Skan				else if (*ip == PT_SETDBREGS)
299169689Skan					(void)printf("(%s", "PT_SETDBREGS");
300169689Skan#endif
301169689Skan				else
302169689Skan					(void)printf("(%ld", (long)*ip);
303169689Skan				c = ',';
304169689Skan				ip++;
305169689Skan				narg--;
306169689Skan			}
307169689Skan		}
308169689Skan		while (narg) {
309169689Skan			if (decimal)
310169689Skan				(void)printf("%c%ld", c, (long)*ip);
311169689Skan			else
312169689Skan				(void)printf("%c%#lx", c, (long)*ip);
313169689Skan			c = ',';
314169689Skan			ip++;
315169689Skan			narg--;
316169689Skan		}
317169689Skan		(void)putchar(')');
318169689Skan	}
319169689Skan	(void)putchar('\n');
320169689Skan}
321169689Skan
322169689Skanktrsysret(ktr)
323169689Skan	struct ktr_sysret *ktr;
324169689Skan{
325169689Skan	register register_t ret = ktr->ktr_retval;
326169689Skan	register int error = ktr->ktr_error;
327169689Skan	register int code = ktr->ktr_code;
328169689Skan
329169689Skan	if (code >= nsyscalls || code < 0)
330169689Skan		(void)printf("[%d] ", code);
331169689Skan	else
332169689Skan		(void)printf("%s ", syscallnames[code]);
333169689Skan
334169689Skan	if (error == 0) {
335169689Skan		if (fancy) {
336169689Skan			(void)printf("%d", ret);
337169689Skan			if (ret < 0 || ret > 9)
338169689Skan				(void)printf("/%#lx", (long)ret);
339169689Skan		} else {
340169689Skan			if (decimal)
341169689Skan				(void)printf("%ld", (long)ret);
342169689Skan			else
343169689Skan				(void)printf("%#lx", (long)ret);
344169689Skan		}
345169689Skan	} else if (error == ERESTART)
346169689Skan		(void)printf("RESTART");
347169689Skan	else if (error == EJUSTRETURN)
348169689Skan		(void)printf("JUSTRETURN");
349169689Skan	else {
350169689Skan		(void)printf("-1 errno %d", ktr->ktr_error);
351169689Skan		if (fancy)
352169689Skan			(void)printf(" %s", strerror(ktr->ktr_error));
353169689Skan	}
354169689Skan	(void)putchar('\n');
355169689Skan}
356169689Skan
357169689Skanktrnamei(cp, len)
358169689Skan	char *cp;
359169689Skan{
360169689Skan	(void)printf("\"%.*s\"\n", len, cp);
361169689Skan}
362169689Skan
363169689Skanktrgenio(ktr, len)
364169689Skan	struct ktr_genio *ktr;
365169689Skan{
366169689Skan	register int datalen = len - sizeof (struct ktr_genio);
367169689Skan	register char *dp = (char *)ktr + sizeof (struct ktr_genio);
368169689Skan	register char *cp;
369169689Skan	register int col = 0;
370169689Skan	register width;
371169689Skan	char visbuf[5];
372169689Skan	static screenwidth = 0;
373169689Skan
374169689Skan	if (screenwidth == 0) {
375169689Skan		struct winsize ws;
376169689Skan
377169689Skan		if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
378169689Skan		    ws.ws_col > 8)
379169689Skan			screenwidth = ws.ws_col;
380169689Skan		else
381169689Skan			screenwidth = 80;
382169689Skan	}
383169689Skan	printf("fd %d %s %d byte%s\n", ktr->ktr_fd,
384169689Skan		ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen,
385169689Skan		datalen == 1 ? "" : "s");
386169689Skan	if (maxdata && datalen > maxdata)
387169689Skan		datalen = maxdata;
388169689Skan	(void)printf("       \"");
389169689Skan	col = 8;
390169689Skan	for (;datalen > 0; datalen--, dp++) {
391169689Skan		(void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
392169689Skan		cp = visbuf;
393169689Skan		/*
394169689Skan		 * Keep track of printables and
395169689Skan		 * space chars (like fold(1)).
396169689Skan		 */
397169689Skan		if (col == 0) {
398169689Skan			(void)putchar('\t');
399169689Skan			col = 8;
400169689Skan		}
401169689Skan		switch(*cp) {
402169689Skan		case '\n':
403169689Skan			col = 0;
404169689Skan			(void)putchar('\n');
405169689Skan			continue;
406169689Skan		case '\t':
407169689Skan			width = 8 - (col&07);
408169689Skan			break;
409169689Skan		default:
410169689Skan			width = strlen(cp);
411169689Skan		}
412169689Skan		if (col + width > (screenwidth-2)) {
413169689Skan			(void)printf("\\\n\t");
414169689Skan			col = 8;
415169689Skan		}
416169689Skan		col += width;
417169689Skan		do {
418169689Skan			(void)putchar(*cp++);
419169689Skan		} while (*cp);
420169689Skan	}
421169689Skan	if (col == 0)
422169689Skan		(void)printf("       ");
423169689Skan	(void)printf("\"\n");
424169689Skan}
425169689Skan
426169689Skanchar *signames[] = {
427169689Skan	"NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT",	/*  1 - 6  */
428169689Skan	"EMT", "FPE", "KILL", "BUS", "SEGV", "SYS",		/*  7 - 12 */
429169689Skan	"PIPE", "ALRM",  "TERM", "URG", "STOP", "TSTP",		/* 13 - 18 */
430169689Skan	"CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU",		/* 19 - 24 */
431169689Skan	"XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1",	/* 25 - 30 */
432169689Skan	"USR2", NULL,						/* 31 - 32 */
433169689Skan};
434169689Skan
435169689Skanktrpsig(psig)
436169689Skan	struct ktr_psig *psig;
437169689Skan{
438169689Skan	(void)printf("SIG%s ", signames[psig->signo]);
439169689Skan	if (psig->action == SIG_DFL)
440169689Skan		(void)printf("SIG_DFL\n");
441169689Skan	else
442169689Skan		(void)printf("caught handler=0x%lx mask=0x%x code=0x%x\n",
443169689Skan		    (u_long)psig->action, psig->mask, psig->code);
444169689Skan}
445169689Skan
446169689Skanktrcsw(cs)
447169689Skan	struct ktr_csw *cs;
448169689Skan{
449169689Skan	(void)printf("%s %s\n", cs->out ? "stop" : "resume",
450169689Skan		cs->user ? "user" : "kernel");
451169689Skan}
452169689Skan
453169689Skanktruser(len, p)
454169689Skan	int len;
455169689Skan	unsigned char *p;
456169689Skan{
457169689Skan	(void)printf("%d ", len);
458169689Skan	while (len--)
459169689Skan		(void)printf(" %02x", *p++);
460169689Skan	(void)printf("\n");
461169689Skan
462169689Skan}
463169689Skan
464169689Skanusage()
465169689Skan{
466169689Skan	(void)fprintf(stderr,
467169689Skan	    "usage: kdump [-dnlRT] [-f trfile] [-m maxdata] [-t [cnisuw]]\n");
468169689Skan	exit(1);
469169689Skan}
470169689Skan