]> git.saurik.com Git - apple/system_cmds.git/blobdiff - trace.tproj/trace.c
system_cmds-790.tar.gz
[apple/system_cmds.git] / trace.tproj / trace.c
index 1673325adbef981ca7f5a3bad38ff92d36ff77ad..98aadc885883b51e2f04db6eded95d55fe0da364 100644 (file)
@@ -2,6 +2,10 @@
     cc -I/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders -arch x86_64 -arch i386  -O -o trace trace.c
 */
 
+/*
+ * NOTE: There exists another copy of this file in the kernel_tools.  Changes
+ * made here may also need to be made there.
+ */
 
 #include <sys/param.h>
 #include <sys/types.h>
 #include <string.h>
 #include <paths.h>
 #include <err.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <spawn.h>
+#include <assert.h>
+#include <signal.h>
+#include <sysexits.h>
 
 #include <libutil.h>
 
+#ifndef KERNEL_PRIVATE
+#define KERNEL_PRIVATE
+#include <sys/kdebug.h>
+#undef KERNEL_PRIVATE
+#else
 #include <sys/kdebug.h>
+#endif /*KERNEL_PRIVATE*/
+#include <sys/param.h>
 
 #include <mach/mach.h>
 #include <mach/mach_time.h>
 
-
 int nbufs = 0;
 int enable_flag=0;
 int execute_flag=0;
@@ -47,22 +63,25 @@ int kval_flag=0;
 int remove_flag=0;
 int bufset_flag=0;
 int bufget_flag=0;
-int class_flag=0;
-int subclass_flag=0;
+int filter_flag=0;
+int filter_file_flag=0;
+int filter_alloced=0;
 int trace_flag=0;
 int nowrap_flag=0;
 int freerun_flag=0;
 int verbose_flag=0;
+int usage_flag=0;
 int pid_flag=0;
 int pid_exflag=0;
 int ppt_flag=0;
-unsigned int class=0;
-unsigned int class2=0;
-unsigned int subclass=0;
+int done_with_args=0;
+int no_default_codes_flag=0;
+
 unsigned int value1=0;
 unsigned int value2=0;
 unsigned int value3=0;
 unsigned int value4=0;
+
 pid_t pid=0;
 int reenable=0;
 
@@ -79,6 +98,9 @@ int   output_fd;
 
 extern char **environ;
 
+uint8_t* type_filter_bitmap;
+
+#define SIZE_4KB (4 * (1 << 10))
 
 #define DBG_FUNC_ALL           (DBG_FUNC_START | DBG_FUNC_END)
 #define DBG_FUNC_MASK  0xfffffffc
@@ -87,13 +109,8 @@ extern char **environ;
 
 #define CSC_MASK               0xffff0000
 
-#define VFS_LOOKUP             0x03010090
 #define BSC_exit               0x040c0004
 #define BSC_thread_terminate   0x040c05a4
-#define TRACE_DATA_NEWTHREAD   0x07000004
-#define TRACE_STRING_NEWTHREAD 0x07010004
-#define TRACE_STRING_EXEC      0x07010008
-#define TRACE_LOST_EVENTS      0x07020008
 #define MACH_SCHEDULED         0x01400000
 #define MACH_MAKERUNNABLE      0x01400018
 #define MACH_STKHANDOFF                0x01400008
@@ -107,8 +124,11 @@ int total_threads = 0;
 int nthreads = 0;
 kd_threadmap *mapptr = 0;
 
-/* 
-   If NUMPARMS changes from the kernel, 
+kd_cpumap_header* cpumap_header = NULL;
+kd_cpumap* cpumap = NULL;
+
+/*
+   If NUMPARMS changes from the kernel,
    then PATHLENGTH will also reflect the change
    This is for the vfslookup entries that
    return pathnames
@@ -120,7 +140,7 @@ kd_threadmap *mapptr = 0;
 #define US_TO_SLEEP    50000
 #define BASE_EVENTS    500000
 
-
+mach_timebase_info_data_t mach_timebase;
 double divisor;
 
 typedef struct {
@@ -128,7 +148,9 @@ typedef struct {
        char    *debug_string;
 } code_type_t;
 
-code_type_t * codesc = 0;
+code_type_t*   codesc = 0;
+size_t                 codesc_idx = 0; // Index into first empty codesc entry
+
 
 
 typedef struct event *event_t;
@@ -145,7 +167,7 @@ typedef struct lookup *lookup_t;
 
 struct lookup {
        lookup_t  lk_next;
-       
+
        uintptr_t lk_thread;
        uintptr_t lk_dvp;
        long     *lk_pathptr;
@@ -156,13 +178,12 @@ typedef struct threadmap *threadmap_t;
 
 struct threadmap {
        threadmap_t     tm_next;
-       
+
        uintptr_t       tm_thread;
        uintptr_t       tm_pthread;
        boolean_t       tm_deleteme;
        char            tm_command[MAXCOMLEN + 1];
 };
-       
 
 #define HASH_SIZE      1024
 #define HASH_MASK      1023
@@ -188,16 +209,15 @@ kbufinfo_t bufinfo = {0, 0, 0, 0};
 
 int   codenum = 0;
 int   codeindx_cache = 0;
-char  codefile[] = "codes";
-char *cfile = (char *)0;
-
 
 static void quit(char *);
 static int match_debugid(unsigned int, char *, int *);
 static void usage(int short_help);
 static int argtoi(int flag, char *req, char *str, int base);
-static int parse_codefile(char *filename);
-static int read_command_map(int, int);
+static int parse_codefile(const char *filename);
+static void codesc_find_dupes(void);
+static int read_command_map(int, uint32_t);
+static void read_cpu_map(int);
 static void find_thread_command(kd_buf *, char **);
 static void create_map_entry(uintptr_t, char *);
 static void getdivisor();
@@ -211,10 +231,9 @@ static void set_pidexclude(int, int);
 static void set_numbufs(int);
 static void set_freerun();
 static void get_bufinfo(kbufinfo_t *);
+static int get_ktrace_state(void);
 static void set_init();
-static void set_class();
 static void set_kval_list();
-static void set_subclass();
 static void readtrace(char *);
 static void log_trace();
 static void Log_trace();
@@ -225,14 +244,27 @@ static void delete_thread_entry(uintptr_t);
 static void find_and_insert_tmp_map_entry(uintptr_t, char *);
 static void create_tmp_map_entry(uintptr_t, uintptr_t);
 static void find_thread_name(uintptr_t, char **, boolean_t);
+static void execute_process(char * const argv[]);
 
 static int  writetrace(int);
 static int  write_command_map(int);
-static int  debugid_compar(code_type_t *, code_type_t *);
+static int  debugid_compar(const void *, const void *);
 
 static threadmap_t find_thread_entry(uintptr_t);
 
+static void saw_filter_class(uint8_t class);
+static void saw_filter_end_range(uint8_t end_class);
+static void saw_filter_subclass(uint8_t subclass);
+static void filter_done_parsing(void);
+
+static void set_filter(void);
+static void set_filter_class(uint8_t class);
+static void set_filter_range(uint8_t class, uint8_t end);
+static void set_filter_subclass(uint8_t class, uint8_t subclass);
 
+static void parse_filter_file(char *filename);
+
+static void quit_args(const char *fmt, ...)  __printflike(1, 2);
 
 #ifndef        KERN_KDWRITETR
 #define KERN_KDWRITETR 17
@@ -258,6 +290,13 @@ typedef struct {
 #define RAW_VERSION1    0x55aa0101
 #endif
 
+#define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(*x)))
+
+#define EXTRACT_CLASS_LOW(debugid)     ( (uint8_t) ( ((debugid) & 0xFF00   ) >> 8 ) )
+#define EXTRACT_SUBCLASS_LOW(debugid)  ( (uint8_t) ( ((debugid) & 0xFF     )      ) )
+
+#define ENCODE_CSC_LOW(class, subclass) \
+  ( (uint16_t) ( ((class) & 0xff) << 8 ) | ((subclass) & 0xff) )
 
 RAW_header     raw_header;
 
@@ -279,16 +318,20 @@ void set_enable(int val)
 #endif
        mib[4] = 0;
        mib[5] = 0;
-       if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
-               quit("trace facility failure, KERN_KDENABLE\n");
+       if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0) {
+               if (errno == EINVAL) {
+                       quit_args("trace facility failure, KERN_KDENABLE: trace buffer is uninitialized\n");
+               }
+               quit_args("trace facility failure, KERN_KDENABLE: %s\n", strerror(errno));
+       }
 }
 
-void set_remove()
+void set_remove(void)
 {
        extern int errno;
-    
+
        errno = 0;
-    
+
        mib[0] = CTL_KERN;
        mib[1] = KERN_KDEBUG;
        mib[2] = KERN_KDREMOVE;
@@ -300,7 +343,7 @@ void set_remove()
                if (errno == EBUSY)
                        quit("the trace facility is currently in use...\n          fs_usage, sc_usage, trace, and latency use this feature.\n\n");
                else
-                       quit("trace facility failure, KERN_KDREMOVE\n");
+                       quit_args("trace facility failure, KERN_KDREMOVE: %s\n", strerror(errno));
        }
 }
 
@@ -313,8 +356,8 @@ void set_numbufs(int nbufs)
        mib[4] = 0;
        mib[5] = 0;
        if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
-               quit("trace facility failure, KERN_KDSETBUF\n");
-    
+               quit_args("trace facility failure, KERN_KDSETBUF: %s\n", strerror(errno));
+
        mib[0] = CTL_KERN;
        mib[1] = KERN_KDEBUG;
        mib[2] = KERN_KDSETUP;
@@ -322,10 +365,10 @@ void set_numbufs(int nbufs)
        mib[4] = 0;
        mib[5] = 0;
        if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
-               quit("trace facility failure, KERN_KDSETUP\n");
+               quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno));
 }
 
-void set_nowrap()
+void set_nowrap(void)
 {
         mib[0] = CTL_KERN;
         mib[1] = KERN_KDEBUG;
@@ -334,14 +377,14 @@ void set_nowrap()
         mib[4] = 0;
         mib[5] = 0;            /* no flags */
         if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
-               quit("trace facility failure, KDBG_NOWRAP\n");
+               quit_args("trace facility failure, KDBG_NOWRAP: %s\n", strerror(errno));
 
 }
 
 void set_pidcheck(int pid, int on_off_flag)
 {
        kd_regtype kr;
-    
+
        kr.type = KDBG_TYPENONE;
        kr.value1 = pid;
        kr.value2 = on_off_flag;
@@ -354,11 +397,20 @@ void set_pidcheck(int pid, int on_off_flag)
        mib[5] = 0;
        if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
        {
-               if (on_off_flag == 1)
+               if (errno == EACCES)
+               {
+                       quit_args("trace facility failure, setting pid filter: %s\n",
+                                 strerror(errno));
+               }
+               else if (on_off_flag == 1 && errno == ESRCH)
                {
-                       printf("trace facility failure, KERN_KDPIDTR,\n\tpid %d does not exist\n", pid);
                        set_remove();
-                       exit(2);
+                       quit_args("trace facility failure, setting pid filter: "
+                                 "pid %d does not exist\n", pid);
+               }
+               else
+               {
+                       quit_args("trace facility failure, KERN_KDPIDTR: %s\n", strerror(errno));
                }
        }
 }
