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