xref: /dragonfly/usr.bin/kdump/kdump.c (revision 984263bc)
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   "$FreeBSD: src/usr.bin/kdump/kdump.c,v 1.17 1999/12/29 05:05:33 peter 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",	"PT_ATTACH",	"PT_DETACH",
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 < sizeof(ptrace_ops) /
275 				    sizeof(ptrace_ops[0]) && *ip >= 0)
276 					(void)printf("(%s", ptrace_ops[*ip]);
277 #ifdef PT_GETREGS
278 				else if (*ip == PT_GETREGS)
279 					(void)printf("(%s", "PT_GETREGS");
280 #endif
281 #ifdef PT_SETREGS
282 				else if (*ip == PT_SETREGS)
283 					(void)printf("(%s", "PT_SETREGS");
284 #endif
285 #ifdef PT_GETFPREGS
286 				else if (*ip == PT_GETFPREGS)
287 					(void)printf("(%s", "PT_GETFPREGS");
288 #endif
289 #ifdef PT_SETFPREGS
290 				else if (*ip == PT_SETFPREGS)
291 					(void)printf("(%s", "PT_SETFPREGS");
292 #endif
293 #ifdef PT_GETDBREGS
294 				else if (*ip == PT_GETDBREGS)
295 					(void)printf("(%s", "PT_GETDBREGS");
296 #endif
297 #ifdef PT_SETDBREGS
298 				else if (*ip == PT_SETDBREGS)
299 					(void)printf("(%s", "PT_SETDBREGS");
300 #endif
301 				else
302 					(void)printf("(%ld", (long)*ip);
303 				c = ',';
304 				ip++;
305 				narg--;
306 			}
307 		}
308 		while (narg) {
309 			if (decimal)
310 				(void)printf("%c%ld", c, (long)*ip);
311 			else
312 				(void)printf("%c%#lx", c, (long)*ip);
313 			c = ',';
314 			ip++;
315 			narg--;
316 		}
317 		(void)putchar(')');
318 	}
319 	(void)putchar('\n');
320 }
321 
322 ktrsysret(ktr)
323 	struct ktr_sysret *ktr;
324 {
325 	register register_t ret = ktr->ktr_retval;
326 	register int error = ktr->ktr_error;
327 	register int code = ktr->ktr_code;
328 
329 	if (code >= nsyscalls || code < 0)
330 		(void)printf("[%d] ", code);
331 	else
332 		(void)printf("%s ", syscallnames[code]);
333 
334 	if (error == 0) {
335 		if (fancy) {
336 			(void)printf("%d", ret);
337 			if (ret < 0 || ret > 9)
338 				(void)printf("/%#lx", (long)ret);
339 		} else {
340 			if (decimal)
341 				(void)printf("%ld", (long)ret);
342 			else
343 				(void)printf("%#lx", (long)ret);
344 		}
345 	} else if (error == ERESTART)
346 		(void)printf("RESTART");
347 	else if (error == EJUSTRETURN)
348 		(void)printf("JUSTRETURN");
349 	else {
350 		(void)printf("-1 errno %d", ktr->ktr_error);
351 		if (fancy)
352 			(void)printf(" %s", strerror(ktr->ktr_error));
353 	}
354 	(void)putchar('\n');
355 }
356 
357 ktrnamei(cp, len)
358 	char *cp;
359 {
360 	(void)printf("\"%.*s\"\n", len, cp);
361 }
362 
363 ktrgenio(ktr, len)
364 	struct ktr_genio *ktr;
365 {
366 	register int datalen = len - sizeof (struct ktr_genio);
367 	register char *dp = (char *)ktr + sizeof (struct ktr_genio);
368 	register char *cp;
369 	register int col = 0;
370 	register width;
371 	char visbuf[5];
372 	static screenwidth = 0;
373 
374 	if (screenwidth == 0) {
375 		struct winsize ws;
376 
377 		if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
378 		    ws.ws_col > 8)
379 			screenwidth = ws.ws_col;
380 		else
381 			screenwidth = 80;
382 	}
383 	printf("fd %d %s %d byte%s\n", ktr->ktr_fd,
384 		ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen,
385 		datalen == 1 ? "" : "s");
386 	if (maxdata && datalen > maxdata)
387 		datalen = maxdata;
388 	(void)printf("       \"");
389 	col = 8;
390 	for (;datalen > 0; datalen--, dp++) {
391 		(void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
392 		cp = visbuf;
393 		/*
394 		 * Keep track of printables and
395 		 * space chars (like fold(1)).
396 		 */
397 		if (col == 0) {
398 			(void)putchar('\t');
399 			col = 8;
400 		}
401 		switch(*cp) {
402 		case '\n':
403 			col = 0;
404 			(void)putchar('\n');
405 			continue;
406 		case '\t':
407 			width = 8 - (col&07);
408 			break;
409 		default:
410 			width = strlen(cp);
411 		}
412 		if (col + width > (screenwidth-2)) {
413 			(void)printf("\\\n\t");
414 			col = 8;
415 		}
416 		col += width;
417 		do {
418 			(void)putchar(*cp++);
419 		} while (*cp);
420 	}
421 	if (col == 0)
422 		(void)printf("       ");
423 	(void)printf("\"\n");
424 }
425 
426 char *signames[] = {
427 	"NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT",	/*  1 - 6  */
428 	"EMT", "FPE", "KILL", "BUS", "SEGV", "SYS",		/*  7 - 12 */
429 	"PIPE", "ALRM",  "TERM", "URG", "STOP", "TSTP",		/* 13 - 18 */
430 	"CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU",		/* 19 - 24 */
431 	"XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1",	/* 25 - 30 */
432 	"USR2", NULL,						/* 31 - 32 */
433 };
434 
435 ktrpsig(psig)
436 	struct ktr_psig *psig;
437 {
438 	(void)printf("SIG%s ", signames[psig->signo]);
439 	if (psig->action == SIG_DFL)
440 		(void)printf("SIG_DFL\n");
441 	else
442 		(void)printf("caught handler=0x%lx mask=0x%x code=0x%x\n",
443 		    (u_long)psig->action, psig->mask, psig->code);
444 }
445 
446 ktrcsw(cs)
447 	struct ktr_csw *cs;
448 {
449 	(void)printf("%s %s\n", cs->out ? "stop" : "resume",
450 		cs->user ? "user" : "kernel");
451 }
452 
453 ktruser(len, p)
454 	int len;
455 	unsigned char *p;
456 {
457 	(void)printf("%d ", len);
458 	while (len--)
459 		(void)printf(" %02x", *p++);
460 	(void)printf("\n");
461 
462 }
463 
464 usage()
465 {
466 	(void)fprintf(stderr,
467 	    "usage: kdump [-dnlRT] [-f trfile] [-m maxdata] [-t [cnisuw]]\n");
468 	exit(1);
469 }
470