@@ -366,7 +418,7 @@ void set_pidcheck(int pid, int on_off_flag)
 void set_pidexclude(int pid, int on_off_flag)
 {
        kd_regtype kr;
-    
+
        kr.type = KDBG_TYPENONE;
        kr.value1 = pid;
        kr.value2 = on_off_flag;
@@ -388,7 +440,7 @@ void set_pidexclude(int pid, int on_off_flag)
        }
 }
 
-void set_freerun()
+void set_freerun(void)
 {
         mib[0] = CTL_KERN;
         mib[1] = KERN_KDEBUG;
@@ -397,7 +449,19 @@ void set_freerun()
         mib[4] = 0;
         mib[5] = 0;
         if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
-               quit("trace facility failure, KDBG_FREERUN\n");
+               quit_args("trace facility failure, KDBG_FREERUN: %s\n", strerror(errno));
+}
+
+static int get_ktrace_state(void)
+{
+       int state;
+       size_t state_size = sizeof(state);
+       int err = sysctlbyname("ktrace.state", &state, &state_size, NULL, 0);
+       if (err) {
+               fprintf(stderr, "error: could not query ktrace.state sysctl (%d: %s)\n", errno, strerror(errno));
+               exit(1);
+       }
+       return state;
 }
 
 void get_bufinfo(kbufinfo_t *val)
@@ -410,13 +474,13 @@ void get_bufinfo(kbufinfo_t *val)
        mib[4] = 0;
        mib[5] = 0;
        if (sysctl(mib, 3, val, &needed, 0, 0) < 0)
-               quit("trace facility failure, KERN_KDGETBUF\n");
+               quit_args("trace facility failure, KERN_KDGETBUF: %s\n", strerror(errno));
 }
 
-void set_init()
+void set_init(void)
 {
         kd_regtype kr;
-    
+
         kr.type = KDBG_RANGETYPE;
         kr.value1 = 0;
         kr.value2 = -1;
@@ -428,8 +492,8 @@ void set_init()
         mib[4] = 0;
        mib[5] = 0;
         if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
-            quit("trace facility failure, KERN_KDSETREG (rangetype)\n");
-    
+            quit_args("trace facility failure, KERN_KDSETREG (rangetype): %s\n", strerror(errno));
+
         mib[0] = CTL_KERN;
         mib[1] = KERN_KDEBUG;
         mib[2] = KERN_KDSETUP;
@@ -437,32 +501,25 @@ void set_init()
         mib[4] = 0;
         mib[5] = 0;
         if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
-            quit("trace facility failure, KERN_KDSETUP\n");
+            quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno));
 }
 
-
-void set_class()
+static void
+set_filter(void)
 {
-        kd_regtype kr;
-    
-        kr.type = KDBG_CLASSTYPE;
-        kr.value1 = class;
-        kr.value2 = class2;
-        needed = sizeof(kd_regtype);
-        mib[0] = CTL_KERN;
-        mib[1] = KERN_KDEBUG;
-        mib[2] = KERN_KDSETREG;
-        mib[3] = 0;
-        mib[4] = 0;
-        mib[5] = 0;
-        if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
-            quit("trace facility failure, KERN_KDSETREG (classtype)\n");
+       errno = 0;
+       int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDSET_TYPEFILTER };
+       size_t needed = KDBG_TYPEFILTER_BITMAP_SIZE;
+
+       if(sysctl(mib, ARRAYSIZE(mib), type_filter_bitmap, &needed, NULL, 0)) {
+               quit_args("trace facility failure, KERN_KDSET_TYPEFILTER: %s\n", strerror(errno));
+       }
 }
 
-void set_kval_list()
+void set_kval_list(void)
 {
         kd_regtype kr;
-    
+
         kr.type = KDBG_VALCHECK;
         kr.value1 = value1;
         kr.value2 = value2;
@@ -476,25 +533,7 @@ void set_kval_list()
         mib[4] = 0;
         mib[5] = 0;
         if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
-            quit("trace facility failure, KERN_KDSETREG (valcheck)\n");
-}
-
-void set_subclass()
-{
-        kd_regtype kr;
-    
-        kr.type = KDBG_SUBCLSTYPE;
-        kr.value1 = class;
-        kr.value2 = subclass;
-        needed = sizeof(kd_regtype);
-        mib[0] = CTL_KERN;
-        mib[1] = KERN_KDEBUG;
-        mib[2] = KERN_KDSETREG;
-        mib[3] = 0;
-        mib[4] = 0;
-        mib[5] = 0;
-        if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
-            quit("trace facility failure, KERN_KDSETREG (subclstype)\n");
+            quit_args("trace facility failure, KERN_KDSETREG (valcheck): %s\n", strerror(errno));
 }
 
 
@@ -502,13 +541,13 @@ void readtrace(char *buffer)
 {
        mib[0] = CTL_KERN;
        mib[1] = KERN_KDEBUG;
-       mib[2] = KERN_KDREADTR;         
+       mib[2] = KERN_KDREADTR;
        mib[3] = 0;
        mib[4] = 0;
        mib[5] = 0;
 
        if (sysctl(mib, 3, buffer, &needed, NULL, 0) < 0)
-               quit("trace facility failure, KERN_KDREADTR\n");
+               quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno));
 }
 
 
@@ -537,8 +576,15 @@ int write_command_map(int fd)
        mib[4] = 0;
        mib[5] = 0;
 
-       if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
-               return 1;
+       if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0) {
+               if (errno == ENODATA) {
+                       if (verbose_flag) {
+                               printf("Cannot write thread map -- this is not fatal\n");
+                       }
+               } else {
+                       return 1;
+               }
+       }
 
        return 0;
 }
@@ -669,7 +715,7 @@ uint64_t consume_start_event(uintptr_t thread, int debugid, uint64_t now)
                        evp_prev = evp;
 
                        for (evp = evp->ev_next; evp; evp = evp->ev_next) {
-                               
+
                                if (evp->ev_thread == thread && evp->ev_debugid == debugid) {
                                        evp_prev->ev_next = evp->ev_next;
                                        break;
@@ -679,7 +725,7 @@ uint64_t consume_start_event(uintptr_t thread, int debugid, uint64_t now)
                }
                if (evp) {
                        elapsed = now - evp->ev_timestamp;
-                       
+
                        evp->ev_next = event_freelist;
                        event_freelist = evp;
                }
@@ -687,19 +733,21 @@ uint64_t consume_start_event(uintptr_t thread, int debugid, uint64_t now)
        return (elapsed);
 }
 
-
 void
-log_trace()
+log_trace(void)
 {
-        char           *buffer;
-       uint32_t        buffer_size;
-       int             fd;
-       int             size;
-       int             pad_size;
-       char            pad_buf[4096];
+       int fd = -1;
+       int ret = 0;
+       char *buffer;
+       uint32_t buffer_size = 1000000 * sizeof(kd_buf);
 
+       if (logfile[0] == '-' && logfile[1] == '\0') {
+               fd = STDOUT_FILENO;
+       } else {
+               fd = open(logfile, O_TRUNC | O_WRONLY | O_CREAT, 0777);
+       }
 
-       if ((fd = open(logfile, O_TRUNC|O_WRONLY|O_CREAT, 0777)) == -1) {
+       if (fd == -1) {
                perror("Can't open logfile");
                exit(1);
        }
@@ -717,64 +765,61 @@ log_trace()
                else
                        printf("Buffer has not wrapped\n");
        }
-       buffer_size = 1000000 * sizeof(kd_buf);
-       buffer = malloc(buffer_size);
 
-       if (buffer == (char *) 0)
-               quit("can't allocate memory for tracing info\n");
-
-       read_command_map(0, 0);
-
-       raw_header.version_no = RAW_VERSION1;
-       raw_header.thread_count = total_threads;
-       raw_header.TOD_secs = time((long *)0);
-       raw_header.TOD_usecs = 0;
-
-       write(fd, &raw_header, sizeof(RAW_header));
-
-       size = total_threads * sizeof(kd_threadmap);
-       write(fd, (char *)mapptr, size);
+       ret = write_command_map(fd);
+       if (ret) {
+               close(fd);
+               perror("failed to write logfile");
+               exit(1);
+       }
 
-       pad_size = 4096 - ((sizeof(RAW_header) + size) & 4095);
-       memset(pad_buf, 0, pad_size);
-                       
-       write(fd, pad_buf, pad_size);
+       buffer = malloc(buffer_size);
+       if (buffer == NULL) {
+               quit("can't allocate memory for events\n");
+       }
 
        for (;;) {
                needed = buffer_size;
 
                readtrace(buffer);
 
-               if (needed == 0)
+               if (needed == 0) {
                        break;
+               }
+
                write(fd, buffer, needed * sizeof(kd_buf));
        }
+
+       free(buffer);
+
        close(fd);
 }
 
+/*
+ * Why does this function exist?
+ * trace -L needs millisecond level wait times.
+ * When this code is running remotely, the mach_timebase_info_t data may
+ * be from a device with a different timebase. This code avoids using
+ * mach_absolute_time(), so that time calculations come out correct both
+ * locally and remotely.
+ */
+static uint64_t current_millis() {
+       struct timeval time;
+       gettimeofday(&time, NULL);
+       return (time.tv_sec * 1000) + (time.tv_usec / 1000);
+}
 
 void
