2 * Copyright (c) 2002 Jake Burkholder
3 * Copyright (c) 2004 Robert Watson
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
27 * $FreeBSD: src/usr.bin/ktrdump/ktrdump.c,v 1.10 2005/05/21 09:55:06 ru Exp $
30 #include <sys/types.h>
34 #include <sys/queue.h>
53 struct ktr_entry
*ents
;
56 int beg_idx
; /* Beginning index */
57 int end_idx
; /* Ending index */
60 static struct nlist nl1
[] = {
61 { .n_name
= "_ktr_version" },
62 { .n_name
= "_ktr_entries" },
63 { .n_name
= "_ncpus" },
67 static struct nlist nl2
[] = {
68 { .n_name
= "_tsc_frequency" },
72 static struct nlist nl_version_ktr_idx
[] = {
73 { .n_name
= "_ktr_idx" },
74 { .n_name
= "_ktr_buf" },
78 static struct nlist nl_version_ktr_cpu
[] = {
79 { .n_name
= "_ktr_cpu" },
85 const void *save_kptr
;
88 typedef void (*ktr_iter_cb_t
)(void *, int, int, struct ktr_entry
*, uint64_t *);
91 /* defined according to the x86_64 ABI spec */
93 uint32_t gp_offset
; /* offset to next available gpr in reg_save_area */
94 uint32_t fp_offset
; /* offset to next available fpr in reg_save_area */
95 void *overflow_arg_area
; /* args that are passed on the stack */
96 struct reg_save_area
*reg_save_area
; /* register args */
98 * NOT part of the ABI. ->overflow_arg_area gets advanced when code
99 * iterates over the arguments with va_arg(). That means we need to
100 * keep a copy in order to free the allocated memory (if any)
102 void *overflow_arg_area_save
;
103 } __attribute__((packed
));
105 typedef struct my_va_list
*machine_va_list
;
107 struct reg_save_area
{
108 uint64_t rdi
, rsi
, rdx
, rcx
, r8
, r9
;
109 /* XMM registers follow, but we don't use them */
127 static double tsc_frequency
;
128 static double correction_factor
= 0.0;
130 static char corefile
[PATH_MAX
];
131 static char execfile
[PATH_MAX
];
133 static char errbuf
[_POSIX2_LINE_MAX
];
136 static int entries_per_buf
;
137 static int fifo_mask
;
138 static int ktr_version
;
140 static void usage(void);
141 static int earliest_ts(struct ktr_buffer
*);
142 static void dump_machine_info(evtr_t
);
143 static void dump_device_info(evtr_t
);
144 static void print_header(FILE *, int);
145 static void print_entry(FILE *, int, int, struct ktr_entry
*, u_int64_t
*);
146 static void print_callback(void *, int, int, struct ktr_entry
*, uint64_t *);
147 static void dump_callback(void *, int, int, struct ktr_entry
*, uint64_t *);
148 static struct ktr_info
*kvm_ktrinfo(void *, struct save_ctx
*);
149 static const char *kvm_string(const char *, struct save_ctx
*);
150 static const char *trunc_path(const char *, int);
151 static void read_symbols(const char *);
152 static const char *address_to_symbol(void *, struct save_ctx
*);
153 static struct ktr_buffer
*ktr_bufs_init(void);
154 static void get_indices(struct ktr_entry
**, int *);
155 static void load_bufs(struct ktr_buffer
*, struct ktr_entry
**, int *);
156 static void iterate_buf(FILE *, struct ktr_buffer
*, int, u_int64_t
*, ktr_iter_cb_t
);
157 static void iterate_bufs_timesorted(FILE *, struct ktr_buffer
*, u_int64_t
*, ktr_iter_cb_t
);
158 static void kvmfprintf(FILE *fp
, const char *ctl
, va_list va
);
159 static int va_list_from_blob(machine_va_list
*valist
, const char *fmt
, char *blob
, size_t blobsize
);
160 static void va_list_cleanup(machine_va_list
*valist
);
162 * Reads the ktr trace buffer from kernel memory and prints the trace entries.
165 main(int ac
, char **av
)
167 struct ktr_buffer
*ktr_bufs
;
168 struct ktr_entry
**ktr_kbuf
;
169 ktr_iter_cb_t callback
= &print_callback
;
174 int *ktr_start_index
;
179 * Parse commandline arguments.
182 while ((c
= getopt(ac
, av
, "acfinqrtxpslA:N:M:o:d")) != -1) {
198 callback
= &dump_callback
;
201 if (strlcpy(execfile
, optarg
, sizeof(execfile
))
203 errx(1, "%s: File name too long", optarg
);
216 correction_factor
= strtod(optarg
, NULL
);
219 if (strlcpy(corefile
, optarg
, sizeof(corefile
))
221 errx(1, "%s: File name too long", optarg
);
228 if ((fo
= fopen(optarg
, "w")) == NULL
)
229 err(1, "%s", optarg
);
241 sflag
= 1; /* sort across the cpus */
256 ctx
= evtr_open_write(fo
);
258 err(1, "Can't create event stream");
261 if (cflag
+ iflag
+ tflag
+ xflag
+ fflag
+ pflag
== 0) {
267 if (correction_factor
!= 0.0 && (rflag
== 0 || nflag
)) {
268 fprintf(stderr
, "Correction factor can only be applied with -r and without -n\n");
277 * Open our execfile and corefile, resolve needed symbols and read in
280 if ((kd
= kvm_openfiles(Nflag
? execfile
: NULL
,
281 Mflag
? corefile
: NULL
, NULL
, O_RDONLY
, errbuf
)) == NULL
)
282 errx(1, "%s", errbuf
);
283 if (kvm_nlist(kd
, nl1
) != 0)
284 errx(1, "%s", kvm_geterr(kd
));
285 if (kvm_read(kd
, nl1
[0].n_value
, &ktr_version
, sizeof(ktr_version
)) == -1)
286 errx(1, "%s", kvm_geterr(kd
));
287 if (kvm_read(kd
, nl1
[2].n_value
, &ncpus
, sizeof(ncpus
)) == -1)
288 errx(1, "%s", kvm_geterr(kd
));
289 ktr_start_index
= malloc(sizeof(*ktr_start_index
) * ncpus
);
290 if (ktr_version
>= KTR_VERSION_WITH_FREQ
&& kvm_nlist(kd
, nl2
) == 0) {
291 if (kvm_read(kd
, nl2
[0].n_value
, &tts
, sizeof(tts
)) == -1)
292 errx(1, "%s", kvm_geterr(kd
));
293 tsc_frequency
= (double)tts
;
295 if (ktr_version
> KTR_VERSION
)
296 errx(1, "ktr version too high for us to handle");
297 if (kvm_read(kd
, nl1
[1].n_value
, &entries_per_buf
,
298 sizeof(entries_per_buf
)) == -1)
299 errx(1, "%s", kvm_geterr(kd
));
300 fifo_mask
= entries_per_buf
- 1;
302 printf("TSC frequency is %6.3f MHz\n", tsc_frequency
/ 1000000.0);
305 dump_machine_info((evtr_t
)ctx
);
306 dump_device_info((evtr_t
)ctx
);
308 ktr_kbuf
= calloc(ncpus
, sizeof(*ktr_kbuf
));
309 ktr_idx
= calloc(ncpus
, sizeof(*ktr_idx
));
312 read_symbols(Nflag
? execfile
: NULL
);
314 if (ktr_version
< KTR_VERSION_KTR_CPU
) {
315 if (kvm_nlist(kd
, nl_version_ktr_idx
))
316 errx(1, "%s", kvm_geterr(kd
));
318 if (kvm_nlist(kd
, nl_version_ktr_cpu
))
319 errx(1, "%s", kvm_geterr(kd
));
322 get_indices(ktr_kbuf
, ktr_idx
);
324 ktr_bufs
= ktr_bufs_init();
327 u_int64_t last_timestamp
= 0;
329 load_bufs(ktr_bufs
, ktr_kbuf
, ktr_idx
);
330 iterate_bufs_timesorted(ctx
, ktr_bufs
, &last_timestamp
,
333 usleep(1000000 / 10);
336 u_int64_t
*last_timestamp
= calloc(sizeof(u_int64_t
), ncpus
);
338 load_bufs(ktr_bufs
, ktr_kbuf
, ktr_idx
);
339 for (n
= 0; n
< ncpus
; ++n
)
340 iterate_buf(ctx
, ktr_bufs
, n
, &last_timestamp
[n
],
343 usleep(1000000 / 10);
353 dump_devinfo(struct devinfo_dev
*dev
, void *arg
)
355 struct evtr_event ev
;
356 evtr_t evtr
= (evtr_t
)arg
;
357 const char *fmt
= "#devicenames[\"%s\"] = %#lx";
358 char fmtdatabuf
[sizeof(char *) + sizeof(devinfo_handle_t
)];
359 char *fmtdata
= fmtdatabuf
;
361 if (!dev
->dd_name
[0])
363 ev
.type
= EVTR_TYPE_PROBE
;
370 ((char **)fmtdata
)[0] = &dev
->dd_name
[0];
371 fmtdata
+= sizeof(char *);
372 ((devinfo_handle_t
*)fmtdata
)[0] = dev
->dd_handle
;
373 ev
.fmtdata
= fmtdatabuf
;
374 ev
.fmtdatalen
= sizeof(fmtdatabuf
);
376 if (evtr_dump_event(evtr
, &ev
)) {
377 err(1, "%s", evtr_errmsg(evtr
));
380 return devinfo_foreach_device_child(dev
, dump_devinfo
, evtr
);
385 dump_device_info(evtr_t evtr
)
387 struct devinfo_dev
*root
;
390 if (!(root
= devinfo_handle_to_device(DEVINFO_ROOT_DEVICE
))) {
391 warn("can't find root device");
394 devinfo_foreach_device_child(root
, dump_devinfo
, evtr
);
399 dump_machine_info(evtr_t evtr
)
401 struct evtr_event ev
;
404 bzero(&ev
, sizeof(ev
));
405 ev
.type
= EVTR_TYPE_SYSINFO
;
407 evtr_dump_event(evtr
, &ev
);
408 if (evtr_error(evtr
)) {
409 err(1, "%s", evtr_errmsg(evtr
));
412 for (i
= 0; i
< ncpus
; ++i
) {
413 bzero(&ev
, sizeof(ev
));
414 ev
.type
= EVTR_TYPE_CPUINFO
;
416 ev
.cpuinfo
.freq
= tsc_frequency
;
417 evtr_dump_event(evtr
, &ev
);
418 if (evtr_error(evtr
)) {
419 err(1, "%s", evtr_errmsg(evtr
));
425 print_header(FILE *fo
, int row
)
427 if (qflag
== 0 && (u_int32_t
)row
% 20 == 0) {
428 fprintf(fo
, "%-6s ", "index");
430 fprintf(fo
, "%-3s ", "cpu");
432 fprintf(fo
, "%-16s ", "timestamp");
435 fprintf(fo
, "%-18s %-18s ", "caller2", "caller1");
437 fprintf(fo
, "%-25s %-25s ", "caller2", "caller1");
440 fprintf(fo
, "%-20s ", "ID");
442 fprintf(fo
, "%10s%-30s", "", "file and line");
444 fprintf(fo
, "%s", "trace");
450 print_entry(FILE *fo
, int n
, int row
, struct ktr_entry
*entry
,
451 u_int64_t
*last_timestamp
)
453 struct ktr_info
*info
= NULL
;
454 static struct save_ctx nctx
, pctx
, fmtctx
, symctx
, infoctx
;
456 fprintf(fo
, "%06x ", row
& 0x00FFFFFF);
458 fprintf(fo
, "%-3d ", n
);
459 if (tflag
|| rflag
) {
460 if (rflag
&& !nflag
&& tsc_frequency
!= 0.0) {
461 fprintf(fo
, "%13.3f uS ",
462 (double)(entry
->ktr_timestamp
- *last_timestamp
) * 1000000.0 / tsc_frequency
- correction_factor
);
464 fprintf(fo
, "%-16ju ",
465 (uintmax_t)(entry
->ktr_timestamp
- *last_timestamp
));
467 fprintf(fo
, "%-16ju ",
468 (uintmax_t)entry
->ktr_timestamp
);
473 fprintf(fo
, "%p %p ",
474 entry
->ktr_caller2
, entry
->ktr_caller1
);
476 fprintf(fo
, "%-25s ",
477 address_to_symbol(entry
->ktr_caller2
, &symctx
));
478 fprintf(fo
, "%-25s ",
479 address_to_symbol(entry
->ktr_caller1
, &symctx
));
483 info
= kvm_ktrinfo(entry
->ktr_info
, &infoctx
);
485 fprintf(fo
, "%-20s ", kvm_string(info
->kf_name
, &nctx
));
487 fprintf(fo
, "%-20s ", "<empty>");
490 fprintf(fo
, "%34s:%-4d ",
491 trunc_path(kvm_string(entry
->ktr_file
, &pctx
), 34),
495 info
= kvm_ktrinfo(entry
->ktr_info
, &infoctx
);
499 fmt
= kvm_string(info
->kf_format
, &fmtctx
);
500 if (va_list_from_blob(&ap
, fmt
,
501 (char *)&entry
->ktr_data
,
503 err(2, "Can't generate va_list from %s", fmt
);
504 kvmfprintf(fo
, kvm_string(info
->kf_format
, &fmtctx
),
506 va_list_cleanup(&ap
);
510 *last_timestamp
= entry
->ktr_timestamp
;
515 print_callback(void *ctx
, int n
, int row
, struct ktr_entry
*entry
, uint64_t *last_ts
)
517 FILE *fo
= (FILE *)ctx
;
518 print_header(fo
, row
);
519 print_entry(fo
, n
, row
, entry
, last_ts
);
523 * If free == 0, replace all (kvm) string pointers in fmtdata with pointers
524 * to user-allocated copies of the strings.
525 * If free != 0, free those pointers.
529 mangle_string_ptrs(const char *fmt
, uint8_t *fmtdata
, int dofree
)
532 size_t skipsize
, intsz
;
533 static struct save_ctx strctx
;
536 for (f
= fmt
; f
[0] != '\0'; ++f
) {
541 for (p
= f
; p
[0]; ++p
) {
544 * Eat flags. Notice this will accept duplicate
560 /* Eat minimum field width, if any */
561 for (; isdigit(p
[0]); ++p
)
565 /* Eat precision, if any */
566 for (; isdigit(p
[0]); ++p
)
573 intsz
= sizeof(char);
575 intsz
= sizeof(short);
581 intsz
= sizeof(long long);
583 intsz
= sizeof(long);
587 intsz
= sizeof(intmax_t);
590 intsz
= sizeof(ptrdiff_t);
593 intsz
= sizeof(size_t);
614 skipsize
= sizeof(void *);
618 skipsize
= sizeof(double);
620 skipsize
= sizeof(float);
624 char *t
= ((char **)fmtdata
)[0];
626 skipsize
= sizeof(char *);
628 char *t
= strdup(kvm_string(((char **)fmtdata
)[0],
630 ((const char **)fmtdata
)[0] = t
;
632 skipsize
= sizeof(char *);
637 fprintf(stderr
, "Unknown conversion specifier %c "
638 "in fmt starting with %s\n", p
[0], f
- 1);
648 dump_callback(void *ctx
, int n
, int row __unused
, struct ktr_entry
*entry
,
649 uint64_t *last_ts __unused
)
651 evtr_t evtr
= (evtr_t
)ctx
;
652 struct evtr_event ev
;
653 static struct save_ctx pctx
, fmtctx
, infoctx
;
655 int conv
= 0; /* pointless */
657 ev
.ts
= entry
->ktr_timestamp
;
658 ev
.type
= EVTR_TYPE_PROBE
;
659 ev
.line
= entry
->ktr_line
;
660 ev
.file
= kvm_string(entry
->ktr_file
, &pctx
);
663 if ((ki
= kvm_ktrinfo(entry
->ktr_info
, &infoctx
))) {
664 ev
.fmt
= kvm_string(ki
->kf_format
, &fmtctx
);
665 ev
.fmtdata
= entry
->ktr_data
;
666 if ((conv
= mangle_string_ptrs(ev
.fmt
,
667 __DECONST(uint8_t *, ev
.fmtdata
),
669 errx(1, "Can't parse format string");
670 ev
.fmtdatalen
= ki
->kf_data_size
;
672 ev
.fmt
= ev
.fmtdata
= NULL
;
675 if (evtr_dump_event(evtr
, &ev
)) {
676 err(1, "%s", evtr_errmsg(evtr
));
678 if (ev
.fmtdata
&& conv
) {
679 mangle_string_ptrs(ev
.fmt
, __DECONST(uint8_t *, ev
.fmtdata
),
686 kvm_ktrinfo(void *kptr
, struct save_ctx
*ctx
)
688 struct ktr_info
*ki
= (void *)ctx
->save_buf
;
692 if (ctx
->save_kptr
!= kptr
) {
693 if (kvm_read(kd
, (uintptr_t)kptr
, ki
, sizeof(*ki
)) == -1) {
694 bzero(ki
, sizeof(*ki
));
696 ctx
->save_kptr
= kptr
;
704 kvm_string(const char *kptr
, struct save_ctx
*ctx
)
711 if (ctx
->save_kptr
!= (const void *)kptr
) {
712 ctx
->save_kptr
= (const void *)kptr
;
714 while (l
< sizeof(ctx
->save_buf
) - 1) {
715 n
= 256 - ((intptr_t)(kptr
+ l
) & 255);
716 if (n
> sizeof(ctx
->save_buf
) - l
- 1)
717 n
= sizeof(ctx
->save_buf
) - l
- 1;
718 if (kvm_read(kd
, (uintptr_t)(kptr
+ l
), ctx
->save_buf
+ l
, n
) < 0)
720 while (l
< sizeof(ctx
->save_buf
) && n
) {
721 if (ctx
->save_buf
[l
] == 0)
729 ctx
->save_buf
[l
] = 0;
731 return(ctx
->save_buf
);
736 trunc_path(const char *str
, int maxlen
)
738 int len
= strlen(str
);
741 return(str
+ len
- maxlen
);
747 TAILQ_ENTRY(symdata
) link
;
753 static TAILQ_HEAD(symlist
, symdata
) symlist
;
754 static struct symdata
*symcache
;
755 static char *symbegin
;
760 read_symbols(const char *file
)
764 size_t buflen
= sizeof(buf
);
766 struct symdata
*sym
= NULL
;
771 TAILQ_INIT(&symlist
);
774 if (sysctlbyname("kern.bootfile", buf
, &buflen
, NULL
, 0) < 0)
775 file
= "/boot/kernel/kernel";
779 snprintf(cmd
, sizeof(cmd
), "nm -n %s", file
);
780 if ((fp
= popen(cmd
, "r")) != NULL
) {
781 while (fgets(buf
, sizeof(buf
), fp
) != NULL
) {
782 s1
= strtok(buf
, " \t\n");
783 s2
= strtok(NULL
, " \t\n");
784 s3
= strtok(NULL
, " \t\n");
785 if (s1
&& s2
&& s3
) {
786 sym
= malloc(sizeof(struct symdata
));
787 sym
->symaddr
= (char *)strtoul(s1
, NULL
, 16);
788 sym
->symtype
= s2
[0];
789 sym
->symname
= strdup(s3
);
790 if (strcmp(s3
, "kernbase") == 0)
791 symbegin
= sym
->symaddr
;
792 if (strcmp(s3
, "end") == 0 || strcmp(s3
, "_end") == 0)
793 symend
= sym
->symaddr
;
794 TAILQ_INSERT_TAIL(&symlist
, sym
, link
);
799 if (symend
== NULL
) {
801 symend
= sym
->symaddr
;
805 symcache
= TAILQ_FIRST(&symlist
);
810 address_to_symbol(void *kptr
, struct save_ctx
*ctx
)
812 char *buf
= ctx
->save_buf
;
813 int size
= sizeof(ctx
->save_buf
);
815 if (symcache
== NULL
||
816 (char *)kptr
< symbegin
|| (char *)kptr
>= symend
818 snprintf(buf
, size
, "%p", kptr
);
821 while ((char *)symcache
->symaddr
< (char *)kptr
) {
822 if (TAILQ_NEXT(symcache
, link
) == NULL
)
824 symcache
= TAILQ_NEXT(symcache
, link
);
826 while ((char *)symcache
->symaddr
> (char *)kptr
) {
827 if (symcache
!= TAILQ_FIRST(&symlist
))
828 symcache
= TAILQ_PREV(symcache
, symlist
, link
);
830 snprintf(buf
, size
, "%s+%d", symcache
->symname
,
831 (int)((char *)kptr
- symcache
->symaddr
));
839 struct ktr_buffer
*ktr_bufs
, *it
;
842 ktr_bufs
= malloc(sizeof(*ktr_bufs
) * ncpus
);
844 err(1, "can't allocate data structures");
845 for (i
= 0; i
< ncpus
; ++i
) {
847 it
->ents
= malloc(sizeof(struct ktr_entry
) * entries_per_buf
);
848 if (it
->ents
== NULL
)
849 err(1, "can't allocate data structures");
859 get_indices(struct ktr_entry
**ktr_kbuf
, int *ktr_idx
)
861 static struct ktr_cpu
*ktr_cpus
;
864 if (ktr_cpus
== NULL
)
865 ktr_cpus
= malloc(sizeof(*ktr_cpus
) * ncpus
);
867 if (ktr_version
< KTR_VERSION_KTR_CPU
) {
868 if (kvm_read(kd
, nl_version_ktr_idx
[0].n_value
, ktr_idx
,
869 sizeof(*ktr_idx
) * ncpus
) == -1) {
870 errx(1, "%s", kvm_geterr(kd
));
872 if (ktr_kbuf
[0] == NULL
) {
873 if (kvm_read(kd
, nl_version_ktr_idx
[1].n_value
,
874 ktr_kbuf
, sizeof(*ktr_kbuf
) * ncpus
) == -1) {
875 errx(1, "%s", kvm_geterr(kd
));
879 if (kvm_read(kd
, nl_version_ktr_cpu
[0].n_value
,
880 ktr_cpus
, sizeof(*ktr_cpus
) * ncpus
) == -1) {
881 errx(1, "%s", kvm_geterr(kd
));
883 for (i
= 0; i
< ncpus
; ++i
) {
884 ktr_idx
[i
] = ktr_cpus
[i
].core
.ktr_idx
;
885 ktr_kbuf
[i
] = ktr_cpus
[i
].core
.ktr_buf
;
891 * Get the trace buffer data from the kernel
895 load_bufs(struct ktr_buffer
*ktr_bufs
, struct ktr_entry
**kbufs
, int *ktr_idx
)
897 struct ktr_buffer
*kbuf
;
900 get_indices(kbufs
, ktr_idx
);
901 for (i
= 0; i
< ncpus
; ++i
) {
903 if (ktr_idx
[i
] == kbuf
->end_idx
)
905 kbuf
->end_idx
= ktr_idx
[i
];
908 * If we do not have a notion of the beginning index, assume
909 * it is entries_per_buf before the ending index. Don't
910 * worry about underflows/negative numbers, the indices will
914 kbuf
->beg_idx
= kbuf
->end_idx
- entries_per_buf
+ 1;
917 if (kvm_read(kd
, (uintptr_t)kbufs
[i
], ktr_bufs
[i
].ents
,
918 sizeof(struct ktr_entry
) * entries_per_buf
)
920 errx(1, "%s", kvm_geterr(kd
));
922 kbuf
->beg_idx
= earliest_ts(kbuf
);
928 * Locate the earliest timestamp iterating backwards from end_idx, but
929 * not going further back then beg_idx. We have to do this because
930 * the kernel uses a circulating buffer.
934 earliest_ts(struct ktr_buffer
*buf
)
936 struct ktr_entry
*save
;
937 int count
, scan
, i
, earliest
;
940 earliest
= buf
->end_idx
- 1;
941 save
= &buf
->ents
[earliest
& fifo_mask
];
942 for (scan
= buf
->end_idx
- 1; scan
!= buf
->beg_idx
-1; --scan
) {
943 i
= scan
& fifo_mask
;
944 if (buf
->ents
[i
].ktr_timestamp
<= save
->ktr_timestamp
&&
945 buf
->ents
[i
].ktr_timestamp
> 0)
948 * We may have gotten so far behind that beg_idx wrapped
949 * more then once around the buffer. Just stop
951 if (++count
== entries_per_buf
)
959 iterate_buf(FILE *fo
, struct ktr_buffer
*ktr_bufs
, int cpu
,
960 u_int64_t
*last_timestamp
, ktr_iter_cb_t cb
)
962 struct ktr_buffer
*buf
= ktr_bufs
+ cpu
;
964 if (buf
->modified
== 0)
966 if (*last_timestamp
== 0) {
968 buf
->ents
[buf
->beg_idx
& fifo_mask
].ktr_timestamp
;
970 while (buf
->beg_idx
!= buf
->end_idx
) {
971 cb(fo
, cpu
, buf
->beg_idx
,
972 &buf
->ents
[buf
->beg_idx
& fifo_mask
],
981 iterate_bufs_timesorted(FILE *fo
, struct ktr_buffer
*ktr_bufs
,
982 u_int64_t
*last_timestamp
, ktr_iter_cb_t cb
)
984 struct ktr_entry
*ent
;
985 struct ktr_buffer
*buf
;
993 for (n
= 0; n
< ncpus
; ++n
) {
995 if (buf
->beg_idx
== buf
->end_idx
)
997 ent
= &buf
->ents
[buf
->beg_idx
& fifo_mask
];
998 if (ts
== 0 || (ts
>= ent
->ktr_timestamp
)) {
999 ts
= ent
->ktr_timestamp
;
1003 if ((bestn
< 0) || (ts
< *last_timestamp
))
1005 buf
= ktr_bufs
+ bestn
;
1007 &buf
->ents
[buf
->beg_idx
& fifo_mask
],
1010 *last_timestamp
= ts
;
1017 kvmfprintf(FILE *fp
, const char *ctl
, va_list va
)
1023 static struct save_ctx strctx
;
1027 for (n
= 0; ctl
[n
]; ++n
) {
1036 while (n
< (int)sizeof(fmt
)) {
1064 va_arg(va
, long long));
1068 va_arg(va
, size_t));
1075 fprintf(fp
, "%c", va_arg(va
, int));
1083 s
= kvm_string(va_arg(va
, char *), &strctx
);
1084 fwrite(s
, 1, strlen(s
), fp
);
1093 va_arg(va
, double));
1137 fprintf(fp
, fmt
, NULL
);
1146 fprintf(stderr
, "usage: ktrdump [-acfilnpqrstx] [-A factor] "
1147 "[-N execfile] [-M corefile] [-o outfile]\n");
1151 enum argument_class
{
1159 conversion_size(const char *fmt
, enum argument_class
*argclass
)
1162 size_t convsize
, intsz
;
1164 *argclass
= ARGCLASS_ERR
;
1169 for (p
= fmt
+ 1; p
[0]; ++p
) {
1172 * Eat flags. Notice this will accept duplicate
1188 /* Eat minimum field width, if any */
1189 for (; isdigit(p
[0]); ++p
)
1193 /* Eat precision, if any */
1194 for (; isdigit(p
[0]); ++p
)
1201 intsz
= sizeof(char);
1203 intsz
= sizeof(short);
1209 intsz
= sizeof(long long);
1211 intsz
= sizeof(long);
1215 intsz
= sizeof(intmax_t);
1218 intsz
= sizeof(ptrdiff_t);
1221 intsz
= sizeof(size_t);
1224 p
--; /* Anticipate the ++p that follows. Yes, I know. Eeek. */
1228 intsz
= sizeof(int);
1233 /* for %c, we only store 1 byte in the ktr entry */
1234 convsize
= sizeof(char);
1235 *argclass
= ARGCLASS_INTEGER
;
1244 *argclass
= ARGCLASS_INTEGER
;
1247 convsize
= sizeof(void *);
1248 *argclass
= ARGCLASS_INTEGER
;
1252 convsize
= sizeof(double);
1254 convsize
= sizeof(float);
1255 *argclass
= ARGCLASS_FP
;
1258 convsize
= sizeof(char *);
1259 *argclass
= ARGCLASS_INTEGER
;
1263 *argclass
= ARGCLASS_NONE
;
1266 fprintf(stderr
, "Unknown conversion specifier %c "
1267 "in fmt starting with %s\n", p
[0], fmt
- 1);
1275 va_list_push_integral(struct my_va_list
*valist
, void *val
, size_t valsize
,
1282 r
= *(uint8_t *)val
; break;
1284 r
= *(uint32_t *)val
; break;
1286 r
= (*(uint32_t *)val
); break;
1288 r
= *(uint64_t *)val
; break;
1292 /* we always need to push the full 8 bytes */
1293 if ((valist
->gp_offset
+ valsize
) <= 48) { /* got a free reg */
1295 memcpy(((char *)valist
->reg_save_area
+ valist
->gp_offset
),
1297 valist
->gp_offset
+= sizeof(r
);
1300 /* push to "stack" */
1301 if (!(valist
->overflow_arg_area
= realloc(valist
->overflow_arg_area
,
1302 *stacksize
+ sizeof(r
))))
1305 * Keep a pointer to the start of the allocated memory block so
1306 * we can free it later. We need to update it after every realloc().
1308 valist
->overflow_arg_area_save
= valist
->overflow_arg_area
;
1309 memcpy((char *)valist
->overflow_arg_area
+ *stacksize
, &r
, sizeof(r
));
1310 *stacksize
+= sizeof(r
);
1315 va_list_rewind(struct my_va_list
*valist
)
1317 valist
->gp_offset
= 0;
1321 va_list_cleanup(machine_va_list
*_valist
)
1323 machine_va_list valist
;
1324 if (!_valist
|| !*_valist
)
1327 if (valist
->reg_save_area
)
1328 free(valist
->reg_save_area
);
1329 if (valist
->overflow_arg_area_save
)
1330 free(valist
->overflow_arg_area_save
);
1335 va_list_from_blob(machine_va_list
*_valist
, const char *fmt
, char *blob
, size_t blobsize
)
1337 machine_va_list valist
;
1338 struct reg_save_area
*regs
;
1339 enum argument_class argclass
;
1341 size_t stacksize
, sz
;
1343 if (!(valist
= malloc(sizeof(*valist
))))
1345 if (!(regs
= malloc(sizeof(*regs
))))
1347 *valist
= (struct my_va_list
) {
1350 .overflow_arg_area
= NULL
,
1351 .reg_save_area
= regs
,
1352 .overflow_arg_area_save
= NULL
,
1356 for (f
= fmt
; *f
!= '\0'; ++f
) {
1359 sz
= conversion_size(f
, &argclass
);
1360 if (argclass
== ARGCLASS_INTEGER
) {
1361 if (blobsize
< sz
) {
1362 fprintf(stderr
, "not enough data available "
1363 "for format: %s\n", fmt
);
1366 if (va_list_push_integral(valist
, blob
, sz
, &stacksize
))
1370 } else if (argclass
!= ARGCLASS_NONE
)
1372 /* walk past the '%' */
1376 fprintf(stderr
, "Couldn't consume all data for format %s "
1377 "(%zu bytes left over)\n", fmt
, blobsize
);
1380 va_list_rewind(valist
);
1384 if (valist
->reg_save_area
)
1385 free(valist
->reg_save_area
);
1386 if (valist
->overflow_arg_area_save
)
1387 free(valist
->overflow_arg_area_save
);
1395 #error "Don't know how to get a va_list on this platform"