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