xref: /netbsd-src/usr.bin/kdump/kdump.c (revision d0fed6c87ddc40a8bffa6f99e7433ddfc864dd83)
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 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.4 (Berkeley) 4/28/95";
43 #endif
44 static char *rcsid = "$NetBSD: kdump.c,v 1.15 1997/01/27 21:39:50 cgd Exp $";
45 #endif /* not lint */
46 
47 #include <sys/param.h>
48 #define _KERNEL
49 #include <sys/errno.h>
50 #undef _KERNEL
51 #include <sys/time.h>
52 #include <sys/uio.h>
53 #include <sys/ktrace.h>
54 #include <sys/ioctl.h>
55 #include <sys/ptrace.h>
56 
57 #include <err.h>
58 #include <signal.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <unistd.h>
63 #include <vis.h>
64 
65 #include "ktrace.h"
66 
67 int timestamp, decimal, fancy = 1, tail, maxdata;
68 char *tracefile = DEF_TRACEFILE;
69 struct ktr_header ktr_header;
70 
71 #define eqs(s1, s2)	(strcmp((s1), (s2)) == 0)
72 
73 #include <sys/syscall.h>
74 
75 #include "../../sys/compat/hpux/hpux_syscall.h"
76 #include "../../sys/compat/ibcs2/ibcs2_syscall.h"
77 #include "../../sys/compat/linux/linux_syscall.h"
78 #include "../../sys/compat/osf1/osf1_syscall.h"
79 #include "../../sys/compat/sunos/sunos_syscall.h"
80 #include "../../sys/compat/svr4/svr4_syscall.h"
81 #include "../../sys/compat/ultrix/ultrix_syscall.h"
82 
83 #define KTRACE
84 #include "../../sys/kern/syscalls.c"
85 
86 #include "../../sys/compat/hpux/hpux_syscalls.c"
87 #include "../../sys/compat/ibcs2/ibcs2_syscalls.c"
88 #include "../../sys/compat/linux/linux_syscalls.c"
89 #include "../../sys/compat/osf1/osf1_syscalls.c"
90 #include "../../sys/compat/sunos/sunos_syscalls.c"
91 #include "../../sys/compat/svr4/svr4_syscalls.c"
92 #include "../../sys/compat/ultrix/ultrix_syscalls.c"
93 #undef KTRACE
94 
95 struct emulation {
96 	char *name;		/* Emulation name */
97 	char **sysnames;	/* Array of system call names */
98 	int  nsysnames;		/* Number of */
99 };
100 
101 static struct emulation emulations[] = {
102 	{ "netbsd",	     syscallnames,        SYS_MAXSYSCALL },
103 	{ "hpux",	hpux_syscallnames,   HPUX_SYS_MAXSYSCALL },
104 	{ "ibcs2",     ibcs2_syscallnames,  IBCS2_SYS_MAXSYSCALL },
105 	{ "linux",     linux_syscallnames,  LINUX_SYS_MAXSYSCALL },
106 	{ "osf1",       osf1_syscallnames,   OSF1_SYS_MAXSYSCALL },
107 	{ "sunos",     sunos_syscallnames,  SUNOS_SYS_MAXSYSCALL },
108 	{ "svr4",       svr4_syscallnames,   SVR4_SYS_MAXSYSCALL },
109 	{ "ultrix",   ultrix_syscallnames, ULTRIX_SYS_MAXSYSCALL },
110 	{ NULL,			     NULL,		    NULL }
111 };
112 
113 struct emulation *current;
114 
115 
116 static char *ptrace_ops[] = {
117 	"PT_TRACE_ME",	"PT_READ_I",	"PT_READ_D",	"PT_READ_U",
118 	"PT_WRITE_I",	"PT_WRITE_D",	"PT_WRITE_U",	"PT_CONTINUE",
119 	"PT_KILL",	"PT_ATTACH",	"PT_DETACH",
120 };
121 
122 int
123 main(argc, argv)
124 	int argc;
125 	char *argv[];
126 {
127 	int ch, ktrlen, size;
128 	register void *m;
129 	int trpoints = ALL_POINTS;
130 
131 	current = &emulations[0];	/* NetBSD */
132 
133 	while ((ch = getopt(argc, argv, "e:f:dlm:nRTt:")) != -1)
134 		switch (ch) {
135 		case 'e':
136 			setemul(optarg);
137 			break;
138 		case 'f':
139 			tracefile = optarg;
140 			break;
141 		case 'd':
142 			decimal = 1;
143 			break;
144 		case 'l':
145 			tail = 1;
146 			break;
147 		case 'm':
148 			maxdata = atoi(optarg);
149 			break;
150 		case 'n':
151 			fancy = 0;
152 			break;
153 		case 'R':
154 			timestamp = 2;	/* relative timestamp */
155 			break;
156 		case 'T':
157 			timestamp = 1;
158 			break;
159 		case 't':
160 			trpoints = getpoints(optarg);
161 			if (trpoints < 0)
162 				errx(1, "unknown trace point in %s", optarg);
163 			break;
164 		default:
165 			usage();
166 		}
167 	argv += optind;
168 	argc -= optind;
169 
170 	if (argc > 1)
171 		usage();
172 
173 	m = (void *)malloc(size = 1025);
174 	if (m == NULL)
175 		errx(1, "%s", strerror(ENOMEM));
176 	if (!freopen(tracefile, "r", stdin))
177 		err(1, "%s", tracefile);
178 	while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) {
179 		if (trpoints & (1<<ktr_header.ktr_type))
180 			dumpheader(&ktr_header);
181 		if ((ktrlen = ktr_header.ktr_len) < 0)
182 			errx(1, "bogus length 0x%x", ktrlen);
183 		if (ktrlen > size) {
184 			m = (void *)realloc(m, ktrlen+1);
185 			if (m == NULL)
186 				errx(1, "%s", strerror(ENOMEM));
187 			size = ktrlen;
188 		}
189 		if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
190 			errx(1, "data too short");
191 		if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
192 			continue;
193 		switch (ktr_header.ktr_type) {
194 		case KTR_SYSCALL:
195 			ktrsyscall((struct ktr_syscall *)m);
196 			break;
197 		case KTR_SYSRET:
198 			ktrsysret((struct ktr_sysret *)m);
199 			break;
200 		case KTR_NAMEI:
201 			ktrnamei(m, ktrlen);
202 			break;
203 		case KTR_GENIO:
204 			ktrgenio((struct ktr_genio *)m, ktrlen);
205 			break;
206 		case KTR_PSIG:
207 			ktrpsig((struct ktr_psig *)m);
208 			break;
209 		case KTR_CSW:
210 			ktrcsw((struct ktr_csw *)m);
211 			break;
212 		case KTR_EMUL:
213 			ktremul(m, ktrlen);
214 			break;
215 		}
216 		if (tail)
217 			(void)fflush(stdout);
218 	}
219 }
220 
221 fread_tail(buf, size, num)
222 	char *buf;
223 	int num, size;
224 {
225 	int i;
226 
227 	while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
228 		(void)sleep(1);
229 		clearerr(stdin);
230 	}
231 	return (i);
232 }
233 
234 dumpheader(kth)
235 	struct ktr_header *kth;
236 {
237 	char unknown[64], *type;
238 	static struct timeval prevtime;
239 	struct timeval temp;
240 
241 	switch (kth->ktr_type) {
242 	case KTR_SYSCALL:
243 		type = "CALL";
244 		break;
245 	case KTR_SYSRET:
246 		type = "RET ";
247 		break;
248 	case KTR_NAMEI:
249 		type = "NAMI";
250 		break;
251 	case KTR_GENIO:
252 		type = "GIO ";
253 		break;
254 	case KTR_PSIG:
255 		type = "PSIG";
256 		break;
257 	case KTR_CSW:
258 		type = "CSW";
259 		break;
260 	case KTR_EMUL:
261 		type = "EMUL";
262 		break;
263 	default:
264 		(void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type);
265 		type = unknown;
266 	}
267 
268 	(void)printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN, kth->ktr_comm);
269 	if (timestamp) {
270 		if (timestamp == 2) {
271 			timersub(&kth->ktr_time, &prevtime, &temp);
272 			prevtime = kth->ktr_time;
273 		} else
274 			temp = kth->ktr_time;
275 		(void)printf("%ld.%06ld ", temp.tv_sec, temp.tv_usec);
276 	}
277 	(void)printf("%s  ", type);
278 }
279 
280 void
281 ioctldecode(cmd)
282 	u_long cmd;
283 {
284 	char dirbuf[4], *dir = dirbuf;
285 
286 	if (cmd & IOC_IN)
287 		*dir++ = 'W';
288 	if (cmd & IOC_OUT)
289 		*dir++ = 'R';
290 	*dir = '\0';
291 
292 	printf(decimal ? ",_IO%s('%c',%ld" : ",_IO%s('%c',%#lx",
293 	    dirbuf, (cmd >> 8) & 0xff, cmd & 0xff);
294 	if ((cmd & IOC_VOID) == 0)
295 		printf(decimal ? ",%ld)" : ",%#lx)", (cmd >> 16) & 0xff);
296 	else
297 		printf(")");
298 }
299 
300 ktrsyscall(ktr)
301 	register struct ktr_syscall *ktr;
302 {
303 	register argsize = ktr->ktr_argsize;
304 	register register_t *ap;
305 	char *ioctlname();
306 
307 	if (ktr->ktr_code >= current->nsysnames || ktr->ktr_code < 0)
308 		(void)printf("[%d]", ktr->ktr_code);
309 	else
310 		(void)printf("%s", current->sysnames[ktr->ktr_code]);
311 	ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall));
312 	if (argsize) {
313 		char c = '(';
314 		if (fancy) {
315 			if (ktr->ktr_code == SYS_ioctl) {
316 				char *cp;
317 				if (decimal)
318 					(void)printf("(%ld", (long)*ap);
319 				else
320 					(void)printf("(%#lx", (long)*ap);
321 				ap++;
322 				argsize -= sizeof(register_t);
323 				if ((cp = ioctlname(*ap)) != NULL)
324 					(void)printf(",%s", cp);
325 				else
326 					ioctldecode(*ap);
327 				c = ',';
328 				ap++;
329 				argsize -= sizeof(register_t);
330 			} else if (ktr->ktr_code == SYS_ptrace) {
331 				if (*ap >= 0 && *ap <=
332 				    sizeof(ptrace_ops) / sizeof(ptrace_ops[0]))
333 					(void)printf("(%s", ptrace_ops[*ap]);
334 				else
335 					(void)printf("(%ld", (long)*ap);
336 				c = ',';
337 				ap++;
338 				argsize -= sizeof(register_t);
339 			}
340 		}
341 		while (argsize) {
342 			if (decimal)
343 				(void)printf("%c%ld", c, (long)*ap);
344 			else
345 				(void)printf("%c%#lx", c, (long)*ap);
346 			c = ',';
347 			ap++;
348 			argsize -= sizeof(register_t);
349 		}
350 		(void)putchar(')');
351 	}
352 	(void)putchar('\n');
353 }
354 
355 ktrsysret(ktr)
356 	struct ktr_sysret *ktr;
357 {
358 	register int ret = ktr->ktr_retval;
359 	register int error = ktr->ktr_error;
360 	register int code = ktr->ktr_code;
361 
362 	if (code >= current->nsysnames || code < 0)
363 		(void)printf("[%d] ", code);
364 	else
365 		(void)printf("%s ", current->sysnames[code]);
366 
367 	if (error == 0) {
368 		if (fancy) {
369 			(void)printf("%d", ret);
370 			if (ret < 0 || ret > 9)
371 				(void)printf("/%#x", ret);
372 		} else {
373 			if (decimal)
374 				(void)printf("%d", ret);
375 			else
376 				(void)printf("%#x", ret);
377 		}
378 	} else if (error == ERESTART)
379 		(void)printf("RESTART");
380 	else if (error == EJUSTRETURN)
381 		(void)printf("JUSTRETURN");
382 	else {
383 		(void)printf("-1 errno %d", ktr->ktr_error);
384 		if (fancy)
385 			(void)printf(" %s", strerror(ktr->ktr_error));
386 	}
387 	(void)putchar('\n');
388 }
389 
390 ktrnamei(cp, len)
391 	char *cp;
392 {
393 	(void)printf("\"%.*s\"\n", len, cp);
394 }
395 
396 ktremul(cp, len)
397 	char *cp;
398 {
399 	char name[1024];
400 
401 	if (len >= sizeof(name))
402 		errx(1, "Emulation name too long");
403 
404 	strncpy(name, cp, len);
405 	name[len] = '\0';
406 	(void)printf("\"%s\"\n", name);
407 
408 	setemul(name);
409 }
410 
411 ktrgenio(ktr, len)
412 	struct ktr_genio *ktr;
413 {
414 	register int datalen = len - sizeof (struct ktr_genio);
415 	register char *dp = (char *)ktr + sizeof (struct ktr_genio);
416 	register char *cp;
417 	register int col = 0;
418 	register width;
419 	char visbuf[5];
420 	static screenwidth = 0;
421 
422 	if (screenwidth == 0) {
423 		struct winsize ws;
424 
425 		if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
426 		    ws.ws_col > 8)
427 			screenwidth = ws.ws_col;
428 		else
429 			screenwidth = 80;
430 	}
431 	printf("fd %d %s %d bytes\n", ktr->ktr_fd,
432 		ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen);
433 	if (maxdata && datalen > maxdata)
434 		datalen = maxdata;
435 	(void)printf("       \"");
436 	col = 8;
437 	for (; datalen > 0; datalen--, dp++) {
438 		(void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
439 		cp = visbuf;
440 		/*
441 		 * Keep track of printables and
442 		 * space chars (like fold(1)).
443 		 */
444 		if (col == 0) {
445 			(void)putchar('\t');
446 			col = 8;
447 		}
448 		switch(*cp) {
449 		case '\n':
450 			col = 0;
451 			(void)putchar('\n');
452 			continue;
453 		case '\t':
454 			width = 8 - (col&07);
455 			break;
456 		default:
457 			width = strlen(cp);
458 		}
459 		if (col + width > (screenwidth-2)) {
460 			(void)printf("\\\n\t");
461 			col = 8;
462 		}
463 		col += width;
464 		do {
465 			(void)putchar(*cp++);
466 		} while (*cp);
467 	}
468 	if (col == 0)
469 		(void)printf("       ");
470 	(void)printf("\"\n");
471 }
472 
473 ktrpsig(psig)
474 	struct ktr_psig *psig;
475 {
476 	(void)printf("SIG%s ", sys_signame[psig->signo]);
477 	if (psig->action == SIG_DFL)
478 		(void)printf("SIG_DFL\n");
479 	else
480 		(void)printf("caught handler=0x%lx mask=0x%x code=0x%x\n",
481 		    (u_long)psig->action, psig->mask, psig->code);
482 }
483 
484 ktrcsw(cs)
485 	struct ktr_csw *cs;
486 {
487 	(void)printf("%s %s\n", cs->out ? "stop" : "resume",
488 	    cs->user ? "user" : "kernel");
489 }
490 
491 usage()
492 {
493 
494 	(void)fprintf(stderr,
495 "usage: kdump [-dnlRT] [-e emulation] [-f trfile] [-m maxdata] [-t [cnis]]\n");
496 	exit(1);
497 }
498 
499 setemul(name)
500 	char *name;
501 {
502 	int i;
503 	for (i = 0; emulations[i].name != NULL; i++)
504 		if (strcmp(emulations[i].name, name) == 0) {
505 			current = &emulations[i];
506 			return;
507 		}
508 	warnx("Emulation `%s' unknown", name);
509 }
510