-Log_trace()
+Log_trace(void)
 {
-       int     size;
-       kd_buf  kd_tmp;
        size_t  len;
-       int     num_cpus;
-       int     try_writetrace = 1;
+       int     num_cpus = 0;
        int     fd;
-        char           *buffer;
-        kd_buf         *kd;
-       uint64_t sample_window_abs;
-       uint64_t next_window_begins;
-       uint64_t current_abs;
-       uint64_t ending_abstime;
+       uint64_t current_ms;
+       uint64_t ending_ms = 0;
        uint64_t last_time_written;
-       uint32_t us_to_sleep;
-       uint32_t us_to_adjust;
        uint32_t ms_to_run;
 
-       memset(&kd_tmp, 0, sizeof(kd_tmp));
-
        if ((fd = open(logfile, O_TRUNC|O_WRONLY|O_CREAT, 0777)) == -1) {
                perror("Can't open logfile");
                exit(1);
@@ -797,123 +842,55 @@ Log_trace()
                set_numbufs(nbufs);
                set_init();
 
-               if (class_flag)
-                       set_class();
-
-               if (subclass_flag)
-                       set_subclass();
+               if (filter_flag)
+                       set_filter();
 
                if (kval_flag)
                        set_kval_list();
        }
-       /* Get kernel buffer information */
-       get_bufinfo(&bufinfo);
-
-       buffer = malloc(bufinfo.nkdbufs * sizeof(kd_buf));
-       if (buffer == (char *) 0)
-               quit("can't allocate memory for tracing info\n");
-       memset(buffer, 0, bufinfo.nkdbufs * sizeof(kd_buf));
 
        if (use_current_buf == 0)
                set_enable(1);
 
        if (write_command_map(fd)) {
-               int  pad_size;
-               char pad_buf[4096];
-
-               read_command_map(0, 0);
-
-               raw_header.version_no = RAW_VERSION1;
-               raw_header.thread_count = total_threads;
-               raw_header.TOD_secs = time((long *)0);
-               raw_header.TOD_usecs = 0;
-
-               write(fd, &raw_header, sizeof(RAW_header));
-
-               size = total_threads * sizeof(kd_threadmap);
-               write(fd, (char *)mapptr, size);
-
-               pad_size = 4096 - ((sizeof(RAW_header) + size) & 4095);
-               memset(pad_buf, 0, pad_size);
-                       
-               write(fd, pad_buf, pad_size);
+               quit("can't write tracefile header\n");
        }
-       sample_window_abs = (uint64_t)((double)US_TO_SLEEP * divisor);
 
-       next_window_begins = mach_absolute_time() + sample_window_abs;
+       last_time_written = current_millis();
 
        if (secs_to_run) {
-               ending_abstime = mach_absolute_time() + (uint64_t)((double)secs_to_run * (double)1000000 * divisor);
                ms_to_run = secs_to_run * 1000;
+               ending_ms = last_time_written + ms_to_run;
        } else
                ms_to_run = 0;
-       last_time_written = mach_absolute_time();
 
        while (LogRAW_flag) {
-               current_abs = mach_absolute_time();
-
-               if (try_writetrace) {
-                       needed = ms_to_run;
-                               
-                       if (writetrace(fd))
-                               try_writetrace = 0;
-                       else {
-                               if (needed) {
-                                       current_abs = mach_absolute_time();
+               needed = ms_to_run;
 
-                                       printf("wrote %d events - elapsed time = %.1f secs\n",
-                                              (int)needed, ((double)(current_abs - last_time_written) / divisor) / 1000000);
+               if (writetrace(fd)) {
+                       perror("KDWRITETR returned error");
 
-                                       last_time_written = current_abs;
-                               }
-                       }
+                       /* Clean up and exit in case of write fail */
+                       break;
                }
-               if (try_writetrace == 0) {
-
-                       if (next_window_begins > current_abs)
-                               us_to_adjust = US_TO_SLEEP - (uint32_t)((double)(next_window_begins - current_abs) / divisor);
-                       else
-                               us_to_adjust = US_TO_SLEEP;
-                       
-                       next_window_begins = current_abs + sample_window_abs;
-
-                       us_to_sleep = US_TO_SLEEP - us_to_adjust;
-
-                       next_window_begins = current_abs + (uint64_t)((double)(us_to_sleep + US_TO_SLEEP) * divisor);
-
-                       if (us_to_sleep)
-                               usleep(us_to_sleep);
-
-                       get_bufinfo(&bufinfo);
-
-                       if (bufinfo.flags & KDBG_WRAPPED)
-                               printf("lost events\n");
-
-                       needed = bufinfo.nkdbufs * sizeof(kd_buf);
-
-                       readtrace(buffer);
 
-                       if (bufinfo.flags & KDBG_WRAPPED) {
+               if (needed) {
+                       current_ms = current_millis();
 
-                               kd = (kd_buf *) buffer;
+                       printf("wrote %d events - elapsed time = %.1f secs\n",
+                              (int)needed, (double)(current_ms - last_time_written) / 1000.0);
 
-                               kd_tmp.timestamp = kd[0].timestamp;
-                               kd_tmp.debugid = TRACE_LOST_EVENTS;
-
-                               write(fd, &kd_tmp, sizeof(kd_tmp));
-                       }
-                       write(fd, buffer, needed * sizeof(kd_buf));
-
-                       if (verbose_flag && needed > nbufs)
-                               printf("needed = %ld\n", needed);
+                       last_time_written = current_ms;
                }
+
                if (secs_to_run) {
-                       current_abs = mach_absolute_time();
+                       current_ms = current_millis();
 
-                       if (current_abs > ending_abstime)
+                       if (current_ms > ending_ms)
                                break;
-                       ms_to_run = (ending_abstime - current_abs) / (1000 * 1000);
-                       
+
+                       ms_to_run = (uint32_t)(ending_ms - current_ms);
+
                        if (ms_to_run == 0)
                                break;
                }
@@ -926,13 +903,13 @@ Log_trace()
 }
 
 
-void read_trace()
+void read_trace(void)
 {
         char           *buffer;
        uint32_t        buffer_size;
         kd_buf         *kd;
        int             fd;
-       int             firsttime = 1;
+       int             firsttime = 1;
        int             lines = 0;
        int             io_lines = 0;
        uint64_t        bias = 0;
@@ -978,9 +955,37 @@ void read_trace()
                                perror("read failed");
                                exit(2);
                        }
+               } else if (raw_header.version_no == RAW_VERSION1) {
+#if defined(__ILP32__)
+                       /*
+                        * If the raw trace file was written by armv7k, the 64-bit alignment
+                        * of TOD_secs causes RAW_header to be 24 bytes. If we only read 20
+                        * bytes, the next 4 bytes might be a legitimate thread_id, but it might
+                        * also be 0 or a leaked kernel pointer from an armv7k trace file. For
+                        * both those cases, consume the 4 bytes and look for the thread map
+                        * after it.
+                        */
+                       if (sizeof(raw_header) == 20) {
+                               uint32_t alignment_garbage;
+
+                               if (read(fd, &alignment_garbage, sizeof(alignment_garbage)) != sizeof(alignment_garbage)) {
+                                       perror("read failed");
+                                       exit(2);
+                               }
+
+                               if ((alignment_garbage == 0) || (alignment_garbage >= 0x80000000)) {
+                                       if (verbose_flag) {
+                                               printf("Skipping 4 bytes to find valid thread map\n");
+                                       }
+                               } else {
+                                       /* oops, go back to where we were */
+                                       lseek(fd, -(off_t)sizeof(alignment_garbage), SEEK_CUR);
+                               }
+                       }
+#endif
                }
                count_of_names = raw_header.thread_count;
-               trace_time = raw_header.TOD_secs;
+               trace_time = (time_t) (raw_header.TOD_secs);
 
                printf("%s\n", ctime(&trace_time));
        }
@@ -990,20 +995,21 @@ void read_trace()
        if (buffer == (char *) 0)
                quit("can't allocate memory for tracing info\n");
 
-       kd = (kd_buf *)buffer;
+       kd = (kd_buf *)(uintptr_t)buffer;
 
        read_command_map(fd, count_of_names);
+       read_cpu_map(fd);
 
        for (;;) {
                uint32_t count;
                uint64_t now = 0;
                uint64_t prev;
-               uint64_t prevdelta;
-               uint32_t cpunum;
+               uint64_t prevdelta = 0;
+               uint32_t cpunum = 0;
                uintptr_t thread;
                double  x = 0.0;
                double  y = 0.0;
-               double  event_elapsed_time;
+               double  event_elapsed_time = 0;
                kd_buf *kdp;
                lookup_t  lkp;
                boolean_t ending_event;
@@ -1020,21 +1026,21 @@ void read_trace()
 
                        mib[0] = CTL_KERN;
                        mib[1] = KERN_KDEBUG;
-                       mib[2] = KERN_KDREADTR;         
+                       mib[2] = KERN_KDREADTR;
                        mib[3] = 0;
                        mib[4] = 0;
                        mib[5] = 0;
                        if (sysctl(mib, 3, buffer, &needed, NULL, 0) < 0)
-                               quit("trace facility failure, KERN_KDREADTR\n");
+                               quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno));
 
                        if (needed == 0)
                                break;
