kdump.c revision 127402
1/*-
2 * Copyright (c) 1988, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static const char copyright[] =
36"@(#) Copyright (c) 1988, 1993\n\
37	The Regents of the University of California.  All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)kdump.c	8.1 (Berkeley) 6/6/93";
43#endif
44#endif /* not lint */
45#include <sys/cdefs.h>
46__FBSDID("$FreeBSD: head/usr.bin/kdump/kdump.c 127402 2004-03-25 12:33:55Z phk $");
47
48#define _KERNEL
49extern int errno;
50#include <sys/errno.h>
51#undef _KERNEL
52#include <sys/param.h>
53#include <sys/errno.h>
54#define _KERNEL
55#include <sys/time.h>
56#undef _KERNEL
57#include <sys/uio.h>
58#include <sys/ktrace.h>
59#include <sys/ioctl.h>
60#include <sys/ptrace.h>
61#include <err.h>
62#include <locale.h>
63#include <stdio.h>
64#include <stdlib.h>
65#include <string.h>
66#include <unistd.h>
67#include <vis.h>
68#include "ktrace.h"
69
70int fread_tail(void *, int, int);
71void dumpheader(struct ktr_header *);
72void ktrsyscall(struct ktr_syscall *);
73void ktrsysret(struct ktr_sysret *);
74void ktrnamei(char *, int);
75void hexdump(char *, int, int);
76void visdump(char *, int, int);
77void ktrgenio(struct ktr_genio *, int);
78void ktrpsig(struct ktr_psig *);
79void ktrcsw(struct ktr_csw *);
80void ktruser(int, unsigned char *);
81void usage(void);
82
83int timestamp, decimal, fancy = 1, tail, maxdata;
84const char *tracefile = DEF_TRACEFILE;
85struct ktr_header ktr_header;
86
87#define eqs(s1, s2)	(strcmp((s1), (s2)) == 0)
88
89int
90main(int argc, char *argv[])
91{
92	int ch, ktrlen, size;
93	void *m;
94	int trpoints = ALL_POINTS;
95	int drop_logged;
96	pid_t pid = 0;
97
98	(void) setlocale(LC_CTYPE, "");
99
100	while ((ch = getopt(argc,argv,"f:dElm:np:RTt:")) != -1)
101		switch((char)ch) {
102		case 'f':
103			tracefile = optarg;
104			break;
105		case 'd':
106			decimal = 1;
107			break;
108		case 'l':
109			tail = 1;
110			break;
111		case 'm':
112			maxdata = atoi(optarg);
113			break;
114		case 'n':
115			fancy = 0;
116			break;
117		case 'p':
118			pid = atoi(optarg);
119			break;
120		case 'E':
121			timestamp = 3;	/* elapsed timestamp */
122			break;
123		case 'R':
124			timestamp = 2;	/* relative timestamp */
125			break;
126		case 'T':
127			timestamp = 1;
128			break;
129		case 't':
130			trpoints = getpoints(optarg);
131			if (trpoints < 0)
132				errx(1, "unknown trace point in %s", optarg);
133			break;
134		default:
135			usage();
136		}
137
138	if (argc > optind)
139		usage();
140
141	m = (void *)malloc(size = 1025);
142	if (m == NULL)
143		errx(1, "%s", strerror(ENOMEM));
144	if (!freopen(tracefile, "r", stdin))
145		err(1, "%s", tracefile);
146	drop_logged = 0;
147	while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) {
148		if (ktr_header.ktr_type & KTR_DROP) {
149			ktr_header.ktr_type &= ~KTR_DROP;
150			if (!drop_logged) {
151				(void)printf("%6d %-8.*s Events dropped.\n",
152				    ktr_header.ktr_pid, MAXCOMLEN,
153				    ktr_header.ktr_comm);
154				drop_logged = 1;
155			}
156		}
157		if (trpoints & (1<<ktr_header.ktr_type))
158			if (pid == 0 || ktr_header.ktr_pid == pid)
159				dumpheader(&ktr_header);
160		if ((ktrlen = ktr_header.ktr_len) < 0)
161			errx(1, "bogus length 0x%x", ktrlen);
162		if (ktrlen > size) {
163			m = (void *)realloc(m, ktrlen+1);
164			if (m == NULL)
165				errx(1, "%s", strerror(ENOMEM));
166			size = ktrlen;
167		}
168		if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
169			errx(1, "data too short");
170		if (pid && ktr_header.ktr_pid != pid)
171			continue;
172		if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
173			continue;
174		drop_logged = 0;
175		switch (ktr_header.ktr_type) {
176		case KTR_SYSCALL:
177			ktrsyscall((struct ktr_syscall *)m);
178			break;
179		case KTR_SYSRET:
180			ktrsysret((struct ktr_sysret *)m);
181			break;
182		case KTR_NAMEI:
183			ktrnamei(m, ktrlen);
184			break;
185		case KTR_GENIO:
186			ktrgenio((struct ktr_genio *)m, ktrlen);
187			break;
188		case KTR_PSIG:
189			ktrpsig((struct ktr_psig *)m);
190			break;
191		case KTR_CSW:
192			ktrcsw((struct ktr_csw *)m);
193			break;
194		case KTR_USER:
195			ktruser(ktrlen, m);
196			break;
197		default:
198			printf("\n");
199			break;
200		}
201		if (tail)
202			(void)fflush(stdout);
203	}
204	return 0;
205}
206
207int
208fread_tail(void *buf, int size, int num)
209{
210	int i;
211
212	while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
213		(void)sleep(1);
214		clearerr(stdin);
215	}
216	return (i);
217}
218
219void
220dumpheader(struct ktr_header *kth)
221{
222	static char unknown[64];
223	static struct timeval prevtime, temp;
224	const char *type;
225
226	switch (kth->ktr_type) {
227	case KTR_SYSCALL:
228		type = "CALL";
229		break;
230	case KTR_SYSRET:
231		type = "RET ";
232		break;
233	case KTR_NAMEI:
234		type = "NAMI";
235		break;
236	case KTR_GENIO:
237		type = "GIO ";
238		break;
239	case KTR_PSIG:
240		type = "PSIG";
241		break;
242	case KTR_CSW:
243		type = "CSW";
244		break;
245	case KTR_USER:
246		type = "USER";
247		break;
248	default:
249		(void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type);
250		type = unknown;
251	}
252
253	(void)printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN, kth->ktr_comm);
254	if (timestamp) {
255		if (timestamp == 3) {
256			if (prevtime.tv_sec == 0)
257				prevtime = kth->ktr_time;
258			timevalsub(&kth->ktr_time, &prevtime);
259		}
260		if (timestamp == 2) {
261			temp = kth->ktr_time;
262			timevalsub(&kth->ktr_time, &prevtime);
263			prevtime = temp;
264		}
265		(void)printf("%ld.%06ld ",
266		    kth->ktr_time.tv_sec, kth->ktr_time.tv_usec);
267	}
268	(void)printf("%s  ", type);
269}
270
271#include <sys/syscall.h>
272#define KTRACE
273#include <sys/kern/syscalls.c>
274#undef KTRACE
275int nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]);
276
277static const char *ptrace_ops[] = {
278	"PT_TRACE_ME",	"PT_READ_I",	"PT_READ_D",	"PT_READ_U",
279	"PT_WRITE_I",	"PT_WRITE_D",	"PT_WRITE_U",	"PT_CONTINUE",
280	"PT_KILL",	"PT_STEP",	"PT_ATTACH",	"PT_DETACH",
281};
282
283void
284ktrsyscall(struct ktr_syscall *ktr)
285{
286	int narg = ktr->ktr_narg;
287	register_t *ip;
288	const char *ioctlname(u_long);
289
290	if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0)
291		(void)printf("[%d]", ktr->ktr_code);
292	else
293		(void)printf("%s", syscallnames[ktr->ktr_code]);
294	ip = &ktr->ktr_args[0];
295	if (narg) {
296		char c = '(';
297		if (fancy) {
298			if (ktr->ktr_code == SYS_ioctl) {
299				const char *cp;
300				if (decimal)
301					(void)printf("(%ld", (long)*ip);
302				else
303					(void)printf("(%#lx", (long)*ip);
304				ip++;
305				narg--;
306				if ((cp = ioctlname(*ip)) != NULL)
307					(void)printf(",%s", cp);
308				else {
309					if (decimal)
310						(void)printf(",%ld", (long)*ip);
311					else
312						(void)printf(",%#lx ", (long)*ip);
313				}
314				c = ',';
315				ip++;
316				narg--;
317			} else if (ktr->ktr_code == SYS_ptrace) {
318				if ((size_t)*ip < sizeof(ptrace_ops) /
319				    sizeof(ptrace_ops[0]) && *ip >= 0)
320					(void)printf("(%s", ptrace_ops[*ip]);
321#ifdef PT_GETREGS
322				else if (*ip == PT_GETREGS)
323					(void)printf("(%s", "PT_GETREGS");
324#endif
325#ifdef PT_SETREGS
326				else if (*ip == PT_SETREGS)
327					(void)printf("(%s", "PT_SETREGS");
328#endif
329#ifdef PT_GETFPREGS
330				else if (*ip == PT_GETFPREGS)
331					(void)printf("(%s", "PT_GETFPREGS");
332#endif
333#ifdef PT_SETFPREGS
334				else if (*ip == PT_SETFPREGS)
335					(void)printf("(%s", "PT_SETFPREGS");
336#endif
337#ifdef PT_GETDBREGS
338				else if (*ip == PT_GETDBREGS)
339					(void)printf("(%s", "PT_GETDBREGS");
340#endif
341#ifdef PT_SETDBREGS
342				else if (*ip == PT_SETDBREGS)
343					(void)printf("(%s", "PT_SETDBREGS");
344#endif
345				else
346					(void)printf("(%ld", (long)*ip);
347				c = ',';
348				ip++;
349				narg--;
350			}
351		}
352		while (narg) {
353			if (decimal)
354				(void)printf("%c%ld", c, (long)*ip);
355			else
356				(void)printf("%c%#lx", c, (long)*ip);
357			c = ',';
358			ip++;
359			narg--;
360		}
361		(void)putchar(')');
362	}
363	(void)putchar('\n');
364}
365
366void
367ktrsysret(struct ktr_sysret *ktr)
368{
369	register_t ret = ktr->ktr_retval;
370	int error = ktr->ktr_error;
371	int code = ktr->ktr_code;
372
373	if (code >= nsyscalls || code < 0)
374		(void)printf("[%d] ", code);
375	else
376		(void)printf("%s ", syscallnames[code]);
377
378	if (error == 0) {
379		if (fancy) {
380			(void)printf("%d", ret);
381			if (ret < 0 || ret > 9)
382				(void)printf("/%#lx", (long)ret);
383		} else {
384			if (decimal)
385				(void)printf("%ld", (long)ret);
386			else
387				(void)printf("%#lx", (long)ret);
388		}
389	} else if (error == ERESTART)
390		(void)printf("RESTART");
391	else if (error == EJUSTRETURN)
392		(void)printf("JUSTRETURN");
393	else {
394		(void)printf("-1 errno %d", ktr->ktr_error);
395		if (fancy)
396			(void)printf(" %s", strerror(ktr->ktr_error));
397	}
398	(void)putchar('\n');
399}
400
401void
402ktrnamei(char *cp, int len)
403{
404	(void)printf("\"%.*s\"\n", len, cp);
405}
406
407void
408hexdump(char *p, int len, int screenwidth)
409{
410	int n, i;
411	int width;
412
413	width = 0;
414	do {
415		width += 2;
416		i = 13;			/* base offset */
417		i += (width / 2) + 1;	/* spaces every second byte */
418		i += (width * 2);	/* width of bytes */
419		i += 3;			/* "  |" */
420		i += width;		/* each byte */
421		i += 1;			/* "|" */
422	} while (i < screenwidth);
423	width -= 2;
424
425	for (n = 0; n < len; n += width) {
426		for (i = n; i < n + width; i++) {
427			if ((i % width) == 0) {	/* beginning of line */
428				printf("       0x%04x", i);
429			}
430			if ((i % 2) == 0) {
431				printf(" ");
432			}
433			if (i < len)
434				printf("%02x", p[i] & 0xff);
435			else
436				printf("  ");
437		}
438		printf("  |");
439		for (i = n; i < n + width; i++) {
440			if (i >= len)
441				break;
442			if (p[i] >= ' ' && p[i] <= '~')
443				printf("%c", p[i]);
444			else
445				printf(".");
446		}
447		printf("|\n");
448	}
449	if ((i % width) != 0)
450		printf("\n");
451}
452
453void
454visdump(char *dp, int datalen, int screenwidth)
455{
456	int col = 0;
457	char *cp;
458	int width;
459	char visbuf[5];
460
461	(void)printf("       \"");
462	col = 8;
463	for (;datalen > 0; datalen--, dp++) {
464		(void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
465		cp = visbuf;
466		/*
467		 * Keep track of printables and
468		 * space chars (like fold(1)).
469		 */
470		if (col == 0) {
471			(void)putchar('\t');
472			col = 8;
473		}
474		switch(*cp) {
475		case '\n':
476			col = 0;
477			(void)putchar('\n');
478			continue;
479		case '\t':
480			width = 8 - (col&07);
481			break;
482		default:
483			width = strlen(cp);
484		}
485		if (col + width > (screenwidth-2)) {
486			(void)printf("\\\n\t");
487			col = 8;
488		}
489		col += width;
490		do {
491			(void)putchar(*cp++);
492		} while (*cp);
493	}
494	if (col == 0)
495		(void)printf("       ");
496	(void)printf("\"\n");
497}
498
499void
500ktrgenio(struct ktr_genio *ktr, int len)
501{
502	int datalen = len - sizeof (struct ktr_genio);
503	char *dp = (char *)ktr + sizeof (struct ktr_genio);
504	static int screenwidth = 0;
505	int i, binary;
506
507	if (screenwidth == 0) {
508		struct winsize ws;
509
510		if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
511		    ws.ws_col > 8)
512			screenwidth = ws.ws_col;
513		else
514			screenwidth = 80;
515	}
516	printf("fd %d %s %d byte%s\n", ktr->ktr_fd,
517		ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen,
518		datalen == 1 ? "" : "s");
519	if (maxdata && datalen > maxdata)
520		datalen = maxdata;
521
522	for (i = 0, binary = 0; i < datalen && binary == 0; i++)  {
523		if (dp[i] >= 32 && dp[i] < 127)
524			continue;
525		if (dp[i] == 10 || dp[i] == 13 || dp[i] == 0 || dp[i] == 9)
526			continue;
527		binary = 1;
528	}
529	if (binary)
530		hexdump(dp, datalen, screenwidth);
531	else
532		visdump(dp, datalen, screenwidth);
533}
534
535const char *signames[] = {
536	"NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT",	/*  1 - 6  */
537	"EMT", "FPE", "KILL", "BUS", "SEGV", "SYS",		/*  7 - 12 */
538	"PIPE", "ALRM",  "TERM", "URG", "STOP", "TSTP",		/* 13 - 18 */
539	"CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU",		/* 19 - 24 */
540	"XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1",	/* 25 - 30 */
541	"USR2", NULL,						/* 31 - 32 */
542};
543
544void
545ktrpsig(struct ktr_psig *psig)
546{
547	(void)printf("SIG%s ", signames[psig->signo]);
548	if (psig->action == SIG_DFL)
549		(void)printf("SIG_DFL\n");
550	else {
551		(void)printf("caught handler=0x%lx mask=0x%x code=0x%x\n",
552		    (u_long)psig->action, psig->mask.__bits[0], psig->code);
553	}
554}
555
556void
557ktrcsw(struct ktr_csw *cs)
558{
559	(void)printf("%s %s\n", cs->out ? "stop" : "resume",
560		cs->user ? "user" : "kernel");
561}
562
563void
564ktruser(int len, unsigned char *p)
565{
566	(void)printf("%d ", len);
567	while (len--)
568		if (decimal)
569			(void)printf(" %d", *p++);
570		else
571			(void)printf(" %02x", *p++);
572	(void)printf("\n");
573
574}
575
576void
577usage(void)
578{
579	(void)fprintf(stderr,
580    "usage: kdump [-dEnlRT] [-f trfile] [-m maxdata] [-p pid] [-t [cnisuw]]\n");
581	exit(1);
582}
583