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