-                       count = needed;
+                       count = (uint32_t)needed;
 
                } else {
                        uint32_t bytes_read;
 
-                       bytes_read = read(fd, buffer, buffer_size);
+                       bytes_read = (uint32_t)read(fd, buffer, buffer_size);
 
                        if (bytes_read == -1) {
                                perror("read failed");
@@ -1051,12 +1057,35 @@ void read_trace()
                        debugid = kdp->debugid;
                        debugid_base = debugid & DBG_FUNC_MASK;
                        now = kdp->timestamp & KDBG_TIMESTAMP_MASK;
+                       cpunum = kdbg_get_cpu(kdp);
+
+                       /*
+                        * Is this event from an IOP? If so, there will be no
+                        * thread command, label it with the symbolic IOP name
+                        */
+                       if (cpumap && (cpunum < cpumap_header->cpu_count) && (cpumap[cpunum].flags & KDBG_CPUMAP_IS_IOP)) {
+                               command = cpumap[cpunum].name;
+                       } else {
+                               find_thread_command(kdp, &command);
+                       }
+
+                       /*
+                        * The internal use TRACE points clutter the output.
+                        * Print them only if in verbose mode.
+                        */
+                       if (!verbose_flag)
+                       {
+                               /* Is this entry of Class DBG_TRACE */
+                               if ((debugid >> 24) == DBG_TRACE) {
+                                       if (((debugid >> 16) & 0xff) != DBG_TRACE_INFO)
+                                               continue;
+                               }
+                       }
 
                        if (firsttime)
                                bias = now;
                        now -= bias;
 
-                       cpunum = kdbg_get_cpu(kdp); 
                        thread = kdp->arg5;
 
                        if (lines == 64 || firsttime)
@@ -1072,8 +1101,8 @@ void read_trace()
                                        fprintf(output_file, "\n\nNumber of microsecs since in last page %8.1f\n", x);
                                }
                                prevdelta = now;
-           
-                               /* 
+
+                               /*
                                 * Output description row to output file (make sure to format correctly for 32-bit and 64-bit)
                                 */
                                fprintf(output_file,
@@ -1083,9 +1112,9 @@ void read_trace()
                                        "   AbsTime(Us)      Delta            debugid                       arg1           arg2           arg3           arg4                thread   cpu#  command\n\n"
 #endif
                                        );
-           
+
                                lines = 0;
-                               
+
                                if (io_lines > 15000) {
                                        fcntl(output_fd, F_FLUSH_DATA, 0);
 
@@ -1100,6 +1129,7 @@ void read_trace()
                                if ( !lkp || !(debugid & DBG_FUNC_END))
                                        continue;
                        }
+
                        x = (double)now;
                        x /= divisor;
 
@@ -1110,23 +1140,9 @@ void read_trace()
                        last_event_time = x;
                        ending_event = FALSE;
 
-                       find_thread_command(kdp, &command);
-
-                       /*
-                        * The internal use TRACE points clutter the output.
-                        * Print them only if in verbose mode.
-                        */
-                       if (!verbose_flag)
-                       {
-                               /* Is this entry of Class DBG_TRACE */
-                               if ((debugid >> 24) == DBG_TRACE) {
-                                       if (((debugid >> 16) & 0xff) != DBG_TRACE_INFO)
-                                               continue;
-                               }
-                       }
                        if ( !lkp) {
                                int t_debugid;
-                               int t_thread;
+                               uintptr_t t_thread;
 
                                if ((debugid & DBG_FUNC_START) || debugid == MACH_MAKERUNNABLE) {
 
@@ -1141,7 +1157,7 @@ void read_trace()
                                        }
 
                                } else if ((debugid & DBG_FUNC_END) || debugid == MACH_STKHANDOFF || debugid == MACH_SCHEDULED) {
-                                       
+
                                        if (debugid == MACH_STKHANDOFF || debugid == MACH_SCHEDULED) {
                                                t_debugid = MACH_MAKERUNNABLE;
                                                t_thread = kdp->arg2;
@@ -1206,7 +1222,7 @@ void read_trace()
                                /*
                                 * print the tail end of the pathname
                                 */
-                               len = strlen(strptr);
+                               len = (int)strlen(strptr);
                                if (len > 51)
                                        len -= 51;
                                else
@@ -1218,6 +1234,12 @@ void read_trace()
                                fprintf(output_file, "%-8x   %-51s   %-8lx   %-2d  %s\n", (unsigned int)lkp->lk_dvp, &strptr[len], thread, cpunum, command);
 #endif
                                delete_lookup_event(thread, lkp);
+                       } else if (debugid == TRACE_INFO_STRING) {
+#ifdef __LP64__
+                               fprintf(output_file, "%-32s%-36s %-16lx  %-2d %s\n", (char *) &kdp->arg1, "", thread, cpunum, command);
+#else
+                               fprintf(output_file, "%-16s%-46s   %-8lx   %-2d  %s\n", (char *) &kdp->arg1, "", thread, cpunum, command);
+#endif
                        } else {
 #ifdef __LP64__
                                fprintf(output_file, "%-16lx %-16lx %-16lx %-16lx  %-16lx  %-2d %s\n", kdp->arg1, kdp->arg2, kdp->arg3, kdp->arg4, thread, cpunum, command);
@@ -1235,7 +1257,7 @@ void read_trace()
 
 
 
-void signal_handler(int sig) 
+void signal_handler(int sig)
 {
        ptrace(PT_KILL, pid, (caddr_t)0, 0);
        /*
@@ -1251,18 +1273,14 @@ void signal_handler_RAW(int sig)
 }
 
 
-
-int main(argc, argv, env)
-int argc;
-char **argv;
-char **env;
+int main (int argc, char* argv[], char *envp[])
 {
        extern char *optarg;
        extern int optind;
-       int status;
        int ch;
        int i;
        char *output_filename = NULL;
+       unsigned int parsed_arg;
 
        for (i = 1; i < argc; i++) {
                if (strcmp("-X", argv[i]) == 0) {
@@ -1288,12 +1306,12 @@ char **env;
        output_file = stdout;
        output_fd = 1;
 
-       while ((ch = getopt(argc, argv, "hedEk:irb:gc:p:s:tR:L:l:S:F:a:x:Xnfvo:P")) != EOF)
+       while ((ch = getopt(argc, argv, "hedEk:irb:gc:p:s:tR:L:l:S:F:a:x:Xnfvo:PT:N")) != EOF)
        {
                switch(ch)
                {
                case 'h': /* help */
-                       usage(LONG_HELP);
+                       usage_flag=1;
                        break;
                case 'S':
                        secs_to_run = argtoi('S', "decimal number", optarg, 10);
@@ -1332,13 +1350,13 @@ char **env;
                        break;
                case 'k':
                        if (kval_flag == 0)
-                               value1 = argtoul('k', "hex number", optarg, 16);
+                               value1 = (unsigned int) argtoul('k', "hex number", optarg, 16);
                        else if (kval_flag == 1)
-                               value2 = argtoul('k', "hex number", optarg, 16);
+                               value2 = (unsigned int) argtoul('k', "hex number", optarg, 16);
                        else if (kval_flag == 2)
-                               value3 = argtoul('k', "hex number", optarg, 16);
+                               value3 = (unsigned int) argtoul('k', "hex number", optarg, 16);
                        else if (kval_flag == 3)
-                               value4 = argtoul('k', "hex number", optarg, 16);
+                               value4 = (unsigned int) argtoul('k', "hex number", optarg, 16);
                        else
                        {
                                fprintf(stderr, "A maximum of four values can be specified with -k\n");
@@ -1370,20 +1388,28 @@ char **env;
                        nbufs = argtoi('b', "decimal number", optarg, 10);
                        break;
                case 'c':
-                       class_flag = 1;
-                       class = argtoi('c', "decimal number", optarg, 10);
-                       class2 = class+1;
+                       filter_flag = 1;
+                       parsed_arg = argtoi('c', "decimal, hex, or octal number", optarg, 0);
+                       if (parsed_arg > 0xFF)
+                               quit_args("argument '-c %s' parsed as %u, "
+                                         "class value must be 0-255\n", optarg, parsed_arg);
+                       saw_filter_class(parsed_arg);
                        break;
                case 's':
-                       subclass_flag = 1;
-                       subclass = argtoi('s', "decimal number", optarg, 10);
+                       filter_flag = 1;
+                       parsed_arg = argtoi('s', "decimal, hex, or octal number", optarg, 0);
+                       if (parsed_arg > 0xFF)
+                               quit_args("argument '-s %s' parsed as %u, "
+                                         "subclass value must be 0-255\n", optarg, parsed_arg);
+                       saw_filter_subclass(parsed_arg);
                        break;
                case 'p':
-                       if (class_flag != 1)
-                       {       fprintf(stderr, "-p must follow -c\n");
-                               exit(1);
-                       }
-                       class2 = argtoi('p', "decimal number", optarg, 10);
+                       filter_flag = 1;
+                       parsed_arg = argtoi('p', "decimal, hex, or octal number", optarg, 0);
+                       if (parsed_arg > 0xFF)
+                               quit_args("argument '-p %s' parsed as %u, "
+                                         "end range value must be 0-255\n", optarg, parsed_arg);
+                       saw_filter_end_range(parsed_arg);
                        break;
                case 'P':
                        ppt_flag = 1;
@@ -1396,61 +1422,79 @@ char **env;
                        break;
                case 'X':
                        break;
+               case 'N':
+                       no_default_codes_flag = 1;
+                       break;
+               case 'T':
+                       filter_flag = 1;
+
+                       // Flush out any unclosed -c argument
+                       filter_done_parsing();
+
+                       parse_filter_file(optarg);
+                       break;
                default:
                        usage(SHORT_HELP);
                }
        }
        argc -= optind;
 
+       if (!no_default_codes_flag)
+       {
+               if (verbose_flag)
+                       printf("Adding default code file /usr/share/misc/trace.codes. Use '-N' to skip this.\n");
+               parse_codefile("/usr/share/misc/trace.codes");
+       }
+
        if (argc)
        {
                if (!execute_flag)
                {
-                       cfile = argv[optind];
-                       if (verbose_flag)
-                               printf("Code file is %s \n", cfile);
-                       if (parse_codefile(cfile) == -1)
-                               cfile = (char *)0;
+                       while (argc--)
+                       {
+                               const char *cfile = argv[optind++];
+                               if (verbose_flag) printf("Adding code file %s \n", cfile);
+                               parse_codefile(cfile);
+                       }
                }
        }
        else
        {
                if (execute_flag)
-               {
-                       printf("-E flag needs an executable to launch\n");
-                       exit(1);
-               }
+                       quit_args("-E flag needs an executable to launch\n");
        }
+
+       if (usage_flag)
+               usage(LONG_HELP);
+
        getdivisor();
 
        if (pid_flag && pid_exflag)
-       {
-               fprintf(stderr, "Can't use both -a and -x flag together\n");
-               exit(1);
-       }
-
-       if (subclass_flag && !class_flag) {
-               fprintf(stderr,"Must define a class ('c') with the subclass ('s') option\n");
-               usage(SHORT_HELP);
-       }
+               quit_args("Can't use both -a and -x flag together\n");
 
-       if (kval_flag && (subclass_flag || class_flag))
-       {
-               fprintf(stderr,"Don't use class or subclass with the 'k' code options.\n");
-               usage(SHORT_HELP);
-       }
+       if (kval_flag && filter_flag)
+               quit_args("Cannot use -k flag with -c, -s, or -p\n");
 
        if (output_filename && !trace_flag && !readRAW_flag)
-       {
-               fprintf(stderr, "When using 'o' option, must use the 't' or 'R' option too\n");
-               usage(SHORT_HELP);
-       }
+               quit_args("When using 'o' option, must use the 't' or 'R' option too\n");
+
+       filter_done_parsing();
+
+       done_with_args = 1;
 
        if (LogRAW_flag) {
                get_bufinfo(&bufinfo);
+               int ktrace_state = get_ktrace_state();
 
-               if (bufinfo.nolog == 0)
+               /*
+                * Only use the current kdebug configuration when foreground
+                * tracing is enabled.  Both checks are necessary because the
+                * background tool might have enabled tracing, but as soon as we
+                * try to write a header, that configuration is removed for us.
+                */
+               if ((ktrace_state == 1) && (bufinfo.nolog == 0)) {
                        use_current_buf = 1;
+               }
        }
 
        if (disable_flag)
@@ -1458,23 +1502,23 @@ char **env;
                if (pid_flag)
                {
                        set_pidcheck(pid, 0);   /* disable pid check for given pid */
-                       exit(1);
+                       exit(0);
                }
                else if (pid_exflag)
                {
                        set_pidexclude(pid, 0);  /* disable pid exclusion for given pid */
-                       exit(1);
+                       exit(0);
                }
                set_enable(0);
-               exit(1);
+               exit(0);
        }
 
        if (remove_flag)
        {
                set_remove();
-               exit(1);
+               exit(0);
        }
-    
+
        if (bufset_flag )
        {
                if (!init_flag && !LogRAW_flag)
@@ -1484,15 +1528,50 @@ char **env;
                }
                set_numbufs(nbufs);
        }
-    
+
        if (nowrap_flag)
                set_nowrap();
 
        if (freerun_flag)
                set_freerun();
+
        if (bufget_flag)
        {
+               printf("The kernel tracing settings are:\n");
+
+               /* determine the state of ktrace */
+               int state = get_ktrace_state();
+
+               /* get the name of the last process to configure ktrace */
+               char execname[20] = { 0 };
+               size_t execname_size = sizeof(execname);
+               int err = sysctlbyname("ktrace.configured_by", &execname, &execname_size, NULL, 0);
+               if (err) {
+                       fprintf(stderr, "error: could not query ktrace.configured_by sysctl (%d: %s)\n", errno, strerror(errno));
+                       exit(1);
+               }
+
+               printf("\tTracing is ");
+               switch (state) {
+               case 0:
+                       printf("off");
+                       break;
+               case 1:
+                       printf("active (foreground)");
+                       break;
+               case 2:
+                       printf("active (background)");
+                       break;
+               default:
+                       printf("in an invalid state");
+                       break;
+               }
+               printf("\n");
+
+               printf("\tLast configured by \"%s\"\n", execname[0] == '\0' ? "<unknown>" : execname);
+
+               /* get kdebug info */
+
                get_bufinfo(&bufinfo);
 
                printf("The kernel buffer settings are:\n");
@@ -1533,9 +1612,14 @@ char **env;
 
                if (bufinfo.flags & KDBG_VALCHECK)
                        printf("\tCollecting specific code values is enabled\n");
-               else    
+               else
                        printf("\tCollecting specific code values is disabled\n");
-               
+
+               if (bufinfo.flags & KDBG_TYPEFILTER_CHECK)
+                       printf("\tCollection based on a filter is enabled\n");
+               else
+                       printf("\tCollection based on a filter is disabled\n");
+
                if (bufinfo.flags & KDBG_PIDCHECK)
                        printf("\tCollection based on pid is enabled\n");
                else
@@ -1550,16 +1634,57 @@ char **env;
                        printf("\tKernel buffer is not controlled by any process.\n");
                else
                        printf("\tKernel buffer is controlled by proc id [%d]\n", bufinfo.bufid);
+
+
+               if (bufinfo.flags & KDBG_TYPEFILTER_CHECK) {
+                       if (verbose_flag) {
+                               bool (^should_print)(uint8_t*) = ^bool(uint8_t* ptr) {
+                                       for (uint32_t i=0; i<32; ++i) {
+                                               if (ptr[i] > 0) return true;
+                                       }
+
+                                       return false;
+                               };
+
+                               uint8_t* typefilter = (uint8_t*)kdebug_typefilter();
+                               if (typefilter) {
+                                       bool header = false;
+
+                                       // Reduce noise, only print lines that are allowing events.
+                                       for (uint32_t tclass = 0; tclass < 0x100; ++tclass) {
+                                               uint8_t* base = &typefilter[tclass * 32];
+                                               if (should_print(base)) {
+                                                       if (!header) {
+                                                               header = true;
+                                                               printf("\tTypefilter:\n");
+                                                               printf("%18s  ","");
+                                                               for (uint32_t tsubclass=0; tsubclass<32; ++tsubclass) {
+                                                                       printf("%02x ", tsubclass * 8);
+                                                               }
+                                                               printf("\n");
+                                                               printf("%18s  ","");
+                                                               for (uint32_t tsubclass=0; tsubclass<32; ++tsubclass) {
+                                                                       printf("---");
+                                                               }
+                                                               printf("\n");
+                                                       }
+                                                       printf("%16s%02x: ", "", tclass);
+                                                       for (uint32_t tsubclass=0; tsubclass<32; ++tsubclass) {
+                                                               printf("%02X ", typefilter[(tclass * 32) + tsubclass]);
+                                                       }
+                                                       printf("\n");
+                                               }
+                                       }
+                               }
+                       }
+               }
        }
 
        if (init_flag)
                set_init();
 
-       if (class_flag)
-               set_class();
-
-       if (subclass_flag)
-               set_subclass();
+       if (filter_flag)
+               set_filter();
 
        if (kval_flag)
                set_kval_list();
@@ -1570,26 +1695,8 @@ char **env;
                fflush(stdout);
                fflush(stderr);
 
-               switch ((pid = vfork()))
-               {
-               case -1:
-                       perror("vfork: ");
-                       exit(1);
-               case 0: /* child */
-                       setsid();
-                       ptrace(PT_TRACE_ME, 0, (caddr_t)0, 0);
-                       execve(argv[optind], &argv[optind], environ);
-                       perror("execve:");
-                       exit(1);
-               }
-               sleep(1);
+               execute_process(&(argv[optind]));
 
-               signal(SIGINT, signal_handler);
-               set_pidcheck(pid, 1);
-               set_enable(1);
-               ptrace(PT_CONTINUE, pid, (caddr_t)1, 0);
-               waitpid(pid, &status, 0);
-               /* child is gone; no need to disable the pid */
                exit(0);
        }
        else if (enable_flag)
