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