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