xref: /original-bsd/usr.bin/kdump/kdump.c (revision 90bde559)
1 /*
2  * Copyright (c) 1988 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1988 The Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)kdump.c	1.8 (Berkeley) 05/23/90";
26 #endif /* not lint */
27 
28 #include <cencode.h>
29 #include "ktrace.h"
30 #include <sys/ioctl.h>
31 
32 int timestamp, decimal, fancy = 1, tail, maxdata;
33 char *tracefile = DEF_TRACEFILE;
34 struct ktr_header ktr_header;
35 int size = 1024;	/* initial size - grow as needed */
36 
37 #define USAGE	\
38 	"usage: kdump [-dnlT] [-t trops] [-f trfile] [-m maxdata]\n\
39 	trops: c = syscalls, n = namei, g = generic-i/o, a = everything\n"
40 
41 #define eqs(s1, s2)	(strcmp((s1), (s2)) == 0)
42 
43 main(argc, argv)
44 	char *argv[];
45 {
46 	extern int optind;
47 	extern char *optarg;
48 	int ch, ktrlen;
49 	register char *m;
50 	int trpoints = ALL_POINTS;
51 
52 	while ((ch = getopt(argc,argv,"t:f:dnlTRm:")) != EOF)
53 		switch((char)ch) {
54 		case 't':
55 			trpoints = getpoints(optarg);
56 			if (trpoints < 0) {
57 				fprintf(stderr,
58 				     "kdump: unknown trace point in %s\n",
59 					optarg);
60 				exit(1);
61 			}
62 			break;
63 		case 'f':
64 			tracefile = optarg;
65 			break;
66 		case 'd':
67 			decimal = 1;
68 			break;
69 		case 'n':
70 			fancy = 0;
71 			break;
72 		case 'l':
73 			tail = 1;
74 			break;
75 		case 'T':
76 			timestamp = 1;
77 			break;
78 		case 'R':
79 			timestamp = 2;	/* relative timestamp */
80 			break;
81 		case 'm':
82 			maxdata = atoi(optarg);
83 			break;
84 		default:
85 			fprintf(stderr, USAGE);
86 			exit(1);
87 		}
88 	argv += optind, argc -= optind;
89 
90 	if (argc > 1) {
91 		fprintf(stderr, USAGE);
92 		exit(1);
93 	}
94 	if (!eqs(tracefile, "-")) {
95 		if (freopen(tracefile, "r", stdin) == NULL) {
96 			fprintf(stderr, "kdump: %s: ", tracefile);
97 			perror("");
98 			exit(1);
99 		}
100 	}
101 	m = (char *)malloc(size+1);
102 	if (m == NULL) {
103 		fprintf(stderr, "kdump: ain't gots no memory\n");
104 		exit(1);
105 	}
106 	while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1,
107 	       stdin, tail)) {
108 		if (trpoints & (1<<ktr_header.ktr_type))
109 			dumpheader(&ktr_header);
110 		if ((ktrlen = ktr_header.ktr_len) < 0) {
111 			fprintf(stderr, "kdump: bogus length 0x%x\n",
112 				ktrlen);
113 			exit(1);
114 		}
115 		if (ktrlen > size) {
116 			m = (char *)realloc(m, ktrlen+1);
117 			if (m == NULL) {
118 				fprintf(stderr,"kdump: out of memory\n");
119 				exit(1);
120 			}
121 			size = ktrlen;
122 		}
123 		if (ktrlen && fread_tail(m, ktrlen, 1, stdin, tail) == 0) {
124 			fprintf(stderr, "kdump: data too short\n");
125 			exit(1);
126 		}
127 		if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
128 			continue;
129 		switch (ktr_header.ktr_type) {
130 		case KTR_SYSCALL:
131 			ktrsyscall((struct ktr_syscall *)m, ktrlen);
132 			break;
133 		case KTR_SYSRET:
134 			ktrsysret((struct ktr_sysret *)m, ktrlen);
135 			break;
136 		case KTR_NAMEI:
137 			ktrnamei(m, ktrlen);
138 			break;
139 		case KTR_GENIO:
140 			ktrgenio((struct ktr_genio *)m, ktrlen);
141 			break;
142 		case KTR_PSIG:
143 			ktrpsig((struct ktr_psig *)m, ktrlen);
144 			break;
145 		}
146 		if (tail)
147 			fflush(stdout);
148 	}
149 }
150 
151 fread_tail(buf, size, num, stream, tail)
152 	char *buf;
153 	FILE *stream;
154 {
155 	int i;
156 
157 	while ((i = fread(buf, size, num, stream)) == 0 && tail) {
158 		sleep(1);
159 		clearerr(stream);
160 	}
161 	return (i);
162 }
163 
164 dumpheader(kth)
165 	struct ktr_header *kth;
166 {
167 	static char unknown[64];
168 	static struct timeval prevtime, temp;
169 	char *type;
170 
171 	switch (kth->ktr_type) {
172 	case KTR_SYSCALL:
173 		type = "CALL";
174 		break;
175 	case KTR_SYSRET:
176 		type = "RET ";
177 		break;
178 	case KTR_NAMEI:
179 		type = "NAMI";
180 		break;
181 	case KTR_GENIO:
182 		type = "GIO ";
183 		break;
184 	case KTR_PSIG:
185 		type = "PSIG";
186 		break;
187 	default:
188 		sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type);
189 		type = unknown;
190 	}
191 
192 	printf("%6d %-8s ",
193 		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 		printf("%d.%06d ", kth->ktr_time.tv_sec, kth->ktr_time.tv_usec);
201 	}
202 	printf("%s  ", type);
203 }
204 
205 #include <sys/syscall.h>
206 #define KTRACE
207 #include "/sys/kern/syscalls.c"
208 #undef KTRACE
209 int nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]);
210 
211 ktrsyscall(ktr, len)
212 	register struct ktr_syscall *ktr;
213 {
214 	register narg = ktr->ktr_narg;
215 	register int *ip;
216 	char *ioctlname();
217 
218 	if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0)
219 		printf("[%d]", ktr->ktr_code);
220 	else
221 		printf("%s", syscallnames[ktr->ktr_code]);
222 	ip = (int *)((char *)ktr + sizeof(struct ktr_syscall));
223 	if (narg) {
224 		char c = '(';
225 		if (fancy && ktr->ktr_code == SYS_ioctl) {
226 			char *cp;
227 			if (decimal)
228 				printf("(%d", *ip);
229 			else
230 				printf("(%#x", *ip);
231 			ip++; narg--;
232 			if ((cp = ioctlname(*ip)) != NULL)
233 				printf(",%s", cp);
234 			else {
235 				if (decimal)
236 					printf(",%d", *ip);
237 				else
238 					printf(",%#x ", *ip);
239 			}
240 			c = ',';
241 			ip++; narg--;
242 		}
243 		while (narg) {
244 			if (decimal)
245 				printf("%c%d", c, *ip);
246 			else
247 				printf("%c%#x", c, *ip);
248 			c = ',';
249 			ip++; narg--;
250 		}
251 		putchar(')');
252 	}
253 	putchar('\n');
254 }
255 
256 ktrsysret(ktr, len)
257 	struct ktr_sysret *ktr;
258 {
259 	extern char *sys_errlist[];
260 	int ret = ktr->ktr_retval;
261 
262 	if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0)
263 		printf("[%d] ", ktr->ktr_code);
264 	else
265 		printf("%s ", syscallnames[ktr->ktr_code]);
266 	if (ktr->ktr_eosys == RESTARTSYS)
267 		printf("RESTART");
268 	else if (ktr->ktr_error) {
269 		printf("-1 errno %d", ktr->ktr_error);
270 		if (fancy)
271 			printf(" %s", strerror(ktr->ktr_error));
272 	} else {
273 		if (fancy) {
274 			printf("%d", ret);
275 			if (ret < 0 || ret > 9)
276 				printf("/%#x", ret);
277 		} else {
278 			if (decimal)
279 				printf("%d", ret);
280 			else
281 				printf("%#x", ret);
282 		}
283 	}
284 	putchar('\n');
285 }
286 
287 ktrnamei(cp, len)
288 	char *cp;
289 {
290 	printf("\"%.*s\"\n", len, cp);
291 }
292 
293 #define CENC_ALL (CENC_CSTYLE | CENC_GRAPH | CENC_OCTAL)
294 
295 ktrgenio(ktr, len)
296 	struct ktr_genio *ktr;
297 {
298 	register int datalen = len - sizeof (struct ktr_genio);
299 	register char *dp = (char *)ktr + sizeof (struct ktr_genio);
300 	register char *cp;
301 	register int col = 0;
302 	register char c;
303 	register width;
304 	static screenwidth = 0;
305 
306 	if (screenwidth == 0) {
307 		struct winsize ws;
308 
309 		if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
310 		    ws.ws_col > 8)
311 			screenwidth = ws.ws_col;
312 		else
313 			screenwidth = 80;
314 	}
315 	printf("fd %d %s %d bytes\n", ktr->ktr_fd,
316 		ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen);
317 	if (maxdata && datalen > maxdata)
318 		datalen = maxdata;
319 	printf("       \"");
320 	col = 8;
321 	for (;datalen > 0; datalen--, dp++) {
322 		cp = cencode(*dp, CENC_ALL | CENC_RACHAR, *(dp+1));
323 		if (*cp == '\r')
324 			cp = "\\r";
325 		/*
326 		 * Keep track of printables and
327 		 * space chars (like fold(1)).
328 		 */
329 		if (col == 0) {
330 			putchar('\t');
331 			col = 8;
332 		}
333 		switch(*cp) {
334 		case '\n':
335 			col = 0;
336 			putchar('\n');
337 			continue;
338 		case '\t':
339 			width = 8 - (col&07);
340 			break;
341 		default:
342 			width = strlen(cp);
343 		}
344 		if (col + width > (screenwidth-2)) {
345 			printf("\\\n\t");
346 			col = 8;
347 		}
348 		col += width;
349 		do {
350 			putchar(*cp++);
351 		} while (*cp);
352 	}
353 	if (col == 0)
354 		printf("       ");
355 	printf("\"\n");
356 }
357 
358 
359 char *signames[] = {
360 	"NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT",	/*  1 - 6  */
361 	"EMT", "FPE", "KILL", "BUS", "SEGV", "SYS",		/*  7 - 12 */
362 	"PIPE", "ALRM",  "TERM", "URG", "STOP", "TSTP",		/* 13 - 18 */
363 	"CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU",		/* 19 - 24 */
364 	"XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1",	/* 25 - 30 */
365 	"USR2", NULL,						/* 31 - 32 */
366 };
367 
368 ktrpsig(psig, len)
369 	struct ktr_psig *psig;
370 {
371 	printf("SIG%s ", signames[psig->signo]);
372 	if (psig->action == SIG_DFL)
373 		printf("SIG_DFL\n");
374 	else {
375 		printf("caught handler=0x%x mask=0x%x code=0x%x\n",
376 			psig->action, psig->mask, psig->code);
377 	}
378 }
379