]> git.saurik.com Git - apple/system_cmds.git/blob - trace.tproj/trace.c
59d657f56ca94d819e74efca58135eedbeffc443
[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
32 #include <libutil.h>
33
34 #ifndef KERNEL_PRIVATE
35 #define KERNEL_PRIVATE
36 #include <sys/kdebug.h>
37 #undef KERNEL_PRIVATE
38 #else
39 #include <sys/kdebug.h>
40 #endif /*KERNEL_PRIVATE*/
41 #include <sys/param.h>
42
43 #include <mach/mach.h>
44 #include <mach/mach_time.h>
45
46
47 int nbufs = 0;
48 int enable_flag=0;
49 int execute_flag=0;
50 int logRAW_flag=0;
51 int LogRAW_flag=0;
52 int readRAW_flag = 0;
53 int disable_flag=0;
54 int init_flag=0;
55 int kval_flag=0;
56 int remove_flag=0;
57 int bufset_flag=0;
58 int bufget_flag=0;
59 int filter_flag=0;
60 int filter_file_flag=0;
61 int filter_alloced=0;
62 int trace_flag=0;
63 int nowrap_flag=0;
64 int freerun_flag=0;
65 int verbose_flag=0;
66 int usage_flag=0;
67 int pid_flag=0;
68 int pid_exflag=0;
69 int ppt_flag=0;
70 int done_with_args=0;
71 int no_default_codes_flag=0;
72
73 unsigned int value1=0;
74 unsigned int value2=0;
75 unsigned int value3=0;
76 unsigned int value4=0;
77
78 pid_t pid=0;
79 int reenable=0;
80
81 int force_32bit_exec = 0;
82 int frequency = 0;
83
84 int mib[6];
85 size_t needed;
86
87 char *logfile = (char *)0; /* This file is trace format */
88 char *RAW_file = (char *)0;
89 FILE *output_file;
90 int output_fd;
91
92 extern char **environ;
93
94 uint8_t* type_filter_bitmap;
95
96
97 #define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
98 #define DBG_FUNC_MASK 0xfffffffc
99 #define SHORT_HELP 1
100 #define LONG_HELP 0
101
102 #define CSC_MASK 0xffff0000
103
104 #define VFS_LOOKUP 0x03010090
105 #define BSC_exit 0x040c0004
106 #define BSC_thread_terminate 0x040c05a4
107 #define TRACE_DATA_NEWTHREAD 0x07000004
108 #define TRACE_STRING_NEWTHREAD 0x07010004
109 #define TRACE_STRING_EXEC 0x07010008
110 #define TRACE_LOST_EVENTS 0x07020008
111 #define TRACE_INFO_STRING 0x07020010
112 #define MACH_SCHEDULED 0x01400000
113 #define MACH_MAKERUNNABLE 0x01400018
114 #define MACH_STKHANDOFF 0x01400008
115
116 #define EMPTYSTRING ""
117 #define UNKNOWN "unknown"
118
119 char tmpcommand[MAXCOMLEN];
120
121 int total_threads = 0;
122 int nthreads = 0;
123 kd_threadmap *mapptr = 0;
124
125 kd_cpumap_header* cpumap_header = NULL;
126 kd_cpumap* cpumap = NULL;
127
128 /*
129 If NUMPARMS changes from the kernel,
130 then PATHLENGTH will also reflect the change
131 This is for the vfslookup entries that
132 return pathnames
133 */
134 #define NUMPARMS 23
135 #define PATHLENGTH (NUMPARMS*sizeof(long))
136
137
138 #define US_TO_SLEEP 50000
139 #define BASE_EVENTS 500000
140
141
142 double divisor;
143
144 typedef struct {
145 uint32_t debugid;
146 char *debug_string;
147 } code_type_t;
148
149 code_type_t* codesc = 0;
150 size_t codesc_idx = 0; // Index into first empty codesc entry
151
152
153
154 typedef struct event *event_t;
155
156 struct event {
157 event_t ev_next;
158
159 uintptr_t ev_thread;
160 uint32_t ev_debugid;
161 uint64_t ev_timestamp;
162 };
163
164 typedef struct lookup *lookup_t;
165
166 struct lookup {
167 lookup_t lk_next;
168
169 uintptr_t lk_thread;
170 uintptr_t lk_dvp;
171 long *lk_pathptr;
172 long lk_pathname[NUMPARMS + 1];
173 };
174
175 typedef struct threadmap *threadmap_t;
176
177 struct threadmap {
178 threadmap_t tm_next;
179
180 uintptr_t tm_thread;
181 uintptr_t tm_pthread;
182 boolean_t tm_deleteme;
183 char tm_command[MAXCOMLEN + 1];
184 };
185
186
187 #define HASH_SIZE 1024
188 #define HASH_MASK 1023
189
190 event_t event_hash[HASH_SIZE];
191 lookup_t lookup_hash[HASH_SIZE];
192 threadmap_t threadmap_hash[HASH_SIZE];
193
194 event_t event_freelist;
195 lookup_t lookup_freelist;
196 threadmap_t threadmap_freelist;
197 threadmap_t threadmap_temp;
198
199
200 #define SBUFFER_SIZE (128 * 4096)
201 char sbuffer[SBUFFER_SIZE];
202
203 int secs_to_run = 0;
204 int use_current_buf = 0;
205
206
207 kbufinfo_t bufinfo = {0, 0, 0, 0};
208
209 int codenum = 0;
210 int codeindx_cache = 0;
211
212 static void quit(char *);
213 static int match_debugid(unsigned int, char *, int *);
214 static void usage(int short_help);
215 static int argtoi(int flag, char *req, char *str, int base);
216 static int parse_codefile(const char *filename);
217 static void codesc_find_dupes(void);
218 static int read_command_map(int, uint32_t);
219 static void read_cpu_map(int);
220 static void find_thread_command(kd_buf *, char **);
221 static void create_map_entry(uintptr_t, char *);
222 static void getdivisor();
223 static unsigned long argtoul();
224
225 static void set_enable(int);
226 static void set_remove();
227 static void set_nowrap();
228 static void set_pidcheck(int, int);
229 static void set_pidexclude(int, int);
230 static void set_numbufs(int);
231 static void set_freerun();
232 static void get_bufinfo(kbufinfo_t *);
233 static void set_init();
234 static void set_kval_list();
235 static void readtrace(char *);
236 static void log_trace();
237 static void Log_trace();
238 static void read_trace();
239 static void signal_handler(int);
240 static void signal_handler_RAW(int);
241 static void delete_thread_entry(uintptr_t);
242 static void find_and_insert_tmp_map_entry(uintptr_t, char *);
243 static void create_tmp_map_entry(uintptr_t, uintptr_t);
244 static void find_thread_name(uintptr_t, char **, boolean_t);
245
246 static int writetrace(int);
247 static int write_command_map(int);
248 static int debugid_compar(code_type_t *, code_type_t *);
249
250 static threadmap_t find_thread_entry(uintptr_t);
251
252 static void saw_filter_class(uint8_t class);
253 static void saw_filter_end_range(uint8_t end_class);
254 static void saw_filter_subclass(uint8_t subclass);
255 static void filter_done_parsing(void);
256
257 static void set_filter(void);
258 static void set_filter_class(uint8_t class);
259 static void set_filter_range(uint8_t class, uint8_t end);
260 static void set_filter_subclass(uint8_t class, uint8_t subclass);
261
262 static void parse_filter_file(char *filename);
263
264 static void quit_args(const char *fmt, ...) __printflike(1, 2);
265
266 #ifndef KERN_KDWRITETR
267 #define KERN_KDWRITETR 17
268 #endif
269
270 #ifndef KERN_KDWRITEMAP
271 #define KERN_KDWRITEMAP 18
272 #endif
273
274 #ifndef F_FLUSH_DATA
275 #define F_FLUSH_DATA 40
276 #endif
277
278 #ifndef RAW_VERSION1
279 typedef struct {
280 int version_no;
281 int thread_count;
282 uint64_t TOD_secs;
283 uint32_t TOD_usecs;
284 } RAW_header;
285
286 #define RAW_VERSION0 0x55aa0000
287 #define RAW_VERSION1 0x55aa0101
288 #endif
289
290 #define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(*x)))
291
292 #define EXTRACT_CLASS_LOW(debugid) ( (uint8_t) ( ((debugid) & 0xFF00 ) >> 8 ) )
293 #define EXTRACT_SUBCLASS_LOW(debugid) ( (uint8_t) ( ((debugid) & 0xFF ) ) )
294
295 #define ENCODE_CSC_LOW(class, subclass) \
296 ( (uint16_t) ( ((class) & 0xff) << 8 ) | ((subclass) & 0xff) )
297
298 RAW_header raw_header;
299
300
301
302 void set_enable(int val)
303 {
304 mib[0] = CTL_KERN;
305 mib[1] = KERN_KDEBUG;
306 mib[2] = KERN_KDENABLE;
307 #ifdef KDEBUG_ENABLE_PPT
308 if (ppt_flag && val) {
309 mib[3] = KDEBUG_ENABLE_PPT;
310 } else {
311 mib[3] = val;
312 }
313 #else
314 mib[3] = val;
315 #endif
316 mib[4] = 0;
317 mib[5] = 0;
318 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
319 quit_args("trace facility failure, KERN_KDENABLE: %s\n", strerror(errno));
320 }
321
322 void set_remove()
323 {
324 extern int errno;
325
326 errno = 0;
327
328 mib[0] = CTL_KERN;
329 mib[1] = KERN_KDEBUG;
330 mib[2] = KERN_KDREMOVE;
331 mib[3] = 0;
332 mib[4] = 0;
333 mib[5] = 0;
334 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
335 {
336 if (errno == EBUSY)
337 quit("the trace facility is currently in use...\n fs_usage, sc_usage, trace, and latency use this feature.\n\n");
338 else
339 quit_args("trace facility failure, KERN_KDREMOVE: %s\n", strerror(errno));
340 }
341 }
342
343 void set_numbufs(int nbufs)
344 {
345 mib[0] = CTL_KERN;
346 mib[1] = KERN_KDEBUG;
347 mib[2] = KERN_KDSETBUF;
348 mib[3] = nbufs;
349 mib[4] = 0;
350 mib[5] = 0;
351 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
352 quit_args("trace facility failure, KERN_KDSETBUF: %s\n", strerror(errno));
353
354 mib[0] = CTL_KERN;
355 mib[1] = KERN_KDEBUG;
356 mib[2] = KERN_KDSETUP;
357 mib[3] = 0;
358 mib[4] = 0;
359 mib[5] = 0;
360 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
361 quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno));
362 }
363
364 void set_nowrap()
365 {
366 mib[0] = CTL_KERN;
367 mib[1] = KERN_KDEBUG;
368 mib[2] = KERN_KDEFLAGS;
369 mib[3] = KDBG_NOWRAP;
370 mib[4] = 0;
371 mib[5] = 0; /* no flags */
372 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
373 quit_args("trace facility failure, KDBG_NOWRAP: %s\n", strerror(errno));
374
375 }
376
377 void set_pidcheck(int pid, int on_off_flag)
378 {
379 kd_regtype kr;
380
381 kr.type = KDBG_TYPENONE;
382 kr.value1 = pid;
383 kr.value2 = on_off_flag;
384 needed = sizeof(kd_regtype);
385 mib[0] = CTL_KERN;
386 mib[1] = KERN_KDEBUG;
387 mib[2] = KERN_KDPIDTR;
388 mib[3] = 0;
389 mib[4] = 0;
390 mib[5] = 0;
391 if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
392 {
393 if (on_off_flag == 1)
394 {
395 printf("trace facility failure, KERN_KDPIDTR,\n\tpid %d does not exist\n", pid);
396 set_remove();
397 exit(2);
398 }
399 }
400 }
401
402 void set_pidexclude(int pid, int on_off_flag)
403 {
404 kd_regtype kr;
405
406 kr.type = KDBG_TYPENONE;
407 kr.value1 = pid;
408 kr.value2 = on_off_flag;
409 needed = sizeof(kd_regtype);
410 mib[0] = CTL_KERN;
411 mib[1] = KERN_KDEBUG;
412 mib[2] = KERN_KDPIDEX;
413 mib[3] = 0;
414 mib[4] = 0;
415 mib[5] = 0;
416 if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
417 {
418 if (on_off_flag == 1)
419 {
420 printf ("pid %d does not exist\n", pid);
421 set_remove();
422 exit(2);
423 }
424 }
425 }
426
427 void set_freerun()
428 {
429 mib[0] = CTL_KERN;
430 mib[1] = KERN_KDEBUG;
431 mib[2] = KERN_KDEFLAGS;
432 mib[3] = KDBG_FREERUN;
433 mib[4] = 0;
434 mib[5] = 0;
435 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
436 quit_args("trace facility failure, KDBG_FREERUN: %s\n", strerror(errno));
437 }
438
439 void get_bufinfo(kbufinfo_t *val)
440 {
441 needed = sizeof (*val);
442 mib[0] = CTL_KERN;
443 mib[1] = KERN_KDEBUG;
444 mib[2] = KERN_KDGETBUF;
445 mib[3] = 0;
446 mib[4] = 0;
447 mib[5] = 0;
448 if (sysctl(mib, 3, val, &needed, 0, 0) < 0)
449 quit_args("trace facility failure, KERN_KDGETBUF: %s\n", strerror(errno));
450 }
451
452 void set_init()
453 {
454 kd_regtype kr;
455
456 kr.type = KDBG_RANGETYPE;
457 kr.value1 = 0;
458 kr.value2 = -1;
459 needed = sizeof(kd_regtype);
460 mib[0] = CTL_KERN;
461 mib[1] = KERN_KDEBUG;
462 mib[2] = KERN_KDSETREG;
463 mib[3] = 0;
464 mib[4] = 0;
465 mib[5] = 0;
466 if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
467 quit_args("trace facility failure, KERN_KDSETREG (rangetype): %s\n", strerror(errno));
468
469 mib[0] = CTL_KERN;
470 mib[1] = KERN_KDEBUG;
471 mib[2] = KERN_KDSETUP;
472 mib[3] = 0;
473 mib[4] = 0;
474 mib[5] = 0;
475 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
476 quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno));
477 }
478
479
480 static void
481 set_filter(void)
482 {
483 errno = 0;
484 int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDSET_TYPEFILTER };
485 size_t needed = KDBG_TYPEFILTER_BITMAP_SIZE;
486
487 if(sysctl(mib, ARRAYSIZE(mib), type_filter_bitmap, &needed, NULL, 0)) {
488 quit_args("trace facility failure, KERN_KDSET_TYPEFILTER: %s\n", strerror(errno));
489 }
490 }
491
492 void set_kval_list()
493 {
494 kd_regtype kr;
495
496 kr.type = KDBG_VALCHECK;
497 kr.value1 = value1;
498 kr.value2 = value2;
499 kr.value3 = value3;
500 kr.value4 = value4;
501 needed = sizeof(kd_regtype);
502 mib[0] = CTL_KERN;
503 mib[1] = KERN_KDEBUG;
504 mib[2] = KERN_KDSETREG;
505 mib[3] = 0;
506 mib[4] = 0;
507 mib[5] = 0;
508 if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
509 quit_args("trace facility failure, KERN_KDSETREG (valcheck): %s\n", strerror(errno));
510 }
511
512
513 void readtrace(char *buffer)
514 {
515 mib[0] = CTL_KERN;
516 mib[1] = KERN_KDEBUG;
517 mib[2] = KERN_KDREADTR;
518 mib[3] = 0;
519 mib[4] = 0;
520 mib[5] = 0;
521
522 if (sysctl(mib, 3, buffer, &needed, NULL, 0) < 0)
523 quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno));
524 }
525
526
527 int writetrace(int fd)
528 {
529 mib[0] = CTL_KERN;
530 mib[1] = KERN_KDEBUG;
531 mib[2] = KERN_KDWRITETR;
532 mib[3] = fd;
533 mib[4] = 0;
534 mib[5] = 0;
535
536 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
537 return 1;
538
539 return 0;
540 }
541
542
543 int write_command_map(int fd)
544 {
545 mib[0] = CTL_KERN;
546 mib[1] = KERN_KDEBUG;
547 mib[2] = KERN_KDWRITEMAP;
548 mib[3] = fd;
549 mib[4] = 0;
550 mib[5] = 0;
551
552 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
553 return 1;
554
555 return 0;
556 }
557
558
559 static
560 lookup_t handle_lookup_event(uintptr_t thread, int debugid, kd_buf *kdp)
561 {
562 lookup_t lkp;
563 int hashid;
564 boolean_t first_record = FALSE;
565
566 hashid = thread & HASH_MASK;
567
568 if (debugid & DBG_FUNC_START)
569 first_record = TRUE;
570
571 for (lkp = lookup_hash[hashid]; lkp; lkp = lkp->lk_next) {
572 if (lkp->lk_thread == thread)
573 break;
574 }
575 if (lkp == NULL) {
576 if (first_record == FALSE)
577 return (0);
578
579 if ((lkp = lookup_freelist))
580 lookup_freelist = lkp->lk_next;
581 else
582 lkp = (lookup_t)malloc(sizeof(struct lookup));
583
584 lkp->lk_thread = thread;
585
586 lkp->lk_next = lookup_hash[hashid];
587 lookup_hash[hashid] = lkp;
588 }
589
590 if (first_record == TRUE) {
591 lkp->lk_pathptr = lkp->lk_pathname;
592 lkp->lk_dvp = kdp->arg1;
593 } else {
594 if (lkp->lk_pathptr > &lkp->lk_pathname[NUMPARMS-4])
595 return (lkp);
596
597 *lkp->lk_pathptr++ = kdp->arg1;
598 }
599 *lkp->lk_pathptr++ = kdp->arg2;
600 *lkp->lk_pathptr++ = kdp->arg3;
601 *lkp->lk_pathptr++ = kdp->arg4;
602 *lkp->lk_pathptr = 0;
603
604 return (lkp);
605 }
606
607
608 static
609 void delete_lookup_event(uintptr_t thread, lookup_t lkp_to_delete)
610 {
611 lookup_t lkp;
612 lookup_t lkp_prev;
613 int hashid;
614
615 hashid = thread & HASH_MASK;
616
617 if ((lkp = lookup_hash[hashid])) {
618 if (lkp == lkp_to_delete)
619 lookup_hash[hashid] = lkp->lk_next;
620 else {
621 lkp_prev = lkp;
622
623 for (lkp = lkp->lk_next; lkp; lkp = lkp->lk_next) {
624 if (lkp == lkp_to_delete) {
625 lkp_prev->lk_next = lkp->lk_next;
626 break;
627 }
628 lkp_prev = lkp;
629 }
630 }
631 if (lkp) {
632 lkp->lk_next = lookup_freelist;
633 lookup_freelist = lkp;
634 }
635 }
636 }
637
638
639 static
640 void insert_start_event(uintptr_t thread, int debugid, uint64_t now)
641 {
642 event_t evp;
643 int hashid;
644
645 hashid = thread & HASH_MASK;
646
647 for (evp = event_hash[hashid]; evp; evp = evp->ev_next) {
648 if (evp->ev_thread == thread && evp->ev_debugid == debugid)
649 break;
650 }
651 if (evp == NULL) {
652 if ((evp = event_freelist))
653 event_freelist = evp->ev_next;
654 else
655 evp = (event_t)malloc(sizeof(struct event));
656
657 evp->ev_thread = thread;
658 evp->ev_debugid = debugid;
659
660 evp->ev_next = event_hash[hashid];
661 event_hash[hashid] = evp;
662 }
663 evp->ev_timestamp = now;
664 }
665
666
667 static
668 uint64_t consume_start_event(uintptr_t thread, int debugid, uint64_t now)
669 {
670 event_t evp;
671 event_t evp_prev;
672 int hashid;
673 uint64_t elapsed = 0;
674
675 hashid = thread & HASH_MASK;
676
677 if ((evp = event_hash[hashid])) {
678 if (evp->ev_thread == thread && evp->ev_debugid == debugid)
679 event_hash[hashid] = evp->ev_next;
680 else {
681 evp_prev = evp;
682
683 for (evp = evp->ev_next; evp; evp = evp->ev_next) {
684
685 if (evp->ev_thread == thread && evp->ev_debugid == debugid) {
686 evp_prev->ev_next = evp->ev_next;
687 break;
688 }
689 evp_prev = evp;
690 }
691 }
692 if (evp) {
693 elapsed = now - evp->ev_timestamp;
694
695 evp->ev_next = event_freelist;
696 event_freelist = evp;
697 }
698 }
699 return (elapsed);
700 }
701
702
703 void
704 log_trace()
705 {
706 char *buffer;
707 uint32_t buffer_size;
708 int fd;
709 int size;
710 int pad_size;
711 char pad_buf[4096];
712
713
714 if ((fd = open(logfile, O_TRUNC|O_WRONLY|O_CREAT, 0777)) == -1) {
715 perror("Can't open logfile");
716 exit(1);
717 }
718 get_bufinfo(&bufinfo);
719
720 if (bufinfo.nolog != 1) {
721 reenable = 1;
722 set_enable(0); /* disable logging*/
723 }
724 get_bufinfo(&bufinfo);
725
726 if (verbose_flag) {
727 if (bufinfo.flags & KDBG_WRAPPED)
728 printf("Buffer has wrapped\n");
729 else
730 printf("Buffer has not wrapped\n");
731 }
732 buffer_size = 1000000 * sizeof(kd_buf);
733 buffer = malloc(buffer_size);
734
735 if (buffer == (char *) 0)
736 quit("can't allocate memory for tracing info\n");
737
738 read_command_map(0, 0);
739 read_cpu_map(0);
740
741 raw_header.version_no = RAW_VERSION1;
742 raw_header.thread_count = total_threads;
743 raw_header.TOD_secs = time((long *)0);
744 raw_header.TOD_usecs = 0;
745
746 write(fd, &raw_header, sizeof(RAW_header));
747
748 size = total_threads * sizeof(kd_threadmap);
749 write(fd, (char *)mapptr, size);
750
751 pad_size = 4096 - ((sizeof(RAW_header) + size) & 4095);
752
753 if (cpumap_header) {
754 size_t cpumap_size = sizeof(kd_cpumap_header) + cpumap_header->cpu_count * sizeof(kd_cpumap);
755 if (pad_size >= cpumap_size) {
756 write(fd, (char *)cpumap_header, cpumap_size);
757 pad_size -= cpumap_size;
758 }
759 }
760
761 memset(pad_buf, 0, pad_size);
762 write(fd, pad_buf, pad_size);
763
764 for (;;) {
765 needed = buffer_size;
766
767 readtrace(buffer);
768
769 if (needed == 0)
770 break;
771 write(fd, buffer, needed * sizeof(kd_buf));
772 }
773 close(fd);
774 }
775
776
777 void
778 Log_trace()
779 {
780 int size;
781 kd_buf kd_tmp;
782 size_t len;
783 int num_cpus;
784 int try_writetrace = 1;
785 int fd;
786 char *buffer;
787 kd_buf *kd;
788 uint64_t sample_window_abs;
789 uint64_t next_window_begins;
790 uint64_t current_abs;
791 uint64_t ending_abstime;
792 uint64_t last_time_written;
793 uint32_t us_to_sleep;
794 uint32_t us_to_adjust;
795 uint32_t ms_to_run;
796
797 memset(&kd_tmp, 0, sizeof(kd_tmp));
798
799 if ((fd = open(logfile, O_TRUNC|O_WRONLY|O_CREAT, 0777)) == -1) {
800 perror("Can't open logfile");
801 exit(1);
802 }
803 if (use_current_buf == 0) {
804 /*
805 * grab the number of cpus and scale the buffer size
806 */
807 mib[0] = CTL_HW;
808 mib[1] = HW_NCPU;
809 mib[2] = 0;
810 len = sizeof(num_cpus);
811
812 sysctl(mib, 2, &num_cpus, &len, NULL, 0);
813
814 if (!bufset_flag)
815 nbufs = BASE_EVENTS * num_cpus;
816
817 set_remove();
818 set_numbufs(nbufs);
819 set_init();
820
821 if (filter_flag)
822 set_filter();
823
824 if (kval_flag)
825 set_kval_list();
826 }
827 /* Get kernel buffer information */
828 get_bufinfo(&bufinfo);
829
830 buffer = malloc(bufinfo.nkdbufs * sizeof(kd_buf));
831 if (buffer == (char *) 0)
832 quit("can't allocate memory for tracing info\n");
833 memset(buffer, 0, bufinfo.nkdbufs * sizeof(kd_buf));
834
835 if (use_current_buf == 0)
836 set_enable(1);
837
838 if (write_command_map(fd)) {
839 int pad_size;
840 char pad_buf[4096];
841
842 read_command_map(0, 0);
843 read_cpu_map(0);
844
845 raw_header.version_no = RAW_VERSION1;
846 raw_header.thread_count = total_threads;
847 raw_header.TOD_secs = time((long *)0);
848 raw_header.TOD_usecs = 0;
849
850 write(fd, &raw_header, sizeof(RAW_header));
851
852 size = total_threads * sizeof(kd_threadmap);
853 write(fd, (char *)mapptr, size);
854
855 pad_size = 4096 - ((sizeof(RAW_header) + size) & 4095);
856
857 if (cpumap_header) {
858 size_t cpumap_size = sizeof(kd_cpumap_header) + cpumap_header->cpu_count * sizeof(kd_cpumap);
859 if (pad_size >= cpumap_size) {
860 write(fd, (char *)cpumap_header, cpumap_size);
861 pad_size -= cpumap_size;
862 }
863 }
864
865 memset(pad_buf, 0, pad_size);
866 write(fd, pad_buf, pad_size);
867 }
868 sample_window_abs = (uint64_t)((double)US_TO_SLEEP * divisor);
869
870 next_window_begins = mach_absolute_time() + sample_window_abs;
871
872 if (secs_to_run) {
873 ending_abstime = mach_absolute_time() + (uint64_t)((double)secs_to_run * (double)1000000 * divisor);
874 ms_to_run = secs_to_run * 1000;
875 } else
876 ms_to_run = 0;
877 last_time_written = mach_absolute_time();
878
879 while (LogRAW_flag) {
880 current_abs = mach_absolute_time();
881
882 if (try_writetrace) {
883 needed = ms_to_run;
884
885 if (writetrace(fd))
886 try_writetrace = 0;
887 else {
888 if (needed) {
889 current_abs = mach_absolute_time();
890
891 printf("wrote %d events - elapsed time = %.1f secs\n",
892 (int)needed, ((double)(current_abs - last_time_written) / divisor) / 1000000);
893
894 last_time_written = current_abs;
895 }
896 }
897 }
898 if (try_writetrace == 0) {
899
900 if (next_window_begins > current_abs)
901 us_to_adjust = US_TO_SLEEP - (uint32_t)((double)(next_window_begins - current_abs) / divisor);
902 else
903 us_to_adjust = US_TO_SLEEP;
904
905 next_window_begins = current_abs + sample_window_abs;
906
907 us_to_sleep = US_TO_SLEEP - us_to_adjust;
908
909 next_window_begins = current_abs + (uint64_t)((double)(us_to_sleep + US_TO_SLEEP) * divisor);
910
911 if (us_to_sleep)
912 usleep(us_to_sleep);
913
914 get_bufinfo(&bufinfo);
915
916 if (bufinfo.flags & KDBG_WRAPPED)
917 printf("lost events\n");
918
919 needed = bufinfo.nkdbufs * sizeof(kd_buf);
920
921 readtrace(buffer);
922
923 if (bufinfo.flags & KDBG_WRAPPED) {
924
925 kd = (kd_buf *) buffer;
926
927 kd_tmp.timestamp = kd[0].timestamp;
928 kd_tmp.debugid = TRACE_LOST_EVENTS;
929
930 write(fd, &kd_tmp, sizeof(kd_tmp));
931 }
932 write(fd, buffer, needed * sizeof(kd_buf));
933
934 if (verbose_flag && needed > nbufs)
935 printf("needed = %ld\n", needed);
936 }
937 if (secs_to_run) {
938 current_abs = mach_absolute_time();
939
940 if (current_abs > ending_abstime)
941 break;
942 ms_to_run = (ending_abstime - current_abs) / (1000 * 1000);
943
944 if (ms_to_run == 0)
945 break;
946 }
947 }
948 set_enable(0);
949 set_numbufs(0);
950 set_remove();
951
952 close(fd);
953 }
954
955
956 void read_trace()
957 {
958 char *buffer;
959 uint32_t buffer_size;
960 kd_buf *kd;
961 int fd;
962 int firsttime = 1;
963 int lines = 0;
964 int io_lines = 0;
965 uint64_t bias = 0;
966 uint32_t count_of_names;
967 double last_event_time = 0.0;
968 time_t trace_time;
969
970 if (!readRAW_flag) {
971 get_bufinfo(&bufinfo);
972
973 if (bufinfo.nolog != 1) {
974 reenable = 1;
975 set_enable(0); /* disable logging*/
976 }
977 if (verbose_flag) {
978 if (bufinfo.flags & KDBG_WRAPPED)
979 printf("Buffer has wrapped\n");
980 else
981 printf("Buffer has not wrapped\n");
982 }
983 fd = 0;
984 count_of_names = 0;
985
986 } else {
987 fd = open(RAW_file, O_RDONLY);
988
989 if (fd < 0) {
990 perror("Can't open file");
991 exit(1);
992 }
993 if (read(fd, &raw_header, sizeof(RAW_header)) != sizeof(RAW_header)) {
994 perror("read failed");
995 exit(2);
996 }
997 if (raw_header.version_no != RAW_VERSION1) {
998 raw_header.version_no = RAW_VERSION0;
999 raw_header.TOD_secs = time((long *)0);
1000 raw_header.TOD_usecs = 0;
1001
1002 lseek(fd, (off_t)0, SEEK_SET);
1003
1004 if (read(fd, &raw_header.thread_count, sizeof(int)) != sizeof(int)) {
1005 perror("read failed");
1006 exit(2);
1007 }
1008 }
1009 count_of_names = raw_header.thread_count;
1010 trace_time = (time_t) (raw_header.TOD_secs);
1011
1012 printf("%s\n", ctime(&trace_time));
1013 }
1014 buffer_size = 1000000 * sizeof(kd_buf);
1015 buffer = malloc(buffer_size);
1016
1017 if (buffer == (char *) 0)
1018 quit("can't allocate memory for tracing info\n");
1019
1020 kd = (kd_buf *)buffer;
1021
1022 read_command_map(fd, count_of_names);
1023 read_cpu_map(fd);
1024
1025 for (;;) {
1026 uint32_t count;
1027 uint64_t now = 0;
1028 uint64_t prev;
1029 uint64_t prevdelta;
1030 uint32_t cpunum;
1031 uintptr_t thread;
1032 double x = 0.0;
1033 double y = 0.0;
1034 double event_elapsed_time;
1035 kd_buf *kdp;
1036 lookup_t lkp;
1037 boolean_t ending_event;
1038 int i;
1039 int debugid;
1040 int debugid_base;
1041 int dmsgindex;
1042 char dbgmessge[80];
1043 char outbuf[32];
1044 char *command;
1045
1046 if (!readRAW_flag) {
1047 needed = buffer_size;
1048
1049 mib[0] = CTL_KERN;
1050 mib[1] = KERN_KDEBUG;
1051 mib[2] = KERN_KDREADTR;
1052 mib[3] = 0;
1053 mib[4] = 0;
1054 mib[5] = 0;
1055 if (sysctl(mib, 3, buffer, &needed, NULL, 0) < 0)
1056 quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno));
1057
1058 if (needed == 0)
1059 break;
1060 count = needed;
1061
1062 } else {
1063 uint32_t bytes_read;
1064
1065 bytes_read = read(fd, buffer, buffer_size);
1066
1067 if (bytes_read == -1) {
1068 perror("read failed");
1069 exit(2);
1070 }
1071 count = bytes_read / sizeof(kd_buf);
1072
1073 if (count == 0)
1074 break;
1075 }
1076 for (kdp = &kd[0], i = 0; i < count; i++, kdp++) {
1077
1078 prev = now;
1079 debugid = kdp->debugid;
1080 debugid_base = debugid & DBG_FUNC_MASK;
1081 now = kdp->timestamp & KDBG_TIMESTAMP_MASK;
1082
1083 if (firsttime)
1084 bias = now;
1085 now -= bias;
1086
1087 cpunum = kdbg_get_cpu(kdp);
1088 thread = kdp->arg5;
1089
1090 if (lines == 64 || firsttime)
1091 {
1092 prevdelta = now - prevdelta;
1093
1094 if (firsttime)
1095 firsttime = 0;
1096 else {
1097 x = (double)prevdelta;
1098 x /= divisor;
1099
1100 fprintf(output_file, "\n\nNumber of microsecs since in last page %8.1f\n", x);
1101 }
1102 prevdelta = now;
1103
1104 /*
1105 * Output description row to output file (make sure to format correctly for 32-bit and 64-bit)
1106 */
1107 fprintf(output_file,
1108 #ifdef __LP64__
1109 " AbsTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu# command\n\n"
1110 #else
1111 " AbsTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu# command\n\n"
1112 #endif
1113 );
1114
1115 lines = 0;
1116
1117 if (io_lines > 15000) {
1118 fcntl(output_fd, F_FLUSH_DATA, 0);
1119
1120 io_lines = 0;
1121 }
1122 }
1123 lkp = 0;
1124
1125 if (debugid_base == VFS_LOOKUP) {
1126 lkp = handle_lookup_event(thread, debugid, kdp);
1127
1128 if ( !lkp || !(debugid & DBG_FUNC_END))
1129 continue;
1130 }
1131 x = (double)now;
1132 x /= divisor;
1133
1134 if (last_event_time)
1135 y = x - last_event_time;
1136 else
1137 y = x;
1138 last_event_time = x;
1139 ending_event = FALSE;
1140
1141 /*
1142 * Is this event from an IOP? If so, there will be no
1143 * thread command, label it with the symbolic IOP name
1144 */
1145 if (cpumap && (cpunum < cpumap_header->cpu_count) && (cpumap[cpunum].flags & KDBG_CPUMAP_IS_IOP)) {
1146 command = cpumap[cpunum].name;
1147 } else {
1148 find_thread_command(kdp, &command);
1149 }
1150
1151 /*
1152 * The internal use TRACE points clutter the output.
1153 * Print them only if in verbose mode.
1154 */
1155 if (!verbose_flag)
1156 {
1157 /* Is this entry of Class DBG_TRACE */
1158 if ((debugid >> 24) == DBG_TRACE) {
1159 if (((debugid >> 16) & 0xff) != DBG_TRACE_INFO)
1160 continue;
1161 }
1162 }
1163 if ( !lkp) {
1164 int t_debugid;
1165 int t_thread;
1166
1167 if ((debugid & DBG_FUNC_START) || debugid == MACH_MAKERUNNABLE) {
1168
1169 if (debugid_base != BSC_thread_terminate && debugid_base != BSC_exit) {
1170
1171 if (debugid == MACH_MAKERUNNABLE)
1172 t_thread = kdp->arg1;
1173 else
1174 t_thread = thread;
1175
1176 insert_start_event(t_thread, debugid_base, now);
1177 }
1178
1179 } else if ((debugid & DBG_FUNC_END) || debugid == MACH_STKHANDOFF || debugid == MACH_SCHEDULED) {
1180
1181 if (debugid == MACH_STKHANDOFF || debugid == MACH_SCHEDULED) {
1182 t_debugid = MACH_MAKERUNNABLE;
1183 t_thread = kdp->arg2;
1184 } else {
1185 t_debugid = debugid_base;
1186 t_thread = thread;
1187 }
1188 event_elapsed_time = (double)consume_start_event(t_thread, t_debugid, now);
1189 event_elapsed_time /= divisor;
1190 ending_event = TRUE;
1191
1192 if (event_elapsed_time == 0 && (debugid == MACH_STKHANDOFF || debugid == MACH_SCHEDULED))
1193 ending_event = FALSE;
1194 }
1195 }
1196 if (ending_event) {
1197 char *ch;
1198
1199 sprintf(&outbuf[0], "(%-10.1f)", event_elapsed_time);
1200 /*
1201 * fix that right paren
1202 */
1203 ch = &outbuf[11];
1204
1205 if (*ch != ')') {
1206 ch = strchr (&outbuf[0], ')');
1207 }
1208 if (ch)
1209 {
1210 *ch = ' ';
1211 --ch;
1212
1213 while (ch != &outbuf[0])
1214 {
1215 if (*ch == ' ')
1216 --ch;
1217 else
1218 {
1219 *(++ch) = ')';
1220 break;
1221 }
1222 }
1223 }
1224 }
1225 if (match_debugid(debugid_base, dbgmessge, &dmsgindex)) {
1226 if (ending_event)
1227 fprintf(output_file, "%13.1f %10.1f%s %-28x ", x, y, outbuf, debugid_base);
1228 else
1229 fprintf(output_file, "%13.1f %10.1f %-28x ", x, y, debugid_base);
1230 } else {
1231 if (ending_event)
1232 fprintf(output_file, "%13.1f %10.1f%s %-28.28s ", x, y, outbuf, dbgmessge);
1233 else
1234 fprintf(output_file, "%13.1f %10.1f %-28.28s ", x, y, dbgmessge);
1235 }
1236 if (lkp) {
1237 char *strptr;
1238 int len;
1239
1240 strptr = (char *)lkp->lk_pathname;
1241
1242 /*
1243 * print the tail end of the pathname
1244 */
1245 len = strlen(strptr);
1246 if (len > 51)
1247 len -= 51;
1248 else
1249 len = 0;
1250 #ifdef __LP64__
1251
1252 fprintf(output_file, "%-16lx %-51s %-16lx %-2d %s\n", lkp->lk_dvp, &strptr[len], thread, cpunum, command);
1253 #else
1254 fprintf(output_file, "%-8x %-51s %-8lx %-2d %s\n", (unsigned int)lkp->lk_dvp, &strptr[len], thread, cpunum, command);
1255 #endif
1256 delete_lookup_event(thread, lkp);
1257 } else if (debugid == TRACE_INFO_STRING) {
1258 #ifdef __LP64__
1259 fprintf(output_file, "%-32s%-36s %-16lx %-2d %s\n", (char *) &kdp->arg1, "", thread, cpunum, command);
1260 #else
1261 fprintf(output_file, "%-16s%-46s %-8lx %-2d %s\n", (char *) &kdp->arg1, "", thread, cpunum, command);
1262 #endif
1263 } else {
1264 #ifdef __LP64__
1265 fprintf(output_file, "%-16lx %-16lx %-16lx %-16lx %-16lx %-2d %s\n", kdp->arg1, kdp->arg2, kdp->arg3, kdp->arg4, thread, cpunum, command);
1266 #else
1267 fprintf(output_file, "%-8lx %-8lx %-8lx %-8lx %-8lx %-2d %s\n", kdp->arg1, kdp->arg2, kdp->arg3, kdp->arg4, thread, cpunum, command);
1268 #endif
1269 }
1270 lines++;
1271 io_lines++;
1272 }
1273 }
1274 if (reenable == 1)
1275 set_enable(1); /* re-enable kernel logging */
1276 }
1277
1278
1279
1280 void signal_handler(int sig)
1281 {
1282 ptrace(PT_KILL, pid, (caddr_t)0, 0);
1283 /*
1284 * child is gone; no need to disable the pid
1285 */
1286 exit(2);
1287 }
1288
1289
1290 void signal_handler_RAW(int sig)
1291 {
1292 LogRAW_flag = 0;
1293 }
1294
1295
1296
1297 int main(argc, argv, env)
1298 int argc;
1299 char **argv;
1300 char **env;
1301 {
1302 extern char *optarg;
1303 extern int optind;
1304 int status;
1305 int ch;
1306 int i;
1307 char *output_filename = NULL;
1308 char *filter_filename = NULL;
1309 unsigned int parsed_arg;
1310
1311 for (i = 1; i < argc; i++) {
1312 if (strcmp("-X", argv[i]) == 0) {
1313 force_32bit_exec = 1;
1314 break;
1315 }
1316 }
1317 if (force_32bit_exec) {
1318 if (0 != reexec_to_match_lp64ness(FALSE)) {
1319 fprintf(stderr, "Could not re-execute: %d\n", errno);
1320 exit(1);
1321 }
1322 } else {
1323 if (0 != reexec_to_match_kernel()) {
1324 fprintf(stderr, "Could not re-execute: %d\n", errno);
1325 exit(1);
1326 }
1327 }
1328 if (setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_PASSIVE) < 0) {
1329 printf("setiopolicy failed\n");
1330 exit(1);
1331 }
1332 output_file = stdout;
1333 output_fd = 1;
1334
1335 while ((ch = getopt(argc, argv, "hedEk:irb:gc:p:s:tR:L:l:S:F:a:x:Xnfvo:PT:N")) != EOF)
1336 {
1337 switch(ch)
1338 {
1339 case 'h': /* help */
1340 usage_flag=1;
1341 break;
1342 case 'S':
1343 secs_to_run = argtoi('S', "decimal number", optarg, 10);
1344 break;
1345 case 'a': /* set tracing on a pid */
1346 pid_flag=1;
1347 pid = argtoi('a', "decimal number", optarg, 10);
1348 break;
1349 case 'x': /* exclude a pid from tracing */
1350 pid_exflag=1;
1351 pid = argtoi('x', "decimal number", optarg, 10);
1352 break;
1353 case 'v':
1354 verbose_flag=1;
1355 break;
1356 case 'l':
1357 logRAW_flag = 1;
1358 logfile = optarg;
1359 break;
1360 case 'L':
1361 LogRAW_flag = 1;
1362 logfile = optarg;
1363 signal(SIGINT, signal_handler_RAW);
1364 break;
1365 case 'e':
1366 enable_flag = 1;
1367 break;
1368 case 'i':
1369 init_flag = 1;
1370 break;
1371 case 'E':
1372 execute_flag = 1;
1373 break;
1374 case 'd':
1375 disable_flag = 1;
1376 break;
1377 case 'k':
1378 if (kval_flag == 0)
1379 value1 = (unsigned int) argtoul('k', "hex number", optarg, 16);
1380 else if (kval_flag == 1)
1381 value2 = (unsigned int) argtoul('k', "hex number", optarg, 16);
1382 else if (kval_flag == 2)
1383 value3 = (unsigned int) argtoul('k', "hex number", optarg, 16);
1384 else if (kval_flag == 3)
1385 value4 = (unsigned int) argtoul('k', "hex number", optarg, 16);
1386 else
1387 {
1388 fprintf(stderr, "A maximum of four values can be specified with -k\n");
1389 usage(SHORT_HELP);
1390 }
1391 kval_flag++;
1392 break;
1393 case 'r':
1394 remove_flag = 1;
1395 break;
1396 case 'g':
1397 bufget_flag = 1;
1398 break;
1399 case 't':
1400 trace_flag = 1;
1401 break;
1402 case 'R':
1403 readRAW_flag = 1;
1404 RAW_file = optarg;
1405 break;
1406 case 'n':
1407 nowrap_flag = 1;
1408 break;
1409 case 'f':
1410 freerun_flag = 1;
1411 break;
1412 case 'b':
1413 bufset_flag = 1;
1414 nbufs = argtoi('b', "decimal number", optarg, 10);
1415 break;
1416 case 'c':
1417 filter_flag = 1;
1418 parsed_arg = argtoi('c', "decimal, hex, or octal number", optarg, 0);
1419 if (parsed_arg > 0xFF)
1420 quit_args("argument '-c %s' parsed as %u, "
1421 "class value must be 0-255\n", optarg, parsed_arg);
1422 saw_filter_class(parsed_arg);
1423 break;
1424 case 's':
1425 filter_flag = 1;
1426 parsed_arg = argtoi('s', "decimal, hex, or octal number", optarg, 0);
1427 if (parsed_arg > 0xFF)
1428 quit_args("argument '-s %s' parsed as %u, "
1429 "subclass value must be 0-255\n", optarg, parsed_arg);
1430 saw_filter_subclass(parsed_arg);
1431 break;
1432 case 'p':
1433 filter_flag = 1;
1434 parsed_arg = argtoi('p', "decimal, hex, or octal number", optarg, 0);
1435 if (parsed_arg > 0xFF)
1436 quit_args("argument '-p %s' parsed as %u, "
1437 "end range value must be 0-255\n", optarg, parsed_arg);
1438 saw_filter_end_range(parsed_arg);
1439 break;
1440 case 'P':
1441 ppt_flag = 1;
1442 break;
1443 case 'o':
1444 output_filename = optarg;
1445 break;
1446 case 'F':
1447 frequency = argtoi('F', "decimal number", optarg, 10);
1448 break;
1449 case 'X':
1450 break;
1451 case 'N':
1452 no_default_codes_flag = 1;
1453 break;
1454 case 'T':
1455 filter_flag = 1;
1456
1457 // Flush out any unclosed -c argument
1458 filter_done_parsing();
1459
1460 parse_filter_file(optarg);
1461 break;
1462 default:
1463 usage(SHORT_HELP);
1464 }
1465 }
1466 argc -= optind;
1467
1468 if (!no_default_codes_flag)
1469 {
1470 if (verbose_flag)
1471 printf("Adding default code file /usr/share/misc/trace.codes. Use '-N' to skip this.\n");
1472 parse_codefile("/usr/share/misc/trace.codes");
1473 }
1474
1475 if (argc)
1476 {
1477 if (!execute_flag)
1478 {
1479 while (argc--)
1480 {
1481 const char *cfile = argv[optind++];
1482 if (verbose_flag) printf("Adding code file %s \n", cfile);
1483 parse_codefile(cfile);
1484 }
1485 }
1486 }
1487 else
1488 {
1489 if (execute_flag)
1490 quit_args("-E flag needs an executable to launch\n");
1491 }
1492
1493 if (usage_flag)
1494 usage(LONG_HELP);
1495
1496 getdivisor();
1497
1498 if (pid_flag && pid_exflag)
1499 quit_args("Can't use both -a and -x flag together\n");
1500
1501 if (kval_flag && filter_flag)
1502 quit_args("Cannot use -k flag with -c, -s, or -p\n");
1503
1504 if (output_filename && !trace_flag && !readRAW_flag)
1505 quit_args("When using 'o' option, must use the 't' or 'R' option too\n");
1506
1507 filter_done_parsing();
1508
1509 done_with_args = 1;
1510
1511 if (LogRAW_flag) {
1512 get_bufinfo(&bufinfo);
1513
1514 if (bufinfo.nolog == 0)
1515 use_current_buf = 1;
1516 }
1517
1518 if (disable_flag)
1519 {
1520 if (pid_flag)
1521 {
1522 set_pidcheck(pid, 0); /* disable pid check for given pid */
1523 exit(1);
1524 }
1525 else if (pid_exflag)
1526 {
1527 set_pidexclude(pid, 0); /* disable pid exclusion for given pid */
1528 exit(1);
1529 }
1530 set_enable(0);
1531 exit(1);
1532 }
1533
1534 if (remove_flag)
1535 {
1536 set_remove();
1537 exit(1);
1538 }
1539
1540 if (bufset_flag )
1541 {
1542 if (!init_flag && !LogRAW_flag)
1543 {
1544 fprintf(stderr,"The -b flag must be used with the -i flag\n");
1545 exit(1);
1546 }
1547 set_numbufs(nbufs);
1548 }
1549
1550 if (nowrap_flag)
1551 set_nowrap();
1552
1553 if (freerun_flag)
1554 set_freerun();
1555
1556 if (bufget_flag)
1557 {
1558 get_bufinfo(&bufinfo);
1559
1560 printf("The kernel buffer settings are:\n");
1561
1562 if (bufinfo.flags & KDBG_BUFINIT)
1563 printf("\tKernel buffer is initialized\n");
1564 else
1565 printf("\tKernel buffer is not initialized\n");
1566
1567 printf("\t number of buf entries = %d\n", bufinfo.nkdbufs);
1568
1569 if (verbose_flag)
1570 {
1571 if (bufinfo.flags & KDBG_MAPINIT)
1572 printf("\tKernel thread map is initialized\n");
1573 else
1574 printf("\tKernel thread map is not initialized\n");
1575 printf("\t number of thread entries = %d\n", bufinfo.nkdthreads);
1576 }
1577
1578 if (bufinfo.nolog)
1579 printf("\tBuffer logging is disabled\n");
1580 else
1581 printf("\tBuffer logging is enabled\n");
1582
1583 if (verbose_flag)
1584 printf("\tkernel flags = 0x%x\n", bufinfo.flags);
1585
1586 if (bufinfo.flags & KDBG_NOWRAP)
1587 printf("\tKernel buffer wrap is disabled\n");
1588 else
1589 printf("\tKernel buffer wrap is enabled\n");
1590
1591 if (bufinfo.flags & KDBG_RANGECHECK)
1592 printf("\tCollection within a range is enabled\n");
1593 else
1594 printf("\tCollection within a range is disabled\n");
1595
1596 if (bufinfo.flags & KDBG_VALCHECK)
1597 printf("\tCollecting specific code values is enabled\n");
1598 else
1599 printf("\tCollecting specific code values is disabled\n");
1600
1601 if (bufinfo.flags & KDBG_TYPEFILTER_CHECK)
1602 printf("\tCollection based on a filter is enabled\n");
1603 else
1604 printf("\tCollection based on a filter is disabled\n");
1605
1606 if (bufinfo.flags & KDBG_PIDCHECK)
1607 printf("\tCollection based on pid is enabled\n");
1608 else
1609 printf("\tCollection based on pid is disabled\n");
1610
1611 if (bufinfo.flags & KDBG_PIDEXCLUDE)
1612 printf("\tCollection based on pid exclusion is enabled\n");
1613 else
1614 printf("\tCollection based on pid exclusion is disabled\n");
1615
1616 if (bufinfo.bufid == -1)
1617 printf("\tKernel buffer is not controlled by any process.\n");
1618 else
1619 printf("\tKernel buffer is controlled by proc id [%d]\n", bufinfo.bufid);
1620 }
1621
1622 if (init_flag)
1623 set_init();
1624
1625 if (filter_flag)
1626 set_filter();
1627
1628 if (kval_flag)
1629 set_kval_list();
1630
1631 if (execute_flag)
1632 {
1633 fprintf(stderr, "Starting program: %s\n", argv[optind]);
1634 fflush(stdout);
1635 fflush(stderr);
1636
1637 switch ((pid = vfork()))
1638 {
1639 case -1:
1640 perror("vfork: ");
1641 exit(1);
1642 case 0: /* child */
1643 setsid();
1644 ptrace(PT_TRACE_ME, 0, (caddr_t)0, 0);
1645 execve(argv[optind], &argv[optind], environ);
1646 perror("execve:");
1647 exit(1);
1648 }
1649 sleep(1);
1650
1651 signal(SIGINT, signal_handler);
1652 set_pidcheck(pid, 1);
1653 set_enable(1);
1654 ptrace(PT_CONTINUE, pid, (caddr_t)1, 0);
1655 waitpid(pid, &status, 0);
1656 /* child is gone; no need to disable the pid */
1657 exit(0);
1658 }
1659 else if (enable_flag)
1660 {
1661 if (pid_flag)
1662 set_pidcheck(pid, 1);
1663 else if (pid_exflag)
1664 set_pidexclude(pid, 1);
1665 set_enable(1);
1666 }
1667
1668 if (output_filename)
1669 {
1670 if (((output_fd = open(output_filename, O_CREAT | O_TRUNC | O_WRONLY | O_APPEND, 0644)) < 0 ) ||
1671 !(output_file = fdopen(output_fd, "w")))
1672 {
1673 fprintf(stderr, "Cannot open file \"%s\" for writing.\n", output_filename);
1674 usage(SHORT_HELP);
1675 }
1676 setbuffer(output_file, &sbuffer[0], SBUFFER_SIZE);
1677
1678 if (fcntl(output_fd, F_NOCACHE, 1) < 0)
1679 {
1680 /* Not fatal */
1681 fprintf(stderr, "Warning: setting F_NOCACHE on %s, failed\n", output_filename);
1682 }
1683 }
1684 if (!LogRAW_flag && !logRAW_flag)
1685 setbuffer(output_file, &sbuffer[0], SBUFFER_SIZE);
1686
1687 if (trace_flag || readRAW_flag)
1688 read_trace();
1689 else if (LogRAW_flag)
1690 Log_trace();
1691 else if (logRAW_flag)
1692 log_trace();
1693
1694 exit(0);
1695
1696 } /* end main */
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 base_offset = lseek(fd, (off_t)0, SEEK_CUR);
2516 off_t aligned_offset = (base_offset + (4095)) & ~4095; /* <rdar://problem/13500105> */
2517
2518 size_t padding_bytes = (size_t)(aligned_offset - base_offset);
2519
2520 if (read(fd, cpumap_header, padding_bytes) == padding_bytes) {
2521 if (cpumap_header->version_no == RAW_VERSION1) {
2522 cpumap = (kd_cpumap*)&cpumap_header[1];
2523 }
2524 }
2525 }
2526 } else {
2527 int mib[3];
2528
2529 mib[0] = CTL_KERN;
2530 mib[1] = KERN_KDEBUG;
2531 mib[2] = KERN_KDCPUMAP;
2532
2533 size_t temp = PAGE_SIZE;
2534 if (sysctl(mib, 3, cpumap_header, &temp, NULL, 0) == 0) {
2535 if (PAGE_SIZE >= temp) {
2536 if (cpumap_header->version_no == RAW_VERSION1) {
2537 cpumap = (kd_cpumap*)&cpumap_header[1];
2538 }
2539 }
2540 }
2541 }
2542
2543 if (!cpumap) {
2544 printf("Can't read the cpu map -- this is not fatal\n");
2545 free(cpumap_header);
2546 cpumap_header = NULL;
2547 } else if (verbose_flag) {
2548 /* Dump the initial cpumap */
2549 printf("\nCPU\tName\n");
2550 for (int i = 0; i < cpumap_header->cpu_count; i++) {
2551 printf ("%2d\t%s\n", cpumap[i].cpu_id, cpumap[i].name);
2552 }
2553 printf("\n");
2554 }
2555 }
2556
2557 int
2558 read_command_map(int fd, uint32_t count)
2559 {
2560 int i;
2561 size_t size;
2562 int mib[6];
2563
2564 if (readRAW_flag) {
2565 total_threads = count;
2566 size = count * sizeof(kd_threadmap);
2567 } else {
2568 get_bufinfo(&bufinfo);
2569
2570 total_threads = bufinfo.nkdthreads;
2571 size = bufinfo.nkdthreads * sizeof(kd_threadmap);
2572 }
2573 mapptr = 0;
2574 nthreads = total_threads * 2;
2575
2576 if (verbose_flag)
2577 printf("Size of map table is %d, thus %d entries\n", (int)size, total_threads);
2578
2579 if (size) {
2580 if ((mapptr = (kd_threadmap *) malloc(size)))
2581 bzero (mapptr, size);
2582 else
2583 {
2584 if (verbose_flag)
2585 printf("Thread map is not initialized -- this is not fatal\n");
2586 return(0);
2587 }
2588 }
2589 if (readRAW_flag) {
2590 if (read(fd, mapptr, size) != size) {
2591 if (verbose_flag)
2592 printf("Can't read the thread map -- this is not fatal\n");
2593 free(mapptr);
2594 mapptr = 0;
2595
2596 return (int)size;
2597 }
2598 } else {
2599 /* Now read the threadmap */
2600 mib[0] = CTL_KERN;
2601 mib[1] = KERN_KDEBUG;
2602 mib[2] = KERN_KDTHRMAP;
2603 mib[3] = 0;
2604 mib[4] = 0;
2605 mib[5] = 0; /* no flags */
2606 if (sysctl(mib, 3, mapptr, &size, NULL, 0) < 0)
2607 {
2608 /* This is not fatal -- just means I cant map command strings */
2609 if (verbose_flag)
2610 printf("Can't read the thread map -- this is not fatal\n");
2611 free(mapptr);
2612 mapptr = 0;
2613 return(0);
2614 }
2615 }
2616 for (i = 0; i < total_threads; i++) {
2617 if (mapptr[i].thread)
2618 create_map_entry(mapptr[i].thread, &mapptr[i].command[0]);
2619 }
2620
2621 if (verbose_flag) {
2622 /* Dump the initial map */
2623
2624 printf("Size of maptable returned is %ld, thus %ld entries\n", size, (size/sizeof(kd_threadmap)));
2625
2626 printf("Thread Command\n");
2627 for (i = 0; i < total_threads; i++) {
2628 printf ("0x%lx %s\n",
2629 mapptr[i].thread,
2630 mapptr[i].command);
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 }