]> git.saurik.com Git - apple/system_cmds.git/blob - trace.tproj/trace.c
system_cmds-880.100.5.tar.gz
[apple/system_cmds.git] / trace.tproj / trace.c
1 /*
2 cc -I/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders -arch x86_64 -arch i386 -O -o trace trace.c
3 */
4
5 /*
6 * NOTE: There exists another copy of this file in the kernel_tools. Changes
7 * made here may also need to be made there.
8 */
9
10 #include <sys/param.h>
11 #include <sys/types.h>
12 #include <sys/file.h>
13 #include <sys/socket.h>
14 #include <sys/stat.h>
15 #include <sys/ioctl.h>
16 #include <sys/mbuf.h>
17 #include <sys/mman.h>
18 #include <sys/ucred.h>
19 #include <sys/time.h>
20 #include <sys/proc.h>
21 #include <sys/ptrace.h>
22 #include <sys/sysctl.h>
23 #include <sys/wait.h>
24 #include <sys/resource.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <paths.h>
32 #include <err.h>
33 #include <stdarg.h>
34 #include <inttypes.h>
35 #include <spawn.h>
36 #include <assert.h>
37 #include <signal.h>
38 #include <sysexits.h>
39
40 #include <libutil.h>
41
42 #ifndef KERNEL_PRIVATE
43 #define KERNEL_PRIVATE
44 #include <sys/kdebug.h>
45 #undef KERNEL_PRIVATE
46 #else
47 #include <sys/kdebug.h>
48 #endif /*KERNEL_PRIVATE*/
49 #include <sys/param.h>
50
51 #include <mach/mach.h>
52 #include <mach/mach_time.h>
53
54 int nbufs = 0;
55 int enable_flag=0;
56 int execute_flag=0;
57 int logRAW_flag=0;
58 int LogRAW_flag=0;
59 int readRAW_flag = 0;
60 int disable_flag=0;
61 int init_flag=0;
62 int kval_flag=0;
63 int remove_flag=0;
64 int bufset_flag=0;
65 int bufget_flag=0;
66 int filter_flag=0;
67 int filter_file_flag=0;
68 int filter_alloced=0;
69 int trace_flag=0;
70 int nowrap_flag=0;
71 int freerun_flag=0;
72 int verbose_flag=0;
73 int usage_flag=0;
74 int pid_flag=0;
75 int pid_exflag=0;
76 int ppt_flag=0;
77 int done_with_args=0;
78 int no_default_codes_flag=0;
79
80 unsigned int value1=0;
81 unsigned int value2=0;
82 unsigned int value3=0;
83 unsigned int value4=0;
84
85 pid_t pid=0;
86 int reenable=0;
87
88 int force_32bit_exec = 0;
89 int frequency = 0;
90
91 int mib[6];
92 size_t needed;
93
94 char *logfile = (char *)0; /* This file is trace format */
95 char *RAW_file = (char *)0;
96 FILE *output_file;
97 int output_fd;
98
99 extern char **environ;
100
101 uint8_t* type_filter_bitmap;
102
103 #define SIZE_4KB (4 * (1 << 10))
104
105 #define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
106 #define DBG_FUNC_MASK 0xfffffffc
107 #define SHORT_HELP 1
108 #define LONG_HELP 0
109
110 #define CSC_MASK 0xffff0000
111
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
117
118 #define EMPTYSTRING ""
119 #define UNKNOWN "unknown"
120
121 char tmpcommand[MAXCOMLEN];
122
123 int total_threads = 0;
124 int nthreads = 0;
125 kd_threadmap *mapptr = 0;
126
127 kd_cpumap_header* cpumap_header = NULL;
128 kd_cpumap* cpumap = NULL;
129
130 /*
131 If NUMPARMS changes from the kernel,
132 then PATHLENGTH will also reflect the change
133 This is for the vfslookup entries that
134 return pathnames
135 */
136 #define NUMPARMS 23
137 #define PATHLENGTH (NUMPARMS*sizeof(long))
138
139
140 #define US_TO_SLEEP 50000
141 #define BASE_EVENTS 500000
142
143 mach_timebase_info_data_t mach_timebase;
144 double divisor;
145
146 typedef struct {
147 uint32_t debugid;
148 char *debug_string;
149 } code_type_t;
150
151 code_type_t* codesc = 0;
152 size_t codesc_idx = 0; // Index into first empty codesc entry
153
154
155
156 typedef struct event *event_t;
157
158 struct event {
159 event_t ev_next;
160
161 uint64_t ev_thread;
162 uint32_t ev_debugid;
163 uint64_t ev_timestamp;
164 };
165
166 typedef struct lookup *lookup_t;
167
168 struct lookup {
169 lookup_t lk_next;
170
171 uint64_t lk_thread;
172 uint64_t lk_dvp;
173 int64_t *lk_pathptr;
174 int64_t lk_pathname[NUMPARMS + 1];
175 };
176
177 typedef struct threadmap *threadmap_t;
178
179 struct threadmap {
180 threadmap_t tm_next;
181
182 uint64_t tm_thread;
183 uint64_t tm_pthread;
184 boolean_t tm_deleteme;
185 char tm_command[MAXCOMLEN + 1];
186 };
187
188 #define HASH_SIZE 1024
189 #define HASH_MASK 1023
190
191 event_t event_hash[HASH_SIZE];
192 lookup_t lookup_hash[HASH_SIZE];
193 threadmap_t threadmap_hash[HASH_SIZE];
194
195 event_t event_freelist;
196 lookup_t lookup_freelist;
197 threadmap_t threadmap_freelist;
198 threadmap_t threadmap_temp;
199
200
201 #define SBUFFER_SIZE (128 * 4096)
202 char sbuffer[SBUFFER_SIZE];
203
204 int secs_to_run = 0;
205 int use_current_buf = 0;
206
207
208 kbufinfo_t bufinfo = {0, 0, 0, 0};
209
210 int codenum = 0;
211 int codeindx_cache = 0;
212
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();
225
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[]);
248
249 static int writetrace(int);
250 static int write_command_map(int);
251 static int debugid_compar(const void *, const void *);
252
253 static threadmap_t find_thread_entry(uint64_t);
254
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);
259
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);
264
265 static void parse_filter_file(char *filename);
266
267 static void quit_args(const char *fmt, ...) __printflike(1, 2);
268
269 #ifndef KERN_KDWRITETR
270 #define KERN_KDWRITETR 17
271 #endif
272
273 #ifndef KERN_KDWRITEMAP
274 #define KERN_KDWRITEMAP 18
275 #endif
276
277 #ifndef F_FLUSH_DATA
278 #define F_FLUSH_DATA 40
279 #endif
280
281 #ifndef RAW_VERSION1
282 typedef struct {
283 int version_no;
284 int thread_count;
285 uint64_t TOD_secs;
286 uint32_t TOD_usecs;
287 } RAW_header;
288
289 #define RAW_VERSION0 0x55aa0000
290 #define RAW_VERSION1 0x55aa0101
291 #endif
292
293 #define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(*x)))
294
295 #define EXTRACT_CLASS_LOW(debugid) ( (uint8_t) ( ((debugid) & 0xFF00 ) >> 8 ) )
296 #define EXTRACT_SUBCLASS_LOW(debugid) ( (uint8_t) ( ((debugid) & 0xFF ) ) )
297
298 #define ENCODE_CSC_LOW(class, subclass) \
299 ( (uint16_t) ( ((class) & 0xff) << 8 ) | ((subclass) & 0xff) )
300
301 RAW_header raw_header;
302
303
304
305 void set_enable(int val)
306 {
307 mib[0] = CTL_KERN;
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;
313 } else {
314 mib[3] = val;
315 }
316 #else
317 mib[3] = val;
318 #endif
319 mib[4] = 0;
320 mib[5] = 0;
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");
324 }
325 quit_args("trace facility failure, KERN_KDENABLE: %s\n", strerror(errno));
326 }
327 }
328
329 void set_remove(void)
330 {
331 extern int errno;
332
333 errno = 0;
334
335 mib[0] = CTL_KERN;
336 mib[1] = KERN_KDEBUG;
337 mib[2] = KERN_KDREMOVE;
338 mib[3] = 0;
339 mib[4] = 0;
340 mib[5] = 0;
341 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
342 {
343 if (errno == EBUSY)
344 quit("the trace facility is currently in use...\n fs_usage, sc_usage, trace, and latency use this feature.\n\n");
345 else
346 quit_args("trace facility failure, KERN_KDREMOVE: %s\n", strerror(errno));
347 }
348 }
349
350 void set_numbufs(int nbufs)
351 {
352 mib[0] = CTL_KERN;
353 mib[1] = KERN_KDEBUG;
354 mib[2] = KERN_KDSETBUF;
355 mib[3] = nbufs;
356 mib[4] = 0;
357 mib[5] = 0;
358 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
359 quit_args("trace facility failure, KERN_KDSETBUF: %s\n", strerror(errno));
360
361 mib[0] = CTL_KERN;
362 mib[1] = KERN_KDEBUG;
363 mib[2] = KERN_KDSETUP;
364 mib[3] = 0;
365 mib[4] = 0;
366 mib[5] = 0;
367 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
368 quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno));
369 }
370
371 void set_nowrap(void)
372 {
373 mib[0] = CTL_KERN;
374 mib[1] = KERN_KDEBUG;
375 mib[2] = KERN_KDEFLAGS;
376 mib[3] = KDBG_NOWRAP;
377 mib[4] = 0;
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));
381
382 }
383
384 void set_pidcheck(int pid, int on_off_flag)
385 {
386 kd_regtype kr;
387
388 kr.type = KDBG_TYPENONE;
389 kr.value1 = pid;
390 kr.value2 = on_off_flag;
391 needed = sizeof(kd_regtype);
392 mib[0] = CTL_KERN;
393 mib[1] = KERN_KDEBUG;
394 mib[2] = KERN_KDPIDTR;
395 mib[3] = 0;
396 mib[4] = 0;
397 mib[5] = 0;
398 if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
399 {
400 if (errno == EACCES)
401 {
402 quit_args("trace facility failure, setting pid filter: %s\n",
403 strerror(errno));
404 }
405 else if (on_off_flag == 1 && errno == ESRCH)
406 {
407 set_remove();
408 quit_args("trace facility failure, setting pid filter: "
409 "pid %d does not exist\n", pid);
410 }
411 else
412 {
413 quit_args("trace facility failure, KERN_KDPIDTR: %s\n", strerror(errno));
414 }
415 }
416 }
417
418 void set_pidexclude(int pid, int on_off_flag)
419 {
420 kd_regtype kr;
421
422 kr.type = KDBG_TYPENONE;
423 kr.value1 = pid;
424 kr.value2 = on_off_flag;
425 needed = sizeof(kd_regtype);
426 mib[0] = CTL_KERN;
427 mib[1] = KERN_KDEBUG;
428 mib[2] = KERN_KDPIDEX;
429 mib[3] = 0;
430 mib[4] = 0;
431 mib[5] = 0;
432 if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
433 {
434 if (on_off_flag == 1)
435 {
436 printf ("pid %d does not exist\n", pid);
437 set_remove();
438 exit(2);
439 }
440 }
441 }
442
443 void set_freerun(void)
444 {
445 mib[0] = CTL_KERN;
446 mib[1] = KERN_KDEBUG;
447 mib[2] = KERN_KDEFLAGS;
448 mib[3] = KDBG_FREERUN;
449 mib[4] = 0;
450 mib[5] = 0;
451 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
452 quit_args("trace facility failure, KDBG_FREERUN: %s\n", strerror(errno));
453 }
454
455 static int get_ktrace_state(void)
456 {
457 int state;
458 size_t state_size = sizeof(state);
459 int err = sysctlbyname("ktrace.state", &state, &state_size, NULL, 0);
460 if (err) {
461 fprintf(stderr, "error: could not query ktrace.state sysctl (%d: %s)\n", errno, strerror(errno));
462 exit(1);
463 }
464 return state;
465 }
466
467 void get_bufinfo(kbufinfo_t *val)
468 {
469 needed = sizeof (*val);
470 mib[0] = CTL_KERN;
471 mib[1] = KERN_KDEBUG;
472 mib[2] = KERN_KDGETBUF;
473 mib[3] = 0;
474 mib[4] = 0;
475 mib[5] = 0;
476 if (sysctl(mib, 3, val, &needed, 0, 0) < 0)
477 quit_args("trace facility failure, KERN_KDGETBUF: %s\n", strerror(errno));
478 }
479
480 void set_init(void)
481 {
482 kd_regtype kr;
483
484 kr.type = KDBG_RANGETYPE;
485 kr.value1 = 0;
486 kr.value2 = -1;
487 needed = sizeof(kd_regtype);
488 mib[0] = CTL_KERN;
489 mib[1] = KERN_KDEBUG;
490 mib[2] = KERN_KDSETREG;
491 mib[3] = 0;
492 mib[4] = 0;
493 mib[5] = 0;
494 if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
495 quit_args("trace facility failure, KERN_KDSETREG (rangetype): %s\n", strerror(errno));
496
497 mib[0] = CTL_KERN;
498 mib[1] = KERN_KDEBUG;
499 mib[2] = KERN_KDSETUP;
500 mib[3] = 0;
501 mib[4] = 0;
502 mib[5] = 0;
503 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
504 quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno));
505 }
506
507 static void
508 set_filter(void)
509 {
510 errno = 0;
511 int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDSET_TYPEFILTER };
512 size_t needed = KDBG_TYPEFILTER_BITMAP_SIZE;
513
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));
516 }
517 }
518
519 void set_kval_list(void)
520 {
521 kd_regtype kr;
522
523 kr.type = KDBG_VALCHECK;
524 kr.value1 = value1;
525 kr.value2 = value2;
526 kr.value3 = value3;
527 kr.value4 = value4;
528 needed = sizeof(kd_regtype);
529 mib[0] = CTL_KERN;
530 mib[1] = KERN_KDEBUG;
531 mib[2] = KERN_KDSETREG;
532 mib[3] = 0;
533 mib[4] = 0;
534 mib[5] = 0;
535 if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
536 quit_args("trace facility failure, KERN_KDSETREG (valcheck): %s\n", strerror(errno));
537 }
538
539
540 void readtrace(char *buffer)
541 {
542 mib[0] = CTL_KERN;
543 mib[1] = KERN_KDEBUG;
544 mib[2] = KERN_KDREADTR;
545 mib[3] = 0;
546 mib[4] = 0;
547 mib[5] = 0;
548
549 if (sysctl(mib, 3, buffer, &needed, NULL, 0) < 0)
550 quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno));
551 }
552
553
554 int writetrace(int fd)
555 {
556 mib[0] = CTL_KERN;
557 mib[1] = KERN_KDEBUG;
558 mib[2] = KERN_KDWRITETR;
559 mib[3] = fd;
560 mib[4] = 0;
561 mib[5] = 0;
562
563 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
564 return 1;
565
566 return 0;
567 }
568
569
570 int write_command_map(int fd)
571 {
572 mib[0] = CTL_KERN;
573 mib[1] = KERN_KDEBUG;
574 mib[2] = KERN_KDWRITEMAP;
575 mib[3] = fd;
576 mib[4] = 0;
577 mib[5] = 0;
578
579 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0) {
580 if (errno == ENODATA) {
581 if (verbose_flag) {
582 printf("Cannot write thread map -- this is not fatal\n");
583 }
584 } else {
585 return 1;
586 }
587 }
588
589 return 0;
590 }
591
592
593 static
594 lookup_t handle_lookup_event(uint64_t thread, int debugid, kd_buf *kdp)
595 {
596 lookup_t lkp;
597 int hashid;
598 boolean_t first_record = FALSE;
599
600 hashid = thread & HASH_MASK;
601
602 if (debugid & DBG_FUNC_START)
603 first_record = TRUE;
604
605 for (lkp = lookup_hash[hashid]; lkp; lkp = lkp->lk_next) {
606 if (lkp->lk_thread == thread)
607 break;
608 }
609 if (lkp == NULL) {
610 if (first_record == FALSE)
611 return (0);
612
613 if ((lkp = lookup_freelist))
614 lookup_freelist = lkp->lk_next;
615 else
616 lkp = (lookup_t)malloc(sizeof(struct lookup));
617
618 lkp->lk_thread = thread;
619
620 lkp->lk_next = lookup_hash[hashid];
621 lookup_hash[hashid] = lkp;
622 }
623
624 if (first_record == TRUE) {
625 lkp->lk_pathptr = lkp->lk_pathname;
626 lkp->lk_dvp = kdp->arg1;
627 } else {
628 if (lkp->lk_pathptr > &lkp->lk_pathname[NUMPARMS-4])
629 return (lkp);
630
631 *lkp->lk_pathptr++ = kdp->arg1;
632 }
633 *lkp->lk_pathptr++ = kdp->arg2;
634 *lkp->lk_pathptr++ = kdp->arg3;
635 *lkp->lk_pathptr++ = kdp->arg4;
636 *lkp->lk_pathptr = 0;
637
638 return (lkp);
639 }
640
641
642 static
643 void delete_lookup_event(uint64_t thread, lookup_t lkp_to_delete)
644 {
645 lookup_t lkp;
646 lookup_t lkp_prev;
647 int hashid;
648
649 hashid = thread & HASH_MASK;
650
651 if ((lkp = lookup_hash[hashid])) {
652 if (lkp == lkp_to_delete)
653 lookup_hash[hashid] = lkp->lk_next;
654 else {
655 lkp_prev = lkp;
656
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;
660 break;
661 }
662 lkp_prev = lkp;
663 }
664 }
665 if (lkp) {
666 lkp->lk_next = lookup_freelist;
667 lookup_freelist = lkp;
668 }
669 }
670 }
671
672
673 static
674 void insert_start_event(uint64_t thread, int debugid, uint64_t now)
675 {
676 event_t evp;
677 int hashid;
678
679 hashid = thread & HASH_MASK;
680
681 for (evp = event_hash[hashid]; evp; evp = evp->ev_next) {
682 if (evp->ev_thread == thread && evp->ev_debugid == debugid)
683 break;
684 }
685 if (evp == NULL) {
686 if ((evp = event_freelist))
687 event_freelist = evp->ev_next;
688 else
689 evp = (event_t)malloc(sizeof(struct event));
690
691 evp->ev_thread = thread;
692 evp->ev_debugid = debugid;
693
694 evp->ev_next = event_hash[hashid];
695 event_hash[hashid] = evp;
696 }
697 evp->ev_timestamp = now;
698 }
699
700
701 static
702 uint64_t consume_start_event(uint64_t thread, int debugid, uint64_t now)
703 {
704 event_t evp;
705 event_t evp_prev;
706 int hashid;
707 uint64_t elapsed = 0;
708
709 hashid = thread & HASH_MASK;
710
711 if ((evp = event_hash[hashid])) {
712 if (evp->ev_thread == thread && evp->ev_debugid == debugid)
713 event_hash[hashid] = evp->ev_next;
714 else {
715 evp_prev = evp;
716
717 for (evp = evp->ev_next; evp; evp = evp->ev_next) {
718
719 if (evp->ev_thread == thread && evp->ev_debugid == debugid) {
720 evp_prev->ev_next = evp->ev_next;
721 break;
722 }
723 evp_prev = evp;
724 }
725 }
726 if (evp) {
727 elapsed = now - evp->ev_timestamp;
728
729 evp->ev_next = event_freelist;
730 event_freelist = evp;
731 }
732 }
733 return (elapsed);
734 }
735
736 void
737 log_trace(void)
738 {
739 int fd = -1;
740 int ret = 0;
741 char *buffer;
742 uint32_t buffer_size = 1000000 * sizeof(kd_buf);
743
744 if (logfile[0] == '-' && logfile[1] == '\0') {
745 fd = STDOUT_FILENO;
746 } else {
747 fd = open(logfile, O_TRUNC | O_WRONLY | O_CREAT, 0777);
748 }
749
750 if (fd == -1) {
751 perror("Can't open logfile");
752 exit(1);
753 }
754 get_bufinfo(&bufinfo);
755
756 if (bufinfo.nolog != 1) {
757 reenable = 1;
758 set_enable(0); /* disable logging*/
759 }
760 get_bufinfo(&bufinfo);
761
762 if (verbose_flag) {
763 if (bufinfo.flags & KDBG_WRAPPED)
764 printf("Buffer has wrapped\n");
765 else
766 printf("Buffer has not wrapped\n");
767 }
768
769 ret = write_command_map(fd);
770 if (ret) {
771 close(fd);
772 perror("failed to write logfile");
773 exit(1);
774 }
775
776 buffer = malloc(buffer_size);
777 if (buffer == NULL) {
778 quit("can't allocate memory for events\n");
779 }
780
781 for (;;) {
782 needed = buffer_size;
783
784 readtrace(buffer);
785
786 if (needed == 0) {
787 break;
788 }
789
790 write(fd, buffer, needed * sizeof(kd_buf));
791 }
792
793 free(buffer);
794
795 close(fd);
796 }
797
798 /*
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.
805 */
806 static uint64_t current_millis() {
807 struct timeval time;
808 gettimeofday(&time, NULL);
809 return (time.tv_sec * 1000) + (time.tv_usec / 1000);
810 }
811
812 void
813 Log_trace(void)
814 {
815 size_t len;
816 int num_cpus = 0;
817 int fd;
818 uint64_t current_ms;
819 uint64_t ending_ms = 0;
820 uint64_t last_time_written;
821 uint32_t ms_to_run;
822
823 if ((fd = open(logfile, O_TRUNC|O_WRONLY|O_CREAT, 0777)) == -1) {
824 perror("Can't open logfile");
825 exit(1);
826 }
827 if (use_current_buf == 0) {
828 /*
829 * grab the number of cpus and scale the buffer size
830 */
831 mib[0] = CTL_HW;
832 mib[1] = HW_NCPU;
833 mib[2] = 0;
834 len = sizeof(num_cpus);
835
836 sysctl(mib, 2, &num_cpus, &len, NULL, 0);
837
838 if (!bufset_flag)
839 nbufs = BASE_EVENTS * num_cpus;
840
841 set_remove();
842 set_numbufs(nbufs);
843 set_init();
844
845 if (filter_flag)
846 set_filter();
847
848 if (kval_flag)
849 set_kval_list();
850 }
851
852 if (use_current_buf == 0)
853 set_enable(1);
854
855 if (write_command_map(fd)) {
856 quit("can't write tracefile header\n");
857 }
858
859 last_time_written = current_millis();
860
861 if (secs_to_run) {
862 ms_to_run = secs_to_run * 1000;
863 ending_ms = last_time_written + ms_to_run;
864 } else
865 ms_to_run = 0;
866
867 while (LogRAW_flag) {
868 needed = ms_to_run;
869
870 if (writetrace(fd)) {
871 perror("KDWRITETR returned error");
872
873 /* Clean up and exit in case of write fail */
874 break;
875 }
876
877 if (needed) {
878 current_ms = current_millis();
879
880 printf("wrote %d events - elapsed time = %.1f secs\n",
881 (int)needed, (double)(current_ms - last_time_written) / 1000.0);
882
883 last_time_written = current_ms;
884 }
885
886 if (secs_to_run) {
887 current_ms = current_millis();
888
889 if (current_ms > ending_ms)
890 break;
891
892 ms_to_run = (uint32_t)(ending_ms - current_ms);
893
894 if (ms_to_run == 0)
895 break;
896 }
897 }
898 set_enable(0);
899 set_numbufs(0);
900 set_remove();
901
902 close(fd);
903 }
904
905
906 void read_trace(void)
907 {
908 char *buffer;
909 uint32_t buffer_size;
910 kd_buf *kd;
911 int fd;
912 int firsttime = 1;
913 int lines = 0;
914 int io_lines = 0;
915 uint64_t bias = 0;
916 uint32_t count_of_names;
917 double last_event_time = 0.0;
918 time_t trace_time;
919
920 if (!readRAW_flag) {
921 get_bufinfo(&bufinfo);
922
923 if (bufinfo.nolog != 1) {
924 reenable = 1;
925 set_enable(0); /* disable logging*/
926 }
927 if (verbose_flag) {
928 if (bufinfo.flags & KDBG_WRAPPED)
929 printf("Buffer has wrapped\n");
930 else
931 printf("Buffer has not wrapped\n");
932 }
933 fd = 0;
934 count_of_names = 0;
935
936 } else {
937 fd = open(RAW_file, O_RDONLY);
938
939 if (fd < 0) {
940 perror("Can't open file");
941 exit(1);
942 }
943 if (read(fd, &raw_header, sizeof(RAW_header)) != sizeof(RAW_header)) {
944 perror("read failed");
945 exit(2);
946 }
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;
951
952 lseek(fd, (off_t)0, SEEK_SET);
953
954 if (read(fd, &raw_header.thread_count, sizeof(int)) != sizeof(int)) {
955 perror("read failed");
956 exit(2);
957 }
958 } else if (raw_header.version_no == RAW_VERSION1) {
959 #if defined(__ILP32__)
960 /*
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
966 * after it.
967 */
968 if (sizeof(raw_header) == 20) {
969 uint32_t alignment_garbage;
970
971 if (read(fd, &alignment_garbage, sizeof(alignment_garbage)) != sizeof(alignment_garbage)) {
972 perror("read failed");
973 exit(2);
974 }
975
976 if ((alignment_garbage == 0) || (alignment_garbage >= 0x80000000)) {
977 if (verbose_flag) {
978 printf("Skipping 4 bytes to find valid thread map\n");
979 }
980 } else {
981 /* oops, go back to where we were */
982 lseek(fd, -(off_t)sizeof(alignment_garbage), SEEK_CUR);
983 }
984 }
985 #endif
986 }
987 count_of_names = raw_header.thread_count;
988 trace_time = (time_t) (raw_header.TOD_secs);
989
990 printf("%s\n", ctime(&trace_time));
991 }
992 buffer_size = 1000000 * sizeof(kd_buf);
993 buffer = malloc(buffer_size);
994
995 if (buffer == (char *) 0)
996 quit("can't allocate memory for tracing info\n");
997
998 kd = (kd_buf *)(uintptr_t)buffer;
999
1000 read_command_map(fd, count_of_names);
1001 read_cpu_map(fd);
1002
1003 for (;;) {
1004 uint32_t count;
1005 uint64_t now = 0;
1006 uint64_t prev;
1007 uint64_t prevdelta = 0;
1008 uint32_t cpunum = 0;
1009 uint64_t thread;
1010 double x = 0.0;
1011 double y = 0.0;
1012 double event_elapsed_time = 0;
1013 kd_buf *kdp;
1014 lookup_t lkp;
1015 boolean_t ending_event;
1016 int i;
1017 int debugid;
1018 int debugid_base;
1019 int dmsgindex;
1020 char dbgmessge[80];
1021 char outbuf[32];
1022 char *command;
1023
1024 if (!readRAW_flag) {
1025 needed = buffer_size;
1026
1027 mib[0] = CTL_KERN;
1028 mib[1] = KERN_KDEBUG;
1029 mib[2] = KERN_KDREADTR;
1030 mib[3] = 0;
1031 mib[4] = 0;
1032 mib[5] = 0;
1033 if (sysctl(mib, 3, buffer, &needed, NULL, 0) < 0)
1034 quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno));
1035
1036 if (needed == 0)
1037 break;
1038 count = (uint32_t)needed;
1039
1040 } else {
1041 uint32_t bytes_read;
1042
1043 bytes_read = (uint32_t)read(fd, buffer, buffer_size);
1044
1045 if (bytes_read == -1) {
1046 perror("read failed");
1047 exit(2);
1048 }
1049 count = bytes_read / sizeof(kd_buf);
1050
1051 if (count == 0)
1052 break;
1053 }
1054 for (kdp = &kd[0], i = 0; i < count; i++, kdp++) {
1055
1056 prev = now;
1057 debugid = kdp->debugid;
1058 debugid_base = debugid & DBG_FUNC_MASK;
1059 now = kdp->timestamp & KDBG_TIMESTAMP_MASK;
1060 cpunum = kdbg_get_cpu(kdp);
1061
1062 /*
1063 * Is this event from an IOP? If so, there will be no
1064 * thread command, label it with the symbolic IOP name
1065 */
1066 if (cpumap && (cpunum < cpumap_header->cpu_count) && (cpumap[cpunum].flags & KDBG_CPUMAP_IS_IOP)) {
1067 command = cpumap[cpunum].name;
1068 } else {
1069 find_thread_command(kdp, &command);
1070 }
1071
1072 /*
1073 * The internal use TRACE points clutter the output.
1074 * Print them only if in verbose mode.
1075 */
1076 if (!verbose_flag)
1077 {
1078 /* Is this entry of Class DBG_TRACE */
1079 if ((debugid >> 24) == DBG_TRACE) {
1080 if (((debugid >> 16) & 0xff) != DBG_TRACE_INFO)
1081 continue;
1082 }
1083 }
1084
1085 if (firsttime)
1086 bias = now;
1087 now -= bias;
1088
1089 thread = kdp->arg5;
1090
1091 if (lines == 64 || firsttime)
1092 {
1093 prevdelta = now - prevdelta;
1094
1095 if (firsttime)
1096 firsttime = 0;
1097 else {
1098 x = (double)prevdelta;
1099 x /= divisor;
1100
1101 fprintf(output_file, "\n\nNumber of microsecs since in last page %8.1f\n", x);
1102 }
1103 prevdelta = now;
1104
1105 /*
1106 * Output description row to output file (make sure to format correctly for 32-bit and 64-bit)
1107 */
1108 fprintf(output_file,
1109 #ifdef __LP64__
1110 " AbsTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu# command\n\n"
1111 #else
1112 " AbsTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu# command\n\n"
1113 #endif
1114 );
1115
1116 lines = 0;
1117
1118 if (io_lines > 15000) {
1119 fcntl(output_fd, F_FLUSH_DATA, 0);
1120
1121 io_lines = 0;
1122 }
1123 }
1124 lkp = 0;
1125
1126 if (debugid_base == VFS_LOOKUP) {
1127 lkp = handle_lookup_event(thread, debugid, kdp);
1128
1129 if ( !lkp || !(debugid & DBG_FUNC_END))
1130 continue;
1131 }
1132
1133 x = (double)now;
1134 x /= divisor;
1135
1136 if (last_event_time)
1137 y = x - last_event_time;
1138 else
1139 y = x;
1140 last_event_time = x;
1141 ending_event = FALSE;
1142
1143 if ( !lkp) {
1144 int t_debugid;
1145 uint64_t t_thread;
1146
1147 if ((debugid & DBG_FUNC_START) || debugid == MACH_MAKERUNNABLE) {
1148
1149 if (debugid_base != BSC_thread_terminate && debugid_base != BSC_exit) {
1150
1151 if (debugid == MACH_MAKERUNNABLE)
1152 t_thread = kdp->arg1;
1153 else
1154 t_thread = thread;
1155
1156 insert_start_event(t_thread, debugid_base, now);
1157 }
1158
1159 } else if ((debugid & DBG_FUNC_END) || debugid == MACH_STKHANDOFF || debugid == MACH_SCHEDULED) {
1160
1161 if (debugid == MACH_STKHANDOFF || debugid == MACH_SCHEDULED) {
1162 t_debugid = MACH_MAKERUNNABLE;
1163 t_thread = kdp->arg2;
1164 } else {
1165 t_debugid = debugid_base;
1166 t_thread = thread;
1167 }
1168 event_elapsed_time = (double)consume_start_event(t_thread, t_debugid, now);
1169 event_elapsed_time /= divisor;
1170 ending_event = TRUE;
1171
1172 if (event_elapsed_time == 0 && (debugid == MACH_STKHANDOFF || debugid == MACH_SCHEDULED))
1173 ending_event = FALSE;
1174 }
1175 }
1176 if (ending_event) {
1177 char *ch;
1178
1179 sprintf(&outbuf[0], "(%-10.1f)", event_elapsed_time);
1180 /*
1181 * fix that right paren
1182 */
1183 ch = &outbuf[11];
1184
1185 if (*ch != ')') {
1186 ch = strchr (&outbuf[0], ')');
1187 }
1188 if (ch)
1189 {
1190 *ch = ' ';
1191 --ch;
1192
1193 while (ch != &outbuf[0])
1194 {
1195 if (*ch == ' ')
1196 --ch;
1197 else
1198 {
1199 *(++ch) = ')';
1200 break;
1201 }
1202 }
1203 }
1204 }
1205 if (match_debugid(debugid_base, dbgmessge, &dmsgindex)) {
1206 if (ending_event)
1207 fprintf(output_file, "%13.1f %10.1f%s %-28x ", x, y, outbuf, debugid_base);
1208 else
1209 fprintf(output_file, "%13.1f %10.1f %-28x ", x, y, debugid_base);
1210 } else {
1211 if (ending_event)
1212 fprintf(output_file, "%13.1f %10.1f%s %-28.28s ", x, y, outbuf, dbgmessge);
1213 else
1214 fprintf(output_file, "%13.1f %10.1f %-28.28s ", x, y, dbgmessge);
1215 }
1216 if (lkp) {
1217 char *strptr;
1218 int len;
1219
1220 strptr = (char *)lkp->lk_pathname;
1221
1222 /*
1223 * print the tail end of the pathname
1224 */
1225 len = (int)strlen(strptr);
1226 if (len > 51)
1227 len -= 51;
1228 else
1229 len = 0;
1230 #if defined(__LP64__) || defined(__arm64__)
1231
1232 fprintf(output_file, "%-16llx %-51s %-16" PRIx64 " %-2d %s\n", (uint64_t)lkp->lk_dvp, &strptr[len], thread, cpunum, command);
1233 #else
1234 fprintf(output_file, "%-8x %-51s %-8" PRIx64 " %-2d %s\n", (unsigned int)lkp->lk_dvp, &strptr[len], thread, cpunum, command);
1235 #endif
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);
1240 #else
1241 fprintf(output_file, "%-16s%-46s %-8" PRIx64 " %-2d %s\n", (char *) &kdp->arg1, "", thread, cpunum, command);
1242 #endif
1243 } else {
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);
1247 #else
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);
1250 #endif
1251 }
1252 lines++;
1253 io_lines++;
1254 }
1255 }
1256 if (reenable == 1)
1257 set_enable(1); /* re-enable kernel logging */
1258 }
1259
1260
1261
1262 void signal_handler(int sig)
1263 {
1264 ptrace(PT_KILL, pid, (caddr_t)0, 0);
1265 /*
1266 * child is gone; no need to disable the pid
1267 */
1268 exit(2);
1269 }
1270
1271
1272 void signal_handler_RAW(int sig)
1273 {
1274 LogRAW_flag = 0;
1275 }
1276
1277
1278 int main (int argc, char* argv[], char *envp[])
1279 {
1280 extern char *optarg;
1281 extern int optind;
1282 int ch;
1283 int i;
1284 char *output_filename = NULL;
1285 unsigned int parsed_arg;
1286
1287 for (i = 1; i < argc; i++) {
1288 if (strcmp("-X", argv[i]) == 0) {
1289 force_32bit_exec = 1;
1290 break;
1291 }
1292 }
1293 if (force_32bit_exec) {
1294 if (0 != reexec_to_match_lp64ness(FALSE)) {
1295 fprintf(stderr, "Could not re-execute: %d\n", errno);
1296 exit(1);
1297 }
1298 }
1299 #if !defined(__arm64__)
1300 else {
1301 if (0 != reexec_to_match_kernel()) {
1302 fprintf(stderr, "Could not re-execute: %d\n", errno);
1303 exit(1);
1304 }
1305 }
1306 #endif
1307 if (setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_PASSIVE) < 0) {
1308 printf("setiopolicy failed\n");
1309 exit(1);
1310 }
1311 output_file = stdout;
1312 output_fd = 1;
1313
1314 while ((ch = getopt(argc, argv, "hedEk:irb:gc:p:s:tR:L:l:S:F:a:x:Xnfvo:PT:N")) != EOF)
1315 {
1316 switch(ch)
1317 {
1318 case 'h': /* help */
1319 usage_flag=1;
1320 break;
1321 case 'S':
1322 secs_to_run = argtoi('S', "decimal number", optarg, 10);
1323 break;
1324 case 'a': /* set tracing on a pid */
1325 pid_flag=1;
1326 pid = argtoi('a', "decimal number", optarg, 10);
1327 break;
1328 case 'x': /* exclude a pid from tracing */
1329 pid_exflag=1;
1330 pid = argtoi('x', "decimal number", optarg, 10);
1331 break;
1332 case 'v':
1333 verbose_flag=1;
1334 break;
1335 case 'l':
1336 logRAW_flag = 1;
1337 logfile = optarg;
1338 break;
1339 case 'L':
1340 LogRAW_flag = 1;
1341 logfile = optarg;
1342 signal(SIGINT, signal_handler_RAW);
1343 break;
1344 case 'e':
1345 enable_flag = 1;
1346 break;
1347 case 'i':
1348 init_flag = 1;
1349 break;
1350 case 'E':
1351 execute_flag = 1;
1352 break;
1353 case 'd':
1354 disable_flag = 1;
1355 break;
1356 case 'k':
1357 if (kval_flag == 0)
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);
1365 else
1366 {
1367 fprintf(stderr, "A maximum of four values can be specified with -k\n");
1368 usage(SHORT_HELP);
1369 }
1370 kval_flag++;
1371 break;
1372 case 'r':
1373 remove_flag = 1;
1374 break;
1375 case 'g':
1376 bufget_flag = 1;
1377 break;
1378 case 't':
1379 trace_flag = 1;
1380 break;
1381 case 'R':
1382 readRAW_flag = 1;
1383 RAW_file = optarg;
1384 break;
1385 case 'n':
1386 nowrap_flag = 1;
1387 break;
1388 case 'f':
1389 freerun_flag = 1;
1390 break;
1391 case 'b':
1392 bufset_flag = 1;
1393 nbufs = argtoi('b', "decimal number", optarg, 10);
1394 break;
1395 case 'c':
1396 filter_flag = 1;
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);
1402 break;
1403 case 's':
1404 filter_flag = 1;
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);
1410 break;
1411 case 'p':
1412 filter_flag = 1;
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);
1418 break;
1419 case 'P':
1420 ppt_flag = 1;
1421 break;
1422 case 'o':
1423 output_filename = optarg;
1424 break;
1425 case 'F':
1426 frequency = argtoi('F', "decimal number", optarg, 10);
1427 break;
1428 case 'X':
1429 break;
1430 case 'N':
1431 no_default_codes_flag = 1;
1432 break;
1433 case 'T':
1434 filter_flag = 1;
1435
1436 // Flush out any unclosed -c argument
1437 filter_done_parsing();
1438
1439 parse_filter_file(optarg);
1440 break;
1441 default:
1442 usage(SHORT_HELP);
1443 }
1444 }
1445 argc -= optind;
1446
1447 if (!no_default_codes_flag)
1448 {
1449 if (verbose_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");
1452 }
1453
1454 if (argc)
1455 {
1456 if (!execute_flag)
1457 {
1458 while (argc--)
1459 {
1460 const char *cfile = argv[optind++];
1461 if (verbose_flag) printf("Adding code file %s \n", cfile);
1462 parse_codefile(cfile);
1463 }
1464 }
1465 }
1466 else
1467 {
1468 if (execute_flag)
1469 quit_args("-E flag needs an executable to launch\n");
1470 }
1471
1472 if (usage_flag)
1473 usage(LONG_HELP);
1474
1475 getdivisor();
1476
1477 if (pid_flag && pid_exflag)
1478 quit_args("Can't use both -a and -x flag together\n");
1479
1480 if (kval_flag && filter_flag)
1481 quit_args("Cannot use -k flag with -c, -s, or -p\n");
1482
1483 if (output_filename && !trace_flag && !readRAW_flag)
1484 quit_args("When using 'o' option, must use the 't' or 'R' option too\n");
1485
1486 filter_done_parsing();
1487
1488 done_with_args = 1;
1489
1490 if (LogRAW_flag) {
1491 get_bufinfo(&bufinfo);
1492 int ktrace_state = get_ktrace_state();
1493
1494 /*
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.
1499 */
1500 if ((ktrace_state == 1) && (bufinfo.nolog == 0)) {
1501 use_current_buf = 1;
1502 }
1503 }
1504
1505 if (disable_flag)
1506 {
1507 if (pid_flag)
1508 {
1509 set_pidcheck(pid, 0); /* disable pid check for given pid */
1510 exit(0);
1511 }
1512 else if (pid_exflag)
1513 {
1514 set_pidexclude(pid, 0); /* disable pid exclusion for given pid */
1515 exit(0);
1516 }
1517 set_enable(0);
1518 exit(0);
1519 }
1520
1521 if (remove_flag)
1522 {
1523 set_remove();
1524 exit(0);
1525 }
1526
1527 if (bufset_flag )
1528 {
1529 if (!init_flag && !LogRAW_flag)
1530 {
1531 fprintf(stderr,"The -b flag must be used with the -i flag\n");
1532 exit(1);
1533 }
1534 set_numbufs(nbufs);
1535 }
1536
1537 if (nowrap_flag)
1538 set_nowrap();
1539
1540 if (freerun_flag)
1541 set_freerun();
1542
1543 if (bufget_flag)
1544 {
1545 printf("The kernel tracing settings are:\n");
1546
1547 /* determine the state of ktrace */
1548 int state = get_ktrace_state();
1549
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);
1554 if (err) {
1555 fprintf(stderr, "error: could not query ktrace.configured_by sysctl (%d: %s)\n", errno, strerror(errno));
1556 exit(1);
1557 }
1558
1559 printf("\tTracing is ");
1560 switch (state) {
1561 case 0:
1562 printf("off");
1563 break;
1564 case 1:
1565 printf("active (foreground)");
1566 break;
1567 case 2:
1568 printf("active (background)");
1569 break;
1570 default:
1571 printf("in an invalid state");
1572 break;
1573 }
1574 printf("\n");
1575
1576 printf("\tLast configured by \"%s\"\n", execname[0] == '\0' ? "<unknown>" : execname);
1577
1578 /* get kdebug info */
1579
1580 get_bufinfo(&bufinfo);
1581
1582 printf("The kernel buffer settings are:\n");
1583
1584 if (bufinfo.flags & KDBG_BUFINIT)
1585 printf("\tKernel buffer is initialized\n");
1586 else
1587 printf("\tKernel buffer is not initialized\n");
1588
1589 printf("\t number of buf entries = %d\n", bufinfo.nkdbufs);
1590
1591 if (verbose_flag)
1592 {
1593 if (bufinfo.flags & KDBG_MAPINIT)
1594 printf("\tKernel thread map is initialized\n");
1595 else
1596 printf("\tKernel thread map is not initialized\n");
1597 printf("\t number of thread entries = %d\n", bufinfo.nkdthreads);
1598 }
1599
1600 if (bufinfo.nolog)
1601 printf("\tBuffer logging is disabled\n");
1602 else
1603 printf("\tBuffer logging is enabled\n");
1604
1605 if (verbose_flag)
1606 printf("\tkernel flags = 0x%x\n", bufinfo.flags);
1607
1608 if (bufinfo.flags & KDBG_NOWRAP)
1609 printf("\tKernel buffer wrap is disabled\n");
1610 else
1611 printf("\tKernel buffer wrap is enabled\n");
1612
1613 if (bufinfo.flags & KDBG_RANGECHECK)
1614 printf("\tCollection within a range is enabled\n");
1615 else
1616 printf("\tCollection within a range is disabled\n");
1617
1618 if (bufinfo.flags & KDBG_VALCHECK)
1619 printf("\tCollecting specific code values is enabled\n");
1620 else
1621 printf("\tCollecting specific code values is disabled\n");
1622
1623 if (bufinfo.flags & KDBG_TYPEFILTER_CHECK)
1624 printf("\tCollection based on a filter is enabled\n");
1625 else
1626 printf("\tCollection based on a filter is disabled\n");
1627
1628 if (bufinfo.flags & KDBG_PIDCHECK)
1629 printf("\tCollection based on pid is enabled\n");
1630 else
1631 printf("\tCollection based on pid is disabled\n");
1632
1633 if (bufinfo.flags & KDBG_PIDEXCLUDE)
1634 printf("\tCollection based on pid exclusion is enabled\n");
1635 else
1636 printf("\tCollection based on pid exclusion is disabled\n");
1637
1638 if (bufinfo.bufid == -1)
1639 printf("\tKernel buffer is not controlled by any process.\n");
1640 else
1641 printf("\tKernel buffer is controlled by proc id [%d]\n", bufinfo.bufid);
1642
1643
1644 if (bufinfo.flags & KDBG_TYPEFILTER_CHECK) {
1645 if (verbose_flag) {
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;
1649 }
1650
1651 return false;
1652 };
1653
1654 uint8_t* typefilter = (uint8_t*)kdebug_typefilter();
1655 if (typefilter) {
1656 bool header = false;
1657
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)) {
1662 if (!header) {
1663 header = true;
1664 printf("\tTypefilter:\n");
1665 printf("%18s ","");
1666 for (uint32_t tsubclass=0; tsubclass<32; ++tsubclass) {
1667 printf("%02x ", tsubclass * 8);
1668 }
1669 printf("\n");
1670 printf("%18s ","");
1671 for (uint32_t tsubclass=0; tsubclass<32; ++tsubclass) {
1672 printf("---");
1673 }
1674 printf("\n");
1675 }
1676 printf("%16s%02x: ", "", tclass);
1677 for (uint32_t tsubclass=0; tsubclass<32; ++tsubclass) {
1678 printf("%02X ", typefilter[(tclass * 32) + tsubclass]);
1679 }
1680 printf("\n");
1681 }
1682 }
1683 }
1684 }
1685 }
1686 }
1687
1688 if (init_flag)
1689 set_init();
1690
1691 if (filter_flag)
1692 set_filter();
1693
1694 if (kval_flag)
1695 set_kval_list();
1696
1697 if (execute_flag)
1698 {
1699 fprintf(stderr, "Starting program: %s\n", argv[optind]);
1700 fflush(stdout);
1701 fflush(stderr);
1702
1703 execute_process(&(argv[optind]));
1704
1705 exit(0);
1706 }
1707 else if (enable_flag)
1708 {
1709 if (pid_flag)
1710 set_pidcheck(pid, 1);
1711 else if (pid_exflag)
1712 set_pidexclude(pid, 1);
1713 set_enable(1);
1714 }
1715
1716 if (output_filename)
1717 {
1718 if (((output_fd = open(output_filename, O_CREAT | O_TRUNC | O_WRONLY | O_APPEND, 0644)) < 0 ) ||
1719 !(output_file = fdopen(output_fd, "w")))
1720 {
1721 fprintf(stderr, "Cannot open file \"%s\" for writing.\n", output_filename);
1722 usage(SHORT_HELP);
1723 }
1724 setbuffer(output_file, &sbuffer[0], SBUFFER_SIZE);
1725
1726 if (fcntl(output_fd, F_NOCACHE, 1) < 0)
1727 {
1728 /* Not fatal */
1729 fprintf(stderr, "Warning: setting F_NOCACHE on %s, failed\n", output_filename);
1730 }
1731 }
1732 if (!LogRAW_flag && !logRAW_flag)
1733 setbuffer(output_file, &sbuffer[0], SBUFFER_SIZE);
1734
1735 if (trace_flag || readRAW_flag)
1736 read_trace();
1737 else if (LogRAW_flag)
1738 Log_trace();
1739 else if (logRAW_flag)
1740 log_trace();
1741
1742 exit(0);
1743
1744 } /* end main */
1745
1746 static void
1747 execute_process(char * const argv[])
1748 {
1749 int status = 0;
1750 int rc = 0;
1751 posix_spawnattr_t spawn_attrs;
1752
1753 assert(argv);
1754
1755 /* ensure that the process being spawned starts suspended */
1756 rc = posix_spawnattr_init(&spawn_attrs);
1757 if (rc != 0) {
1758 quit_args("Failed to initialize spawn attrs: %s\n", strerror(rc));
1759 }
1760 rc = posix_spawnattr_setflags(&spawn_attrs,
1761 POSIX_SPAWN_START_SUSPENDED);
1762 if (rc != 0) {
1763 quit_args("Unable to start process suspended: %s\n", strerror(rc));
1764 }
1765
1766 /* spawn the process with the rest of the arguments */
1767 rc = posix_spawnp(&pid, argv[0], NULL, &spawn_attrs, argv, environ);
1768 if (rc != 0) {
1769 quit_args("Unabled to start process: %s\n", strerror(rc));
1770 }
1771
1772 signal(SIGINT, signal_handler);
1773 set_pidcheck(pid, 1);
1774 set_enable(1);
1775
1776 /* start the child process */
1777 rc = kill(pid, SIGCONT);
1778 if (rc != 0) {
1779 perror("Failed to continue child process:");
1780 exit(EX_OSERR);
1781 }
1782
1783 rc = waitpid(pid, &status, 0);
1784 if (rc == -1) {
1785 perror("Failed to wait for process: ");
1786 }
1787 }
1788
1789 static void
1790 quit_args(const char *fmt, ...)
1791 {
1792 char buffer[1024];
1793
1794 if (reenable == 1)
1795 {
1796 reenable = 0;
1797 set_enable(1); /* re-enable kernel logging */
1798 }
1799
1800 va_list args;
1801
1802 va_start (args, fmt);
1803 vsnprintf(buffer, sizeof(buffer), fmt, args);
1804
1805 fprintf(stderr, "trace error: %s", buffer);
1806
1807 va_end(args);
1808
1809 if (!done_with_args)
1810 usage(SHORT_HELP);
1811
1812 exit(1);
1813 }
1814
1815
1816 void
1817 quit(char *s)
1818 {
1819 if (reenable == 1)
1820 {
1821 reenable = 0;
1822 set_enable(1); /* re-enable kernel logging */
1823 }
1824
1825 printf("trace: ");
1826 if (s)
1827 printf("%s", s);
1828 exit(1);
1829 }
1830
1831 static void
1832 usage(int short_help)
1833 {
1834
1835 if (short_help)
1836 {
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");
1843
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");
1850
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");
1857
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");
1868 exit(1);
1869 }
1870
1871
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");
1876
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");
1882
1883 (void)fprintf(stderr, "usage: trace -g\n");
1884 (void)fprintf(stderr, "\tGet the kernel buffer settings.\n\n");
1885
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");
1890
1891 (void)fprintf(stderr, "usage: trace -r\n");
1892 (void)fprintf(stderr, "\tRemove the kernel trace buffer. Set controls to default.\n\n");
1893
1894 (void)fprintf(stderr, "usage: trace -n\n");
1895 (void)fprintf(stderr, "\tDisables kernel buffer wrap around.\n\n");
1896
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");
1924
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");
1934
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");
1939
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");
1948
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");
1953
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");
1957
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");
1961
1962 if (verbose_flag) {
1963 (void)fprintf(stderr,
1964 "Code file: \n"
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"
1968
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"
1976
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"
1982 "\n");
1983
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"
1990
1991 "\t File syntax: \n"
1992 "\t Class filter: \n"
1993 "\t C 0xXX \n"
1994 "\t Subclass filter (includes class): \n"
1995 "\t S 0xXXXX \n"
1996 "\t Comment: \n"
1997 "\t # This is a comment \n\n"
1998
1999 "\t For example, to trace Mach events (class 1):\n"
2000 "\t C 0x01 \n"
2001 "\t or to trace Mach system calls (class 1 subclass 13): \n"
2002 "\t S 0x010C \n"
2003 "\n");
2004 }
2005
2006 exit(1);
2007 }
2008
2009
2010 static int
2011 argtoi(int flag, char *req, char *str, int base)
2012 {
2013 char *cp;
2014 int ret;
2015
2016 ret = (int)strtol(str, &cp, base);
2017 if (cp == str || *cp)
2018 errx(EINVAL, "-%c flag requires a %s", flag, req);
2019 return (ret);
2020 }
2021
2022 static unsigned long
2023 argtoul(int flag, char *req, char *str, int base)
2024 {
2025 char *cp;
2026 unsigned long ret;
2027
2028 ret = (int)strtoul(str, &cp, base);
2029 if (cp == str || *cp)
2030 errx(EINVAL, "-%c flag requires a %s", flag, req);
2031 return (ret);
2032 }
2033
2034 /*
2035 * comparison function for qsort
2036 * sort by debugid
2037 */
2038 int
2039 debugid_compar(const void *p1, const void *p2)
2040 {
2041 const code_type_t *q1 = (const code_type_t *)p1;
2042 const code_type_t *q2 = (const code_type_t *)p2;
2043
2044 if (q1->debugid > q2->debugid)
2045 return (1);
2046 else if (q1->debugid == q2->debugid)
2047 return (0);
2048 else
2049 return (-1);
2050 }
2051
2052 /*
2053 * Filter args parsing state machine:
2054 *
2055 * Allowed args:
2056 * -c -p
2057 * -c -s (-s)*
2058 * -c (-c)*
2059 * every -c goes back to start
2060 *
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)
2069 *
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
2074 */
2075
2076
2077 // What type of flag did I last see?
2078 enum {
2079 FILTER_MODE_START,
2080 FILTER_MODE_CLASS,
2081 FILTER_MODE_CLASS_RANGE,
2082 FILTER_MODE_SUBCLASS
2083 } filter_mode = FILTER_MODE_START;
2084
2085 uint8_t filter_current_class = 0;
2086 uint8_t filter_current_subclass = 0;
2087 uint8_t filter_current_class_range = 0;
2088
2089 static void
2090 saw_filter_class(uint8_t class)
2091 {
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
2102 break;
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;
2110 break;
2111 default:
2112 quit_args("invalid case in saw_filter_class\n");
2113 }
2114 }
2115
2116 static void
2117 saw_filter_end_range(uint8_t end_class)
2118 {
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);
2124 break;
2125 case FILTER_MODE_START:
2126 quit_args("must provide '-c class' before '-p 0x%x'\n",
2127 end_class);
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);
2138 default:
2139 quit_args("invalid case in saw_filter_end_range\n");
2140 }
2141 }
2142
2143 static void
2144 saw_filter_subclass(uint8_t subclass)
2145 {
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);
2152 break;
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);
2162 default:
2163 quit_args("invalid case in saw_filter_subclass\n");
2164 }
2165 }
2166
2167 static void
2168 filter_done_parsing(void)
2169 {
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;
2178 break;
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;
2186 break;
2187 default:
2188 quit_args("invalid case in filter_done_parsing\n");
2189 }
2190 }
2191
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;
2195
2196 static void
2197 set_filter_subclass(uint8_t class, uint8_t subclass)
2198 {
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");
2203 filter_alloced = 1;
2204 }
2205
2206 uint16_t csc = ENCODE_CSC_LOW(class, subclass);
2207
2208 if (verbose_flag && !setting_class)
2209 printf("tracing subclass: 0x%4.4x\n", csc);
2210
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);
2214
2215 setbit(type_filter_bitmap, csc);
2216 }
2217
2218 static void
2219 set_filter_class(uint8_t class)
2220 {
2221 if (verbose_flag && !setting_range)
2222 printf("tracing class: 0x%2.2x\n", class);
2223
2224 setting_class = TRUE;
2225
2226 for (int i = 0; i < 256; i++)
2227 set_filter_subclass(class, i);
2228
2229 setting_class = FALSE;
2230 }
2231
2232 static void
2233 set_filter_range(uint8_t class, uint8_t end)
2234 {
2235 if (verbose_flag)
2236 printf("tracing range: 0x%2.2x - 0x%2.2x\n", class, end);
2237
2238 setting_range = TRUE;
2239
2240 for (int i = class; i <= end; i++)
2241 set_filter_class(i);
2242
2243 setting_range = FALSE;
2244 }
2245
2246 /*
2247 * Syntax of filter file:
2248 * Hexadecimal numbers only
2249 * Class:
2250 * C 0xXX
2251 * Subclass (includes class):
2252 * S 0xXXXX
2253 * Comment:
2254 * # <string>
2255 * TBD: Class ranges?
2256 * TBD: K for -k flag?
2257 */
2258
2259 static void
2260 parse_filter_file(char *filename)
2261 {
2262 FILE* file;
2263 uint32_t current_line = 0;
2264 uint32_t parsed_arg = 0;
2265 int rval;
2266
2267 char line[256];
2268
2269 if ( (file = fopen(filename, "r")) == NULL ) {
2270 quit_args("Failed to open filter description file %s: %s\n",
2271 filename, strerror(errno));
2272 }
2273
2274 if (verbose_flag)
2275 printf("Parsing typefilter file: %s\n", filename);
2276
2277 while( fgets(line, sizeof(line), file) != NULL ) {
2278 current_line++;
2279
2280 switch (line[0]) {
2281 case 'C':
2282 rval = sscanf(line, "C 0x%x\n", &parsed_arg);
2283 if (rval != 1)
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"
2288 "parsed as 0x%x, "
2289 "class value must be 0x0-0xFF\n",
2290 current_line, filename, line, parsed_arg);
2291 set_filter_class((uint8_t)parsed_arg);
2292 break;
2293 case 'S':
2294 rval = sscanf(line, "S 0x%x\n", &parsed_arg);
2295 if (rval != 1)
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"
2300 "parsed as 0x%x, "
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));
2305 break;
2306 case '#':
2307 // comment
2308 break;
2309 case '\n':
2310 // empty line
2311 break;
2312 case '\0':
2313 // end of file
2314 break;
2315 default:
2316 quit_args("Invalid filter description file: %s\n"
2317 "could not parse line %d: %s\n",
2318 filename, current_line, line);
2319 }
2320 }
2321
2322 fclose(file);
2323 }
2324
2325 /*
2326 * Find the debugid code in the list and return its index
2327 */
2328 static int
2329 binary_search(code_type_t *list, int lowbound, int highbound, unsigned int code)
2330 {
2331 int low, high, mid;
2332 int tries = 0;
2333
2334 low = lowbound;
2335 high = highbound;
2336
2337 while (1)
2338 {
2339 mid = (low + high) / 2;
2340
2341 tries++;
2342
2343 if (low > high)
2344 return (-1); /* failed */
2345 else if ( low + 1 >= high)
2346 {
2347 /* We have a match */
2348 if (list[high].debugid == code)
2349 return(high);
2350 else if (list[low].debugid == code)
2351 return(low);
2352 else
2353 return(-1); /* search failed */
2354 }
2355 else if (code < list[mid].debugid)
2356 high = mid;
2357 else
2358 low = mid;
2359 }
2360 }
2361
2362
2363 static int
2364 parse_codefile(const char *filename)
2365 {
2366 int fd;
2367 int j, line;
2368 size_t count;
2369 struct stat stat_buf;
2370 size_t file_size;
2371 char *file_addr, *endp;
2372
2373 if ((fd = open(filename, O_RDONLY, 0)) == -1)
2374 {
2375 printf("Failed to open code description file %s\n",filename);
2376 return(-1);
2377 }
2378
2379 if (fstat(fd, &stat_buf) == -1)
2380 {
2381 printf("Error: Can't fstat file: %s\n", filename);
2382 return(-1);
2383 }
2384
2385 /*
2386 * For some reason mapping files with zero size fails
2387 * so it has to be handled specially.
2388 */
2389 file_size = (size_t)stat_buf.st_size;
2390
2391 if (stat_buf.st_size != 0)
2392 {
2393 file_addr = mmap(0, file_size, PROT_READ | PROT_WRITE,
2394 MAP_PRIVATE | MAP_FILE, fd, 0);
2395 if (file_addr == MAP_FAILED)
2396 {
2397 printf("Error: Can't map file: %s\n", filename);
2398 close(fd);
2399 return(-1);
2400 }
2401 }
2402 else
2403 {
2404 // Skip empty files
2405 close(fd);
2406 return(0);
2407 }
2408 close(fd);
2409
2410
2411 /*
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.
2415 */
2416
2417 for (count = 0, j=1; j < file_size; j++)
2418 {
2419 if (file_addr[j] == '\n')
2420 count++;
2421 }
2422
2423 if (count == 0)
2424 {
2425 printf("Error: No codes in %s\n", filename);
2426 return(-1);
2427 }
2428
2429 /*
2430 * Fudge the count to accomodate the last line in the file -
2431 * in case it doesn't end in a newline.
2432 */
2433 count++;
2434
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));
2438
2439 if (new_codesc == NULL) {
2440 printf("Failed to grow/allocate buffer. Skipping file %s\n", filename);
2441 return (-1);
2442 }
2443 codesc = new_codesc;
2444 bzero((char *)(codesc + codesc_idx), count * sizeof(code_type_t));
2445
2446 for (line = 1, j = 0; j < file_size && codesc_idx < total_count;
2447 codesc_idx++)
2448 {
2449 /* Skip blank lines */
2450 while (j < file_size && file_addr[j] == '\n')
2451 {
2452 j++;
2453 line++;
2454 }
2455
2456 /* Skip leading whitespace */
2457 while (file_addr[j] == ' ' || file_addr[j] == '\t')
2458 j++;
2459
2460 /* Get the debugid code */
2461 codesc[codesc_idx].debugid = (uint32_t)strtoul(file_addr + j, &endp, 16);
2462 j = (int)(endp - file_addr);
2463
2464 if (codesc[codesc_idx].debugid == 0)
2465 {
2466 /* We didn't find a debugid code - skip this line */
2467 if (verbose_flag)
2468 printf("Error: while parsing line %d, skip\n", line);
2469 while (j < file_size && file_addr[j] != '\n')
2470 j++;
2471 codesc_idx--;
2472 line++;
2473 continue;
2474 }
2475
2476 /* Skip whitespace */
2477 while (j < file_size && (file_addr[j] == ' ' || file_addr[j] == '\t'))
2478 {
2479 j++;
2480 }
2481
2482 if (j >= file_size)
2483 {
2484 break;
2485 }
2486
2487 /* Get around old file that had count at the beginning */
2488 if (file_addr[j] == '\n')
2489 {
2490 /* missing debugid string - skip */
2491 if (verbose_flag)
2492 {
2493 printf("Error: while parsing line %d, (0x%x) skip\n", line,
2494 codesc[codesc_idx].debugid);
2495 }
2496
2497 j++;
2498 codesc_idx--;
2499 line++;
2500 continue;
2501 }
2502
2503 if (j >= file_size)
2504 {
2505 break;
2506 }
2507
2508 /* Next is the debugid string terminated by a newline */
2509 codesc[codesc_idx].debug_string = &file_addr[j];
2510
2511 /* Null out the newline terminator */
2512 while (j < file_size && file_addr[j] != '\n')
2513 {
2514 j++;
2515 }
2516
2517 if (j >= file_size)
2518 {
2519 break;
2520 }
2521
2522 file_addr[j] = '\0'; /* File must be read-write */
2523 j++;
2524 line++;
2525 codenum++; /*Index into codesc is 0 to codenum-1 */
2526 }
2527
2528 if (verbose_flag)
2529 {
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);
2533 }
2534
2535 /* sort */
2536 qsort((void *)codesc, codesc_idx, sizeof(code_type_t), debugid_compar);
2537
2538 if (verbose_flag)
2539 {
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);
2543 }
2544 codesc_find_dupes();
2545
2546 #if 0
2547 /* Dump the codefile */
2548 int i;
2549 for (i = 0; i < codesc_idx; i++)
2550 printf("[%d] 0x%x %s\n",i+1, codesc[i].debugid, codesc[i].debug_string);
2551 #endif
2552 return(0);
2553 }
2554
2555 static void
2556 codesc_find_dupes(void)
2557 {
2558 boolean_t found_dupes = FALSE;
2559 if (codesc_idx == 0)
2560 {
2561 return;
2562 }
2563 uint32_t last_debugid = codesc[0].debugid;
2564 for(int i = 1; i < codesc_idx; i++)
2565 {
2566 if(codesc[i].debugid == last_debugid)
2567 {
2568 found_dupes = TRUE;
2569 if (verbose_flag) {
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);
2571 }
2572 }
2573 last_debugid = codesc[i].debugid;
2574 }
2575 if (found_dupes)
2576 {
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");
2578 }
2579 }
2580
2581 int
2582 match_debugid(unsigned int xx, char * debugstr, int * yy)
2583 {
2584 int indx;
2585
2586 if (codenum == 0)
2587 return(-1);
2588
2589 if (codesc[codeindx_cache].debugid != xx)
2590 indx = binary_search(codesc, 0, (codenum-1), xx);
2591 else
2592 indx = codeindx_cache;
2593
2594 if (indx == -1)
2595 return(indx); /* match failed */
2596 else {
2597 bcopy(&codesc[indx].debug_string[0], debugstr,80);
2598 *yy = indx;
2599 codeindx_cache = indx;
2600 return(0); /* match success */
2601 }
2602 }
2603
2604 void
2605 read_cpu_map(int fd)
2606 {
2607 if (cpumap_header) {
2608 free(cpumap_header);
2609 cpumap_header = NULL;
2610 cpumap = NULL;
2611 }
2612
2613 /*
2614 * To fit in the padding space of a VERSION1 file, the max possible
2615 * cpumap size is one page.
2616 */
2617 cpumap_header = malloc(PAGE_SIZE);
2618
2619 if (readRAW_flag) {
2620 /*
2621 * cpu maps exist in a RAW_VERSION1+ header only
2622 */
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));
2627
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];
2631 }
2632 }
2633 }
2634 } else {
2635 int mib[3];
2636
2637 mib[0] = CTL_KERN;
2638 mib[1] = KERN_KDEBUG;
2639 mib[2] = KERN_KDCPUMAP;
2640
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];
2646 }
2647 }
2648 }
2649 }
2650
2651 if (!cpumap) {
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);
2660 }
2661 printf("\n");
2662 }
2663 }
2664
2665 int
2666 read_command_map(int fd, uint32_t count)
2667 {
2668 int i;
2669 size_t size;
2670 int mib[6];
2671
2672 if (readRAW_flag) {
2673 total_threads = count;
2674 size = count * sizeof(kd_threadmap);
2675 } else {
2676 get_bufinfo(&bufinfo);
2677
2678 total_threads = bufinfo.nkdthreads;
2679 size = bufinfo.nkdthreads * sizeof(kd_threadmap);
2680 }
2681 mapptr = 0;
2682 nthreads = total_threads * 2;
2683
2684 if (verbose_flag)
2685 printf("Size of map table is %d, thus %d entries\n", (int)size, total_threads);
2686
2687 if (size) {
2688 if ((mapptr = (kd_threadmap *) malloc(size)))
2689 bzero (mapptr, size);
2690 else
2691 {
2692 if (verbose_flag)
2693 printf("Thread map is not initialized -- this is not fatal\n");
2694 return(0);
2695 }
2696 }
2697 if (readRAW_flag) {
2698 if (read(fd, mapptr, size) != size) {
2699 if (verbose_flag)
2700 printf("Can't read the thread map -- this is not fatal\n");
2701 free(mapptr);
2702 mapptr = 0;
2703
2704 return (int)size;
2705 }
2706 } else {
2707 /* Now read the threadmap */
2708 mib[0] = CTL_KERN;
2709 mib[1] = KERN_KDEBUG;
2710 mib[2] = KERN_KDTHRMAP;
2711 mib[3] = 0;
2712 mib[4] = 0;
2713 mib[5] = 0; /* no flags */
2714 if (sysctl(mib, 3, mapptr, &size, NULL, 0) < 0)
2715 {
2716 /* This is not fatal -- just means I cant map command strings */
2717 if (verbose_flag)
2718 printf("Can't read the thread map -- this is not fatal\n");
2719 free(mapptr);
2720 mapptr = 0;
2721 return(0);
2722 }
2723 }
2724 for (i = 0; i < total_threads; i++) {
2725 if (mapptr[i].thread)
2726 create_map_entry(mapptr[i].thread, &mapptr[i].command[0]);
2727 }
2728
2729 if (verbose_flag) {
2730 /* Dump the initial map */
2731
2732 printf("Size of maptable returned is %ld, thus %ld entries\n", size, (size/sizeof(kd_threadmap)));
2733
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,
2738 mapptr[i].command);
2739 }
2740 }
2741
2742 return (int)size;
2743 }
2744
2745 void
2746 create_map_entry(uint64_t thread, char *command)
2747 {
2748 threadmap_t tme;
2749 int hashid;
2750
2751 if ((tme = threadmap_freelist))
2752 threadmap_freelist = tme->tm_next;
2753 else
2754 tme = (threadmap_t)malloc(sizeof(struct threadmap));
2755
2756 tme->tm_thread = thread;
2757 tme->tm_deleteme = FALSE;
2758
2759 (void)strncpy (tme->tm_command, command, MAXCOMLEN);
2760 tme->tm_command[MAXCOMLEN] = '\0';
2761
2762 hashid = thread & HASH_MASK;
2763
2764 tme->tm_next = threadmap_hash[hashid];
2765 threadmap_hash[hashid] = tme;
2766 }
2767
2768 void
2769 delete_thread_entry(uint64_t thread)
2770 {
2771 threadmap_t tme = 0;
2772 threadmap_t tme_prev;
2773 int hashid;
2774
2775 hashid = thread & HASH_MASK;
2776
2777 if ((tme = threadmap_hash[hashid])) {
2778 if (tme->tm_thread == thread)
2779 threadmap_hash[hashid] = tme->tm_next;
2780 else {
2781 tme_prev = tme;
2782
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;
2786 break;
2787 }
2788 tme_prev = tme;
2789 }
2790 }
2791 if (tme) {
2792 tme->tm_next = threadmap_freelist;
2793 threadmap_freelist = tme;
2794 }
2795 }
2796 }
2797
2798 void
2799 find_and_insert_tmp_map_entry(uint64_t pthread, char *command)
2800 {
2801 threadmap_t tme = 0;
2802 threadmap_t tme_prev;
2803 int hashid;
2804
2805 if ((tme = threadmap_temp)) {
2806 if (tme->tm_pthread == pthread)
2807 threadmap_temp = tme->tm_next;
2808 else {
2809 tme_prev = tme;
2810
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;
2814 break;
2815 }
2816 tme_prev = tme;
2817 }
2818 }
2819 if (tme) {
2820 (void)strncpy (tme->tm_command, command, MAXCOMLEN);
2821 tme->tm_command[MAXCOMLEN] = '\0';
2822
2823 delete_thread_entry(tme->tm_thread);
2824
2825 hashid = tme->tm_thread & HASH_MASK;
2826
2827 tme->tm_next = threadmap_hash[hashid];
2828 threadmap_hash[hashid] = tme;
2829 }
2830 }
2831 }
2832
2833 void
2834 create_tmp_map_entry(uint64_t thread, uint64_t pthread)
2835 {
2836 threadmap_t tme;
2837
2838 if ((tme = threadmap_freelist))
2839 threadmap_freelist = tme->tm_next;
2840 else
2841 tme = (threadmap_t)malloc(sizeof(struct threadmap));
2842
2843 tme->tm_thread = thread;
2844 tme->tm_pthread = pthread;
2845 tme->tm_deleteme = FALSE;
2846 tme->tm_command[0] = '\0';
2847
2848 tme->tm_next = threadmap_temp;
2849 threadmap_temp = tme;
2850 }
2851
2852
2853 threadmap_t
2854 find_thread_entry(uint64_t thread)
2855 {
2856 threadmap_t tme;
2857 int hashid;
2858
2859 hashid = thread & HASH_MASK;
2860
2861 for (tme = threadmap_hash[hashid]; tme; tme = tme->tm_next) {
2862 if (tme->tm_thread == thread)
2863 return (tme);
2864 }
2865 return (0);
2866 }
2867
2868 void
2869 find_thread_name(uint64_t thread, char **command, boolean_t deleteme)
2870 {
2871 threadmap_t tme;
2872
2873 if ((tme = find_thread_entry(thread))) {
2874 *command = tme->tm_command;
2875
2876 if (deleteme == TRUE)
2877 tme->tm_deleteme = deleteme;
2878 } else
2879 *command = EMPTYSTRING;
2880 }
2881
2882 void
2883 find_thread_command(kd_buf *kbufp, char **command)
2884 {
2885 uint64_t thread;
2886 threadmap_t tme;
2887 int debugid_base;
2888
2889 *command = EMPTYSTRING;
2890
2891 thread = kbufp->arg5;
2892 debugid_base = kbufp->debugid & DBG_FUNC_MASK;
2893
2894 if (debugid_base == BSC_exit || debugid_base == MACH_STKHANDOFF) {
2895 /*
2896 * Mark entry as invalid and return temp command pointer
2897 */
2898 if ((tme = find_thread_entry(thread))) {
2899
2900 strncpy(tmpcommand, tme->tm_command, MAXCOMLEN);
2901 *command = tmpcommand;
2902
2903 if (debugid_base == BSC_exit || tme->tm_deleteme == TRUE)
2904 delete_thread_entry(thread);
2905 }
2906 }
2907 else if (debugid_base == TRACE_DATA_NEWTHREAD) {
2908 /*
2909 * Save the create thread data
2910 */
2911 create_tmp_map_entry(kbufp->arg1, kbufp->arg5);
2912 }
2913 else if (debugid_base == TRACE_STRING_NEWTHREAD) {
2914 /*
2915 * process new map entry
2916 */
2917 find_and_insert_tmp_map_entry(kbufp->arg5, (char *)&kbufp->arg1);
2918 }
2919 else if (debugid_base == TRACE_STRING_EXEC) {
2920
2921 delete_thread_entry(kbufp->arg5);
2922
2923 create_map_entry(kbufp->arg5, (char *)&kbufp->arg1);
2924 }
2925 else
2926 find_thread_name(thread, command, (debugid_base == BSC_thread_terminate));
2927 }
2928
2929 static void
2930 getdivisor(void)
2931 {
2932 (void) mach_timebase_info (&mach_timebase);
2933
2934 if (frequency == 0) {
2935 divisor = ( (double)mach_timebase.denom / (double)mach_timebase.numer) * 1000;
2936 } else
2937 divisor = (double)frequency / 1000000;
2938
2939 if (verbose_flag)
2940 printf("divisor = %g\n", divisor);
2941 }