xref: /dragonfly/usr.bin/kdump/kdump.c (revision 685c703c)
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  * @(#) Copyright (c) 1988, 1993 The Regents of the University of California.  All rights reserved.
34  * @(#)kdump.c	8.1 (Berkeley) 6/6/93
35  * $FreeBSD: src/usr.bin/kdump/kdump.c,v 1.17 1999/12/29 05:05:33 peter Exp $
36  * $DragonFly: src/usr.bin/kdump/kdump.c,v 1.7 2006/07/20 22:57:47 corecode Exp $
37  */
38 
39 #define _KERNEL_STRUCTURES
40 
41 #include <sys/errno.h>
42 #include <sys/param.h>
43 #include <sys/errno.h>
44 #include <sys/time.h>
45 #include <sys/uio.h>
46 #include <sys/ktrace.h>
47 #include <sys/ioctl.h>
48 #include <sys/ptrace.h>
49 #include <err.h>
50 #include <locale.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <unistd.h>
55 #include <vis.h>
56 #include "ktrace.h"
57 
58 int timestamp, decimal, fancy = 1, tail, maxdata = 64;
59 char *tracefile = DEF_TRACEFILE;
60 struct ktr_header ktr_header;
61 
62 #define eqs(s1, s2)	(strcmp((s1), (s2)) == 0)
63 
64 main(int argc, char **argv)
65 {
66 	int ch, col, ktrlen, size;
67 	pid_t do_pid = -1;
68 	register void *m;
69 	int trpoints = ALL_POINTS;
70 	char *cp;
71 
72 	(void) setlocale(LC_CTYPE, "");
73 
74 	while ((ch = getopt(argc,argv,"f:dlm:np:RTt:")) != -1)
75 		switch((char)ch) {
76 		case 'f':
77 			tracefile = optarg;
78 			break;
79 		case 'd':
80 			decimal = 1;
81 			break;
82 		case 'l':
83 			tail = 1;
84 			break;
85 		case 'm':
86 			maxdata = atoi(optarg);
87 			break;
88 		case 'n':
89 			fancy = 0;
90 			break;
91 		case 'p':
92 			do_pid = strtoul(optarg, &cp, 0);
93 			if (*cp != 0)
94 				errx(1,"invalid number %s", optarg);
95 			break;
96 		case 'R':
97 			timestamp = 2;	/* relative timestamp */
98 			break;
99 		case 'T':
100 			timestamp = 1;
101 			break;
102 		case 't':
103 			trpoints = getpoints(optarg);
104 			if (trpoints < 0)
105 				errx(1, "unknown trace point in %s", optarg);
106 			break;
107 		default:
108 			usage();
109 		}
110 
111 	if (argc > optind)
112 		usage();
113 
114 	m = (void *)malloc(size = 1025);
115 	if (m == NULL)
116 		errx(1, "%s", strerror(ENOMEM));
117 	if (!freopen(tracefile, "r", stdin))
118 		err(1, "%s", tracefile);
119 	while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) {
120 		if (trpoints & (1 << ktr_header.ktr_type) &&
121 		    (do_pid == -1 || ktr_header.ktr_pid == do_pid))
122 			col = dumpheader(&ktr_header);
123 		else
124 			col = -1;
125 		if ((ktrlen = ktr_header.ktr_len) < 0)
126 			errx(1, "bogus length 0x%x", ktrlen);
127 		if (ktrlen > size) {
128 			m = (void *)realloc(m, ktrlen+1);
129 			if (m == NULL)
130 				errx(1, "%s", strerror(ENOMEM));
131 			size = ktrlen;
132 		}
133 		if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
134 			errx(1, "data too short");
135 		if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
136 			continue;
137 		if (col == -1)
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(char *buf, int size, int num)
168 {
169 	int i;
170 
171 	while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
172 		(void)sleep(1);
173 		clearerr(stdin);
174 	}
175 	return (i);
176 }
177 
178 dumpheader(struct ktr_header *kth)
179 {
180 	static char unknown[64];
181 	static struct timeval prevtime, temp;
182 	char *type;
183 	int col;
184 
185 	switch (kth->ktr_type) {
186 	case KTR_SYSCALL:
187 		type = "CALL";
188 		break;
189 	case KTR_SYSRET:
190 		type = "RET ";
191 		break;
192 	case KTR_NAMEI:
193 		type = "NAMI";
194 		break;
195 	case KTR_GENIO:
196 		type = "GIO ";
197 		break;
198 	case KTR_PSIG:
199 		type = "PSIG";
200 		break;
201 	case KTR_CSW:
202 		type = "CSW";
203 		break;
204 	case KTR_USER:
205 		type = "USER";
206 		break;
207 	default:
208 		(void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type);
209 		type = unknown;
210 	}
211 
212 	col = printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN, kth->ktr_comm);
213 	if (timestamp) {
214 		if (timestamp == 2) {
215 			temp = kth->ktr_time;
216 			timevalsub(&kth->ktr_time, &prevtime);
217 			prevtime = temp;
218 		}
219 		col += printf("%ld.%06ld ",
220 		    kth->ktr_time.tv_sec, kth->ktr_time.tv_usec);
221 	}
222 	col += printf("%s  ", type);
223 	return col;
224 }
225 
226 #include <sys/syscall.h>
227 #define KTRACE
228 #include <sys/kern/syscalls.c>
229 #undef KTRACE
230 int nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]);
231 
232 static char *ptrace_ops[] = {
233 	"PT_TRACE_ME",	"PT_READ_I",	"PT_READ_D",	"PT_READ_U",
234 	"PT_WRITE_I",	"PT_WRITE_D",	"PT_WRITE_U",	"PT_CONTINUE",
235 	"PT_KILL",	"PT_STEP",	"PT_ATTACH",	"PT_DETACH",
236 };
237 
238 ktrsyscall(register struct ktr_syscall *ktr)
239 {
240 	register narg = ktr->ktr_narg;
241 	register register_t *ip;
242 	char *ioctlname();
243 
244 	if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0)
245 		(void)printf("[%d]", ktr->ktr_code);
246 	else
247 		(void)printf("%s", syscallnames[ktr->ktr_code]);
248 	ip = &ktr->ktr_args[0];
249 	if (narg) {
250 		char c = '(';
251 		if (fancy) {
252 			if (ktr->ktr_code == SYS_ioctl) {
253 				char *cp;
254 				if (decimal)
255 					(void)printf("(%ld", (long)*ip);
256 				else
257 					(void)printf("(%#lx", (long)*ip);
258 				ip++;
259 				narg--;
260 				if ((cp = ioctlname(*ip)) != NULL)
261 					(void)printf(",%s", cp);
262 				else {
263 					if (decimal)
264 						(void)printf(",%ld", (long)*ip);
265 					else
266 						(void)printf(",%#lx ", (long)*ip);
267 				}
268 				c = ',';
269 				ip++;
270 				narg--;
271 			} else if (ktr->ktr_code == SYS_ptrace) {
272 				if (*ip < sizeof(ptrace_ops) /
273 				    sizeof(ptrace_ops[0]) && *ip >= 0)
274 					(void)printf("(%s", ptrace_ops[*ip]);
275 #ifdef PT_GETREGS
276 				else if (*ip == PT_GETREGS)
277 					(void)printf("(%s", "PT_GETREGS");
278 #endif
279 #ifdef PT_SETREGS
280 				else if (*ip == PT_SETREGS)
281 					(void)printf("(%s", "PT_SETREGS");
282 #endif
283 #ifdef PT_GETFPREGS
284 				else if (*ip == PT_GETFPREGS)
285 					(void)printf("(%s", "PT_GETFPREGS");
286 #endif
287 #ifdef PT_SETFPREGS
288 				else if (*ip == PT_SETFPREGS)
289 					(void)printf("(%s", "PT_SETFPREGS");
290 #endif
291 #ifdef PT_GETDBREGS
292 				else if (*ip == PT_GETDBREGS)
293 					(void)printf("(%s", "PT_GETDBREGS");
294 #endif
295 #ifdef PT_SETDBREGS
296 				else if (*ip == PT_SETDBREGS)
297 					(void)printf("(%s", "PT_SETDBREGS");
298 #endif
299 				else
300 					(void)printf("(%ld", (long)*ip);
301 				c = ',';
302 				ip++;
303 				narg--;
304 			}
305 		}
306 		while (narg) {
307 			if (decimal)
308 				(void)printf("%c%ld", c, (long)*ip);
309 			else
310 				(void)printf("%c%#lx", c, (long)*ip);
311 			c = ',';
312 			ip++;
313 			narg--;
314 		}
315 		(void)putchar(')');
316 	}
317 	(void)putchar('\n');
318 }
319 
320 ktrsysret(struct ktr_sysret *ktr)
321 {
322 	register register_t ret = ktr->ktr_retval;
323 	register int error = ktr->ktr_error;
324 	register int code = ktr->ktr_code;
325 
326 	if (code >= nsyscalls || code < 0)
327 		(void)printf("[%d] ", code);
328 	else
329 		(void)printf("%s ", syscallnames[code]);
330 
331 	if (error == 0) {
332 		if (fancy) {
333 			(void)printf("%d", ret);
334 			if (ret < 0 || ret > 9)
335 				(void)printf("/%#lx", (long)ret);
336 		} else {
337 			if (decimal)
338 				(void)printf("%ld", (long)ret);
339 			else
340 				(void)printf("%#lx", (long)ret);
341 		}
342 	} else if (error == ERESTART)
343 		(void)printf("RESTART");
344 	else if (error == EJUSTRETURN)
345 		(void)printf("JUSTRETURN");
346 	else {
347 		(void)printf("-1 errno %d", ktr->ktr_error);
348 		if (fancy)
349 			(void)printf(" %s", strerror(ktr->ktr_error));
350 	}
351 	(void)putchar('\n');
352 }
353 
354 ktrnamei(char *cp, int len)
355 {
356 	(void)printf("\"%.*s\"\n", len, cp);
357 }
358 
359 ktrgenio(struct ktr_genio *ktr, int len)
360 {
361 	register int datalen = len - sizeof (struct ktr_genio);
362 	register char *dp = (char *)ktr + sizeof (struct ktr_genio);
363 	register char *cp;
364 	register int col = 0;
365 	register width;
366 	char visbuf[5];
367 	static screenwidth = 0;
368 
369 	if (screenwidth == 0) {
370 		struct winsize ws;
371 
372 		if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
373 		    ws.ws_col > 8)
374 			screenwidth = ws.ws_col;
375 		else
376 			screenwidth = 80;
377 	}
378 	printf("fd %d %s %d byte%s\n", ktr->ktr_fd,
379 		ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen,
380 		datalen == 1 ? "" : "s");
381 	if (maxdata && datalen > maxdata)
382 		datalen = maxdata;
383 	(void)printf("       \"");
384 	col = 8;
385 	for (;datalen > 0; datalen--, dp++) {
386 		(void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
387 		cp = visbuf;
388 		/*
389 		 * Keep track of printables and
390 		 * space chars (like fold(1)).
391 		 */
392 		if (col == 0) {
393 			(void)putchar('\t');
394 			col = 8;
395 		}
396 		switch(*cp) {
397 		case '\n':
398 			col = 0;
399 			(void)putchar('\n');
400 			continue;
401 		case '\t':
402 			width = 8 - (col&07);
403 			break;
404 		default:
405 			width = strlen(cp);
406 		}
407 		if (col + width > (screenwidth-2)) {
408 			(void)printf("\\\n\t");
409 			col = 8;
410 		}
411 		col += width;
412 		do {
413 			(void)putchar(*cp++);
414 		} while (*cp);
415 	}
416 	if (col == 0)
417 		(void)printf("       ");
418 	(void)printf("\"\n");
419 }
420 
421 char *signames[] = {
422 	"NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT",	/*  1 - 6  */
423 	"EMT", "FPE", "KILL", "BUS", "SEGV", "SYS",		/*  7 - 12 */
424 	"PIPE", "ALRM",  "TERM", "URG", "STOP", "TSTP",		/* 13 - 18 */
425 	"CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU",		/* 19 - 24 */
426 	"XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1",	/* 25 - 30 */
427 	"USR2", NULL,						/* 31 - 32 */
428 };
429 
430 ktrpsig(struct ktr_psig *psig)
431 {
432 	(void)printf("SIG%s ", signames[psig->signo]);
433 	if (psig->action == SIG_DFL)
434 		(void)printf("SIG_DFL\n");
435 	else
436 		(void)printf("caught handler=0x%lx mask=0x%x code=0x%x\n",
437 		    (u_long)psig->action, psig->mask, psig->code);
438 }
439 
440 ktrcsw(struct ktr_csw *cs)
441 {
442 	(void)printf("%s %s\n", cs->out ? "stop" : "resume",
443 		cs->user ? "user" : "kernel");
444 }
445 
446 ktruser(int len, unsigned char *p)
447 {
448 	(void)printf("%d ", len);
449 	while (len--)
450 		(void)printf(" %02x", *p++);
451 	(void)printf("\n");
452 
453 }
454 
455 usage(void)
456 {
457 	(void)fprintf(stderr,
458 	    "usage: kdump [-dnlRT] [-f trfile] [-m maxdata] [-t [cnisuw]] [-p pid]\n");
459 	exit(1);
460 }
461 
462 timevalsub(struct timeval *t1, struct timeval *t2)
463 {
464 	t1->tv_sec -= t2->tv_sec;
465 	t1->tv_usec -= t2->tv_usec;
466 	timevalfix(t1);
467 }
468 
469 timevalfix(struct timeval *t1)
470 {
471 	if (t1->tv_usec < 0) {
472 		t1->tv_sec--;
473 		t1->tv_usec += 1000000;
474 	}
475 	if (t1->tv_usec >= 1000000) {
476 		t1->tv_sec++;
477 		t1->tv_usec -= 1000000;
478 	}
479 }
480