@@ -1610,7 +1717,7 @@ char **env;
                        usage(SHORT_HELP);
                }
                setbuffer(output_file, &sbuffer[0], SBUFFER_SIZE);
-       
+
                if (fcntl(output_fd, F_NOCACHE, 1) < 0)
                {
                        /* Not fatal */
@@ -1631,6 +1738,75 @@ char **env;
 
 } /* end main */
 
+static void
+execute_process(char * const argv[])
+{
+       int status = 0;
+       int rc = 0;
+       posix_spawnattr_t spawn_attrs;
+
+       assert(argv);
+
+       /* ensure that the process being spawned starts suspended */
+       rc = posix_spawnattr_init(&spawn_attrs);
+       if (rc != 0) {
+               quit_args("Failed to initialize spawn attrs: %s\n", strerror(rc));
+       }
+       rc = posix_spawnattr_setflags(&spawn_attrs,
+                                     POSIX_SPAWN_START_SUSPENDED);
+       if (rc != 0) {
+               quit_args("Unable to start process suspended: %s\n", strerror(rc));
+       }
+
+       /* spawn the process with the rest of the arguments */
+       rc = posix_spawnp(&pid, argv[0], NULL, &spawn_attrs, argv, environ);
+       if (rc != 0) {
+               quit_args("Unabled to start process: %s\n", strerror(rc));
+       }
+
+       signal(SIGINT, signal_handler);
+       set_pidcheck(pid, 1);
+       set_enable(1);
+
+       /* start the child process */
+       rc = kill(pid, SIGCONT);
+       if (rc != 0) {
+               perror("Failed to continue child process:");
+               exit(EX_OSERR);
+       }
+
+       rc = waitpid(pid, &status, 0);
+       if (rc == -1) {
+               perror("Failed to wait for process: ");
+       }
+}
+
+static void
+quit_args(const char *fmt, ...)
+{
+       char buffer[1024];
+
+       if (reenable == 1)
+       {
+               reenable = 0;
+               set_enable(1);  /* re-enable kernel logging */
+       }
+
+       va_list args;
+
+       va_start (args, fmt);
+       vsnprintf(buffer, sizeof(buffer), fmt, args);
+
+       fprintf(stderr, "trace error: %s", buffer);
+
+       va_end(args);
+
+       if (!done_with_args)
+               usage(SHORT_HELP);
+
+       exit(1);
+}
+
 
 void
 quit(char *s)
@@ -1643,7 +1819,7 @@ quit(char *s)
 
        printf("trace: ");
        if (s)
-               printf("%s ", s);
+               printf("%s", s);
        exit(1);
 }
 
@@ -1653,7 +1829,7 @@ usage(int short_help)
 
        if (short_help)
        {
-               (void)fprintf(stderr, "  usage: trace -h\n");
+               (void)fprintf(stderr, "  usage: trace -h [-v]\n");
                (void)fprintf(stderr, "  usage: trace -i [-b numbufs]\n");
                (void)fprintf(stderr, "  usage: trace -g\n");
                (void)fprintf(stderr, "  usage: trace -d [-a pid | -x pid ]\n");
@@ -1661,14 +1837,16 @@ usage(int short_help)
                (void)fprintf(stderr, "  usage: trace -n\n");
 
                (void)fprintf(stderr,
-                             "  usage: trace -e [ -c class [-p class] [-s subclass] ] [-a pid | -x pid] |\n");
+                             "  usage: trace -e [ -c class [[-s subclass]... | -p class ]]... | \n");
                (void)fprintf(stderr,
-                             "                  [-k code | -k code | -k code | -k code] [-P] \n\n");
+                             "                  [-k code | -k code | -k code | -k code] [-P] [-T tracefilter] \n");
+               (void)fprintf(stderr,
+                             "                  [-a pid | -x pid] \n\n");
 
                (void)fprintf(stderr,
-                             "  usage: trace -E [ -c class [-p class] [-s subclass] ] |\n");
+                             "  usage: trace -E [ -c class [[-s subclass]... | -p class ]]... | \n");
                (void)fprintf(stderr,
-                             "                  [-k code | -k code | -k code | -k code] [-P]\n");
+                             "                  [-k code | -k code | -k code | -k code] [-P] [-T tracefilter] \n");
                (void)fprintf(stderr,
                              "                  executable_path [optional args to executable] \n\n");
 
@@ -1677,16 +1855,19 @@ usage(int short_help)
                (void)fprintf(stderr,
                              "  usage: trace -l RawFilename\n");
                (void)fprintf(stderr,
-                             "  usage: trace -R RawFilename [-X] [-F frequency] [-o OutputFilename] [CodeFilename]\n");
+                             "  usage: trace -R RawFilename [-X] [-F frequency] [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...]\n");
+               (void)fprintf(stderr,
+                             "  usage: trace -t [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...]\n");
                (void)fprintf(stderr,
-                             "  usage: trace -t [-o OutputFilename] [CodeFilename]\n");
+                                 "  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");
                exit(1);
        }
 
 
-       /* Only get here of printing long usage list */
-       (void)fprintf(stderr, "usage: trace -h\n");
+       /* Only get here if printing long usage info */
+       (void)fprintf(stderr, "usage: trace -h [-v]\n");
        (void)fprintf(stderr, "\tPrint this long command help.\n\n");
+       (void)fprintf(stderr, "\t -v Print extra information about tracefilter and code files.\n\n");
 
        (void)fprintf(stderr, "usage: trace -i [-b numbufs]\n");
        (void)fprintf(stderr, "\tInitialize the kernel trace buffer.\n\n");
