ktrdump: always sort entries when dumping
[dragonfly.git] / usr.bin / ktrdump / ktrdump.c
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 <err.h>
41 #include <fcntl.h>
42 #include <kvm.h>
43 #include <limits.h>
44 #include <nlist.h>
45 #include <stdint.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50 #include <evtr.h>
51 #include <stdarg.h>
52
53 struct ktr_buffer {
54         struct ktr_entry *ents;
55         int modified;
56         int reset;
57         int beg_idx;            /* Beginning index */
58         int end_idx;            /* Ending index */
59 };
60
61 static struct nlist nl1[] = {
62         { .n_name = "_ktr_version" },
63         { .n_name = "_ktr_entries" },
64         { .n_name = "_ncpus" },
65         { .n_name = NULL }
66 };
67
68 static struct nlist nl2[] = {
69         { .n_name = "_tsc_frequency" },
70         { .n_name = NULL }
71 };
72
73 static struct nlist nl_version_ktr_idx[] = {
74         { .n_name = "_ktr_idx" },
75         { .n_name = "_ktr_buf" },
76         { .n_name = NULL }
77 };
78
79 static struct nlist nl_version_ktr_cpu[] = {
80         { .n_name = "_ktr_cpu" },
81         { .n_name = NULL }
82 };
83
84 struct save_ctx {
85         char save_buf[512];
86         const void *save_kptr;
87 };
88
89 typedef void (*ktr_iter_cb_t)(void *, int, int, struct ktr_entry *, uint64_t *);
90
91 static int cflag;
92 static int dflag;
93 static int fflag;
94 static int iflag;
95 static int lflag;
96 static int nflag;
97 static int qflag;
98 static int rflag;
99 static int sflag;
100 static int tflag;
101 static int xflag;
102 static int pflag;
103 static int Mflag;
104 static int Nflag;
105 static double tsc_frequency;
106 static double correction_factor = 0.0;
107
108 static char corefile[PATH_MAX];
109 static char execfile[PATH_MAX];
110
111 static char errbuf[_POSIX2_LINE_MAX];
112 static int ncpus;
113 static kvm_t *kd;
114 static int entries_per_buf;
115 static int fifo_mask;
116 static int ktr_version;
117
118 static void usage(void);
119 static int earliest_ts(struct ktr_buffer *);
120 static void dump_machine_info(evtr_t);
121 static void print_header(FILE *, int);
122 static void print_entry(FILE *, int, int, struct ktr_entry *, u_int64_t *);
123 static void print_callback(void *, int, int, struct ktr_entry *, uint64_t *);
124 static void dump_callback(void *, int, int, struct ktr_entry *, uint64_t *);
125 static struct ktr_info *kvm_ktrinfo(void *, struct save_ctx *);
126 static const char *kvm_string(const char *, struct save_ctx *);
127 static const char *trunc_path(const char *, int);
128 static void read_symbols(const char *);
129 static const char *address_to_symbol(void *, struct save_ctx *);
130 static struct ktr_buffer *ktr_bufs_init(void);
131 static void get_indices(struct ktr_entry **, int *);
132 static void load_bufs(struct ktr_buffer *, struct ktr_entry **, int *);
133 static void iterate_buf(FILE *, struct ktr_buffer *, int, u_int64_t *, ktr_iter_cb_t);
134 static void iterate_bufs_timesorted(FILE *, struct ktr_buffer *, u_int64_t *, ktr_iter_cb_t);
135 static void kvmfprintf(FILE *fp, const char *ctl, va_list va);
136
137 /*
138  * Reads the ktr trace buffer from kernel memory and prints the trace entries.
139  */
140 int
141 main(int ac, char **av)
142 {
143         struct ktr_buffer *ktr_bufs;
144         struct ktr_entry **ktr_kbuf;
145         ktr_iter_cb_t callback = &print_callback;
146         int *ktr_idx;
147         FILE *fo;
148         void *ctx;
149         int64_t tts;
150         int *ktr_start_index;
151         int c;
152         int n;
153
154         /*
155          * Parse commandline arguments.
156          */
157         fo = stdout;
158         while ((c = getopt(ac, av, "acfinqrtxpslA:N:M:o:d")) != -1) {
159                 switch (c) {
160                 case 'a':
161                         cflag = 1;
162                         iflag = 1;
163                         rflag = 1;
164                         xflag = 1;
165                         pflag = 1;
166                         sflag = 1;
167                         break;
168                 case 'c':
169                         cflag = 1;
170                         break;
171                 case 'd':
172                         dflag = 1;
173                         sflag = 1;
174                         callback = &dump_callback;
175                         break;
176                 case 'N':
177                         if (strlcpy(execfile, optarg, sizeof(execfile))
178                             >= sizeof(execfile))
179                                 errx(1, "%s: File name too long", optarg);
180                         Nflag = 1;
181                         break;
182                 case 'f':
183                         fflag = 1;
184                         break;
185                 case 'l':
186                         lflag = 1;
187                         break;
188                 case 'i':
189                         iflag = 1;
190                         break;
191                 case 'A':
192                         correction_factor = strtod(optarg, NULL);
193                         break;
194                 case 'M':
195                         if (strlcpy(corefile, optarg, sizeof(corefile))
196                             >= sizeof(corefile))
197                                 errx(1, "%s: File name too long", optarg);
198                         Mflag = 1;
199                         break;
200                 case 'n':
201                         nflag = 1;
202                         break;
203                 case 'o':
204                         if ((fo = fopen(optarg, "w")) == NULL)
205                                 err(1, "%s", optarg);
206                         break;
207                 case 'p':
208                         pflag++;
209                         break;
210                 case 'q':
211                         qflag++;
212                         break;
213                 case 'r':
214                         rflag = 1;
215                         break;
216                 case 's':
217                         sflag = 1;      /* sort across the cpus */
218                         break;
219                 case 't':
220                         tflag = 1;
221                         break;
222                 case 'x':
223                         xflag = 1;
224                         break;
225                 case '?':
226                 default:
227                         usage();
228                 }
229         }
230         ctx = fo;
231         if (dflag) {
232                 ctx = evtr_open_write(fo);
233                 if (!ctx) {
234                         err(1, "Can't create event stream");
235                 }
236         }
237         if (cflag + iflag + tflag + xflag + fflag + pflag == 0) {
238                 cflag = 1;
239                 iflag = 1;
240                 tflag = 1;
241                 pflag = 1;
242         }
243         if (correction_factor != 0.0 && (rflag == 0 || nflag)) {
244                 fprintf(stderr, "Correction factor can only be applied with -r and without -n\n");
245                 exit(1);
246         }
247         ac -= optind;
248         av += optind;
249         if (ac != 0)
250                 usage();
251
252         /*
253          * Open our execfile and corefile, resolve needed symbols and read in
254          * the trace buffer.
255          */
256         if ((kd = kvm_openfiles(Nflag ? execfile : NULL,
257             Mflag ? corefile : NULL, NULL, O_RDONLY, errbuf)) == NULL)
258                 errx(1, "%s", errbuf);
259         if (kvm_nlist(kd, nl1) != 0)
260                 errx(1, "%s", kvm_geterr(kd));
261         if (kvm_read(kd, nl1[0].n_value, &ktr_version, sizeof(ktr_version)) == -1)
262                 errx(1, "%s", kvm_geterr(kd));
263         if (kvm_read(kd, nl1[2].n_value, &ncpus, sizeof(ncpus)) == -1)
264                 errx(1, "%s", kvm_geterr(kd));
265         ktr_start_index = malloc(sizeof(*ktr_start_index) * ncpus);
266         if (ktr_version >= KTR_VERSION_WITH_FREQ && kvm_nlist(kd, nl2) == 0) {
267                 if (kvm_read(kd, nl2[0].n_value, &tts, sizeof(tts)) == -1)
268                         errx(1, "%s", kvm_geterr(kd));
269                 tsc_frequency = (double)tts;
270         }
271         if (ktr_version > KTR_VERSION)
272                 errx(1, "ktr version too high for us to handle");
273         if (kvm_read(kd, nl1[1].n_value, &entries_per_buf,
274                                 sizeof(entries_per_buf)) == -1)
275                 errx(1, "%s", kvm_geterr(kd));
276         fifo_mask = entries_per_buf - 1;
277
278         printf("TSC frequency is %6.3f MHz\n", tsc_frequency / 1000000.0);
279
280         if (dflag) {
281                 dump_machine_info((evtr_t)ctx);
282         }
283         ktr_kbuf = calloc(ncpus, sizeof(*ktr_kbuf));
284         ktr_idx = calloc(ncpus, sizeof(*ktr_idx));
285
286         if (nflag == 0)
287                 read_symbols(Nflag ? execfile : NULL);
288
289         if (ktr_version < KTR_VERSION_KTR_CPU) {
290                 if (kvm_nlist(kd, nl_version_ktr_idx))
291                         errx(1, "%s", kvm_geterr(kd));
292         } else {
293                 if (kvm_nlist(kd, nl_version_ktr_cpu))
294                         errx(1, "%s", kvm_geterr(kd));
295         }
296
297         get_indices(ktr_kbuf, ktr_idx);
298
299         ktr_bufs = ktr_bufs_init();
300
301         if (sflag) {
302                 u_int64_t last_timestamp = 0;
303                 do {
304                         load_bufs(ktr_bufs, ktr_kbuf, ktr_idx);
305                         iterate_bufs_timesorted(ctx, ktr_bufs, &last_timestamp,
306                                                 callback);
307                         if (lflag)
308                                 usleep(1000000 / 10);
309                 } while (lflag);
310         } else {
311                 u_int64_t *last_timestamp = calloc(sizeof(u_int64_t), ncpus);
312                 do {
313                         load_bufs(ktr_bufs, ktr_kbuf, ktr_idx);
314                         for (n = 0; n < ncpus; ++n)
315                                 iterate_buf(ctx, ktr_bufs, n, &last_timestamp[n],
316                                         callback);
317                         if (lflag)
318                                 usleep(1000000 / 10);
319                 } while (lflag);
320         }
321         if (dflag)
322                 evtr_close(ctx);
323         return (0);
324 }
325
326 static
327 void
328 dump_machine_info(evtr_t evtr)
329 {
330         struct evtr_event ev;
331         int i;
332
333         bzero(&ev, sizeof(ev));
334         ev.type = EVTR_TYPE_SYSINFO;
335         ev.ncpus = ncpus;
336         evtr_dump_event(evtr, &ev);
337         if (evtr_error(evtr)) {
338                 err(1, evtr_errmsg(evtr));
339         }
340
341         for (i = 0; i < ncpus; ++i) {
342                 bzero(&ev, sizeof(ev));
343                 ev.type = EVTR_TYPE_CPUINFO;
344                 ev.cpu = i;
345                 ev.cpuinfo.freq = tsc_frequency;
346                 evtr_dump_event(evtr, &ev);
347                 if (evtr_error(evtr)) {
348                         err(1, evtr_errmsg(evtr));
349                 }
350         }
351 }
352
353 static void
354 print_header(FILE *fo, int row)
355 {
356         if (qflag == 0 && (u_int32_t)row % 20 == 0) {
357                 fprintf(fo, "%-6s ", "index");
358                 if (cflag)
359                         fprintf(fo, "%-3s ", "cpu");
360                 if (tflag || rflag)
361                         fprintf(fo, "%-16s ", "timestamp");
362                 if (xflag) {
363                         if (nflag)
364                             fprintf(fo, "%-10s %-10s", "caller2", "caller1");
365                         else
366                             fprintf(fo, "%-20s %-20s", "caller2", "caller1");
367                 }
368                 if (iflag)
369                         fprintf(fo, "%-20s ", "ID");
370                 if (fflag)
371                         fprintf(fo, "%10s%-30s ", "", "file and line");
372                 if (pflag)
373                         fprintf(fo, "%s", "trace");
374                 fprintf(fo, "\n");
375         }
376 }
377
378 static void
379 print_entry(FILE *fo, int n, int row, struct ktr_entry *entry,
380             u_int64_t *last_timestamp)
381 {
382         struct ktr_info *info = NULL;
383         static struct save_ctx nctx, pctx, fmtctx, symctx, infoctx;
384
385         fprintf(fo, " %06x ", row & 0x00FFFFFF);
386         if (cflag)
387                 fprintf(fo, "%-3d ", n);
388         if (tflag || rflag) {
389                 if (rflag && !nflag && tsc_frequency != 0.0) {
390                         fprintf(fo, "%13.3f uS ",
391                                 (double)(entry->ktr_timestamp - *last_timestamp) * 1000000.0 / tsc_frequency - correction_factor);
392                 } else if (rflag) {
393                         fprintf(fo, "%-16ju ",
394                             (uintmax_t)(entry->ktr_timestamp - *last_timestamp));
395                 } else {
396                         fprintf(fo, "%-16ju ",
397                             (uintmax_t)entry->ktr_timestamp);
398                 }
399         }
400         if (xflag) {
401                 if (nflag) {
402                     fprintf(fo, "%p %p ", 
403                             entry->ktr_caller2, entry->ktr_caller1);
404                 } else {
405                     fprintf(fo, "%-25s ", 
406                             address_to_symbol(entry->ktr_caller2, &symctx));
407                     fprintf(fo, "%-25s ", 
408                             address_to_symbol(entry->ktr_caller1, &symctx));
409                 }
410         }
411         if (iflag) {
412                 info = kvm_ktrinfo(entry->ktr_info, &infoctx);
413                 if (info)
414                         fprintf(fo, "%-20s ", kvm_string(info->kf_name, &nctx));
415                 else
416                         fprintf(fo, "%-20s ", "<empty>");
417         }
418         if (fflag)
419                 fprintf(fo, "%34s:%-4d ",
420                         trunc_path(kvm_string(entry->ktr_file, &pctx), 34),
421                         entry->ktr_line);
422         if (pflag) {
423                 if (info == NULL)
424                         info = kvm_ktrinfo(entry->ktr_info, &infoctx);
425                 if (info)
426                         kvmfprintf(fo, kvm_string(info->kf_format, &fmtctx),
427                                  (void *)&entry->ktr_data);
428         }
429         fprintf(fo, "\n");
430         *last_timestamp = entry->ktr_timestamp;
431 }
432
433 static
434 void
435 print_callback(void *ctx, int n, int row, struct ktr_entry *entry, uint64_t *last_ts)
436 {
437         FILE *fo = (FILE *)ctx;
438         print_header(fo, row);
439         print_entry(fo, n, row, entry, last_ts);
440 }
441
442 /*
443  * If free == 0, replace all (kvm) string pointers in fmtdata with pointers
444  * to user-allocated copies of the strings.
445  * If free != 0, free those pointers.
446  */
447 static
448 int
449 mangle_string_ptrs(const char *fmt, uint8_t *fmtdata, int dofree)
450 {
451         const char *f, *p;
452         size_t skipsize, intsz;
453         static struct save_ctx strctx;
454         int ret = 0;
455
456         for (f = fmt; f[0] != '\0'; ++f) {
457                 if (f[0] != '%')
458                         continue;
459                 ++f;
460                 skipsize = 0;
461                 for (p = f; p[0]; ++p) {
462                         int again = 0;
463                         /*
464                          * Eat flags. Notice this will accept duplicate
465                          * flags.
466                          */
467                         switch (p[0]) {
468                         case '#':
469                         case '0':
470                         case '-':
471                         case ' ':
472                         case '+':
473                         case '\'':
474                                 again = !0;
475                                 break;
476                         }
477                         if (!again)
478                                 break;
479                 }
480                 /* Eat minimum field width, if any */
481                 for (; isdigit(p[0]); ++p)
482                         ;
483                 if (p[0] == '.')
484                         ++p;
485                 /* Eat precision, if any */
486                 for (; isdigit(p[0]); ++p)
487                         ;
488                 intsz = 0;
489                 switch (p[0]) {
490                 case 'l':
491                         if (p[1] == 'l') {
492                                 ++p;
493                                 intsz = sizeof(long long);
494                         } else {
495                                 intsz = sizeof(long);
496                         }
497                         break;
498                 case 'j':
499                         intsz = sizeof(intmax_t);
500                         break;
501                 case 't':
502                         intsz = sizeof(ptrdiff_t);
503                         break;
504                 case 'z':
505                         intsz = sizeof(size_t);
506                         break;
507                 default:
508                         break;
509                 }
510                 if (intsz != 0)
511                         ++p;
512                 else
513                         intsz = sizeof(int);
514
515                 switch (p[0]) {
516                 case 'd':
517                 case 'i':
518                 case 'o':
519                 case 'u':
520                 case 'x':
521                 case 'X':
522                 case 'c':
523                         skipsize = intsz;
524                         break;
525                 case 'p':
526                         skipsize = sizeof(void *);
527                         break;
528                 case 'f':
529                         if (p[-1] == 'l')
530                                 skipsize = sizeof(double);
531                         else
532                                 skipsize = sizeof(float);
533                         break;
534                 case 's':
535                         if (dofree) {
536                           char *t = ((char **)fmtdata)[0];
537                           free(t);
538                           skipsize = sizeof(char *);
539                         } else {
540                           char *t = strdup(kvm_string(((char **)fmtdata)[0],
541                                                           &strctx));
542                           ((const char **)fmtdata)[0] = t;
543                                         
544                                 skipsize = sizeof(char *);
545                         }
546                         ++ret;
547                         break;
548                 default:
549                         fprintf(stderr, "Unknown conversion specifier %c "
550                                 "in fmt starting with %s", p[0], f - 1);
551                         return -1;
552                 }
553                 fmtdata += skipsize;
554         }
555         return ret;
556 }
557
558 static
559 void
560 dump_callback(void *ctx, int n, int row __unused, struct ktr_entry *entry,
561               uint64_t *last_ts __unused)
562 {
563         evtr_t evtr = (evtr_t)ctx;
564         struct evtr_event ev;
565         static struct save_ctx pctx, fmtctx, infoctx;
566         struct ktr_info *ki;
567         int conv = 0;   /* pointless */
568
569         ev.ts = entry->ktr_timestamp;
570         ev.type = EVTR_TYPE_PROBE;
571         ev.line = entry->ktr_line;
572         ev.file = kvm_string(entry->ktr_file, &pctx);
573         ev.func = NULL;
574         ev.cpu = n;
575         if ((ki = kvm_ktrinfo(entry->ktr_info, &infoctx))) {
576                 ev.fmt = kvm_string(ki->kf_format, &fmtctx);
577                 ev.fmtdata = entry->ktr_data;
578                 if ((conv = mangle_string_ptrs(ev.fmt,
579                                                __DECONST(uint8_t *, ev.fmtdata),
580                                                0)) < 0)
581                         errx(1, "Can't parse format string\n");
582                 ev.fmtdatalen = ki->kf_data_size;
583         } else {
584                 ev.fmt = ev.fmtdata = NULL;
585                 ev.fmtdatalen = 0;
586         }
587         if (evtr_dump_event(evtr, &ev)) {
588                 err(1, evtr_errmsg(evtr));
589         }
590         if (ev.fmtdata && conv) {
591                 mangle_string_ptrs(ev.fmt, __DECONST(uint8_t *, ev.fmtdata),
592                                    !0);
593         }
594 }
595
596 static
597 struct ktr_info *
598 kvm_ktrinfo(void *kptr, struct save_ctx *ctx)
599 {
600         struct ktr_info *ki = (void *)ctx->save_buf;
601
602         if (kptr == NULL)
603                 return(NULL);
604         if (ctx->save_kptr != kptr) {
605                 if (kvm_read(kd, (uintptr_t)kptr, ki, sizeof(*ki)) == -1) {
606                         bzero(&ki, sizeof(*ki));
607                 } else {
608                         ctx->save_kptr = kptr;
609                 }
610         }
611         return(ki);
612 }
613
614 static
615 const char *
616 kvm_string(const char *kptr, struct save_ctx *ctx)
617 {
618         u_int l;
619         u_int n;
620
621         if (kptr == NULL)
622                 return("?");
623         if (ctx->save_kptr != (const void *)kptr) {
624                 ctx->save_kptr = (const void *)kptr;
625                 l = 0;
626                 while (l < sizeof(ctx->save_buf) - 1) {
627                         n = 256 - ((intptr_t)(kptr + l) & 255);
628                         if (n > sizeof(ctx->save_buf) - l - 1)
629                                 n = sizeof(ctx->save_buf) - l - 1;
630                         if (kvm_read(kd, (uintptr_t)(kptr + l), ctx->save_buf + l, n) < 0)
631                                 break;
632                         while (l < sizeof(ctx->save_buf) && n) {
633                             if (ctx->save_buf[l] == 0)
634                                     break;
635                             --n;
636                             ++l;
637                         }
638                         if (n)
639                             break;
640                 }
641                 ctx->save_buf[l] = 0;
642         }
643         return(ctx->save_buf);
644 }
645
646 static
647 const char *
648 trunc_path(const char *str, int maxlen)
649 {
650         int len = strlen(str);
651
652         if (len > maxlen)
653                 return(str + len - maxlen);
654         else
655                 return(str);
656 }
657
658 struct symdata {
659         TAILQ_ENTRY(symdata) link;
660         const char *symname;
661         char *symaddr;
662         char symtype;
663 };
664
665 static TAILQ_HEAD(symlist, symdata) symlist;
666 static struct symdata *symcache;
667 static char *symbegin;
668 static char *symend;
669
670 static
671 void
672 read_symbols(const char *file)
673 {
674         char buf[256];
675         char cmd[256];
676         size_t buflen = sizeof(buf);
677         FILE *fp;
678         struct symdata *sym;
679         char *s1;
680         char *s2;
681         char *s3;
682
683         TAILQ_INIT(&symlist);
684
685         if (file == NULL) {
686                 if (sysctlbyname("kern.bootfile", buf, &buflen, NULL, 0) < 0)
687                         file = "/boot/kernel";
688                 else
689                         file = buf;
690         }
691         snprintf(cmd, sizeof(cmd), "nm -n %s", file);
692         if ((fp = popen(cmd, "r")) != NULL) {
693                 while (fgets(buf, sizeof(buf), fp) != NULL) {
694                     s1 = strtok(buf, " \t\n");
695                     s2 = strtok(NULL, " \t\n");
696                     s3 = strtok(NULL, " \t\n");
697                     if (s1 && s2 && s3) {
698                         sym = malloc(sizeof(struct symdata));
699                         sym->symaddr = (char *)strtoul(s1, NULL, 16);
700                         sym->symtype = s2[0];
701                         sym->symname = strdup(s3);
702                         if (strcmp(s3, "kernbase") == 0)
703                                 symbegin = sym->symaddr;
704                         if (strcmp(s3, "end") == 0)
705                                 symend = sym->symaddr;
706                         TAILQ_INSERT_TAIL(&symlist, sym, link);
707                     }
708                 }
709                 pclose(fp);
710         }
711         symcache = TAILQ_FIRST(&symlist);
712 }
713
714 static
715 const char *
716 address_to_symbol(void *kptr, struct save_ctx *ctx)
717 {
718         char *buf = ctx->save_buf;
719         int size = sizeof(ctx->save_buf);
720
721         if (symcache == NULL ||
722            (char *)kptr < symbegin || (char *)kptr >= symend
723         ) {
724                 snprintf(buf, size, "%p", kptr);
725                 return(buf);
726         }
727         while ((char *)symcache->symaddr < (char *)kptr) {
728                 if (TAILQ_NEXT(symcache, link) == NULL)
729                         break;
730                 symcache = TAILQ_NEXT(symcache, link);
731         }
732         while ((char *)symcache->symaddr > (char *)kptr) {
733                 if (symcache != TAILQ_FIRST(&symlist))
734                         symcache = TAILQ_PREV(symcache, symlist, link);
735         }
736         snprintf(buf, size, "%s+%d", symcache->symname,
737                 (int)((char *)kptr - symcache->symaddr));
738         return(buf);
739 }
740
741 static
742 struct ktr_buffer *
743 ktr_bufs_init(void)
744 {
745         struct ktr_buffer *ktr_bufs, *it;
746         int i;
747
748         ktr_bufs = malloc(sizeof(*ktr_bufs) * ncpus);
749         if (!ktr_bufs)
750                 err(1, "can't allocate data structures\n");
751         for (i = 0; i < ncpus; ++i) {
752                 it = ktr_bufs + i;
753                 it->ents = malloc(sizeof(struct ktr_entry) * entries_per_buf);
754                 if (it->ents == NULL)
755                         err(1, "can't allocate data structures\n");
756                 it->reset = 1;
757                 it->beg_idx = -1;
758                 it->end_idx = -1;
759         }
760         return ktr_bufs;
761 }
762
763 static
764 void
765 get_indices(struct ktr_entry **ktr_kbuf, int *ktr_idx)
766 {
767         static struct ktr_cpu *ktr_cpus;
768         int i;
769
770         if (ktr_cpus == NULL)
771                 ktr_cpus = malloc(sizeof(*ktr_cpus) * ncpus);
772
773         if (ktr_version < KTR_VERSION_KTR_CPU) {
774                 if (kvm_read(kd, nl_version_ktr_idx[0].n_value, ktr_idx,
775                     sizeof(*ktr_idx) * ncpus) == -1) {
776                         errx(1, "%s", kvm_geterr(kd));
777                 }
778                 if (ktr_kbuf[0] == NULL) {
779                         if (kvm_read(kd, nl_version_ktr_idx[1].n_value,
780                             ktr_kbuf, sizeof(*ktr_kbuf) * ncpus) == -1) {
781                                 errx(1, "%s", kvm_geterr(kd));
782                         }
783                 }
784         } else {
785                 if (kvm_read(kd, nl_version_ktr_cpu[0].n_value,
786                              ktr_cpus, sizeof(*ktr_cpus) * ncpus) == -1) {
787                                 errx(1, "%s", kvm_geterr(kd));
788                 }
789                 for (i = 0; i < ncpus; ++i) {
790                         ktr_idx[i] = ktr_cpus[i].core.ktr_idx;
791                         ktr_kbuf[i] = ktr_cpus[i].core.ktr_buf;
792                 }
793         }
794 }
795
796 /*
797  * Get the trace buffer data from the kernel
798  */
799 static
800 void
801 load_bufs(struct ktr_buffer *ktr_bufs, struct ktr_entry **kbufs, int *ktr_idx)
802 {
803         struct ktr_buffer *kbuf;
804         int i;
805
806         get_indices(kbufs, ktr_idx);
807         for (i = 0; i < ncpus; ++i) {
808                 kbuf = &ktr_bufs[i];
809                 if (ktr_idx[i] == kbuf->end_idx)
810                         continue;
811                 kbuf->end_idx = ktr_idx[i];
812
813                 /*
814                  * If we do not have a notion of the beginning index, assume
815                  * it is entries_per_buf before the ending index.  Don't
816                  * worry about underflows/negative numbers, the indices will
817                  * be masked.
818                  */
819                 if (kbuf->reset) {
820                         kbuf->beg_idx = kbuf->end_idx - entries_per_buf + 1;
821                         kbuf->reset = 0;
822                 }
823                 if (kvm_read(kd, (uintptr_t)kbufs[i], ktr_bufs[i].ents,
824                                 sizeof(struct ktr_entry) * entries_per_buf)
825                                                                         == -1)
826                         errx(1, "%s", kvm_geterr(kd));
827                 kbuf->modified = 1;
828                 kbuf->beg_idx = earliest_ts(kbuf);
829         }
830
831 }
832
833 /*
834  * Locate the earliest timestamp iterating backwards from end_idx, but
835  * not going further back then beg_idx.  We have to do this because
836  * the kernel uses a circulating buffer.
837  */
838 static
839 int
840 earliest_ts(struct ktr_buffer *buf)
841 {
842         struct ktr_entry *save;
843         int count, scan, i, earliest;
844
845         count = 0;
846         earliest = buf->end_idx - 1;
847         save = &buf->ents[earliest & fifo_mask];
848         for (scan = buf->end_idx - 1; scan != buf->beg_idx -1; --scan) {
849                 i = scan & fifo_mask;
850                 if (buf->ents[i].ktr_timestamp <= save->ktr_timestamp &&
851                     buf->ents[i].ktr_timestamp > 0)
852                         earliest = scan;
853                 /*
854                  * We may have gotten so far behind that beg_idx wrapped
855                  * more then once around the buffer.  Just stop
856                  */
857                 if (++count == entries_per_buf)
858                         break;
859         }
860         return earliest;
861 }
862
863 static
864 void
865 iterate_buf(FILE *fo, struct ktr_buffer *ktr_bufs, int cpu,
866             u_int64_t *last_timestamp, ktr_iter_cb_t cb)
867 {
868         struct ktr_buffer *buf = ktr_bufs + cpu;
869
870         if (buf->modified == 0)
871                 return;
872         if (*last_timestamp == 0) {
873                 *last_timestamp =
874                         buf->ents[buf->beg_idx & fifo_mask].ktr_timestamp;
875         }
876         while (buf->beg_idx != buf->end_idx) {
877                 cb(fo, cpu, buf->beg_idx,
878                    &buf->ents[buf->beg_idx & fifo_mask],
879                    last_timestamp);
880                 ++buf->beg_idx;
881         }
882         buf->modified = 0;
883 }
884
885 static
886 void
887 iterate_bufs_timesorted(FILE *fo, struct ktr_buffer *ktr_bufs,
888                         u_int64_t *last_timestamp, ktr_iter_cb_t cb)
889 {
890         struct ktr_entry *ent;
891         struct ktr_buffer *buf;
892         int n, bestn;
893         u_int64_t ts;
894         static int row = 0;
895
896         for (;;) {
897                 ts = 0;
898                 bestn = -1;
899                 for (n = 0; n < ncpus; ++n) {
900                         buf = ktr_bufs + n;
901                         if (buf->beg_idx == buf->end_idx)
902                                 continue;
903                         ent = &buf->ents[buf->beg_idx & fifo_mask];
904                         if (ts == 0 || (ts >= ent->ktr_timestamp)) {
905                                 ts = ent->ktr_timestamp;
906                                 bestn = n;
907                         }
908                 }
909                 if ((bestn < 0) || (ts < *last_timestamp))
910                         break;
911                 buf = ktr_bufs + bestn;
912                 cb(fo, bestn, row,
913                    &buf->ents[buf->beg_idx & fifo_mask],
914                    last_timestamp);
915                 ++buf->beg_idx;
916                 *last_timestamp = ts;
917                 ++row;
918         }
919 }
920
921 static
922 void
923 kvmfprintf(FILE *fp, const char *ctl, va_list va)
924 {
925         int n;
926         int is_long;
927         int is_done;
928         char fmt[256];
929         static struct save_ctx strctx;
930         const char *s;
931
932         while (*ctl) {
933                 for (n = 0; ctl[n]; ++n) {
934                         fmt[n] = ctl[n];
935                         if (ctl[n] == '%')
936                                 break;
937                 }
938                 if (n == 0) {
939                         is_long = 0;
940                         is_done = 0;
941                         n = 1;
942                         while (n < (int)sizeof(fmt)) {
943                                 fmt[n] = ctl[n];
944                                 fmt[n+1] = 0;
945
946                                 switch(ctl[n]) {
947                                 case 'p':
948                                         is_long = 1;
949                                         /* fall through */
950                                 case 'd':
951                                 case 'u':
952                                 case 'x':
953                                 case 'o':
954                                 case 'X':
955                                         /*
956                                          * Integral
957                                          */
958                                         switch(is_long) {
959                                         case 0:
960                                                 fprintf(fp, fmt,
961                                                         va_arg(va, int));
962                                                 break;
963                                         case 1:
964                                                 fprintf(fp, fmt,
965                                                         va_arg(va, long));
966                                                 break;
967                                         case 2:
968                                                 fprintf(fp, fmt,
969                                                     va_arg(va, long long));
970                                                 break;
971                                         case 3:
972                                                 fprintf(fp, fmt,
973                                                     va_arg(va, size_t));
974                                                 break;
975                                         }
976                                         ++n;
977                                         is_done = 1;
978                                         break;
979                                 case 's':
980                                         /*
981                                          * String
982                                          */
983                                         s = kvm_string(va_arg(va, char *), &strctx);
984                                         fwrite(s, 1, strlen(s), fp);
985                                         ++n;
986                                         is_done = 1;
987                                         break;
988                                 case 'f':
989                                         /*
990                                          * Floating
991                                          */
992                                         fprintf(fp, fmt,
993                                                 va_arg(va, double));
994                                         ++n;
995                                         break;
996                                 case 'j':
997                                         is_long = 3;
998                                         break;
999                                 case 'l':
1000                                         if (is_long)
1001                                                 is_long = 2;
1002                                         else
1003                                                 is_long = 1;
1004                                         break;
1005                                 case '.':
1006                                 case '-':
1007                                 case '+':
1008                                 case '0':
1009                                 case '1':
1010                                 case '2':
1011                                 case '3':
1012                                 case '4':
1013                                 case '5':
1014                                 case '6':
1015                                 case '7':
1016                                 case '8':
1017                                 case '9':
1018                                         break;
1019                                 default:
1020                                         is_done = 1;
1021                                         break;
1022                                 }
1023                                 if (is_done)
1024                                         break;
1025                                 ++n;
1026                         }
1027                 } else {
1028                         fmt[n] = 0;
1029                         fprintf(fp, fmt, NULL);
1030                 }
1031                 ctl += n;
1032         }
1033 }
1034
1035 static void
1036 usage(void)
1037 {
1038         fprintf(stderr, "usage: ktrdump [-acfilnpqrstx] [-A factor] "
1039                         "[-N execfile] [-M corefile] [-o outfile]\n");
1040         exit(1);
1041 }