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