@@ -1709,62 +1890,120 @@ usage(int short_help)
        (void)fprintf(stderr, "\tDisables kernel buffer wrap around.\n\n");
 
        (void)fprintf(stderr,
-                     "usage: trace -e [ -c class [-p class] [-s subclass] ] [-a pid | -x pid] |\n");
+                     "usage: trace -e [ -c class [[-s subclass]... | -p class ]]...  |\n");
        (void)fprintf(stderr,
-                     "             [-k code | -k code | -k code | -k code] \n\n");
-       (void)fprintf(stderr, "\tEnable/start collection of kernel trace elements.\n");
-       (void)fprintf(stderr, "\tEnter values in decimal notation unless otherwise noted..\n\n");
-       (void)fprintf(stderr, "\t -c class    Restrict trace collection to given class.\n\n");
-       (void)fprintf(stderr, "\t -p class    Restrict trace collection to given class range.\n");
-       (void)fprintf(stderr, "\t             Must provide class with -c first.\n\n");
-       (void)fprintf(stderr, "\t -s subclass    Restrict trace collection to given subclass.\n");
-       (void)fprintf(stderr, "\t                Must provide class with -c.\n\n");
+                     "             [-k code | -k code | -k code | -k code] [-P] [-T tracefilter]\n");
+       (void) fprintf(stderr,
+                     "             [-a pid | -x pid]\n\n");
+       (void)fprintf(stderr, "\t Enable/start collection of kernel trace elements. \n\n");
+       (void)fprintf(stderr, "\t By default, trace collects all tracepoints. \n");
+       (void)fprintf(stderr, "\t The following arguments may be used to restrict collection \n");
+       (void)fprintf(stderr, "\t to a limited set of tracepoints. \n\n");
+       (void)fprintf(stderr, "\t Multiple classes can be specified by repeating -c. \n");
+       (void)fprintf(stderr, "\t Multiple subclasses can be specified by repeating -s after -c. \n");
+       (void)fprintf(stderr, "\t Classes, subclasses, and class ranges can be entered \n");
+       (void)fprintf(stderr, "\t in hex (0xXX), decimal (XX), or octal (0XX). \n\n");
+       (void)fprintf(stderr, "\t -c class    Restrict trace collection to given class. \n\n");
+       (void)fprintf(stderr, "\t -p class    Restrict trace collection to given class range. \n");
+       (void)fprintf(stderr, "\t             Must provide class with -c first. \n\n");
+       (void)fprintf(stderr, "\t -s subclass    Restrict trace collection to given subclass. \n");
+       (void)fprintf(stderr, "\t                Must provide class with -c first. \n\n");
        (void)fprintf(stderr, "\t -a pid     Restrict trace collection to the given process.\n\n");
        (void)fprintf(stderr, "\t -x pid     Exclude the given process from trace collection.\n\n");
        (void)fprintf(stderr, "\t -k code    Restrict trace collection up to four specific codes.\n");
-       (void)fprintf(stderr, "\t            Enter codes in hex values.\n\n");
+       (void)fprintf(stderr, "\t            Enter codes in hex (0xXXXXXXXX). \n\n");
        (void)fprintf(stderr, "\t -P         Enable restricted PPT trace points only.\n\n");
+       (void)fprintf(stderr, "\t -T tracefilter     Read class and subclass restrictions from a \n");
+       (void)fprintf(stderr, "\t                    tracefilter description file. \n");
+       (void)fprintf(stderr, "\t                    Run trace -h -v for more info on this file. \n\n");
 
        (void)fprintf(stderr,
-                     "usage: trace -E [ -c class [-p class] [-s subclass] ] |\n");
+                     "usage: trace -E [ -c class [[-s subclass]... | -p class ]]... |\n");
        (void)fprintf(stderr,
-                     "             [-k code | -k code | -k code | -k code] \n");
+                     "             [-k code | -k code | -k code | -k code] [-P] [-T tracefilter]\n");
        (void)fprintf(stderr,
                      "             executable_path [optional args to executable] \n\n");
        (void)fprintf(stderr, "\tLaunch the given executable and enable/start\n");
        (void)fprintf(stderr, "\tcollection of kernel trace elements for that process.\n");
        (void)fprintf(stderr, "\tSee -e(enable) flag for option descriptions.\n\n");
 
-       (void)fprintf(stderr,
-                     "usage: trace -t [-o OutputFilename] [CodeFilename] \n");
+    (void)fprintf(stderr, "usage: trace -t [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...] \n");
        (void)fprintf(stderr, "\tCollect the kernel buffer trace data and print it.\n\n");
+       (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");
        (void)fprintf(stderr, "\t -o OutputFilename  Print trace output to OutputFilename. Default is stdout.\n\n");
 
        (void)fprintf(stderr,
-                     "usage: trace -R RawFilename [-X] [-F frequency] [-o OutputFilename] [CodeFilename] \n");
+                     "usage: trace -R RawFilename [-X] [-F frequency] [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...] \n");
        (void)fprintf(stderr, "\tRead raw trace file and print it.\n\n");
