xref: /freebsd/usr.bin/kdump/kdump.c (revision 6e8394b8baa7d5d9153ab90de6824bcd19b3b4e1)
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
35 static 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
42 static char sccsid[] = "@(#)kdump.c	8.1 (Berkeley) 6/6/93";
43 #endif
44 static const char rcsid[] =
45 	"$Id: kdump.c,v 1.12 1999/05/21 01:09:45 jmz Exp $";
46 #endif /* not lint */
47 
48 #define KERNEL
49 extern int errno;
50 #include <sys/errno.h>
51 #undef KERNEL
52 #include <sys/param.h>
53 #include <sys/errno.h>
54 #include <sys/time.h>
55 #include <sys/uio.h>
56 #include <sys/ktrace.h>
57 #include <sys/ioctl.h>
58 #include <sys/ptrace.h>
59 #include <err.h>
60 #include <locale.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <unistd.h>
65 #include <vis.h>
66 #include "ktrace.h"
67 
68 int timestamp, decimal, fancy = 1, tail, maxdata;
69 char *tracefile = DEF_TRACEFILE;
70 struct ktr_header ktr_header;
71 
72 #define eqs(s1, s2)	(strcmp((s1), (s2)) == 0)
73 
74 main(argc, argv)
75 	int argc;
76 	char *argv[];
77 {
78 	int ch, ktrlen, size;
79 	register void *m;
80 	int trpoints = ALL_POINTS;
81 
82 	(void) setlocale(LC_CTYPE, "");
83 
84 	while ((ch = getopt(argc,argv,"f:dlm:nRTt:")) != -1)
85 		switch((char)ch) {
86 		case 'f':
87 			tracefile = optarg;
88 			break;
89 		case 'd':
90 			decimal = 1;
91 			break;
92 		case 'l':
93 			tail = 1;
94 			break;
95 		case 'm':
96 			maxdata = atoi(optarg);
97 			break;
98 		case 'n':
99 			fancy = 0;
100 			break;
101 		case 'R':
102 			timestamp = 2;	/* relative timestamp */
103 			break;
104 		case 'T':
105 			timestamp = 1;
106 			break;
107 		case 't':
108 			trpoints = getpoints(optarg);
109 			if (trpoints < 0)
110 				errx(1, "unknown trace point in %s", optarg);
111 			break;
112 		default:
113 			usage();
114 		}
115 
116 	if (argc > optind)
117 		usage();
118 
119 	m = (void *)malloc(size = 1025);
120 	if (m == NULL)
121 		errx(1, "%s", strerror(ENOMEM));
122 	if (!freopen(tracefile, "r", stdin))
123 		err(1, "%s", tracefile);
124 	while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) {
125 		if (trpoints & (1<<ktr_header.ktr_type))
126 			dumpheader(&ktr_header);
127 		if ((ktrlen = ktr_header.ktr_len) < 0)
128 			errx(1, "bogus length 0x%x", ktrlen);
129 		if (ktrlen > size) {
130 			m = (void *)realloc(m, ktrlen+1);
131 			if (m == NULL)
132 				errx(1, "%s", strerror(ENOMEM));
133 			size = ktrlen;
134 		}
135 		if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
136 			errx(1, "data too short");
137 		if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
138 			continue;
139 		switch (ktr_header.ktr_type) {
140 		case KTR_SYSCALL:
141 			ktrsyscall((struct ktr_syscall *)m);
142 			break;
143 		case KTR_SYSRET:
144 			ktrsysret((struct ktr_sysret *)m);
145 			break;
146 		case KTR_NAMEI:
147 			ktrnamei(m, ktrlen);
148 			break;
149 		case KTR_GENIO:
150 			ktrgenio((struct ktr_genio *)m, ktrlen);
151 			break;
152 		case KTR_PSIG:
153 			ktrpsig((struct ktr_psig *)m);
154 			break;
155 		case KTR_CSW:
156 			ktrcsw((struct ktr_csw *)m);
157 			break;
158 		case KTR_USER:
159 			ktruser(ktrlen, m);
160 			break;
161 		}
162 		if (tail)
163 			(void)fflush(stdout);
164 	}
165 }
166 
167 fread_tail(buf, size, num)
168 	char *buf;
169 	int num, size;
170 {
171 	int i;
172 
173 	while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
174 		(void)sleep(1);
175 		clearerr(stdin);
176 	}
177 	return (i);
178 }
179 
180 dumpheader(kth)
181 	struct ktr_header *kth;
182 {
183 	static char unknown[64];
184 	static struct timeval prevtime, temp;
185 	char *type;
186 
187 	switch (kth->ktr_type) {
188 	case KTR_SYSCALL:
189 		type = "CALL";
190 		break;
191 	case KTR_SYSRET:
192 		type = "RET ";
193 		break;
194 	case KTR_NAMEI:
195 		type = "NAMI";
196 		break;
197 	case KTR_GENIO:
198 		type = "GIO ";
199 		break;
200 	case KTR_PSIG:
201 		type = "PSIG";
202 		break;
203 	case KTR_CSW:
204 		type = "CSW";
205 		break;
206 	case KTR_USER:
207 		type = "USER";
208 		break;
209 	default:
210 		(void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type);
211 		type = unknown;
212 	}
213 
214 	(void)printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN, kth->ktr_comm);
215 	if (timestamp) {
216 		if (timestamp == 2) {
217 			temp = kth->ktr_time;
218 			timevalsub(&kth->ktr_time, &prevtime);
219 			prevtime = temp;
220 		}
221 		(void)printf("%ld.%06ld ",
222 		    kth->ktr_time.tv_sec, kth->ktr_time.tv_usec);
223 	}
224 	(void)printf("%s  ", type);
225 }
226 
227 #include <sys/syscall.h>
228 #define KTRACE
229 #include <sys/kern/syscalls.c>
230 #undef KTRACE
231 int nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]);
232 
233 static char *ptrace_ops[] = {
234 	"PT_TRACE_ME",	"PT_READ_I",	"PT_READ_D",	"PT_READ_U",
235 	"PT_WRITE_I",	"PT_WRITE_D",	"PT_WRITE_U",	"PT_CONTINUE",
236 	"PT_KILL",	"PT_STEP",
237 };
238 
239 ktrsyscall(ktr)
240 	register struct ktr_syscall *ktr;
241 {
242 	register narg = ktr->ktr_narg;
243 	register register_t *ip;
244 	char *ioctlname();
245 
246 	if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0)
247 		(void)printf("[%d]", ktr->ktr_code);
248 	else
249 		(void)printf("%s", syscallnames[ktr->ktr_code]);
250 	ip = &ktr->ktr_args[0];
251 	if (narg) {
252 		char c = '(';
253 		if (fancy) {
254 			if (ktr->ktr_code == SYS_ioctl) {
255 				char *cp;
256 				if (decimal)
257 					(void)printf("(%ld", (long)*ip);
258 				else
259 					(void)printf("(%#lx", (long)*ip);
260 				ip++;
261 				narg--;
262 				if ((cp = ioctlname(*ip)) != NULL)
263 					(void)printf(",%s", cp);
264 				else {
265 					if (decimal)
266 						(void)printf(",%ld", (long)*ip);
267 					else
268 						(void)printf(",%#lx ", (long)*ip);
269 				}
270 				c = ',';
271 				ip++;
272 				narg--;
273 			} else if (ktr->ktr_code == SYS_ptrace) {
274 				if (*ip <= PT_STEP && *ip >= 0)
275 					(void)printf("(%s", ptrace_ops[*ip]);
276 				else
277 					(void)printf("(%ld", (long)*ip);
278 				c = ',';
279 				ip++;
280 				narg--;
281 			}
282 		}
283 		while (narg) {
284 			if (decimal)
285 				(void)printf("%c%ld", c, (long)*ip);
286 			else
287 				(void)printf("%c%#lx", c, (long)*ip);
288 			c = ',';
289 			ip++;
290 			narg--;
291 		}
292 		(void)putchar(')');
293 	}
294 	(void)putchar('\n');
295 }
296 
297 ktrsysret(ktr)
298 	struct ktr_sysret *ktr;
299 {
300 	register register_t ret = ktr->ktr_retval;
301 	register int error = ktr->ktr_error;
302 	register int code = ktr->ktr_code;
303 
304 	if (code >= nsyscalls || code < 0)
305 		(void)printf("[%d] ", code);
306 	else
307 		(void)printf("%s ", syscallnames[code]);
308 
309 	if (error == 0) {
310 		if (fancy) {
311 			(void)printf("%d", ret);
312 			if (ret < 0 || ret > 9)
313 				(void)printf("/%#lx", (long)ret);
314 		} else {
315 			if (decimal)
316 				(void)printf("%ld", (long)ret);
317 			else
318 				(void)printf("%#lx", (long)ret);
319 		}
320 	} else if (error == ERESTART)
321 		(void)printf("RESTART");
322 	else if (error == EJUSTRETURN)
323 		(void)printf("JUSTRETURN");
324 	else {
325 		(void)printf("-1 errno %d", ktr->ktr_error);
326 		if (fancy)
327 			(void)printf(" %s", strerror(ktr->ktr_error));
328 	}
329 	(void)putchar('\n');
330 }
331 
332 ktrnamei(cp, len)
333 	char *cp;
334 {
335 	(void)printf("\"%.*s\"\n", len, cp);
336 }
337 
338 ktrgenio(ktr, len)
339 	struct ktr_genio *ktr;
340 {
341 	register int datalen = len - sizeof (struct ktr_genio);
342 	register char *dp = (char *)ktr + sizeof (struct ktr_genio);
343 	register char *cp;
344 	register int col = 0;
345 	register width;
346 	char visbuf[5];
347 	static screenwidth = 0;
348 
349 	if (screenwidth == 0) {
350 		struct winsize ws;
351 
352 		if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
353 		    ws.ws_col > 8)
354 			screenwidth = ws.ws_col;
355 		else
356 			screenwidth = 80;
357 	}
358 	printf("fd %d %s %d byte%s\n", ktr->ktr_fd,
359 		ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen,
360 		datalen == 1 ? "" : "s");
361 	if (maxdata && datalen > maxdata)
362 		datalen = maxdata;
363 	(void)printf("       \"");
364 	col = 8;
365 	for (;datalen > 0; datalen--, dp++) {
366 		(void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
367 		cp = visbuf;
368 		/*
369 		 * Keep track of printables and
370 		 * space chars (like fold(1)).
371 		 */
372 		if (col == 0) {
373 			(void)putchar('\t');
374 			col = 8;
375 		}
376 		switch(*cp) {
377 		case '\n':
378 			col = 0;
379 			(void)putchar('\n');
380 			continue;
381 		case '\t':
382 			width = 8 - (col&07);
383 			break;
384 		default:
385 			width = strlen(cp);
386 		}
387 		if (col + width > (screenwidth-2)) {
388 			(void)printf("\\\n\t");
389 			col = 8;
390 		}
391 		col += width;
392 		do {
393 			(void)putchar(*cp++);
394 		} while (*cp);
395 	}
396 	if (col == 0)
397 		(void)printf("       ");
398 	(void)printf("\"\n");
399 }
400 
401 char *signames[] = {
402 	"NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT",	/*  1 - 6  */
403 	"EMT", "FPE", "KILL", "BUS", "SEGV", "SYS",		/*  7 - 12 */
404 	"PIPE", "ALRM",  "TERM", "URG", "STOP", "TSTP",		/* 13 - 18 */
405 	"CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU",		/* 19 - 24 */
406 	"XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1",	/* 25 - 30 */
407 	"USR2", NULL,						/* 31 - 32 */
408 };
409 
410 ktrpsig(psig)
411 	struct ktr_psig *psig;
412 {
413 	(void)printf("SIG%s ", signames[psig->signo]);
414 	if (psig->action == SIG_DFL)
415 		(void)printf("SIG_DFL\n");
416 	else
417 		(void)printf("caught handler=0x%lx mask=0x%x code=0x%x\n",
418 		    (u_long)psig->action, psig->mask, psig->code);
419 }
420 
421 ktrcsw(cs)
422 	struct ktr_csw *cs;
423 {
424 	(void)printf("%s %s\n", cs->out ? "stop" : "resume",
425 		cs->user ? "user" : "kernel");
426 }
427 
428 ktruser(len, p)
429 	int len;
430 	unsigned char *p;
431 {
432 	(void)printf("%d ", len);
433 	while (len--)
434 		(void)printf(" %02x", *p++);
435 	(void)printf("\n");
436 
437 }
438 
439 usage()
440 {
441 	(void)fprintf(stderr,
442 	    "usage: kdump [-dnlRT] [-f trfile] [-m maxdata] [-t [cnisuw]]\n");
443 	exit(1);
444 }
445