xref: /freebsd/usr.bin/kdump/kdump.c (revision c96ae1968a6ab7056427a739bce81bf07447c2d4)
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/ptrace.h>
61 #include <sys/socket.h>
62 #include <dlfcn.h>
63 #include <err.h>
64 #include <locale.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <string.h>
68 #include <unistd.h>
69 #include <vis.h>
70 #include "ktrace.h"
71 #include "kdump_subr.h"
72 
73 int fread_tail(void *, int, int);
74 void dumpheader(struct ktr_header *);
75 void ktrsyscall(struct ktr_syscall *);
76 void ktrsysret(struct ktr_sysret *);
77 void ktrnamei(char *, int);
78 void hexdump(char *, int, int);
79 void visdump(char *, int, int);
80 void ktrgenio(struct ktr_genio *, int);
81 void ktrpsig(struct ktr_psig *);
82 void ktrcsw(struct ktr_csw *);
83 void ktruser(int, unsigned char *);
84 void usage(void);
85 const char *ioctlname(u_long);
86 
87 int timestamp, decimal, fancy = 1, suppressdata, tail, threads, maxdata;
88 const char *tracefile = DEF_TRACEFILE;
89 struct ktr_header ktr_header;
90 
91 #define eqs(s1, s2)	(strcmp((s1), (s2)) == 0)
92 
93 int
94 main(int argc, char *argv[])
95 {
96 	int ch, ktrlen, size;
97 	void *m;
98 	int trpoints = ALL_POINTS;
99 	int drop_logged;
100 	pid_t pid = 0;
101 
102 	(void) setlocale(LC_CTYPE, "");
103 
104 	while ((ch = getopt(argc,argv,"f:dElm:np:HRsTt:")) != -1)
105 		switch((char)ch) {
106 		case 'f':
107 			tracefile = optarg;
108 			break;
109 		case 'd':
110 			decimal = 1;
111 			break;
112 		case 'l':
113 			tail = 1;
114 			break;
115 		case 'm':
116 			maxdata = atoi(optarg);
117 			break;
118 		case 'n':
119 			fancy = 0;
120 			break;
121 		case 'p':
122 			pid = atoi(optarg);
123 			break;
124 		case 's':
125 			suppressdata = 1;
126 			break;
127 		case 'E':
128 			timestamp = 3;	/* elapsed timestamp */
129 			break;
130 		case 'H':
131 			threads = 1;
132 			break;
133 		case 'R':
134 			timestamp = 2;	/* relative timestamp */
135 			break;
136 		case 'T':
137 			timestamp = 1;
138 			break;
139 		case 't':
140 			trpoints = getpoints(optarg);
141 			if (trpoints < 0)
142 				errx(1, "unknown trace point in %s", optarg);
143 			break;
144 		default:
145 			usage();
146 		}
147 
148 	if (argc > optind)
149 		usage();
150 
151 	m = (void *)malloc(size = 1025);
152 	if (m == NULL)
153 		errx(1, "%s", strerror(ENOMEM));
154 	if (!freopen(tracefile, "r", stdin))
155 		err(1, "%s", tracefile);
156 	drop_logged = 0;
157 	while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) {
158 		if (ktr_header.ktr_type & KTR_DROP) {
159 			ktr_header.ktr_type &= ~KTR_DROP;
160 			if (!drop_logged && threads) {
161 				(void)printf("%6d %6d %-8.*s Events dropped.\n",
162 				    ktr_header.ktr_pid, ktr_header.ktr_tid >
163 				    0 ? ktr_header.ktr_tid : 0, MAXCOMLEN,
164 				    ktr_header.ktr_comm);
165 				drop_logged = 1;
166 			} else if (!drop_logged) {
167 				(void)printf("%6d %-8.*s Events dropped.\n",
168 				    ktr_header.ktr_pid, MAXCOMLEN,
169 				    ktr_header.ktr_comm);
170 				drop_logged = 1;
171 			}
172 		}
173 		if (trpoints & (1<<ktr_header.ktr_type))
174 			if (pid == 0 || ktr_header.ktr_pid == pid)
175 				dumpheader(&ktr_header);
176 		if ((ktrlen = ktr_header.ktr_len) < 0)
177 			errx(1, "bogus length 0x%x", ktrlen);
178 		if (ktrlen > size) {
179 			m = (void *)realloc(m, ktrlen+1);
180 			if (m == NULL)
181 				errx(1, "%s", strerror(ENOMEM));
182 			size = ktrlen;
183 		}
184 		if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
185 			errx(1, "data too short");
186 		if (pid && ktr_header.ktr_pid != pid)
187 			continue;
188 		if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
189 			continue;
190 		drop_logged = 0;
191 		switch (ktr_header.ktr_type) {
192 		case KTR_SYSCALL:
193 			ktrsyscall((struct ktr_syscall *)m);
194 			break;
195 		case KTR_SYSRET:
196 			ktrsysret((struct ktr_sysret *)m);
197 			break;
198 		case KTR_NAMEI:
199 			ktrnamei(m, ktrlen);
200 			break;
201 		case KTR_GENIO:
202 			ktrgenio((struct ktr_genio *)m, ktrlen);
203 			break;
204 		case KTR_PSIG:
205 			ktrpsig((struct ktr_psig *)m);
206 			break;
207 		case KTR_CSW:
208 			ktrcsw((struct ktr_csw *)m);
209 			break;
210 		case KTR_USER:
211 			ktruser(ktrlen, m);
212 			break;
213 		default:
214 			printf("\n");
215 			break;
216 		}
217 		if (tail)
218 			(void)fflush(stdout);
219 	}
220 	return 0;
221 }
222 
223 int
224 fread_tail(void *buf, int size, int num)
225 {
226 	int i;
227 
228 	while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
229 		(void)sleep(1);
230 		clearerr(stdin);
231 	}
232 	return (i);
233 }
234 
235 void
236 dumpheader(struct ktr_header *kth)
237 {
238 	static char unknown[64];
239 	static struct timeval prevtime, temp;
240 	const char *type;
241 
242 	switch (kth->ktr_type) {
243 	case KTR_SYSCALL:
244 		type = "CALL";
245 		break;
246 	case KTR_SYSRET:
247 		type = "RET ";
248 		break;
249 	case KTR_NAMEI:
250 		type = "NAMI";
251 		break;
252 	case KTR_GENIO:
253 		type = "GIO ";
254 		break;
255 	case KTR_PSIG:
256 		type = "PSIG";
257 		break;
258 	case KTR_CSW:
259 		type = "CSW";
260 		break;
261 	case KTR_USER:
262 		type = "USER";
263 		break;
264 	default:
265 		(void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type);
266 		type = unknown;
267 	}
268 
269 	/*
270 	 * The ktr_tid field was previously the ktr_buffer field, which held
271 	 * the kernel pointer value for the buffer associated with data
272 	 * following the record header.  It now holds a threadid, but only
273 	 * for trace files after the change.  Older trace files still contain
274 	 * kernel pointers.  Detect this and suppress the results by printing
275 	 * negative tid's as 0.
276 	 */
277 	if (threads)
278 		(void)printf("%6d %6d %-8.*s ", kth->ktr_pid, kth->ktr_tid >
279 		    0 ? kth->ktr_tid : 0, MAXCOMLEN, kth->ktr_comm);
280 	else
281 		(void)printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN,
282 		    kth->ktr_comm);
283 	if (timestamp) {
284 		if (timestamp == 3) {
285 			if (prevtime.tv_sec == 0)
286 				prevtime = kth->ktr_time;
287 			timevalsub(&kth->ktr_time, &prevtime);
288 		}
289 		if (timestamp == 2) {
290 			temp = kth->ktr_time;
291 			timevalsub(&kth->ktr_time, &prevtime);
292 			prevtime = temp;
293 		}
294 		(void)printf("%ld.%06ld ",
295 		    kth->ktr_time.tv_sec, kth->ktr_time.tv_usec);
296 	}
297 	(void)printf("%s  ", type);
298 }
299 
300 #include <sys/syscall.h>
301 #define KTRACE
302 #include <sys/kern/syscalls.c>
303 #undef KTRACE
304 int nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]);
305 
306 static const char *ptrace_ops[] = {
307 	"PT_TRACE_ME",	"PT_READ_I",	"PT_READ_D",	"PT_READ_U",
308 	"PT_WRITE_I",	"PT_WRITE_D",	"PT_WRITE_U",	"PT_CONTINUE",
309 	"PT_KILL",	"PT_STEP",	"PT_ATTACH",	"PT_DETACH",
310 };
311 
312 void
313 ktrsyscall(struct ktr_syscall *ktr)
314 {
315 	int narg = ktr->ktr_narg;
316 	register_t *ip;
317 
318 	if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0)
319 		(void)printf("[%d]", ktr->ktr_code);
320 	else
321 		(void)printf("%s", syscallnames[ktr->ktr_code]);
322 	ip = &ktr->ktr_args[0];
323 	if (narg) {
324 		char c = '(';
325 		if (fancy) {
326 
327 #define print_number(i,n,c) do {                      \
328 	if (decimal)                                  \
329 		(void)printf("%c%ld", c, (long)*i);   \
330 	else                                          \
331 		(void)printf("%c%#lx", c, (long)*i);  \
332 	i++;                                          \
333 	n--;                                          \
334 	c = ',';                                      \
335 	} while (0);
336 
337 			if (ktr->ktr_code == SYS_ioctl) {
338 				const char *cp;
339 				print_number(ip,narg,c);
340 				if ((cp = ioctlname(*ip)) != NULL)
341 					(void)printf(",%s", cp);
342 				else {
343 					if (decimal)
344 						(void)printf(",%ld", (long)*ip);
345 					else
346 						(void)printf(",%#lx ", (long)*ip);
347 				}
348 				c = ',';
349 				ip++;
350 				narg--;
351 			} else if (ktr->ktr_code == SYS_ptrace) {
352 				if ((size_t)*ip < sizeof(ptrace_ops) /
353 				    sizeof(ptrace_ops[0]) && *ip >= 0)
354 					(void)printf("(%s", ptrace_ops[*ip]);
355 #ifdef PT_GETREGS
356 				else if (*ip == PT_GETREGS)
357 					(void)printf("(%s", "PT_GETREGS");
358 #endif
359 #ifdef PT_SETREGS
360 				else if (*ip == PT_SETREGS)
361 					(void)printf("(%s", "PT_SETREGS");
362 #endif
363 #ifdef PT_GETFPREGS
364 				else if (*ip == PT_GETFPREGS)
365 					(void)printf("(%s", "PT_GETFPREGS");
366 #endif
367 #ifdef PT_SETFPREGS
368 				else if (*ip == PT_SETFPREGS)
369 					(void)printf("(%s", "PT_SETFPREGS");
370 #endif
371 #ifdef PT_GETDBREGS
372 				else if (*ip == PT_GETDBREGS)
373 					(void)printf("(%s", "PT_GETDBREGS");
374 #endif
375 #ifdef PT_SETDBREGS
376 				else if (*ip == PT_SETDBREGS)
377 					(void)printf("(%s", "PT_SETDBREGS");
378 #endif
379 				else
380 					(void)printf("(%ld", (long)*ip);
381 				c = ',';
382 				ip++;
383 				narg--;
384 			} else if (ktr->ktr_code == SYS_access ||
385 				   ktr->ktr_code == SYS_eaccess) {
386 				print_number(ip,narg,c);
387 				(void)putchar(',');
388 				accessmodename ((int)*ip);
389 				ip++;
390 				narg--;
391 			} else if (ktr->ktr_code == SYS_open) {
392 				int	flags;
393 				int	mode;
394 				print_number(ip,narg,c);
395 				flags = *ip;
396 				mode = *++ip;
397 				(void)putchar(',');
398 				flagsandmodename (flags, mode, decimal);
399 				ip++;
400 				narg-=2;
401 			} else if (ktr->ktr_code == SYS_wait4) {
402 				print_number(ip,narg,c);
403 				print_number(ip,narg,c);
404 				(void)putchar(',');
405 				wait4optname ((int)*ip);
406 				ip++;
407 				narg--;
408 			} else if (ktr->ktr_code == SYS_chmod ||
409 				   ktr->ktr_code == SYS_fchmod ||
410 				   ktr->ktr_code == SYS_lchmod) {
411 				print_number(ip,narg,c);
412 				(void)putchar(',');
413 				modename ((int)*ip);
414 				ip++;
415 				narg--;
416 			} else if (ktr->ktr_code == SYS_mknod) {
417 				print_number(ip,narg,c);
418 				(void)putchar(',');
419 				modename ((int)*ip);
420 				ip++;
421 				narg--;
422 			} else if (ktr->ktr_code == SYS_getfsstat) {
423 				print_number(ip,narg,c);
424 				print_number(ip,narg,c);
425 				(void)putchar(',');
426 				getfsstatflagsname ((int)*ip);
427 				ip++;
428 				narg--;
429 			} else if (ktr->ktr_code == SYS_mount) {
430 				print_number(ip,narg,c);
431 				print_number(ip,narg,c);
432 				(void)putchar(',');
433 				mountflagsname ((int)*ip);
434 				ip++;
435 				narg--;
436 			} else if (ktr->ktr_code == SYS_unmount) {
437 				print_number(ip,narg,c);
438 				(void)putchar(',');
439 				mountflagsname ((int)*ip);
440 				ip++;
441 				narg--;
442 			} else if (ktr->ktr_code == SYS_recvmsg ||
443 				   ktr->ktr_code == SYS_sendmsg) {
444 				print_number(ip,narg,c);
445 				print_number(ip,narg,c);
446 				(void)putchar(',');
447 				sendrecvflagsname ((int)*ip);
448 				ip++;
449 				narg--;
450 			} else if (ktr->ktr_code == SYS_recvfrom ||
451 				   ktr->ktr_code == SYS_sendto) {
452 				print_number(ip,narg,c);
453 				print_number(ip,narg,c);
454 				print_number(ip,narg,c);
455 				(void)putchar(',');
456 				sendrecvflagsname ((int)*ip);
457 				ip++;
458 				narg--;
459 			} else if (ktr->ktr_code == SYS_chflags ||
460 				   ktr->ktr_code == SYS_fchflags ||
461 				   ktr->ktr_code == SYS_lchflags) {
462 				print_number(ip,narg,c);
463 				(void)putchar(',');
464 				modename((int)*ip);
465 				ip++;
466 				narg--;
467 			} else if (ktr->ktr_code == SYS_kill) {
468 				print_number(ip,narg,c);
469 				(void)putchar(',');
470 				signame((int)*ip);
471 				ip++;
472 				narg--;
473 			} else if (ktr->ktr_code == SYS_reboot) {
474 				(void)putchar('(');
475 				rebootoptname((int)*ip);
476 				ip++;
477 				narg--;
478 			} else if (ktr->ktr_code == SYS_umask) {
479 				(void)putchar('(');
480 				modename((int)*ip);
481 				ip++;
482 				narg--;
483 			} else if (ktr->ktr_code == SYS_msync) {
484 				print_number(ip,narg,c);
485 				print_number(ip,narg,c);
486 				(void)putchar(',');
487 				msyncflagsname((int)*ip);
488 				ip++;
489 				narg--;
490 			} else if (ktr->ktr_code == SYS_mmap) {
491 				print_number(ip,narg,c);
492 				print_number(ip,narg,c);
493 				(void)putchar(',');
494 				mmapprotname ((int)*ip);
495 				(void)putchar(',');
496 				ip++;
497 				narg--;
498 				mmapflagsname ((int)*ip);
499 				ip++;
500 				narg--;
501 			} else if (ktr->ktr_code == SYS_mprotect) {
502 				print_number(ip,narg,c);
503 				print_number(ip,narg,c);
504 				(void)putchar(',');
505 				mmapprotname ((int)*ip);
506 				ip++;
507 				narg--;
508 			} else if (ktr->ktr_code == SYS_madvise) {
509 				print_number(ip,narg,c);
510 				print_number(ip,narg,c);
511 				(void)putchar(',');
512 				madvisebehavname((int)*ip);
513 				ip++;
514 				narg--;
515 			} else if (ktr->ktr_code == SYS_setpriority) {
516 				print_number(ip,narg,c);
517 				print_number(ip,narg,c);
518 				(void)putchar(',');
519 				prioname((int)*ip);
520 				ip++;
521 				narg--;
522 			} else if (ktr->ktr_code == SYS_fcntl) {
523 				int cmd;
524 				int arg;
525 				print_number(ip,narg,c);
526 				cmd = *ip;
527 				arg = *++ip;
528 				(void)putchar(',');
529 				fcntlcmdname(cmd, arg, decimal);
530 				ip++;
531 				narg-=2;
532 			} else if (ktr->ktr_code == SYS_socket) {
533 				int sockdomain;
534 				(void)putchar('(');
535 				sockdomain=(int)*ip;
536 				sockdomainname(sockdomain);
537 				ip++;
538 				narg--;
539 				(void)putchar(',');
540 				socktypename((int)*ip);
541 				ip++;
542 				narg--;
543 				if (sockdomain == PF_INET ||
544 				    sockdomain == PF_INET6) {
545 					(void)putchar(',');
546 					sockipprotoname((int)*ip);
547 					ip++;
548 					narg--;
549 				}
550 				c = ',';
551 			} else if (ktr->ktr_code == SYS_setsockopt ||
552 				   ktr->ktr_code == SYS_getsockopt) {
553 				print_number(ip,narg,c);
554 				(void)putchar(',');
555 				sockoptlevelname((int)*ip, decimal);
556 				ip++;
557 				narg--;
558 				(void)putchar(',');
559 				sockoptname((int)*ip);
560 				ip++;
561 				narg--;
562 			} else if (ktr->ktr_code == SYS_lseek) {
563 				print_number(ip,narg,c);
564 				/* Hidden 'pad' argument, not in lseek(2) */
565 				print_number(ip,narg,c);
566 				print_number(ip,narg,c);
567 				(void)putchar(',');
568 				whencename ((int)*ip);
569 				ip++;
570 				narg--;
571 			} else if (ktr->ktr_code == SYS_flock) {
572 				print_number(ip,narg,c);
573 				(void)putchar(',');
574 				flockname((int)*ip);
575 				ip++;
576 				narg--;
577 			} else if (ktr->ktr_code == SYS_mkfifo ||
578 				   ktr->ktr_code == SYS_mkdir) {
579 				print_number(ip,narg,c);
580 				(void)putchar(',');
581 				modename((int)*ip);
582 				ip++;
583 				narg--;
584 			} else if (ktr->ktr_code == SYS_shutdown) {
585 				print_number(ip,narg,c);
586 				(void)putchar(',');
587 				shutdownhowname((int)*ip);
588 				ip++;
589 				narg--;
590 			} else if (ktr->ktr_code == SYS_socketpair) {
591 				(void)putchar('(');
592 				sockdomainname((int)*ip);
593 				ip++;
594 				narg--;
595 				(void)putchar(',');
596 				socktypename((int)*ip);
597 				ip++;
598 				narg--;
599 				c = ',';
600 			} else if (ktr->ktr_code == SYS_getrlimit ||
601 				   ktr->ktr_code == SYS_setrlimit) {
602 				(void)putchar('(');
603 				rlimitname((int)*ip);
604 				ip++;
605 				narg--;
606 				c = ',';
607 			} else if (ktr->ktr_code == SYS_quotactl) {
608 				print_number(ip,narg,c);
609 				quotactlname((int)*ip);
610 				ip++;
611 				narg--;
612 				c = ',';
613 			} else if (ktr->ktr_code == SYS_nfssvc) {
614 				(void)putchar('(');
615 				nfssvcname((int)*ip);
616 				ip++;
617 				narg--;
618 				c = ',';
619 			} else if (ktr->ktr_code == SYS_rtprio) {
620 				(void)putchar('(');
621 				rtprioname((int)*ip);
622 				ip++;
623 				narg--;
624 				c = ',';
625 			} else if (ktr->ktr_code == SYS___semctl) {
626 				print_number(ip,narg,c);
627 				print_number(ip,narg,c);
628 				semctlname((int)*ip);
629 				ip++;
630 				narg--;
631 			} else if (ktr->ktr_code == SYS_semget) {
632 				print_number(ip,narg,c);
633 				print_number(ip,narg,c);
634 				semgetname((int)*ip);
635 				ip++;
636 				narg--;
637 			} else if (ktr->ktr_code == SYS_msgctl) {
638 				print_number(ip,narg,c);
639 				shmctlname((int)*ip);
640 				ip++;
641 				narg--;
642 			} else if (ktr->ktr_code == SYS_shmat) {
643 				print_number(ip,narg,c);
644 				print_number(ip,narg,c);
645 				shmatname((int)*ip);
646 				ip++;
647 				narg--;
648 			} else if (ktr->ktr_code == SYS_shmctl) {
649 				print_number(ip,narg,c);
650 				shmctlname((int)*ip);
651 				ip++;
652 				narg--;
653 			} else if (ktr->ktr_code == SYS_minherit) {
654 				print_number(ip,narg,c);
655 				print_number(ip,narg,c);
656 				minheritname((int)*ip);
657 				ip++;
658 				narg--;
659 			} else if (ktr->ktr_code == SYS_rfork) {
660 				(void)putchar('(');
661 				rforkname((int)*ip);
662 				ip++;
663 				narg--;
664 				c = ',';
665 			} else if (ktr->ktr_code == SYS_lio_listio) {
666 				(void)putchar('(');
667 				lio_listioname((int)*ip);
668 				ip++;
669 				narg--;
670 				c = ',';
671 			} else if (ktr->ktr_code == SYS_mlockall) {
672 				(void)putchar('(');
673 				mlockallname((int)*ip);
674 				ip++;
675 				narg--;
676 			} else if (ktr->ktr_code == SYS_sched_setscheduler) {
677 				print_number(ip,narg,c);
678 				schedpolicyname((int)*ip);
679 				ip++;
680 				narg--;
681 			} else if (ktr->ktr_code == SYS_sched_get_priority_max ||
682 				   ktr->ktr_code == SYS_sched_get_priority_min) {
683 				(void)putchar('(');
684 				schedpolicyname((int)*ip);
685 				ip++;
686 				narg--;
687 			} else if (ktr->ktr_code == SYS_sendfile) {
688 				print_number(ip,narg,c);
689 				print_number(ip,narg,c);
690 				print_number(ip,narg,c);
691 				print_number(ip,narg,c);
692 				print_number(ip,narg,c);
693 				print_number(ip,narg,c);
694 				sendfileflagsname((int)*ip);
695 				ip++;
696 				narg--;
697 			} else if (ktr->ktr_code == SYS_kldsym) {
698 				print_number(ip,narg,c);
699 				kldsymcmdname((int)*ip);
700 				ip++;
701 				narg--;
702 			} else if (ktr->ktr_code == SYS_sigprocmask) {
703 				(void)putchar('(');
704 				sigprocmaskhowname((int)*ip);
705 				ip++;
706 				narg--;
707 				c = ',';
708 			} else if (ktr->ktr_code == SYS___acl_get_file ||
709 				   ktr->ktr_code == SYS___acl_set_file ||
710 				   ktr->ktr_code == SYS___acl_get_fd ||
711 				   ktr->ktr_code == SYS___acl_set_fd ||
712 				   ktr->ktr_code == SYS___acl_delete_file ||
713 				   ktr->ktr_code == SYS___acl_delete_fd ||
714 				   ktr->ktr_code == SYS___acl_aclcheck_file ||
715 				   ktr->ktr_code == SYS___acl_aclcheck_fd ||
716 				   ktr->ktr_code == SYS___acl_get_link ||
717 				   ktr->ktr_code == SYS___acl_set_link ||
718 				   ktr->ktr_code == SYS___acl_delete_link ||
719 				   ktr->ktr_code == SYS___acl_aclcheck_link) {
720 				print_number(ip,narg,c);
721 				acltypename((int)*ip);
722 				ip++;
723 				narg--;
724 			} else if (ktr->ktr_code == SYS_sigaction) {
725 				(void)putchar('(');
726 				signame((int)*ip);
727 				ip++;
728 				narg--;
729 				c = ',';
730 			} else if (ktr->ktr_code == SYS_extattrctl) {
731 				print_number(ip,narg,c);
732 				extattrctlname((int)*ip);
733 				ip++;
734 				narg--;
735 			} else if (ktr->ktr_code == SYS_nmount) {
736 				print_number(ip,narg,c);
737 				print_number(ip,narg,c);
738 				(void)putchar(',');
739 				mountflagsname ((int)*ip);
740 				ip++;
741 				narg--;
742 			} else if (ktr->ktr_code == SYS_kse_thr_interrupt) {
743 				print_number(ip,narg,c);
744 				(void)putchar(',');
745 				ksethrcmdname ((int)*ip);
746 				ip++;
747 				narg--;
748 			} else if (ktr->ktr_code == SYS_thr_create) {
749 				print_number(ip,narg,c);
750 				print_number(ip,narg,c);
751 				(void)putchar(',');
752 				thrcreateflagsname ((int)*ip);
753 				ip++;
754 				narg--;
755 			} else if (ktr->ktr_code == SYS_thr_kill) {
756 				print_number(ip,narg,c);
757 				(void)putchar(',');
758 				signame ((int)*ip);
759 				ip++;
760 				narg--;
761 			} else if (ktr->ktr_code == SYS_kldunloadf) {
762 				print_number(ip,narg,c);
763 				(void)putchar(',');
764 				kldunloadfflagsname ((int)*ip);
765 				ip++;
766 				narg--;
767 			}
768 		}
769 		while (narg) {
770 			print_number(ip,narg,c);
771 		}
772 		(void)putchar(')');
773 	}
774 	(void)putchar('\n');
775 }
776 
777 void
778 ktrsysret(struct ktr_sysret *ktr)
779 {
780 	register_t ret = ktr->ktr_retval;
781 	int error = ktr->ktr_error;
782 	int code = ktr->ktr_code;
783 
784 	if (code >= nsyscalls || code < 0)
785 		(void)printf("[%d] ", code);
786 	else
787 		(void)printf("%s ", syscallnames[code]);
788 
789 	if (error == 0) {
790 		if (fancy) {
791 			(void)printf("%d", ret);
792 			if (ret < 0 || ret > 9)
793 				(void)printf("/%#lx", (long)ret);
794 		} else {
795 			if (decimal)
796 				(void)printf("%ld", (long)ret);
797 			else
798 				(void)printf("%#lx", (long)ret);
799 		}
800 	} else if (error == ERESTART)
801 		(void)printf("RESTART");
802 	else if (error == EJUSTRETURN)
803 		(void)printf("JUSTRETURN");
804 	else {
805 		(void)printf("-1 errno %d", ktr->ktr_error);
806 		if (fancy)
807 			(void)printf(" %s", strerror(ktr->ktr_error));
808 	}
809 	(void)putchar('\n');
810 }
811 
812 void
813 ktrnamei(char *cp, int len)
814 {
815 	(void)printf("\"%.*s\"\n", len, cp);
816 }
817 
818 void
819 hexdump(char *p, int len, int screenwidth)
820 {
821 	int n, i;
822 	int width;
823 
824 	width = 0;
825 	do {
826 		width += 2;
827 		i = 13;			/* base offset */
828 		i += (width / 2) + 1;	/* spaces every second byte */
829 		i += (width * 2);	/* width of bytes */
830 		i += 3;			/* "  |" */
831 		i += width;		/* each byte */
832 		i += 1;			/* "|" */
833 	} while (i < screenwidth);
834 	width -= 2;
835 
836 	for (n = 0; n < len; n += width) {
837 		for (i = n; i < n + width; i++) {
838 			if ((i % width) == 0) {	/* beginning of line */
839 				printf("       0x%04x", i);
840 			}
841 			if ((i % 2) == 0) {
842 				printf(" ");
843 			}
844 			if (i < len)
845 				printf("%02x", p[i] & 0xff);
846 			else
847 				printf("  ");
848 		}
849 		printf("  |");
850 		for (i = n; i < n + width; i++) {
851 			if (i >= len)
852 				break;
853 			if (p[i] >= ' ' && p[i] <= '~')
854 				printf("%c", p[i]);
855 			else
856 				printf(".");
857 		}
858 		printf("|\n");
859 	}
860 	if ((i % width) != 0)
861 		printf("\n");
862 }
863 
864 void
865 visdump(char *dp, int datalen, int screenwidth)
866 {
867 	int col = 0;
868 	char *cp;
869 	int width;
870 	char visbuf[5];
871 
872 	(void)printf("       \"");
873 	col = 8;
874 	for (;datalen > 0; datalen--, dp++) {
875 		(void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
876 		cp = visbuf;
877 		/*
878 		 * Keep track of printables and
879 		 * space chars (like fold(1)).
880 		 */
881 		if (col == 0) {
882 			(void)putchar('\t');
883 			col = 8;
884 		}
885 		switch(*cp) {
886 		case '\n':
887 			col = 0;
888 			(void)putchar('\n');
889 			continue;
890 		case '\t':
891 			width = 8 - (col&07);
892 			break;
893 		default:
894 			width = strlen(cp);
895 		}
896 		if (col + width > (screenwidth-2)) {
897 			(void)printf("\\\n\t");
898 			col = 8;
899 		}
900 		col += width;
901 		do {
902 			(void)putchar(*cp++);
903 		} while (*cp);
904 	}
905 	if (col == 0)
906 		(void)printf("       ");
907 	(void)printf("\"\n");
908 }
909 
910 void
911 ktrgenio(struct ktr_genio *ktr, int len)
912 {
913 	int datalen = len - sizeof (struct ktr_genio);
914 	char *dp = (char *)ktr + sizeof (struct ktr_genio);
915 	static int screenwidth = 0;
916 	int i, binary;
917 
918 	if (screenwidth == 0) {
919 		struct winsize ws;
920 
921 		if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
922 		    ws.ws_col > 8)
923 			screenwidth = ws.ws_col;
924 		else
925 			screenwidth = 80;
926 	}
927 	printf("fd %d %s %d byte%s\n", ktr->ktr_fd,
928 		ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen,
929 		datalen == 1 ? "" : "s");
930 	if (suppressdata)
931 		return;
932 	if (maxdata && datalen > maxdata)
933 		datalen = maxdata;
934 
935 	for (i = 0, binary = 0; i < datalen && binary == 0; i++)  {
936 		if (dp[i] >= 32 && dp[i] < 127)
937 			continue;
938 		if (dp[i] == 10 || dp[i] == 13 || dp[i] == 0 || dp[i] == 9)
939 			continue;
940 		binary = 1;
941 	}
942 	if (binary)
943 		hexdump(dp, datalen, screenwidth);
944 	else
945 		visdump(dp, datalen, screenwidth);
946 }
947 
948 const char *signames[] = {
949 	"NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT",	/*  1 - 6  */
950 	"EMT", "FPE", "KILL", "BUS", "SEGV", "SYS",		/*  7 - 12 */
951 	"PIPE", "ALRM",  "TERM", "URG", "STOP", "TSTP",		/* 13 - 18 */
952 	"CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU",		/* 19 - 24 */
953 	"XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1",	/* 25 - 30 */
954 	"USR2", NULL,						/* 31 - 32 */
955 };
956 
957 void
958 ktrpsig(struct ktr_psig *psig)
959 {
960 	if (psig->signo > 0 && psig->signo < NSIG)
961 		(void)printf("SIG%s ", signames[psig->signo]);
962 	else
963 		(void)printf("SIG %d ", psig->signo);
964 	if (psig->action == SIG_DFL)
965 		(void)printf("SIG_DFL\n");
966 	else {
967 		(void)printf("caught handler=0x%lx mask=0x%x code=0x%x\n",
968 		    (u_long)psig->action, psig->mask.__bits[0], psig->code);
969 	}
970 }
971 
972 void
973 ktrcsw(struct ktr_csw *cs)
974 {
975 	(void)printf("%s %s\n", cs->out ? "stop" : "resume",
976 		cs->user ? "user" : "kernel");
977 }
978 
979 #define	UTRACE_DLOPEN_START		1
980 #define	UTRACE_DLOPEN_STOP		2
981 #define	UTRACE_DLCLOSE_START		3
982 #define	UTRACE_DLCLOSE_STOP		4
983 #define	UTRACE_LOAD_OBJECT		5
984 #define	UTRACE_UNLOAD_OBJECT		6
985 #define	UTRACE_ADD_RUNDEP		7
986 #define	UTRACE_PRELOAD_FINISHED		8
987 #define	UTRACE_INIT_CALL		9
988 #define	UTRACE_FINI_CALL		10
989 
990 struct utrace_rtld {
991 	char sig[4];				/* 'RTLD' */
992 	int event;
993 	void *handle;
994 	void *mapbase;
995 	size_t mapsize;
996 	int refcnt;
997 	char name[MAXPATHLEN];
998 };
999 
1000 void
1001 ktruser_rtld(int len, unsigned char *p)
1002 {
1003 	struct utrace_rtld *ut = (struct utrace_rtld *)p;
1004 	void *parent;
1005 	int mode;
1006 
1007 	switch (ut->event) {
1008 	case UTRACE_DLOPEN_START:
1009 		mode = ut->refcnt;
1010 		printf("dlopen(%s, ", ut->name);
1011 		switch (mode & RTLD_MODEMASK) {
1012 		case RTLD_NOW:
1013 			printf("RTLD_NOW");
1014 			break;
1015 		case RTLD_LAZY:
1016 			printf("RTLD_LAZY");
1017 			break;
1018 		default:
1019 			printf("%#x", mode & RTLD_MODEMASK);
1020 		}
1021 		if (mode & RTLD_GLOBAL)
1022 			printf(" | RTLD_GLOBAL");
1023 		if (mode & RTLD_TRACE)
1024 			printf(" | RTLD_TRACE");
1025 		if (mode & ~(RTLD_MODEMASK | RTLD_GLOBAL | RTLD_TRACE))
1026 			printf(" | %#x", mode &
1027 			    ~(RTLD_MODEMASK | RTLD_GLOBAL | RTLD_TRACE));
1028 		printf(")\n");
1029 		break;
1030 	case UTRACE_DLOPEN_STOP:
1031 		printf("%p = dlopen(%s) ref %d\n", ut->handle, ut->name,
1032 		    ut->refcnt);
1033 		break;
1034 	case UTRACE_DLCLOSE_START:
1035 		printf("dlclose(%p) (%s, %d)\n", ut->handle, ut->name,
1036 		    ut->refcnt);
1037 		break;
1038 	case UTRACE_DLCLOSE_STOP:
1039 		printf("dlclose(%p) finished\n", ut->handle);
1040 		break;
1041 	case UTRACE_LOAD_OBJECT:
1042 		printf("RTLD: loaded   %p @ %p - %p (%s)\n", ut->handle,
1043 		    ut->mapbase, (char *)ut->mapbase + ut->mapsize - 1,
1044 		    ut->name);
1045 		break;
1046 	case UTRACE_UNLOAD_OBJECT:
1047 		printf("RTLD: unloaded %p @ %p - %p (%s)\n", ut->handle,
1048 		    ut->mapbase, (char *)ut->mapbase + ut->mapsize - 1,
1049 		    ut->name);
1050 		break;
1051 	case UTRACE_ADD_RUNDEP:
1052 		parent = ut->mapbase;
1053 		printf("RTLD: %p now depends on %p (%s, %d)\n", parent,
1054 		    ut->handle, ut->name, ut->refcnt);
1055 		break;
1056 	case UTRACE_PRELOAD_FINISHED:
1057 		printf("RTLD: LD_PRELOAD finished\n");
1058 		break;
1059 	case UTRACE_INIT_CALL:
1060 		printf("RTLD: init %p for %p (%s)\n", ut->mapbase, ut->handle,
1061 		    ut->name);
1062 		break;
1063 	case UTRACE_FINI_CALL:
1064 		printf("RTLD: fini %p for %p (%s)\n", ut->mapbase, ut->handle,
1065 		    ut->name);
1066 		break;
1067 	default:
1068 		p += 4;
1069 		len -= 4;
1070 		printf("RTLD: %d ", len);
1071 		while (len--)
1072 			if (decimal)
1073 				printf(" %d", *p++);
1074 			else
1075 				printf(" %02x", *p++);
1076 		printf("\n");
1077 	}
1078 }
1079 
1080 struct utrace_malloc {
1081 	void *p;
1082 	size_t s;
1083 	void *r;
1084 };
1085 
1086 void
1087 ktruser_malloc(int len, unsigned char *p)
1088 {
1089 	struct utrace_malloc *ut = (struct utrace_malloc *)p;
1090 
1091 	if (ut->p == NULL) {
1092 		if (ut->s == 0 && ut->r == NULL)
1093 			printf("malloc_init()\n");
1094 		else
1095 			printf("%p = malloc(%zu)\n", ut->r, ut->s);
1096 	} else {
1097 		if (ut->s == 0)
1098 			printf("free(%p)\n", ut->p);
1099 		else
1100 			printf("%p = realloc(%p, %zu)\n", ut->r, ut->p, ut->s);
1101 	}
1102 }
1103 
1104 void
1105 ktruser(int len, unsigned char *p)
1106 {
1107 
1108 	if (len >= 8 && bcmp(p, "RTLD", 4) == 0) {
1109 		ktruser_rtld(len, p);
1110 		return;
1111 	}
1112 
1113 	if (len == sizeof(struct utrace_malloc)) {
1114 		ktruser_malloc(len, p);
1115 		return;
1116 	}
1117 
1118 	(void)printf("%d ", len);
1119 	while (len--)
1120 		if (decimal)
1121 			(void)printf(" %d", *p++);
1122 		else
1123 			(void)printf(" %02x", *p++);
1124 	(void)printf("\n");
1125 }
1126 
1127 void
1128 usage(void)
1129 {
1130 	(void)fprintf(stderr,
1131   "usage: kdump [-dEnlHRsT] [-f trfile] [-m maxdata] [-p pid] [-t [cnisuw]]\n");
1132 	exit(1);
1133 }
1134