xref: /freebsd/usr.bin/kdump/kdump.c (revision 531c890b8aecbf157fe3491503b5ca62c0b01093)
1 /*-
2  * Copyright (c) 1988, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 static const char copyright[] =
36 "@(#) Copyright (c) 1988, 1993\n\
37 	The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39 
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)kdump.c	8.1 (Berkeley) 6/6/93";
43 #endif
44 #endif /* not lint */
45 #include <sys/cdefs.h>
46 __FBSDID("$FreeBSD$");
47 
48 #define _KERNEL
49 extern int errno;
50 #include <sys/errno.h>
51 #undef _KERNEL
52 #include <sys/param.h>
53 #include <sys/errno.h>
54 #define _KERNEL
55 #include <sys/time.h>
56 #undef _KERNEL
57 #include <sys/uio.h>
58 #include <sys/ktrace.h>
59 #include <sys/ioctl.h>
60 #include <sys/socket.h>
61 #include <sys/stat.h>
62 #include <sys/un.h>
63 #ifdef IPX
64 #include <sys/types.h>
65 #include <netipx/ipx.h>
66 #endif
67 #ifdef NETATALK
68 #include <netatalk/at.h>
69 #endif
70 #include <netinet/in.h>
71 #include <dlfcn.h>
72 #include <err.h>
73 #include <grp.h>
74 #include <inttypes.h>
75 #include <locale.h>
76 #include <pwd.h>
77 #include <stdio.h>
78 #include <stdlib.h>
79 #include <string.h>
80 #include <time.h>
81 #include <unistd.h>
82 #include <vis.h>
83 #include "ktrace.h"
84 #include "kdump_subr.h"
85 
86 int fread_tail(void *, int, int);
87 void dumpheader(struct ktr_header *);
88 void ktrsyscall(struct ktr_syscall *);
89 void ktrsysret(struct ktr_sysret *);
90 void ktrnamei(char *, int);
91 void hexdump(char *, int, int);
92 void visdump(char *, int, int);
93 void ktrgenio(struct ktr_genio *, int);
94 void ktrpsig(struct ktr_psig *);
95 void ktrcsw(struct ktr_csw *);
96 void ktruser(int, unsigned char *);
97 void ktrsockaddr(struct sockaddr *);
98 void ktrstat(struct stat *);
99 void ktrstruct(char *, size_t);
100 void usage(void);
101 const char *ioctlname(u_long);
102 
103 int timestamp, decimal, fancy = 1, suppressdata, tail, threads, maxdata,
104     resolv = 0;
105 const char *tracefile = DEF_TRACEFILE;
106 struct ktr_header ktr_header;
107 
108 #define TIME_FORMAT	"%b %e %T %Y"
109 #define eqs(s1, s2)	(strcmp((s1), (s2)) == 0)
110 
111 int
112 main(int argc, char *argv[])
113 {
114 	int ch, ktrlen, size;
115 	void *m;
116 	int trpoints = ALL_POINTS;
117 	int drop_logged;
118 	pid_t pid = 0;
119 
120 	(void) setlocale(LC_CTYPE, "");
121 
122 	while ((ch = getopt(argc,argv,"f:dElm:np:HRrsTt:")) != -1)
123 		switch((char)ch) {
124 		case 'f':
125 			tracefile = optarg;
126 			break;
127 		case 'd':
128 			decimal = 1;
129 			break;
130 		case 'l':
131 			tail = 1;
132 			break;
133 		case 'm':
134 			maxdata = atoi(optarg);
135 			break;
136 		case 'n':
137 			fancy = 0;
138 			break;
139 		case 'p':
140 			pid = atoi(optarg);
141 			break;
142 		case 'r':
143 			resolv = 1;
144 			break;
145 		case 's':
146 			suppressdata = 1;
147 			break;
148 		case 'E':
149 			timestamp = 3;	/* elapsed timestamp */
150 			break;
151 		case 'H':
152 			threads = 1;
153 			break;
154 		case 'R':
155 			timestamp = 2;	/* relative timestamp */
156 			break;
157 		case 'T':
158 			timestamp = 1;
159 			break;
160 		case 't':
161 			trpoints = getpoints(optarg);
162 			if (trpoints < 0)
163 				errx(1, "unknown trace point in %s", optarg);
164 			break;
165 		default:
166 			usage();
167 		}
168 
169 	if (argc > optind)
170 		usage();
171 
172 	m = (void *)malloc(size = 1025);
173 	if (m == NULL)
174 		errx(1, "%s", strerror(ENOMEM));
175 	if (!freopen(tracefile, "r", stdin))
176 		err(1, "%s", tracefile);
177 	drop_logged = 0;
178 	while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) {
179 		if (ktr_header.ktr_type & KTR_DROP) {
180 			ktr_header.ktr_type &= ~KTR_DROP;
181 			if (!drop_logged && threads) {
182 				(void)printf("%6d %6d %-8.*s Events dropped.\n",
183 				    ktr_header.ktr_pid, ktr_header.ktr_tid >
184 				    0 ? ktr_header.ktr_tid : 0, MAXCOMLEN,
185 				    ktr_header.ktr_comm);
186 				drop_logged = 1;
187 			} else if (!drop_logged) {
188 				(void)printf("%6d %-8.*s Events dropped.\n",
189 				    ktr_header.ktr_pid, MAXCOMLEN,
190 				    ktr_header.ktr_comm);
191 				drop_logged = 1;
192 			}
193 		}
194 		if (trpoints & (1<<ktr_header.ktr_type))
195 			if (pid == 0 || ktr_header.ktr_pid == pid)
196 				dumpheader(&ktr_header);
197 		if ((ktrlen = ktr_header.ktr_len) < 0)
198 			errx(1, "bogus length 0x%x", ktrlen);
199 		if (ktrlen > size) {
200 			m = (void *)realloc(m, ktrlen+1);
201 			if (m == NULL)
202 				errx(1, "%s", strerror(ENOMEM));
203 			size = ktrlen;
204 		}
205 		if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
206 			errx(1, "data too short");
207 		if (pid && ktr_header.ktr_pid != pid)
208 			continue;
209 		if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
210 			continue;
211 		drop_logged = 0;
212 		switch (ktr_header.ktr_type) {
213 		case KTR_SYSCALL:
214 			ktrsyscall((struct ktr_syscall *)m);
215 			break;
216 		case KTR_SYSRET:
217 			ktrsysret((struct ktr_sysret *)m);
218 			break;
219 		case KTR_NAMEI:
220 			ktrnamei(m, ktrlen);
221 			break;
222 		case KTR_GENIO:
223 			ktrgenio((struct ktr_genio *)m, ktrlen);
224 			break;
225 		case KTR_PSIG:
226 			ktrpsig((struct ktr_psig *)m);
227 			break;
228 		case KTR_CSW:
229 			ktrcsw((struct ktr_csw *)m);
230 			break;
231 		case KTR_USER:
232 			ktruser(ktrlen, m);
233 			break;
234 		case KTR_STRUCT:
235 			ktrstruct(m, ktrlen);
236 			break;
237 		default:
238 			printf("\n");
239 			break;
240 		}
241 		if (tail)
242 			(void)fflush(stdout);
243 	}
244 	return 0;
245 }
246 
247 int
248 fread_tail(void *buf, int size, int num)
249 {
250 	int i;
251 
252 	while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
253 		(void)sleep(1);
254 		clearerr(stdin);
255 	}
256 	return (i);
257 }
258 
259 void
260 dumpheader(struct ktr_header *kth)
261 {
262 	static char unknown[64];
263 	static struct timeval prevtime, temp;
264 	const char *type;
265 
266 	switch (kth->ktr_type) {
267 	case KTR_SYSCALL:
268 		type = "CALL";
269 		break;
270 	case KTR_SYSRET:
271 		type = "RET ";
272 		break;
273 	case KTR_NAMEI:
274 		type = "NAMI";
275 		break;
276 	case KTR_GENIO:
277 		type = "GIO ";
278 		break;
279 	case KTR_PSIG:
280 		type = "PSIG";
281 		break;
282 	case KTR_CSW:
283 		type = "CSW ";
284 		break;
285 	case KTR_USER:
286 		type = "USER";
287 		break;
288 	case KTR_STRUCT:
289 		type = "STRU";
290 		break;
291 	default:
292 		(void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type);
293 		type = unknown;
294 	}
295 
296 	/*
297 	 * The ktr_tid field was previously the ktr_buffer field, which held
298 	 * the kernel pointer value for the buffer associated with data
299 	 * following the record header.  It now holds a threadid, but only
300 	 * for trace files after the change.  Older trace files still contain
301 	 * kernel pointers.  Detect this and suppress the results by printing
302 	 * negative tid's as 0.
303 	 */
304 	if (threads)
305 		(void)printf("%6d %6d %-8.*s ", kth->ktr_pid, kth->ktr_tid >
306 		    0 ? kth->ktr_tid : 0, MAXCOMLEN, kth->ktr_comm);
307 	else
308 		(void)printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN,
309 		    kth->ktr_comm);
310 	if (timestamp) {
311 		if (timestamp == 3) {
312 			if (prevtime.tv_sec == 0)
313 				prevtime = kth->ktr_time;
314 			timevalsub(&kth->ktr_time, &prevtime);
315 		}
316 		if (timestamp == 2) {
317 			temp = kth->ktr_time;
318 			timevalsub(&kth->ktr_time, &prevtime);
319 			prevtime = temp;
320 		}
321 		(void)printf("%ld.%06ld ",
322 		    kth->ktr_time.tv_sec, kth->ktr_time.tv_usec);
323 	}
324 	(void)printf("%s  ", type);
325 }
326 
327 #include <sys/syscall.h>
328 #define KTRACE
329 #include <sys/kern/syscalls.c>
330 #undef KTRACE
331 int nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]);
332 
333 void
334 ktrsyscall(struct ktr_syscall *ktr)
335 {
336 	int narg = ktr->ktr_narg;
337 	register_t *ip;
338 
339 	if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0)
340 		(void)printf("[%d]", ktr->ktr_code);
341 	else
342 		(void)printf("%s", syscallnames[ktr->ktr_code]);
343 	ip = &ktr->ktr_args[0];
344 	if (narg) {
345 		char c = '(';
346 		if (fancy) {
347 
348 #define print_number(i,n,c) do {                      \
349 	if (decimal)                                  \
350 		(void)printf("%c%ld", c, (long)*i);   \
351 	else                                          \
352 		(void)printf("%c%#lx", c, (long)*i);  \
353 	i++;                                          \
354 	n--;                                          \
355 	c = ',';                                      \
356 	} while (0);
357 
358 			if (ktr->ktr_code == SYS_ioctl) {
359 				const char *cp;
360 				print_number(ip,narg,c);
361 				if ((cp = ioctlname(*ip)) != NULL)
362 					(void)printf(",%s", cp);
363 				else {
364 					if (decimal)
365 						(void)printf(",%ld", (long)*ip);
366 					else
367 						(void)printf(",%#lx ", (long)*ip);
368 				}
369 				c = ',';
370 				ip++;
371 				narg--;
372 			} else if (ktr->ktr_code == SYS_ptrace) {
373 				(void)putchar('(');
374 				ptraceopname ((int)*ip);
375 				c = ',';
376 				ip++;
377 				narg--;
378 			} else if (ktr->ktr_code == SYS_access ||
379 				   ktr->ktr_code == SYS_eaccess) {
380 				print_number(ip,narg,c);
381 				(void)putchar(',');
382 				accessmodename ((int)*ip);
383 				ip++;
384 				narg--;
385 			} else if (ktr->ktr_code == SYS_open) {
386 				int	flags;
387 				int	mode;
388 				print_number(ip,narg,c);
389 				flags = *ip;
390 				mode = *++ip;
391 				(void)putchar(',');
392 				flagsandmodename (flags, mode, decimal);
393 				ip++;
394 				narg-=2;
395 			} else if (ktr->ktr_code == SYS_wait4) {
396 				print_number(ip,narg,c);
397 				print_number(ip,narg,c);
398 				(void)putchar(',');
399 				wait4optname ((int)*ip);
400 				ip++;
401 				narg--;
402 			} else if (ktr->ktr_code == SYS_chmod ||
403 				   ktr->ktr_code == SYS_fchmod ||
404 				   ktr->ktr_code == SYS_lchmod) {
405 				print_number(ip,narg,c);
406 				(void)putchar(',');
407 				modename ((int)*ip);
408 				ip++;
409 				narg--;
410 			} else if (ktr->ktr_code == SYS_mknod) {
411 				print_number(ip,narg,c);
412 				(void)putchar(',');
413 				modename ((int)*ip);
414 				ip++;
415 				narg--;
416 			} else if (ktr->ktr_code == SYS_getfsstat) {
417 				print_number(ip,narg,c);
418 				print_number(ip,narg,c);
419 				(void)putchar(',');
420 				getfsstatflagsname ((int)*ip);
421 				ip++;
422 				narg--;
423 			} else if (ktr->ktr_code == SYS_mount) {
424 				print_number(ip,narg,c);
425 				print_number(ip,narg,c);
426 				(void)putchar(',');
427 				mountflagsname ((int)*ip);
428 				ip++;
429 				narg--;
430 			} else if (ktr->ktr_code == SYS_unmount) {
431 				print_number(ip,narg,c);
432 				(void)putchar(',');
433 				mountflagsname ((int)*ip);
434 				ip++;
435 				narg--;
436 			} else if (ktr->ktr_code == SYS_recvmsg ||
437 				   ktr->ktr_code == SYS_sendmsg) {
438 				print_number(ip,narg,c);
439 				print_number(ip,narg,c);
440 				(void)putchar(',');
441 				sendrecvflagsname ((int)*ip);
442 				ip++;
443 				narg--;
444 			} else if (ktr->ktr_code == SYS_recvfrom ||
445 				   ktr->ktr_code == SYS_sendto) {
446 				print_number(ip,narg,c);
447 				print_number(ip,narg,c);
448 				print_number(ip,narg,c);
449 				(void)putchar(',');
450 				sendrecvflagsname ((int)*ip);
451 				ip++;
452 				narg--;
453 			} else if (ktr->ktr_code == SYS_chflags ||
454 				   ktr->ktr_code == SYS_fchflags ||
455 				   ktr->ktr_code == SYS_lchflags) {
456 				print_number(ip,narg,c);
457 				(void)putchar(',');
458 				modename((int)*ip);
459 				ip++;
460 				narg--;
461 			} else if (ktr->ktr_code == SYS_kill) {
462 				print_number(ip,narg,c);
463 				(void)putchar(',');
464 				signame((int)*ip);
465 				ip++;
466 				narg--;
467 			} else if (ktr->ktr_code == SYS_reboot) {
468 				(void)putchar('(');
469 				rebootoptname((int)*ip);
470 				ip++;
471 				narg--;
472 			} else if (ktr->ktr_code == SYS_umask) {
473 				(void)putchar('(');
474 				modename((int)*ip);
475 				ip++;
476 				narg--;
477 			} else if (ktr->ktr_code == SYS_msync) {
478 				print_number(ip,narg,c);
479 				print_number(ip,narg,c);
480 				(void)putchar(',');
481 				msyncflagsname((int)*ip);
482 				ip++;
483 				narg--;
484 #ifdef SYS_freebsd6_mmap
485 			} else if (ktr->ktr_code == SYS_freebsd6_mmap) {
486 				print_number(ip,narg,c);
487 				print_number(ip,narg,c);
488 				(void)putchar(',');
489 				mmapprotname ((int)*ip);
490 				(void)putchar(',');
491 				ip++;
492 				narg--;
493 				mmapflagsname ((int)*ip);
494 				ip++;
495 				narg--;
496 #endif
497 			} else if (ktr->ktr_code == SYS_mmap) {
498 				print_number(ip,narg,c);
499 				print_number(ip,narg,c);
500 				(void)putchar(',');
501 				mmapprotname ((int)*ip);
502 				(void)putchar(',');
503 				ip++;
504 				narg--;
505 				mmapflagsname ((int)*ip);
506 				ip++;
507 				narg--;
508 			} else if (ktr->ktr_code == SYS_mprotect) {
509 				print_number(ip,narg,c);
510 				print_number(ip,narg,c);
511 				(void)putchar(',');
512 				mmapprotname ((int)*ip);
513 				ip++;
514 				narg--;
515 			} else if (ktr->ktr_code == SYS_madvise) {
516 				print_number(ip,narg,c);
517 				print_number(ip,narg,c);
518 				(void)putchar(',');
519 				madvisebehavname((int)*ip);
520 				ip++;
521 				narg--;
522 			} else if (ktr->ktr_code == SYS_setpriority) {
523 				print_number(ip,narg,c);
524 				print_number(ip,narg,c);
525 				(void)putchar(',');
526 				prioname((int)*ip);
527 				ip++;
528 				narg--;
529 			} else if (ktr->ktr_code == SYS_fcntl) {
530 				int cmd;
531 				int arg;
532 				print_number(ip,narg,c);
533 				cmd = *ip;
534 				arg = *++ip;
535 				(void)putchar(',');
536 				fcntlcmdname(cmd, arg, decimal);
537 				ip++;
538 				narg-=2;
539 			} else if (ktr->ktr_code == SYS_socket) {
540 				int sockdomain;
541 				(void)putchar('(');
542 				sockdomain=(int)*ip;
543 				sockdomainname(sockdomain);
544 				ip++;
545 				narg--;
546 				(void)putchar(',');
547 				socktypename((int)*ip);
548 				ip++;
549 				narg--;
550 				if (sockdomain == PF_INET ||
551 				    sockdomain == PF_INET6) {
552 					(void)putchar(',');
553 					sockipprotoname((int)*ip);
554 					ip++;
555 					narg--;
556 				}
557 				c = ',';
558 			} else if (ktr->ktr_code == SYS_setsockopt ||
559 				   ktr->ktr_code == SYS_getsockopt) {
560 				print_number(ip,narg,c);
561 				(void)putchar(',');
562 				sockoptlevelname((int)*ip, decimal);
563 				if ((int)*ip == SOL_SOCKET) {
564 					ip++;
565 					narg--;
566 					(void)putchar(',');
567 					sockoptname((int)*ip);
568 				}
569 				ip++;
570 				narg--;
571 #ifdef SYS_freebsd6_lseek
572 			} else if (ktr->ktr_code == SYS_freebsd6_lseek) {
573 				print_number(ip,narg,c);
574 				/* Hidden 'pad' argument, not in lseek(2) */
575 				print_number(ip,narg,c);
576 				print_number(ip,narg,c);
577 				(void)putchar(',');
578 				whencename ((int)*ip);
579 				ip++;
580 				narg--;
581 #endif
582 			} else if (ktr->ktr_code == SYS_lseek) {
583 				print_number(ip,narg,c);
584 				/* Hidden 'pad' argument, not in lseek(2) */
585 				print_number(ip,narg,c);
586 				(void)putchar(',');
587 				whencename ((int)*ip);
588 				ip++;
589 				narg--;
590 
591 			} else if (ktr->ktr_code == SYS_flock) {
592 				print_number(ip,narg,c);
593 				(void)putchar(',');
594 				flockname((int)*ip);
595 				ip++;
596 				narg--;
597 			} else if (ktr->ktr_code == SYS_mkfifo ||
598 				   ktr->ktr_code == SYS_mkdir) {
599 				print_number(ip,narg,c);
600 				(void)putchar(',');
601 				modename((int)*ip);
602 				ip++;
603 				narg--;
604 			} else if (ktr->ktr_code == SYS_shutdown) {
605 				print_number(ip,narg,c);
606 				(void)putchar(',');
607 				shutdownhowname((int)*ip);
608 				ip++;
609 				narg--;
610 			} else if (ktr->ktr_code == SYS_socketpair) {
611 				(void)putchar('(');
612 				sockdomainname((int)*ip);
613 				ip++;
614 				narg--;
615 				(void)putchar(',');
616 				socktypename((int)*ip);
617 				ip++;
618 				narg--;
619 				c = ',';
620 			} else if (ktr->ktr_code == SYS_getrlimit ||
621 				   ktr->ktr_code == SYS_setrlimit) {
622 				(void)putchar('(');
623 				rlimitname((int)*ip);
624 				ip++;
625 				narg--;
626 				c = ',';
627 			} else if (ktr->ktr_code == SYS_quotactl) {
628 				print_number(ip,narg,c);
629 				(void)putchar(',');
630 				quotactlname((int)*ip);
631 				ip++;
632 				narg--;
633 				c = ',';
634 			} else if (ktr->ktr_code == SYS_nfssvc) {
635 				(void)putchar('(');
636 				nfssvcname((int)*ip);
637 				ip++;
638 				narg--;
639 				c = ',';
640 			} else if (ktr->ktr_code == SYS_rtprio) {
641 				(void)putchar('(');
642 				rtprioname((int)*ip);
643 				ip++;
644 				narg--;
645 				c = ',';
646 			} else if (ktr->ktr_code == SYS___semctl) {
647 				print_number(ip,narg,c);
648 				print_number(ip,narg,c);
649 				(void)putchar(',');
650 				semctlname((int)*ip);
651 				ip++;
652 				narg--;
653 			} else if (ktr->ktr_code == SYS_semget) {
654 				print_number(ip,narg,c);
655 				print_number(ip,narg,c);
656 				(void)putchar(',');
657 				semgetname((int)*ip);
658 				ip++;
659 				narg--;
660 			} else if (ktr->ktr_code == SYS_msgctl) {
661 				print_number(ip,narg,c);
662 				(void)putchar(',');
663 				shmctlname((int)*ip);
664 				ip++;
665 				narg--;
666 			} else if (ktr->ktr_code == SYS_shmat) {
667 				print_number(ip,narg,c);
668 				print_number(ip,narg,c);
669 				(void)putchar(',');
670 				shmatname((int)*ip);
671 				ip++;
672 				narg--;
673 			} else if (ktr->ktr_code == SYS_shmctl) {
674 				print_number(ip,narg,c);
675 				(void)putchar(',');
676 				shmctlname((int)*ip);
677 				ip++;
678 				narg--;
679 			} else if (ktr->ktr_code == SYS_minherit) {
680 				print_number(ip,narg,c);
681 				print_number(ip,narg,c);
682 				(void)putchar(',');
683 				minheritname((int)*ip);
684 				ip++;
685 				narg--;
686 			} else if (ktr->ktr_code == SYS_rfork) {
687 				(void)putchar('(');
688 				rforkname((int)*ip);
689 				ip++;
690 				narg--;
691 				c = ',';
692 			} else if (ktr->ktr_code == SYS_lio_listio) {
693 				(void)putchar('(');
694 				lio_listioname((int)*ip);
695 				ip++;
696 				narg--;
697 				c = ',';
698 			} else if (ktr->ktr_code == SYS_mlockall) {
699 				(void)putchar('(');
700 				mlockallname((int)*ip);
701 				ip++;
702 				narg--;
703 			} else if (ktr->ktr_code == SYS_sched_setscheduler) {
704 				print_number(ip,narg,c);
705 				(void)putchar(',');
706 				schedpolicyname((int)*ip);
707 				ip++;
708 				narg--;
709 			} else if (ktr->ktr_code == SYS_sched_get_priority_max ||
710 				   ktr->ktr_code == SYS_sched_get_priority_min) {
711 				(void)putchar('(');
712 				schedpolicyname((int)*ip);
713 				ip++;
714 				narg--;
715 			} else if (ktr->ktr_code == SYS_sendfile) {
716 				print_number(ip,narg,c);
717 				print_number(ip,narg,c);
718 				print_number(ip,narg,c);
719 				print_number(ip,narg,c);
720 				print_number(ip,narg,c);
721 				print_number(ip,narg,c);
722 				(void)putchar(',');
723 				sendfileflagsname((int)*ip);
724 				ip++;
725 				narg--;
726 			} else if (ktr->ktr_code == SYS_kldsym) {
727 				print_number(ip,narg,c);
728 				(void)putchar(',');
729 				kldsymcmdname((int)*ip);
730 				ip++;
731 				narg--;
732 			} else if (ktr->ktr_code == SYS_sigprocmask) {
733 				(void)putchar('(');
734 				sigprocmaskhowname((int)*ip);
735 				ip++;
736 				narg--;
737 				c = ',';
738 			} else if (ktr->ktr_code == SYS___acl_get_file ||
739 				   ktr->ktr_code == SYS___acl_set_file ||
740 				   ktr->ktr_code == SYS___acl_get_fd ||
741 				   ktr->ktr_code == SYS___acl_set_fd ||
742 				   ktr->ktr_code == SYS___acl_delete_file ||
743 				   ktr->ktr_code == SYS___acl_delete_fd ||
744 				   ktr->ktr_code == SYS___acl_aclcheck_file ||
745 				   ktr->ktr_code == SYS___acl_aclcheck_fd ||
746 				   ktr->ktr_code == SYS___acl_get_link ||
747 				   ktr->ktr_code == SYS___acl_set_link ||
748 				   ktr->ktr_code == SYS___acl_delete_link ||
749 				   ktr->ktr_code == SYS___acl_aclcheck_link) {
750 				print_number(ip,narg,c);
751 				(void)putchar(',');
752 				acltypename((int)*ip);
753 				ip++;
754 				narg--;
755 			} else if (ktr->ktr_code == SYS_sigaction) {
756 				(void)putchar('(');
757 				signame((int)*ip);
758 				ip++;
759 				narg--;
760 				c = ',';
761 			} else if (ktr->ktr_code == SYS_extattrctl) {
762 				print_number(ip,narg,c);
763 				(void)putchar(',');
764 				extattrctlname((int)*ip);
765 				ip++;
766 				narg--;
767 			} else if (ktr->ktr_code == SYS_nmount) {
768 				print_number(ip,narg,c);
769 				print_number(ip,narg,c);
770 				(void)putchar(',');
771 				mountflagsname ((int)*ip);
772 				ip++;
773 				narg--;
774 			} else if (ktr->ktr_code == SYS_kse_thr_interrupt) {
775 				print_number(ip,narg,c);
776 				(void)putchar(',');
777 				ksethrcmdname ((int)*ip);
778 				ip++;
779 				narg--;
780 			} else if (ktr->ktr_code == SYS_thr_create) {
781 				print_number(ip,narg,c);
782 				print_number(ip,narg,c);
783 				(void)putchar(',');
784 				thrcreateflagsname ((int)*ip);
785 				ip++;
786 				narg--;
787 			} else if (ktr->ktr_code == SYS_thr_kill) {
788 				print_number(ip,narg,c);
789 				(void)putchar(',');
790 				signame ((int)*ip);
791 				ip++;
792 				narg--;
793 			} else if (ktr->ktr_code == SYS_kldunloadf) {
794 				print_number(ip,narg,c);
795 				(void)putchar(',');
796 				kldunloadfflagsname ((int)*ip);
797 				ip++;
798 				narg--;
799 			}
800 		}
801 		while (narg) {
802 			print_number(ip,narg,c);
803 		}
804 		(void)putchar(')');
805 	}
806 	(void)putchar('\n');
807 }
808 
809 void
810 ktrsysret(struct ktr_sysret *ktr)
811 {
812 	register_t ret = ktr->ktr_retval;
813 	int error = ktr->ktr_error;
814 	int code = ktr->ktr_code;
815 
816 	if (code >= nsyscalls || code < 0)
817 		(void)printf("[%d] ", code);
818 	else
819 		(void)printf("%s ", syscallnames[code]);
820 
821 	if (error == 0) {
822 		if (fancy) {
823 			(void)printf("%d", ret);
824 			if (ret < 0 || ret > 9)
825 				(void)printf("/%#lx", (long)ret);
826 		} else {
827 			if (decimal)
828 				(void)printf("%ld", (long)ret);
829 			else
830 				(void)printf("%#lx", (long)ret);
831 		}
832 	} else if (error == ERESTART)
833 		(void)printf("RESTART");
834 	else if (error == EJUSTRETURN)
835 		(void)printf("JUSTRETURN");
836 	else {
837 		(void)printf("-1 errno %d", ktr->ktr_error);
838 		if (fancy)
839 			(void)printf(" %s", strerror(ktr->ktr_error));
840 	}
841 	(void)putchar('\n');
842 }
843 
844 void
845 ktrnamei(char *cp, int len)
846 {
847 	(void)printf("\"%.*s\"\n", len, cp);
848 }
849 
850 void
851 hexdump(char *p, int len, int screenwidth)
852 {
853 	int n, i;
854 	int width;
855 
856 	width = 0;
857 	do {
858 		width += 2;
859 		i = 13;			/* base offset */
860 		i += (width / 2) + 1;	/* spaces every second byte */
861 		i += (width * 2);	/* width of bytes */
862 		i += 3;			/* "  |" */
863 		i += width;		/* each byte */
864 		i += 1;			/* "|" */
865 	} while (i < screenwidth);
866 	width -= 2;
867 
868 	for (n = 0; n < len; n += width) {
869 		for (i = n; i < n + width; i++) {
870 			if ((i % width) == 0) {	/* beginning of line */
871 				printf("       0x%04x", i);
872 			}
873 			if ((i % 2) == 0) {
874 				printf(" ");
875 			}
876 			if (i < len)
877 				printf("%02x", p[i] & 0xff);
878 			else
879 				printf("  ");
880 		}
881 		printf("  |");
882 		for (i = n; i < n + width; i++) {
883 			if (i >= len)
884 				break;
885 			if (p[i] >= ' ' && p[i] <= '~')
886 				printf("%c", p[i]);
887 			else
888 				printf(".");
889 		}
890 		printf("|\n");
891 	}
892 	if ((i % width) != 0)
893 		printf("\n");
894 }
895 
896 void
897 visdump(char *dp, int datalen, int screenwidth)
898 {
899 	int col = 0;
900 	char *cp;
901 	int width;
902 	char visbuf[5];
903 
904 	(void)printf("       \"");
905 	col = 8;
906 	for (;datalen > 0; datalen--, dp++) {
907 		(void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
908 		cp = visbuf;
909 		/*
910 		 * Keep track of printables and
911 		 * space chars (like fold(1)).
912 		 */
913 		if (col == 0) {
914 			(void)putchar('\t');
915 			col = 8;
916 		}
917 		switch(*cp) {
918 		case '\n':
919 			col = 0;
920 			(void)putchar('\n');
921 			continue;
922 		case '\t':
923 			width = 8 - (col&07);
924 			break;
925 		default:
926 			width = strlen(cp);
927 		}
928 		if (col + width > (screenwidth-2)) {
929 			(void)printf("\\\n\t");
930 			col = 8;
931 		}
932 		col += width;
933 		do {
934 			(void)putchar(*cp++);
935 		} while (*cp);
936 	}
937 	if (col == 0)
938 		(void)printf("       ");
939 	(void)printf("\"\n");
940 }
941 
942 void
943 ktrgenio(struct ktr_genio *ktr, int len)
944 {
945 	int datalen = len - sizeof (struct ktr_genio);
946 	char *dp = (char *)ktr + sizeof (struct ktr_genio);
947 	static int screenwidth = 0;
948 	int i, binary;
949 
950 	if (screenwidth == 0) {
951 		struct winsize ws;
952 
953 		if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
954 		    ws.ws_col > 8)
955 			screenwidth = ws.ws_col;
956 		else
957 			screenwidth = 80;
958 	}
959 	printf("fd %d %s %d byte%s\n", ktr->ktr_fd,
960 		ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen,
961 		datalen == 1 ? "" : "s");
962 	if (suppressdata)
963 		return;
964 	if (maxdata && datalen > maxdata)
965 		datalen = maxdata;
966 
967 	for (i = 0, binary = 0; i < datalen && binary == 0; i++)  {
968 		if (dp[i] >= 32 && dp[i] < 127)
969 			continue;
970 		if (dp[i] == 10 || dp[i] == 13 || dp[i] == 0 || dp[i] == 9)
971 			continue;
972 		binary = 1;
973 	}
974 	if (binary)
975 		hexdump(dp, datalen, screenwidth);
976 	else
977 		visdump(dp, datalen, screenwidth);
978 }
979 
980 const char *signames[] = {
981 	"NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT",	/*  1 - 6  */
982 	"EMT", "FPE", "KILL", "BUS", "SEGV", "SYS",		/*  7 - 12 */
983 	"PIPE", "ALRM",  "TERM", "URG", "STOP", "TSTP",		/* 13 - 18 */
984 	"CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU",		/* 19 - 24 */
985 	"XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1",	/* 25 - 30 */
986 	"USR2", NULL,						/* 31 - 32 */
987 };
988 
989 void
990 ktrpsig(struct ktr_psig *psig)
991 {
992 	if (psig->signo > 0 && psig->signo < NSIG)
993 		(void)printf("SIG%s ", signames[psig->signo]);
994 	else
995 		(void)printf("SIG %d ", psig->signo);
996 	if (psig->action == SIG_DFL)
997 		(void)printf("SIG_DFL\n");
998 	else {
999 		(void)printf("caught handler=0x%lx mask=0x%x code=0x%x\n",
1000 		    (u_long)psig->action, psig->mask.__bits[0], psig->code);
1001 	}
1002 }
1003 
1004 void
1005 ktrcsw(struct ktr_csw *cs)
1006 {
1007 	(void)printf("%s %s\n", cs->out ? "stop" : "resume",
1008 		cs->user ? "user" : "kernel");
1009 }
1010 
1011 #define	UTRACE_DLOPEN_START		1
1012 #define	UTRACE_DLOPEN_STOP		2
1013 #define	UTRACE_DLCLOSE_START		3
1014 #define	UTRACE_DLCLOSE_STOP		4
1015 #define	UTRACE_LOAD_OBJECT		5
1016 #define	UTRACE_UNLOAD_OBJECT		6
1017 #define	UTRACE_ADD_RUNDEP		7
1018 #define	UTRACE_PRELOAD_FINISHED		8
1019 #define	UTRACE_INIT_CALL		9
1020 #define	UTRACE_FINI_CALL		10
1021 
1022 struct utrace_rtld {
1023 	char sig[4];				/* 'RTLD' */
1024 	int event;
1025 	void *handle;
1026 	void *mapbase;
1027 	size_t mapsize;
1028 	int refcnt;
1029 	char name[MAXPATHLEN];
1030 };
1031 
1032 void
1033 ktruser_rtld(int len, unsigned char *p)
1034 {
1035 	struct utrace_rtld *ut = (struct utrace_rtld *)p;
1036 	void *parent;
1037 	int mode;
1038 
1039 	switch (ut->event) {
1040 	case UTRACE_DLOPEN_START:
1041 		mode = ut->refcnt;
1042 		printf("dlopen(%s, ", ut->name);
1043 		switch (mode & RTLD_MODEMASK) {
1044 		case RTLD_NOW:
1045 			printf("RTLD_NOW");
1046 			break;
1047 		case RTLD_LAZY:
1048 			printf("RTLD_LAZY");
1049 			break;
1050 		default:
1051 			printf("%#x", mode & RTLD_MODEMASK);
1052 		}
1053 		if (mode & RTLD_GLOBAL)
1054 			printf(" | RTLD_GLOBAL");
1055 		if (mode & RTLD_TRACE)
1056 			printf(" | RTLD_TRACE");
1057 		if (mode & ~(RTLD_MODEMASK | RTLD_GLOBAL | RTLD_TRACE))
1058 			printf(" | %#x", mode &
1059 			    ~(RTLD_MODEMASK | RTLD_GLOBAL | RTLD_TRACE));
1060 		printf(")\n");
1061 		break;
1062 	case UTRACE_DLOPEN_STOP:
1063 		printf("%p = dlopen(%s) ref %d\n", ut->handle, ut->name,
1064 		    ut->refcnt);
1065 		break;
1066 	case UTRACE_DLCLOSE_START:
1067 		printf("dlclose(%p) (%s, %d)\n", ut->handle, ut->name,
1068 		    ut->refcnt);
1069 		break;
1070 	case UTRACE_DLCLOSE_STOP:
1071 		printf("dlclose(%p) finished\n", ut->handle);
1072 		break;
1073 	case UTRACE_LOAD_OBJECT:
1074 		printf("RTLD: loaded   %p @ %p - %p (%s)\n", ut->handle,
1075 		    ut->mapbase, (char *)ut->mapbase + ut->mapsize - 1,
1076 		    ut->name);
1077 		break;
1078 	case UTRACE_UNLOAD_OBJECT:
1079 		printf("RTLD: unloaded %p @ %p - %p (%s)\n", ut->handle,
1080 		    ut->mapbase, (char *)ut->mapbase + ut->mapsize - 1,
1081 		    ut->name);
1082 		break;
1083 	case UTRACE_ADD_RUNDEP:
1084 		parent = ut->mapbase;
1085 		printf("RTLD: %p now depends on %p (%s, %d)\n", parent,
1086 		    ut->handle, ut->name, ut->refcnt);
1087 		break;
1088 	case UTRACE_PRELOAD_FINISHED:
1089 		printf("RTLD: LD_PRELOAD finished\n");
1090 		break;
1091 	case UTRACE_INIT_CALL:
1092 		printf("RTLD: init %p for %p (%s)\n", ut->mapbase, ut->handle,
1093 		    ut->name);
1094 		break;
1095 	case UTRACE_FINI_CALL:
1096 		printf("RTLD: fini %p for %p (%s)\n", ut->mapbase, ut->handle,
1097 		    ut->name);
1098 		break;
1099 	default:
1100 		p += 4;
1101 		len -= 4;
1102 		printf("RTLD: %d ", len);
1103 		while (len--)
1104 			if (decimal)
1105 				printf(" %d", *p++);
1106 			else
1107 				printf(" %02x", *p++);
1108 		printf("\n");
1109 	}
1110 }
1111 
1112 struct utrace_malloc {
1113 	void *p;
1114 	size_t s;
1115 	void *r;
1116 };
1117 
1118 void
1119 ktruser_malloc(int len, unsigned char *p)
1120 {
1121 	struct utrace_malloc *ut = (struct utrace_malloc *)p;
1122 
1123 	if (ut->p == NULL) {
1124 		if (ut->s == 0 && ut->r == NULL)
1125 			printf("malloc_init()\n");
1126 		else
1127 			printf("%p = malloc(%zu)\n", ut->r, ut->s);
1128 	} else {
1129 		if (ut->s == 0)
1130 			printf("free(%p)\n", ut->p);
1131 		else
1132 			printf("%p = realloc(%p, %zu)\n", ut->r, ut->p, ut->s);
1133 	}
1134 }
1135 
1136 void
1137 ktruser(int len, unsigned char *p)
1138 {
1139 
1140 	if (len >= 8 && bcmp(p, "RTLD", 4) == 0) {
1141 		ktruser_rtld(len, p);
1142 		return;
1143 	}
1144 
1145 	if (len == sizeof(struct utrace_malloc)) {
1146 		ktruser_malloc(len, p);
1147 		return;
1148 	}
1149 
1150 	(void)printf("%d ", len);
1151 	while (len--)
1152 		if (decimal)
1153 			(void)printf(" %d", *p++);
1154 		else
1155 			(void)printf(" %02x", *p++);
1156 	(void)printf("\n");
1157 }
1158 
1159 void
1160 ktrsockaddr(struct sockaddr *sa)
1161 {
1162 /*
1163  TODO: Support additional address families
1164 	#include <netatm/atm.h>
1165 	struct sockaddr_atm	*atm;
1166 	#include <netnatm/natm.h>
1167 	struct sockaddr_natm	*natm;
1168 	#include <netsmb/netbios.h>
1169 	struct sockaddr_nb	*nb;
1170 */
1171 	char addr[64];
1172 
1173 	/*
1174 	 * note: ktrstruct() has already verified that sa points to a
1175 	 * buffer at least sizeof(struct sockaddr) bytes long and exactly
1176 	 * sa->sa_len bytes long.
1177 	 */
1178 	printf("struct sockaddr { ");
1179 	sockfamilyname(sa->sa_family);
1180 	printf(", ");
1181 
1182 #define check_sockaddr_len(n)					\
1183 	if (sa_##n->s##n##_len < sizeof(struct sockaddr_##n)) {	\
1184 		printf("invalid");				\
1185 		break;						\
1186 	}
1187 
1188 	switch(sa->sa_family) {
1189 	case AF_INET: {
1190 		struct sockaddr_in	*sa_in;
1191 
1192 		sa_in = (struct sockaddr_in *)sa;
1193 		check_sockaddr_len(in);
1194 		inet_ntop(AF_INET, &sa_in->sin_addr, addr, sizeof addr);
1195 		printf("%s:%u", addr, ntohs(sa_in->sin_port));
1196 		break;
1197 	}
1198 #ifdef NETATALK
1199 	case AF_APPLETALK: {
1200 		struct sockaddr_at	*sa_at;
1201 		struct netrange		*nr;
1202 
1203 		sa_at = (struct sockaddr_at *)sa;
1204 		check_sockaddr_len(at);
1205 		nr = &sa_at->sat_range.r_netrange;
1206 		printf("%d.%d, %d-%d, %d", ntohs(sa_at->sat_addr.s_net),
1207 			sa_at->sat_addr.s_node, ntohs(nr->nr_firstnet),
1208 			ntohs(nr->nr_lastnet), nr->nr_phase);
1209 		break;
1210 	}
1211 #endif
1212 	case AF_INET6: {
1213 		struct sockaddr_in6	*sa_in6;
1214 
1215 		sa_in6 = (struct sockaddr_in6 *)sa;
1216 		check_sockaddr_len(in6);
1217 		inet_ntop(AF_INET6, &sa_in6->sin6_addr, addr, sizeof addr);
1218 		printf("[%s]:%u", addr, htons(sa_in6->sin6_port));
1219 		break;
1220 	}
1221 #ifdef IPX
1222 	case AF_IPX: {
1223 		struct sockaddr_ipx	*sa_ipx;
1224 
1225 		sa_ipx = (struct sockaddr_ipx *)sa;
1226 		check_sockaddr_len(ipx);
1227 		/* XXX wish we had ipx_ntop */
1228 		printf("%s", ipx_ntoa(sa_ipx->sipx_addr));
1229 		break;
1230 	}
1231 #endif
1232 	case AF_UNIX: {
1233 		struct sockaddr_un *sa_un;
1234 
1235 		sa_un = (struct sockaddr_un *)sa;
1236 		check_sockaddr_len(un);
1237 		printf("%.*s", (int)sizeof(sa_un->sun_path), sa_un->sun_path);
1238 		break;
1239 	}
1240 	default:
1241 		printf("unknown address family");
1242 	}
1243 	printf(" }\n");
1244 }
1245 
1246 void
1247 ktrstat(struct stat *statp)
1248 {
1249 	char mode[12], timestr[PATH_MAX + 4];
1250 	struct passwd *pwd;
1251 	struct group  *grp;
1252 	struct tm *tm;
1253 
1254 	/*
1255 	 * note: ktrstruct() has already verified that statp points to a
1256 	 * buffer exactly sizeof(struct stat) bytes long.
1257 	 */
1258 	printf("struct stat {");
1259 	strmode(statp->st_mode, mode);
1260 	printf("dev=%ju, ino=%ju, mode=%s, nlink=%ju, ",
1261 		(uintmax_t)statp->st_dev, (uintmax_t)statp->st_ino, mode,
1262 		(uintmax_t)statp->st_nlink);
1263 	if (resolv == 0 || (pwd = getpwuid(statp->st_uid)) == NULL)
1264 		printf("uid=%ju, ", (uintmax_t)statp->st_uid);
1265 	else
1266 		printf("uid=\"%s\", ", pwd->pw_name);
1267 	if (resolv == 0 || (grp = getgrgid(statp->st_gid)) == NULL)
1268 		printf("gid=%ju, ", (uintmax_t)statp->st_gid);
1269 	else
1270 		printf("gid=\"%s\", ", grp->gr_name);
1271 	printf("rdev=%ju, ", (uintmax_t)statp->st_rdev);
1272 	printf("atime=");
1273 	if (resolv == 0)
1274 		printf("%ld", statp->st_atimespec.tv_sec);
1275 	else {
1276 		tm = localtime(&statp->st_atimespec.tv_sec);
1277 		(void)strftime(timestr, sizeof(timestr), TIME_FORMAT, tm);
1278 		printf("\"%s\"", timestr);
1279 	}
1280 	if (statp->st_atimespec.tv_nsec != 0)
1281 		printf(".%09ld, ", statp->st_atimespec.tv_nsec);
1282 	else
1283 		printf(", ");
1284 	printf("stime=");
1285 	if (resolv == 0)
1286 		printf("%ld", statp->st_mtimespec.tv_sec);
1287 	else {
1288 		tm = localtime(&statp->st_mtimespec.tv_sec);
1289 		(void)strftime(timestr, sizeof(timestr), TIME_FORMAT, tm);
1290 		printf("\"%s\"", timestr);
1291 	}
1292 	if (statp->st_mtimespec.tv_nsec != 0)
1293 		printf(".%09ld, ", statp->st_mtimespec.tv_nsec);
1294 	else
1295 		printf(", ");
1296 	printf("ctime=");
1297 	if (resolv == 0)
1298 		printf("%ld", statp->st_ctimespec.tv_sec);
1299 	else {
1300 		tm = localtime(&statp->st_ctimespec.tv_sec);
1301 		(void)strftime(timestr, sizeof(timestr), TIME_FORMAT, tm);
1302 		printf("\"%s\"", timestr);
1303 	}
1304 	if (statp->st_ctimespec.tv_nsec != 0)
1305 		printf(".%09ld, ", statp->st_ctimespec.tv_nsec);
1306 	else
1307 		printf(", ");
1308 	printf("birthtime=");
1309 	if (resolv == 0)
1310 		printf("%ld", statp->st_birthtimespec.tv_sec);
1311 	else {
1312 		tm = localtime(&statp->st_birthtimespec.tv_sec);
1313 		(void)strftime(timestr, sizeof(timestr), TIME_FORMAT, tm);
1314 		printf("\"%s\"", timestr);
1315 	}
1316 	if (statp->st_birthtimespec.tv_nsec != 0)
1317 		printf(".%09ld, ", statp->st_birthtimespec.tv_nsec);
1318 	else
1319 		printf(", ");
1320 	printf("size=%jd, blksize=%ju, blocks=%jd, flags=0x%x",
1321 		(uintmax_t)statp->st_size, (uintmax_t)statp->st_blksize,
1322 		(intmax_t)statp->st_blocks, statp->st_flags);
1323 	printf(" }\n");
1324 }
1325 
1326 void
1327 ktrstruct(char *buf, size_t buflen)
1328 {
1329 	char *name, *data;
1330 	size_t namelen, datalen;
1331 	int i;
1332 
1333 	for (name = buf, namelen = 0;
1334 	     namelen < buflen && name[namelen] != '\0';
1335 	     ++namelen)
1336 		/* nothing */;
1337 	if (namelen == buflen)
1338 		goto invalid;
1339 	if (name[namelen] != '\0')
1340 		goto invalid;
1341 	data = buf + namelen + 1;
1342 	datalen = buflen - namelen - 1;
1343 	if (datalen == 0)
1344 		goto invalid;
1345 	/* sanity check */
1346 	for (i = 0; i < namelen; ++i)
1347 		if (!isalpha((unsigned char)name[i]))
1348 			goto invalid;
1349 	if (strcmp(name, "stat") == 0) {
1350 		if (datalen != sizeof(struct stat))
1351 			goto invalid;
1352 		ktrstat((struct stat *)data);
1353 	} else if (strcmp(name, "sockaddr") == 0) {
1354 		if (datalen < sizeof(struct sockaddr) ||
1355 		    datalen != ((struct sockaddr *)(data))->sa_len)
1356 			goto invalid;
1357 		ktrsockaddr((struct sockaddr *)data);
1358 	} else {
1359 		printf("unknown structure\n");
1360 	}
1361 	return;
1362 invalid:
1363 	printf("invalid record\n");
1364 }
1365 
1366 void
1367 usage(void)
1368 {
1369 	fprintf(stderr, "usage: kdump [-dEnlHRrsT] [-f trfile] "
1370 	    "[-m maxdata] [-p pid] [-t [cnistuw]]\n");
1371 	exit(1);
1372 }
1373