-       (void)fprintf(stderr, "\t -X                 Force trace to interpret trace data as 32 bit.  Default is to match the current systems bit width.\n");
-       (void)fprintf(stderr, "\t -F frequency       Specify the frequency of the clock used to timestamp entries in RawFilename\n");
+       (void)fprintf(stderr, "\t -X                 Force trace to interpret trace data as 32 bit. \n");
+       (void)fprintf(stderr, "\t                          Default is to match the bit width of the current system. \n");
+       (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");
+       (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");
        (void)fprintf(stderr, "\t -o OutputFilename  Print trace output to OutputFilename. Default is stdout.\n\n");
 
        (void)fprintf(stderr,
                      "usage: trace -L RawFilename [-S SecsToRun]\n");
-       (void)fprintf(stderr, "\tContinuously collect the kernel buffer trace data in the raw format and write it to RawFilename.\n\n");
+       (void)fprintf(stderr, "\tContinuously collect the kernel buffer trace data in the raw format \n");
+       (void)fprintf(stderr, "\tand write it to RawFilename. \n");
+
+       (void)fprintf(stderr, "\t-L implies -r -i if tracing isn't currently enabled.\n");
+       (void)fprintf(stderr, "\tOptions passed to -e(enable) are also accepted by -L. (except -a -x -P)\n\n");
        (void)fprintf(stderr, "\t -S SecsToRun       Specify the number of seconds to collect trace data.\n\n");
 
        (void)fprintf(stderr,
                      "usage: trace -l RawFilename\n");
        (void)fprintf(stderr, "\tCollect the existing kernel buffer trace data in the raw format.\n\n");
 
+       if (verbose_flag) {
+               (void)fprintf(stderr,
+                             "Code file: \n"
+                             "\t A code file consists of a list of tracepoints, one per line, \n"
+                             "\t with one tracepoint code in hex, followed by a tab, \n"
+                             "\t followed by the tracepoint's name. \n\n"
+
+                             "\t Example tracepoint: \n"
+                             "\t 0x010c007c\tMSC_mach_msg_trap \n"
+                             "\t This describes the tracepoint with the following info: \n"
+                             "\t Name:          MSC_mach_msg_trap \n"
+                             "\t Class:         0x01   (Mach events) \n"
+                             "\t Subclass:      0x0c   (Mach system calls) \n"
+                             "\t Code:          0x007c (Mach syscall number 31) \n\n"
+
+                             "\t See /usr/include/sys/kdebug.h for the currently defined \n"
+                             "\t class and subclass values. \n"
+                             "\t See /usr/share/misc/trace.codes for the currently allocated \n"
+                             "\t system tracepoints in trace code file format. \n"
+                             "\t This codefile is useful with the -R argument to trace. \n"
+                             "\n");
+
+               (void)fprintf(stderr,
+                             "Tracefilter description file: \n"
+                             "\t A tracefilter description file consists of a list of \n"
+                             "\t class and subclass filters in hex, one per line,  \n"
+                             "\t which are applied as if they were passed with -c and -s. \n"
+                             "\t Pass -v to see what classes and subclasses are being set. \n\n"
+
+                             "\t File syntax: \n"
+                             "\t  Class filter: \n"
+                             "\t  C 0xXX \n"
+                             "\t  Subclass filter (includes class): \n"
+                             "\t  S 0xXXXX \n"
+                             "\t  Comment: \n"
+                             "\t  # This is a comment \n\n"
+
+                             "\t For example, to trace Mach events (class 1):\n"
+                             "\t C 0x01 \n"
+                             "\t or to trace Mach system calls (class 1 subclass 13): \n"
+                             "\t S 0x010C \n"
+                             "\n");
+       }
+
        exit(1);
 }
 
 
 static int
-argtoi(flag, req, str, base)
-int flag;
-char *req, *str;
-int base;
+argtoi(int flag, char *req, char *str, int base)
 {
        char *cp;
        int ret;
@@ -1775,12 +2014,8 @@ int base;
        return (ret);
 }
 
-
 static unsigned long
-argtoul(flag, req, str, base)
-int flag;
-char *req, *str;
-int base;
+argtoul(int flag, char *req, char *str, int base)
 {
        char *cp;
        unsigned long ret;
@@ -1791,31 +2026,302 @@ int base;
        return (ret);
 }
 
-
 /*
  * comparison function for qsort
  * sort by debugid
  */
-int debugid_compar(p1, p2)
-       code_type_t *p1;
-       code_type_t *p2;
+int
+debugid_compar(const void *p1, const void *p2)
 {
-       if (p1->debugid > p2->debugid)
-               return(1);
-       else if (p1->debugid == p2->debugid)
-               return(0);
+       const code_type_t *q1 = (const code_type_t *)p1;
+       const code_type_t *q2 = (const code_type_t *)p2;
+
+       if (q1->debugid > q2->debugid)
+               return (1);
+       else if (q1->debugid == q2->debugid)
+               return (0);
        else
-               return(-1);
+               return (-1);
+}
+
+/*
+ * Filter args parsing state machine:
+ *
+ * Allowed args:
+ * -c -p
+ * -c -s (-s)*
+ * -c (-c)*
+ * every -c goes back to start
+ *
+ * Valid transitions:
+ * start -> class (first -c)
+ * class -> range (-c -p)
+ * class -> sub   (-c -s)
+ * class -> class (-c -c)
+ * range -> class (-c -p -c)
+ * sub   -> class (-c -s -c)
+ * *     -> start (on filter_done_parsing)
+ *
+ * Need to call filter_done_parsing after
+ * calling saw_filter_*
+ * to flush out any class flag waiting to see if
+ * there is a -s flag coming up
+ */
+
+
+// What type of flag did I last see?
+enum {
+       FILTER_MODE_START,
+       FILTER_MODE_CLASS,
+       FILTER_MODE_CLASS_RANGE,
+       FILTER_MODE_SUBCLASS
+} filter_mode = FILTER_MODE_START;
+
+uint8_t filter_current_class        = 0;
+uint8_t filter_current_subclass     = 0;
+uint8_t filter_current_class_range  = 0;
+
+static void
+saw_filter_class(uint8_t class)
+{
+       switch(filter_mode) {
+       case FILTER_MODE_START:
+       case FILTER_MODE_CLASS_RANGE:
+       case FILTER_MODE_SUBCLASS:
+               filter_mode = FILTER_MODE_CLASS;
+               filter_current_class       = class;
+               filter_current_subclass    = 0;
+               filter_current_class_range = 0;
+               // the case of a lone -c is taken care of
+               // by filter_done_parsing
+               break;
+       case FILTER_MODE_CLASS:
+               filter_mode = FILTER_MODE_CLASS;
+               // set old class, remember new one 
+               set_filter_class(filter_current_class);
+               filter_current_class       = class;
+               filter_current_subclass    = 0;
+               filter_current_class_range = 0;
+               break;
+       default:
+               quit_args("invalid case in saw_filter_class\n");
+       }
+}
+
+static void
+saw_filter_end_range(uint8_t end_class)
+{
+       switch(filter_mode) {
+       case FILTER_MODE_CLASS:
+               filter_mode = FILTER_MODE_CLASS_RANGE;
+               filter_current_class_range = end_class;
+               set_filter_range(filter_current_class, filter_current_class_range);
+               break;
+       case FILTER_MODE_START:
+               quit_args("must provide '-c class' before '-p 0x%x'\n",
+                         end_class);
+       case FILTER_MODE_CLASS_RANGE:
+               quit_args("extra range end '-p 0x%x'"
+                         " for class '-c 0x%x'\n",
+                         end_class, filter_current_class);
+       case FILTER_MODE_SUBCLASS:
+               quit_args("cannot provide both range end '-p 0x%x'"
+                         " and subclass '-s 0x%x'"
+                         " for class '-c 0x%x'\n",
+                         end_class, filter_current_subclass,
+                         filter_current_class);
+       default:
+               quit_args("invalid case in saw_filter_end_range\n");
+       }
+}
+
+static void
+saw_filter_subclass(uint8_t subclass)
+{
+       switch(filter_mode) {
+       case FILTER_MODE_CLASS:
+       case FILTER_MODE_SUBCLASS:
+               filter_mode = FILTER_MODE_SUBCLASS;
+               filter_current_subclass = subclass;
+               set_filter_subclass(filter_current_class, filter_current_subclass);
+               break;
+       case FILTER_MODE_START:
+               quit_args("must provide '-c class'"
+                         " before subclass '-s 0x%x'\n", subclass);
+       case FILTER_MODE_CLASS_RANGE:
+               quit_args("cannot provide both range end '-p 0x%x'"
+                         " and subclass '-s 0x%x'"
+                         " for the same class '-c 0x%x'\n",
+                         filter_current_class_range,
+                         subclass, filter_current_class);
+       default:
+               quit_args("invalid case in saw_filter_subclass\n");
+       }
+}
+
+static void
+filter_done_parsing(void)
+{
+       switch(filter_mode) {
+       case FILTER_MODE_CLASS:
+               // flush out the current class
+               set_filter_class(filter_current_class);
+               filter_mode = FILTER_MODE_START;
+               filter_current_class       = 0;
+               filter_current_subclass    = 0;
+               filter_current_class_range = 0;
+               break;
+       case FILTER_MODE_SUBCLASS:
+       case FILTER_MODE_START:
+       case FILTER_MODE_CLASS_RANGE:
+               filter_mode = FILTER_MODE_START;
+               filter_current_class       = 0;
+               filter_current_subclass    = 0;
+               filter_current_class_range = 0;
+               break;
+       default:
+               quit_args("invalid case in filter_done_parsing\n");
+       }
+}
+
+/* Tell set_filter_subclass not to print every. single. subclass. */
+static boolean_t setting_class = FALSE;
+static boolean_t setting_range = FALSE;
+
+static void
+set_filter_subclass(uint8_t class, uint8_t subclass)
+{
+       if (!filter_alloced) {
+               type_filter_bitmap = (uint8_t *) calloc(1, KDBG_TYPEFILTER_BITMAP_SIZE);
+               if (type_filter_bitmap == NULL)
+                       quit_args("Could not allocate type_filter_bitmap.\n");
+               filter_alloced = 1;
+       }
+
+       uint16_t csc = ENCODE_CSC_LOW(class, subclass);
+
+       if (verbose_flag && !setting_class)
+               printf("tracing subclass: 0x%4.4x\n", csc);
+
+       if (verbose_flag && isset(type_filter_bitmap, csc))
+               printf("class %u (0x%2.2x), subclass %u (0x%2.2x) set twice.\n",
+                      class, class, subclass, subclass);
+
+       setbit(type_filter_bitmap, csc);
 }
 
+static void
+set_filter_class(uint8_t class)
+{
+       if (verbose_flag && !setting_range)
+               printf("tracing class:    0x%2.2x\n", class);
+
+       setting_class = TRUE;
+
+       for (int i = 0; i < 256; i++)
+               set_filter_subclass(class, i);
+
+       setting_class = FALSE;
+}
+
+static void
+set_filter_range(uint8_t class, uint8_t end)
+{
+       if (verbose_flag)
+               printf("tracing range:    0x%2.2x - 0x%2.2x\n", class, end);
+
+       setting_range = TRUE;
+
+       for (int i = class; i <= end; i++)
+               set_filter_class(i);
+
+       setting_range = FALSE;
+}
+
+/*
+ * Syntax of filter file:
+ * Hexadecimal numbers only
+ * Class:
+ * C 0xXX
+ * Subclass (includes class):
+ * S 0xXXXX
+ * Comment:
+ * # <string>
+ * TBD: Class ranges?
+ * TBD: K for -k flag?
+ */
+
+static void
+parse_filter_file(char *filename)
+{
+       FILE* file;
+       uint32_t current_line = 0;
+       uint32_t parsed_arg   = 0;
+       int rval;
+
+       char line[256];
+
+       if ( (file = fopen(filename, "r")) == NULL ) {
+               quit_args("Failed to open filter description file %s: %s\n",
+                         filename, strerror(errno));
+       }
+
+       if (verbose_flag)
+               printf("Parsing typefilter file: %s\n", filename);
+
+       while( fgets(line, sizeof(line), file) != NULL ) {
+               current_line++;
+
+               switch (line[0]) {
+               case 'C':
+                       rval = sscanf(line, "C 0x%x\n", &parsed_arg);
+                       if (rval != 1)
+                               quit_args("invalid line %d of file %s: %s\n",
+                                        current_line, filename, line);
+                       if (parsed_arg > 0xFF)
+                               quit_args("line %d of file %s: %s\n"
+                                         "parsed as 0x%x, "
+                                         "class value must be 0x0-0xFF\n",
+                                         current_line, filename, line, parsed_arg);
+                       set_filter_class((uint8_t)parsed_arg);
+                       break;
+               case 'S':
+                       rval = sscanf(line, "S 0x%x\n", &parsed_arg);
+                       if (rval != 1)
+                               quit_args("invalid line %d of file %s: %s\n",
+                                         current_line, filename, line);
+                       if (parsed_arg > 0xFFFF)
+                               quit_args("line %d of file %s: %s\n"
+                                         "parsed as 0x%x, "
+                                         "value must be 0x0-0xFFFF\n",
+                                         current_line, filename, line, parsed_arg);
+                       set_filter_subclass(EXTRACT_CLASS_LOW(parsed_arg),
+                                           EXTRACT_SUBCLASS_LOW(parsed_arg));
+                       break;
+               case '#':
+                       // comment
+                       break;
+               case '\n':
+                       // empty line
+                       break;
+               case '\0':
+                       // end of file
+                       break;
+               default:
+                       quit_args("Invalid filter description file: %s\n"
+                                 "could not parse line %d: %s\n",
+                                 filename, current_line, line);
+               }
+       }
+
+       fclose(file);
+}
 
 /*
  *  Find the debugid code in the list and return its index
  */
-static int binary_search(list, lowbound, highbound, code)
-       code_type_t *list;
-       int lowbound, highbound;
-       unsigned int code;
+static int
+binary_search(code_type_t *list, int lowbound, int highbound, unsigned int code)
 {
        int low, high, mid;
        int tries = 0;
@@ -1850,12 +2356,13 @@ static int binary_search(list, lowbound, highbound, code)
 
 
 static int
-parse_codefile(char *filename)
+parse_codefile(const char *filename)
 {
        int fd;
-       int i, j, count, line;
+       int j, line;
+       size_t count;
        struct stat stat_buf;
-       unsigned long file_size;
+       size_t file_size;
        char *file_addr, *endp; 
 
        if ((fd = open(filename, O_RDONLY, 0)) == -1)
@@ -1874,11 +2381,11 @@ parse_codefile(char *filename)
         * For some reason mapping files with zero size fails
         * so it has to be handled specially.
         */
-       file_size = stat_buf.st_size;
-    
+       file_size = (size_t)stat_buf.st_size;
+
        if (stat_buf.st_size != 0)
        {
-               if ((file_addr = mmap(0, stat_buf.st_size, PROT_READ|PROT_WRITE, 
+               if ((file_addr = mmap(0, file_size, PROT_READ|PROT_WRITE,
                                      MAP_PRIVATE|MAP_FILE, fd, 0)) == (char*) -1)
                {
                        printf("Error: Can't map file: %s\n", filename);
@@ -1888,9 +2395,9 @@ parse_codefile(char *filename)
        }
        else
        {
-               printf("Error: Zero sized file: %s\n", filename);
+               // Skip empty files
                close(fd);
-               return(-1);
+               return(0);
        }
        close(fd);
 
@@ -1919,15 +2426,18 @@ parse_codefile(char *filename)
         */
        count++;
 
-       if ((codesc = (code_type_t *)malloc(count * sizeof(code_type_t))) == 0 ) {
-               printf("Failed to allocate buffer for code descriptions\n");
-               return(-1);
-       }
+       // Grow the size of codesc to store new entries.
+       size_t total_count = codesc_idx + count;
+       code_type_t *new_codesc = (code_type_t *)realloc(codesc, (total_count) * sizeof(code_type_t));
 
-       bzero((char *)codesc, count * sizeof(code_type_t));
-       codenum = 0;
+       if (new_codesc == NULL) {
+               printf("Failed to grow/allocate buffer. Skipping file %s\n", filename);
+               return (-1);
+       }
+       codesc = new_codesc;
+       bzero((char *)(codesc + codesc_idx), count * sizeof(code_type_t));
 
-       for (line = 1, i = 0, j = 0; j < file_size && i < count ; i++)
+       for (line = 1, j = 0; j < file_size && codesc_idx < total_count; codesc_idx++)
        {
                /* Skip blank lines */
                while (file_addr[j] == '\n')
@@ -1935,23 +2445,23 @@ parse_codefile(char *filename)
                        j++;
                        line++;
                }
-       
+
                /* Skip leading whitespace */
                while (file_addr[j] == ' ' || file_addr[j] == '\t')
                        j++;
 
                /* Get the debugid code */
-               codesc[i].debugid = strtoul(file_addr + j, &endp, 16);
-               j = endp - file_addr;
+               codesc[codesc_idx].debugid = (uint32_t)strtoul(file_addr + j, &endp, 16);
+               j = (int)(endp - file_addr);
 
-               if (codesc[i].debugid == 0)
+               if (codesc[codesc_idx].debugid == 0)
                {
                        /* We didn't find a debugid code - skip this line */
                        if (verbose_flag)
                                printf("Error: while parsing line %d, skip\n", line);
                        while (file_addr[j] != '\n' && j < file_size)
                                j++;
-                       i--;
+                       codesc_idx--;
                        line++;
                        continue;
                }
@@ -1965,16 +2475,16 @@ parse_codefile(char *filename)
                {
                        /* missing debugid string - skip */
                        if (verbose_flag)
-                               printf("Error: while parsing line %d, (0x%x) skip\n", line, codesc[i].debugid);
-           
+                               printf("Error: while parsing line %d, (0x%x) skip\n", line, codesc[codesc_idx].debugid);
+
                        j++;
-                       i--;
+                       codesc_idx--;
                        line++;
                        continue;
                }
 
                /* Next is the debugid string terminated by a newline */
-               codesc[i].debug_string = &file_addr[j];
+               codesc[codesc_idx].debug_string = &file_addr[j];
 
                /* Null out the newline terminator */
                while ((j < file_size) && (file_addr[j] != '\n'))
@@ -1993,26 +2503,53 @@ parse_codefile(char *filename)
        }
 
        /* sort */
-       qsort((void *)codesc, codenum, sizeof(code_type_t), debugid_compar);
+       qsort((void *)codesc, codesc_idx, sizeof(code_type_t), debugid_compar);
 
        if (verbose_flag)
        {
-               printf("Sorted %d codes in %s\n", codenum, filename);
+               printf("Sorted %zd codes in %s\n", codesc_idx, filename);
                printf("lowbound  [%6d]: 0x%8x %s\n", 0, codesc[0].debugid, codesc[0].debug_string);
-               printf("highbound [%6d]: 0x%8x %s\n\n", codenum-1, codesc[codenum-1].debugid, codesc[codenum-1].debug_string);
+               printf("highbound [%6zd]: 0x%8x %s\n\n", codesc_idx - 1, codesc[codesc_idx - 1].debugid, codesc[codesc_idx - 1].debug_string);
        }
+       codesc_find_dupes();
 
 #if 0
        /* Dump the codefile */
-       for (i = 0; i < codenum; i++)
+       int i;
+       for (i = 0; i < codesc_idx; i++)
                printf("[%d]  0x%x   %s\n",i+1, codesc[i].debugid, codesc[i].debug_string);
 #endif
        return(0);
 }
 
+static void
+codesc_find_dupes(void)
+{
+       boolean_t found_dupes = FALSE;
+       if (codesc_idx == 0)
+       {
+               return;
+       }
+       uint32_t last_debugid = codesc[0].debugid;
+       for(int i = 1; i < codesc_idx; i++)
+       {
+               if(codesc[i].debugid == last_debugid)
+               {
+                       found_dupes = TRUE;
+                       if (verbose_flag) {
+                               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);
+                       }
+               }
+               last_debugid = codesc[i].debugid;
+       }
+       if (found_dupes)
+       {
+               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");
+       }
+}
 
-
-int match_debugid(unsigned int xx, char * debugstr, int * yy)
+int
+match_debugid(unsigned int xx, char * debugstr, int * yy)
 {
        int indx;
 
@@ -2034,9 +2571,69 @@ int match_debugid(unsigned int xx, char * debugstr, int * yy)
        }
 }
 
+void
+read_cpu_map(int fd)
+{
+       if (cpumap_header) {
+               free(cpumap_header);
+               cpumap_header = NULL;
+               cpumap = NULL;
+       }
+
+       /*
+        * To fit in the padding space of a VERSION1 file, the max possible
+        * cpumap size is one page.
+        */
+       cpumap_header = malloc(PAGE_SIZE);
+
+       if (readRAW_flag) {
+               /*
+                * cpu maps exist in a RAW_VERSION1+ header only
+                */
+               if (raw_header.version_no == RAW_VERSION1) {
+                       off_t cpumap_position = lseek(fd, 0, SEEK_CUR);
+            /* cpumap is part of the last 4KB of padding in the preamble */
+                       size_t padding_bytes = SIZE_4KB - (cpumap_position & (SIZE_4KB - 1));
+
+                       if (read(fd, cpumap_header, padding_bytes) == padding_bytes) {
+                               if (cpumap_header->version_no == RAW_VERSION1) {
+                                       cpumap = (kd_cpumap*)&cpumap_header[1];
+                               }
+                       }
+               }
+       } else {
+               int mib[3];
+
+               mib[0] = CTL_KERN;
+               mib[1] = KERN_KDEBUG;
+               mib[2] = KERN_KDCPUMAP;
+
+               size_t temp = PAGE_SIZE;
+               if (sysctl(mib, 3, cpumap_header, &temp, NULL, 0) == 0) {
+                       if (PAGE_SIZE >= temp) {
+                               if (cpumap_header->version_no == RAW_VERSION1) {
+                                       cpumap = (kd_cpumap*)&cpumap_header[1];
+                               }
+                       }
+               }
+       }
+
+       if (!cpumap) {
+               printf("Can't read the cpu map -- this is not fatal\n");
+               free(cpumap_header);
+               cpumap_header = NULL;
+       } else if (verbose_flag) {
+               /* Dump the initial cpumap */
+               printf("\nCPU\tName\n");
+               for (int i = 0; i < cpumap_header->cpu_count; i++) {
+                       printf ("%2d\t%s\n", cpumap[i].cpu_id, cpumap[i].name);
+               }
+               printf("\n");
+       }
+}
 
 int
-read_command_map(int fd, int count)
+read_command_map(int fd, uint32_t count)
 {
        int i;
        size_t size;
@@ -2068,21 +2665,13 @@ read_command_map(int fd, int count)
                }
        }
        if (readRAW_flag) {
-               off_t   offset;
-               
                if (read(fd, mapptr, size) != size) {
                        if (verbose_flag)
                                printf("Can't read the thread map -- this is not fatal\n");
                        free(mapptr);
                        mapptr = 0;
 
-                       return(size);
-               }
-               if (raw_header.version_no != RAW_VERSION0) {
-                       offset = lseek(fd, (off_t)0, SEEK_CUR);
-                       offset = (offset + (4095)) & ~4095;
-               
-                       lseek(fd, offset, SEEK_SET);
+                       return (int)size;
                }
        } else {
                /* Now read the threadmap */
@@ -2102,27 +2691,29 @@ read_command_map(int fd, int count)
                        return(0);
                }
        }
-       for (i = 0; i < total_threads; i++)
-               create_map_entry(mapptr[i].thread, &mapptr[i].command[0]);
+       for (i = 0; i < total_threads; i++) {
+               if (mapptr[i].thread)
+                       create_map_entry(mapptr[i].thread, &mapptr[i].command[0]);
+       }
 
        if (verbose_flag) {
                /* Dump the initial map */
-               
+
                printf("Size of maptable returned is %ld, thus %ld entries\n", size, (size/sizeof(kd_threadmap)));
 
                printf("Thread    Command\n");
-               for (i = 0; i < total_threads; i++)
-               {
+               for (i = 0; i < total_threads; i++) {
                        printf ("0x%lx    %s\n",
                                mapptr[i].thread,
                                mapptr[i].command);
                }
        }
-       return(size);
-}
 
+       return (int)size;
+}
 
