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