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