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
47int nbufs = 0;
48int enable_flag=0;
49int execute_flag=0;
50int logRAW_flag=0;
51int LogRAW_flag=0;
52int readRAW_flag = 0;
53int disable_flag=0;
54int init_flag=0;
55int kval_flag=0;
56int remove_flag=0;
57int bufset_flag=0;
58int bufget_flag=0;
59int filter_flag=0;
60int filter_file_flag=0;
61int filter_alloced=0;
62int trace_flag=0;
63int nowrap_flag=0;
64int freerun_flag=0;
65int verbose_flag=0;
66int usage_flag=0;
67int pid_flag=0;
68int pid_exflag=0;
69int ppt_flag=0;
70int done_with_args=0;
71int no_default_codes_flag=0;
72
73unsigned int value1=0;
74unsigned int value2=0;
75unsigned int value3=0;
76unsigned int value4=0;
77
78pid_t pid=0;
79int reenable=0;
80
81int force_32bit_exec = 0;
82int frequency = 0;
83
84int mib[6];
85size_t needed;
86
87char *logfile = (char *)0;      /* This file is trace format */
88char *RAW_file = (char *)0;
89FILE *output_file;
90int   output_fd;
91
92extern char **environ;
93
94uint8_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
118char tmpcommand[MAXCOMLEN];
119
120int total_threads = 0;
121int nthreads = 0;
122kd_threadmap *mapptr = 0;
123
124kd_cpumap_header* cpumap_header = NULL;
125kd_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
141double divisor;
142
143typedef struct {
144	uint32_t debugid;
145	char	*debug_string;
146} code_type_t;
147
148code_type_t*	codesc = 0;
149size_t			codesc_idx = 0; // Index into first empty codesc entry
150
151
152
153typedef struct event *event_t;
154
155struct event {
156	event_t	  ev_next;
157
158	uintptr_t ev_thread;
159	uint32_t  ev_debugid;
160	uint64_t  ev_timestamp;
161};
162
163typedef struct lookup *lookup_t;
164
165struct 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
174typedef struct threadmap *threadmap_t;
175
176struct 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
189event_t		event_hash[HASH_SIZE];
190lookup_t	lookup_hash[HASH_SIZE];
191threadmap_t	threadmap_hash[HASH_SIZE];
192
193event_t		event_freelist;
194lookup_t	lookup_freelist;
195threadmap_t	threadmap_freelist;
196threadmap_t	threadmap_temp;
197
198
199#define		SBUFFER_SIZE	(128 * 4096)
200char		sbuffer[SBUFFER_SIZE];
201
202int secs_to_run = 0;
203int use_current_buf = 0;
204
205
206kbufinfo_t bufinfo = {0, 0, 0, 0};
207
208int   codenum = 0;
209int   codeindx_cache = 0;
210
211static void quit(char *);
212static int match_debugid(unsigned int, char *, int *);
213static void usage(int short_help);
214static int argtoi(int flag, char *req, char *str, int base);
215static int parse_codefile(const char *filename);
216static void codesc_find_dupes(void);
217static int read_command_map(int, uint32_t);
218static void read_cpu_map(int);
219static void find_thread_command(kd_buf *, char **);
220static void create_map_entry(uintptr_t, char *);
221static void getdivisor();
222static unsigned long argtoul();
223
224static void set_enable(int);
225static void set_remove();
226static void set_nowrap();
227static void set_pidcheck(int, int);
228static void set_pidexclude(int, int);
229static void set_numbufs(int);
230static void set_freerun();
231static void get_bufinfo(kbufinfo_t *);
232static void set_init();
233static void set_kval_list();
234static void readtrace(char *);
235static void log_trace();
236static void Log_trace();
237static void read_trace();
238static void signal_handler(int);
239static void signal_handler_RAW(int);
240static void delete_thread_entry(uintptr_t);
241static void find_and_insert_tmp_map_entry(uintptr_t, char *);
242static void create_tmp_map_entry(uintptr_t, uintptr_t);
243static void find_thread_name(uintptr_t, char **, boolean_t);
244
245static int  writetrace(int);
246static int  write_command_map(int);
247static int  debugid_compar(code_type_t *, code_type_t *);
248
249static threadmap_t find_thread_entry(uintptr_t);
250
251static void saw_filter_class(uint8_t class);
252static void saw_filter_end_range(uint8_t end_class);
253static void saw_filter_subclass(uint8_t subclass);
254static void filter_done_parsing(void);
255
256static void set_filter(void);
257static void set_filter_class(uint8_t class);
258static void set_filter_range(uint8_t class, uint8_t end);
259static void set_filter_subclass(uint8_t class, uint8_t subclass);
260
261static void parse_filter_file(char *filename);
262
263static 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
278typedef 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
297RAW_header	raw_header;
298
299
300
301void 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
321void 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
342void 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
363void 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
376void 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
401void 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
426void 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
438void 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
451void 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
479static void
480set_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
491void 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
512void 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
526int 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
542int 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
558static
559lookup_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
607static
608void 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
638static
639void 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
666static
667uint64_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
702void
703log_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
776void
777Log_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
955void 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
1273void 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
1283void signal_handler_RAW(int sig)
1284{
1285	LogRAW_flag = 0;
1286}
1287
1288
1289
1290int main(argc, argv, env)
1291int argc;
1292char **argv;
1293char **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
1691static void
1692quit_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
1718void
1719quit(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
1733static void
1734usage(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
1912static int
1913argtoi(flag, req, str, base)
1914int flag;
1915char *req, *str;
1916int 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
1928static unsigned long
1929argtoul(flag, req, str, base)
1930int flag;
1931char *req, *str;
1932int 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 */
1948int 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?
1987enum {
1988	FILTER_MODE_START,
1989	FILTER_MODE_CLASS,
1990	FILTER_MODE_CLASS_RANGE,
1991	FILTER_MODE_SUBCLASS
1992} filter_mode = FILTER_MODE_START;
1993
1994uint8_t filter_current_class        = 0;
1995uint8_t filter_current_subclass     = 0;
1996uint8_t filter_current_class_range  = 0;
1997
1998static void
1999saw_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
2025static void
2026saw_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
2052static void
2053saw_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
2076static void
2077filter_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. */
2102static boolean_t setting_class = FALSE;
2103static boolean_t setting_range = FALSE;
2104
2105static void
2106set_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
2127static void
2128set_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
2141static void
2142set_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
2168static void
2169parse_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 */
2237static 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
2274static int
2275parse_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
2440static 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
2466int 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
2488void
2489read_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
2550int
2551read_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
2630void 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
2653void 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
2683void 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
2718void 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
2737threadmap_t
2738find_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
2753void 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
2767void 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
2813static
2814void 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}
2828