xref: /openbsd/usr.bin/kdump/kdump.c (revision 891d7ab6)
1 /*	$OpenBSD: kdump.c,v 1.51 2011/06/20 17:54:48 otto Exp $	*/
2 
3 /*-
4  * Copyright (c) 1988, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/param.h>
33 #include <sys/time.h>
34 #include <sys/uio.h>
35 #include <sys/ktrace.h>
36 #include <sys/ioctl.h>
37 #include <sys/ptrace.h>
38 #include <sys/socket.h>
39 #include <sys/sysctl.h>
40 #define _KERNEL
41 #include <sys/errno.h>
42 #undef _KERNEL
43 
44 #include <ctype.h>
45 #include <err.h>
46 #include <signal.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <vis.h>
52 
53 #include "ktrace.h"
54 #include "kdump.h"
55 #include "kdump_subr.h"
56 #include "extern.h"
57 
58 int timestamp, decimal, iohex, fancy = 1, tail, maxdata;
59 char *tracefile = DEF_TRACEFILE;
60 struct ktr_header ktr_header;
61 pid_t pid = -1;
62 
63 #define eqs(s1, s2)	(strcmp((s1), (s2)) == 0)
64 
65 #include <sys/syscall.h>
66 
67 #include <compat/linux/linux_syscall.h>
68 #include <compat/svr4/svr4_syscall.h>
69 
70 #define KTRACE
71 #define PTRACE
72 #define NFSCLIENT
73 #define NFSSERVER
74 #define SYSVSEM
75 #define SYSVMSG
76 #define SYSVSHM
77 #define LFS
78 #include <kern/syscalls.c>
79 
80 #include <compat/linux/linux_syscalls.c>
81 #include <compat/svr4/svr4_syscalls.c>
82 #undef KTRACE
83 #undef PTRACE
84 #undef NFSCLIENT
85 #undef NFSSERVER
86 #undef SYSVSEM
87 #undef SYSVMSG
88 #undef SYSVSHM
89 #undef LFS
90 
91 struct emulation {
92 	char *name;		/* Emulation name */
93 	char **sysnames;	/* Array of system call names */
94 	int  nsysnames;		/* Number of */
95 };
96 
97 static struct emulation emulations[] = {
98 	{ "native",	syscallnames,		SYS_MAXSYSCALL },
99 	{ "linux",	linux_syscallnames,	LINUX_SYS_MAXSYSCALL },
100 	{ "svr4",	svr4_syscallnames,	SVR4_SYS_MAXSYSCALL },
101 	{ NULL,		NULL,			0 }
102 };
103 
104 struct emulation *current;
105 
106 
107 static char *ptrace_ops[] = {
108 	"PT_TRACE_ME",	"PT_READ_I",	"PT_READ_D",	"PT_READ_U",
109 	"PT_WRITE_I",	"PT_WRITE_D",	"PT_WRITE_U",	"PT_CONTINUE",
110 	"PT_KILL",	"PT_ATTACH",	"PT_DETACH",	"PT_IO",
111 };
112 
113 static int fread_tail(void *, size_t, size_t);
114 static void dumpheader(struct ktr_header *);
115 static void ktrcsw(struct ktr_csw *);
116 static void ktremul(char *, size_t);
117 static void ktrgenio(struct ktr_genio *, size_t);
118 static void ktrnamei(const char *, size_t);
119 static void ktrpsig(struct ktr_psig *);
120 static void ktrsyscall(struct ktr_syscall *);
121 static void ktrsysret(struct ktr_sysret *);
122 static void setemul(const char *);
123 static void usage(void);
124 
125 int
126 main(int argc, char *argv[])
127 {
128 	int ch, silent;
129 	size_t ktrlen, size;
130 	int trpoints = ALL_POINTS;
131 	void *m;
132 
133 	current = &emulations[0];	/* native */
134 
135 	while ((ch = getopt(argc, argv, "e:f:dlm:nRp:Tt:xX")) != -1)
136 		switch (ch) {
137 		case 'e':
138 			setemul(optarg);
139 			break;
140 		case 'f':
141 			tracefile = optarg;
142 			break;
143 		case 'd':
144 			decimal = 1;
145 			break;
146 		case 'l':
147 			tail = 1;
148 			break;
149 		case 'm':
150 			maxdata = atoi(optarg);
151 			break;
152 		case 'n':
153 			fancy = 0;
154 			break;
155 		case 'p':
156 			pid = atoi(optarg);
157 			break;
158 		case 'R':
159 			timestamp = 2;	/* relative timestamp */
160 			break;
161 		case 'T':
162 			timestamp = 1;
163 			break;
164 		case 't':
165 			trpoints = getpoints(optarg);
166 			if (trpoints < 0)
167 				errx(1, "unknown trace point in %s", optarg);
168 			break;
169 		case 'x':
170 			iohex = 1;
171 			break;
172 		case 'X':
173 			iohex = 2;
174 			break;
175 		default:
176 			usage();
177 		}
178 	if (argc > optind)
179 		usage();
180 
181 	m = malloc(size = 1025);
182 	if (m == NULL)
183 		err(1, NULL);
184 	if (!freopen(tracefile, "r", stdin))
185 		err(1, "%s", tracefile);
186 	while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) {
187 		silent = 0;
188 		if (pid != -1 && pid != ktr_header.ktr_pid)
189 			silent = 1;
190 		if (silent == 0 && trpoints & (1<<ktr_header.ktr_type))
191 			dumpheader(&ktr_header);
192 		ktrlen = ktr_header.ktr_len;
193 		if (ktrlen > size) {
194 			void *newm;
195 
196 			newm = realloc(m, ktrlen+1);
197 			if (newm == NULL)
198 				err(1, NULL);
199 			m = newm;
200 			size = ktrlen;
201 		}
202 		if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
203 			errx(1, "data too short");
204 		if (silent)
205 			continue;
206 		if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
207 			continue;
208 		switch (ktr_header.ktr_type) {
209 		case KTR_SYSCALL:
210 			ktrsyscall((struct ktr_syscall *)m);
211 			break;
212 		case KTR_SYSRET:
213 			ktrsysret((struct ktr_sysret *)m);
214 			break;
215 		case KTR_NAMEI:
216 			ktrnamei(m, ktrlen);
217 			break;
218 		case KTR_GENIO:
219 			ktrgenio((struct ktr_genio *)m, ktrlen);
220 			break;
221 		case KTR_PSIG:
222 			ktrpsig((struct ktr_psig *)m);
223 			break;
224 		case KTR_CSW:
225 			ktrcsw((struct ktr_csw *)m);
226 			break;
227 		case KTR_EMUL:
228 			ktremul(m, ktrlen);
229 			break;
230 		}
231 		if (tail)
232 			(void)fflush(stdout);
233 	}
234 	exit(0);
235 }
236 
237 static int
238 fread_tail(void *buf, size_t size, size_t num)
239 {
240 	int i;
241 
242 	while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
243 		(void)sleep(1);
244 		clearerr(stdin);
245 	}
246 	return (i);
247 }
248 
249 static void
250 dumpheader(struct ktr_header *kth)
251 {
252 	static struct timeval prevtime;
253 	char unknown[64], *type;
254 	struct timeval temp;
255 
256 	switch (kth->ktr_type) {
257 	case KTR_SYSCALL:
258 		type = "CALL";
259 		break;
260 	case KTR_SYSRET:
261 		type = "RET ";
262 		break;
263 	case KTR_NAMEI:
264 		type = "NAMI";
265 		break;
266 	case KTR_GENIO:
267 		type = "GIO ";
268 		break;
269 	case KTR_PSIG:
270 		type = "PSIG";
271 		break;
272 	case KTR_CSW:
273 		type = "CSW";
274 		break;
275 	case KTR_EMUL:
276 		type = "EMUL";
277 		break;
278 	default:
279 		(void)snprintf(unknown, sizeof unknown, "UNKNOWN(%d)",
280 		    kth->ktr_type);
281 		type = unknown;
282 	}
283 
284 	(void)printf("%6ld %-8.*s ", (long)kth->ktr_pid, MAXCOMLEN,
285 	    kth->ktr_comm);
286 	if (timestamp) {
287 		if (timestamp == 2) {
288 			timersub(&kth->ktr_time, &prevtime, &temp);
289 			prevtime = kth->ktr_time;
290 		} else
291 			temp = kth->ktr_time;
292 		(void)printf("%ld.%06ld ", temp.tv_sec, temp.tv_usec);
293 	}
294 	(void)printf("%s  ", type);
295 }
296 
297 static void
298 ioctldecode(u_long cmd)
299 {
300 	char dirbuf[4], *dir = dirbuf;
301 
302 	if (cmd & IOC_IN)
303 		*dir++ = 'W';
304 	if (cmd & IOC_OUT)
305 		*dir++ = 'R';
306 	*dir = '\0';
307 
308 	printf(decimal ? ",_IO%s('%c',%lu" : ",_IO%s('%c',%#lx",
309 	    dirbuf, (int)((cmd >> 8) & 0xff), cmd & 0xff);
310 	if ((cmd & IOC_VOID) == 0)
311 		printf(decimal ? ",%lu)" : ",%#lx)", (cmd >> 16) & 0xff);
312 	else
313 		printf(")");
314 }
315 
316 #define print_number(i, n, c) do {			\
317 	if (c)						\
318 		(void)putchar(c);			\
319 	if (decimal)					\
320 		(void)printf("%ld", (long)*i);		\
321 	else						\
322 		(void)printf("%#lx", (long)*i);		\
323 	i++;						\
324 	n--; 						\
325 	c = ',';					\
326 } while (0);
327 
328 static void
329 ktrsyscall(struct ktr_syscall *ktr)
330 {
331 	int narg = ktr->ktr_argsize / sizeof(register_t);
332 	register_t *ap;
333 
334 	if (ktr->ktr_code >= current->nsysnames || ktr->ktr_code < 0)
335 		(void)printf("[%d]", ktr->ktr_code);
336 	else
337 		(void)printf("%s", current->sysnames[ktr->ktr_code]);
338 	ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall));
339 	(void)putchar('(');
340 	if (narg) {
341 		char c = '\0';
342 		if (fancy) {
343 			switch (ktr->ktr_code) {
344 			case SYS_ioctl: {
345 				const char *cp;
346 
347 				if (decimal)
348 					(void)printf("%ld", (long)*ap);
349 				else
350 					(void)printf("%#lx", (long)*ap);
351 				ap++;
352 				narg--;
353 				if ((cp = ioctlname(*ap)) != NULL)
354 					(void)printf(",%s", cp);
355 				else
356 					ioctldecode(*ap);
357 				c = ',';
358 				ap++;
359 				narg--;
360 				break;
361 			}
362 			case SYS___sysctl: {
363 				int *np, n;
364 
365 				n = ap[1];
366 				if (n > CTL_MAXNAME)
367 					n = CTL_MAXNAME;
368 				np = (int *)(ap + 6);
369 				for (; n--; np++) {
370 					if (c)
371 						putchar(c);
372 					printf("%d", *np);
373 					c = '.';
374 				}
375 
376 				c = ',';
377 				ap += 2;
378 				narg -= 2;
379 				break;
380 			}
381 			case SYS_ptrace:
382 				if (*ap >= 0 && *ap <
383 				    sizeof(ptrace_ops) / sizeof(ptrace_ops[0]))
384 					(void)printf("%s", ptrace_ops[*ap]);
385 				else switch(*ap) {
386 #ifdef PT_GETFPREGS
387 				case PT_GETFPREGS:
388 					(void)printf("PT_GETFPREGS");
389 					break;
390 #endif
391 				case PT_GETREGS:
392 					(void)printf("PT_GETREGS");
393 					break;
394 #ifdef PT_SETFPREGS
395 				case PT_SETFPREGS:
396 					(void)printf("PT_SETFPREGS");
397 					break;
398 #endif
399 				case PT_SETREGS:
400 					(void)printf("PT_SETREGS");
401 					break;
402 #ifdef PT_STEP
403 				case PT_STEP:
404 					(void)printf("PT_STEP");
405 					break;
406 #endif
407 #ifdef PT_WCOOKIE
408 				case PT_WCOOKIE:
409 					(void)printf("PT_WCOOKIE");
410 					break;
411 #endif
412 				default:
413 					(void)printf("%ld", (long)*ap);
414 					break;
415 				}
416 				c = ',';
417 				ap++;
418 				narg--;
419 				break;
420 			case SYS_access:
421 				print_number(ap, narg, c);
422 				(void)putchar(',');
423 				accessmodename((int)*ap);
424 				ap++;
425 				narg--;
426 				break;
427 			case SYS_chmod:
428 			case SYS_fchmod:
429 				print_number(ap, narg, c);
430 				(void)putchar(',');
431 				modename((int)*ap);
432 				ap++;
433 				narg--;
434 				break;
435 			case SYS_fcntl: {
436 				int cmd;
437 				int arg;
438 				print_number(ap, narg, c);
439 				cmd = *ap;
440 				arg = *++ap;
441 				(void)putchar(',');
442 				fcntlcmdname(cmd, arg, decimal);
443 				ap++;
444 				narg -= 2;
445 				break;
446 			}
447 			case SYS_flock:
448 				print_number(ap, narg, c);
449 				(void)putchar(',');
450 				flockname((int)*ap);
451 				ap++;
452 				narg--;
453 				break;
454 			case SYS_getrlimit:
455 			case SYS_setrlimit:
456 				rlimitname((int)*ap);
457 				ap++;
458 				narg--;
459 				c = ',';
460 				break;
461 			case SYS_getsockopt:
462 			case SYS_setsockopt:
463 				print_number(ap, narg, c);
464 				(void)putchar(',');
465 				sockoptlevelname((int)*ap, decimal);
466 				if ((int)*ap == SOL_SOCKET) {
467 					ap++;
468 					narg--;
469 					(void)putchar(',');
470 					sockoptname((int)*ap);
471 				}
472 				ap++;
473 				narg--;
474 				break;
475 			case SYS_kill:
476 				print_number(ap, narg, c);
477 				(void)putchar(',');
478 				signame((int)*ap);
479 				ap++;
480 				narg--;
481 				break;
482 			case SYS_lseek:
483 				print_number(ap, narg, c);
484 				/* skip padding */
485 				ap++;
486 				narg--;
487 				print_number(ap, narg, c);
488 				(void)putchar(',');
489 				whencename((int)*ap);
490 				ap++;
491 				narg--;
492 				break;
493 			case SYS_madvise:
494 				print_number(ap, narg, c);
495 				print_number(ap, narg, c);
496 				(void)putchar(',');
497 				madvisebehavname((int)*ap);
498 				ap++;
499 				narg--;
500 				break;
501 			case SYS_minherit:
502 				print_number(ap, narg, c);
503 				print_number(ap, narg, c);
504 				(void)putchar(',');
505 				minheritname((int)*ap);
506 				ap++;
507 				narg--;
508 				break;
509 			case SYS_mlockall:
510 				mlockallname((int)*ap);
511 				ap++;
512 				narg--;
513 				break;
514 			case SYS_mmap:
515 				print_number(ap, narg, c);
516 				print_number(ap, narg, c);
517 				(void)putchar(',');
518 				mmapprotname((int)*ap);
519 				(void)putchar(',');
520 				ap++;
521 				narg--;
522 				mmapflagsname((int)*ap);
523 				ap++;
524 				narg--;
525 				print_number(ap, narg, c);
526 				/* skip padding */
527 				ap++;
528 				narg--;
529 				break;
530 			case SYS_mprotect:
531 				print_number(ap, narg, c);
532 				print_number(ap, narg, c);
533 				(void)putchar(',');
534 				mmapprotname((int)*ap);
535 				ap++;
536 				narg--;
537 				break;
538 			case SYS_mquery:
539 				print_number(ap, narg, c);
540 				print_number(ap, narg, c);
541 				(void)putchar(',');
542 				mmapprotname((int)*ap);
543 				ap++;
544 				narg--;
545 				(void)putchar(',');
546 				mmapflagsname((int)*ap);
547 				ap++;
548 				narg--;
549 				print_number(ap, narg, c);
550 				/* skip padding */
551 				ap++;
552 				narg--;
553 				break;
554 			case SYS_msync:
555 				print_number(ap, narg, c);
556 				print_number(ap, narg, c);
557 				(void)putchar(',');
558 				msyncflagsname((int)*ap);
559 				ap++;
560 				narg--;
561 				break;
562 			case SYS_msgctl:
563 				print_number(ap, narg, c);
564 				(void)putchar(',');
565 				shmctlname((int)*ap);
566 				ap++;
567 				narg--;
568 				break;
569 			case SYS_open: {
570 				int     flags;
571 				int     mode;
572 				print_number(ap, narg, c);
573 				flags = *ap;
574 				mode = *++ap;
575 				(void)putchar(',');
576 				flagsandmodename(flags, mode, decimal);
577 				ap++;
578 				narg -= 2;
579 				break;
580 			}
581 			case SYS_pread:
582 			case SYS_preadv:
583 			case SYS_pwrite:
584 			case SYS_pwritev:
585 				print_number(ap, narg, c);
586 				print_number(ap, narg, c);
587 				print_number(ap, narg, c);
588 				/* skip padding */
589 				ap++;
590 				narg--;
591 				break;
592 			case SYS_recvmsg:
593 			case SYS_sendmsg:
594 				print_number(ap, narg, c);
595 				print_number(ap, narg, c);
596 				(void)putchar(',');
597 				sendrecvflagsname((int)*ap);
598 				ap++;
599 				narg--;
600 				break;
601 			case SYS_recvfrom:
602 			case SYS_sendto:
603 				print_number(ap, narg, c);
604 				print_number(ap, narg, c);
605 				print_number(ap, narg, c);
606 				(void)putchar(',');
607 				sendrecvflagsname((int)*ap);
608 				ap++;
609 				narg--;
610 				break;
611 			case SYS___semctl:
612 				print_number(ap, narg, c);
613 				print_number(ap, narg, c);
614 				(void)putchar(',');
615 				semctlname((int)*ap);
616 				ap++;
617 				narg--;
618 				break;
619 			case SYS_semget:
620 				print_number(ap, narg, c);
621 				print_number(ap, narg, c);
622 				(void)putchar(',');
623 				semgetname((int)*ap);
624 				ap++;
625 				narg--;
626 				break;
627 			case SYS_shmat:
628 				print_number(ap, narg, c);
629 				print_number(ap, narg, c);
630 				(void)putchar(',');
631 				shmatname((int)*ap);
632 				ap++;
633 				narg--;
634 				break;
635 			case SYS_shmctl:
636 				print_number(ap, narg, c);
637 				(void)putchar(',');
638 				shmctlname((int)*ap);
639 				ap++;
640 				narg--;
641 				break;
642 			case SYS_sigaction:
643 				signame((int)*ap);
644 				ap++;
645 				narg--;
646 				c = ',';
647 				break;
648 			case SYS_sigprocmask:
649 				sigprocmaskhowname((int)*ap);
650 				ap++;
651 				narg--;
652 				c = ',';
653 				break;
654 			case SYS_socket: {
655 				int sockdomain = (int)*ap;
656 				sockdomainname(sockdomain);
657 				ap++;
658 				narg--;
659 				(void)putchar(',');
660 				socktypename((int)*ap);
661 				ap++;
662 				narg--;
663 				if (sockdomain == PF_INET ||
664 				    sockdomain == PF_INET6) {
665 					(void)putchar(',');
666 					sockipprotoname((int)*ap);
667 					ap++;
668 					narg--;
669 				}
670 				c = ',';
671 				break;
672 			}
673 			case SYS_socketpair:
674 				sockdomainname((int)*ap);
675 				ap++;
676 				narg--;
677 				(void)putchar(',');
678 				socktypename((int)*ap);
679 				ap++;
680 				narg--;
681 				c = ',';
682 				break;
683 			case SYS_truncate:
684 			case SYS_ftruncate:
685 				print_number(ap, narg, c);
686 				/* skip padding */
687 				ap++;
688 				narg--;
689 				break;
690 			case SYS_wait4:
691 				print_number(ap, narg, c);
692 				print_number(ap, narg, c);
693 				(void)putchar(',');
694 				wait4optname((int)*ap);
695 				ap++;
696 				narg--;
697 				break;
698 			}
699 		}
700 		while (narg) {
701 			if (c)
702 				putchar(c);
703 			if (decimal)
704 				(void)printf("%ld", (long)*ap);
705 			else
706 				(void)printf("%#lx", (long)*ap);
707 			c = ',';
708 			ap++;
709 			narg--;
710 		}
711 	}
712 	(void)printf(")\n");
713 }
714 
715 static void
716 ktrsysret(struct ktr_sysret *ktr)
717 {
718 	register_t ret = ktr->ktr_retval;
719 	int error = ktr->ktr_error;
720 	int code = ktr->ktr_code;
721 
722 	if (code >= current->nsysnames || code < 0)
723 		(void)printf("[%d] ", code);
724 	else
725 		(void)printf("%s ", current->sysnames[code]);
726 
727 	if (error == 0) {
728 		if (fancy) {
729 			(void)printf("%ld", (long)ret);
730 			if (ret < 0 || ret > 9)
731 				(void)printf("/%#lx", (long)ret);
732 		} else {
733 			if (decimal)
734 				(void)printf("%ld", (long)ret);
735 			else
736 				(void)printf("%#lx", (long)ret);
737 		}
738 	} else if (error == ERESTART)
739 		(void)printf("RESTART");
740 	else if (error == EJUSTRETURN)
741 		(void)printf("JUSTRETURN");
742 	else {
743 		(void)printf("-1 errno %d", ktr->ktr_error);
744 		if (fancy)
745 			(void)printf(" %s", strerror(ktr->ktr_error));
746 	}
747 	(void)putchar('\n');
748 }
749 
750 static void
751 ktrnamei(const char *cp, size_t len)
752 {
753 	(void)printf("\"%.*s\"\n", (int)len, cp);
754 }
755 
756 static void
757 ktremul(char *cp, size_t len)
758 {
759 	char name[1024];
760 
761 	if (len >= sizeof(name))
762 		errx(1, "Emulation name too long");
763 
764 	strncpy(name, cp, len);
765 	name[len] = '\0';
766 	(void)printf("\"%s\"\n", name);
767 
768 	setemul(name);
769 }
770 
771 static void
772 ktrgenio(struct ktr_genio *ktr, size_t len)
773 {
774 	unsigned char *dp = (unsigned char *)ktr + sizeof(struct ktr_genio);
775 	int i, j;
776 	size_t datalen = len - sizeof(struct ktr_genio);
777 	static int screenwidth = 0;
778 	int col = 0, width, bpl;
779 	unsigned char visbuf[5], *cp, c;
780 
781 	if (screenwidth == 0) {
782 		struct winsize ws;
783 
784 		if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
785 		    ws.ws_col > 8)
786 			screenwidth = ws.ws_col;
787 		else
788 			screenwidth = 80;
789 	}
790 	printf("fd %d %s %zu bytes\n", ktr->ktr_fd,
791 		ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen);
792 	if (maxdata && datalen > maxdata)
793 		datalen = maxdata;
794 	if (iohex && !datalen)
795 		return;
796 	if (iohex == 1) {
797 		putchar('\t');
798 		col = 8;
799 		for (i = 0; i < datalen; i++) {
800 			printf("%02x", dp[i]);
801 			col += 3;
802 			if (i < datalen - 1) {
803 				if (col + 3 > screenwidth) {
804 					printf("\n\t");
805 					col = 8;
806 				} else
807 					putchar(' ');
808 			}
809 		}
810 		putchar('\n');
811 		return;
812 	}
813 	if (iohex == 2) {
814 		bpl = (screenwidth - 13)/4;
815 		if (bpl <= 0)
816 			bpl = 1;
817 		for (i = 0; i < datalen; i += bpl) {
818 			printf("   %04x:  ", i);
819 			for (j = 0; j < bpl; j++) {
820 				if (i+j >= datalen)
821 					printf("   ");
822 				else
823 					printf("%02x ", dp[i+j]);
824 			}
825 			putchar(' ');
826 			for (j = 0; j < bpl; j++) {
827 				if (i+j >= datalen)
828 					break;
829 				c = dp[i+j];
830 				if (!isprint(c))
831 					c = '.';
832 				putchar(c);
833 			}
834 			putchar('\n');
835 		}
836 		return;
837 	}
838 	(void)printf("       \"");
839 	col = 8;
840 	for (; datalen > 0; datalen--, dp++) {
841 		(void)vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
842 		cp = visbuf;
843 
844 		/*
845 		 * Keep track of printables and
846 		 * space chars (like fold(1)).
847 		 */
848 		if (col == 0) {
849 			(void)putchar('\t');
850 			col = 8;
851 		}
852 		switch (*cp) {
853 		case '\n':
854 			col = 0;
855 			(void)putchar('\n');
856 			continue;
857 		case '\t':
858 			width = 8 - (col&07);
859 			break;
860 		default:
861 			width = strlen(cp);
862 		}
863 		if (col + width > (screenwidth-2)) {
864 			(void)printf("\\\n\t");
865 			col = 8;
866 		}
867 		col += width;
868 		do {
869 			(void)putchar(*cp++);
870 		} while (*cp);
871 	}
872 	if (col == 0)
873 		(void)printf("       ");
874 	(void)printf("\"\n");
875 }
876 
877 static void
878 ktrpsig(struct ktr_psig *psig)
879 {
880 	(void)printf("SIG%s ", sys_signame[psig->signo]);
881 	if (psig->action == SIG_DFL)
882 		(void)printf("SIG_DFL code %d", psig->code);
883 	else
884 		(void)printf("caught handler=0x%lx mask=0x%x",
885 		    (u_long)psig->action, psig->mask);
886 	switch (psig->signo) {
887 	case SIGSEGV:
888 	case SIGILL:
889 	case SIGBUS:
890 	case SIGFPE:
891 		printf(" addr=%p trapno=%d", psig->si.si_addr,
892 		    psig->si.si_trapno);
893 		break;
894 	default:
895 		break;
896 	}
897 	printf("\n");
898 }
899 
900 static void
901 ktrcsw(struct ktr_csw *cs)
902 {
903 	(void)printf("%s %s\n", cs->out ? "stop" : "resume",
904 	    cs->user ? "user" : "kernel");
905 }
906 
907 static void
908 usage(void)
909 {
910 
911 	extern char *__progname;
912 	fprintf(stderr, "usage: %s "
913 	    "[-dlnRTXx] [-e emulation] [-f file] [-m maxdata] [-p pid]\n"
914 	    "%*s[-t [ceinsw]]\n",
915 	    __progname, (int)(sizeof("usage: ") + strlen(__progname)), "");
916 	exit(1);
917 }
918 
919 static void
920 setemul(const char *name)
921 {
922 	int i;
923 
924 	for (i = 0; emulations[i].name != NULL; i++)
925 		if (strcmp(emulations[i].name, name) == 0) {
926 			current = &emulations[i];
927 			return;
928 		}
929 	warnx("Emulation `%s' unknown", name);
930 }
931