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