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>
38 #ifndef KERNEL_PRIVATE
39 #define KERNEL_PRIVATE
40 #include <sys/kdebug.h>
43 #include <sys/kdebug.h>
44 #endif /*KERNEL_PRIVATE*/
45 #include <sys/param.h>
47 #include <mach/mach.h>
48 #include <mach/mach_time.h>
64 int filter_file_flag
=0;
75 int no_default_codes_flag
=0;
77 unsigned int value1
=0;
78 unsigned int value2
=0;
79 unsigned int value3
=0;
80 unsigned int value4
=0;
85 int force_32bit_exec
= 0;
91 char *logfile
= (char *)0; /* This file is trace format */
92 char *RAW_file
= (char *)0;
96 extern char **environ
;
98 uint8_t* type_filter_bitmap
;
100 #define SIZE_4KB (4 * (1 << 10))
102 #define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
103 #define DBG_FUNC_MASK 0xfffffffc
107 #define CSC_MASK 0xffff0000
109 #define VFS_LOOKUP 0x03010090
110 #define BSC_exit 0x040c0004
111 #define BSC_thread_terminate 0x040c05a4
112 #define TRACE_DATA_NEWTHREAD 0x07000004
113 #define TRACE_STRING_NEWTHREAD 0x07010004
114 #define TRACE_STRING_EXEC 0x07010008
115 #define TRACE_LOST_EVENTS 0x07020008
116 #define TRACE_INFO_STRING 0x07020010
117 #define MACH_SCHEDULED 0x01400000
118 #define MACH_MAKERUNNABLE 0x01400018
119 #define MACH_STKHANDOFF 0x01400008
121 #define EMPTYSTRING ""
122 #define UNKNOWN "unknown"
124 char tmpcommand
[MAXCOMLEN
];
126 int total_threads
= 0;
128 kd_threadmap
*mapptr
= 0;
130 kd_cpumap_header
* cpumap_header
= NULL
;
131 kd_cpumap
* cpumap
= NULL
;
134 If NUMPARMS changes from the kernel,
135 then PATHLENGTH will also reflect the change
136 This is for the vfslookup entries that
140 #define PATHLENGTH (NUMPARMS*sizeof(long))
143 #define US_TO_SLEEP 50000
144 #define BASE_EVENTS 500000
154 code_type_t
* codesc
= 0;
155 size_t codesc_idx
= 0; // Index into first empty codesc entry
159 typedef struct event
*event_t
;
166 uint64_t ev_timestamp
;
169 typedef struct lookup
*lookup_t
;
177 long lk_pathname
[NUMPARMS
+ 1];
180 typedef struct threadmap
*threadmap_t
;
186 uintptr_t tm_pthread
;
187 boolean_t tm_deleteme
;
188 char tm_command
[MAXCOMLEN
+ 1];
191 #define HASH_SIZE 1024
192 #define HASH_MASK 1023
194 event_t event_hash
[HASH_SIZE
];
195 lookup_t lookup_hash
[HASH_SIZE
];
196 threadmap_t threadmap_hash
[HASH_SIZE
];
198 event_t event_freelist
;
199 lookup_t lookup_freelist
;
200 threadmap_t threadmap_freelist
;
201 threadmap_t threadmap_temp
;
204 #define SBUFFER_SIZE (128 * 4096)
205 char sbuffer
[SBUFFER_SIZE
];
208 int use_current_buf
= 0;
211 kbufinfo_t bufinfo
= {0, 0, 0, 0};
214 int codeindx_cache
= 0;
216 static void quit(char *);
217 static int match_debugid(unsigned int, char *, int *);
218 static void usage(int short_help
);
219 static int argtoi(int flag
, char *req
, char *str
, int base
);
220 static int parse_codefile(const char *filename
);
221 static void codesc_find_dupes(void);
222 static int read_command_map(int, uint32_t);
223 static void read_cpu_map(int);
224 static void find_thread_command(kd_buf
*, char **);
225 static void create_map_entry(uintptr_t, char *);
226 static void getdivisor();
227 static unsigned long argtoul();
229 static void set_enable(int);
230 static void set_remove();
231 static void set_nowrap();
232 static void set_pidcheck(int, int);
233 static void set_pidexclude(int, int);
234 static void set_numbufs(int);
235 static void set_freerun();
236 static void get_bufinfo(kbufinfo_t
*);
237 static void set_init();
238 static void set_kval_list();
239 static void readtrace(char *);
240 static void log_trace();
241 static void Log_trace();
242 static void read_trace();
243 static void signal_handler(int);
244 static void signal_handler_RAW(int);
245 static void delete_thread_entry(uintptr_t);
246 static void find_and_insert_tmp_map_entry(uintptr_t, char *);
247 static void create_tmp_map_entry(uintptr_t, uintptr_t);
248 static void find_thread_name(uintptr_t, char **, boolean_t
);
249 static void execute_process(char * const argv
[]);
251 static int writetrace(int);
252 static int write_command_map(int);
253 static int debugid_compar(code_type_t
*, code_type_t
*);
255 static threadmap_t
find_thread_entry(uintptr_t);
257 static void saw_filter_class(uint8_t class);
258 static void saw_filter_end_range(uint8_t end_class
);
259 static void saw_filter_subclass(uint8_t subclass
);
260 static void filter_done_parsing(void);
262 static void set_filter(void);
263 static void set_filter_class(uint8_t class);
264 static void set_filter_range(uint8_t class, uint8_t end
);
265 static void set_filter_subclass(uint8_t class, uint8_t subclass
);
267 static void parse_filter_file(char *filename
);
269 static void quit_args(const char *fmt
, ...) __printflike(1, 2);
271 #ifndef KERN_KDWRITETR
272 #define KERN_KDWRITETR 17
275 #ifndef KERN_KDWRITEMAP
276 #define KERN_KDWRITEMAP 18
280 #define F_FLUSH_DATA 40
291 #define RAW_VERSION0 0x55aa0000
292 #define RAW_VERSION1 0x55aa0101
295 #define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(*x)))
297 #define EXTRACT_CLASS_LOW(debugid) ( (uint8_t) ( ((debugid) & 0xFF00 ) >> 8 ) )
298 #define EXTRACT_SUBCLASS_LOW(debugid) ( (uint8_t) ( ((debugid) & 0xFF ) ) )
300 #define ENCODE_CSC_LOW(class, subclass) \
301 ( (uint16_t) ( ((class) & 0xff) << 8 ) | ((subclass) & 0xff) )
303 RAW_header raw_header
;
307 void set_enable(int val
)
310 mib
[1] = KERN_KDEBUG
;
311 mib
[2] = KERN_KDENABLE
;
312 #ifdef KDEBUG_ENABLE_PPT
313 if (ppt_flag
&& val
) {
314 mib
[3] = KDEBUG_ENABLE_PPT
;
323 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0) {
324 if (errno
== EINVAL
) {
325 quit_args("trace facility failure, KERN_KDENABLE: trace buffer is uninitialized\n");
327 quit_args("trace facility failure, KERN_KDENABLE: %s\n", strerror(errno
));
338 mib
[1] = KERN_KDEBUG
;
339 mib
[2] = KERN_KDREMOVE
;
343 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
346 quit("the trace facility is currently in use...\n fs_usage, sc_usage, trace, and latency use this feature.\n\n");
348 quit_args("trace facility failure, KERN_KDREMOVE: %s\n", strerror(errno
));
352 void set_numbufs(int nbufs
)
355 mib
[1] = KERN_KDEBUG
;
356 mib
[2] = KERN_KDSETBUF
;
360 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
361 quit_args("trace facility failure, KERN_KDSETBUF: %s\n", strerror(errno
));
364 mib
[1] = KERN_KDEBUG
;
365 mib
[2] = KERN_KDSETUP
;
369 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
370 quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno
));
376 mib
[1] = KERN_KDEBUG
;
377 mib
[2] = KERN_KDEFLAGS
;
378 mib
[3] = KDBG_NOWRAP
;
380 mib
[5] = 0; /* no flags */
381 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
382 quit_args("trace facility failure, KDBG_NOWRAP: %s\n", strerror(errno
));
386 void set_pidcheck(int pid
, int on_off_flag
)
390 kr
.type
= KDBG_TYPENONE
;
392 kr
.value2
= on_off_flag
;
393 needed
= sizeof(kd_regtype
);
395 mib
[1] = KERN_KDEBUG
;
396 mib
[2] = KERN_KDPIDTR
;
400 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
404 quit_args("trace facility failure, setting pid filter: %s\n",
407 else if (on_off_flag
== 1 && errno
== ESRCH
)
410 quit_args("trace facility failure, setting pid filter: "
411 "pid %d does not exist\n", pid
);
415 quit_args("trace facility failure, KERN_KDPIDTR: %s\n", strerror(errno
));
420 void set_pidexclude(int pid
, int on_off_flag
)
424 kr
.type
= KDBG_TYPENONE
;
426 kr
.value2
= on_off_flag
;
427 needed
= sizeof(kd_regtype
);
429 mib
[1] = KERN_KDEBUG
;
430 mib
[2] = KERN_KDPIDEX
;
434 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
436 if (on_off_flag
== 1)
438 printf ("pid %d does not exist\n", pid
);
448 mib
[1] = KERN_KDEBUG
;
449 mib
[2] = KERN_KDEFLAGS
;
450 mib
[3] = KDBG_FREERUN
;
453 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
454 quit_args("trace facility failure, KDBG_FREERUN: %s\n", strerror(errno
));
457 void get_bufinfo(kbufinfo_t
*val
)
459 needed
= sizeof (*val
);
461 mib
[1] = KERN_KDEBUG
;
462 mib
[2] = KERN_KDGETBUF
;
466 if (sysctl(mib
, 3, val
, &needed
, 0, 0) < 0)
467 quit_args("trace facility failure, KERN_KDGETBUF: %s\n", strerror(errno
));
474 kr
.type
= KDBG_RANGETYPE
;
477 needed
= sizeof(kd_regtype
);
479 mib
[1] = KERN_KDEBUG
;
480 mib
[2] = KERN_KDSETREG
;
484 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
485 quit_args("trace facility failure, KERN_KDSETREG (rangetype): %s\n", strerror(errno
));
488 mib
[1] = KERN_KDEBUG
;
489 mib
[2] = KERN_KDSETUP
;
493 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
494 quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno
));
502 int mib
[] = { CTL_KERN
, KERN_KDEBUG
, KERN_KDSET_TYPEFILTER
};
503 size_t needed
= KDBG_TYPEFILTER_BITMAP_SIZE
;
505 if(sysctl(mib
, ARRAYSIZE(mib
), type_filter_bitmap
, &needed
, NULL
, 0)) {
506 quit_args("trace facility failure, KERN_KDSET_TYPEFILTER: %s\n", strerror(errno
));
514 kr
.type
= KDBG_VALCHECK
;
519 needed
= sizeof(kd_regtype
);
521 mib
[1] = KERN_KDEBUG
;
522 mib
[2] = KERN_KDSETREG
;
526 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
527 quit_args("trace facility failure, KERN_KDSETREG (valcheck): %s\n", strerror(errno
));
531 void readtrace(char *buffer
)
534 mib
[1] = KERN_KDEBUG
;
535 mib
[2] = KERN_KDREADTR
;
540 if (sysctl(mib
, 3, buffer
, &needed
, NULL
, 0) < 0)
541 quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno
));
545 int writetrace(int fd
)
548 mib
[1] = KERN_KDEBUG
;
549 mib
[2] = KERN_KDWRITETR
;
554 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
561 int write_command_map(int fd
)
564 mib
[1] = KERN_KDEBUG
;
565 mib
[2] = KERN_KDWRITEMAP
;
570 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
578 lookup_t
handle_lookup_event(uintptr_t thread
, int debugid
, kd_buf
*kdp
)
582 boolean_t first_record
= FALSE
;
584 hashid
= thread
& HASH_MASK
;
586 if (debugid
& DBG_FUNC_START
)
589 for (lkp
= lookup_hash
[hashid
]; lkp
; lkp
= lkp
->lk_next
) {
590 if (lkp
->lk_thread
== thread
)
594 if (first_record
== FALSE
)
597 if ((lkp
= lookup_freelist
))
598 lookup_freelist
= lkp
->lk_next
;
600 lkp
= (lookup_t
)malloc(sizeof(struct lookup
));
602 lkp
->lk_thread
= thread
;
604 lkp
->lk_next
= lookup_hash
[hashid
];
605 lookup_hash
[hashid
] = lkp
;
608 if (first_record
== TRUE
) {
609 lkp
->lk_pathptr
= lkp
->lk_pathname
;
610 lkp
->lk_dvp
= kdp
->arg1
;
612 if (lkp
->lk_pathptr
> &lkp
->lk_pathname
[NUMPARMS
-4])
615 *lkp
->lk_pathptr
++ = kdp
->arg1
;
617 *lkp
->lk_pathptr
++ = kdp
->arg2
;
618 *lkp
->lk_pathptr
++ = kdp
->arg3
;
619 *lkp
->lk_pathptr
++ = kdp
->arg4
;
620 *lkp
->lk_pathptr
= 0;
627 void delete_lookup_event(uintptr_t thread
, lookup_t lkp_to_delete
)
633 hashid
= thread
& HASH_MASK
;
635 if ((lkp
= lookup_hash
[hashid
])) {
636 if (lkp
== lkp_to_delete
)
637 lookup_hash
[hashid
] = lkp
->lk_next
;
641 for (lkp
= lkp
->lk_next
; lkp
; lkp
= lkp
->lk_next
) {
642 if (lkp
== lkp_to_delete
) {
643 lkp_prev
->lk_next
= lkp
->lk_next
;
650 lkp
->lk_next
= lookup_freelist
;
651 lookup_freelist
= lkp
;
658 void insert_start_event(uintptr_t thread
, int debugid
, uint64_t now
)
663 hashid
= thread
& HASH_MASK
;
665 for (evp
= event_hash
[hashid
]; evp
; evp
= evp
->ev_next
) {
666 if (evp
->ev_thread
== thread
&& evp
->ev_debugid
== debugid
)
670 if ((evp
= event_freelist
))
671 event_freelist
= evp
->ev_next
;
673 evp
= (event_t
)malloc(sizeof(struct event
));
675 evp
->ev_thread
= thread
;
676 evp
->ev_debugid
= debugid
;
678 evp
->ev_next
= event_hash
[hashid
];
679 event_hash
[hashid
] = evp
;
681 evp
->ev_timestamp
= now
;
686 uint64_t consume_start_event(uintptr_t thread
, int debugid
, uint64_t now
)
691 uint64_t elapsed
= 0;
693 hashid
= thread
& HASH_MASK
;
695 if ((evp
= event_hash
[hashid
])) {
696 if (evp
->ev_thread
== thread
&& evp
->ev_debugid
== debugid
)
697 event_hash
[hashid
] = evp
->ev_next
;
701 for (evp
= evp
->ev_next
; evp
; evp
= evp
->ev_next
) {
703 if (evp
->ev_thread
== thread
&& evp
->ev_debugid
== debugid
) {
704 evp_prev
->ev_next
= evp
->ev_next
;
711 elapsed
= now
- evp
->ev_timestamp
;
713 evp
->ev_next
= event_freelist
;
714 event_freelist
= evp
;
727 uint32_t buffer_size
= 1000000 * sizeof(kd_buf
);
729 fd
= open(logfile
, O_TRUNC
| O_WRONLY
| O_CREAT
, 0777);
731 perror("Can't open logfile");
734 get_bufinfo(&bufinfo
);
736 if (bufinfo
.nolog
!= 1) {
738 set_enable(0); /* disable logging*/
740 get_bufinfo(&bufinfo
);
743 if (bufinfo
.flags
& KDBG_WRAPPED
)
744 printf("Buffer has wrapped\n");
746 printf("Buffer has not wrapped\n");
749 ret
= write_command_map(fd
);
752 perror("failed to write logfile");
756 buffer
= malloc(buffer_size
);
757 if (buffer
== NULL
) {
758 quit("can't allocate memory for events\n");
762 needed
= buffer_size
;
770 write(fd
, buffer
, needed
* sizeof(kd_buf
));
786 int try_writetrace
= 1;
790 uint64_t sample_window_abs
;
791 uint64_t next_window_begins
;
792 uint64_t current_abs
;
793 uint64_t ending_abstime
;
794 uint64_t last_time_written
;
795 uint32_t us_to_sleep
;
796 uint32_t us_to_adjust
;
799 memset(&kd_tmp
, 0, sizeof(kd_tmp
));
801 if ((fd
= open(logfile
, O_TRUNC
|O_WRONLY
|O_CREAT
, 0777)) == -1) {
802 perror("Can't open logfile");
805 if (use_current_buf
== 0) {
807 * grab the number of cpus and scale the buffer size
812 len
= sizeof(num_cpus
);
814 sysctl(mib
, 2, &num_cpus
, &len
, NULL
, 0);
817 nbufs
= BASE_EVENTS
* num_cpus
;
829 /* Get kernel buffer information */
830 get_bufinfo(&bufinfo
);
832 buffer
= malloc(bufinfo
.nkdbufs
* sizeof(kd_buf
));
833 if (buffer
== (char *) 0)
834 quit("can't allocate memory for tracing info\n");
835 memset(buffer
, 0, bufinfo
.nkdbufs
* sizeof(kd_buf
));
837 if (use_current_buf
== 0)
840 if (write_command_map(fd
)) {
841 quit("can't write tracefile header\n");
844 sample_window_abs
= (uint64_t)((double)US_TO_SLEEP
* divisor
);
846 next_window_begins
= mach_absolute_time() + sample_window_abs
;
849 ending_abstime
= mach_absolute_time() + (uint64_t)((double)secs_to_run
* (double)1000000 * divisor
);
850 ms_to_run
= secs_to_run
* 1000;
853 last_time_written
= mach_absolute_time();
855 while (LogRAW_flag
) {
856 current_abs
= mach_absolute_time();
858 if (try_writetrace
) {
865 current_abs
= mach_absolute_time();
867 printf("wrote %d events - elapsed time = %.1f secs\n",
868 (int)needed
, ((double)(current_abs
- last_time_written
) / divisor
) / 1000000);
870 last_time_written
= current_abs
;
874 if (try_writetrace
== 0) {
876 if (next_window_begins
> current_abs
)
877 us_to_adjust
= US_TO_SLEEP
- (uint32_t)((double)(next_window_begins
- current_abs
) / divisor
);
879 us_to_adjust
= US_TO_SLEEP
;
881 next_window_begins
= current_abs
+ sample_window_abs
;
883 us_to_sleep
= US_TO_SLEEP
- us_to_adjust
;
885 next_window_begins
= current_abs
+ (uint64_t)((double)(us_to_sleep
+ US_TO_SLEEP
) * divisor
);
890 get_bufinfo(&bufinfo
);
892 if (bufinfo
.flags
& KDBG_WRAPPED
)
893 printf("lost events\n");
895 needed
= bufinfo
.nkdbufs
* sizeof(kd_buf
);
899 if (bufinfo
.flags
& KDBG_WRAPPED
) {
901 kd
= (kd_buf
*) buffer
;
903 kd_tmp
.timestamp
= kd
[0].timestamp
;
904 kd_tmp
.debugid
= TRACE_LOST_EVENTS
;
906 write(fd
, &kd_tmp
, sizeof(kd_tmp
));
908 write(fd
, buffer
, needed
* sizeof(kd_buf
));
910 if (verbose_flag
&& needed
> nbufs
)
911 printf("needed = %ld\n", needed
);
914 current_abs
= mach_absolute_time();
916 if (current_abs
> ending_abstime
)
918 ms_to_run
= (ending_abstime
- current_abs
) / (1000 * 1000);
935 uint32_t buffer_size
;
942 uint32_t count_of_names
;
943 double last_event_time
= 0.0;
947 get_bufinfo(&bufinfo
);
949 if (bufinfo
.nolog
!= 1) {
951 set_enable(0); /* disable logging*/
954 if (bufinfo
.flags
& KDBG_WRAPPED
)
955 printf("Buffer has wrapped\n");
957 printf("Buffer has not wrapped\n");
963 fd
= open(RAW_file
, O_RDONLY
);
966 perror("Can't open file");
969 if (read(fd
, &raw_header
, sizeof(RAW_header
)) != sizeof(RAW_header
)) {
970 perror("read failed");
973 if (raw_header
.version_no
!= RAW_VERSION1
) {
974 raw_header
.version_no
= RAW_VERSION0
;
975 raw_header
.TOD_secs
= time((long *)0);
976 raw_header
.TOD_usecs
= 0;
978 lseek(fd
, (off_t
)0, SEEK_SET
);
980 if (read(fd
, &raw_header
.thread_count
, sizeof(int)) != sizeof(int)) {
981 perror("read failed");
985 count_of_names
= raw_header
.thread_count
;
986 trace_time
= (time_t) (raw_header
.TOD_secs
);
988 printf("%s\n", ctime(&trace_time
));
990 buffer_size
= 1000000 * sizeof(kd_buf
);
991 buffer
= malloc(buffer_size
);
993 if (buffer
== (char *) 0)
994 quit("can't allocate memory for tracing info\n");
996 kd
= (kd_buf
*)buffer
;
998 read_command_map(fd
, count_of_names
);
1010 double event_elapsed_time
;
1013 boolean_t ending_event
;
1022 if (!readRAW_flag
) {
1023 needed
= buffer_size
;
1026 mib
[1] = KERN_KDEBUG
;
1027 mib
[2] = KERN_KDREADTR
;
1031 if (sysctl(mib
, 3, buffer
, &needed
, NULL
, 0) < 0)
1032 quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno
));
1039 uint32_t bytes_read
;
1041 bytes_read
= read(fd
, buffer
, buffer_size
);
1043 if (bytes_read
== -1) {
1044 perror("read failed");
1047 count
= bytes_read
/ sizeof(kd_buf
);
1052 for (kdp
= &kd
[0], i
= 0; i
< count
; i
++, kdp
++) {
1055 debugid
= kdp
->debugid
;
1056 debugid_base
= debugid
& DBG_FUNC_MASK
;
1057 now
= kdp
->timestamp
& KDBG_TIMESTAMP_MASK
;
1063 cpunum
= kdbg_get_cpu(kdp
);
1066 if (lines
== 64 || firsttime
)
1068 prevdelta
= now
- prevdelta
;
1073 x
= (double)prevdelta
;
1076 fprintf(output_file
, "\n\nNumber of microsecs since in last page %8.1f\n", x
);
1081 * Output description row to output file (make sure to format correctly for 32-bit and 64-bit)
1083 fprintf(output_file
,
1085 " AbsTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu# command\n\n"
1087 " AbsTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu# command\n\n"
1093 if (io_lines
> 15000) {
1094 fcntl(output_fd
, F_FLUSH_DATA
, 0);
1101 if (debugid_base
== VFS_LOOKUP
) {
1102 lkp
= handle_lookup_event(thread
, debugid
, kdp
);
1104 if ( !lkp
|| !(debugid
& DBG_FUNC_END
))
1110 if (last_event_time
)
1111 y
= x
- last_event_time
;
1114 last_event_time
= x
;
1115 ending_event
= FALSE
;
1118 * Is this event from an IOP? If so, there will be no
1119 * thread command, label it with the symbolic IOP name
1121 if (cpumap
&& (cpunum
< cpumap_header
->cpu_count
) && (cpumap
[cpunum
].flags
& KDBG_CPUMAP_IS_IOP
)) {
1122 command
= cpumap
[cpunum
].name
;
1124 find_thread_command(kdp
, &command
);
1128 * The internal use TRACE points clutter the output.
1129 * Print them only if in verbose mode.
1133 /* Is this entry of Class DBG_TRACE */
1134 if ((debugid
>> 24) == DBG_TRACE
) {
1135 if (((debugid
>> 16) & 0xff) != DBG_TRACE_INFO
)
1143 if ((debugid
& DBG_FUNC_START
) || debugid
== MACH_MAKERUNNABLE
) {
1145 if (debugid_base
!= BSC_thread_terminate
&& debugid_base
!= BSC_exit
) {
1147 if (debugid
== MACH_MAKERUNNABLE
)
1148 t_thread
= kdp
->arg1
;
1152 insert_start_event(t_thread
, debugid_base
, now
);
1155 } else if ((debugid
& DBG_FUNC_END
) || debugid
== MACH_STKHANDOFF
|| debugid
== MACH_SCHEDULED
) {
1157 if (debugid
== MACH_STKHANDOFF
|| debugid
== MACH_SCHEDULED
) {
1158 t_debugid
= MACH_MAKERUNNABLE
;
1159 t_thread
= kdp
->arg2
;
1161 t_debugid
= debugid_base
;
1164 event_elapsed_time
= (double)consume_start_event(t_thread
, t_debugid
, now
);
1165 event_elapsed_time
/= divisor
;
1166 ending_event
= TRUE
;
1168 if (event_elapsed_time
== 0 && (debugid
== MACH_STKHANDOFF
|| debugid
== MACH_SCHEDULED
))
1169 ending_event
= FALSE
;
1175 sprintf(&outbuf
[0], "(%-10.1f)", event_elapsed_time
);
1177 * fix that right paren
1182 ch
= strchr (&outbuf
[0], ')');
1189 while (ch
!= &outbuf
[0])
1201 if (match_debugid(debugid_base
, dbgmessge
, &dmsgindex
)) {
1203 fprintf(output_file
, "%13.1f %10.1f%s %-28x ", x
, y
, outbuf
, debugid_base
);
1205 fprintf(output_file
, "%13.1f %10.1f %-28x ", x
, y
, debugid_base
);
1208 fprintf(output_file
, "%13.1f %10.1f%s %-28.28s ", x
, y
, outbuf
, dbgmessge
);
1210 fprintf(output_file
, "%13.1f %10.1f %-28.28s ", x
, y
, dbgmessge
);
1216 strptr
= (char *)lkp
->lk_pathname
;
1219 * print the tail end of the pathname
1221 len
= strlen(strptr
);
1228 fprintf(output_file
, "%-16lx %-51s %-16lx %-2d %s\n", lkp
->lk_dvp
, &strptr
[len
], thread
, cpunum
, command
);
1230 fprintf(output_file
, "%-8x %-51s %-8lx %-2d %s\n", (unsigned int)lkp
->lk_dvp
, &strptr
[len
], thread
, cpunum
, command
);
1232 delete_lookup_event(thread
, lkp
);
1233 } else if (debugid
== TRACE_INFO_STRING
) {
1235 fprintf(output_file
, "%-32s%-36s %-16lx %-2d %s\n", (char *) &kdp
->arg1
, "", thread
, cpunum
, command
);
1237 fprintf(output_file
, "%-16s%-46s %-8lx %-2d %s\n", (char *) &kdp
->arg1
, "", thread
, cpunum
, command
);
1241 fprintf(output_file
, "%-16lx %-16lx %-16lx %-16lx %-16lx %-2d %s\n", kdp
->arg1
, kdp
->arg2
, kdp
->arg3
, kdp
->arg4
, thread
, cpunum
, command
);
1243 fprintf(output_file
, "%-8lx %-8lx %-8lx %-8lx %-8lx %-2d %s\n", kdp
->arg1
, kdp
->arg2
, kdp
->arg3
, kdp
->arg4
, thread
, cpunum
, command
);
1251 set_enable(1); /* re-enable kernel logging */
1256 void signal_handler(int sig
)
1258 ptrace(PT_KILL
, pid
, (caddr_t
)0, 0);
1260 * child is gone; no need to disable the pid
1266 void signal_handler_RAW(int sig
)
1273 int main(argc
, argv
, env
)
1278 extern char *optarg
;
1282 char *output_filename
= NULL
;
1283 char *filter_filename
= NULL
;
1284 unsigned int parsed_arg
;
1286 for (i
= 1; i
< argc
; i
++) {
1287 if (strcmp("-X", argv
[i
]) == 0) {
1288 force_32bit_exec
= 1;
1292 if (force_32bit_exec
) {
1293 if (0 != reexec_to_match_lp64ness(FALSE
)) {
1294 fprintf(stderr
, "Could not re-execute: %d\n", errno
);
1298 if (0 != reexec_to_match_kernel()) {
1299 fprintf(stderr
, "Could not re-execute: %d\n", errno
);
1303 if (setiopolicy_np(IOPOL_TYPE_DISK
, IOPOL_SCOPE_PROCESS
, IOPOL_PASSIVE
) < 0) {
1304 printf("setiopolicy failed\n");
1307 output_file
= stdout
;
1310 while ((ch
= getopt(argc
, argv
, "hedEk:irb:gc:p:s:tR:L:l:S:F:a:x:Xnfvo:PT:N")) != EOF
)
1314 case 'h': /* help */
1318 secs_to_run
= argtoi('S', "decimal number", optarg
, 10);
1320 case 'a': /* set tracing on a pid */
1322 pid
= argtoi('a', "decimal number", optarg
, 10);
1324 case 'x': /* exclude a pid from tracing */
1326 pid
= argtoi('x', "decimal number", optarg
, 10);
1338 signal(SIGINT
, signal_handler_RAW
);
1354 value1
= (unsigned int) argtoul('k', "hex number", optarg
, 16);
1355 else if (kval_flag
== 1)
1356 value2
= (unsigned int) argtoul('k', "hex number", optarg
, 16);
1357 else if (kval_flag
== 2)
1358 value3
= (unsigned int) argtoul('k', "hex number", optarg
, 16);
1359 else if (kval_flag
== 3)
1360 value4
= (unsigned int) argtoul('k', "hex number", optarg
, 16);
1363 fprintf(stderr
, "A maximum of four values can be specified with -k\n");
1389 nbufs
= argtoi('b', "decimal number", optarg
, 10);
1393 parsed_arg
= argtoi('c', "decimal, hex, or octal number", optarg
, 0);
1394 if (parsed_arg
> 0xFF)
1395 quit_args("argument '-c %s' parsed as %u, "
1396 "class value must be 0-255\n", optarg
, parsed_arg
);
1397 saw_filter_class(parsed_arg
);
1401 parsed_arg
= argtoi('s', "decimal, hex, or octal number", optarg
, 0);
1402 if (parsed_arg
> 0xFF)
1403 quit_args("argument '-s %s' parsed as %u, "
1404 "subclass value must be 0-255\n", optarg
, parsed_arg
);
1405 saw_filter_subclass(parsed_arg
);
1409 parsed_arg
= argtoi('p', "decimal, hex, or octal number", optarg
, 0);
1410 if (parsed_arg
> 0xFF)
1411 quit_args("argument '-p %s' parsed as %u, "
1412 "end range value must be 0-255\n", optarg
, parsed_arg
);
1413 saw_filter_end_range(parsed_arg
);
1419 output_filename
= optarg
;
1422 frequency
= argtoi('F', "decimal number", optarg
, 10);
1427 no_default_codes_flag
= 1;
1432 // Flush out any unclosed -c argument
1433 filter_done_parsing();
1435 parse_filter_file(optarg
);
1443 if (!no_default_codes_flag
)
1446 printf("Adding default code file /usr/share/misc/trace.codes. Use '-N' to skip this.\n");
1447 parse_codefile("/usr/share/misc/trace.codes");
1456 const char *cfile
= argv
[optind
++];
1457 if (verbose_flag
) printf("Adding code file %s \n", cfile
);
1458 parse_codefile(cfile
);
1465 quit_args("-E flag needs an executable to launch\n");
1473 if (pid_flag
&& pid_exflag
)
1474 quit_args("Can't use both -a and -x flag together\n");
1476 if (kval_flag
&& filter_flag
)
1477 quit_args("Cannot use -k flag with -c, -s, or -p\n");
1479 if (output_filename
&& !trace_flag
&& !readRAW_flag
)
1480 quit_args("When using 'o' option, must use the 't' or 'R' option too\n");
1482 filter_done_parsing();
1487 get_bufinfo(&bufinfo
);
1489 if (bufinfo
.nolog
== 0)
1490 use_current_buf
= 1;
1497 set_pidcheck(pid
, 0); /* disable pid check for given pid */
1500 else if (pid_exflag
)
1502 set_pidexclude(pid
, 0); /* disable pid exclusion for given pid */
1517 if (!init_flag
&& !LogRAW_flag
)
1519 fprintf(stderr
,"The -b flag must be used with the -i flag\n");
1533 get_bufinfo(&bufinfo
);
1535 printf("The kernel buffer settings are:\n");
1537 if (bufinfo
.flags
& KDBG_BUFINIT
)
1538 printf("\tKernel buffer is initialized\n");
1540 printf("\tKernel buffer is not initialized\n");
1542 printf("\t number of buf entries = %d\n", bufinfo
.nkdbufs
);
1546 if (bufinfo
.flags
& KDBG_MAPINIT
)
1547 printf("\tKernel thread map is initialized\n");
1549 printf("\tKernel thread map is not initialized\n");
1550 printf("\t number of thread entries = %d\n", bufinfo
.nkdthreads
);
1554 printf("\tBuffer logging is disabled\n");
1556 printf("\tBuffer logging is enabled\n");
1559 printf("\tkernel flags = 0x%x\n", bufinfo
.flags
);
1561 if (bufinfo
.flags
& KDBG_NOWRAP
)
1562 printf("\tKernel buffer wrap is disabled\n");
1564 printf("\tKernel buffer wrap is enabled\n");
1566 if (bufinfo
.flags
& KDBG_RANGECHECK
)
1567 printf("\tCollection within a range is enabled\n");
1569 printf("\tCollection within a range is disabled\n");
1571 if (bufinfo
.flags
& KDBG_VALCHECK
)
1572 printf("\tCollecting specific code values is enabled\n");
1574 printf("\tCollecting specific code values is disabled\n");
1576 if (bufinfo
.flags
& KDBG_TYPEFILTER_CHECK
)
1577 printf("\tCollection based on a filter is enabled\n");
1579 printf("\tCollection based on a filter is disabled\n");
1581 if (bufinfo
.flags
& KDBG_PIDCHECK
)
1582 printf("\tCollection based on pid is enabled\n");
1584 printf("\tCollection based on pid is disabled\n");
1586 if (bufinfo
.flags
& KDBG_PIDEXCLUDE
)
1587 printf("\tCollection based on pid exclusion is enabled\n");
1589 printf("\tCollection based on pid exclusion is disabled\n");
1591 if (bufinfo
.bufid
== -1)
1592 printf("\tKernel buffer is not controlled by any process.\n");
1594 printf("\tKernel buffer is controlled by proc id [%d]\n", bufinfo
.bufid
);
1608 fprintf(stderr
, "Starting program: %s\n", argv
[optind
]);
1612 execute_process(&(argv
[optind
]));
1616 else if (enable_flag
)
1619 set_pidcheck(pid
, 1);
1620 else if (pid_exflag
)
1621 set_pidexclude(pid
, 1);
1625 if (output_filename
)
1627 if (((output_fd
= open(output_filename
, O_CREAT
| O_TRUNC
| O_WRONLY
| O_APPEND
, 0644)) < 0 ) ||
1628 !(output_file
= fdopen(output_fd
, "w")))
1630 fprintf(stderr
, "Cannot open file \"%s\" for writing.\n", output_filename
);
1633 setbuffer(output_file
, &sbuffer
[0], SBUFFER_SIZE
);
1635 if (fcntl(output_fd
, F_NOCACHE
, 1) < 0)
1638 fprintf(stderr
, "Warning: setting F_NOCACHE on %s, failed\n", output_filename
);
1641 if (!LogRAW_flag
&& !logRAW_flag
)
1642 setbuffer(output_file
, &sbuffer
[0], SBUFFER_SIZE
);
1644 if (trace_flag
|| readRAW_flag
)
1646 else if (LogRAW_flag
)
1648 else if (logRAW_flag
)
1656 execute_process(char * const argv
[])
1660 posix_spawnattr_t spawn_attrs
;
1664 /* ensure that the process being spawned starts suspended */
1665 rc
= posix_spawnattr_init(&spawn_attrs
);
1667 quit_args("Failed to initialize spawn attrs: %s\n", strerror(rc
));
1669 rc
= posix_spawnattr_setflags(&spawn_attrs
,
1670 POSIX_SPAWN_START_SUSPENDED
);
1672 quit_args("Unable to start process suspended: %s\n", strerror(rc
));
1675 /* spawn the process with the rest of the arguments */
1676 rc
= posix_spawnp(&pid
, argv
[0], NULL
, &spawn_attrs
, argv
, environ
);
1678 quit_args("Unabled to start process: %s\n", strerror(rc
));
1681 signal(SIGINT
, signal_handler
);
1682 set_pidcheck(pid
, 1);
1685 /* start the child process */
1686 rc
= kill(pid
, SIGCONT
);
1688 perror("Failed to continue child process:");
1692 rc
= waitpid(pid
, &status
, 0);
1694 perror("Failed to wait for process: ");
1699 quit_args(const char *fmt
, ...)
1706 set_enable(1); /* re-enable kernel logging */
1711 va_start (args
, fmt
);
1712 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
1714 fprintf(stderr
, "trace error: %s", buffer
);
1718 if (!done_with_args
)
1731 set_enable(1); /* re-enable kernel logging */
1741 usage(int short_help
)
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");
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");
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");
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");
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");
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");
1792 (void)fprintf(stderr
, "usage: trace -g\n");
1793 (void)fprintf(stderr
, "\tGet the kernel buffer settings.\n\n");
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");
1800 (void)fprintf(stderr
, "usage: trace -r\n");
1801 (void)fprintf(stderr
, "\tRemove the kernel trace buffer. Set controls to default.\n\n");
1803 (void)fprintf(stderr
, "usage: trace -n\n");
1804 (void)fprintf(stderr
, "\tDisables kernel buffer wrap around.\n\n");
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");
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");
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");
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");
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");
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");
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");
1872 (void)fprintf(stderr
,
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"
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"
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"
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"
1900 "\t File syntax: \n"
1901 "\t Class filter: \n"
1903 "\t Subclass filter (includes class): \n"
1906 "\t # This is a comment \n\n"
1908 "\t For example, to trace Mach events (class 1):\n"
1910 "\t or to trace Mach system calls (class 1 subclass 13): \n"
1920 argtoi(flag
, req
, str
, base
)
1928 ret
= (int)strtol(str
, &cp
, base
);
1929 if (cp
== str
|| *cp
)
1930 errx(EINVAL
, "-%c flag requires a %s", flag
, req
);
1935 static unsigned long
1936 argtoul(flag
, req
, str
, base
)
1944 ret
= (int)strtoul(str
, &cp
, base
);
1945 if (cp
== str
|| *cp
)
1946 errx(EINVAL
, "-%c flag requires a %s", flag
, req
);
1952 * comparison function for qsort
1955 int debugid_compar(p1
, p2
)
1959 if (p1
->debugid
> p2
->debugid
)
1961 else if (p1
->debugid
== p2
->debugid
)
1969 * Filter args parsing state machine:
1975 * every -c goes back to start
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)
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
1993 // What type of flag did I last see?
1997 FILTER_MODE_CLASS_RANGE
,
1998 FILTER_MODE_SUBCLASS
1999 } filter_mode
= FILTER_MODE_START
;
2001 uint8_t filter_current_class
= 0;
2002 uint8_t filter_current_subclass
= 0;
2003 uint8_t filter_current_class_range
= 0;
2006 saw_filter_class(uint8_t class)
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
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;
2028 quit_args("invalid case in saw_filter_class\n");
2033 saw_filter_end_range(uint8_t end_class
)
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
);
2041 case FILTER_MODE_START
:
2042 quit_args("must provide '-c class' before '-p 0x%x'\n",
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
);
2055 quit_args("invalid case in saw_filter_end_range\n");
2060 saw_filter_subclass(uint8_t subclass
)
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
);
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
);
2079 quit_args("invalid case in saw_filter_subclass\n");
2084 filter_done_parsing(void)
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;
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;
2104 quit_args("invalid case in filter_done_parsing\n");
2108 /* Tell set_filter_subclass not to print every. single. subclass. */
2109 static boolean_t setting_class
= FALSE
;
2110 static boolean_t setting_range
= FALSE
;
2113 set_filter_subclass(uint8_t class, uint8_t subclass
)
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");
2122 uint16_t csc
= ENCODE_CSC_LOW(class, subclass
);
2124 if (verbose_flag
&& !setting_class
)
2125 printf("tracing subclass: 0x%4.4x\n", csc
);
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
);
2131 setbit(type_filter_bitmap
, csc
);
2135 set_filter_class(uint8_t class)
2137 if (verbose_flag
&& !setting_range
)
2138 printf("tracing class: 0x%2.2x\n", class);
2140 setting_class
= TRUE
;
2142 for (int i
= 0; i
< 256; i
++)
2143 set_filter_subclass(class, i
);
2145 setting_class
= FALSE
;
2149 set_filter_range(uint8_t class, uint8_t end
)
2152 printf("tracing range: 0x%2.2x - 0x%2.2x\n", class, end
);
2154 setting_range
= TRUE
;
2156 for (int i
= class; i
<= end
; i
++)
2157 set_filter_class(i
);
2159 setting_range
= FALSE
;
2163 * Syntax of filter file:
2164 * Hexadecimal numbers only
2167 * Subclass (includes class):
2171 * TBD: Class ranges?
2172 * TBD: K for -k flag?
2176 parse_filter_file(char *filename
) {
2178 uint32_t current_line
= 0;
2179 uint32_t parsed_arg
= 0;
2184 if ( (file
= fopen(filename
, "r")) == NULL
) {
2185 quit_args("Failed to open filter description file %s: %s\n",
2186 filename
, strerror(errno
));
2190 printf("Parsing typefilter file: %s\n", filename
);
2192 while( fgets(line
, sizeof(line
), file
) != NULL
) {
2197 rval
= sscanf(line
, "C 0x%x\n", &parsed_arg
);
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"
2204 "class value must be 0x0-0xFF\n",
2205 current_line
, filename
, line
, parsed_arg
);
2206 set_filter_class((uint8_t)parsed_arg
);
2209 rval
= sscanf(line
, "S 0x%x\n", &parsed_arg
);
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"
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
));
2231 quit_args("Invalid filter description file: %s\n"
2232 "could not parse line %d: %s\n",
2233 filename
, current_line
, line
);
2242 * Find the debugid code in the list and return its index
2244 static int binary_search(list
, lowbound
, highbound
, code
)
2246 int lowbound
, highbound
;
2257 mid
= (low
+ high
) / 2;
2262 return (-1); /* failed */
2263 else if ( low
+ 1 >= high
)
2265 /* We have a match */
2266 if (list
[high
].debugid
== code
)
2268 else if (list
[low
].debugid
== code
)
2271 return(-1); /* search failed */
2273 else if (code
< list
[mid
].debugid
)
2282 parse_codefile(const char *filename
)
2287 struct stat stat_buf
;
2288 unsigned long file_size
;
2289 char *file_addr
, *endp
;
2291 if ((fd
= open(filename
, O_RDONLY
, 0)) == -1)
2293 printf("Failed to open code description file %s\n",filename
);
2297 if (fstat(fd
, &stat_buf
) == -1)
2299 printf("Error: Can't fstat file: %s\n", filename
);
2304 * For some reason mapping files with zero size fails
2305 * so it has to be handled specially.
2307 file_size
= stat_buf
.st_size
;
2309 if (stat_buf
.st_size
!= 0)
2311 if ((file_addr
= mmap(0, stat_buf
.st_size
, PROT_READ
|PROT_WRITE
,
2312 MAP_PRIVATE
|MAP_FILE
, fd
, 0)) == (char*) -1)
2314 printf("Error: Can't map file: %s\n", filename
);
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.
2334 for (count
= 0, j
=1; j
< file_size
; j
++)
2336 if (file_addr
[j
] == '\n')
2342 printf("Error: No codes in %s\n", filename
);
2347 * Fudge the count to accomodate the last line in the file -
2348 * in case it doesn't end in a newline.
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
));
2356 if (new_codesc
== NULL
) {
2357 printf("Failed to grow/allocate buffer. Skipping file %s\n", filename
);
2360 codesc
= new_codesc
;
2361 bzero((char *)(codesc
+ codesc_idx
), count
* sizeof(code_type_t
));
2363 for (line
= 1, j
= 0; j
< file_size
&& codesc_idx
< total_count
; codesc_idx
++)
2365 /* Skip blank lines */
2366 while (file_addr
[j
] == '\n')
2372 /* Skip leading whitespace */
2373 while (file_addr
[j
] == ' ' || file_addr
[j
] == '\t')
2376 /* Get the debugid code */
2377 codesc
[codesc_idx
].debugid
= strtoul(file_addr
+ j
, &endp
, 16);
2378 j
= endp
- file_addr
;
2380 if (codesc
[codesc_idx
].debugid
== 0)
2382 /* We didn't find a debugid code - skip this line */
2384 printf("Error: while parsing line %d, skip\n", line
);
2385 while (file_addr
[j
] != '\n' && j
< file_size
)
2392 /* Skip whitespace */
2393 while (file_addr
[j
] == ' ' || file_addr
[j
] == '\t')
2396 /* Get around old file that had count at the beginning */
2397 if (file_addr
[j
] == '\n')
2399 /* missing debugid string - skip */
2401 printf("Error: while parsing line %d, (0x%x) skip\n", line
, codesc
[codesc_idx
].debugid
);
2409 /* Next is the debugid string terminated by a newline */
2410 codesc
[codesc_idx
].debug_string
= &file_addr
[j
];
2412 /* Null out the newline terminator */
2413 while ((j
< file_size
) && (file_addr
[j
] != '\n'))
2415 file_addr
[j
] = '\0'; /* File must be read-write */
2418 codenum
++; /*Index into codesc is 0 to codenum-1 */
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
);
2429 qsort((void *)codesc
, codesc_idx
, sizeof(code_type_t
), debugid_compar
);
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
);
2437 codesc_find_dupes();
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
);
2447 static void codesc_find_dupes(void)
2449 boolean_t found_dupes
= FALSE
;
2450 if (codesc_idx
== 0)
2454 uint32_t last_debugid
= codesc
[0].debugid
;
2455 for(int i
= 1; i
< codesc_idx
; i
++)
2457 if(codesc
[i
].debugid
== last_debugid
)
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
);
2464 last_debugid
= codesc
[i
].debugid
;
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");
2473 int match_debugid(unsigned int xx
, char * debugstr
, int * yy
)
2480 if (codesc
[codeindx_cache
].debugid
!= xx
)
2481 indx
= binary_search(codesc
, 0, (codenum
-1), xx
);
2483 indx
= codeindx_cache
;
2486 return(indx
); /* match failed */
2488 bcopy(&codesc
[indx
].debug_string
[0], debugstr
,80);
2490 codeindx_cache
= indx
;
2491 return(0); /* match success */
2496 read_cpu_map(int fd
)
2498 if (cpumap_header
) {
2499 free(cpumap_header
);
2500 cpumap_header
= NULL
;
2505 * To fit in the padding space of a VERSION1 file, the max possible
2506 * cpumap size is one page.
2508 cpumap_header
= malloc(PAGE_SIZE
);
2512 * cpu maps exist in a RAW_VERSION1+ header only
2514 if (raw_header
.version_no
== RAW_VERSION1
) {
2515 off_t cpumap_position
= lseek(fd
, 0, SEEK_CUR
);
2516 /* cpumap is part of the last 4KB of padding in the preamble */
2517 size_t padding_bytes
= SIZE_4KB
- (cpumap_position
& (SIZE_4KB
- 1));
2519 if (read(fd
, cpumap_header
, padding_bytes
) == padding_bytes
) {
2520 if (cpumap_header
->version_no
== RAW_VERSION1
) {
2521 cpumap
= (kd_cpumap
*)&cpumap_header
[1];
2529 mib
[1] = KERN_KDEBUG
;
2530 mib
[2] = KERN_KDCPUMAP
;
2532 size_t temp
= PAGE_SIZE
;
2533 if (sysctl(mib
, 3, cpumap_header
, &temp
, NULL
, 0) == 0) {
2534 if (PAGE_SIZE
>= temp
) {
2535 if (cpumap_header
->version_no
== RAW_VERSION1
) {
2536 cpumap
= (kd_cpumap
*)&cpumap_header
[1];
2543 printf("Can't read the cpu map -- this is not fatal\n");
2544 free(cpumap_header
);
2545 cpumap_header
= NULL
;
2546 } else if (verbose_flag
) {
2547 /* Dump the initial cpumap */
2548 printf("\nCPU\tName\n");
2549 for (int i
= 0; i
< cpumap_header
->cpu_count
; i
++) {
2550 printf ("%2d\t%s\n", cpumap
[i
].cpu_id
, cpumap
[i
].name
);
2557 read_command_map(int fd
, uint32_t count
)
2564 total_threads
= count
;
2565 size
= count
* sizeof(kd_threadmap
);
2567 get_bufinfo(&bufinfo
);
2569 total_threads
= bufinfo
.nkdthreads
;
2570 size
= bufinfo
.nkdthreads
* sizeof(kd_threadmap
);
2573 nthreads
= total_threads
* 2;
2576 printf("Size of map table is %d, thus %d entries\n", (int)size
, total_threads
);
2579 if ((mapptr
= (kd_threadmap
*) malloc(size
)))
2580 bzero (mapptr
, size
);
2584 printf("Thread map is not initialized -- this is not fatal\n");
2589 if (read(fd
, mapptr
, size
) != size
) {
2591 printf("Can't read the thread map -- this is not fatal\n");
2598 /* Now read the threadmap */
2600 mib
[1] = KERN_KDEBUG
;
2601 mib
[2] = KERN_KDTHRMAP
;
2604 mib
[5] = 0; /* no flags */
2605 if (sysctl(mib
, 3, mapptr
, &size
, NULL
, 0) < 0)
2607 /* This is not fatal -- just means I cant map command strings */
2609 printf("Can't read the thread map -- this is not fatal\n");
2615 for (i
= 0; i
< total_threads
; i
++) {
2616 if (mapptr
[i
].thread
)
2617 create_map_entry(mapptr
[i
].thread
, &mapptr
[i
].command
[0]);
2621 /* Dump the initial map */
2623 printf("Size of maptable returned is %ld, thus %ld entries\n", size
, (size
/sizeof(kd_threadmap
)));
2625 printf("Thread Command\n");
2626 for (i
= 0; i
< total_threads
; i
++) {
2627 printf ("0x%lx %s\n",
2637 void create_map_entry(uintptr_t thread
, char *command
)
2642 if ((tme
= threadmap_freelist
))
2643 threadmap_freelist
= tme
->tm_next
;
2645 tme
= (threadmap_t
)malloc(sizeof(struct threadmap
));
2647 tme
->tm_thread
= thread
;
2648 tme
->tm_deleteme
= FALSE
;
2650 (void)strncpy (tme
->tm_command
, command
, MAXCOMLEN
);
2651 tme
->tm_command
[MAXCOMLEN
] = '\0';
2653 hashid
= thread
& HASH_MASK
;
2655 tme
->tm_next
= threadmap_hash
[hashid
];
2656 threadmap_hash
[hashid
] = tme
;
2660 void delete_thread_entry(uintptr_t thread
)
2662 threadmap_t tme
= 0;
2663 threadmap_t tme_prev
;
2666 hashid
= thread
& HASH_MASK
;
2668 if ((tme
= threadmap_hash
[hashid
])) {
2669 if (tme
->tm_thread
== thread
)
2670 threadmap_hash
[hashid
] = tme
->tm_next
;
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
;
2683 tme
->tm_next
= threadmap_freelist
;
2684 threadmap_freelist
= tme
;
2690 void find_and_insert_tmp_map_entry(uintptr_t pthread
, char *command
)
2692 threadmap_t tme
= 0;
2693 threadmap_t tme_prev
;
2696 if ((tme
= threadmap_temp
)) {
2697 if (tme
->tm_pthread
== pthread
)
2698 threadmap_temp
= tme
->tm_next
;
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
;
2711 (void)strncpy (tme
->tm_command
, command
, MAXCOMLEN
);
2712 tme
->tm_command
[MAXCOMLEN
] = '\0';
2714 delete_thread_entry(tme
->tm_thread
);
2716 hashid
= tme
->tm_thread
& HASH_MASK
;
2718 tme
->tm_next
= threadmap_hash
[hashid
];
2719 threadmap_hash
[hashid
] = tme
;
2725 void create_tmp_map_entry(uintptr_t thread
, uintptr_t pthread
)
2729 if ((tme
= threadmap_freelist
))
2730 threadmap_freelist
= tme
->tm_next
;
2732 tme
= (threadmap_t
)malloc(sizeof(struct threadmap
));
2734 tme
->tm_thread
= thread
;
2735 tme
->tm_pthread
= pthread
;
2736 tme
->tm_deleteme
= FALSE
;
2737 tme
->tm_command
[0] = '\0';
2739 tme
->tm_next
= threadmap_temp
;
2740 threadmap_temp
= tme
;
2745 find_thread_entry(uintptr_t thread
)
2750 hashid
= thread
& HASH_MASK
;
2752 for (tme
= threadmap_hash
[hashid
]; tme
; tme
= tme
->tm_next
) {
2753 if (tme
->tm_thread
== thread
)
2760 void find_thread_name(uintptr_t thread
, char **command
, boolean_t deleteme
)
2764 if ((tme
= find_thread_entry(thread
))) {
2765 *command
= tme
->tm_command
;
2767 if (deleteme
== TRUE
)
2768 tme
->tm_deleteme
= deleteme
;
2770 *command
= EMPTYSTRING
;
2774 void find_thread_command(kd_buf
*kbufp
, char **command
)
2780 *command
= EMPTYSTRING
;
2782 thread
= kbufp
->arg5
;
2783 debugid_base
= kbufp
->debugid
& DBG_FUNC_MASK
;
2785 if (debugid_base
== BSC_exit
|| debugid_base
== MACH_STKHANDOFF
) {
2787 * Mark entry as invalid and return temp command pointer
2789 if ((tme
= find_thread_entry(thread
))) {
2791 strncpy(tmpcommand
, tme
->tm_command
, MAXCOMLEN
);
2792 *command
= tmpcommand
;
2794 if (debugid_base
== BSC_exit
|| tme
->tm_deleteme
== TRUE
)
2795 delete_thread_entry(thread
);
2798 else if (debugid_base
== TRACE_DATA_NEWTHREAD
) {
2800 * Save the create thread data
2802 create_tmp_map_entry(kbufp
->arg1
, kbufp
->arg5
);
2804 else if (debugid_base
== TRACE_STRING_NEWTHREAD
) {
2806 * process new map entry
2808 find_and_insert_tmp_map_entry(kbufp
->arg5
, (char *)&kbufp
->arg1
);
2810 else if (debugid_base
== TRACE_STRING_EXEC
) {
2812 delete_thread_entry(kbufp
->arg5
);
2814 create_map_entry(kbufp
->arg5
, (char *)&kbufp
->arg1
);
2817 find_thread_name(thread
, command
, (debugid_base
== BSC_thread_terminate
));
2824 mach_timebase_info_data_t info
;
2826 if (frequency
== 0) {
2827 (void) mach_timebase_info (&info
);
2829 divisor
= ( (double)info
.denom
/ (double)info
.numer
) * 1000;
2831 divisor
= (double)frequency
/ 1000000;
2834 printf("divisor = %g\n", divisor
);