xref: /netbsd-src/usr.bin/kdump/kdump.c (revision d710132b4b8ce7f7cccaaf660cb16aa16b4077a0)
1 /*	$NetBSD: kdump.c,v 1.48 2003/05/15 12:57:54 dsl Exp $	*/
2 
3 /*-
4  * Copyright (c) 1988, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __COPYRIGHT("@(#) Copyright (c) 1988, 1993\n\
39 	The Regents of the University of California.  All rights reserved.\n");
40 #endif /* not lint */
41 
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "@(#)kdump.c	8.4 (Berkeley) 4/28/95";
45 #else
46 __RCSID("$NetBSD: kdump.c,v 1.48 2003/05/15 12:57:54 dsl Exp $");
47 #endif
48 #endif /* not lint */
49 
50 #include <sys/param.h>
51 #define _KERNEL
52 #include <sys/errno.h>
53 #undef _KERNEL
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 
60 #include <ctype.h>
61 #include <err.h>
62 #include <signal.h>
63 #include <stddef.h>
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <unistd.h>
68 #include <vis.h>
69 
70 #include "ktrace.h"
71 #include "setemul.h"
72 
73 #include <sys/syscall.h>
74 
75 int timestamp, decimal, plain, tail, maxdata = -1, numeric;
76 pid_t do_pid = -1;
77 const char *tracefile = NULL;
78 struct ktr_header ktr_header;
79 int emul_changed = 0;
80 
81 #define eqs(s1, s2)	(strcmp((s1), (s2)) == 0)
82 
83 static const char *ptrace_ops[] = {
84 	"PT_TRACE_ME",	"PT_READ_I",	"PT_READ_D",	"PT_READ_U",
85 	"PT_WRITE_I",	"PT_WRITE_D",	"PT_WRITE_U",	"PT_CONTINUE",
86 	"PT_KILL",	"PT_ATTACH",	"PT_DETACH",
87 };
88 
89 static const char *linux_ptrace_ops[] = {
90 	"PTRACE_TRACEME",
91 	"PTRACE_PEEKTEXT", "PTRACE_PEEKDATA", "PTRACE_PEEKUSER",
92 	"PTRACE_POKETEXT", "PTRACE_POKEDATA", "PTRACE_POKEUSER",
93 	"PTRACE_CONT", "PTRACE_KILL", "PTRACE_SINGLESTEP",
94 	NULL, NULL,
95 	"PTRACE_GETREGS", "PTRACE_SETREGS", "PTRACE_GETFPREGS",
96 	"PTRACE_SETFPREGS", "PTRACE_ATTACH", "PTRACE_DETACH",
97 	"PTRACE_SYSCALL",
98 };
99 
100 int	main __P((int, char **));
101 int	fread_tail __P((char *, int, int));
102 void	dumpheader __P((struct ktr_header *));
103 void	ioctldecode __P((u_long));
104 void	ktrsyscall __P((struct ktr_syscall *));
105 void	ktrsysret __P((struct ktr_sysret *, int));
106 void	ktrnamei __P((char *, int));
107 void	ktremul __P((char *, int, int));
108 void	ktrgenio __P((struct ktr_genio *, int));
109 void	ktrpsig __P((struct ktr_psig *));
110 void	ktrcsw __P((struct ktr_csw *));
111 void	ktruser __P((struct ktr_user *, int));
112 void	ktrmmsg __P((struct ktr_mmsg *, int));
113 void	usage __P((void));
114 void	eprint __P((int));
115 void	rprint __P((register_t));
116 char	*ioctlname __P((long));
117 static const char *signame __P((long, int));
118 
119 int
120 main(argc, argv)
121 	int argc;
122 	char *argv[];
123 {
124 	int ch, ktrlen, size;
125 	void *m;
126 	int trpoints = ALL_POINTS;
127 	const char *emul_name = "netbsd";
128 
129 	while ((ch = getopt(argc, argv, "e:f:dlm:Nnp:RTt:")) != -1)
130 		switch (ch) {
131 		case 'e':
132 			emul_name = strdup(optarg); /* it's safer to copy it */
133 			break;
134 		case 'f':
135 			tracefile = optarg;
136 			break;
137 		case 'd':
138 			decimal = 1;
139 			break;
140 		case 'l':
141 			tail = 1;
142 			break;
143 		case 'p':
144 			do_pid = atoi(optarg);
145 			break;
146 		case 'm':
147 			maxdata = atoi(optarg);
148 			break;
149 		case 'N':
150 			numeric++;
151 			break;
152 		case 'n':
153 			plain++;
154 			break;
155 		case 'R':
156 			timestamp = 2;	/* relative timestamp */
157 			break;
158 		case 'T':
159 			timestamp = 1;
160 			break;
161 		case 't':
162 			trpoints = getpoints(optarg);
163 			if (trpoints < 0)
164 				errx(1, "unknown trace point in %s", optarg);
165 			break;
166 		default:
167 			usage();
168 		}
169 	argv += optind;
170 	argc -= optind;
171 
172 	if (tracefile == NULL) {
173 		if (argc == 1) {
174 			tracefile = argv[0];
175 			argv++;
176 			argc--;
177 		}
178 		else
179 			tracefile = DEF_TRACEFILE;
180 	}
181 
182 	if (argc > 0)
183 		usage();
184 
185 	setemul(emul_name, 0, 0);
186 	mach_lookup_emul();
187 
188 	m = malloc(size = 1024);
189 	if (m == NULL)
190 		errx(1, "malloc: %s", strerror(ENOMEM));
191 	if (!freopen(tracefile, "r", stdin))
192 		err(1, "%s", tracefile);
193 	while (fread_tail((char *)&ktr_header, sizeof(struct ktr_header), 1)) {
194 		if (trpoints & (1<<ktr_header.ktr_type))
195 			if (do_pid == -1 || ktr_header.ktr_pid == do_pid)
196 				dumpheader(&ktr_header);
197 		if ((ktrlen = ktr_header.ktr_len) < 0)
198 			errx(1, "bogus length 0x%x", ktrlen);
199 		if (ktrlen > size) {
200 			while(ktrlen > size) size *= 2;
201 			m = (void *)realloc(m, size);
202 			if (m == NULL)
203 				errx(1, "realloc: %s", strerror(ENOMEM));
204 		}
205 		if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
206 			errx(1, "data too short");
207 		if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
208 			continue;
209 
210 		/* update context to match currently processed record */
211 		if (do_pid != -1 && ktr_header.ktr_pid != do_pid)
212 			continue;
213 		ectx_sanify(ktr_header.ktr_pid);
214 
215 		switch (ktr_header.ktr_type) {
216 		case KTR_SYSCALL:
217 			ktrsyscall((struct ktr_syscall *)m);
218 			break;
219 		case KTR_SYSRET:
220 			ktrsysret((struct ktr_sysret *)m, ktrlen);
221 			break;
222 		case KTR_NAMEI:
223 			ktrnamei(m, ktrlen);
224 			break;
225 		case KTR_GENIO:
226 			ktrgenio((struct ktr_genio *)m, ktrlen);
227 			break;
228 		case KTR_PSIG:
229 			ktrpsig((struct ktr_psig *)m);
230 			break;
231 		case KTR_CSW:
232 			ktrcsw((struct ktr_csw *)m);
233 			break;
234 		case KTR_EMUL:
235 			ktremul(m, ktrlen, size);
236 			break;
237 		case KTR_USER:
238 			ktruser((struct ktr_user *)m, ktrlen);
239 			break;
240 		case KTR_MMSG:
241 			ktrmmsg((struct ktr_mmsg *)m, ktrlen);
242 			break;
243 		}
244 		if (tail)
245 			(void)fflush(stdout);
246 	}
247 	return (0);
248 }
249 
250 int
251 fread_tail(buf, size, num)
252 	char *buf;
253 	int num, size;
254 {
255 	int i;
256 
257 	while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
258 		(void)sleep(1);
259 		clearerr(stdin);
260 	}
261 	return (i);
262 }
263 
264 void
265 dumpheader(kth)
266 	struct ktr_header *kth;
267 {
268 	char unknown[64], *type;
269 	static struct timeval prevtime;
270 	struct timeval temp;
271 
272 	switch (kth->ktr_type) {
273 	case KTR_SYSCALL:
274 		type = "CALL";
275 		break;
276 	case KTR_SYSRET:
277 		type = "RET ";
278 		break;
279 	case KTR_NAMEI:
280 		type = "NAMI";
281 		break;
282 	case KTR_GENIO:
283 		type = "GIO ";
284 		break;
285 	case KTR_PSIG:
286 		type = "PSIG";
287 		break;
288 	case KTR_CSW:
289 		type = "CSW";
290 		break;
291 	case KTR_EMUL:
292 		type = "EMUL";
293 		break;
294 	case KTR_USER:
295 		type = "USER";
296 		break;
297 	case KTR_MMSG:
298 		type = "MMSG";
299 		break;
300 	default:
301 		(void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type);
302 		type = unknown;
303 	}
304 
305 	(void)printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN, kth->ktr_comm);
306 	if (timestamp) {
307 		if (timestamp == 2) {
308 			timersub(&kth->ktr_time, &prevtime, &temp);
309 			prevtime = kth->ktr_time;
310 		} else
311 			temp = kth->ktr_time;
312 		(void)printf("%ld.%06ld ",
313 		    (long int)temp.tv_sec, (long int)temp.tv_usec);
314 	}
315 	(void)printf("%s  ", type);
316 }
317 
318 void
319 ioctldecode(cmd)
320 	u_long cmd;
321 {
322 	char dirbuf[4], *dir = dirbuf;
323 
324 	if (cmd & IOC_IN)
325 		*dir++ = 'W';
326 	if (cmd & IOC_OUT)
327 		*dir++ = 'R';
328 	*dir = '\0';
329 
330 	printf(decimal ? ",_IO%s('%c',%ld" : ",_IO%s('%c',%#lx",
331 	    dirbuf, (int) ((cmd >> 8) & 0xff), cmd & 0xff);
332 	if ((cmd & IOC_VOID) == 0)
333 		printf(decimal ? ",%ld)" : ",%#lx)", (cmd >> 16) & 0xff);
334 	else
335 		printf(")");
336 }
337 
338 void
339 ktrsyscall(ktr)
340 	struct ktr_syscall *ktr;
341 {
342 	int argsize = ktr->ktr_argsize;
343 	const struct emulation *revelant = current;
344 	register_t *ap;
345 
346 	if (((ktr->ktr_code >= revelant->nsysnames || ktr->ktr_code < 0)
347 	    && (mach_traps_dispatch(&ktr->ktr_code, &revelant) == 0)) ||
348 	    numeric)
349 		(void)printf("[%d]", ktr->ktr_code);
350 	else
351 		(void)printf("%s", revelant->sysnames[ktr->ktr_code]);
352 	ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall));
353 	if (argsize) {
354 		char c = '(';
355 		if (!plain) {
356 			char *cp;
357 
358 			switch (ktr->ktr_code) {
359 			case SYS_ioctl:
360 				if (decimal)
361 					(void)printf("(%ld", (long)*ap);
362 				else
363 					(void)printf("(%#lx", (long)*ap);
364 				ap++;
365 				argsize -= sizeof(register_t);
366 				if ((cp = ioctlname(*ap)) != NULL)
367 					(void)printf(",%s", cp);
368 				else
369 					ioctldecode(*ap);
370 				c = ',';
371 				ap++;
372 				argsize -= sizeof(register_t);
373 				break;
374 
375 			case SYS_ptrace:
376 				if (strcmp(revelant->name, "linux") == 0) {
377 				  if (*ap >= 0 && *ap <=
378 				      sizeof(linux_ptrace_ops) /
379 				      sizeof(linux_ptrace_ops[0]))
380 					(void)printf("(%s",
381 					    linux_ptrace_ops[*ap]);
382 				  else
383 					(void)printf("(%ld", (long)*ap);
384 				} else {
385 				  if (*ap >= 0 && *ap <=
386 				    sizeof(ptrace_ops) / sizeof(ptrace_ops[0]))
387 					(void)printf("(%s", ptrace_ops[*ap]);
388 				  else
389 					(void)printf("(%ld", (long)*ap);
390 				}
391 				c = ',';
392 				ap++;
393 				argsize -= sizeof(register_t);
394 				break;
395 
396 			case SYS_kill:
397 				if (decimal)
398 					(void)printf("(%ld, SIG%s",
399 					    (long)ap[0], signame(ap[1], 1));
400 				else
401 					(void)printf("(%#lx, SIG%s",
402 					    (long)ap[0], signame(ap[1], 1));
403 				ap += 2;
404 				argsize -= 2 * sizeof(register_t);
405 				break;
406 
407 			default:
408 				/* No special handling */
409 				break;
410 			}
411 		}
412 		while (argsize) {
413 			if (decimal)
414 				(void)printf("%c%ld", c, (long)*ap);
415 			else
416 				(void)printf("%c%#lx", c, (long)*ap);
417 			c = ',';
418 			ap++;
419 			argsize -= sizeof(register_t);
420 		}
421 		(void)putchar(')');
422 	}
423 	(void)putchar('\n');
424 }
425 
426 void
427 ktrsysret(ktr, len)
428 	struct ktr_sysret *ktr;
429 	int len;
430 {
431 	const struct emulation *revelant;
432 	int error = ktr->ktr_error;
433 	int code = ktr->ktr_code;
434 
435 	if (emul_changed)
436 		revelant = previous;
437 	else
438 		revelant = current;
439 	emul_changed = 0;
440 
441 	if ((code >= revelant->nsysnames || code < 0 || plain > 1)
442 	    && (mach_traps_dispatch(&code, &revelant) == 0))
443 		(void)printf("[%d] ", code);
444 	else
445 		(void)printf("%s ", revelant->sysnames[code]);
446 
447 	switch (error) {
448 	case 0:
449 		rprint(ktr->ktr_retval);
450 		if (len > offsetof(struct ktr_sysret, ktr_retval_1) &&
451 		    ktr->ktr_retval_1 != 0) {
452 			(void)printf(", ");
453 			rprint(ktr->ktr_retval_1);
454 		}
455 		break;
456 
457 	default:
458 		eprint(error);
459 		break;
460 	}
461 	(void)putchar('\n');
462 }
463 
464 void
465 rprint(register_t ret)
466 {
467 	if (!plain) {
468 		(void)printf("%ld", (long)ret);
469 		if (ret < 0 || ret > 9)
470 			(void)printf("/%#lx", (long)ret);
471 	} else {
472 		if (decimal)
473 			(void)printf("%ld", (long)ret);
474 		else
475 			(void)printf("%#lx", (long)ret);
476 	}
477 }
478 
479 /*
480  * We print the original emulation's error numerically, but we
481  * translate it to netbsd to print it symbolically.
482  */
483 void
484 eprint(e)
485 	int e;
486 {
487 	int i = e;
488 
489 	if (current->errnomap) {
490 
491 		/* No remapping for ERESTART and EJUSTRETURN */
492 		/* Kludge for linux that has negative error numbers */
493 		if (current->errnomap[2] > 0 && e < 0)
494 			goto normal;
495 
496 		for (i = 0; i < current->nerrnomap; i++)
497 			if (e == current->errnomap[i])
498 				break;
499 
500 		if (i == current->nerrnomap) {
501 			printf("-1 unknown errno %d", e);
502 			return;
503 		}
504 	}
505 
506 normal:
507 	switch (i) {
508 	case ERESTART:
509 		(void)printf("RESTART");
510 		break;
511 
512 	case EJUSTRETURN:
513 		(void)printf("JUSTRETURN");
514 		break;
515 
516 	default:
517 		(void)printf("-1 errno %d", e);
518 		if (!plain)
519 			(void)printf(" %s", strerror(i));
520 	}
521 }
522 
523 void
524 ktrnamei(cp, len)
525 	char *cp;
526 	int len;
527 {
528 
529 	(void)printf("\"%.*s\"\n", len, cp);
530 }
531 
532 void
533 ktremul(name, len, bufsize)
534 	char *name;
535 	int len, bufsize;
536 {
537 	if (len >= bufsize)
538 		len = bufsize - 1;
539 
540 	name[len] = '\0';
541 	setemul(name, ktr_header.ktr_pid, 1);
542 	emul_changed = 1;
543 
544 	(void)printf("\"%s\"\n", name);
545 }
546 
547 void
548 ktrgenio(ktr, len)
549 	struct ktr_genio *ktr;
550 	int len;
551 {
552 	int datalen = len - sizeof (struct ktr_genio);
553 	char *dp = (char *)ktr + sizeof (struct ktr_genio);
554 	char *cp;
555 	int col = 0;
556 	int width;
557 	char visbuf[5];
558 	static int screenwidth = 0;
559 
560 	if (screenwidth == 0) {
561 		struct winsize ws;
562 
563 		if (!plain && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
564 		    ws.ws_col > 8)
565 			screenwidth = ws.ws_col;
566 		else
567 			screenwidth = 80;
568 	}
569 	printf("fd %d %s %d bytes\n", ktr->ktr_fd,
570 		ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen);
571 	if (maxdata == 0)
572 		return;
573 	if (maxdata > 0 && datalen > maxdata)
574 		datalen = maxdata;
575 	(void)printf("       \"");
576 	col = 8;
577 	for (; datalen > 0; datalen--, dp++) {
578 		(void) vis(visbuf, *dp, VIS_CSTYLE, datalen>1?*(dp+1):0);
579 		cp = visbuf;
580 		/*
581 		 * Keep track of printables and
582 		 * space chars (like fold(1)).
583 		 */
584 		if (col == 0) {
585 			(void)putchar('\t');
586 			col = 8;
587 		}
588 		switch(*cp) {
589 		case '\n':
590 			col = 0;
591 			(void)putchar('\n');
592 			continue;
593 		case '\t':
594 			width = 8 - (col&07);
595 			break;
596 		default:
597 			width = strlen(cp);
598 		}
599 		if (col + width > (screenwidth-2)) {
600 			(void)printf("\\\n\t");
601 			col = 8;
602 		}
603 		col += width;
604 		do {
605 			(void)putchar(*cp++);
606 		} while (*cp);
607 	}
608 	if (col == 0)
609 		(void)printf("       ");
610 	(void)printf("\"\n");
611 }
612 
613 void
614 ktrpsig(psig)
615 	struct ktr_psig *psig;
616 {
617 	int signo, first;
618 
619 	(void)printf("SIG%s ", signame(psig->signo, 0));
620 	if (psig->action == SIG_DFL)
621 		(void)printf("SIG_DFL\n");
622 	else {
623 		(void)printf("caught handler=0x%lx mask=(",
624 		    (u_long)psig->action);
625 		first = 1;
626 		for (signo = 1; signo < NSIG; signo++) {
627 			if (sigismember(&psig->mask, signo)) {
628 				if (first)
629 					first = 0;
630 				else
631 					(void)printf(",");
632 				(void)printf("%d", signo);
633 			}
634 		}
635 		(void)printf(") code=0x%x\n", psig->code);
636 	}
637 }
638 
639 void
640 ktrcsw(cs)
641 	struct ktr_csw *cs;
642 {
643 
644 	(void)printf("%s %s\n", cs->out ? "stop" : "resume",
645 	    cs->user ? "user" : "kernel");
646 }
647 
648 void
649 ktruser(usr, len)
650 	struct ktr_user *usr;
651 	int len;
652 {
653 	int i;
654 	unsigned char *dta;
655 
656 	printf("\"%.*s: %d, ", KTR_USER_MAXIDLEN, usr->ktr_id, len);
657 	dta = (unsigned char *)usr;
658 	for(i=sizeof(struct ktr_user); i < len; i++)
659 		printf("%02x", (unsigned int) dta[i]);
660 	printf("\"\n");
661 }
662 
663 void
664 ktrmmsg(mmsg, len)
665 	struct ktr_mmsg *mmsg;
666 	int len;
667 {
668 	int i,j;
669 	unsigned char *data;
670 	int row_len = 16;
671 	int aligned_len;
672 
673 	printf("id %d [0x%x -> 0x%x] %d bytes, flags 0x%x",
674 	    mmsg->ktr_id, mmsg->ktr_local_port,
675 	    mmsg->ktr_remote_port, mmsg->ktr_size, mmsg->ktr_bits);
676 
677 	data = (unsigned char *)mmsg;
678 	aligned_len = (len & ~(row_len - 1)) + row_len;
679 	for (i = 0; i < aligned_len; i += row_len) {
680 		printf("\n\t0x%04x  ", i);
681 
682 		for (j = 0; j < row_len; j += sizeof(int))
683 			if ((i + j) < len)
684 				printf("0x%08x ", *((int *)&data[i + j]));
685 			else
686 				printf("           ");
687 
688 		printf("  ");
689 
690 		for (j = 0; j < row_len; j++) {
691 			if ((i + j) < len) {
692 				if (isprint(data[i + j]))
693 					printf("%c", data[i + j]);
694 				else
695 					printf(".");
696 			} else {
697 				printf(" ");
698 			}
699 		}
700 	}
701 
702 	if (aligned_len != sizeof(struct ktr_mmsg))
703 		printf("\n");
704 }
705 
706 static const char *
707 signame(long sig, int xlat)
708 {
709 	static char buf[64];
710 	if (sig == 0)
711 		return " 0";
712 	else if (sig < 0 || sig >= NSIG) {
713 		(void)snprintf(buf, sizeof(buf), "*unknown %ld*", sig);
714 		return buf;
715 	} else
716 		return sys_signame[(xlat && current->signalmap != NULL) ?
717 		    current->signalmap[sig] : sig];
718 }
719 
720 void
721 usage()
722 {
723 
724 	(void)fprintf(stderr, "usage: kdump [-dlNnRT] [-e emulation] "
725 	   "[-f file] [-m maxdata] [-p pid]\n             [-t trstr] "
726 	   "[file]\n");
727 	exit(1);
728 }
729