xref: /original-bsd/usr.bin/kdump/kdump.c (revision 3b6250d9)
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	5.3 (Berkeley) 01/17/91";
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 		}
141 		if (tail)
142 			(void)fflush(stdout);
143 	}
144 }
145 
146 fread_tail(buf, size, num)
147 	char *buf;
148 	int num, size;
149 {
150 	int i;
151 
152 	while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
153 		(void)sleep(1);
154 		clearerr(stdin);
155 	}
156 	return (i);
157 }
158 
159 dumpheader(kth)
160 	struct ktr_header *kth;
161 {
162 	static char unknown[64];
163 	static struct timeval prevtime, temp;
164 	char *type;
165 
166 	switch (kth->ktr_type) {
167 	case KTR_SYSCALL:
168 		type = "CALL";
169 		break;
170 	case KTR_SYSRET:
171 		type = "RET ";
172 		break;
173 	case KTR_NAMEI:
174 		type = "NAMI";
175 		break;
176 	case KTR_GENIO:
177 		type = "GIO ";
178 		break;
179 	case KTR_PSIG:
180 		type = "PSIG";
181 		break;
182 	default:
183 		(void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type);
184 		type = unknown;
185 	}
186 
187 	(void)printf("%6d %-8s ", kth->ktr_pid, kth->ktr_comm);
188 	if (timestamp) {
189 		if (timestamp == 2) {
190 			temp = kth->ktr_time;
191 			timevalsub(&kth->ktr_time, &prevtime);
192 			prevtime = temp;
193 		}
194 		(void)printf("%ld.%06ld ",
195 		    kth->ktr_time.tv_sec, kth->ktr_time.tv_usec);
196 	}
197 	(void)printf("%s  ", type);
198 }
199 
200 #include <sys/syscall.h>
201 #define KTRACE
202 #include "/sys/kern/syscalls.c"
203 #undef KTRACE
204 int nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]);
205 
206 static char *ptrace_ops[] = {
207 	"PT_TRACE_ME",	"PT_READ_I",	"PT_READ_D",	"PT_READ_U",
208 	"PT_WRITE_I",	"PT_WRITE_D",	"PT_WRITE_U",	"PT_CONTINUE",
209 	"PT_KILL",	"PT_STEP",
210 };
211 
212 ktrsyscall(ktr)
213 	register struct ktr_syscall *ktr;
214 {
215 	register narg = ktr->ktr_narg;
216 	register int *ip;
217 	char *ioctlname();
218 
219 	if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0)
220 		(void)printf("[%d]", ktr->ktr_code);
221 	else
222 		(void)printf("%s", syscallnames[ktr->ktr_code]);
223 	ip = (int *)((char *)ktr + sizeof(struct ktr_syscall));
224 	if (narg) {
225 		char c = '(';
226 		if (fancy) {
227 			if (ktr->ktr_code == SYS_ioctl) {
228 				char *cp;
229 				if (decimal)
230 					(void)printf("(%d", *ip);
231 				else
232 					(void)printf("(%#x", *ip);
233 				ip++;
234 				narg--;
235 				if ((cp = ioctlname(*ip)) != NULL)
236 					(void)printf(",%s", cp);
237 				else {
238 					if (decimal)
239 						(void)printf(",%d", *ip);
240 					else
241 						(void)printf(",%#x ", *ip);
242 				}
243 				c = ',';
244 				ip++;
245 				narg--;
246 			} else if (ktr->ktr_code == SYS_ptrace) {
247 				if (*ip <= PT_STEP && *ip >= 0)
248 					(void)printf("(%s", ptrace_ops[*ip]);
249 				else
250 					(void)printf("(%d", *ip);
251 				c = ',';
252 				ip++;
253 				narg--;
254 			}
255 		}
256 		while (narg) {
257 			if (decimal)
258 				(void)printf("%c%d", c, *ip);
259 			else
260 				(void)printf("%c%#x", c, *ip);
261 			c = ',';
262 			ip++;
263 			narg--;
264 		}
265 		(void)putchar(')');
266 	}
267 	(void)putchar('\n');
268 }
269 
270 ktrsysret(ktr)
271 	struct ktr_sysret *ktr;
272 {
273 	register int ret = ktr->ktr_retval;
274 	register int error = ktr->ktr_error;
275 	register int code = ktr->ktr_code;
276 
277 	if (code >= nsyscalls || code < 0)
278 		(void)printf("[%d] ", code);
279 	else
280 		(void)printf("%s ", syscallnames[code]);
281 
282 	if (error == 0) {
283 		if (fancy) {
284 			(void)printf("%d", ret);
285 			if (ret < 0 || ret > 9)
286 				(void)printf("/%#x", ret);
287 		} else {
288 			if (decimal)
289 				(void)printf("%d", ret);
290 			else
291 				(void)printf("%#x", ret);
292 		}
293 	} else if (error == ERESTART)
294 		(void)printf("RESTART");
295 	else if (error == EJUSTRETURN)
296 		(void)printf("JUSTRETURN");
297 	else {
298 		(void)printf("-1 errno %d", ktr->ktr_error);
299 		if (fancy)
300 			(void)printf(" %s", strerror(ktr->ktr_error));
301 	}
302 	(void)putchar('\n');
303 }
304 
305 ktrnamei(cp, len)
306 	char *cp;
307 {
308 	(void)printf("\"%.*s\"\n", len, cp);
309 }
310 
311 ktrgenio(ktr, len)
312 	struct ktr_genio *ktr;
313 {
314 	register int datalen = len - sizeof (struct ktr_genio);
315 	register char *dp = (char *)ktr + sizeof (struct ktr_genio);
316 	register char *cp;
317 	register int col = 0;
318 	register width;
319 	char visbuf[5];
320 	static screenwidth = 0;
321 
322 	if (screenwidth == 0) {
323 		struct winsize ws;
324 
325 		if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
326 		    ws.ws_col > 8)
327 			screenwidth = ws.ws_col;
328 		else
329 			screenwidth = 80;
330 	}
331 	printf("fd %d %s %d bytes\n", ktr->ktr_fd,
332 		ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen);
333 	if (maxdata && datalen > maxdata)
334 		datalen = maxdata;
335 	(void)printf("       \"");
336 	col = 8;
337 	for (;datalen > 0; datalen--, dp++) {
338 		(void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
339 		cp = visbuf;
340 		/*
341 		 * Keep track of printables and
342 		 * space chars (like fold(1)).
343 		 */
344 		if (col == 0) {
345 			(void)putchar('\t');
346 			col = 8;
347 		}
348 		switch(*cp) {
349 		case '\n':
350 			col = 0;
351 			(void)putchar('\n');
352 			continue;
353 		case '\t':
354 			width = 8 - (col&07);
355 			break;
356 		default:
357 			width = strlen(cp);
358 		}
359 		if (col + width > (screenwidth-2)) {
360 			(void)printf("\\\n\t");
361 			col = 8;
362 		}
363 		col += width;
364 		do {
365 			(void)putchar(*cp++);
366 		} while (*cp);
367 	}
368 	if (col == 0)
369 		(void)printf("       ");
370 	(void)printf("\"\n");
371 }
372 
373 char *signames[] = {
374 	"NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT",	/*  1 - 6  */
375 	"EMT", "FPE", "KILL", "BUS", "SEGV", "SYS",		/*  7 - 12 */
376 	"PIPE", "ALRM",  "TERM", "URG", "STOP", "TSTP",		/* 13 - 18 */
377 	"CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU",		/* 19 - 24 */
378 	"XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1",	/* 25 - 30 */
379 	"USR2", NULL,						/* 31 - 32 */
380 };
381 
382 ktrpsig(psig)
383 	struct ktr_psig *psig;
384 {
385 	(void)printf("SIG%s ", signames[psig->signo]);
386 	if (psig->action == SIG_DFL)
387 		(void)printf("SIG_DFL\n");
388 	else
389 		(void)printf("caught handler=0x%x mask=0x%x code=0x%x\n",
390 		    (u_int)psig->action, psig->mask, psig->code);
391 }
392 
393 usage()
394 {
395 	(void)fprintf(stderr,
396 	    "usage: kdump [-dnlRT] [-f trfile] [-m maxdata] [-t [cnis]]\n");
397 	exit(1);
398 }
399