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