2 cc -I/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders -arch x86_64 -arch i386 -O -o trace trace.c
6 * NOTE: There exists another copy of this file in the kernel_tools. Changes
7 * made here may also need to be made there.
10 #include <sys/param.h>
11 #include <sys/types.h>
13 #include <sys/socket.h>
15 #include <sys/ioctl.h>
18 #include <sys/ucred.h>
21 #include <sys/ptrace.h>
22 #include <sys/sysctl.h>
24 #include <sys/resource.h>
42 #ifndef KERNEL_PRIVATE
43 #define KERNEL_PRIVATE
44 #include <sys/kdebug.h>
47 #include <sys/kdebug.h>
48 #endif /*KERNEL_PRIVATE*/
49 #include <sys/param.h>
51 #include <mach/mach.h>
52 #include <mach/mach_time.h>
67 int filter_file_flag
=0;
78 int no_default_codes_flag
=0;
80 unsigned int value1
=0;
81 unsigned int value2
=0;
82 unsigned int value3
=0;
83 unsigned int value4
=0;
88 int force_32bit_exec
= 0;
94 char *logfile
= (char *)0; /* This file is trace format */
95 char *RAW_file
= (char *)0;
99 extern char **environ
;
101 uint8_t* type_filter_bitmap
;
103 #define SIZE_4KB (4 * (1 << 10))
105 #define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
106 #define DBG_FUNC_MASK 0xfffffffc
110 #define CSC_MASK 0xffff0000
112 #define BSC_exit 0x040c0004
113 #define BSC_thread_terminate 0x040c05a4
114 #define MACH_SCHEDULED 0x01400000
115 #define MACH_MAKERUNNABLE 0x01400018
116 #define MACH_STKHANDOFF 0x01400008
118 #define EMPTYSTRING ""
119 #define UNKNOWN "unknown"
121 char tmpcommand
[MAXCOMLEN
];
123 int total_threads
= 0;
125 kd_threadmap
*mapptr
= 0;
127 kd_cpumap_header
* cpumap_header
= NULL
;
128 kd_cpumap
* cpumap
= NULL
;
131 If NUMPARMS changes from the kernel,
132 then PATHLENGTH will also reflect the change
133 This is for the vfslookup entries that
137 #define PATHLENGTH (NUMPARMS*sizeof(long))
140 #define US_TO_SLEEP 50000
141 #define BASE_EVENTS 500000
143 mach_timebase_info_data_t mach_timebase
;
151 code_type_t
* codesc
= 0;
152 size_t codesc_idx
= 0; // Index into first empty codesc entry
156 typedef struct event
*event_t
;
163 uint64_t ev_timestamp
;
166 typedef struct lookup
*lookup_t
;
174 long lk_pathname
[NUMPARMS
+ 1];
177 typedef struct threadmap
*threadmap_t
;
183 uintptr_t tm_pthread
;
184 boolean_t tm_deleteme
;
185 char tm_command
[MAXCOMLEN
+ 1];
188 #define HASH_SIZE 1024
189 #define HASH_MASK 1023
191 event_t event_hash
[HASH_SIZE
];
192 lookup_t lookup_hash
[HASH_SIZE
];
193 threadmap_t threadmap_hash
[HASH_SIZE
];
195 event_t event_freelist
;
196 lookup_t lookup_freelist
;
197 threadmap_t threadmap_freelist
;
198 threadmap_t threadmap_temp
;
201 #define SBUFFER_SIZE (128 * 4096)
202 char sbuffer
[SBUFFER_SIZE
];
205 int use_current_buf
= 0;
208 kbufinfo_t bufinfo
= {0, 0, 0, 0};
211 int codeindx_cache
= 0;
213 static void quit(char *);
214 static int match_debugid(unsigned int, char *, int *);
215 static void usage(int short_help
);
216 static int argtoi(int flag
, char *req
, char *str
, int base
);
217 static int parse_codefile(const char *filename
);
218 static void codesc_find_dupes(void);
219 static int read_command_map(int, uint32_t);
220 static void read_cpu_map(int);
221 static void find_thread_command(kd_buf
*, char **);
222 static void create_map_entry(uintptr_t, char *);
223 static void getdivisor();
224 static unsigned long argtoul();
226 static void set_enable(int);
227 static void set_remove();
228 static void set_nowrap();
229 static void set_pidcheck(int, int);
230 static void set_pidexclude(int, int);
231 static void set_numbufs(int);
232 static void set_freerun();
233 static void get_bufinfo(kbufinfo_t
*);
234 static int get_ktrace_state(void);
235 static void set_init();
236 static void set_kval_list();
237 static void readtrace(char *);
238 static void log_trace();
239 static void Log_trace();
240 static void read_trace();
241 static void signal_handler(int);
242 static void signal_handler_RAW(int);
243 static void delete_thread_entry(uintptr_t);
244 static void find_and_insert_tmp_map_entry(uintptr_t, char *);
245 static void create_tmp_map_entry(uintptr_t, uintptr_t);
246 static void find_thread_name(uintptr_t, char **, boolean_t
);
247 static void execute_process(char * const argv
[]);
249 static int writetrace(int);
250 static int write_command_map(int);
251 static int debugid_compar(const void *, const void *);
253 static threadmap_t
find_thread_entry(uintptr_t);
255 static void saw_filter_class(uint8_t class);
256 static void saw_filter_end_range(uint8_t end_class
);
257 static void saw_filter_subclass(uint8_t subclass
);
258 static void filter_done_parsing(void);
260 static void set_filter(void);
261 static void set_filter_class(uint8_t class);
262 static void set_filter_range(uint8_t class, uint8_t end
);
263 static void set_filter_subclass(uint8_t class, uint8_t subclass
);
265 static void parse_filter_file(char *filename
);
267 static void quit_args(const char *fmt
, ...) __printflike(1, 2);
269 #ifndef KERN_KDWRITETR
270 #define KERN_KDWRITETR 17
273 #ifndef KERN_KDWRITEMAP
274 #define KERN_KDWRITEMAP 18
278 #define F_FLUSH_DATA 40
289 #define RAW_VERSION0 0x55aa0000
290 #define RAW_VERSION1 0x55aa0101
293 #define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(*x)))
295 #define EXTRACT_CLASS_LOW(debugid) ( (uint8_t) ( ((debugid) & 0xFF00 ) >> 8 ) )
296 #define EXTRACT_SUBCLASS_LOW(debugid) ( (uint8_t) ( ((debugid) & 0xFF ) ) )
298 #define ENCODE_CSC_LOW(class, subclass) \
299 ( (uint16_t) ( ((class) & 0xff) << 8 ) | ((subclass) & 0xff) )
301 RAW_header raw_header
;
305 void set_enable(int val
)
308 mib
[1] = KERN_KDEBUG
;
309 mib
[2] = KERN_KDENABLE
;
310 #ifdef KDEBUG_ENABLE_PPT
311 if (ppt_flag
&& val
) {
312 mib
[3] = KDEBUG_ENABLE_PPT
;
321 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0) {
322 if (errno
== EINVAL
) {
323 quit_args("trace facility failure, KERN_KDENABLE: trace buffer is uninitialized\n");
325 quit_args("trace facility failure, KERN_KDENABLE: %s\n", strerror(errno
));
329 void set_remove(void)
336 mib
[1] = KERN_KDEBUG
;
337 mib
[2] = KERN_KDREMOVE
;
341 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
344 quit("the trace facility is currently in use...\n fs_usage, sc_usage, trace, and latency use this feature.\n\n");
346 quit_args("trace facility failure, KERN_KDREMOVE: %s\n", strerror(errno
));
350 void set_numbufs(int nbufs
)
353 mib
[1] = KERN_KDEBUG
;
354 mib
[2] = KERN_KDSETBUF
;
358 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
359 quit_args("trace facility failure, KERN_KDSETBUF: %s\n", strerror(errno
));
362 mib
[1] = KERN_KDEBUG
;
363 mib
[2] = KERN_KDSETUP
;
367 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
368 quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno
));
371 void set_nowrap(void)
374 mib
[1] = KERN_KDEBUG
;
375 mib
[2] = KERN_KDEFLAGS
;
376 mib
[3] = KDBG_NOWRAP
;
378 mib
[5] = 0; /* no flags */
379 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
380 quit_args("trace facility failure, KDBG_NOWRAP: %s\n", strerror(errno
));
384 void set_pidcheck(int pid
, int on_off_flag
)
388 kr
.type
= KDBG_TYPENONE
;
390 kr
.value2
= on_off_flag
;
391 needed
= sizeof(kd_regtype
);
393 mib
[1] = KERN_KDEBUG
;
394 mib
[2] = KERN_KDPIDTR
;
398 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
402 quit_args("trace facility failure, setting pid filter: %s\n",
405 else if (on_off_flag
== 1 && errno
== ESRCH
)
408 quit_args("trace facility failure, setting pid filter: "
409 "pid %d does not exist\n", pid
);
413 quit_args("trace facility failure, KERN_KDPIDTR: %s\n", strerror(errno
));
418 void set_pidexclude(int pid
, int on_off_flag
)
422 kr
.type
= KDBG_TYPENONE
;
424 kr
.value2
= on_off_flag
;
425 needed
= sizeof(kd_regtype
);
427 mib
[1] = KERN_KDEBUG
;
428 mib
[2] = KERN_KDPIDEX
;
432 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
434 if (on_off_flag
== 1)
436 printf ("pid %d does not exist\n", pid
);
443 void set_freerun(void)
446 mib
[1] = KERN_KDEBUG
;
447 mib
[2] = KERN_KDEFLAGS
;
448 mib
[3] = KDBG_FREERUN
;
451 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
452 quit_args("trace facility failure, KDBG_FREERUN: %s\n", strerror(errno
));
455 static int get_ktrace_state(void)
458 size_t state_size
= sizeof(state
);
459 int err
= sysctlbyname("ktrace.state", &state
, &state_size
, NULL
, 0);
461 fprintf(stderr
, "error: could not query ktrace.state sysctl (%d: %s)\n", errno
, strerror(errno
));
467 void get_bufinfo(kbufinfo_t
*val
)
469 needed
= sizeof (*val
);
471 mib
[1] = KERN_KDEBUG
;
472 mib
[2] = KERN_KDGETBUF
;
476 if (sysctl(mib
, 3, val
, &needed
, 0, 0) < 0)
477 quit_args("trace facility failure, KERN_KDGETBUF: %s\n", strerror(errno
));
484 kr
.type
= KDBG_RANGETYPE
;
487 needed
= sizeof(kd_regtype
);
489 mib
[1] = KERN_KDEBUG
;
490 mib
[2] = KERN_KDSETREG
;
494 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
495 quit_args("trace facility failure, KERN_KDSETREG (rangetype): %s\n", strerror(errno
));
498 mib
[1] = KERN_KDEBUG
;
499 mib
[2] = KERN_KDSETUP
;
503 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
504 quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno
));
511 int mib
[] = { CTL_KERN
, KERN_KDEBUG
, KERN_KDSET_TYPEFILTER
};
512 size_t needed
= KDBG_TYPEFILTER_BITMAP_SIZE
;
514 if(sysctl(mib
, ARRAYSIZE(mib
), type_filter_bitmap
, &needed
, NULL
, 0)) {
515 quit_args("trace facility failure, KERN_KDSET_TYPEFILTER: %s\n", strerror(errno
));
519 void set_kval_list(void)
523 kr
.type
= KDBG_VALCHECK
;
528 needed
= sizeof(kd_regtype
);
530 mib
[1] = KERN_KDEBUG
;
531 mib
[2] = KERN_KDSETREG
;
535 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
536 quit_args("trace facility failure, KERN_KDSETREG (valcheck): %s\n", strerror(errno
));
540 void readtrace(char *buffer
)
543 mib
[1] = KERN_KDEBUG
;
544 mib
[2] = KERN_KDREADTR
;
549 if (sysctl(mib
, 3, buffer
, &needed
, NULL
, 0) < 0)
550 quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno
));
554 int writetrace(int fd
)
557 mib
[1] = KERN_KDEBUG
;
558 mib
[2] = KERN_KDWRITETR
;
563 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
570 int write_command_map(int fd
)
573 mib
[1] = KERN_KDEBUG
;
574 mib
[2] = KERN_KDWRITEMAP
;
579 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0) {
580 if (errno
== ENODATA
) {
582 printf("Cannot write thread map -- this is not fatal\n");
594 lookup_t
handle_lookup_event(uintptr_t thread
, int debugid
, kd_buf
*kdp
)
598 boolean_t first_record
= FALSE
;
600 hashid
= thread
& HASH_MASK
;
602 if (debugid
& DBG_FUNC_START
)
605 for (lkp
= lookup_hash
[hashid
]; lkp
; lkp
= lkp
->lk_next
) {
606 if (lkp
->lk_thread
== thread
)
610 if (first_record
== FALSE
)
613 if ((lkp
= lookup_freelist
))
614 lookup_freelist
= lkp
->lk_next
;
616 lkp
= (lookup_t
)malloc(sizeof(struct lookup
));
618 lkp
->lk_thread
= thread
;
620 lkp
->lk_next
= lookup_hash
[hashid
];
621 lookup_hash
[hashid
] = lkp
;
624 if (first_record
== TRUE
) {
625 lkp
->lk_pathptr
= lkp
->lk_pathname
;
626 lkp
->lk_dvp
= kdp
->arg1
;
628 if (lkp
->lk_pathptr
> &lkp
->lk_pathname
[NUMPARMS
-4])
631 *lkp
->lk_pathptr
++ = kdp
->arg1
;
633 *lkp
->lk_pathptr
++ = kdp
->arg2
;
634 *lkp
->lk_pathptr
++ = kdp
->arg3
;
635 *lkp
->lk_pathptr
++ = kdp
->arg4
;
636 *lkp
->lk_pathptr
= 0;
643 void delete_lookup_event(uintptr_t thread
, lookup_t lkp_to_delete
)
649 hashid
= thread
& HASH_MASK
;
651 if ((lkp
= lookup_hash
[hashid
])) {
652 if (lkp
== lkp_to_delete
)
653 lookup_hash
[hashid
] = lkp
->lk_next
;
657 for (lkp
= lkp
->lk_next
; lkp
; lkp
= lkp
->lk_next
) {
658 if (lkp
== lkp_to_delete
) {
659 lkp_prev
->lk_next
= lkp
->lk_next
;
666 lkp
->lk_next
= lookup_freelist
;
667 lookup_freelist
= lkp
;
674 void insert_start_event(uintptr_t thread
, int debugid
, uint64_t now
)
679 hashid
= thread
& HASH_MASK
;
681 for (evp
= event_hash
[hashid
]; evp
; evp
= evp
->ev_next
) {
682 if (evp
->ev_thread
== thread
&& evp
->ev_debugid
== debugid
)
686 if ((evp
= event_freelist
))
687 event_freelist
= evp
->ev_next
;
689 evp
= (event_t
)malloc(sizeof(struct event
));
691 evp
->ev_thread
= thread
;
692 evp
->ev_debugid
= debugid
;
694 evp
->ev_next
= event_hash
[hashid
];
695 event_hash
[hashid
] = evp
;
697 evp
->ev_timestamp
= now
;
702 uint64_t consume_start_event(uintptr_t thread
, int debugid
, uint64_t now
)
707 uint64_t elapsed
= 0;
709 hashid
= thread
& HASH_MASK
;
711 if ((evp
= event_hash
[hashid
])) {
712 if (evp
->ev_thread
== thread
&& evp
->ev_debugid
== debugid
)
713 event_hash
[hashid
] = evp
->ev_next
;
717 for (evp
= evp
->ev_next
; evp
; evp
= evp
->ev_next
) {
719 if (evp
->ev_thread
== thread
&& evp
->ev_debugid
== debugid
) {
720 evp_prev
->ev_next
= evp
->ev_next
;
727 elapsed
= now
- evp
->ev_timestamp
;
729 evp
->ev_next
= event_freelist
;
730 event_freelist
= evp
;
742 uint32_t buffer_size
= 1000000 * sizeof(kd_buf
);
744 if (logfile
[0] == '-' && logfile
[1] == '\0') {
747 fd
= open(logfile
, O_TRUNC
| O_WRONLY
| O_CREAT
, 0777);
751 perror("Can't open logfile");
754 get_bufinfo(&bufinfo
);
756 if (bufinfo
.nolog
!= 1) {
758 set_enable(0); /* disable logging*/
760 get_bufinfo(&bufinfo
);
763 if (bufinfo
.flags
& KDBG_WRAPPED
)
764 printf("Buffer has wrapped\n");
766 printf("Buffer has not wrapped\n");
769 ret
= write_command_map(fd
);
772 perror("failed to write logfile");
776 buffer
= malloc(buffer_size
);
777 if (buffer
== NULL
) {
778 quit("can't allocate memory for events\n");
782 needed
= buffer_size
;
790 write(fd
, buffer
, needed
* sizeof(kd_buf
));
799 * Why does this function exist?
800 * trace -L needs millisecond level wait times.
801 * When this code is running remotely, the mach_timebase_info_t data may
802 * be from a device with a different timebase. This code avoids using
803 * mach_absolute_time(), so that time calculations come out correct both
804 * locally and remotely.
806 static uint64_t current_millis() {
808 gettimeofday(&time
, NULL
);
809 return (time
.tv_sec
* 1000) + (time
.tv_usec
/ 1000);
819 uint64_t ending_ms
= 0;
820 uint64_t last_time_written
;
823 if ((fd
= open(logfile
, O_TRUNC
|O_WRONLY
|O_CREAT
, 0777)) == -1) {
824 perror("Can't open logfile");
827 if (use_current_buf
== 0) {
829 * grab the number of cpus and scale the buffer size
834 len
= sizeof(num_cpus
);
836 sysctl(mib
, 2, &num_cpus
, &len
, NULL
, 0);
839 nbufs
= BASE_EVENTS
* num_cpus
;
852 if (use_current_buf
== 0)
855 if (write_command_map(fd
)) {
856 quit("can't write tracefile header\n");
859 last_time_written
= current_millis();
862 ms_to_run
= secs_to_run
* 1000;
863 ending_ms
= last_time_written
+ ms_to_run
;
867 while (LogRAW_flag
) {
870 if (writetrace(fd
)) {
871 perror("KDWRITETR returned error");
873 /* Clean up and exit in case of write fail */
878 current_ms
= current_millis();
880 printf("wrote %d events - elapsed time = %.1f secs\n",
881 (int)needed
, (double)(current_ms
- last_time_written
) / 1000.0);
883 last_time_written
= current_ms
;
887 current_ms
= current_millis();
889 if (current_ms
> ending_ms
)
892 ms_to_run
= (uint32_t)(ending_ms
- current_ms
);
906 void read_trace(void)
909 uint32_t buffer_size
;
916 uint32_t count_of_names
;
917 double last_event_time
= 0.0;
921 get_bufinfo(&bufinfo
);
923 if (bufinfo
.nolog
!= 1) {
925 set_enable(0); /* disable logging*/
928 if (bufinfo
.flags
& KDBG_WRAPPED
)
929 printf("Buffer has wrapped\n");
931 printf("Buffer has not wrapped\n");
937 fd
= open(RAW_file
, O_RDONLY
);
940 perror("Can't open file");
943 if (read(fd
, &raw_header
, sizeof(RAW_header
)) != sizeof(RAW_header
)) {
944 perror("read failed");
947 if (raw_header
.version_no
!= RAW_VERSION1
) {
948 raw_header
.version_no
= RAW_VERSION0
;
949 raw_header
.TOD_secs
= time((long *)0);
950 raw_header
.TOD_usecs
= 0;
952 lseek(fd
, (off_t
)0, SEEK_SET
);
954 if (read(fd
, &raw_header
.thread_count
, sizeof(int)) != sizeof(int)) {
955 perror("read failed");
958 } else if (raw_header
.version_no
== RAW_VERSION1
) {
959 #if defined(__ILP32__)
961 * If the raw trace file was written by armv7k, the 64-bit alignment
962 * of TOD_secs causes RAW_header to be 24 bytes. If we only read 20
963 * bytes, the next 4 bytes might be a legitimate thread_id, but it might
964 * also be 0 or a leaked kernel pointer from an armv7k trace file. For
965 * both those cases, consume the 4 bytes and look for the thread map
968 if (sizeof(raw_header
) == 20) {
969 uint32_t alignment_garbage
;
971 if (read(fd
, &alignment_garbage
, sizeof(alignment_garbage
)) != sizeof(alignment_garbage
)) {
972 perror("read failed");
976 if ((alignment_garbage
== 0) || (alignment_garbage
>= 0x80000000)) {
978 printf("Skipping 4 bytes to find valid thread map\n");
981 /* oops, go back to where we were */
982 lseek(fd
, -(off_t
)sizeof(alignment_garbage
), SEEK_CUR
);
987 count_of_names
= raw_header
.thread_count
;
988 trace_time
= (time_t) (raw_header
.TOD_secs
);
990 printf("%s\n", ctime(&trace_time
));
992 buffer_size
= 1000000 * sizeof(kd_buf
);
993 buffer
= malloc(buffer_size
);
995 if (buffer
== (char *) 0)
996 quit("can't allocate memory for tracing info\n");
998 kd
= (kd_buf
*)(uintptr_t)buffer
;
1000 read_command_map(fd
, count_of_names
);
1007 uint64_t prevdelta
= 0;
1008 uint32_t cpunum
= 0;
1012 double event_elapsed_time
= 0;
1015 boolean_t ending_event
;
1024 if (!readRAW_flag
) {
1025 needed
= buffer_size
;
1028 mib
[1] = KERN_KDEBUG
;
1029 mib
[2] = KERN_KDREADTR
;
1033 if (sysctl(mib
, 3, buffer
, &needed
, NULL
, 0) < 0)
1034 quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno
));
1038 count
= (uint32_t)needed
;
1041 uint32_t bytes_read
;
1043 bytes_read
= (uint32_t)read(fd
, buffer
, buffer_size
);
1045 if (bytes_read
== -1) {
1046 perror("read failed");
1049 count
= bytes_read
/ sizeof(kd_buf
);
1054 for (kdp
= &kd
[0], i
= 0; i
< count
; i
++, kdp
++) {
1057 debugid
= kdp
->debugid
;
1058 debugid_base
= debugid
& DBG_FUNC_MASK
;
1059 now
= kdp
->timestamp
& KDBG_TIMESTAMP_MASK
;
1062 * Is this event from an IOP? If so, there will be no
1063 * thread command, label it with the symbolic IOP name
1065 if (cpumap
&& (cpunum
< cpumap_header
->cpu_count
) && (cpumap
[cpunum
].flags
& KDBG_CPUMAP_IS_IOP
)) {
1066 command
= cpumap
[cpunum
].name
;
1068 find_thread_command(kdp
, &command
);
1072 * The internal use TRACE points clutter the output.
1073 * Print them only if in verbose mode.
1077 /* Is this entry of Class DBG_TRACE */
1078 if ((debugid
>> 24) == DBG_TRACE
) {
1079 if (((debugid
>> 16) & 0xff) != DBG_TRACE_INFO
)
1088 cpunum
= kdbg_get_cpu(kdp
);
1091 if (lines
== 64 || firsttime
)
1093 prevdelta
= now
- prevdelta
;
1098 x
= (double)prevdelta
;
1101 fprintf(output_file
, "\n\nNumber of microsecs since in last page %8.1f\n", x
);
1106 * Output description row to output file (make sure to format correctly for 32-bit and 64-bit)
1108 fprintf(output_file
,
1110 " AbsTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu# command\n\n"
1112 " AbsTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu# command\n\n"
1118 if (io_lines
> 15000) {
1119 fcntl(output_fd
, F_FLUSH_DATA
, 0);
1126 if (debugid_base
== VFS_LOOKUP
) {
1127 lkp
= handle_lookup_event(thread
, debugid
, kdp
);
1129 if ( !lkp
|| !(debugid
& DBG_FUNC_END
))
1136 if (last_event_time
)
1137 y
= x
- last_event_time
;
1140 last_event_time
= x
;
1141 ending_event
= FALSE
;
1147 if ((debugid
& DBG_FUNC_START
) || debugid
== MACH_MAKERUNNABLE
) {
1149 if (debugid_base
!= BSC_thread_terminate
&& debugid_base
!= BSC_exit
) {
1151 if (debugid
== MACH_MAKERUNNABLE
)
1152 t_thread
= kdp
->arg1
;
1156 insert_start_event(t_thread
, debugid_base
, now
);
1159 } else if ((debugid
& DBG_FUNC_END
) || debugid
== MACH_STKHANDOFF
|| debugid
== MACH_SCHEDULED
) {
1161 if (debugid
== MACH_STKHANDOFF
|| debugid
== MACH_SCHEDULED
) {
1162 t_debugid
= MACH_MAKERUNNABLE
;
1163 t_thread
= kdp
->arg2
;
1165 t_debugid
= debugid_base
;
1168 event_elapsed_time
= (double)consume_start_event(t_thread
, t_debugid
, now
);
1169 event_elapsed_time
/= divisor
;
1170 ending_event
= TRUE
;
1172 if (event_elapsed_time
== 0 && (debugid
== MACH_STKHANDOFF
|| debugid
== MACH_SCHEDULED
))
1173 ending_event
= FALSE
;
1179 sprintf(&outbuf
[0], "(%-10.1f)", event_elapsed_time
);
1181 * fix that right paren
1186 ch
= strchr (&outbuf
[0], ')');
1193 while (ch
!= &outbuf
[0])
1205 if (match_debugid(debugid_base
, dbgmessge
, &dmsgindex
)) {
1207 fprintf(output_file
, "%13.1f %10.1f%s %-28x ", x
, y
, outbuf
, debugid_base
);
1209 fprintf(output_file
, "%13.1f %10.1f %-28x ", x
, y
, debugid_base
);
1212 fprintf(output_file
, "%13.1f %10.1f%s %-28.28s ", x
, y
, outbuf
, dbgmessge
);
1214 fprintf(output_file
, "%13.1f %10.1f %-28.28s ", x
, y
, dbgmessge
);
1220 strptr
= (char *)lkp
->lk_pathname
;
1223 * print the tail end of the pathname
1225 len
= (int)strlen(strptr
);
1232 fprintf(output_file
, "%-16lx %-51s %-16lx %-2d %s\n", lkp
->lk_dvp
, &strptr
[len
], thread
, cpunum
, command
);
1234 fprintf(output_file
, "%-8x %-51s %-8lx %-2d %s\n", (unsigned int)lkp
->lk_dvp
, &strptr
[len
], thread
, cpunum
, command
);
1236 delete_lookup_event(thread
, lkp
);
1237 } else if (debugid
== TRACE_INFO_STRING
) {
1239 fprintf(output_file
, "%-32s%-36s %-16lx %-2d %s\n", (char *) &kdp
->arg1
, "", thread
, cpunum
, command
);
1241 fprintf(output_file
, "%-16s%-46s %-8lx %-2d %s\n", (char *) &kdp
->arg1
, "", thread
, cpunum
, command
);
1245 fprintf(output_file
, "%-16lx %-16lx %-16lx %-16lx %-16lx %-2d %s\n", kdp
->arg1
, kdp
->arg2
, kdp
->arg3
, kdp
->arg4
, thread
, cpunum
, command
);
1247 fprintf(output_file
, "%-8lx %-8lx %-8lx %-8lx %-8lx %-2d %s\n", kdp
->arg1
, kdp
->arg2
, kdp
->arg3
, kdp
->arg4
, thread
, cpunum
, command
);
1255 set_enable(1); /* re-enable kernel logging */
1260 void signal_handler(int sig
)
1262 ptrace(PT_KILL
, pid
, (caddr_t
)0, 0);
1264 * child is gone; no need to disable the pid
1270 void signal_handler_RAW(int sig
)
1276 int main (int argc
, char* argv
[], char *envp
[])
1278 extern char *optarg
;
1282 char *output_filename
= NULL
;
1283 unsigned int parsed_arg
;
1285 for (i
= 1; i
< argc
; i
++) {
1286 if (strcmp("-X", argv
[i
]) == 0) {
1287 force_32bit_exec
= 1;
1291 if (force_32bit_exec
) {
1292 if (0 != reexec_to_match_lp64ness(FALSE
)) {
1293 fprintf(stderr
, "Could not re-execute: %d\n", errno
);
1297 if (0 != reexec_to_match_kernel()) {
1298 fprintf(stderr
, "Could not re-execute: %d\n", errno
);
1302 if (setiopolicy_np(IOPOL_TYPE_DISK
, IOPOL_SCOPE_PROCESS
, IOPOL_PASSIVE
) < 0) {
1303 printf("setiopolicy failed\n");
1306 output_file
= stdout
;
1309 while ((ch
= getopt(argc
, argv
, "hedEk:irb:gc:p:s:tR:L:l:S:F:a:x:Xnfvo:PT:N")) != EOF
)
1313 case 'h': /* help */
1317 secs_to_run
= argtoi('S', "decimal number", optarg
, 10);
1319 case 'a': /* set tracing on a pid */
1321 pid
= argtoi('a', "decimal number", optarg
, 10);
1323 case 'x': /* exclude a pid from tracing */
1325 pid
= argtoi('x', "decimal number", optarg
, 10);
1337 signal(SIGINT
, signal_handler_RAW
);
1353 value1
= (unsigned int) argtoul('k', "hex number", optarg
, 16);
1354 else if (kval_flag
== 1)
1355 value2
= (unsigned int) argtoul('k', "hex number", optarg
, 16);
1356 else if (kval_flag
== 2)
1357 value3
= (unsigned int) argtoul('k', "hex number", optarg
, 16);
1358 else if (kval_flag
== 3)
1359 value4
= (unsigned int) argtoul('k', "hex number", optarg
, 16);
1362 fprintf(stderr
, "A maximum of four values can be specified with -k\n");
1388 nbufs
= argtoi('b', "decimal number", optarg
, 10);
1392 parsed_arg
= argtoi('c', "decimal, hex, or octal number", optarg
, 0);
1393 if (parsed_arg
> 0xFF)
1394 quit_args("argument '-c %s' parsed as %u, "
1395 "class value must be 0-255\n", optarg
, parsed_arg
);
1396 saw_filter_class(parsed_arg
);
1400 parsed_arg
= argtoi('s', "decimal, hex, or octal number", optarg
, 0);
1401 if (parsed_arg
> 0xFF)
1402 quit_args("argument '-s %s' parsed as %u, "
1403 "subclass value must be 0-255\n", optarg
, parsed_arg
);
1404 saw_filter_subclass(parsed_arg
);
1408 parsed_arg
= argtoi('p', "decimal, hex, or octal number", optarg
, 0);
1409 if (parsed_arg
> 0xFF)
1410 quit_args("argument '-p %s' parsed as %u, "
1411 "end range value must be 0-255\n", optarg
, parsed_arg
);
1412 saw_filter_end_range(parsed_arg
);
1418 output_filename
= optarg
;
1421 frequency
= argtoi('F', "decimal number", optarg
, 10);
1426 no_default_codes_flag
= 1;
1431 // Flush out any unclosed -c argument
1432 filter_done_parsing();
1434 parse_filter_file(optarg
);
1442 if (!no_default_codes_flag
)
1445 printf("Adding default code file /usr/share/misc/trace.codes. Use '-N' to skip this.\n");
1446 parse_codefile("/usr/share/misc/trace.codes");
1455 const char *cfile
= argv
[optind
++];
1456 if (verbose_flag
) printf("Adding code file %s \n", cfile
);
1457 parse_codefile(cfile
);
1464 quit_args("-E flag needs an executable to launch\n");
1472 if (pid_flag
&& pid_exflag
)
1473 quit_args("Can't use both -a and -x flag together\n");
1475 if (kval_flag
&& filter_flag
)
1476 quit_args("Cannot use -k flag with -c, -s, or -p\n");
1478 if (output_filename
&& !trace_flag
&& !readRAW_flag
)
1479 quit_args("When using 'o' option, must use the 't' or 'R' option too\n");
1481 filter_done_parsing();
1486 get_bufinfo(&bufinfo
);
1487 int ktrace_state
= get_ktrace_state();
1490 * Only use the current kdebug configuration when foreground
1491 * tracing is enabled. Both checks are necessary because the
1492 * background tool might have enabled tracing, but as soon as we
1493 * try to write a header, that configuration is removed for us.
1495 if ((ktrace_state
== 1) && (bufinfo
.nolog
== 0)) {
1496 use_current_buf
= 1;
1504 set_pidcheck(pid
, 0); /* disable pid check for given pid */
1507 else if (pid_exflag
)
1509 set_pidexclude(pid
, 0); /* disable pid exclusion for given pid */
1524 if (!init_flag
&& !LogRAW_flag
)
1526 fprintf(stderr
,"The -b flag must be used with the -i flag\n");
1540 printf("The kernel tracing settings are:\n");
1542 /* determine the state of ktrace */
1543 int state
= get_ktrace_state();
1545 /* get the name of the last process to configure ktrace */
1546 char execname
[20] = { 0 };
1547 size_t execname_size
= sizeof(execname
);
1548 int err
= sysctlbyname("ktrace.configured_by", &execname
, &execname_size
, NULL
, 0);
1550 fprintf(stderr
, "error: could not query ktrace.configured_by sysctl (%d: %s)\n", errno
, strerror(errno
));
1554 printf("\tTracing is ");
1560 printf("active (foreground)");
1563 printf("active (background)");
1566 printf("in an invalid state");
1571 printf("\tLast configured by \"%s\"\n", execname
[0] == '\0' ? "<unknown>" : execname
);
1573 /* get kdebug info */
1575 get_bufinfo(&bufinfo
);
1577 printf("The kernel buffer settings are:\n");
1579 if (bufinfo
.flags
& KDBG_BUFINIT
)
1580 printf("\tKernel buffer is initialized\n");
1582 printf("\tKernel buffer is not initialized\n");
1584 printf("\t number of buf entries = %d\n", bufinfo
.nkdbufs
);
1588 if (bufinfo
.flags
& KDBG_MAPINIT
)
1589 printf("\tKernel thread map is initialized\n");
1591 printf("\tKernel thread map is not initialized\n");
1592 printf("\t number of thread entries = %d\n", bufinfo
.nkdthreads
);
1596 printf("\tBuffer logging is disabled\n");
1598 printf("\tBuffer logging is enabled\n");
1601 printf("\tkernel flags = 0x%x\n", bufinfo
.flags
);
1603 if (bufinfo
.flags
& KDBG_NOWRAP
)
1604 printf("\tKernel buffer wrap is disabled\n");
1606 printf("\tKernel buffer wrap is enabled\n");
1608 if (bufinfo
.flags
& KDBG_RANGECHECK
)
1609 printf("\tCollection within a range is enabled\n");
1611 printf("\tCollection within a range is disabled\n");
1613 if (bufinfo
.flags
& KDBG_VALCHECK
)
1614 printf("\tCollecting specific code values is enabled\n");
1616 printf("\tCollecting specific code values is disabled\n");
1618 if (bufinfo
.flags
& KDBG_TYPEFILTER_CHECK
)
1619 printf("\tCollection based on a filter is enabled\n");
1621 printf("\tCollection based on a filter is disabled\n");
1623 if (bufinfo
.flags
& KDBG_PIDCHECK
)
1624 printf("\tCollection based on pid is enabled\n");
1626 printf("\tCollection based on pid is disabled\n");
1628 if (bufinfo
.flags
& KDBG_PIDEXCLUDE
)
1629 printf("\tCollection based on pid exclusion is enabled\n");
1631 printf("\tCollection based on pid exclusion is disabled\n");
1633 if (bufinfo
.bufid
== -1)
1634 printf("\tKernel buffer is not controlled by any process.\n");
1636 printf("\tKernel buffer is controlled by proc id [%d]\n", bufinfo
.bufid
);
1639 if (bufinfo
.flags
& KDBG_TYPEFILTER_CHECK
) {
1641 bool (^should_print
)(uint8_t*) = ^bool(uint8_t* ptr
) {
1642 for (uint32_t i
=0; i
<32; ++i
) {
1643 if (ptr
[i
] > 0) return true;
1649 uint8_t* typefilter
= (uint8_t*)kdebug_typefilter();
1651 bool header
= false;
1653 // Reduce noise, only print lines that are allowing events.
1654 for (uint32_t tclass
= 0; tclass
< 0x100; ++tclass
) {
1655 uint8_t* base
= &typefilter
[tclass
* 32];
1656 if (should_print(base
)) {
1659 printf("\tTypefilter:\n");
1661 for (uint32_t tsubclass
=0; tsubclass
<32; ++tsubclass
) {
1662 printf("%02x ", tsubclass
* 8);
1666 for (uint32_t tsubclass
=0; tsubclass
<32; ++tsubclass
) {
1671 printf("%16s%02x: ", "", tclass
);
1672 for (uint32_t tsubclass
=0; tsubclass
<32; ++tsubclass
) {
1673 printf("%02X ", typefilter
[(tclass
* 32) + tsubclass
]);
1694 fprintf(stderr
, "Starting program: %s\n", argv
[optind
]);
1698 execute_process(&(argv
[optind
]));
1702 else if (enable_flag
)
1705 set_pidcheck(pid
, 1);
1706 else if (pid_exflag
)
1707 set_pidexclude(pid
, 1);
1711 if (output_filename
)
1713 if (((output_fd
= open(output_filename
, O_CREAT
| O_TRUNC
| O_WRONLY
| O_APPEND
, 0644)) < 0 ) ||
1714 !(output_file
= fdopen(output_fd
, "w")))
1716 fprintf(stderr
, "Cannot open file \"%s\" for writing.\n", output_filename
);
1719 setbuffer(output_file
, &sbuffer
[0], SBUFFER_SIZE
);
1721 if (fcntl(output_fd
, F_NOCACHE
, 1) < 0)
1724 fprintf(stderr
, "Warning: setting F_NOCACHE on %s, failed\n", output_filename
);
1727 if (!LogRAW_flag
&& !logRAW_flag
)
1728 setbuffer(output_file
, &sbuffer
[0], SBUFFER_SIZE
);
1730 if (trace_flag
|| readRAW_flag
)
1732 else if (LogRAW_flag
)
1734 else if (logRAW_flag
)
1742 execute_process(char * const argv
[])
1746 posix_spawnattr_t spawn_attrs
;
1750 /* ensure that the process being spawned starts suspended */
1751 rc
= posix_spawnattr_init(&spawn_attrs
);
1753 quit_args("Failed to initialize spawn attrs: %s\n", strerror(rc
));
1755 rc
= posix_spawnattr_setflags(&spawn_attrs
,
1756 POSIX_SPAWN_START_SUSPENDED
);
1758 quit_args("Unable to start process suspended: %s\n", strerror(rc
));
1761 /* spawn the process with the rest of the arguments */
1762 rc
= posix_spawnp(&pid
, argv
[0], NULL
, &spawn_attrs
, argv
, environ
);
1764 quit_args("Unabled to start process: %s\n", strerror(rc
));
1767 signal(SIGINT
, signal_handler
);
1768 set_pidcheck(pid
, 1);
1771 /* start the child process */
1772 rc
= kill(pid
, SIGCONT
);
1774 perror("Failed to continue child process:");
1778 rc
= waitpid(pid
, &status
, 0);
1780 perror("Failed to wait for process: ");
1785 quit_args(const char *fmt
, ...)
1792 set_enable(1); /* re-enable kernel logging */
1797 va_start (args
, fmt
);
1798 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
1800 fprintf(stderr
, "trace error: %s", buffer
);
1804 if (!done_with_args
)
1817 set_enable(1); /* re-enable kernel logging */
1827 usage(int short_help
)
1832 (void)fprintf(stderr
, " usage: trace -h [-v]\n");
1833 (void)fprintf(stderr
, " usage: trace -i [-b numbufs]\n");
1834 (void)fprintf(stderr
, " usage: trace -g\n");
1835 (void)fprintf(stderr
, " usage: trace -d [-a pid | -x pid ]\n");
1836 (void)fprintf(stderr
, " usage: trace -r\n");
1837 (void)fprintf(stderr
, " usage: trace -n\n");
1839 (void)fprintf(stderr
,
1840 " usage: trace -e [ -c class [[-s subclass]... | -p class ]]... | \n");
1841 (void)fprintf(stderr
,
1842 " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter] \n");
1843 (void)fprintf(stderr
,
1844 " [-a pid | -x pid] \n\n");
1846 (void)fprintf(stderr
,
1847 " usage: trace -E [ -c class [[-s subclass]... | -p class ]]... | \n");
1848 (void)fprintf(stderr
,
1849 " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter] \n");
1850 (void)fprintf(stderr
,
1851 " executable_path [optional args to executable] \n\n");
1853 (void)fprintf(stderr
,
1854 " usage: trace -L RawFilename [-S SecsToRun]\n");
1855 (void)fprintf(stderr
,
1856 " usage: trace -l RawFilename\n");
1857 (void)fprintf(stderr
,
1858 " usage: trace -R RawFilename [-X] [-F frequency] [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...]\n");
1859 (void)fprintf(stderr
,
1860 " usage: trace -t [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...]\n");
1861 (void)fprintf(stderr
,
1862 " 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");
1867 /* Only get here if printing long usage info */
1868 (void)fprintf(stderr
, "usage: trace -h [-v]\n");
1869 (void)fprintf(stderr
, "\tPrint this long command help.\n\n");
1870 (void)fprintf(stderr
, "\t -v Print extra information about tracefilter and code files.\n\n");
1872 (void)fprintf(stderr
, "usage: trace -i [-b numbufs]\n");
1873 (void)fprintf(stderr
, "\tInitialize the kernel trace buffer.\n\n");
1874 (void)fprintf(stderr
, "\t-b numbufs The number of trace elements the kernel buffer\n");
1875 (void)fprintf(stderr
, "\t can hold is set to numbufs. Use with the -i flag.\n");
1876 (void)fprintf(stderr
, "\t Enter a decimal value.\n\n");
1878 (void)fprintf(stderr
, "usage: trace -g\n");
1879 (void)fprintf(stderr
, "\tGet the kernel buffer settings.\n\n");
1881 (void)fprintf(stderr
, "usage: trace -d [-a pid | -x pid]\n");
1882 (void)fprintf(stderr
, "\tDisable/stop collection of kernel trace elements.\n\n");
1883 (void)fprintf(stderr
, "\t -a pid Disable/stop collection for this process only.\n\n");
1884 (void)fprintf(stderr
, "\t -x pid Disable/stop exclusion of this process only.\n\n");
1886 (void)fprintf(stderr
, "usage: trace -r\n");
1887 (void)fprintf(stderr
, "\tRemove the kernel trace buffer. Set controls to default.\n\n");
1889 (void)fprintf(stderr
, "usage: trace -n\n");
1890 (void)fprintf(stderr
, "\tDisables kernel buffer wrap around.\n\n");
1892 (void)fprintf(stderr
,
1893 "usage: trace -e [ -c class [[-s subclass]... | -p class ]]... |\n");
1894 (void)fprintf(stderr
,
1895 " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter]\n");
1896 (void) fprintf(stderr
,
1897 " [-a pid | -x pid]\n\n");
1898 (void)fprintf(stderr
, "\t Enable/start collection of kernel trace elements. \n\n");
1899 (void)fprintf(stderr
, "\t By default, trace collects all tracepoints. \n");
1900 (void)fprintf(stderr
, "\t The following arguments may be used to restrict collection \n");
1901 (void)fprintf(stderr
, "\t to a limited set of tracepoints. \n\n");
1902 (void)fprintf(stderr
, "\t Multiple classes can be specified by repeating -c. \n");
1903 (void)fprintf(stderr
, "\t Multiple subclasses can be specified by repeating -s after -c. \n");
1904 (void)fprintf(stderr
, "\t Classes, subclasses, and class ranges can be entered \n");
1905 (void)fprintf(stderr
, "\t in hex (0xXX), decimal (XX), or octal (0XX). \n\n");
1906 (void)fprintf(stderr
, "\t -c class Restrict trace collection to given class. \n\n");
1907 (void)fprintf(stderr
, "\t -p class Restrict trace collection to given class range. \n");
1908 (void)fprintf(stderr
, "\t Must provide class with -c first. \n\n");
1909 (void)fprintf(stderr
, "\t -s subclass Restrict trace collection to given subclass. \n");
1910 (void)fprintf(stderr
, "\t Must provide class with -c first. \n\n");
1911 (void)fprintf(stderr
, "\t -a pid Restrict trace collection to the given process.\n\n");
1912 (void)fprintf(stderr
, "\t -x pid Exclude the given process from trace collection.\n\n");
1913 (void)fprintf(stderr
, "\t -k code Restrict trace collection up to four specific codes.\n");
1914 (void)fprintf(stderr
, "\t Enter codes in hex (0xXXXXXXXX). \n\n");
1915 (void)fprintf(stderr
, "\t -P Enable restricted PPT trace points only.\n\n");
1916 (void)fprintf(stderr
, "\t -T tracefilter Read class and subclass restrictions from a \n");
1917 (void)fprintf(stderr
, "\t tracefilter description file. \n");
1918 (void)fprintf(stderr
, "\t Run trace -h -v for more info on this file. \n\n");
1920 (void)fprintf(stderr
,
1921 "usage: trace -E [ -c class [[-s subclass]... | -p class ]]... |\n");
1922 (void)fprintf(stderr
,
1923 " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter]\n");
1924 (void)fprintf(stderr
,
1925 " executable_path [optional args to executable] \n\n");
1926 (void)fprintf(stderr
, "\tLaunch the given executable and enable/start\n");
1927 (void)fprintf(stderr
, "\tcollection of kernel trace elements for that process.\n");
1928 (void)fprintf(stderr
, "\tSee -e(enable) flag for option descriptions.\n\n");
1930 (void)fprintf(stderr
, "usage: trace -t [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...] \n");
1931 (void)fprintf(stderr
, "\tCollect the kernel buffer trace data and print it.\n\n");
1932 (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");
1933 (void)fprintf(stderr
, "\t -o OutputFilename Print trace output to OutputFilename. Default is stdout.\n\n");
1935 (void)fprintf(stderr
,
1936 "usage: trace -R RawFilename [-X] [-F frequency] [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...] \n");
1937 (void)fprintf(stderr
, "\tRead raw trace file and print it.\n\n");
1938 (void)fprintf(stderr
, "\t -X Force trace to interpret trace data as 32 bit. \n");
1939 (void)fprintf(stderr
, "\t Default is to match the bit width of the current system. \n");
1940 (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");
1941 (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");
1942 (void)fprintf(stderr
, "\t -o OutputFilename Print trace output to OutputFilename. Default is stdout.\n\n");
1944 (void)fprintf(stderr
,
1945 "usage: trace -L RawFilename [-S SecsToRun]\n");
1946 (void)fprintf(stderr
, "\tContinuously collect the kernel buffer trace data in the raw format \n");
1947 (void)fprintf(stderr
, "\tand write it to RawFilename. \n");
1949 (void)fprintf(stderr
, "\t-L implies -r -i if tracing isn't currently enabled.\n");
1950 (void)fprintf(stderr
, "\tOptions passed to -e(enable) are also accepted by -L. (except -a -x -P)\n\n");
1951 (void)fprintf(stderr
, "\t -S SecsToRun Specify the number of seconds to collect trace data.\n\n");
1953 (void)fprintf(stderr
,
1954 "usage: trace -l RawFilename\n");
1955 (void)fprintf(stderr
, "\tCollect the existing kernel buffer trace data in the raw format.\n\n");
1958 (void)fprintf(stderr
,
1960 "\t A code file consists of a list of tracepoints, one per line, \n"
1961 "\t with one tracepoint code in hex, followed by a tab, \n"
1962 "\t followed by the tracepoint's name. \n\n"
1964 "\t Example tracepoint: \n"
1965 "\t 0x010c007c\tMSC_mach_msg_trap \n"
1966 "\t This describes the tracepoint with the following info: \n"
1967 "\t Name: MSC_mach_msg_trap \n"
1968 "\t Class: 0x01 (Mach events) \n"
1969 "\t Subclass: 0x0c (Mach system calls) \n"
1970 "\t Code: 0x007c (Mach syscall number 31) \n\n"
1972 "\t See /usr/include/sys/kdebug.h for the currently defined \n"
1973 "\t class and subclass values. \n"
1974 "\t See /usr/share/misc/trace.codes for the currently allocated \n"
1975 "\t system tracepoints in trace code file format. \n"
1976 "\t This codefile is useful with the -R argument to trace. \n"
1979 (void)fprintf(stderr
,
1980 "Tracefilter description file: \n"
1981 "\t A tracefilter description file consists of a list of \n"
1982 "\t class and subclass filters in hex, one per line, \n"
1983 "\t which are applied as if they were passed with -c and -s. \n"
1984 "\t Pass -v to see what classes and subclasses are being set. \n\n"
1986 "\t File syntax: \n"
1987 "\t Class filter: \n"
1989 "\t Subclass filter (includes class): \n"
1992 "\t # This is a comment \n\n"
1994 "\t For example, to trace Mach events (class 1):\n"
1996 "\t or to trace Mach system calls (class 1 subclass 13): \n"
2006 argtoi(int flag
, char *req
, char *str
, int base
)
2011 ret
= (int)strtol(str
, &cp
, base
);
2012 if (cp
== str
|| *cp
)
2013 errx(EINVAL
, "-%c flag requires a %s", flag
, req
);
2017 static unsigned long
2018 argtoul(int flag
, char *req
, char *str
, int base
)
2023 ret
= (int)strtoul(str
, &cp
, base
);
2024 if (cp
== str
|| *cp
)
2025 errx(EINVAL
, "-%c flag requires a %s", flag
, req
);
2030 * comparison function for qsort
2034 debugid_compar(const void *p1
, const void *p2
)
2036 const code_type_t
*q1
= (const code_type_t
*)p1
;
2037 const code_type_t
*q2
= (const code_type_t
*)p2
;
2039 if (q1
->debugid
> q2
->debugid
)
2041 else if (q1
->debugid
== q2
->debugid
)
2048 * Filter args parsing state machine:
2054 * every -c goes back to start
2056 * Valid transitions:
2057 * start -> class (first -c)
2058 * class -> range (-c -p)
2059 * class -> sub (-c -s)
2060 * class -> class (-c -c)
2061 * range -> class (-c -p -c)
2062 * sub -> class (-c -s -c)
2063 * * -> start (on filter_done_parsing)
2065 * Need to call filter_done_parsing after
2066 * calling saw_filter_*
2067 * to flush out any class flag waiting to see if
2068 * there is a -s flag coming up
2072 // What type of flag did I last see?
2076 FILTER_MODE_CLASS_RANGE
,
2077 FILTER_MODE_SUBCLASS
2078 } filter_mode
= FILTER_MODE_START
;
2080 uint8_t filter_current_class
= 0;
2081 uint8_t filter_current_subclass
= 0;
2082 uint8_t filter_current_class_range
= 0;
2085 saw_filter_class(uint8_t class)
2087 switch(filter_mode
) {
2088 case FILTER_MODE_START
:
2089 case FILTER_MODE_CLASS_RANGE
:
2090 case FILTER_MODE_SUBCLASS
:
2091 filter_mode
= FILTER_MODE_CLASS
;
2092 filter_current_class
= class;
2093 filter_current_subclass
= 0;
2094 filter_current_class_range
= 0;
2095 // the case of a lone -c is taken care of
2096 // by filter_done_parsing
2098 case FILTER_MODE_CLASS
:
2099 filter_mode
= FILTER_MODE_CLASS
;
2100 // set old class, remember new one
2101 set_filter_class(filter_current_class
);
2102 filter_current_class
= class;
2103 filter_current_subclass
= 0;
2104 filter_current_class_range
= 0;
2107 quit_args("invalid case in saw_filter_class\n");
2112 saw_filter_end_range(uint8_t end_class
)
2114 switch(filter_mode
) {
2115 case FILTER_MODE_CLASS
:
2116 filter_mode
= FILTER_MODE_CLASS_RANGE
;
2117 filter_current_class_range
= end_class
;
2118 set_filter_range(filter_current_class
, filter_current_class_range
);
2120 case FILTER_MODE_START
:
2121 quit_args("must provide '-c class' before '-p 0x%x'\n",
2123 case FILTER_MODE_CLASS_RANGE
:
2124 quit_args("extra range end '-p 0x%x'"
2125 " for class '-c 0x%x'\n",
2126 end_class
, filter_current_class
);
2127 case FILTER_MODE_SUBCLASS
:
2128 quit_args("cannot provide both range end '-p 0x%x'"
2129 " and subclass '-s 0x%x'"
2130 " for class '-c 0x%x'\n",
2131 end_class
, filter_current_subclass
,
2132 filter_current_class
);
2134 quit_args("invalid case in saw_filter_end_range\n");
2139 saw_filter_subclass(uint8_t subclass
)
2141 switch(filter_mode
) {
2142 case FILTER_MODE_CLASS
:
2143 case FILTER_MODE_SUBCLASS
:
2144 filter_mode
= FILTER_MODE_SUBCLASS
;
2145 filter_current_subclass
= subclass
;
2146 set_filter_subclass(filter_current_class
, filter_current_subclass
);
2148 case FILTER_MODE_START
:
2149 quit_args("must provide '-c class'"
2150 " before subclass '-s 0x%x'\n", subclass
);
2151 case FILTER_MODE_CLASS_RANGE
:
2152 quit_args("cannot provide both range end '-p 0x%x'"
2153 " and subclass '-s 0x%x'"
2154 " for the same class '-c 0x%x'\n",
2155 filter_current_class_range
,
2156 subclass
, filter_current_class
);
2158 quit_args("invalid case in saw_filter_subclass\n");
2163 filter_done_parsing(void)
2165 switch(filter_mode
) {
2166 case FILTER_MODE_CLASS
:
2167 // flush out the current class
2168 set_filter_class(filter_current_class
);
2169 filter_mode
= FILTER_MODE_START
;
2170 filter_current_class
= 0;
2171 filter_current_subclass
= 0;
2172 filter_current_class_range
= 0;
2174 case FILTER_MODE_SUBCLASS
:
2175 case FILTER_MODE_START
:
2176 case FILTER_MODE_CLASS_RANGE
:
2177 filter_mode
= FILTER_MODE_START
;
2178 filter_current_class
= 0;
2179 filter_current_subclass
= 0;
2180 filter_current_class_range
= 0;
2183 quit_args("invalid case in filter_done_parsing\n");
2187 /* Tell set_filter_subclass not to print every. single. subclass. */
2188 static boolean_t setting_class
= FALSE
;
2189 static boolean_t setting_range
= FALSE
;
2192 set_filter_subclass(uint8_t class, uint8_t subclass
)
2194 if (!filter_alloced
) {
2195 type_filter_bitmap
= (uint8_t *) calloc(1, KDBG_TYPEFILTER_BITMAP_SIZE
);
2196 if (type_filter_bitmap
== NULL
)
2197 quit_args("Could not allocate type_filter_bitmap.\n");
2201 uint16_t csc
= ENCODE_CSC_LOW(class, subclass
);
2203 if (verbose_flag
&& !setting_class
)
2204 printf("tracing subclass: 0x%4.4x\n", csc
);
2206 if (verbose_flag
&& isset(type_filter_bitmap
, csc
))
2207 printf("class %u (0x%2.2x), subclass %u (0x%2.2x) set twice.\n",
2208 class, class, subclass
, subclass
);
2210 setbit(type_filter_bitmap
, csc
);
2214 set_filter_class(uint8_t class)
2216 if (verbose_flag
&& !setting_range
)
2217 printf("tracing class: 0x%2.2x\n", class);
2219 setting_class
= TRUE
;
2221 for (int i
= 0; i
< 256; i
++)
2222 set_filter_subclass(class, i
);
2224 setting_class
= FALSE
;
2228 set_filter_range(uint8_t class, uint8_t end
)
2231 printf("tracing range: 0x%2.2x - 0x%2.2x\n", class, end
);
2233 setting_range
= TRUE
;
2235 for (int i
= class; i
<= end
; i
++)
2236 set_filter_class(i
);
2238 setting_range
= FALSE
;
2242 * Syntax of filter file:
2243 * Hexadecimal numbers only
2246 * Subclass (includes class):
2250 * TBD: Class ranges?
2251 * TBD: K for -k flag?
2255 parse_filter_file(char *filename
)
2258 uint32_t current_line
= 0;
2259 uint32_t parsed_arg
= 0;
2264 if ( (file
= fopen(filename
, "r")) == NULL
) {
2265 quit_args("Failed to open filter description file %s: %s\n",
2266 filename
, strerror(errno
));
2270 printf("Parsing typefilter file: %s\n", filename
);
2272 while( fgets(line
, sizeof(line
), file
) != NULL
) {
2277 rval
= sscanf(line
, "C 0x%x\n", &parsed_arg
);
2279 quit_args("invalid line %d of file %s: %s\n",
2280 current_line
, filename
, line
);
2281 if (parsed_arg
> 0xFF)
2282 quit_args("line %d of file %s: %s\n"
2284 "class value must be 0x0-0xFF\n",
2285 current_line
, filename
, line
, parsed_arg
);
2286 set_filter_class((uint8_t)parsed_arg
);
2289 rval
= sscanf(line
, "S 0x%x\n", &parsed_arg
);
2291 quit_args("invalid line %d of file %s: %s\n",
2292 current_line
, filename
, line
);
2293 if (parsed_arg
> 0xFFFF)
2294 quit_args("line %d of file %s: %s\n"
2296 "value must be 0x0-0xFFFF\n",
2297 current_line
, filename
, line
, parsed_arg
);
2298 set_filter_subclass(EXTRACT_CLASS_LOW(parsed_arg
),
2299 EXTRACT_SUBCLASS_LOW(parsed_arg
));
2311 quit_args("Invalid filter description file: %s\n"
2312 "could not parse line %d: %s\n",
2313 filename
, current_line
, line
);
2321 * Find the debugid code in the list and return its index
2324 binary_search(code_type_t
*list
, int lowbound
, int highbound
, unsigned int code
)
2334 mid
= (low
+ high
) / 2;
2339 return (-1); /* failed */
2340 else if ( low
+ 1 >= high
)
2342 /* We have a match */
2343 if (list
[high
].debugid
== code
)
2345 else if (list
[low
].debugid
== code
)
2348 return(-1); /* search failed */
2350 else if (code
< list
[mid
].debugid
)
2359 parse_codefile(const char *filename
)
2364 struct stat stat_buf
;
2366 char *file_addr
, *endp
;
2368 if ((fd
= open(filename
, O_RDONLY
, 0)) == -1)
2370 printf("Failed to open code description file %s\n",filename
);
2374 if (fstat(fd
, &stat_buf
) == -1)
2376 printf("Error: Can't fstat file: %s\n", filename
);
2381 * For some reason mapping files with zero size fails
2382 * so it has to be handled specially.
2384 file_size
= (size_t)stat_buf
.st_size
;
2386 if (stat_buf
.st_size
!= 0)
2388 if ((file_addr
= mmap(0, file_size
, PROT_READ
|PROT_WRITE
,
2389 MAP_PRIVATE
|MAP_FILE
, fd
, 0)) == (char*) -1)
2391 printf("Error: Can't map file: %s\n", filename
);
2406 * If we get here, we have mapped the file
2407 * and we are ready to parse it. Count
2408 * the newlines to get total number of codes.
2411 for (count
= 0, j
=1; j
< file_size
; j
++)
2413 if (file_addr
[j
] == '\n')
2419 printf("Error: No codes in %s\n", filename
);
2424 * Fudge the count to accomodate the last line in the file -
2425 * in case it doesn't end in a newline.
2429 // Grow the size of codesc to store new entries.
2430 size_t total_count
= codesc_idx
+ count
;
2431 code_type_t
*new_codesc
= (code_type_t
*)realloc(codesc
, (total_count
) * sizeof(code_type_t
));
2433 if (new_codesc
== NULL
) {
2434 printf("Failed to grow/allocate buffer. Skipping file %s\n", filename
);
2437 codesc
= new_codesc
;
2438 bzero((char *)(codesc
+ codesc_idx
), count
* sizeof(code_type_t
));
2440 for (line
= 1, j
= 0; j
< file_size
&& codesc_idx
< total_count
; codesc_idx
++)
2442 /* Skip blank lines */
2443 while (file_addr
[j
] == '\n')
2449 /* Skip leading whitespace */
2450 while (file_addr
[j
] == ' ' || file_addr
[j
] == '\t')
2453 /* Get the debugid code */
2454 codesc
[codesc_idx
].debugid
= (uint32_t)strtoul(file_addr
+ j
, &endp
, 16);
2455 j
= (int)(endp
- file_addr
);
2457 if (codesc
[codesc_idx
].debugid
== 0)
2459 /* We didn't find a debugid code - skip this line */
2461 printf("Error: while parsing line %d, skip\n", line
);
2462 while (file_addr
[j
] != '\n' && j
< file_size
)
2469 /* Skip whitespace */
2470 while (file_addr
[j
] == ' ' || file_addr
[j
] == '\t')
2473 /* Get around old file that had count at the beginning */
2474 if (file_addr
[j
] == '\n')
2476 /* missing debugid string - skip */
2478 printf("Error: while parsing line %d, (0x%x) skip\n", line
, codesc
[codesc_idx
].debugid
);
2486 /* Next is the debugid string terminated by a newline */
2487 codesc
[codesc_idx
].debug_string
= &file_addr
[j
];
2489 /* Null out the newline terminator */
2490 while ((j
< file_size
) && (file_addr
[j
] != '\n'))
2492 file_addr
[j
] = '\0'; /* File must be read-write */
2495 codenum
++; /*Index into codesc is 0 to codenum-1 */
2500 printf("Parsed %d codes in %s\n", codenum
, filename
);
2501 printf("[%6d] 0x%8x %s\n", 0, codesc
[0].debugid
, codesc
[0].debug_string
);
2502 printf("[%6d] 0x%8x %s\n\n", codenum
-1, codesc
[codenum
-1].debugid
, codesc
[codenum
-1].debug_string
);
2506 qsort((void *)codesc
, codesc_idx
, sizeof(code_type_t
), debugid_compar
);
2510 printf("Sorted %zd codes in %s\n", codesc_idx
, filename
);
2511 printf("lowbound [%6d]: 0x%8x %s\n", 0, codesc
[0].debugid
, codesc
[0].debug_string
);
2512 printf("highbound [%6zd]: 0x%8x %s\n\n", codesc_idx
- 1, codesc
[codesc_idx
- 1].debugid
, codesc
[codesc_idx
- 1].debug_string
);
2514 codesc_find_dupes();
2517 /* Dump the codefile */
2519 for (i
= 0; i
< codesc_idx
; i
++)
2520 printf("[%d] 0x%x %s\n",i
+1, codesc
[i
].debugid
, codesc
[i
].debug_string
);
2526 codesc_find_dupes(void)
2528 boolean_t found_dupes
= FALSE
;
2529 if (codesc_idx
== 0)
2533 uint32_t last_debugid
= codesc
[0].debugid
;
2534 for(int i
= 1; i
< codesc_idx
; i
++)
2536 if(codesc
[i
].debugid
== last_debugid
)
2540 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
);
2543 last_debugid
= codesc
[i
].debugid
;
2547 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");
2552 match_debugid(unsigned int xx
, char * debugstr
, int * yy
)
2559 if (codesc
[codeindx_cache
].debugid
!= xx
)
2560 indx
= binary_search(codesc
, 0, (codenum
-1), xx
);
2562 indx
= codeindx_cache
;
2565 return(indx
); /* match failed */
2567 bcopy(&codesc
[indx
].debug_string
[0], debugstr
,80);
2569 codeindx_cache
= indx
;
2570 return(0); /* match success */
2575 read_cpu_map(int fd
)
2577 if (cpumap_header
) {
2578 free(cpumap_header
);
2579 cpumap_header
= NULL
;
2584 * To fit in the padding space of a VERSION1 file, the max possible
2585 * cpumap size is one page.
2587 cpumap_header
= malloc(PAGE_SIZE
);
2591 * cpu maps exist in a RAW_VERSION1+ header only
2593 if (raw_header
.version_no
== RAW_VERSION1
) {
2594 off_t cpumap_position
= lseek(fd
, 0, SEEK_CUR
);
2595 /* cpumap is part of the last 4KB of padding in the preamble */
2596 size_t padding_bytes
= SIZE_4KB
- (cpumap_position
& (SIZE_4KB
- 1));
2598 if (read(fd
, cpumap_header
, padding_bytes
) == padding_bytes
) {
2599 if (cpumap_header
->version_no
== RAW_VERSION1
) {
2600 cpumap
= (kd_cpumap
*)&cpumap_header
[1];
2608 mib
[1] = KERN_KDEBUG
;
2609 mib
[2] = KERN_KDCPUMAP
;
2611 size_t temp
= PAGE_SIZE
;
2612 if (sysctl(mib
, 3, cpumap_header
, &temp
, NULL
, 0) == 0) {
2613 if (PAGE_SIZE
>= temp
) {
2614 if (cpumap_header
->version_no
== RAW_VERSION1
) {
2615 cpumap
= (kd_cpumap
*)&cpumap_header
[1];
2622 printf("Can't read the cpu map -- this is not fatal\n");
2623 free(cpumap_header
);
2624 cpumap_header
= NULL
;
2625 } else if (verbose_flag
) {
2626 /* Dump the initial cpumap */
2627 printf("\nCPU\tName\n");
2628 for (int i
= 0; i
< cpumap_header
->cpu_count
; i
++) {
2629 printf ("%2d\t%s\n", cpumap
[i
].cpu_id
, cpumap
[i
].name
);
2636 read_command_map(int fd
, uint32_t count
)
2643 total_threads
= count
;
2644 size
= count
* sizeof(kd_threadmap
);
2646 get_bufinfo(&bufinfo
);
2648 total_threads
= bufinfo
.nkdthreads
;
2649 size
= bufinfo
.nkdthreads
* sizeof(kd_threadmap
);
2652 nthreads
= total_threads
* 2;
2655 printf("Size of map table is %d, thus %d entries\n", (int)size
, total_threads
);
2658 if ((mapptr
= (kd_threadmap
*) malloc(size
)))
2659 bzero (mapptr
, size
);
2663 printf("Thread map is not initialized -- this is not fatal\n");
2668 if (read(fd
, mapptr
, size
) != size
) {
2670 printf("Can't read the thread map -- this is not fatal\n");
2677 /* Now read the threadmap */
2679 mib
[1] = KERN_KDEBUG
;
2680 mib
[2] = KERN_KDTHRMAP
;
2683 mib
[5] = 0; /* no flags */
2684 if (sysctl(mib
, 3, mapptr
, &size
, NULL
, 0) < 0)
2686 /* This is not fatal -- just means I cant map command strings */
2688 printf("Can't read the thread map -- this is not fatal\n");
2694 for (i
= 0; i
< total_threads
; i
++) {
2695 if (mapptr
[i
].thread
)
2696 create_map_entry(mapptr
[i
].thread
, &mapptr
[i
].command
[0]);
2700 /* Dump the initial map */
2702 printf("Size of maptable returned is %ld, thus %ld entries\n", size
, (size
/sizeof(kd_threadmap
)));
2704 printf("Thread Command\n");
2705 for (i
= 0; i
< total_threads
; i
++) {
2706 printf ("0x%lx %s\n",
2716 create_map_entry(uintptr_t thread
, char *command
)
2721 if ((tme
= threadmap_freelist
))
2722 threadmap_freelist
= tme
->tm_next
;
2724 tme
= (threadmap_t
)malloc(sizeof(struct threadmap
));
2726 tme
->tm_thread
= thread
;
2727 tme
->tm_deleteme
= FALSE
;
2729 (void)strncpy (tme
->tm_command
, command
, MAXCOMLEN
);
2730 tme
->tm_command
[MAXCOMLEN
] = '\0';
2732 hashid
= thread
& HASH_MASK
;
2734 tme
->tm_next
= threadmap_hash
[hashid
];
2735 threadmap_hash
[hashid
] = tme
;
2739 delete_thread_entry(uintptr_t thread
)
2741 threadmap_t tme
= 0;
2742 threadmap_t tme_prev
;
2745 hashid
= thread
& HASH_MASK
;
2747 if ((tme
= threadmap_hash
[hashid
])) {
2748 if (tme
->tm_thread
== thread
)
2749 threadmap_hash
[hashid
] = tme
->tm_next
;
2753 for (tme
= tme
->tm_next
; tme
; tme
= tme
->tm_next
) {
2754 if (tme
->tm_thread
== thread
) {
2755 tme_prev
->tm_next
= tme
->tm_next
;
2762 tme
->tm_next
= threadmap_freelist
;
2763 threadmap_freelist
= tme
;
2769 find_and_insert_tmp_map_entry(uintptr_t pthread
, char *command
)
2771 threadmap_t tme
= 0;
2772 threadmap_t tme_prev
;
2775 if ((tme
= threadmap_temp
)) {
2776 if (tme
->tm_pthread
== pthread
)
2777 threadmap_temp
= tme
->tm_next
;
2781 for (tme
= tme
->tm_next
; tme
; tme
= tme
->tm_next
) {
2782 if (tme
->tm_pthread
== pthread
) {
2783 tme_prev
->tm_next
= tme
->tm_next
;
2790 (void)strncpy (tme
->tm_command
, command
, MAXCOMLEN
);
2791 tme
->tm_command
[MAXCOMLEN
] = '\0';
2793 delete_thread_entry(tme
->tm_thread
);
2795 hashid
= tme
->tm_thread
& HASH_MASK
;
2797 tme
->tm_next
= threadmap_hash
[hashid
];
2798 threadmap_hash
[hashid
] = tme
;
2804 create_tmp_map_entry(uintptr_t thread
, uintptr_t pthread
)
2808 if ((tme
= threadmap_freelist
))
2809 threadmap_freelist
= tme
->tm_next
;
2811 tme
= (threadmap_t
)malloc(sizeof(struct threadmap
));
2813 tme
->tm_thread
= thread
;
2814 tme
->tm_pthread
= pthread
;
2815 tme
->tm_deleteme
= FALSE
;
2816 tme
->tm_command
[0] = '\0';
2818 tme
->tm_next
= threadmap_temp
;
2819 threadmap_temp
= tme
;
2824 find_thread_entry(uintptr_t thread
)
2829 hashid
= thread
& HASH_MASK
;
2831 for (tme
= threadmap_hash
[hashid
]; tme
; tme
= tme
->tm_next
) {
2832 if (tme
->tm_thread
== thread
)
2839 find_thread_name(uintptr_t thread
, char **command
, boolean_t deleteme
)
2843 if ((tme
= find_thread_entry(thread
))) {
2844 *command
= tme
->tm_command
;
2846 if (deleteme
== TRUE
)
2847 tme
->tm_deleteme
= deleteme
;
2849 *command
= EMPTYSTRING
;
2853 find_thread_command(kd_buf
*kbufp
, char **command
)
2859 *command
= EMPTYSTRING
;
2861 thread
= kbufp
->arg5
;
2862 debugid_base
= kbufp
->debugid
& DBG_FUNC_MASK
;
2864 if (debugid_base
== BSC_exit
|| debugid_base
== MACH_STKHANDOFF
) {
2866 * Mark entry as invalid and return temp command pointer
2868 if ((tme
= find_thread_entry(thread
))) {
2870 strncpy(tmpcommand
, tme
->tm_command
, MAXCOMLEN
);
2871 *command
= tmpcommand
;
2873 if (debugid_base
== BSC_exit
|| tme
->tm_deleteme
== TRUE
)
2874 delete_thread_entry(thread
);
2877 else if (debugid_base
== TRACE_DATA_NEWTHREAD
) {
2879 * Save the create thread data
2881 create_tmp_map_entry(kbufp
->arg1
, kbufp
->arg5
);
2883 else if (debugid_base
== TRACE_STRING_NEWTHREAD
) {
2885 * process new map entry
2887 find_and_insert_tmp_map_entry(kbufp
->arg5
, (char *)&kbufp
->arg1
);
2889 else if (debugid_base
== TRACE_STRING_EXEC
) {
2891 delete_thread_entry(kbufp
->arg5
);
2893 create_map_entry(kbufp
->arg5
, (char *)&kbufp
->arg1
);
2896 find_thread_name(thread
, command
, (debugid_base
== BSC_thread_terminate
));
2902 (void) mach_timebase_info (&mach_timebase
);
2904 if (frequency
== 0) {
2905 divisor
= ( (double)mach_timebase
.denom
/ (double)mach_timebase
.numer
) * 1000;
2907 divisor
= (double)frequency
/ 1000000;
2910 printf("divisor = %g\n", divisor
);