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 int64_t lk_pathname
[NUMPARMS
+ 1];
177 typedef struct threadmap
*threadmap_t
;
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(uint64_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(uint64_t);
244 static void find_and_insert_tmp_map_entry(uint64_t, char *);
245 static void create_tmp_map_entry(uint64_t, uint64_t);
246 static void find_thread_name(uint64_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(uint64_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(uint64_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(uint64_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(uint64_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(uint64_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
;
1060 cpunum
= kdbg_get_cpu(kdp
);
1063 * Is this event from an IOP? If so, there will be no
1064 * thread command, label it with the symbolic IOP name
1066 if (cpumap
&& (cpunum
< cpumap_header
->cpu_count
) && (cpumap
[cpunum
].flags
& KDBG_CPUMAP_IS_IOP
)) {
1067 command
= cpumap
[cpunum
].name
;
1069 find_thread_command(kdp
, &command
);
1073 * The internal use TRACE points clutter the output.
1074 * Print them only if in verbose mode.
1078 /* Is this entry of Class DBG_TRACE */
1079 if ((debugid
>> 24) == DBG_TRACE
) {
1080 if (((debugid
>> 16) & 0xff) != DBG_TRACE_INFO
)
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
);
1230 #if defined(__LP64__) || defined(__arm64__)
1232 fprintf(output_file
, "%-16llx %-51s %-16" PRIx64
" %-2d %s\n", (uint64_t)lkp
->lk_dvp
, &strptr
[len
], thread
, cpunum
, command
);
1234 fprintf(output_file
, "%-8x %-51s %-8" PRIx64
" %-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
) {
1238 #if defined(__LP64__) || defined(__arm64__)
1239 fprintf(output_file
, "%-32s%-36s %-16" PRIx64
" %-2d %s\n", (char *) &kdp
->arg1
, "", thread
, cpunum
, command
);
1241 fprintf(output_file
, "%-16s%-46s %-8" PRIx64
" %-2d %s\n", (char *) &kdp
->arg1
, "", thread
, cpunum
, command
);
1244 #if defined(__LP64__) || defined(__arm64__)
1245 fprintf(output_file
, "%-16" PRIx64
" %-16" PRIx64
" %-16" PRIx64
" %-16" PRIx64
" %-16" PRIx64
" %-2d %s\n",
1246 (uint64_t)kdp
->arg1
, (uint64_t)kdp
->arg2
, (uint64_t)kdp
->arg3
, (uint64_t)kdp
->arg4
, thread
, cpunum
, command
);
1248 fprintf(output_file
, "%-8" PRIx64
" %-8" PRIx64
" %-8" PRIx64
" %-8" PRIx64
" %-8" PRIx64
" %-2d %s\n",
1249 (uint64_t)kdp
->arg1
, (uint64_t)kdp
->arg2
, (uint64_t)kdp
->arg3
, (uint64_t)kdp
->arg4
, thread
, cpunum
, command
);
1257 set_enable(1); /* re-enable kernel logging */
1262 void signal_handler(int sig
)
1264 ptrace(PT_KILL
, pid
, (caddr_t
)0, 0);
1266 * child is gone; no need to disable the pid
1272 void signal_handler_RAW(int sig
)
1278 int main (int argc
, char* argv
[], char *envp
[])
1280 extern char *optarg
;
1284 char *output_filename
= NULL
;
1285 unsigned int parsed_arg
;
1287 for (i
= 1; i
< argc
; i
++) {
1288 if (strcmp("-X", argv
[i
]) == 0) {
1289 force_32bit_exec
= 1;
1293 if (force_32bit_exec
) {
1294 if (0 != reexec_to_match_lp64ness(FALSE
)) {
1295 fprintf(stderr
, "Could not re-execute: %d\n", errno
);
1299 #if !defined(__arm64__)
1301 if (0 != reexec_to_match_kernel()) {
1302 fprintf(stderr
, "Could not re-execute: %d\n", errno
);
1307 if (setiopolicy_np(IOPOL_TYPE_DISK
, IOPOL_SCOPE_PROCESS
, IOPOL_PASSIVE
) < 0) {
1308 printf("setiopolicy failed\n");
1311 output_file
= stdout
;
1314 while ((ch
= getopt(argc
, argv
, "hedEk:irb:gc:p:s:tR:L:l:S:F:a:x:Xnfvo:PT:N")) != EOF
)
1318 case 'h': /* help */
1322 secs_to_run
= argtoi('S', "decimal number", optarg
, 10);
1324 case 'a': /* set tracing on a pid */
1326 pid
= argtoi('a', "decimal number", optarg
, 10);
1328 case 'x': /* exclude a pid from tracing */
1330 pid
= argtoi('x', "decimal number", optarg
, 10);
1342 signal(SIGINT
, signal_handler_RAW
);
1358 value1
= (unsigned int) argtoul('k', "hex number", optarg
, 16);
1359 else if (kval_flag
== 1)
1360 value2
= (unsigned int) argtoul('k', "hex number", optarg
, 16);
1361 else if (kval_flag
== 2)
1362 value3
= (unsigned int) argtoul('k', "hex number", optarg
, 16);
1363 else if (kval_flag
== 3)
1364 value4
= (unsigned int) argtoul('k', "hex number", optarg
, 16);
1367 fprintf(stderr
, "A maximum of four values can be specified with -k\n");
1393 nbufs
= argtoi('b', "decimal number", optarg
, 10);
1397 parsed_arg
= argtoi('c', "decimal, hex, or octal number", optarg
, 0);
1398 if (parsed_arg
> 0xFF)
1399 quit_args("argument '-c %s' parsed as %u, "
1400 "class value must be 0-255\n", optarg
, parsed_arg
);
1401 saw_filter_class(parsed_arg
);
1405 parsed_arg
= argtoi('s', "decimal, hex, or octal number", optarg
, 0);
1406 if (parsed_arg
> 0xFF)
1407 quit_args("argument '-s %s' parsed as %u, "
1408 "subclass value must be 0-255\n", optarg
, parsed_arg
);
1409 saw_filter_subclass(parsed_arg
);
1413 parsed_arg
= argtoi('p', "decimal, hex, or octal number", optarg
, 0);
1414 if (parsed_arg
> 0xFF)
1415 quit_args("argument '-p %s' parsed as %u, "
1416 "end range value must be 0-255\n", optarg
, parsed_arg
);
1417 saw_filter_end_range(parsed_arg
);
1423 output_filename
= optarg
;
1426 frequency
= argtoi('F', "decimal number", optarg
, 10);
1431 no_default_codes_flag
= 1;
1436 // Flush out any unclosed -c argument
1437 filter_done_parsing();
1439 parse_filter_file(optarg
);
1447 if (!no_default_codes_flag
)
1450 printf("Adding default code file /usr/share/misc/trace.codes. Use '-N' to skip this.\n");
1451 parse_codefile("/usr/share/misc/trace.codes");
1460 const char *cfile
= argv
[optind
++];
1461 if (verbose_flag
) printf("Adding code file %s \n", cfile
);
1462 parse_codefile(cfile
);
1469 quit_args("-E flag needs an executable to launch\n");
1477 if (pid_flag
&& pid_exflag
)
1478 quit_args("Can't use both -a and -x flag together\n");
1480 if (kval_flag
&& filter_flag
)
1481 quit_args("Cannot use -k flag with -c, -s, or -p\n");
1483 if (output_filename
&& !trace_flag
&& !readRAW_flag
)
1484 quit_args("When using 'o' option, must use the 't' or 'R' option too\n");
1486 filter_done_parsing();
1491 get_bufinfo(&bufinfo
);
1492 int ktrace_state
= get_ktrace_state();
1495 * Only use the current kdebug configuration when foreground
1496 * tracing is enabled. Both checks are necessary because the
1497 * background tool might have enabled tracing, but as soon as we
1498 * try to write a header, that configuration is removed for us.
1500 if ((ktrace_state
== 1) && (bufinfo
.nolog
== 0)) {
1501 use_current_buf
= 1;
1509 set_pidcheck(pid
, 0); /* disable pid check for given pid */
1512 else if (pid_exflag
)
1514 set_pidexclude(pid
, 0); /* disable pid exclusion for given pid */
1529 if (!init_flag
&& !LogRAW_flag
)
1531 fprintf(stderr
,"The -b flag must be used with the -i flag\n");
1545 printf("The kernel tracing settings are:\n");
1547 /* determine the state of ktrace */
1548 int state
= get_ktrace_state();
1550 /* get the name of the last process to configure ktrace */
1551 char execname
[20] = { 0 };
1552 size_t execname_size
= sizeof(execname
);
1553 int err
= sysctlbyname("ktrace.configured_by", &execname
, &execname_size
, NULL
, 0);
1555 fprintf(stderr
, "error: could not query ktrace.configured_by sysctl (%d: %s)\n", errno
, strerror(errno
));
1559 printf("\tTracing is ");
1565 printf("active (foreground)");
1568 printf("active (background)");
1571 printf("in an invalid state");
1576 printf("\tLast configured by \"%s\"\n", execname
[0] == '\0' ? "<unknown>" : execname
);
1578 /* get kdebug info */
1580 get_bufinfo(&bufinfo
);
1582 printf("The kernel buffer settings are:\n");
1584 if (bufinfo
.flags
& KDBG_BUFINIT
)
1585 printf("\tKernel buffer is initialized\n");
1587 printf("\tKernel buffer is not initialized\n");
1589 printf("\t number of buf entries = %d\n", bufinfo
.nkdbufs
);
1593 if (bufinfo
.flags
& KDBG_MAPINIT
)
1594 printf("\tKernel thread map is initialized\n");
1596 printf("\tKernel thread map is not initialized\n");
1597 printf("\t number of thread entries = %d\n", bufinfo
.nkdthreads
);
1601 printf("\tBuffer logging is disabled\n");
1603 printf("\tBuffer logging is enabled\n");
1606 printf("\tkernel flags = 0x%x\n", bufinfo
.flags
);
1608 if (bufinfo
.flags
& KDBG_NOWRAP
)
1609 printf("\tKernel buffer wrap is disabled\n");
1611 printf("\tKernel buffer wrap is enabled\n");
1613 if (bufinfo
.flags
& KDBG_RANGECHECK
)
1614 printf("\tCollection within a range is enabled\n");
1616 printf("\tCollection within a range is disabled\n");
1618 if (bufinfo
.flags
& KDBG_VALCHECK
)
1619 printf("\tCollecting specific code values is enabled\n");
1621 printf("\tCollecting specific code values is disabled\n");
1623 if (bufinfo
.flags
& KDBG_TYPEFILTER_CHECK
)
1624 printf("\tCollection based on a filter is enabled\n");
1626 printf("\tCollection based on a filter is disabled\n");
1628 if (bufinfo
.flags
& KDBG_PIDCHECK
)
1629 printf("\tCollection based on pid is enabled\n");
1631 printf("\tCollection based on pid is disabled\n");
1633 if (bufinfo
.flags
& KDBG_PIDEXCLUDE
)
1634 printf("\tCollection based on pid exclusion is enabled\n");
1636 printf("\tCollection based on pid exclusion is disabled\n");
1638 if (bufinfo
.bufid
== -1)
1639 printf("\tKernel buffer is not controlled by any process.\n");
1641 printf("\tKernel buffer is controlled by proc id [%d]\n", bufinfo
.bufid
);
1644 if (bufinfo
.flags
& KDBG_TYPEFILTER_CHECK
) {
1646 bool (^should_print
)(uint8_t*) = ^bool(uint8_t* ptr
) {
1647 for (uint32_t i
=0; i
<32; ++i
) {
1648 if (ptr
[i
] > 0) return true;
1654 uint8_t* typefilter
= (uint8_t*)kdebug_typefilter();
1656 bool header
= false;
1658 // Reduce noise, only print lines that are allowing events.
1659 for (uint32_t tclass
= 0; tclass
< 0x100; ++tclass
) {
1660 uint8_t* base
= &typefilter
[tclass
* 32];
1661 if (should_print(base
)) {
1664 printf("\tTypefilter:\n");
1666 for (uint32_t tsubclass
=0; tsubclass
<32; ++tsubclass
) {
1667 printf("%02x ", tsubclass
* 8);
1671 for (uint32_t tsubclass
=0; tsubclass
<32; ++tsubclass
) {
1676 printf("%16s%02x: ", "", tclass
);
1677 for (uint32_t tsubclass
=0; tsubclass
<32; ++tsubclass
) {
1678 printf("%02X ", typefilter
[(tclass
* 32) + tsubclass
]);
1699 fprintf(stderr
, "Starting program: %s\n", argv
[optind
]);
1703 execute_process(&(argv
[optind
]));
1707 else if (enable_flag
)
1710 set_pidcheck(pid
, 1);
1711 else if (pid_exflag
)
1712 set_pidexclude(pid
, 1);
1716 if (output_filename
)
1718 if (((output_fd
= open(output_filename
, O_CREAT
| O_TRUNC
| O_WRONLY
| O_APPEND
, 0644)) < 0 ) ||
1719 !(output_file
= fdopen(output_fd
, "w")))
1721 fprintf(stderr
, "Cannot open file \"%s\" for writing.\n", output_filename
);
1724 setbuffer(output_file
, &sbuffer
[0], SBUFFER_SIZE
);
1726 if (fcntl(output_fd
, F_NOCACHE
, 1) < 0)
1729 fprintf(stderr
, "Warning: setting F_NOCACHE on %s, failed\n", output_filename
);
1732 if (!LogRAW_flag
&& !logRAW_flag
)
1733 setbuffer(output_file
, &sbuffer
[0], SBUFFER_SIZE
);
1735 if (trace_flag
|| readRAW_flag
)
1737 else if (LogRAW_flag
)
1739 else if (logRAW_flag
)
1747 execute_process(char * const argv
[])
1751 posix_spawnattr_t spawn_attrs
;
1755 /* ensure that the process being spawned starts suspended */
1756 rc
= posix_spawnattr_init(&spawn_attrs
);
1758 quit_args("Failed to initialize spawn attrs: %s\n", strerror(rc
));
1760 rc
= posix_spawnattr_setflags(&spawn_attrs
,
1761 POSIX_SPAWN_START_SUSPENDED
);
1763 quit_args("Unable to start process suspended: %s\n", strerror(rc
));
1766 /* spawn the process with the rest of the arguments */
1767 rc
= posix_spawnp(&pid
, argv
[0], NULL
, &spawn_attrs
, argv
, environ
);
1769 quit_args("Unabled to start process: %s\n", strerror(rc
));
1772 signal(SIGINT
, signal_handler
);
1773 set_pidcheck(pid
, 1);
1776 /* start the child process */
1777 rc
= kill(pid
, SIGCONT
);
1779 perror("Failed to continue child process:");
1783 rc
= waitpid(pid
, &status
, 0);
1785 perror("Failed to wait for process: ");
1790 quit_args(const char *fmt
, ...)
1797 set_enable(1); /* re-enable kernel logging */
1802 va_start (args
, fmt
);
1803 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
1805 fprintf(stderr
, "trace error: %s", buffer
);
1809 if (!done_with_args
)
1822 set_enable(1); /* re-enable kernel logging */
1832 usage(int short_help
)
1837 (void)fprintf(stderr
, " usage: trace -h [-v]\n");
1838 (void)fprintf(stderr
, " usage: trace -i [-b numbufs]\n");
1839 (void)fprintf(stderr
, " usage: trace -g\n");
1840 (void)fprintf(stderr
, " usage: trace -d [-a pid | -x pid ]\n");
1841 (void)fprintf(stderr
, " usage: trace -r\n");
1842 (void)fprintf(stderr
, " usage: trace -n\n");
1844 (void)fprintf(stderr
,
1845 " usage: trace -e [ -c class [[-s subclass]... | -p class ]]... | \n");
1846 (void)fprintf(stderr
,
1847 " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter] \n");
1848 (void)fprintf(stderr
,
1849 " [-a pid | -x pid] \n\n");
1851 (void)fprintf(stderr
,
1852 " usage: trace -E [ -c class [[-s subclass]... | -p class ]]... | \n");
1853 (void)fprintf(stderr
,
1854 " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter] \n");
1855 (void)fprintf(stderr
,
1856 " executable_path [optional args to executable] \n\n");
1858 (void)fprintf(stderr
,
1859 " usage: trace -L RawFilename [-S SecsToRun]\n");
1860 (void)fprintf(stderr
,
1861 " usage: trace -l RawFilename\n");
1862 (void)fprintf(stderr
,
1863 " usage: trace -R RawFilename [-X] [-F frequency] [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...]\n");
1864 (void)fprintf(stderr
,
1865 " usage: trace -t [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...]\n");
1866 (void)fprintf(stderr
,
1867 " 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");
1872 /* Only get here if printing long usage info */
1873 (void)fprintf(stderr
, "usage: trace -h [-v]\n");
1874 (void)fprintf(stderr
, "\tPrint this long command help.\n\n");
1875 (void)fprintf(stderr
, "\t -v Print extra information about tracefilter and code files.\n\n");
1877 (void)fprintf(stderr
, "usage: trace -i [-b numbufs]\n");
1878 (void)fprintf(stderr
, "\tInitialize the kernel trace buffer.\n\n");
1879 (void)fprintf(stderr
, "\t-b numbufs The number of trace elements the kernel buffer\n");
1880 (void)fprintf(stderr
, "\t can hold is set to numbufs. Use with the -i flag.\n");
1881 (void)fprintf(stderr
, "\t Enter a decimal value.\n\n");
1883 (void)fprintf(stderr
, "usage: trace -g\n");
1884 (void)fprintf(stderr
, "\tGet the kernel buffer settings.\n\n");
1886 (void)fprintf(stderr
, "usage: trace -d [-a pid | -x pid]\n");
1887 (void)fprintf(stderr
, "\tDisable/stop collection of kernel trace elements.\n\n");
1888 (void)fprintf(stderr
, "\t -a pid Disable/stop collection for this process only.\n\n");
1889 (void)fprintf(stderr
, "\t -x pid Disable/stop exclusion of this process only.\n\n");
1891 (void)fprintf(stderr
, "usage: trace -r\n");
1892 (void)fprintf(stderr
, "\tRemove the kernel trace buffer. Set controls to default.\n\n");
1894 (void)fprintf(stderr
, "usage: trace -n\n");
1895 (void)fprintf(stderr
, "\tDisables kernel buffer wrap around.\n\n");
1897 (void)fprintf(stderr
,
1898 "usage: trace -e [ -c class [[-s subclass]... | -p class ]]... |\n");
1899 (void)fprintf(stderr
,
1900 " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter]\n");
1901 (void) fprintf(stderr
,
1902 " [-a pid | -x pid]\n\n");
1903 (void)fprintf(stderr
, "\t Enable/start collection of kernel trace elements. \n\n");
1904 (void)fprintf(stderr
, "\t By default, trace collects all tracepoints. \n");
1905 (void)fprintf(stderr
, "\t The following arguments may be used to restrict collection \n");
1906 (void)fprintf(stderr
, "\t to a limited set of tracepoints. \n\n");
1907 (void)fprintf(stderr
, "\t Multiple classes can be specified by repeating -c. \n");
1908 (void)fprintf(stderr
, "\t Multiple subclasses can be specified by repeating -s after -c. \n");
1909 (void)fprintf(stderr
, "\t Classes, subclasses, and class ranges can be entered \n");
1910 (void)fprintf(stderr
, "\t in hex (0xXX), decimal (XX), or octal (0XX). \n\n");
1911 (void)fprintf(stderr
, "\t -c class Restrict trace collection to given class. \n\n");
1912 (void)fprintf(stderr
, "\t -p class Restrict trace collection to given class range. \n");
1913 (void)fprintf(stderr
, "\t Must provide class with -c first. \n\n");
1914 (void)fprintf(stderr
, "\t -s subclass Restrict trace collection to given subclass. \n");
1915 (void)fprintf(stderr
, "\t Must provide class with -c first. \n\n");
1916 (void)fprintf(stderr
, "\t -a pid Restrict trace collection to the given process.\n\n");
1917 (void)fprintf(stderr
, "\t -x pid Exclude the given process from trace collection.\n\n");
1918 (void)fprintf(stderr
, "\t -k code Restrict trace collection up to four specific codes.\n");
1919 (void)fprintf(stderr
, "\t Enter codes in hex (0xXXXXXXXX). \n\n");
1920 (void)fprintf(stderr
, "\t -P Enable restricted PPT trace points only.\n\n");
1921 (void)fprintf(stderr
, "\t -T tracefilter Read class and subclass restrictions from a \n");
1922 (void)fprintf(stderr
, "\t tracefilter description file. \n");
1923 (void)fprintf(stderr
, "\t Run trace -h -v for more info on this file. \n\n");
1925 (void)fprintf(stderr
,
1926 "usage: trace -E [ -c class [[-s subclass]... | -p class ]]... |\n");
1927 (void)fprintf(stderr
,
1928 " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter]\n");
1929 (void)fprintf(stderr
,
1930 " executable_path [optional args to executable] \n\n");
1931 (void)fprintf(stderr
, "\tLaunch the given executable and enable/start\n");
1932 (void)fprintf(stderr
, "\tcollection of kernel trace elements for that process.\n");
1933 (void)fprintf(stderr
, "\tSee -e(enable) flag for option descriptions.\n\n");
1935 (void)fprintf(stderr
, "usage: trace -t [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...] \n");
1936 (void)fprintf(stderr
, "\tCollect the kernel buffer trace data and print it.\n\n");
1937 (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");
1938 (void)fprintf(stderr
, "\t -o OutputFilename Print trace output to OutputFilename. Default is stdout.\n\n");
1940 (void)fprintf(stderr
,
1941 "usage: trace -R RawFilename [-X] [-F frequency] [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...] \n");
1942 (void)fprintf(stderr
, "\tRead raw trace file and print it.\n\n");
1943 (void)fprintf(stderr
, "\t -X Force trace to interpret trace data as 32 bit. \n");
1944 (void)fprintf(stderr
, "\t Default is to match the bit width of the current system. \n");
1945 (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");
1946 (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");
1947 (void)fprintf(stderr
, "\t -o OutputFilename Print trace output to OutputFilename. Default is stdout.\n\n");
1949 (void)fprintf(stderr
,
1950 "usage: trace -L RawFilename [-S SecsToRun]\n");
1951 (void)fprintf(stderr
, "\tContinuously collect the kernel buffer trace data in the raw format \n");
1952 (void)fprintf(stderr
, "\tand write it to RawFilename. \n");
1954 (void)fprintf(stderr
, "\t-L implies -r -i if tracing isn't currently enabled.\n");
1955 (void)fprintf(stderr
, "\tOptions passed to -e(enable) are also accepted by -L. (except -a -x -P)\n\n");
1956 (void)fprintf(stderr
, "\t -S SecsToRun Specify the number of seconds to collect trace data.\n\n");
1958 (void)fprintf(stderr
,
1959 "usage: trace -l RawFilename\n");
1960 (void)fprintf(stderr
, "\tCollect the existing kernel buffer trace data in the raw format.\n\n");
1963 (void)fprintf(stderr
,
1965 "\t A code file consists of a list of tracepoints, one per line, \n"
1966 "\t with one tracepoint code in hex, followed by a tab, \n"
1967 "\t followed by the tracepoint's name. \n\n"
1969 "\t Example tracepoint: \n"
1970 "\t 0x010c007c\tMSC_mach_msg_trap \n"
1971 "\t This describes the tracepoint with the following info: \n"
1972 "\t Name: MSC_mach_msg_trap \n"
1973 "\t Class: 0x01 (Mach events) \n"
1974 "\t Subclass: 0x0c (Mach system calls) \n"
1975 "\t Code: 0x007c (Mach syscall number 31) \n\n"
1977 "\t See /usr/include/sys/kdebug.h for the currently defined \n"
1978 "\t class and subclass values. \n"
1979 "\t See /usr/share/misc/trace.codes for the currently allocated \n"
1980 "\t system tracepoints in trace code file format. \n"
1981 "\t This codefile is useful with the -R argument to trace. \n"
1984 (void)fprintf(stderr
,
1985 "Tracefilter description file: \n"
1986 "\t A tracefilter description file consists of a list of \n"
1987 "\t class and subclass filters in hex, one per line, \n"
1988 "\t which are applied as if they were passed with -c and -s. \n"
1989 "\t Pass -v to see what classes and subclasses are being set. \n\n"
1991 "\t File syntax: \n"
1992 "\t Class filter: \n"
1994 "\t Subclass filter (includes class): \n"
1997 "\t # This is a comment \n\n"
1999 "\t For example, to trace Mach events (class 1):\n"
2001 "\t or to trace Mach system calls (class 1 subclass 13): \n"
2011 argtoi(int flag
, char *req
, char *str
, int base
)
2016 ret
= (int)strtol(str
, &cp
, base
);
2017 if (cp
== str
|| *cp
)
2018 errx(EINVAL
, "-%c flag requires a %s", flag
, req
);
2022 static unsigned long
2023 argtoul(int flag
, char *req
, char *str
, int base
)
2028 ret
= (int)strtoul(str
, &cp
, base
);
2029 if (cp
== str
|| *cp
)
2030 errx(EINVAL
, "-%c flag requires a %s", flag
, req
);
2035 * comparison function for qsort
2039 debugid_compar(const void *p1
, const void *p2
)
2041 const code_type_t
*q1
= (const code_type_t
*)p1
;
2042 const code_type_t
*q2
= (const code_type_t
*)p2
;
2044 if (q1
->debugid
> q2
->debugid
)
2046 else if (q1
->debugid
== q2
->debugid
)
2053 * Filter args parsing state machine:
2059 * every -c goes back to start
2061 * Valid transitions:
2062 * start -> class (first -c)
2063 * class -> range (-c -p)
2064 * class -> sub (-c -s)
2065 * class -> class (-c -c)
2066 * range -> class (-c -p -c)
2067 * sub -> class (-c -s -c)
2068 * * -> start (on filter_done_parsing)
2070 * Need to call filter_done_parsing after
2071 * calling saw_filter_*
2072 * to flush out any class flag waiting to see if
2073 * there is a -s flag coming up
2077 // What type of flag did I last see?
2081 FILTER_MODE_CLASS_RANGE
,
2082 FILTER_MODE_SUBCLASS
2083 } filter_mode
= FILTER_MODE_START
;
2085 uint8_t filter_current_class
= 0;
2086 uint8_t filter_current_subclass
= 0;
2087 uint8_t filter_current_class_range
= 0;
2090 saw_filter_class(uint8_t class)
2092 switch(filter_mode
) {
2093 case FILTER_MODE_START
:
2094 case FILTER_MODE_CLASS_RANGE
:
2095 case FILTER_MODE_SUBCLASS
:
2096 filter_mode
= FILTER_MODE_CLASS
;
2097 filter_current_class
= class;
2098 filter_current_subclass
= 0;
2099 filter_current_class_range
= 0;
2100 // the case of a lone -c is taken care of
2101 // by filter_done_parsing
2103 case FILTER_MODE_CLASS
:
2104 filter_mode
= FILTER_MODE_CLASS
;
2105 // set old class, remember new one
2106 set_filter_class(filter_current_class
);
2107 filter_current_class
= class;
2108 filter_current_subclass
= 0;
2109 filter_current_class_range
= 0;
2112 quit_args("invalid case in saw_filter_class\n");
2117 saw_filter_end_range(uint8_t end_class
)
2119 switch(filter_mode
) {
2120 case FILTER_MODE_CLASS
:
2121 filter_mode
= FILTER_MODE_CLASS_RANGE
;
2122 filter_current_class_range
= end_class
;
2123 set_filter_range(filter_current_class
, filter_current_class_range
);
2125 case FILTER_MODE_START
:
2126 quit_args("must provide '-c class' before '-p 0x%x'\n",
2128 case FILTER_MODE_CLASS_RANGE
:
2129 quit_args("extra range end '-p 0x%x'"
2130 " for class '-c 0x%x'\n",
2131 end_class
, filter_current_class
);
2132 case FILTER_MODE_SUBCLASS
:
2133 quit_args("cannot provide both range end '-p 0x%x'"
2134 " and subclass '-s 0x%x'"
2135 " for class '-c 0x%x'\n",
2136 end_class
, filter_current_subclass
,
2137 filter_current_class
);
2139 quit_args("invalid case in saw_filter_end_range\n");
2144 saw_filter_subclass(uint8_t subclass
)
2146 switch(filter_mode
) {
2147 case FILTER_MODE_CLASS
:
2148 case FILTER_MODE_SUBCLASS
:
2149 filter_mode
= FILTER_MODE_SUBCLASS
;
2150 filter_current_subclass
= subclass
;
2151 set_filter_subclass(filter_current_class
, filter_current_subclass
);
2153 case FILTER_MODE_START
:
2154 quit_args("must provide '-c class'"
2155 " before subclass '-s 0x%x'\n", subclass
);
2156 case FILTER_MODE_CLASS_RANGE
:
2157 quit_args("cannot provide both range end '-p 0x%x'"
2158 " and subclass '-s 0x%x'"
2159 " for the same class '-c 0x%x'\n",
2160 filter_current_class_range
,
2161 subclass
, filter_current_class
);
2163 quit_args("invalid case in saw_filter_subclass\n");
2168 filter_done_parsing(void)
2170 switch(filter_mode
) {
2171 case FILTER_MODE_CLASS
:
2172 // flush out the current class
2173 set_filter_class(filter_current_class
);
2174 filter_mode
= FILTER_MODE_START
;
2175 filter_current_class
= 0;
2176 filter_current_subclass
= 0;
2177 filter_current_class_range
= 0;
2179 case FILTER_MODE_SUBCLASS
:
2180 case FILTER_MODE_START
:
2181 case FILTER_MODE_CLASS_RANGE
:
2182 filter_mode
= FILTER_MODE_START
;
2183 filter_current_class
= 0;
2184 filter_current_subclass
= 0;
2185 filter_current_class_range
= 0;
2188 quit_args("invalid case in filter_done_parsing\n");
2192 /* Tell set_filter_subclass not to print every. single. subclass. */
2193 static boolean_t setting_class
= FALSE
;
2194 static boolean_t setting_range
= FALSE
;
2197 set_filter_subclass(uint8_t class, uint8_t subclass
)
2199 if (!filter_alloced
) {
2200 type_filter_bitmap
= (uint8_t *) calloc(1, KDBG_TYPEFILTER_BITMAP_SIZE
);
2201 if (type_filter_bitmap
== NULL
)
2202 quit_args("Could not allocate type_filter_bitmap.\n");
2206 uint16_t csc
= ENCODE_CSC_LOW(class, subclass
);
2208 if (verbose_flag
&& !setting_class
)
2209 printf("tracing subclass: 0x%4.4x\n", csc
);
2211 if (verbose_flag
&& isset(type_filter_bitmap
, csc
))
2212 printf("class %u (0x%2.2x), subclass %u (0x%2.2x) set twice.\n",
2213 class, class, subclass
, subclass
);
2215 setbit(type_filter_bitmap
, csc
);
2219 set_filter_class(uint8_t class)
2221 if (verbose_flag
&& !setting_range
)
2222 printf("tracing class: 0x%2.2x\n", class);
2224 setting_class
= TRUE
;
2226 for (int i
= 0; i
< 256; i
++)
2227 set_filter_subclass(class, i
);
2229 setting_class
= FALSE
;
2233 set_filter_range(uint8_t class, uint8_t end
)
2236 printf("tracing range: 0x%2.2x - 0x%2.2x\n", class, end
);
2238 setting_range
= TRUE
;
2240 for (int i
= class; i
<= end
; i
++)
2241 set_filter_class(i
);
2243 setting_range
= FALSE
;
2247 * Syntax of filter file:
2248 * Hexadecimal numbers only
2251 * Subclass (includes class):
2255 * TBD: Class ranges?
2256 * TBD: K for -k flag?
2260 parse_filter_file(char *filename
)
2263 uint32_t current_line
= 0;
2264 uint32_t parsed_arg
= 0;
2269 if ( (file
= fopen(filename
, "r")) == NULL
) {
2270 quit_args("Failed to open filter description file %s: %s\n",
2271 filename
, strerror(errno
));
2275 printf("Parsing typefilter file: %s\n", filename
);
2277 while( fgets(line
, sizeof(line
), file
) != NULL
) {
2282 rval
= sscanf(line
, "C 0x%x\n", &parsed_arg
);
2284 quit_args("invalid line %d of file %s: %s\n",
2285 current_line
, filename
, line
);
2286 if (parsed_arg
> 0xFF)
2287 quit_args("line %d of file %s: %s\n"
2289 "class value must be 0x0-0xFF\n",
2290 current_line
, filename
, line
, parsed_arg
);
2291 set_filter_class((uint8_t)parsed_arg
);
2294 rval
= sscanf(line
, "S 0x%x\n", &parsed_arg
);
2296 quit_args("invalid line %d of file %s: %s\n",
2297 current_line
, filename
, line
);
2298 if (parsed_arg
> 0xFFFF)
2299 quit_args("line %d of file %s: %s\n"
2301 "value must be 0x0-0xFFFF\n",
2302 current_line
, filename
, line
, parsed_arg
);
2303 set_filter_subclass(EXTRACT_CLASS_LOW(parsed_arg
),
2304 EXTRACT_SUBCLASS_LOW(parsed_arg
));
2316 quit_args("Invalid filter description file: %s\n"
2317 "could not parse line %d: %s\n",
2318 filename
, current_line
, line
);
2326 * Find the debugid code in the list and return its index
2329 binary_search(code_type_t
*list
, int lowbound
, int highbound
, unsigned int code
)
2339 mid
= (low
+ high
) / 2;
2344 return (-1); /* failed */
2345 else if ( low
+ 1 >= high
)
2347 /* We have a match */
2348 if (list
[high
].debugid
== code
)
2350 else if (list
[low
].debugid
== code
)
2353 return(-1); /* search failed */
2355 else if (code
< list
[mid
].debugid
)
2364 parse_codefile(const char *filename
)
2369 struct stat stat_buf
;
2371 char *file_addr
, *endp
;
2373 if ((fd
= open(filename
, O_RDONLY
, 0)) == -1)
2375 printf("Failed to open code description file %s\n",filename
);
2379 if (fstat(fd
, &stat_buf
) == -1)
2381 printf("Error: Can't fstat file: %s\n", filename
);
2386 * For some reason mapping files with zero size fails
2387 * so it has to be handled specially.
2389 file_size
= (size_t)stat_buf
.st_size
;
2391 if (stat_buf
.st_size
!= 0)
2393 file_addr
= mmap(0, file_size
, PROT_READ
| PROT_WRITE
,
2394 MAP_PRIVATE
| MAP_FILE
, fd
, 0);
2395 if (file_addr
== MAP_FAILED
)
2397 printf("Error: Can't map file: %s\n", filename
);
2412 * If we get here, we have mapped the file
2413 * and we are ready to parse it. Count
2414 * the newlines to get total number of codes.
2417 for (count
= 0, j
=1; j
< file_size
; j
++)
2419 if (file_addr
[j
] == '\n')
2425 printf("Error: No codes in %s\n", filename
);
2430 * Fudge the count to accomodate the last line in the file -
2431 * in case it doesn't end in a newline.
2435 /* Grow the size of codesc to store new entries. */
2436 size_t total_count
= codesc_idx
+ count
;
2437 code_type_t
*new_codesc
= (code_type_t
*)realloc(codesc
, (total_count
) * sizeof(code_type_t
));
2439 if (new_codesc
== NULL
) {
2440 printf("Failed to grow/allocate buffer. Skipping file %s\n", filename
);
2443 codesc
= new_codesc
;
2444 bzero((char *)(codesc
+ codesc_idx
), count
* sizeof(code_type_t
));
2446 for (line
= 1, j
= 0; j
< file_size
&& codesc_idx
< total_count
;
2449 /* Skip blank lines */
2450 while (j
< file_size
&& file_addr
[j
] == '\n')
2456 /* Skip leading whitespace */
2457 while (file_addr
[j
] == ' ' || file_addr
[j
] == '\t')
2460 /* Get the debugid code */
2461 codesc
[codesc_idx
].debugid
= (uint32_t)strtoul(file_addr
+ j
, &endp
, 16);
2462 j
= (int)(endp
- file_addr
);
2464 if (codesc
[codesc_idx
].debugid
== 0)
2466 /* We didn't find a debugid code - skip this line */
2468 printf("Error: while parsing line %d, skip\n", line
);
2469 while (j
< file_size
&& file_addr
[j
] != '\n')
2476 /* Skip whitespace */
2477 while (j
< file_size
&& (file_addr
[j
] == ' ' || file_addr
[j
] == '\t'))
2487 /* Get around old file that had count at the beginning */
2488 if (file_addr
[j
] == '\n')
2490 /* missing debugid string - skip */
2493 printf("Error: while parsing line %d, (0x%x) skip\n", line
,
2494 codesc
[codesc_idx
].debugid
);
2508 /* Next is the debugid string terminated by a newline */
2509 codesc
[codesc_idx
].debug_string
= &file_addr
[j
];
2511 /* Null out the newline terminator */
2512 while (j
< file_size
&& file_addr
[j
] != '\n')
2522 file_addr
[j
] = '\0'; /* File must be read-write */
2525 codenum
++; /*Index into codesc is 0 to codenum-1 */
2530 printf("Parsed %d codes in %s\n", codenum
, filename
);
2531 printf("[%6d] 0x%8x %s\n", 0, codesc
[0].debugid
, codesc
[0].debug_string
);
2532 printf("[%6d] 0x%8x %s\n\n", codenum
-1, codesc
[codenum
-1].debugid
, codesc
[codenum
-1].debug_string
);
2536 qsort((void *)codesc
, codesc_idx
, sizeof(code_type_t
), debugid_compar
);
2540 printf("Sorted %zd codes in %s\n", codesc_idx
, filename
);
2541 printf("lowbound [%6d]: 0x%8x %s\n", 0, codesc
[0].debugid
, codesc
[0].debug_string
);
2542 printf("highbound [%6zd]: 0x%8x %s\n\n", codesc_idx
- 1, codesc
[codesc_idx
- 1].debugid
, codesc
[codesc_idx
- 1].debug_string
);
2544 codesc_find_dupes();
2547 /* Dump the codefile */
2549 for (i
= 0; i
< codesc_idx
; i
++)
2550 printf("[%d] 0x%x %s\n",i
+1, codesc
[i
].debugid
, codesc
[i
].debug_string
);
2556 codesc_find_dupes(void)
2558 boolean_t found_dupes
= FALSE
;
2559 if (codesc_idx
== 0)
2563 uint32_t last_debugid
= codesc
[0].debugid
;
2564 for(int i
= 1; i
< codesc_idx
; i
++)
2566 if(codesc
[i
].debugid
== last_debugid
)
2570 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
);
2573 last_debugid
= codesc
[i
].debugid
;
2577 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");
2582 match_debugid(unsigned int xx
, char * debugstr
, int * yy
)
2589 if (codesc
[codeindx_cache
].debugid
!= xx
)
2590 indx
= binary_search(codesc
, 0, (codenum
-1), xx
);
2592 indx
= codeindx_cache
;
2595 return(indx
); /* match failed */
2597 bcopy(&codesc
[indx
].debug_string
[0], debugstr
,80);
2599 codeindx_cache
= indx
;
2600 return(0); /* match success */
2605 read_cpu_map(int fd
)
2607 if (cpumap_header
) {
2608 free(cpumap_header
);
2609 cpumap_header
= NULL
;
2614 * To fit in the padding space of a VERSION1 file, the max possible
2615 * cpumap size is one page.
2617 cpumap_header
= malloc(PAGE_SIZE
);
2621 * cpu maps exist in a RAW_VERSION1+ header only
2623 if (raw_header
.version_no
== RAW_VERSION1
) {
2624 off_t cpumap_position
= lseek(fd
, 0, SEEK_CUR
);
2625 /* cpumap is part of the last 4KB of padding in the preamble */
2626 size_t padding_bytes
= SIZE_4KB
- (cpumap_position
& (SIZE_4KB
- 1));
2628 if (read(fd
, cpumap_header
, padding_bytes
) == padding_bytes
) {
2629 if (cpumap_header
->version_no
== RAW_VERSION1
) {
2630 cpumap
= (kd_cpumap
*)&cpumap_header
[1];
2638 mib
[1] = KERN_KDEBUG
;
2639 mib
[2] = KERN_KDCPUMAP
;
2641 size_t temp
= PAGE_SIZE
;
2642 if (sysctl(mib
, 3, cpumap_header
, &temp
, NULL
, 0) == 0) {
2643 if (PAGE_SIZE
>= temp
) {
2644 if (cpumap_header
->version_no
== RAW_VERSION1
) {
2645 cpumap
= (kd_cpumap
*)&cpumap_header
[1];
2652 printf("Can't read the cpu map -- this is not fatal\n");
2653 free(cpumap_header
);
2654 cpumap_header
= NULL
;
2655 } else if (verbose_flag
) {
2656 /* Dump the initial cpumap */
2657 printf("\nCPU\tName\n");
2658 for (int i
= 0; i
< cpumap_header
->cpu_count
; i
++) {
2659 printf ("%2d\t%s\n", cpumap
[i
].cpu_id
, cpumap
[i
].name
);
2666 read_command_map(int fd
, uint32_t count
)
2673 total_threads
= count
;
2674 size
= count
* sizeof(kd_threadmap
);
2676 get_bufinfo(&bufinfo
);
2678 total_threads
= bufinfo
.nkdthreads
;
2679 size
= bufinfo
.nkdthreads
* sizeof(kd_threadmap
);
2682 nthreads
= total_threads
* 2;
2685 printf("Size of map table is %d, thus %d entries\n", (int)size
, total_threads
);
2688 if ((mapptr
= (kd_threadmap
*) malloc(size
)))
2689 bzero (mapptr
, size
);
2693 printf("Thread map is not initialized -- this is not fatal\n");
2698 if (read(fd
, mapptr
, size
) != size
) {
2700 printf("Can't read the thread map -- this is not fatal\n");
2707 /* Now read the threadmap */
2709 mib
[1] = KERN_KDEBUG
;
2710 mib
[2] = KERN_KDTHRMAP
;
2713 mib
[5] = 0; /* no flags */
2714 if (sysctl(mib
, 3, mapptr
, &size
, NULL
, 0) < 0)
2716 /* This is not fatal -- just means I cant map command strings */
2718 printf("Can't read the thread map -- this is not fatal\n");
2724 for (i
= 0; i
< total_threads
; i
++) {
2725 if (mapptr
[i
].thread
)
2726 create_map_entry(mapptr
[i
].thread
, &mapptr
[i
].command
[0]);
2730 /* Dump the initial map */
2732 printf("Size of maptable returned is %ld, thus %ld entries\n", size
, (size
/sizeof(kd_threadmap
)));
2734 printf("Thread Command\n");
2735 for (i
= 0; i
< total_threads
; i
++) {
2736 printf ("0x%" PRIx64
" %s\n",
2737 (uint64_t)mapptr
[i
].thread
,
2746 create_map_entry(uint64_t thread
, char *command
)
2751 if ((tme
= threadmap_freelist
))
2752 threadmap_freelist
= tme
->tm_next
;
2754 tme
= (threadmap_t
)malloc(sizeof(struct threadmap
));
2756 tme
->tm_thread
= thread
;
2757 tme
->tm_deleteme
= FALSE
;
2759 (void)strncpy (tme
->tm_command
, command
, MAXCOMLEN
);
2760 tme
->tm_command
[MAXCOMLEN
] = '\0';
2762 hashid
= thread
& HASH_MASK
;
2764 tme
->tm_next
= threadmap_hash
[hashid
];
2765 threadmap_hash
[hashid
] = tme
;
2769 delete_thread_entry(uint64_t thread
)
2771 threadmap_t tme
= 0;
2772 threadmap_t tme_prev
;
2775 hashid
= thread
& HASH_MASK
;
2777 if ((tme
= threadmap_hash
[hashid
])) {
2778 if (tme
->tm_thread
== thread
)
2779 threadmap_hash
[hashid
] = tme
->tm_next
;
2783 for (tme
= tme
->tm_next
; tme
; tme
= tme
->tm_next
) {
2784 if (tme
->tm_thread
== thread
) {
2785 tme_prev
->tm_next
= tme
->tm_next
;
2792 tme
->tm_next
= threadmap_freelist
;
2793 threadmap_freelist
= tme
;
2799 find_and_insert_tmp_map_entry(uint64_t pthread
, char *command
)
2801 threadmap_t tme
= 0;
2802 threadmap_t tme_prev
;
2805 if ((tme
= threadmap_temp
)) {
2806 if (tme
->tm_pthread
== pthread
)
2807 threadmap_temp
= tme
->tm_next
;
2811 for (tme
= tme
->tm_next
; tme
; tme
= tme
->tm_next
) {
2812 if (tme
->tm_pthread
== pthread
) {
2813 tme_prev
->tm_next
= tme
->tm_next
;
2820 (void)strncpy (tme
->tm_command
, command
, MAXCOMLEN
);
2821 tme
->tm_command
[MAXCOMLEN
] = '\0';
2823 delete_thread_entry(tme
->tm_thread
);
2825 hashid
= tme
->tm_thread
& HASH_MASK
;
2827 tme
->tm_next
= threadmap_hash
[hashid
];
2828 threadmap_hash
[hashid
] = tme
;
2834 create_tmp_map_entry(uint64_t thread
, uint64_t pthread
)
2838 if ((tme
= threadmap_freelist
))
2839 threadmap_freelist
= tme
->tm_next
;
2841 tme
= (threadmap_t
)malloc(sizeof(struct threadmap
));
2843 tme
->tm_thread
= thread
;
2844 tme
->tm_pthread
= pthread
;
2845 tme
->tm_deleteme
= FALSE
;
2846 tme
->tm_command
[0] = '\0';
2848 tme
->tm_next
= threadmap_temp
;
2849 threadmap_temp
= tme
;
2854 find_thread_entry(uint64_t thread
)
2859 hashid
= thread
& HASH_MASK
;
2861 for (tme
= threadmap_hash
[hashid
]; tme
; tme
= tme
->tm_next
) {
2862 if (tme
->tm_thread
== thread
)
2869 find_thread_name(uint64_t thread
, char **command
, boolean_t deleteme
)
2873 if ((tme
= find_thread_entry(thread
))) {
2874 *command
= tme
->tm_command
;
2876 if (deleteme
== TRUE
)
2877 tme
->tm_deleteme
= deleteme
;
2879 *command
= EMPTYSTRING
;
2883 find_thread_command(kd_buf
*kbufp
, char **command
)
2889 *command
= EMPTYSTRING
;
2891 thread
= kbufp
->arg5
;
2892 debugid_base
= kbufp
->debugid
& DBG_FUNC_MASK
;
2894 if (debugid_base
== BSC_exit
|| debugid_base
== MACH_STKHANDOFF
) {
2896 * Mark entry as invalid and return temp command pointer
2898 if ((tme
= find_thread_entry(thread
))) {
2900 strncpy(tmpcommand
, tme
->tm_command
, MAXCOMLEN
);
2901 *command
= tmpcommand
;
2903 if (debugid_base
== BSC_exit
|| tme
->tm_deleteme
== TRUE
)
2904 delete_thread_entry(thread
);
2907 else if (debugid_base
== TRACE_DATA_NEWTHREAD
) {
2909 * Save the create thread data
2911 create_tmp_map_entry(kbufp
->arg1
, kbufp
->arg5
);
2913 else if (debugid_base
== TRACE_STRING_NEWTHREAD
) {
2915 * process new map entry
2917 find_and_insert_tmp_map_entry(kbufp
->arg5
, (char *)&kbufp
->arg1
);
2919 else if (debugid_base
== TRACE_STRING_EXEC
) {
2921 delete_thread_entry(kbufp
->arg5
);
2923 create_map_entry(kbufp
->arg5
, (char *)&kbufp
->arg1
);
2926 find_thread_name(thread
, command
, (debugid_base
== BSC_thread_terminate
));
2932 (void) mach_timebase_info (&mach_timebase
);
2934 if (frequency
== 0) {
2935 divisor
= ( (double)mach_timebase
.denom
/ (double)mach_timebase
.numer
) * 1000;
2937 divisor
= (double)frequency
/ 1000000;
2940 printf("divisor = %g\n", divisor
);