xref: /original-bsd/usr.bin/kdump/kdump.c (revision c3e32dec)
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.1 (Berkeley) 06/06/93";
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 narg = ktr->ktr_narg;
222 	register int *ip;
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 	ip = (int *)((char *)ktr + sizeof(struct ktr_syscall));
230 	if (narg) {
231 		char c = '(';
232 		if (fancy) {
233 			if (ktr->ktr_code == SYS_ioctl) {
234 				char *cp;
235 				if (decimal)
236 					(void)printf("(%d", *ip);
237 				else
238 					(void)printf("(%#x", *ip);
239 				ip++;
240 				narg--;
241 				if ((cp = ioctlname(*ip)) != NULL)
242 					(void)printf(",%s", cp);
243 				else {
244 					if (decimal)
245 						(void)printf(",%d", *ip);
246 					else
247 						(void)printf(",%#x ", *ip);
248 				}
249 				c = ',';
250 				ip++;
251 				narg--;
252 			} else if (ktr->ktr_code == SYS_ptrace) {
253 				if (*ip <= PT_STEP && *ip >= 0)
254 					(void)printf("(%s", ptrace_ops[*ip]);
255 				else
256 					(void)printf("(%d", *ip);
257 				c = ',';
258 				ip++;
259 				narg--;
260 			}
261 		}
262 		while (narg) {
263 			if (decimal)
264 				(void)printf("%c%d", c, *ip);
265 			else
266 				(void)printf("%c%#x", c, *ip);
267 			c = ',';
268 			ip++;
269 			narg--;
270 		}
271 		(void)putchar(')');
272 	}
273 	(void)putchar('\n');
274 }
275 
276 ktrsysret(ktr)
277 	struct ktr_sysret *ktr;
278 {
279 	register int ret = ktr->ktr_retval;
280 	register int error = ktr->ktr_error;
281 	register int code = ktr->ktr_code;
282 
283 	if (code >= nsyscalls || code < 0)
284 		(void)printf("[%d] ", code);
285 	else
286 		(void)printf("%s ", syscallnames[code]);
287 
288 	if (error == 0) {
289 		if (fancy) {
290 			(void)printf("%d", ret);
291 			if (ret < 0 || ret > 9)
292 				(void)printf("/%#x", ret);
293 		} else {
294 			if (decimal)
295 				(void)printf("%d", ret);
296 			else
297 				(void)printf("%#x", ret);
298 		}
299 	} else if (error == ERESTART)
300 		(void)printf("RESTART");
301 	else if (error == EJUSTRETURN)
302 		(void)printf("JUSTRETURN");
303 	else {
304 		(void)printf("-1 errno %d", ktr->ktr_error);
305 		if (fancy)
306 			(void)printf(" %s", strerror(ktr->ktr_error));
307 	}
308 	(void)putchar('\n');
309 }
310 
311 ktrnamei(cp, len)
312 	char *cp;
313 {
314 	(void)printf("\"%.*s\"\n", len, cp);
315 }
316 
317 ktrgenio(ktr, len)
318 	struct ktr_genio *ktr;
319 {
320 	register int datalen = len - sizeof (struct ktr_genio);
321 	register char *dp = (char *)ktr + sizeof (struct ktr_genio);
322 	register char *cp;
323 	register int col = 0;
324 	register width;
325 	char visbuf[5];
326 	static screenwidth = 0;
327 
328 	if (screenwidth == 0) {
329 		struct winsize ws;
330 
331 		if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
332 		    ws.ws_col > 8)
333 			screenwidth = ws.ws_col;
334 		else
335 			screenwidth = 80;
336 	}
337 	printf("fd %d %s %d bytes\n", ktr->ktr_fd,
338 		ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen);
339 	if (maxdata && datalen > maxdata)
340 		datalen = maxdata;
341 	(void)printf("       \"");
342 	col = 8;
343 	for (;datalen > 0; datalen--, dp++) {
344 		(void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
345 		cp = visbuf;
346 		/*
347 		 * Keep track of printables and
348 		 * space chars (like fold(1)).
349 		 */
350 		if (col == 0) {
351 			(void)putchar('\t');
352 			col = 8;
353 		}
354 		switch(*cp) {
355 		case '\n':
356 			col = 0;
357 			(void)putchar('\n');
358 			continue;
359 		case '\t':
360 			width = 8 - (col&07);
361 			break;
362 		default:
363 			width = strlen(cp);
364 		}
365 		if (col + width > (screenwidth-2)) {
366 			(void)printf("\\\n\t");
367 			col = 8;
368 		}
369 		col += width;
370 		do {
371 			(void)putchar(*cp++);
372 		} while (*cp);
373 	}
374 	if (col == 0)
375 		(void)printf("       ");
376 	(void)printf("\"\n");
377 }
378 
379 char *signames[] = {
380 	"NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT",	/*  1 - 6  */
381 	"EMT", "FPE", "KILL", "BUS", "SEGV", "SYS",		/*  7 - 12 */
382 	"PIPE", "ALRM",  "TERM", "URG", "STOP", "TSTP",		/* 13 - 18 */
383 	"CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU",		/* 19 - 24 */
384 	"XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1",	/* 25 - 30 */
385 	"USR2", NULL,						/* 31 - 32 */
386 };
387 
388 ktrpsig(psig)
389 	struct ktr_psig *psig;
390 {
391 	(void)printf("SIG%s ", signames[psig->signo]);
392 	if (psig->action == SIG_DFL)
393 		(void)printf("SIG_DFL\n");
394 	else
395 		(void)printf("caught handler=0x%x mask=0x%x code=0x%x\n",
396 		    (u_int)psig->action, psig->mask, psig->code);
397 }
398 
399 ktrcsw(cs)
400 	struct ktr_csw *cs;
401 {
402 	(void)printf("%s %s\n", cs->out ? "stop" : "resume",
403 		cs->user ? "user" : "kernel");
404 }
405 
406 usage()
407 {
408 	(void)fprintf(stderr,
409 	    "usage: kdump [-dnlRT] [-f trfile] [-m maxdata] [-t [cnis]]\n");
410 	exit(1);
411 }
412