]> git.saurik.com Git - apple/system_cmds.git/blob - trace.tproj/trace.c
system_cmds-735.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 uintptr_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 uintptr_t lk_thread;
172 uintptr_t lk_dvp;
173 long *lk_pathptr;
174 long lk_pathname[NUMPARMS + 1];
175 };
176
177 typedef struct threadmap *threadmap_t;
178
179 struct threadmap {
180 threadmap_t tm_next;
181
182 uintptr_t tm_thread;
183 uintptr_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(uintptr_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(uintptr_t);
244 static void find_and_insert_tmp_map_entry(uintptr_t, char *);
245 static void create_tmp_map_entry(uintptr_t, uintptr_t);
246 static void find_thread_name(uintptr_t, char **, boolean_t);
247 static void execute_process(char * const argv[]);
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(uintptr_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(uintptr_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(uintptr_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(uintptr_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(uintptr_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 uintptr_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
1061 /*
1062 * Is this event from an IOP? If so, there will be no
1063 * thread command, label it with the symbolic IOP name
1064 */
1065 if (cpumap && (cpunum < cpumap_header->cpu_count) && (cpumap[cpunum].flags & KDBG_CPUMAP_IS_IOP)) {
1066 command = cpumap[cpunum].name;
1067 } else {
1068 find_thread_command(kdp, &command);
1069 }
1070
1071 /*
1072 * The internal use TRACE points clutter the output.
1073 * Print them only if in verbose mode.
1074 */
1075 if (!verbose_flag)
1076 {
1077 /* Is this entry of Class DBG_TRACE */
1078 if ((debugid >> 24) == DBG_TRACE) {
1079 if (((debugid >> 16) & 0xff) != DBG_TRACE_INFO)
1080 continue;
1081 }
1082 }
1083
1084 if (firsttime)
1085 bias = now;
1086 now -= bias;
1087
1088 cpunum = kdbg_get_cpu(kdp);
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 uintptr_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 #ifdef __LP64__
1231
1232 fprintf(output_file, "%-16lx %-51s %-16lx %-2d %s\n", lkp->lk_dvp, &strptr[len], thread, cpunum, command);
1233 #else
1234 fprintf(output_file, "%-8x %-51s %-8lx %-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 #ifdef __LP64__
1239 fprintf(output_file, "%-32s%-36s %-16lx %-2d %s\n", (char *) &kdp->arg1, "", thread, cpunum, command);
1240 #else
1241 fprintf(output_file, "%-16s%-46s %-8lx %-2d %s\n", (char *) &kdp->arg1, "", thread, cpunum, command);
1242 #endif
1243 } else {
1244 #ifdef __LP64__
1245 fprintf(output_file, "%-16lx %-16lx %-16lx %-16lx %-16lx %-2d %s\n", kdp->arg1, kdp->arg2, kdp->arg3, kdp->arg4, thread, cpunum, command);
1246 #else
1247 fprintf(output_file, "%-8lx %-8lx %-8lx %-8lx %-8lx %-2d %s\n", kdp->arg1, kdp->arg2, kdp->arg3, kdp->arg4, thread, cpunum, command);
1248 #endif
1249 }
1250 lines++;
1251 io_lines++;
1252 }
1253 }
1254 if (reenable == 1)
1255 set_enable(1); /* re-enable kernel logging */
1256 }
1257
1258
1259
1260 void signal_handler(int sig)
1261 {
1262 ptrace(PT_KILL, pid, (caddr_t)0, 0);
1263 /*
1264 * child is gone; no need to disable the pid
1265 */
1266 exit(2);
1267 }
1268
1269
1270 void signal_handler_RAW(int sig)
1271 {
1272 LogRAW_flag = 0;
1273 }
1274
1275
1276 int main (int argc, char* argv[], char *envp[])
1277 {
1278 extern char *optarg;
1279 extern int optind;
1280 int ch;
1281 int i;
1282 char *output_filename = NULL;
1283 unsigned int parsed_arg;
1284
1285 for (i = 1; i < argc; i++) {
1286 if (strcmp("-X", argv[i]) == 0) {
1287 force_32bit_exec = 1;
1288 break;
1289 }
1290 }
1291 if (force_32bit_exec) {
1292 if (0 != reexec_to_match_lp64ness(FALSE)) {
1293 fprintf(stderr, "Could not re-execute: %d\n", errno);
1294 exit(1);
1295 }
1296 } else {
1297 if (0 != reexec_to_match_kernel()) {
1298 fprintf(stderr, "Could not re-execute: %d\n", errno);
1299 exit(1);
1300 }
1301 }
1302 if (setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_PASSIVE) < 0) {
1303 printf("setiopolicy failed\n");
1304 exit(1);
1305 }
1306 output_file = stdout;
1307 output_fd = 1;
1308
1309 while ((ch = getopt(argc, argv, "hedEk:irb:gc:p:s:tR:L:l:S:F:a:x:Xnfvo:PT:N")) != EOF)
1310 {
1311 switch(ch)
1312 {
1313 case 'h': /* help */
1314 usage_flag=1;
1315 break;
1316 case 'S':
1317 secs_to_run = argtoi('S', "decimal number", optarg, 10);
1318 break;
1319 case 'a': /* set tracing on a pid */
1320 pid_flag=1;
1321 pid = argtoi('a', "decimal number", optarg, 10);
1322 break;
1323 case 'x': /* exclude a pid from tracing */
1324 pid_exflag=1;
1325 pid = argtoi('x', "decimal number", optarg, 10);
1326 break;
1327 case 'v':
1328 verbose_flag=1;
1329 break;
1330 case 'l':
1331 logRAW_flag = 1;
1332 logfile = optarg;
1333 break;
1334 case 'L':
1335 LogRAW_flag = 1;
1336 logfile = optarg;
1337 signal(SIGINT, signal_handler_RAW);
1338 break;
1339 case 'e':
1340 enable_flag = 1;
1341 break;
1342 case 'i':
1343 init_flag = 1;
1344 break;
1345 case 'E':
1346 execute_flag = 1;
1347 break;
1348 case 'd':
1349 disable_flag = 1;
1350 break;
1351 case 'k':
1352 if (kval_flag == 0)
1353 value1 = (unsigned int) argtoul('k', "hex number", optarg, 16);
1354 else if (kval_flag == 1)
1355 value2 = (unsigned int) argtoul('k', "hex number", optarg, 16);
1356 else if (kval_flag == 2)
1357 value3 = (unsigned int) argtoul('k', "hex number", optarg, 16);
1358 else if (kval_flag == 3)
1359 value4 = (unsigned int) argtoul('k', "hex number", optarg, 16);
1360 else
1361 {
1362 fprintf(stderr, "A maximum of four values can be specified with -k\n");
1363 usage(SHORT_HELP);
1364 }
1365 kval_flag++;
1366 break;
1367 case 'r':
1368 remove_flag = 1;
1369 break;
1370 case 'g':
1371 bufget_flag = 1;
1372 break;
1373 case 't':
1374 trace_flag = 1;
1375 break;
1376 case 'R':
1377 readRAW_flag = 1;
1378 RAW_file = optarg;
1379 break;
1380 case 'n':
1381 nowrap_flag = 1;
1382 break;
1383 case 'f':
1384 freerun_flag = 1;
1385 break;
1386 case 'b':
1387 bufset_flag = 1;
1388 nbufs = argtoi('b', "decimal number", optarg, 10);
1389 break;
1390 case 'c':
1391 filter_flag = 1;
1392 parsed_arg = argtoi('c', "decimal, hex, or octal number", optarg, 0);
1393 if (parsed_arg > 0xFF)
1394 quit_args("argument '-c %s' parsed as %u, "
1395 "class value must be 0-255\n", optarg, parsed_arg);
1396 saw_filter_class(parsed_arg);
1397 break;
1398 case 's':
1399 filter_flag = 1;
1400 parsed_arg = argtoi('s', "decimal, hex, or octal number", optarg, 0);
1401 if (parsed_arg > 0xFF)
1402 quit_args("argument '-s %s' parsed as %u, "
1403 "subclass value must be 0-255\n", optarg, parsed_arg);
1404 saw_filter_subclass(parsed_arg);
1405 break;
1406 case 'p':
1407 filter_flag = 1;
1408 parsed_arg = argtoi('p', "decimal, hex, or octal number", optarg, 0);
1409 if (parsed_arg > 0xFF)
1410 quit_args("argument '-p %s' parsed as %u, "
1411 "end range value must be 0-255\n", optarg, parsed_arg);
1412 saw_filter_end_range(parsed_arg);
1413 break;
1414 case 'P':
1415 ppt_flag = 1;
1416 break;
1417 case 'o':
1418 output_filename = optarg;
1419 break;
1420 case 'F':
1421 frequency = argtoi('F', "decimal number", optarg, 10);
1422 break;
1423 case 'X':
1424 break;
1425 case 'N':
1426 no_default_codes_flag = 1;
1427 break;
1428 case 'T':
1429 filter_flag = 1;
1430
1431 // Flush out any unclosed -c argument
1432 filter_done_parsing();
1433
1434 parse_filter_file(optarg);
1435 break;
1436 default:
1437 usage(SHORT_HELP);
1438 }
1439 }
1440 argc -= optind;
1441
1442 if (!no_default_codes_flag)
1443 {
1444 if (verbose_flag)
1445 printf("Adding default code file /usr/share/misc/trace.codes. Use '-N' to skip this.\n");
1446 parse_codefile("/usr/share/misc/trace.codes");
1447 }
1448
1449 if (argc)
1450 {
1451 if (!execute_flag)
1452 {
1453 while (argc--)
1454 {
1455 const char *cfile = argv[optind++];
1456 if (verbose_flag) printf("Adding code file %s \n", cfile);
1457 parse_codefile(cfile);
1458 }
1459 }
1460 }
1461 else
1462 {
1463 if (execute_flag)
1464 quit_args("-E flag needs an executable to launch\n");
1465 }
1466
1467 if (usage_flag)
1468 usage(LONG_HELP);
1469
1470 getdivisor();
1471
1472 if (pid_flag && pid_exflag)
1473 quit_args("Can't use both -a and -x flag together\n");
1474
1475 if (kval_flag && filter_flag)
1476 quit_args("Cannot use -k flag with -c, -s, or -p\n");
1477
1478 if (output_filename && !trace_flag && !readRAW_flag)
1479 quit_args("When using 'o' option, must use the 't' or 'R' option too\n");
1480
1481 filter_done_parsing();
1482
1483 done_with_args = 1;
1484
1485 if (LogRAW_flag) {
1486 get_bufinfo(&bufinfo);
1487 int ktrace_state = get_ktrace_state();
1488
1489 /*
1490 * Only use the current kdebug configuration when foreground
1491 * tracing is enabled. Both checks are necessary because the
1492 * background tool might have enabled tracing, but as soon as we
1493 * try to write a header, that configuration is removed for us.
1494 */
1495 if ((ktrace_state == 1) && (bufinfo.nolog == 0)) {
1496 use_current_buf = 1;
1497 }
1498 }
1499
1500 if (disable_flag)
1501 {
1502 if (pid_flag)
1503 {
1504 set_pidcheck(pid, 0); /* disable pid check for given pid */
1505 exit(0);
1506 }
1507 else if (pid_exflag)
1508 {
1509 set_pidexclude(pid, 0); /* disable pid exclusion for given pid */
1510 exit(0);
1511 }
1512 set_enable(0);
1513 exit(0);
1514 }
1515
1516 if (remove_flag)
1517 {
1518 set_remove();
1519 exit(0);
1520 }
1521
1522 if (bufset_flag )
1523 {
1524 if (!init_flag && !LogRAW_flag)
1525 {
1526 fprintf(stderr,"The -b flag must be used with the -i flag\n");
1527 exit(1);
1528 }
1529 set_numbufs(nbufs);
1530 }
1531
1532 if (nowrap_flag)
1533 set_nowrap();
1534
1535 if (freerun_flag)
1536 set_freerun();
1537
1538 if (bufget_flag)
1539 {
1540 printf("The kernel tracing settings are:\n");
1541
1542 /* determine the state of ktrace */
1543 int state = get_ktrace_state();
1544
1545 /* get the name of the last process to configure ktrace */
1546 char execname[20] = { 0 };
1547 size_t execname_size = sizeof(execname);
1548 int err = sysctlbyname("ktrace.configured_by", &execname, &execname_size, NULL, 0);
1549 if (err) {
1550 fprintf(stderr, "error: could not query ktrace.configured_by sysctl (%d: %s)\n", errno, strerror(errno));
1551 exit(1);
1552 }
1553
1554 printf("\tTracing is ");
1555 switch (state) {
1556 case 0:
1557 printf("off");
1558 break;
1559 case 1:
1560 printf("active (foreground)");
1561 break;
1562 case 2:
1563 printf("active (background)");
1564 break;
1565 default:
1566 printf("in an invalid state");
1567 break;
1568 }
1569 printf("\n");
1570
1571 printf("\tLast configured by \"%s\"\n", execname[0] == '\0' ? "<unknown>" : execname);
1572
1573 /* get kdebug info */
1574
1575 get_bufinfo(&bufinfo);
1576
1577 printf("The kernel buffer settings are:\n");
1578
1579 if (bufinfo.flags & KDBG_BUFINIT)
1580 printf("\tKernel buffer is initialized\n");
1581 else
1582 printf("\tKernel buffer is not initialized\n");
1583
1584 printf("\t number of buf entries = %d\n", bufinfo.nkdbufs);
1585
1586 if (verbose_flag)
1587 {
1588 if (bufinfo.flags & KDBG_MAPINIT)
1589 printf("\tKernel thread map is initialized\n");
1590 else
1591 printf("\tKernel thread map is not initialized\n");
1592 printf("\t number of thread entries = %d\n", bufinfo.nkdthreads);
1593 }
1594
1595 if (bufinfo.nolog)
1596 printf("\tBuffer logging is disabled\n");
1597 else
1598 printf("\tBuffer logging is enabled\n");
1599
1600 if (verbose_flag)
1601 printf("\tkernel flags = 0x%x\n", bufinfo.flags);
1602
1603 if (bufinfo.flags & KDBG_NOWRAP)
1604 printf("\tKernel buffer wrap is disabled\n");
1605 else
1606 printf("\tKernel buffer wrap is enabled\n");
1607
1608 if (bufinfo.flags & KDBG_RANGECHECK)
1609 printf("\tCollection within a range is enabled\n");
1610 else
1611 printf("\tCollection within a range is disabled\n");
1612
1613 if (bufinfo.flags & KDBG_VALCHECK)
1614 printf("\tCollecting specific code values is enabled\n");
1615 else
1616 printf("\tCollecting specific code values is disabled\n");
1617
1618 if (bufinfo.flags & KDBG_TYPEFILTER_CHECK)
1619 printf("\tCollection based on a filter is enabled\n");
1620 else
1621 printf("\tCollection based on a filter is disabled\n");
1622
1623 if (bufinfo.flags & KDBG_PIDCHECK)
1624 printf("\tCollection based on pid is enabled\n");
1625 else
1626 printf("\tCollection based on pid is disabled\n");
1627
1628 if (bufinfo.flags & KDBG_PIDEXCLUDE)
1629 printf("\tCollection based on pid exclusion is enabled\n");
1630 else
1631 printf("\tCollection based on pid exclusion is disabled\n");
1632
1633 if (bufinfo.bufid == -1)
1634 printf("\tKernel buffer is not controlled by any process.\n");
1635 else
1636 printf("\tKernel buffer is controlled by proc id [%d]\n", bufinfo.bufid);
1637
1638
1639 if (bufinfo.flags & KDBG_TYPEFILTER_CHECK) {
1640 if (verbose_flag) {
1641 bool (^should_print)(uint8_t*) = ^bool(uint8_t* ptr) {
1642 for (uint32_t i=0; i<32; ++i) {
1643 if (ptr[i] > 0) return true;
1644 }
1645
1646 return false;
1647 };
1648
1649 uint8_t* typefilter = (uint8_t*)kdebug_typefilter();
1650 if (typefilter) {
1651 bool header = false;
1652
1653 // Reduce noise, only print lines that are allowing events.
1654 for (uint32_t tclass = 0; tclass < 0x100; ++tclass) {
1655 uint8_t* base = &typefilter[tclass * 32];
1656 if (should_print(base)) {
1657 if (!header) {
1658 header = true;
1659 printf("\tTypefilter:\n");
1660 printf("%18s ","");
1661 for (uint32_t tsubclass=0; tsubclass<32; ++tsubclass) {
1662 printf("%02x ", tsubclass * 8);
1663 }
1664 printf("\n");
1665 printf("%18s ","");
1666 for (uint32_t tsubclass=0; tsubclass<32; ++tsubclass) {
1667 printf("---");
1668 }
1669 printf("\n");
1670 }
1671 printf("%16s%02x: ", "", tclass);
1672 for (uint32_t tsubclass=0; tsubclass<32; ++tsubclass) {
1673 printf("%02X ", typefilter[(tclass * 32) + tsubclass]);
1674 }
1675 printf("\n");
1676 }
1677 }
1678 }
1679 }
1680 }
1681 }
1682
1683 if (init_flag)
1684 set_init();
1685
1686 if (filter_flag)
1687 set_filter();
1688
1689 if (kval_flag)
1690 set_kval_list();
1691
1692 if (execute_flag)
1693 {
1694 fprintf(stderr, "Starting program: %s\n", argv[optind]);
1695 fflush(stdout);
1696 fflush(stderr);
1697
1698 execute_process(&(argv[optind]));
1699
1700 exit(0);
1701 }
1702 else if (enable_flag)
1703 {
1704 if (pid_flag)
1705 set_pidcheck(pid, 1);
1706 else if (pid_exflag)
1707 set_pidexclude(pid, 1);
1708 set_enable(1);
1709 }
1710
1711 if (output_filename)
1712 {
1713 if (((output_fd = open(output_filename, O_CREAT | O_TRUNC | O_WRONLY | O_APPEND, 0644)) < 0 ) ||
1714 !(output_file = fdopen(output_fd, "w")))
1715 {
1716 fprintf(stderr, "Cannot open file \"%s\" for writing.\n", output_filename);
1717 usage(SHORT_HELP);
1718 }
1719 setbuffer(output_file, &sbuffer[0], SBUFFER_SIZE);
1720
1721 if (fcntl(output_fd, F_NOCACHE, 1) < 0)
1722 {
1723 /* Not fatal */
1724 fprintf(stderr, "Warning: setting F_NOCACHE on %s, failed\n", output_filename);
1725 }
1726 }
1727 if (!LogRAW_flag && !logRAW_flag)
1728 setbuffer(output_file, &sbuffer[0], SBUFFER_SIZE);
1729
1730 if (trace_flag || readRAW_flag)
1731 read_trace();
1732 else if (LogRAW_flag)
1733 Log_trace();
1734 else if (logRAW_flag)
1735 log_trace();
1736
1737 exit(0);
1738
1739 } /* end main */
1740
1741 static void
1742 execute_process(char * const argv[])
1743 {
1744 int status = 0;
1745 int rc = 0;
1746 posix_spawnattr_t spawn_attrs;
1747
1748 assert(argv);
1749
1750 /* ensure that the process being spawned starts suspended */
1751 rc = posix_spawnattr_init(&spawn_attrs);
1752 if (rc != 0) {
1753 quit_args("Failed to initialize spawn attrs: %s\n", strerror(rc));
1754 }
1755 rc = posix_spawnattr_setflags(&spawn_attrs,
1756 POSIX_SPAWN_START_SUSPENDED);
1757 if (rc != 0) {
1758 quit_args("Unable to start process suspended: %s\n", strerror(rc));
1759 }
1760
1761 /* spawn the process with the rest of the arguments */
1762 rc = posix_spawnp(&pid, argv[0], NULL, &spawn_attrs, argv, environ);
1763 if (rc != 0) {
1764 quit_args("Unabled to start process: %s\n", strerror(rc));
1765 }
1766
1767 signal(SIGINT, signal_handler);
1768 set_pidcheck(pid, 1);
1769 set_enable(1);
1770
1771 /* start the child process */
1772 rc = kill(pid, SIGCONT);
1773 if (rc != 0) {
1774 perror("Failed to continue child process:");
1775 exit(EX_OSERR);
1776 }
1777
1778 rc = waitpid(pid, &status, 0);
1779 if (rc == -1) {
1780 perror("Failed to wait for process: ");
1781 }
1782 }
1783
1784 static void
1785 quit_args(const char *fmt, ...)
1786 {
1787 char buffer[1024];
1788
1789 if (reenable == 1)
1790 {
1791 reenable = 0;
1792 set_enable(1); /* re-enable kernel logging */
1793 }
1794
1795 va_list args;
1796
1797 va_start (args, fmt);
1798 vsnprintf(buffer, sizeof(buffer), fmt, args);
1799
1800 fprintf(stderr, "trace error: %s", buffer);
1801
1802 va_end(args);
1803
1804 if (!done_with_args)
1805 usage(SHORT_HELP);
1806
1807 exit(1);
1808 }
1809
1810
1811 void
1812 quit(char *s)
1813 {
1814 if (reenable == 1)
1815 {
1816 reenable = 0;
1817 set_enable(1); /* re-enable kernel logging */
1818 }
1819
1820 printf("trace: ");
1821 if (s)
1822 printf("%s", s);
1823 exit(1);
1824 }
1825
1826 static void
1827 usage(int short_help)
1828 {
1829
1830 if (short_help)
1831 {
1832 (void)fprintf(stderr, " usage: trace -h [-v]\n");
1833 (void)fprintf(stderr, " usage: trace -i [-b numbufs]\n");
1834 (void)fprintf(stderr, " usage: trace -g\n");
1835 (void)fprintf(stderr, " usage: trace -d [-a pid | -x pid ]\n");
1836 (void)fprintf(stderr, " usage: trace -r\n");
1837 (void)fprintf(stderr, " usage: trace -n\n");
1838
1839 (void)fprintf(stderr,
1840 " usage: trace -e [ -c class [[-s subclass]... | -p class ]]... | \n");
1841 (void)fprintf(stderr,
1842 " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter] \n");
1843 (void)fprintf(stderr,
1844 " [-a pid | -x pid] \n\n");
1845
1846 (void)fprintf(stderr,
1847 " usage: trace -E [ -c class [[-s subclass]... | -p class ]]... | \n");
1848 (void)fprintf(stderr,
1849 " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter] \n");
1850 (void)fprintf(stderr,
1851 " executable_path [optional args to executable] \n\n");
1852
1853 (void)fprintf(stderr,
1854 " usage: trace -L RawFilename [-S SecsToRun]\n");
1855 (void)fprintf(stderr,
1856 " usage: trace -l RawFilename\n");
1857 (void)fprintf(stderr,
1858 " usage: trace -R RawFilename [-X] [-F frequency] [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...]\n");
1859 (void)fprintf(stderr,
1860 " usage: trace -t [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...]\n");
1861 (void)fprintf(stderr,
1862 " Trace will import /usr/share/misc/trace.codes as a default codefile unless -N is specified. Extra codefiles specified are used in addition to the default codefile.\n");
1863 exit(1);
1864 }
1865
1866
1867 /* Only get here if printing long usage info */
1868 (void)fprintf(stderr, "usage: trace -h [-v]\n");
1869 (void)fprintf(stderr, "\tPrint this long command help.\n\n");
1870 (void)fprintf(stderr, "\t -v Print extra information about tracefilter and code files.\n\n");
1871
1872 (void)fprintf(stderr, "usage: trace -i [-b numbufs]\n");
1873 (void)fprintf(stderr, "\tInitialize the kernel trace buffer.\n\n");
1874 (void)fprintf(stderr, "\t-b numbufs The number of trace elements the kernel buffer\n");
1875 (void)fprintf(stderr, "\t can hold is set to numbufs. Use with the -i flag.\n");
1876 (void)fprintf(stderr, "\t Enter a decimal value.\n\n");
1877
1878 (void)fprintf(stderr, "usage: trace -g\n");
1879 (void)fprintf(stderr, "\tGet the kernel buffer settings.\n\n");
1880
1881 (void)fprintf(stderr, "usage: trace -d [-a pid | -x pid]\n");
1882 (void)fprintf(stderr, "\tDisable/stop collection of kernel trace elements.\n\n");
1883 (void)fprintf(stderr, "\t -a pid Disable/stop collection for this process only.\n\n");
1884 (void)fprintf(stderr, "\t -x pid Disable/stop exclusion of this process only.\n\n");
1885
1886 (void)fprintf(stderr, "usage: trace -r\n");
1887 (void)fprintf(stderr, "\tRemove the kernel trace buffer. Set controls to default.\n\n");
1888
1889 (void)fprintf(stderr, "usage: trace -n\n");
1890 (void)fprintf(stderr, "\tDisables kernel buffer wrap around.\n\n");
1891
1892 (void)fprintf(stderr,
1893 "usage: trace -e [ -c class [[-s subclass]... | -p class ]]... |\n");
1894 (void)fprintf(stderr,
1895 " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter]\n");
1896 (void) fprintf(stderr,
1897 " [-a pid | -x pid]\n\n");
1898 (void)fprintf(stderr, "\t Enable/start collection of kernel trace elements. \n\n");
1899 (void)fprintf(stderr, "\t By default, trace collects all tracepoints. \n");
1900 (void)fprintf(stderr, "\t The following arguments may be used to restrict collection \n");
1901 (void)fprintf(stderr, "\t to a limited set of tracepoints. \n\n");
1902 (void)fprintf(stderr, "\t Multiple classes can be specified by repeating -c. \n");
1903 (void)fprintf(stderr, "\t Multiple subclasses can be specified by repeating -s after -c. \n");
1904 (void)fprintf(stderr, "\t Classes, subclasses, and class ranges can be entered \n");
1905 (void)fprintf(stderr, "\t in hex (0xXX), decimal (XX), or octal (0XX). \n\n");
1906 (void)fprintf(stderr, "\t -c class Restrict trace collection to given class. \n\n");
1907 (void)fprintf(stderr, "\t -p class Restrict trace collection to given class range. \n");
1908 (void)fprintf(stderr, "\t Must provide class with -c first. \n\n");
1909 (void)fprintf(stderr, "\t -s subclass Restrict trace collection to given subclass. \n");
1910 (void)fprintf(stderr, "\t Must provide class with -c first. \n\n");
1911 (void)fprintf(stderr, "\t -a pid Restrict trace collection to the given process.\n\n");
1912 (void)fprintf(stderr, "\t -x pid Exclude the given process from trace collection.\n\n");
1913 (void)fprintf(stderr, "\t -k code Restrict trace collection up to four specific codes.\n");
1914 (void)fprintf(stderr, "\t Enter codes in hex (0xXXXXXXXX). \n\n");
1915 (void)fprintf(stderr, "\t -P Enable restricted PPT trace points only.\n\n");
1916 (void)fprintf(stderr, "\t -T tracefilter Read class and subclass restrictions from a \n");
1917 (void)fprintf(stderr, "\t tracefilter description file. \n");
1918 (void)fprintf(stderr, "\t Run trace -h -v for more info on this file. \n\n");
1919
1920 (void)fprintf(stderr,
1921 "usage: trace -E [ -c class [[-s subclass]... | -p class ]]... |\n");
1922 (void)fprintf(stderr,
1923 " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter]\n");
1924 (void)fprintf(stderr,
1925 " executable_path [optional args to executable] \n\n");
1926 (void)fprintf(stderr, "\tLaunch the given executable and enable/start\n");
1927 (void)fprintf(stderr, "\tcollection of kernel trace elements for that process.\n");
1928 (void)fprintf(stderr, "\tSee -e(enable) flag for option descriptions.\n\n");
1929
1930 (void)fprintf(stderr, "usage: trace -t [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...] \n");
1931 (void)fprintf(stderr, "\tCollect the kernel buffer trace data and print it.\n\n");
1932 (void)fprintf(stderr, "\t -N Do not import /usr/share/misc/trace.codes (for raw hex tracing or supplying an alternate set of codefiles)\n");
1933 (void)fprintf(stderr, "\t -o OutputFilename Print trace output to OutputFilename. Default is stdout.\n\n");
1934
1935 (void)fprintf(stderr,
1936 "usage: trace -R RawFilename [-X] [-F frequency] [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...] \n");
1937 (void)fprintf(stderr, "\tRead raw trace file and print it.\n\n");
1938 (void)fprintf(stderr, "\t -X Force trace to interpret trace data as 32 bit. \n");
1939 (void)fprintf(stderr, "\t Default is to match the bit width of the current system. \n");
1940 (void)fprintf(stderr, "\t -N Do not import /usr/share/misc/trace.codes (for raw hex tracing or supplying an alternate set of codefiles)\n");
1941 (void)fprintf(stderr, "\t -F frequency Specify the frequency of the clock used to timestamp entries in RawFilename.\n\t Use command \"sysctl hw.tbfrequency\" on the target device, to get target frequency.\n");
1942 (void)fprintf(stderr, "\t -o OutputFilename Print trace output to OutputFilename. Default is stdout.\n\n");
1943
1944 (void)fprintf(stderr,
1945 "usage: trace -L RawFilename [-S SecsToRun]\n");
1946 (void)fprintf(stderr, "\tContinuously collect the kernel buffer trace data in the raw format \n");
1947 (void)fprintf(stderr, "\tand write it to RawFilename. \n");
1948
1949 (void)fprintf(stderr, "\t-L implies -r -i if tracing isn't currently enabled.\n");
1950 (void)fprintf(stderr, "\tOptions passed to -e(enable) are also accepted by -L. (except -a -x -P)\n\n");
1951 (void)fprintf(stderr, "\t -S SecsToRun Specify the number of seconds to collect trace data.\n\n");
1952
1953 (void)fprintf(stderr,
1954 "usage: trace -l RawFilename\n");
1955 (void)fprintf(stderr, "\tCollect the existing kernel buffer trace data in the raw format.\n\n");
1956
1957 if (verbose_flag) {
1958 (void)fprintf(stderr,
1959 "Code file: \n"
1960 "\t A code file consists of a list of tracepoints, one per line, \n"
1961 "\t with one tracepoint code in hex, followed by a tab, \n"
1962 "\t followed by the tracepoint's name. \n\n"
1963
1964 "\t Example tracepoint: \n"
1965 "\t 0x010c007c\tMSC_mach_msg_trap \n"
1966 "\t This describes the tracepoint with the following info: \n"
1967 "\t Name: MSC_mach_msg_trap \n"
1968 "\t Class: 0x01 (Mach events) \n"
1969 "\t Subclass: 0x0c (Mach system calls) \n"
1970 "\t Code: 0x007c (Mach syscall number 31) \n\n"
1971
1972 "\t See /usr/include/sys/kdebug.h for the currently defined \n"
1973 "\t class and subclass values. \n"
1974 "\t See /usr/share/misc/trace.codes for the currently allocated \n"
1975 "\t system tracepoints in trace code file format. \n"
1976 "\t This codefile is useful with the -R argument to trace. \n"
1977 "\n");
1978
1979 (void)fprintf(stderr,
1980 "Tracefilter description file: \n"
1981 "\t A tracefilter description file consists of a list of \n"
1982 "\t class and subclass filters in hex, one per line, \n"
1983 "\t which are applied as if they were passed with -c and -s. \n"
1984 "\t Pass -v to see what classes and subclasses are being set. \n\n"
1985
1986 "\t File syntax: \n"
1987 "\t Class filter: \n"
1988 "\t C 0xXX \n"
1989 "\t Subclass filter (includes class): \n"
1990 "\t S 0xXXXX \n"
1991 "\t Comment: \n"
1992 "\t # This is a comment \n\n"
1993
1994 "\t For example, to trace Mach events (class 1):\n"
1995 "\t C 0x01 \n"
1996 "\t or to trace Mach system calls (class 1 subclass 13): \n"
1997 "\t S 0x010C \n"
1998 "\n");
1999 }
2000
2001 exit(1);
2002 }
2003
2004
2005 static int
2006 argtoi(int flag, char *req, char *str, int base)
2007 {
2008 char *cp;
2009 int ret;
2010
2011 ret = (int)strtol(str, &cp, base);
2012 if (cp == str || *cp)
2013 errx(EINVAL, "-%c flag requires a %s", flag, req);
2014 return (ret);
2015 }
2016
2017 static unsigned long
2018 argtoul(int flag, char *req, char *str, int base)
2019 {
2020 char *cp;
2021 unsigned long ret;
2022
2023 ret = (int)strtoul(str, &cp, base);
2024 if (cp == str || *cp)
2025 errx(EINVAL, "-%c flag requires a %s", flag, req);
2026 return (ret);
2027 }
2028
2029 /*
2030 * comparison function for qsort
2031 * sort by debugid
2032 */
2033 int
2034 debugid_compar(const void *p1, const void *p2)
2035 {
2036 const code_type_t *q1 = (const code_type_t *)p1;
2037 const code_type_t *q2 = (const code_type_t *)p2;
2038
2039 if (q1->debugid > q2->debugid)
2040 return (1);
2041 else if (q1->debugid == q2->debugid)
2042 return (0);
2043 else
2044 return (-1);
2045 }
2046
2047 /*
2048 * Filter args parsing state machine:
2049 *
2050 * Allowed args:
2051 * -c -p
2052 * -c -s (-s)*
2053 * -c (-c)*
2054 * every -c goes back to start
2055 *
2056 * Valid transitions:
2057 * start -> class (first -c)
2058 * class -> range (-c -p)
2059 * class -> sub (-c -s)
2060 * class -> class (-c -c)
2061 * range -> class (-c -p -c)
2062 * sub -> class (-c -s -c)
2063 * * -> start (on filter_done_parsing)
2064 *
2065 * Need to call filter_done_parsing after
2066 * calling saw_filter_*
2067 * to flush out any class flag waiting to see if
2068 * there is a -s flag coming up
2069 */
2070
2071
2072 // What type of flag did I last see?
2073 enum {
2074 FILTER_MODE_START,
2075 FILTER_MODE_CLASS,
2076 FILTER_MODE_CLASS_RANGE,
2077 FILTER_MODE_SUBCLASS
2078 } filter_mode = FILTER_MODE_START;
2079
2080 uint8_t filter_current_class = 0;
2081 uint8_t filter_current_subclass = 0;
2082 uint8_t filter_current_class_range = 0;
2083
2084 static void
2085 saw_filter_class(uint8_t class)
2086 {
2087 switch(filter_mode) {
2088 case FILTER_MODE_START:
2089 case FILTER_MODE_CLASS_RANGE:
2090 case FILTER_MODE_SUBCLASS:
2091 filter_mode = FILTER_MODE_CLASS;
2092 filter_current_class = class;
2093 filter_current_subclass = 0;
2094 filter_current_class_range = 0;
2095 // the case of a lone -c is taken care of
2096 // by filter_done_parsing
2097 break;
2098 case FILTER_MODE_CLASS:
2099 filter_mode = FILTER_MODE_CLASS;
2100 // set old class, remember new one
2101 set_filter_class(filter_current_class);
2102 filter_current_class = class;
2103 filter_current_subclass = 0;
2104 filter_current_class_range = 0;
2105 break;
2106 default:
2107 quit_args("invalid case in saw_filter_class\n");
2108 }
2109 }
2110
2111 static void
2112 saw_filter_end_range(uint8_t end_class)
2113 {
2114 switch(filter_mode) {
2115 case FILTER_MODE_CLASS:
2116 filter_mode = FILTER_MODE_CLASS_RANGE;
2117 filter_current_class_range = end_class;
2118 set_filter_range(filter_current_class, filter_current_class_range);
2119 break;
2120 case FILTER_MODE_START:
2121 quit_args("must provide '-c class' before '-p 0x%x'\n",
2122 end_class);
2123 case FILTER_MODE_CLASS_RANGE:
2124 quit_args("extra range end '-p 0x%x'"
2125 " for class '-c 0x%x'\n",
2126 end_class, filter_current_class);
2127 case FILTER_MODE_SUBCLASS:
2128 quit_args("cannot provide both range end '-p 0x%x'"
2129 " and subclass '-s 0x%x'"
2130 " for class '-c 0x%x'\n",
2131 end_class, filter_current_subclass,
2132 filter_current_class);
2133 default:
2134 quit_args("invalid case in saw_filter_end_range\n");
2135 }
2136 }
2137
2138 static void
2139 saw_filter_subclass(uint8_t subclass)
2140 {
2141 switch(filter_mode) {
2142 case FILTER_MODE_CLASS:
2143 case FILTER_MODE_SUBCLASS:
2144 filter_mode = FILTER_MODE_SUBCLASS;
2145 filter_current_subclass = subclass;
2146 set_filter_subclass(filter_current_class, filter_current_subclass);
2147 break;
2148 case FILTER_MODE_START:
2149 quit_args("must provide '-c class'"
2150 " before subclass '-s 0x%x'\n", subclass);
2151 case FILTER_MODE_CLASS_RANGE:
2152 quit_args("cannot provide both range end '-p 0x%x'"
2153 " and subclass '-s 0x%x'"
2154 " for the same class '-c 0x%x'\n",
2155 filter_current_class_range,
2156 subclass, filter_current_class);
2157 default:
2158 quit_args("invalid case in saw_filter_subclass\n");
2159 }
2160 }
2161
2162 static void
2163 filter_done_parsing(void)
2164 {
2165 switch(filter_mode) {
2166 case FILTER_MODE_CLASS:
2167 // flush out the current class
2168 set_filter_class(filter_current_class);
2169 filter_mode = FILTER_MODE_START;
2170 filter_current_class = 0;
2171 filter_current_subclass = 0;
2172 filter_current_class_range = 0;
2173 break;
2174 case FILTER_MODE_SUBCLASS:
2175 case FILTER_MODE_START:
2176 case FILTER_MODE_CLASS_RANGE:
2177 filter_mode = FILTER_MODE_START;
2178 filter_current_class = 0;
2179 filter_current_subclass = 0;
2180 filter_current_class_range = 0;
2181 break;
2182 default:
2183 quit_args("invalid case in filter_done_parsing\n");
2184 }
2185 }
2186
2187 /* Tell set_filter_subclass not to print every. single. subclass. */
2188 static boolean_t setting_class = FALSE;
2189 static boolean_t setting_range = FALSE;
2190
2191 static void
2192 set_filter_subclass(uint8_t class, uint8_t subclass)
2193 {
2194 if (!filter_alloced) {
2195 type_filter_bitmap = (uint8_t *) calloc(1, KDBG_TYPEFILTER_BITMAP_SIZE);
2196 if (type_filter_bitmap == NULL)
2197 quit_args("Could not allocate type_filter_bitmap.\n");
2198 filter_alloced = 1;
2199 }
2200
2201 uint16_t csc = ENCODE_CSC_LOW(class, subclass);
2202
2203 if (verbose_flag && !setting_class)
2204 printf("tracing subclass: 0x%4.4x\n", csc);
2205
2206 if (verbose_flag && isset(type_filter_bitmap, csc))
2207 printf("class %u (0x%2.2x), subclass %u (0x%2.2x) set twice.\n",
2208 class, class, subclass, subclass);
2209
2210 setbit(type_filter_bitmap, csc);
2211 }
2212
2213 static void
2214 set_filter_class(uint8_t class)
2215 {
2216 if (verbose_flag && !setting_range)
2217 printf("tracing class: 0x%2.2x\n", class);
2218
2219 setting_class = TRUE;
2220
2221 for (int i = 0; i < 256; i++)
2222 set_filter_subclass(class, i);
2223
2224 setting_class = FALSE;
2225 }
2226
2227 static void
2228 set_filter_range(uint8_t class, uint8_t end)
2229 {
2230 if (verbose_flag)
2231 printf("tracing range: 0x%2.2x - 0x%2.2x\n", class, end);
2232
2233 setting_range = TRUE;
2234
2235 for (int i = class; i <= end; i++)
2236 set_filter_class(i);
2237
2238 setting_range = FALSE;
2239 }
2240
2241 /*
2242 * Syntax of filter file:
2243 * Hexadecimal numbers only
2244 * Class:
2245 * C 0xXX
2246 * Subclass (includes class):
2247 * S 0xXXXX
2248 * Comment:
2249 * # <string>
2250 * TBD: Class ranges?
2251 * TBD: K for -k flag?
2252 */
2253
2254 static void
2255 parse_filter_file(char *filename)
2256 {
2257 FILE* file;
2258 uint32_t current_line = 0;
2259 uint32_t parsed_arg = 0;
2260 int rval;
2261
2262 char line[256];
2263
2264 if ( (file = fopen(filename, "r")) == NULL ) {
2265 quit_args("Failed to open filter description file %s: %s\n",
2266 filename, strerror(errno));
2267 }
2268
2269 if (verbose_flag)
2270 printf("Parsing typefilter file: %s\n", filename);
2271
2272 while( fgets(line, sizeof(line), file) != NULL ) {
2273 current_line++;
2274
2275 switch (line[0]) {
2276 case 'C':
2277 rval = sscanf(line, "C 0x%x\n", &parsed_arg);
2278 if (rval != 1)
2279 quit_args("invalid line %d of file %s: %s\n",
2280 current_line, filename, line);
2281 if (parsed_arg > 0xFF)
2282 quit_args("line %d of file %s: %s\n"
2283 "parsed as 0x%x, "
2284 "class value must be 0x0-0xFF\n",
2285 current_line, filename, line, parsed_arg);
2286 set_filter_class((uint8_t)parsed_arg);
2287 break;
2288 case 'S':
2289 rval = sscanf(line, "S 0x%x\n", &parsed_arg);
2290 if (rval != 1)
2291 quit_args("invalid line %d of file %s: %s\n",
2292 current_line, filename, line);
2293 if (parsed_arg > 0xFFFF)
2294 quit_args("line %d of file %s: %s\n"
2295 "parsed as 0x%x, "
2296 "value must be 0x0-0xFFFF\n",
2297 current_line, filename, line, parsed_arg);
2298 set_filter_subclass(EXTRACT_CLASS_LOW(parsed_arg),
2299 EXTRACT_SUBCLASS_LOW(parsed_arg));
2300 break;
2301 case '#':
2302 // comment
2303 break;
2304 case '\n':
2305 // empty line
2306 break;
2307 case '\0':
2308 // end of file
2309 break;
2310 default:
2311 quit_args("Invalid filter description file: %s\n"
2312 "could not parse line %d: %s\n",
2313 filename, current_line, line);
2314 }
2315 }
2316
2317 fclose(file);
2318 }
2319
2320 /*
2321 * Find the debugid code in the list and return its index
2322 */
2323 static int
2324 binary_search(code_type_t *list, int lowbound, int highbound, unsigned int code)
2325 {
2326 int low, high, mid;
2327 int tries = 0;
2328
2329 low = lowbound;
2330 high = highbound;
2331
2332 while (1)
2333 {
2334 mid = (low + high) / 2;
2335
2336 tries++;
2337
2338 if (low > high)
2339 return (-1); /* failed */
2340 else if ( low + 1 >= high)
2341 {
2342 /* We have a match */
2343 if (list[high].debugid == code)
2344 return(high);
2345 else if (list[low].debugid == code)
2346 return(low);
2347 else
2348 return(-1); /* search failed */
2349 }
2350 else if (code < list[mid].debugid)
2351 high = mid;
2352 else
2353 low = mid;
2354 }
2355 }
2356
2357
2358 static int
2359 parse_codefile(const char *filename)
2360 {
2361 int fd;
2362 int j, line;
2363 size_t count;
2364 struct stat stat_buf;
2365 size_t file_size;
2366 char *file_addr, *endp;
2367
2368 if ((fd = open(filename, O_RDONLY, 0)) == -1)
2369 {
2370 printf("Failed to open code description file %s\n",filename);
2371 return(-1);
2372 }
2373
2374 if (fstat(fd, &stat_buf) == -1)
2375 {
2376 printf("Error: Can't fstat file: %s\n", filename);
2377 return(-1);
2378 }
2379
2380 /*
2381 * For some reason mapping files with zero size fails
2382 * so it has to be handled specially.
2383 */
2384 file_size = (size_t)stat_buf.st_size;
2385
2386 if (stat_buf.st_size != 0)
2387 {
2388 if ((file_addr = mmap(0, file_size, PROT_READ|PROT_WRITE,
2389 MAP_PRIVATE|MAP_FILE, fd, 0)) == (char*) -1)
2390 {
2391 printf("Error: Can't map file: %s\n", filename);
2392 close(fd);
2393 return(-1);
2394 }
2395 }
2396 else
2397 {
2398 // Skip empty files
2399 close(fd);
2400 return(0);
2401 }
2402 close(fd);
2403
2404
2405 /*
2406 * If we get here, we have mapped the file
2407 * and we are ready to parse it. Count
2408 * the newlines to get total number of codes.
2409 */
2410
2411 for (count = 0, j=1; j < file_size; j++)
2412 {
2413 if (file_addr[j] == '\n')
2414 count++;
2415 }
2416
2417 if (count == 0)
2418 {
2419 printf("Error: No codes in %s\n", filename);
2420 return(-1);
2421 }
2422
2423 /*
2424 * Fudge the count to accomodate the last line in the file -
2425 * in case it doesn't end in a newline.
2426 */
2427 count++;
2428
2429 // Grow the size of codesc to store new entries.
2430 size_t total_count = codesc_idx + count;
2431 code_type_t *new_codesc = (code_type_t *)realloc(codesc, (total_count) * sizeof(code_type_t));
2432
2433 if (new_codesc == NULL) {
2434 printf("Failed to grow/allocate buffer. Skipping file %s\n", filename);
2435 return (-1);
2436 }
2437 codesc = new_codesc;
2438 bzero((char *)(codesc + codesc_idx), count * sizeof(code_type_t));
2439
2440 for (line = 1, j = 0; j < file_size && codesc_idx < total_count; codesc_idx++)
2441 {
2442 /* Skip blank lines */
2443 while (file_addr[j] == '\n')
2444 {
2445 j++;
2446 line++;
2447 }
2448
2449 /* Skip leading whitespace */
2450 while (file_addr[j] == ' ' || file_addr[j] == '\t')
2451 j++;
2452
2453 /* Get the debugid code */
2454 codesc[codesc_idx].debugid = (uint32_t)strtoul(file_addr + j, &endp, 16);
2455 j = (int)(endp - file_addr);
2456
2457 if (codesc[codesc_idx].debugid == 0)
2458 {
2459 /* We didn't find a debugid code - skip this line */
2460 if (verbose_flag)
2461 printf("Error: while parsing line %d, skip\n", line);
2462 while (file_addr[j] != '\n' && j < file_size)
2463 j++;
2464 codesc_idx--;
2465 line++;
2466 continue;
2467 }
2468
2469 /* Skip whitespace */
2470 while (file_addr[j] == ' ' || file_addr[j] == '\t')
2471 j++;
2472
2473 /* Get around old file that had count at the beginning */
2474 if (file_addr[j] == '\n')
2475 {
2476 /* missing debugid string - skip */
2477 if (verbose_flag)
2478 printf("Error: while parsing line %d, (0x%x) skip\n", line, codesc[codesc_idx].debugid);
2479
2480 j++;
2481 codesc_idx--;
2482 line++;
2483 continue;
2484 }
2485
2486 /* Next is the debugid string terminated by a newline */
2487 codesc[codesc_idx].debug_string = &file_addr[j];
2488
2489 /* Null out the newline terminator */
2490 while ((j < file_size) && (file_addr[j] != '\n'))
2491 j++;
2492 file_addr[j] = '\0'; /* File must be read-write */
2493 j++;
2494 line++;
2495 codenum++; /*Index into codesc is 0 to codenum-1 */
2496 }
2497
2498 if (verbose_flag)
2499 {
2500 printf("Parsed %d codes in %s\n", codenum, filename);
2501 printf("[%6d] 0x%8x %s\n", 0, codesc[0].debugid, codesc[0].debug_string);
2502 printf("[%6d] 0x%8x %s\n\n", codenum-1, codesc[codenum-1].debugid, codesc[codenum-1].debug_string);
2503 }
2504
2505 /* sort */
2506 qsort((void *)codesc, codesc_idx, sizeof(code_type_t), debugid_compar);
2507
2508 if (verbose_flag)
2509 {
2510 printf("Sorted %zd codes in %s\n", codesc_idx, filename);
2511 printf("lowbound [%6d]: 0x%8x %s\n", 0, codesc[0].debugid, codesc[0].debug_string);
2512 printf("highbound [%6zd]: 0x%8x %s\n\n", codesc_idx - 1, codesc[codesc_idx - 1].debugid, codesc[codesc_idx - 1].debug_string);
2513 }
2514 codesc_find_dupes();
2515
2516 #if 0
2517 /* Dump the codefile */
2518 int i;
2519 for (i = 0; i < codesc_idx; i++)
2520 printf("[%d] 0x%x %s\n",i+1, codesc[i].debugid, codesc[i].debug_string);
2521 #endif
2522 return(0);
2523 }
2524
2525 static void
2526 codesc_find_dupes(void)
2527 {
2528 boolean_t found_dupes = FALSE;
2529 if (codesc_idx == 0)
2530 {
2531 return;
2532 }
2533 uint32_t last_debugid = codesc[0].debugid;
2534 for(int i = 1; i < codesc_idx; i++)
2535 {
2536 if(codesc[i].debugid == last_debugid)
2537 {
2538 found_dupes = TRUE;
2539 if (verbose_flag) {
2540 fprintf(stderr, "WARNING: The debugid 0x%"PRIx32" (%s) has already been defined as '%s'.\n", codesc[i].debugid, codesc[i].debug_string, codesc[i - 1].debug_string);
2541 }
2542 }
2543 last_debugid = codesc[i].debugid;
2544 }
2545 if (found_dupes)
2546 {
2547 fprintf(stderr, "WARNING: One or more duplicate entries found in your codefiles, which will lead to unpredictable decoding behavior. Re-run with -v for more info\n");
2548 }
2549 }
2550
2551 int
2552 match_debugid(unsigned int xx, char * debugstr, int * yy)
2553 {
2554 int indx;
2555
2556 if (codenum == 0)
2557 return(-1);
2558
2559 if (codesc[codeindx_cache].debugid != xx)
2560 indx = binary_search(codesc, 0, (codenum-1), xx);
2561 else
2562 indx = codeindx_cache;
2563
2564 if (indx == -1)
2565 return(indx); /* match failed */
2566 else {
2567 bcopy(&codesc[indx].debug_string[0], debugstr,80);
2568 *yy = indx;
2569 codeindx_cache = indx;
2570 return(0); /* match success */
2571 }
2572 }
2573
2574 void
2575 read_cpu_map(int fd)
2576 {
2577 if (cpumap_header) {
2578 free(cpumap_header);
2579 cpumap_header = NULL;
2580 cpumap = NULL;
2581 }
2582
2583 /*
2584 * To fit in the padding space of a VERSION1 file, the max possible
2585 * cpumap size is one page.
2586 */
2587 cpumap_header = malloc(PAGE_SIZE);
2588
2589 if (readRAW_flag) {
2590 /*
2591 * cpu maps exist in a RAW_VERSION1+ header only
2592 */
2593 if (raw_header.version_no == RAW_VERSION1) {
2594 off_t cpumap_position = lseek(fd, 0, SEEK_CUR);
2595 /* cpumap is part of the last 4KB of padding in the preamble */
2596 size_t padding_bytes = SIZE_4KB - (cpumap_position & (SIZE_4KB - 1));
2597
2598 if (read(fd, cpumap_header, padding_bytes) == padding_bytes) {
2599 if (cpumap_header->version_no == RAW_VERSION1) {
2600 cpumap = (kd_cpumap*)&cpumap_header[1];
2601 }
2602 }
2603 }
2604 } else {
2605 int mib[3];
2606
2607 mib[0] = CTL_KERN;
2608 mib[1] = KERN_KDEBUG;
2609 mib[2] = KERN_KDCPUMAP;
2610
2611 size_t temp = PAGE_SIZE;
2612 if (sysctl(mib, 3, cpumap_header, &temp, NULL, 0) == 0) {
2613 if (PAGE_SIZE >= temp) {
2614 if (cpumap_header->version_no == RAW_VERSION1) {
2615 cpumap = (kd_cpumap*)&cpumap_header[1];
2616 }
2617 }
2618 }
2619 }
2620
2621 if (!cpumap) {
2622 printf("Can't read the cpu map -- this is not fatal\n");
2623 free(cpumap_header);
2624 cpumap_header = NULL;
2625 } else if (verbose_flag) {
2626 /* Dump the initial cpumap */
2627 printf("\nCPU\tName\n");
2628 for (int i = 0; i < cpumap_header->cpu_count; i++) {
2629 printf ("%2d\t%s\n", cpumap[i].cpu_id, cpumap[i].name);
2630 }
2631 printf("\n");
2632 }
2633 }
2634
2635 int
2636 read_command_map(int fd, uint32_t count)
2637 {
2638 int i;
2639 size_t size;
2640 int mib[6];
2641
2642 if (readRAW_flag) {
2643 total_threads = count;
2644 size = count * sizeof(kd_threadmap);
2645 } else {
2646 get_bufinfo(&bufinfo);
2647
2648 total_threads = bufinfo.nkdthreads;
2649 size = bufinfo.nkdthreads * sizeof(kd_threadmap);
2650 }
2651 mapptr = 0;
2652 nthreads = total_threads * 2;
2653
2654 if (verbose_flag)
2655 printf("Size of map table is %d, thus %d entries\n", (int)size, total_threads);
2656
2657 if (size) {
2658 if ((mapptr = (kd_threadmap *) malloc(size)))
2659 bzero (mapptr, size);
2660 else
2661 {
2662 if (verbose_flag)
2663 printf("Thread map is not initialized -- this is not fatal\n");
2664 return(0);
2665 }
2666 }
2667 if (readRAW_flag) {
2668 if (read(fd, mapptr, size) != size) {
2669 if (verbose_flag)
2670 printf("Can't read the thread map -- this is not fatal\n");
2671 free(mapptr);
2672 mapptr = 0;
2673
2674 return (int)size;
2675 }
2676 } else {
2677 /* Now read the threadmap */
2678 mib[0] = CTL_KERN;
2679 mib[1] = KERN_KDEBUG;
2680 mib[2] = KERN_KDTHRMAP;
2681 mib[3] = 0;
2682 mib[4] = 0;
2683 mib[5] = 0; /* no flags */
2684 if (sysctl(mib, 3, mapptr, &size, NULL, 0) < 0)
2685 {
2686 /* This is not fatal -- just means I cant map command strings */
2687 if (verbose_flag)
2688 printf("Can't read the thread map -- this is not fatal\n");
2689 free(mapptr);
2690 mapptr = 0;
2691 return(0);
2692 }
2693 }
2694 for (i = 0; i < total_threads; i++) {
2695 if (mapptr[i].thread)
2696 create_map_entry(mapptr[i].thread, &mapptr[i].command[0]);
2697 }
2698
2699 if (verbose_flag) {
2700 /* Dump the initial map */
2701
2702 printf("Size of maptable returned is %ld, thus %ld entries\n", size, (size/sizeof(kd_threadmap)));
2703
2704 printf("Thread Command\n");
2705 for (i = 0; i < total_threads; i++) {
2706 printf ("0x%lx %s\n",
2707 mapptr[i].thread,
2708 mapptr[i].command);
2709 }
2710 }
2711
2712 return (int)size;
2713 }
2714
2715 void
2716 create_map_entry(uintptr_t thread, char *command)
2717 {
2718 threadmap_t tme;
2719 int hashid;
2720
2721 if ((tme = threadmap_freelist))
2722 threadmap_freelist = tme->tm_next;
2723 else
2724 tme = (threadmap_t)malloc(sizeof(struct threadmap));
2725
2726 tme->tm_thread = thread;
2727 tme->tm_deleteme = FALSE;
2728
2729 (void)strncpy (tme->tm_command, command, MAXCOMLEN);
2730 tme->tm_command[MAXCOMLEN] = '\0';
2731
2732 hashid = thread & HASH_MASK;
2733
2734 tme->tm_next = threadmap_hash[hashid];
2735 threadmap_hash[hashid] = tme;
2736 }
2737
2738 void
2739 delete_thread_entry(uintptr_t thread)
2740 {
2741 threadmap_t tme = 0;
2742 threadmap_t tme_prev;
2743 int hashid;
2744
2745 hashid = thread & HASH_MASK;
2746
2747 if ((tme = threadmap_hash[hashid])) {
2748 if (tme->tm_thread == thread)
2749 threadmap_hash[hashid] = tme->tm_next;
2750 else {
2751 tme_prev = tme;
2752
2753 for (tme = tme->tm_next; tme; tme = tme->tm_next) {
2754 if (tme->tm_thread == thread) {
2755 tme_prev->tm_next = tme->tm_next;
2756 break;
2757 }
2758 tme_prev = tme;
2759 }
2760 }
2761 if (tme) {
2762 tme->tm_next = threadmap_freelist;
2763 threadmap_freelist = tme;
2764 }
2765 }
2766 }
2767
2768 void
2769 find_and_insert_tmp_map_entry(uintptr_t pthread, char *command)
2770 {
2771 threadmap_t tme = 0;
2772 threadmap_t tme_prev;
2773 int hashid;
2774
2775 if ((tme = threadmap_temp)) {
2776 if (tme->tm_pthread == pthread)
2777 threadmap_temp = tme->tm_next;
2778 else {
2779 tme_prev = tme;
2780
2781 for (tme = tme->tm_next; tme; tme = tme->tm_next) {
2782 if (tme->tm_pthread == pthread) {
2783 tme_prev->tm_next = tme->tm_next;
2784 break;
2785 }
2786 tme_prev = tme;
2787 }
2788 }
2789 if (tme) {
2790 (void)strncpy (tme->tm_command, command, MAXCOMLEN);
2791 tme->tm_command[MAXCOMLEN] = '\0';
2792
2793 delete_thread_entry(tme->tm_thread);
2794
2795 hashid = tme->tm_thread & HASH_MASK;
2796
2797 tme->tm_next = threadmap_hash[hashid];
2798 threadmap_hash[hashid] = tme;
2799 }
2800 }
2801 }
2802
2803 void
2804 create_tmp_map_entry(uintptr_t thread, uintptr_t pthread)
2805 {
2806 threadmap_t tme;
2807
2808 if ((tme = threadmap_freelist))
2809 threadmap_freelist = tme->tm_next;
2810 else
2811 tme = (threadmap_t)malloc(sizeof(struct threadmap));
2812
2813 tme->tm_thread = thread;
2814 tme->tm_pthread = pthread;
2815 tme->tm_deleteme = FALSE;
2816 tme->tm_command[0] = '\0';
2817
2818 tme->tm_next = threadmap_temp;
2819 threadmap_temp = tme;
2820 }
2821
2822
2823 threadmap_t
2824 find_thread_entry(uintptr_t thread)
2825 {
2826 threadmap_t tme;
2827 int hashid;
2828
2829 hashid = thread & HASH_MASK;
2830
2831 for (tme = threadmap_hash[hashid]; tme; tme = tme->tm_next) {
2832 if (tme->tm_thread == thread)
2833 return (tme);
2834 }
2835 return (0);
2836 }
2837
2838 void
2839 find_thread_name(uintptr_t thread, char **command, boolean_t deleteme)
2840 {
2841 threadmap_t tme;
2842
2843 if ((tme = find_thread_entry(thread))) {
2844 *command = tme->tm_command;
2845
2846 if (deleteme == TRUE)
2847 tme->tm_deleteme = deleteme;
2848 } else
2849 *command = EMPTYSTRING;
2850 }
2851
2852 void
2853 find_thread_command(kd_buf *kbufp, char **command)
2854 {
2855 uintptr_t thread;
2856 threadmap_t tme;
2857 int debugid_base;
2858
2859 *command = EMPTYSTRING;
2860
2861 thread = kbufp->arg5;
2862 debugid_base = kbufp->debugid & DBG_FUNC_MASK;
2863
2864 if (debugid_base == BSC_exit || debugid_base == MACH_STKHANDOFF) {
2865 /*
2866 * Mark entry as invalid and return temp command pointer
2867 */
2868 if ((tme = find_thread_entry(thread))) {
2869
2870 strncpy(tmpcommand, tme->tm_command, MAXCOMLEN);
2871 *command = tmpcommand;
2872
2873 if (debugid_base == BSC_exit || tme->tm_deleteme == TRUE)
2874 delete_thread_entry(thread);
2875 }
2876 }
2877 else if (debugid_base == TRACE_DATA_NEWTHREAD) {
2878 /*
2879 * Save the create thread data
2880 */
2881 create_tmp_map_entry(kbufp->arg1, kbufp->arg5);
2882 }
2883 else if (debugid_base == TRACE_STRING_NEWTHREAD) {
2884 /*
2885 * process new map entry
2886 */
2887 find_and_insert_tmp_map_entry(kbufp->arg5, (char *)&kbufp->arg1);
2888 }
2889 else if (debugid_base == TRACE_STRING_EXEC) {
2890
2891 delete_thread_entry(kbufp->arg5);
2892
2893 create_map_entry(kbufp->arg5, (char *)&kbufp->arg1);
2894 }
2895 else
2896 find_thread_name(thread, command, (debugid_base == BSC_thread_terminate));
2897 }
2898
2899 static void
2900 getdivisor(void)
2901 {
2902 (void) mach_timebase_info (&mach_timebase);
2903
2904 if (frequency == 0) {
2905 divisor = ( (double)mach_timebase.denom / (double)mach_timebase.numer) * 1000;
2906 } else
2907 divisor = (double)frequency / 1000000;
2908
2909 if (verbose_flag)
2910 printf("divisor = %g\n", divisor);
2911 }