2 cc -I/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders -arch x86_64 -arch i386 -O -o trace trace.c
9 #include <sys/socket.h>
11 #include <sys/ioctl.h>
14 #include <sys/ucred.h>
17 #include <sys/ptrace.h>
18 #include <sys/sysctl.h>
20 #include <sys/resource.h>
34 #ifndef KERNEL_PRIVATE
35 #define KERNEL_PRIVATE
36 #include <sys/kdebug.h>
39 #include <sys/kdebug.h>
40 #endif /*KERNEL_PRIVATE*/
41 #include <sys/param.h>
43 #include <mach/mach.h>
44 #include <mach/mach_time.h>
60 int filter_file_flag
=0;
71 int no_default_codes_flag
=0;
73 unsigned int value1
=0;
74 unsigned int value2
=0;
75 unsigned int value3
=0;
76 unsigned int value4
=0;
81 int force_32bit_exec
= 0;
87 char *logfile
= (char *)0; /* This file is trace format */
88 char *RAW_file
= (char *)0;
92 extern char **environ
;
94 uint8_t* type_filter_bitmap
;
97 #define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
98 #define DBG_FUNC_MASK 0xfffffffc
102 #define CSC_MASK 0xffff0000
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
115 #define EMPTYSTRING ""
116 #define UNKNOWN "unknown"
118 char tmpcommand
[MAXCOMLEN
];
120 int total_threads
= 0;
122 kd_threadmap
*mapptr
= 0;
124 kd_cpumap_header
* cpumap_header
= NULL
;
125 kd_cpumap
* cpumap
= NULL
;
128 If NUMPARMS changes from the kernel,
129 then PATHLENGTH will also reflect the change
130 This is for the vfslookup entries that
134 #define PATHLENGTH (NUMPARMS*sizeof(long))
137 #define US_TO_SLEEP 50000
138 #define BASE_EVENTS 500000
148 code_type_t
* codesc
= 0;
149 size_t codesc_idx
= 0; // Index into first empty codesc entry
153 typedef struct event
*event_t
;
160 uint64_t ev_timestamp
;
163 typedef struct lookup
*lookup_t
;
171 long lk_pathname
[NUMPARMS
+ 1];
174 typedef struct threadmap
*threadmap_t
;
180 uintptr_t tm_pthread
;
181 boolean_t tm_deleteme
;
182 char tm_command
[MAXCOMLEN
+ 1];
186 #define HASH_SIZE 1024
187 #define HASH_MASK 1023
189 event_t event_hash
[HASH_SIZE
];
190 lookup_t lookup_hash
[HASH_SIZE
];
191 threadmap_t threadmap_hash
[HASH_SIZE
];
193 event_t event_freelist
;
194 lookup_t lookup_freelist
;
195 threadmap_t threadmap_freelist
;
196 threadmap_t threadmap_temp
;
199 #define SBUFFER_SIZE (128 * 4096)
200 char sbuffer
[SBUFFER_SIZE
];
203 int use_current_buf
= 0;
206 kbufinfo_t bufinfo
= {0, 0, 0, 0};
209 int codeindx_cache
= 0;
211 static void quit(char *);
212 static int match_debugid(unsigned int, char *, int *);
213 static void usage(int short_help
);
214 static int argtoi(int flag
, char *req
, char *str
, int base
);
215 static int parse_codefile(const char *filename
);
216 static void codesc_find_dupes(void);
217 static int read_command_map(int, uint32_t);
218 static void read_cpu_map(int);
219 static void find_thread_command(kd_buf
*, char **);
220 static void create_map_entry(uintptr_t, char *);
221 static void getdivisor();
222 static unsigned long argtoul();
224 static void set_enable(int);
225 static void set_remove();
226 static void set_nowrap();
227 static void set_pidcheck(int, int);
228 static void set_pidexclude(int, int);
229 static void set_numbufs(int);
230 static void set_freerun();
231 static void get_bufinfo(kbufinfo_t
*);
232 static void set_init();
233 static void set_kval_list();
234 static void readtrace(char *);
235 static void log_trace();
236 static void Log_trace();
237 static void read_trace();
238 static void signal_handler(int);
239 static void signal_handler_RAW(int);
240 static void delete_thread_entry(uintptr_t);
241 static void find_and_insert_tmp_map_entry(uintptr_t, char *);
242 static void create_tmp_map_entry(uintptr_t, uintptr_t);
243 static void find_thread_name(uintptr_t, char **, boolean_t
);
245 static int writetrace(int);
246 static int write_command_map(int);
247 static int debugid_compar(code_type_t
*, code_type_t
*);
249 static threadmap_t
find_thread_entry(uintptr_t);
251 static void saw_filter_class(uint8_t class);
252 static void saw_filter_end_range(uint8_t end_class
);
253 static void saw_filter_subclass(uint8_t subclass
);
254 static void filter_done_parsing(void);
256 static void set_filter(void);
257 static void set_filter_class(uint8_t class);
258 static void set_filter_range(uint8_t class, uint8_t end
);
259 static void set_filter_subclass(uint8_t class, uint8_t subclass
);
261 static void parse_filter_file(char *filename
);
263 static void quit_args(const char *fmt
, ...) __printflike(1, 2);
265 #ifndef KERN_KDWRITETR
266 #define KERN_KDWRITETR 17
269 #ifndef KERN_KDWRITEMAP
270 #define KERN_KDWRITEMAP 18
274 #define F_FLUSH_DATA 40
285 #define RAW_VERSION0 0x55aa0000
286 #define RAW_VERSION1 0x55aa0101
289 #define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(*x)))
291 #define EXTRACT_CLASS_LOW(debugid) ( (uint8_t) ( ((debugid) & 0xFF00 ) >> 8 ) )
292 #define EXTRACT_SUBCLASS_LOW(debugid) ( (uint8_t) ( ((debugid) & 0xFF ) ) )
294 #define ENCODE_CSC_LOW(class, subclass) \
295 ( (uint16_t) ( ((class) & 0xff) << 8 ) | ((subclass) & 0xff) )
297 RAW_header raw_header
;
301 void set_enable(int val
)
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
;
317 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
318 quit_args("trace facility failure, KERN_KDENABLE: %s\n", strerror(errno
));
328 mib
[1] = KERN_KDEBUG
;
329 mib
[2] = KERN_KDREMOVE
;
333 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
336 quit("the trace facility is currently in use...\n fs_usage, sc_usage, trace, and latency use this feature.\n\n");
338 quit_args("trace facility failure, KERN_KDREMOVE: %s\n", strerror(errno
));
342 void set_numbufs(int nbufs
)
345 mib
[1] = KERN_KDEBUG
;
346 mib
[2] = KERN_KDSETBUF
;
350 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
351 quit_args("trace facility failure, KERN_KDSETBUF: %s\n", strerror(errno
));
354 mib
[1] = KERN_KDEBUG
;
355 mib
[2] = KERN_KDSETUP
;
359 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
360 quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno
));
366 mib
[1] = KERN_KDEBUG
;
367 mib
[2] = KERN_KDEFLAGS
;
368 mib
[3] = KDBG_NOWRAP
;
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
));
376 void set_pidcheck(int pid
, int on_off_flag
)
380 kr
.type
= KDBG_TYPENONE
;
382 kr
.value2
= on_off_flag
;
383 needed
= sizeof(kd_regtype
);
385 mib
[1] = KERN_KDEBUG
;
386 mib
[2] = KERN_KDPIDTR
;
390 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
392 if (on_off_flag
== 1)
394 printf("trace facility failure, KERN_KDPIDTR,\n\tpid %d does not exist\n", pid
);
401 void set_pidexclude(int pid
, int on_off_flag
)
405 kr
.type
= KDBG_TYPENONE
;
407 kr
.value2
= on_off_flag
;
408 needed
= sizeof(kd_regtype
);
410 mib
[1] = KERN_KDEBUG
;
411 mib
[2] = KERN_KDPIDEX
;
415 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
417 if (on_off_flag
== 1)
419 printf ("pid %d does not exist\n", pid
);
429 mib
[1] = KERN_KDEBUG
;
430 mib
[2] = KERN_KDEFLAGS
;
431 mib
[3] = KDBG_FREERUN
;
434 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
435 quit_args("trace facility failure, KDBG_FREERUN: %s\n", strerror(errno
));
438 void get_bufinfo(kbufinfo_t
*val
)
440 needed
= sizeof (*val
);
442 mib
[1] = KERN_KDEBUG
;
443 mib
[2] = KERN_KDGETBUF
;
447 if (sysctl(mib
, 3, val
, &needed
, 0, 0) < 0)
448 quit_args("trace facility failure, KERN_KDGETBUF: %s\n", strerror(errno
));
455 kr
.type
= KDBG_RANGETYPE
;
458 needed
= sizeof(kd_regtype
);
460 mib
[1] = KERN_KDEBUG
;
461 mib
[2] = KERN_KDSETREG
;
465 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
466 quit_args("trace facility failure, KERN_KDSETREG (rangetype): %s\n", strerror(errno
));
469 mib
[1] = KERN_KDEBUG
;
470 mib
[2] = KERN_KDSETUP
;
474 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
475 quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno
));
483 int mib
[] = { CTL_KERN
, KERN_KDEBUG
, KERN_KDSET_TYPEFILTER
};
484 size_t needed
= KDBG_TYPEFILTER_BITMAP_SIZE
;
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
));
495 kr
.type
= KDBG_VALCHECK
;
500 needed
= sizeof(kd_regtype
);
502 mib
[1] = KERN_KDEBUG
;
503 mib
[2] = KERN_KDSETREG
;
507 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
508 quit_args("trace facility failure, KERN_KDSETREG (valcheck): %s\n", strerror(errno
));
512 void readtrace(char *buffer
)
515 mib
[1] = KERN_KDEBUG
;
516 mib
[2] = KERN_KDREADTR
;
521 if (sysctl(mib
, 3, buffer
, &needed
, NULL
, 0) < 0)
522 quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno
));
526 int writetrace(int fd
)
529 mib
[1] = KERN_KDEBUG
;
530 mib
[2] = KERN_KDWRITETR
;
535 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
542 int write_command_map(int fd
)
545 mib
[1] = KERN_KDEBUG
;
546 mib
[2] = KERN_KDWRITEMAP
;
551 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
559 lookup_t
handle_lookup_event(uintptr_t thread
, int debugid
, kd_buf
*kdp
)
563 boolean_t first_record
= FALSE
;
565 hashid
= thread
& HASH_MASK
;
567 if (debugid
& DBG_FUNC_START
)
570 for (lkp
= lookup_hash
[hashid
]; lkp
; lkp
= lkp
->lk_next
) {
571 if (lkp
->lk_thread
== thread
)
575 if (first_record
== FALSE
)
578 if ((lkp
= lookup_freelist
))
579 lookup_freelist
= lkp
->lk_next
;
581 lkp
= (lookup_t
)malloc(sizeof(struct lookup
));
583 lkp
->lk_thread
= thread
;
585 lkp
->lk_next
= lookup_hash
[hashid
];
586 lookup_hash
[hashid
] = lkp
;
589 if (first_record
== TRUE
) {
590 lkp
->lk_pathptr
= lkp
->lk_pathname
;
591 lkp
->lk_dvp
= kdp
->arg1
;
593 if (lkp
->lk_pathptr
> &lkp
->lk_pathname
[NUMPARMS
-4])
596 *lkp
->lk_pathptr
++ = kdp
->arg1
;
598 *lkp
->lk_pathptr
++ = kdp
->arg2
;
599 *lkp
->lk_pathptr
++ = kdp
->arg3
;
600 *lkp
->lk_pathptr
++ = kdp
->arg4
;
601 *lkp
->lk_pathptr
= 0;
608 void delete_lookup_event(uintptr_t thread
, lookup_t lkp_to_delete
)
614 hashid
= thread
& HASH_MASK
;
616 if ((lkp
= lookup_hash
[hashid
])) {
617 if (lkp
== lkp_to_delete
)
618 lookup_hash
[hashid
] = lkp
->lk_next
;
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
;
631 lkp
->lk_next
= lookup_freelist
;
632 lookup_freelist
= lkp
;
639 void insert_start_event(uintptr_t thread
, int debugid
, uint64_t now
)
644 hashid
= thread
& HASH_MASK
;
646 for (evp
= event_hash
[hashid
]; evp
; evp
= evp
->ev_next
) {
647 if (evp
->ev_thread
== thread
&& evp
->ev_debugid
== debugid
)
651 if ((evp
= event_freelist
))
652 event_freelist
= evp
->ev_next
;
654 evp
= (event_t
)malloc(sizeof(struct event
));
656 evp
->ev_thread
= thread
;
657 evp
->ev_debugid
= debugid
;
659 evp
->ev_next
= event_hash
[hashid
];
660 event_hash
[hashid
] = evp
;
662 evp
->ev_timestamp
= now
;
667 uint64_t consume_start_event(uintptr_t thread
, int debugid
, uint64_t now
)
672 uint64_t elapsed
= 0;
674 hashid
= thread
& HASH_MASK
;
676 if ((evp
= event_hash
[hashid
])) {
677 if (evp
->ev_thread
== thread
&& evp
->ev_debugid
== debugid
)
678 event_hash
[hashid
] = evp
->ev_next
;
682 for (evp
= evp
->ev_next
; evp
; evp
= evp
->ev_next
) {
684 if (evp
->ev_thread
== thread
&& evp
->ev_debugid
== debugid
) {
685 evp_prev
->ev_next
= evp
->ev_next
;
692 elapsed
= now
- evp
->ev_timestamp
;
694 evp
->ev_next
= event_freelist
;
695 event_freelist
= evp
;
706 uint32_t buffer_size
;
713 if ((fd
= open(logfile
, O_TRUNC
|O_WRONLY
|O_CREAT
, 0777)) == -1) {
714 perror("Can't open logfile");
717 get_bufinfo(&bufinfo
);
719 if (bufinfo
.nolog
!= 1) {
721 set_enable(0); /* disable logging*/
723 get_bufinfo(&bufinfo
);
726 if (bufinfo
.flags
& KDBG_WRAPPED
)
727 printf("Buffer has wrapped\n");
729 printf("Buffer has not wrapped\n");
731 buffer_size
= 1000000 * sizeof(kd_buf
);
732 buffer
= malloc(buffer_size
);
734 if (buffer
== (char *) 0)
735 quit("can't allocate memory for tracing info\n");
737 read_command_map(0, 0);
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;
745 write(fd
, &raw_header
, sizeof(RAW_header
));
747 size
= total_threads
* sizeof(kd_threadmap
);
748 write(fd
, (char *)mapptr
, size
);
750 pad_size
= 4096 - ((sizeof(RAW_header
) + size
) & 4095);
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
;
760 memset(pad_buf
, 0, pad_size
);
761 write(fd
, pad_buf
, pad_size
);
764 needed
= buffer_size
;
770 write(fd
, buffer
, needed
* sizeof(kd_buf
));
783 int try_writetrace
= 1;
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
;
796 memset(&kd_tmp
, 0, sizeof(kd_tmp
));
798 if ((fd
= open(logfile
, O_TRUNC
|O_WRONLY
|O_CREAT
, 0777)) == -1) {
799 perror("Can't open logfile");
802 if (use_current_buf
== 0) {
804 * grab the number of cpus and scale the buffer size
809 len
= sizeof(num_cpus
);
811 sysctl(mib
, 2, &num_cpus
, &len
, NULL
, 0);
814 nbufs
= BASE_EVENTS
* num_cpus
;
826 /* Get kernel buffer information */
827 get_bufinfo(&bufinfo
);
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
));
834 if (use_current_buf
== 0)
837 if (write_command_map(fd
)) {
841 read_command_map(0, 0);
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;
849 write(fd
, &raw_header
, sizeof(RAW_header
));
851 size
= total_threads
* sizeof(kd_threadmap
);
852 write(fd
, (char *)mapptr
, size
);
854 pad_size
= 4096 - ((sizeof(RAW_header
) + size
) & 4095);
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
;
864 memset(pad_buf
, 0, pad_size
);
865 write(fd
, pad_buf
, pad_size
);
867 sample_window_abs
= (uint64_t)((double)US_TO_SLEEP
* divisor
);
869 next_window_begins
= mach_absolute_time() + sample_window_abs
;
872 ending_abstime
= mach_absolute_time() + (uint64_t)((double)secs_to_run
* (double)1000000 * divisor
);
873 ms_to_run
= secs_to_run
* 1000;
876 last_time_written
= mach_absolute_time();
878 while (LogRAW_flag
) {
879 current_abs
= mach_absolute_time();
881 if (try_writetrace
) {
888 current_abs
= mach_absolute_time();
890 printf("wrote %d events - elapsed time = %.1f secs\n",
891 (int)needed
, ((double)(current_abs
- last_time_written
) / divisor
) / 1000000);
893 last_time_written
= current_abs
;
897 if (try_writetrace
== 0) {
899 if (next_window_begins
> current_abs
)
900 us_to_adjust
= US_TO_SLEEP
- (uint32_t)((double)(next_window_begins
- current_abs
) / divisor
);
902 us_to_adjust
= US_TO_SLEEP
;
904 next_window_begins
= current_abs
+ sample_window_abs
;
906 us_to_sleep
= US_TO_SLEEP
- us_to_adjust
;
908 next_window_begins
= current_abs
+ (uint64_t)((double)(us_to_sleep
+ US_TO_SLEEP
) * divisor
);
913 get_bufinfo(&bufinfo
);
915 if (bufinfo
.flags
& KDBG_WRAPPED
)
916 printf("lost events\n");
918 needed
= bufinfo
.nkdbufs
* sizeof(kd_buf
);
922 if (bufinfo
.flags
& KDBG_WRAPPED
) {
924 kd
= (kd_buf
*) buffer
;
926 kd_tmp
.timestamp
= kd
[0].timestamp
;
927 kd_tmp
.debugid
= TRACE_LOST_EVENTS
;
929 write(fd
, &kd_tmp
, sizeof(kd_tmp
));
931 write(fd
, buffer
, needed
* sizeof(kd_buf
));
933 if (verbose_flag
&& needed
> nbufs
)
934 printf("needed = %ld\n", needed
);
937 current_abs
= mach_absolute_time();
939 if (current_abs
> ending_abstime
)
941 ms_to_run
= (ending_abstime
- current_abs
) / (1000 * 1000);
958 uint32_t buffer_size
;
965 uint32_t count_of_names
;
966 double last_event_time
= 0.0;
970 get_bufinfo(&bufinfo
);
972 if (bufinfo
.nolog
!= 1) {
974 set_enable(0); /* disable logging*/
977 if (bufinfo
.flags
& KDBG_WRAPPED
)
978 printf("Buffer has wrapped\n");
980 printf("Buffer has not wrapped\n");
986 fd
= open(RAW_file
, O_RDONLY
);
989 perror("Can't open file");
992 if (read(fd
, &raw_header
, sizeof(RAW_header
)) != sizeof(RAW_header
)) {
993 perror("read failed");
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;
1001 lseek(fd
, (off_t
)0, SEEK_SET
);
1003 if (read(fd
, &raw_header
.thread_count
, sizeof(int)) != sizeof(int)) {
1004 perror("read failed");
1008 count_of_names
= raw_header
.thread_count
;
1009 trace_time
= (time_t) (raw_header
.TOD_secs
);
1011 printf("%s\n", ctime(&trace_time
));
1013 buffer_size
= 1000000 * sizeof(kd_buf
);
1014 buffer
= malloc(buffer_size
);
1016 if (buffer
== (char *) 0)
1017 quit("can't allocate memory for tracing info\n");
1019 kd
= (kd_buf
*)buffer
;
1021 read_command_map(fd
, count_of_names
);
1033 double event_elapsed_time
;
1036 boolean_t ending_event
;
1045 if (!readRAW_flag
) {
1046 needed
= buffer_size
;
1049 mib
[1] = KERN_KDEBUG
;
1050 mib
[2] = KERN_KDREADTR
;
1054 if (sysctl(mib
, 3, buffer
, &needed
, NULL
, 0) < 0)
1055 quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno
));
1062 uint32_t bytes_read
;
1064 bytes_read
= read(fd
, buffer
, buffer_size
);
1066 if (bytes_read
== -1) {
1067 perror("read failed");
1070 count
= bytes_read
/ sizeof(kd_buf
);
1075 for (kdp
= &kd
[0], i
= 0; i
< count
; i
++, kdp
++) {
1078 debugid
= kdp
->debugid
;
1079 debugid_base
= debugid
& DBG_FUNC_MASK
;
1080 now
= kdp
->timestamp
& KDBG_TIMESTAMP_MASK
;
1086 cpunum
= kdbg_get_cpu(kdp
);
1089 if (lines
== 64 || firsttime
)
1091 prevdelta
= now
- prevdelta
;
1096 x
= (double)prevdelta
;
1099 fprintf(output_file
, "\n\nNumber of microsecs since in last page %8.1f\n", x
);
1104 * Output description row to output file (make sure to format correctly for 32-bit and 64-bit)
1106 fprintf(output_file
,
1108 " AbsTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu# command\n\n"
1110 " AbsTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu# command\n\n"
1116 if (io_lines
> 15000) {
1117 fcntl(output_fd
, F_FLUSH_DATA
, 0);
1124 if (debugid_base
== VFS_LOOKUP
) {
1125 lkp
= handle_lookup_event(thread
, debugid
, kdp
);
1127 if ( !lkp
|| !(debugid
& DBG_FUNC_END
))
1133 if (last_event_time
)
1134 y
= x
- last_event_time
;
1137 last_event_time
= x
;
1138 ending_event
= FALSE
;
1141 * Is this event from an IOP? If so, there will be no
1142 * thread command, label it with the symbolic IOP name
1144 if (cpumap
&& (cpunum
< cpumap_header
->cpu_count
) && (cpumap
[cpunum
].flags
& KDBG_CPUMAP_IS_IOP
)) {
1145 command
= cpumap
[cpunum
].name
;
1147 find_thread_command(kdp
, &command
);
1151 * The internal use TRACE points clutter the output.
1152 * Print them only if in verbose mode.
1156 /* Is this entry of Class DBG_TRACE */
1157 if ((debugid
>> 24) == DBG_TRACE
) {
1158 if (((debugid
>> 16) & 0xff) != DBG_TRACE_INFO
)
1166 if ((debugid
& DBG_FUNC_START
) || debugid
== MACH_MAKERUNNABLE
) {
1168 if (debugid_base
!= BSC_thread_terminate
&& debugid_base
!= BSC_exit
) {
1170 if (debugid
== MACH_MAKERUNNABLE
)
1171 t_thread
= kdp
->arg1
;
1175 insert_start_event(t_thread
, debugid_base
, now
);
1178 } else if ((debugid
& DBG_FUNC_END
) || debugid
== MACH_STKHANDOFF
|| debugid
== MACH_SCHEDULED
) {
1180 if (debugid
== MACH_STKHANDOFF
|| debugid
== MACH_SCHEDULED
) {
1181 t_debugid
= MACH_MAKERUNNABLE
;
1182 t_thread
= kdp
->arg2
;
1184 t_debugid
= debugid_base
;
1187 event_elapsed_time
= (double)consume_start_event(t_thread
, t_debugid
, now
);
1188 event_elapsed_time
/= divisor
;
1189 ending_event
= TRUE
;
1191 if (event_elapsed_time
== 0 && (debugid
== MACH_STKHANDOFF
|| debugid
== MACH_SCHEDULED
))
1192 ending_event
= FALSE
;
1198 sprintf(&outbuf
[0], "(%-10.1f)", event_elapsed_time
);
1200 * fix that right paren
1205 ch
= strchr (&outbuf
[0], ')');
1212 while (ch
!= &outbuf
[0])
1224 if (match_debugid(debugid_base
, dbgmessge
, &dmsgindex
)) {
1226 fprintf(output_file
, "%13.1f %10.1f%s %-28x ", x
, y
, outbuf
, debugid_base
);
1228 fprintf(output_file
, "%13.1f %10.1f %-28x ", x
, y
, debugid_base
);
1231 fprintf(output_file
, "%13.1f %10.1f%s %-28.28s ", x
, y
, outbuf
, dbgmessge
);
1233 fprintf(output_file
, "%13.1f %10.1f %-28.28s ", x
, y
, dbgmessge
);
1239 strptr
= (char *)lkp
->lk_pathname
;
1242 * print the tail end of the pathname
1244 len
= strlen(strptr
);
1251 fprintf(output_file
, "%-16lx %-51s %-16lx %-2d %s\n", lkp
->lk_dvp
, &strptr
[len
], thread
, cpunum
, command
);
1253 fprintf(output_file
, "%-8x %-51s %-8lx %-2d %s\n", (unsigned int)lkp
->lk_dvp
, &strptr
[len
], thread
, cpunum
, command
);
1255 delete_lookup_event(thread
, lkp
);
1258 fprintf(output_file
, "%-16lx %-16lx %-16lx %-16lx %-16lx %-2d %s\n", kdp
->arg1
, kdp
->arg2
, kdp
->arg3
, kdp
->arg4
, thread
, cpunum
, command
);
1260 fprintf(output_file
, "%-8lx %-8lx %-8lx %-8lx %-8lx %-2d %s\n", kdp
->arg1
, kdp
->arg2
, kdp
->arg3
, kdp
->arg4
, thread
, cpunum
, command
);
1268 set_enable(1); /* re-enable kernel logging */
1273 void signal_handler(int sig
)
1275 ptrace(PT_KILL
, pid
, (caddr_t
)0, 0);
1277 * child is gone; no need to disable the pid
1283 void signal_handler_RAW(int sig
)
1290 int main(argc
, argv
, env
)
1295 extern char *optarg
;
1300 char *output_filename
= NULL
;
1301 char *filter_filename
= NULL
;
1302 unsigned int parsed_arg
;
1304 for (i
= 1; i
< argc
; i
++) {
1305 if (strcmp("-X", argv
[i
]) == 0) {
1306 force_32bit_exec
= 1;
1310 if (force_32bit_exec
) {
1311 if (0 != reexec_to_match_lp64ness(FALSE
)) {
1312 fprintf(stderr
, "Could not re-execute: %d\n", errno
);
1316 if (0 != reexec_to_match_kernel()) {
1317 fprintf(stderr
, "Could not re-execute: %d\n", errno
);
1321 if (setiopolicy_np(IOPOL_TYPE_DISK
, IOPOL_SCOPE_PROCESS
, IOPOL_PASSIVE
) < 0) {
1322 printf("setiopolicy failed\n");
1325 output_file
= stdout
;
1328 while ((ch
= getopt(argc
, argv
, "hedEk:irb:gc:p:s:tR:L:l:S:F:a:x:Xnfvo:PT:N")) != EOF
)
1332 case 'h': /* help */
1336 secs_to_run
= argtoi('S', "decimal number", optarg
, 10);
1338 case 'a': /* set tracing on a pid */
1340 pid
= argtoi('a', "decimal number", optarg
, 10);
1342 case 'x': /* exclude a pid from tracing */
1344 pid
= argtoi('x', "decimal number", optarg
, 10);
1356 signal(SIGINT
, signal_handler_RAW
);
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);
1381 fprintf(stderr
, "A maximum of four values can be specified with -k\n");
1407 nbufs
= argtoi('b', "decimal number", optarg
, 10);
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
);
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
);
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
);
1437 output_filename
= optarg
;
1440 frequency
= argtoi('F', "decimal number", optarg
, 10);
1445 no_default_codes_flag
= 1;
1450 // Flush out any unclosed -c argument
1451 filter_done_parsing();
1453 parse_filter_file(optarg
);
1461 if (!no_default_codes_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");
1474 const char *cfile
= argv
[optind
++];
1475 if (verbose_flag
) printf("Adding code file %s \n", cfile
);
1476 parse_codefile(cfile
);
1483 quit_args("-E flag needs an executable to launch\n");
1491 if (pid_flag
&& pid_exflag
)
1492 quit_args("Can't use both -a and -x flag together\n");
1494 if (kval_flag
&& filter_flag
)
1495 quit_args("Cannot use -k flag with -c, -s, or -p\n");
1497 if (output_filename
&& !trace_flag
&& !readRAW_flag
)
1498 quit_args("When using 'o' option, must use the 't' or 'R' option too\n");
1500 filter_done_parsing();
1505 get_bufinfo(&bufinfo
);
1507 if (bufinfo
.nolog
== 0)
1508 use_current_buf
= 1;
1515 set_pidcheck(pid
, 0); /* disable pid check for given pid */
1518 else if (pid_exflag
)
1520 set_pidexclude(pid
, 0); /* disable pid exclusion for given pid */
1535 if (!init_flag
&& !LogRAW_flag
)
1537 fprintf(stderr
,"The -b flag must be used with the -i flag\n");
1551 get_bufinfo(&bufinfo
);
1553 printf("The kernel buffer settings are:\n");
1555 if (bufinfo
.flags
& KDBG_BUFINIT
)
1556 printf("\tKernel buffer is initialized\n");
1558 printf("\tKernel buffer is not initialized\n");
1560 printf("\t number of buf entries = %d\n", bufinfo
.nkdbufs
);
1564 if (bufinfo
.flags
& KDBG_MAPINIT
)
1565 printf("\tKernel thread map is initialized\n");
1567 printf("\tKernel thread map is not initialized\n");
1568 printf("\t number of thread entries = %d\n", bufinfo
.nkdthreads
);
1572 printf("\tBuffer logging is disabled\n");
1574 printf("\tBuffer logging is enabled\n");
1577 printf("\tkernel flags = 0x%x\n", bufinfo
.flags
);
1579 if (bufinfo
.flags
& KDBG_NOWRAP
)
1580 printf("\tKernel buffer wrap is disabled\n");
1582 printf("\tKernel buffer wrap is enabled\n");
1584 if (bufinfo
.flags
& KDBG_RANGECHECK
)
1585 printf("\tCollection within a range is enabled\n");
1587 printf("\tCollection within a range is disabled\n");
1589 if (bufinfo
.flags
& KDBG_VALCHECK
)
1590 printf("\tCollecting specific code values is enabled\n");
1592 printf("\tCollecting specific code values is disabled\n");
1594 if (bufinfo
.flags
& KDBG_TYPEFILTER_CHECK
)
1595 printf("\tCollection based on a filter is enabled\n");
1597 printf("\tCollection based on a filter is disabled\n");
1599 if (bufinfo
.flags
& KDBG_PIDCHECK
)
1600 printf("\tCollection based on pid is enabled\n");
1602 printf("\tCollection based on pid is disabled\n");
1604 if (bufinfo
.flags
& KDBG_PIDEXCLUDE
)
1605 printf("\tCollection based on pid exclusion is enabled\n");
1607 printf("\tCollection based on pid exclusion is disabled\n");
1609 if (bufinfo
.bufid
== -1)
1610 printf("\tKernel buffer is not controlled by any process.\n");
1612 printf("\tKernel buffer is controlled by proc id [%d]\n", bufinfo
.bufid
);
1626 fprintf(stderr
, "Starting program: %s\n", argv
[optind
]);
1630 switch ((pid
= vfork()))
1637 ptrace(PT_TRACE_ME
, 0, (caddr_t
)0, 0);
1638 execve(argv
[optind
], &argv
[optind
], environ
);
1644 signal(SIGINT
, signal_handler
);
1645 set_pidcheck(pid
, 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 */
1652 else if (enable_flag
)
1655 set_pidcheck(pid
, 1);
1656 else if (pid_exflag
)
1657 set_pidexclude(pid
, 1);
1661 if (output_filename
)
1663 if (((output_fd
= open(output_filename
, O_CREAT
| O_TRUNC
| O_WRONLY
| O_APPEND
, 0644)) < 0 ) ||
1664 !(output_file
= fdopen(output_fd
, "w")))
1666 fprintf(stderr
, "Cannot open file \"%s\" for writing.\n", output_filename
);
1669 setbuffer(output_file
, &sbuffer
[0], SBUFFER_SIZE
);
1671 if (fcntl(output_fd
, F_NOCACHE
, 1) < 0)
1674 fprintf(stderr
, "Warning: setting F_NOCACHE on %s, failed\n", output_filename
);
1677 if (!LogRAW_flag
&& !logRAW_flag
)
1678 setbuffer(output_file
, &sbuffer
[0], SBUFFER_SIZE
);
1680 if (trace_flag
|| readRAW_flag
)
1682 else if (LogRAW_flag
)
1684 else if (logRAW_flag
)
1692 quit_args(const char *fmt
, ...)
1699 set_enable(1); /* re-enable kernel logging */
1704 va_start (args
, fmt
);
1705 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
1707 fprintf(stderr
, "trace error: %s", buffer
);
1711 if (!done_with_args
)
1724 set_enable(1); /* re-enable kernel logging */
1734 usage(int short_help
)
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");
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");
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");
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");
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");
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");
1785 (void)fprintf(stderr
, "usage: trace -g\n");
1786 (void)fprintf(stderr
, "\tGet the kernel buffer settings.\n\n");
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");
1793 (void)fprintf(stderr
, "usage: trace -r\n");
1794 (void)fprintf(stderr
, "\tRemove the kernel trace buffer. Set controls to default.\n\n");
1796 (void)fprintf(stderr
, "usage: trace -n\n");
1797 (void)fprintf(stderr
, "\tDisables kernel buffer wrap around.\n\n");
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");
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");
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");
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");
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");
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");
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");
1865 (void)fprintf(stderr
,
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"
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"
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"
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"
1893 "\t File syntax: \n"
1894 "\t Class filter: \n"
1896 "\t Subclass filter (includes class): \n"
1899 "\t # This is a comment \n\n"
1901 "\t For example, to trace Mach events (class 1):\n"
1903 "\t or to trace Mach system calls (class 1 subclass 13): \n"
1913 argtoi(flag
, req
, str
, base
)
1921 ret
= (int)strtol(str
, &cp
, base
);
1922 if (cp
== str
|| *cp
)
1923 errx(EINVAL
, "-%c flag requires a %s", flag
, req
);
1928 static unsigned long
1929 argtoul(flag
, req
, str
, base
)
1937 ret
= (int)strtoul(str
, &cp
, base
);
1938 if (cp
== str
|| *cp
)
1939 errx(EINVAL
, "-%c flag requires a %s", flag
, req
);
1945 * comparison function for qsort
1948 int debugid_compar(p1
, p2
)
1952 if (p1
->debugid
> p2
->debugid
)
1954 else if (p1
->debugid
== p2
->debugid
)
1962 * Filter args parsing state machine:
1968 * every -c goes back to start
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)
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
1986 // What type of flag did I last see?
1990 FILTER_MODE_CLASS_RANGE
,
1991 FILTER_MODE_SUBCLASS
1992 } filter_mode
= FILTER_MODE_START
;
1994 uint8_t filter_current_class
= 0;
1995 uint8_t filter_current_subclass
= 0;
1996 uint8_t filter_current_class_range
= 0;
1999 saw_filter_class(uint8_t class)
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
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;
2021 quit_args("invalid case in saw_filter_class\n");
2026 saw_filter_end_range(uint8_t end_class
)
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
);
2034 case FILTER_MODE_START
:
2035 quit_args("must provide '-c class' before '-p 0x%x'\n",
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
);
2048 quit_args("invalid case in saw_filter_end_range\n");
2053 saw_filter_subclass(uint8_t subclass
)
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
);
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
);
2072 quit_args("invalid case in saw_filter_subclass\n");
2077 filter_done_parsing(void)
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;
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;
2097 quit_args("invalid case in filter_done_parsing\n");
2101 /* Tell set_filter_subclass not to print every. single. subclass. */
2102 static boolean_t setting_class
= FALSE
;
2103 static boolean_t setting_range
= FALSE
;
2106 set_filter_subclass(uint8_t class, uint8_t subclass
)
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");
2115 uint16_t csc
= ENCODE_CSC_LOW(class, subclass
);
2117 if (verbose_flag
&& !setting_class
)
2118 printf("tracing subclass: 0x%4.4x\n", csc
);
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
);
2124 setbit(type_filter_bitmap
, csc
);
2128 set_filter_class(uint8_t class)
2130 if (verbose_flag
&& !setting_range
)
2131 printf("tracing class: 0x%2.2x\n", class);
2133 setting_class
= TRUE
;
2135 for (int i
= 0; i
< 256; i
++)
2136 set_filter_subclass(class, i
);
2138 setting_class
= FALSE
;
2142 set_filter_range(uint8_t class, uint8_t end
)
2145 printf("tracing range: 0x%2.2x - 0x%2.2x\n", class, end
);
2147 setting_range
= TRUE
;
2149 for (int i
= class; i
<= end
; i
++)
2150 set_filter_class(i
);
2152 setting_range
= FALSE
;
2156 * Syntax of filter file:
2157 * Hexadecimal numbers only
2160 * Subclass (includes class):
2164 * TBD: Class ranges?
2165 * TBD: K for -k flag?
2169 parse_filter_file(char *filename
) {
2171 uint32_t current_line
= 0;
2172 uint32_t parsed_arg
= 0;
2177 if ( (file
= fopen(filename
, "r")) == NULL
) {
2178 quit_args("Failed to open filter description file %s: %s\n",
2179 filename
, strerror(errno
));
2183 printf("Parsing typefilter file: %s\n", filename
);
2185 while( fgets(line
, sizeof(line
), file
) != NULL
) {
2190 rval
= sscanf(line
, "C 0x%x\n", &parsed_arg
);
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"
2197 "class value must be 0x0-0xFF\n",
2198 current_line
, filename
, line
, parsed_arg
);
2199 set_filter_class((uint8_t)parsed_arg
);
2202 rval
= sscanf(line
, "S 0x%x\n", &parsed_arg
);
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"
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
));
2224 quit_args("Invalid filter description file: %s\n"
2225 "could not parse line %d: %s\n",
2226 filename
, current_line
, line
);
2235 * Find the debugid code in the list and return its index
2237 static int binary_search(list
, lowbound
, highbound
, code
)
2239 int lowbound
, highbound
;
2250 mid
= (low
+ high
) / 2;
2255 return (-1); /* failed */
2256 else if ( low
+ 1 >= high
)
2258 /* We have a match */
2259 if (list
[high
].debugid
== code
)
2261 else if (list
[low
].debugid
== code
)
2264 return(-1); /* search failed */
2266 else if (code
< list
[mid
].debugid
)
2275 parse_codefile(const char *filename
)
2280 struct stat stat_buf
;
2281 unsigned long file_size
;
2282 char *file_addr
, *endp
;
2284 if ((fd
= open(filename
, O_RDONLY
, 0)) == -1)
2286 printf("Failed to open code description file %s\n",filename
);
2290 if (fstat(fd
, &stat_buf
) == -1)
2292 printf("Error: Can't fstat file: %s\n", filename
);
2297 * For some reason mapping files with zero size fails
2298 * so it has to be handled specially.
2300 file_size
= stat_buf
.st_size
;
2302 if (stat_buf
.st_size
!= 0)
2304 if ((file_addr
= mmap(0, stat_buf
.st_size
, PROT_READ
|PROT_WRITE
,
2305 MAP_PRIVATE
|MAP_FILE
, fd
, 0)) == (char*) -1)
2307 printf("Error: Can't map file: %s\n", filename
);
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.
2327 for (count
= 0, j
=1; j
< file_size
; j
++)
2329 if (file_addr
[j
] == '\n')
2335 printf("Error: No codes in %s\n", filename
);
2340 * Fudge the count to accomodate the last line in the file -
2341 * in case it doesn't end in a newline.
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
));
2349 if (new_codesc
== NULL
) {
2350 printf("Failed to grow/allocate buffer. Skipping file %s\n", filename
);
2353 codesc
= new_codesc
;
2354 bzero((char *)(codesc
+ codesc_idx
), count
* sizeof(code_type_t
));
2356 for (line
= 1, j
= 0; j
< file_size
&& codesc_idx
< total_count
; codesc_idx
++)
2358 /* Skip blank lines */
2359 while (file_addr
[j
] == '\n')
2365 /* Skip leading whitespace */
2366 while (file_addr
[j
] == ' ' || file_addr
[j
] == '\t')
2369 /* Get the debugid code */
2370 codesc
[codesc_idx
].debugid
= strtoul(file_addr
+ j
, &endp
, 16);
2371 j
= endp
- file_addr
;
2373 if (codesc
[codesc_idx
].debugid
== 0)
2375 /* We didn't find a debugid code - skip this line */
2377 printf("Error: while parsing line %d, skip\n", line
);
2378 while (file_addr
[j
] != '\n' && j
< file_size
)
2385 /* Skip whitespace */
2386 while (file_addr
[j
] == ' ' || file_addr
[j
] == '\t')
2389 /* Get around old file that had count at the beginning */
2390 if (file_addr
[j
] == '\n')
2392 /* missing debugid string - skip */
2394 printf("Error: while parsing line %d, (0x%x) skip\n", line
, codesc
[codesc_idx
].debugid
);
2402 /* Next is the debugid string terminated by a newline */
2403 codesc
[codesc_idx
].debug_string
= &file_addr
[j
];
2405 /* Null out the newline terminator */
2406 while ((j
< file_size
) && (file_addr
[j
] != '\n'))
2408 file_addr
[j
] = '\0'; /* File must be read-write */
2411 codenum
++; /*Index into codesc is 0 to codenum-1 */
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
);
2422 qsort((void *)codesc
, codesc_idx
, sizeof(code_type_t
), debugid_compar
);
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
);
2430 codesc_find_dupes();
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
);
2440 static void codesc_find_dupes(void)
2442 boolean_t found_dupes
= FALSE
;
2443 if (codesc_idx
== 0)
2447 uint32_t last_debugid
= codesc
[0].debugid
;
2448 for(int i
= 1; i
< codesc_idx
; i
++)
2450 if(codesc
[i
].debugid
== last_debugid
)
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
);
2457 last_debugid
= codesc
[i
].debugid
;
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");
2466 int match_debugid(unsigned int xx
, char * debugstr
, int * yy
)
2473 if (codesc
[codeindx_cache
].debugid
!= xx
)
2474 indx
= binary_search(codesc
, 0, (codenum
-1), xx
);
2476 indx
= codeindx_cache
;
2479 return(indx
); /* match failed */
2481 bcopy(&codesc
[indx
].debug_string
[0], debugstr
,80);
2483 codeindx_cache
= indx
;
2484 return(0); /* match success */
2489 read_cpu_map(int fd
)
2491 if (cpumap_header
) {
2492 free(cpumap_header
);
2493 cpumap_header
= NULL
;
2498 * To fit in the padding space of a VERSION1 file, the max possible
2499 * cpumap size is one page.
2501 cpumap_header
= malloc(PAGE_SIZE
);
2505 * cpu maps exist in a RAW_VERSION1+ header only
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> */
2511 size_t padding_bytes
= (size_t)(aligned_offset
- base_offset
);
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];
2523 mib
[1] = KERN_KDEBUG
;
2524 mib
[2] = KERN_KDCPUMAP
;
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];
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
);
2551 read_command_map(int fd
, uint32_t count
)
2558 total_threads
= count
;
2559 size
= count
* sizeof(kd_threadmap
);
2561 get_bufinfo(&bufinfo
);
2563 total_threads
= bufinfo
.nkdthreads
;
2564 size
= bufinfo
.nkdthreads
* sizeof(kd_threadmap
);
2567 nthreads
= total_threads
* 2;
2570 printf("Size of map table is %d, thus %d entries\n", (int)size
, total_threads
);
2573 if ((mapptr
= (kd_threadmap
*) malloc(size
)))
2574 bzero (mapptr
, size
);
2578 printf("Thread map is not initialized -- this is not fatal\n");
2583 if (read(fd
, mapptr
, size
) != size
) {
2585 printf("Can't read the thread map -- this is not fatal\n");
2592 /* Now read the threadmap */
2594 mib
[1] = KERN_KDEBUG
;
2595 mib
[2] = KERN_KDTHRMAP
;
2598 mib
[5] = 0; /* no flags */
2599 if (sysctl(mib
, 3, mapptr
, &size
, NULL
, 0) < 0)
2601 /* This is not fatal -- just means I cant map command strings */
2603 printf("Can't read the thread map -- this is not fatal\n");
2609 for (i
= 0; i
< total_threads
; i
++) {
2610 if (mapptr
[i
].thread
)
2611 create_map_entry(mapptr
[i
].thread
, &mapptr
[i
].command
[0]);
2615 /* Dump the initial map */
2617 printf("Size of maptable returned is %ld, thus %ld entries\n", size
, (size
/sizeof(kd_threadmap
)));
2619 printf("Thread Command\n");
2620 for (i
= 0; i
< total_threads
; i
++) {
2621 printf ("0x%lx %s\n",
2630 void create_map_entry(uintptr_t thread
, char *command
)
2635 if ((tme
= threadmap_freelist
))
2636 threadmap_freelist
= tme
->tm_next
;
2638 tme
= (threadmap_t
)malloc(sizeof(struct threadmap
));
2640 tme
->tm_thread
= thread
;
2641 tme
->tm_deleteme
= FALSE
;
2643 (void)strncpy (tme
->tm_command
, command
, MAXCOMLEN
);
2644 tme
->tm_command
[MAXCOMLEN
] = '\0';
2646 hashid
= thread
& HASH_MASK
;
2648 tme
->tm_next
= threadmap_hash
[hashid
];
2649 threadmap_hash
[hashid
] = tme
;
2653 void delete_thread_entry(uintptr_t thread
)
2655 threadmap_t tme
= 0;
2656 threadmap_t tme_prev
;
2659 hashid
= thread
& HASH_MASK
;
2661 if ((tme
= threadmap_hash
[hashid
])) {
2662 if (tme
->tm_thread
== thread
)
2663 threadmap_hash
[hashid
] = tme
->tm_next
;
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
;
2676 tme
->tm_next
= threadmap_freelist
;
2677 threadmap_freelist
= tme
;
2683 void find_and_insert_tmp_map_entry(uintptr_t pthread
, char *command
)
2685 threadmap_t tme
= 0;
2686 threadmap_t tme_prev
;
2689 if ((tme
= threadmap_temp
)) {
2690 if (tme
->tm_pthread
== pthread
)
2691 threadmap_temp
= tme
->tm_next
;
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
;
2704 (void)strncpy (tme
->tm_command
, command
, MAXCOMLEN
);
2705 tme
->tm_command
[MAXCOMLEN
] = '\0';
2707 delete_thread_entry(tme
->tm_thread
);
2709 hashid
= tme
->tm_thread
& HASH_MASK
;
2711 tme
->tm_next
= threadmap_hash
[hashid
];
2712 threadmap_hash
[hashid
] = tme
;
2718 void create_tmp_map_entry(uintptr_t thread
, uintptr_t pthread
)
2722 if ((tme
= threadmap_freelist
))
2723 threadmap_freelist
= tme
->tm_next
;
2725 tme
= (threadmap_t
)malloc(sizeof(struct threadmap
));
2727 tme
->tm_thread
= thread
;
2728 tme
->tm_pthread
= pthread
;
2729 tme
->tm_deleteme
= FALSE
;
2730 tme
->tm_command
[0] = '\0';
2732 tme
->tm_next
= threadmap_temp
;
2733 threadmap_temp
= tme
;
2738 find_thread_entry(uintptr_t thread
)
2743 hashid
= thread
& HASH_MASK
;
2745 for (tme
= threadmap_hash
[hashid
]; tme
; tme
= tme
->tm_next
) {
2746 if (tme
->tm_thread
== thread
)
2753 void find_thread_name(uintptr_t thread
, char **command
, boolean_t deleteme
)
2757 if ((tme
= find_thread_entry(thread
))) {
2758 *command
= tme
->tm_command
;
2760 if (deleteme
== TRUE
)
2761 tme
->tm_deleteme
= deleteme
;
2763 *command
= EMPTYSTRING
;
2767 void find_thread_command(kd_buf
*kbufp
, char **command
)
2773 thread
= kbufp
->arg5
;
2774 debugid_base
= kbufp
->debugid
& DBG_FUNC_MASK
;
2776 if (debugid_base
== BSC_exit
|| debugid_base
== MACH_STKHANDOFF
) {
2778 * Mark entry as invalid and return temp command pointer
2780 if ((tme
= find_thread_entry(thread
))) {
2782 strncpy(tmpcommand
, tme
->tm_command
, MAXCOMLEN
);
2783 *command
= tmpcommand
;
2785 if (debugid_base
== BSC_exit
|| tme
->tm_deleteme
== TRUE
)
2786 delete_thread_entry(thread
);
2788 *command
= EMPTYSTRING
;
2790 else if (debugid_base
== TRACE_DATA_NEWTHREAD
) {
2792 * Save the create thread data
2794 create_tmp_map_entry(kbufp
->arg1
, kbufp
->arg5
);
2796 else if (debugid_base
== TRACE_STRING_NEWTHREAD
) {
2798 * process new map entry
2800 find_and_insert_tmp_map_entry(kbufp
->arg5
, (char *)&kbufp
->arg1
);
2802 else if (debugid_base
== TRACE_STRING_EXEC
) {
2804 delete_thread_entry(kbufp
->arg5
);
2806 create_map_entry(kbufp
->arg5
, (char *)&kbufp
->arg1
);
2809 find_thread_name(thread
, command
, (debugid_base
== BSC_thread_terminate
));
2816 mach_timebase_info_data_t info
;
2818 if (frequency
== 0) {
2819 (void) mach_timebase_info (&info
);
2821 divisor
= ( (double)info
.denom
/ (double)info
.numer
) * 1000;
2823 divisor
= (double)frequency
/ 1000000;
2826 printf("divisor = %g\n", divisor
);