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