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