xref: /openbsd-src/usr.bin/kdump/kdump.c (revision 43003dfe3ad45d1698bed8a37f2b0f5b14f20d4f)
1 /*	$OpenBSD: kdump.c,v 1.39 2007/05/29 02:01:03 deraadt 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. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #ifndef lint
33 static const char copyright[] =
34 "@(#) Copyright (c) 1988, 1993\n\
35 	The Regents of the University of California.  All rights reserved.\n";
36 #endif /* not lint */
37 
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)kdump.c	8.4 (Berkeley) 4/28/95";
41 #endif
42 static const char rcsid[] = "$OpenBSD: kdump.c,v 1.39 2007/05/29 02:01:03 deraadt Exp $";
43 #endif /* not lint */
44 
45 #include <sys/param.h>
46 #include <sys/time.h>
47 #include <sys/uio.h>
48 #include <sys/ktrace.h>
49 #include <sys/ioctl.h>
50 #include <sys/ptrace.h>
51 #include <sys/sysctl.h>
52 #define _KERNEL
53 #include <sys/errno.h>
54 #undef _KERNEL
55 
56 #include <ctype.h>
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 #include "kdump.h"
67 #include "extern.h"
68 
69 int timestamp, decimal, iohex, fancy = 1, tail, maxdata;
70 char *tracefile = DEF_TRACEFILE;
71 struct ktr_header ktr_header;
72 pid_t pid = -1;
73 
74 #define eqs(s1, s2)	(strcmp((s1), (s2)) == 0)
75 
76 #include <sys/syscall.h>
77 
78 #include <compat/bsdos/bsdos_syscall.h>
79 #include <compat/freebsd/freebsd_syscall.h>
80 #if defined(__hppa__) || defined(__m68k__)
81 #include <compat/hpux/hpux_syscall.h>
82 #endif
83 #include <compat/ibcs2/ibcs2_syscall.h>
84 #include <compat/linux/linux_syscall.h>
85 #include <compat/osf1/osf1_syscall.h>
86 #include <compat/sunos/sunos_syscall.h>
87 #include <compat/svr4/svr4_syscall.h>
88 #include <compat/ultrix/ultrix_syscall.h>
89 
90 #define KTRACE
91 #define PTRACE
92 #define NFSCLIENT
93 #define NFSSERVER
94 #define SYSVSEM
95 #define SYSVMSG
96 #define SYSVSHM
97 #define LFS
98 #define RTHREADS
99 #include <kern/syscalls.c>
100 
101 #include <compat/bsdos/bsdos_syscalls.c>
102 #include <compat/freebsd/freebsd_syscalls.c>
103 #if defined(__hppa__) || defined(__m68k__)
104 #include <compat/hpux/hpux_syscalls.c>
105 #endif
106 #include <compat/ibcs2/ibcs2_syscalls.c>
107 #include <compat/linux/linux_syscalls.c>
108 #include <compat/osf1/osf1_syscalls.c>
109 #include <compat/sunos/sunos_syscalls.c>
110 #include <compat/svr4/svr4_syscalls.c>
111 #include <compat/ultrix/ultrix_syscalls.c>
112 #undef KTRACE
113 #undef PTRACE
114 #undef NFSCLIENT
115 #undef NFSSERVER
116 #undef SYSVSEM
117 #undef SYSVMSG
118 #undef SYSVSHM
119 #undef LFS
120 #undef RTHREADS
121 
122 struct emulation {
123 	char *name;		/* Emulation name */
124 	char **sysnames;	/* Array of system call names */
125 	int  nsysnames;		/* Number of */
126 };
127 
128 static struct emulation emulations[] = {
129 	{ "native",	syscallnames,		SYS_MAXSYSCALL },
130 #if defined(__hppa__) || defined(__m68k__)
131 	{ "hpux",	hpux_syscallnames,	HPUX_SYS_MAXSYSCALL },
132 #endif
133 	{ "ibcs2",	ibcs2_syscallnames,	IBCS2_SYS_MAXSYSCALL },
134 	{ "linux",	linux_syscallnames,	LINUX_SYS_MAXSYSCALL },
135 	{ "osf1",	osf1_syscallnames,	OSF1_SYS_MAXSYSCALL },
136 	{ "sunos",	sunos_syscallnames,	SUNOS_SYS_MAXSYSCALL },
137 	{ "svr4",	svr4_syscallnames,	SVR4_SYS_MAXSYSCALL },
138 	{ "ultrix",	ultrix_syscallnames,	ULTRIX_SYS_MAXSYSCALL },
139 	{ "bsdos",	bsdos_syscallnames,	BSDOS_SYS_MAXSYSCALL },
140 	{ "freebsd",	freebsd_syscallnames,	FREEBSD_SYS_MAXSYSCALL },
141 	{ NULL,		NULL,			NULL }
142 };
143 
144 struct emulation *current;
145 
146 
147 static char *ptrace_ops[] = {
148 	"PT_TRACE_ME",	"PT_READ_I",	"PT_READ_D",	"PT_READ_U",
149 	"PT_WRITE_I",	"PT_WRITE_D",	"PT_WRITE_U",	"PT_CONTINUE",
150 	"PT_KILL",	"PT_ATTACH",	"PT_DETACH",	"PT_IO",
151 };
152 
153 static int fread_tail(void *, size_t, size_t);
154 static void dumpheader(struct ktr_header *);
155 static void ktrcsw(struct ktr_csw *);
156 static void ktremul(char *, size_t);
157 static void ktrgenio(struct ktr_genio *, size_t);
158 static void ktrnamei(const char *, size_t);
159 static void ktrpsig(struct ktr_psig *);
160 static void ktrsyscall(struct ktr_syscall *);
161 static void ktrsysret(struct ktr_sysret *);
162 static void setemul(const char *);
163 static void usage(void);
164 
165 int
166 main(int argc, char *argv[])
167 {
168 	int ch, silent;
169 	size_t ktrlen, size;
170 	int trpoints = ALL_POINTS;
171 	void *m;
172 
173 	current = &emulations[0];	/* native */
174 
175 	while ((ch = getopt(argc, argv, "e:f:dlm:nRp:Tt:xX")) != -1)
176 		switch (ch) {
177 		case 'e':
178 			setemul(optarg);
179 			break;
180 		case 'f':
181 			tracefile = optarg;
182 			break;
183 		case 'd':
184 			decimal = 1;
185 			break;
186 		case 'l':
187 			tail = 1;
188 			break;
189 		case 'm':
190 			maxdata = atoi(optarg);
191 			break;
192 		case 'n':
193 			fancy = 0;
194 			break;
195 		case 'p':
196 			pid = atoi(optarg);
197 			break;
198 		case 'R':
199 			timestamp = 2;	/* relative timestamp */
200 			break;
201 		case 'T':
202 			timestamp = 1;
203 			break;
204 		case 't':
205 			trpoints = getpoints(optarg);
206 			if (trpoints < 0)
207 				errx(1, "unknown trace point in %s", optarg);
208 			break;
209 		case 'x':
210 			iohex = 1;
211 			break;
212 		case 'X':
213 			iohex = 2;
214 			break;
215 		default:
216 			usage();
217 		}
218 	if (argc > optind)
219 		usage();
220 
221 	m = malloc(size = 1025);
222 	if (m == NULL)
223 		err(1, NULL);
224 	if (!freopen(tracefile, "r", stdin))
225 		err(1, "%s", tracefile);
226 	while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) {
227 		silent = 0;
228 		if (pid != -1 && pid != ktr_header.ktr_pid)
229 			silent = 1;
230 		if (silent == 0 && trpoints & (1<<ktr_header.ktr_type))
231 			dumpheader(&ktr_header);
232 		ktrlen = ktr_header.ktr_len;
233 		if (ktrlen > size) {
234 			void *newm;
235 
236 			newm = realloc(m, ktrlen+1);
237 			if (newm == NULL)
238 				err(1, NULL);
239 			m = newm;
240 			size = ktrlen;
241 		}
242 		if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
243 			errx(1, "data too short");
244 		if (silent)
245 			continue;
246 		if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
247 			continue;
248 		switch (ktr_header.ktr_type) {
249 		case KTR_SYSCALL:
250 			ktrsyscall((struct ktr_syscall *)m);
251 			break;
252 		case KTR_SYSRET:
253 			ktrsysret((struct ktr_sysret *)m);
254 			break;
255 		case KTR_NAMEI:
256 			ktrnamei(m, ktrlen);
257 			break;
258 		case KTR_GENIO:
259 			ktrgenio((struct ktr_genio *)m, ktrlen);
260 			break;
261 		case KTR_PSIG:
262 			ktrpsig((struct ktr_psig *)m);
263 			break;
264 		case KTR_CSW:
265 			ktrcsw((struct ktr_csw *)m);
266 			break;
267 		case KTR_EMUL:
268 			ktremul(m, ktrlen);
269 			break;
270 		}
271 		if (tail)
272 			(void)fflush(stdout);
273 	}
274 	exit(0);
275 }
276 
277 static int
278 fread_tail(void *buf, size_t size, size_t num)
279 {
280 	int i;
281 
282 	while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
283 		(void)sleep(1);
284 		clearerr(stdin);
285 	}
286 	return (i);
287 }
288 
289 static void
290 dumpheader(struct ktr_header *kth)
291 {
292 	static struct timeval prevtime;
293 	char unknown[64], *type;
294 	struct timeval temp;
295 
296 	switch (kth->ktr_type) {
297 	case KTR_SYSCALL:
298 		type = "CALL";
299 		break;
300 	case KTR_SYSRET:
301 		type = "RET ";
302 		break;
303 	case KTR_NAMEI:
304 		type = "NAMI";
305 		break;
306 	case KTR_GENIO:
307 		type = "GIO ";
308 		break;
309 	case KTR_PSIG:
310 		type = "PSIG";
311 		break;
312 	case KTR_CSW:
313 		type = "CSW";
314 		break;
315 	case KTR_EMUL:
316 		type = "EMUL";
317 		break;
318 	default:
319 		(void)snprintf(unknown, sizeof unknown, "UNKNOWN(%d)",
320 		    kth->ktr_type);
321 		type = unknown;
322 	}
323 
324 	(void)printf("%6ld %-8.*s ", (long)kth->ktr_pid, MAXCOMLEN,
325 	    kth->ktr_comm);
326 	if (timestamp) {
327 		if (timestamp == 2) {
328 			timersub(&kth->ktr_time, &prevtime, &temp);
329 			prevtime = kth->ktr_time;
330 		} else
331 			temp = kth->ktr_time;
332 		(void)printf("%ld.%06ld ", temp.tv_sec, temp.tv_usec);
333 	}
334 	(void)printf("%s  ", type);
335 }
336 
337 static void
338 ioctldecode(u_long cmd)
339 {
340 	char dirbuf[4], *dir = dirbuf;
341 
342 	if (cmd & IOC_IN)
343 		*dir++ = 'W';
344 	if (cmd & IOC_OUT)
345 		*dir++ = 'R';
346 	*dir = '\0';
347 
348 	printf(decimal ? ",_IO%s('%c',%lu" : ",_IO%s('%c',%#lx",
349 	    dirbuf, (int)((cmd >> 8) & 0xff), cmd & 0xff);
350 	if ((cmd & IOC_VOID) == 0)
351 		printf(decimal ? ",%lu)" : ",%#lx)", (cmd >> 16) & 0xff);
352 	else
353 		printf(")");
354 }
355 
356 static void
357 ktrsyscall(struct ktr_syscall *ktr)
358 {
359 	int argsize = ktr->ktr_argsize;
360 	register_t *ap;
361 
362 	if (ktr->ktr_code >= current->nsysnames || ktr->ktr_code < 0)
363 		(void)printf("[%d]", ktr->ktr_code);
364 	else
365 		(void)printf("%s", current->sysnames[ktr->ktr_code]);
366 	ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall));
367 	(void)putchar('(');
368 	if (argsize) {
369 		char c = '\0';
370 		if (fancy) {
371 			if (ktr->ktr_code == SYS_ioctl) {
372 				const char *cp;
373 
374 				if (decimal)
375 					(void)printf("%ld", (long)*ap);
376 				else
377 					(void)printf("%#lx", (long)*ap);
378 				ap++;
379 				argsize -= sizeof(register_t);
380 				if ((cp = ioctlname(*ap)) != NULL)
381 					(void)printf(",%s", cp);
382 				else
383 					ioctldecode(*ap);
384 				c = ',';
385 				ap++;
386 				argsize -= sizeof(register_t);
387 			} else if (ktr->ktr_code == SYS___sysctl) {
388 				int *np, n;
389 
390 				n = ap[1];
391 				if (n > CTL_MAXNAME)
392 					n = CTL_MAXNAME;
393 				np = (int *)(ap + 6);
394 				for (; n--; np++) {
395 					if (c)
396 						putchar(c);
397 					printf("%d", *np);
398 					c = '.';
399 				}
400 
401 				c = ',';
402 				ap += 2;
403 				argsize -= 2 * sizeof(register_t);
404 			} else if (ktr->ktr_code == SYS_ptrace) {
405 				if (*ap >= 0 && *ap <
406 				    sizeof(ptrace_ops) / sizeof(ptrace_ops[0]))
407 					(void)printf("%s", ptrace_ops[*ap]);
408 				else switch(*ap) {
409 #ifdef PT_GETFPREGS
410 				case PT_GETFPREGS:
411 					(void)printf("PT_GETFPREGS");
412 					break;
413 #endif
414 				case PT_GETREGS:
415 					(void)printf("PT_GETREGS");
416 					break;
417 #ifdef PT_SETFPREGS
418 				case PT_SETFPREGS:
419 					(void)printf("PT_SETFPREGS");
420 					break;
421 #endif
422 				case PT_SETREGS:
423 					(void)printf("PT_SETREGS");
424 					break;
425 #ifdef PT_STEP
426 				case PT_STEP:
427 					(void)printf("PT_STEP");
428 					break;
429 #endif
430 #ifdef PT_WCOOKIE
431 				case PT_WCOOKIE:
432 					(void)printf("PT_WCOOKIE");
433 					break;
434 #endif
435 				default:
436 					(void)printf("%ld", (long)*ap);
437 					break;
438 				}
439 				c = ',';
440 				ap++;
441 				argsize -= sizeof(register_t);
442 			}
443 		}
444 		while (argsize) {
445 			if (c)
446 				putchar(c);
447 			if (decimal)
448 				(void)printf("%ld", (long)*ap);
449 			else
450 				(void)printf("%#lx", (long)*ap);
451 			c = ',';
452 			ap++;
453 			argsize -= sizeof(register_t);
454 		}
455 	}
456 	(void)printf(")\n");
457 }
458 
459 static void
460 ktrsysret(struct ktr_sysret *ktr)
461 {
462 	int ret = ktr->ktr_retval;
463 	int error = ktr->ktr_error;
464 	int code = ktr->ktr_code;
465 
466 	if (code >= current->nsysnames || code < 0)
467 		(void)printf("[%d] ", code);
468 	else
469 		(void)printf("%s ", current->sysnames[code]);
470 
471 	if (error == 0) {
472 		if (fancy) {
473 			(void)printf("%d", ret);
474 			if (ret < 0 || ret > 9)
475 				(void)printf("/%#x", ret);
476 		} else {
477 			if (decimal)
478 				(void)printf("%d", ret);
479 			else
480 				(void)printf("%#x", ret);
481 		}
482 	} else if (error == ERESTART)
483 		(void)printf("RESTART");
484 	else if (error == EJUSTRETURN)
485 		(void)printf("JUSTRETURN");
486 	else {
487 		(void)printf("-1 errno %d", ktr->ktr_error);
488 		if (fancy)
489 			(void)printf(" %s", strerror(ktr->ktr_error));
490 	}
491 	(void)putchar('\n');
492 }
493 
494 static void
495 ktrnamei(const char *cp, size_t len)
496 {
497 	(void)printf("\"%.*s\"\n", (int)len, cp);
498 }
499 
500 static void
501 ktremul(char *cp, size_t len)
502 {
503 	char name[1024];
504 
505 	if (len >= sizeof(name))
506 		errx(1, "Emulation name too long");
507 
508 	strncpy(name, cp, len);
509 	name[len] = '\0';
510 	(void)printf("\"%s\"\n", name);
511 
512 	setemul(name);
513 }
514 
515 static void
516 ktrgenio(struct ktr_genio *ktr, size_t len)
517 {
518 	unsigned char *dp = (unsigned char *)ktr + sizeof(struct ktr_genio);
519 	int i, j;
520 	size_t datalen = len - sizeof(struct ktr_genio);
521 	static int screenwidth = 0;
522 	int col = 0, width, bpl;
523 	unsigned char visbuf[5], *cp, c;
524 
525 	if (screenwidth == 0) {
526 		struct winsize ws;
527 
528 		if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
529 		    ws.ws_col > 8)
530 			screenwidth = ws.ws_col;
531 		else
532 			screenwidth = 80;
533 	}
534 	printf("fd %d %s %zu bytes\n", ktr->ktr_fd,
535 		ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen);
536 	if (maxdata && datalen > maxdata)
537 		datalen = maxdata;
538 	if (iohex && !datalen)
539 		return;
540 	if (iohex == 1) {
541 		putchar('\t');
542 		col = 8;
543 		for (i = 0; i < datalen; i++) {
544 			printf("%02x", dp[i]);
545 			col += 3;
546 			if (i < datalen - 1) {
547 				if (col + 3 > screenwidth) {
548 					printf("\n\t");
549 					col = 8;
550 				} else
551 					putchar(' ');
552 			}
553 		}
554 		putchar('\n');
555 		return;
556 	}
557 	if (iohex == 2) {
558 		bpl = (screenwidth - 13)/4;
559 		if (bpl <= 0)
560 			bpl = 1;
561 		for (i = 0; i < datalen; i += bpl) {
562 			printf("   %04x:  ", i);
563 			for (j = 0; j < bpl; j++) {
564 				if (i+j >= datalen)
565 					printf("   ");
566 				else
567 					printf("%02x ", dp[i+j]);
568 			}
569 			putchar(' ');
570 			for (j = 0; j < bpl; j++) {
571 				if (i+j >= datalen)
572 					break;
573 				c = dp[i+j];
574 				if (!isprint(c))
575 					c = '.';
576 				putchar(c);
577 			}
578 			putchar('\n');
579 		}
580 		return;
581 	}
582 	(void)printf("       \"");
583 	col = 8;
584 	for (; datalen > 0; datalen--, dp++) {
585 		(void)vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
586 		cp = visbuf;
587 
588 		/*
589 		 * Keep track of printables and
590 		 * space chars (like fold(1)).
591 		 */
592 		if (col == 0) {
593 			(void)putchar('\t');
594 			col = 8;
595 		}
596 		switch (*cp) {
597 		case '\n':
598 			col = 0;
599 			(void)putchar('\n');
600 			continue;
601 		case '\t':
602 			width = 8 - (col&07);
603 			break;
604 		default:
605 			width = strlen(cp);
606 		}
607 		if (col + width > (screenwidth-2)) {
608 			(void)printf("\\\n\t");
609 			col = 8;
610 		}
611 		col += width;
612 		do {
613 			(void)putchar(*cp++);
614 		} while (*cp);
615 	}
616 	if (col == 0)
617 		(void)printf("       ");
618 	(void)printf("\"\n");
619 }
620 
621 static void
622 ktrpsig(struct ktr_psig *psig)
623 {
624 	(void)printf("SIG%s ", sys_signame[psig->signo]);
625 	if (psig->action == SIG_DFL)
626 		(void)printf("SIG_DFL code %d", psig->code);
627 	else
628 		(void)printf("caught handler=0x%lx mask=0x%x",
629 		    (u_long)psig->action, psig->mask);
630 	switch (psig->signo) {
631 	case SIGSEGV:
632 	case SIGILL:
633 	case SIGBUS:
634 	case SIGFPE:
635 		printf(" addr=%p trapno=%d", psig->si.si_addr,
636 		    psig->si.si_trapno);
637 		break;
638 	default:
639 		break;
640 	}
641 	printf("\n");
642 }
643 
644 static void
645 ktrcsw(struct ktr_csw *cs)
646 {
647 	(void)printf("%s %s\n", cs->out ? "stop" : "resume",
648 	    cs->user ? "user" : "kernel");
649 }
650 
651 static void
652 usage(void)
653 {
654 
655 	extern char *__progname;
656 	fprintf(stderr, "usage: %s "
657 	    "[-dlnRTXx] [-e emulation] [-p pid] [-f trfile] [-m maxdata] "
658 	    "[-t [ceinsw]]\n", __progname);
659 	exit(1);
660 }
661 
662 static void
663 setemul(const char *name)
664 {
665 	int i;
666 
667 	for (i = 0; emulations[i].name != NULL; i++)
668 		if (strcmp(emulations[i].name, name) == 0) {
669 			current = &emulations[i];
670 			return;
671 		}
672 	warnx("Emulation `%s' unknown", name);
673 }
674