-void create_map_entry(uintptr_t thread, char *command)
+void
+create_map_entry(uintptr_t thread, char *command)
 {
        threadmap_t     tme;
        int             hashid;
@@ -2144,8 +2735,8 @@ void create_map_entry(uintptr_t thread, char *command)
        threadmap_hash[hashid] = tme;
 }
 
-
-void delete_thread_entry(uintptr_t thread)
+void
+delete_thread_entry(uintptr_t thread)
 {
        threadmap_t     tme = 0;
        threadmap_t     tme_prev;
@@ -2174,8 +2765,8 @@ void delete_thread_entry(uintptr_t thread)
        }
 }
 
-
-void find_and_insert_tmp_map_entry(uintptr_t pthread, char *command)
+void
+find_and_insert_tmp_map_entry(uintptr_t pthread, char *command)
 {
        threadmap_t     tme = 0;
        threadmap_t     tme_prev;
@@ -2209,8 +2800,8 @@ void find_and_insert_tmp_map_entry(uintptr_t pthread, char *command)
        }
 }
 
-
-void create_tmp_map_entry(uintptr_t thread, uintptr_t pthread)
+void
+create_tmp_map_entry(uintptr_t thread, uintptr_t pthread)
 {
        threadmap_t     tme;
 
@@ -2244,8 +2835,8 @@ find_thread_entry(uintptr_t thread)
        return (0);
 }
 
-
-void find_thread_name(uintptr_t thread, char **command, boolean_t deleteme)
+void
+find_thread_name(uintptr_t thread, char **command, boolean_t deleteme)
 {
        threadmap_t     tme;
 
@@ -2258,13 +2849,15 @@ void find_thread_name(uintptr_t thread, char **command, boolean_t deleteme)
                *command = EMPTYSTRING;
 }
 
-
-void find_thread_command(kd_buf *kbufp, char **command)
+void
+find_thread_command(kd_buf *kbufp, char **command)
 {
        uintptr_t       thread;
        threadmap_t     tme;
        int             debugid_base;
 
+       *command = EMPTYSTRING;
+
        thread = kbufp->arg5;
        debugid_base = kbufp->debugid & DBG_FUNC_MASK;
 
@@ -2279,8 +2872,7 @@ void find_thread_command(kd_buf *kbufp, char **command)
 
                        if (debugid_base == BSC_exit || tme->tm_deleteme == TRUE)
                                delete_thread_entry(thread);
-               } else
-                       *command = EMPTYSTRING;
+               }
        }
        else if (debugid_base == TRACE_DATA_NEWTHREAD) {
                /*
@@ -2304,16 +2896,13 @@ void find_thread_command(kd_buf *kbufp, char **command)
                find_thread_name(thread, command, (debugid_base == BSC_thread_terminate));
 }
 
-
-static
-void getdivisor()
+static void
+getdivisor(void)
 {
-       mach_timebase_info_data_t info;
+       (void) mach_timebase_info (&mach_timebase);
 
        if (frequency == 0) {
-               (void) mach_timebase_info (&info);
-
-               divisor = ( (double)info.denom / (double)info.numer) * 1000;
+               divisor = ( (double)mach_timebase.denom / (double)mach_timebase.numer) * 1000;
        } else
                divisor = (double)frequency / 1000000;