xref: /dragonfly/usr.bin/ktrdump/ktrdump.c (revision e96fb831)
1 /*-
2  * Copyright (c) 2002 Jake Burkholder
3  * Copyright (c) 2004 Robert Watson
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD: src/usr.bin/ktrdump/ktrdump.c,v 1.10 2005/05/21 09:55:06 ru Exp $
28  * $DragonFly: src/usr.bin/ktrdump/ktrdump.c,v 1.13 2008/11/10 02:05:31 swildner Exp $
29  */
30 
31 #include <sys/cdefs.h>
32 
33 #include <sys/types.h>
34 #include <sys/ktr.h>
35 #include <sys/mman.h>
36 #include <sys/stat.h>
37 #include <sys/queue.h>
38 
39 #include <ctype.h>
40 #include <devinfo.h>
41 #include <err.h>
42 #include <fcntl.h>
43 #include <kvm.h>
44 #include <limits.h>
45 #include <nlist.h>
46 #include <stdint.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <evtr.h>
52 #include <stdarg.h>
53 
54 struct ktr_buffer {
55 	struct ktr_entry *ents;
56 	int modified;
57 	int reset;
58 	int beg_idx;		/* Beginning index */
59 	int end_idx;		/* Ending index */
60 };
61 
62 static struct nlist nl1[] = {
63 	{ .n_name = "_ktr_version" },
64 	{ .n_name = "_ktr_entries" },
65 	{ .n_name = "_ncpus" },
66 	{ .n_name = NULL }
67 };
68 
69 static struct nlist nl2[] = {
70 	{ .n_name = "_tsc_frequency" },
71 	{ .n_name = NULL }
72 };
73 
74 static struct nlist nl_version_ktr_idx[] = {
75 	{ .n_name = "_ktr_idx" },
76 	{ .n_name = "_ktr_buf" },
77 	{ .n_name = NULL }
78 };
79 
80 static struct nlist nl_version_ktr_cpu[] = {
81 	{ .n_name = "_ktr_cpu" },
82 	{ .n_name = NULL }
83 };
84 
85 struct save_ctx {
86 	char save_buf[512];
87 	const void *save_kptr;
88 };
89 
90 typedef void (*ktr_iter_cb_t)(void *, int, int, struct ktr_entry *, uint64_t *);
91 
92 #ifdef __x86_64__
93 /* defined according to the x86_64 ABI spec */
94 struct my_va_list {
95 	uint32_t gp_offset;	/* offset to next available gpr in reg_save_area */
96 	uint32_t fp_offset;	/* offset to next available fpr in reg_save_area */
97 	void *overflow_arg_area;	/* args that are passed on the stack */
98 	struct reg_save_area *reg_save_area;		/* register args */
99 } __attribute__((packed));
100 
101 typedef struct my_va_list machine_va_list;
102 
103 struct reg_save_area {
104 	uint64_t rdi, rsi, rdx, rcx, r8, r9;
105 	/* XMM registers follow, but we don't use them */
106 };
107 #elif __i386__
108 typedef void *machine_va_list;
109 #endif
110 
111 static int cflag;
112 static int dflag;
113 static int fflag;
114 static int iflag;
115 static int lflag;
116 static int nflag;
117 static int qflag;
118 static int rflag;
119 static int sflag;
120 static int tflag;
121 static int xflag;
122 static int pflag;
123 static int Mflag;
124 static int Nflag;
125 static double tsc_frequency;
126 static double correction_factor = 0.0;
127 
128 static char corefile[PATH_MAX];
129 static char execfile[PATH_MAX];
130 
131 static char errbuf[_POSIX2_LINE_MAX];
132 static int ncpus;
133 static kvm_t *kd;
134 static int entries_per_buf;
135 static int fifo_mask;
136 static int ktr_version;
137 
138 static void usage(void);
139 static int earliest_ts(struct ktr_buffer *);
140 static void dump_machine_info(evtr_t);
141 static void dump_device_info(evtr_t);
142 static void print_header(FILE *, int);
143 static void print_entry(FILE *, int, int, struct ktr_entry *, u_int64_t *);
144 static void print_callback(void *, int, int, struct ktr_entry *, uint64_t *);
145 static void dump_callback(void *, int, int, struct ktr_entry *, uint64_t *);
146 static struct ktr_info *kvm_ktrinfo(void *, struct save_ctx *);
147 static const char *kvm_string(const char *, struct save_ctx *);
148 static const char *trunc_path(const char *, int);
149 static void read_symbols(const char *);
150 static const char *address_to_symbol(void *, struct save_ctx *);
151 static struct ktr_buffer *ktr_bufs_init(void);
152 static void get_indices(struct ktr_entry **, int *);
153 static void load_bufs(struct ktr_buffer *, struct ktr_entry **, int *);
154 static void iterate_buf(FILE *, struct ktr_buffer *, int, u_int64_t *, ktr_iter_cb_t);
155 static void iterate_bufs_timesorted(FILE *, struct ktr_buffer *, u_int64_t *, ktr_iter_cb_t);
156 static void kvmfprintf(FILE *fp, const char *ctl, va_list va);
157 static int va_list_from_blob(machine_va_list *valist, const char *fmt, char *blob, size_t blobsize);
158 
159 /*
160  * Reads the ktr trace buffer from kernel memory and prints the trace entries.
161  */
162 int
163 main(int ac, char **av)
164 {
165 	struct ktr_buffer *ktr_bufs;
166 	struct ktr_entry **ktr_kbuf;
167 	ktr_iter_cb_t callback = &print_callback;
168 	int *ktr_idx;
169 	FILE *fo;
170 	void *ctx;
171 	int64_t tts;
172 	int *ktr_start_index;
173 	int c;
174 	int n;
175 
176 	/*
177 	 * Parse commandline arguments.
178 	 */
179 	fo = stdout;
180 	while ((c = getopt(ac, av, "acfinqrtxpslA:N:M:o:d")) != -1) {
181 		switch (c) {
182 		case 'a':
183 			cflag = 1;
184 			iflag = 1;
185 			rflag = 1;
186 			xflag = 1;
187 			pflag = 1;
188 			sflag = 1;
189 			break;
190 		case 'c':
191 			cflag = 1;
192 			break;
193 		case 'd':
194 			dflag = 1;
195 			sflag = 1;
196 			callback = &dump_callback;
197 			break;
198 		case 'N':
199 			if (strlcpy(execfile, optarg, sizeof(execfile))
200 			    >= sizeof(execfile))
201 				errx(1, "%s: File name too long", optarg);
202 			Nflag = 1;
203 			break;
204 		case 'f':
205 			fflag = 1;
206 			break;
207 		case 'l':
208 			lflag = 1;
209 			break;
210 		case 'i':
211 			iflag = 1;
212 			break;
213 		case 'A':
214 			correction_factor = strtod(optarg, NULL);
215 			break;
216 		case 'M':
217 			if (strlcpy(corefile, optarg, sizeof(corefile))
218 			    >= sizeof(corefile))
219 				errx(1, "%s: File name too long", optarg);
220 			Mflag = 1;
221 			break;
222 		case 'n':
223 			nflag = 1;
224 			break;
225 		case 'o':
226 			if ((fo = fopen(optarg, "w")) == NULL)
227 				err(1, "%s", optarg);
228 			break;
229 		case 'p':
230 			pflag++;
231 			break;
232 		case 'q':
233 			qflag++;
234 			break;
235 		case 'r':
236 			rflag = 1;
237 			break;
238 		case 's':
239 			sflag = 1;	/* sort across the cpus */
240 			break;
241 		case 't':
242 			tflag = 1;
243 			break;
244 		case 'x':
245 			xflag = 1;
246 			break;
247 		case '?':
248 		default:
249 			usage();
250 		}
251 	}
252 	ctx = fo;
253 	if (dflag) {
254 		ctx = evtr_open_write(fo);
255 		if (!ctx) {
256 			err(1, "Can't create event stream");
257 		}
258 	}
259 	if (cflag + iflag + tflag + xflag + fflag + pflag == 0) {
260 		cflag = 1;
261 		iflag = 1;
262 		tflag = 1;
263 		pflag = 1;
264 	}
265 	if (correction_factor != 0.0 && (rflag == 0 || nflag)) {
266 		fprintf(stderr, "Correction factor can only be applied with -r and without -n\n");
267 		exit(1);
268 	}
269 	ac -= optind;
270 	av += optind;
271 	if (ac != 0)
272 		usage();
273 
274 	/*
275 	 * Open our execfile and corefile, resolve needed symbols and read in
276 	 * the trace buffer.
277 	 */
278 	if ((kd = kvm_openfiles(Nflag ? execfile : NULL,
279 	    Mflag ? corefile : NULL, NULL, O_RDONLY, errbuf)) == NULL)
280 		errx(1, "%s", errbuf);
281 	if (kvm_nlist(kd, nl1) != 0)
282 		errx(1, "%s", kvm_geterr(kd));
283 	if (kvm_read(kd, nl1[0].n_value, &ktr_version, sizeof(ktr_version)) == -1)
284 		errx(1, "%s", kvm_geterr(kd));
285 	if (kvm_read(kd, nl1[2].n_value, &ncpus, sizeof(ncpus)) == -1)
286 		errx(1, "%s", kvm_geterr(kd));
287 	ktr_start_index = malloc(sizeof(*ktr_start_index) * ncpus);
288 	if (ktr_version >= KTR_VERSION_WITH_FREQ && kvm_nlist(kd, nl2) == 0) {
289 		if (kvm_read(kd, nl2[0].n_value, &tts, sizeof(tts)) == -1)
290 			errx(1, "%s", kvm_geterr(kd));
291 		tsc_frequency = (double)tts;
292 	}
293 	if (ktr_version > KTR_VERSION)
294 		errx(1, "ktr version too high for us to handle");
295 	if (kvm_read(kd, nl1[1].n_value, &entries_per_buf,
296 				sizeof(entries_per_buf)) == -1)
297 		errx(1, "%s", kvm_geterr(kd));
298 	fifo_mask = entries_per_buf - 1;
299 
300 	printf("TSC frequency is %6.3f MHz\n", tsc_frequency / 1000000.0);
301 
302 	if (dflag) {
303 		dump_machine_info((evtr_t)ctx);
304 		dump_device_info((evtr_t)ctx);
305 	}
306 	ktr_kbuf = calloc(ncpus, sizeof(*ktr_kbuf));
307 	ktr_idx = calloc(ncpus, sizeof(*ktr_idx));
308 
309 	if (nflag == 0)
310 		read_symbols(Nflag ? execfile : NULL);
311 
312 	if (ktr_version < KTR_VERSION_KTR_CPU) {
313 		if (kvm_nlist(kd, nl_version_ktr_idx))
314 			errx(1, "%s", kvm_geterr(kd));
315 	} else {
316 		if (kvm_nlist(kd, nl_version_ktr_cpu))
317 			errx(1, "%s", kvm_geterr(kd));
318 	}
319 
320 	get_indices(ktr_kbuf, ktr_idx);
321 
322 	ktr_bufs = ktr_bufs_init();
323 
324 	if (sflag) {
325 		u_int64_t last_timestamp = 0;
326 		do {
327 			load_bufs(ktr_bufs, ktr_kbuf, ktr_idx);
328 			iterate_bufs_timesorted(ctx, ktr_bufs, &last_timestamp,
329 						callback);
330 			if (lflag)
331 				usleep(1000000 / 10);
332 		} while (lflag);
333 	} else {
334 		u_int64_t *last_timestamp = calloc(sizeof(u_int64_t), ncpus);
335 		do {
336 			load_bufs(ktr_bufs, ktr_kbuf, ktr_idx);
337 			for (n = 0; n < ncpus; ++n)
338 				iterate_buf(ctx, ktr_bufs, n, &last_timestamp[n],
339 					callback);
340 			if (lflag)
341 				usleep(1000000 / 10);
342 		} while (lflag);
343 	}
344 	if (dflag)
345 		evtr_close(ctx);
346 	return (0);
347 }
348 
349 static
350 int
351 dump_devinfo(struct devinfo_dev *dev, void *arg)
352 {
353 	struct evtr_event ev;
354 	evtr_t evtr = (evtr_t)arg;
355 	const char *fmt = "#devicenames[\"%s\"] = %#lx";
356 	char fmtdatabuf[sizeof(char *) + sizeof(devinfo_handle_t)];
357 	char *fmtdata = fmtdatabuf;
358 
359 	if (!dev->dd_name[0])
360 		return 0;
361 	ev.type = EVTR_TYPE_PROBE;
362 	ev.ts = 0;
363 	ev.line = 0;
364 	ev.file = NULL;
365 	ev.cpu = -1;
366 	ev.func = NULL;
367 	ev.fmt = fmt;
368 	((char **)fmtdata)[0] = &dev->dd_name[0];
369 	fmtdata += sizeof(char *);
370 	((devinfo_handle_t *)fmtdata)[0] = dev->dd_handle;
371 	ev.fmtdata = fmtdatabuf;
372 	ev.fmtdatalen = sizeof(fmtdatabuf);
373 
374 	if (evtr_dump_event(evtr, &ev)) {
375 		err(1, evtr_errmsg(evtr));
376 	}
377 
378 	return devinfo_foreach_device_child(dev, dump_devinfo, evtr);
379 }
380 
381 static
382 void
383 dump_device_info(evtr_t evtr)
384 {
385 	struct devinfo_dev *root;
386 	if (devinfo_init())
387 		return;
388 	if (!(root = devinfo_handle_to_device(DEVINFO_ROOT_DEVICE))) {
389 		warn("can't find root device");
390 		return;
391 	}
392 	devinfo_foreach_device_child(root, dump_devinfo, evtr);
393 }
394 
395 static
396 void
397 dump_machine_info(evtr_t evtr)
398 {
399 	struct evtr_event ev;
400 	int i;
401 
402 	bzero(&ev, sizeof(ev));
403 	ev.type = EVTR_TYPE_SYSINFO;
404 	ev.ncpus = ncpus;
405 	evtr_dump_event(evtr, &ev);
406 	if (evtr_error(evtr)) {
407 		err(1, evtr_errmsg(evtr));
408 	}
409 
410 	for (i = 0; i < ncpus; ++i) {
411 		bzero(&ev, sizeof(ev));
412 		ev.type = EVTR_TYPE_CPUINFO;
413 		ev.cpu = i;
414 		ev.cpuinfo.freq = tsc_frequency;
415 		evtr_dump_event(evtr, &ev);
416 		if (evtr_error(evtr)) {
417 			err(1, evtr_errmsg(evtr));
418 		}
419 	}
420 }
421 
422 static void
423 print_header(FILE *fo, int row)
424 {
425 	if (qflag == 0 && (u_int32_t)row % 20 == 0) {
426 		fprintf(fo, "%-6s ", "index");
427 		if (cflag)
428 			fprintf(fo, "%-3s ", "cpu");
429 		if (tflag || rflag)
430 			fprintf(fo, "%-16s ", "timestamp");
431 		if (xflag) {
432 			if (nflag)
433 			    fprintf(fo, "%-10s %-10s", "caller2", "caller1");
434 			else
435 			    fprintf(fo, "%-20s %-20s", "caller2", "caller1");
436 		}
437 		if (iflag)
438 			fprintf(fo, "%-20s ", "ID");
439 		if (fflag)
440 			fprintf(fo, "%10s%-30s ", "", "file and line");
441 		if (pflag)
442 			fprintf(fo, "%s", "trace");
443 		fprintf(fo, "\n");
444 	}
445 }
446 
447 static void
448 print_entry(FILE *fo, int n, int row, struct ktr_entry *entry,
449 	    u_int64_t *last_timestamp)
450 {
451 	struct ktr_info *info = NULL;
452 	static struct save_ctx nctx, pctx, fmtctx, symctx, infoctx;
453 
454 	fprintf(fo, " %06x ", row & 0x00FFFFFF);
455 	if (cflag)
456 		fprintf(fo, "%-3d ", n);
457 	if (tflag || rflag) {
458 		if (rflag && !nflag && tsc_frequency != 0.0) {
459 			fprintf(fo, "%13.3f uS ",
460 				(double)(entry->ktr_timestamp - *last_timestamp) * 1000000.0 / tsc_frequency - correction_factor);
461 		} else if (rflag) {
462 			fprintf(fo, "%-16ju ",
463 			    (uintmax_t)(entry->ktr_timestamp - *last_timestamp));
464 		} else {
465 			fprintf(fo, "%-16ju ",
466 			    (uintmax_t)entry->ktr_timestamp);
467 		}
468 	}
469 	if (xflag) {
470 		if (nflag) {
471 		    fprintf(fo, "%p %p ",
472 			    entry->ktr_caller2, entry->ktr_caller1);
473 		} else {
474 		    fprintf(fo, "%-25s ",
475 			    address_to_symbol(entry->ktr_caller2, &symctx));
476 		    fprintf(fo, "%-25s ",
477 			    address_to_symbol(entry->ktr_caller1, &symctx));
478 		}
479 	}
480 	if (iflag) {
481 		info = kvm_ktrinfo(entry->ktr_info, &infoctx);
482 		if (info)
483 			fprintf(fo, "%-20s ", kvm_string(info->kf_name, &nctx));
484 		else
485 			fprintf(fo, "%-20s ", "<empty>");
486 	}
487 	if (fflag)
488 		fprintf(fo, "%34s:%-4d ",
489 			trunc_path(kvm_string(entry->ktr_file, &pctx), 34),
490 			entry->ktr_line);
491 	if (pflag) {
492 		if (info == NULL)
493 			info = kvm_ktrinfo(entry->ktr_info, &infoctx);
494 		if (info) {
495 			machine_va_list ap;
496 			const char *fmt;
497 			fmt = kvm_string(info->kf_format, &fmtctx);
498 			if (va_list_from_blob(&ap, fmt,
499 					      (char *)&entry->ktr_data,
500 					      info->kf_data_size))
501 				err(2, "Can't generate va_list from %s\n", fmt);
502 			kvmfprintf(fo, kvm_string(info->kf_format, &fmtctx),
503 				   (void *)&ap);
504 		}
505 	}
506 	fprintf(fo, "\n");
507 	*last_timestamp = entry->ktr_timestamp;
508 }
509 
510 static
511 void
512 print_callback(void *ctx, int n, int row, struct ktr_entry *entry, uint64_t *last_ts)
513 {
514 	FILE *fo = (FILE *)ctx;
515 	print_header(fo, row);
516 	print_entry(fo, n, row, entry, last_ts);
517 }
518 
519 /*
520  * If free == 0, replace all (kvm) string pointers in fmtdata with pointers
521  * to user-allocated copies of the strings.
522  * If free != 0, free those pointers.
523  */
524 static
525 int
526 mangle_string_ptrs(const char *fmt, uint8_t *fmtdata, int dofree)
527 {
528 	const char *f, *p;
529 	size_t skipsize, intsz;
530 	static struct save_ctx strctx;
531 	int ret = 0;
532 
533 	for (f = fmt; f[0] != '\0'; ++f) {
534 		if (f[0] != '%')
535 			continue;
536 		++f;
537 		skipsize = 0;
538 		for (p = f; p[0]; ++p) {
539 			int again = 0;
540 			/*
541 			 * Eat flags. Notice this will accept duplicate
542 			 * flags.
543 			 */
544 			switch (p[0]) {
545 			case '#':
546 			case '0':
547 			case '-':
548 			case ' ':
549 			case '+':
550 			case '\'':
551 				again = !0;
552 				break;
553 			}
554 			if (!again)
555 				break;
556 		}
557 		/* Eat minimum field width, if any */
558 		for (; isdigit(p[0]); ++p)
559 			;
560 		if (p[0] == '.')
561 			++p;
562 		/* Eat precision, if any */
563 		for (; isdigit(p[0]); ++p)
564 			;
565 		intsz = 0;
566 		switch (p[0]) {
567 		case 'l':
568 			if (p[1] == 'l') {
569 				++p;
570 				intsz = sizeof(long long);
571 			} else {
572 				intsz = sizeof(long);
573 			}
574 			break;
575 		case 'j':
576 			intsz = sizeof(intmax_t);
577 			break;
578 		case 't':
579 			intsz = sizeof(ptrdiff_t);
580 			break;
581 		case 'z':
582 			intsz = sizeof(size_t);
583 			break;
584 		default:
585 			break;
586 		}
587 		if (intsz != 0)
588 			++p;
589 		else
590 			intsz = sizeof(int);
591 
592 		switch (p[0]) {
593 		case 'd':
594 		case 'i':
595 		case 'o':
596 		case 'u':
597 		case 'x':
598 		case 'X':
599 		case 'c':
600 			skipsize = intsz;
601 			break;
602 		case 'p':
603 			skipsize = sizeof(void *);
604 			break;
605 		case 'f':
606 			if (p[-1] == 'l')
607 				skipsize = sizeof(double);
608 			else
609 				skipsize = sizeof(float);
610 			break;
611 		case 's':
612 			if (dofree) {
613 			  char *t = ((char **)fmtdata)[0];
614 			  free(t);
615 			  skipsize = sizeof(char *);
616 			} else {
617 			  char *t = strdup(kvm_string(((char **)fmtdata)[0],
618 							  &strctx));
619 			  ((const char **)fmtdata)[0] = t;
620 
621 				skipsize = sizeof(char *);
622 			}
623 			++ret;
624 			break;
625 		default:
626 			fprintf(stderr, "Unknown conversion specifier %c "
627 				"in fmt starting with %s", p[0], f - 1);
628 			return -1;
629 		}
630 		fmtdata += skipsize;
631 	}
632 	return ret;
633 }
634 
635 static
636 void
637 dump_callback(void *ctx, int n, int row __unused, struct ktr_entry *entry,
638 	      uint64_t *last_ts __unused)
639 {
640 	evtr_t evtr = (evtr_t)ctx;
641 	struct evtr_event ev;
642 	static struct save_ctx pctx, fmtctx, infoctx;
643 	struct ktr_info *ki;
644 	int conv = 0;	/* pointless */
645 
646 	ev.ts = entry->ktr_timestamp;
647 	ev.type = EVTR_TYPE_PROBE;
648 	ev.line = entry->ktr_line;
649 	ev.file = kvm_string(entry->ktr_file, &pctx);
650 	ev.func = NULL;
651 	ev.cpu = n;
652 	if ((ki = kvm_ktrinfo(entry->ktr_info, &infoctx))) {
653 		ev.fmt = kvm_string(ki->kf_format, &fmtctx);
654 		ev.fmtdata = entry->ktr_data;
655 		if ((conv = mangle_string_ptrs(ev.fmt,
656 					       __DECONST(uint8_t *, ev.fmtdata),
657 					       0)) < 0)
658 			errx(1, "Can't parse format string\n");
659 		ev.fmtdatalen = ki->kf_data_size;
660 	} else {
661 		ev.fmt = ev.fmtdata = NULL;
662 		ev.fmtdatalen = 0;
663 	}
664 	if (evtr_dump_event(evtr, &ev)) {
665 		err(1, evtr_errmsg(evtr));
666 	}
667 	if (ev.fmtdata && conv) {
668 		mangle_string_ptrs(ev.fmt, __DECONST(uint8_t *, ev.fmtdata),
669 				   !0);
670 	}
671 }
672 
673 static
674 struct ktr_info *
675 kvm_ktrinfo(void *kptr, struct save_ctx *ctx)
676 {
677 	struct ktr_info *ki = (void *)ctx->save_buf;
678 
679 	if (kptr == NULL)
680 		return(NULL);
681 	if (ctx->save_kptr != kptr) {
682 		if (kvm_read(kd, (uintptr_t)kptr, ki, sizeof(*ki)) == -1) {
683 			bzero(&ki, sizeof(*ki));
684 		} else {
685 			ctx->save_kptr = kptr;
686 		}
687 	}
688 	return(ki);
689 }
690 
691 static
692 const char *
693 kvm_string(const char *kptr, struct save_ctx *ctx)
694 {
695 	u_int l;
696 	u_int n;
697 
698 	if (kptr == NULL)
699 		return("?");
700 	if (ctx->save_kptr != (const void *)kptr) {
701 		ctx->save_kptr = (const void *)kptr;
702 		l = 0;
703 		while (l < sizeof(ctx->save_buf) - 1) {
704 			n = 256 - ((intptr_t)(kptr + l) & 255);
705 			if (n > sizeof(ctx->save_buf) - l - 1)
706 				n = sizeof(ctx->save_buf) - l - 1;
707 			if (kvm_read(kd, (uintptr_t)(kptr + l), ctx->save_buf + l, n) < 0)
708 				break;
709 			while (l < sizeof(ctx->save_buf) && n) {
710 			    if (ctx->save_buf[l] == 0)
711 				    break;
712 			    --n;
713 			    ++l;
714 			}
715 			if (n)
716 			    break;
717 		}
718 		ctx->save_buf[l] = 0;
719 	}
720 	return(ctx->save_buf);
721 }
722 
723 static
724 const char *
725 trunc_path(const char *str, int maxlen)
726 {
727 	int len = strlen(str);
728 
729 	if (len > maxlen)
730 		return(str + len - maxlen);
731 	else
732 		return(str);
733 }
734 
735 struct symdata {
736 	TAILQ_ENTRY(symdata) link;
737 	const char *symname;
738 	char *symaddr;
739 	char symtype;
740 };
741 
742 static TAILQ_HEAD(symlist, symdata) symlist;
743 static struct symdata *symcache;
744 static char *symbegin;
745 static char *symend;
746 
747 static
748 void
749 read_symbols(const char *file)
750 {
751 	char buf[256];
752 	char cmd[256];
753 	size_t buflen = sizeof(buf);
754 	FILE *fp;
755 	struct symdata *sym;
756 	char *s1;
757 	char *s2;
758 	char *s3;
759 
760 	TAILQ_INIT(&symlist);
761 
762 	if (file == NULL) {
763 		if (sysctlbyname("kern.bootfile", buf, &buflen, NULL, 0) < 0)
764 			file = "/boot/kernel";
765 		else
766 			file = buf;
767 	}
768 	snprintf(cmd, sizeof(cmd), "nm -n %s", file);
769 	if ((fp = popen(cmd, "r")) != NULL) {
770 		while (fgets(buf, sizeof(buf), fp) != NULL) {
771 		    s1 = strtok(buf, " \t\n");
772 		    s2 = strtok(NULL, " \t\n");
773 		    s3 = strtok(NULL, " \t\n");
774 		    if (s1 && s2 && s3) {
775 			sym = malloc(sizeof(struct symdata));
776 			sym->symaddr = (char *)strtoul(s1, NULL, 16);
777 			sym->symtype = s2[0];
778 			sym->symname = strdup(s3);
779 			if (strcmp(s3, "kernbase") == 0)
780 				symbegin = sym->symaddr;
781 			if (strcmp(s3, "end") == 0)
782 				symend = sym->symaddr;
783 			TAILQ_INSERT_TAIL(&symlist, sym, link);
784 		    }
785 		}
786 		pclose(fp);
787 	}
788 	symcache = TAILQ_FIRST(&symlist);
789 }
790 
791 static
792 const char *
793 address_to_symbol(void *kptr, struct save_ctx *ctx)
794 {
795 	char *buf = ctx->save_buf;
796 	int size = sizeof(ctx->save_buf);
797 
798 	if (symcache == NULL ||
799 	   (char *)kptr < symbegin || (char *)kptr >= symend
800 	) {
801 		snprintf(buf, size, "%p", kptr);
802 		return(buf);
803 	}
804 	while ((char *)symcache->symaddr < (char *)kptr) {
805 		if (TAILQ_NEXT(symcache, link) == NULL)
806 			break;
807 		symcache = TAILQ_NEXT(symcache, link);
808 	}
809 	while ((char *)symcache->symaddr > (char *)kptr) {
810 		if (symcache != TAILQ_FIRST(&symlist))
811 			symcache = TAILQ_PREV(symcache, symlist, link);
812 	}
813 	snprintf(buf, size, "%s+%d", symcache->symname,
814 		(int)((char *)kptr - symcache->symaddr));
815 	return(buf);
816 }
817 
818 static
819 struct ktr_buffer *
820 ktr_bufs_init(void)
821 {
822 	struct ktr_buffer *ktr_bufs, *it;
823 	int i;
824 
825 	ktr_bufs = malloc(sizeof(*ktr_bufs) * ncpus);
826 	if (!ktr_bufs)
827 		err(1, "can't allocate data structures\n");
828 	for (i = 0; i < ncpus; ++i) {
829 		it = ktr_bufs + i;
830 		it->ents = malloc(sizeof(struct ktr_entry) * entries_per_buf);
831 		if (it->ents == NULL)
832 			err(1, "can't allocate data structures\n");
833 		it->reset = 1;
834 		it->beg_idx = -1;
835 		it->end_idx = -1;
836 	}
837 	return ktr_bufs;
838 }
839 
840 static
841 void
842 get_indices(struct ktr_entry **ktr_kbuf, int *ktr_idx)
843 {
844 	static struct ktr_cpu *ktr_cpus;
845 	int i;
846 
847 	if (ktr_cpus == NULL)
848 		ktr_cpus = malloc(sizeof(*ktr_cpus) * ncpus);
849 
850 	if (ktr_version < KTR_VERSION_KTR_CPU) {
851 		if (kvm_read(kd, nl_version_ktr_idx[0].n_value, ktr_idx,
852 		    sizeof(*ktr_idx) * ncpus) == -1) {
853 			errx(1, "%s", kvm_geterr(kd));
854 		}
855 		if (ktr_kbuf[0] == NULL) {
856 			if (kvm_read(kd, nl_version_ktr_idx[1].n_value,
857 			    ktr_kbuf, sizeof(*ktr_kbuf) * ncpus) == -1) {
858 				errx(1, "%s", kvm_geterr(kd));
859 			}
860 		}
861 	} else {
862 		if (kvm_read(kd, nl_version_ktr_cpu[0].n_value,
863 			     ktr_cpus, sizeof(*ktr_cpus) * ncpus) == -1) {
864 				errx(1, "%s", kvm_geterr(kd));
865 		}
866 		for (i = 0; i < ncpus; ++i) {
867 			ktr_idx[i] = ktr_cpus[i].core.ktr_idx;
868 			ktr_kbuf[i] = ktr_cpus[i].core.ktr_buf;
869 		}
870 	}
871 }
872 
873 /*
874  * Get the trace buffer data from the kernel
875  */
876 static
877 void
878 load_bufs(struct ktr_buffer *ktr_bufs, struct ktr_entry **kbufs, int *ktr_idx)
879 {
880 	struct ktr_buffer *kbuf;
881 	int i;
882 
883 	get_indices(kbufs, ktr_idx);
884 	for (i = 0; i < ncpus; ++i) {
885 		kbuf = &ktr_bufs[i];
886 		if (ktr_idx[i] == kbuf->end_idx)
887 			continue;
888 		kbuf->end_idx = ktr_idx[i];
889 
890 		/*
891 		 * If we do not have a notion of the beginning index, assume
892 		 * it is entries_per_buf before the ending index.  Don't
893 		 * worry about underflows/negative numbers, the indices will
894 		 * be masked.
895 		 */
896 		if (kbuf->reset) {
897 			kbuf->beg_idx = kbuf->end_idx - entries_per_buf + 1;
898 			kbuf->reset = 0;
899 		}
900 		if (kvm_read(kd, (uintptr_t)kbufs[i], ktr_bufs[i].ents,
901 				sizeof(struct ktr_entry) * entries_per_buf)
902 									== -1)
903 			errx(1, "%s", kvm_geterr(kd));
904 		kbuf->modified = 1;
905 		kbuf->beg_idx = earliest_ts(kbuf);
906 	}
907 
908 }
909 
910 /*
911  * Locate the earliest timestamp iterating backwards from end_idx, but
912  * not going further back then beg_idx.  We have to do this because
913  * the kernel uses a circulating buffer.
914  */
915 static
916 int
917 earliest_ts(struct ktr_buffer *buf)
918 {
919 	struct ktr_entry *save;
920 	int count, scan, i, earliest;
921 
922 	count = 0;
923 	earliest = buf->end_idx - 1;
924 	save = &buf->ents[earliest & fifo_mask];
925 	for (scan = buf->end_idx - 1; scan != buf->beg_idx -1; --scan) {
926 		i = scan & fifo_mask;
927 		if (buf->ents[i].ktr_timestamp <= save->ktr_timestamp &&
928 		    buf->ents[i].ktr_timestamp > 0)
929 			earliest = scan;
930 		/*
931 		 * We may have gotten so far behind that beg_idx wrapped
932 		 * more then once around the buffer.  Just stop
933 		 */
934 		if (++count == entries_per_buf)
935 			break;
936 	}
937 	return earliest;
938 }
939 
940 static
941 void
942 iterate_buf(FILE *fo, struct ktr_buffer *ktr_bufs, int cpu,
943 	    u_int64_t *last_timestamp, ktr_iter_cb_t cb)
944 {
945 	struct ktr_buffer *buf = ktr_bufs + cpu;
946 
947 	if (buf->modified == 0)
948 		return;
949 	if (*last_timestamp == 0) {
950 		*last_timestamp =
951 			buf->ents[buf->beg_idx & fifo_mask].ktr_timestamp;
952 	}
953 	while (buf->beg_idx != buf->end_idx) {
954 		cb(fo, cpu, buf->beg_idx,
955 		   &buf->ents[buf->beg_idx & fifo_mask],
956 		   last_timestamp);
957 		++buf->beg_idx;
958 	}
959 	buf->modified = 0;
960 }
961 
962 static
963 void
964 iterate_bufs_timesorted(FILE *fo, struct ktr_buffer *ktr_bufs,
965 			u_int64_t *last_timestamp, ktr_iter_cb_t cb)
966 {
967 	struct ktr_entry *ent;
968 	struct ktr_buffer *buf;
969 	int n, bestn;
970 	u_int64_t ts;
971 	static int row = 0;
972 
973 	for (;;) {
974 		ts = 0;
975 		bestn = -1;
976 		for (n = 0; n < ncpus; ++n) {
977 			buf = ktr_bufs + n;
978 			if (buf->beg_idx == buf->end_idx)
979 				continue;
980 			ent = &buf->ents[buf->beg_idx & fifo_mask];
981 			if (ts == 0 || (ts >= ent->ktr_timestamp)) {
982 				ts = ent->ktr_timestamp;
983 				bestn = n;
984 			}
985 		}
986 		if ((bestn < 0) || (ts < *last_timestamp))
987 			break;
988 		buf = ktr_bufs + bestn;
989 		cb(fo, bestn, row,
990 		   &buf->ents[buf->beg_idx & fifo_mask],
991 		   last_timestamp);
992 		++buf->beg_idx;
993 		*last_timestamp = ts;
994 		++row;
995 	}
996 }
997 
998 static
999 void
1000 kvmfprintf(FILE *fp, const char *ctl, va_list va)
1001 {
1002 	int n;
1003 	int is_long;
1004 	int is_done;
1005 	char fmt[256];
1006 	static struct save_ctx strctx;
1007 	const char *s;
1008 
1009 	while (*ctl) {
1010 		for (n = 0; ctl[n]; ++n) {
1011 			fmt[n] = ctl[n];
1012 			if (ctl[n] == '%')
1013 				break;
1014 		}
1015 		if (n == 0) {
1016 			is_long = 0;
1017 			is_done = 0;
1018 			n = 1;
1019 			while (n < (int)sizeof(fmt)) {
1020 				fmt[n] = ctl[n];
1021 				fmt[n+1] = 0;
1022 
1023 				switch(ctl[n]) {
1024 				case 'p':
1025 					is_long = 1;
1026 					/* fall through */
1027 				case 'd':
1028 				case 'u':
1029 				case 'x':
1030 				case 'o':
1031 				case 'X':
1032 					/*
1033 					 * Integral
1034 					 */
1035 					switch(is_long) {
1036 					case 0:
1037 						fprintf(fp, fmt,
1038 							va_arg(va, int));
1039 						break;
1040 					case 1:
1041 						fprintf(fp, fmt,
1042 							va_arg(va, long));
1043 						break;
1044 					case 2:
1045 						fprintf(fp, fmt,
1046 						    va_arg(va, long long));
1047 						break;
1048 					case 3:
1049 						fprintf(fp, fmt,
1050 						    va_arg(va, size_t));
1051 						break;
1052 					}
1053 					++n;
1054 					is_done = 1;
1055 					break;
1056 				case 'c':
1057 				        fprintf(fp, "%c", va_arg(va, int));
1058 					++n;
1059 					is_done = 1;
1060 					break;
1061 				case 's':
1062 					/*
1063 					 * String
1064 					 */
1065 					s = kvm_string(va_arg(va, char *), &strctx);
1066 					fwrite(s, 1, strlen(s), fp);
1067 					++n;
1068 					is_done = 1;
1069 					break;
1070 				case 'f':
1071 					/*
1072 					 * Floating
1073 					 */
1074 					fprintf(fp, fmt,
1075 						va_arg(va, double));
1076 					++n;
1077 					break;
1078 				case 'j':
1079 					is_long = 2;
1080 					break;
1081 				case 'z':
1082 					is_long = 3;
1083 					break;
1084 				case 'l':
1085 					if (is_long)
1086 						is_long = 2;
1087 					else
1088 						is_long = 1;
1089 					break;
1090 				case '.':
1091 				case '-':
1092 				case '+':
1093 				case '0':
1094 				case '1':
1095 				case '2':
1096 				case '3':
1097 				case '4':
1098 				case '5':
1099 				case '6':
1100 				case '7':
1101 				case '8':
1102 				case '9':
1103 					break;
1104 				default:
1105 					is_done = 1;
1106 					break;
1107 				}
1108 				if (is_done)
1109 					break;
1110 				++n;
1111 			}
1112 		} else {
1113 			fmt[n] = 0;
1114 			fprintf(fp, fmt, NULL);
1115 		}
1116 		ctl += n;
1117 	}
1118 }
1119 
1120 static void
1121 usage(void)
1122 {
1123 	fprintf(stderr, "usage: ktrdump [-acfilnpqrstx] [-A factor] "
1124 			"[-N execfile] [-M corefile] [-o outfile]\n");
1125 	exit(1);
1126 }
1127 
1128 enum argument_class {
1129 	ARGCLASS_NONE,
1130 	ARGCLASS_INTEGER,
1131 	ARGCLASS_FP,
1132 	ARGCLASS_MEMORY,
1133 	ARGCLASS_ERR,
1134 };
1135 static size_t
1136 conversion_size(const char *fmt, enum argument_class *argclass)
1137 {
1138 	const char *p;
1139 	size_t convsize, intsz;
1140 
1141 	*argclass = ARGCLASS_ERR;
1142 	if (fmt[0] != '%')
1143 		return -1;
1144 
1145 	convsize = -1;
1146 	for (p = fmt + 1; p[0]; ++p) {
1147 		int again = 0;
1148 		/*
1149 		 * Eat flags. Notice this will accept duplicate
1150 		 * flags.
1151 		 */
1152 		switch (p[0]) {
1153 		case '#':
1154 		case '0':
1155 		case '-':
1156 		case ' ':
1157 		case '+':
1158 		case '\'':
1159 			again = !0;
1160 			break;
1161 		}
1162 		if (!again)
1163 			break;
1164 	}
1165 	/* Eat minimum field width, if any */
1166 	for (; isdigit(p[0]); ++p)
1167 			;
1168 	if (p[0] == '.')
1169 		++p;
1170 	/* Eat precision, if any */
1171 	for (; isdigit(p[0]); ++p)
1172 		;
1173 	intsz = 0;
1174 	switch (p[0]) {
1175 	case 'h':
1176 		if (p[1] == 'h') {
1177 			++p;
1178 			intsz = sizeof(char);
1179 		} else {
1180 			intsz = sizeof(short);
1181 		}
1182 		break;
1183 	case 'l':
1184 		if (p[1] == 'l') {
1185 			++p;
1186 			intsz = sizeof(long long);
1187 		} else {
1188 			intsz = sizeof(long);
1189 		}
1190 		break;
1191 	case 'j':
1192 		intsz = sizeof(intmax_t);
1193 		break;
1194 	case 't':
1195 		intsz = sizeof(ptrdiff_t);
1196 		break;
1197 	case 'z':
1198 		intsz = sizeof(size_t);
1199 		break;
1200 	default:
1201 		p--;	/* Anticipate the ++p that follows. Yes, I know. Eeek. */
1202 		break;
1203 	}
1204 	if (intsz == 0)
1205 		intsz = sizeof(int);
1206 	++p;
1207 
1208 	switch (p[0]) {
1209 	case 'c':
1210 		/* for %c, we only store 1 byte in the ktr entry */
1211 		convsize = sizeof(char);
1212 		*argclass = ARGCLASS_INTEGER;
1213 		break;
1214 	case 'd':
1215 	case 'i':
1216 	case 'o':
1217 	case 'u':
1218 	case 'x':
1219 	case 'X':
1220 		convsize = intsz;
1221 		*argclass = ARGCLASS_INTEGER;
1222 		break;
1223 	case 'p':
1224 		convsize = sizeof(void *);
1225 		*argclass = ARGCLASS_INTEGER;
1226 		break;
1227 	case 'f':
1228 		if (p[-1] == 'l')
1229 			convsize = sizeof(double);
1230 		else
1231 			convsize = sizeof(float);
1232 		break;
1233 		*argclass = ARGCLASS_FP;
1234 	case 's':
1235 		convsize = sizeof(char *);
1236 		*argclass = ARGCLASS_INTEGER;
1237 		break;
1238 	case '%':
1239 		convsize = 0;
1240 		*argclass = ARGCLASS_NONE;
1241 		break;
1242 	default:
1243 		fprintf(stderr, "Unknown conversion specifier %c "
1244 			"in fmt starting with %s", p[0], fmt - 1);
1245 		return -2;
1246 	}
1247 	return convsize;
1248 }
1249 
1250 #ifdef __x86_64__
1251 static int
1252 va_list_push_integral(struct my_va_list *valist, void *val, size_t valsize,
1253 		     size_t *stacksize)
1254 {
1255 	uint64_t r;
1256 
1257 	switch (valsize) {
1258 	case 1:
1259 		r = *(uint8_t *)val; break;
1260 	case 2:
1261 		r = *(uint32_t *)val; break;
1262 	case 4:
1263 		r = (*(uint32_t *)val); break;
1264 	case 8:
1265 		r = *(uint64_t *)val; break;
1266 	default:
1267 		err(1, "WTF\n");
1268 	}
1269 	/* we always need to push the full 8 bytes */
1270 	if ((valist->gp_offset + valsize) <= 48) {	/* got a free reg */
1271 
1272 		memcpy(((char *)valist->reg_save_area + valist->gp_offset),
1273 		       &r, sizeof(r));
1274 		valist->gp_offset += sizeof(r);
1275 		return 0;
1276 	}
1277 	/* push to "stack" */
1278 	if (!(valist->overflow_arg_area = realloc(valist->overflow_arg_area,
1279 						  *stacksize + sizeof(r))))
1280 		return -1;
1281 	memcpy((char *)valist->overflow_arg_area + *stacksize, &r, sizeof(r));
1282 	*stacksize += sizeof(r);
1283 	return 0;
1284 }
1285 
1286 static void
1287 va_list_rewind(struct my_va_list *valist)
1288 {
1289 	valist->gp_offset = 0;
1290 }
1291 
1292 static int
1293 va_list_from_blob(machine_va_list *valist, const char *fmt, char *blob, size_t blobsize)
1294 {
1295 	struct reg_save_area *regs;
1296 	const char *f;
1297 	size_t sz;
1298 
1299 	if (!(regs = malloc(sizeof(*regs))))
1300 		return -1;
1301 	*valist = (struct my_va_list) {
1302 		.gp_offset = 0,
1303 		.fp_offset = 0,
1304 		.overflow_arg_area = NULL,
1305 		.reg_save_area = regs,
1306 	};
1307 	enum argument_class argclass;
1308 	size_t stacksize = 0;
1309 
1310 	for (f = fmt; *f != '\0'; ++f) {
1311 		if (*f != '%')
1312 			continue;
1313 		sz = conversion_size(f, &argclass);
1314 		if (argclass == ARGCLASS_INTEGER) {
1315 			if (blobsize < sz) {
1316 				fprintf(stderr, "not enough data available "
1317 					"for format: %s", fmt);
1318 				return -1;
1319 			}
1320 			if (va_list_push_integral(valist, blob, sz, &stacksize))
1321 				return -1;
1322 			blob += sz;
1323 			blobsize -= sz;
1324 		} else if (argclass != ARGCLASS_NONE)
1325 			return -1;
1326 		/* walk past the '%' */
1327 		++f;
1328 	}
1329 	if (blobsize) {
1330 		fprintf(stderr, "Couldn't consume all data for format %s "
1331 			"(%zd bytes left over)\n", fmt, blobsize);
1332 		return -1;
1333 	}
1334 	va_list_rewind(valist);
1335 	return 0;
1336 }
1337 #elif __i386__
1338 static int
1339 va_list_from_blob(machine_va_list *valist, const char *fmt, char *blob, size_t blobsize)
1340 {
1341 	const char *f;
1342 	char *n;
1343 	size_t bytes, sz;
1344 	enum argument_class argclass;
1345 
1346 	n = NULL;
1347 	bytes = 0;
1348 	for (f = fmt; *f != '\0'; ++f) {
1349 		if (*f != '%')
1350 			continue;
1351 		sz = conversion_size(f, &argclass);
1352 		if (blobsize < sz) {
1353 			fprintf(stderr, "not enough data available "
1354 				"for format: %s", fmt);
1355 			return -1;
1356 		}
1357 		if ((argclass == ARGCLASS_INTEGER) && (sz < 4)) {
1358 			int i = -1;	/* do C integer promotion */
1359 			if (sz == 1)
1360 				i = *(char *)blob;
1361 			else
1362 				i = *(short *)blob;
1363 			if (!(n = realloc(n, bytes + 4)))
1364 				return -1;
1365 			memcpy(n + bytes, &i, sizeof(i));
1366 			bytes += 4;
1367 		} else {
1368 			if (!(n = realloc(n, bytes + sz)))
1369 				return -1;
1370 			memcpy(n + bytes, blob, sz);
1371 			bytes += sz;
1372 		}
1373 		blob += sz;
1374 		blobsize -= sz;
1375 
1376 	}
1377 	if (blobsize) {
1378 		fprintf(stderr, "Couldn't consume all data for format %s "
1379 			"(%zd bytes left over)\n", fmt, blobsize);
1380 		return -1;
1381 	}
1382 	*valist = n;
1383 	return 0;
1384 }
1385 #else
1386 #error "Don't know how to get a va_list on this platform"
1387 #endif
1388