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 TRACE_INFO_STRING 0x07020010
112 #define MACH_SCHEDULED 0x01400000
113 #define MACH_MAKERUNNABLE 0x01400018
114 #define MACH_STKHANDOFF 0x01400008
116 #define EMPTYSTRING ""
117 #define UNKNOWN "unknown"
119 char tmpcommand
[MAXCOMLEN
];
121 int total_threads
= 0;
123 kd_threadmap
*mapptr
= 0;
125 kd_cpumap_header
* cpumap_header
= NULL
;
126 kd_cpumap
* cpumap
= NULL
;
129 If NUMPARMS changes from the kernel,
130 then PATHLENGTH will also reflect the change
131 This is for the vfslookup entries that
135 #define PATHLENGTH (NUMPARMS*sizeof(long))
138 #define US_TO_SLEEP 50000
139 #define BASE_EVENTS 500000
149 code_type_t
* codesc
= 0;
150 size_t codesc_idx
= 0; // Index into first empty codesc entry
154 typedef struct event
*event_t
;
161 uint64_t ev_timestamp
;
164 typedef struct lookup
*lookup_t
;
172 long lk_pathname
[NUMPARMS
+ 1];
175 typedef struct threadmap
*threadmap_t
;
181 uintptr_t tm_pthread
;
182 boolean_t tm_deleteme
;
183 char tm_command
[MAXCOMLEN
+ 1];
187 #define HASH_SIZE 1024
188 #define HASH_MASK 1023
190 event_t event_hash
[HASH_SIZE
];
191 lookup_t lookup_hash
[HASH_SIZE
];
192 threadmap_t threadmap_hash
[HASH_SIZE
];
194 event_t event_freelist
;
195 lookup_t lookup_freelist
;
196 threadmap_t threadmap_freelist
;
197 threadmap_t threadmap_temp
;
200 #define SBUFFER_SIZE (128 * 4096)
201 char sbuffer
[SBUFFER_SIZE
];
204 int use_current_buf
= 0;
207 kbufinfo_t bufinfo
= {0, 0, 0, 0};
210 int codeindx_cache
= 0;
212 static void quit(char *);
213 static int match_debugid(unsigned int, char *, int *);
214 static void usage(int short_help
);
215 static int argtoi(int flag
, char *req
, char *str
, int base
);
216 static int parse_codefile(const char *filename
);
217 static void codesc_find_dupes(void);
218 static int read_command_map(int, uint32_t);
219 static void read_cpu_map(int);
220 static void find_thread_command(kd_buf
*, char **);
221 static void create_map_entry(uintptr_t, char *);
222 static void getdivisor();
223 static unsigned long argtoul();
225 static void set_enable(int);
226 static void set_remove();
227 static void set_nowrap();
228 static void set_pidcheck(int, int);
229 static void set_pidexclude(int, int);
230 static void set_numbufs(int);
231 static void set_freerun();
232 static void get_bufinfo(kbufinfo_t
*);
233 static void set_init();
234 static void set_kval_list();
235 static void readtrace(char *);
236 static void log_trace();
237 static void Log_trace();
238 static void read_trace();
239 static void signal_handler(int);
240 static void signal_handler_RAW(int);
241 static void delete_thread_entry(uintptr_t);
242 static void find_and_insert_tmp_map_entry(uintptr_t, char *);
243 static void create_tmp_map_entry(uintptr_t, uintptr_t);
244 static void find_thread_name(uintptr_t, char **, boolean_t
);
246 static int writetrace(int);
247 static int write_command_map(int);
248 static int debugid_compar(code_type_t
*, code_type_t
*);
250 static threadmap_t
find_thread_entry(uintptr_t);
252 static void saw_filter_class(uint8_t class);
253 static void saw_filter_end_range(uint8_t end_class
);
254 static void saw_filter_subclass(uint8_t subclass
);
255 static void filter_done_parsing(void);
257 static void set_filter(void);
258 static void set_filter_class(uint8_t class);
259 static void set_filter_range(uint8_t class, uint8_t end
);
260 static void set_filter_subclass(uint8_t class, uint8_t subclass
);
262 static void parse_filter_file(char *filename
);
264 static void quit_args(const char *fmt
, ...) __printflike(1, 2);
266 #ifndef KERN_KDWRITETR
267 #define KERN_KDWRITETR 17
270 #ifndef KERN_KDWRITEMAP
271 #define KERN_KDWRITEMAP 18
275 #define F_FLUSH_DATA 40
286 #define RAW_VERSION0 0x55aa0000
287 #define RAW_VERSION1 0x55aa0101
290 #define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(*x)))
292 #define EXTRACT_CLASS_LOW(debugid) ( (uint8_t) ( ((debugid) & 0xFF00 ) >> 8 ) )
293 #define EXTRACT_SUBCLASS_LOW(debugid) ( (uint8_t) ( ((debugid) & 0xFF ) ) )
295 #define ENCODE_CSC_LOW(class, subclass) \
296 ( (uint16_t) ( ((class) & 0xff) << 8 ) | ((subclass) & 0xff) )
298 RAW_header raw_header
;
302 void set_enable(int val
)
305 mib
[1] = KERN_KDEBUG
;
306 mib
[2] = KERN_KDENABLE
;
307 #ifdef KDEBUG_ENABLE_PPT
308 if (ppt_flag
&& val
) {
309 mib
[3] = KDEBUG_ENABLE_PPT
;
318 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
319 quit_args("trace facility failure, KERN_KDENABLE: %s\n", strerror(errno
));
329 mib
[1] = KERN_KDEBUG
;
330 mib
[2] = KERN_KDREMOVE
;
334 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
337 quit("the trace facility is currently in use...\n fs_usage, sc_usage, trace, and latency use this feature.\n\n");
339 quit_args("trace facility failure, KERN_KDREMOVE: %s\n", strerror(errno
));
343 void set_numbufs(int nbufs
)
346 mib
[1] = KERN_KDEBUG
;
347 mib
[2] = KERN_KDSETBUF
;
351 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
352 quit_args("trace facility failure, KERN_KDSETBUF: %s\n", strerror(errno
));
355 mib
[1] = KERN_KDEBUG
;
356 mib
[2] = KERN_KDSETUP
;
360 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
361 quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno
));
367 mib
[1] = KERN_KDEBUG
;
368 mib
[2] = KERN_KDEFLAGS
;
369 mib
[3] = KDBG_NOWRAP
;
371 mib
[5] = 0; /* no flags */
372 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
373 quit_args("trace facility failure, KDBG_NOWRAP: %s\n", strerror(errno
));
377 void set_pidcheck(int pid
, int on_off_flag
)
381 kr
.type
= KDBG_TYPENONE
;
383 kr
.value2
= on_off_flag
;
384 needed
= sizeof(kd_regtype
);
386 mib
[1] = KERN_KDEBUG
;
387 mib
[2] = KERN_KDPIDTR
;
391 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
393 if (on_off_flag
== 1)
395 printf("trace facility failure, KERN_KDPIDTR,\n\tpid %d does not exist\n", pid
);
402 void set_pidexclude(int pid
, int on_off_flag
)
406 kr
.type
= KDBG_TYPENONE
;
408 kr
.value2
= on_off_flag
;
409 needed
= sizeof(kd_regtype
);
411 mib
[1] = KERN_KDEBUG
;
412 mib
[2] = KERN_KDPIDEX
;
416 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
418 if (on_off_flag
== 1)
420 printf ("pid %d does not exist\n", pid
);
430 mib
[1] = KERN_KDEBUG
;
431 mib
[2] = KERN_KDEFLAGS
;
432 mib
[3] = KDBG_FREERUN
;
435 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
436 quit_args("trace facility failure, KDBG_FREERUN: %s\n", strerror(errno
));
439 void get_bufinfo(kbufinfo_t
*val
)
441 needed
= sizeof (*val
);
443 mib
[1] = KERN_KDEBUG
;
444 mib
[2] = KERN_KDGETBUF
;
448 if (sysctl(mib
, 3, val
, &needed
, 0, 0) < 0)
449 quit_args("trace facility failure, KERN_KDGETBUF: %s\n", strerror(errno
));
456 kr
.type
= KDBG_RANGETYPE
;
459 needed
= sizeof(kd_regtype
);
461 mib
[1] = KERN_KDEBUG
;
462 mib
[2] = KERN_KDSETREG
;
466 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
467 quit_args("trace facility failure, KERN_KDSETREG (rangetype): %s\n", strerror(errno
));
470 mib
[1] = KERN_KDEBUG
;
471 mib
[2] = KERN_KDSETUP
;
475 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
476 quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno
));
484 int mib
[] = { CTL_KERN
, KERN_KDEBUG
, KERN_KDSET_TYPEFILTER
};
485 size_t needed
= KDBG_TYPEFILTER_BITMAP_SIZE
;
487 if(sysctl(mib
, ARRAYSIZE(mib
), type_filter_bitmap
, &needed
, NULL
, 0)) {
488 quit_args("trace facility failure, KERN_KDSET_TYPEFILTER: %s\n", strerror(errno
));
496 kr
.type
= KDBG_VALCHECK
;
501 needed
= sizeof(kd_regtype
);
503 mib
[1] = KERN_KDEBUG
;
504 mib
[2] = KERN_KDSETREG
;
508 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
509 quit_args("trace facility failure, KERN_KDSETREG (valcheck): %s\n", strerror(errno
));
513 void readtrace(char *buffer
)
516 mib
[1] = KERN_KDEBUG
;
517 mib
[2] = KERN_KDREADTR
;
522 if (sysctl(mib
, 3, buffer
, &needed
, NULL
, 0) < 0)
523 quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno
));
527 int writetrace(int fd
)
530 mib
[1] = KERN_KDEBUG
;
531 mib
[2] = KERN_KDWRITETR
;
536 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
543 int write_command_map(int fd
)
546 mib
[1] = KERN_KDEBUG
;
547 mib
[2] = KERN_KDWRITEMAP
;
552 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
560 lookup_t
handle_lookup_event(uintptr_t thread
, int debugid
, kd_buf
*kdp
)
564 boolean_t first_record
= FALSE
;
566 hashid
= thread
& HASH_MASK
;
568 if (debugid
& DBG_FUNC_START
)
571 for (lkp
= lookup_hash
[hashid
]; lkp
; lkp
= lkp
->lk_next
) {
572 if (lkp
->lk_thread
== thread
)
576 if (first_record
== FALSE
)
579 if ((lkp
= lookup_freelist
))
580 lookup_freelist
= lkp
->lk_next
;
582 lkp
= (lookup_t
)malloc(sizeof(struct lookup
));
584 lkp
->lk_thread
= thread
;
586 lkp
->lk_next
= lookup_hash
[hashid
];
587 lookup_hash
[hashid
] = lkp
;
590 if (first_record
== TRUE
) {
591 lkp
->lk_pathptr
= lkp
->lk_pathname
;
592 lkp
->lk_dvp
= kdp
->arg1
;
594 if (lkp
->lk_pathptr
> &lkp
->lk_pathname
[NUMPARMS
-4])
597 *lkp
->lk_pathptr
++ = kdp
->arg1
;
599 *lkp
->lk_pathptr
++ = kdp
->arg2
;
600 *lkp
->lk_pathptr
++ = kdp
->arg3
;
601 *lkp
->lk_pathptr
++ = kdp
->arg4
;
602 *lkp
->lk_pathptr
= 0;
609 void delete_lookup_event(uintptr_t thread
, lookup_t lkp_to_delete
)
615 hashid
= thread
& HASH_MASK
;
617 if ((lkp
= lookup_hash
[hashid
])) {
618 if (lkp
== lkp_to_delete
)
619 lookup_hash
[hashid
] = lkp
->lk_next
;
623 for (lkp
= lkp
->lk_next
; lkp
; lkp
= lkp
->lk_next
) {
624 if (lkp
== lkp_to_delete
) {
625 lkp_prev
->lk_next
= lkp
->lk_next
;
632 lkp
->lk_next
= lookup_freelist
;
633 lookup_freelist
= lkp
;
640 void insert_start_event(uintptr_t thread
, int debugid
, uint64_t now
)
645 hashid
= thread
& HASH_MASK
;
647 for (evp
= event_hash
[hashid
]; evp
; evp
= evp
->ev_next
) {
648 if (evp
->ev_thread
== thread
&& evp
->ev_debugid
== debugid
)
652 if ((evp
= event_freelist
))
653 event_freelist
= evp
->ev_next
;
655 evp
= (event_t
)malloc(sizeof(struct event
));
657 evp
->ev_thread
= thread
;
658 evp
->ev_debugid
= debugid
;
660 evp
->ev_next
= event_hash
[hashid
];
661 event_hash
[hashid
] = evp
;
663 evp
->ev_timestamp
= now
;
668 uint64_t consume_start_event(uintptr_t thread
, int debugid
, uint64_t now
)
673 uint64_t elapsed
= 0;
675 hashid
= thread
& HASH_MASK
;
677 if ((evp
= event_hash
[hashid
])) {
678 if (evp
->ev_thread
== thread
&& evp
->ev_debugid
== debugid
)
679 event_hash
[hashid
] = evp
->ev_next
;
683 for (evp
= evp
->ev_next
; evp
; evp
= evp
->ev_next
) {
685 if (evp
->ev_thread
== thread
&& evp
->ev_debugid
== debugid
) {
686 evp_prev
->ev_next
= evp
->ev_next
;
693 elapsed
= now
- evp
->ev_timestamp
;
695 evp
->ev_next
= event_freelist
;
696 event_freelist
= evp
;
707 uint32_t buffer_size
;
714 if ((fd
= open(logfile
, O_TRUNC
|O_WRONLY
|O_CREAT
, 0777)) == -1) {
715 perror("Can't open logfile");
718 get_bufinfo(&bufinfo
);
720 if (bufinfo
.nolog
!= 1) {
722 set_enable(0); /* disable logging*/
724 get_bufinfo(&bufinfo
);
727 if (bufinfo
.flags
& KDBG_WRAPPED
)
728 printf("Buffer has wrapped\n");
730 printf("Buffer has not wrapped\n");
732 buffer_size
= 1000000 * sizeof(kd_buf
);
733 buffer
= malloc(buffer_size
);
735 if (buffer
== (char *) 0)
736 quit("can't allocate memory for tracing info\n");
738 read_command_map(0, 0);
741 raw_header
.version_no
= RAW_VERSION1
;
742 raw_header
.thread_count
= total_threads
;
743 raw_header
.TOD_secs
= time((long *)0);
744 raw_header
.TOD_usecs
= 0;
746 write(fd
, &raw_header
, sizeof(RAW_header
));
748 size
= total_threads
* sizeof(kd_threadmap
);
749 write(fd
, (char *)mapptr
, size
);
751 pad_size
= 4096 - ((sizeof(RAW_header
) + size
) & 4095);
754 size_t cpumap_size
= sizeof(kd_cpumap_header
) + cpumap_header
->cpu_count
* sizeof(kd_cpumap
);
755 if (pad_size
>= cpumap_size
) {
756 write(fd
, (char *)cpumap_header
, cpumap_size
);
757 pad_size
-= cpumap_size
;
761 memset(pad_buf
, 0, pad_size
);
762 write(fd
, pad_buf
, pad_size
);
765 needed
= buffer_size
;
771 write(fd
, buffer
, needed
* sizeof(kd_buf
));
784 int try_writetrace
= 1;
788 uint64_t sample_window_abs
;
789 uint64_t next_window_begins
;
790 uint64_t current_abs
;
791 uint64_t ending_abstime
;
792 uint64_t last_time_written
;
793 uint32_t us_to_sleep
;
794 uint32_t us_to_adjust
;
797 memset(&kd_tmp
, 0, sizeof(kd_tmp
));
799 if ((fd
= open(logfile
, O_TRUNC
|O_WRONLY
|O_CREAT
, 0777)) == -1) {
800 perror("Can't open logfile");
803 if (use_current_buf
== 0) {
805 * grab the number of cpus and scale the buffer size
810 len
= sizeof(num_cpus
);
812 sysctl(mib
, 2, &num_cpus
, &len
, NULL
, 0);
815 nbufs
= BASE_EVENTS
* num_cpus
;
827 /* Get kernel buffer information */
828 get_bufinfo(&bufinfo
);
830 buffer
= malloc(bufinfo
.nkdbufs
* sizeof(kd_buf
));
831 if (buffer
== (char *) 0)
832 quit("can't allocate memory for tracing info\n");
833 memset(buffer
, 0, bufinfo
.nkdbufs
* sizeof(kd_buf
));
835 if (use_current_buf
== 0)
838 if (write_command_map(fd
)) {
842 read_command_map(0, 0);
845 raw_header
.version_no
= RAW_VERSION1
;
846 raw_header
.thread_count
= total_threads
;
847 raw_header
.TOD_secs
= time((long *)0);
848 raw_header
.TOD_usecs
= 0;
850 write(fd
, &raw_header
, sizeof(RAW_header
));
852 size
= total_threads
* sizeof(kd_threadmap
);
853 write(fd
, (char *)mapptr
, size
);
855 pad_size
= 4096 - ((sizeof(RAW_header
) + size
) & 4095);
858 size_t cpumap_size
= sizeof(kd_cpumap_header
) + cpumap_header
->cpu_count
* sizeof(kd_cpumap
);
859 if (pad_size
>= cpumap_size
) {
860 write(fd
, (char *)cpumap_header
, cpumap_size
);
861 pad_size
-= cpumap_size
;
865 memset(pad_buf
, 0, pad_size
);
866 write(fd
, pad_buf
, pad_size
);
868 sample_window_abs
= (uint64_t)((double)US_TO_SLEEP
* divisor
);
870 next_window_begins
= mach_absolute_time() + sample_window_abs
;
873 ending_abstime
= mach_absolute_time() + (uint64_t)((double)secs_to_run
* (double)1000000 * divisor
);
874 ms_to_run
= secs_to_run
* 1000;
877 last_time_written
= mach_absolute_time();
879 while (LogRAW_flag
) {
880 current_abs
= mach_absolute_time();
882 if (try_writetrace
) {
889 current_abs
= mach_absolute_time();
891 printf("wrote %d events - elapsed time = %.1f secs\n",
892 (int)needed
, ((double)(current_abs
- last_time_written
) / divisor
) / 1000000);
894 last_time_written
= current_abs
;
898 if (try_writetrace
== 0) {
900 if (next_window_begins
> current_abs
)
901 us_to_adjust
= US_TO_SLEEP
- (uint32_t)((double)(next_window_begins
- current_abs
) / divisor
);
903 us_to_adjust
= US_TO_SLEEP
;
905 next_window_begins
= current_abs
+ sample_window_abs
;
907 us_to_sleep
= US_TO_SLEEP
- us_to_adjust
;
909 next_window_begins
= current_abs
+ (uint64_t)((double)(us_to_sleep
+ US_TO_SLEEP
) * divisor
);
914 get_bufinfo(&bufinfo
);
916 if (bufinfo
.flags
& KDBG_WRAPPED
)
917 printf("lost events\n");
919 needed
= bufinfo
.nkdbufs
* sizeof(kd_buf
);
923 if (bufinfo
.flags
& KDBG_WRAPPED
) {
925 kd
= (kd_buf
*) buffer
;
927 kd_tmp
.timestamp
= kd
[0].timestamp
;
928 kd_tmp
.debugid
= TRACE_LOST_EVENTS
;
930 write(fd
, &kd_tmp
, sizeof(kd_tmp
));
932 write(fd
, buffer
, needed
* sizeof(kd_buf
));
934 if (verbose_flag
&& needed
> nbufs
)
935 printf("needed = %ld\n", needed
);
938 current_abs
= mach_absolute_time();
940 if (current_abs
> ending_abstime
)
942 ms_to_run
= (ending_abstime
- current_abs
) / (1000 * 1000);
959 uint32_t buffer_size
;
966 uint32_t count_of_names
;
967 double last_event_time
= 0.0;
971 get_bufinfo(&bufinfo
);
973 if (bufinfo
.nolog
!= 1) {
975 set_enable(0); /* disable logging*/
978 if (bufinfo
.flags
& KDBG_WRAPPED
)
979 printf("Buffer has wrapped\n");
981 printf("Buffer has not wrapped\n");
987 fd
= open(RAW_file
, O_RDONLY
);
990 perror("Can't open file");
993 if (read(fd
, &raw_header
, sizeof(RAW_header
)) != sizeof(RAW_header
)) {
994 perror("read failed");
997 if (raw_header
.version_no
!= RAW_VERSION1
) {
998 raw_header
.version_no
= RAW_VERSION0
;
999 raw_header
.TOD_secs
= time((long *)0);
1000 raw_header
.TOD_usecs
= 0;
1002 lseek(fd
, (off_t
)0, SEEK_SET
);
1004 if (read(fd
, &raw_header
.thread_count
, sizeof(int)) != sizeof(int)) {
1005 perror("read failed");
1009 count_of_names
= raw_header
.thread_count
;
1010 trace_time
= (time_t) (raw_header
.TOD_secs
);
1012 printf("%s\n", ctime(&trace_time
));
1014 buffer_size
= 1000000 * sizeof(kd_buf
);
1015 buffer
= malloc(buffer_size
);
1017 if (buffer
== (char *) 0)
1018 quit("can't allocate memory for tracing info\n");
1020 kd
= (kd_buf
*)buffer
;
1022 read_command_map(fd
, count_of_names
);
1034 double event_elapsed_time
;
1037 boolean_t ending_event
;
1046 if (!readRAW_flag
) {
1047 needed
= buffer_size
;
1050 mib
[1] = KERN_KDEBUG
;
1051 mib
[2] = KERN_KDREADTR
;
1055 if (sysctl(mib
, 3, buffer
, &needed
, NULL
, 0) < 0)
1056 quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno
));
1063 uint32_t bytes_read
;
1065 bytes_read
= read(fd
, buffer
, buffer_size
);
1067 if (bytes_read
== -1) {
1068 perror("read failed");
1071 count
= bytes_read
/ sizeof(kd_buf
);
1076 for (kdp
= &kd
[0], i
= 0; i
< count
; i
++, kdp
++) {
1079 debugid
= kdp
->debugid
;
1080 debugid_base
= debugid
& DBG_FUNC_MASK
;
1081 now
= kdp
->timestamp
& KDBG_TIMESTAMP_MASK
;
1087 cpunum
= kdbg_get_cpu(kdp
);
1090 if (lines
== 64 || firsttime
)
1092 prevdelta
= now
- prevdelta
;
1097 x
= (double)prevdelta
;
1100 fprintf(output_file
, "\n\nNumber of microsecs since in last page %8.1f\n", x
);
1105 * Output description row to output file (make sure to format correctly for 32-bit and 64-bit)
1107 fprintf(output_file
,
1109 " AbsTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu# command\n\n"
1111 " AbsTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu# command\n\n"
1117 if (io_lines
> 15000) {
1118 fcntl(output_fd
, F_FLUSH_DATA
, 0);
1125 if (debugid_base
== VFS_LOOKUP
) {
1126 lkp
= handle_lookup_event(thread
, debugid
, kdp
);
1128 if ( !lkp
|| !(debugid
& DBG_FUNC_END
))
1134 if (last_event_time
)
1135 y
= x
- last_event_time
;
1138 last_event_time
= x
;
1139 ending_event
= FALSE
;
1142 * Is this event from an IOP? If so, there will be no
1143 * thread command, label it with the symbolic IOP name
1145 if (cpumap
&& (cpunum
< cpumap_header
->cpu_count
) && (cpumap
[cpunum
].flags
& KDBG_CPUMAP_IS_IOP
)) {
1146 command
= cpumap
[cpunum
].name
;
1148 find_thread_command(kdp
, &command
);
1152 * The internal use TRACE points clutter the output.
1153 * Print them only if in verbose mode.
1157 /* Is this entry of Class DBG_TRACE */
1158 if ((debugid
>> 24) == DBG_TRACE
) {
1159 if (((debugid
>> 16) & 0xff) != DBG_TRACE_INFO
)
1167 if ((debugid
& DBG_FUNC_START
) || debugid
== MACH_MAKERUNNABLE
) {
1169 if (debugid_base
!= BSC_thread_terminate
&& debugid_base
!= BSC_exit
) {
1171 if (debugid
== MACH_MAKERUNNABLE
)
1172 t_thread
= kdp
->arg1
;
1176 insert_start_event(t_thread
, debugid_base
, now
);
1179 } else if ((debugid
& DBG_FUNC_END
) || debugid
== MACH_STKHANDOFF
|| debugid
== MACH_SCHEDULED
) {
1181 if (debugid
== MACH_STKHANDOFF
|| debugid
== MACH_SCHEDULED
) {
1182 t_debugid
= MACH_MAKERUNNABLE
;
1183 t_thread
= kdp
->arg2
;
1185 t_debugid
= debugid_base
;
1188 event_elapsed_time
= (double)consume_start_event(t_thread
, t_debugid
, now
);
1189 event_elapsed_time
/= divisor
;
1190 ending_event
= TRUE
;
1192 if (event_elapsed_time
== 0 && (debugid
== MACH_STKHANDOFF
|| debugid
== MACH_SCHEDULED
))
1193 ending_event
= FALSE
;
1199 sprintf(&outbuf
[0], "(%-10.1f)", event_elapsed_time
);
1201 * fix that right paren
1206 ch
= strchr (&outbuf
[0], ')');
1213 while (ch
!= &outbuf
[0])
1225 if (match_debugid(debugid_base
, dbgmessge
, &dmsgindex
)) {
1227 fprintf(output_file
, "%13.1f %10.1f%s %-28x ", x
, y
, outbuf
, debugid_base
);
1229 fprintf(output_file
, "%13.1f %10.1f %-28x ", x
, y
, debugid_base
);
1232 fprintf(output_file
, "%13.1f %10.1f%s %-28.28s ", x
, y
, outbuf
, dbgmessge
);
1234 fprintf(output_file
, "%13.1f %10.1f %-28.28s ", x
, y
, dbgmessge
);
1240 strptr
= (char *)lkp
->lk_pathname
;
1243 * print the tail end of the pathname
1245 len
= strlen(strptr
);
1252 fprintf(output_file
, "%-16lx %-51s %-16lx %-2d %s\n", lkp
->lk_dvp
, &strptr
[len
], thread
, cpunum
, command
);
1254 fprintf(output_file
, "%-8x %-51s %-8lx %-2d %s\n", (unsigned int)lkp
->lk_dvp
, &strptr
[len
], thread
, cpunum
, command
);
1256 delete_lookup_event(thread
, lkp
);
1257 } else if (debugid
== TRACE_INFO_STRING
) {
1259 fprintf(output_file
, "%-32s%-36s %-16lx %-2d %s\n", (char *) &kdp
->arg1
, "", thread
, cpunum
, command
);
1261 fprintf(output_file
, "%-16s%-46s %-8lx %-2d %s\n", (char *) &kdp
->arg1
, "", thread
, cpunum
, command
);
1265 fprintf(output_file
, "%-16lx %-16lx %-16lx %-16lx %-16lx %-2d %s\n", kdp
->arg1
, kdp
->arg2
, kdp
->arg3
, kdp
->arg4
, thread
, cpunum
, command
);
1267 fprintf(output_file
, "%-8lx %-8lx %-8lx %-8lx %-8lx %-2d %s\n", kdp
->arg1
, kdp
->arg2
, kdp
->arg3
, kdp
->arg4
, thread
, cpunum
, command
);
1275 set_enable(1); /* re-enable kernel logging */
1280 void signal_handler(int sig
)
1282 ptrace(PT_KILL
, pid
, (caddr_t
)0, 0);
1284 * child is gone; no need to disable the pid
1290 void signal_handler_RAW(int sig
)
1297 int main(argc
, argv
, env
)
1302 extern char *optarg
;
1307 char *output_filename
= NULL
;
1308 char *filter_filename
= NULL
;
1309 unsigned int parsed_arg
;
1311 for (i
= 1; i
< argc
; i
++) {
1312 if (strcmp("-X", argv
[i
]) == 0) {
1313 force_32bit_exec
= 1;
1317 if (force_32bit_exec
) {
1318 if (0 != reexec_to_match_lp64ness(FALSE
)) {
1319 fprintf(stderr
, "Could not re-execute: %d\n", errno
);
1323 if (0 != reexec_to_match_kernel()) {
1324 fprintf(stderr
, "Could not re-execute: %d\n", errno
);
1328 if (setiopolicy_np(IOPOL_TYPE_DISK
, IOPOL_SCOPE_PROCESS
, IOPOL_PASSIVE
) < 0) {
1329 printf("setiopolicy failed\n");
1332 output_file
= stdout
;
1335 while ((ch
= getopt(argc
, argv
, "hedEk:irb:gc:p:s:tR:L:l:S:F:a:x:Xnfvo:PT:N")) != EOF
)
1339 case 'h': /* help */
1343 secs_to_run
= argtoi('S', "decimal number", optarg
, 10);
1345 case 'a': /* set tracing on a pid */
1347 pid
= argtoi('a', "decimal number", optarg
, 10);
1349 case 'x': /* exclude a pid from tracing */
1351 pid
= argtoi('x', "decimal number", optarg
, 10);
1363 signal(SIGINT
, signal_handler_RAW
);
1379 value1
= (unsigned int) argtoul('k', "hex number", optarg
, 16);
1380 else if (kval_flag
== 1)
1381 value2
= (unsigned int) argtoul('k', "hex number", optarg
, 16);
1382 else if (kval_flag
== 2)
1383 value3
= (unsigned int) argtoul('k', "hex number", optarg
, 16);
1384 else if (kval_flag
== 3)
1385 value4
= (unsigned int) argtoul('k', "hex number", optarg
, 16);
1388 fprintf(stderr
, "A maximum of four values can be specified with -k\n");
1414 nbufs
= argtoi('b', "decimal number", optarg
, 10);
1418 parsed_arg
= argtoi('c', "decimal, hex, or octal number", optarg
, 0);
1419 if (parsed_arg
> 0xFF)
1420 quit_args("argument '-c %s' parsed as %u, "
1421 "class value must be 0-255\n", optarg
, parsed_arg
);
1422 saw_filter_class(parsed_arg
);
1426 parsed_arg
= argtoi('s', "decimal, hex, or octal number", optarg
, 0);
1427 if (parsed_arg
> 0xFF)
1428 quit_args("argument '-s %s' parsed as %u, "
1429 "subclass value must be 0-255\n", optarg
, parsed_arg
);
1430 saw_filter_subclass(parsed_arg
);
1434 parsed_arg
= argtoi('p', "decimal, hex, or octal number", optarg
, 0);
1435 if (parsed_arg
> 0xFF)
1436 quit_args("argument '-p %s' parsed as %u, "
1437 "end range value must be 0-255\n", optarg
, parsed_arg
);
1438 saw_filter_end_range(parsed_arg
);
1444 output_filename
= optarg
;
1447 frequency
= argtoi('F', "decimal number", optarg
, 10);
1452 no_default_codes_flag
= 1;
1457 // Flush out any unclosed -c argument
1458 filter_done_parsing();
1460 parse_filter_file(optarg
);
1468 if (!no_default_codes_flag
)
1471 printf("Adding default code file /usr/share/misc/trace.codes. Use '-N' to skip this.\n");
1472 parse_codefile("/usr/share/misc/trace.codes");
1481 const char *cfile
= argv
[optind
++];
1482 if (verbose_flag
) printf("Adding code file %s \n", cfile
);
1483 parse_codefile(cfile
);
1490 quit_args("-E flag needs an executable to launch\n");
1498 if (pid_flag
&& pid_exflag
)
1499 quit_args("Can't use both -a and -x flag together\n");
1501 if (kval_flag
&& filter_flag
)
1502 quit_args("Cannot use -k flag with -c, -s, or -p\n");
1504 if (output_filename
&& !trace_flag
&& !readRAW_flag
)
1505 quit_args("When using 'o' option, must use the 't' or 'R' option too\n");
1507 filter_done_parsing();
1512 get_bufinfo(&bufinfo
);
1514 if (bufinfo
.nolog
== 0)
1515 use_current_buf
= 1;
1522 set_pidcheck(pid
, 0); /* disable pid check for given pid */
1525 else if (pid_exflag
)
1527 set_pidexclude(pid
, 0); /* disable pid exclusion for given pid */
1542 if (!init_flag
&& !LogRAW_flag
)
1544 fprintf(stderr
,"The -b flag must be used with the -i flag\n");
1558 get_bufinfo(&bufinfo
);
1560 printf("The kernel buffer settings are:\n");
1562 if (bufinfo
.flags
& KDBG_BUFINIT
)
1563 printf("\tKernel buffer is initialized\n");
1565 printf("\tKernel buffer is not initialized\n");
1567 printf("\t number of buf entries = %d\n", bufinfo
.nkdbufs
);
1571 if (bufinfo
.flags
& KDBG_MAPINIT
)
1572 printf("\tKernel thread map is initialized\n");
1574 printf("\tKernel thread map is not initialized\n");
1575 printf("\t number of thread entries = %d\n", bufinfo
.nkdthreads
);
1579 printf("\tBuffer logging is disabled\n");
1581 printf("\tBuffer logging is enabled\n");
1584 printf("\tkernel flags = 0x%x\n", bufinfo
.flags
);
1586 if (bufinfo
.flags
& KDBG_NOWRAP
)
1587 printf("\tKernel buffer wrap is disabled\n");
1589 printf("\tKernel buffer wrap is enabled\n");
1591 if (bufinfo
.flags
& KDBG_RANGECHECK
)
1592 printf("\tCollection within a range is enabled\n");
1594 printf("\tCollection within a range is disabled\n");
1596 if (bufinfo
.flags
& KDBG_VALCHECK
)
1597 printf("\tCollecting specific code values is enabled\n");
1599 printf("\tCollecting specific code values is disabled\n");
1601 if (bufinfo
.flags
& KDBG_TYPEFILTER_CHECK
)
1602 printf("\tCollection based on a filter is enabled\n");
1604 printf("\tCollection based on a filter is disabled\n");
1606 if (bufinfo
.flags
& KDBG_PIDCHECK
)
1607 printf("\tCollection based on pid is enabled\n");
1609 printf("\tCollection based on pid is disabled\n");
1611 if (bufinfo
.flags
& KDBG_PIDEXCLUDE
)
1612 printf("\tCollection based on pid exclusion is enabled\n");
1614 printf("\tCollection based on pid exclusion is disabled\n");
1616 if (bufinfo
.bufid
== -1)
1617 printf("\tKernel buffer is not controlled by any process.\n");
1619 printf("\tKernel buffer is controlled by proc id [%d]\n", bufinfo
.bufid
);
1633 fprintf(stderr
, "Starting program: %s\n", argv
[optind
]);
1637 switch ((pid
= vfork()))
1644 ptrace(PT_TRACE_ME
, 0, (caddr_t
)0, 0);
1645 execve(argv
[optind
], &argv
[optind
], environ
);
1651 signal(SIGINT
, signal_handler
);
1652 set_pidcheck(pid
, 1);
1654 ptrace(PT_CONTINUE
, pid
, (caddr_t
)1, 0);
1655 waitpid(pid
, &status
, 0);
1656 /* child is gone; no need to disable the pid */
1659 else if (enable_flag
)
1662 set_pidcheck(pid
, 1);
1663 else if (pid_exflag
)
1664 set_pidexclude(pid
, 1);
1668 if (output_filename
)
1670 if (((output_fd
= open(output_filename
, O_CREAT
| O_TRUNC
| O_WRONLY
| O_APPEND
, 0644)) < 0 ) ||
1671 !(output_file
= fdopen(output_fd
, "w")))
1673 fprintf(stderr
, "Cannot open file \"%s\" for writing.\n", output_filename
);
1676 setbuffer(output_file
, &sbuffer
[0], SBUFFER_SIZE
);
1678 if (fcntl(output_fd
, F_NOCACHE
, 1) < 0)
1681 fprintf(stderr
, "Warning: setting F_NOCACHE on %s, failed\n", output_filename
);
1684 if (!LogRAW_flag
&& !logRAW_flag
)
1685 setbuffer(output_file
, &sbuffer
[0], SBUFFER_SIZE
);
1687 if (trace_flag
|| readRAW_flag
)
1689 else if (LogRAW_flag
)
1691 else if (logRAW_flag
)
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 base_offset
= lseek(fd
, (off_t
)0, SEEK_CUR
);
2516 off_t aligned_offset
= (base_offset
+ (4095)) & ~4095; /* <rdar://problem/13500105> */
2518 size_t padding_bytes
= (size_t)(aligned_offset
- base_offset
);
2520 if (read(fd
, cpumap_header
, padding_bytes
) == padding_bytes
) {
2521 if (cpumap_header
->version_no
== RAW_VERSION1
) {
2522 cpumap
= (kd_cpumap
*)&cpumap_header
[1];
2530 mib
[1] = KERN_KDEBUG
;
2531 mib
[2] = KERN_KDCPUMAP
;
2533 size_t temp
= PAGE_SIZE
;
2534 if (sysctl(mib
, 3, cpumap_header
, &temp
, NULL
, 0) == 0) {
2535 if (PAGE_SIZE
>= temp
) {
2536 if (cpumap_header
->version_no
== RAW_VERSION1
) {
2537 cpumap
= (kd_cpumap
*)&cpumap_header
[1];
2544 printf("Can't read the cpu map -- this is not fatal\n");
2545 free(cpumap_header
);
2546 cpumap_header
= NULL
;
2547 } else if (verbose_flag
) {
2548 /* Dump the initial cpumap */
2549 printf("\nCPU\tName\n");
2550 for (int i
= 0; i
< cpumap_header
->cpu_count
; i
++) {
2551 printf ("%2d\t%s\n", cpumap
[i
].cpu_id
, cpumap
[i
].name
);
2558 read_command_map(int fd
, uint32_t count
)
2565 total_threads
= count
;
2566 size
= count
* sizeof(kd_threadmap
);
2568 get_bufinfo(&bufinfo
);
2570 total_threads
= bufinfo
.nkdthreads
;
2571 size
= bufinfo
.nkdthreads
* sizeof(kd_threadmap
);
2574 nthreads
= total_threads
* 2;
2577 printf("Size of map table is %d, thus %d entries\n", (int)size
, total_threads
);
2580 if ((mapptr
= (kd_threadmap
*) malloc(size
)))
2581 bzero (mapptr
, size
);
2585 printf("Thread map is not initialized -- this is not fatal\n");
2590 if (read(fd
, mapptr
, size
) != size
) {
2592 printf("Can't read the thread map -- this is not fatal\n");
2599 /* Now read the threadmap */
2601 mib
[1] = KERN_KDEBUG
;
2602 mib
[2] = KERN_KDTHRMAP
;
2605 mib
[5] = 0; /* no flags */
2606 if (sysctl(mib
, 3, mapptr
, &size
, NULL
, 0) < 0)
2608 /* This is not fatal -- just means I cant map command strings */
2610 printf("Can't read the thread map -- this is not fatal\n");
2616 for (i
= 0; i
< total_threads
; i
++) {
2617 if (mapptr
[i
].thread
)
2618 create_map_entry(mapptr
[i
].thread
, &mapptr
[i
].command
[0]);
2622 /* Dump the initial map */
2624 printf("Size of maptable returned is %ld, thus %ld entries\n", size
, (size
/sizeof(kd_threadmap
)));
2626 printf("Thread Command\n");
2627 for (i
= 0; i
< total_threads
; i
++) {
2628 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
);