1/* 2 cc -I/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders -arch x86_64 -arch i386 -O -o trace trace.c 3*/ 4 5 6#include <sys/param.h> 7#include <sys/types.h> 8#include <sys/file.h> 9#include <sys/socket.h> 10#include <sys/stat.h> 11#include <sys/ioctl.h> 12#include <sys/mbuf.h> 13#include <sys/mman.h> 14#include <sys/ucred.h> 15#include <sys/time.h> 16#include <sys/proc.h> 17#include <sys/ptrace.h> 18#include <sys/sysctl.h> 19#include <sys/wait.h> 20#include <sys/resource.h> 21#include <errno.h> 22#include <unistd.h> 23#include <stdio.h> 24#include <ctype.h> 25#include <stdlib.h> 26#include <string.h> 27#include <paths.h> 28#include <err.h> 29#include <stdarg.h> 30#include <inttypes.h> 31 32#include <libutil.h> 33 34#ifndef KERNEL_PRIVATE 35#define KERNEL_PRIVATE 36#include <sys/kdebug.h> 37#undef KERNEL_PRIVATE 38#else 39#include <sys/kdebug.h> 40#endif /*KERNEL_PRIVATE*/ 41#include <sys/param.h> 42 43#include <mach/mach.h> 44#include <mach/mach_time.h> 45 46 47int nbufs = 0; 48int enable_flag=0; 49int execute_flag=0; 50int logRAW_flag=0; 51int LogRAW_flag=0; 52int readRAW_flag = 0; 53int disable_flag=0; 54int init_flag=0; 55int kval_flag=0; 56int remove_flag=0; 57int bufset_flag=0; 58int bufget_flag=0; 59int filter_flag=0; 60int filter_file_flag=0; 61int filter_alloced=0; 62int trace_flag=0; 63int nowrap_flag=0; 64int freerun_flag=0; 65int verbose_flag=0; 66int usage_flag=0; 67int pid_flag=0; 68int pid_exflag=0; 69int ppt_flag=0; 70int done_with_args=0; 71int no_default_codes_flag=0; 72 73unsigned int value1=0; 74unsigned int value2=0; 75unsigned int value3=0; 76unsigned int value4=0; 77 78pid_t pid=0; 79int reenable=0; 80 81int force_32bit_exec = 0; 82int frequency = 0; 83 84int mib[6]; 85size_t needed; 86 87char *logfile = (char *)0; /* This file is trace format */ 88char *RAW_file = (char *)0; 89FILE *output_file; 90int output_fd; 91 92extern char **environ; 93 94uint8_t* type_filter_bitmap; 95 96 97#define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END) 98#define DBG_FUNC_MASK 0xfffffffc 99#define SHORT_HELP 1 100#define LONG_HELP 0 101 102#define CSC_MASK 0xffff0000 103 104#define VFS_LOOKUP 0x03010090 105#define BSC_exit 0x040c0004 106#define BSC_thread_terminate 0x040c05a4 107#define TRACE_DATA_NEWTHREAD 0x07000004 108#define TRACE_STRING_NEWTHREAD 0x07010004 109#define TRACE_STRING_EXEC 0x07010008 110#define TRACE_LOST_EVENTS 0x07020008 111#define MACH_SCHEDULED 0x01400000 112#define MACH_MAKERUNNABLE 0x01400018 113#define MACH_STKHANDOFF 0x01400008 114 115#define EMPTYSTRING "" 116#define UNKNOWN "unknown" 117 118char tmpcommand[MAXCOMLEN]; 119 120int total_threads = 0; 121int nthreads = 0; 122kd_threadmap *mapptr = 0; 123 124kd_cpumap_header* cpumap_header = NULL; 125kd_cpumap* cpumap = NULL; 126 127/* 128 If NUMPARMS changes from the kernel, 129 then PATHLENGTH will also reflect the change 130 This is for the vfslookup entries that 131 return pathnames 132*/ 133#define NUMPARMS 23 134#define PATHLENGTH (NUMPARMS*sizeof(long)) 135 136 137#define US_TO_SLEEP 50000 138#define BASE_EVENTS 500000 139 140 141double divisor; 142 143typedef struct { 144 uint32_t debugid; 145 char *debug_string; 146} code_type_t; 147 148code_type_t* codesc = 0; 149size_t codesc_idx = 0; // Index into first empty codesc entry 150 151 152 153typedef struct event *event_t; 154 155struct event { 156 event_t ev_next; 157 158 uintptr_t ev_thread; 159 uint32_t ev_debugid; 160 uint64_t ev_timestamp; 161}; 162 163typedef struct lookup *lookup_t; 164 165struct lookup { 166 lookup_t lk_next; 167 168 uintptr_t lk_thread; 169 uintptr_t lk_dvp; 170 long *lk_pathptr; 171 long lk_pathname[NUMPARMS + 1]; 172}; 173 174typedef struct threadmap *threadmap_t; 175 176struct threadmap { 177 threadmap_t tm_next; 178 179 uintptr_t tm_thread; 180 uintptr_t tm_pthread; 181 boolean_t tm_deleteme; 182 char tm_command[MAXCOMLEN + 1]; 183}; 184 185 186#define HASH_SIZE 1024 187#define HASH_MASK 1023 188 189event_t event_hash[HASH_SIZE]; 190lookup_t lookup_hash[HASH_SIZE]; 191threadmap_t threadmap_hash[HASH_SIZE]; 192 193event_t event_freelist; 194lookup_t lookup_freelist; 195threadmap_t threadmap_freelist; 196threadmap_t threadmap_temp; 197 198 199#define SBUFFER_SIZE (128 * 4096) 200char sbuffer[SBUFFER_SIZE]; 201 202int secs_to_run = 0; 203int use_current_buf = 0; 204 205 206kbufinfo_t bufinfo = {0, 0, 0, 0}; 207 208int codenum = 0; 209int codeindx_cache = 0; 210 211static void quit(char *); 212static int match_debugid(unsigned int, char *, int *); 213static void usage(int short_help); 214static int argtoi(int flag, char *req, char *str, int base); 215static int parse_codefile(const char *filename); 216static void codesc_find_dupes(void); 217static int read_command_map(int, uint32_t); 218static void read_cpu_map(int); 219static void find_thread_command(kd_buf *, char **); 220static void create_map_entry(uintptr_t, char *); 221static void getdivisor(); 222static unsigned long argtoul(); 223 224static void set_enable(int); 225static void set_remove(); 226static void set_nowrap(); 227static void set_pidcheck(int, int); 228static void set_pidexclude(int, int); 229static void set_numbufs(int); 230static void set_freerun(); 231static void get_bufinfo(kbufinfo_t *); 232static void set_init(); 233static void set_kval_list(); 234static void readtrace(char *); 235static void log_trace(); 236static void Log_trace(); 237static void read_trace(); 238static void signal_handler(int); 239static void signal_handler_RAW(int); 240static void delete_thread_entry(uintptr_t); 241static void find_and_insert_tmp_map_entry(uintptr_t, char *); 242static void create_tmp_map_entry(uintptr_t, uintptr_t); 243static void find_thread_name(uintptr_t, char **, boolean_t); 244 245static int writetrace(int); 246static int write_command_map(int); 247static int debugid_compar(code_type_t *, code_type_t *); 248 249static threadmap_t find_thread_entry(uintptr_t); 250 251static void saw_filter_class(uint8_t class); 252static void saw_filter_end_range(uint8_t end_class); 253static void saw_filter_subclass(uint8_t subclass); 254static void filter_done_parsing(void); 255 256static void set_filter(void); 257static void set_filter_class(uint8_t class); 258static void set_filter_range(uint8_t class, uint8_t end); 259static void set_filter_subclass(uint8_t class, uint8_t subclass); 260 261static void parse_filter_file(char *filename); 262 263static void quit_args(const char *fmt, ...) __printflike(1, 2); 264 265#ifndef KERN_KDWRITETR 266#define KERN_KDWRITETR 17 267#endif 268 269#ifndef KERN_KDWRITEMAP 270#define KERN_KDWRITEMAP 18 271#endif 272 273#ifndef F_FLUSH_DATA 274#define F_FLUSH_DATA 40 275#endif 276 277#ifndef RAW_VERSION1 278typedef struct { 279 int version_no; 280 int thread_count; 281 uint64_t TOD_secs; 282 uint32_t TOD_usecs; 283} RAW_header; 284 285#define RAW_VERSION0 0x55aa0000 286#define RAW_VERSION1 0x55aa0101 287#endif 288 289#define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(*x))) 290 291#define EXTRACT_CLASS_LOW(debugid) ( (uint8_t) ( ((debugid) & 0xFF00 ) >> 8 ) ) 292#define EXTRACT_SUBCLASS_LOW(debugid) ( (uint8_t) ( ((debugid) & 0xFF ) ) ) 293 294#define ENCODE_CSC_LOW(class, subclass) \ 295 ( (uint16_t) ( ((class) & 0xff) << 8 ) | ((subclass) & 0xff) ) 296 297RAW_header raw_header; 298 299 300 301void set_enable(int val) 302{ 303 mib[0] = CTL_KERN; 304 mib[1] = KERN_KDEBUG; 305 mib[2] = KERN_KDENABLE; 306#ifdef KDEBUG_ENABLE_PPT 307 if (ppt_flag && val) { 308 mib[3] = KDEBUG_ENABLE_PPT; 309 } else { 310 mib[3] = val; 311 } 312#else 313 mib[3] = val; 314#endif 315 mib[4] = 0; 316 mib[5] = 0; 317 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0) 318 quit_args("trace facility failure, KERN_KDENABLE: %s\n", strerror(errno)); 319} 320 321void set_remove() 322{ 323 extern int errno; 324 325 errno = 0; 326 327 mib[0] = CTL_KERN; 328 mib[1] = KERN_KDEBUG; 329 mib[2] = KERN_KDREMOVE; 330 mib[3] = 0; 331 mib[4] = 0; 332 mib[5] = 0; 333 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0) 334 { 335 if (errno == EBUSY) 336 quit("the trace facility is currently in use...\n fs_usage, sc_usage, trace, and latency use this feature.\n\n"); 337 else 338 quit_args("trace facility failure, KERN_KDREMOVE: %s\n", strerror(errno)); 339 } 340} 341 342void set_numbufs(int nbufs) 343{ 344 mib[0] = CTL_KERN; 345 mib[1] = KERN_KDEBUG; 346 mib[2] = KERN_KDSETBUF; 347 mib[3] = nbufs; 348 mib[4] = 0; 349 mib[5] = 0; 350 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0) 351 quit_args("trace facility failure, KERN_KDSETBUF: %s\n", strerror(errno)); 352 353 mib[0] = CTL_KERN; 354 mib[1] = KERN_KDEBUG; 355 mib[2] = KERN_KDSETUP; 356 mib[3] = 0; 357 mib[4] = 0; 358 mib[5] = 0; 359 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0) 360 quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno)); 361} 362 363void set_nowrap() 364{ 365 mib[0] = CTL_KERN; 366 mib[1] = KERN_KDEBUG; 367 mib[2] = KERN_KDEFLAGS; 368 mib[3] = KDBG_NOWRAP; 369 mib[4] = 0; 370 mib[5] = 0; /* no flags */ 371 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0) 372 quit_args("trace facility failure, KDBG_NOWRAP: %s\n", strerror(errno)); 373 374} 375 376void set_pidcheck(int pid, int on_off_flag) 377{ 378 kd_regtype kr; 379 380 kr.type = KDBG_TYPENONE; 381 kr.value1 = pid; 382 kr.value2 = on_off_flag; 383 needed = sizeof(kd_regtype); 384 mib[0] = CTL_KERN; 385 mib[1] = KERN_KDEBUG; 386 mib[2] = KERN_KDPIDTR; 387 mib[3] = 0; 388 mib[4] = 0; 389 mib[5] = 0; 390 if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0) 391 { 392 if (on_off_flag == 1) 393 { 394 printf("trace facility failure, KERN_KDPIDTR,\n\tpid %d does not exist\n", pid); 395 set_remove(); 396 exit(2); 397 } 398 } 399} 400 401void set_pidexclude(int pid, int on_off_flag) 402{ 403 kd_regtype kr; 404 405 kr.type = KDBG_TYPENONE; 406 kr.value1 = pid; 407 kr.value2 = on_off_flag; 408 needed = sizeof(kd_regtype); 409 mib[0] = CTL_KERN; 410 mib[1] = KERN_KDEBUG; 411 mib[2] = KERN_KDPIDEX; 412 mib[3] = 0; 413 mib[4] = 0; 414 mib[5] = 0; 415 if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0) 416 { 417 if (on_off_flag == 1) 418 { 419 printf ("pid %d does not exist\n", pid); 420 set_remove(); 421 exit(2); 422 } 423 } 424} 425 426void set_freerun() 427{ 428 mib[0] = CTL_KERN; 429 mib[1] = KERN_KDEBUG; 430 mib[2] = KERN_KDEFLAGS; 431 mib[3] = KDBG_FREERUN; 432 mib[4] = 0; 433 mib[5] = 0; 434 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0) 435 quit_args("trace facility failure, KDBG_FREERUN: %s\n", strerror(errno)); 436} 437 438void get_bufinfo(kbufinfo_t *val) 439{ 440 needed = sizeof (*val); 441 mib[0] = CTL_KERN; 442 mib[1] = KERN_KDEBUG; 443 mib[2] = KERN_KDGETBUF; 444 mib[3] = 0; 445 mib[4] = 0; 446 mib[5] = 0; 447 if (sysctl(mib, 3, val, &needed, 0, 0) < 0) 448 quit_args("trace facility failure, KERN_KDGETBUF: %s\n", strerror(errno)); 449} 450 451void set_init() 452{ 453 kd_regtype kr; 454 455 kr.type = KDBG_RANGETYPE; 456 kr.value1 = 0; 457 kr.value2 = -1; 458 needed = sizeof(kd_regtype); 459 mib[0] = CTL_KERN; 460 mib[1] = KERN_KDEBUG; 461 mib[2] = KERN_KDSETREG; 462 mib[3] = 0; 463 mib[4] = 0; 464 mib[5] = 0; 465 if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0) 466 quit_args("trace facility failure, KERN_KDSETREG (rangetype): %s\n", strerror(errno)); 467 468 mib[0] = CTL_KERN; 469 mib[1] = KERN_KDEBUG; 470 mib[2] = KERN_KDSETUP; 471 mib[3] = 0; 472 mib[4] = 0; 473 mib[5] = 0; 474 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0) 475 quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno)); 476} 477 478 479static void 480set_filter(void) 481{ 482 errno = 0; 483 int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDSET_TYPEFILTER }; 484 size_t needed = KDBG_TYPEFILTER_BITMAP_SIZE; 485 486 if(sysctl(mib, ARRAYSIZE(mib), type_filter_bitmap, &needed, NULL, 0)) { 487 quit_args("trace facility failure, KERN_KDSET_TYPEFILTER: %s\n", strerror(errno)); 488 } 489} 490 491void set_kval_list() 492{ 493 kd_regtype kr; 494 495 kr.type = KDBG_VALCHECK; 496 kr.value1 = value1; 497 kr.value2 = value2; 498 kr.value3 = value3; 499 kr.value4 = value4; 500 needed = sizeof(kd_regtype); 501 mib[0] = CTL_KERN; 502 mib[1] = KERN_KDEBUG; 503 mib[2] = KERN_KDSETREG; 504 mib[3] = 0; 505 mib[4] = 0; 506 mib[5] = 0; 507 if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0) 508 quit_args("trace facility failure, KERN_KDSETREG (valcheck): %s\n", strerror(errno)); 509} 510 511 512void readtrace(char *buffer) 513{ 514 mib[0] = CTL_KERN; 515 mib[1] = KERN_KDEBUG; 516 mib[2] = KERN_KDREADTR; 517 mib[3] = 0; 518 mib[4] = 0; 519 mib[5] = 0; 520 521 if (sysctl(mib, 3, buffer, &needed, NULL, 0) < 0) 522 quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno)); 523} 524 525 526int writetrace(int fd) 527{ 528 mib[0] = CTL_KERN; 529 mib[1] = KERN_KDEBUG; 530 mib[2] = KERN_KDWRITETR; 531 mib[3] = fd; 532 mib[4] = 0; 533 mib[5] = 0; 534 535 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0) 536 return 1; 537 538 return 0; 539} 540 541 542int write_command_map(int fd) 543{ 544 mib[0] = CTL_KERN; 545 mib[1] = KERN_KDEBUG; 546 mib[2] = KERN_KDWRITEMAP; 547 mib[3] = fd; 548 mib[4] = 0; 549 mib[5] = 0; 550 551 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0) 552 return 1; 553 554 return 0; 555} 556 557 558static 559lookup_t handle_lookup_event(uintptr_t thread, int debugid, kd_buf *kdp) 560{ 561 lookup_t lkp; 562 int hashid; 563 boolean_t first_record = FALSE; 564 565 hashid = thread & HASH_MASK; 566 567 if (debugid & DBG_FUNC_START) 568 first_record = TRUE; 569 570 for (lkp = lookup_hash[hashid]; lkp; lkp = lkp->lk_next) { 571 if (lkp->lk_thread == thread) 572 break; 573 } 574 if (lkp == NULL) { 575 if (first_record == FALSE) 576 return (0); 577 578 if ((lkp = lookup_freelist)) 579 lookup_freelist = lkp->lk_next; 580 else 581 lkp = (lookup_t)malloc(sizeof(struct lookup)); 582 583 lkp->lk_thread = thread; 584 585 lkp->lk_next = lookup_hash[hashid]; 586 lookup_hash[hashid] = lkp; 587 } 588 589 if (first_record == TRUE) { 590 lkp->lk_pathptr = lkp->lk_pathname; 591 lkp->lk_dvp = kdp->arg1; 592 } else { 593 if (lkp->lk_pathptr > &lkp->lk_pathname[NUMPARMS-4]) 594 return (lkp); 595 596 *lkp->lk_pathptr++ = kdp->arg1; 597 } 598 *lkp->lk_pathptr++ = kdp->arg2; 599 *lkp->lk_pathptr++ = kdp->arg3; 600 *lkp->lk_pathptr++ = kdp->arg4; 601 *lkp->lk_pathptr = 0; 602 603 return (lkp); 604} 605 606 607static 608void delete_lookup_event(uintptr_t thread, lookup_t lkp_to_delete) 609{ 610 lookup_t lkp; 611 lookup_t lkp_prev; 612 int hashid; 613 614 hashid = thread & HASH_MASK; 615 616 if ((lkp = lookup_hash[hashid])) { 617 if (lkp == lkp_to_delete) 618 lookup_hash[hashid] = lkp->lk_next; 619 else { 620 lkp_prev = lkp; 621 622 for (lkp = lkp->lk_next; lkp; lkp = lkp->lk_next) { 623 if (lkp == lkp_to_delete) { 624 lkp_prev->lk_next = lkp->lk_next; 625 break; 626 } 627 lkp_prev = lkp; 628 } 629 } 630 if (lkp) { 631 lkp->lk_next = lookup_freelist; 632 lookup_freelist = lkp; 633 } 634 } 635} 636 637 638static 639void insert_start_event(uintptr_t thread, int debugid, uint64_t now) 640{ 641 event_t evp; 642 int hashid; 643 644 hashid = thread & HASH_MASK; 645 646 for (evp = event_hash[hashid]; evp; evp = evp->ev_next) { 647 if (evp->ev_thread == thread && evp->ev_debugid == debugid) 648 break; 649 } 650 if (evp == NULL) { 651 if ((evp = event_freelist)) 652 event_freelist = evp->ev_next; 653 else 654 evp = (event_t)malloc(sizeof(struct event)); 655 656 evp->ev_thread = thread; 657 evp->ev_debugid = debugid; 658 659 evp->ev_next = event_hash[hashid]; 660 event_hash[hashid] = evp; 661 } 662 evp->ev_timestamp = now; 663} 664 665 666static 667uint64_t consume_start_event(uintptr_t thread, int debugid, uint64_t now) 668{ 669 event_t evp; 670 event_t evp_prev; 671 int hashid; 672 uint64_t elapsed = 0; 673 674 hashid = thread & HASH_MASK; 675 676 if ((evp = event_hash[hashid])) { 677 if (evp->ev_thread == thread && evp->ev_debugid == debugid) 678 event_hash[hashid] = evp->ev_next; 679 else { 680 evp_prev = evp; 681 682 for (evp = evp->ev_next; evp; evp = evp->ev_next) { 683 684 if (evp->ev_thread == thread && evp->ev_debugid == debugid) { 685 evp_prev->ev_next = evp->ev_next; 686 break; 687 } 688 evp_prev = evp; 689 } 690 } 691 if (evp) { 692 elapsed = now - evp->ev_timestamp; 693 694 evp->ev_next = event_freelist; 695 event_freelist = evp; 696 } 697 } 698 return (elapsed); 699} 700 701 702void 703log_trace() 704{ 705 char *buffer; 706 uint32_t buffer_size; 707 int fd; 708 int size; 709 int pad_size; 710 char pad_buf[4096]; 711 712 713 if ((fd = open(logfile, O_TRUNC|O_WRONLY|O_CREAT, 0777)) == -1) { 714 perror("Can't open logfile"); 715 exit(1); 716 } 717 get_bufinfo(&bufinfo); 718 719 if (bufinfo.nolog != 1) { 720 reenable = 1; 721 set_enable(0); /* disable logging*/ 722 } 723 get_bufinfo(&bufinfo); 724 725 if (verbose_flag) { 726 if (bufinfo.flags & KDBG_WRAPPED) 727 printf("Buffer has wrapped\n"); 728 else 729 printf("Buffer has not wrapped\n"); 730 } 731 buffer_size = 1000000 * sizeof(kd_buf); 732 buffer = malloc(buffer_size); 733 734 if (buffer == (char *) 0) 735 quit("can't allocate memory for tracing info\n"); 736 737 read_command_map(0, 0); 738 read_cpu_map(0); 739 740 raw_header.version_no = RAW_VERSION1; 741 raw_header.thread_count = total_threads; 742 raw_header.TOD_secs = time((long *)0); 743 raw_header.TOD_usecs = 0; 744 745 write(fd, &raw_header, sizeof(RAW_header)); 746 747 size = total_threads * sizeof(kd_threadmap); 748 write(fd, (char *)mapptr, size); 749 750 pad_size = 4096 - ((sizeof(RAW_header) + size) & 4095); 751 752 if (cpumap_header) { 753 size_t cpumap_size = sizeof(kd_cpumap_header) + cpumap_header->cpu_count * sizeof(kd_cpumap); 754 if (pad_size >= cpumap_size) { 755 write(fd, (char *)cpumap_header, cpumap_size); 756 pad_size -= cpumap_size; 757 } 758 } 759 760 memset(pad_buf, 0, pad_size); 761 write(fd, pad_buf, pad_size); 762 763 for (;;) { 764 needed = buffer_size; 765 766 readtrace(buffer); 767 768 if (needed == 0) 769 break; 770 write(fd, buffer, needed * sizeof(kd_buf)); 771 } 772 close(fd); 773} 774 775 776void 777Log_trace() 778{ 779 int size; 780 kd_buf kd_tmp; 781 size_t len; 782 int num_cpus; 783 int try_writetrace = 1; 784 int fd; 785 char *buffer; 786 kd_buf *kd; 787 uint64_t sample_window_abs; 788 uint64_t next_window_begins; 789 uint64_t current_abs; 790 uint64_t ending_abstime; 791 uint64_t last_time_written; 792 uint32_t us_to_sleep; 793 uint32_t us_to_adjust; 794 uint32_t ms_to_run; 795 796 memset(&kd_tmp, 0, sizeof(kd_tmp)); 797 798 if ((fd = open(logfile, O_TRUNC|O_WRONLY|O_CREAT, 0777)) == -1) { 799 perror("Can't open logfile"); 800 exit(1); 801 } 802 if (use_current_buf == 0) { 803 /* 804 * grab the number of cpus and scale the buffer size 805 */ 806 mib[0] = CTL_HW; 807 mib[1] = HW_NCPU; 808 mib[2] = 0; 809 len = sizeof(num_cpus); 810 811 sysctl(mib, 2, &num_cpus, &len, NULL, 0); 812 813 if (!bufset_flag) 814 nbufs = BASE_EVENTS * num_cpus; 815 816 set_remove(); 817 set_numbufs(nbufs); 818 set_init(); 819 820 if (filter_flag) 821 set_filter(); 822 823 if (kval_flag) 824 set_kval_list(); 825 } 826 /* Get kernel buffer information */ 827 get_bufinfo(&bufinfo); 828 829 buffer = malloc(bufinfo.nkdbufs * sizeof(kd_buf)); 830 if (buffer == (char *) 0) 831 quit("can't allocate memory for tracing info\n"); 832 memset(buffer, 0, bufinfo.nkdbufs * sizeof(kd_buf)); 833 834 if (use_current_buf == 0) 835 set_enable(1); 836 837 if (write_command_map(fd)) { 838 int pad_size; 839 char pad_buf[4096]; 840 841 read_command_map(0, 0); 842 read_cpu_map(0); 843 844 raw_header.version_no = RAW_VERSION1; 845 raw_header.thread_count = total_threads; 846 raw_header.TOD_secs = time((long *)0); 847 raw_header.TOD_usecs = 0; 848 849 write(fd, &raw_header, sizeof(RAW_header)); 850 851 size = total_threads * sizeof(kd_threadmap); 852 write(fd, (char *)mapptr, size); 853 854 pad_size = 4096 - ((sizeof(RAW_header) + size) & 4095); 855 856 if (cpumap_header) { 857 size_t cpumap_size = sizeof(kd_cpumap_header) + cpumap_header->cpu_count * sizeof(kd_cpumap); 858 if (pad_size >= cpumap_size) { 859 write(fd, (char *)cpumap_header, cpumap_size); 860 pad_size -= cpumap_size; 861 } 862 } 863 864 memset(pad_buf, 0, pad_size); 865 write(fd, pad_buf, pad_size); 866 } 867 sample_window_abs = (uint64_t)((double)US_TO_SLEEP * divisor); 868 869 next_window_begins = mach_absolute_time() + sample_window_abs; 870 871 if (secs_to_run) { 872 ending_abstime = mach_absolute_time() + (uint64_t)((double)secs_to_run * (double)1000000 * divisor); 873 ms_to_run = secs_to_run * 1000; 874 } else 875 ms_to_run = 0; 876 last_time_written = mach_absolute_time(); 877 878 while (LogRAW_flag) { 879 current_abs = mach_absolute_time(); 880 881 if (try_writetrace) { 882 needed = ms_to_run; 883 884 if (writetrace(fd)) 885 try_writetrace = 0; 886 else { 887 if (needed) { 888 current_abs = mach_absolute_time(); 889 890 printf("wrote %d events - elapsed time = %.1f secs\n", 891 (int)needed, ((double)(current_abs - last_time_written) / divisor) / 1000000); 892 893 last_time_written = current_abs; 894 } 895 } 896 } 897 if (try_writetrace == 0) { 898 899 if (next_window_begins > current_abs) 900 us_to_adjust = US_TO_SLEEP - (uint32_t)((double)(next_window_begins - current_abs) / divisor); 901 else 902 us_to_adjust = US_TO_SLEEP; 903 904 next_window_begins = current_abs + sample_window_abs; 905 906 us_to_sleep = US_TO_SLEEP - us_to_adjust; 907 908 next_window_begins = current_abs + (uint64_t)((double)(us_to_sleep + US_TO_SLEEP) * divisor); 909 910 if (us_to_sleep) 911 usleep(us_to_sleep); 912 913 get_bufinfo(&bufinfo); 914 915 if (bufinfo.flags & KDBG_WRAPPED) 916 printf("lost events\n"); 917 918 needed = bufinfo.nkdbufs * sizeof(kd_buf); 919 920 readtrace(buffer); 921 922 if (bufinfo.flags & KDBG_WRAPPED) { 923 924 kd = (kd_buf *) buffer; 925 926 kd_tmp.timestamp = kd[0].timestamp; 927 kd_tmp.debugid = TRACE_LOST_EVENTS; 928 929 write(fd, &kd_tmp, sizeof(kd_tmp)); 930 } 931 write(fd, buffer, needed * sizeof(kd_buf)); 932 933 if (verbose_flag && needed > nbufs) 934 printf("needed = %ld\n", needed); 935 } 936 if (secs_to_run) { 937 current_abs = mach_absolute_time(); 938 939 if (current_abs > ending_abstime) 940 break; 941 ms_to_run = (ending_abstime - current_abs) / (1000 * 1000); 942 943 if (ms_to_run == 0) 944 break; 945 } 946 } 947 set_enable(0); 948 set_numbufs(0); 949 set_remove(); 950 951 close(fd); 952} 953 954 955void read_trace() 956{ 957 char *buffer; 958 uint32_t buffer_size; 959 kd_buf *kd; 960 int fd; 961 int firsttime = 1; 962 int lines = 0; 963 int io_lines = 0; 964 uint64_t bias = 0; 965 uint32_t count_of_names; 966 double last_event_time = 0.0; 967 time_t trace_time; 968 969 if (!readRAW_flag) { 970 get_bufinfo(&bufinfo); 971 972 if (bufinfo.nolog != 1) { 973 reenable = 1; 974 set_enable(0); /* disable logging*/ 975 } 976 if (verbose_flag) { 977 if (bufinfo.flags & KDBG_WRAPPED) 978 printf("Buffer has wrapped\n"); 979 else 980 printf("Buffer has not wrapped\n"); 981 } 982 fd = 0; 983 count_of_names = 0; 984 985 } else { 986 fd = open(RAW_file, O_RDONLY); 987 988 if (fd < 0) { 989 perror("Can't open file"); 990 exit(1); 991 } 992 if (read(fd, &raw_header, sizeof(RAW_header)) != sizeof(RAW_header)) { 993 perror("read failed"); 994 exit(2); 995 } 996 if (raw_header.version_no != RAW_VERSION1) { 997 raw_header.version_no = RAW_VERSION0; 998 raw_header.TOD_secs = time((long *)0); 999 raw_header.TOD_usecs = 0; 1000 1001 lseek(fd, (off_t)0, SEEK_SET); 1002 1003 if (read(fd, &raw_header.thread_count, sizeof(int)) != sizeof(int)) { 1004 perror("read failed"); 1005 exit(2); 1006 } 1007 } 1008 count_of_names = raw_header.thread_count; 1009 trace_time = (time_t) (raw_header.TOD_secs); 1010 1011 printf("%s\n", ctime(&trace_time)); 1012 } 1013 buffer_size = 1000000 * sizeof(kd_buf); 1014 buffer = malloc(buffer_size); 1015 1016 if (buffer == (char *) 0) 1017 quit("can't allocate memory for tracing info\n"); 1018 1019 kd = (kd_buf *)buffer; 1020 1021 read_command_map(fd, count_of_names); 1022 read_cpu_map(fd); 1023 1024 for (;;) { 1025 uint32_t count; 1026 uint64_t now = 0; 1027 uint64_t prev; 1028 uint64_t prevdelta; 1029 uint32_t cpunum; 1030 uintptr_t thread; 1031 double x = 0.0; 1032 double y = 0.0; 1033 double event_elapsed_time; 1034 kd_buf *kdp; 1035 lookup_t lkp; 1036 boolean_t ending_event; 1037 int i; 1038 int debugid; 1039 int debugid_base; 1040 int dmsgindex; 1041 char dbgmessge[80]; 1042 char outbuf[32]; 1043 char *command; 1044 1045 if (!readRAW_flag) { 1046 needed = buffer_size; 1047 1048 mib[0] = CTL_KERN; 1049 mib[1] = KERN_KDEBUG; 1050 mib[2] = KERN_KDREADTR; 1051 mib[3] = 0; 1052 mib[4] = 0; 1053 mib[5] = 0; 1054 if (sysctl(mib, 3, buffer, &needed, NULL, 0) < 0) 1055 quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno)); 1056 1057 if (needed == 0) 1058 break; 1059 count = needed; 1060 1061 } else { 1062 uint32_t bytes_read; 1063 1064 bytes_read = read(fd, buffer, buffer_size); 1065 1066 if (bytes_read == -1) { 1067 perror("read failed"); 1068 exit(2); 1069 } 1070 count = bytes_read / sizeof(kd_buf); 1071 1072 if (count == 0) 1073 break; 1074 } 1075 for (kdp = &kd[0], i = 0; i < count; i++, kdp++) { 1076 1077 prev = now; 1078 debugid = kdp->debugid; 1079 debugid_base = debugid & DBG_FUNC_MASK; 1080 now = kdp->timestamp & KDBG_TIMESTAMP_MASK; 1081 1082 if (firsttime) 1083 bias = now; 1084 now -= bias; 1085 1086 cpunum = kdbg_get_cpu(kdp); 1087 thread = kdp->arg5; 1088 1089 if (lines == 64 || firsttime) 1090 { 1091 prevdelta = now - prevdelta; 1092 1093 if (firsttime) 1094 firsttime = 0; 1095 else { 1096 x = (double)prevdelta; 1097 x /= divisor; 1098 1099 fprintf(output_file, "\n\nNumber of microsecs since in last page %8.1f\n", x); 1100 } 1101 prevdelta = now; 1102 1103 /* 1104 * Output description row to output file (make sure to format correctly for 32-bit and 64-bit) 1105 */ 1106 fprintf(output_file, 1107#ifdef __LP64__ 1108 " AbsTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu# command\n\n" 1109#else 1110 " AbsTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu# command\n\n" 1111#endif 1112 ); 1113 1114 lines = 0; 1115 1116 if (io_lines > 15000) { 1117 fcntl(output_fd, F_FLUSH_DATA, 0); 1118 1119 io_lines = 0; 1120 } 1121 } 1122 lkp = 0; 1123 1124 if (debugid_base == VFS_LOOKUP) { 1125 lkp = handle_lookup_event(thread, debugid, kdp); 1126 1127 if ( !lkp || !(debugid & DBG_FUNC_END)) 1128 continue; 1129 } 1130 x = (double)now; 1131 x /= divisor; 1132 1133 if (last_event_time) 1134 y = x - last_event_time; 1135 else 1136 y = x; 1137 last_event_time = x; 1138 ending_event = FALSE; 1139 1140 /* 1141 * Is this event from an IOP? If so, there will be no 1142 * thread command, label it with the symbolic IOP name 1143 */ 1144 if (cpumap && (cpunum < cpumap_header->cpu_count) && (cpumap[cpunum].flags & KDBG_CPUMAP_IS_IOP)) { 1145 command = cpumap[cpunum].name; 1146 } else { 1147 find_thread_command(kdp, &command); 1148 } 1149 1150 /* 1151 * The internal use TRACE points clutter the output. 1152 * Print them only if in verbose mode. 1153 */ 1154 if (!verbose_flag) 1155 { 1156 /* Is this entry of Class DBG_TRACE */ 1157 if ((debugid >> 24) == DBG_TRACE) { 1158 if (((debugid >> 16) & 0xff) != DBG_TRACE_INFO) 1159 continue; 1160 } 1161 } 1162 if ( !lkp) { 1163 int t_debugid; 1164 int t_thread; 1165 1166 if ((debugid & DBG_FUNC_START) || debugid == MACH_MAKERUNNABLE) { 1167 1168 if (debugid_base != BSC_thread_terminate && debugid_base != BSC_exit) { 1169 1170 if (debugid == MACH_MAKERUNNABLE) 1171 t_thread = kdp->arg1; 1172 else 1173 t_thread = thread; 1174 1175 insert_start_event(t_thread, debugid_base, now); 1176 } 1177 1178 } else if ((debugid & DBG_FUNC_END) || debugid == MACH_STKHANDOFF || debugid == MACH_SCHEDULED) { 1179 1180 if (debugid == MACH_STKHANDOFF || debugid == MACH_SCHEDULED) { 1181 t_debugid = MACH_MAKERUNNABLE; 1182 t_thread = kdp->arg2; 1183 } else { 1184 t_debugid = debugid_base; 1185 t_thread = thread; 1186 } 1187 event_elapsed_time = (double)consume_start_event(t_thread, t_debugid, now); 1188 event_elapsed_time /= divisor; 1189 ending_event = TRUE; 1190 1191 if (event_elapsed_time == 0 && (debugid == MACH_STKHANDOFF || debugid == MACH_SCHEDULED)) 1192 ending_event = FALSE; 1193 } 1194 } 1195 if (ending_event) { 1196 char *ch; 1197 1198 sprintf(&outbuf[0], "(%-10.1f)", event_elapsed_time); 1199 /* 1200 * fix that right paren 1201 */ 1202 ch = &outbuf[11]; 1203 1204 if (*ch != ')') { 1205 ch = strchr (&outbuf[0], ')'); 1206 } 1207 if (ch) 1208 { 1209 *ch = ' '; 1210 --ch; 1211 1212 while (ch != &outbuf[0]) 1213 { 1214 if (*ch == ' ') 1215 --ch; 1216 else 1217 { 1218 *(++ch) = ')'; 1219 break; 1220 } 1221 } 1222 } 1223 } 1224 if (match_debugid(debugid_base, dbgmessge, &dmsgindex)) { 1225 if (ending_event) 1226 fprintf(output_file, "%13.1f %10.1f%s %-28x ", x, y, outbuf, debugid_base); 1227 else 1228 fprintf(output_file, "%13.1f %10.1f %-28x ", x, y, debugid_base); 1229 } else { 1230 if (ending_event) 1231 fprintf(output_file, "%13.1f %10.1f%s %-28.28s ", x, y, outbuf, dbgmessge); 1232 else 1233 fprintf(output_file, "%13.1f %10.1f %-28.28s ", x, y, dbgmessge); 1234 } 1235 if (lkp) { 1236 char *strptr; 1237 int len; 1238 1239 strptr = (char *)lkp->lk_pathname; 1240 1241 /* 1242 * print the tail end of the pathname 1243 */ 1244 len = strlen(strptr); 1245 if (len > 51) 1246 len -= 51; 1247 else 1248 len = 0; 1249#ifdef __LP64__ 1250 1251 fprintf(output_file, "%-16lx %-51s %-16lx %-2d %s\n", lkp->lk_dvp, &strptr[len], thread, cpunum, command); 1252#else 1253 fprintf(output_file, "%-8x %-51s %-8lx %-2d %s\n", (unsigned int)lkp->lk_dvp, &strptr[len], thread, cpunum, command); 1254#endif 1255 delete_lookup_event(thread, lkp); 1256 } else { 1257#ifdef __LP64__ 1258 fprintf(output_file, "%-16lx %-16lx %-16lx %-16lx %-16lx %-2d %s\n", kdp->arg1, kdp->arg2, kdp->arg3, kdp->arg4, thread, cpunum, command); 1259#else 1260 fprintf(output_file, "%-8lx %-8lx %-8lx %-8lx %-8lx %-2d %s\n", kdp->arg1, kdp->arg2, kdp->arg3, kdp->arg4, thread, cpunum, command); 1261#endif 1262 } 1263 lines++; 1264 io_lines++; 1265 } 1266 } 1267 if (reenable == 1) 1268 set_enable(1); /* re-enable kernel logging */ 1269} 1270 1271 1272 1273void signal_handler(int sig) 1274{ 1275 ptrace(PT_KILL, pid, (caddr_t)0, 0); 1276 /* 1277 * child is gone; no need to disable the pid 1278 */ 1279 exit(2); 1280} 1281 1282 1283void signal_handler_RAW(int sig) 1284{ 1285 LogRAW_flag = 0; 1286} 1287 1288 1289 1290int main(argc, argv, env) 1291int argc; 1292char **argv; 1293char **env; 1294{ 1295 extern char *optarg; 1296 extern int optind; 1297 int status; 1298 int ch; 1299 int i; 1300 char *output_filename = NULL; 1301 char *filter_filename = NULL; 1302 unsigned int parsed_arg; 1303 1304 for (i = 1; i < argc; i++) { 1305 if (strcmp("-X", argv[i]) == 0) { 1306 force_32bit_exec = 1; 1307 break; 1308 } 1309 } 1310 if (force_32bit_exec) { 1311 if (0 != reexec_to_match_lp64ness(FALSE)) { 1312 fprintf(stderr, "Could not re-execute: %d\n", errno); 1313 exit(1); 1314 } 1315 } else { 1316 if (0 != reexec_to_match_kernel()) { 1317 fprintf(stderr, "Could not re-execute: %d\n", errno); 1318 exit(1); 1319 } 1320 } 1321 if (setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_PASSIVE) < 0) { 1322 printf("setiopolicy failed\n"); 1323 exit(1); 1324 } 1325 output_file = stdout; 1326 output_fd = 1; 1327 1328 while ((ch = getopt(argc, argv, "hedEk:irb:gc:p:s:tR:L:l:S:F:a:x:Xnfvo:PT:N")) != EOF) 1329 { 1330 switch(ch) 1331 { 1332 case 'h': /* help */ 1333 usage_flag=1; 1334 break; 1335 case 'S': 1336 secs_to_run = argtoi('S', "decimal number", optarg, 10); 1337 break; 1338 case 'a': /* set tracing on a pid */ 1339 pid_flag=1; 1340 pid = argtoi('a', "decimal number", optarg, 10); 1341 break; 1342 case 'x': /* exclude a pid from tracing */ 1343 pid_exflag=1; 1344 pid = argtoi('x', "decimal number", optarg, 10); 1345 break; 1346 case 'v': 1347 verbose_flag=1; 1348 break; 1349 case 'l': 1350 logRAW_flag = 1; 1351 logfile = optarg; 1352 break; 1353 case 'L': 1354 LogRAW_flag = 1; 1355 logfile = optarg; 1356 signal(SIGINT, signal_handler_RAW); 1357 break; 1358 case 'e': 1359 enable_flag = 1; 1360 break; 1361 case 'i': 1362 init_flag = 1; 1363 break; 1364 case 'E': 1365 execute_flag = 1; 1366 break; 1367 case 'd': 1368 disable_flag = 1; 1369 break; 1370 case 'k': 1371 if (kval_flag == 0) 1372 value1 = (unsigned int) argtoul('k', "hex number", optarg, 16); 1373 else if (kval_flag == 1) 1374 value2 = (unsigned int) argtoul('k', "hex number", optarg, 16); 1375 else if (kval_flag == 2) 1376 value3 = (unsigned int) argtoul('k', "hex number", optarg, 16); 1377 else if (kval_flag == 3) 1378 value4 = (unsigned int) argtoul('k', "hex number", optarg, 16); 1379 else 1380 { 1381 fprintf(stderr, "A maximum of four values can be specified with -k\n"); 1382 usage(SHORT_HELP); 1383 } 1384 kval_flag++; 1385 break; 1386 case 'r': 1387 remove_flag = 1; 1388 break; 1389 case 'g': 1390 bufget_flag = 1; 1391 break; 1392 case 't': 1393 trace_flag = 1; 1394 break; 1395 case 'R': 1396 readRAW_flag = 1; 1397 RAW_file = optarg; 1398 break; 1399 case 'n': 1400 nowrap_flag = 1; 1401 break; 1402 case 'f': 1403 freerun_flag = 1; 1404 break; 1405 case 'b': 1406 bufset_flag = 1; 1407 nbufs = argtoi('b', "decimal number", optarg, 10); 1408 break; 1409 case 'c': 1410 filter_flag = 1; 1411 parsed_arg = argtoi('c', "decimal, hex, or octal number", optarg, 0); 1412 if (parsed_arg > 0xFF) 1413 quit_args("argument '-c %s' parsed as %u, " 1414 "class value must be 0-255\n", optarg, parsed_arg); 1415 saw_filter_class(parsed_arg); 1416 break; 1417 case 's': 1418 filter_flag = 1; 1419 parsed_arg = argtoi('s', "decimal, hex, or octal number", optarg, 0); 1420 if (parsed_arg > 0xFF) 1421 quit_args("argument '-s %s' parsed as %u, " 1422 "subclass value must be 0-255\n", optarg, parsed_arg); 1423 saw_filter_subclass(parsed_arg); 1424 break; 1425 case 'p': 1426 filter_flag = 1; 1427 parsed_arg = argtoi('p', "decimal, hex, or octal number", optarg, 0); 1428 if (parsed_arg > 0xFF) 1429 quit_args("argument '-p %s' parsed as %u, " 1430 "end range value must be 0-255\n", optarg, parsed_arg); 1431 saw_filter_end_range(parsed_arg); 1432 break; 1433 case 'P': 1434 ppt_flag = 1; 1435 break; 1436 case 'o': 1437 output_filename = optarg; 1438 break; 1439 case 'F': 1440 frequency = argtoi('F', "decimal number", optarg, 10); 1441 break; 1442 case 'X': 1443 break; 1444 case 'N': 1445 no_default_codes_flag = 1; 1446 break; 1447 case 'T': 1448 filter_flag = 1; 1449 1450 // Flush out any unclosed -c argument 1451 filter_done_parsing(); 1452 1453 parse_filter_file(optarg); 1454 break; 1455 default: 1456 usage(SHORT_HELP); 1457 } 1458 } 1459 argc -= optind; 1460 1461 if (!no_default_codes_flag) 1462 { 1463 if (verbose_flag) 1464 printf("Adding default code file /usr/share/misc/trace.codes. Use '-N' to skip this.\n"); 1465 parse_codefile("/usr/share/misc/trace.codes"); 1466 } 1467 1468 if (argc) 1469 { 1470 if (!execute_flag) 1471 { 1472 while (argc--) 1473 { 1474 const char *cfile = argv[optind++]; 1475 if (verbose_flag) printf("Adding code file %s \n", cfile); 1476 parse_codefile(cfile); 1477 } 1478 } 1479 } 1480 else 1481 { 1482 if (execute_flag) 1483 quit_args("-E flag needs an executable to launch\n"); 1484 } 1485 1486 if (usage_flag) 1487 usage(LONG_HELP); 1488 1489 getdivisor(); 1490 1491 if (pid_flag && pid_exflag) 1492 quit_args("Can't use both -a and -x flag together\n"); 1493 1494 if (kval_flag && filter_flag) 1495 quit_args("Cannot use -k flag with -c, -s, or -p\n"); 1496 1497 if (output_filename && !trace_flag && !readRAW_flag) 1498 quit_args("When using 'o' option, must use the 't' or 'R' option too\n"); 1499 1500 filter_done_parsing(); 1501 1502 done_with_args = 1; 1503 1504 if (LogRAW_flag) { 1505 get_bufinfo(&bufinfo); 1506 1507 if (bufinfo.nolog == 0) 1508 use_current_buf = 1; 1509 } 1510 1511 if (disable_flag) 1512 { 1513 if (pid_flag) 1514 { 1515 set_pidcheck(pid, 0); /* disable pid check for given pid */ 1516 exit(1); 1517 } 1518 else if (pid_exflag) 1519 { 1520 set_pidexclude(pid, 0); /* disable pid exclusion for given pid */ 1521 exit(1); 1522 } 1523 set_enable(0); 1524 exit(1); 1525 } 1526 1527 if (remove_flag) 1528 { 1529 set_remove(); 1530 exit(1); 1531 } 1532 1533 if (bufset_flag ) 1534 { 1535 if (!init_flag && !LogRAW_flag) 1536 { 1537 fprintf(stderr,"The -b flag must be used with the -i flag\n"); 1538 exit(1); 1539 } 1540 set_numbufs(nbufs); 1541 } 1542 1543 if (nowrap_flag) 1544 set_nowrap(); 1545 1546 if (freerun_flag) 1547 set_freerun(); 1548 1549 if (bufget_flag) 1550 { 1551 get_bufinfo(&bufinfo); 1552 1553 printf("The kernel buffer settings are:\n"); 1554 1555 if (bufinfo.flags & KDBG_BUFINIT) 1556 printf("\tKernel buffer is initialized\n"); 1557 else 1558 printf("\tKernel buffer is not initialized\n"); 1559 1560 printf("\t number of buf entries = %d\n", bufinfo.nkdbufs); 1561 1562 if (verbose_flag) 1563 { 1564 if (bufinfo.flags & KDBG_MAPINIT) 1565 printf("\tKernel thread map is initialized\n"); 1566 else 1567 printf("\tKernel thread map is not initialized\n"); 1568 printf("\t number of thread entries = %d\n", bufinfo.nkdthreads); 1569 } 1570 1571 if (bufinfo.nolog) 1572 printf("\tBuffer logging is disabled\n"); 1573 else 1574 printf("\tBuffer logging is enabled\n"); 1575 1576 if (verbose_flag) 1577 printf("\tkernel flags = 0x%x\n", bufinfo.flags); 1578 1579 if (bufinfo.flags & KDBG_NOWRAP) 1580 printf("\tKernel buffer wrap is disabled\n"); 1581 else 1582 printf("\tKernel buffer wrap is enabled\n"); 1583 1584 if (bufinfo.flags & KDBG_RANGECHECK) 1585 printf("\tCollection within a range is enabled\n"); 1586 else 1587 printf("\tCollection within a range is disabled\n"); 1588 1589 if (bufinfo.flags & KDBG_VALCHECK) 1590 printf("\tCollecting specific code values is enabled\n"); 1591 else 1592 printf("\tCollecting specific code values is disabled\n"); 1593 1594 if (bufinfo.flags & KDBG_TYPEFILTER_CHECK) 1595 printf("\tCollection based on a filter is enabled\n"); 1596 else 1597 printf("\tCollection based on a filter is disabled\n"); 1598 1599 if (bufinfo.flags & KDBG_PIDCHECK) 1600 printf("\tCollection based on pid is enabled\n"); 1601 else 1602 printf("\tCollection based on pid is disabled\n"); 1603 1604 if (bufinfo.flags & KDBG_PIDEXCLUDE) 1605 printf("\tCollection based on pid exclusion is enabled\n"); 1606 else 1607 printf("\tCollection based on pid exclusion is disabled\n"); 1608 1609 if (bufinfo.bufid == -1) 1610 printf("\tKernel buffer is not controlled by any process.\n"); 1611 else 1612 printf("\tKernel buffer is controlled by proc id [%d]\n", bufinfo.bufid); 1613 } 1614 1615 if (init_flag) 1616 set_init(); 1617 1618 if (filter_flag) 1619 set_filter(); 1620 1621 if (kval_flag) 1622 set_kval_list(); 1623 1624 if (execute_flag) 1625 { 1626 fprintf(stderr, "Starting program: %s\n", argv[optind]); 1627 fflush(stdout); 1628 fflush(stderr); 1629 1630 switch ((pid = vfork())) 1631 { 1632 case -1: 1633 perror("vfork: "); 1634 exit(1); 1635 case 0: /* child */ 1636 setsid(); 1637 ptrace(PT_TRACE_ME, 0, (caddr_t)0, 0); 1638 execve(argv[optind], &argv[optind], environ); 1639 perror("execve:"); 1640 exit(1); 1641 } 1642 sleep(1); 1643 1644 signal(SIGINT, signal_handler); 1645 set_pidcheck(pid, 1); 1646 set_enable(1); 1647 ptrace(PT_CONTINUE, pid, (caddr_t)1, 0); 1648 waitpid(pid, &status, 0); 1649 /* child is gone; no need to disable the pid */ 1650 exit(0); 1651 } 1652 else if (enable_flag) 1653 { 1654 if (pid_flag) 1655 set_pidcheck(pid, 1); 1656 else if (pid_exflag) 1657 set_pidexclude(pid, 1); 1658 set_enable(1); 1659 } 1660 1661 if (output_filename) 1662 { 1663 if (((output_fd = open(output_filename, O_CREAT | O_TRUNC | O_WRONLY | O_APPEND, 0644)) < 0 ) || 1664 !(output_file = fdopen(output_fd, "w"))) 1665 { 1666 fprintf(stderr, "Cannot open file \"%s\" for writing.\n", output_filename); 1667 usage(SHORT_HELP); 1668 } 1669 setbuffer(output_file, &sbuffer[0], SBUFFER_SIZE); 1670 1671 if (fcntl(output_fd, F_NOCACHE, 1) < 0) 1672 { 1673 /* Not fatal */ 1674 fprintf(stderr, "Warning: setting F_NOCACHE on %s, failed\n", output_filename); 1675 } 1676 } 1677 if (!LogRAW_flag && !logRAW_flag) 1678 setbuffer(output_file, &sbuffer[0], SBUFFER_SIZE); 1679 1680 if (trace_flag || readRAW_flag) 1681 read_trace(); 1682 else if (LogRAW_flag) 1683 Log_trace(); 1684 else if (logRAW_flag) 1685 log_trace(); 1686 1687 exit(0); 1688 1689} /* end main */ 1690 1691static void 1692quit_args(const char *fmt, ...) 1693{ 1694 char buffer[1024]; 1695 1696 if (reenable == 1) 1697 { 1698 reenable = 0; 1699 set_enable(1); /* re-enable kernel logging */ 1700 } 1701 1702 va_list args; 1703 1704 va_start (args, fmt); 1705 vsnprintf(buffer, sizeof(buffer), fmt, args); 1706 1707 fprintf(stderr, "trace error: %s", buffer); 1708 1709 va_end(args); 1710 1711 if (!done_with_args) 1712 usage(SHORT_HELP); 1713 1714 exit(1); 1715} 1716 1717 1718void 1719quit(char *s) 1720{ 1721 if (reenable == 1) 1722 { 1723 reenable = 0; 1724 set_enable(1); /* re-enable kernel logging */ 1725 } 1726 1727 printf("trace: "); 1728 if (s) 1729 printf("%s ", s); 1730 exit(1); 1731} 1732 1733static void 1734usage(int short_help) 1735{ 1736 1737 if (short_help) 1738 { 1739 (void)fprintf(stderr, " usage: trace -h [-v]\n"); 1740 (void)fprintf(stderr, " usage: trace -i [-b numbufs]\n"); 1741 (void)fprintf(stderr, " usage: trace -g\n"); 1742 (void)fprintf(stderr, " usage: trace -d [-a pid | -x pid ]\n"); 1743 (void)fprintf(stderr, " usage: trace -r\n"); 1744 (void)fprintf(stderr, " usage: trace -n\n"); 1745 1746 (void)fprintf(stderr, 1747 " usage: trace -e [ -c class [[-s subclass]... | -p class ]]... | \n"); 1748 (void)fprintf(stderr, 1749 " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter] \n"); 1750 (void)fprintf(stderr, 1751 " [-a pid | -x pid] \n\n"); 1752 1753 (void)fprintf(stderr, 1754 " usage: trace -E [ -c class [[-s subclass]... | -p class ]]... | \n"); 1755 (void)fprintf(stderr, 1756 " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter] \n"); 1757 (void)fprintf(stderr, 1758 " executable_path [optional args to executable] \n\n"); 1759 1760 (void)fprintf(stderr, 1761 " usage: trace -L RawFilename [-S SecsToRun]\n"); 1762 (void)fprintf(stderr, 1763 " usage: trace -l RawFilename\n"); 1764 (void)fprintf(stderr, 1765 " usage: trace -R RawFilename [-X] [-F frequency] [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...]\n"); 1766 (void)fprintf(stderr, 1767 " usage: trace -t [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...]\n"); 1768 (void)fprintf(stderr, 1769 " Trace will import /usr/share/misc/trace.codes as a default codefile unless -N is specified. Extra codefiles specified are used in addition to the default codefile.\n"); 1770 exit(1); 1771 } 1772 1773 1774 /* Only get here if printing long usage info */ 1775 (void)fprintf(stderr, "usage: trace -h [-v]\n"); 1776 (void)fprintf(stderr, "\tPrint this long command help.\n\n"); 1777 (void)fprintf(stderr, "\t -v Print extra information about tracefilter and code files.\n\n"); 1778 1779 (void)fprintf(stderr, "usage: trace -i [-b numbufs]\n"); 1780 (void)fprintf(stderr, "\tInitialize the kernel trace buffer.\n\n"); 1781 (void)fprintf(stderr, "\t-b numbufs The number of trace elements the kernel buffer\n"); 1782 (void)fprintf(stderr, "\t can hold is set to numbufs. Use with the -i flag.\n"); 1783 (void)fprintf(stderr, "\t Enter a decimal value.\n\n"); 1784 1785 (void)fprintf(stderr, "usage: trace -g\n"); 1786 (void)fprintf(stderr, "\tGet the kernel buffer settings.\n\n"); 1787 1788 (void)fprintf(stderr, "usage: trace -d [-a pid | -x pid]\n"); 1789 (void)fprintf(stderr, "\tDisable/stop collection of kernel trace elements.\n\n"); 1790 (void)fprintf(stderr, "\t -a pid Disable/stop collection for this process only.\n\n"); 1791 (void)fprintf(stderr, "\t -x pid Disable/stop exclusion of this process only.\n\n"); 1792 1793 (void)fprintf(stderr, "usage: trace -r\n"); 1794 (void)fprintf(stderr, "\tRemove the kernel trace buffer. Set controls to default.\n\n"); 1795 1796 (void)fprintf(stderr, "usage: trace -n\n"); 1797 (void)fprintf(stderr, "\tDisables kernel buffer wrap around.\n\n"); 1798 1799 (void)fprintf(stderr, 1800 "usage: trace -e [ -c class [[-s subclass]... | -p class ]]... |\n"); 1801 (void)fprintf(stderr, 1802 " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter]\n"); 1803 (void) fprintf(stderr, 1804 " [-a pid | -x pid]\n\n"); 1805 (void)fprintf(stderr, "\t Enable/start collection of kernel trace elements. \n\n"); 1806 (void)fprintf(stderr, "\t By default, trace collects all tracepoints. \n"); 1807 (void)fprintf(stderr, "\t The following arguments may be used to restrict collection \n"); 1808 (void)fprintf(stderr, "\t to a limited set of tracepoints. \n\n"); 1809 (void)fprintf(stderr, "\t Multiple classes can be specified by repeating -c. \n"); 1810 (void)fprintf(stderr, "\t Multiple subclasses can be specified by repeating -s after -c. \n"); 1811 (void)fprintf(stderr, "\t Classes, subclasses, and class ranges can be entered \n"); 1812 (void)fprintf(stderr, "\t in hex (0xXX), decimal (XX), or octal (0XX). \n\n"); 1813 (void)fprintf(stderr, "\t -c class Restrict trace collection to given class. \n\n"); 1814 (void)fprintf(stderr, "\t -p class Restrict trace collection to given class range. \n"); 1815 (void)fprintf(stderr, "\t Must provide class with -c first. \n\n"); 1816 (void)fprintf(stderr, "\t -s subclass Restrict trace collection to given subclass. \n"); 1817 (void)fprintf(stderr, "\t Must provide class with -c first. \n\n"); 1818 (void)fprintf(stderr, "\t -a pid Restrict trace collection to the given process.\n\n"); 1819 (void)fprintf(stderr, "\t -x pid Exclude the given process from trace collection.\n\n"); 1820 (void)fprintf(stderr, "\t -k code Restrict trace collection up to four specific codes.\n"); 1821 (void)fprintf(stderr, "\t Enter codes in hex (0xXXXXXXXX). \n\n"); 1822 (void)fprintf(stderr, "\t -P Enable restricted PPT trace points only.\n\n"); 1823 (void)fprintf(stderr, "\t -T tracefilter Read class and subclass restrictions from a \n"); 1824 (void)fprintf(stderr, "\t tracefilter description file. \n"); 1825 (void)fprintf(stderr, "\t Run trace -h -v for more info on this file. \n\n"); 1826 1827 (void)fprintf(stderr, 1828 "usage: trace -E [ -c class [[-s subclass]... | -p class ]]... |\n"); 1829 (void)fprintf(stderr, 1830 " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter]\n"); 1831 (void)fprintf(stderr, 1832 " executable_path [optional args to executable] \n\n"); 1833 (void)fprintf(stderr, "\tLaunch the given executable and enable/start\n"); 1834 (void)fprintf(stderr, "\tcollection of kernel trace elements for that process.\n"); 1835 (void)fprintf(stderr, "\tSee -e(enable) flag for option descriptions.\n\n"); 1836 1837 (void)fprintf(stderr, "usage: trace -t [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...] \n"); 1838 (void)fprintf(stderr, "\tCollect the kernel buffer trace data and print it.\n\n"); 1839 (void)fprintf(stderr, "\t -N Do not import /usr/share/misc/trace.codes (for raw hex tracing or supplying an alternate set of codefiles)\n"); 1840 (void)fprintf(stderr, "\t -o OutputFilename Print trace output to OutputFilename. Default is stdout.\n\n"); 1841 1842 (void)fprintf(stderr, 1843 "usage: trace -R RawFilename [-X] [-F frequency] [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...] \n"); 1844 (void)fprintf(stderr, "\tRead raw trace file and print it.\n\n"); 1845 (void)fprintf(stderr, "\t -X Force trace to interpret trace data as 32 bit. \n"); 1846 (void)fprintf(stderr, "\t Default is to match the bit width of the current system. \n"); 1847 (void)fprintf(stderr, "\t -N Do not import /usr/share/misc/trace.codes (for raw hex tracing or supplying an alternate set of codefiles)\n"); 1848 (void)fprintf(stderr, "\t -F frequency Specify the frequency of the clock used to timestamp entries in RawFilename.\n\t Use command \"sysctl hw.tbfrequency\" on the target device, to get target frequency.\n"); 1849 (void)fprintf(stderr, "\t -o OutputFilename Print trace output to OutputFilename. Default is stdout.\n\n"); 1850 1851 (void)fprintf(stderr, 1852 "usage: trace -L RawFilename [-S SecsToRun]\n"); 1853 (void)fprintf(stderr, "\tContinuously collect the kernel buffer trace data in the raw format \n"); 1854 (void)fprintf(stderr, "\tand write it to RawFilename. \n"); 1855 1856 (void)fprintf(stderr, "\t-L implies -r -i if tracing isn't currently enabled.\n"); 1857 (void)fprintf(stderr, "\tOptions passed to -e(enable) are also accepted by -L. (except -a -x -P)\n\n"); 1858 (void)fprintf(stderr, "\t -S SecsToRun Specify the number of seconds to collect trace data.\n\n"); 1859 1860 (void)fprintf(stderr, 1861 "usage: trace -l RawFilename\n"); 1862 (void)fprintf(stderr, "\tCollect the existing kernel buffer trace data in the raw format.\n\n"); 1863 1864 if (verbose_flag) { 1865 (void)fprintf(stderr, 1866 "Code file: \n" 1867 "\t A code file consists of a list of tracepoints, one per line, \n" 1868 "\t with one tracepoint code in hex, followed by a tab, \n" 1869 "\t followed by the tracepoint's name. \n\n" 1870 1871 "\t Example tracepoint: \n" 1872 "\t 0x010c007c\tMSC_mach_msg_trap \n" 1873 "\t This describes the tracepoint with the following info: \n" 1874 "\t Name: MSC_mach_msg_trap \n" 1875 "\t Class: 0x01 (Mach events) \n" 1876 "\t Subclass: 0x0c (Mach system calls) \n" 1877 "\t Code: 0x007c (Mach syscall number 31) \n\n" 1878 1879 "\t See /usr/include/sys/kdebug.h for the currently defined \n" 1880 "\t class and subclass values. \n" 1881 "\t See /usr/share/misc/trace.codes for the currently allocated \n" 1882 "\t system tracepoints in trace code file format. \n" 1883 "\t This codefile is useful with the -R argument to trace. \n" 1884 "\n"); 1885 1886 (void)fprintf(stderr, 1887 "Tracefilter description file: \n" 1888 "\t A tracefilter description file consists of a list of \n" 1889 "\t class and subclass filters in hex, one per line, \n" 1890 "\t which are applied as if they were passed with -c and -s. \n" 1891 "\t Pass -v to see what classes and subclasses are being set. \n\n" 1892 1893 "\t File syntax: \n" 1894 "\t Class filter: \n" 1895 "\t C 0xXX \n" 1896 "\t Subclass filter (includes class): \n" 1897 "\t S 0xXXXX \n" 1898 "\t Comment: \n" 1899 "\t # This is a comment \n\n" 1900 1901 "\t For example, to trace Mach events (class 1):\n" 1902 "\t C 0x01 \n" 1903 "\t or to trace Mach system calls (class 1 subclass 13): \n" 1904 "\t S 0x010C \n" 1905 "\n"); 1906 } 1907 1908 exit(1); 1909} 1910 1911 1912static int 1913argtoi(flag, req, str, base) 1914int flag; 1915char *req, *str; 1916int base; 1917{ 1918 char *cp; 1919 int ret; 1920 1921 ret = (int)strtol(str, &cp, base); 1922 if (cp == str || *cp) 1923 errx(EINVAL, "-%c flag requires a %s", flag, req); 1924 return (ret); 1925} 1926 1927 1928static unsigned long 1929argtoul(flag, req, str, base) 1930int flag; 1931char *req, *str; 1932int base; 1933{ 1934 char *cp; 1935 unsigned long ret; 1936 1937 ret = (int)strtoul(str, &cp, base); 1938 if (cp == str || *cp) 1939 errx(EINVAL, "-%c flag requires a %s", flag, req); 1940 return (ret); 1941} 1942 1943 1944/* 1945 * comparison function for qsort 1946 * sort by debugid 1947 */ 1948int debugid_compar(p1, p2) 1949 code_type_t *p1; 1950 code_type_t *p2; 1951{ 1952 if (p1->debugid > p2->debugid) 1953 return(1); 1954 else if (p1->debugid == p2->debugid) 1955 return(0); 1956 else 1957 return(-1); 1958} 1959 1960 1961/* 1962 * Filter args parsing state machine: 1963 * 1964 * Allowed args: 1965 * -c -p 1966 * -c -s (-s)* 1967 * -c (-c)* 1968 * every -c goes back to start 1969 * 1970 * Valid transitions: 1971 * start -> class (first -c) 1972 * class -> range (-c -p) 1973 * class -> sub (-c -s) 1974 * class -> class (-c -c) 1975 * range -> class (-c -p -c) 1976 * sub -> class (-c -s -c) 1977 * * -> start (on filter_done_parsing) 1978 * 1979 * Need to call filter_done_parsing after 1980 * calling saw_filter_* 1981 * to flush out any class flag waiting to see if 1982 * there is a -s flag coming up 1983 */ 1984 1985 1986// What type of flag did I last see? 1987enum { 1988 FILTER_MODE_START, 1989 FILTER_MODE_CLASS, 1990 FILTER_MODE_CLASS_RANGE, 1991 FILTER_MODE_SUBCLASS 1992} filter_mode = FILTER_MODE_START; 1993 1994uint8_t filter_current_class = 0; 1995uint8_t filter_current_subclass = 0; 1996uint8_t filter_current_class_range = 0; 1997 1998static void 1999saw_filter_class(uint8_t class) 2000{ 2001 switch(filter_mode) { 2002 case FILTER_MODE_START: 2003 case FILTER_MODE_CLASS_RANGE: 2004 case FILTER_MODE_SUBCLASS: 2005 filter_mode = FILTER_MODE_CLASS; 2006 filter_current_class = class; 2007 filter_current_subclass = 0; 2008 filter_current_class_range = 0; 2009 // the case of a lone -c is taken care of 2010 // by filter_done_parsing 2011 break; 2012 case FILTER_MODE_CLASS: 2013 filter_mode = FILTER_MODE_CLASS; 2014 // set old class, remember new one 2015 set_filter_class(filter_current_class); 2016 filter_current_class = class; 2017 filter_current_subclass = 0; 2018 filter_current_class_range = 0; 2019 break; 2020 default: 2021 quit_args("invalid case in saw_filter_class\n"); 2022 } 2023} 2024 2025static void 2026saw_filter_end_range(uint8_t end_class) 2027{ 2028 switch(filter_mode) { 2029 case FILTER_MODE_CLASS: 2030 filter_mode = FILTER_MODE_CLASS_RANGE; 2031 filter_current_class_range = end_class; 2032 set_filter_range(filter_current_class, filter_current_class_range); 2033 break; 2034 case FILTER_MODE_START: 2035 quit_args("must provide '-c class' before '-p 0x%x'\n", 2036 end_class); 2037 case FILTER_MODE_CLASS_RANGE: 2038 quit_args("extra range end '-p 0x%x'" 2039 " for class '-c 0x%x'\n", 2040 end_class, filter_current_class); 2041 case FILTER_MODE_SUBCLASS: 2042 quit_args("cannot provide both range end '-p 0x%x'" 2043 " and subclass '-s 0x%x'" 2044 " for class '-c 0x%x'\n", 2045 end_class, filter_current_subclass, 2046 filter_current_class); 2047 default: 2048 quit_args("invalid case in saw_filter_end_range\n"); 2049 } 2050} 2051 2052static void 2053saw_filter_subclass(uint8_t subclass) 2054{ 2055 switch(filter_mode) { 2056 case FILTER_MODE_CLASS: 2057 case FILTER_MODE_SUBCLASS: 2058 filter_mode = FILTER_MODE_SUBCLASS; 2059 filter_current_subclass = subclass; 2060 set_filter_subclass(filter_current_class, filter_current_subclass); 2061 break; 2062 case FILTER_MODE_START: 2063 quit_args("must provide '-c class'" 2064 " before subclass '-s 0x%x'\n", subclass); 2065 case FILTER_MODE_CLASS_RANGE: 2066 quit_args("cannot provide both range end '-p 0x%x'" 2067 " and subclass '-s 0x%x'" 2068 " for the same class '-c 0x%x'\n", 2069 filter_current_class_range, 2070 subclass, filter_current_class); 2071 default: 2072 quit_args("invalid case in saw_filter_subclass\n"); 2073 } 2074} 2075 2076static void 2077filter_done_parsing(void) 2078{ 2079 switch(filter_mode) { 2080 case FILTER_MODE_CLASS: 2081 // flush out the current class 2082 set_filter_class(filter_current_class); 2083 filter_mode = FILTER_MODE_START; 2084 filter_current_class = 0; 2085 filter_current_subclass = 0; 2086 filter_current_class_range = 0; 2087 break; 2088 case FILTER_MODE_SUBCLASS: 2089 case FILTER_MODE_START: 2090 case FILTER_MODE_CLASS_RANGE: 2091 filter_mode = FILTER_MODE_START; 2092 filter_current_class = 0; 2093 filter_current_subclass = 0; 2094 filter_current_class_range = 0; 2095 break; 2096 default: 2097 quit_args("invalid case in filter_done_parsing\n"); 2098 } 2099} 2100 2101/* Tell set_filter_subclass not to print every. single. subclass. */ 2102static boolean_t setting_class = FALSE; 2103static boolean_t setting_range = FALSE; 2104 2105static void 2106set_filter_subclass(uint8_t class, uint8_t subclass) 2107{ 2108 if (!filter_alloced) { 2109 type_filter_bitmap = (uint8_t *) calloc(1, KDBG_TYPEFILTER_BITMAP_SIZE); 2110 if (type_filter_bitmap == NULL) 2111 quit_args("Could not allocate type_filter_bitmap.\n"); 2112 filter_alloced = 1; 2113 } 2114 2115 uint16_t csc = ENCODE_CSC_LOW(class, subclass); 2116 2117 if (verbose_flag && !setting_class) 2118 printf("tracing subclass: 0x%4.4x\n", csc); 2119 2120 if (verbose_flag && isset(type_filter_bitmap, csc)) 2121 printf("class %u (0x%2.2x), subclass %u (0x%2.2x) set twice.\n", 2122 class, class, subclass, subclass); 2123 2124 setbit(type_filter_bitmap, csc); 2125} 2126 2127static void 2128set_filter_class(uint8_t class) 2129{ 2130 if (verbose_flag && !setting_range) 2131 printf("tracing class: 0x%2.2x\n", class); 2132 2133 setting_class = TRUE; 2134 2135 for (int i = 0; i < 256; i++) 2136 set_filter_subclass(class, i); 2137 2138 setting_class = FALSE; 2139} 2140 2141static void 2142set_filter_range(uint8_t class, uint8_t end) 2143{ 2144 if (verbose_flag) 2145 printf("tracing range: 0x%2.2x - 0x%2.2x\n", class, end); 2146 2147 setting_range = TRUE; 2148 2149 for (int i = class; i <= end; i++) 2150 set_filter_class(i); 2151 2152 setting_range = FALSE; 2153} 2154 2155/* 2156 * Syntax of filter file: 2157 * Hexadecimal numbers only 2158 * Class: 2159 * C 0xXX 2160 * Subclass (includes class): 2161 * S 0xXXXX 2162 * Comment: 2163 * # <string> 2164 * TBD: Class ranges? 2165 * TBD: K for -k flag? 2166 */ 2167 2168static void 2169parse_filter_file(char *filename) { 2170 FILE* file; 2171 uint32_t current_line = 0; 2172 uint32_t parsed_arg = 0; 2173 int rval; 2174 2175 char line[256]; 2176 2177 if ( (file = fopen(filename, "r")) == NULL ) { 2178 quit_args("Failed to open filter description file %s: %s\n", 2179 filename, strerror(errno)); 2180 } 2181 2182 if (verbose_flag) 2183 printf("Parsing typefilter file: %s\n", filename); 2184 2185 while( fgets(line, sizeof(line), file) != NULL ) { 2186 current_line++; 2187 2188 switch (line[0]) { 2189 case 'C': 2190 rval = sscanf(line, "C 0x%x\n", &parsed_arg); 2191 if (rval != 1) 2192 quit_args("invalid line %d of file %s: %s\n", 2193 current_line, filename, line); 2194 if (parsed_arg > 0xFF) 2195 quit_args("line %d of file %s: %s\n" 2196 "parsed as 0x%x, " 2197 "class value must be 0x0-0xFF\n", 2198 current_line, filename, line, parsed_arg); 2199 set_filter_class((uint8_t)parsed_arg); 2200 break; 2201 case 'S': 2202 rval = sscanf(line, "S 0x%x\n", &parsed_arg); 2203 if (rval != 1) 2204 quit_args("invalid line %d of file %s: %s\n", 2205 current_line, filename, line); 2206 if (parsed_arg > 0xFFFF) 2207 quit_args("line %d of file %s: %s\n" 2208 "parsed as 0x%x, " 2209 "value must be 0x0-0xFFFF\n", 2210 current_line, filename, line, parsed_arg); 2211 set_filter_subclass(EXTRACT_CLASS_LOW(parsed_arg), 2212 EXTRACT_SUBCLASS_LOW(parsed_arg)); 2213 break; 2214 case '#': 2215 // comment 2216 break; 2217 case '\n': 2218 // empty line 2219 break; 2220 case '\0': 2221 // end of file 2222 break; 2223 default: 2224 quit_args("Invalid filter description file: %s\n" 2225 "could not parse line %d: %s\n", 2226 filename, current_line, line); 2227 } 2228 } 2229 2230 fclose(file); 2231} 2232 2233 2234/* 2235 * Find the debugid code in the list and return its index 2236 */ 2237static int binary_search(list, lowbound, highbound, code) 2238 code_type_t *list; 2239 int lowbound, highbound; 2240 unsigned int code; 2241{ 2242 int low, high, mid; 2243 int tries = 0; 2244 2245 low = lowbound; 2246 high = highbound; 2247 2248 while (1) 2249 { 2250 mid = (low + high) / 2; 2251 2252 tries++; 2253 2254 if (low > high) 2255 return (-1); /* failed */ 2256 else if ( low + 1 >= high) 2257 { 2258 /* We have a match */ 2259 if (list[high].debugid == code) 2260 return(high); 2261 else if (list[low].debugid == code) 2262 return(low); 2263 else 2264 return(-1); /* search failed */ 2265 } 2266 else if (code < list[mid].debugid) 2267 high = mid; 2268 else 2269 low = mid; 2270 } 2271} 2272 2273 2274static int 2275parse_codefile(const char *filename) 2276{ 2277 int fd; 2278 int i, j, line; 2279 size_t count; 2280 struct stat stat_buf; 2281 unsigned long file_size; 2282 char *file_addr, *endp; 2283 2284 if ((fd = open(filename, O_RDONLY, 0)) == -1) 2285 { 2286 printf("Failed to open code description file %s\n",filename); 2287 return(-1); 2288 } 2289 2290 if (fstat(fd, &stat_buf) == -1) 2291 { 2292 printf("Error: Can't fstat file: %s\n", filename); 2293 return(-1); 2294 } 2295 2296 /* 2297 * For some reason mapping files with zero size fails 2298 * so it has to be handled specially. 2299 */ 2300 file_size = stat_buf.st_size; 2301 2302 if (stat_buf.st_size != 0) 2303 { 2304 if ((file_addr = mmap(0, stat_buf.st_size, PROT_READ|PROT_WRITE, 2305 MAP_PRIVATE|MAP_FILE, fd, 0)) == (char*) -1) 2306 { 2307 printf("Error: Can't map file: %s\n", filename); 2308 close(fd); 2309 return(-1); 2310 } 2311 } 2312 else 2313 { 2314 // Skip empty files 2315 close(fd); 2316 return(0); 2317 } 2318 close(fd); 2319 2320 2321 /* 2322 * If we get here, we have mapped the file 2323 * and we are ready to parse it. Count 2324 * the newlines to get total number of codes. 2325 */ 2326 2327 for (count = 0, j=1; j < file_size; j++) 2328 { 2329 if (file_addr[j] == '\n') 2330 count++; 2331 } 2332 2333 if (count == 0) 2334 { 2335 printf("Error: No codes in %s\n", filename); 2336 return(-1); 2337 } 2338 2339 /* 2340 * Fudge the count to accomodate the last line in the file - 2341 * in case it doesn't end in a newline. 2342 */ 2343 count++; 2344 2345 // Grow the size of codesc to store new entries. 2346 size_t total_count = codesc_idx + count; 2347 code_type_t *new_codesc = (code_type_t *)realloc(codesc, (total_count) * sizeof(code_type_t)); 2348 2349 if (new_codesc == NULL) { 2350 printf("Failed to grow/allocate buffer. Skipping file %s\n", filename); 2351 return (-1); 2352 } 2353 codesc = new_codesc; 2354 bzero((char *)(codesc + codesc_idx), count * sizeof(code_type_t)); 2355 2356 for (line = 1, j = 0; j < file_size && codesc_idx < total_count; codesc_idx++) 2357 { 2358 /* Skip blank lines */ 2359 while (file_addr[j] == '\n') 2360 { 2361 j++; 2362 line++; 2363 } 2364 2365 /* Skip leading whitespace */ 2366 while (file_addr[j] == ' ' || file_addr[j] == '\t') 2367 j++; 2368 2369 /* Get the debugid code */ 2370 codesc[codesc_idx].debugid = strtoul(file_addr + j, &endp, 16); 2371 j = endp - file_addr; 2372 2373 if (codesc[codesc_idx].debugid == 0) 2374 { 2375 /* We didn't find a debugid code - skip this line */ 2376 if (verbose_flag) 2377 printf("Error: while parsing line %d, skip\n", line); 2378 while (file_addr[j] != '\n' && j < file_size) 2379 j++; 2380 codesc_idx--; 2381 line++; 2382 continue; 2383 } 2384 2385 /* Skip whitespace */ 2386 while (file_addr[j] == ' ' || file_addr[j] == '\t') 2387 j++; 2388 2389 /* Get around old file that had count at the beginning */ 2390 if (file_addr[j] == '\n') 2391 { 2392 /* missing debugid string - skip */ 2393 if (verbose_flag) 2394 printf("Error: while parsing line %d, (0x%x) skip\n", line, codesc[codesc_idx].debugid); 2395 2396 j++; 2397 codesc_idx--; 2398 line++; 2399 continue; 2400 } 2401 2402 /* Next is the debugid string terminated by a newline */ 2403 codesc[codesc_idx].debug_string = &file_addr[j]; 2404 2405 /* Null out the newline terminator */ 2406 while ((j < file_size) && (file_addr[j] != '\n')) 2407 j++; 2408 file_addr[j] = '\0'; /* File must be read-write */ 2409 j++; 2410 line++; 2411 codenum++; /*Index into codesc is 0 to codenum-1 */ 2412 } 2413 2414 if (verbose_flag) 2415 { 2416 printf("Parsed %d codes in %s\n", codenum, filename); 2417 printf("[%6d] 0x%8x %s\n", 0, codesc[0].debugid, codesc[0].debug_string); 2418 printf("[%6d] 0x%8x %s\n\n", codenum-1, codesc[codenum-1].debugid, codesc[codenum-1].debug_string); 2419 } 2420 2421 /* sort */ 2422 qsort((void *)codesc, codesc_idx, sizeof(code_type_t), debugid_compar); 2423 2424 if (verbose_flag) 2425 { 2426 printf("Sorted %zd codes in %s\n", codesc_idx, filename); 2427 printf("lowbound [%6d]: 0x%8x %s\n", 0, codesc[0].debugid, codesc[0].debug_string); 2428 printf("highbound [%6zd]: 0x%8x %s\n\n", codesc_idx - 1, codesc[codesc_idx - 1].debugid, codesc[codesc_idx - 1].debug_string); 2429 } 2430 codesc_find_dupes(); 2431 2432#if 0 2433 /* Dump the codefile */ 2434 for (i = 0; i < codesc_idx; i++) 2435 printf("[%d] 0x%x %s\n",i+1, codesc[i].debugid, codesc[i].debug_string); 2436#endif 2437 return(0); 2438} 2439 2440static void codesc_find_dupes(void) 2441{ 2442 boolean_t found_dupes = FALSE; 2443 if (codesc_idx == 0) 2444 { 2445 return; 2446 } 2447 uint32_t last_debugid = codesc[0].debugid; 2448 for(int i = 1; i < codesc_idx; i++) 2449 { 2450 if(codesc[i].debugid == last_debugid) 2451 { 2452 found_dupes = TRUE; 2453 if (verbose_flag) { 2454 fprintf(stderr, "WARNING: The debugid 0x%"PRIx32" (%s) has already been defined as '%s'.\n", codesc[i].debugid, codesc[i].debug_string, codesc[i - 1].debug_string); 2455 } 2456 } 2457 last_debugid = codesc[i].debugid; 2458 } 2459 if (found_dupes) 2460 { 2461 fprintf(stderr, "WARNING: One or more duplicate entries found in your codefiles, which will lead to unpredictable decoding behavior. Re-run with -v for more info\n"); 2462 } 2463} 2464 2465 2466int match_debugid(unsigned int xx, char * debugstr, int * yy) 2467{ 2468 int indx; 2469 2470 if (codenum == 0) 2471 return(-1); 2472 2473 if (codesc[codeindx_cache].debugid != xx) 2474 indx = binary_search(codesc, 0, (codenum-1), xx); 2475 else 2476 indx = codeindx_cache; 2477 2478 if (indx == -1) 2479 return(indx); /* match failed */ 2480 else { 2481 bcopy(&codesc[indx].debug_string[0], debugstr,80); 2482 *yy = indx; 2483 codeindx_cache = indx; 2484 return(0); /* match success */ 2485 } 2486} 2487 2488void 2489read_cpu_map(int fd) 2490{ 2491 if (cpumap_header) { 2492 free(cpumap_header); 2493 cpumap_header = NULL; 2494 cpumap = NULL; 2495 } 2496 2497 /* 2498 * To fit in the padding space of a VERSION1 file, the max possible 2499 * cpumap size is one page. 2500 */ 2501 cpumap_header = malloc(PAGE_SIZE); 2502 2503 if (readRAW_flag) { 2504 /* 2505 * cpu maps exist in a RAW_VERSION1+ header only 2506 */ 2507 if (raw_header.version_no == RAW_VERSION1) { 2508 off_t base_offset = lseek(fd, (off_t)0, SEEK_CUR); 2509 off_t aligned_offset = (base_offset + (4095)) & ~4095; /* <rdar://problem/13500105> */ 2510 2511 size_t padding_bytes = (size_t)(aligned_offset - base_offset); 2512 2513 if (read(fd, cpumap_header, padding_bytes) == padding_bytes) { 2514 if (cpumap_header->version_no == RAW_VERSION1) { 2515 cpumap = (kd_cpumap*)&cpumap_header[1]; 2516 } 2517 } 2518 } 2519 } else { 2520 int mib[3]; 2521 2522 mib[0] = CTL_KERN; 2523 mib[1] = KERN_KDEBUG; 2524 mib[2] = KERN_KDCPUMAP; 2525 2526 size_t temp = PAGE_SIZE; 2527 if (sysctl(mib, 3, cpumap_header, &temp, NULL, 0) == 0) { 2528 if (PAGE_SIZE >= temp) { 2529 if (cpumap_header->version_no == RAW_VERSION1) { 2530 cpumap = (kd_cpumap*)&cpumap_header[1]; 2531 } 2532 } 2533 } 2534 } 2535 2536 if (!cpumap) { 2537 printf("Can't read the cpu map -- this is not fatal\n"); 2538 free(cpumap_header); 2539 cpumap_header = NULL; 2540 } else if (verbose_flag) { 2541 /* Dump the initial cpumap */ 2542 printf("\nCPU\tName\n"); 2543 for (int i = 0; i < cpumap_header->cpu_count; i++) { 2544 printf ("%2d\t%s\n", cpumap[i].cpu_id, cpumap[i].name); 2545 } 2546 printf("\n"); 2547 } 2548} 2549 2550int 2551read_command_map(int fd, uint32_t count) 2552{ 2553 int i; 2554 size_t size; 2555 int mib[6]; 2556 2557 if (readRAW_flag) { 2558 total_threads = count; 2559 size = count * sizeof(kd_threadmap); 2560 } else { 2561 get_bufinfo(&bufinfo); 2562 2563 total_threads = bufinfo.nkdthreads; 2564 size = bufinfo.nkdthreads * sizeof(kd_threadmap); 2565 } 2566 mapptr = 0; 2567 nthreads = total_threads * 2; 2568 2569 if (verbose_flag) 2570 printf("Size of map table is %d, thus %d entries\n", (int)size, total_threads); 2571 2572 if (size) { 2573 if ((mapptr = (kd_threadmap *) malloc(size))) 2574 bzero (mapptr, size); 2575 else 2576 { 2577 if (verbose_flag) 2578 printf("Thread map is not initialized -- this is not fatal\n"); 2579 return(0); 2580 } 2581 } 2582 if (readRAW_flag) { 2583 if (read(fd, mapptr, size) != size) { 2584 if (verbose_flag) 2585 printf("Can't read the thread map -- this is not fatal\n"); 2586 free(mapptr); 2587 mapptr = 0; 2588 2589 return (int)size; 2590 } 2591 } else { 2592 /* Now read the threadmap */ 2593 mib[0] = CTL_KERN; 2594 mib[1] = KERN_KDEBUG; 2595 mib[2] = KERN_KDTHRMAP; 2596 mib[3] = 0; 2597 mib[4] = 0; 2598 mib[5] = 0; /* no flags */ 2599 if (sysctl(mib, 3, mapptr, &size, NULL, 0) < 0) 2600 { 2601 /* This is not fatal -- just means I cant map command strings */ 2602 if (verbose_flag) 2603 printf("Can't read the thread map -- this is not fatal\n"); 2604 free(mapptr); 2605 mapptr = 0; 2606 return(0); 2607 } 2608 } 2609 for (i = 0; i < total_threads; i++) { 2610 if (mapptr[i].thread) 2611 create_map_entry(mapptr[i].thread, &mapptr[i].command[0]); 2612 } 2613 2614 if (verbose_flag) { 2615 /* Dump the initial map */ 2616 2617 printf("Size of maptable returned is %ld, thus %ld entries\n", size, (size/sizeof(kd_threadmap))); 2618 2619 printf("Thread Command\n"); 2620 for (i = 0; i < total_threads; i++) { 2621 printf ("0x%lx %s\n", 2622 mapptr[i].thread, 2623 mapptr[i].command); 2624 } 2625 } 2626 return (int)size; 2627} 2628 2629 2630void create_map_entry(uintptr_t thread, char *command) 2631{ 2632 threadmap_t tme; 2633 int hashid; 2634 2635 if ((tme = threadmap_freelist)) 2636 threadmap_freelist = tme->tm_next; 2637 else 2638 tme = (threadmap_t)malloc(sizeof(struct threadmap)); 2639 2640 tme->tm_thread = thread; 2641 tme->tm_deleteme = FALSE; 2642 2643 (void)strncpy (tme->tm_command, command, MAXCOMLEN); 2644 tme->tm_command[MAXCOMLEN] = '\0'; 2645 2646 hashid = thread & HASH_MASK; 2647 2648 tme->tm_next = threadmap_hash[hashid]; 2649 threadmap_hash[hashid] = tme; 2650} 2651 2652 2653void delete_thread_entry(uintptr_t thread) 2654{ 2655 threadmap_t tme = 0; 2656 threadmap_t tme_prev; 2657 int hashid; 2658 2659 hashid = thread & HASH_MASK; 2660 2661 if ((tme = threadmap_hash[hashid])) { 2662 if (tme->tm_thread == thread) 2663 threadmap_hash[hashid] = tme->tm_next; 2664 else { 2665 tme_prev = tme; 2666 2667 for (tme = tme->tm_next; tme; tme = tme->tm_next) { 2668 if (tme->tm_thread == thread) { 2669 tme_prev->tm_next = tme->tm_next; 2670 break; 2671 } 2672 tme_prev = tme; 2673 } 2674 } 2675 if (tme) { 2676 tme->tm_next = threadmap_freelist; 2677 threadmap_freelist = tme; 2678 } 2679 } 2680} 2681 2682 2683void find_and_insert_tmp_map_entry(uintptr_t pthread, char *command) 2684{ 2685 threadmap_t tme = 0; 2686 threadmap_t tme_prev; 2687 int hashid; 2688 2689 if ((tme = threadmap_temp)) { 2690 if (tme->tm_pthread == pthread) 2691 threadmap_temp = tme->tm_next; 2692 else { 2693 tme_prev = tme; 2694 2695 for (tme = tme->tm_next; tme; tme = tme->tm_next) { 2696 if (tme->tm_pthread == pthread) { 2697 tme_prev->tm_next = tme->tm_next; 2698 break; 2699 } 2700 tme_prev = tme; 2701 } 2702 } 2703 if (tme) { 2704 (void)strncpy (tme->tm_command, command, MAXCOMLEN); 2705 tme->tm_command[MAXCOMLEN] = '\0'; 2706 2707 delete_thread_entry(tme->tm_thread); 2708 2709 hashid = tme->tm_thread & HASH_MASK; 2710 2711 tme->tm_next = threadmap_hash[hashid]; 2712 threadmap_hash[hashid] = tme; 2713 } 2714 } 2715} 2716 2717 2718void create_tmp_map_entry(uintptr_t thread, uintptr_t pthread) 2719{ 2720 threadmap_t tme; 2721 2722 if ((tme = threadmap_freelist)) 2723 threadmap_freelist = tme->tm_next; 2724 else 2725 tme = (threadmap_t)malloc(sizeof(struct threadmap)); 2726 2727 tme->tm_thread = thread; 2728 tme->tm_pthread = pthread; 2729 tme->tm_deleteme = FALSE; 2730 tme->tm_command[0] = '\0'; 2731 2732 tme->tm_next = threadmap_temp; 2733 threadmap_temp = tme; 2734} 2735 2736 2737threadmap_t 2738find_thread_entry(uintptr_t thread) 2739{ 2740 threadmap_t tme; 2741 int hashid; 2742 2743 hashid = thread & HASH_MASK; 2744 2745 for (tme = threadmap_hash[hashid]; tme; tme = tme->tm_next) { 2746 if (tme->tm_thread == thread) 2747 return (tme); 2748 } 2749 return (0); 2750} 2751 2752 2753void find_thread_name(uintptr_t thread, char **command, boolean_t deleteme) 2754{ 2755 threadmap_t tme; 2756 2757 if ((tme = find_thread_entry(thread))) { 2758 *command = tme->tm_command; 2759 2760 if (deleteme == TRUE) 2761 tme->tm_deleteme = deleteme; 2762 } else 2763 *command = EMPTYSTRING; 2764} 2765 2766 2767void find_thread_command(kd_buf *kbufp, char **command) 2768{ 2769 uintptr_t thread; 2770 threadmap_t tme; 2771 int debugid_base; 2772 2773 thread = kbufp->arg5; 2774 debugid_base = kbufp->debugid & DBG_FUNC_MASK; 2775 2776 if (debugid_base == BSC_exit || debugid_base == MACH_STKHANDOFF) { 2777 /* 2778 * Mark entry as invalid and return temp command pointer 2779 */ 2780 if ((tme = find_thread_entry(thread))) { 2781 2782 strncpy(tmpcommand, tme->tm_command, MAXCOMLEN); 2783 *command = tmpcommand; 2784 2785 if (debugid_base == BSC_exit || tme->tm_deleteme == TRUE) 2786 delete_thread_entry(thread); 2787 } else 2788 *command = EMPTYSTRING; 2789 } 2790 else if (debugid_base == TRACE_DATA_NEWTHREAD) { 2791 /* 2792 * Save the create thread data 2793 */ 2794 create_tmp_map_entry(kbufp->arg1, kbufp->arg5); 2795 } 2796 else if (debugid_base == TRACE_STRING_NEWTHREAD) { 2797 /* 2798 * process new map entry 2799 */ 2800 find_and_insert_tmp_map_entry(kbufp->arg5, (char *)&kbufp->arg1); 2801 } 2802 else if (debugid_base == TRACE_STRING_EXEC) { 2803 2804 delete_thread_entry(kbufp->arg5); 2805 2806 create_map_entry(kbufp->arg5, (char *)&kbufp->arg1); 2807 } 2808 else 2809 find_thread_name(thread, command, (debugid_base == BSC_thread_terminate)); 2810} 2811 2812 2813static 2814void getdivisor() 2815{ 2816 mach_timebase_info_data_t info; 2817 2818 if (frequency == 0) { 2819 (void) mach_timebase_info (&info); 2820 2821 divisor = ( (double)info.denom / (double)info.numer) * 1000; 2822 } else 2823 divisor = (double)frequency / 1000000; 2824 2825 if (verbose_flag) 2826 printf("divisor = %g\n", divisor); 2827} 2828