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 } 1042